常微分方程的龙格库塔显式与隐式解法

  • 本文中的常微分方程均为一元常微分方程,原因无他,拓展成多元的需要画更多的时间,属于付费知识
  • 好习惯,讲问题之前先来介绍一下最近生活状况。
    • 得到了 熟人的 熟人认证 很好 很荣幸了 属于是
  • 先上全部代码与效果图
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import fsolve

class odesolver():
    def __init__(self, f, X_start=0, X_end=1, Y_start=1, dY_start=1, h=0.01):
        self.f = f
        self.h = h
        self.X = np.arange(X_start, X_end, self.h)
        self.Y = np.zeros(self.X.size)
        self.Y[0] = Y_start
        self.Y[1] = Y_start + self.h * dY_start
        self.tol = 1e-6
        
    def __str__(self):
        return f"y'(x) = f(x) = ({self.f}) only one variable"

    def RK4(self):
        for i in range(1, self.X.size):
            k1 = self.f(self.X[i-1], self.Y[i-1])
            k2 = self.f(self.X[i-1]+self.h/2, self.Y[i-1]+1/2*self.h*k1)
            k3 = self.f(self.X[i-1]+self.h/2, self.Y[i-1]+1/2*self.h*k2)
            k4 = self.f(self.X[i-1]+self.h, self.Y[i-1]+self.h*k3)
            self.Y[i] = self.Y[i-1] + 1/6 * self.h * (k1 + 2*k2 + 2*k3 + k4)
        return self.Y

    def IRK4(self):
        for i in range(1, self.X.size):
            f1 = lambda k:self.f(self.X[i-1]+self.h*(3-3**0.5)/6, \
                                self.Y[i-1]+k[0]/4*self.h+(3-2*3**0.5)/12*k[1]*self.h) - k[0] 
            f2 = lambda k:self.f(self.X[i-1]+self.h*(3+3**0.5)/6, \
                                self.Y[i-1]+k[1]/4*self.h+(3+2*3**0.5)/12*k[0]*self.h) - k[1]            
            sol = fsolve(lambda k: [f1(k), f2(k)], [0, 0])
            self.Y[i] = self.Y[i-1] + 1/2 * self.h * (sol[0] + sol[1])
        return self.Y

    def IRK6(self):
        for i in range(1, self.X.size):
            f1 = lambda k:self.h * self.f(self.X[i-1]+self.h*(5-15**0.5)/10, \
                                self.Y[i-1]+k[0]*5/36                +(10-3*15**0.5)/45*k[1]  +(25-6*15**0.5)/180*k[2]) - k[0] 
            f2 = lambda k:self.h * self.f(self.X[i-1]+self.h/2, \
                                self.Y[i-1]+k[0]*(10+3*15**0.5)/72   +2/9*k[1]                +(10-3*15**0.5)/12*k[2]) - k[1]            
            f3 = lambda k:self.h * self.f(self.X[i-1]+self.h*(5+15**0.5)/10, \
                                self.Y[i-1]+k[0]*(25+6*15**0.5)/180  +(10+3*15**0.5)/45*k[1]  +5/36*k[2]) - k[2]            
            sol = fsolve(lambda k: [f1(k), f2(k), f3(k)], [0, 0, 0])
            self.Y[i] = self.Y[i-1] + (5/18*sol[0] + 4/9*sol[1] + 5/18*sol[2])
        return self.Y

    def Milne(self):
        for i in range(1, self.X.size):
            k1 = self.h * self.f(self.X[i-1], self.Y[i-1])
            k2 = self.h * self.f(self.X[i-1]+self.h/3, self.Y[i-1]+1/3*k1)
            k3 = self.h * self.f(self.X[i-1]+self.h*2/3, self.Y[i-1]+1/3*k1+k2)
            k4 = self.h * self.f(self.X[i-1]+self.h, self.Y[i-1]+k1-k2+k3)
            self.Y[i] = self.Y[i-1] + 1/8 * (k1 + 8*k2 + 3*k3 + k4)
        return self.Y

    def Kutta(self):
        for i in range(1, self.X.size):
            k1 = self.h * self.f(self.X[i-1], self.Y[i-1])
            k2 = self.h * self.f(self.X[i-1]+self.h/2, self.Y[i-1]+1/2*k1)
            k3 = self.h * self.f(self.X[i-1]+self.h/2, self.Y[i-1]+(2**0.5-1)/2*k1+(1-2**0.5/2)*k2)
            k4 = self.h * self.f(self.X[i-1]+self.h, self.Y[i-1]-2**0.5/2*k2+(1+2**0.5/2)*k3)
            self.Y[i] = self.Y[i-1] + 1/6 * (k1 + (2-2**0.5)*k2 + (2+2**0.5)*k3 + k4)
        return self.Y
    
