Update interface.py
Browse files- interface.py +68 -59
interface.py
CHANGED
|
@@ -48,6 +48,7 @@ class BioprocessModel:
|
|
| 48 |
self.datax_std = []
|
| 49 |
self.datas_std = []
|
| 50 |
self.datap_std = []
|
|
|
|
| 51 |
|
| 52 |
@staticmethod
|
| 53 |
def logistic(time, xo, xm, um):
|
|
@@ -108,36 +109,70 @@ class BioprocessModel:
|
|
| 108 |
|
| 109 |
self.time = time
|
| 110 |
|
| 111 |
-
def
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
return y_pred
|
| 142 |
|
| 143 |
def plot_combined_results(self, time, biomass, substrate, product,
|
|
@@ -305,8 +340,8 @@ def process_and_plot(
|
|
| 305 |
|
| 306 |
# Usa el primer modelo de biomasa para X(t)
|
| 307 |
biomass_model = biomass_results[0]['model']
|
| 308 |
-
X_t_func = biomass_model.models['biomass']['function']
|
| 309 |
biomass_params_values = list(biomass_model.params['biomass'].values())
|
|
|
|
| 310 |
|
| 311 |
# Ajusta los modelos de Sustrato
|
| 312 |
for i in range(len(substrate_eqs)):
|
|
@@ -315,20 +350,7 @@ def process_and_plot(
|
|
| 315 |
bounds_str = substrate_bounds[i]
|
| 316 |
|
| 317 |
model = BioprocessModel()
|
| 318 |
-
|
| 319 |
-
t_symbol = symbols('t')
|
| 320 |
-
expr_substrate = sympify(equation)
|
| 321 |
-
substrate_params_symbols = symbols([param.strip() for param in params_str.split(',')])
|
| 322 |
-
substrate_func_expr = expr_substrate.subs('X(t)', X_t_func(t_symbol, *biomass_params_values))
|
| 323 |
-
substrate_func = lambdify(
|
| 324 |
-
(t_symbol, *substrate_params_symbols),
|
| 325 |
-
substrate_func_expr,
|
| 326 |
-
'numpy'
|
| 327 |
-
)
|
| 328 |
-
model.models['substrate'] = {
|
| 329 |
-
'function': substrate_func,
|
| 330 |
-
'params': [param.strip() for param in params_str.split(',')]
|
| 331 |
-
}
|
| 332 |
|
| 333 |
params = model.models['substrate']['params']
|
| 334 |
lower_bounds, upper_bounds = parse_bounds(bounds_str, len(params))
|
|
@@ -350,20 +372,7 @@ def process_and_plot(
|
|
| 350 |
bounds_str = product_bounds[i]
|
| 351 |
|
| 352 |
model = BioprocessModel()
|
| 353 |
-
|
| 354 |
-
t_symbol = symbols('t')
|
| 355 |
-
expr_product = sympify(equation)
|
| 356 |
-
product_params_symbols = symbols([param.strip() for param in params_str.split(',')])
|
| 357 |
-
product_func_expr = expr_product.subs('X(t)', X_t_func(t_symbol, *biomass_params_values))
|
| 358 |
-
product_func = lambdify(
|
| 359 |
-
(t_symbol, *product_params_symbols),
|
| 360 |
-
product_func_expr,
|
| 361 |
-
'numpy'
|
| 362 |
-
)
|
| 363 |
-
model.models['product'] = {
|
| 364 |
-
'function': product_func,
|
| 365 |
-
'params': [param.strip() for param in params_str.split(',')]
|
| 366 |
-
}
|
| 367 |
|
| 368 |
params = model.models['product']['params']
|
| 369 |
lower_bounds, upper_bounds = parse_bounds(bounds_str, len(params))
|
|
|
|
| 48 |
self.datax_std = []
|
| 49 |
self.datas_std = []
|
| 50 |
self.datap_std = []
|
| 51 |
+
self.models = {} # Initialize the models dictionary
|
| 52 |
|
| 53 |
@staticmethod
|
| 54 |
def logistic(time, xo, xm, um):
|
|
|
|
| 109 |
|
| 110 |
self.time = time
|
| 111 |
|
| 112 |
+
def set_model(self, model_type, equation, params_str):
|
| 113 |
+
"""
|
| 114 |
+
Sets up the model based on the type, equation, and parameters.
|
| 115 |
+
|
| 116 |
+
:param model_type: Type of the model ('biomass', 'substrate', 'product')
|
| 117 |
+
:param equation: The equation as a string
|
| 118 |
+
:param params_str: Comma-separated string of parameter names
|
| 119 |
+
"""
|
| 120 |
+
t_symbol = symbols('t')
|
| 121 |
+
expr = sympify(equation)
|
| 122 |
+
params = [param.strip() for param in params_str.split(',')]
|
| 123 |
+
params_symbols = symbols(params)
|
| 124 |
+
|
| 125 |
+
if model_type == 'biomass':
|
| 126 |
+
# Assuming biomass is a function of time only for logistic
|
| 127 |
+
func_expr = expr
|
| 128 |
+
func = lambdify(t_symbol, func_expr, 'numpy')
|
| 129 |
+
self.models['biomass'] = {
|
| 130 |
+
'function': func,
|
| 131 |
+
'params': params
|
| 132 |
+
}
|
| 133 |
+
elif model_type in ['substrate', 'product']:
|
| 134 |
+
# These models depend on biomass, which should already be set
|
| 135 |
+
if 'biomass' not in self.models:
|
| 136 |
+
raise ValueError("Biomass model must be set before substrate or product models.")
|
| 137 |
+
biomass_func = self.models['biomass']['function']
|
| 138 |
+
func_expr = expr.subs('X(t)', biomass_func(t_symbol))
|
| 139 |
+
func = lambdify((t_symbol, *params_symbols), func_expr, 'numpy')
|
| 140 |
+
self.models[model_type] = {
|
| 141 |
+
'function': func,
|
| 142 |
+
'params': params
|
| 143 |
+
}
|
| 144 |
+
else:
|
| 145 |
+
raise ValueError(f"Unsupported model type: {model_type}")
|
| 146 |
+
|
| 147 |
+
def fit_model(self, model_type, time, data, bounds=([-np.inf], [np.inf])):
|
| 148 |
+
"""
|
| 149 |
+
Fits the model to the data.
|
| 150 |
+
|
| 151 |
+
:param model_type: Type of the model ('biomass', 'substrate', 'product')
|
| 152 |
+
:param time: Time data
|
| 153 |
+
:param data: Observed data to fit
|
| 154 |
+
:param bounds: Bounds for the parameters
|
| 155 |
+
:return: Predicted data from the model
|
| 156 |
+
"""
|
| 157 |
+
if model_type not in self.models:
|
| 158 |
+
raise ValueError(f"Model type '{model_type}' is not set. Please use set_model first.")
|
| 159 |
+
|
| 160 |
+
func = self.models[model_type]['function']
|
| 161 |
+
params = self.models[model_type]['params']
|
| 162 |
+
|
| 163 |
+
# Define the fitting function based on model type
|
| 164 |
+
if model_type == 'biomass':
|
| 165 |
+
def fit_func(t, *args):
|
| 166 |
+
return func(t, *args)
|
| 167 |
+
else:
|
| 168 |
+
def fit_func(t, *args):
|
| 169 |
+
return func(t, *args)
|
| 170 |
+
|
| 171 |
+
popt, _ = curve_fit(fit_func, time, data, bounds=bounds, maxfev=10000)
|
| 172 |
+
self.params[model_type] = {param: val for param, val in zip(params, popt)}
|
| 173 |
+
y_pred = fit_func(time, *popt)
|
| 174 |
+
self.r2[model_type] = 1 - (np.sum((data - y_pred) ** 2) / np.sum((data - np.mean(data)) ** 2))
|
| 175 |
+
self.rmse[model_type] = np.sqrt(mean_squared_error(data, y_pred))
|
| 176 |
return y_pred
|
| 177 |
|
| 178 |
def plot_combined_results(self, time, biomass, substrate, product,
|
|
|
|
| 340 |
|
| 341 |
# Usa el primer modelo de biomasa para X(t)
|
| 342 |
biomass_model = biomass_results[0]['model']
|
|
|
|
| 343 |
biomass_params_values = list(biomass_model.params['biomass'].values())
|
| 344 |
+
biomass_func = biomass_model.models['biomass']['function']
|
| 345 |
|
| 346 |
# Ajusta los modelos de Sustrato
|
| 347 |
for i in range(len(substrate_eqs)):
|
|
|
|
| 350 |
bounds_str = substrate_bounds[i]
|
| 351 |
|
| 352 |
model = BioprocessModel()
|
| 353 |
+
model.set_model('substrate', equation, params_str)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
|
| 355 |
params = model.models['substrate']['params']
|
| 356 |
lower_bounds, upper_bounds = parse_bounds(bounds_str, len(params))
|
|
|
|
| 372 |
bounds_str = product_bounds[i]
|
| 373 |
|
| 374 |
model = BioprocessModel()
|
| 375 |
+
model.set_model('product', equation, params_str)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 376 |
|
| 377 |
params = model.models['product']['params']
|
| 378 |
lower_bounds, upper_bounds = parse_bounds(bounds_str, len(params))
|