16 KiB
Outlook: GNN-Guided Adaptive Mesh Refinement for 2D Helmholtz Scattering
1. 问题定义
求解 2D 介质圆柱的电磁散射(散射场公式):
∇²u + k²·ε_r·u = −k²·(ε_r − 1)·u_inc
∂u/∂n − i·k_local·u = 0 (Sommerfeld 辐射 BC)
- 入射波:
u_inc = exp(i·k·x),参考解:Mie 解析解 - 参数空间:k∈[3,15],eps_r∈[2,8],cx/cy∈[0.2,0.8],radius∈[0.05,0.25]
- 核心目标:在参数化 Helmholtz 散射问题中,学习一个无在线求解的预算约束网格预测器,用于近似 residual-AMR 的最终加密分布,并在低预算下优于简单物理启发式网格。
2. 算法全流程
Step 1. 数据生成 (gen.py)
残差驱动 AMR → 每步保存 cell 状态 + 标签
│
▼
Step 2. 训练 (train_correction.py)
features(15-dim) + physics_score → GNN → sigmoid → 二分类 teacher_mark
│
▼
Step 3. 评估
3a. 离线指标 (test_correction.py) — top-k overlap / AUC
3b. Rollout 评估 (eval_correction.py) — 迭代加密 → FEM → aw_rel
│
▼
Step 4. 可视化 (viz_correction.py)
amr 模式: GNN 驱动完整 AMR → 网格 + 场 + 误差
step 模式: 单步 GNN vs teacher vs physics 标记对比
3. 数据生成 (gen.py)
3.1 初始网格
物理自适应初始网格(build_physics_safe_initial_mesh):
- 均匀基底网格 + 迭代局部加密
- 介质外:h ≤ λ₀/q,介质内:h ≤ λ_eff/q(q=2,每波长 2 个单元)
- 加密准则:
score = max_edge / h_target > 1的单元被加密 - 二分搜索控制每批加密数量,不超预算
3.2 AMR 循环(每步保存)
初始 mesh → FEM solve → 残差估计器 η → teacher_mark (η top-k)
├── physics_score → physics_mark (top-k)
├── correction_label = teacher_mark − physics_mark
└── 保存 .npz → 按 η 选单元加密 → 下一步
残差估计器 η(environment/helmholtz.py:_compute_residual_indicator):
- 内部残差:
h_K/k · √V_K · |k²ε_r·u_h + k²(ε_r−1)·u_inc| - 梯度跳变:
√(½ Σ h_e/k · |[[∇u_h·n]]|²) - SBC 边界残差:
h_bnd/k · |∂u/∂n − i·k_local·u|
标记策略:
- teacher_mark:按 η 取 top
mark_fraction(默认 3%) - physics_mark:按
physics_score取 topmark_fraction - correction_label = +1(teacher 独有)、0(一致)、−1(physics 独有)
安全过滤:
- 面积过滤:排除面积 ≤ 1e-10 的退化单元
- 反向 Dörfler:排除误差贡献最低 1% 的单元
3.3 输出格式
outlook/data_correction/
├── params_list.npz # (n_samples, 5) PDE 参数
├── sample0000_step000.npz # 逐样本逐步数据
└── summary.json
每个 step .npz:
| 字段 | 形状 | 说明 |
|---|---|---|
features |
(n_elem, 15) |
几何/物理特征 |
edge_index |
(2, n_edges) |
网格图结构 |
physics_score |
(n_elem,) |
h/λ_eff |
teacher_eta |
(n_elem,) |
残差估计器 |
teacher_mark |
(n_elem,) |
η top-k 标记 (0/1) |
physics_mark |
(n_elem,) |
physics top-k 标记 (0/1) |
correction_label |
(n_elem,) |
teacher − physics (−1/0/+1) |
4. 特征工程
4.1 15 维基础特征
| 维 | 特征 | 说明 |
|---|---|---|
| 0,1 | x, y | 单元中点坐标 |
| 2 | area | 单元面积 |
| 3 | dist_to_center | 到圆柱中心距离 |
| 4 | signed_dist | dist − radius(负=介质内) |
| 5 | inside | 是否在圆柱内 (0/1) |
| 6 | k | 波数 |
| 7 | eps_r | 介电常数 |
| 8 | radius | 半径 |
| 9,10 | cx, cy | 圆柱中心 |
| 11 | k_h | k × √area |
| 12 | k_eps_h | k × √eps_r × √area |
| 13,14 | sin(k·x), cos(k·x) | 入射波相位 |
4.2 Physics Score(第 16 维输入)
lambda_eff = 2π / (k · √eps_r) # 介质内
或 2π / k # 介质外
physics_score = max_edge / lambda_eff # >1 = 分辨率不足
4.3 归一化
训练集 z-score 归一化,推理复用同一统计量:
x_norm = (concat(features, physics_score) - mean) / scale
5. GNN 架构
5.1 CorrectionGNN
基于 DensityGNN 骨干,替换密度回归头为二分类 logit 头:
Input: (n_cells, 16) node features
│
├── node_embedding: Linear(16 → latent_dim)
├── edge_embedding: Linear(16 → latent_dim)
│
├── N × MessagePassingStep:
│ ├── EdgeModule: MLP([src | dst | edge_attr]) → latent_dim
│ ├── NodeModule: MLP([node | mean(incoming_edges)]) → latent_dim
│ └── LayerNorm + Residual
│
├── GlobalVirtualNode: mean_pool → attention_gate → broadcast
│
└── head: Linear(latent → hidden) → ReLU → Linear(hidden → 1 logit)
5.2 关键设计
- 边特征:
edge_attr = |x[src] - x[dst]|(节点特征差绝对值) - 边丢弃:训练 0.1,推理 0.0
- 损失:BCEWithLogitsLoss + per-graph
pos_weight = neg/pos
5.3 训练配置
| 参数 | 值 |
|---|---|
| latent_dim | 64 |
| num_mp_steps | 3 |
| head_hidden | 64 |
| lr | 1e-3 |
| optimizer | Adam |
| scheduler | ReduceLROnPlateau (patience=10) |
6. 评估体系
6.1 离线指标(test_correction.py)
- top-k overlap:GNN 概率最高的 k 个 cell 与 teacher_mark 的交集 / k
- AUC:ROC-AUC(GNN vs physics baseline)
- gnn_beats_physics_ratio:GNN 优于 physics 的样本比例
6.2 Rollout 评估(eval_correction.py)
从初始 mesh 出发,无 teacher_eta,无残差标记,无中间 FEM solve。每步只用分数决定加密单元,最终一次 FEM solve 计算误差。
三种方法:
| 方法 | 打分 | 说明 |
|---|---|---|
physics |
physics_score |
纯物理先验 |
neural |
model(features + physics_score) |
纯 GNN |
hybrid |
α·zscore(physics) + β·zscore(neural) |
混合(默认 α=β=0.5) |
6.3 误差指标
aw_rel(面积加权相对误差):
aw_rel = √( Σ err²_tri · area / Σ ref²_tri · area )
max_err(最大逐点误差):
max_err = max |Re(u_fem) − Re(u_mie)|
7. 可视化
7.1 amr 模式
GNN 驱动完整 AMR,每步 FEM solve,展示网格和场演变。
输出:
amr_overview.png— 所有步骤总览amr_steps/step{XX}.png— 每步 3 面板(FEM 场 / Mie 参考 / 误差)ground_truth.png— 高保真参考解(--compare时)compare.png— Physics vs GNN vs Eta 对比(--compare时)
7.2 step 模式
重建指定 AMR 步的 mesh,对比 GNN / teacher / physics 标记。
输出:
marks_*.png— 2×2 对比图(teacher / GNN / physics / TP/FP/FN/TN)field_gnn_*.png— GNN 加密后 3 面板图field_eta_*.png— 传统 η 加密后 3 面板图
8. 使用方法
8.1 数据生成
python outlook/src/gen.py \
--n-samples 100 \
--max-elements 12000 \
--mark-fraction 0.03 \
--output-dir outlook/data_correction
8.2 训练
python outlook/src/train_correction.py \
--data-dir outlook/data_correction \
--epochs 100 \
--batch-size 32 \
--lr 1e-3 \
--device cuda \
--checkpoint-out outlook/ckpt/correction.pt
输出:
correction.pt— 最终模型correction_best.pt— val_loss 最低 checkpointcorrection_train_log.json— 逐 epoch 日志
8.3 离线指标评估
python outlook/src/test_correction.py \
--checkpoint outlook/ckpt/correction.pt \
--data-dir outlook/data_correction \
--device cuda \
--visualize \
--output-dir outlook/result/correction/test
8.4 Rollout 评估
python outlook/src/eval_correction.py \
--checkpoint outlook/ckpt/correction.pt \
--data-dir outlook/data_correction \
--target-elements 2000,4000,8000,12000 \
--mark-fraction 0.03 \
--max-steps 40 \
--methods physics,neural,hybrid \
--alpha 0.5 --beta 0.5 \
--device cuda \
--output-dir outlook/result/correction/rollout
输出:
eval_results.json— 详细结果 + 聚合统计 + 改善比例summary.csv— 每行一个 (method, target) 汇总aw_rel_vs_elements.png/max_err_vs_elements.png
8.5 可视化
# 端到端 AMR
python outlook/src/viz_correction.py \
--checkpoint outlook/ckpt/correction.pt \
--data-dir outlook/data_correction \
--mode amr --sample-id 0 --max-elements 5000 \
--device cuda \
--output-dir outlook/result/correction/viz
# 单步对比
python outlook/src/viz_correction.py \
--checkpoint outlook/ckpt/correction.pt \
--data-dir outlook/data_correction \
--mode step --sample-id 0 --step 0 \
--device cuda \
--output-dir outlook/result/correction/viz
# OOD 评估(自定义物理参数,需同时指定 k, eps-r, cx, cy, radius)
python outlook/src/viz_correction.py \
--checkpoint outlook/ckpt/correction.pt \
--data-dir outlook/data_correction \
--mode amr \
--k 30 --eps-r 4 --cx 0.5 --cy 0.5 --radius 0.15 \
--max-elements 6000 --compare \
--device cuda \
--output-dir outlook/result/correction/viz
9. 目录结构
outlook/
├── README.md # 本文档
├── train.sh # SLURM 训练脚本(可配置 batch_size,默认 1)
├── analyze_budget_teacher.py # Budget teacher 数据集分析
├── check_correction_data.py # 数据质量校验
│
├── src/
│ ├── gen.py # 数据生成
│ ├── train_correction.py # 训练
│ ├── test_correction.py # 离线指标评估
│ ├── eval_correction.py # Rollout 评估
│ ├── viz_correction.py # 可视化
│ ├── rollout.py # 统一 AMR rollout(核心循环 + 共享 refinement 工具)
│ ├── gnn.py # DensityGNN 模型
│ ├── feat.py # 特征提取
│ ├── graph.py # mesh → PyG graph(含 build_edge_index_np)
│ ├── mesh.py # score → refined mesh
│ ├── metrics.py # aw_rel / max_err
│ ├── problem.py # PDE 参数 → HelmholtzProblem
│ └── amr.py # 残差 AMR teacher
│
├── ckpt/ # checkpoint
├── data_correction/ # 训练数据
└── result/ # 评估结果
10. 辅助模块
| 模块 | 职责 |
|---|---|
rollout.py |
统一 AMR rollout:run_rollout_to_budget() 驱动完整加密循环,支持 physics/neural/hybrid/eta 四种打分方法 |
feat.py |
构建 15 维基础特征 + budget_code |
graph.py |
mesh → PyG Data(边特征 = phase_distance) |
mesh.py |
score → 迭代 top-k 加密(叶子继承初始单元 score) |
problem.py |
参数字典 → HelmholtzProblem 实例 |
amr.py |
纯残差驱动 AMR teacher(无网络) |
metrics.py |
compute_mie_error(aw_rel + max_err) |
11. 测试结果
11.1 训练配置
- 数据集:100 样本,~19 步/样本,1888 个 step 文件
- 训练/验证划分:80/20(按 sample_id,seed=42)
- 训练图:1513 个,验证图:375 个
- 正样本比例:3.0%(teacher_mark top-3%)
- 训练 100 epoch,最佳 epoch 57(val_loss=0.5873)
11.2 离线指标(test_correction.py)
在 20 个验证样本的 375 个 step 图上评估:
| 指标 | GNN | Physics Baseline |
|---|---|---|
| AUC | 0.9412 | 0.0000 |
| top-k overlap 均值 | 0.440 | 0.131 |
| GNN beats physics | 372/375 (99.2%) | — |
Physics AUC=0.0 是因为 physics_score 在均匀网格上只有 2 个离散值,无法区分排序。GNN 通过学习 η 的空间分布模式,top-k overlap 提升 3.4 倍。
11.3 Rollout 评估(eval_correction.py)
20 个验证样本 × 3 种方法 × 3 个目标预算,每次 rollout 最终做 1 次 FEM solve:
aw_rel(面积加权相对误差):
| 方法 | target=2000 | target=4000 | target=8000 |
|---|---|---|---|
| physics | 19.19% | 14.04% | 13.25% |
| neural | 15.96% | 13.72% | 12.98% |
| hybrid | 15.78% | 13.57% | 12.94% |
max_err(最大逐点误差):
| 方法 | target=2000 | target=4000 | target=8000 |
|---|---|---|---|
| physics | 0.3301 | 0.2514 | 0.2418 |
| neural | 0.2741 | 0.2431 | 0.2376 |
| hybrid | 0.2686 | 0.2430 | 0.2383 |
相对 physics-only 的改善:
| 方法 | target | aw_rel 改善 | max_err 改善 |
|---|---|---|---|
| hybrid | 2000 | +9.8% | +6.9% |
| neural | 2000 | +9.9% | +6.2% |
| hybrid | 4000 | +1.9% | +1.5% |
| neural | 4000 | +1.1% | +1.4% |
| hybrid | 8000 | +1.9% | +1.3% |
| neural | 8000 | +1.8% | +1.5% |
11.4 关键发现
- GNN 显著优于 physics baseline:离线 top-k overlap 从 0.131 提升到 0.440(3.4×),99.2% 的验证图上 GNN 胜出
- 低预算改善最大:target=2000 时 aw_rel 改善 ~10%,max_err 改善 ~7%;高预算时改善收窄到 ~2%(因为预算充足时 physics 也够用)
- hybrid 略优于 neural:z-score 混合策略在多数场景下比纯 GNN 更稳定
- GNN 推理效率:neural 方法比 physics 方法少用 ~12% 的 refinement 步数达到相同预算(8.9 vs 9.4 步 @2000),因为 GNN 的标记更精准
11.5 OOD 评估(k 超出训练范围 [3,15])
固定 eps_r=4, cx=cy=0.5, radius=0.15,在 k=20/30/50/80 上做三方法对比(target=5000/10000/20000):
aw_rel (%):
| k | 方法 | target=5000 | target=10000 | target=20000 |
|---|---|---|---|---|
| 20 | physics | 32.17 | 24.55 | 10.61 |
| 20 | neural | 32.56 | 17.85 | 10.68 |
| 20 | hybrid | 31.73 | 19.57 | 14.03 |
| 30 | physics | 33.94 | 15.15 | 10.14 |
| 30 | neural | 23.52 | 13.40 | 8.38 |
| 30 | hybrid | 27.94 | 13.34 | 7.96 |
| 50 | physics | 94.00 | 73.56 | 33.00 |
| 50 | neural | 88.16 | 52.92 | 27.99 |
| 50 | hybrid | 90.97 | 68.47 | 29.27 |
| 80 | physics | 122.06 | 135.78 | 101.64 |
| 80 | neural | 139.84 | 127.65 | 92.67 |
| 80 | hybrid | 139.84 | 127.68 | 105.94 |
相对 physics-only 的改善 (%):
| k | 方法 | target=5000 | target=10000 | target=20000 |
|---|---|---|---|---|
| 20 | neural | −1.2 | +27.3 | −0.7 |
| 20 | hybrid | +1.4 | +20.3 | −32.3 |
| 30 | neural | +30.7 | +11.6 | +17.4 |
| 30 | hybrid | +17.7 | +12.0 | +21.5 |
| 50 | neural | +6.2 | +28.1 | +15.2 |
| 50 | hybrid | +3.2 | +6.9 | +11.3 |
| 80 | neural | −14.6 | +6.0 | +8.8 |
| 80 | hybrid | −14.6 | +6.0 | −4.2 |
OOD 关键发现:
- neural 在远 OOD(k=50)优势最大:target=10000 时 aw_rel 从 73.56% 降至 52.92%(改善 +28.1%),hybrid 仅改善 +6.9%
- hybrid 的 physics 先验在 OOD 时成为拖累:z-score 混合中 physics_score 的
max_edge/h_target在高 k 下不再准确,导致 hybrid 的标记不如纯 neural - neural 的泛化来自几何特征:GNN 学到的是"界面附近 + 介质内 → 高密度"的空间模式,这一模式在 k 超出训练范围时仍然成立;而 physics_score 依赖
lambda_eff = 2π/(k√ε_r)的具体数值 - 极端 OOD(k=80)两者都差:误差超过 100%,说明 20000 个单元完全不够分辨 k=80 的短波结构(λ_eff≈0.028,需要 ~70000+ 单元)
- k=20/30 时 hybrid 反而更好:接近训练分布时 physics 先验有价值,hybrid 通过混合两种信号获得更稳定的标记