一个简单的二维波动方程有限差分正演示例(均匀介质,无吸收边界条件及震源)

博客介绍二维波动方程格式及算法原理。先给出波动方程、初值条件和边界条件及解析解,接着进行网格划分,将方程离散化,包括波动方程、初值条件和边界条件的离散推导,最后提及生成动图及下一目标是实现二维声波方程的有限差分正演。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从FWI.yml文件中导入环境配置

from IPython.display import Latex
from IPython.display import HTML

二维波动方程格式

utt(x,y,t)=uxx(x,y,t)+uyy(x,y,t),(x,y)∈Ω=(0,1)×(0,1),t∈(0,1.4)(1)u_{tt}(x,y,t)=u_{xx}(x,y,t)+u_{yy}(x,y,t),\quad (x,y)\in\Omega = (0,1)\times(0,1),t\in(0,1.4)\quad(1)utt(x,y,t)=uxx(x,y,t)+uyy(x,y,t),(x,y)Ω=(0,1)×(0,1),t(0,1.4)(1)

u(x,y,0)=sin⁡(πx)sin⁡(πy),ut(x,y,0)=0,(x,y)∈(0,1)×(0,1)(2)u(x,y,0) = \sin(\pi x)\sin(\pi y),\quad u_t(x,y,0) = 0, \quad(x,y)\in(0,1)\times(0,1)\quad(2)u(x,y,0)=sin(πx)sin(πy),ut(x,y,0)=0,(x,y)(0,1)×(0,1)(2)

u(x,y,t)=0,(x,y)∈∂Ωt∈[0,1.4](3)u(x,y,t) = 0,\quad(x,y)\in\partial \Omega\quad t\in[0,1.4]\quad(3)u(x,y,t)=0,(x,y)Ωt[0,1.4](3)

解析解为u(x,y,t)=cos⁡(2πt)sin⁡(πx)sin⁡(πy)u(x,y,t)=\cos(\sqrt2\pi t)\sin(\pi x)\sin(\pi y)u(x,y,t)=cos(2πt)sin(πx)sin(πy)

算法原理

网格划分取h=△x=△y=0.01τ=△t=0.1hh =\triangle x = \triangle y = 0.01\quad \tau = \triangle t = 0.1hh=x=y=0.01τ=t=0.1h 由此,空间采样点N=1h=100N=\frac{1}{h}=100N=h1=100, 时间采样点M=1.40.1h=1400M = \frac{1.4}{0.1h}= 1400M=0.1h1.4=1400,令xi=ih,yj=jh,tk=kτ,i∈[0,N],j∈[0,N],k∈[0,M]x_i = ih,y_j =jh,t_k=k\tau,\quad i\in[0,N],j\in[0,N],k\in[0,M]xi=ih,yj=jh,tk=kτ,i[0,N],j[0,N],k[0,M]

1中(1)、(2)、(3)可离散为

ui,jk+1=r2(ui+1,jk+ui−1,jk+ui,j+1k+ui,j−1k)+(2−4r2)ui,jk−ui,jk−1i∈[1,N−1],j∈[1,N−1],k∈[1,M−1]u_{i,j}^{k+1} = r^2(u_{i+1,j}^{k} +u_{i-1,j}^{k} +u_{i,j+1}^{k} +u_{i,j-1}^{k} )+(2-4r^2)u_{i,j}^k -u_{i,j}^{k-1}\quad i\in[1,N-1],j\in[1,N-1],k\in[1,M-1]ui,jk+1=r2(ui+1,jk+ui1,jk+ui,j+1k+ui,j1k)+(24r2)ui,jkui,jk1i[1,N1],j[1,N1],k[1,M1],r=τh=0.1r=\frac{\tau}{h}=0.1r=hτ=0.1

ui,j0=sin⁡(πxi)sin⁡(πyj)=sin⁡(πih)sin⁡(πjh),i∈[0,N],j∈[0,N]u_{i,j}^0 = \sin(\pi x_i)\sin(\pi y_j)=\sin(\pi ih)\sin(\pi jh), \quad i\in[0,N],j\in[0,N]ui,j0=sin(πxi)sin(πyj)=sin(πih)sin(πjh),i[0,N],j[0,N]

