Go to file
vvvvonly fa2c670f8d Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
checkpoints Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
checkpoints_before first commit 2026-05-26 18:45:19 +08:00
checkpoints_beforedwr Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
checkpoints_beforegvn Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
checkpoints_beforenfft Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
checkpoints_stop150 Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
environment Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
logs Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
outlook Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
output Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
result Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
src Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
README.md Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00
analysis_reward.md first commit 2026-05-26 18:45:19 +08:00
asmr++_architecture.md first commit 2026-05-26 18:45:19 +08:00
cmp_adv.py first commit 2026-05-26 18:45:19 +08:00
git.txt Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
mie.m first commit 2026-05-26 18:45:19 +08:00
outlook.md first commit 2026-05-26 18:45:19 +08:00
paper_outline.md Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
paper_outline.tex Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
pyrightconfig.json first commit 2026-05-26 18:45:19 +08:00
sync.ps1 Auto-sync from Server A at 2026-06-01 11:26:06 2026-06-01 11:26:08 +08:00
train.sh Auto-sync from Server A at 2026-06-09 12:21:00 2026-06-09 12:21:02 +08:00

README.md

AFEM — 自适应网格细化的 GNN + PPO 强化学习

项目架构

afem/
├── src/                            # 应用层
│   ├── config.yaml                 #   配置文件
│   ├── main.py                     #   入口:解析命令行 → train / test / viz
│   ├── network.py                  #   GNN + Actor-Critic 完整网络定义
│   ├── ppo.py                      #   RolloutBuffer + PPOTrainer
│   ├── utils.py                    #   读配置、保存/加载 checkpoint
│   └── visualize.py                #   viz 模式:加载模型 → 推理 → 存 PNG
│
├── environment/                    # 仿真环境层
│   ├── mesh_refinement.py          #   ★ 核心:网格细化 RL 环境
│   │                               #     - GNN 图观测构建(节点 + 边特征)
│   │                               #     - continuous_sizing_field (score-based + budget) 细化策略
│   │                               #     - spatial 奖励 + step0 penalty 降权
│   ├── helmholtz.py                #   Helmholtz FEM 求解器 + 残差误差估计
│   ├── fem_problem.py              #   FEM 问题封装 + PDE 循环缓冲区
│   ├── fem_util.py                 #   三角形面积、中点、随机采样、尺寸场函数
│   ├── domain.py                   #   计算域meshpy 三角剖分
│   ├── utils.py                    #   数组拼接、随机索引采样
│   └── visualization.py            #   plotly 网格渲染RL 环境用)
│
├── checkpoints/                    # 模型保存
├── result/                         # 可视化输出
└── README.md

项目简介

物理场景

二维 Helmholtz 电磁散射:

∇²u_scat + k²·ε_r·u_scat = k²·(1-ε_r)·u_inc
  • 入射波: 沿 -x 方向的平面波 u_inc = exp(i·k·x)
  • 散射体: 圆形介质柱ε_r 随机采样),位置和半径可配
  • 边界条件: SBC (Sommerfeld) ∂u/∂n = i·k·u
  • : 可配矩形域,初始网格密度自适应 + domain area 线性缩放:N_init = N_base × (k/k_ref)^k_exponent × domain_area。k_ref 和 k_exponent 均可通过 helmholtz config 配置(默认 k_exponent=2.0, k_ref=6.0),保证不同域尺寸下每单位面积单元数一致
  • 可配 exponent^2 = P1 Helmholtz 理论最优 (污染误差 ∝ k²)。建议 N_base 配合 exponent 调整,使 N_init 约为 COMSOL 目标 (λ/10√ε_r) 的 30-50%,为 RL agent 留出充分细化空间
  • 介质区前渐近区边缘约束: 介质内 λ_d = 2π/(k√ε_r) 更短,强制迭代细化至 h ≤ λ_d/N默认 N=2.0helmholtz.pre_asymptotic_N 可配)。约 2 点/波长,赋予初始网格基本相位解析能力但不过度消耗物理预算,为 RL agent 留出充分的选择性细化空间
  • 后验误差: 残差型 indicatorAinsworth & Oden 风格),含单元内部残差 + 梯度跳变 + SBC 边界残差