c = odesolver(f=lambda x,y:x*y)
x = np.arange(0, 1, 0.01)
y1 = c.RK4()
y2 = c.IRK4()
y3 = c.IRK6()
y4 = c.Milne()
y5 = c.Kutta()
f_true = lambda x:np.exp(x**2/2)
y_true = f_true(x)

plt.plot(x, y1, label="RK4")
plt.plot(x, y2, label="IRK4")
plt.plot(x, y3, label="IRK6")
plt.plot(x, y4, label="Milne")
plt.plot(x, y5, label="Kutta")
plt.plot(x, y_true, label="true")
plt.legend()
plt.pause(0.01)
  • 你就说这个代码写得规不规范,整不整齐
  • 效果图

常微分方程的龙格库塔显式与隐式解法_第1张图片

 常微分方程的隐式与显式解法详解

  • 说到这一点,就必须将一个故事
    • 有天 博主在网上逛 但是发现这里竟然没有一篇能完整得给出解微分方程隐式方法的完整代码的博客,于是决定写一篇
  • 什么是显式方法呢,就是每一步的值仅有上一步或前几步有关
  • 什么是隐式方法呢,就是对于每一步必须要求解一个方程以得到该步的近似值
  • 很好,我觉得我解释得极其精确无误了

常用公式

四级四阶显式 Runge - Kutta 方法

\begin{matrix} y_{n+1}=y_n+\frac{1}{6}(k_1+2k_2+2k_3+k_4)\\ k_1=f(x_n,y_n)\\ k_2=f(x_n+\frac{h}{2},y_n+\frac{hk_1}{2})\\ k_3=f(x_n+\frac{h}{2},y_n+\frac{hk_2}{2})\\ k_4=f(x_n+h,y_i+hk_3) \end{matrix}

二级四阶隐式 Runge - Kutta 方法

\begin{matrix} y_{n+1}=y_n+\frac{1}{2}(k_1+k_2)\\ k_1 = f(x_n+\frac{3-\sqrt{3}}{6}h,y_i+\frac{k_1h}{4}+\frac{3-2\sqrt{3}}{12}k_2h)\\ k_2 = f(x_n+\frac{3+\sqrt{3}}{6}h,y_i+\frac{k_2h}{4}+\frac{3+2\sqrt{3}}{12}k_1h) \end{matrix}

三级六阶隐式 Runge - Kutta 方法

\begin{matrix} y_{n+1}=y_n+\frac{5}{18}k_1+\frac{4}{9}k_2+\frac{5}{18}k_3\\ k_1=hf(x_n+\frac{5-\sqrt{15}}{10}h,y_n+\frac{5}{36}k_1+\frac{10-3\sqrt{15}}{45}k_2+\frac{25-6\sqrt{15}}{180}k_3)\\ k_2=hf(x_n+\frac{h}{2},y_n+\frac{10+3\sqrt{15}}{72}k_1+\frac{2}{9}k_2+\frac{10-3\sqrt{15}}{12}k_3)\\ k_3=hf(x_n+\frac{5+\sqrt{15}}{10}h,y_n+\frac{25+6\sqrt{15}}{180}k_1+\frac{10+3\sqrt{15}}{45}k_2+\frac{5}{36}k_3) \end{matrix}

四级四阶 Kutta 方法

\left\{\begin{matrix} y_{n+1}=y_n + \frac{1}{8}(k_1+8k_2+3k_3+k_4)\\ k_1=hf(x_n,y_n)\\ k_2=hf(x_n+\frac{h}{3},y_n+\frac{k_1}{3})\\ k_3=hf(x_n+\frac{2h}{3},y_n+\frac{k_1}{3}+k_2)\\ k_4=hf(x_n+h,y_n+k_1-k_2+k_3) \end{matrix}\right.

四级四阶 Milne 方法

\left\{\begin{matrix} y_{n+1}=y_n + \frac{1}{6}(k_1+(2-\sqrt{2})k_2+(2+\sqrt{2})k_3+k_4)\\ k_1=hf(x_n,y_n)\\ k_2=hf(x_n+\frac{h}{2},y_n+\frac{k_1}{2})\\ k_3=hf(x_n+\frac{h}{2},y_n+\frac{\sqrt{2}-1}{2}k_1+(1-\frac{\sqrt{2}}{2})k_2)\\ k_4=hf(x_n+h,y_n-\frac{\sqrt{2}}{2}k_2+(1+\frac{\sqrt{2}}{2})k_3) \end{matrix}\right.

求根方法

  • 这个我以后再讲,前面陆陆续续讲过几次,在特征值里面,请大家自行翻阅

你可能感兴趣的:(#,科学计算原理,算法,数学建模,抽象代数,numpy,python)