1. 热-力耦合PINN基础模型
任务目标
构建一个物理信息神经网络(PINN),以热-力耦合问题为对象,同时预测温度场 \( T(x) \) 和位移场 \( u(x) \)。该模型在单一网络中共享隐藏层,分别输出温度和位移,并在损失函数中同时嵌入热传导方程与热弹性静力平衡方程,从而验证热应力耦合的基本原理。
问题定义与方程
考虑一维长度为 \( L=1 \) 的杆,左端固定(\( u(0)=0 \)),右端自由。温度边界为 \( T(0)=0 \)、\( T(1)=1 \)。稳态条件下,控制方程为:
- 热传导方程:\( \frac{d^2 T}{dx^2} = 0 \),解析解为 \( T(x)=x \);
- 热弹性平衡方程:\( \frac{d}{dx}\left( E \frac{du}{dx} - \alpha E T \right) = 0 \),其中 \( E=1 \)、\( \alpha=0.01 \)。
该问题的位移解析解为 \( u(x) = \alpha \int_0^x T(s) ds = 0.005 x^2 \)。模型将利用这两个解析解作为验证基准,但训练时仅使用物理方程残差与边界条件,不向模型提供内部解析解信息。
模型架构与实现
使用PyTorch构建一个全连接网络,输入 \( x \),输出 \( [T, u] \)。损失函数由三部分组成:热方程残差、力平衡方程残差、边界条件误差。自动微分用于计算二阶导数。
import torch
import torch.nn as nn
import numpy as np
# 固定随机种子保证可复现
torch.manual_seed(42)
# 物理参数
L = 1.0
E = 1.0
alpha = 0.01
# 网络定义:输入x,输出[T, u]
class ThermalStressPINN(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(1, 20), nn.Tanh(),
nn.Linear(20, 20), nn.Tanh(),
nn.Linear(20, 20), nn.Tanh(),
nn.Linear(20, 2)
)
def forward(self, x):
return self.net(x)
# 自动微分求导数
def derivatives(model, x):
x = x.clone().requires_grad_(True)
out = model(x)
T = out[:, 0:1]
u = out[:, 1:2]
# 一阶导数
dT_dx = torch.autograd.grad(T, x, grad_outputs=torch.ones_like(T), create_graph=True)[0]
du_dx = torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u), create_graph=True)[0]
# 二阶导数
d2T_dx2 = torch.autograd.grad(dT_dx, x, grad_outputs=torch.ones_like(dT_dx), create_graph=True)[0]
return T, u, dT_dx, du_dx, d2T_dx2
# 训练设置
model = ThermalStressPINN()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 内部配点(用于物理方程残差)
x_collocation = torch.linspace(0, L, 100, requires_grad=True).reshape(-1, 1)
# 边界点
x_boundary = torch.tensor([[0.0], [1.0]])
# 训练循环
epochs = 2000
for epoch in range(epochs):
optimizer.zero_grad()
# 内部点物理残差
T_c, u_c, _, du_dx_c, d2T_dx2_c = derivatives(model, x_collocation)
# 热传导方程残差: d2T/dx2 = 0
f_heat = d2T_dx2_c
# 力平衡方程残差: d/dx(E*du/dx - alpha*E*T) = 0
# 即 E*d2u/dx2 - alpha*E*dT/dx = 0,需要额外求d2u/dx2和dT/dx
x2 = x_collocation.clone().requires_grad_(True)
out2 = model(x2)
T2 = out2[:, 0:1]
u2 = out2[:, 1:2]
dT2_dx = torch.autograd.grad(T2, x2, grad_outputs=torch.ones_like(T2), create_graph=True)[0]
du2_dx = torch.autograd.grad(u2, x2, grad_outputs=torch.ones_like(u2), create_graph=True)[0]
d2u2_dx2 = torch.autograd.grad(du2_dx, x2, grad_outputs=torch.ones_like(du2_dx), create_graph=True)[0]
f_stress = E * d2u2_dx2 - alpha * E * dT2_dx
# 边界条件
T_b, u_b = model(x_boundary).split(1, dim=1)
# 温度边界: T(0)=0, T(1)=1
bc_T = torch.cat([T_b[0] - 0, T_b[1] - 1])
# 位移边界: u(0)=0, 自由端应力为0: E*du/dx(1) - alpha*E*T(1) = 0
x_b1 = torch.tensor([[1.0]], requires_grad=True)
out_b1 = model(x_b1)
T_b1 = out_b1[:, 0:1]
u_b1 = out_b1[:, 1:2]
du_b1_dx = torch.autograd.grad(u_b1, x_b1, grad_outputs=torch.ones_like(u_b1), create_graph=True)[0]
stress_free = E * du_b1_dx - alpha * E * T_b1
bc_u = torch.cat([u_b[0] - 0, stress_free])
# 总损失
loss_heat = torch.mean(f_heat**2)
loss_stress = torch.mean(f_stress**2)
loss_bc = torch.mean(bc_T**2) + torch.mean(bc_u**2)
loss = loss_heat + loss_stress + loss_bc
loss.backward()
optimizer.step()
if (epoch+1) % 500 == 0:
print(f'Epoch {epoch+1}, Loss: {loss.item():.2e}')
# 验证:与解析解对比
x_test = torch.linspace(0, L, 50).reshape(-1, 1)
with torch.no_grad():
pred = model(x_test)
T_pred = pred[:, 0].numpy()
u_pred = pred[:, 1].numpy()
x_np = x_test.numpy().flatten()
T_exact = x_np # T = x
u_exact = 0.005 * x_np**2 # u = 0.005*x^2
# 计算误差
T_error = np.max(np.abs(T_pred - T_exact))
u_error = np.max(np.abs(u_pred - u_exact))
print(f'Max |T_error|: {T_error:.2e}')
print(f'Max |u_error|: {u_error:.2e}')
运行方式与依赖
需要安装 torch 和 numpy。将上述代码保存为 thermal_stress_pinn.py,在命令行执行:
python thermal_stress_pinn.py
验证方法与通过标准
训练完成后,程序会打印最大误差。判定训练成功的标准为:
- 温度场最大误差 \( \max|T_{pred}-T_{exact}| < 0.01 \);
- 位移场最大误差 \( \max|u_{pred}-u_{exact}| < 0.001 \)。
若误差未达上述标准,可增加训练轮次至3000或调整学习率为0.005后重新运行。该误差指标基于解析解直接计算,属于确定性输出,用于验证模型是否同时正确学习了热传导与热应力耦合关系。
上图展示了模型的数据流:输入坐标 \( x \) 经共享隐藏层后同时输出温度 \( T \) 和位移 \( u \),两者分别受热传导方程与热弹性平衡方程约束,并与边界条件共同构成总损失。这种共享表示结构使网络在训练中隐式学习温度场对位移场的耦合影响,无需显式构造耦合项。