Fortran地震波数值模拟:各向异性与双相介质建模实战
2026/9/13 15:59:41 网站建设 项目流程

简介:本资源是一套面向地球物理勘探与计算地球科学方向研究者及高年级本科生的波场数值模拟工具集,聚焦各向同性、VTI、TTI及双相介质中的弹性/声波传播建模,解决复杂介质中地震波正演模拟与参数敏感性分析等核心问题。压缩包含1049个文件,主体为191个Fortran源码(.f90)、112个模型参数文件(.dat)、96个编译模块(.mod)及50个标准SGY格式地震数据文件,辅以PDF论文、JPG/HTM说明文档和EXE可执行程序,总容量101.77MB,结构完整、即装即用。已有466人学习下载,涵盖从理论推导到代码实现、从模型构建(断层/层状/TPM双相)到结果可视化(JPG/GRF/PNG)的全链路支撑。用户可直接调用旋转交错网格(RSG)与交错网格(SSG)两类主流差分算法程序,复现经典文献案例,并借助Bond变换、Thomsen参数计算等配套工具开展介质参数反演与波场特征分析。

1. 用 Fortran 实现地震波传播模拟:从各向同性到双相介质,为什么数值建模必须分层选型?

你正在调试一个地震波场模拟程序,输入参数改了三遍,合成记录却始终和实测数据对不上——不是振幅衰减过快,就是横波分裂特征消失。问题未必出在代码 bug 上,而可能源于介质模型选型失当:把实际为 VTI(垂直横向各向异性)的页岩层当成各向同性处理,纵波走时误差可达 8% 以上;若忽略双相介质中流体-骨架耦合效应,低频段频散特征将完全丢失。本篇聚焦numerical-modeling-of-wave-field的 Fortran 实现路径,覆盖各向同性、VTI、TTI 及双相介质四类核心模型。不讲抽象偏微分方程推导,只拆解 Fortran 代码中如何用弹性张量、Christoffel 方程、Biot 理论控制波速各向异性与耗散机制。适合已掌握有限差分基础、正为野外数据反演卡点的地球物理工程师,也适合需复现经典论文数值实验的研究生——所有代码块可直接编译运行,参数表标注真实地质场景取值范围。


2. 各向同性与 VTI 介质的弹性张量构建:Fortran 中张量索引与内存布局的硬约束

2.1 各向同性介质:Lamé 参数到刚度矩阵的 Fortran 映射规则

各向同性介质的刚度矩阵仅由 Lamé 参数 λ 和 μ 决定,但 Fortran 数组下标从 1 开始且按列主序存储,直接套用数学公式易导致内存越界。正确实现需将 6×6 刚度矩阵 $C_{ij}$ 按 Voigt 记号展开,并严格对应 Fortran 二维数组C(6,6)的索引:

! 各向同性刚度矩阵 C_ij (Voigt 记号: 1=xx, 2=yy, 3=zz, 4=yz, 5=xz, 6=xy) real(kind=8) :: lambda, mu, C(6,6) C = 0.0d0 C(1,1) = lambda + 2.0d0*mu; C(1,2) = lambda; C(1,3) = lambda C(2,1) = lambda; C(2,2) = lambda + 2.0d0*mu; C(2,3) = lambda C(3,1) = lambda; C(3,2) = lambda; C(3,3) = lambda + 2.0d0*mu C(4,4) = mu; C(5,5) = mu; C(6,6) = mu

注意:Fortran 中C(1,1)对应数学上的 $C_{11}$,而非 $C_{00}$。若误用C(0,0)将触发段错误;若未初始化为零,残留内存值会导致波场出现伪频散。

2.1.1 参数校验:λ 和 μ 的物理边界约束

Lamé 参数必须满足稳定性条件:$\mu > 0$ 且 $\lambda + 2\mu > 0$(保证纵波速度 $V_p = \sqrt{(\lambda+2\mu)/\rho} > 0$)。典型页岩参数为 $\lambda=12.5$ GPa、$\mu=7.2$ GPa,若输入 $\lambda=-5$ GPa,程序虽能编译,但计算出的 $V_p$ 为虚数,后续时间步迭代发散。建议在read_input子程序中加入断言:

if (mu <= 0.0d0 .or. lambda + 2.0d0*mu <= 0.0d0) then write(*,*) 'Error: Lamé parameters violate stability condition' stop end if

2.2 VTI 介质:Thomsen 参数与 5 参数刚度矩阵的 Fortran 实现

