Biotech2 / bioprocess_model.py
C2MV's picture
Update bioprocess_model.py
6e8da07 verified
raw
history blame
5.17 kB
# bioprocess_model.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sklearn.metrics import mean_squared_error
from sympy import symbols, lambdify, sympify, Function
class BioprocessModel:
def __init__(self):
self.params = {}
self.r2 = {}
self.rmse = {}
self.models = {} # Initialize the models dictionary
@staticmethod
def logistic(time, xo, xm, um):
return (xo * np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time)))
@staticmethod
def substrate(time, so, p, q, xo, xm, um):
return so - (p * xo * ((np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time))) - 1)) - \
(q * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
@staticmethod
def product(time, po, alpha, beta, xo, xm, um):
return po + (alpha * xo * ((np.exp(um * time) / (1 - (xo / xm) * (1 - np.exp(um * time))) - 1))) + \
(beta * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
def set_model(self, model_type, equation, params_str):
"""
Configures the model based on the type, equation, and parameters.
:param model_type: Type of the model ('biomass', 'substrate', 'product')
:param equation: The equation as a string
:param params_str: Comma-separated string of parameter names
"""
t_symbol = symbols('t')
X = Function('X') # Definir 'X(t)' como una funci贸n simb贸lica
try:
expr = sympify(equation)
except Exception as e:
raise ValueError(f"Error al parsear la ecuaci贸n '{equation}': {e}")
params = [param.strip() for param in params_str.split(',')]
params_symbols = symbols(params)
# Extraer s铆mbolos utilizados en la expresi贸n
used_symbols = expr.free_symbols
# Convertir s铆mbolos a strings
used_params = [str(s) for s in used_symbols if s != t_symbol]
# Verificar que todos los par谩metros en params_str est茅n usados en la ecuaci贸n
for param in params:
if param not in used_params:
raise ValueError(f"El par谩metro '{param}' no se usa en la ecuaci贸n '{equation}'.")
if model_type == 'biomass':
# Biomasa como funci贸n de tiempo y par谩metros
func_expr = expr
func = lambdify((t_symbol, *params_symbols), func_expr, 'numpy')
self.models['biomass'] = {
'function': func,
'params': params
}
elif model_type in ['substrate', 'product']:
# Estos modelos dependen de biomasa, que ya deber铆a estar establecida
if 'biomass' not in self.models:
raise ValueError("Biomasa debe estar configurada antes de Sustrato o Producto.")
biomass_func = self.models['biomass']['function']
# Reemplazar 'X(t)' por la funci贸n de biomasa
func_expr = expr.subs('X(t)', biomass_func)
func = lambdify((t_symbol, *params_symbols), func_expr, 'numpy')
self.models[model_type] = {
'function': func,
'params': params
}
else:
raise ValueError(f"Tipo de modelo no soportado: {model_type}")
def fit_model(self, model_type, time, data, bounds=([-np.inf], [np.inf])):
"""
Fits the model to the data.
:param model_type: Type of the model ('biomass', 'substrate', 'product')
:param time: Time data
:param data: Observed data to fit
:param bounds: Bounds for the parameters
:return: Predicted data from the model
"""
if model_type not in self.models:
raise ValueError(f"Model type '{model_type}' is not set. Please use set_model first.")
func = self.models[model_type]['function']
params = self.models[model_type]['params']
# Definir la funci贸n de ajuste
def fit_func(t, *args):
try:
y = func(t, *args)
return y
except Exception as e:
raise RuntimeError(f"Error en fit_func: {e}")
# Definir una estimaci贸n inicial para los par谩metros
p0 = [1.0] * len(params) # Puedes ajustar estos valores seg煤n sea necesario
try:
# Definir los l铆mites correctamente
lower_bounds, upper_bounds = bounds
# Ajustar el modelo usando curve_fit con p0
popt, _ = curve_fit(fit_func, time, data, p0=p0, bounds=(lower_bounds, upper_bounds), maxfev=10000)
# Guardar los par谩metros ajustados en el modelo
self.params[model_type] = {param: val for param, val in zip(params, popt)}
y_pred = fit_func(time, *popt)
self.r2[model_type] = 1 - (np.sum((data - y_pred) ** 2) / np.sum((data - np.mean(data)) ** 2))
self.rmse[model_type] = np.sqrt(mean_squared_error(data, y_pred))
return y_pred
except Exception as e:
raise RuntimeError(f"Error while fitting {model_type} model: {str(e)}")