量化 scipy ode / ODEPACK 的积分误差

计算科学 误差估计 scipy
2021-11-25 05:58:54

我正在尝试使用包装在 scipy.integrate.ode() 中的 lsoda 求解器将二阶 ODE 与潜在的几个奇点集成。我想在解决方案上放置一个错误栏,或者至少估计错误的上限。

了解如何计算简单有限差分方法的截断误差。但是从scipy 文档来看, LSODA 似乎更复杂,求解器使用自适应步长并自动在刚性和非刚性方法之间切换。

存在设置绝对容差、相对容差和最大步长的选项,但我不明白它们与本文档中我的解决方案中的错误有何关系。

在少数情况下,解析解是可能的。例如,我在上一个问题中调试的案例。

该方程是来自等离子体物理领域的纽康的欧拉-拉格朗日方程。

ddr(fdξdr)gξ=0
或作为一组一阶 ODE:
y0=ξ
y1=fξ
y0=y1f
y1=y0g

fg是磁场和压力梯度的复杂表达式。对于更复杂的情况,我使用 scipy.interpolate.InterpolateUnivariateSpline() 生成的样条曲线来描述磁场和压力梯度。 fg可以快速变化并且f可以在几个位置为零,从而导致奇点。我使用 Frobenius 展开来找到接近奇点的解。

这是一个简单案例的简短示例代码fg, 只有一个奇点在r=0.

import numpy as np
from scipy.integrate import ode

# Setup ODE system
def f(r):
   return r

def g(r):
    return -1 + r + 1./r

def der(r, y):
    y_der = np.zeros(2)
    y_der[0] = y[1]/f(r)
    y_der[1] = g(r)*y[0]
    return y_der

#Integrate
integrator = ode(der)
integrator.set_integrator('lsoda') 
r_init = 1E-3
init = [r_init, 1.]
integrator.set_initial_value(init, t=r_init)
r = np.linspace(r_init, 1., 100)
results = np.zeros((2, r.size))
results[:,0] = init
for i, position in enumerate(r[1:]):
    integrator.integrate(position)
    results[:, i+1] = integrator.y
1个回答

如果我没记错的话,你有一些选择:

  • 您可以使用通过区间算术计算严格界限的积分器。例如,泰勒模型就是这样一种方法,你可以看看Berz 和 Makino的工作。您将需要使用不同的积分器,并且可能会大幅更改您的代码以启用区间算术数据类型(和操作)。

  • 您可以使用后验方法来估计误差,其中有几种。这份 Emil Constantinescu 的预印本对文献进行了全面回顾。其中一种方法(Robert Skeel 在 Emil 的论文中引用了 13 种方法,因此还有其他方法)是推导出一个近似误差的缺陷方程,并及时整合它,因此您必须至少求解两次 ODE。

  • 根据全局误差估计,您实际上可以尝试控制集成中的全局误差。Cao 和 Petzold使用 DASPK 描述了这种方法。为了使用此方法,您需要使用能够进行伴随灵敏度分析的求解器。Cao 和 Petzold 使用 DASPK,但您也可以使用 CVODES。这是 DavidKetcheson 所说的方法的一个例子。