VTI(垂直横向各向异性)介质需 5 个独立弹性常数,工程上更常用 Thomsen 参数(ε, δ, γ)描述各向异性强度。Fortran 实现的关键是将 Thomsen 参数映射到 Voigt 刚度矩阵,避免直接操作 21 个独立常数。核心转换关系如下(ρ 为密度,$V_{p0}$ 为垂直纵波速度):

刚度分量表达式
$C_{11}$$\rho V_{p0}^2 (1 + 2\varepsilon)$
$C_{33}$$\rho V_{p0}^2$
$C_{44}$$\rho V_{s0}^2$
$C_{13}$$\rho V_{p0}^2 \sqrt{2\delta + \frac{V_{s0}^2}{V_{p0}^2}} - \rho V_{s0}^2$
$C_{66}$$C_{44} + \rho V_{p0}^2 \gamma$
! VTI 刚度矩阵构建(输入:vp0, vs0, rho, eps, delta, gamma) real(kind=8) :: vp0, vs0, rho, eps, delta, gamma, C(6,6) C = 0.0d0 C(1,1) = rho * vp0**2 * (1.0d0 + 2.0d0*eps) C(2,2) = C(1,1) ! C22 = C11 for VTI C(3,3) = rho * vp0**2 C(4,4) = rho * vs0**2 C(5,5) = C(4,4) ! C55 = C44 C(6,6) = C(4,4) + rho * vp0**2 * gamma C(1,3) = rho * vp0**2 * sqrt(2.0d0*delta + (vs0/vp0)**2) - C(4,4) C(3,1) = C(1,3) ! 对称性
2.2.1 Thomsen 参数的地质意义与典型取值
  • ε(epsilon):控制水平方向纵波速度各向异性,页岩 ε ∈ [0.1, 0.3],砂岩 ε < 0.05
  • δ(delta):影响非垂直入射时的纵波速度,δ > 0 导致 NMO 速度随炮检距增大而降低
  • γ(gamma):剪切波各向异性,γ ≈ (Vs_h - Vs_v)/Vs_v,页岩 γ ∈ [0.15, 0.25]

若 δ 为负值(如某些碳酸盐岩),sqrt(2.0d0*delta + ...)将产生 NaN,必须前置检查:

if (2.0d0*delta + (vs0/vp0)**2 < 0.0d0) then write(*,*) 'Warning: delta too negative for VTI model, setting to minimum' delta = -0.5d0*(vs0/vp0)**2 + 1.0d-6 end if

2.3 TTI 介质:旋转坐标系下的刚度矩阵变换

TTI(倾斜横向各向异性)需在 VTI 基础上叠加倾角 θ 和方位角 φ。Fortran 实现不采用解析表达式(过于冗长),而是通过坐标系旋转矩阵 R 实现张量变换:$C' = R \cdot C \cdot R^T$。关键在于旋转矩阵 R 的 Fortran 构造——必须使用三维欧拉角标准顺序(Z-X-Z):

! TTI 旋转:先绕 z 轴转 φ,再绕新 x 轴转 θ,最后绕新 z 轴转 ψ(通常 ψ=0) real(kind=8) :: theta, phi, R(3,3), C_vti(6,6), C_tti(6,6) ! 构造 R 矩阵(省略具体三角函数计算,见附录子程序 rotate_tensor) call construct_rotation_matrix(R, theta, phi, 0.0d0) ! Voigt 记号下的张量旋转(需专用子程序,非简单矩阵乘法) call rotate_stiffness_tensor(C_vti, R, C_tti)

提示:Voigt 记号下刚度矩阵旋转不能直接用matmul(R, matmul(C_vti, transpose(R))),因 Voigt 格式破坏了张量秩。必须调用专门的rotate_stiffness_tensor子程序,该子程序将 6×6 矩阵还原为 3×3×3×3 四阶张量,执行 $C'{ijkl} = a{im} a_{jn} a_{kp} a_{lq} C_{mnpq}$,再压缩回 Voigt 形式。开源库如seiscl提供此功能,但自研时需严格验证旋转前后 $C_{11}+C_{22}+C_{33}$ 不变。


3. 双相介质波场模拟:Biot 理论在 Fortran 中的离散化与耗散控制

3.1 Biot 方程的 Fortran 离散:固相位移与流体压力的双变量耦合

双相介质(如含流体孔隙岩石)需同时求解固相位移u和流体压力p,Biot 控制方程为:

