Math 如何实现自适应步长Runge-Kutta Cash-Karp?

Math 如何实现自适应步长Runge-Kutta Cash-Karp?,math,mathematical-optimization,numerical-methods,ode,runge-kutta,Math,Mathematical Optimization,Numerical Methods,Ode,Runge Kutta,尝试实施自适应步长Runge Kutta Cash Karp,但失败,出现以下错误: home/anaconda/lib/python3.6/site-packages/ipykernel_launcher.py:15: RuntimeWarning: divide by zero encountered in double_scalars from ipykernel import kernelapp as app 我试图解决的ODE(在下面的示例中使用,从高阶转换为一阶ODE系统)如下所示

尝试实施自适应步长Runge Kutta Cash Karp,但失败,出现以下错误:

home/anaconda/lib/python3.6/site-packages/ipykernel_launcher.py:15: RuntimeWarning: divide by zero encountered in double_scalars from ipykernel import kernelapp as app
我试图解决的ODE(在下面的示例中使用,从高阶转换为一阶ODE系统)如下所示:

以下是我正在使用的实现:

def rkck(f, x, y, h, tol):
    #xn = x + h
    err = 2 * tol
    while (err > tol):
        xn = x + h
        k1 = h*f(x,y)
        k2 = h*f(x+(1/5)*h,y+((1/5)*k1)) 
        k3 = h*f(x+(3/10)*h,y+((3/40)*k1)+((9/40)*k2))
        k4 = h*f(x+(3/5)*h,y+((3/10)*k1)-((9/10)*k2)+((6/5)*k3))
        k5 = h*f(x+(1/1)*h,y-((11/54)*k1)+((5/2)*k2)-((70/27)*k3)+((35/27)*k4))
        k6 = h*f(x+(7/8)*h,y+((1631/55296)*k1)+((175/512)*k2)+((575/13824)*k3)+((44275/110592)*k4)+((253/4096)*k5))
        yn4 = y + ((37/378)*k1)+((250/621)*k3)+((125/594)*k4)+((512/1771)*k6)
        yn5 = y + ((2825/27648)*k1)+((18575/48384)*k3)+((13525/55296)*k4)+((277/14336)*k5)+((1/4)*k6)
        err = yn4[-1]-yn5[-1]
        if (err != 0):
            h = 0.8 * h * (tol/err)**(1/float(5))
        yn = yn4
    return xn, yn

def integrate_sStepControl(f, t0, y0, tend, h, tol):
    T = [t0]
    Y = [y0]
    t = t0
    y = y0 
    while (t < tend):
        h = min(h, tend-t)
        t, y = rkck(f, t, y, h, tol)
        T.append(t)
        Y.append(y)
    return np.array(T), np.array(Y)

def f_1(t,y): 
    return np.array([ y[1], -y[0]-(y[0])**3 ])

Y0_f1 = np.array([1.0,1.0])


# Execution
h = 0.05
tv, yv = integrate_sStepControl(f=f_1, t0=0.0, y0=Y0_f1, tend=100.0, h=h, tol=1.0E-05)
print("[ %20.15f, %20.15f]"%(yv[-1,0], yv[-1,1]) )
plt.plot(tv, yv)
def-rkck(f,x,y,h,tol):
#xn=x+h
误差=2*tol
而(err>tol):
xn=x+h
k1=h*f(x,y)
k2=h*f(x+(1/5)*h,y+((1/5)*k1))
k3=h*f(x+(3/10)*h,y+((3/40)*k1)+((9/40)*k2))
k4=h*f(x+(3/5)*h,y+((3/10)*k1)-(9/10)*k2)+((6/5)*k3))
k5=h*f(x+(1/1)*h,y-((11/54)*k1)+((5/2)*k2)-(70/27)*k3)+((35/27)*k4))
k6=h*f(x+(7/8)*h,y+((1631/55296)*k1)+((175/512)*k2)+((575/13824)*k3)+((44275/110592)*k4)+((253/4096)*k5))
yn4=y+((37/378)*k1)+((250/621)*k3)+((125/594)*k4)+((512/1771)*k6)
yn5=y+((2825/27648)*k1)+((18575/48384)*k3)+((13525/55296)*k4)+((277/14336)*k5)+((1/4)*k6)
err=yn4[-1]-yn5[-1]
如果(错误!=0):
h=0.8*h*(tol/err)**(1/float(5))
yn=yn4
返回xn,yn
def集成步骤控制(f、t0、y0、tend、h、tol):
T=[t0]
Y=[y0]
t=t0
y=y0
而(t
获取上面的错误,但它会被绘制出来。不知道我做错了什么:-/

编辑:
添加了err==0的检查,您需要实际传回计算出的新步长
h
,以便在第一步的主循环中使用它

误差应按标准计算。添加一些小数字以避免被零除

对于四阶方法,前导误差项是
C*h^5
。这必须与所需的本地错误进行比较。总的来说,这将导致计算最佳
h
的第四个根。取第五根可以提供某种阻尼,但是对全局误差的影响不是很直接

def-rkck(f,x,y,h,tol):
#xn=x+h
误差=2*tol
而(err>tol):
xn=x+h
k1=h*f(x,y)
k2=h*f(x+(1/5)*h,y+((1/5)*k1))
k3=h*f(x+(3/10)*h,y+((3/40)*k1)+((9/40)*k2))
k4=h*f(x+(3/5)*h,y+((3/10)*k1)-(9/10)*k2)+((6/5)*k3))
k5=h*f(x+(1/1)*h,y-((11/54)*k1)+((5/2)*k2)-(70/27)*k3)+((35/27)*k4))
k6=h*f(x+(7/8)*h,y+((1631/55296)*k1)+((175/512)*k2)+((575/13824)*k3)+((44275/110592)*k4)+((253/4096)*k5))
dy4=((37/378)*k1)+((250/621)*k3)+((125/594)*k4)+((512/1771)*k6)
dy5=((2825/27648)*k1)+((18575/48384)*k3)+((13525/55296)*k4)+((277/14336)*k5)+((1/4)*k6)
err=1e-2*tol+max(abs(dy4-dy5))
#h=0.95*h*(tol/err)**(1/5)
h=0.8*h*(tol*h/err)**(1/4)
yn=y+dy4
返回xn,yn,h
def集成步骤控制(f、t0、y0、tend、h、tol):
T=[t0]
Y=[y0]
t=t0
y=y0
而(t
因此,您的示例给出了解决方案、时间步长和错误/错误的下图


完成!非常感谢。您可以在尝试除以之前检查
err==0
。好的。但除此之外,您对实施有何看法?是否正确?如果err==0,则不需要计算
h
,因为while循环将退出,不再需要
h
。至于实现,我不知道,但一个好的开始是对照已知结果检查结果。您没有将
h
的计算值传递回主循环,因此此计算被丢弃。您还需要避免使用负值
err
,您可以通过设置
err=1e-40+norm(y4-y5)
/请注明问题的交叉张贴,以避免重复答案。非常感谢您的回答!非常详细,再好不过了!你真的帮助我理解了我的错误!我不知道该如何感谢你为科学界所做的一切!