Files
DCTS/workflows/sdB_cno.yaml
T
fmq 43b82b1ae2 feat(all): 物理正确性五重硬门槛、输入文件结构化与 fort.55 错位修复、conv 诊断 DB 化与阶段归因修复、ORELAX 收敛修复与导入工具下线
物理正确性校验体系(common/conv_check.rs +494 行)
- 新增 5 类硬门槛:能量守恒(.6)、温度结构(.7)、emflux 积分校验(.emflux,含全 NaN 判失败)、假收敛排查(itek 轨迹首末比)、b 因子合理性(.bfac)
- runner 在 TLUSTY 阶段结束后执行全部校验,任一失败判 final_converged=false
- GridConfig 新增 8 个可配阈值,经 scheduler→executor→runner 全链路透传

输入文件配置结构化重构(config.rs +1453 行)
- TlustyInput 拆为 dot5/nst 分层结构,字段名严格映射 tlusty208.f READ 语句;SynspecInput 重构为 9 个 Fort55Line 子结构体
- 移除 ChainStep.metals 字段,元素集改由 dot5.atoms/ions 显式声明(gen_input5/nst_writer 同步重写为三源融合 / 分层覆盖)
- fort.55 修复行结构 bug:补全分子表行(7→9 行),IDSTD 50→0 错位修正(影响全部光谱线强归一化,需重算 SYNSPEC 阶段)

conv 诊断 DB 化与阶段归因修复(server)
- 单点详情 conv 面板从磁盘 conv.json 改读 DB grid_points.summary_json;grid_points 新增 summary_json/last_elapsed_sec 两列(旧库幂等 ALTER)
- record_task_report 阶段归因列加 CASE 守卫 + clear_synspec 对称处理,修复 synspec-only/TLUSTY-only 重跑污染统计
- 新增 summary_merge.rs 点级增量合并,避免重跑覆盖诊断字段

收敛性 ORELAX 修复与 seed_chain 可配(sdB_cno.yaml + node)
- nl 阶段加 orelax=0.5、seed_nc 加 orelax=0.3,阻尼中温区 relc 振荡发散
- seed_chain 块可配,executor 优先采用用户配置而非内置默认链

导入工具下线
- 删除 import_results 客户端工具及 Windows 推送脚本;移除 /admin/import_seed 端点
- 改为服务端临时 migrate_conv 端点(扫 conv.json 增量合并入库,迁移后可删)

文档与分析
- 新增 1305 失败点根因分析、fort.14 全 NaN 物理含义分析两份深度文档
- spectrum_correctness_analysis 两次修订标注已修复项;fetch_results.sh 修 trap RETURN 的 set -u 报错
2026-08-09 12:09:48 +08:00