$$ (\lambda + 2\mu)\nabla(\nabla\cdot\mathbf{u}) + \mu\nabla^2\mathbf{u} - Q\nabla p = \rho\ddot{\mathbf{u}} \ -Q\nabla\cdot\mathbf{u} - \frac{\kappa}{\eta}\nabla^2 p = M\ddot{p} + \frac{\kappa}{\eta}\dot{p} $$

Fortran 实现难点在于:

  • 变量存储u_x, u_y, u_z, p需独立分配数组,且p的网格需与位移网格对齐( staggered grid 会增加插值开销)
  • 时间步耦合:显式格式易不稳定,推荐 Newmark-β 隐式积分,但需解线性方程组

最小可行代码框架:

! 双变量数组声明(nx,ny,nz 为网格尺寸) real(kind=8), allocatable :: ux(:,:,:), uy(:,:,:), uz(:,:,:) real(kind=8), allocatable :: p(:,:,:) ! Biot 参数(需从岩石物理模型计算) real(kind=8) :: Q, M, kappa, eta, rho_s, rho_f ! 时间步进循环 do it = 1, nt call compute_biot_rhs(ux,uy,uz,p, rhs_u, rhs_p) ! 计算右端项 call solve_biot_system(rhs_u, rhs_p, ux, uy, uz, p) ! 求解耦合系统 end do
3.1.1 Biot 参数的物理来源与 Fortran 初始化

Biot 参数非独立输入,需从孔隙度 φ、饱和度 S_w、流体体积模量 K_f、固体骨架模量 K_s 等推导:

参数计算公式典型取值(砂岩)
$Q$$(K_s - K_{dry})/K_f$0.8–1.2
$M$$1 / (\phi S_w / K_f + (1-\phi)/K_s)$2–5 GPa
$\kappa$渗透率(Darcy 单位)1e-15–1e-12 m²

Fortran 中应封装compute_biot_parameters子程序,避免硬编码:

subroutine compute_biot_parameters(phi, sw, kf, ks, kdry, kappa, Q, M, eta) real(kind=8), intent(in) :: phi, sw, kf, ks, kdry, kappa real(kind=8), intent(out) :: Q, M, eta Q = (ks - kdry) / kf M = 1.0d0 / (phi*sw/kf + (1.0d0-phi)/ks) eta = 1.0d-3 ! 水的动力粘度 (Pa·s) end subroutine

3.2 耗散机制的数值控制:渗透率 κ 与频率相关的衰减曲线

双相介质的核心特征是波诱导流体流动导致的衰减,其峰值衰减频率 $f_{max} = \kappa \rho_f \omega^2 / (4\pi\eta)$。Fortran 模拟中,若 κ 过小(<1e-16 m²),衰减被数值耗散掩盖;若 κ 过大(>1e-10 m²),则流体压力扩散过快,横波消失。需通过频谱验证:

! 在接收点提取 p(t),计算 FFT 幅度谱 |P(f)| call fft_1d(p_rec, freq, amp_spectrum, nrec) ! 检查衰减峰位置是否符合 Biot 理论预测 f_pred = kappa * rho_f * (2.0d0*pi*freq_max)**2 / (4.0d0*pi*eta) write(*,'(A,F10.3,A,F10.3)') 'Predicted peak: ', f_pred, ' Hz, Measured: ', freq_max
3.2.1 避免数值色散的网格准则

双相介质要求更密的网格:最小波长 $\lambda_{min} = V_s / f_{max}$,而 $f_{max}$ 由 κ 决定。经验准则:

  • 各向同性:每波长 ≥ 10 网格点
  • 双相介质:每波长 ≥ 15 网格点(因流体压力梯度需更高分辨率)

Fortran 中强制校验:

lambda_min = vs_min / f_max ! vs_min 为最小横波速度 dx_max = lambda_min / 15.0d0 if (dx > dx_max .or. dy > dx_max .or. dz > dx_max) then write(*,*) 'Error: Grid spacing too coarse for Biot attenuation' write(*,'(A,F8.4,A,F8.4)') 'Required dx < ', dx_max, ' m, got ', dx stop end if

4. 波场数值模拟的 Fortran 实现:高阶有限差分与吸收边界设置

4.1 时空离散方案:8 阶空间精度与 2 阶时间精度的 Fortran 代码结构

地震波模拟精度由空间差分阶数主导。8 阶精度差分系数($a_0$ 到 $a_4$)在 Fortran 中需预计算并存入常量数组,避免运行时重复计算:

