I am new to using the lmfit library. I am trying to optimize parameters to a set of given data by fitting an ODE model. The code below works quite well, however, I have a problem with the dimension of my dataset. It seems that the sets of data must be one-dimensional (R,), however, to solve the ODE, the y-data must be (R,1).
Many thanks in advance for your help.
from lmfit import minimize, Parameters, Parameter, report_fit, Model
from scipy.integrate import odeint
M = 3
b = 0.254e-9
alpha = 0.3
G = 83000
sigma_0 = 364
D = 20e-6
x = x_given[::50] # x shape is (83,)
y = y_given[::50].reshape(-1,1) # y shape is (83,1)
def f(rho, x, k1, k2, zeta, n_g_s):
"""
Derivative to be evaluated
"""
return M*(1/(b*D)*(1-(n_g_s*(1-np.exp(-zeta/(n_g_s*b)*x)))/n_g_s)+k1/b*(rho)**(1/2)-k2*rho)
def g(x, rho_0, k1, k2, zeta, n_g_s):
"""
Solving ODE.
"""
rho = odeint(f, rho_0, x, args=(k1, k2, zeta, n_g_s))
return rho
def iso(x,k1,k2,zeta,n_g_s):
return sigma_0 + M*alpha*G*b*(g(x, rho_0, k1, k2, zeta, n_g_s))**(1/2)
def cine(x,zeta,n_g_s):
return M*G*b/D*n_g_s*(1-np.exp(-zeta/(n_g_s*b)*x))
def flow(x,k1,k2,zeta,n_g_s):
return iso(x,k1,k2,zeta,n_g_s) + cine(x,zeta,n_g_s)
mod = Model(flow)
pars = mod.make_params()
pars['k1'].set(value=0.01, min=0.001, max=0.1)
pars['k2'].set(value=4, min=1, max=9)
pars['zeta'].set(value=0.254e-7, min=0.254e-8, max=0.254e-6)
pars['n_g_s'].set(value=9, min=1, max=10)
result = mod.fit(y,pars,x=x)
print(result.fit_report())
plt.plot(x, y, 'bo')
plt.plot(x, result.init_fit, 'k--', label='initial fit')
plt.plot(x, result.best_fit, 'r-', label='best fit')
dely = result.eval_uncertainty(x=x, sigma=3)
plt.fill_between(x, result.best_fit-dely, result.best_fit+dely, color="#ABABAB",
label='3-$\sigma$ uncertainty band')
plt.legend(loc='best')
plt.show()