Alex van der Kooi
Alex van der Kooi

Reputation: 3

Scipy minimize to optimize ODE parameters

I have defined an ode function, langmuir_ode, as follows:

def langmuir_ode(t, AL, Rmax, kon, koff):
    A = np.interp(t, time, concs)
    L = Rmax - AL
    return kon * A * L - koff * AL

t is some time array (n,). concs is a (n,) array with values per timepoint in t. Since solve_ivp may want to evaluate time points not directly in t, I'm allowing interpolation to find a value A from the time and concs arrays. Rmax, kon and koff are parameters I would like to optimize using scipy minimize.

Next, I define the obj function to calculate the error between some simulated data ysim and the solution found by solve_ivp:

def obj(t, *args):
    sol = solve_ivp(fun=langmuir_ode, 
                    t_span=[0,t[-1]], 
                    y0=[0.0], 
                    t_eval=t, 
                    args=args
                    )
    sol = sol.y.ravel()
    error = ysim - sol
    res_sd = np.std(error)
    print('Standard deviation of fit residuals:', format(res_sd,'.2f'))
    SSQ = np.sum(error**2)
    return SSQ

Using the parameters known to be correct for the simulated data, I get good values of SSQ as per:

print('Sum of squared fit residuals:', format(obj(time, 250, 1e5, 5e-3),'.2f'))
Standard deviation of fit residuals: 1.58
Sum of squared fit residuals: 848.23

My question: how do I use Scipy's minimize function to optimize parameters Rmax, kon and koff given some initial values and the above functions?

initial_values = 300, 5e4, 4e-5
fit = minimize(obj, initial_values)

gives:

Traceback (most recent call last):

  File C:\Program Files\Spyder\pkgs\spyder_kernels\py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File c:\users\avdkadmin\untitled0.py:66
    fit = minimize(obj, initial_values)

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_minimize.py:691 in minimize
    res = _minimize_bfgs(fun, x0, args, jac, callback, **options)

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_optimize.py:1362 in _minimize_bfgs
    sf = _prepare_scalar_function(fun, x0, jac, args=args, epsilon=eps,

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_optimize.py:332 in _prepare_scalar_function
    sf = ScalarFunction(fun, x0, args, grad, hess,

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_differentiable_functions.py:158 in __init__
    self._update_fun()

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_differentiable_functions.py:251 in _update_fun
    self._update_fun_impl()

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_differentiable_functions.py:155 in update_fun
    self.f = fun_wrapped(self.x)

  File C:\Program Files\Spyder\pkgs\scipy\optimize\_differentiable_functions.py:137 in fun_wrapped
    fx = fun(np.copy(x), *args)

  File c:\users\avdkadmin\untitled0.py:50 in obj
    sol = solve_ivp(fun=langmuir_ode,

  File C:\Program Files\Spyder\pkgs\scipy\integrate\_ivp\ivp.py:540 in solve_ivp
    raise ValueError("Values in `t_eval` are not within `t_span`.")

ValueError: Values in `t_eval` are not within `t_span`.

I'm probaby misunderstanding the syntax needed for correctly calling the minimize function. Any suggestions?

Upvotes: 0

Views: 65

Answers (1)

jared
jared

Reputation: 9046

A full answer would require a minimal reproducible example on your part. But despite that, I can tell you what your issue is and a possible fix.

Your issue is that scipy.optimize.minimize expects the function to be of the form f(x, *args), where x is the term being optimized. Your function is in the same form but *args is the argument being optimized.

What you need to do is to change your obj function definition and how you're calling it with minimize.

def obj(args, t):  # not *args because there is a set number of arguments
    ...

initial_values = 300, 5e4, 4e-5
# time will be passed as the second argument and won't change between calls
fit = minimize(obj, initial_values, args=(time,))

Upvotes: 0

Related Questions