Python 了解自适应Runge-Kutta积分器的局部截断误差

Python 了解自适应Runge-Kutta积分器的局部截断误差,python,physics,numerical-methods,numerical-integration,runge-kutta,Python,Physics,Numerical Methods,Numerical Integration,Runge Kutta,我正在实现一个RKF4(5)积分器,我不知道我的代码是否正常工作,我不理解局部截断错误,或者我的代码是否正常工作 对于代码块的大小,我深表歉意,但在本例中,最小可再现示例相当大 将numpy导入为np def RKF45(状态,导数函数,h): """ 使用四阶计算和五阶误差计算下一个状态 检查 投入: 状态:函数的当前值,float 导数函数:具有状态的函数(以浮点形式给出) 并返回函数在该点的导数 h:步长,浮动 """ k1=h*导数函数(状态) k2=h*导数函数(状态+(k1/4))

我正在实现一个RKF4(5)积分器,我不知道我的代码是否正常工作,我不理解局部截断错误,或者我的代码是否正常工作

对于代码块的大小,我深表歉意,但在本例中,最小可再现示例相当大

将numpy导入为np
def RKF45(状态,导数函数,h):
"""
使用四阶计算和五阶误差计算下一个状态
检查
投入:
状态:函数的当前值,float
导数函数:具有状态的函数(以浮点形式给出)
并返回函数在该点的导数
h:步长,浮动
"""
k1=h*导数函数(状态)
k2=h*导数函数(状态+(k1/4))
k3=h*导数函数(状态+(k1*(3/32))+(k2*(9/32)))
k4=h*导数函数(状态+(k1*(1932/2197))+(k2*(-7200/2197))+(k3*(7296/2197)))
k5=h*导数函数(状态+(k1*(439/216))+(k2*(-8))+(k3*(3680/513))+(k4*(-845/4104)))
k6=h*导数函数(状态+(k1*(-8/27))+(k2*(2))+(k3*(-3544/2565))+(k4*(1859/4104))+(k5*(-11/40)))
y1=状态+((25/216)*k1)+((1408/2565)*k3)+((2197/4101)*k4)-(1/5)*k5)
y2=状态+((16/135)*k1)+((6656/12825)*k3)+((28561/56430)*k4)-(9/50)*k5)+((2/55)*k6)
返回(y1,y2)
def integrate_RKF45(t0,tmax,tol,h_init,x_0,df,verbose=False):
"""
积分导数为df从t0到tmax的函数
t0:开始时间
tmax:结束时间
h_init:初始时间步
x_0:起始位置
df:取x并返回函数在x处的导数的函数
"""
h=h_init
x_i=x_0
t=t0
当ttol:
h*=δ
返回(x_i)
def指数(x_0,k=1):
"""
一个简单的测试函数,它返回输入,因此它将集成到e^x。
"""
返回(k*x_0)
如果名称=“\uuuuu main\uuuuuuuu”:
积分RKF45(t0=0)。,
tmax=0.15,
tol=1e-4,
h_init=1e-2,
x_0=1。,
df=指数,
详细=正确)
所以,这段代码的工作范围是,它返回我给它的任何函数的积分的近似值。然而,局部截断误差似乎太大了。运行上述代码将输出:

t: 0.00e+00, dt: 1.00e-02, x: 1.00e+00, err: 3.95e-06
t: 1.00e-02, dt: 1.00e-02, x: 1.01e+00, err: 3.99e-06
t: 2.00e-02, dt: 1.00e-02, x: 1.02e+00, err: 4.03e-06
t: 3.00e-02, dt: 1.00e-02, x: 1.03e+00, err: 4.07e-06
t: 4.00e-02, dt: 1.00e-02, x: 1.04e+00, err: 4.11e-06
t: 5.00e-02, dt: 1.00e-02, x: 1.05e+00, err: 4.16e-06
t: 6.00e-02, dt: 1.00e-02, x: 1.06e+00, err: 4.20e-06
t: 7.00e-02, dt: 1.00e-02, x: 1.07e+00, err: 4.24e-06
t: 8.00e-02, dt: 1.00e-02, x: 1.08e+00, err: 4.28e-06
t: 9.00e-02, dt: 1.00e-02, x: 1.09e+00, err: 4.32e-06
t: 1.00e-01, dt: 1.00e-02, x: 1.11e+00, err: 4.37e-06
t: 1.10e-01, dt: 1.00e-02, x: 1.12e+00, err: 4.41e-06
t: 1.20e-01, dt: 1.00e-02, x: 1.13e+00, err: 4.46e-06
t: 1.30e-01, dt: 1.00e-02, x: 1.14e+00, err: 4.50e-06
t: 1.40e-01, dt: 1.00e-02, x: 1.15e+00, err: 4.55e-06
其中,
err
值是四阶和五阶方法之间的差值。我的印象是,
n^th
-顺序方法的局部截断误差为顺序
O(dt^(n+1))
,这意味着上述积分应具有大约
1e-9
的误差,而不是
1e-6

那么,是我的代码错了还是我的理解错了? 谢谢

请参见,您似乎对方法系数使用了相同的损坏源

y1中的分母4101错误,必须是4104。

增量因子应该稍微缓和一点,
delta=(tol/R)**(1/5)
delta=(tol/R)**(1/6)
,并应用于每个步骤,也应用于成功的步骤

本地错误的参考误差
err_i
tol*h
,这就是为什么在
R
中你要除以
h

然后,这将导致测试场景的无辐射迭代步骤

t:0.000000e+00,dt:1.00e-02,x:1.000000e+00,err:1.28e-13
t:1.000000e-02,dt:1.40e-01,x:1.010050e+00,误差:6.60e-08
t:1.500000e-01,dt:3.88e-01,x:1.161834e+00
或者在稍长的时间间隔内查看步长控制器的实际工作情况

t:0.000000e+00,dt:1.00e-02,x:1.000000e+00,err:1.28e-13
t:1.000000e-02,dt:2.27e-01,x:1.010050e+00,误差:7.18e-07
t:2.372490e-01,dt:4.31e-01,x:1.267757e+00,误差:2.02e-05
t:6.680839e-01,dt:4.76e-01,x:1.950509e+00,误差:5.03e-05
t:6.680839e-01,dt:4.47e-01,x:1.950509e+00,误差:3.73e-05
t:1.115525e+00,dt:3.84e-01,x:3.051213e+00,误差:2.81e-05
t:1.500000e+00,dt:3.89e-01,x:4.481769e+00
​ 所有提到的修正给出了RKF45中的新循环

而t
非常感谢!我很感激。是的,很难找到RK方法的权威来源。我发现在“错误”的确切含义以及计算下一步尺寸时应将什么值与公差进行比较,甚至delta的值都有很多分歧。实际上,@lutz lehmann,你知道RK方法的一个很好的参考吗?Haier等人关于“解算ODE”的书包含有关验证步长控制的顺序和功能的方法和测试的良好信息。最近有一些关于“基于过滤器”的方法的文献,这些方法在某种移动平均中考虑了“delta”值的历史,如中提出的。我还没有找到一个可以复制这些结果、不良行为和改进的测试场景,但它表明这是一个利基的东西