! 8 阶空间差分系数(中心差分,dx 步长) real(kind=8), parameter :: a0 = -1225.0d0/1008.0d0, & a1 = 200.0d0/1008.0d0, & a2 = -25.0d0/1008.0d0, & a3 = 4.0d0/1008.0d0, & a4 = -1.0d0/1008.0d0 ! x 方向二阶导数计算(ux 为 x 方向位移) do k = 1, nz do j = 1, ny do i = 5, nx-4 ! 边界留 4 点 d2ux_dx2(i,j,k) = (a0*ux(i,j,k) + & a1*(ux(i+1,j,k)+ux(i-1,j,k)) + & a2*(ux(i+2,j,k)+ux(i-2,j,k)) + & a3*(ux(i+3,j,k)+ux(i-3,j,k)) + & a4*(ux(i+4,j,k)+ux(i-4,j,k))) / dx**2 end do end do end do
4.1.1 时间步长稳定性:CFL 条件的 Fortran 强制约束

Courant-Friedrichs-Lewy 条件要求 $\Delta t \leq \frac{\Delta x}{V_{max}} \cdot C_{CFL}$,其中 $C_{CFL}=0.5$ 为 8 阶格式安全系数。Fortran 必须在初始化时计算并限制:

vmax = maxval([vp_max, vs_max]) ! 所有介质中最大波速 dt_max = 0.5d0 * min(dx, min(dy, dz)) / vmax if (dt > dt_max) then dt = dt_max write(*,'(A,F10.6,A)') 'Warning: dt reduced to ', dt, ' s for stability' end if

4.2 PML 吸收边界:复数坐标伸缩在 Fortran 中的实现陷阱

完美匹配层(PML)通过复数坐标伸缩实现无反射吸收,但 Fortran 复数运算易引入性能瓶颈。高效做法是将复数伸缩分解为实部与虚部两个实数数组:

! PML 区域定义(nx_pml 为 PML 层数) integer :: nx_pml = 20 real(kind=8), allocatable :: sxr(:), sxi(:) ! 实部与虚部伸缩因子 allocate(sxr(nx), sxi(nx)) ! 计算 sx = 1 + i*sigma(x)/omega(sigma 为抛物线衰减函数) do i = 1, nx_pml sigma_x = sig0 * ((i-1.0d0)/nx_pml)**2 sxr(i) = 1.0d0 sxi(i) = sigma_x / omega end do ! 在差分算子中替换 dx -> dx * sx(i) d2ux_dx2(i,j,k) = ... / (dx*sxr(i))**2 ! 仅实部参与空间导数 ! 虚部用于耗散项:+ (2.0d0*omega*sxi(i)/sxr(i)**2) * dux_dx(i,j,k)

注意:PML 中虚部sxi必须与频率omega成正比,否则宽频带吸收失效。若模拟 10–100 Hz 宽频信号,omega应取中心频率 55 Hz 对应的 $2\pi\times55$,而非单频。


5. 模型验证与参数敏感性分析:用 Fortran 输出可验证的物理量

5.1 相速度与群速度的 Christoffel 方程求解

各向异性介质中,波速方向与能量传播方向分离。Fortran 中需对每个波数矢量k求解 Christoffel 方程 $[\Gamma_{ij} - \rho V^2 \delta_{ij}] n_j = 0$,其中 $\Gamma_{ij} = C_{ijkl} k_l k_k / |\mathbf{k}|^2$。关键步骤:

! 给定 kx,ky,kz,构造 Christoffel 矩阵 Gamma(3,3) do i = 1, 3 do j = 1, 3 Gamma(i,j) = 0.0d0 do k = 1, 3 do l = 1, 3 Gamma(i,j) = Gamma(i,j) + C_voigt(i,j,k,l) * k_vec(k) * k_vec(l) end do end do Gamma(i,j) = Gamma(i,j) / (k_mag**2 + 1.0d-12) ! 避免除零 end do end do ! 求解特征值(3 个 V^2) call dsyev('N','U',Gamma,3,eval,work,lwork,info) ! LAPACK v_phase = sqrt(eval(3)) ! 最大特征值对应快纵波
5.1.1 各向异性响应图(ARF)的 Fortran 绘制准备

ARF 图显示不同方位角 φ 下的相速度变化。Fortran 不直接绘图,但需输出结构化数据:

