feat(all): 任务引擎双阶段解耦、僵尸涡旋修复、动态 CPU 配额与前端详情页重构
将 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 笔误
This commit is contained in:
+80
-35
@@ -1,6 +1,9 @@
|
||||
# DCTS 物理计算与流程设计 (Physics Pipeline Design)
|
||||
|
||||
> 本文档详细阐述 DCTS 核心物理计算引擎的设计原理、4 阶段 TLUSTY/SYNSPEC 计算链,以及冷启动与种子步进(Seed Stepping)发散回退机制。
|
||||
> 本文档阐述 DCTS 核心物理计算引擎的设计原理、TLUSTY/SYNSPEC 计算链(冷启动 / 种子步进),
|
||||
> 以及基于策略链(Strategy Chain)的回退机制与种子匹配算法。
|
||||
> 阶段独立配置(`enabled` / `policy` / `strategies`)的完整设计见
|
||||
> [`task_engine_decoupling_design.md`](./task_engine_decoupling_design.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -8,7 +11,9 @@
|
||||
|
||||
TLUSTY 通过**完全线性化 (Complete Linearization)** 方法求解恒星大气结构的 NLTE(非局部热力学平衡)统计平衡方程与辐射转移方程。由于线性化的收敛半径有限,若初始猜想(初猜)偏离真解较远,迭代极易发生数值发散。
|
||||
|
||||
DCTS 将单点计算划分为 **4 个渐进物理阶段**:
|
||||
DCTS 把单点计算拆分为 **TLUSTY 大气结构求解 + SYNSPEC 光谱合成**两个独立阶段(各自有 `enabled` 开关)。TLUSTY 阶段内再按执行策略选用不同收敛链:
|
||||
|
||||
**冷启动链 (ColdRun,`default_cold_chain`)**:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -17,52 +22,92 @@ flowchart LR
|
||||
Stage3 --> Stage4["4. 合成光谱\n(synspec)\n输出 .spec / .cont"]
|
||||
```
|
||||
|
||||
**种子步进链 (SeedStep,`default_seed_chain`)**:直接以近邻已收敛大气为热启动起点,**跳过 lte 灰大气阶段**:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Seed1["1. NLTE 连续谱热启动\n(seed_nc / tlusty)\n以种子 .7 作 fort.8 初猜"] --> Seed2["2. NLTE 完整谱线\n(nl / tlusty)\n精化收敛"]
|
||||
Seed2 --> Seed3["3. 合成光谱\n(synspec)"]
|
||||
```
|
||||
|
||||
### 各阶段物理配置与功能明细
|
||||
|
||||
| 阶段 | 执行程序 | 物理含义 | 关键参数 | 典型迭代/耗时 |
|
||||
阶段配置见 `common::runner::default_cold_chain` / `default_seed_chain`(`StageConfig`):
|
||||
|
||||
| 阶段 | 执行程序 | 物理含义 | 关键参数 | 迭代上限 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **1. LTE 灰大气 (lte)** | `tlusty.exe` | 解析灰色不透明度求解温度结构,无需种子,提供合理起点。 | `T T` 模式 | 0 次迭代 / 1-3 秒 |
|
||||
| **2. NLTE 连续谱 (nc)** | `tlusty.exe` | 切换到 NLTE,忽略束缚-束缚线跃迁(`ilvlin=0`),收敛基础电离平衡。 | `F F`, `ilvlin=0` | 10 次迭代 / 1-5 分钟 |
|
||||
| **3. NLTE 完整谱线 (nl)** | `tlusty.exe` | 引入全部线跃迁(`ilvlin=100`),求解包含非平衡辐射场的大气结构。 | `F F`, `ilvlin=100` | 15-30 次迭代 / 5-20 分钟 |
|
||||
| **4. 合成光谱 (synspec)** | `synspec.exe` | 基于阶段 3 收敛的大气结构(`.7` 文件),计算高分辨率合成光谱。 | `INPOP=35` | 3-10 秒 |
|
||||
| **1. LTE 灰大气 (lte)** | `tlusty.exe` | 解析灰色不透明度求解温度结构,无需种子,提供合理起点。 | `lte=T, ltgray=T, niter=0, ilvlin=0` | 0 次(生成初始结构) |
|
||||
| **2. NLTE 连续谱 (nc)** | `tlusty.exe` | 切换到 NLTE,忽略束缚-束缚线跃迁(`ilvlin=0`),收敛基础电离平衡。 | `lte=F, ltgray=F, ilvlin=0, niter=10` | 10 次 |
|
||||
| **3. NLTE 完整谱线 (nl)** | `tlusty.exe` | 引入全部线跃迁(`ilvlin=100`),求解包含非平衡辐射场的大气结构;**要求收敛**(`require_converged=true`)。 | `lte=F, ltgray=F, ilvlin=100, niter=100` | 100 次 |
|
||||
| **3'. 种子热启动 (seed_nc)** | `tlusty.exe` | 以近邻收敛大气 `.7` 为 `fort.8` 初猜做 NLTE 连续谱收敛(跳过低温度灰大气阶段)。 | `lte=F, ltgray=F, ilvlin=0, niter=20, ichang=0` | 20 次 |
|
||||
| **4. 合成光谱 (synspec)** | `synspec.exe` | 基于收敛大气结构(`.7`),计算高分辨率合成光谱。 | 波长窗/展宽/截断由 `synspec:` 数值参数配置 | — |
|
||||
|
||||
> 阶段标签由 workflow 配置保证唯一(`lte`/`nc`/`nl`/`seed_nc`),各阶段输入卡/日志/大气/收敛诊断
|
||||
> 以 `<name>.<label>.<后缀>` 快照落盘归档(见 [`tlusty_result_artifacts.md`](./tlusty_result_artifacts.md))。
|
||||
|
||||
---
|
||||
|
||||
## 2. 冷启动链 vs 种子步进链 (Seed-Stepping Fallback)
|
||||
## 2. 冷启动链 vs 种子步进链(策略链机制)
|
||||
|
||||
在极端高有效温度(如 $T_{\text{eff}} \ge 50,000\text{ K}$)、极低氦丰度或强金属线空白区,从 LTE 灰大气直接启动的**冷启动链 (DEFAULT_CHAIN)** 容易发散。
|
||||
|
||||
针对这一问题,DCTS 引入了**动态种子步进机制 (Seed Stepping Chain)**:
|
||||
在极端高有效温度、极低氦丰度或强金属线空白区,从 LTE 灰大气直接启动的冷启动链容易发散。DCTS 通过 **策略链 (Strategy Chain)** 机制处理:工作流可配置 `tlusty_strategies`(如 `["cold_run", "seed_step"]`),调度器按顺序派发,失败时弹出链首、以剩余链回退重试(见 `task_engine_decoupling_design.md §4.2`)。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start([开始计算指定网格点]) --> ExecCold[执行冷启动链 lte -> nc -> nl]
|
||||
ExecCold --> CheckCold{nl 阶段物理收敛?}
|
||||
|
||||
CheckCold -- "是 (Success)" --> RunSyn1[运行 Synspec 生成光谱] --> Save1[保存结果 & 汇报成功]
|
||||
CheckCold -- "否 (Diverging)" --> IsolCold[清理并隔离冷启动失败现场]
|
||||
|
||||
IsolCold --> FindSeed[在种子库搜索最近邻已收敛 .7 种子]
|
||||
FindSeed --> HasSeed{找到合规邻居种子?}
|
||||
|
||||
HasSeed -- "是" --> ExecSeed[启动种子步进链 seed_nc -> nl\nLTGRAY=F 热启动]
|
||||
ExecSeed --> CheckSeed{nl 阶段物理收敛?}
|
||||
|
||||
CheckSeed -- "是 (Success)" --> RunSyn2[运行 Synspec 生成光谱] --> Save2[标记 seed_step_used=true & 汇报成功]
|
||||
CheckSeed -- "否 (Failed)" --> MarkFail[标记任务彻底失败]
|
||||
|
||||
HasSeed -- "否" --> MarkFail
|
||||
Start([开始计算指定网格点]) --> Resolve[调度器解析策略链\nresolve_dispatchable_chain]
|
||||
Resolve --> Exec[执行链首策略]
|
||||
Exec --> Check{nl 阶段物理收敛?}
|
||||
Check -- "是 (Success)" --> RunSyn[运行 Synspec 生成光谱] --> Save[结果入库 & 汇报成功]
|
||||
Check -- "否 (失败)" --> Pop[服务端弹出链首策略\ntrigger_strategy_fallback]
|
||||
Pop --> Rest{剩余链非空?}
|
||||
Rest -- "是,下一顺位 seed_step" --> FindSeed[查全局种子池找近邻收敛 .7 种子]
|
||||
FindSeed --> HasSeed{找到合规种子?}
|
||||
HasSeed -- "是" --> Inject[注入 seed_point_name\n重置 pending 再派发] --> Exec
|
||||
HasSeed -- "否" --> Hold[保持 pending 待种子出现后自愈\n(seed_step 顺位暂存链尾)]
|
||||
Rest -- "否(链耗尽)" --> Fail[标记任务彻底失败]
|
||||
```
|
||||
|
||||
### 种子匹配策略 (Seed Finding Algorithm)
|
||||
要点:
|
||||
|
||||
`common::seed_finder` 模块彻底摆脱了早期对文件系统进行同步阻塞遍历式查档的高耗延迟做法,改为经由 Master 服务端 SQLite 内存快照索表直接执行多级筛选,并使用标准化欧氏距离(Euclidean Distance)查找最佳热起邻格起点:
|
||||
1. **派发门控**:链首为 `seed_step` 时必须能查到近邻种子才可派发;无种子则暂存该顺位到链尾、继续解析下一项(保证终止性,重复 seed_step 不陷入死循环)。初始派发与失败回退共用 `resolve_dispatchable_chain`。
|
||||
2. **种子注入**:`seed_step` 派发时服务端在 `tasks` 行写入 `seed_point_name`,节点凭此下载种子大气(`GET /api/seed/<name>`),TLUSTY 以种子 `.7` 作为 `fort.8` 热启动输入,跳过灰大气阶段直接跑 `seed_nc -> nl`。
|
||||
3. **回退语义**:仅 `failed` 状态且状态实际迁移时触发(2026-08-02 修复,杜绝重复失败报告触发多余 seed_step);回退保留派发时的策略链快照,不修改原 `policy`。
|
||||
|
||||
$$d(p_1, p_2) = \sqrt{ \sum_{i} w_i \left( \frac{x_{1,i} - x_{2,i}}{\sigma_i} \right)^2 }$$
|
||||
---
|
||||
|
||||
优先匹配有效温度 $T_{\text{eff}}$ 和表面重力 $\log g$ 变化最小的已收敛 `.7` 大气结构作为 `fort.8` 热启动输入,跳过容易发散的灰大气阶段。
|
||||
## 3. 种子匹配算法 (Seed Finding)
|
||||
|
||||
> [!NOTE]
|
||||
> **物理现场溯源说明**:为了服务于严谨的天文理论算理复盘,Node 端的沙盒演算文件夹(`data/work/task_{uuid}`)及其中所产生成的全部迭代物理日志与 Fortran 临时数表不会触发自动入侵清除,为发生极端大气参数无解突断时的推导验证提供了长期完整的痕迹。
|
||||
>
|
||||
> **严谨声明校验**:在 `GridConfig` 的加载引擎中引入了非合规键位阻断(Denying Unknown Fields),有效杜绝了用户在定义参数和扩展选项(如 `niter`, `itek_fallback`, `template`, `fort55`, `linelist`)由于错拼被静默忽略而导致不可预测迭代的行为。
|
||||
种子池是**全局共享的物理资源池**(`seeds` 表 + 内存缓存 + 索引,跨工作流共享)。收敛且大气干净(无 NaN)的结果上报时,`.7` 大气原子写入 `seeds_dir/<name>/<name>.7` 并入库。
|
||||
|
||||
### 3.1 exact_family 桶索引
|
||||
|
||||
`(teff/5000, logg×100, loghe×100)` 量化成 `SeedBucketKey`,插入时写入 floor/floor+1 的 8 个笛卡尔积桶,查询时查 8 桶 → O(1)~O(小) 缩候选集,桶内再精算距离(量化只缩候选、不影响正确性)。
|
||||
|
||||
### 3.2 有向 CNO 距离(非对称,核心创新)
|
||||
|
||||
exact_family 判定(同物理族,仅 CNO 不同):`Δteff<5000 && Δlogg<0.01 && Δloghe<0.01`。候选按**有向 CNO 距离**排序:
|
||||
|
||||
```
|
||||
delta = target − cand(对 logc / logn / logo 各分量)
|
||||
delta > 0(目标更富,坏方向)→ 惩罚 4.0 × delta
|
||||
delta < 0(目标更贫,好方向)→ 惩罚 1.0 × |delta|
|
||||
```
|
||||
|
||||
**数据标定依据**:对历史 1191 个真实 seed_step 配对的成败统计——贫金属方向(种子更富、目标往贫走)成功率 42–54%,富金属方向仅 3–11%(`he=-4` 时 54% vs 3%,差 18 倍)。物理解释:从高金属收敛解**减少**金属是稳定微扰;反过来**增加**金属时,新增紫外谱线辐射驱动会破坏已建立的辐射平衡 → 发散出现 NaN。
|
||||
|
||||
### 3.3 全局距离(跨 teff)
|
||||
|
||||
exact_family 未命中时退化到全量扫描,候选需 `d ≤ 3.0`:
|
||||
|
||||
```
|
||||
d = Δteff/5000 + Δlogg×2 + Δloghe×0.5 + Δcno×0.1
|
||||
```
|
||||
|
||||
权重物理意义:Teff 主导黑体势(÷5000 归一);logg 破坏静力学压强平衡最烈(×2);loghe 次之(×0.5);CNO 影响紫外谱线辐射驱动,方向性已由有向距离表达(×0.1)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 节点端执行与现场处理
|
||||
|
||||
1. **种子获取**:seed_step 任务凭 `seed_point_name` 下载种子 `.7`,落 `.seed_cache/`(LRU 上限 8),再复制私有副本进 slot 沙盒作为 `fort.8`。
|
||||
2. **沙盒生命周期**:任务算完 → 上报成功(或失败,尽力而为)→ **白名单归档**(`result_dir/<name>/`,永久保留)→ **清理沙盒**;节点重启时也会**清理残留的 `task_*` 沙盒**(2026-08-02 修复:避免强杀遗留工作目录写满磁盘)。归档白名单与 TLUSTY fort 单元语义详见 [`tlusty_result_artifacts.md`](./tlusty_result_artifacts.md)。
|
||||
3. **节点无感知**:节点只执行 `strategies[0]` + 注入的 `seed_point_name`,对回退过程完全无感知,调度与计算解耦。
|
||||
|
||||
Reference in New Issue
Block a user