强化学习建模

概念 对应实体
智能体 每个三角形网格单元
状态 GNN 节点特征(几何 + PDE 残差 + 振幅 + 相位方向 + 物理参数,节点 13 维 + 边 1 维) + 13 维全局统计向量
动作 1 维连续标量 δ_i → score_i = log(η_i + ε) + c·tanh(δ_i) 降序 top-k 选择(η baseline + bounded Actor correction
奖励 纯局部 r_local = log(η_old) log(l2(η_child))clip [0, 2.0]减去动作惩罚step0 降权);未细化单元 r=0
终止 达到最大步数、超过最大单元数、或 sel=0无单元可选

网络架构

双流 GNN 架构Actor / Critic 共享基座,各自独立头):

图观测 → MessagePassingBase → Actor MLP → δ_i (连续动作)
          ├─ nn.Linear嵌入              → Critic MLP → V(s) (标量)
          ├─ MessagePassingStack2 层消息传递 + MultiPoolGVN 全局广播)
          │    ├─ MessagePassingStep × 2
          │    │    ├─ EdgeModule:  MLP([src | dst | edge_attr])
          │    │    └─ NodeModule:  MLP([node | scatter(入边)])
          │    │    内残差 + LayerNorm
          │    └─ MultiPoolGVN: 多策略池化 + 13 维全局统计 → 注意力门控广播
          │         Stage A: g_global = MLP(concat(g_mean, g_eta, global_stats))
          │         Stage B: α_v = σ(W_att[h_v || g_global])
          │                  h_v ← h_v + scale · α_v ⊙ W_V · g_global
          └─ 输出: 节点隐向量 h_i

Actor 输入:  concat(h_i, g_global, rel_logeta, rel_area, is_top_eta, budget_stats)  [2D+6]
Critic 输入: concat(h_i, g_global)  [2D]

MultiPoolGVN — 多池化全局虚拟节点

替代原始单一 η 加权 GVN用多种池化策略聚合节点嵌入拼接全局统计后生成 g_global

池化模式 公式 说明
mean g_mean = Σ h_v / N 均匀平均
eta_softmax g_eta = Σ (η_v / Ση) · h_v η 加权 softmax高误差节点主导
top_eta g_top = mean(h_v : log η_v > μ + σ) top-η 节点均值log 空间 >1σ

配置项 gvn_pooling: [mean, eta_softmax],可选加 top_eta

Global Stats — 13 维图级统计

每个图观测附带 13 维全局统计向量(graph.global_stats),用于 GVN 和 Actor/Critic 的条件输入:

索引 名称 说明
0 remaining_ratio (N_budget N_current) / N_budget
1 step_ratio current_step / max_steps
2 elem_ratio N_current / N_budget
3 logeta_mean log(η) 均值
4 logeta_std log(η) 标准差
5 logeta_max log(η) 最大值
6 logeta_p90 log(η) P90
7 logeta_p75 log(η) P75
8 top10_eta_energy top 10% η² 能量占比
9 eligible_ratio 面积安全阈值以上元素占比
10 inside_eta_energy 散射体内 η² 能量占比
11 outside_eta_energy 散射体外 η² 能量占比
12 interface_eta_energy 界面附近 η² 能量占比

全局条件化 Actor/Critic

use_global_conditioned_correction: trueActor 和 Critic 的输入额外拼接全局上下文:

  • Actor: concat(h_i, g_global, rel_logeta, rel_area, is_top_eta, budget_stats) → 维度 2D + 6
    • rel_logeta: (log η_i μ) / σper-graph 标准化
    • rel_area: log(area_i / mean_area)per-graph 相对面积
    • is_top_eta: rel_logeta > 1.0 的 0/1 标记
    • budget_stats: [remaining_ratio, step_ratio, elem_ratio]
  • Critic: concat(h_i, g_global) → 维度 2D

