|
|
|
|
|
import numpy as np |
|
from scipy.optimize import curve_fit |
|
from sympy import symbols, sympify, lambdify |
|
import warnings |
|
|
|
class BioprocessModel: |
|
def __init__(self): |
|
self.params = {} |
|
self.models = {} |
|
self.r2 = {} |
|
self.rmse = {} |
|
|
|
def set_model(self, model_type, equation_str, param_str): |
|
equation_str = equation_str.strip() |
|
if '=' in equation_str: |
|
equation_str = equation_str.split('=', 1)[1].strip() |
|
|
|
params = [param.strip() for param in param_str.split(',')] |
|
self.models[model_type] = { |
|
'equation_str': equation_str, |
|
'params': params |
|
} |
|
|
|
t = symbols('t') |
|
param_symbols = symbols(params) |
|
expr = sympify(equation_str) |
|
func = lambdify((t, *param_symbols), expr, 'numpy') |
|
self.models[model_type]['function'] = func |
|
|
|
def fit_model(self, model_type, time, data, bounds): |
|
func = self.models[model_type]['function'] |
|
params = self.models[model_type]['params'] |
|
|
|
p0 = np.ones(len(params)) |
|
lower_bounds, upper_bounds = bounds |
|
|
|
lower_bounds = np.array(lower_bounds) |
|
upper_bounds = np.array(upper_bounds) |
|
|
|
if len(lower_bounds) != len(params): |
|
lower_bounds = np.full(len(params), -np.inf) |
|
if len(upper_bounds) != len(params): |
|
upper_bounds = np.full(len(params), np.inf) |
|
|
|
with warnings.catch_warnings(): |
|
warnings.simplefilter("ignore") |
|
popt, _ = curve_fit(func, time, data, p0=p0, bounds=(lower_bounds, upper_bounds), maxfev=10000) |
|
|
|
self.params[model_type] = dict(zip(params, popt)) |
|
y_pred = func(time, *popt) |
|
ss_res = np.sum((data - y_pred) ** 2) |
|
ss_tot = np.sum((data - np.mean(data)) ** 2) |
|
self.r2[model_type] = 1 - (ss_res / ss_tot) |
|
self.rmse[model_type] = np.sqrt(np.mean((data - y_pred) ** 2)) |
|
return y_pred |
|
|