我显然已经阅读了documentation,但我无法找到更详细的描述正在发生的事情。具体来说,有一些我非常困惑的行为:
import numpy as np
from scipy.integrate import ode
#Constants in ODE
N = 30
K = 0.5
w = np.random.normal(np.pi, 0.1, N)
#Integration parameters
y0 = np.linspace(0, 2*np.pi, N, endpoint=False)
t0 = 0
#Set up the solver
solver = ode(lambda t,y: w + K/N*np.sum( np.sin( y - y.reshape(N,1) ), axis=1))
solver.set_integrator('vode', method='bdf')
solver.set_initial_value(y0, t0)
solver.integrate(t0)
失败设置积分器,并在第一次询问t0
时的值会返回成功的积分。重复此操作将返回正确的数字,但solver.successful()
方法返回false:
solver.integrate(t0)
>>> array([ 0. , 0.20943951, 0.41887902, ..., 5.65486678,
5.86430629, 6.0737458 ])
solver.successful()
>>> True
solver.integrate(t0)
>>> array([ 0. , 0.20943951, 0.41887902, ..., 5.65486678,
5.86430629, 6.0737458 ])
solver.successful()
>>> False
我的问题是,solver.integrate(t)
方法中发生了什么导致它第一次成功,然后失败,以及“不成功”整合意味着什么?此外,为什么集成商会无声地失败,并继续产生有用的输出,直到我明确询问它是否成功?
相关,有没有办法重置失败的集成,还是需要从头开始重新实例化解算器?
t
即使y0
的初始值为t0=0
,我也可以t=10000
请求值并立即得到答案。我希望在如此大的时间跨度上进行数值积分至少需要几秒钟(例如在Matlab中,要求整合超过10000个时间步骤需要几分钟)。
例如,从上面重新运行设置并执行:
solver.integrate(10000)
>>> array([ 2153.90803383, 2153.63023706, 2153.60964064, ..., 2160.00982959,
2159.90446056, 2159.82900895])
Python真的那么快,还是这个输出完全是废话?
答案 0 :(得分:4)
不要忽略错误消息。是的,ode
的错误消息有时会很神秘,但您仍然希望避免它们。
由于您在t0
的第一次通话时已经整合到solver.integrate(t0)
,因此您正在与第二次通话合并0
的时间步长。这引发了一个神秘的错误:
DVODE-- ISTATE (=I1) .gt. 1 but DVODE not initialized
In above message, I1 = 2
/usr/lib/python3/dist-packages/scipy/integrate/_ode.py:869: UserWarning: vode: Illegal input detected. (See printed message.)
'Unexpected istate=%s' % istate))
在一次调用中,解算器将采用最大数量的(内部)步骤而不会抛出错误。可以使用nsteps
set_integrator
参数进行设置。如果您一次集成大量时间,即使没有任何错误,也会超出nsteps
,并抛出以下错误消息:
/usr/lib/python3/dist-packages/scipy/integrate/_ode.py:869: UserWarning: vode: Excess work done on this call. (Perhaps wrong MF.)
'Unexpected istate=%s' % istate))
然后,只要发生这种情况,积分器就会停止。
如果设置nsteps=10**10
,则集成运行没有问题。它仍然很快(在我的机器上大约1s)。原因如下:
对于像你这样的多维系统,集成时有两个主要的运行时接收器:
积分器内的矢量和矩阵运算。在scipy.ode
中,这些都是通过NumPy操作或移植Fortran或C代码实现的。无论如何,它们是通过编译代码实现的,没有Python开销,因此非常有效。
评估衍生产品(在您的案例中为lambda t,y: w + K/N*np.sum( np.sin( y - y.reshape(N,1) ), axis=1)
)。您通过NumPy操作实现了这一点,这些操作再次通过编译代码实现并且非常高效。您可以使用纯编译函数稍微改进一下,但这最多只会给您一个小因素。如果您使用Python列表和循环,那将非常慢。
因此,对于您的问题,所有相关内容都由编译后的代码处理,并且集成的处理效率与例如纯C程序的效率相当。我不知道在Matlab中如何处理上述两个方面,但如果使用解释而不是编译循环处理上述任何一个挑战,这将解释您观察到的运行时差异。
答案 1 :(得分:1)
对于第二个问题,是的,输出可能是无意义的。局部误差,无论是来自离散化还是浮点运算,都会以复合因子累积,该复合因子约为ODE函数的Lipschitz常数。在第一次估计中,这里的Lipschitz常数是K=0.5
。因此,早期误差的放大率,即它们作为全局误差的一部分的系数,可以与exp(0.5*10000)
一样大,这是一个巨大的数字。
另一方面,整合速度快也就不足为奇了。大多数提供的方法使用步长调整,并且对于标准误差容差,这可能仅导致几十个内部步骤。减小误差容差会增加内部步骤的数量,并可能会大幅改变数值结果。