2. 一维Cahn-Hilliard方程显式有限差分解
一维 Cahn-Hilliard 方程的显式有限差分格式
一维 Cahn-Hilliard 方程写作
∂c/∂t = M ∇²μ, μ = f′(c) − κ ∇²c
其中 c 为保守序参量,M 为迁移率,κ 为梯度能系数,f(c) 取双阱势 f(c)= (c²−1)²/4,于是 f′(c)=c³−c。展开后得到四阶方程:
∂c/∂t = M ∇²(c³ − c) − Mκ ∇⁴c
在一维周期域 [0,L] 上,用均匀网格 x_i = iΔx(i=0,…,N−1),显式欧拉时间推进,二阶中心差分近似空间导数。记 c_i^n 为第 n 步第 i 点的值,则离散格式为:
c_i^{n+1} = c_i^n + dt * M * ( lap_mu_i^n )
lap_mu_i^n = ( mu_{i+1}^n - 2 mu_i^n + mu_{i-1}^n ) / dx^2
mu_i^n = (c_i^n)^3 - c_i^n - kappa * ( c_{i+1}^n - 2 c_i^n + c_{i-1}^n ) / dx^2
周期边界通过索引取模实现:i+1 与 i−1 分别对 N 取模。显式格式的稳定性受四阶项限制,时间步需满足 dt ≲ dx⁴/(16 M κ) 量级,实际计算中应取更保守的值。
线性稳定性与生长率
在 c≈0 附近线性化,令 c = c₀ + δc,δc ∝ exp(ikx + σt),代入线性化方程得到色散关系:
σ(k) = −M k² ( f″(c₀) + κ k² )
当 f″(c₀)=−1(旋节线内),σ(k) = M k² (1 − κ k²)。可见:
- k < k_c = 1/√κ 时 σ(k) > 0,扰动增长,发生旋节线分解;
- k = k_max = 1/√(2κ) 时 σ 最大,对应最快增长波数;
- k > k_c 时 σ(k) < 0,扰动衰减。
本案例用显式有限差分模拟早期浓度波增长,提取不同波数下的生长率,并与上述理论曲线对比。
显式差分实现要点
下面给出可直接运行的一维 Cahn-Hilliard 显式有限差分核心代码。参数取 M=1.0,κ=1.0,L=100,N=256,dx=L/N,dt=1e-4,总步数 20000。初始条件为 c₀=0 加小振幅单波扰动 c_i = 0.01·cos(2π k x_i / L),k 取不同整数波数。
import numpy as np
def ch1d_explicit(N=256, L=100.0, M=1.0, kappa=1.0,
dt=1e-4, nsteps=20000, k_mode=3, amp=0.01):
dx = L / N
x = np.arange(N) * dx
c = amp * np.cos(2 * np.pi * k_mode * x / L)
for n in range(nsteps):
# 周期边界索引
ip1 = (np.arange(N) + 1) % N
im1 = (np.arange(N) - 1) % N
# 化学势 mu = c^3 - c - kappa * lap(c)
lap_c = (c[ip1] - 2*c + c[im1]) / dx**2
mu = c**3 - c - kappa * lap_c
# 拉普拉斯 mu
lap_mu = (mu[ip1] - 2*mu + mu[im1]) / dx**2
# 显式更新
c = c + dt * M * lap_mu
return x, c
# 提取生长率:记录振幅随时间变化
def growth_rate(k_mode, N=256, L=100.0, M=1.0, kappa=1.0,
dt=1e-4, nsteps=5000, amp=0.01):
dx = L / N
x = np.arange(N) * dx
c = amp * np.cos(2 * np.pi * k_mode * x / L)
amps = []
times = []
for n in range(nsteps):
ip1 = (np.arange(N) + 1) % N
im1 = (np.arange(N) - 1) % N
lap_c = (c[ip1] - 2*c + c[im1]) / dx**2
mu = c**3 - c - kappa * lap_c
lap_mu = (mu[ip1] - 2*mu + mu[im1]) / dx**2
c = c + dt * M * lap_mu
if n % 100 == 0:
# 提取该波数傅里叶分量振幅
ck = np.fft.fft(c)[k_mode] / N
amps.append(2 * abs(ck))
times.append(n * dt)
return np.array(times), np.array(amps)
生长率提取与理论对比
对每个波数 k_mode,取早期线性阶段(振幅仍远小于 1,例如 A < 0.05)的数据,对 ln A(t) 做线性拟合,斜率即为数值生长率 σ_num。理论生长率由 σ_theory = M k²(1 − κk²) 给出,其中 k = 2π k_mode / L。
下表给出一组示例参数下的预期对比(M=1,κ=1,L=100,N=256,dt=1e-4):
| k_mode | k = 2πk_mode/L | σ_theory | σ_num(示例拟合值) | 相对误差 |
|---|---|---|---|---|
| 1 | 0.0628 | 0.00393 | 0.00391 | 0.5% |
| 2 | 0.1257 | 0.0156 | 0.0155 | 0.6% |
| 3 | 0.1885 | 0.0346 | 0.0344 | 0.6% |
| 4 | 0.2513 | 0.0595 | 0.0591 | 0.7% |
| 5 | 0.3142 | 0.0877 | 0.0870 | 0.8% |
| 6 | 0.3770 | 0.116 | 0.115 | 0.9% |
| 7 | 0.4398 | 0.141 | 0.139 | 1.4% |
| 8 | 0.5027 | 0.157 | 0.154 | 1.9% |
| 9 | 0.5655 | 0.158 | 0.154 | 2.5% |
| 10 | 0.6283 | 0.141 | 0.136 | 3.5% |
注意:上表 σ_num 为示例拟合值,用于说明对比方法,实际运行结果会因 dt、N、拟合区间不同而有差异。当 k 接近 k_c = 1/√κ = 1 时,σ 趋近于 0,数值误差相对增大;当 k > k_c 时 σ < 0,扰动衰减,应观察到振幅单调下降。
结果判读与验证
- 对 k < k_c 的扰动,振幅随时间指数增长,ln A(t) 呈直线,斜率 σ_num > 0;
- 对 k > k_c 的扰动,振幅衰减,σ_num < 0;
- σ_num(k) 随 k 先增后减,峰值在 k_max = 1/√(2κ) 附近;
- 将 σ_num 与 σ_theory 画在同一张图上,若两者在 k < 0.8k_c 范围内相对误差小于 5%,说明显式差分格式和生长率提取流程正确。
通过本案例,可以掌握保守序参量四阶方程的显式离散方法、周期边界处理、线性稳定性理论对比以及生长率提取的完整流程,为后续半隐式谱方法和二维旋节线分解打下基础。