Files
DCTS/.agents/skills/tlusty-synspec-test/references/physics-checks.md
T
fmq b058e66722 feat(all): NaN 伪收敛否决与 nl_tight 能量回退、emflux 检验 4π 修正、nst 行宽与种子边界修复、gfATO 谱线表接通与网格加密 9216 点、阶段分项统计与跳板机部署
物理修复(400 失败点归因,见 docs/failed400_nan_pseudo_convergence_2026_08_17.md):
- runner: 阶段 converged 后复查 fort.7,含 NaN/Inf 即否决(fort.9 全零伪收敛,
  曾致 261 点误跳过 nl_direct 回退);否决阶段不产出种子,阻断污染传播
- runner: nl_tight 回退——仅能量边际失败时以 CHMAX 收紧 10× 从自身模型续迭代,
  残差降幅 ~10×;execute_tlusty_stage 抽取供主链与回退共用
- conv_check: fort.14 为 Eddington 通量 Hλ,积分需乘 4π 再比 σTeff⁴
  (旧版 ratio 稳定 0.0796=1/4π,全点系统性假阳性)+ 回归测试
- nst_writer: 单行超 80 字符被 TLUSTY 静默截断,IFALI/JALI/TRAD 等从未生效;
  按 75 字符自动换行
- seed_finder: Teff 容忍度改含边界 <=,相邻 5000K 档恢复互为种子 + 回归测试

谱线表与网格:
- 默认线表 gfVIS99 → gfATO(全波段 18-23000Å),TaskSpec.linelist 支持工作流
  级覆盖,节点按需下载(进程互斥锁防并发重复下载 238MB)
- sdB_cno Teff 加密至 5000K 步长,432 → 9216 点;tlusty/synspec 静态二进制更新

统计与部署:
- grid 汇总改按 tlusty_status/synspec_status 分项计数,新增 tlusty_failed/
  synspec_failed/synspec_pending,前端详情页双视图适配
- deploy/fetch_results 支持跳板机 ProxyJump 与 SSH 主连接复用,fetch 新增 --force;
- Docker 构建支持 CARGO_MIRROR/USE_MIRRORS 国内镜像参数;移除 tools/ 拷贝
- 新增 tlusty-synspec-test skill 与 6 篇根因分析/验证文档
2026-08-17 23:55:26 +08:00

5.7 KiB
Raw Blame History

物理校验判据与 fort.7 解析(DCTS 权威)

参考源码:dcts/crates/common/src/conv_check.rs物理性判定必须以这里的逻辑为准,不要用经验标准。

温度结构判据:check_temperature_structure

conv_check.rs:463。返回 TempStructCheckResultvalid = violations.is_empty()。三项全过才算物理:

  1. 表层 T < max_factor × Teff
    • surface_ratio = temps[0] / tefftemps[0] = 最浅深度 = 表层)
    • surface_ratio > max_factor(默认 3.0)→ 违规
    • teff <= 0 → ratio = +Inf → 必违规
  2. 每个深度 T ∈ [temp_floor, temp_ceiling]
    • 默认 [10.0, 1.0e8] K
    • 任一深度 T 越界 → 违规
  3. 无 NaN/Inf
    • 非有限 T(NaN/Inf)→ 违规(被第 2 条的 is_finite() 捕获)

报告首个违规深度。

物理参考(不是硬判据,仅辅助判断)

  • Eddington 灰大气T(τ=0) ≈ 0.84 × Teff。60kK 模型表层应约 5 万 K。
  • 生产基准:已收敛种子 t60000_g5.0_he-2_c-3_n-4_o-4.7 表层约 0.78×Teff。
  • 内部温度:无 1e7+ 异常隆起(如某修复前组合曾出现 6.2e9 K 内部尖峰)。

⚠️ 判据修正历史(为何只信 DCTS 三项)

  • 旧经验"表层应 0.51.5×Teff"过严,曾误判物理模型为不物理(把表层 0.78×Teff 的好模型判死)。
  • 旧经验"表层应 36 万 K":对 60kK 模型偏低,曾误判。
  • 正确做法:只用"表层 < 3×Teff 且各深度 ∈ [10,1e8] 且无 NaN"三项硬判据,Eddington 0.84 仅作物理直觉参考。

fort.7 大气模型文件格式与解析

conv_check.rs:470-502,对应 TLUSTY 源 tlusty208.f:14066-14108OUTPUT 子程序):

第 1 行:           ND NUMPAR
                   ND = 深度点数; NUMPAR = 每深度参数数 = NLEVEL + NUMLT