超参数

超参数
latent_dim 64
消息传递层数 2
残差连接 inner
归一化 inner LayerNorm
边 dropout 0.1
Actor MLP 2 层 tanh
Critic MLP 2 层 tanh
Optimizer Adam, lr=3e-4, lr_decay=1.0
动作分布 DiagGaussianDistribution(连续 Box 动作空间),log_std 可学习clamp 在 [-2.5, -1.0]
log_std 策略 初始化 -2.0std≈0.135),每步 optimizer.step() 后 clamp 到 [-2.5, -1.0]std ∈ [0.082, 0.368]),熵系数 0.01
correction_scale 0.3 — Actor 修正幅值 c·tanh(δ) ∈ [0.3, +0.3]
correction_reg_coef 0.03 — correction 正则化系数L_corr = coef × mean(correction²)
step0_penalty_scale 0.3 — 第一步 element penalty 降权系数

动作分布策略说明

环境定义的是 _action_space(下划线前缀),网络初始化时必须用 environment._action_space 而非 environment.action_space(后者默认为 None会错误回退到 CategoricalDistribution(1),导致 policy gradient 恒为零)。

continuous_sizing_fieldscore-based的 scoring 公式:

  • score_i = log(η_i + ε) + c·tanh(δ_i),其中 c=correction_scale
  • Actor 输出 δ_i经 tanh 限幅,只能微调 log(η) 基准排序,不能覆盖物理先验
  • 选 top-k 按 score 降序(越大越优先)
  • initial_log_std=-2.0std≈0.135clamp 在 [-2.5, -1.0]std ∈ [0.082, 0.368]
  • entropy_coefficient=0.01

输入特征

节点特征13 维)

