# Phase 3: 验证工作流参考 > 状态:待启动(Phase 2 集成完成后进入) > 模式:参照 `tlusty-iteration` skill 的逐模块严格验证流程 ## 文件路径 | 内容 | 路径 | |------|------| | Fortran 源码 | `tlusty/extracted/*.f`、`synspec/extracted/*.f` | | Rust 源码 | `src/tlusty/`、`src/synspec/` | | 验证进度 | `.claude/skills/codegraph-guide/references/verify-progress.md` | | TLUSTY Fortran 测试 | `$TLUSTY/tests/tlusty/hhe/` | | SYNSPEC Fortran 测试 | `$TLUSTY/tests/synspec/hhe/` | | TLUSTY Rust 测试 | `tests/tlusty/hhe_rust/` | | SYNSPEC Rust 测试 | `tests/synspec/hhe/` | ## 测试方式 ### TLUSTY 端到端 ```bash # Fortran 参考 cd $TLUSTY/tests/tlusty/hhe $TLUSTY/tlusty/tlusty.exe < hhe35lt.5 > hhe35lt.6 cp fort.7 hhe35lt.7.ref # Rust cargo build --bin tlusty cd tests/tlusty/hhe_rust rm -f fort.7 ../../../target/debug/tlusty < hhe35lt.5 > rust.6 2>stderr.txt # 对比 diff hhe35lt.7.ref fort.7 ``` ### SYNSPEC 端到端 ```bash # 准备(测试目录 tests/synspec/hhe/ 已有 fort.8、fort.55.con 等文件) cd tests/synspec/hhe cp hhe35nl.7 fort.8 ln -sf fort.55.con fort.55 # Fortran 参考(生成 results_original/ 中的 .spec/.cont/.iden) # 需要先编译:gfortran -O3 -fno-automatic -mcmodel=large -o synspec.exe synspec54.f ./synspec.exe < hhe35nl.5 # Rust cargo build --bin synspec cd tests/synspec/hhe rm -f fort.7 ../../../target/debug/synspec < hhe35nl.5 > rust.6 2>stderr.txt # 对比(与 Fortran 参考结果比对) diff results_original/hhe35nl.spec fort.7 ``` ## 验证工作流(严格遵守) ``` 每次会话: 1. 读取 verify-progress.md → 恢复验证进度 2. 运行 Rust → 与 Fortran 参考输出对比 3. 输出完全一致 → 更新 verify-progress.md → 结束 4. 输出不一致 → 从断点继续逐模块验证: a. 读取 verify-progress.md 中 "下一个待验证模块" b. ★ 必须先读取对应的 Fortran 文件,逐行理解原始逻辑 c. 然后读取对应的 Rust 文件 d. 逐行对比: 调用顺序、变量映射、索引转换、逻辑分支 e. 发现差异 → 立即修复 → cargo build 验证 f. 更新 verify-progress.md → 继续下一个模块 5. 全部通过 → 运行测试套件 → 更新 verify-progress.md ``` ## ★ 核心原则:必须参考 Fortran 代码 ``` 严禁凭猜测修改代码!每次修改前必须: 1. 先读取对应的 Fortran 源码文件 2. 理解 Fortran 的确切逻辑流程 3. 找到 Fortran 中的对应行 4. 然后对照修改 Rust 代码 违反此原则是产生 bug 的最主要原因。 ``` ## 验证顺序 ### TLUSTY 调用链 ``` TLUSTY (tlusty.f) → START (start.f) → INITIA (initia.f) ★ 最大模块 → HEDIF (hedif.f) [可选] → COMSET (comset.f) → PRDINI (prdini.f) → RESOLV (resolv.f) → INILAM, LINSEL, OPAINI ... → OPACF0, OPACF1, RTEFR1 ... → LUCY (lucy.f) → OUTPUT → ACCEL2 (accel2.f) → SOLVE / SOLVES / RYBSOL → MATGEN → BRTE, BHE, BRE → MATINV ``` ### SYNSPEC 调用链 ``` SYNSPEC (synspec54.f) → START → INITIA → STATE0, RDATA → INPMOD / INKUR → TINT, INIMOD → INILIN → read_line_list → INIBL0 / INIBL1 → RESOLV → INILAM, HYLSET, HE2SET → INIBLA, INIBLM → OPAC → HYDLIN, LINOP, ... → RTE / RTECD → OUTPRI ``` ## 模块文件映射 ### TLUSTY | Fortran 模块 | Fortran 文件 | Rust 文件 | 子目录 | |-------------|-------------|-----------|--------| | TLUSTY | tlusty.f | `src/tlusty/main.rs` | (主程序) | | START | start.f | `src/tlusty/io/start.rs` | io/ | | INITIA | initia.f | `src/tlusty/io/initia.rs` | io/ | | RESOLV | resolv.f | `src/tlusty/io/resolv.rs` | io/ | | ACCEL2 | accel2.f | `src/tlusty/math/ali/accel2.rs` | math/ali/ | | SOLVE | solve.f | `src/tlusty/math/solvers/solve.rs` | math/solvers/ | 特殊映射(多合一 Rust 文件): - `bhe.rs` ← BHE, BHED, BHEZ - `gfree.rs` ← GFREE0, GFREED, GFREE1 - `interpolate.rs` ← YINT, LAGRAN - `sgmer.rs` ← SGMER0, SGMER1, SGMERD - `ctdata.rs` ← HCTION, HCTRECOM - `cross.rs` ← CROSS, CROSSD - `expint.rs` ← EINT, EXPINX - `erfcx.rs` ← ERFCX, ERFCIN math 子目录: ali, atomic, continuum, convection, eos, hydrogen, interpolation, odf, opacity, partition, population, radiative, rates, solvers, special, temperature, utils ### SYNSPEC | Fortran 模块 | Fortran 文件 | Rust 文件 | 子目录 | |-------------|-------------|-----------|--------| | SYNSPEC | synspec54.f | `src/bin/synspec.rs` → `src/synspec/runner.rs` | bin/ | | INITIA | initia.f | `src/synspec/math/initia_synspec.rs` | math/ | | INILIN | inilin.f | `src/synspec/math/inilin.rs` | math/ | | RESOLV | resolv.f | `src/synspec/math/resolv.rs` | math/ | | OPAC | opac.f | `src/synspec/math/opac.rs` | math/ | | RTE | rte.f | `src/synspec/math/rte.rs` | math/ | | OUTPRI | outpri.f | `src/synspec/math/outpri.rs` | math/ | ## 检查清单(每个模块必须逐项验证) ``` [ ] 调用顺序: Fortran CALL 顺序 == Rust 函数顺序 [ ] 变量映射: Fortran COMMON 变量 → 正确的 Rust struct 字段 [ ] 数组下标: 1-based→0-based, Fortran 列主序→Rust 行主序 [ ] 循环边界: DO I=1,N → 0..n, DO I=N,1,-1 → (0..n).rev() [ ] IF 条件: .AND.→&&, .OR.→||, .EQ.→==, .NE.→!=, 全覆盖 [ ] 赋值完整性: 每个 Fortran 赋值都有对应 Rust 赋值(无遗漏) [ ] I/O 语句: WRITE/READ/PRINT 对应 Rust 的文件 I/O [ ] 函数调用: 每个子程序调用参数正确传递 [ ] 回调模式: 回调/closure 必须调用实际函数(不能是空壳 NoOp) [ ] 数学公式: 常数和计算公式与特殊函数完全一致 [ ] 编译验证: cargo build 无错误 [ ] DATA 语句: 已预提取到 src/data.rs ``` ## 判断标准 模块检查结果只有三种状态: ``` 通过 — 逐行对比一致,调用完整,无空壳,逻辑相同。通过时立即检查下一个模块 未通过 — 发现具体差异,修复后 cargo build 通过,但输出仍不一致 跳过 — 不需要检查(如纯工具函数,已有充分单元测试覆盖) ``` ## 修复原则 ``` 1. 严格对照 Fortran: 按 Fortran 代码行号逐行对比 Rust 实现 2. 保持调用顺序: Fortran 中的 CALL 顺序必须严格保持 3. 正确映射 COMMON: 使用 Fortran INCLUDE 文件确认变量含义 4. 控制流程等价: IF/DO/SELECT CASE 逻辑必须一致 5. 数组下标转换: Fortran 列主序 1-based → Rust 行主序 0-based 6. 不能用 NoOp 回调: 如果 Fortran 有 CALL,Rust 必须调用实际函数 7. 复杂模块分解: 分步骤修复,每步验证编译 ``` ## 完成标准 1. TLUSTY 端到端: `fort.7` 与 Fortran 参考二进制一致 2. SYNSPEC 端到端: `fort.7` 与 Fortran 参考二进制一致 3. `cargo clippy` 零错误 4. 相关模块的单元测试通过(禁止全量测试,内存会被占满) 5. 全部通过后创建 `.f2r_complete` 文件