接下来 ceil(ND/6) 行: DM 列阵(质量深度),每行 6 个值(FORMAT 502)
接下来 ND 个深度块:    每块 ceil(NUMPAR/5) 行(FORMAT 503,每行 5 值)
                   每块【第一行第一个 token】= 该深度的温度 TEMP(ID)
                   块内其余 = 电子密度、质量密度、NLTE 能级布居/ departure 系数

temps[0] = 表层(ID=1,最浅);temps[nd-1] = 底层(最深)。

解析算法(check_temperature.py 复刻)

1. 读第1行 → nd, numpar = 前两个 token。任一为 0 → 跳过(返回 None,不判失败)
2. dm_lines   = (nd + 5) // 6      # 跳过 DM 列阵
   block_lines = (numpar + 4) // 5  # 每深度块行数
3. 跳过 dm_lines 行
4. 对 nd 个深度,每个:
     取块第一行第一个 tokenparse_fortran_float → temps[id]
     跳过 block_lines - 1 行
5. 检查三层判据

parse_fortran_floatconv_check.rs:44)兼容 Fortran 无-E 记数法:指数 ≥100 时 gfortran 挤掉 E,如 -1.35E+118 输出成 -1.35+118。解析:先标准 parse;失败则正则 ^([+-]?[\d.]+)([+-]\d+)$ 在尾符号前插 E 再 parse;溢出返回 ±Inf。

参考实现见 conv_check.rs:1339 make_dot7(temps) —— 构造测试用 fort.7 的辅助函数(写 ND NUMPAR=3,一行 DM 占位,每深度一行 T 1.0E+10 1.0E-15)。

收敛轨迹判据:check_fort9

conv_check.rs:68。解析 fort.9(迭代收敛记录)。

fort.9 格式

 RELATIVE CHANGES OF VECTOR PSI
  ITER  ID    TEMP        NE       POP     RAD      MAXIMUM   ilev   ifr
    1   50 -8.46E-04  1.53E-03  2.51E-02 -2.20E-03  2.51E-02   74    1
    1   49 ...
    ...
    2   50 ...

每行 = 一次迭代在一个深度点的相对变化:ITER(迭代号) ID(深度) TEMP NE POP RAD MAXIMUM(本次迭代本深度的最大相对变化) ilev ifr

判据

  • 每次 ITER 的 max_relc = 该 ITER 所有深度行 |MAXIMUM| 的最大值
  • 末次迭代max_relc = 整个阶段的结果
  • 收敛 = max_relc < chmax(默认 0.001)且 is_finite()
  • 单调下降 = 健康;突然涨几个数量级 = 雪崩发散
  • chmax <= 0 或非有限 = 非法配置(返回错误,max_relc=Inf

STOP 检测(fort.6

fort.6stdout)里的 **** STOP in SOLVE after ITER N = 求解器发散中止。conv_check.rsSOLVER_STOP_RE 匹配。这是比"非零 rc"更具体的发散信号。

NaN / 伪收敛检测

NaN 匹配模式(与 Rust 一致)

conv_check.rs:18 NAN_RE_PATTERN = (?i)(\bnan\b|\binf(?:inity)?\b|\*{3,}|[eE]\+(?:3\d{2}|[4-9]\d{2,}))

匹配:nan / inf / infinity / ***(3+星) / 正指数 E+300E+999(超高正指数视同数值无效,因发散时布居数变化可达 ±100±200 量级但温度/流量场溢出用 ***E+300+)。

相关函数:

  • atmosphere_has_nanL246):扫 fort.7 全部数值 token
  • spec_is_validL290):扫光谱文件,同正则

伪收敛陷阱(必查)

max_relc 极低 ≠ 收敛。若模型已 NaN在 NaN 上迭代的相对变化为 0,会伪装成 max_relc≈0 的"收敛"。

正确流程(每次事后审查都要做):

  1. check_fort9.py 看轨迹 + STOP + max_relc
  2. check_temperature.py 看温度结构三项(含 NaN 检查)
  3. 两者都过才算真收敛;仅 fort.9 看着收敛但 fort.7 有 NaN = 伪收敛

其他 DCTS 校验(了解即可)

conv_check.rs 还提供(生产链用,测试时按需):

  • check_energy_conservationL374):能量守恒
  • check_emflux_bolometricL578):辐射通量
  • check_convergence_traceL691):收敛轨迹综合
  • check_bfactorL759):departure 系数(.bfac 文件,同样 ND NUMPAR + DM 头格式)
  • extract_failure_hintL851):失败原因提取

测试中常用前两类(温度结构 + 收敛轨迹)即可覆盖绝大多数判断。