将 TLUSTY/SYNSPEC 拆为各自独立的 enabled/policy/strategies 阶段,
以策略链自动弹栈取代单级 seed_step 布尔回退;定向修复 2026-08-02
僵尸任务涡旋事故;新增节点并发配额热调;前端详情页从 1412 行巨型
视图拆为薄控制器 + detail 子模块,并补齐工具层与单测。
引擎与调度(task_engine_decoupling_design.md)
- models.rs: 新增 StagePolicy / EngineStageConfig / TaskSpec 阶段字段、
normalize_compat() 校正旧版在途消息策略链、failed_stage 归因
- scheduler.rs: resolve_dispatchable_chain 派发门控、
trigger_strategy_fallback 按 failed_stage 精确弹栈;启动期
force_recompute/skip_converged(默认)/skip_failed 三策略
- db.rs: tasks 表 +7 列持久化阶段配置;终态守卫
(mark_grid_point_running 仅 pending/queued→running;
record_task_report 拒绝迟到失败翻黑 converged);策略弹栈快照
僵尸涡旋修复(runbook-20260802-zombie-vortex-fix.md)
- 全链路跨库活性交叉校验:派发/claim/孤儿回收/回退统一查 MQ 队列活性,
活则放行、死则清僵尸,结构性消除"每点重复派发"
- stop/重启卫生:清队列同步 delete_tasks_by_ids,杜绝遗留 pending 行
- report_task: 幂等吸收 + 409 区分迟到冗余结果,仅 state_changed 时回退
- MQ: NULL workflow_name 回填 __legacy__、requeue 后迟到上报被 403 竞态修复
动态 CPU 配额(dynamic_cpu_slots_design.md)
- admin.rs: POST /admin/nodes/:id/quota(Option<Option<i32>> 区分
缺字段/显式 null);nodes 表 +admin_max_slots
- worker.rs: effective_max_slots = min(admin, physical),心跳下发原子生效
科学产物保全(tlusty_result_artifacts.md)
- runner.rs: SYNSPEC 启动前快照 fort.12/fort.14 → .bfac/.emflux 防覆盖
- 半失败点(大气收敛+光谱失败)改判 Failed 并写入 note;仅 SYNSPEC
场景不再恒判失败;撤销归档 LRU 200 上限改为永久保留
- executor.rs: 透传 synspec_params 数值参数(此前固定 None)
前端(dashboard/)
- workflowDetail.js 1412→328 行,拆出 views/detail/{ctx,overview,
pointsTable,parSets,pointPanel}.js,AbortController 治理监听/请求生命周期
- 删除 wfActions.js,新增 wfEnginePanel.js(双阶段三维配置编辑面板)
- 新增 utils/{errors,format,icons,polling,yamlStage}.js 纯函数模块
- 路由级动态 import 代码分割;节点配额三点菜单 + Modal 管理
- 首次引入 node:test 单测(format/polling/yamlStage/psCache,644 行)
- 系统性补齐 a11y:skip-link、ARIA、Tab 键盘漫游、toast 关闭、退出动画
文档与工具
- 新增 6 篇设计/调研:引擎解耦、动态配额、涡旋 runbook、
光谱正确性分析、收敛判断、产物归档
- PIPELINE/design/api/database 等协同重写为分布式 C/S 架构口径
- scripts/fetch_results.sh 跨节点产物备份;import_results 按 cno 升序导入
- workflows/sdB_cno.yaml: 新增 tlusty/synspec_stage 配置块,修正 wstart 笔误
10 KiB
TLUSTY 结果产物分析:Node 归档白名单与 fort 单元快照
本文档记录对 TLUSTY/SYNSPEC 源码的单元号(fort.N)语义分析,以及据此确定的 Node 端结果归档(
result_dir)白名单与 TLUSTY b 因子/出射谱快照的设计依据。 源码路径:TLUSTY 位于/home/fmq/program/SpectraRust/tlusty/(tlusty208.f), SYNSPEC 位于/home/fmq/program/SpectraRust/synspec/(synspec54.f)。 归档逻辑实现于crates/node/src/executor.rs、crates/common/src/runner.rs、crates/common/src/result_filter.rs。
1. 背景与问题
Node 每个任务算完后,把沙盒 work_dir/task_<id>/<name>/ 内的产物拷贝到持久归档
result_dir/<name>/。归档采用白名单策略(is_result_worthy),只保留有语义价值
的产物,丢弃 Tlusty/Synspec 运行时的中间工作单元(旧版 catch-all 会把它们一并搬进
归档,每个模型浪费约 2MB / 4.8MB)。
需要回答的核心问题:
- 当前归档到底保留了哪些文件?
- TLUSTY 的
fort.12(b 因子)、fort.14(出射谱)、fort.69(计时日志)是否有 保存价值?—— 需以 TLUSTY 源码为准。 - TLUSTY 出射谱(fort.14)与 SYNSPEC 输出的
.spec有什么区别,是否冗余?
2. Node 结果归档机制(现状)
- 归档路径:
result_dir/<name>/(result_dir由 node 配置指定,默认为data/result/)。 - 触发时机:上报成功后(上报失败也归档,用于排错),随后清理沙盒。
- 原子写入:先拷为
.result.tmp.<uuid>再 rename,防止半截文件。 - 无 LRU 上限:所有已算网格点产物永久保留(2026-08-02 撤销此前 200 目录上限)。
- 白名单判定:
common::result_filter::is_result_worthy(fname, model_name)。
2.1 保留的文件(白名单)
model_name 为网格点权威名,如 t20000_g5.0_he-2_c-4_n-4_o-4。
裸名保留(不以 model_name 为前缀,有独立语义):
| 文件 | 语义 |
|---|---|
conv.json |
收敛摘要 |
fort.8 |
SYNSPEC 输入大气 |
fort.55 |
SYNSPEC 控制卡 |
科学核心 <name>.<后缀>:
| 后缀 | 来源 | 语义 |
|---|---|---|
.7 |
TLUSTY/SYNSPEC | 最终大气 |
.spec |
SYNSPEC fort.7 | 合成光谱(高分辨率) |
.cont |
SYNSPEC fort.17 | 连续谱 |
.iden |
SYNSPEC fort.12 | 谱线证认表 |
.log |
SYNSPEC | SYNSPEC 日志 |
.bfac |
TLUSTY fort.12 快照 | 最终模型 b 因子(非 LTE 偏离因子) |
.emflux |
TLUSTY fort.14 快照 | 最终模型出射谱(波长 Å + Fλ) |
阶段快照 <name>.<label>.<后缀>(label ∈ lte/nc/nl/seed_nc):
.5(输入卡)、.6(输出日志)、.err(错误日志)、.nst(控制卡)、.7(该阶段大气)
收敛诊断 <name>.<label>_chmax*.9:唯一保留的 .9 形态(裸 <name>.<label>.9
与 _chmax*.9 内容重复,runner 源头已停止写出)。
2.2 丢弃的内容
- 所有 Tlusty 中间工作单元:
fort.1/2/3/10/11/13/14/18/22/42/44/50/57/69/82/95 fort.84(NATOMS 崩溃缓存)、.tmp残留- 符号链接(
data、fort.19等共享 runtime 资源)、子目录 - 不以
<name>.开头且不在裸名列表的文件、未知后缀/未知阶段标签 fort.12/fort.17:被 runner 消费(见 §4.1)后删除
3. TLUSTY fort 单元语义(源码分析)
TLUSTY 每次运行到达最终迭代(LFIN=.TRUE.)时,经 OUTPRI(tlusty208.f:14156,调用点
:3889)一次性写出多个单元。各单元语义与行号:
| 单元 | 内容 | 源码位置 | 判定 |
|---|---|---|---|
fort.12 |
b 因子(非 LTE 偏离因子表):头 2I5 + 每深度 TEMP/ELEC/DENS/BFAC,格式 701/702/703 | :14344 | 科学价值高,需快照 |
fort.13 |
出射辐射场(FREQ, FLUX=H(ν), FH=Eddington 因子),格式 602 | :14185 | 与 fort.14 同源,未快照 |
fort.14 |
出射谱(波长 Å + Fλ),格式 614 F15.3,1pe15.3 |
:14188 | 科学价值高,需快照 |
fort.17 |
每深度布居数 POPUL(格式 503) | :14124 | SYNSPEC 覆盖后转存 .cont |
fort.20 |
b 因子 BFAC(另一分支) | :14119 | 未保留 |
fort.22 |
绝对 b 因子 BFAB | :14346 | 未保留 |
fort.69 |
迭代计时日志:TIMING 子程序写 IP/MOD/TIME/DT/ROUT(FORMAL SOLUTION / LINEARIZATION),格式 600 |
:29937 | 纯性能诊断,丢弃 |
注意:
OUTPRI仅在最终迭代调用,故每个单元内保存的是最后一次迭代的最终值。 收敛链上最后一次 TLUSTY 运行即最终模型。
4. SYNSPEC 对 unit 12/14 的覆盖与丢失风险
4.1 单元号复用导致覆盖
TLUSTY 与 SYNSPEC 同目录串行执行,且两个程序复用相同的单元号:
| 单元 | TLUSTY 写 | SYNSPEC 写 |
|---|---|---|
| 12 | b 因子 | 谱线证认表(synspec54.f:9719,格式 603) |
| 14 | 出射谱 | 谱线数据(synspec54.f:9852,格式 601) |
由于 TLUSTY 先跑、SYNSPEC 后跑,SYNSPEC 会把 fort.12/fort.14 覆盖。现有 runner
流程:
- TLUSTY 写 b 因子 + 出射谱 → 被 SYNSPEC 覆盖
- SYNSPEC 写
fort.7(谱)、fort.17(连续谱)、fort.12(谱线证认表) - runner 将
fort.7→.spec、fort.17→.cont、fort.12→.iden,随后删除fort.12/fort.17
结论:归档里的 .iden 保存的是 SYNSPEC 的谱线证认表(覆盖后的 fort.12),
TLUSTY 的 b 因子与出射谱在覆盖前无任何快照,会被静默丢失 —— 这是真实的数据损失点。
4.2 快照决策
fort.69:纯计时日志,不保存(无科学内容)。fort.12(b 因子)与fort.14(出射谱):需快照。
5. 实现:快照 b 因子 + 出射谱
5.1 快照命名与白名单
| 源文件 | 快照名 | 白名单后缀 |
|---|---|---|
fort.12 |
<name>.bfac |
bfac(加入 SCIENCE_SUFFIXES) |
fort.14 |
<name>.emflux |
emflux(加入 SCIENCE_SUFFIXES) |
5.2 插入点
runner::run_model_with_timeout:收敛链循环结束后、SYNSPEC 启动前调用
snapshot_tlusty_outputs(&model_dir, name)。此时 fort.12/14 是最后一次 TLUSTY 运行
(最终模型)的产物,且尚未被 SYNSPEC 覆盖。仅 SYNSPEC 场景(tlusty 未运行)下
fort.12/14 不存在,函数按文件存在性静默跳过。
5.3 变更文件
crates/common/src/runner.rs:新增snapshot_tlusty_outputs()+ 调用 + 2 个测试crates/common/src/result_filter.rs:SCIENCE_SUFFIXES加bfac/emflux+ 文档 + 测试crates/node/src/executor.rs:归档文档、test_save_result_artifacts同步 + 修正fort.13注释(原误标为"NLTE 跃迁频率网格",实为出射辐射场 FREQ/FLUX/FH)
6. TLUSTY 出射谱(fort.14)vs SYNSPEC .spec
两者转换公式完全相同、物理量一致,差异在网格密度、线不透明度处理、覆盖范围与用途。
6.1 相同点
- 公式一字不差:
Fλ = H(ν) × ν² / c- TLUSTY(:14188):
FLAM=FLUX(IJP)*FREQ(IJP)*FREQ(IJP)/2.997925E18 - SYNSPEC(:3365):
FLAM=FLUX(IJ)*FREQ(IJ)*FREQ(IJ)*CAS,CAS=1./2.997925D18
- TLUSTY(:14188):
FLUX都是表面出射 Eddington 通量 H(ν)(erg/cm²/s/sterad/Hz,OUTPRI 注释明确 "precisely the second moment H(freq) at the surface")。- 同一波长点的连续谱水平应当一致。
6.2 差异点
| 维度 | TLUSTY fort.14 | SYNSPEC .spec |
|---|---|---|
| 网格密度 | 模型自身频率网格(NFREQ 个点,数百~数千,非均匀) | 以每条谱线为中心的细网格(FR0=FREQ0(IL0),SPACE/CUTOFF/DOPSTD 采样线轮廓,密度高几个量级) |
| 线不透明度 | 模型求解时的粗/近似线处理(不透明度采样/ODF/超能级),只体现最强线 | 完整线表(fort.19)逐细频点重解辐射转移,得到分辨开的真实线轮廓 |
| 波长覆盖 | 整个模型宽带频率范围 | 仅 fort.55 指定窗口(dcts 默认 1400–1410 Å) |
| FLUX 来源 | 模型迭代过程的自洽辐射场解(顺带用于通量守恒检查 TOTF) | 用已收敛大气在细网格重新解 RT |
| 用途/下游 | 模型副带品,快速看谱/校验 | 科学产品,注释明说 "serves as input to ROTINS"(转动/仪器展宽卷积),用于与观测对比 |
6.3 实际含义
两者是同一物理量(表面 Fλ)在不同分辨率和线处理下的版本,非两种东西。叠画时
连续谱重合,.spec 显示被分辨开的精细谱线轮廓,fort.14 中弱线基本不可见。归档同时
保留二者不构成冗余:.emflux 代表模型自身辐射场(宽带、粗,可独立校验),.spec
代表最终高分辨率合成谱(窄窗、细,与观测对比的产品)。
7. 完整归档文件清单(快照实施后)
result_dir/<name>/
├── conv.json
├── fort.8 # SYNSPEC 输入大气(裸名保留)
├── fort.55 # SYNSPEC 控制卡(裸名保留)
├── <name>.7 # 最终大气
├── <name>.spec # SYNSPEC 合成光谱
├── <name>.cont # SYNSPEC 连续谱
├── <name>.iden # SYNSPEC 谱线证认表
├── <name>.log # SYNSPEC 日志
├── <name>.bfac # TLUSTY 最终 b 因子(快照 fort.12)
├── <name>.emflux # TLUSTY 最终出射谱(快照 fort.14)
├── <name>.<label>.5 # 阶段输入卡快照
├── <name>.<label>.6 # 阶段输出日志快照
├── <name>.<label>.err # 阶段错误日志快照
├── <name>.<label>.nst # 阶段控制卡快照
├── <name>.<label>.7 # 阶段大气快照
└── <name>.<label>_chmax*.9 # 阶段收敛诊断(唯一保留的 .9)
8. 后续可选优化
fort.13(出射辐射场,含 Eddington 因子 FH)未快照;如需保留,在snapshot_tlusty_outputs中加("fort.13", "emrad")并在白名单加emrad后缀即可。fort.20(b 因子)、fort.22(绝对 b 因子)同属 b 因子家族;如需保留可在 TLUSTY 阶段结束后一并快照,但fort.12已覆盖相对 b 因子,绝对 b 因子可由 POPUL/POPLTE 重算。