维度 来源 名称 说明
1 cfg volume 无量纲单元面积volume / λ²
3 cfg internal_residual / gradient_jump / sbc_residual PDE 残差三分量(真空波数 k 归一化,经 log₁₀ 压缩):
`(h_K/k)·√V·
1 cfg element_penalty 单元惩罚系数 λ
1 cfg timestep 当前 rollout 步数
1 cfg k_local_sqrt_vol k × √(ε_r) × √(V)(局域波数 × 特征长度)
1 cfg is_sbc_boundary 是否与 SBC 吸收边界相邻 (0/1)
1 cfg dist_to_interface 到介质圆柱边界的带符号距离,无量纲化后经 sign·ln(1+
1 fix epsilon_r 单元中点相对介电常数(圆柱内 = εᵣ,外 = 1.0
1 fix total_solution_magnitude 散射场振幅 |u_scat|per-element 均值)
1 fix cos_phase Re(u) / (|u| + 1e-8),相位方向余弦,∈ [1, 1],无分支切割
1 fix sin_phase Im(u) / (|u| + 1e-8),相位方向正弦,与 cos 联合编码相位
  • cfg: 由 element_features 配置控制
  • fix: 始终启用Helmholtz 振幅 + 相位方向,硬编码)

GNN 输入用 _compute_residual_components(真空波数 k 归一化log₁₀ 压缩。Reward 用逐单元 η_K_eta_indicator),与 GNN 特征公式一致但不经 log 压缩。SBC 边界条件保留 k_local

边特征1 维)

维度 名称 说明
1 phase_distance 相邻单元中点相位距离 = d × √(k_local_src·k_local_dst) / 2π — 介质内短波长自然放大,赋予 GNN k 不变性

调用逻辑

main.py --mode train/test/viz
  │
  ├─→ utils.load_config()              # 读 YAML
  ├─→ environment.MeshRefinement       # 创建 RL 环境
  │     └─→ FEMProblemCircularQueue    #   管理 N 个随机 PDE 实例
  │           └─→ HelmholtzProblem     #     FEM 求解 + 残差误差
  ├─→ network.create_model()           # 创建 ActorCritic
  │
  └─ [train] → ppo.PPOTrainer.fit_iteration() 循环
       ├─ collect_rollouts()           #   256 步 rollout
       │    └─ buffer.compute_returns_and_advantage()
       │         └─ 单路 GAE          #   逐 agent 时序差分scatter_add 处理网格细化)
       │         └─ Return / value 归一化
       └─ train_step()                 #   多 epoch PPO 更新
            ├─ policy_loss()           #     Clipped PPO
            ├─ value_loss()            #     Clipped value loss
            ├─ entropy_loss()          #     熵正则
            └─ correction_reg()        #     Correction 正则化 L_corr

环境内部调用

MeshRefinement.reset()
  └─→ FEMProblemWrapper.reset()
        └─→ initial_mesh (meshpy → 介质内 前渐近区边缘迭代细化)

MeshRefinement.step(action)
  ├─→ score = log(η) + c·tanh(δ) 排序 + 物理预算约束 → top-k 细化单元
  ├─→ FEMProblemWrapper.refine_mesh()  # scikit-fem refine
  ├─→ calculate_solution_and_get_error()
  │     ├─→ HelmholtzProblem.calculate_solution()    # FEM 求解
  │     └─→ _compute_residual_indicator()            # 残差误差
  ├─→ _get_reward_by_type()            # spatial 奖励 + step0 penalty 降权
  └─→ last_observation                 # 构建 Data(x, edge_index, edge_attr, eta, area, global_stats)

训练

CUDA_VISIBLE_DEVICES=7 python src/main.py --mode train --config src/config.yaml

首次迭代需收集 256 步 rollout含 FEM 求解),后续打印:

it | loss ev agents avg_r sum_r corr_m corr_s r_le_sc δ<0 elig sel rem_r corr_reg corr_l2 corr_a p_sc avg_p avg_rl step_id time
字段 含义 健康范围
corr_m c·tanh(δ) 均值 接近 0Actor 修正无系统性偏差
corr_s c·tanh(δ) 标准差 应稳定在 0.030.08,不应持续涨到 0.15
r_le_sc Pearson r(log_η, score) 接近 1.0 → Actor 修正小;<0.9 → Actor 在主动修正
δ<0 Actor 输出负值的比例(纯诊断)
elig 通过双过滤器的候选占比
sel 实际选中的细化单元数 每步最多 N_current // 4
rem_r remaining / N_budget
corr_reg correction 正则化损失 L_corr 监控 correction drift
corr_l2 mean(correction²) 监控 correction 幅值增长
corr_a mean(|correction|) 监控 correction 绝对值
p_sc penalty_scale step0=0.3,后续=1.0
avg_p 平均 element penalty step0 应明显小于后续
avg_r_local 平均 r_localpenalty 前)
step_id 当前步数

测试

python src/main.py --mode test --checkpoint checkpoints/model_final.pt --k-test 6.0
python src/main.py --mode test --checkpoint checkpoints/model_final.pt \
    --k-test 6.0 --center 0.3,0.6 --radius 0.15

输出:

Step  0: reward=---      aw_rel=79.28%  max_err=2.2133  elements=1078  budget=...
Step  1: reward=+2.345   aw_rel=30.10%  max_err=0.7096  elements=2020   sel=269
...

每步打印 reward aw_rel max_err elements sel,第 0 步额外显示 N_budget

可视化

python src/main.py --mode viz --checkpoint checkpoints/model_final.pt --k-test 30.0

输出: result/visualization.png(总览)+ result/visualization_steps/step*.png(逐步对比)。


后验误差估计

残差 indicator 公式(无量纲化)

引入局部波数 k_{local} = k\sqrt{\max(\varepsilon_r, 1.0)},消除纯几何尺度 h 带来的特征偏差, 使误差指示子反映"相位分辨率残差"而非"网格粗疏程度"。

对 P1 三角单元 K三项残差分量为

r_{\text{int}} = \frac{h_K}{k} \sqrt{V_K} \cdot \left| k^2\varepsilon_r u + k^2(\varepsilon_r-1)u_{inc} \right|_K \tag{1}
r_{\text{jump}} = \sqrt{\frac{1}{2}\sum_{e\in\partial K} \frac{h_e}{k} \cdot \left| [[\nabla u \cdot n]] \right|^2_e} \tag{2}
r_{\text{sbc}} = \frac{h_{bnd}}{k} \cdot \left| \frac{\partial u}{\partial n} - ik_{local}u \right| \tag{3}

逐单元误差指示子

\eta_K = \sqrt{r_{\text{int}}^2 + r_{\text{jump}}^2 + r_{\text{sbc}}^2}

量纲分析(k \sim [L]^{-1}h_e \sim [L]|\text{jump}|^2 \sim [L]^{-2} 三项均严格无量纲:h_e/k \cdot |\text{jump}|^2 \sim [L]^2 \cdot [L]^{-2} = 1。 SBC 边界条件仍用 k_{local}(物理正确),仅归一化因子改用 k。 介质内残差不再被 \sqrt{\varepsilon_r} 压低Agent 获得正确的介质内/外优先级信号。

η_K 的计算(_compute_residual_indicator)与 GNN 输入特征(_compute_residual_components)公式完全一致,特征仅多一层 log₁₀ 压缩。关键验证点:

  • 内部残差P1 元 ∇²u_h ≡ 0仅含反应项 k²ε_r·u + k²(ε_r-1)·u_inc,真空波数 k 归一化
  • 梯度跳变:(h_e/k)·|jump|²,½ 分配给相邻左右单元;h_e 保留边积分路径,细化后自然衰减
  • SBC 项归一化用 k物理条件保留 k_local(h_bnd²/k²)·|∂u/∂n i·k_local·u|²

连续尺寸场策略score-based + 物理预算约束 + 动作掩码)

Actor 输出标量 δ_i → score_i = log(η_i + ε) + c·tanh(δ_i),在预算和上限内选 top-k

ε = max(0.01·median(η), 1e-12)               // 动态 eps防止 log(0)
corr_i = c · tanh(δ_i)   c = correction_scale // Actor 修正幅值 ∈ [c, +c]
score_i = log(η_i + ε) + corr_i               // 降序 top-k

A_budget_i = ½(λ_local_i / 6)²               // 每局部波长方向 ~6 尺度点(仅用于 N_budget
N_budget = max(N_phys, ⌈5·N_init⌉)            // rho_min=5.0
remaining = N_budget  N_current
V_min_safeguard = 1e-10 × domain_area
eligible: area > V_min_safeguard  AND  η_K ∈ Reverse Dörfler 保留集 (ε_noise=0.01, ≥20% floor)
num = min(|eligible|, N_current//4, remaining//3)
selected = top-k by score descending → 1-to-4 切分
  • Actor 通过 bounded correction 微调排序,不能覆盖物理先验 log(η)
  • Reverse Dörfler 动作掩码剔除噪声尾部≥20% floor 确保 Agent 始终有选择空间
  • sel=0 提前终止agent 选中 0 个单元时 episode 自动结束
  • k_exponent=2.0P1 Helmholtz 理论最优初始网格缩放

奖励计算

纯局部改善 reward无调制、无 bonus

r_local_i = log(η_old_i + ε)  log(l2_η_children_i + ε)
l2_η_children_i = √(Σ_{j∈C(i)} η_new_j²)

reward_i = clip(r_local_i, 0, rmax)  penalty_scale · λ · (n_child_i  1)

rmax = 2.0
λ = 0.02 (element_penalty.value)

penalty_scale = step0_penalty_scale  if current_step == 0   (默认 0.3)
             = 1.0                  otherwise
组件 聚合 作用
局部项 log(η_old / √(Σ η_child²)) scatter_add仅 refined parents L₂ 保证 r_local ≥ 0clip 到 [0, 2.0]
动作惩罚 λ=0.02 per-refined-parent 轻微抑制网格膨胀1-to-4 扣 0.06
step0 降权 step 0 时 penalty × 0.3 防止第一步"真实误差改善但 reward 给负反馈"
因果隔离 r=0 unrefined parents 未细化元素干净零基准

step0 penalty 降权动机:诊断发现 step 0 经常出现 reward < 0 但真实 aw_rel 改善的情况,说明 element penalty 淹没了真实的物理改善信号。降权后 step 0 的 reward 与 Δaw_rel 符号一致性提高。


PPO 关键细节

  • 单路 GAE: r_local 自身已闭合因果(细化单元的局部误差改善),不需要势函数塑形。用 scatter_add 将细化后的子单元值聚合回父单元,单路 GAE 即可
  • 奖励归一化: rollout 内 reward 做 z-score 归一化std < 1e-8 则跳过)
  • Value clipping: 默认 clip_range=0.2
  • 梯度裁剪: max_grad_norm=0.5
  • log_std clamp: 每步 optimizer.step() 后将 log_std clamp 到 [-2.5, -1.0]σ ∈ [0.082, 0.37]
    初始化 -2.0 (σ≈0.135),放宽下限防止策略过早确定化
  • 熵正则: entropy_coefficient=0.01
  • epochs_per_iteration: 3

Correction 正则化

为防止 Actor 学会利用"大 correction"刷局部 residual rewardcorrection drift / reward hacking在 PPO loss 中加入 correction 正则项:

correction_i = correction_scale · tanh(action_i)
L_corr = correction_reg_coef · mean(correction²)

loss = policy_loss + value_coef · value_loss + entropy_coef · entropy_loss + L_corr
  • correction_reg_coef 默认 0.03,设为 0 可禁用
  • correction 在 PPO 训练时从 stored actions 重新计算(与环境中的公式一致)
  • 目标corr_std 不再从 ~0.03 持续涨到 ~0.15r_le_sc 保持更接近 η baselinevalidation aw_rel 不随训练后期变差
  • 训练 reward 可能因正则化而下降,这是正常现象;成功标准是测试误差更稳定

训练诊断字段

字段 来源 说明
corr_reg train_step L_corr = coef × mean(corr²),监控 correction drift
corr_l2 train_step mean(correction²)correction 幅值
corr_abs train_step mean(|correction|)correction 绝对值
penalty_scale environment step0=0.3,后续=1.0
avg_penalty environment 平均 element penaltyrefined parents
avg_r_local environment 平均 r_localpenalty 前refined parents
step_id environment 当前 timestep

配置参考

algorithm:
    batch_size: 32
    discount_factor: 1.0
    ppo:
        clip_range: 0.2
        entropy_coefficient: 0.01
        correction_reg_coef: 0.03       # correction 正则化系数
        epochs_per_iteration: 3
        gae_lambda: 0.95
        initial_log_std: -2.0
        max_grad_norm: 0.5
        num_rollout_steps: 256
        value_function_coefficient: 0.5
    use_gpu: true

environment:
    mesh_refinement:
        correction_scale: 0.3           # c in score = log(η) + c·tanh(δ)
        step0_penalty_scale: 0.3        # step 0 element penalty 降权
        num_timesteps: 4
        refinement_strategy: continuous_sizing_field
        reward_type: spatial
        element_penalty:
            value: 0.02
        maximum_elements: 50000
        element_limit_penalty: 10000
        # ... (FEM / Helmholtz / 特征配置见 config.yaml)

network:
    latent_dimension: 64
    use_global_conditioned_correction: true   # Actor/Critic 拼接 g_global + 局部相对特征
    use_global_stats: true                    # 启用 MultiPoolGVN + 13 维全局统计
    gvn_pooling: [mean, eta_softmax]          # 池化策略(可选加 top_eta
    correction_centering: true                # correction 在 eligible 集内中心化
    base:
        edge_dropout: 0.1
        scatter_reduce: mean
        stack:
            num_steps: 2
            mlp:
                activation_function: leakyrelu
                num_layers: 2
    actor:
        mlp:
            activation_function: tanh
            num_layers: 2
    critic:
        mlp:
            activation_function: tanh
            num_layers: 2
    training:
        learning_rate: 0.0003
        lr_decay: 1.0

实验对照建议

实验 correction_reg_coef step0_penalty_scale 目的
A (baseline) 0.0 1.0 无正则、无降权
B (corr reg only) 0.03 1.0 验证 correction 正则效果(优先)
C (both) 0.03 0.3 正则 + step0 降权

成功标准(非训练 reward 高低):

  • corr_std 不再持续涨到 ~0.15
  • r_le_sc 保持更接近 η baseline
  • top-k overlap 不随训练后期明显下降
  • validation aw_rel / max_err 更稳定

Correction GNN 训练数据

Correction GNN 用于二分类预测给定当前网格哪些单元需要加密teacher_mark=1。 训练数据由 outlook/src/gen.py 生成。

参数采样

每个样本随机采样物理参数:

参数 分布 说明
k Uniform(3, 15) 波数
eps_r Uniform(2, 8) 介质相对介电常数
cx Uniform(0.2, 0.8) 散射体中心 x
cy Uniform(0.2, 0.8) 散射体中心 y
radius Uniform(0.05, 0.25) 散射体半径

初始网格

采用物理自适应初始网格(make_initial_mesh),元素尺寸由局域波长决定:

  • 介质外: h ≤ λ₀ / q, λ₀ = 2π / k
  • 介质内/散射体附近: h ≤ λ_eff / q, λ_eff = 2π / (k √ε_r)
  • q = 2(每波长 2 个单元)

网格在 [0,1]×[0,1] 域上通过张量积生成x/y 方向各自根据散射体位置做分级加密:

  • 远离散射体粗网格h = λ₀/q
  • 散射体附近含过渡区细网格h = λ_eff/q

AMR 循环与标签生成

对每个参数样本,运行残差驱动 AMR 循环,每步保存快照:

for step in range(max_steps):
    1. FEM 求解 → u_scat
    2. 计算残差指示子 ηteacher 信号)
    3. 计算 physics_score = h / λ_eff物理 baseline
    4. teacher_mark  = top-fraction(η,           mark_fraction)  # 二值标签
       physics_mark  = top-fraction(physics_score, mark_fraction)  # 物理 baseline
       correction_label = teacher_mark - physics_mark  # {-1, 0, +1}
    5. 提取 16 维节点特征 + 边索引
    6. 保存 .npz → 残差指示子 top-k 加密 → 下一步
  • mark_fraction: 默认 0.03(每步标记 top 3% 的单元为正样本)
  • top-fraction: 按 score 降序取 top n × fraction 个单元,标记为 1
  • teacher_mark: 以 η(残差指示子)为 score代表"最优加密目标"
  • physics_mark: 以 h/λ_eff 为 score代表"纯物理 baseline"
  • correction_label: teacher 与 physics 的差集,+1 = teacher 独有GNN 应补充),-1 = physics 独有GNN 应抑制)

数据文件格式

每个样本每步保存为 sample{id}_step{step}.npz,包含:

字段 形状 说明
features (n_elem, 16) 15 维几何/PDE 特征 + 1 维 physics_score
edge_index (2, n_edges) 双向边 + 自环
physics_score (n_elem,) h / λ_eff
teacher_eta (n_elem,) 残差指示子 η
teacher_mark (n_elem,) 二值标签 (0/1)
physics_mark (n_elem,) 物理 baseline 标签 (0/1)
correction_label (n_elem,) 差集标签 (-1/0/+1)
k, eps_r, cx, cy, radius scalar 物理参数
elements scalar 当前单元数
step scalar AMR 步数

One-Shot Density Prediction

One-shot final mesh density prediction experiments are documented in outlook/README.md.