问题
For solving simple ODEs using SciPy, I used to use the odeint function, with form:
scipy.integrate.odeint(func, y0, t, args=(), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0)[source]
where a simple function to be integrated could include additional arguments of the form:
def dy_dt(t, y, arg1, arg2):
# processing code here
In SciPy 1.0, it seems the ode and odeint funcs have been replaced by a newer solve_ivp method.
scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)
However, this doesn't seem to offer an args parameter, nor any indication in the documentation as to implementing the passing of args.
Therefore, I wonder if arg passing is possible with the new API, or is this a feature that has yet to be added? (It would seem an oversight to me if this features has been intentionally removed?)
Reference: https://docs.scipy.org/doc/scipy/reference/integrate.html
回答1:
It doesn't seem like the new function has an args
parameter. As a workaround you can create a wrapper like
def wrapper(t, y):
orig_func(t,y,hardcoded_args)
and pass that in.
回答2:
Relatively recently there appeared a similar question on scipy's github. Their solution is to use lambda
:
solve_ivp(fun=lambda t, y: fun(t, y, *args), ...)
And they argue that there is already enough overhead for this not to matter.
回答3:
Recently the 'args' option was added to solve_ivp, see here: https://github.com/scipy/scipy/issues/8352#issuecomment-535689344
回答4:
Adding to Cleb's answer, here's an example for using the lambda t,y: fun(t,y,args)
method. We set up the function handle that returns the rhs of a second order homogeneous ODE with two parameters. Then we feed it to our solver, along with a couple options.
import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt
def rhs_2nd_order_ode(t, y, a, b):
"""
2nd order ODE function handle for use with scipy.integrate.solve_ivp
Solves u'' + au'+ bu = 0 after reducing order with y[0]=u and y[1]=u'.
:param t: dependent variable
:param y: independent variables
:param a: a
:param b: b
:return: Returns the rhs of y[0]' = y[1] and y[1]' = -a*y[1] - b*y[0]
"""
return [y[1], -a*y[1] - b*y[0]]
if __name__ == "__main__":
t_span = (0, 10)
t_eval = np.linspace(t_span[0], t_span[1], 100)
y0 = [0, 1]
a = 1
b = 2
sol = integrate.solve_ivp(lambda t,y: rhs_2nd_order_ode(t,y,a,b), t_span, y0,
method='RK45', t_eval=t_eval)
fig, ax = plt.subplots(1, 1)
ax.plot(sol.t, sol.y[0])
ax.set(xlabel='t',ylabel='y')
回答5:
For completeness, I think you can also do this but I'm not sure why you would bother with the other two options posted here which look perfectly fine.
from functools import partial
fun = partial(dy_dt, arg1=arg1, arg2=arg2)
scipy.integrate.solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)
来源:https://stackoverflow.com/questions/48245765/pass-args-for-solve-ivp-new-scipy-ode-api