基于Python编写求解抛物型pde方程的经典数值格式模拟

2023-10-19 13:59

本文主要是介绍基于Python编写求解抛物型pde方程的经典数值格式模拟,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于Python编写求解抛物型pde方程的经典数值格式模拟

    • 前言
    • 一:一维热传导方程简介
    • 二:差分格式
    • 三:代码实现
    • 四:数值结果
    • 五:总结

前言

热方程的在很多领域都有所应用,熟知的在金融领域求解期权定价公式之Black-Scholes方程,就可以用数值格式求解此类方程,因为很多复杂的期权定价公式很难有显式解,数值方法在这方面就有很多优越性。本文将基于Python编写常见的三种数值格式来求解传统的初-边值一维热方程问题。

岁月如云,匪我思存,写作不易,望路过的朋友们点赞收藏加关注哈,在此表示感谢!

一:一维热传导方程简介

一维热传导方程如下:
ϑ u ϑ t = a ϑ 2 u ϑ x 2 + f ( x ) , 0 < t ≤ T . ( 1 ) \frac{\vartheta u}{\vartheta t}=a\frac{\vartheta^2u}{\vartheta x^2}+f(x),0< t\leq T.(1) ϑtϑu=aϑx2ϑ2u+f(x),0<tT.1
其中 a 是正常数, f(x) 是给定的连续函数,对于初-边值问题的描述为,对于有一定阶偏导微商函数 u ( x , t ) u(x,t) u(x,t) ,满足方程(1)的初始条件: u ( x , 0 ) = Φ ( x ) , 0 < x < l u(x,0)=\Phi(x),0<x<l u(x,0)=Φ(x),0<x<l 以及边界条件 u ( 0 , t ) = u ( l , t ) = 0 , 0 ≤ t ≤ T u(0,t)=u(l,t)=0,0\leq t\leq T u(0,t)=u(l,t)=0,0tT

特别提示:由于本文不是纯粹的数学推理文章,所以会涉及到一些条件和假设的简化,如果从纯粹数学角度考虑,一个条件的成立往往需要很多假设和前提,以及精准的定义,这一点跟工业中算法成立还是有很大区别的。

对于光滑 f ( x ) f(x) f(x) Φ ( x ) \Phi(x) Φ(x) ,我们从初-边值考虑差分逼近。取空间步长 h = l / J h=l/J h=l/J 和时间步长 τ = T / N \tau=T/N τ=T/N ,其中 J 、 N J、N JN 都是自然数。用两族平行直线 x = x j = j h ( j = 0 , 1 , . . . , J ) x=x_j=jh(j=0,1,...,J) x=xj=jh(j=0,1,...,J) t = t n = n τ ( n = 0 , 1 , . . . N ) t=t_n=n\tau(n=0,1,...N) t=tn=nτ(n=0,1,...N) 将如下矩形分割成网格,网格节点设为 ( x j , t n ) (x_j,t_n) (xj,tn)
在这里插入图片描述

我们用 u j n u_j^n ujn 表示定义在网点 ( x j , t n ) (x_j,t_n) (xj,tn) 上的函数,接着用差商代替上述(1)方程,接下来介绍几种简便的经典差分格式。

二:差分格式

  • 向前差分格式(显式格式)

u j n + 1 − u j n τ = a u j + 1 n − 2 u j n + u j − 1 n h 2 + f j \frac{u_j^{n+1}-u_j^n}{\tau}=a\frac{u_{j+1}^{n}-2u_j^n+u_{j-1}^n}{h^2}+f_j τujn+1ujn=ah2uj+1n2ujn+uj1n+fj ,其中 j = 1 , 2 , . . . , J − 1 , n = 0 , 1 , . . . , N − 1 j=1,2,...,J-1,n=0,1,...,N-1 j=1,2,...,J1,n=0,1,...,N1 ,以 α = a τ / h 2 \alpha=a\tau/h^2 α=aτ/h2 表示网格比,上式我们变形可得: u j n + 1 = α u j + 1 n + ( 1 − 2 α ) u j n + r u j − 1 n + τ f j u_j^{n+1}=\alpha u_{j+1}^n+(1-2\alpha)u_j^n+ru_{j-1}^n+\tau f_j ujn+1=αuj+1n+(12α)ujn+ruj1n+τfj ,取 n = 0 n=0 n=0 ,利用初值 u j 0 = φ j u_j^0=\varphi_j uj0=φj 和边值 u 0 n = u J n = 0 u_0^n=u_J^n=0 u0n=uJn=0 可以通过变形式算出 u j 1 u_j^1 uj1 ,同理下去可以算出 u j 2 . . . . u_j^2.... uj2....,此格式不需要求解线性方程组,所以此格式视为显式格式,但显式格式并不是无条件稳定的,只有当 α ≤ 1 / 2 \alpha\leq1/2 α1/2 时,格式才是稳定的通过泰勒公式与截断误差定义,我们能证明出此格式基于时间步长 τ \tau τ 是一阶收敛的(由于此文不是存粹数学文章,这里涉及到的一些结论不再过多深入,有兴趣的朋友可以参考相关文献)。

  • 向后差分格式(隐式格式)

