346 lines
17 KiB
Markdown
346 lines
17 KiB
Markdown
# CNO 热亚矮星光谱:调试经验与批量网格操作手册
|
||
|
||
> 本文档记录在 `tl208-s54/cno_grid/` 上构建含 C/N/O 金属线的热亚矮星理论光谱
|
||
> 过程中积累的全部经验,重点是**收敛调试中踩过的坑**和**已验证可行的配方**。
|
||
> 基础背景知识见 `tests/cno_sdspectrum/GUIDE.md`(必读)。
|
||
|
||
---
|
||
|
||
## 1. 核心结论(先读这一节)
|
||
|
||
1. **金属线必须进大气模型。** 实测证实:纯 H+He 大气下跑 synspec,C/N/O 谱线
|
||
全部产生 NaN——因为大气里没有金属能级,synspec 无法计算谱线不透明度。
|
||
所以 C/N/O 必须作为显式 NLTE 原子(mode=2)写进 `.5` 的大气和 ions 段。
|
||
这正是 `tests/cno_sdspectrum/GUIDE.md` 的方案 B(自洽)。
|
||
|
||
2. **收敛必须走三步法,`nc` 步骤不可省略:**
|
||
```
|
||
LTE 灰大气 (T T, NITER=0) → 初始温度结构
|
||
NLTE 连续谱 (F F, ilvlin=0, "nc") → 收敛电离平衡+布居数(不含谱线扰动)
|
||
NLTE 含线 (F F, ilvlin=100, "nl")→ 加谱线,从 nc 种子快速收敛
|
||
SYNSPEC → 合成可观测光谱
|
||
```
|
||
`nc` 是关键:它在没有谱线扰动的情况下先收敛 NLTE 电离平衡,给 `nl` 一个
|
||
稳定种子。**跳过 nc(grey-LTE → 直接含线 NLTE)必定发散**(见第 3 节)。
|
||
|
||
3. **端到端已验证跑通**(35000K / logg 5.5 / logHe=-2 / CNO=-1):
|
||
lte✓ → nc✓ → **nl 收敛 (max_relc=0.0043)** → synspec✓,产出 111500 个有效
|
||
通量点,CNO 吸收线清晰可见(3000–3500Å 吸收深度 68%)。单模型约 14 分钟。
|
||
|
||
---
|
||
|
||
## 2. 已验证的精确配方
|
||
|
||
### 2.1 `.5` 文件三阶段配置
|
||
|
||
三个阶段用**相同**的 NATOMS(8)和 ions 能级数,**只改三处**:第 2 行 LTE/LTGRAY
|
||
标志、第 3 行 nst 文件名、ions 段第 5 列 `ilvlin`。
|
||
|
||
| 阶段 | 第2行 | nst | ilvlin | 说明 |
|
||
|------|-------|-----|--------|------|
|
||
| lte | `T T` | nst (NITER=0) | 0/100 均可(LTE忽略线) | 灰大气,不迭代 |
|
||
| nc | `F F` | nst_nc (NITER=50) | **0** | NLTE 连续谱,**无线跃迁** |
|
||
| nl | `F F` | nst_nl (NITER=100) | **100** | NLTE 全谱线 |
|
||
|
||
> `ilvlin=0` 让该离子的束缚-束缚跃迁不参与计算(只保留连续谱),这正是 nc 步骤
|
||
> 稳定收敛的原因。`ilvlin=100` 恢复全部线跃迁。
|
||
|
||
### 2.2 CNO 模型原子(能级数,照搬 BSTAR2006)
|
||
|
||
| 元素 | 离子 / 能级 / 数据文件 |
|
||
|------|------------------------|
|
||
| C (Z=6) | C I 40 `c1.dat` / C II 22 `c2.dat` / C III 46 `c3_34+12lev.dat` / C IV 25 `c4.dat` / C V 1 |
|
||
| N (Z=7) | N I 34 `n1.dat` / N II 42 `n2_32+10lev.dat` / N III 32 `n3.dat` / N IV 48 `n4_34+14lev.dat` / N V 16 `n5.dat` / N VI 1 |
|
||
| O (Z=8) | O I 33 `o1_23+10lev.dat` / O II 48 `o2_36+12lev.dat` / O III 41 `o3_28+13lev.dat` / O IV 39 `o4.dat` / O V 6 `o5.dat` / O VI 1 |
|
||
| He | He I **24** `he1.dat` / He II **20** `he2.dat`(Peter Nemeth 邮件建议,勿用 14-level) |
|
||
| H | H I 9 `h1.dat` |
|
||
|
||
合计约 530 个能级,全部文件在 `$TLUSTY/data/` 下已确认存在。
|
||
|
||
### 2.3 nst 非标准参数(已验证)
|
||
|
||
```
|
||
ND=50,NLAMBD=3,VTB=2.,ISPODF=1,DDNU=50.,CNU1=6.,CHMAX=<阶段>,ITEK=3,NITER=<阶段>
|
||
IELCOR=-1
|
||
```
|
||
- lte 阶段:NITER=0(灰大气不迭代)
|
||
- nc 阶段:NITER=50, CHMAX=0.1(不必完全收敛,作种子即可)
|
||
- nl 阶段:NITER=100, CHMAX=0.01(要求收敛)
|
||
- `NLAMBD=3, ISPODF=1, DDNU=50., CNU1=6.` 是频率网格细化参数,**不能省**
|
||
- `IELCOR=-1` 关闭电子密度修正(这些 sdB 模型需要)
|
||
|
||
### 2.4 丰度约定
|
||
|
||
`.5` 的 atoms 段 `abn` 列:
|
||
- `0` = 太阳丰度(Tlusty 内置 Grevesse & Sauval 1998)
|
||
- `>0` = 绝对比值 N(elem)/N(H),即 `10^logX`(logX = −1 → abn=0.1)
|
||
- `<0` = 太阳丰度的倍数(−0.1 = 0.1×太阳,−5 = 5×太阳)
|
||
|
||
本次网格统一用 `abn = 10^logX`(logX 为 −4..2 / −2..1)。
|
||
|
||
### 2.5 synspec 波长窗口
|
||
|
||
`fort.55.lin` 第 6 行 `WLMIN WLMAX WLSTEP ...`。验证用的是 3000–7000Å(光学,
|
||
覆盖 C II 4267、C III 4647 等)。要 UV 段(含更多 CNO 线)用 `fort.55.uvopt`
|
||
(900–8000Å,见 `tests/cno_sdspectrum/`)。谱线表用 `data/gfVIS99.dat`(含
|
||
C 1412 / N 2396 / O 1885 条线)或 `data/gfATO.dat`(更全)。
|
||
|
||
---
|
||
|
||
## 3. 调试踩坑记录(避免重蹈覆辙)
|
||
|
||
### 坑 1:跳过 nc 步骤 → NLTE 发散 ❌→✅
|
||
|
||
**现象**:从 grey-LTE 种子直接跑含线 NLTE(ilvlin=100),max_relc 在 iter 4 起
|
||
爆炸到 1e20 并产生 NaN。
|
||
**根因**:grey-LTE 的 LTE 布居数与 NLTE 解差距巨大,加上数千条谱线的扰动同时
|
||
涌入,线性化必然爆。
|
||
**解决**:插入 nc 步骤(ilvlin=0),先无谱线地收敛 NLTE 电离平衡。
|
||
**这是最重要的经验。**
|
||
|
||
### 坑 2:ITEK=100 反而更差 ❌
|
||
|
||
**现象**:nc/nl 不收敛时把 ITEK 升到 100(Peter 邮件提过 3/15/100)。
|
||
**结果**:ITEK=100 导致 overshoot,max_relc 飙到 1e29,比 ITEK=3 更糟。
|
||
**解决**:ITEK 回退链上限设为 15,不要用 100。
|
||
|
||
### 坑 3:纯 H+He 种子喂含 CNO 模型 → 全 NaN ❌
|
||
|
||
**现象**:把纯 H+He 的 `.7`(38 能级)作 fort.8 种子跑含 CNO 模型(530 能级),
|
||
fort.7 全 NaN。
|
||
**根因**:种子与目标的能级结构不匹配,tlusty 无法映射布居数。
|
||
**解决**:三步法的三个阶段用**相同** NATOMS 和 ions 配置(只改 ilvlin/LTE 标志),
|
||
保证种子结构兼容。lte 的 `.7` 已经包含全部 CNO 能级位置(LTE 填充),所以能
|
||
正确喂给 nc。
|
||
|
||
### 坑 4:NITER=0 的 LTE 阶段不产生 fort.9 ❌→✅
|
||
|
||
**现象**:lte 阶段 NITER=0(灰大气不迭代),不输出 fort.9 收敛日志,自动化脚本
|
||
判定"失败"并跳过种子复制。
|
||
**解决**:脚本里对 fort.7(大气)单独判存在;NITER=0 时无 fort.9 是正常的,
|
||
直接把 fort.7 当种子传给下一阶段。
|
||
|
||
### 坑 5:grey-LTE 单独跑 synspec → 全 NaN ❌
|
||
|
||
**现象**:grey-LTE 大气(未做 nc/nl)直接跑 synspec,谱线全 NaN。
|
||
**根因**:grey 温度结构错误(标准深度 T=127834K),所有线被拒。
|
||
**结论**:synspec 必须用经过 nc→nl 收敛的 NLTE 大气,不能用 grey 或纯 LTE 大气。
|
||
|
||
### 坑 6:分析脚本读错列 → 误判"整数发散"❌
|
||
|
||
**现象**:监控脚本显示 max_relc = 1.0, 2.0, 3.0... 精确整数线性增长,一度怀疑
|
||
二进制有未初始化变量 bug。
|
||
**真相**:正则捕获了迭代号(第 1 列)而非 max_relc(第 7 列)。
|
||
**教训**:fort.9 列顺序是 `ITER ID TEMP NE POP RAD MAXIMUM ilev ifr`,
|
||
max_relc 在**第 7 列**。`check_conv.py` 一直是对的,是临时监控脚本错了。
|
||
**始终用 `check_conv.py` 判收敛,不要手写解析。**
|
||
|
||
### 坑 7:logg 跨度太大的种子 → 发散 ❌
|
||
|
||
**现象**:用 logg=4.0 的种子跑 logg=5.5 的模型(重力差 100 倍),发散。
|
||
**解决**:网格扩展时用"种子步进"——相邻参数点之间步长要小(logg 每步 ≤0.5,
|
||
Teff 每步 ≤5000K),用最近邻已收敛模型作种子。`run_grid.py` 已实现此逻辑。
|
||
|
||
---
|
||
|
||
## 4. 自动化系统使用说明(`cno_grid/`)
|
||
|
||
### 4.1 目录结构
|
||
```
|
||
cno_grid/
|
||
├── config.yaml # 6维网格 + 收敛链配置
|
||
├── templates/
|
||
│ ├── cno_atmos.5.tpl # (备用)模板
|
||
│ ├── nst # (备用)nst
|
||
│ └── fort.55.lin # synspec 波长窗口
|
||
├── src/
|
||
│ ├── gen_input5.py # 6维参数 → .5(支持 ilvlin / metals 子集)
|
||
│ ├── check_conv.py # fort.9 收敛判定
|
||
│ ├── run_one.py # 单模型三步链 + synspec(核心)
|
||
│ ├── run_grid.py # 6维网格调度(断点续算/并行/种子复用)
|
||
│ └── plot_spec.py # 归一化光谱 + CNO 诊断线标注
|
||
└── results/<model_name>/ # 每个模型的 .5/.7/.9/.spec/.cont/conv.json
|
||
```
|
||
|
||
### 4.2 跑单个模型
|
||
```bash
|
||
export TLUSTY=/home/dckj/program/tlusty/tl208-s54
|
||
python3 cno_grid/src/run_one.py \
|
||
--teff 35000 --logg 5.5 --loghe -2 --logc -1 --logn -1 --logo -1
|
||
# 结果在 cno_grid/results/t35000_g5.5_he-2_c-1_n-1_o-1/
|
||
# conv.json - 收敛状态(converged: true/false + 各阶段 max_relc)
|
||
# *.spec/.cont - synspec 光谱/连续谱
|
||
# *.lte.7/nc.7/nl.7 - 各阶段大气快照
|
||
```
|
||
|
||
### 4.3 批量网格
|
||
```bash
|
||
# 编辑 config.yaml 的 grid 轴(各维点列表),然后:
|
||
python3 cno_grid/src/run_grid.py cno_grid/config.yaml --dry-run # 先看总数
|
||
python3 cno_grid/src/run_grid.py cno_grid/config.yaml # 正式跑
|
||
python3 cno_grid/src/run_grid.py cno_grid/config.yaml --only teff=35000,logg=5.5 # 子集
|
||
python3 cno_grid/src/run_grid.py cno_grid/config.yaml --limit 3 # 只跑3个(测试)
|
||
|
||
# 特性:
|
||
# - resume: 跳过 conv.json 里 converged=true 的模型(断点续算)
|
||
# - 种子复用: 新模型自动找最近邻已收敛 .7 作种子
|
||
# - nworkers: config.yaml 里设并行进程数
|
||
# - 失败隔离: 单点失败不中断网格,记入 grid_status.json
|
||
```
|
||
|
||
### 4.4 检查收敛 / 画图
|
||
```bash
|
||
python3 cno_grid/src/check_conv.py results/<model>/<model>.nl.9 --chmax 0.01
|
||
python3 cno_grid/src/plot_spec.py results/<model> # 出 spectrum.png + CNO 线标注
|
||
```
|
||
|
||
### 4.5 收敛链调参(config.yaml 的 chain 段)
|
||
|
||
默认链已验证可行。若某些参数点(He-rich / 高金属)不收敛,可调:
|
||
- 放宽 nl 的 CHMAX(0.01 → 0.05)
|
||
- 增加 nc 的 NITER(50 → 200,GUIDE 提到 200 可完全收敛)
|
||
- 在 nc/nl 加 ORELAX 阻尼(`orelax: 0.5`)
|
||
- He-rich 点可能物理上无法收敛到 0.01(Peter 邮件预警),如实记录即可
|
||
|
||
---
|
||
|
||
## 5. 已知的 NaN 问题(非阻塞)
|
||
|
||
synspec 输出的 `.spec` 在部分波长区有 NaN(典型 ~70% 点有效)。这是 synspec54
|
||
在致密谱线区的数值行为("lines rejected based on opacities")。**有效区间的
|
||
光谱是可信的**——35000K 模型在 3000–3500Å 有 73627 个有效点,吸收深度 68%,
|
||
CNO 线清晰。降低波长采样密度或换 `gfATO.bin` 谱线表可能减少 NaN,但不影响
|
||
已验证的物理结论。
|
||
|
||
---
|
||
|
||
## 5.5 网格边界测试结果(8/8 全部成功)
|
||
|
||
在网格边界挑 8 个代表性难点(覆盖 Teff/logg/logHe 和 CNO 丰度两个轴),用三步法
|
||
(lte→nc→nl)+ 稳定化(方案 B,对所有 NLTE 阶段无条件启用)实测,**全部成功**:
|
||
|
||
### Teff / logg / logHe 边界(CNO=0 太阳丰度)
|
||
|
||
| # | 参数 (Teff/logg/logHe/CNO) | nl 收敛 | max_relc | 有效点 | 结论 |
|
||
|---|---------------------------|---------|----------|--------|------|
|
||
| 1 | 20000/5.0/+2/0(低温He-rich,最难) | YES | 0.00654 | 115362 | ✓ |
|
||
| 2 | 80000/6.5/+2/0(高温He-rich) | YES | 0.00915 | 105183 | ✓ 修复后 |
|
||
| 3 | 80000/6.5/−4/0(高温He-poor) | YES | 0.00769 | 106469 | ✓ 修复后 |
|
||
| 4 | 40000/6.0/0/+1(高金属CNO=10×H) | YES | 0.0069 | 108693 | ✓ |
|
||
| 5 | 20000/6.5/−4/0(低温贫He) | YES | 0.00927 | 115479 | ✓ |
|
||
|
||
### CNO 丰度边界(含非对称丰度)
|
||
|
||
| # | 参数 (Teff/logg/logHe/C/N/O) | nl 收敛 | max_relc | 有效点 | 结论 |
|
||
|---|------------------------------|---------|----------|--------|------|
|
||
| 6 | 40000/5.5/0/−2/−2/−2(极贫金属,0.01×H) | YES | 0.00764 | 108693 | ✓ 修复后 |
|
||
| 7 | 40000/5.5/0/+1/−2/−2(C富N/O贫,sdB典型) | YES | 0.00376 | 108576 | ✓ |
|
||
| 8 | 80000/6.5/−4/−2/−2/−2(高温+极贫金属) | YES | 0.00394 | 105300 | ✓ |
|
||
|
||
### 关键发现
|
||
|
||
1. **8/8 全部收敛,全部产出有效光谱(10万+ 有效点)**——整个网格边界(Teff
|
||
20000-80000、logg 5.0-6.5、logHe −4..2、CNO −2..1,含非对称丰度)均可计算。
|
||
|
||
2. **发散不只与高温有关**:测试 #6(40000K/logg5.5/logHe=0)初次也发散了,
|
||
证明发散触发条件是 Teff/logg/logHe 的组合,不只高温。因此方案 B(IDLTE=45
|
||
等)改为**对所有 NLTE 阶段无条件启用**——物理上深层 LTE 对所有 sdB 都成立。
|
||
|
||
3. **非对称丰度可行**:测试 #7(C=10×H, N=O=0.01×H)这种 sdB 典型的 C-rich
|
||
组合收敛良好(relc=0.00376),说明 C/N/O 可独立取不同丰度值。
|
||
|
||
4. **耗时**:80000K 点因方案 B 的 nc 快速收敛,仅 58s;40000K 含线 nl 较慢
|
||
(~20-30 min)。24 核并行约每小时 72 个模型。
|
||
|
||
---
|
||
|
||
## 5.6 80000K 高温发散:源码级根因与解决方案
|
||
|
||
### 问题
|
||
初次边界测试中,两个 80000K 点(He-rich 和 He-poor)在 nc 阶段发散:
|
||
max_relc 从 iter1 的 ~40 单调爆炸到 iter10 的 1e13–1e17(触发 `tlusty208.f:14700`
|
||
的 `ABS(CHMX).GT.1.D16` 硬停止)。35000K 同配方则正常收敛。
|
||
|
||
### 根因(tlusty208.f 源码分析)
|
||
通过分析源码确认发散由三个叠加因素导致,**全部集中在深层(ID 1-8)的能级
|
||
布居数(POP 列),温度变化很小**:
|
||
|
||
1. **ORELAX=1.0 无阻尼**(`tlusty208.f:14647`):ORELAX 只乘到布居数修正上。
|
||
默认 1.0 = 纯线性化无阻尼,首次迭代就把深层 CNO 高价离子(O IV/V、C IV、
|
||
N IV/V)布居数猛推向 NLTE,每步最多变 10 倍(DPSILG=10 限幅器,`14652`)。
|
||
|
||
2. **Ng 加速 iter7 起雪上加霜**(IACC=7 默认,`tlusty208.f:29704`):Ng 外推
|
||
假定迭代已近线性收敛;在强烈非线性区外推会放大误差。fort.10 显示 iter7 正是
|
||
深层 POP 从 1e2 跳到 1e4 的转折点。
|
||
|
||
3. **深层无 LTE 保护**(IDLTE=1000 默认,`tlusty208.f:5515`):所有 50 层都解
|
||
NLTE。80000K 深层高电离能级的光致电离-复合平衡极陡峭,完全线性化给出的
|
||
修正方向不稳定。
|
||
|
||
物理本质:80000K 下 CNO 多次电离,LTE 灰大气初猜的布居数与真实 NLTE 解差太远。
|
||
与 He 丰度无关(He-rich 和 He-poor 都发散)。
|
||
|
||
### 解决方案 B(已验证,已集成进代码)
|
||
```
|
||
IDLTE=45, IACC=NITER+1 (对所有 NLTE 阶段无条件启用)
|
||
```
|
||
- **IDLTE=45**(`tlusty208.f:5515`):强制最深的 5 层走 LTE。物理合理——深层
|
||
τ≫1 本就该接近 LTE,且消除深层高电离能级的发散源。对所有 sdB 都成立。
|
||
- **IACC=NITER+1**(`tlusty208.f:29704`):完全关闭 Ng 加速(设大于 NITER 使
|
||
ACCEL2 早返回),避免外推放大误差。
|
||
|
||
效果(边界点3,80000/He-poor):
|
||
- 修复前:nc iter1=38.8 → iter10=1.5e13(发散),大气全 NaN,0 有效光谱点
|
||
- 修复后:nc iter1=2.39 → iter5=0.067(5 次收敛),nl iter6=0.0078(收敛),
|
||
**106469 有效光谱点,零 NaN**
|
||
|
||
> 注:ORELAX 当前未默认启用(保持 1.0),因为 IDLTE+IACC 已足够稳定。若遇极端
|
||
> 点仍发散,可在 config.yaml 的 chain 阶段加 `orelax: 0.5` 进一步阻尼。
|
||
|
||
`run_one.py` 已自动处理:所有 `lte=="F"` 的阶段(nc/nl)自动加 IDLTE=45 和
|
||
IACC=NITER+1;LTE 灰大气阶段(NITER=0)保持干净不加。
|
||
|
||
### 备选方案(若方案 B 仍不够,按推荐度)
|
||
- **方案 A(碰撞-辐射开关)**:`ICRSW=1, SWPFAC=0.1, SWPINC=3.0`(`SWITCH`
|
||
子程序 `tlusty208.f:4556`)。首轮压低辐射率使布居数接近 LTE,逐步恢复真
|
||
NLTE。Hummer & Voels (1988) 标准稳定化手段。
|
||
- **方案 C(强限幅)**:`DPSILG=3.0, ORELAX=0.3, ITEK=5`。把单步布居数变化
|
||
上限从 10× 降到 3×,更保守但迭代更多。
|
||
|
||
### 关键源码位置(供进一步调参参考)
|
||
| 参数 | 源码行 | 作用 |
|
||
|------|--------|------|
|
||
| ORELAX | 14647, 844 | 布居数过松弛(<1 阻尼) |
|
||
| IDLTE | 5515 | 深层强制 LTE 的深度阈值 |
|
||
| IACC/IACD | 29704, 29750 | Ng 加速起始/间隔 |
|
||
| ITEK | 836-860 | 完全线性化迭代数(之后转 Kantorovich) |
|
||
| DPSILG/DPSILT | 14652-14659 | 单步修正限幅(通用/温度) |
|
||
| ICRSW/SWPFAC | 4556-4642 | 碰撞-辐射开关(逐步引入 NLTE) |
|
||
| POPZCH | 22910 | max_relc 计算时跳过的小布居数阈值 |
|
||
|
||
---
|
||
|
||
## 6. 邮件往来要点(Peter Nemeth,2024-10~11)
|
||
|
||
完整邮件在 `hot_subdwarf/letter/`。关键技术建议:
|
||
1. 收敛判定:fort.9 各深度相对变化都 < CHMAX(用 `check_conv.py`)
|
||
2. He 用最复杂模型原子(24-level He I + 20-level He II)
|
||
3. He-rich 模型难收敛属正常;用模型链(粗→精 CHMAX);可减小模型间步长
|
||
4. ITEK 可调(3/15/100)提升稳定性——但实测 100 会 overshoot,勿超 15
|
||
5. CHMAX:普通星 0.001 可达;He-dominated 可放到几个%;先 10% 再 1% 逐步收紧
|
||
6. synspec 后处理(卷积、vsini)仅在比对观测时需要;纯理论光谱可直接用 fort.7
|
||
|
||
---
|
||
|
||
## 7. 参考文件索引
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `tests/cno_sdspectrum/GUIDE.md` | 你写的原始指南(基础流程、.5 格式、nst 说明)—— **必读** |
|
||
| `tests/cno_sdspectrum/R1_full` | 你验证过的完整四步运行脚本 |
|
||
| `tests/cno_sdspectrum/sdB35000g550_{lte,nc,nl}.5` | 三阶段的范例 .5 文件 |
|
||
| `tests/sdB_spectra/runs/test_cno/` | 已算好的 35000/5.5 CNO 模型结果 |
|
||
| `tl208-s54/tests/tlusty/bstar/BGA20000g400v2a.5` | BSTAR2006 含全套金属参考模型 |
|
||
| `hot_subdwarf/letter/` | 与 Peter Nemeth 的全部邮件 |
|
||
| `cno_grid/src/run_one.py` | 三步链实现(DEFAULT_CHAIN 即验证配方) |
|