ui,j1=r22(ui+1,j0+ui−1,j0+ui,j+10+ui,j−10)+(1−2r2)ui,j0i∈(0,N),j∈(0,N)u_{i,j}^{1} = \frac{r^2}{2}(u_{i+1,j}^{0} +u_{i-1,j}^{0} +u_{i,j+1}^{0} +u_{i,j-1}^{0} )+(1-2r^2)u_{i,j}^0\quad i\in(0,N),j\in(0,N)ui,j1=2r2(ui+1,j0+ui1,j0+ui,j+10+ui,j10)+(12r2)ui,j0i0,N,j0,N

u0,0k=u0,Nk=uN,0k=uN,Nk=0k∈[0,M]u_{0,0}^k=u_{0,N}^k=u_{N,0}^k=u_{N,N}^k=0 \quad k\in[0,M]u0,0k=u0,Nk=uN,0k=uN,Nk=0k[0,M]

具体推导如下

离散化波动方程

对波动方程(1)建立二阶有限差分格式可以得到:

ui,jk+1−2ui,jk+ui,jk−1τ2=ui+1,jk−2ui,jk+ui−1,jkh2+ui,j+1k−2ui,jk+ui,j−1kh2(4)\frac{u_{i,j}^{k+1}-2u_{i,j}^{k}+u_{i,j}^{k-1}}{\tau^2}=\frac{u_{i+1,j}^k-2u_{i,j}^k+u_{i-1,j}^k}{h^2}+\frac{u_{i,j+1}^k-2u_{i,j}^k+u_{i,j-1}^k}{h^2}\quad(4)τ2ui,jk+12ui,jk+ui,jk1=h2ui+1,jk2ui,jk+ui1,jk+h2ui,j+1k2ui,jk+ui,j1k(4)

整理可得:

ui,jk+1=r2(ui+1,jk+ui−1,jk+ui,j+1k+ui,j−1k)+(2−4r2)ui,jk−ui,jk−1(5)u_{i,j}^{k+1} = r^2(u_{i+1,j}^{k} +u_{i-1,j}^{k} +u_{i,j+1}^{k} +u_{i,j-1}^{k} )+(2-4r^2)u_{i,j}^k -u_{i,j}^{k-1}\quad(5)ui,jk+1=r2(ui+1,jk+ui1,jk+ui,j+1k+ui,j1k)+(24r2)ui,jkui,jk1(5)

其中,i∈[1,N−1],j∈[1,N−1],k∈[1,M−1]i\in[1,N-1],j\in[1,N-1],k\in[1,M-1]i[1,N1],j[1,N1],k[1,M1],r=τh=0.1r=\frac{\tau}{h}=0.1r=hτ=0.1,局部阶段误差为o(h2)o(h^2)o(h2)

离散化初值条件

考虑初直条件u(x,y,0)=sin⁡(πx)sin⁡(πy),(x,y)∈(0,1)×(0,1)u(x,y,0) = \sin(\pi x)\sin(\pi y),\quad(x,y)\in(0,1)\times(0,1)u(x,y,0)=sin(πx)sin(πy),(x,y)(0,1)×(0,1),差分格式为

ui,j0=sin⁡(πxi)sin⁡(πyj)=sin⁡(πih)sin⁡(πjh),i∈[0,N],j∈[0,N](6)u_{i,j}^0 = \sin(\pi x_i)\sin(\pi y_j)=\sin(\pi ih)\sin(\pi jh), \quad i\in[0,N],j\in[0,N]\quad(6)ui,j0=sin(πxi)sin(πyj)=sin(πih)sin(πjh),i[0,N],j[0,N](6)

考虑到初直条件ut(x,y,0)=0,(x,y)∈(0,1)×(0,1)\quad u_t(x,y,0) = 0, \quad(x,y)\in(0,1)\times(0,1)ut(x,y,0)=0,(x,y)(0,1)×(0,1),利用二阶差商近似:

ui,j1−ui,j−12τ=0,(x,y)∈(0,1)×(0,1)(7)\frac{u_{i,j}^1-u_{i,j}^{-1}}{2\tau} =0, \quad(x,y)\in(0,1)\times(0,1)\quad(7)2τui,j1ui,j1=0,(x,y)(0,1)×(0,1)(7)

将k=0代入(5),则有:

ui,j1=r2(ui+1,j0+ui−1,j0+ui,j+10+ui,j−10)+(2−4r2)ui,j0−ui,j−1(8)u_{i,j}^{1} = r^2(u_{i+1,j}^{0} +u_{i-1,j}^{0} +u_{i,j+1}^{0} +u_{i,j-1}^{0} )+(2-4r^2)u_{i,j}^0 -u_{i,j}^{-1}\quad(8)ui,j1=r2(ui+1,j0+ui1,j0+ui,j+10+ui,j10)+(24r2)ui,j0ui,j1(8)

带入(7)中ui,j1=ui,j−1u_{i,j}^1=u_{i,j}^{-1}ui,j1=ui,j1整理得:

ui,j1=r22(ui+1,j0+ui−1,j0+ui,j+10+ui,j−10)+(1−2r2)ui,j0(9)u_{i,j}^{1} = \frac{r^2}{2}(u_{i+1,j}^{0} +u_{i-1,j}^{0} +u_{i,j+1}^{0} +u_{i,j-1}^{0} )+(1-2r^2)u_{i,j}^0\quad(9)ui,j1=2r2(ui+1,j0+ui1,j0+ui,j+10+ui,j10)+(12r2)ui,j0(9)

离散化边界条件

根据边界条件(3)可建立以下差分格式;

u0,0k=u0,Nk=uN,0k=uN,Nk=0(10)u_{0,0}^k=u_{0,N}^k=u_{N,0}^k=u_{N,N}^k=0 \quad(10)u0,0k=u0,Nk=uN,0k=uN,Nk=0(10)

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import animation
#定义计算区域
x0 = 0.0
x1 = 1.0
y0 = 0.0
y1 = 1.0
N = 100
ds = (x1 - x0)/N

t0 = 0.0
t1 = 1.4
M = 1400
dt = (t1 - t0)/M
x = np.linspace(x0, x1, N+1)
y = np.linspace(y0, y1, N+1)
t = np.linspace(t0, t1, M+1)

r = dt/ds;
#初始化计算区域
(X, Y, T) = np.meshgrid(x,y,t)
#解析解
uu = np.multiply(np.multiply(np.cos(np.sqrt(2) * np.pi * T),np.sin(np.pi * X)),np.sin(np.pi * Y))
#有限差分求解
#创建差分数组
u = np.zeros((N+1,N+1,M+1))
#加入初始条件1
for i in range(0,N+1):
    for j in range(0,N+1):
        u[i,j,0] = np.sin(np.pi*i*ds) * np.sin(np.pi*j*ds)
#加入初始条件2
for i in range(1,N):
    for j in range(1,N):
        u[i,j,1] = r**2 / 2 * (u[i+1,j,0] + u[i-1,j,0] + u[i,j+1,0] + u[i,j-1,0]) + (1 - 2*r**2) * u[i,j,0] 
#加入边界条件
for k in range(0,M+1):
    u[0,0,k] = u[0,N,k] = u[N,0,k] = u[N,N,k] = 0
#递推求[1,N-1]时刻波场
for k in range(1,M):
    for i in range(1,N):
        for j in range(1,N):
            u[i,j,k+1] = r**2*(u[i+1,j,k]+u[i-1,j,k]+u[i,j+1,k]+u[i,j-1,k]) + (2-4*r**2)*u[i,j,k] -u[i,j,k-1]
(X, Y) = np.meshgrid(x,y)
t = 100

fig = plt.figure(figsize=(20,16))
ax1 = fig.add_subplot(131,projection='3d')
surf1 = ax1.plot_surface(X, Y, uu[:,:,t], cmap='viridis')
fig.colorbar(surf1)
ax1.set_xlabel('X Label')
ax1.set_ylabel('Y Label')
ax1.set_zlabel('Z Label')
ax1.set_title(f"analysis solution at time {t*dt}")