u j n + 1 − u j n τ = a u j + 1 n + 1 − 2 u j n + 1 + u j − 1 n + 1 h 2 + f j \frac{u_j^{n+1}-u_j^n}{\tau}=a\frac{u_{j+1}^{n+1}-2u_j^{n+1}+u_{j-1}^{n+1}}{h^2}+f_j τujn+1ujn=ah2uj+1n+12ujn+1+uj1n+1+fj ,其中 j = 1 , 2 , . . . , J − 1 , n = 0 , 1 , . . . , N − 1 j=1,2,...,J-1,n=0,1,...,N-1 j=1,2,...,J1,n=0,1,...,N1 ,同理我们改写上式为: − α u j + 1 n + 1 + ( 1 + 2 α ) u j n + 1 − α u j − 1 n + 1 = u j n + τ f j -\alpha u_{j+1}^{n+1}+(1+2\alpha)u_j^{n+1}-\alpha u_{j-1}^{n+1}=u_j^n+\tau f_j αuj+1n+1+(1+2α)ujn+1αuj1n+1=ujn+τfj ,令 $n=0,1,2,… $,则可利用 u j 0 u_j^0 uj0 和边值确定 u j 1 u_j^1 uj1 ,利用 u j 1 u_j^1 uj1 和边值确定 u j 2 u_j^2 uj2 等,现在第 n + 1 n+1 n+1 层的值不能用第 n n n 层值明显表示,而是由线性方程组求解。由于变形式左端系数矩阵是严格对角占优的,所以方程肯定有解的,且该格式是无条件稳定的。同样此格式也是基于时间步长 τ \tau τ 一阶收敛的

  • 六点对称格式(Crank-Nicolson 格式)

即向前差分格式和向后差分格式做算术平均,即可得到CN格式如下:
u j n + 1 − u j n τ = a 2 [ u j + 1 n + 1 − 2 u j n + 1 + u j − 1 n + 1 h 2 + u j + 1 n − 2 u j n + u j − 1 n h 2 ] + f i \frac{u_j^{n+1}-u_j^n}{\tau}=\frac{a}{2}\left[ \frac{u_{j+1}^{n+1}-2u_j^{n+1}+u_{j-1}^{n+1}}{h^2}+\frac{u_{j+1}^n-2u_j^n+u_{j-1}^n}{h^2} \right]+f_i τujn+1ujn=2a[h2uj+1n+12ujn+1+uj1n+1+h2uj+1n2ujn+uj1n]+fi
其中 j = 1 , 2 , . . . , J − 1 , n = 0 , 1 , . . . , N − 1 j=1,2,...,J-1,n=0,1,...,N-1 j=1,2,...,J1,n=0,1,...,N1,同理上式我们可以改写为 − α 2 u j + 1 n + 1 + ( 1 + α ) u j n + 1 − α 2 u j − 1 n + 1 = r 2 u j + 1 n + ( 1 − α ) u j n + α 2 u j − 1 n + τ f j -\frac{\alpha}{2}u_{j+1}^{n+1}+(1+\alpha)u_j^{n+1}-\frac{\alpha}{2}u_{j-1}^{n+1}=\frac{r}{2}u_{j+1}^n+(1-\alpha)u_j^n+\frac{\alpha}{2}u_{j-1}^n+\tau f_j 2αuj+1n+1+(1+α)ujn+12αuj1n+1=2ruj+1n+(1α)ujn+2αuj1n+τfj ,利用 u j 0 u_j^0 uj0 和边值便可以逐层求解到 u j n u_j^n ujn同样 C N CN CN格式是隐式格式,无条件稳定的,由第 n 层计算第 n+1 层时,需要求解线性方程组,但此格式基于时间步长 τ \tau τ 能达到二阶收敛

三:代码实现

接下来我们通过python的面向对象编程,逐一实现上面的三种数值格式。

以下代码经过本人调试,没任何bug,直接复制即可,有兴趣需要的朋友别忘记点赞关注加收藏哦!!谢谢!!

##############导入相应模块
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3Dplt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

编写差分格式类如下:

