许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  隐式三阶Adams方法与四阶Runge-Kutta求解常微分方程的Python实现(含结果与代码)

隐式三阶Adams方法与四阶Runge-Kutta求解常微分方程的Python实现(含结果与代码)

阅读数 3
点赞 0
article_banner

隐式三阶Adams方法与四阶 龙格库塔 求解常微分方程Python实现(含结果与 代码

原理

龙格库塔方法原理

   隐式Adams原理:
在这里插入图片描述

四阶龙格库塔方法

# Code   : UTF-8
# Author : CSDNwoShiXiaoYaoGuai_zhz
# Date   : 2023/11/20
# Project: 4阶Runge-Kutta方法解常微分方程通用程序

def rungeKutta4oneStep(h:float, x0:float, y0:float, f)->float:
    '''
        四阶龙格库塔方法单步
        ------------------------------------------------------------------------
        h   Input   积分步长
        x0  Input   自变量
        y0  Input   x0处对应的因变量
        f   Input   常微分方程
        ------------------------------------------------------------------------
        Return: x0+h处对应的因变量
    '''
    k1 = h * f(x0, y0) * 1.0
    k2 = h * f(x0 + 0.5 * h, y0 + 0.5 * k1) * 1.0
    k3 = h * f(x0 + 0.5 * h, y0 + 0.5 * k2) * 1.0
    k4 = h * f(x0 + h, y0 + k3) * 1.0
    return y0 + (k1 + 2 * k2 + 2 * k3 + k4) / 6.0

def rungeKutta4(h:float, x0:float, y0:float, x:float, f)->list:
    '''
        四阶龙格库塔方法
        ------------------------------------------------------------------------
        h   Input   积分步长
        x0  Input   初始自变量
        y0  Input   x0处对应的因变量 (初始条件)
        x   Input   待求解处相应的自变量
        f   Input   常微分方程
        ------------------------------------------------------------------------
        Return: [[x0, x1, ..., xn], [y0, y1, ..., yn]]
    '''
    steps = int(((x - x0) / h) + 0.5)
    xs = []
    ys = []
    for i in range(0, steps + 1):
        xi = x0 + i * h
        if i == 0:
            yi = y0
        else:
            yi = yi1
        yi1 = rungeKutta4oneStep(h, xi, yi, f)
        xs.append(xi)
        ys.append(yi)
    return [xs, ys]

隐式三阶Adams方法

# Code   : UTF-8
# Author : CSDNwoShiXiaoYaoGuai_zhz
# Date   : 2023/11/20
# Project: Adams隐式3阶方法解常微分方程通用程序

import rungeKutta as rk

def adams3Explicit(h:float, y0s:list, fs:list)->float:
    '''
        显式三阶Adams方法
        ------------------------------------------------------------------------
        h   Input   积分步长
        y0s Input   [y_n, y_(n+1)]
        fs  Input   [f(x_n, y_n), f(x_(n+1), y_(n+1))]
        ------------------------------------------------------------------------
        Return: y_(n+2)
    '''
    return y0s[-1] + h * (3 * fs[-1] - fs[-2]) / 2.0

def adams3oneStep(h:float, x0s:list, y0s:list, f)->float:
    '''
        隐式三阶Adams方法单步
        ------------------------------------------------------------------------
        h   Input   积分步长
        x0s Input   [x_n, x_(n+1)]
        y0s Input   [y_n, y_(n+1)]
        f   Input   常微分方程
        ------------------------------------------------------------------------
        Return: y_(n+2)
    '''
    fs = []
    for i in range(len(x0s)):
        fs.append(f(x0s[i], y0s[i]))
    y0 = rk.rungeKutta4oneStep(h, x0s[-1], y0s[-1], f) # 龙格库塔方法提供初值
    # y0 = adams3Explicit(h, y0s, fs) # Adams显式3阶方法提供初值
    # y0 = 10 # 任意常数提供初值
    
    # 开始迭代
    iter = 0
    changeFactor = 100
    while ((iter < 100) and (changeFactor > 1e-12)):
        fn2 = f(x0s[-1] + h, y0)
        yk = y0s[-1] + h * (5 * fn2 + 8 * fs[-1] - fs[-2]) / 12.0
        changeFactor = abs((yk - y0))
        # changeFactor = abs((yk - y0) / y0)
        iter = iter + 1
        y0 = yk
    return y0

def adams3(h, x0, y0, x, f)->list:
    '''
        隐式三阶Adams方法
        ------------------------------------------------------------------------
        h   Input   积分步长
        x0  Input   初始自变量
        y0  Input   x0处对应的因变量 (初始条件)
        x   Input   待求解处相应的自变量
        f   Input   常微分方程
        ------------------------------------------------------------------------
        Return: [[x0, x1, ..., xn], [y0, y1, ..., yn]]
    '''
    [xs, ys] = rk.rungeKutta4(h, x0, y0, x0 + h, f)
    steps = int(((x - x0) / h) + 0.5)

    for i in range(0, steps - 1):
        y = adams3oneStep(h, xs[-2:], ys[-2:], f)
        xs.append(xs[-1] + h)
        ys.append(y)
    return [xs, ys]

结果绘制

# Code   : UTF-8
# Author : CSDNwoShiXiaoYaoGuai_zhz
# Date   : 2023/11/20
# Project: 结果绘制

import matplotlib.pyplot as plt

def drawResult1(h, rkX, rkY, adamsX, adamsY, diffRk, diffAdams):
    fig = plt.figure(dpi = 200)
    ax1 = plt.subplot(221)
    ax1.plot(rkX, rkY, 'o', label='RK4')
    ax2 = plt.subplot(222)
    ax2.plot(adamsX, adamsY, '+', label='AD3', color = 'orange')
    ax3 = plt.subplot(223)
    ax3.plot(diffRk[0], diffRk[1], 'o', label='biaRK4')
    ax4 = plt.subplot(224)
    ax4.plot(diffAdams[0], diffAdams[1], '+', label='biaAD3', color = 'orange')

    for ax in [ax1, ax2, ax3, ax4]:
        ax.set_xlim(-0.1, 1.6)
        ax.legend(ncol=1)
        ax.grid()
        ax.set_title('Step length: ' + str(h))
        ax.set_xlabel('x')
        ax.set_ylabel('y')
    plt.tight_layout()
    plt.savefig('StepLength' + str(h) + '.jpg')

def drawResult2(lnhs, lnRkErrors, lnAdErrors, kRk, kAd):
    fig, ax = plt.subplots()
    ax.plot(lnhs, lnRkErrors, 'o--', label = 'RK, k=' + str(kRk))
    ax.plot(lnhs, lnAdErrors, 's--', label = 'Adams, k=' + str(kAd))
    ax.legend()
    ax.set_xlabel('ln(h)')
    ax.set_ylabel('ln(error)')
    plt.grid()
    plt.tight_layout()
    plt.savefig('RelationLnhAndLnerror.jpg', dpi = 250)

程序

# Code   : UTF-8
# Author : CSDNwoShiXiaoYaoGuai_zhz
# Date   : 2023/11/20
# Project: 主程序

import rungeKutta as rk
import adams as ad
import drawChart as dc
import math
import numpy as np

def calDiff(xs:list, ys:list, fExact)->list:
    '''
        计算数值解相对于精确解的差
        ------------------------------------------------------------------------
        xs      Input   自变量序列
        ys      Input   自变量对应的因变量数值解序列
        fExact  Input   因变量关于自变量的精确解函数
        ------------------------------------------------------------------------
        Return: [[x0, x1, ..., xn], [diff0, diff1, ..., diffn]]
    '''
    diffs = []
    for i in range(len(xs)):
        diff = ys[i] - fExact(xs[i])
        diffs.append(diff)
    return [xs, diffs]

def differentialEquation(x, y):
    ''' 用户自定义的常微分方程 '''
    return (-1) * (x ** 2) * (y ** 2)

def solExact(x):
    ''' 用户自定义的常微分方程精确解 '''
    return 3.0 / (1 + x ** 3)

def lsq(x, l):
    b = []
    for i in range(len(x)):
        b.append([x[i], 1])
    b = np.mat(b)
    
    l = np.mat(l).T
    x = np.linalg.inv(b.T * b) * b.T * l
    return np.array(x)[0][0]


if __name__ == '__main__':
    hs = []
    rkErrors = []
    adErrors = []

    with open('Result.txt', 'w', encoding='utf-8') as f:
        f.write('步长\t4阶RK数值解\t\tRK数值解与精确解差值\t\t' + 
        '隐式3阶Adams数值解\t隐式3阶Adams数值解与精确解差值\n')
    print('步长\t4阶RK数值解\t\tRK数值解与精确解差值\t\t' + 
        '隐式3阶Adams数值解\t隐式3阶Adams数值解与精确解差值')
    for h in [0.1, 0.1 / 2, 0.1 / 4, 0.1 / 8]:
        # RK方法
        [rkX,rkY] = rk.rungeKutta4(h, 0, 3, 1.5, differentialEquation)
        # Adams方法
        [adamsX,adamsY] = ad.adams3(h, 0, 3, 1.5, differentialEquation)

        # RK数值解与精确解的差值
        diffRk = calDiff(rkX, rkY, solExact)
        # Adams数值解与精确解的差值
        diffAdams = calDiff(adamsX, adamsY, solExact)

        hs.append(math.log(h, math.e)) # ln(h)
        rkErrors.append(math.log(abs(diffRk[1][-1]), math.e)) # ln(err) by RK
        adErrors.append(math.log(abs(diffAdams[1][-1]), math.e)) # ln(err) by AD
        
        # 结果输出
        print(str(h) + '\t' + str(rkY[-1]) + '\t' + str(diffRk[1][-1]) + '\t\t'
            + str(adamsY[-1]) + '\t' + str(diffAdams[1][-1]))
        with open('Result.txt', 'a') as f:
            f.write(str(h) + '\t' + str(rkY[-1]) + '\t' + str(diffRk[1][-1]) 
            + '\t\t' + str(adamsY[-1]) + '\t' + str(diffAdams[1][-1]) + '\n')

        # 结果1绘制
        dc.drawResult1(h, rkX, rkY, adamsX, adamsY, diffRk, diffAdams)

    # 计算回归系数
    kRk = lsq(hs, rkErrors)
    kAd = lsq(hs, adErrors)
    
    # 结果2绘制
    dc.drawResult2(hs, rkErrors, adErrors, kRk, kAd)

计算结果

不同步长时结果
在这里插入图片描述

步长为0.1时两种方法的结果(上图)以及 数值解 与精确解的差值(下图)

两种方法的数值解与精确解的差值的ln值与步长ln值关系
在这里插入图片描述


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

相关文章
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空