ax2 = fig.add_subplot(132,projection='3d')
surf2 = ax2.plot_surface(X, Y, u[:,:,t], cmap='viridis')
fig.colorbar(surf2)
ax2.set_xlabel('X Label')
ax2.set_ylabel('Y Label')
ax2.set_zlabel('Z Label')
ax2.set_title(f"FD solution at time {t*dt}")

ax3 = fig.add_subplot(133,projection='3d')
surf3 = ax3.plot_surface(X, Y, uu[:,:,t]-u[:,:,t], cmap='viridis')
fig.colorbar(surf3)
ax3.set_xlabel('X Label')
ax3.set_ylabel('Y Label')
ax3.set_zlabel('Z Label')
ax3.set_title(f"error at time {t*dt}")

plt.show()

请添加图片描述

生成动图:

# 创建初始数据
data = uu[:, :, 0]

# 创建图形对象
fig, ax = plt.subplots()

# 创建pcolor对象
pc = ax.pcolor(X, Y, data, cmap='rainbow')

# 定义更新函数
def update(i):
    # 生成新的数据
    new_data = u[:, :, i]
    # 更新pcolor对象
    pc.set_array(new_data.ravel())
    ax.set_title(f"{i*dt} s")
    # 返回更新后的pcolor对象
    return pc,
plt.close()
# 创建动画对象
ani = animation.FuncAnimation(fig, update, frames=range(1, M+1), interval=1, blit=True)

# 显示动画
HTML(ani.to_html5_video())






下一目标:实现密度为常数的二维声波方程的有限差分正演
差分格式为:

1v(x,z)2∂2u∂t2−(∂2u∂x2+∂2u∂y2)=f(t)δ(x−xs)δ(z−zs)\frac{1}{v(x,z)^2}\frac{\partial^2u}{\partial t^2}-(\frac{\partial^2u}{\partial x^2}+\frac{\partial^2u}{\partial y^2})=f(t)\delta(x-x_s)\delta(z-z_s)v(x,z)21t22u(x22u+y22u)=f(t)δxxsδzzs

其中u(x,z,t)u(x,z,t)u(x,z,t)表示压力,v(x,z)v(x,z)v(x,z)为介质速度,f(t)f(t)f(t)是震源函数,(xs,zs)(x_s,z_s)(xs,zs)为震源位置。
方程满足初始条件

u(x,z,t=0)=0,∂u∂t(x,z,t=0)=0,(x,z)∈∂Ωu(x,z,t=0)=0,\frac{\partial u}{\partial t}(x,z,t=0)=0,(x,z)\in \partial \Omegau(x,z,t=0)=0,tu(x,z,t=0)=0,(x,z)Ω

