# 冷启动 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` > 本文是对前序"参数调优无效、需连续法"结论的**源码级复核 + 穷举重测**。 > 用户明确指示:前序测试结果不可信,需重测;不要测种子步进,聚焦冷启动失败。 --- ## 一、结论先行 1. **失败特征(已锁定)**:冷启动链 `lte(灰化,NITER=0)→nc(NLTE 连续,NITER=10)`,**nc 阶段从第 1 次迭代即在表层(深度 2–5)发散**。POP(布居数)列始终是 MAXIMUM 且雪崩(iter1≈140→iter10≈1e16),RAD(辐射场)列全程很小(0.01–0.26)。lte 阶段正常。 2. **源码根因**:nc 阶段的 Newton 完全线性化求解器在「高 Teff(≥50kK) + 低 logg(≤5.5) + 贫氦(he≤−2)」参数角的表层 NLTE 方程**雅可比矩阵病态**,灰化 LTE 初值不在收敛域内。是**布居数(尤其表层过渡电离级的 C/N/O)**驱动,不是辐射场。 3. **🔴 关键更正——为何前序所有"调参无效"结论不可信**:TLUSTY 的收敛判据 `CHMX`(fort.9 的 max_relc)取自 `BET(I,ID)=CHAN`(`tlusty208.f:14643`),该赋值在 **ORELAX 阻尼(:14647) 与 DPSILG 限幅(:14652) 之前**。即 **CHMX 用的是未阻尼、未限幅的原始 Newton 修正量**,对 ORELAX / DPSILG / ITEK / IACC **完全不敏感**。前序文档测试的恰恰全是这几个参数,并用 CHMX 判定"无效"——**测了一个对这些参数不敏感的指标**。这正是用户判定"前序结果不可信"的底层原因。 4. **穷举复测(11 个变体,本代表点)**:POPZER/POPZCH/ND=70/非灰LTE中间阶/trace金属置LTE/IFALI=5/logg连续/he连续/nokant——**无一收敛**。nc 的 Newton CL 在该点确实无单参数解。 5. **nc 自身确实无解(nc 阶段的 Newton+Kantorovich 在该参数角失效)**:14+ 变体(含 He-ladder 1 dex 细步、IFALI=6、禁 Kant+Ng)无一让 **nc** 收敛。不稳性在 nc 迭代的加速环节,换起点救不回 nc 自身。 6. **✅ 但找到可行修复(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 收敛"。** 7. **生产没走通是 seed_finder 两个 bug**:(a) `seeds.rs:144-193` exact_family 优先级压倒一切,给 he-4 点选了富方向 CNO 邻居(坏种子)而漏掉经验证有效的 he0(贫 He 方向)种子;(b) `seed_finder.rs:51` `d_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) ```fortran 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) 与雪崩 STOP `ABS(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 | 布居/POPM1e-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`)加一层: 1. **当 seed_nc 发散(STOP/NaN/best_max_relc 超阈)时,不要把 seed_nc 的 fort.7 传给 nl——回退用原始种子(邻居的干净 .7)直接喂 nl**(nl 参数不变:ORELAX=0.5、NITER=100)。 2. 更激进(同样有效):对已知难点直接加一条 `nl_direct` 策略(跳过 seed_nc)。 3. 配合修 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 阶段失败且非链首且有原始种子时,以 `