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

时间:2019-04-25 08:04:01

标签: 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转换为一阶ODE):

2nd order ODE to be transformed in system of two 1st order ODEs

这是我正在使用的实现:

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)

获取上面的错误,但将其绘制出来。在这里不知道我在做什么错:-/ plot

编辑: 添加了对err == 0的检查

1 个答案:

答案 0 :(得分:2)

您实际上需要传回计算出的新步长C*h^5,以便将其用于第一步的主循环中。

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

四阶方法的前导误差项为tol*h。必须将此与所需的本地错误h进行比较。总共得出第4个根,以计算最佳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)) 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*h/err)**(1/5) h = 0.8 * h * (tol*h/err)**(1/4) yn = y+y4 return xn, yn, h 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, h = rkck(f, t, y, h, tol) T.append(t) Y.append(y) return np.array(T), np.array(Y) 。取第五根为基础提供了某种程度的衰减,但是对全局误差的影响不是很直接。

margin

在此示例中,给出了以下解决方案,时间步长和误差/误差的图

enter image description here