以下是一个二维水平分层介质波动方程模拟的 MATLAB 代码。本代码考虑了各向异性介质,使用了有限差分时间域(FDTD)方法。 ```matlab % 声波二维模拟 clc; clear; % 设定模拟区域大小 xmax = 1000; % x方向最大值(单位:m) ymax = 1000; % y方向最大值(单位:m) dx = 10; % 网格间距(单位:m) dy = 10; % 网格间距(单位:m) nx = floor(xmax/dx); % x方向网格数 ny = floor(ymax/dy); % y方向网格数 % 设定模拟时间参数 tmax = 2; % 最大模拟时间(单位:s) dt = 0.001; % 时间步长(单位:s) nt = floor(tmax/dt); % 时间步数 % 设定介质参数 vp = zeros(nx, ny); % 声波速度(单位:m/s) vs = zeros(nx, ny); % 纵波速度(单位:m/s) rho = zeros(nx, ny); % 密度(单位:kg/m^3) epsilon = zeros(nx, ny); % 纵波各向异性系数 delta = zeros(nx, ny); % 横波各向异性系数 % 设定震源参数 sx = nx/2; % 震源位置x坐标 sy = ny/2; % 震源位置y坐标 f0 = 30; % 震源频率 t0 = 0.05; % 震源持续时间 src = zeros(nt,1); % 震源波形 % 生成Ricker子波作为震源波形 for i = 1:nt t = (i-1)*dt; src(i) = (1-2*pi^2*f0^2*(t-t0)^2)*exp(-pi^2*f0^2*(t-t0)^2); end % 初始化波场和边界条件 p = zeros(nx,ny); % 压力波场 vx = zeros(nx,ny); % x方向速度波场 vy = zeros(nx,ny); % y方向速度波场 pml_len = 40; % PML吸收边界层数 pml_coef = 0.001; % PML吸收系数 pml_xmin = zeros(pml_len,ny); % PML吸收边界x方向左侧 pml_xmax = zeros(pml_len,ny); % PML吸收边界x方向右侧 pml_ymin = zeros(nx,pml_len); % PML吸收边界y方向下侧 pml_ymax = zeros(nx,pml_len); % PML吸收边界y方向上侧 % 循环进行时间步进计算 for it = 1:nt % 计算PML吸收边界 if pml_len > 0 for i = 1:pml_len x = (pml_len-i+0.5)*dx; sigmax = pml_coef*(i/pml_len)^2; for j = 1:ny pml_xmin(i,j) = (1-sigmax)*pml_xmin(i,j) + sigmax*p(i,j); pml_xmax(i,j) = (1-sigmax)*pml_xmax(i,j) + sigmax*p(nx-i+1,j); end end for i = 1:nx y = (pml_len-i+0.5)*dy; sigmay = pml_coef*(i/pml_len)^2; for j = 1:pml_len pml_ymin(i,j) = (1-sigmay)*pml_ymin(i,j) + sigmay*p(i,j); pml_ymax(i,j) = (1-sigmay)*pml_ymax(i,j) + sigmay*p(i,ny-j+1); end end end % 计算应力源 if it <= length(src) p(sx,sy) = p(sx,sy) + src(it); end % 计算速度波场 for i = 2:nx-1 for j = 2:ny-1 % 计算x方向速度 vx(i,j) = vx(i,j) + dt/rho(i,j)*(epsilon(i,j)*... (p(i,j+1)-p(i,j))-delta(i,j)*(p(i+1,j+1)-p(i+1,j-1))/4/dy); % 计算y方向速度 vy(i,j) = vy(i,j) + dt/rho(i,j)*(epsilon(i,j)*... (p(i+1,j)-p(i,j))-delta(i,j)*(p(i+1,j+1)-p(i-1,j+1))/4/dx); end end % 计算应力波场 for i = 2:nx-1 for j = 2:ny-1 % 计算x方向应力 p(i,j) = p(i,j) + dt*vp(i,j)^2*rho(i,j)*... (epsilon(i,j)*(vx(i,j)-vx(i,j-1))/dy+delta(i,j)*... (vy(i,j)-vy(i-1,j))/dx); end end % 边界处理 if pml_len > 0 p(1:pml_len,:) = pml_xmin; p(nx-pml_len+1:nx,:) = pml_xmax; p(:,1:pml_len) = pml_ymin; p(:,ny-pml_len+1:ny) = pml_ymax; end % 显示进度条 fprintf('Progress: %.2f%%\n', it/nt*100); end ``` 代码解释如下: 1. 第1-3行:清空命令窗口,清除已经定义的变量。 2. 第6-10行:设定模拟区域大小和网格间距。 3. 第13-15行:设定模拟时间参数。 4. 第18-22行:设定介质参数,包括声波速度、纵波速度、密度、纵波各向异性系数和横波各向异性系数。 5. 第25-28行:设定震源参数,包括震源位置、震源频率和震源持续时间。 6. 第31-36行:生成Ricker子波作为震源波形。 7. 第39-48行:初始化波场和边界条件。波场包括压力波场和速度波场,边界条件包括PML吸收边界。 8. 第51-93行:循环进行时间步进计算。首先计算PML吸收边界,然后计算应力源,接着计算速度波场,最后计算应力波场。边界处理使用PML吸收边界。在每个时间步长结束后,显示进度条。 以上就是一个二维水平分层介质波动方程模拟的 MATLAB 代码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值