2. 二维稳态热传导PINN模拟

任务目标

构建一个物理信息神经网络(PINN),求解如下二维稳态热传导方程(Possion方程):

∇²T = ∂²T/∂x² + ∂²T/∂y² = 0,定义域 Ω = [0,1]×[0,1]

边界条件:T(0,y)=0,T(1,y)=0,T(x,0)=0,T(x,1)=sin(πx)

该问题存在解析解 T_exact(x,y) = sin(πx)·sinh(πy)/sinh(π),用于定量验证PINN精度。

环境依赖

Python 3.9+,PyTorch 2.0+,NumPy,Matplotlib(可选,用于可视化)。无需额外物理库,PINN核心逻辑全部由PyTorch自动微分实现。

关键完整代码

import torch
import torch.nn as nn
import numpy as np

# ---------- 1. 网络定义 ----------
class PINN(nn.Module):
    def __init__(self, n_hidden=4, n_neurons=20):
        super().__init__()
        layers = [nn.Linear(2, n_neurons), nn.Tanh()]
        for _ in range(n_hidden - 1):
            layers += [nn.Linear(n_neurons, n_neurons), nn.Tanh()]
        layers.append(nn.Linear(n_neurons, 1))
        self.net = nn.Sequential(*layers)

    def forward(self, x, y):
        return self.net(torch.cat([x, y], dim=1))

# ---------- 2. 解析解(用于验证) ----------
def exact_solution(x, y):
    return torch.sin(np.pi * x) * torch.sinh(np.pi * y) / torch.sinh(np.pi)

# ---------- 3. 训练准备 ----------
torch.manual_seed(42)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = PINN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

# 内部配点(残差点)
N_f = 2000
x_f = torch.rand(N_f, 1, device=device, requires_grad=True)
y_f = torch.rand(N_f, 1, device=device, requires_grad=True)

# 边界配点(每条边200个点)
N_b = 200
x_left = torch.zeros(N_b, 1, device=device)
y_left = torch.rand(N_b, 1, device=device)
x_right = torch.ones(N_b, 1, device=device)
y_right = torch.rand(N_b, 1, device=device)
x_bottom = torch.rand(N_b, 1, device=device)
y_bottom = torch.zeros(N_b, 1, device=device)
x_top = torch.rand(N_b, 1, device=device)
y_top = torch.ones(N_b, 1, device=device)

# 边界目标值
T_left = torch.zeros(N_b, 1, device=device)
T_right = torch.zeros(N_b, 1, device=device)
T_bottom = torch.zeros(N_b, 1, device=device)
T_top = torch.sin(np.pi * x_top)

# ---------- 4. 损失函数 ----------
def loss_fn():
    # PDE残差:∇²T = 0
    T = model(x_f, y_f)
    dT_dx = torch.autograd.grad(T, x_f, grad_outputs=torch.ones_like(T), create_graph=True)[0]
    dT_dy = torch.autograd.grad(T, y_f, grad_outputs=torch.ones_like(T), create_graph=True)[0]
    d2T_dx2 = torch.autograd.grad(dT_dx, x_f, grad_outputs=torch.ones_like(dT_dx), create_graph=True)[0]
    d2T_dy2 = torch.autograd.grad(dT_dy, y_f, grad_outputs=torch.ones_like(dT_dy), create_graph=True)[0]
    pde_loss = torch.mean((d2T_dx2 + d2T_dy2) ** 2)

    # 边界损失
    bc_loss = (
        torch.mean((model(x_left, y_left) - T_left) ** 2) +
        torch.mean((model(x_right, y_right) - T_right) ** 2) +
        torch.mean((model(x_bottom, y_bottom) - T_bottom) ** 2) +
        torch.mean((model(x_top, y_top) - T_top) ** 2)
    )
    return pde_loss + bc_loss

# ---------- 5. 训练循环 ----------
epochs = 3000
for epoch in range(epochs):
    optimizer.zero_grad()
    loss = loss_fn()
    loss.backward()
    optimizer.step()
    if (epoch + 1) % 500 == 0:
        print(f'Epoch {epoch+1}/{epochs}, Loss: {loss.item():.2e}')

# ---------- 6. 验证:与解析解对比 ----------
with torch.no_grad():
    # 在网格点上评估
    x_grid = torch.linspace(0, 1, 21, device=device)
    y_grid = torch.linspace(0, 1, 21, device=device)
    X, Y = torch.meshgrid(x_grid, y_grid, indexing='ij')
    x_flat = X.reshape(-1, 1)
    y_flat = Y.reshape(-1, 1)
    T_pred = model(x_flat, y_flat).reshape(21, 21)
    T_exact = exact_solution(X, Y)

    # 计算L2相对误差
    l2_error = torch.norm(T_pred - T_exact) / torch.norm(T_exact)
    print(f'L2相对误差: {l2_error.item():.4f}')
    print(f'最大误差: {torch.max(torch.abs(T_pred - T_exact)).item():.4f}')

运行与验证

运行方式:将上述代码保存为 pinn_2d_heat.py,在终端执行 python pinn_2d_heat.py。训练约3000轮(CPU约2~3分钟,GPU约30秒)。

通过判定标准:

  • 训练损失稳定下降至1e-4以下;
  • L2相对误差低于0.05(5%),最大误差低于0.05;
  • 若打印的误差明显偏高(如L2误差>0.1),可增加训练轮数至5000或调整网络宽度(如n_neurons=30)。

预期输出(确定性结果)

由于网络初始化固定(seed=42),训练过程确定,最终误差在固定范围内。典型收敛后损失约1e-5~1e-4,L2相对误差约0.01~0.03。具体数值以实际运行为准,上述范围作为判定参考。

常见问题

  • 损失不下降:检查学习率是否过大(建议1e-3),或网络层数是否过深导致梯度消失;
  • 边界误差大:确认边界点坐标与目标值一一对应,尤其顶部边界T=sin(πx)需使用对应x坐标计算;
  • 训练速度慢:可减少N_f至1000或使用GPU加速。
T = sin(πx) T = 0 T = 0 T = 0 ∇²T = 0 x y 高温 低温 矩形域 [0,1]×[0,1] 边界条件示意

上图展示了本案例的物理设定:矩形区域内部满足拉普拉斯方程,底部与两侧边界温度恒为0,顶部边界温度呈正弦分布。PINN通过最小化内部PDE残差与边界损失之和,学习满足全部约束的温度场。