202 lines
11 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 6 维 CNO NLTE 热亚矮星网格的配置文件。
# 所有丰度均为 log10(nX/nH).5 文件中的 abn 字段设为 10**logX。
#
# 网格各维范围:
# Teff : 20000 - 80000 K
# logg : 5.0 - 6.5
# logHe: -4 - 2 He/H 数密度比:1e-4 .. 100
# logC : -4 - -1 C/H1e-4 .. 0.1;太阳 C/H≈-3.6,落在区间内)
# logN : -4 - -1 N/H:太阳 N/H≈-4.2
# logO : -4 - -1 O/H:太阳 O/H≈-3.3
# CNO 范围已修正为物理上的 sdB 范围,不再是超太阳(旧版 -2..1 会发散)
# ---- 网格轴:显式列出各维采样点 ----
# grid:
# teff: [20000, 60000]
# logg: [5.0]
# loghe: [-2]
# logc: [-4]
# logn: [-4]
# logo: [-4]
grid:
teff: [20000, 30000, 40000, 50000, 60000]
logg: [5.0, 5.5, 6.0, 6.5]
loghe: [-4, -2, 0, 2]
logc: [-4, -3, -2, -1]
logn: [-4, -3, -2, -1]
logo: [-4, -3, -2, -1]
# 共 4*2*2*3*3*3 = 432 个点
# ---- TLUSTY 输入文件全局参数(.5 + nst 的非阶段差异部分)----
# 与 .5 文件 + nst 文件全字段一一对应(见 config.rs 的 Dot5Input / NstInput)。
# gridteff/logg/丰度)和 tlusty_chainlte/ltgray/ilvlin 等)在运行时覆写对应字段。
# 删掉本块 → 走 TlustyInput::default()(与下方声明完全等价)。
tlusty_input:
# .5 文件配置(tlusty208.f:178-450 的 READ(IBUFF,*) 顺序)
dot5:
# 行1 几何(grid 覆写 teff/loggtype=stellar 恒星大气,disk 吸积盘)
geometry: {type: stellar, teff: 35000.0, logg: 5.5}
# 行2 LTE/LTGRAYchain 覆写)
lte: false
ltgray: false
# 行3 nst 文件名(空串=不读 nst)
finstd: "nst"
# 行4 NFREAD 连续频率网格点数(>0 从预设表读)
nfread: 2000
# 行5 IABSET 丰度集选择(不列出=默认 01=abun1 表,2=abun0 表)
# iabset: null
# 行5+ atoms 块(grid 覆写 He/C/N/O 的 abn;列出哪些行就渲染哪些元素)
# mode: 2=显式统计平衡(H/He/CNO), 0=不参与(Li/Be/B); abn=grid 注入或 "0." 太阳默认
atoms:
- {iat: 1, mode: 2, abn: "0.", modpf: 0} # H
- {iat: 2, mode: 2, modpf: 0} # He (abn 由 grid)
- {iat: 3, mode: 0, abn: "0.", modpf: 0} # Li
- {iat: 4, mode: 0, abn: "0.", modpf: 0} # Be
- {iat: 5, mode: 0, abn: "0.", modpf: 0} # B
- {iat: 6, mode: 2, modpf: 0} # C (abn 由 grid)
- {iat: 7, mode: 2, modpf: 0} # N (abn 由 grid)
- {iat: 8, mode: 2, modpf: 0} # O (abn 由 grid)
# ions 块(chain 覆写每行 ilvlin;列出哪些行就渲染哪些元素)
# 显式列出完整 22 行表(H/He/C/N/O)。如需去掉某元素,删对应 iat 行即可;
# 如需加 Fe 等,追加对应行。nonstd≠0 时配 nonstd_extra 附加行(ODF/NONSTD)。
# 注:ilvlin 由 tlusty_chain 的各阶段注入(nlevs==1 裸核强制 0),此处不列。
ions:
# H (iat=1)
- {iat: 1, iz: 0, nlevs: 9, nonstd: 0, typion: " H 1", filei: "data/h1.dat"}
- {iat: 1, iz: 1, nlevs: 1, nonstd: 0, typion: " H 2", filei: " "}
# He (iat=2)
- {iat: 2, iz: 0, nlevs: 14, nonstd: 0, typion: "He 1", filei: "data/he1.dat"}
- {iat: 2, iz: 1, nlevs: 14, nonstd: 0, typion: "He 2", filei: "data/he2.dat"}
- {iat: 2, iz: 2, nlevs: 1, nonstd: 0, typion: "He 3", filei: " "}
# C (iat=6)
- {iat: 6, iz: 0, nlevs: 40, nonstd: 0, typion: " C 1", filei: "data/c1.dat"}
- {iat: 6, iz: 1, nlevs: 22, nonstd: 0, typion: " C 2", filei: "data/c2.dat"}
- {iat: 6, iz: 2, nlevs: 46, nonstd: 0, typion: " C 3", filei: "data/c3_34+12lev.dat"}
- {iat: 6, iz: 3, nlevs: 25, nonstd: 0, typion: " C 4", filei: "data/c4.dat"}
- {iat: 6, iz: 4, nlevs: 1, nonstd: 0, typion: " C 5", filei: " "}
# N (iat=7)
- {iat: 7, iz: 0, nlevs: 34, nonstd: 0, typion: " N 1", filei: "data/n1.dat"}
- {iat: 7, iz: 1, nlevs: 42, nonstd: 0, typion: " N 2", filei: "data/n2_32+10lev.dat"}
- {iat: 7, iz: 2, nlevs: 32, nonstd: 0, typion: " N 3", filei: "data/n3.dat"}
- {iat: 7, iz: 3, nlevs: 48, nonstd: 0, typion: " N 4", filei: "data/n4_34+14lev.dat"}
- {iat: 7, iz: 4, nlevs: 16, nonstd: 0, typion: " N 5", filei: "data/n5.dat"}
- {iat: 7, iz: 5, nlevs: 1, nonstd: 0, typion: " N 6", filei: " "}
# O (iat=8)
- {iat: 8, iz: 0, nlevs: 33, nonstd: 0, typion: " O 1", filei: "data/o1_23+10lev.dat"}
- {iat: 8, iz: 1, nlevs: 48, nonstd: 0, typion: " O 2", filei: "data/o2_36+12lev.dat"}
- {iat: 8, iz: 2, nlevs: 41, nonstd: 0, typion: " O 3", filei: "data/o3_28+13lev.dat"}
- {iat: 8, iz: 3, nlevs: 39, nonstd: 0, typion: " O 4", filei: "data/o4.dat"}
- {iat: 8, iz: 4, nlevs: 6, nonstd: 0, typion: " O 5", filei: "data/o5.dat"}
- {iat: 8, iz: 5, nlevs: 1, nonstd: 0, typion: " O 6", filei: " "}
# CHANGE 块(ICHANG<0 时每能级行;不列出 = 无)
change: null
# nst 高频关键字(236 个中物理相关的,按用途分组)
# 默认值为 sdB 调优值(非 TLUSTY 原始默认)。ChainStep 的 niter/chmax 等阶段级覆盖。
nst:
depth: {nd: 50, nmu: 3, nlambd: 3, isplin: 0}
frequency: {ispodf: 1, ddnu: 50.0, cnu1: 6.0, cnu2: 3.0, nftail: 21, dftail: 0.25,
frcmax: 0.0, frcmin: 0.0, frlmax: 0.0, frlmin: 0.0}
physics: {vtb: 2.0, hmix0: -1.0, mltype: 1, ipturb: 1, ielcor: -1, ibfint: 1, ihecor: 0}
radiative_transfer: {irte: 0, ibc: 3, ifryb: 0, ioptab: 0, ifmol: 0}
nlte: {ifali: 5, ifpopr: 4, jali: 1}
irradiation: {trad: 0.0, wdil: 0.0}
temperature: {tfloor: 8000.0, tdisk: 0.0, tmolim: 9000.0}
# nst 冷门关键字逃逸口(诊断打印 IPR*/内部开关 IOP* 等 ~200 个)
# 示例(当前未启用):
# nst_extra_keys:
# - [CUTBAL, "0.3"]
# - [NDGREY, "20"]
nst_extra_keys: []
# ---- 收敛链 ----
# 参与计算的元素集 / 电离态 **不再由链配置(metals)控制**,而是在上方
# tlusty_input.dot5.atoms8 元素)与 dot5.ions(22 行)中显式声明;此处每个
# step 只控制阶段参数(lte/ltgray/ilvlin/niter/chmax 等)。
# 已验证的三步配方 (tests/sdB_spectra/GUIDE.md 实测, Teff=35000 logg=5.5):
# LTE grey (T T, NITER=0) -> NLTE 连续谱 (nc, ilvlin=0) -> NLTE 谱线 (nl, ilvlin=100)
# nc 步是关键:在不考虑谱线扰动下收敛 NLTE 电离平衡,给 nl 一个稳定种子。
# 跳过 ncgrey -> 完整 NLTE)会发散。
#
# 各 step 的隐式默认值在此显式写出(与代码兜底等价,见下):
# - chmax: 0.001 —— 收敛阈值(runner.rs 兜底默认;缺省时与原兜底完全一致)
# - itek / ichang / idlte / iacc / orelax 留空 → 用 tlusty 内部默认(未结构化为可写值)。
# 注意:设 CHMAX=0.1 会让 nc 提前停止,给 nl 一个坏种子导致发散——勿调大。
#
# nc 的 NITER=10 是实测最优(tests/sdB_spectra/GUIDE.md NITER 扫描结论):
# - NITER=10 总耗时 12.4min35000K CNO 完整模型)
# - 光谱精度 vs NITER=50 差异仅 6e-6(完全等价)
# - NITER=50 浪费 2.2× 时间,NITER=200/500 更浪费且无收益
# 物理上 nc(纯连续谱)缺少谱线约束,外层温度永不真正收敛——追求高 NITER
# 没意义。nl(含谱线)会自修正到正确解(流量差异 <3e-12)。
tlusty_chain:
- {label: lte, lte: T, ltgray: T, ilvlin: 0, require_converged: false, niter: 0, chmax: 0.001}
- {label: nc, lte: F, ltgray: F, ilvlin: 0, require_converged: false, niter: 10, chmax: 0.001}
# nl 步加 orelax=0.5:谱线(ilvlin=100)扰动大,欠松弛阻尼 Newton 步长振荡,
# 避免中温区(20-45kK) nl 阶段 relc 振荡发散(实测验证)。
- {label: nl, lte: F, ltgray: F, ilvlin: 100, require_converged: true, niter: 100, chmax: 0.001, orelax: 0.5}
# 种子热启动链(seed_step 策略用,cold_run 失败后回退)。
# seed_nc 从已收敛邻居热启动,起点扰动小,用更激进的 orelax=0.3;
# nl 与 cold_run 链一致 orelax=0.5。空时 executor 回退 default_seed_chain()(代码内置同值)。
seed_chain:
- {label: seed_nc, lte: F, ltgray: F, ilvlin: 0, require_converged: false, niter: 20, chmax: 0.001, orelax: 0.3}
- {label: nl, lte: F, ltgray: F, ilvlin: 100, require_converged: true, niter: 100, chmax: 0.001, orelax: 0.5}
# ---- 光谱合成 SYNSPEC 输入参数(fort.55 控制卡,9 行子结构体)----
# 启用开关见下方 synspec_stage 块。
#
# fort.55 字段与 synspec54.f 的 READ(55,*) 语句逐行一一对应,字段名严格使用
# SYNSPEC 源码变量名。各行含义见 crates/common/src/config.rs 的 Fort55Line* 文档注释。
# 仅列出与默认值不同的字段;未列出的字段走 SynspecInput::default()(见 config.rs)。
#
# 重要修复:
# - line1.idstd 从旧实现的 50(错位 bug,强制最深层)修正为 0(自动取 2*ND/3≈33,
# τ≈1 参考层)。此变更影响光谱线强归一化,修正后所有光谱需重算(见 §5)。
# - 新增 line_mol(分子表行):SYNSPEC 在 IMODE∈[-3,1] 时会额外读这一行,旧实现漏生成
# 导致 VTB 行被吞、vturb 被错误覆盖。现默认 nmlist=0(无分子线)。
# - line_vtb 默认 -1.0(不覆盖大气 vturb=2 km/s);如需自定义湍流速度设非负值。
synspec_input:
line1: {imode: 0, idstd: 0, iprin: 1} # 行1: IMODE, IDSTD(=0 自动 2ND/3), IPRIN
# line2-line5 走默认(INMOD=1 TLUSTY 模型 / IOPHLI 被 SYNSPEC 强制 0 / IFREQ=1 INLTE=1 / Stark 表全 0
line6:
alam0: 3000.0 # 光谱波长起始点 (Å)
alast: 7000.0 # 光谱波长终止点 (Å)
cutoff0: 10 # 谱线截止距离(推荐 5-10
cutoffs: 0 # 连续谱间距(0→内部取 3
relop: 0.0001 # 线心/连续不透明度最小比
space: 0.01 # 相邻频率点最大间距 (Å)
# line_mol (nmlist=0 无分子表) / line_vtb (vtb=-1 不覆盖大气 vturb) / line_ang (NMU0=0 不算比强度) 走默认
# ====================================================================
# 阶段独立配置(见 docs/task_engine_decoupling_design.md §2-§3
#
# TLUSTY / SYNSPEC 视为正交独立阶段,每阶段三维:
# enabled : 是否执行该阶段
# policy : skip_converged(增量) | force_recompute(强制重算) | skip_failed(忽略失败)
# strategies : 策略链队列,按回退优先级排序;节点执行 strategies[0],失败后服务端弹出首项
#
# 此处显式声明与旧 seed_step_fallback/synspec 块等价的默认配置,便于前端面板编辑。
# 旧字段(seed_step_fallback / synspec)保留作回退兜底,resolve 方法优先用本块。
# ====================================================================
tlusty_stage:
enabled: true
policy: skip_converged
strategies: [cold_run, seed_step]
# ---- 种子步进回退(旧字段,保留兼容;新配置见下方 tlusty_stage 块)----
# 冷启动失败时,自动用已收敛的邻居模型作种子,用 LTGRAY=F 热启动重试。
# 这是高温 He-poor / 富金属区收敛的关键(见 EXPERIENCE.md §5Y)。
# 失败的冷启动结果会备份到 <model>.coldfail/ 目录。
seed_step_fallback: true
synspec_stage:
enabled: true
policy: skip_converged
strategies: [standard]
# ---- 执行参数 ----
timeout_sec: 7200 # 单模型墙钟时间上限(120分钟)