传热学仿真-主题082-凝固与熔化过程模拟
第八十二篇:凝固与熔化过程模拟
摘要
凝固与熔化过程是材料加工、冶金工业、食品冷冻等领域的核心工艺过程,涉及复杂的相变传热、界面移动和微观结构演化。本教程系统介绍凝固与熔化过程的物理机制,讨论移动边界问题的数学描述和数值求解方法。通过Python实现凝固过程的数值模拟,包括显式追踪法、水平集方法和相场模型。本教程涵盖斯蒂芬条件、移动网格技术、潜热释放等核心内容。通过本教程的学习,读者将掌握凝固与熔化过程的建模方法,能够进行铸造、焊接、晶体生长等过程的仿真分析。
关键词
凝固过程,熔化过程,移动边界,斯蒂芬条件,水平集方法,相场模型,数值模拟

1. 凝固与熔化基础
1.1 物理机制
凝固是液态转变为固态的过程,熔化则相反。这两个过程涉及:
- 热量传递(导热、对流)
- 质量传递(溶质再分配)
- 界面动力学(形核与生长)
1.2 斯蒂芬条件
相变界面的能量守恒条件:
ρLdsdt=ks∂T∂n∣s−kl∂T∂n∣l\rho L \frac{ds}{dt} = k_s \frac{\partial T}{\partial n}\bigg|_s - k_l \frac{\partial T}{\partial n}\bigg|_lρLdtds=ks∂n∂T s−kl∂n∂T l
其中:
- ρ\rhoρ:密度
- LLL:相变潜热
- sss:界面位置
- ks,klk_s, k_lks,kl:固液相导热系数
1.3 凝固模式
平面凝固:
TL−TSG/R<mLC0(1−k0)DLk0\frac{T_L - T_S}{G/R} < \frac{m_L C_0 (1-k_0)}{D_L k_0}G/RTL−TS<DLk0mLC0(1−k0)
枝晶凝固:
当过冷度足够大时,界面失稳形成枝晶结构。
2. 数值方法
2.1 显式界面追踪法
直接追踪相变界面位置:
sn+1=sn+Δt⋅1ρL(ks∂T∂x∣s−kl∂T∂x∣l)s^{n+1} = s^n + \Delta t \cdot \frac{1}{\rho L}\left(k_s \frac{\partial T}{\partial x}\bigg|_s - k_l \frac{\partial T}{\partial x}\bigg|_l\right)sn+1=sn+Δt⋅ρL1(ks∂x∂T s−kl∂x∂T l)
2.2 焓方法
统一处理整个区域:
H={csTT<TmcsTm+fLLT=TmcsTm+L+cl(T−Tm)T>TmH = \begin{cases} c_s T & T < T_m \\ c_s T_m + f_L L & T = T_m \\ c_s T_m + L + c_l (T - T_m) & T > T_m \end{cases}H=⎩ ⎨ ⎧csTcsTm+fLLcsTm+L+cl(T−Tm)T<TmT=TmT>Tm
2.3 相场模型
引入序参量 ϕ\phiϕ 描述相态:
τ∂ϕ∂t=W2∇2ϕ+ϕ−ϕ3+λTm−TTm\tau \frac{\partial \phi}{\partial t} = W^2 \nabla^2 \phi + \phi - \phi^3 + \lambda \frac{T_m - T}{T_m}τ∂t∂ϕ=W2∇2ϕ+ϕ−ϕ3+λTmTm−T
3. Python仿真实现
3.1 一维凝固模拟
"""
主题082:凝固与熔化过程模拟
凝固过程数值模拟
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.sparse import diags
from scipy.sparse.linalg import spsolve
import os
# 创建输出目录
output_dir = r'd:\文档\500仿真领域\工程仿真\传热学仿真\主题082'
os.makedirs(output_dir, exist_ok=True)
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
# 物理参数
rho = 1000 # kg/m³
c_s = 2000 # J/(kg·K)
c_l = 4000 # J/(kg·K)
k_s = 2.0 # W/(m·K)
k_l = 0.6 # W/(m·K)
L_fusion = 334e3 # J/kg
T_m = 273.15 # K
alpha_s = k_s / (rho * c_s)
alpha_l = k_l / (rho * c_l)
def solve_stefan_problem_explicit(L, N, dt, t_end, T_init, T_boundary):
"""
显式追踪法求解斯蒂芬问题
"""
dx = L / (N - 1)
x = np.linspace(0, L, N)
# 初始化
T = np.ones(N) * T_init
interface_pos = L # 初始界面在最右端(全部液态)
# 存储结果
T_history = [T.copy()]
interface_history = [interface_pos]
t_history = [0]
t = 0
while t < t_end and interface_pos > 0:
# 找到界面位置索引
interface_idx = int(interface_pos / dx)
interface_idx = max(1, min(interface_idx, N-2))
# 固相区域(左侧)
T_new = T.copy()
for i in range(1, interface_idx):
Fo_s = alpha_s * dt / dx**2
T_new[i] = T[i] + Fo_s * (T[i+1] - 2*T[i] + T[i-1])
# 液相区域(右侧)
for i in range(interface_idx+1, N-1):
Fo_l = alpha_l * dt / dx**2
T_new[i] = T[i] + Fo_l * (T[i+1] - 2*T[i] + T[i-1])
# 边界条件
T_new[0] = T_boundary
T_new[-1] = T_init
# 界面温度
T_new[interface_idx] = T_m
# 更新界面位置(斯蒂芬条件)
if interface_idx > 1 and interface_idx < N-2:
dTdx_s = (T_new[interface_idx] - T_new[interface_idx-1]) / dx
dTdx_l = (T_new[interface_idx+1] - T_new[interface_idx]) / dx
interface_velocity = (k_s * dTdx_s - k_l * dTdx_l) / (rho * L_fusion)
interface_pos -= interface_velocity * dt
interface_pos = max(0, min(interface_pos, L))
T = T_new
t += dt
# 存储历史
if len(T_history) < 50 and t % (t_end/20) < dt:
T_history.append(T.copy())
interface_history.append(interface_pos)
t_history.append(t)
return x, T_history, interface_history, t_history
def solve_enthalpy_method(L, N, dt, t_end, T_init, T_boundary, delta_T=1.0):
"""
焓方法求解相变问题
"""
dx = L / (N - 1)
x = np.linspace(0, L, N)
def temperature_to_enthalpy(T):
"""温度转焓"""
H = np.zeros_like(T)
H[T < T_m - delta_T] = rho * c_s * T[T < T_m - delta_T]
mask_phase = (T >= T_m - delta_T) & (T <= T_m + delta_T)
H[mask_phase] = rho * c_s * (T_m - delta_T) + \
rho * L_fusion * (T[mask_phase] - (T_m - delta_T)) / (2*delta_T)
H[T > T_m + delta_T] = rho * c_s * (T_m - delta_T) + rho * L_fusion + \
rho * c_l * (T[T > T_m + delta_T] - (T_m + delta_T))
return H
def enthalpy_to_temperature(H):
"""焓转温度"""
T = np.zeros_like(H)
H_solid_max = rho * c_s * (T_m - delta_T)
H_liquid_min = rho * c_s * (T_m - delta_T) + rho * L_fusion
T[H < H_solid_max] = H[H < H_solid_max] / (rho * c_s)
mask_phase = (H >= H_solid_max) & (H <= H_liquid_min)
T[mask_phase] = (T_m - delta_T) + (H[mask_phase] - H_solid_max) / (rho * L_fusion) * 2*delta_T
T[H > H_liquid_min] = (T_m + delta_T) + (H[H > H_liquid_min] - H_liquid_min) / (rho * c_l)
return T
# 初始化
H = temperature_to_enthalpy(np.ones(N) * T_init)
H[0] = temperature_to_enthalpy(np.array([T_boundary]))[0]
T_history = []
t_history = []
t = 0
while t < t_end:
T = enthalpy_to_temperature(H)
# 计算等效热容和导热系数
c_eff = np.ones(N) * c_s
k_eff = np.ones(N) * k_s
mask_liquid = T > T_m
c_eff[mask_liquid] = c_l
k_eff[mask_liquid] = k_l
mask_phase = (T >= T_m - delta_T) & (T <= T_m + delta_T)
c_eff[mask_phase] = (c_s + c_l)/2 + L_fusion/(2*delta_T)
k_eff[mask_phase] = (k_s + k_l)/2
alpha_eff = k_eff / (rho * c_eff)
# 显式更新
H_new = H.copy()
for i in range(1, N-1):
Fo = alpha_eff[i] * dt / dx**2
T_i = T[i]
T_new = T_i + Fo * (T[i+1] - 2*T[i] + T[i-1])
H_new[i] = temperature_to_enthalpy(np.array([T_new]))[0]
H_new[0] = temperature_to_enthalpy(np.array([T_boundary]))[0]
H_new[-1] = temperature_to_enthalpy(np.array([T_init]))[0]
H = H_new
t += dt
if len(T_history) < 50 and t % (t_end/20) < dt:
T_history.append(T.copy())
t_history.append(t)
return x, T_history, t_history
# 1. 凝固过程模拟
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 参数设置
L = 0.05 # m
N = 100
dt = 0.1 # s
t_end = 500 # s
T_init = 280 # K
T_boundary = 250 # K
# 显式追踪法
x, T_history, interface_history, t_history = solve_stefan_problem_explicit(
L, N, dt, t_end, T_init, T_boundary)
# 绘制温度分布
colors = plt.cm.coolwarm(np.linspace(0, 1, len(T_history)))
for i, (T, t) in enumerate(zip(T_history, t_history)):
if i % 5 == 0:
axes[0, 0].plot(x*1000, T-273.15, color=colors[i], linewidth=2,
label=f't={t:.0f}s' if i < 20 else '')
axes[0, 0].axhline(y=0, color='k', linestyle='--', linewidth=1, alpha=0.5)
axes[0, 0].set_xlabel('Position (mm)', fontsize=11)
axes[0, 0].set_ylabel('Temperature (°C)', fontsize=11)
axes[0, 0].set_title('Solidification: Temperature Profiles', fontsize=12)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 界面位置
axes[0, 1].plot(t_history, np.array(interface_history)*1000, 'b-o', linewidth=2, markersize=4)
axes[0, 1].set_xlabel('Time (s)', fontsize=11)
axes[0, 1].set_ylabel('Interface Position (mm)', fontsize=11)
axes[0, 1].set_title('Phase Interface Movement', fontsize=12)
axes[0, 1].grid(True, alpha=0.3)
# 焓方法结果
x_e, T_history_e, t_history_e = solve_enthalpy_method(L, N, dt, t_end, T_init, T_boundary)
colors_e = plt.cm.viridis(np.linspace(0, 1, len(T_history_e)))
for i, (T, t) in enumerate(zip(T_history_e, t_history_e)):
if i % 5 == 0:
axes[1, 0].plot(x_e*1000, T-273.15, color=colors_e[i], linewidth=2)
axes[1, 0].axhline(y=0, color='k', linestyle='--', linewidth=1, alpha=0.5)
axes[1, 0].set_xlabel('Position (mm)', fontsize=11)
axes[1, 0].set_ylabel('Temperature (°C)', fontsize=11)
axes[1, 0].set_title('Enthalpy Method: Temperature Profiles', fontsize=12)
axes[1, 0].grid(True, alpha=0.3)
# 固相分数
solid_fractions = []
for T in T_history_e:
f_solid = np.sum(T < T_m) / len(T)
solid_fractions.append(f_solid)
axes[1, 1].plot(t_history_e, solid_fractions, 'r-', linewidth=2)
axes[1, 1].set_xlabel('Time (s)', fontsize=11)
axes[1, 1].set_ylabel('Solid Fraction', fontsize=11)
axes[1, 1].set_title('Solid Fraction Evolution', fontsize=12)
axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(f'{output_dir}/solidification_simulation.png', dpi=150, bbox_inches='tight')
plt.close()
print("凝固模拟图已保存")
print("\n" + "="*60)
print("仿真3:一维凝固问题解析解验证")
print("="*60)
# 一维半无限大区域凝固问题的解析解
# 材料参数(水/冰)
rho = 1000 # kg/m³
c_l = 4200 # J/(kg·K),液态比热
c_s = 2100 # J/(kg·K),固态比热
k_l = 0.6 # W/(m·K),液态导热系数
k_s = 2.2 # W/(m·K),固态导热系数
L = 334e3 # J/kg,潜热
T_m = 273.15 # K,熔点
# 初始和边界条件
T_initial = 280 # K,初始温度
T_wall = 250 # K,壁面温度
# 热扩散系数
alpha_l = k_l / (rho * c_l)
alpha_s = k_s / (rho * c_s)
# 斯蒂芬数
Ste_l = c_l * (T_initial - T_m) / L
Ste_s = c_s * (T_m - T_wall) / L
print("一维凝固问题解析解:")
print(f"斯蒂芬数(液相): {Ste_l:.4f}")
print(f"斯蒂芬数(固相): {Ste_s:.4f}")
# 求解界面位置参数lambda(使用近似公式)
# 对于小斯蒂芬数,可以使用准稳态近似
lambda_approx = np.sqrt(Ste_s / 2)
# 时间范围
t_max = 3600 # s
x = np.linspace(0, 0.1, 200) # m
# 不同时间点的温度分布
times = [60, 300, 600, 1800, 3600]
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for t in times:
# 界面位置
s = 2 * lambda_approx * np.sqrt(alpha_s * t)
# 温度分布(准稳态近似)
T_dist = np.zeros_like(x)
for i, xi in enumerate(x):
if xi < s:
# 固相区
T_dist[i] = T_wall + (T_m - T_wall) * xi / s if s > 0 else T_wall
else:
# 液相区
T_dist[i] = T_initial
axes[0].plot(x*1000, T_dist-273.15, linewidth=2, label=f't={t}s, s={s*1000:.1f}mm')
axes[0].axhline(y=0, color='k', linestyle='--', linewidth=1, alpha=0.5, label='Melting Point')
axes[0].set_xlabel('Position (mm)', fontsize=11)
axes[0].set_ylabel('Temperature (°C)', fontsize=11)
axes[0].set_title('Analytical Solution: Temperature Distribution', fontsize=12, fontweight='bold')
axes[0].legend(fontsize=9)
axes[0].grid(True, alpha=0.3)
# 界面位置随时间变化
t_range = np.linspace(1, t_max, 100)
s_interface = [2 * lambda_approx * np.sqrt(alpha_s * t) * 1000 for t in t_range] # mm
axes[1].plot(t_range, s_interface, 'b-', linewidth=2)
axes[1].fill_between(t_range, s_interface, alpha=0.3)
axes[1].set_xlabel('Time (s)', fontsize=11)
axes[1].set_ylabel('Interface Position (mm)', fontsize=11)
axes[1].set_title('Solidification Front Position vs Time', fontsize=12, fontweight='bold')
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(f'{output_dir}/analytical_solution.png', dpi=150, bbox_inches='tight')
plt.close()
print("\n图3:一维凝固问题解析解验证已保存")
print("\n" + "="*60)
print("仿真4:多相凝固模拟")
print("="*60)
# 模拟二元合金的凝固过程(考虑溶质再分配)
# 合金参数(简化模型)
C_0 = 0.05 # 初始溶质浓度(质量分数)
m = -2.0 # 液相线斜率(K/质量分数)
k_partition = 0.3 # 平衡分配系数
D_l = 1e-9 # m²/s,液相扩散系数
# 网格参数
Nx = 100
x_alloy = np.linspace(0, 0.05, Nx) # m
dx = x_alloy[1] - x_alloy[0]
# 初始条件
C_liquid = np.ones(Nx) * C_0 # 液相浓度
T_alloy = np.ones(Nx) * T_initial # 温度
# 凝固过程模拟
dt_alloy = 1 # s
Nt_alloy = 500
# 记录数据
C_profile_history = []
T_profile_history = []
interface_position_history = []
time_history_alloy = []
for n in range(Nt_alloy):
t = n * dt_alloy
# 简化:假设界面以恒定速度移动
v_interface = 1e-5 # m/s,界面速度
s_interface_pos = v_interface * t
# 找到界面位置索引
i_interface = int(s_interface_pos / dx) if s_interface_pos < x_alloy[-1] else Nx-1
# 更新浓度场(简化模型)
C_new = C_liquid.copy()
for i in range(1, Nx-1):
if i > i_interface: # 液相区
# 扩散方程
C_new[i] = C_liquid[i] + D_l * dt_alloy / dx**2 * (C_liquid[i+1] - 2*C_liquid[i] + C_liquid[i-1])
else: # 固相区
# 固相浓度(根据分配系数)
if i_interface < Nx:
C_interface = C_liquid[i_interface] if i_interface < len(C_liquid) else C_0
C_new[i] = k_partition * C_interface
else:
C_new[i] = k_partition * C_0
C_liquid = C_new.copy()
# 记录数据
if n % 50 == 0 and i_interface < Nx:
C_profile_history.append(C_liquid.copy())
T_profile_history.append(T_alloy.copy())
interface_position_history.append(s_interface_pos * 1000) # mm
time_history_alloy.append(t)
print("多相凝固模拟:")
print(f"初始浓度: {C_0*100:.2f}%")
print(f"分配系数: {k_partition}")
print(f"液相线斜率: {m} K/分数")
print(f"模拟时间: {Nt_alloy*dt_alloy} s")
print(f"最终界面位置: {interface_position_history[-1]:.2f} mm")
# 可视化
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 浓度分布
colors_alloy = plt.cm.viridis(np.linspace(0, 1, len(C_profile_history)))
for i, C_prof in enumerate(C_profile_history):
axes[0].plot(x_alloy*1000, C_prof*100, color=colors_alloy[i], linewidth=2,
label=f't={time_history_alloy[i]:.0f}s')
axes[0].axhline(y=C_0*100, color='r', linestyle='--', linewidth=1, label='Initial C')
axes[0].set_xlabel('Position (mm)', fontsize=11)
axes[0].set_ylabel('Solute Concentration (%)', fontsize=11)
axes[0].set_title('Solute Distribution During Solidification', fontsize=12, fontweight='bold')
axes[0].legend(fontsize=9)
axes[0].grid(True, alpha=0.3)
# 界面位置
axes[1].plot(time_history_alloy, interface_position_history, 'b-', linewidth=2)
axes[1].fill_between(time_history_alloy, interface_position_history, alpha=0.3)
axes[1].set_xlabel('Time (s)', fontsize=11)
axes[1].set_ylabel('Interface Position (mm)', fontsize=11)
axes[1].set_title('Solidification Front Evolution', fontsize=12, fontweight='bold')
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(f'{output_dir}/alloy_solidification.png', dpi=150, bbox_inches='tight')
plt.close()
print("\n图4:多相凝固模拟已保存")
print("\n所有仿真完成!")
4. 工程应用
4.1 铸造工艺
铸造凝固模拟:
- 缩孔预测
- 热节分析
- 冷却系统设计
4.2 晶体生长
单晶硅生长:
- 提拉法(Czochralski)
- 区熔法
- 温度场控制
4.3 食品冷冻
食品冷冻过程:
- 冻结时间预测
- 冰晶分布
- 品质保持
5. 总结
本教程介绍了凝固与熔化过程的数值模拟方法,主要内容包括:
- 物理基础:斯蒂芬条件、凝固模式、界面动力学
- 数值方法:显式追踪法、焓方法、相场模型
- 数值仿真:通过Python实现了凝固过程的数值模拟
- 工程应用:讨论了铸造、晶体生长、食品冷冻等领域的应用
凝固与熔化过程模拟是材料加工和工业制造中的重要工具,掌握其建模方法对于优化工艺参数和提高产品质量具有重要意义。
参考文献
-
Crank, J. (1984). Free and Moving Boundary Problems. Oxford University Press.
-
Alexiades, V., & Solomon, A. D. (1993). Mathematical Modeling of Melting and Freezing Processes. Hemisphere Publishing.
-
Provatas, N., & Elder, K. (2010). Phase-Field Methods in Materials Science and Engineering. Wiley-VCH.
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)