主题073:相场法模拟相变

一、引言

相变是自然界和工程领域中广泛存在的物理现象。从水的结冰到金属的凝固,从聚合物的结晶到合金的沉淀,相变过程伴随着潜热的释放或吸收、界面的移动以及复杂的微观结构演化。准确模拟相变过程对于材料科学、能源工程、气候科学等众多领域具有重要意义。

传统的相变模拟方法,如Stefan问题的前追踪法(Front Tracking),需要显式地追踪相界面位置,这在处理复杂界面形貌(如枝晶生长、多晶交汇)时会遇到巨大困难。相场法(Phase Field Method)作为一种基于连续介质理论的界面追踪方法,通过引入一个连续的序参量(相场变量)来描述不同相之间的过渡,避免了显式追踪界面的复杂性,成为模拟相变过程的有力工具。

本主题将系统介绍相场法的基本理论、数学模型和数值方法,重点探讨Allen-Cahn方程和Cahn-Hilliard方程在相变模拟中的应用,并通过Python实例展示如何实现凝固、熔化、晶粒生长等过程的数值模拟。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、相场法基础理论

2.1 相场法的基本概念

2.1.1 什么是相场法

相场法是一种基于热力学原理的界面追踪方法。其核心思想是引入一个连续的相场变量 ϕ(x,t)\phi(\mathbf{x}, t)ϕ(x,t) 来区分不同的相:

  • ϕ=1\phi = 1ϕ=1 表示一相(如固相)
  • ϕ=−1\phi = -1ϕ=1 表示另一相(如液相)
  • −1<ϕ<1-1 < \phi < 11<ϕ<1 表示界面过渡区域

与传统的尖锐界面模型不同,相场法将界面视为具有一定厚度的扩散区域。这种"扩散界面"的近似使得相场法具有以下优势:

  1. 无需显式追踪界面:界面位置由相场变量的等值面隐式定义
  2. 自动处理拓扑变化:界面的合并、断裂等复杂行为可以自然发生
  3. 易于处理复杂几何:可以模拟枝晶、多晶等复杂微观结构
  4. 热力学一致性:基于自由能泛函变分推导,保证物理守恒
2.1.2 自由能泛函

相场法的理论基础是Ginzburg-Landau理论。系统的总自由能泛函可以写为:

F[ϕ,T]=∫Ω[f(ϕ,T)+ϵ22∣∇ϕ∣2]dΩF[\phi, T] = \int_\Omega \left[ f(\phi, T) + \frac{\epsilon^2}{2} |\nabla \phi|^2 \right] d\OmegaF[ϕ,T]=Ω[f(ϕ,T)+2ϵ2∣∇ϕ2]dΩ

其中:

  • f(ϕ,T)f(\phi, T)f(ϕ,T) 是体自由能密度,描述两相的热力学性质
  • ϵ22∣∇ϕ∣2\frac{\epsilon^2}{2} |\nabla \phi|^22ϵ2∣∇ϕ2 是梯度能项,惩罚相场变量的快速变化,控制界面厚度
  • ϵ\epsilonϵ 是界面厚度参数

体自由能密度通常采用双阱势函数形式:

f(ϕ,T)=14(ϕ2−1)2+λg(ϕ)ΔTf(\phi, T) = \frac{1}{4}(\phi^2 - 1)^2 + \lambda g(\phi) \Delta Tf(ϕ,T)=41(ϕ21)2+λg(ϕ)ΔT

其中:

  • 14(ϕ2−1)2\frac{1}{4}(\phi^2 - 1)^241(ϕ21)2 是双阱势,在 ϕ=±1\phi = \pm 1ϕ=±1 处有两个稳定极小值
  • g(ϕ)g(\phi)g(ϕ) 是插值函数,耦合温度场
  • λ\lambdaλ 是耦合系数
  • ΔT=T−Tm\Delta T = T - T_mΔT=TTm 是过冷度,TmT_mTm 是熔点
2.1.3 界面厚度与表面张力

相场模型中的界面厚度 WWW 与参数 ϵ\epsilonϵ 的关系为:

W=22ϵW = 2\sqrt{2}\epsilonW=22 ϵ

界面能(表面张力)σ\sigmaσ 与相场参数的关系为:

σ=223ϵ\sigma = \frac{2\sqrt{2}}{3} \epsilonσ=322 ϵ

在实际计算中,需要选择适当的界面厚度:

  • 界面太厚:无法捕捉界面细节
  • 界面太薄:需要极细网格,计算成本高

通常选择界面厚度远小于特征长度但足以分辨界面结构。

2.2 Allen-Cahn方程

2.2.1 方程推导

Allen-Cahn方程描述非守恒序参量的演化,适用于凝固、熔化等相变过程。它可以从自由能泛函的变分导出:

∂ϕ∂t=−MϕδFδϕ\frac{\partial \phi}{\partial t} = -M_\phi \frac{\delta F}{\delta \phi}tϕ=MϕδϕδF

其中 MϕM_\phiMϕ 是迁移率(mobility),控制相场演化的速率。

计算变分:

δFδϕ=∂f∂ϕ−ϵ2∇2ϕ\frac{\delta F}{\delta \phi} = \frac{\partial f}{\partial \phi} - \epsilon^2 \nabla^2 \phiδϕδF=ϕfϵ22ϕ

对于双阱势 f=14(ϕ2−1)2f = \frac{1}{4}(\phi^2 - 1)^2f=41(ϕ21)2

∂f∂ϕ=ϕ(ϕ2−1)=ϕ3−ϕ\frac{\partial f}{\partial \phi} = \phi(\phi^2 - 1) = \phi^3 - \phiϕf=ϕ(ϕ21)=ϕ3ϕ

因此,Allen-Cahn方程为:

∂ϕ∂t=Mϕ(ϵ2∇2ϕ−ϕ3+ϕ)\frac{\partial \phi}{\partial t} = M_\phi \left( \epsilon^2 \nabla^2 \phi - \phi^3 + \phi \right)tϕ=Mϕ(ϵ22ϕϕ3+ϕ)

2.2.2 物理意义

Allen-Cahn方程可以重写为:

∂ϕ∂t=Mϕ(ϵ2∇2ϕ−f′(ϕ))\frac{\partial \phi}{\partial t} = M_\phi \left( \epsilon^2 \nabla^2 \phi - f'(\phi) \right)tϕ=Mϕ(ϵ22ϕf(ϕ))

其中:

  • ϵ2∇2ϕ\epsilon^2 \nabla^2 \phiϵ22ϕ 是扩散项,使界面平滑
  • −f′(ϕ)=ϕ−ϕ3-f'(\phi) = \phi - \phi^3f(ϕ)=ϕϕ3 是反应项,驱使系统趋向双阱势的极小值

方程的稳态解(一维情况)为:

ϕ(x)=tanh⁡(x2ϵ)\phi(x) = \tanh\left(\frac{x}{\sqrt{2}\epsilon}\right)ϕ(x)=tanh(2 ϵx)

这是一个光滑的界面轮廓,从 ϕ=−1\phi = -1ϕ=1 过渡到 ϕ=1\phi = 1ϕ=1,界面中心位于 x=0x = 0x=0

2.2.3 与温度的耦合

在凝固问题中,需要将相场方程与温度场耦合。温度场方程为:

∂T∂t=α∇2T+Lcp∂ϕ∂t\frac{\partial T}{\partial t} = \alpha \nabla^2 T + \frac{L}{c_p} \frac{\partial \phi}{\partial t}tT=α2T+cpLtϕ

其中:

  • α\alphaα 是热扩散系数
  • LLL 是潜热
  • cpc_pcp 是比热容
  • Lcp∂ϕ∂t\frac{L}{c_p} \frac{\partial \phi}{\partial t}cpLtϕ 是相变热源项

相场方程也需要包含温度驱动项:

∂ϕ∂t=Mϕ(ϵ2∇2ϕ−ϕ3+ϕ)+Mϕλ(T−Tm)g′(ϕ)\frac{\partial \phi}{\partial t} = M_\phi \left( \epsilon^2 \nabla^2 \phi - \phi^3 + \phi \right) + M_\phi \lambda (T - T_m) g'(\phi)tϕ=Mϕ(ϵ22ϕϕ3+ϕ)+Mϕλ(TTm)g(ϕ)

其中 g(ϕ)=ϕ−ϕ33g(\phi) = \phi - \frac{\phi^3}{3}g(ϕ)=ϕ3ϕ3 是插值函数。

2.3 Cahn-Hilliard方程

2.3.1 守恒型相场方程

Cahn-Hilliard方程描述守恒序参量的演化,适用于成分分离、晶粒粗化等过程。它保证序参量的总量守恒:

∂ϕ∂t=∇⋅(M∇δFδϕ)\frac{\partial \phi}{\partial t} = \nabla \cdot \left( M \nabla \frac{\delta F}{\delta \phi} \right)tϕ=(MδϕδF)

展开后得到:

∂ϕ∂t=∇⋅(M∇(f′(ϕ)−ϵ2∇2ϕ))\frac{\partial \phi}{\partial t} = \nabla \cdot \left( M \nabla (f'(\phi) - \epsilon^2 \nabla^2 \phi) \right)tϕ=(M(f(ϕ)ϵ22ϕ))

或写成:

∂ϕ∂t=M(f′′(ϕ)∇2ϕ−ϵ2∇4ϕ)\frac{\partial \phi}{\partial t} = M \left( f''(\phi) \nabla^2 \phi - \epsilon^2 \nabla^4 \phi \right)tϕ=M(f′′(ϕ)2ϕϵ24ϕ)

2.3.2 与Allen-Cahn方程的区别
特征 Allen-Cahn方程 Cahn-Hilliard方程
守恒性 非守恒 守恒
方程阶数 二阶 四阶
主要应用 凝固/熔化 相分离/晶粒粗化
界面速度 与曲率无关 与曲率相关
数值稳定性 较易处理 需要特殊处理
2.3.3 应用实例

旋节分解(Spinodal Decomposition)
当二元合金从高温淬火到混溶隙以下时,会发生成分分离。Cahn-Hilliard方程可以描述这种自发的相分离过程。

晶粒粗化(Grain Coarsening)
多晶材料中,大晶粒会吞噬小晶粒以降低总界面能。使用多序参量相场模型可以模拟这一过程。

2.4 各向异性与枝晶生长

2.4.1 界面能各向异性

实际晶体材料的界面能通常具有各向异性。在相场模型中,可以通过使界面厚度参数 ϵ\epsilonϵ 或迁移率 MMM 依赖于界面法向方向来引入各向异性。

界面法向量为:

n=−∇ϕ∣∇ϕ∣\mathbf{n} = -\frac{\nabla \phi}{|\nabla \phi|}n=∣∇ϕϕ

对于二维四重对称的枝晶生长,界面能可以表示为:

ϵ(θ)=ϵ0(1+δ4cos⁡(4θ))\epsilon(\theta) = \epsilon_0 (1 + \delta_4 \cos(4\theta))ϵ(θ)=ϵ0(1+δ4cos(4θ))

其中 θ\thetaθ 是界面法向与晶体学方向的夹角,δ4\delta_4δ4 是各向异性强度。

2.4.2 枝晶生长模型

枝晶生长是凝固过程中常见的现象。相场法可以自然地模拟枝晶的形成和演化:

  1. 噪声引入:在相场方程中添加热噪声项,触发界面失稳
  2. 各向异性驱动:界面能各向异性导致优先生长方向
  3. 热扩散限制:潜热释放改变局部温度场,反馈影响生长

枝晶生长的相场方程:

τ∂ϕ∂t=W2∇2ϕ+ϕ(1−ϕ)(ϕ−12+m(T))+各向异性项+噪声项\tau \frac{\partial \phi}{\partial t} = W^2 \nabla^2 \phi + \phi(1-\phi)\left(\phi - \frac{1}{2} + m(T)\right) + \text{各向异性项} + \text{噪声项}τtϕ=W22ϕ+ϕ(1ϕ)(ϕ21+m(T))+各向异性项+噪声项

其中 m(T)m(T)m(T) 是过冷度函数。

三、相场法数值方法

3.1 空间离散方法

3.1.1 有限差分法

有限差分法是相场法最常用的空间离散方法。对于二维问题,使用均匀网格 (i,j)(i, j)(i,j),空间步长为 Δx\Delta xΔx

拉普拉斯算子(五点格式):

∇2ϕi,j=ϕi+1,j+ϕi−1,j+ϕi,j+1+ϕi,j−1−4ϕi,jΔx2\nabla^2 \phi_{i,j} = \frac{\phi_{i+1,j} + \phi_{i-1,j} + \phi_{i,j+1} + \phi_{i,j-1} - 4\phi_{i,j}}{\Delta x^2}2ϕi,j=Δx2ϕi+1,j+ϕi1,j+ϕi,j+1+ϕi,j14ϕi,j

双调和算子(Cahn-Hilliard方程需要):

∇4ϕi,j=∇2ϕi+1,j+∇2ϕi−1,j+∇2ϕi,j+1+∇2ϕi,j−1−4∇2ϕi,jΔx2\nabla^4 \phi_{i,j} = \frac{\nabla^2 \phi_{i+1,j} + \nabla^2 \phi_{i-1,j} + \nabla^2 \phi_{i,j+1} + \nabla^2 \phi_{i,j-1} - 4\nabla^2 \phi_{i,j}}{\Delta x^2}4ϕi,j=Δx22ϕi+1,j+2ϕi1,j+2ϕi,j+1+2ϕi,j142ϕi,j

3.1.2 谱方法

对于周期性边界条件的问题,谱方法(特别是傅里叶谱方法)具有高精度优势。

在傅里叶空间,微分算子变为代数运算:

F(∇2ϕ)=−∣k∣2ϕ^\mathcal{F}(\nabla^2 \phi) = -|\mathbf{k}|^2 \hat{\phi}F(2ϕ)=k2ϕ^

其中 k\mathbf{k}k 是波矢量,ϕ^\hat{\phi}ϕ^ 是傅里叶变换。

Cahn-Hilliard方程在傅里叶空间的半隐式格式:

ϕ^n+1−ϕ^nΔt=−M∣k∣2(f′(ϕ^n)+ϵ2∣k∣2ϕ^n+1)\frac{\hat{\phi}^{n+1} - \hat{\phi}^n}{\Delta t} = -M |\mathbf{k}|^2 \left( f'(\hat{\phi}^n) + \epsilon^2 |\mathbf{k}|^2 \hat{\phi}^{n+1} \right)Δtϕ^n+1ϕ^n=Mk2(f(ϕ^n)+ϵ2k2ϕ^n+1)

3.2 时间积分方法

3.2.1 显式欧拉法

最简单的显式格式:

ϕn+1=ϕn+Δt⋅RHS(ϕn)\phi^{n+1} = \phi^n + \Delta t \cdot \text{RHS}(\phi^n)ϕn+1=ϕn+ΔtRHS(ϕn)

稳定性限制

  • Allen-Cahn方程:Δt<CΔx2ϵ2\Delta t < C \frac{\Delta x^2}{\epsilon^2}Δt<Cϵ2Δx2
  • Cahn-Hilliard方程:Δt<CΔx4ϵ2\Delta t < C \frac{\Delta x^4}{\epsilon^2}Δt<Cϵ2Δx4

Cahn-Hilliard方程的时间步长限制非常严格,通常需要隐式或半隐式方法。

3.2.2 半隐式格式

为了提高稳定性,可以将线性项隐式处理,非线性项显式处理。

Allen-Cahn方程的半隐式格式

ϕn+1−ϕnΔt=Mϕ(ϵ2∇2ϕn+1−(ϕn)3+ϕn)\frac{\phi^{n+1} - \phi^n}{\Delta t} = M_\phi \left( \epsilon^2 \nabla^2 \phi^{n+1} - (\phi^n)^3 + \phi^n \right)Δtϕn+1ϕn=Mϕ(ϵ22ϕn+1(ϕn)3+ϕn)

这可以重写为:

(1−Mϕϵ2Δt∇2)ϕn+1=ϕn+MϕΔt(−(ϕn)3+ϕn)(1 - M_\phi \epsilon^2 \Delta t \nabla^2) \phi^{n+1} = \phi^n + M_\phi \Delta t \left( - (\phi^n)^3 + \phi^n \right)(1Mϕϵ2Δt2)ϕn+1=ϕn+MϕΔt((ϕn)3+ϕn)

左边形成Helmholtz方程,可以用快速算法求解。

3.2.3 自适应时间步长

相变过程中,界面运动速度会随时间变化。自适应时间步长可以提高计算效率:

Δtn+1=min⁡(Δtmax⁡,ϵmax⁡∣∂ϕ/∂t∣)\Delta t_{n+1} = \min\left( \Delta t_{\max}, \frac{\epsilon}{\max|\partial \phi / \partial t|} \right)Δtn+1=min(Δtmax,maxϕ/tϵ)

3.3 边界条件处理

3.3.1 绝热边界

对于绝热边界,使用Neumann边界条件:

∂ϕ∂n=0,∂T∂n=0\frac{\partial \phi}{\partial n} = 0, \quad \frac{\partial T}{\partial n} = 0nϕ=0,nT=0

在有限差分中,使用镜像法:

ϕ−1,j=ϕ1,j,ϕN+1,j=ϕN−1,j\phi_{-1,j} = \phi_{1,j}, \quad \phi_{N+1,j} = \phi_{N-1,j}ϕ1,j=ϕ1,j,ϕN+1,j=ϕN1,j

3.3.2 周期性边界

周期性边界条件:

ϕ(0,y)=ϕ(L,y),ϕ(x,0)=ϕ(x,L)\phi(0, y) = \phi(L, y), \quad \phi(x, 0) = \phi(x, L)ϕ(0,y)=ϕ(L,y),ϕ(x,0)=ϕ(x,L)

适合模拟无限大系统或周期性结构。

3.3.3 固定温度边界

Dirichlet边界条件:

T=TwallT = T_{wall}T=Twall

直接设置边界格点的温度值。

四、Python仿真实例

4.1 案例1:一维相界面演化

本案例模拟一维情况下相界面的平衡轮廓和弛豫过程。

"""
案例1:一维相界面演化
模拟相场变量的平衡轮廓和弛豫过程
"""
import numpy as np
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
Nx = 200  # 网格数
L = 10.0  # 计算域长度
dx = L / Nx  # 空间步长
epsilon = 0.5  # 界面厚度参数
M_phi = 1.0  # 迁移率
dt = 0.001  # 时间步长
Nt = 5000  # 时间步数

# 创建网格
x = np.linspace(-L/2, L/2, Nx)

# 初始条件:阶梯函数
phi = np.ones(Nx)
phi[x < 0] = -1

# 添加小扰动
phi += 0.1 * np.random.randn(Nx) * (np.abs(x) < 2)

# 存储结果
phi_history = [phi.copy()]
t_history = [0]

# 时间推进
for n in range(Nt):
    # 计算拉普拉斯算子(中心差分)
    laplacian = np.zeros_like(phi)
    laplacian[1:-1] = (phi[2:] - 2*phi[1:-1] + phi[:-2]) / dx**2
    laplacian[0] = laplacian[1]  # Neumann边界
    laplacian[-1] = laplacian[-2]
    
    # Allen-Cahn方程
    dphi_dt = M_phi * (epsilon**2 * laplacian - phi**3 + phi)
    phi = phi + dt * dphi_dt
    
    # 保存结果
    if n % 500 == 0:
        phi_history.append(phi.copy())
        t_history.append((n+1) * dt)

# 理论平衡解
phi_theory = np.tanh(x / (np.sqrt(2) * epsilon))

# 绘制结果
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 图1:相场演化
ax = axes[0]
for i, (phi_snap, t) in enumerate(zip(phi_history[::2], t_history[::2])):
    ax.plot(x, phi_snap, label=f't={t:.1f}')
ax.plot(x, phi_theory, 'k--', linewidth=2, label='理论平衡解')
ax.set_xlabel('位置 x')
ax.set_ylabel('相场变量 φ')
ax.set_title('相界面弛豫过程')
ax.legend()
ax.grid(True)
ax.set_ylim(-1.2, 1.2)

# 图2:自由能演化
def free_energy(phi, dx, epsilon):
    """计算自由能"""
    # 梯度能
    grad_phi = np.gradient(phi, dx)
    E_grad = 0.5 * epsilon**2 * np.sum(grad_phi**2) * dx
    
    # 体自由能
    E_bulk = np.sum(0.25 * (phi**2 - 1)**2) * dx
    
    return E_grad + E_bulk

E_history = [free_energy(phi, dx, epsilon) for phi in phi_history]
ax = axes[1]
ax.plot(t_history, E_history, 'b-', linewidth=2)
ax.set_xlabel('时间 t')
ax.set_ylabel('自由能 F')
ax.set_title('自由能随时间演化')
ax.grid(True)

plt.tight_layout()
plt.savefig('d:\\文档\\500仿真领域\\工程仿真\\对流换热仿真\\主题073_相场法模拟相变\\仿真结果\\case1_1d_interface.png', dpi=150)
plt.close()

print("案例1完成!")

4.2 案例2:二维凝固过程

本案例模拟二维空间中的凝固过程,展示平面界面的失稳和胞状结构的形成。

"""
案例2:二维凝固过程
模拟过冷熔体中的凝固过程
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
Nx, Ny = 150, 150  # 网格数
Lx, Ly = 30.0, 30.0  # 计算域尺寸
dx = Lx / Nx  # 空间步长

# 相场参数
epsilon = 0.5  # 界面厚度
M_phi = 1.0  # 相场迁移率
tau = 1.0  # 弛豫时间

# 热力学参数
alpha = 1.0  # 热扩散系数
Tm = 1.0  # 熔点
L_latent = 1.0  # 潜热
cp = 1.0  # 比热容

# 过冷度
T_undercool = 0.55  # 初始过冷度

# 创建网格
x = np.linspace(0, Lx, Nx)
y = np.linspace(0, Ly, Ny)
X, Y = np.meshgrid(x, y)

# 初始化
# 底部为固相,顶部为液相
phi = -np.tanh((Y - 5) / (np.sqrt(2) * epsilon))
T = np.ones((Ny, Nx)) * (Tm - T_undercool)  # 初始均匀过冷

# 在界面附近添加噪声触发失稳
noise_region = np.abs(Y - 5) < 3 * epsilon
phi[noise_region] += 0.1 * np.random.randn(np.sum(noise_region))

# 时间参数
dt = 0.005
Nt = 3000
save_interval = 300

# 存储结果
phi_history = [phi.copy()]
T_history = [T.copy()]

print("开始计算二维凝固过程...")

# 时间推进
for n in range(Nt):
    # 计算相场拉普拉斯
    laplacian_phi = np.zeros_like(phi)
    laplacian_phi[1:-1, 1:-1] = (
        phi[2:, 1:-1] + phi[:-2, 1:-1] + phi[1:-1, 2:] + phi[1:-1, :-2] - 4*phi[1:-1, 1:-1]
    ) / dx**2
    
    # 计算温度拉普拉斯
    laplacian_T = np.zeros_like(T)
    laplacian_T[1:-1, 1:-1] = (
        T[2:, 1:-1] + T[:-2, 1:-1] + T[1:-1, 2:] + T[1:-1, :-2] - 4*T[1:-1, 1:-1]
    ) / dx**2
    
    # 相场方程(简化模型)
    m_T = (Tm - T) / T_undercool  # 过冷度驱动项
    dphi_dt = (laplacian_phi + phi * (1 - phi) * (phi - 0.5 + m_T)) / tau
    
    # 温度方程
    dT_dt = alpha * laplacian_T + L_latent / cp * dphi_dt
    
    # 更新
    phi = phi + dt * dphi_dt
    T = T + dt * dT_dt
    
    # 边界条件
    phi[0, :] = 1  # 底部固相
    phi[-1, :] = -1  # 顶部液相
    T[0, :] = Tm  # 底部恒温
    
    # 保存结果
    if n % save_interval == 0:
        phi_history.append(phi.copy())
        T_history.append(T.copy())
        print(f"时间步 {n}/{Nt}, 固相分数: {np.sum(phi > 0) / (Nx*Ny):.3f}")

# 绘制结果
fig, axes = plt.subplots(2, 2, figsize=(14, 12))

# 图1:最终相场分布
ax = axes[0, 0]
im1 = ax.contourf(X, Y, phi_history[-1], levels=20, cmap='RdYlBu_r', vmin=-1, vmax=1)
plt.colorbar(im1, ax=ax, label='相场变量 φ')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('最终相场分布')
ax.set_aspect('equal')

# 图2:最终温度分布
ax = axes[0, 1]
im2 = ax.contourf(X, Y, T_history[-1], levels=20, cmap='hot')
plt.colorbar(im2, ax=ax, label='温度 T')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('最终温度分布')
ax.set_aspect('equal')

# 图3:相场演化过程
ax = axes[1, 0]
for i, phi_snap in enumerate(phi_history[::2]):
    ax.contour(X, Y, phi_snap, levels=[0], colors=[plt.cm.viridis(i/len(phi_history[::2]))], linewidths=2)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('界面演化过程')
ax.set_aspect('equal')

# 图4:固相分数演化
ax = axes[1, 1]
solid_fraction = [np.sum(phi > 0) / (Nx*Ny) for phi in phi_history]
times = np.arange(len(solid_fraction)) * save_interval * dt
ax.plot(times, solid_fraction, 'b-', linewidth=2)
ax.set_xlabel('时间 t')
ax.set_ylabel('固相分数')
ax.set_title('凝固进程')
ax.grid(True)

plt.tight_layout()
plt.savefig('d:\\文档\\500仿真领域\\工程仿真\\对流换热仿真\\主题073_相场法模拟相变\\仿真结果\\case2_2d_solidification.png', dpi=150)
plt.close()

print("案例2完成!")

4.3 案例3:枝晶生长模拟

本案例模拟各向异性条件下的枝晶生长,展示典型的枝晶形貌。

"""
案例3:枝晶生长模拟
模拟各向异性条件下的枝晶生长
"""
import numpy as np
import matplotlib.pyplot as plt

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
Nx, Ny = 200, 200  # 网格数
L = 40.0  # 计算域尺寸
dx = L / Nx

# 相场参数
epsilon_0 = 0.3  # 基准界面厚度
delta_4 = 0.05  # 四重各向异性强度
tau = 0.3  # 弛豫时间

# 热力学参数
alpha = 2.0  # 热扩散系数
Tm = 1.0  # 熔点
L_latent = 2.0  # 潜热
cp = 1.0  # 比热容

# 过冷度
T_undercool = 0.55

# 创建网格
x = np.linspace(-L/2, L/2, Nx)
y = np.linspace(-L/2, L/2, Ny)
X, Y = np.meshgrid(x, y)

# 初始化:中心为固相晶核
r = np.sqrt(X**2 + Y**2)
phi = -np.tanh((r - 2) / (np.sqrt(2) * epsilon_0))
T = np.ones((Ny, Nx)) * (Tm - T_undercool)

# 时间参数
dt = 0.01
Nt = 4000
save_interval = 400

# 存储结果
phi_history = [phi.copy()]

print("开始计算枝晶生长...")

# 时间推进
for n in range(Nt):
    # 计算梯度
    grad_phi_x = np.zeros_like(phi)
    grad_phi_y = np.zeros_like(phi)
    grad_phi_x[1:-1, :] = (phi[2:, :] - phi[:-2, :]) / (2*dx)
    grad_phi_y[:, 1:-1] = (phi[:, 2:] - phi[:, :-2]) / (2*dx)
    
    # 计算界面法向和角度
    grad_mag = np.sqrt(grad_phi_x**2 + grad_phi_y**2)
    theta = np.arctan2(grad_phi_y, grad_phi_x)
    
    # 各向异性界面厚度
    epsilon = epsilon_0 * (1 + delta_4 * np.cos(4 * theta))
    
    # 计算拉普拉斯
    laplacian_phi = np.zeros_like(phi)
    laplacian_phi[1:-1, 1:-1] = (
        phi[2:, 1:-1] + phi[:-2, 1:-1] + phi[1:-1, 2:] + phi[1:-1, :-2] - 4*phi[1:-1, 1:-1]
    ) / dx**2
    
    laplacian_T = np.zeros_like(T)
    laplacian_T[1:-1, 1:-1] = (
        T[2:, 1:-1] + T[:-2, 1:-1] + T[1:-1, 2:] + T[1:-1, :-2] - 4*T[1:-1, 1:-1]
    ) / dx**2
    
    # 相场方程(含各向异性)
    m_T = (Tm - T) / T_undercool
    noise = 0.05 * np.random.randn(Ny, Nx) * (np.abs(phi) < 0.5)
    dphi_dt = (epsilon**2 * laplacian_phi + phi * (1 - phi) * (phi - 0.5 + m_T)) / tau + noise
    
    # 温度方程
    dT_dt = alpha * laplacian_T + L_latent / cp * dphi_dt
    
    # 更新
    phi = phi + dt * dphi_dt
    T = T + dt * dT_dt
    
    # 边界条件
    phi[0, :] = phi[1, :]
    phi[-1, :] = phi[-2, :]
    phi[:, 0] = phi[:, 1]
    phi[:, -1] = phi[:, -2]
    
    # 保存结果
    if n % save_interval == 0:
        phi_history.append(phi.copy())
        tip_position = np.max(np.sqrt(X[phi > 0.5]**2 + Y[phi > 0.5]**2)) if np.sum(phi > 0.5) > 0 else 0
        print(f"时间步 {n}/{Nt}, 枝晶尖端位置: {tip_position:.2f}")

# 绘制结果
fig, axes = plt.subplots(2, 2, figsize=(14, 12))

# 图1:最终相场分布
ax = axes[0, 0]
im1 = ax.contourf(X, Y, phi_history[-1], levels=20, cmap='RdYlBu_r', vmin=-1, vmax=1)
plt.colorbar(im1, ax=ax, label='相场变量 φ')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('枝晶形貌')
ax.set_aspect('equal')

# 图2:温度场
ax = axes[0, 1]
im2 = ax.contourf(X, Y, T, levels=20, cmap='hot')
plt.colorbar(im2, ax=ax, label='温度 T')
ax.contour(X, Y, phi_history[-1], levels=[0], colors='white', linewidths=1)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('温度场与界面')
ax.set_aspect('equal')

# 图3:界面演化
ax = axes[1, 0]
colors = plt.cm.viridis(np.linspace(0, 1, len(phi_history)))
for i, phi_snap in enumerate(phi_history):
    ax.contour(X, Y, phi_snap, levels=[0], colors=[colors[i]], linewidths=1.5)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('枝晶生长过程')
ax.set_aspect('equal')

# 图4:各向异性函数
ax = axes[1, 1]
theta_plot = np.linspace(0, 2*np.pi, 100)
epsilon_plot = epsilon_0 * (1 + delta_4 * np.cos(4 * theta_plot))
r_plot = epsilon_plot / epsilon_0
ax.plot(theta_plot * 180 / np.pi, r_plot, 'b-', linewidth=2)
ax.axhline(y=1, color='r', linestyle='--', label='各向同性')
ax.set_xlabel('角度 θ (度)')
ax.set_ylabel('ε(θ)/ε₀')
ax.set_title('界面能各向异性')
ax.legend()
ax.grid(True)

plt.tight_layout()
plt.savefig('d:\\文档\\500仿真领域\工程仿真\对流换热仿真\主题073_相场法模拟相变\仿真结果\case3_dendrite_growth.png', dpi=150)
plt.close()

print("案例3完成!")

4.4 案例4:Cahn-Hilliard相分离

本案例使用Cahn-Hilliard方程模拟二元合金的旋节分解过程。

"""
案例4:Cahn-Hilliard相分离
模拟二元合金的旋节分解
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft2, ifft2, fftfreq

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
Nx, Ny = 128, 128  # 网格数
L = 2 * np.pi  # 计算域尺寸
dx = L / Nx

# Cahn-Hilliard参数
epsilon = 0.1  # 界面厚度参数
M = 1.0  # 迁移率

# 创建网格
x = np.linspace(0, L, Nx)
y = np.linspace(0, L, Ny)
X, Y = np.meshgrid(x, y)

# 波矢量(用于谱方法)
kx = 2 * np.pi * fftfreq(Nx, dx)
ky = 2 * np.pi * fftfreq(Ny, dx)
KX, KY = np.meshgrid(kx, ky)
k_squared = KX**2 + KY**2
k_fourth = k_squared**2

# 初始条件:均匀混合物添加小扰动
c0 = 0.0  # 平均浓度
phi = c0 + 0.1 * np.random.randn(Ny, Nx)

# 时间参数
dt = 0.001
Nt = 10000
save_interval = 1000

# 存储结果
phi_history = [phi.copy()]

print("开始计算Cahn-Hilliard相分离...")

# 时间推进(谱方法半隐式格式)
for n in range(Nt):
    # 傅里叶变换
    phi_hat = fft2(phi)
    
    # 计算化学势的导数 f'(phi) = phi^3 - phi
    f_prime = phi**3 - phi
    f_prime_hat = fft2(f_prime)
    
    # 半隐式更新(傅里叶空间)
    # phi^{n+1} = (phi^n - dt * M * k^2 * f'^n) / (1 + dt * M * epsilon^2 * k^4)
    phi_hat_new = (phi_hat - dt * M * k_squared * f_prime_hat) / (1 + dt * M * epsilon**2 * k_fourth)
    
    # 反变换回物理空间
    phi = np.real(ifft2(phi_hat_new))
    
    # 保存结果
    if n % save_interval == 0:
        phi_history.append(phi.copy())
        print(f"时间步 {n}/{Nt}, 浓度范围: [{np.min(phi):.3f}, {np.max(phi):.3f}]")

# 绘制结果
fig, axes = plt.subplots(2, 2, figsize=(14, 12))

# 图1:初始状态
ax = axes[0, 0]
im1 = ax.contourf(X, Y, phi_history[0], levels=20, cmap='RdYlBu_r')
plt.colorbar(im1, ax=ax, label='浓度 c')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('初始状态')
ax.set_aspect('equal')

# 图2:中间状态
ax = axes[0, 1]
im2 = ax.contourf(X, Y, phi_history[len(phi_history)//2], levels=20, cmap='RdYlBu_r')
plt.colorbar(im2, ax=ax, label='浓度 c')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('中间状态')
ax.set_aspect('equal')

# 图3:最终状态
ax = axes[1, 0]
im3 = ax.contourf(X, Y, phi_history[-1], levels=20, cmap='RdYlBu_r')
plt.colorbar(im3, ax=ax, label='浓度 c')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('最终状态')
ax.set_aspect('equal')

# 图4:浓度分布直方图演化
ax = axes[1, 1]
for i, phi_snap in enumerate([phi_history[0], phi_history[len(phi_history)//2], phi_history[-1]]):
    ax.hist(phi_snap.flatten(), bins=30, alpha=0.5, label=f't={i*save_interval*dt*len(phi_history)//2:.1f}')
ax.set_xlabel('浓度 c')
ax.set_ylabel('频率')
ax.set_title('浓度分布演化')
ax.legend()

plt.tight_layout()
plt.savefig('d:\\文档\\500仿真领域\\工程仿真\\对流换热仿真\\主题073_相场法模拟相变\\仿真结果\\case4_cahn_hilliard.png', dpi=150)
plt.close()

print("案例4完成!")

4.5 案例5:熔化过程GIF动画

本案例创建一个熔化过程的GIF动画,展示固相在加热条件下的熔化过程。

"""
案例5:熔化过程GIF动画
模拟固相在加热条件下的熔化过程
"""
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 参数设置
Nx, Ny = 120, 120
L = 20.0
dx = L / Nx

# 相场参数
epsilon = 0.4
M_phi = 1.0
tau = 0.5

# 热力学参数
alpha = 1.5
Tm = 1.0
L_latent = 1.5
cp = 1.0

# 创建网格
x = np.linspace(0, L, Nx)
y = np.linspace(0, L, Ny)
X, Y = np.meshgrid(x, y)

# 初始化:中心为方形固相
phi = -np.ones((Ny, Nx))
solid_mask = (np.abs(X - L/2) < 4) & (np.abs(Y - L/2) < 4)
phi[solid_mask] = 1
phi = np.tanh(phi / (np.sqrt(2) * epsilon))

# 初始温度(略高于熔点,开始熔化)
T = np.ones((Ny, Nx)) * (Tm + 0.1)

# 边界加热
T[0, :] = Tm + 0.5  # 底部加热
T[-1, :] = Tm + 0.5  # 顶部加热
T[:, 0] = Tm + 0.5  # 左侧加热
T[:, -1] = Tm + 0.5  # 右侧加热

# 时间参数
dt = 0.005
Nt = 2000
save_interval = 100

# 存储帧
frames = []

print("生成熔化过程动画...")

# 时间推进
for n in range(Nt):
    # 计算拉普拉斯
    laplacian_phi = np.zeros_like(phi)
    laplacian_phi[1:-1, 1:-1] = (
        phi[2:, 1:-1] + phi[:-2, 1:-1] + phi[1:-1, 2:] + phi[1:-1, :-2] - 4*phi[1:-1, 1:-1]
    ) / dx**2
    
    laplacian_T = np.zeros_like(T)
    laplacian_T[1:-1, 1:-1] = (
        T[2:, 1:-1] + T[:-2, 1:-1] + T[1:-1, 2:] + T[1:-1, :-2] - 4*T[1:-1, 1:-1]
    ) / dx**2
    
    # 相场方程
    m_T = (Tm - T) / 0.5  # 过热驱动熔化
    dphi_dt = (epsilon**2 * laplacian_phi + phi * (1 - phi) * (phi - 0.5 + m_T)) / tau
    
    # 温度方程
    dT_dt = alpha * laplacian_T + L_latent / cp * dphi_dt
    
    # 更新
    phi = phi + dt * dphi_dt
    T = T + dt * dT_dt
    
    # 保持边界温度
    T[0, :] = Tm + 0.5
    T[-1, :] = Tm + 0.5
    T[:, 0] = Tm + 0.5
    T[:, -1] = Tm + 0.5
    
    # 保存帧
    if n % save_interval == 0:
        fig, axes = plt.subplots(1, 2, figsize=(12, 5))
        
        # 相场
        ax = axes[0]
        im1 = ax.contourf(X, Y, phi, levels=20, cmap='RdYlBu_r', vmin=-1, vmax=1)
        plt.colorbar(im1, ax=ax, label='相场变量 φ')
        ax.contour(X, Y, phi, levels=[0], colors='black', linewidths=1)
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_title(f'熔化过程 (t={n*dt:.1f})')
        ax.set_aspect('equal')
        
        # 温度
        ax = axes[1]
        im2 = ax.contourf(X, Y, T, levels=20, cmap='hot')
        plt.colorbar(im2, ax=ax, label='温度 T')
        ax.contour(X, Y, phi, levels=[0], colors='white', linewidths=1)
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_title('温度场')
        ax.set_aspect('equal')
        
        plt.tight_layout()
        
        # 转换为图像
        buf = io.BytesIO()
        fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
        buf.seek(0)
        frames.append(Image.open(buf))
        plt.close()
        
        solid_fraction = np.sum(phi > 0) / (Nx*Ny)
        print(f"帧 {n//save_interval + 1}/{(Nt//save_interval)}, 固相分数: {solid_fraction:.3f}")

# 保存GIF
print("保存GIF动画...")
frames[0].save('d:\\文档\\500仿真领域\\工程仿真\\对流换热仿真\\主题073_相场法模拟相变\\仿真结果\\case5_melting.gif',
               save_all=True, append_images=frames[1:], duration=100, loop=0)

print("案例5完成!")
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