class diff_schemes:def __init__(self,dt,dx,r,x,t):##定义内置初始化函数self.dt = dtself.dx = dxself.r = rself.x = xself.t = tdef make_figure(self,matx,title_msg):###作图fig = plt.figure()ax = fig.gca(projection='3d')x, y = np.meshgrid(self.x, self.t)z = matxax.plot_surface(x, y, z, cmap=cm.coolwarm, linewidth=0, antialiased=False)ax.set_xlabel('X Label')ax.set_ylabel('Y Label')ax.set_zlabel('Z Label')plt.title(title_msg)plt.show()def init_condition(self):##定义初值函数,这里选择混个三角函数return np.sin(self.x) + np.cos(self.x)  ###也可以选择其他函数如指数函数exp(x)等等def forward_diff_scheme(self):##向前差分格式(显式)matx = np.zeros([len(self.t),len(self.x)])###默认边值都为0matx[0,:] = icmatx[:,0] = 0matx[:,-1] = 0for i in range(1,len(self.t)):for j in range(1,len(self.x)-1):matx[i,j] = self.r * matx[i - 1,j - 1] + (1 - 2 * self.r) * matx[i - 1,j] + self.r * matx[i - 1,j + 1]print(matx)return matxdef backward_diff_scheme(self):matx = np.zeros([len(self.t), len(self.x)])matx[0, :] = icmatx[:, 0] = 0matx[:, -1] = 0matxa = np.zeros([len(self.x) - 2,len(self.x) - 2 ])for j in range(len(self.x) - 2):matxa[j, j] = 1 + 2 * self.rif j >= 1:matxa[j - 1, j] = - self.rmatxa[j, j - 1] = - self.riv = ic[1:-1]matxa_t = np.linalg.inv(matxa)##求解线性方程组for i in range(1, len(self.t)):res = np.dot(matxa_t,iv)matx[i,1:-1] = resiv = resprint(matx)return matxdef CN_diff_scheme(self):r1 = 1 + self.rr2 = 1 - self.rmatx = np.zeros([len(self.t), len(self.x)])matx[0, :] = icmatx[:, 0] = 0matx[:, -1] = 0matxp = np.zeros([len(self.x) - 2, len(self.x) - 2])matxq = np.zeros([len(self.x) - 2, len(self.x) - 2])for j in range(len(self.x) - 2):matxp[j, j] = r1matxq[j, j] = r2if j >= 1:matxp[j - 1, j] = - self.r / 2matxp[j, j - 1] = - self.r / 2matxq[j - 1, j] = self.r / 2matxq[j, j - 1] = self.r / 2iv = np.dot(matxq,ic[1:-1])matxa_t = np.linalg.inv(matxp)for i in range(1, len(self.t)):res = np.dot(matxa_t, iv)matx[i, 1:-1] = resiv = np.dot(matxq,res)print(matx)return matx

调用相关类中方法展示实验结果

dt = 0.01##时间步长
dx = 0.01##空间步长
a = 0.5##网格比的取值,且显式格式时a的取值不能大于0.5
X_array = np.arange(-2.5,2.5 + dx,dx)
T_array = np.arange(0,1 + dt,dt)
res = diff_schemes(dt,dx,a,X_array,T_array)
ic = res.init_condition()###初始条件
rfd = res.forward_diff_scheme()
rbd = res.backward_diff_scheme()
rcnd = res.CN_diff_scheme()res.make_figure(rfd,'网格比a=%s时,显式格式求解'%a)
res.make_figure(rbd,'网格比a=%s时,隐式格式求解'%a)
res.make_figure(rcnd,'网格比a=%s时,CN格式求解'%a)

四:数值结果

1

图1

在这里插入图片描述

图2

在这里插入图片描述

图3

在这里插入图片描述

图4(显式格式求解值)

在这里插入图片描述

图5(隐式格式求解值)

在这里插入图片描述

图6(CN格式求解值)

从上面所有图中结果可知,三种格式最终在末端位置(时间末端和空间末端)的运算结果很接近(如果深入从收敛阶角度出发,其实CN格式的精度更高更接近真解,收敛速率最快)。

在这里插入图片描述

图7

当我们网格比取值大于0.5时,显式格式符合理论上的结果,明显不稳定收敛了,但两种隐式格式还是依旧很稳定,从图7很明显能发掘到这一点。

五:总结

本文主要是数值模拟实验类文章,也是学习数值求解偏微分方程的基础性文章。偏微分方程的理论是非常广且深,另外,它跟随机微分方程也有这千丝万缕的联系。如果有兴趣的小伙伴可以多多交流。

写作不易,望路过的朋友们点赞收藏加关注哈,在此表示感谢!
在这里插入图片描述

这篇关于基于Python编写求解抛物型pde方程的经典数值格式模拟的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/240273

相关文章

Python按照24个实用大方向精选的上千种工具库汇总整理

《Python按照24个实用大方向精选的上千种工具库汇总整理》本文整理了Python生态中近千个库,涵盖数据处理、图像处理、网络开发、Web框架、人工智能、科学计算、GUI工具、测试框架、环境管理等多... 目录1、数据处理文本处理特殊文本处理html/XML 解析文件处理配置文件处理文档相关日志管理日期和

Python标准库datetime模块日期和时间数据类型解读

《Python标准库datetime模块日期和时间数据类型解读》文章介绍Python中datetime模块的date、time、datetime类,用于处理日期、时间及日期时间结合体,通过属性获取时间... 目录Datetime常用类日期date类型使用时间 time 类型使用日期和时间的结合体–日期时间(

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我