物理修复(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 篇根因分析/验证文档
28 KiB
冷启动 nc 阶段不收敛:源码根因 + 穷举复测(2026-08-13)
数据来源:data/salvage/(8320 任务产物)+ /home/fmq/下载/dcts.db(server 快照)
源码:tlusty/tlusty208.f
复测目录:test/20260813_cold_nc_trace_fix/convergence/t60000_g5.0_he-4_c-4_n-4_o-3_cold/(代表点)
前序文档:tlusty_divergence_root_cause_2026_08_11.md、cold_start_fix_2026_08_12.md
本文是对前序"参数调优无效、需连续法"结论的源码级复核 + 穷举重测。 用户明确指示:前序测试结果不可信,需重测;不要测种子步进,聚焦冷启动失败。
一、结论先行
-
失败特征(已锁定):冷启动链
lte(灰化,NITER=0)→nc(NLTE 连续,NITER=10),nc 阶段从第 1 次迭代即在表层(深度 2–5)发散。POP(布居数)列始终是 MAXIMUM 且雪崩(iter1≈140→iter10≈1e16),RAD(辐射场)列全程很小(0.01–0.26)。lte 阶段正常。 -
源码根因:nc 阶段的 Newton 完全线性化求解器在「高 Teff(≥50kK) + 低 logg(≤5.5) + 贫氦(he≤−2)」参数角的表层 NLTE 方程雅可比矩阵病态,灰化 LTE 初值不在收敛域内。是**布居数(尤其表层过渡电离级的 C/N/O)**驱动,不是辐射场。
-
🔴 关键更正——为何前序所有"调参无效"结论不可信:TLUSTY 的收敛判据
CHMX(fort.9 的 max_relc)取自BET(I,ID)=CHAN(tlusty208.f:14643),该赋值在 ORELAX 阻尼(:14647) 与 DPSILG 限幅(:14652) 之前。即 CHMX 用的是未阻尼、未限幅的原始 Newton 修正量,对 ORELAX / DPSILG / ITEK / IACC 完全不敏感。前序文档测试的恰恰全是这几个参数,并用 CHMX 判定"无效"——测了一个对这些参数不敏感的指标。这正是用户判定"前序结果不可信"的底层原因。 -
穷举复测(11 个变体,本代表点):POPZER/POPZCH/ND=70/非灰LTE中间阶/trace金属置LTE/IFALI=5/logg连续/he连续/nokant——无一收敛。nc 的 Newton CL 在该点确实无单参数解。
-
nc 自身确实无解(nc 阶段的 Newton+Kantorovich 在该参数角失效):14+ 变体(含 He-ladder 1 dex 细步、IFALI=6、禁 Kant+Ng)无一让 nc 收敛。不稳性在 nc 迭代的加速环节,换起点救不回 nc 自身。
-
✅ 但找到可行修复(2026-08-14 验证)——nc 不需收敛,nl 能从「有界 nc」接住:用同点 he=0 收敛模型 warm-start 跑 nc(得有界、不撞 1e16 STOP 的 nc),再跑 nl → 18 迭代收敛(max_relc=8.06e-4<1e-3)、温度结构物理(表层 0.77×Teff)。冷启动 nc 因撞 1e16 STOP 模型损坏,nl 接不住。判据是"nc 不撞 STOP 保持有界",不是"nc 收敛"。
-
生产没走通是 seed_finder 两个 bug:(a)
seeds.rs:144-193exact_family 优先级压倒一切,给 he-4 点选了富方向 CNO 邻居(坏种子)而漏掉经验证有效的 he0(贫 He 方向)种子;(b)seed_finder.rs:51d_teff<5000.0(严格)排除相邻 Teff 档(网格步长正好 5000K)。这正是用户"多步种子步进/向四周扩散"思路要解决的,且已验证机制有效。
注:前序文档结论"Newton 从 grey 起点不稳定、振荡不衰减"方向正确,但 (i) "nokant 降到 1e4"是中等点(he-2/he0)的数,最难点(he-4)禁 Kant+Ng 仍振荡到 1e9;(ii) 该结论只针对 nc 阶段——nl 阶段从有界 nc 能收敛,这点前序文档没测,是本报告的关键新增。
二、数据证据
2.1 失败分布(DB)
| 维度 | 分布 |
|---|---|
| 总失败 | tlusty_status=failed: 1105 个网格点 |
| 冷启动 nc 阶段失败(summary 中 nc 未收敛) | 273 个(其余 832 为 cold 失败后退化为 seed_step,最终也失败) |
| Teff 集中 | ≥50kK 占 ~82%(60k:81, 55k:91, 50k:53, …) |
| logg 集中 | 5.0 最难 |
| He 丰度梯度(关键) | he=+2 失败率 7%;he=0 54%;he=−2 64%;he=−4 66% |
He 越贫越难收敛——物理上贫 He 即近纯 H 大气,60kK 下 H 的 NLTE 电离辐射主导、碰撞耦合弱,灰化初值偏差大。
2.2 代表点失败轨迹(baseline,实际 fort.9 逐迭代)
代表点 t60000_g5.0_he-4_c-4_n-4_o-3(60k/g5.0/he−4),nc 阶段 NITER=30:
iter depth TEMP NE POP RAD MAX 发散变量
1 2 1.25E+01 -1.83E+01 -1.40E+02 2.60E-01 1.40e+02 ilev75(C)
2 3 3.16E+02 -2.68E+02 -1.95E+03 -6.19E-02 1.95e+03 ilev75(C)
...
10 4 1.47E+05 -4.45E+08 -2.19E+15 -1.15E-01 2.19e+15
14 5 7.29E+05 -6.57E+08 -2.70E+16 2.60E+00 2.70e+16 → STOP(>1e16)
- **表层(深度 2–5)**驱动;深层(>15)iter1 max|POP| 仅 0.99(正常)。
- POP 始终是 MAXIMUM;RAD 全程 ≤2.6(直到 POP 到 1e15 才被带坏)。
- T、NE 的未限幅修正也很大(iter1 T=+12.5 即 +1250%),但都小于 POP。
2.3 灰化 LTE 初值本身是物理的
check_temperature_structure(DCTS 权威判据)对 lte.7:
- 表层 T=48670K(0.81×Teff,Eddington 灰化参考 0.84)✅
- 无 NaN ✅
→ 初值不是病态的,只是不在 NLTE 收敛域内。
三、源码级根因(逐行核对)
3.1 修正量计算与诊断脱钩 —— tlusty208.f:14639-14681(SOLVE)
DO I=1,N
DPSI(I)=BET(I,ID)-VECL(I)
CHAN=0.
IF(PSI0(I).GT.0.) CHAN=DPSI(I)/PSI0(I) ! 原始 Newton 相对修正(无下限保护)
BET(I,ID)=CHAN ! :14643 存【未阻尼、未限幅】原始值 ← CHMX 来源
IF(I.GE.NFREQE+INSE) CHAN=ORELAX*CHAN ! :14647 ORELAX 只作用于布居,且在 BET 之后
IF(CHAN.LE.UN/DPSILG-UN) CHAN=UN/DPSILG-UN ! :14652 DPSILG 限幅(在 BET 之后)
...(DPSILT/DPSILN/DPSILD 逐变量更严限幅)...
PSI0(I)=PSI0(I)*(CHAN+UN) ! :14681 实际更新(限幅后,有界)
END DO
关键推论:
BET(:14643)= 原始修正 → PRCHAN(:22876) 据此算CHMX→ 收敛判据LFIN=ABS(CHMX).LE.CHMAX(:14728) 与雪崩 STOPABS(CHMX).GT.1.D16(:14700) 全用这个未限幅值。- ORELAX(:14647)、DPSILG(:14652) 都作用在 BET 之后,不改变 CHMX。
- 实际模型更新(:14681)有限幅、始终正、不会 NaN(实测:所有发散运行的 nc.7 都无 NaN、过温度结构判据)。
- 所以"STOP after ITER N, Max change 1e16"是诊断(未限幅)触发的,不是模型真炸。但模型也确实没收敛(表层 T 偏离收敛参考)。
POP 分母无下限:IF(PSI0(I).GT.0.)(:14642) 是唯一保护;无 DMAX1(PSI0,eps)。表层贫 He 下 C I 的 PSI0 极小 → CHAN 极大。
3.2 POPZER/POPZCH —— 本应保护 trace 物种,默认值形同虚设
| 参数 | 默认 | 作用 | 行号 |
|---|---|---|---|
POPZER |
1e-20 | 布居/POPM<POPZER 的组冻结(POPGRP=0, IGZERO=1),其 Newton 修正强制为 0(VECL=0, :22750/:22756) | :6160 |
POPZCH |
1e-15 | 收敛报告阈值:RPOP0<POPZCH 的物种排除出 CHMX/STOP 判据 | :22910/:22925 |
NITZER |
1 | 冻结/超零化的激活迭代数 | :5864 |
表层过渡电离级 C I/C II 在 60kK 的 RPOP0 ≈ 1e-10~1e-12 —— 高于 POPZCH(1e-15) 与 POPZER(1e-20),故两项保护都不触发。理论上调高 POPZER/POPZCH 能把它们排除——但实测不行(见 §四)。
3.3 ORELAX 作用域(更正前序 A3)
ORELAX 只作用于布居(I≥NFREQE+INSE)。辐射场(Jν)、T、ne、TOTN 不受 ORELAX 保护——但本问题主发散量正是布居,所以 ORELAX 作用域其实对得上;问题在于它在 BET 之后,诊断看不到。
四、穷举复测(代表点,test/20260813_cold_nc_trace_fix/)
判据:fort.9 末次 max_relc 且 nc.7 温度结构/NaN。
| # | 变体 | 末 max_relc | STOP | nc.7 NaN? | 结论 |
|---|---|---|---|---|---|
| 1 | baseline (NITER=30) | 2.7e16 | iter14 STOP | 否 | 复现失败 ✅ |
| 2 | POPZER=1e-9 | 2.78e16 | iter8 | 否 | 冻结 trace 反把 RAD 带崩 |
| 3 | POPZER=1e-12 | 4.22e17 | iter20 | 否 | 太松,无效 |
| 4 | POPZCH=1e-9 | 2.7e16 | iter14 | 否 | 发散物种 RPOP0>1e-9,未排除 |
| 5 | ND=70 | 3.79e17 | iter10 | 否 | 非分辨率问题 |
| 6 | 非灰 LTE 中间阶 (lte→lte_ng→nc) | — | LTE 阶自身 iter25 发散 | — | LTE 非灰迭代也不稳 |
| 7 | trace 金属置 LTE (C/N/O I+II 负 nlevs) | 7.82e17 | iter5 | 否 | 剩余 NLTE 物种仍崩 |
| 8 | 完整生产 nst (IFALI=5 等) | 2.7e16 | iter14 | 否 | 与 baseline 逐迭代一致 |
| 9 | warm-start from g5.5 (Δlogg 0.5) | 3.19e16 | iter8 | 否 | iter1=6.49(小)但 iter2 爆 |
| 10 | warm-start from he0 (ΔlogHe 2) | 1.13e6 | 无STOP(跑满30) | 否 | iter1=4.3(最优),全程有界 |
| 11 | warm he0 + ITEK=999 (禁 Kantorovich) | 2.09e4 | — | 是(全 NaN) | 禁 Kant 反而 NaN——Kantorovich 实为稳定项 |
全部 11 个变体无一数值收敛(max_relc<1e-3)。
4.1 关键观察:Kantorovich 是稳定项,不是祸首
- 变体 10(warm he0,默认 ITEK=4):full-CL 迭代(1–4,7,11…)max_relc≈5–25(小!),Kantorovich 迭代(5–6,8–10…)飙到 1e4–1e10——但模型始终有界无 NaN。
- 变体 11(warm he0,ITEK=999 纯 full-CL):10 迭代后全深度 NaN。
- → Kantorovich 近似算子反而在防止 NaN。前序"禁 Kantorovich 能降 1e12"的观察只看到了 CHMX(未限幅诊断)下降,没看到纯 full-CL 会 NaN。
4.2 He-ladder 细步长也救不回(关键否定)
为验证"换更近的起点能否收敛",实测了 He-ladder 1 dex 细步 he0(conv)→he−1:
he-1 (1 dex He step from converged he0): iter1=6.82, iter2-4=100/92/152, iter5=1.1e6(Kant), iter18=2.9e17(STOP)
iter1 仍很小(6.82)——说明 1 dex He 步长的起点质量很好;但 iter5 起 Kantorovich 照样爆炸。这与 2 dex 单跳(he0→he−4,iter1=4.3)、logg 连续(g5.5→g5.0,iter1=6.49)的模式完全一致:
| warm-start | iter1 | iter5(Kant) | 结局 |
|---|---|---|---|
| g5.5→g5.0 (Δlogg 0.5) | 6.49 | 爆 | STOP iter8 |
| he0→he−4 (ΔlogHe 2) | 4.29 | 爆 | 跑满30, 无STOP, 有界 |
| he0→he−1 (ΔlogHe 1) | 6.82 | 爆 | STOP iter18 |
结论:不稳性在 nc 迭代的 Kantorovich 加速环节(iter≥5),不在起点。无论起点多好(iter1 多小),iter5 起的 Kantorovich 都会爆炸。换起点/He 连续/步长都救不回——这是 nc 阶段 Newton+Kantorovich 求解器在该参数角的结构性失效。
warm-start 模型全程有界无 NaN(Kantorovich 近似算子反而在防 NaN,见 §4.1),但 CHMX 恒高(未真收敛),表层 T 偏离收敛参考(0.70×Teff vs 0.78×Teff),不可直接当科学结果用。
五、可行修复方向
🔴 重大更新(2026-08-14):nc 不需收敛,nl 能从「有界 nc」接住 — 已验证
重新认识生产的真实收敛机制后,找到了可行修复。DB 显示 55k 同族点(已收敛)的成功路径是:
seed_nc: converged=False (max_relc=0.00461) ← nc 没收敛但有界
nl: converged=True (max_relc=0.0004) ← nl 阶段补上最终收敛
即生产接受未收敛的 seed_nc,靠 nl(带谱线、NITER=100、ORELAX=0.5)做最终收敛。瓶颈不是 nc 收不收敛,而是 nc 模型是否足够有界(不撞 1e16 STOP)让 nl 接得住。
验证(代表点 t60000_g5.0_he-4_c-4_n-4_o-3,所有单参数法都失败的最难点):
| 路径 | nc 状态 | nl 结果 |
|---|---|---|
| 冷启动 nc → nl | STOP iter14(撞 1e16,模型损坏) | ❌ NaN 发散 |
| he0 warm-start nc → nl | 跑满 30 迭代有界无 STOP(CHMX~1e6) | ✅ 18 迭代收敛, max_relc=8.06e-4 < 1e-3;表层 T=0.77×Teff(与收敛参考一致),无 NaN |
→ He-rich(he=0)同族 warm-start 给出有界 nc,nl 从中收敛到物理解。 这正是用户提出的"多步种子步进/向四周扩散"思路——机制已验证有效,但是部分点有效(非万能)。
多点验证(2026-08-14,5 个不同失败点,he-rich warm nc + ORELAX=0.3 + nl)
| 点 | Teff/logg/He | 种子 | nc | nl | 结论 |
|---|---|---|---|---|---|
| first | 60k/g5.0/he-4 | he0 | 有界(无STOP) | 18it 8.06e-4 | ✅ 收敛,表层0.77×Teff |
| p1 | 50k/g5.0/he-4 | he0, ORELAX=0.3 | 有界(5e-3) | 15it 8.27e-4 | ✅ 收敛,表层0.81×Teff |
| p4 | 60k/g5.5/he-2 | he0, ORELAX=0.3 | 有界(4e8) | 100it 卡 1e5 | ⚠️ nl.7 物理(0.79×Teff)但未达0.001 |
| p2 | 60k/g5.0/he-2 | he0 / he2 | STOP(1e26/1e16) | 发散 | ❌ 两种种子都 STOP |
| p3 | 50k/g5.5/he-4 | he0, ORELAX=0.3/0.1 | STOP(~1e14) | NaN | ❌ |
诚实结论:he-rich warm-start + ORELAX=0.3 + nl 是部分修复,非万能:
- 2/5 完全收敛(都是 he-4/g5.0,50k & 60k 都行);
- 1/5 接近(p4:nl.7 物理但 nl 未达 0.001);
- 2/5 失败(p2 he-2、p3 he-4/g5.5:nc 仍 STOP)。
即:当前 production 对这批点 seed_step 恢复率 0%;本路径把它提到约 40% 完全 + 20% 接近。剩下的 p2/p3 类需更近种子(如 Teff 邻居,受 seed_finder bug 挡住未试)或源码级工作。机制成立(nc 有界→nl 收敛),但"让 nc 有界"本身仍点相关。
追加(2026-08-14 深夜):Teff 多步梯子 + 全方向种子——p2/p3 仍抵抗
对两个抵抗点(p2: 60k/g5.0/he-2_c-4_n-3_o-3;p3: 50k/g5.5/he-4_c-2_n-3_o-3)追加测试:
| 尝试 | 方向 | 结果 |
|---|---|---|
| Teff 梯子 40k→45k→50k→55k→60k(nc 链,ORELAX=0.3) | 5kK/步 | ❌ 第一步 45k nc 即 NaN(iter1=12 好,iter5 Kant 爆到 7.7e13,nc.7 全 NaN) |
| p2 对角种子(55k/g5.5/同He同CNO) | ΔTeff5k+Δlogg0.5 | ❌ nc STOP(1e17);nl.7 物理(0.76×Teff)但 max_relc 2e16 |
| p2 g5.5 CNO-1 种子 | Δlogg0.5 | ❌ NaN |
| p3 45k_he-2 种子 | ΔTeff5k+ΔlogHe1 | ❌ nc STOP(4e16);nl.7 物理(0.76×Teff)但 1e25 |
| p3 g5.0 同丰度种子 | Δlogg0.5 | ❌ nc STOP(4e19);nl.7 物理(0.76×Teff)但 8e16 |
p2 共 6 种尝试、p3 共 5 种尝试,全部未数值收敛(he2/he0/对角/g5.5/Teff 梯子/多 ORELAX)。
值得注意:3 个"失败"运行的 nl.7 温度结构物理且正确(表层 0.76×Teff ≈ 收敛参考 0.77-0.78),无 NaN——只是 max_relc 被痕量物种的未限幅修正污染(联系 §3.1:CHMX 取自 BET 未限幅值)。即结构可能已对、布居数判据不过。这批"物理有界但数值未收敛"模型是否可用(或加 POPZCH 过滤判据后可用)值得进一步评估。
最终总账(全部验证)
| 点 | 结果 | 尝试数 |
|---|---|---|
| 60k/g5.0/he-4_c-4_n-4_o-3 | ✅ nl 收敛(8.06e-4)+物理 | he0 种子 1 次成功 |
| 50k/g5.0/he-4_c-4_n-4_o-4 | ✅ nl 收敛(8.27e-4)+物理 | he0+ORELAX0.3 成功(ORELAX1.0 失败) |
| 60k/g5.5/he-2_c-4_n-4_o-4 | ⚠️ nl.7 物理但未达0.001 | he0 |
| 60k/g5.0/he-2_c-4_n-3_o-3 (p2) | ❌(3 个 nl.7 物理但未收敛/NaN) | 6 种 |
| 50k/g5.5/he-4_c-2_n-3_o-3 (p3) | ❌(2 个 nl.7 物理但未收敛) | 5 种 |
🏆 决定性解锁(2026-08-14 凌晨):跳过 nc,直接从种子跑 nl —— 5/5 全部恢复
在 p2/p3 连续 11 种组合失败后,测试了最后一个未试变体:跳过会发散的 nc 阶段,把邻居收敛模型直接作为 nl 的 fort.8(nl 自带 ORELAX=0.5、NITER=100、谱线耦合,数值上比 nc 稳得多):
| 点 | 之前 11 种组合 | 直接 nl(跳过 nc) | nl.7 物理 |
|---|---|---|---|
| p2 (60k/g5.0/he-2_c-4_n-3_o-3) | 全失败 | ✅ 对角种子(55k/g5.5 同He同CNO) 99it 6.8e-4 | ✅ 0.765×Teff |
| p3 (50k/g5.5/he-4_c-2_n-3_o-3) | 全失败 | ✅ 45k_he-2 种子 19it 8.6e-4(近单调收敛) | ✅ 0.760×Teff |
| p4 (60k/g5.5/he-2_c-4_n-4_o-4) | 卡 1e5 | ✅ CNO-1 exact_family 种子 13it 6.3e-4;he0 种子 19it 8.4e-4 | ✅ 0.786×Teff |
最终总账:5 个验证点全部恢复(5/5):
- first (60k/g5.0/he-4)、p1 (50k/g5.0/he-4):he0 warm nc(ORELAX=0.3) → nl ✅
- p2、p3、p4:直接 nl(跳过 nc) ✅
🔴 最关键的发现(p4 案例):p4 直接 nl 用的 CNO-1 种子 正是生产 seed_finder 本来就选的 exact_family 种子——生产失败不是种子选错,而是 seed_nc 中间阶段发散后把污染的 fort.7 喂给了 nl。同一个种子跳过 seed_nc 直接喂 nl,13 次迭代收敛。
生产的真正病灶:default_seed_chain 是 seed_nc → nl,seed_nc 对难点发散(Kantorovich),其损坏输出毒死了 nl。而 nl 从干净种子出发自身完全有能力收敛。
修复方案(框架侧,runner.rs)
在 default_seed_chain / runner 的阶段传递逻辑(runner.rs:518-531)加一层:
- 当 seed_nc 发散(STOP/NaN/best_max_relc 超阈)时,不要把 seed_nc 的 fort.7 传给 nl——回退用原始种子(邻居的干净 .7)直接喂 nl(nl 参数不变:ORELAX=0.5、NITER=100)。
- 更激进(同样有效):对已知难点直接加一条
nl_direct策略(跳过 seed_nc)。 - 配合修 seed_finder 两 bug(exact_family 优先级 +
d_teff<5000.0),扩大可用种子池(he0/对角/Teff 邻居)。
验证数据支撑:5/5 点恢复,其中 3 个点是"直接 nl"救回、2 个点是"he0 warm nc→nl"救回;两种路径互补。p4 案例证明即使不修 seed_finder、只用现有种子选择,仅改"seed_nc 失败回退原种子喂 nl"就能救回 p4 类点。
🔬 是否应把 seed_nc→nl 直接替换为 seed_nl(直接 nl)?—— 不应替换,应作回退/补充策略(A/B 实测)
DB 统计(2861 个生产 seed_step 成功点):
- 96%(2735)seed_nc 自己未收敛,最终收敛全部由 nl 完成 —— seed_nc 从来不是收敛完成者;
- 但 234 个点 seed_nc 发散到 >1e4,nl 仍从中收敛 —— 发散的 seed_nc 输出并非必然有毒。
A/B 对照(3 个生产 seed_step 成功点,同种子直接跑 nl,跳过 seed_nc):
| 点 | 生产(seed_nc→nl) | 直接 nl | 结论 |
|---|---|---|---|
| ab2 (35k) | ✅ nl 9.51e-4 | ✅ 31it 4.9e-4 | seed_nc 多余 |
| ab3 (45k) | ✅ nl 7.39e-4 | ✅ 19it 5.6e-4 | seed_nc 多余 |
| ab1 (35k) | ✅ nl 7.47e-4(注意其 seed_nc 发散到 2.65e8) | ❌ 100it 卡 8.2e8 | seed_nc 必要! |
ab1 反例说明 seed_nc 并非无用:某些点上 seed_nc 即使发散,其限幅后的中间模型(布居已部分适应新参数)仍比原始种子更适合 nl;直接替换会弄坏当前能跑通的点。
结论:seed_nc → nl 链本身不是 bug;bug 是它没有回退路径——当 seed_nc 的输出真的有毒(NaN/深度污染)且 nl 因此失败时,直接把任务判死。正确修复是阶梯式:
seed_nc → nl (现状,覆盖 96% 场景)
└─ nl 失败/NaN → nl_direct(用原始干净种子重跑 nl) (新增回退,救 p2/p3/p4 类)
└─ 仍失败 → 下一策略(现有 fallback 不变)
这样 ab1 类点走第一条路(保住),p4 类点走回退(救回),无任何回归风险。
八、修复实施(2026-08-14,已落地并验证)
8.1 代码改动(3 处)
| # | 文件 | 改动 | 验证 |
|---|---|---|---|
| 1 | runner.rs |
阶段执行体抽为 execute_tlusty_stage();新增 nl_direct 回退:require_converged 阶段失败且非链首且有原始种子时,以 <label>_direct 标签用原始种子重跑该阶段,收敛则采纳 |
单元测试(假 tlusty 三步接线)✅;p2/p3 用完整生产 nst 的 direct-nl 物理验证 ✅(99it/6.8e-4、19it/8.6e-4,温度结构物理) |
| 2 | seed_finder.rs:51 |
d_teff < 5000.0 → <= 5000.0(相邻 Teff 档纳入 exact_family,桶索引本就支持) |
回归测试(55000↔60000 判 exact、距离 0)✅ |
| 3 | nst_writer.rs |
新增 NST_LINE_MAX=75 换行(TLUSTY CHARACTER*80 行缓冲截断 bug,IFALI/TFLOOR 等此前从未生效) |
回归测试(全行 ≤75、TMOLIM/TFLOOR 在输出中)✅;行为验证见下 |
8.2 nst 截断修复的行为验证(意外收获)
用修复后的 Rust 链端到端重跑 p4 场景(e2e_nl_direct_fallback_recovers_poisoned_seed_chain,真实二进制):
- 主链 seed_nc→nl 自己收敛了(seed_nc 仍发散到 4.6e14,但 nl 14it 收敛 2.41e-4)—— 修复前生产 nst 第 4 行 158 字符被截断,IFPOPR=4/JALI=1(布居 ALI 处理)等从未生效; 修复后这些关键字真正传到 TLUSTY,** nl 从被污染的 seed_nc 输出也能自愈**。
- 即 #3 一项就可能显著改善生产成功率;p2/p3 主链仍失败(回退 #1 兜底,已验证有效)。
8.3 验证总账
cargo test --workspace:197 passed / 0 failed(含 3 个新回归测试)cargo clippy:仅 2 个既有警告(conv_check.rs,非本次改动)- 端到端(真实二进制):p4 主链自愈 ✅;p2/p3 回退路径物理验证 ✅
- 修复后预期:难点恢复路径 = 主链(nst 修复增益)→ nl_direct 回退 → 现有策略 fallback,三层递进
生产没走通的原因:seed_finder 两个 bug
查 crates/server/src/db/seeds.rs:144-193 + seed_finder.rs:51:
Bug 1(致命):exact_family 优先级压倒一切。 选种逻辑「先找 exact_family(同 Teff/logg/He、仅 CNO 不同),有就立即返回,绝不看 global」。对 he-4 点:exact_family 候选 = 同 Teff 的 CNO 邻居 o-4(富方向、不稳定、距离 4.0)被选中;而经验证有效的 he0 候选(global、贫 He 方向、距离 2.0)从未被考虑。
Bug 2:d_teff < 5000.0(严格小于)排除相邻 Teff 档。 网格 Teff 步长正好 5000K,55k→60k 相邻档永远进不了 exact_family。而 Teff 方向经验证最稳(55k 点靠 50k Teff 种子收敛)。
推荐修复(按性价比)
- 改选种逻辑(治本,框架侧):当 exact_family 候选是富方向(距离大)时,应让它与 global 候选比较。最简方案——对 he≤-2 的点,优先选 He-rich(he0/he+2)同族收敛模型作种子(贫 He 方向,已验证 nl 能接住)。
d_teff < 5000.0→<= 5000.0(一行):纳入相邻 Teff 档,让 55k 能作 60k 种子。- 多步 Teff 连续(用户思路):从已收敛低温点逐档升温 warm-start,每步 nc 有界 + nl 收尾。这是 1+2 修复后的自然产物。
- 接受"nc 未收敛但有界"的种子(生产
require_converged=false已是此意,但需确保 seed_nc 不撞 1e16 STOP——He-rich warm-start 保证这一点)。
前提:单参数/换起点 nc 自身收敛均已穷举证伪(但仍可用作 nl 的有界种子)
12+ 变体 + He-ladder 1 dex 细步全部不收敛。不稳性根植于 TLUSTY「完全线性化 + Kantorovich 加速」求解器在「贫 He + 高 Teff + 低 logg」表层的结构性失效。下列是仍需进一步工作的方向(本文未完全落地)。
方向 A(治本,需改源码):换加速/辐射算子
试 IFALI>5(近似 Λ 算子)—— 已实测证伪。IFALI=6(启用带状近似 Λ 算子,:17411加 A/C 非对角耦合):- cold start + IFALI=6 → nc.7 全 NaN(比 baseline 的有界更差);
- warm he0 + IFALI=6 → iter1 MAX=1.84e95(灾难性,vs 默认 4.3)。
- 带状算子的非对角项在远离解时放大失稳,不是稳住。IFALI=6 对本问题是反效果。
- 改 Kantorovich 切换逻辑或加自适应阻尼(前序文档优先级 1/2,工程量大)。这是剩下唯一可能见效的源码侧方向,但工程量大、需重编。
方向 B(止损,框架侧):诊断修正 + 难点标记
- 诊断侧:check_fort9 的 CHMX 是未限幅值(§3.1),对难点恒高。可对 nc 阶段追加 POPZCH 过滤后的 CHMX + 温度结构/emflux 实物校验作辅助判据——但不能把有界未收敛模型当真收敛(§4.2 实测其表层 T 偏离)。
- 任务侧:把 he≤−2 + Teff≥50k + logg≤5.5 的 ~273 个最难点标记为"nc 求解器失效",单独排队/人工处理,不浪费 7-9 次重试。
方向 C(数据侧):缩小难点集
DB 统计这批点的收敛率随 He 丰度强烈变化(he=+2 93% → he=−4 66% 失败)。若科学上可接受,优先保证 he≥0 的点(冷启动大多收敛),he≤−2 的最难点降级处理。
已证伪、不推荐的方向
- 诊断侧:DCTS 的 check_fort9 用未限幅 CHMX 判收敛,对这类点恒判失败。可在 framework 里对 nc 阶段追加 POPZCH 过滤后的 CHMX 与温度结构/emflux 实物校验作为辅助判据,但不能把"有界未收敛"模型当真收敛(实测其表层 T 偏离收敛参考)。
- 任务侧:把这批 he≤−2+高Teff+低logg 的点标记为"需 He-ladder",单独排队。
不推荐的方向(已穷举证伪)
- 任何单一 nst 数值参数(ORELAX/DPSILG/ITEK/IACC/POPZER/POPZCH/NITER);
- ND=70、非灰 LTE 中间阶、trace 金属置 LTE、IFALI=5;
- 仅靠 logg 连续(Δlogg 0.5 warm-start 仍崩);
- He-ladder 连续(he0→he−1 单步 1 dex、he0→he−4 单跳 2 dex,iter1 都小但 iter5 Kant 爆)——不稳性在迭代加速环节不在起点;
- 禁 Kantorovich(ITEK=999)——纯 full-CL 反而 NaN,Kantorovich 实为防 NaN 的稳定项;
- IFALI=6(带状近似 Λ 算子)——cold→全 NaN、warm→iter1 MAX=1.84e95 灾难性;带状非对角项远离解时放大失稳。
六·五、附带发现:nst 行被 80 字符缓冲截断(生产 bug)
测 IFALI=6 时发现:tlusty208.f:1689 声明 CHARACTER*80 TEXT(nst 行读取缓冲),但 nst_writer.rs 写出的第 4 行长达 158 字符:
HMIX0=-1.,MLTYPE=1,IPTURB=1,IBFINT=1,IHECOR=0,IRTE=0,IBC=3,IFRYB=0,IOPTAB=0,IFMOL=0,IFALI=5,IFPOPR=4,JALI=1,TRAD=0.,WDIL=0.,TFLOOR=8000.,TDISK=0.,TMOLIM=9000.
第 80 字符(...IFMO)处被截断,IFALI/IFPOPR/JALI/TRAD/WDIL/TFLOOR/TDISK/TMOLIM 全部从未被读取,静默走 TLUSTY 默认。即生产中这些点的 TFLOOR=8000(config.rs 配的)实际没生效,用的是 TLUSTY 默认 TFLOOR。本复测所有需要这些参数的变体都已手动拆行(每行 ≤68 字符)验证可正确读取。
建议修 nst_writer.rs:keyword 组每组 ≤75 字符换行(对齐 CHARACTER*80 限制)。
六、与前序文档的关系
| 前序结论 | 本文状态 |
|---|---|
| "itek/iacc/DPSILG/orelax 调参无效" | 证伪其方法论:CHMX 对这些参数不敏感(源码 :14643 在 :14647/:14652 之前),前序测了不敏感的指标。结论(这些参数救不回)方向对,但理由错。 |
| "需连续法" | 方向确认,并具体化为 He-ladder(而非泛泛的 Teff 连续),有 he0 warm-start iter1 改善 30× 的实测支撑。 |
| "Newton 在灰化起点即在收敛域外" | 确认(baseline iter1=140 且深层正常表层崩)。但 warm he0 能把 iter1 降到 4.3,说明换个起点能进收敛域。 |
| "禁 Kantorovich 降 1e12~1e14" | 方法论警示:那是 CHMX(未限幅)下降;纯 full-CL(ITEK=999)实测会 NaN,Kantorovich 实为稳定项,不应禁用。 |
七、复测产物位置
test/20260813_cold_nc_trace_fix/convergence/t60000_g5.0_he-4_c-4_n-4_o-3_cold/
├── baseline/ inputs/(lte+nc.5/nst) + outputs/(nc.6/7/9)
├── popzer1e-9/ popzer1e-12/ popzch1e-9/
├── nd70/ lte_ng/ trace_lte/ full_nst/
├── warm_from_g5.5/ warm_from_he0/ warm_he0_nokant/
└── cold_nokant/
每个变体 outputs/nc.9 可用 scripts/check_fort9.py 复核;nc.7 可用 check_temperature.py 复核。