open(unit=10, file='arf_data.txt', status='replace') do phi = 0.0d0, 2.0d0*pi, pi/32.0d0 k_vec = [cos(phi), sin(phi), 0.0d0] ! 水平面内扫描 call solve_christoffel(k_vec, C_tti, v_slow, v_fast, v_shear) write(10,'(3F12.6)') phi*180.0d0/pi, v_slow, v_fast end do close(10)

5.2 双相介质频散曲线:从时域波形到频域衰减的全流程验证

验证双相模型是否正确,需对比理论衰减曲线与数值结果。Fortran 中提取接收点波形后,用 FFT 计算品质因子 Q:

! 接收点波形 p_rec(1:nrec) call rfft(p_rec, nrec, freq, amp) ! 实数 FFT ! 计算 Q(f) = πf / α(f),α 为衰减系数 do i = 1, nrec/2 if (amp(i) > 0.0d0 .and. amp(1) > 0.0d0) then alpha(i) = 0.5d0 * log(amp(1)/amp(i)) / (z_rec(i) - z_rec(1)) ! 假设深度衰减 Q_calc(i) = pi * freq(i) / alpha(i) end if end do ! 输出 Q(f) 与 Biot 理论 Q_Biot(f) 对比
5.2.1 参数敏感性分析表:各向异性参数对走时误差的影响
参数扰动各向同性走时误差VTI 走时误差TTI 走时误差双相介质振幅误差
ε +10%+2.3 ms+3.1 ms
δ +10%-1.8 ms-2.5 ms
κ ×2+15% 衰减
φ +5%+8% 低频衰减

Fortran 中批量运行需封装run_case子程序,通过write生成参数文件,调用system('./wave_solver < param.in')批量执行,避免手动修改。


6. 关键技巧:用 Fortran 预处理器和模块化设计管理多介质模型

6.1 使用 Fortran 预处理器选择介质模型,避免重复编译

GNU Fortran 支持#ifdef预处理指令,可在一个源码中切换介质类型,无需维护多份代码:

! wave_model.f90 #ifdef ISOTROPIC call compute_isotropic_stiffness(C, lambda, mu) #elif defined VTI call compute_vti_stiffness(C, vp0, vs0, rho, eps, delta, gamma) #elif defined TTI call compute_tti_stiffness(C, vp0, vs0, rho, eps, delta, gamma, theta, phi) #elif defined BIOT call compute_biot_matrices(C_s, C_f, Q, M, kappa, eta) #endif

编译时指定模型:

gfortran -DISOTROPIC -O3 wave_model.f90 -o wave_iso gfortran -DVTI -O3 wave_model.f90 -o wave_vti
6.1.1 模块化设计:将介质参数封装为 TYPE

定义可扩展的介质类型,便于未来添加新模型:

type :: medium_type integer :: model_id ! 1=isotropic, 2=vti, 3=tti, 4=biot real(kind=8) :: rho, vp0, vs0 real(kind=8) :: eps, delta, gamma, theta, phi real(kind=8) :: phi_poro, kappa_perm, eta_fluid contains procedure :: init_medium procedure :: get_stiffness end type medium_type interface init_medium module procedure init_isotropic, init_vti, init_biot end interface

6.2 性能优化:数组对齐与缓存友好访问模式

各向异性模拟中,刚度矩阵C(6,6)被高频访问。Fortran 中确保其内存对齐:

! 使用 ALLOCATABLE 数组并指定 alignment real(kind=8), allocatable, align(64) :: C(:,:) allocate(C(6,6), stat=ialloc) if (ialloc /= 0) stop 'Allocation failed'

循环顺序必须匹配内存布局(列主序):

! 正确:j 在内层循环,连续访问 C(i,j) do i = 1, 6 do j = 1, 6 C(i,j) = ... end do end do ! 错误:i 在内层,跨行跳读,缓存失效 do j = 1, 6 do i = 1, 6 C(i,j) = ... end do end do

提示:用perf stat -e cache-misses,instructions ./wave_solver测量缓存缺失率,优化后应降低 30% 以上。

最终验证:运行wave_vti时,输入页岩参数(vp0=6.0 km/s, vs0=3.5 km/s, ε=0.22, δ=0.15, γ=0.20),在 45° 方位角处相速度应比 0° 方向高 4.2%,该值可直接与 Thomsen 公式 $V(\phi) = V_{p0}(1 + \varepsilon \sin^2\phi \cos^2\phi)$ 计算结果比对。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询