Update bioprocess_model.py
Browse files- bioprocess_model.py +71 -77
bioprocess_model.py
CHANGED
|
@@ -1,11 +1,8 @@
|
|
| 1 |
# bioprocess_model.py
|
| 2 |
|
| 3 |
import numpy as np
|
| 4 |
-
import pandas as pd
|
| 5 |
-
import matplotlib.pyplot as plt
|
| 6 |
from scipy.optimize import curve_fit
|
| 7 |
from sklearn.metrics import mean_squared_error
|
| 8 |
-
from sympy import symbols, lambdify, sympify, Function
|
| 9 |
|
| 10 |
class BioprocessModel:
|
| 11 |
def __init__(self):
|
|
@@ -18,107 +15,104 @@ class BioprocessModel:
|
|
| 18 |
def logistic(time, xo, xm, um):
|
| 19 |
return (xo * np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time)))
|
| 20 |
|
| 21 |
-
|
| 22 |
-
def substrate(time, so, p, q, xo, xm, um):
|
| 23 |
-
return so - (p * xo * ((np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time))) - 1)) - \
|
| 24 |
-
(q * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
|
| 25 |
-
|
| 26 |
-
@staticmethod
|
| 27 |
-
def product(time, po, alpha, beta, xo, xm, um):
|
| 28 |
-
return po + (alpha * xo * ((np.exp(um * time) / (1 - (xo / xm) * (1 - np.exp(um * time))) - 1))) + \
|
| 29 |
-
(beta * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
|
| 30 |
-
|
| 31 |
-
def set_model(self, model_type, equation, params_str):
|
| 32 |
"""
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
:param
|
| 36 |
-
:param
|
| 37 |
-
:param params_str: Comma-separated string of parameter names
|
| 38 |
"""
|
| 39 |
-
t_symbol = symbols('t')
|
| 40 |
-
X = Function('X') # Definir 'X(t)' como una funci贸n simb贸lica
|
| 41 |
-
|
| 42 |
try:
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
except Exception as e:
|
| 45 |
-
raise ValueError(f"Error al
|
| 46 |
-
|
| 47 |
-
params = [param.strip() for param in params_str.split(',')]
|
| 48 |
-
params_symbols = symbols(params)
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
'
|
| 66 |
-
'params': params
|
| 67 |
}
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
}
|
| 80 |
-
|
| 81 |
-
raise ValueError(f"
|
| 82 |
|
| 83 |
def fit_model(self, model_type, time, data, bounds=([-np.inf], [np.inf])):
|
| 84 |
"""
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
:param model_type:
|
| 88 |
-
:param time:
|
| 89 |
-
:param data:
|
| 90 |
-
:param bounds:
|
| 91 |
-
:return:
|
| 92 |
"""
|
| 93 |
if model_type not in self.models:
|
| 94 |
-
raise ValueError(f"
|
| 95 |
|
| 96 |
func = self.models[model_type]['function']
|
| 97 |
params = self.models[model_type]['params']
|
| 98 |
|
| 99 |
-
# Definir la funci贸n de ajuste
|
| 100 |
def fit_func(t, *args):
|
| 101 |
try:
|
| 102 |
-
y
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
except Exception as e:
|
| 105 |
raise RuntimeError(f"Error en fit_func: {e}")
|
| 106 |
|
| 107 |
-
#
|
| 108 |
p0 = [1.0] * len(params) # Puedes ajustar estos valores seg煤n sea necesario
|
| 109 |
|
| 110 |
try:
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
# Ajustar el modelo usando curve_fit con p0
|
| 115 |
-
popt, _ = curve_fit(fit_func, time, data, p0=p0, bounds=(lower_bounds, upper_bounds), maxfev=10000)
|
| 116 |
-
|
| 117 |
-
# Guardar los par谩metros ajustados en el modelo
|
| 118 |
self.params[model_type] = {param: val for param, val in zip(params, popt)}
|
| 119 |
y_pred = fit_func(time, *popt)
|
| 120 |
self.r2[model_type] = 1 - (np.sum((data - y_pred) ** 2) / np.sum((data - np.mean(data)) ** 2))
|
| 121 |
self.rmse[model_type] = np.sqrt(mean_squared_error(data, y_pred))
|
| 122 |
return y_pred
|
| 123 |
except Exception as e:
|
| 124 |
-
raise RuntimeError(f"Error
|
|
|
|
| 1 |
# bioprocess_model.py
|
| 2 |
|
| 3 |
import numpy as np
|
|
|
|
|
|
|
| 4 |
from scipy.optimize import curve_fit
|
| 5 |
from sklearn.metrics import mean_squared_error
|
|
|
|
| 6 |
|
| 7 |
class BioprocessModel:
|
| 8 |
def __init__(self):
|
|
|
|
| 15 |
def logistic(time, xo, xm, um):
|
| 16 |
return (xo * np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time)))
|
| 17 |
|
| 18 |
+
def set_model_biomass(self, equation, params_str):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
"""
|
| 20 |
+
Configura el modelo de Biomasa.
|
| 21 |
+
|
| 22 |
+
:param equation: La ecuaci贸n de Biomasa como cadena de texto
|
| 23 |
+
:param params_str: Cadena de par谩metros separados por comas
|
|
|
|
| 24 |
"""
|
|
|
|
|
|
|
|
|
|
| 25 |
try:
|
| 26 |
+
# Define la funci贸n de Biomasa directamente
|
| 27 |
+
def biomass_func(t, xo, xm, um):
|
| 28 |
+
return (xo * np.exp(um * t)) / (1 - (xo / xm) * (1 - np.exp(um * t)))
|
| 29 |
+
|
| 30 |
+
self.models['biomass'] = {
|
| 31 |
+
'function': biomass_func,
|
| 32 |
+
'params': [param.strip() for param in params_str.split(',')]
|
| 33 |
+
}
|
| 34 |
except Exception as e:
|
| 35 |
+
raise ValueError(f"Error al configurar el modelo de biomasa: {e}")
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
+
def set_model_substrate(self, equation, params_str):
|
| 38 |
+
"""
|
| 39 |
+
Configura el modelo de Sustrato.
|
| 40 |
+
|
| 41 |
+
:param equation: La ecuaci贸n de Sustrato como cadena de texto (no usada en este enfoque)
|
| 42 |
+
:param params_str: Cadena de par谩metros separados por comas
|
| 43 |
+
"""
|
| 44 |
+
try:
|
| 45 |
+
# Define la funci贸n de Sustrato que depende de Biomasa
|
| 46 |
+
def substrate_func(t, so, p, q, xo, xm, um):
|
| 47 |
+
X_t = self.models['biomass']['function'](t, xo, xm, um)
|
| 48 |
+
return so - p * X_t - q * np.log(1 - (xo / xm) * (1 - np.exp(um * t)))
|
| 49 |
+
|
| 50 |
+
self.models['substrate'] = {
|
| 51 |
+
'function': substrate_func,
|
| 52 |
+
'params': [param.strip() for param in params_str.split(',')]
|
|
|
|
| 53 |
}
|
| 54 |
+
except Exception as e:
|
| 55 |
+
raise ValueError(f"Error al configurar el modelo de sustrato: {e}")
|
| 56 |
+
|
| 57 |
+
def set_model_product(self, equation, params_str):
|
| 58 |
+
"""
|
| 59 |
+
Configura el modelo de Producto.
|
| 60 |
+
|
| 61 |
+
:param equation: La ecuaci贸n de Producto como cadena de texto (no usada en este enfoque)
|
| 62 |
+
:param params_str: Cadena de par谩metros separados por comas
|
| 63 |
+
"""
|
| 64 |
+
try:
|
| 65 |
+
# Define la funci贸n de Producto que depende de Biomasa
|
| 66 |
+
def product_func(t, po, alpha, beta, xo, xm, um):
|
| 67 |
+
X_t = self.models['biomass']['function'](t, xo, xm, um)
|
| 68 |
+
return po + alpha * X_t + beta * np.log(1 - (xo / xm) * (1 - np.exp(um * t)))
|
| 69 |
+
|
| 70 |
+
self.models['product'] = {
|
| 71 |
+
'function': product_func,
|
| 72 |
+
'params': [param.strip() for param in params_str.split(',')]
|
| 73 |
}
|
| 74 |
+
except Exception as e:
|
| 75 |
+
raise ValueError(f"Error al configurar el modelo de producto: {e}")
|
| 76 |
|
| 77 |
def fit_model(self, model_type, time, data, bounds=([-np.inf], [np.inf])):
|
| 78 |
"""
|
| 79 |
+
Ajusta el modelo a los datos.
|
| 80 |
+
|
| 81 |
+
:param model_type: Tipo de modelo ('biomass', 'substrate', 'product')
|
| 82 |
+
:param time: Datos de tiempo
|
| 83 |
+
:param data: Datos observados para ajustar
|
| 84 |
+
:param bounds: L铆mites para los par谩metros
|
| 85 |
+
:return: Datos predichos por el modelo
|
| 86 |
"""
|
| 87 |
if model_type not in self.models:
|
| 88 |
+
raise ValueError(f"Tipo de modelo '{model_type}' no est谩 configurado. Usa set_model primero.")
|
| 89 |
|
| 90 |
func = self.models[model_type]['function']
|
| 91 |
params = self.models[model_type]['params']
|
| 92 |
|
| 93 |
+
# Definir la funci贸n de ajuste para curve_fit
|
| 94 |
def fit_func(t, *args):
|
| 95 |
try:
|
| 96 |
+
# Para Sustrato y Producto, se necesitan los par谩metros de Biomasa
|
| 97 |
+
if model_type in ['substrate', 'product']:
|
| 98 |
+
# Extraer los par谩metros de Biomasa
|
| 99 |
+
xo, xm, um = self.params['biomass']['xo'], self.params['biomass']['xm'], self.params['biomass']['um']
|
| 100 |
+
return func(t, *args, xo, xm, um)
|
| 101 |
+
else:
|
| 102 |
+
return func(t, *args)
|
| 103 |
except Exception as e:
|
| 104 |
raise RuntimeError(f"Error en fit_func: {e}")
|
| 105 |
|
| 106 |
+
# Estimaci贸n inicial de los par谩metros
|
| 107 |
p0 = [1.0] * len(params) # Puedes ajustar estos valores seg煤n sea necesario
|
| 108 |
|
| 109 |
try:
|
| 110 |
+
popt, _ = curve_fit(fit_func, time, data, p0=p0, bounds=bounds, maxfev=10000)
|
| 111 |
+
# Guardar los par谩metros ajustados
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
self.params[model_type] = {param: val for param, val in zip(params, popt)}
|
| 113 |
y_pred = fit_func(time, *popt)
|
| 114 |
self.r2[model_type] = 1 - (np.sum((data - y_pred) ** 2) / np.sum((data - np.mean(data)) ** 2))
|
| 115 |
self.rmse[model_type] = np.sqrt(mean_squared_error(data, y_pred))
|
| 116 |
return y_pred
|
| 117 |
except Exception as e:
|
| 118 |
+
raise RuntimeError(f"Error al ajustar el modelo '{model_type}': {e}")
|