Below is a code for the least-square fitting of parameters for an ODE. Python "minimize" as well as "least-square" functions have been used. Different methods and ODE solvers/steps have been tried (scipy ode/odeint). This is a problem that has been solved in MATLAB easily, but Python keeps returning the initial guess. I hope you find a coding mistake or I would be disappointed by Python optimization functions. Obj shows the objective (residual sum of squares) and ode function (firstorder) shows the equations with unknown parameters. Data set is attached.
import numpy as np
from scipy.integrate import ode
from scipy.optimize import least_squares
from scipy.optimize import minimize
from scipy.optimize import SR1
import matplotlib.pyplot as plt
import math
Minput=np.loadtxt('C:\\Users\\Ladan\\Documents\\Python Scripts\\Python\\moisturesmoothopt.txt')
Minput=Minput.flatten()
time=np.linspace(0,1800,901)
A=np.zeros(3)
XC,RC,alpha=A
#bnds=([0,0,0],[Minput[0],math.inf,math.inf])
bnds=((0,Minput[0]),(0,math.inf),(0,math.inf))
def firstorder(X,time,A):
if X>=XC:
dX=-RC
if X<XC:
dX=-RC*(X/XC)**alpha
return dX
def obj(A):
X0=Minput[0]
# Xpred=odeint(firstorder,X0,time,args=(A,))
Xpred=ode(firstorder).set_integrator('vode', method='bdf',
order=15).set_initial_value(Minput[0],0).set_f_params(A)
#Xpred=ode(firstorder).set_integrator('lsoda').set_initial_value(Minput[0],0).set_f_params(A)
EPR=Xpred
EPR2=EPR.y.flatten()
ERRone=np.sum(np.power((EPR2-Minput),2))
ERR=ERRone/((901-3)) # residual sum of squares deivided by dof
return ERR
XC=1
RC=0.005
alpha=1.5
A0=[XC,RC,alpha]
Parameters=minimize(obj,A0,method='SLSQP',bounds=bnds,options={'ftol':1e-10,
'maxiter': 1000})
print('parameters',Parameters)
Data for Minput array is shared online:
