在不同的 scipy ode 求解器之间进行交换
Posted
技术标签:
【中文标题】在不同的 scipy ode 求解器之间进行交换【英文标题】:Interchanging between different scipy ode solvers 【发布时间】:2016-04-07 02:31:56 【问题描述】:我做了一个求解器,它可以在scipy.integrate.ode
和scipy.integrate.odeint
之间互换。这是代码。
def f(y,s,C,u,v):
y0 = y[0] # u
y1 = y[1] # u'
y2 = y[2] # v
y3 = y[3] # v'
dy = np.zeros_like(y)
dy[0] = y1
dy[2] = y3
C = C.subs(u:y0,v:y2)
dy[1] = -C[0,0][0]*dy[0]**2\
-2*C[0,0][1]*dy[0]*dy[2]\
-C[0,1][1]*dy[2]**2
dy[3] = -C[1,0][0]*dy[0]**2\
-2*C[1,0][1]*dy[0]*dy[2]\
-C[1,1][1]*dy[2]**2
return dy
def solve(C,u0,s0,s1,ds,solver=None):
from sympy.abc import u,v
if solver == None: # use lsoda from scipy.integrate.odeint
s = np.arange(s0,s1+ds,ds)
print 'Running solver ...'
return sc.odeint(f,u0,s,args=(C,u,v))
else: # use any other solver from scipy.integrate.ode
r = sc.ode(f).set_integrator(solver) # vode,zvode,lsoda,dopri5,dop853
r.set_f_params(C,u,v)
r.set_initial_value(u0)
#t = []
y = []
print 'Running solver ...'
while r.successful() and r.t <= s1:
r.integrate(r.t + ds)
y.append(r.y)#; t.append(r.t)
return np.array(y)
我遇到的问题如下。如果我决定使用来自scipy.integrate.odeint
的求解器,则必须按照代码中的顺序指定f
的参数。但是,如果我决定使用来自scipy.integrate.ode
的求解器,我必须将函数f(y,s,C,u,v)
的参数顺序更改为f(s,y,C,u,v)
,否则会出现错误
TypeError: 'float' object has no attribute '__getitem__'
如果我这样做,那么scipy.integrate.odeint
会为定义为f(s,y,C,u,v)
的f
生成相同的错误。无论参数顺序如何,如何统一f
操作?
编辑:
总结问题:
scipy.integrate.ode
求解器在函数 f 定义为 f(s,y,C,u,v)
时工作,scipy.integrate.odeint
求解器在函数 f 定义为 f(y,s,C,u,v)
时工作。为什么会出现这种情况,我该如何解决?
编辑:
Scipy -- 版本 0.16.0
【问题讨论】:
如果我交换 s 和 y 参数,求解器会尝试访问浮点数,就好像它是一个列表一样。这导致了上面的错误消息。 但是为什么你通常需要odeint
? odeint
使用 lsoda
求解器,ode
也可用。
抱歉回复晚了。最初我使用的是 odeint,但后来我想添加使用其他求解器的可能性(除了 Lsoda)。此示例中显示的代码只是整个代码的一小部分。我想我是因为不想更改代码而变得懒惰。但我也认为这个问题似乎很相关,因为这两个求解器有不同的变量映射很奇怪。
【参考方案1】:
为什么会发生这种情况,我该如何解决?
这是由于多年前做出的一个不幸的 API 设计决定而发生的。 odeint
和 ode
类需要不同的签名才能解决系统。
您可以通过添加一个包装器来修复它,该包装器会在您使用 ode
类时更改前两个参数的顺序。例如,您可以更改:
r = sc.ode(f).set_integrator(solver)
到
r = sc.ode(lambda t, x, *args: f(x, t, *args)).set_integrator(solver)
更新:在 SciPy 1.1.0 中,tfirst
参数已添加到 scipy.integrate.odeint
。默认值tfirst=False
保持旧的行为。对于tfirst=True
,odeint
需要 first 参数
func
为 t
(即自变量)。通过使用tfirst=True
,相同的func
可以与ode
、odeint
和更新的solver_ivp
一起使用。
【讨论】:
谢谢!这就像一个魅力。这样,我仍然可以使用相同的函数 f,而无需物理更改参数的顺序或创建新函数。以上是关于在不同的 scipy ode 求解器之间进行交换的主要内容,如果未能解决你的问题,请参考以下文章
Python - Scipy:ode 模块:启用求解器的 step 选项的问题