Python 关于Runge-Kutta-Fehlberg算法的问题

Python 关于Runge-Kutta-Fehlberg算法的问题,python,numpy,runge-kutta,Python,Numpy,Runge Kutta,我已经为四阶龙格库塔编写了一个代码,它对微分方程组非常有效: 将numpy导入为np 将matplotlib.pyplot作为plt导入 进口麻木 导入时间 开始时间=time.clock() @numba.jit() def V(u,t): x1,dx1,x2,dx2=u ddx1=-w**2*x1-b*dx1 ddx2=-(w+0.5)**2*x2-(b+0.1)*dx2 返回np.数组([dx1,ddx1,dx2,ddx2]) @numba.jit() def rk4(f、u0、t0、tf

我已经为四阶龙格库塔编写了一个代码,它对微分方程组非常有效:

将numpy导入为np
将matplotlib.pyplot作为plt导入
进口麻木
导入时间
开始时间=time.clock()
@numba.jit()
def V(u,t):
x1,dx1,x2,dx2=u
ddx1=-w**2*x1-b*dx1
ddx2=-(w+0.5)**2*x2-(b+0.1)*dx2
返回np.数组([dx1,ddx1,dx2,ddx2])
@numba.jit()
def rk4(f、u0、t0、tf、n):
t=np.linspace(t0,tf,n+1)
u=np.数组((n+1)*[u0])
h=t[1]-t[0]
对于范围(n)中的i:
k1=h*f(u[i],t[i])
k2=h*f(u[i]+0.5*k1,t[i]+0.5*h)
k3=h*f(u[i]+0.5*k2,t[i]+0.5*h)
k4=h*f(u[i]+k3,t[i]+h)
u[i+1]=u[i]+(k1+2*(k2+k3)+k4)/6
返回u,t
u、 t=rk4(V,np.数组([0,0.2,0,0.3]),010020000)
打印(“执行时间:,time.clock()-开始时间,秒”)
x1,dx1,x2,dx2=u.T
plt.图(x1,x2)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
上述代码返回所需的结果:

多亏了Numba JIT,这段代码运行得非常快。然而,该方法不使用自适应步长,因此不太适合刚性微分方程组。Runge-Kutta-Fehlberg方法通过使用一种直接的算法来解决这个问题。基于算法()我编写了这段代码,它只适用于一个微分方程:

import numpy as np

def rkf( f, a, b, x0, tol, hmax, hmin ):

    a2  =   2.500000000000000e-01  #  1/4
    a3  =   3.750000000000000e-01  #  3/8
    a4  =   9.230769230769231e-01  #  12/13
    a5  =   1.000000000000000e+00  #  1
    a6  =   5.000000000000000e-01  #  1/2

    b21 =   2.500000000000000e-01  #  1/4
    b31 =   9.375000000000000e-02  #  3/32
    b32 =   2.812500000000000e-01  #  9/32
    b41 =   8.793809740555303e-01  #  1932/2197
    b42 =  -3.277196176604461e+00  # -7200/2197
    b43 =   3.320892125625853e+00  #  7296/2197
    b51 =   2.032407407407407e+00  #  439/216
    b52 =  -8.000000000000000e+00  # -8
    b53 =   7.173489278752436e+00  #  3680/513
    b54 =  -2.058966861598441e-01  # -845/4104
    b61 =  -2.962962962962963e-01  # -8/27
    b62 =   2.000000000000000e+00  #  2
    b63 =  -1.381676413255361e+00  # -3544/2565
    b64 =   4.529727095516569e-01  #  1859/4104
    b65 =  -2.750000000000000e-01  # -11/40

    r1  =   2.777777777777778e-03  #  1/360
    r3  =  -2.994152046783626e-02  # -128/4275
    r4  =  -2.919989367357789e-02  # -2197/75240
    r5  =   2.000000000000000e-02  #  1/50
    r6  =   3.636363636363636e-02  #  2/55

    c1  =   1.157407407407407e-01  #  25/216
    c3  =   5.489278752436647e-01  #  1408/2565
    c4  =   5.353313840155945e-01  #  2197/4104
    c5  =  -2.000000000000000e-01  # -1/5

    t = a
    x = np.array(x0)
    h = hmax

    T = np.array( [t] )
    X = np.array( [x] )
    
    while t < b:

        if t + h > b:
            h = b - t

        k1 = h * f( x, t )
        k2 = h * f( x + b21 * k1, t + a2 * h )
        k3 = h * f( x + b31 * k1 + b32 * k2, t + a3 * h )
        k4 = h * f( x + b41 * k1 + b42 * k2 + b43 * k3, t + a4 * h )
        k5 = h * f( x + b51 * k1 + b52 * k2 + b53 * k3 + b54 * k4, t + a5 * h )
        k6 = h * f( x + b61 * k1 + b62 * k2 + b63 * k3 + b64 * k4 + b65 * k5, \
                    t + a6 * h )

        r = abs( r1 * k1 + r3 * k3 + r4 * k4 + r5 * k5 + r6 * k6 ) / h
        if len( np.shape( r ) ) > 0:
            r = max( r )
        if r <= tol:
            t = t + h
            x = x + c1 * k1 + c3 * k3 + c4 * k4 + c5 * k5
            T = np.append( T, t )
            X = np.append( X, [x], 0 )

        h = h * min( max( 0.84 * ( tol / r )**0.25, 0.1 ), 4.0 )

        if h > hmax:
            h = hmax
        elif h < hmin:
            raise RuntimeError("Error: Could not converge to the required tolerance %e with minimum stepsize  %e." % (tol,hmin))
            break

    return ( T, X )
将numpy导入为np
定义rkf(f,a,b,x0,tol,hmax,hmin):
a2=2.500000000000000e-01#1/4
a3=3.75000000000000E-01#3/8
a4=9.230769230769231e-01#12/13
a5=1.000000000000000 E+00#1
a6=5.000000000000000e-01#1/2
b21=2.500000000000000e-01#1/4
b31=9.375000000000000e-02#3/32
b32=2.81250000000000E-01#9/32
b41=8.793809740555303e-01#1932/2197
b42=-3.277196176604461e+00#-7200/2197
b43=3.320892125625853e+00#7296/2197
b51=2.032407407E+00#439/216
b52=-8.000000000000000 E+00#-8
b53=7.173489278752436e+00#3680/513
b54=-2.058966861598441e-01#-845/4104
b61=-2.962962963E-01#-8/27
b62=2.000000000000000 E+00#2
b63=-1.381676413255361e+00#-3544/2565
b64=4.529727095516569e-01#1859/4104
b65=-2.75000000000000E-01#-11/40
r1=2.778E-03#1/360
r3=-2.994152046783626e-02#-128/4275
r4=-2.919989367357789e-02#-2197/75240
r5=2.000000000000000e-02#1/50
r6=3.636E-02#2/55
c1=1.157407E-01#25/216
c3=5.489278752436647e-01#1408/2565
c4=5.353313840155945e-01#2197/4104
c5=-2.000000000000000e-01#-1/5
t=a
x=np.数组(x0)
h=hmax
T=np.数组([T])
X=np.array([X])
而tb:
h=b-t
k1=h*f(x,t)
k2=h*f(x+b21*k1,t+a2*h)
k3=h*f(x+b31*k1+b32*k2,t+a3*h)
k4=h*f(x+b41*k1+b42*k2+b43*k3,t+a4*h)
k5=h*f(x+b51*k1+b52*k2+b53*k3+b54*k4,t+a5*h)
k6=h*f(x+b61*k1+b62*k2+b63*k3+b64*k4+b65*k5\
t+a6*h)
r=abs(r1*k1+r3*k3+r4*k4+r5*k5+r6*k6)/h
如果len(np.shape(r))>0:
r=最大值(r)
如果r hmax:
h=hmax
elif h

但是我正在努力把它转换成像第一个代码那样的函数,在这里我可以输入一个微分方程组。最让我困惑的是,如何在第二段代码中对所有内容进行矢量化而不把事情搞砸。换句话说,我无法使用RKF算法重现第一个结果。有人能给我指出正确的方向吗?

我真的不确定你的问题在哪里。将未给定的参数设置为
w=1;b=0.1
和呼叫,不做任何更改

T, X = rkf( f=V, a=0, b=100, x0=[0,0.2,0,0.3], tol=1e-6, hmax=1e1, hmin=1e-16 )
给出了相位图

步长随着系统速度的降低而增大


这是未过滤步长控制器的预期行为。

如果您在系统中尝试,具体错误是什么?我看不出任何明显的改变会破坏代码。或者在运行时是否存在问题?它适用于简单的线性系统吗?除了一些基本的清理,以使输入等适合,这似乎很好。我建议使用np.linalg.norm计算r.@LutzLehmann它只适用于一个方程,但我认为我的问题是,在每次迭代中,n个方程存在n个步骤,我认为我应该使用这些n个步骤中的最小值来将其应用于所有计算。(想象一个由两个方程组成的系统,其中一个方程的步长比另一个方程的步长小。那么我想我应该对两个方程都使用较小的一个方程)我不知道如何找到最小步长。如果len(np.shape(r))>0:r=max(r),你已经用线
,因为这将步长控制的输入减少到了一个标量。对于系统的组件,将控制器内部分开,并且只在最后取最小值确实是一种有效的策略。当步长变得太大时,也可以将系统分为快速和慢速移动的组件,或者影响和集成他们有不同的时间步长。我在这里找到了我想要的:。谢谢你的帮助@lutzlehmannI真的太深了,我知道我知道代码已经正确了…谢谢。