# 收敛恒星光谱的物理正确性保证调研 > 调研日期:2026-08-04 > 范围:TLUSTY 208 + SYNSPEC 54 计算的恒星大气与光谱的**物理正确性**保证方法。 > 前置文档:`docs/task_failure_detection_analysis.md`(程序"是否崩溃/收敛"的判定,是本调研的下层)。 > 核心命题:**程序正常退出(rc=0)且 max_relc < chmax ≠ 光谱在物理上正确**。本文调研介于两者之间的静默错误来源与验证方法。 > 方法:源码级静态分析 + 天体物理方法学综述 + 三方独立复核。 --- ## 0. TL;DR 当前 pipeline 对光谱正确性的保证**基本停留在"数值收敛"层面**,完全没有做物理不变量校验。三方调研发现: 1. **最高 ROI 缺口**:TLUSTY 已经无条件地把**能量守恒诊断**(`TOTAL SURFACE FLUX`、逐深度 `RAD/TOT`、`CON/TOT`、`(RAD+CON)/TOT`)写进已归档的 `.6` 文件,**却从未被任何 Rust 代码解析**。这是 Hubeny 官方推荐的 1% 判据,零成本可得,是物理正确性的第一道硬门槛。 2. **系统性的配方风险**:`fort55_writer.rs` 写的字段 `idrv/ifreq` 与 SYNSPEC 实际读取的 `IDSTD/IPRIN` 错位(已核实),导致所有光谱的标准深度参考点与输出详尽度偏离预期。 3. **网格级错误传播**:通过 `converged && !nan` 门控上传的种子大气(`.7`),会把"伪收敛但物理未平衡"的点扩散给整个物理族——这是网格计算特有的静默放大机制,现有检查无法识别。 4. **完整的方法学分层**(§6):硬门槛(线上每点)→ 质量监控(抽样)→ 深度核查(线下基准比对),覆盖辐射平衡、光谱自洽、网格一致性、外部基准四个维度。 --- ## 1. 当前已产出但未利用的物理诊断 > 这是后续做正确性校验的基础——很多信息 TLUSTY/SYNSPEC 已经产出,只是我们没解析。 ### 1.1 能量守恒诊断(最关键,零成本可得) TLUSTY 在 `LFIN`(最终迭代)时由 `OUTPRI` 子程序无条件写出,位于 `.6` 文件(unit 6,已归档): ``` TOTAL SURFACE FLUX 6.77712339D+12 ← 实际积分通量 TOTF ID MASS TAUROSS TEMP NE DENS P_gas LOG(G_rad) RAD/TOT CON/TOT (RAD+CON)/TOT 1 ... 8.913E-01 0.000E+00 8.91264E-01 ``` - `FLTT = SIG4P * TEFF**4`(预期通量 = σTeff⁴/4π,`SIG4P` 见 `BASICS.FOR:51`) - `RAD/TOT` = 辐射通量 / σTeff⁴ - `(RAD+CON)/TOT` = 总通量(辐射+对流)/ σTeff⁴ —— **此列应≈1.0** - 实测样本(发散模型 max_relc≈1e21):`(RAD+CON)/TOT ≈ 0.891`,即 **11% 能量守恒违反**;收敛良好模型应≈1.0 **关键事实**:`.6` 已在归档白名单(`STAGE_SNAPSHOT_SUFFIXES` 含 "6"),但 `crates/` 下无任何代码解析它。**数据已就位,只差一个 `.6` 解析器写入 conv.json**。 ### 1.2 辐射平衡逐深度残差(被覆盖丢失) TLUSTY `RECHCK` 子程序(`tlusty208.f:49854`)在 LFIN 时无条件调用,逐深度计算 `re=(吸收−发射)/发射` 写入 unit 17(fort.17)。但 unit 17 随后被 SYNSPEC `OUTPRI` 覆盖写连续谱(`synspec54.f:3371`)——**成功路径下 RECHCK 输出永久丢失**,仅 SYNSPEC 失败时 `.cont` 里残留的才是 RECHCK 表(这也是 `.cont` 后缀二义性的来源)。 修复方向:仿照 `.bfac`/`.emflux` 的快照做法,在 RECHCK 后/SYNSPEC 前快照 fort.17。 ### 1.3 其他未启用 / 未解析的诊断 | 诊断 | 子程序 | unit→文件 | 启用条件 | 现状 | |------|--------|----------|---------|------| | 能量守恒总表 | `OUTPRI` | 6→`.6` | 无条件 | **已产出,未解析**(最高 ROI) | | 辐射平衡逐深度 | `RECHCK` | 17→`.cont` | 无条件 | **被 SYNSPEC 覆盖丢失** | | 统计平衡残差 | `CHCKSE` | 16→fort.16 | `ICHCKP≠0`(nst 未设) | **未启用** | | 冷却/加热率 | `COOLRT` | 86/87/88 | `ICOOLP≠0`(nst 未设) | **未启用** | | 出射辐射场谱 | `OUTPRI` | 13→fort.13 | 无条件 | **白名单排除**(result_filter.rs:179) | | TLUSTY 出射谱 | `OUTPRI` | 14→`.emflux` | 无条件 | **已快照归档,未解析**(可做 bolometric 积分) | | b 因子(NLTE 偏离) | `OUTPRI` | 12→`.bfac` | 无条件 | **已快照归档,未解析** | | SYNSPEC 谱线统计 | START/OUTPRI | 6→`.log` | 无条件 | **已归档,未解析**(含 `LINES-TOTAL`、波长范围、等效宽度) | ### 1.4 conv.json 的现状 `ModelSummary` / `StageSummary` / `ConvCheckResult`(`models.rs`)记录的字段**全部是数值收敛指标**(max_relc, last_iter, worst_depth, synspec_rc 等),**没有任何物理正确性字段**(能量守恒、辐射平衡、统计平衡残差)。 --- ## 2. 静默错误的物理来源 > "程序正常退出但光谱物理错误"的四层来源,按严重度排序。每层给出源码证据与可检测性。 ### 2.1 第一层:TLUSTY 大气结构错误(光谱错误的根因) | 错误来源 | 物理后果 | 源码证据 | 当前是否捕获 | 严重度 | |---------|---------|---------|------------|--------| | **NITER 截断被当收敛** | 大气未达统计平衡,布居数错误 | `tlusty208.f:14728` `LFIN=ABS(CHMX).LE.CHMAX.OR.ITER.GE.NITER`,OR 短路:CHMX 再大也会因 `ITER≥NITER` 判 LFIN | 部分(`conv_check.rs` 重判 max_relcIP 才替换 | 未捕获 | 高 | | **波长网格步长固定且窗口窄** | 窄线被漏掉,谱"正常但缺线" | `fort55_writer.rs:12` SPACE=0.01;默认窗口仅 1400-1410Å(`runner.rs:522`) | 未捕获 | 中-高 | | **线表缺失(只链 fort.19)** | 缺关键谱线,有计数但无"应有线却缺失"校验 | `runner.rs:540` symlink 单一线表;`:9157` NLIN0 计数 | 未捕获 | 高 | ### 2.3 第三层:数据传递与种子继承(网格级错误放大) | 错误来源 | 物理后果 | 源码证据 | 当前是否捕获 | 严重度 | |---------|---------|---------|------------|--------| | **★种子继承的错误传播** | 伪收敛点的 `.7` 通过 `converged && !nan` 门控上传为种子,被相邻 SeedStep 点热启动,**错误沿网格拓扑传播**;`directed_cno_distance` 倾向选贫方向,一个坏种子可污染整个 Teff/logg 族 | `executor.rs:193` 种子门控;`seed_finder.rs` 最近邻选种 | **未捕获**(坏种子本身"通过"了所有检查) | **极高** | ### 2.4 第四层:编译/数值精度 | 错误来源 | 物理后果 | 源码证据 | 当前是否捕获 | 严重度 | |---------|---------|---------|------------|--------| | **生产编译无 -fcheck/-ffpe-trap** | 数组越界、IEEE 异常 → rc=0 + 静默写越界内存,产出无 NaN 标记但物理错误的大气 | `deployment.md:86,90` `gfortran -fno-automatic -O3` | 未捕获(详见 task_failure_detection_analysis.md §4 漏洞 3) | 高 | > 详见 `task_failure_detection_analysis.md` 的 gfortran 运行时错误退出码实测表。 --- ## 3. 天体物理验证方法学 > 每个方法标注:验证的物理不变量、操作步骤、容差判据、所需数据、实现难度、线上/线下。 ### 3.1 大气模型层面(TLUSTY 产出) | 方法 | 验证的物理不变量 | 容差/判据 | 所需数据 | 难度 | 时机 | |------|----------------|----------|---------|------|------| | **通量守恒** | 每深度 πF(rad+conv)=σTeff⁴ | `(RAD+CON)/TOT` 偏离 1 ≤1%(Hubeny 官方判据);任一深度 >5% 直接判坏 | `.6` 末表 | 低 | **线上** | | **max_relc 收敛门槛** | 状态向量相对修正已可忽略 | < chmax(默认 10⁻³,对 sdB/早型星合理;精密线分析可收紧到 10⁻⁴) | `*_chmax*.9` | 低(已实现) | **线上** | | **假收敛排查** | max_relc 单调下降 ≥3 个量级 | 初始/最终 max_relc ≥10³ | fort.9 全序列 | 中 | 抽样 | | **NaN/Inf 否决(收紧)** | 所有深度点温度/密度为有限物理值 | **任意 1 行命中即否决**(当前 10% 阈值过松) | `.7` | 低 | **线上** | | **温度结构边界** | T(τ) 落在物理合理范围 | 表层 T ≲ 2-3×Teff;idstd 处 T≈(2/3)Teff;总体 10¹-10⁸ K | `.7` | 中 | 抽样 | | **统计平衡残差(NLTE)** | 跃迁平衡 R_ij·n_i=R_ji·n_j、粒子数守恒 | b 因子无 NaN/Inf;关键能级 b∈10⁻³-10³ | `.bfac` | 中 | 抽样 | **对 TLUSTY 的已知坑**:(a) fort.9 缺失分支无条件判收敛 + 虚构 `best_max_relc=0.0`(见 task_failure_detection_analysis.md 漏洞 2);(b) Kantorovich 加速的伪收敛风险;(c) 表层(worst_depth=1)最易出 NaN。 ### 3.2 光谱合成层面(SYNSPEC 产出) | 方法 | 验证的物理不变量 | 容差/判据 | 所需数据 | 难度 | 时机 | |------|----------------|----------|---------|------|------| | **NaN/负值/零行否决(最关键)** | 归一化谱∈[0,1],绝对流量≥0,无 NaN/Inf | **0 容忍**(任意一个即判坏) | `.spec`、`.cont` | 低 | **线上** | | **Rayleigh-Jeans 尾 Planck 检验** | 长波端连续谱 → Bλ(Teff) | 斜率与 Bλ(Teff) 一致;偏离 >20% 异常 | `.cont` + Teff | 中 | 抽样 | | **总积分流量能量守恒** | ∫Fλ dλ ≈ σTeff⁴(bolometric) | 偏离 <1-2% | `.emflux`(全频率范围) | 中 | 抽样 | | **连续谱自洽(TLUSTY vs SYNSPEC)** | 同波长点 `.emflux` 与 `.cont` 水平一致 | 连续谱区差异 <1-2% | `.emflux` + `.cont` | 低 | 抽样 | | **Balmer 线基准** | Hα/Hβ EW 随 Teff/logg 已知行为 | 线心深度∈(0,1);sdB 的 Hβ EW 约 5-15Å;高 Teff(>30kK) 不应异常强 | 光学 `.spec` | 中 | 抽样 | | **He 线电离序列** | He II/He I 强度比随 Teff 单调 | 比值突变 = NLTE 电离平衡错 | 光学 `.spec` | 中 | 抽样 | **归一化谱 vs 绝对流量谱**:归一化谱只验线形/线强,不能验能量守恒;绝对流量谱(`.emflux`、`.cont`)才能验通量守恒与 Planck。两者必须分别处理。 ### 3.3 网格层面(内部一致性) | 方法 | 验证的物理不变量 | 容差/判据 | 所需数据 | 难度 | 时机 | |------|----------------|----------|---------|------|------| | **相邻点平滑性(一阶差分)** | 光谱随参数连续变化 | 连续谱单步 Δ<10-15%;线 EW<30% | 全网格 `.cont`/EW | 中 | 线下 | | **二阶差分 / 离群点检测** | 光谱无孤立异常 | r>4σ 或 \|残差\|>20% 标 outlier | 全网格光谱 | 中 | 线下 | | **沿等参数线单调性** | Balmer/He 线随 Teff/logg 已知单调趋势 | 出现锯齿/反转 = 可疑 | 全网格光谱序列 | 低 | 线下 | | **收敛质量地图** | max_relc 在网格上无孤立坏区 | 孤立高 max_relc 点(邻居都收敛)= 可疑 | 全网格 conv.json | 低 | 线下 | **已知坑**:网格在 80kK+He-poor+富金属区有真实物理极限(CNO 高价离子主导不透明度,线性化无法阻尼)——这片成片失败是物理真实的,不应误判为 bug;但**孤立单点失败**(邻居都好)才需要复查。 ### 3.4 外部基准比对(ground truth) | 基准 | 验证什么 | 容差/判据 | 数据来源 | 难度 | 时机 | |------|---------|----------|---------|------|------| | **Lanz & Hubeny 2003/2007 网格** | 与社区标准 TLUSTY/SYNSPEC 网格逐点一致 | 连续谱 <1-2%,线轮廓 <5% | tlusty.oca.eu(OSTAR2002/BSTAR2006,免费) | 中 | 建库时 | | **NLTE-OBGRID** | Hubeny 更新版网格(更完整 H 原子) | 同上 | MAST archive.stsci.edu/hlsp/nlte-obgrid | 中 | 建库时 | | **PHOENIX / CASTELLI / ATLAS9** | 与独立代码(不同物理近似)合理一致 | 光学几个百分点;UV(400nm)可达 10-20% | STScI | 中-高 | 建库时 | | **CALSPEC 实测标准星** | 终极 ground truth | Bohlin+2020:TLUSTY 白矮星网格 1500Å-30μm 一致到 **1%** | MAST(GD153/GD71/G191B2B) | 高 | 深度核查 | | **Gaia FGK 基准星** | 非光谱学基本参数(干涉/角直径)校验 | gold standard | blancocuaresma.com/s/benchmarkstars | 高 | 深度核查 | **实测比对必须考虑的系统误差**:消光(RV=3.1)、视向速度、instrumental broadening(需 ROTINS 卷积)、距离/标度因子。 --- ## 4. 物理红旗清单(一票否决) 以下任一出现即光谱不可信,必须标记复查: | 红旗 | 物理含义 | 检测方法 | |------|---------|---------| | 连续谱出现负值或 NaN | 辐射转移数值失败 | `.spec`/`.cont` 任意点 <0 或 NaN | | 归一化谱线心深度 >1(流量 <0) | 线吸收过度/数值错 | 归一化谱任意点 <0 或 >1.05 | | `.spec` 全零或行数异常少 | SYNSPEC 中途 quit 留脏数据 | 行数 <预期×0.9 或全零 | | 总积分流量偏离 σTeff⁴ >2% | 能量不守恒 | 积分 `.emflux` | | 通量守恒表末列偏离 1 >1%(任一深度) | 辐射平衡未达 | 读 `.6` 末表 | | 表层温度 >>Teff(如 >3×Teff) | T(τ) 结构非物理 | 读 `.7` 表层 T | | 热星(Teff>30kK)Balmer 线异常强 | NLTE 电离算错 | 测 Hα/Hβ EW 比对基准 | | 连续谱斜率与 Teff 不符 | 温度结构错 | RJ 尾比对 Bλ(Teff) | | 沿 Teff 序列 Balmer/He 线非单调 | 局部点 NLTE 错 | 网格级单调性检查 | | 孤立单点与四邻插值偏离 >20% | 该点异常 | 离群点检测 | --- ## 5. fort.55 字段错位问题(已核实的系统性 bug) 这是一个影响**所有光谱**的系统性问题,值得单独记录。 ### 5.1 事实 - `fort55_writer.rs:5` 生成的第一行:`imode, idrv, ifreq`(值如 `0, 50, 1`) - SYNSPEC `synspec54.f:253` 实际读取:`IMODE, IDSTD, IPRIN` - 即 **`idrv=50` 被当作 `IDSTD=50`,`ifreq=1` 被当作 `IPRIN=1`** ### 5.2 影响 - **IDSTD=50**(=ND,最深层):SYNSPEC 的标准深度(`synspec54.f:2155`)本应自动取 `2*ND/3≈33`,现被强制取最深层。标准深度是谱线多普勒宽度、Stark 加宽的参考层,取错层会让线翼轮廓参考错误深度。 - **IPRIN=1**:SYNSPEC 的输出详尽度开关,影响 `.log` 里打印的诊断量多少。 - **第 3 行 `IOPHLI=0`**(`fort55_writer.rs:7` 第一个 0):`synspec54.f:255` 读取,IOPHLI 控制 Lyman 线翼处理,0 可能关闭相关处理。 ### 5.3 处置 这是配方层面的 bug,需要单独修复(修正 `fort55_writer.rs` 的字段语义,使 IDSTD=0 自动、IPRIN/IPRIND 按需设置),并重算受影响的光谱。本调研仅记录,不含修复实现。 --- ## 6. 分层验证策略建议 > 按"必须做 / 建议做 / 可选做"分层,标注每项的现状与所需投入。 ### 第一层:硬门槛(线上,每个点必跑,0 容忍,失败即标记重算) | # | 校验项 | 现状 | 所需投入 | 依据 | |---|--------|------|---------|------| | 1 | SYNSPEC `.spec`/`.cont` 内容校验(NaN/Inf/负值/全零/行数) | **未做**(漏洞 1) | 低 | task_failure_detection_analysis.md P0 | | 2 | 大气 NaN 否决收紧到 0 行容忍 | 10% 阈值过松(漏洞 4) | 低 | conv_check.rs:212 | | 3 | max_relc < chmax + is_finite + fort.9 真实存在 | 已实现,但 fort.9 缺失分支有虚构值(漏洞 2) | 低 | runner.rs:417 | | 4 | **通量守恒 `(RAD+CON)/TOT` 偏离 1 ≤1%**(从 `.6` 提取) | **未做(数据已就位)** | 低(写一个 .6 解析器) | §1.1,Hubeny 官方判据 | ### 第二层:质量监控(线上抽样 + 线下定期) | # | 校验项 | 现状 | 所需投入 | |---|--------|------|---------| | 5 | 总积分流量 vs σTeff⁴(`.emflux`,偏离 <2%) | 未做,数据已归档 | 中(bolometric 积分) | | 6 | Rayleigh-Jeans 尾 Planck 斜率检验 | 未做 | 中 | | 7 | TLUSTY `.emflux` 与 SYNSPEC `.cont` 连续谱自洽 | 未做 | 低 | | 8 | 假收敛排查(max_relc 下降 ≥3 个量级) | 未做 | 中 | | 9 | 收敛质量热图(网格级 max_relc 分布) | 未做 | 低(数据在 conv.json) | | 10 | 温度结构边界(表层 T、idstd 处 T) | 未做 | 中 | ### 第三层:深度核查(线下,建库时 + 每次配方变更时) | # | 校验项 | 所需投入 | |---|--------|---------| | 11 | 与 Lanz & Hubeny 2003/2007 / NLTE-OBGRID 重叠点逐波长比对 | 中 | | 12 | 与 PHOENIX/CASTELLI 独立代码比对 | 中-高 | | 13 | 与 CALSPEC/SDSS 实测标准星比对 | 高 | | 14 | Balmer/He 线序列单调性与基准 | 中 | | 15 | 网格二阶差分离群点检测 | 中 | | 16 | 统计平衡残差 / b 因子合理性(`.bfac`) | 中 | ### 配方变更触发规则 任何以下变更必须重跑第三层深度核查:CHMAX/NITER/ND 改动、原子模型/线表(fort.19)更新、TLUSTY/SYNSPEC 重编译(尤其加 `-fcheck`/`-ffpe-trap`)、丰度网格范围调整、**fort.55 字段修复(§5)**。 --- ## 7. 综合判断 **当前 pipeline 在"光谱物理正确性校验"上基本没做** —— 只做了数值收敛性(max_relc)和最低限度的完整性(`.7` 无 NaN、synspec 退出码),完全没有能量守恒、辐射平衡、统计平衡这三项核心物理不变量校验。 **投入产出比排序**: 1. **P0:解析 `.6` 的能量守恒诊断**(§1.1)—— 数据已就位,Hubeny 官方 1% 判据,是物理正确性的第一道硬门槛。同时修 `.spec` 内容校验(§6 第一层)。 2. **P1:fort.55 字段错位修复**(§5)—— 影响所有光谱的系统性 bug,需修正后重算。 3. **P1:网格级种子传播校验**(§2.3)—— 这是网格计算特有的静默放大机制,可通过"同一物理族下游点的 max_relc/通量守恒分布异常"间接检测。 4. **P2:质量监控层**(§6 第二层)—— bolometric 积分、Planck 检验、连续谱自洽。 5. **P3:建库时基准比对**(§6 第三层)—— 与 Lanz & Hubeny 网格逐点比对是最直接的同代码 ground truth。 --- ## 8. 参考资料 **官方文档** - Hubeny 2017, "A Brief Introductory Guide to TLUSTY and SYNSPEC"(arXiv:1706.01859)—— 通量守恒 1% 判据、假收敛、ND=50 B 星例、改丰度警告 - TLUSTY User's Guide III(arXiv:1706.01937)—— fort.9 收敛日志格式、unit 6 辐射平衡表 - TLUSTY User's Guide IV, Hubeny 2021(arXiv:2104.02829)—— CHMAX=10⁻⁴ 高精度例 **社区基准网格(ground truth)** - OSTAR2002 / BSTAR2006(tlusty.oca.eu)—— Lanz & Hubeny 2003/2007 社区标准网格 - NLTE-OBGRID(MAST archive.stsci.edu/hlsp/nlte-obgrid)—— Hubeny 更新版 - WD-GRID(MAST archive.stsci.edu/hlsp/wd-grid)—— Bohlin+2020 白矮星 NLTE 网格,1500Å-30μm 对 CALSPEC 1% 一致 **交叉代码比对** - Witzke+2021, MPS-ATLAS(A&A)—— 三代码流量差异:~400nm 最大,其他波段几个百分点 - CASTELLI/Kurucz ATLAS9(STScI) **本仓库内相关文档** - `docs/task_failure_detection_analysis.md` —— rc 不可靠性、fort.9/NaN 阈值漏洞、gfortran 退出码实测(第一层硬门槛的依据) - `docs/tlusty_result_artifacts.md` —— fort 单元语义、`.emflux`/`.bfac` 快照、TLUSTY fort.14 与 SYNSPEC `.spec` 关系 - `docs/PIPELINE.md` —— 阶段链、nst 配方(ND=50、默认 CHMAX=0.001)、物理极限区 **源码证据** - 能量守恒诊断:`tlusty208.f:14179-14191,14271-14273`(OUTPRI);`:49854`(RECHCK);实测 `hotsd/tlusty (副本)/hhe35nl.6:334-339` - fort.55 错位:`fort55_writer.rs:5` vs `synspec54.f:253`(已核实) - 种子传播:`executor.rs:193`、`seed_finder.rs`