SpectraRust/docs/REFACTORING_PLAN.md
2026-03-21 16:23:35 +08:00

5.7 KiB
Raw Blame History

TLUSTY/SYNSPEC Rust 重构计划

概述

目标: 将 TLUSTY/SYNSPEC Fortran 代码渐进式重构为 Rust

策略: 从 tlusty/extracted/ 中无 COMMON 依赖的纯函数开始,一个文件一个文件地重构

代码规模:

  • TLUSTY: 304 个单元195 个纯函数
  • SYNSPEC: 168 个单元93 个纯函数

1. 重构原则

  1. 渐进式: 每次只重构一个文件,保持系统可用
  2. 测试驱动: 每个重构的函数必须有测试验证
  3. 精度保证: 与 Fortran 输出对比,相对误差 < 1e-10
  4. 文档先行: 记录每个函数的算法和边界条件

2. 源文件位置

tlusty/extracted/          # TLUSTY 拆分后的文件
├── expo.f                 # 纯函数示例
├── yint.f
├── tridag.f
├── ...
├── _PURE_UNITS.txt        # 无 COMMON 依赖的函数列表
├── _COMMON_ANALYSIS.txt   # COMMON 依赖分析
└── _SUMMARY.txt           # 提取摘要

synspec/extracted/         # SYNSPEC 拆分后的文件
└── ...

3. 推荐重构顺序

按文件大小从小到大排序(简单优先):

# 查看最小文件
cd /home/fmq/program/tlusty/tl208-s54/rust
while read name; do
    if [ -f "tlusty/extracted/${name,,}.f" ]; then
        lines=$(wc -l < "tlusty/extracted/${name,,}.f")
        echo "$lines $name"
    fi
done < tlusty/extracted/_PURE_UNITS.txt | sort -n | head -20

第一批 (最简单):

顺序 文件 行数 功能
1 expo.f 10 安全指数函数
2 quit.f 10 退出子程序
3 ffcros.f 13 截面计算
4 gamsp.f 14 展宽因子
5 sgmer1.f 14 Stark展宽
6 sgmerd.f 15 Stark展宽
7 lagran.f 16 Lagrange插值
8 gntk.f 17 Gaunt因子
9 raph.f 17 有理化函数
10 cross.f 18 截面计算
11 eint.f 18 指数积分
12 sghe12.f 18 He 展宽
13 yint.f 18 二次插值
14 erfcin.f 20 误差函数补
15 erfcx.f 20 缩放误差函数
16 gfree1.f 21 Gaunt自由
17 sbfhmi_old.f 22 H- 截面
18 tridag.f 22 三对角矩阵求解
19 timing.f 24 计时
20 expint.f 30 指数积分

4. 单文件重构流程

Step 1: 读取并分析 Fortran 源码

# 读取源文件
cat tlusty/extracted/expo.f

记录以下信息:

  • 函数名/子程序名
  • 输入参数及其类型
  • 返回值
  • 算法逻辑
  • 边界条件

Step 2: 创建 Rust 项目结构 (首次执行)

cd /home/fmq/program/tlusty/tl208-s54/rust

# 创建 Cargo.toml
cat > Cargo.toml << 'EOF'
[package]
name = "tlusty-rust"
version = "0.1.0"
edition = "2021"

[dependencies]
ndarray = "0.15"
num-traits = "0.2"
anyhow = "1.0"

[dev-dependencies]
approx = "0.5"
EOF

# 创建目录
mkdir -p src/math src/physics tests/fixtures

Step 3: 编写 Rust 实现

// src/math/expo.rs
/// 安全的指数函数,限制输入范围防止溢出
pub fn expo(x: f64) -> f64 {
    const CRIT: f64 = 80.0;
    x.clamp(-CRIT, CRIT).exp()
}

#[cfg(test)]
mod tests {
    use super::*;
    use approx::assert_relative_eq;

    #[test]
    fn test_expo() {
        assert_relative_eq!(expo(0.0), 1.0);
        assert_relative_eq!(expo(1.0), std::f64::consts::E);
        // 大数被限制
        assert_relative_eq!(expo(100.0), 80.0_f64.exp());
    }
}

Step 4: 更新 lib.rs

// src/lib.rs
pub mod math;

// 已完成的重构
pub mod expo;

Step 5: 运行测试

cargo test expo

Step 6: 记录进度

echo "expo - 10行 - ✓ 完成" >> REFACTORING_PROGRESS.txt

5. Fortran 语法转换参考

变量类型

Fortran Rust
IMPLICIT REAL*8(A-H,O-Z) f64
INTEGER i32
LOGICAL bool
CHARACTER*N [u8; N]String

数组

Fortran (1-indexed) Rust (0-indexed)
DIMENSION A(3) a: [f64; 3]
DIMENSION A(N) a: &[f64]Vec<f64>
A(1) a[0]

控制结构

IF (X .LT. 0) THEN
  Y = -X
ELSE
  Y = X
END IF
let y = if x < 0.0 { -x } else { x };

6. 测试规范

单元测试

每个重构的函数必须有:

  1. 正常值测试
  2. 边界值测试
  3. 特殊情况测试

回归测试

对于复杂函数,用 Fortran 生成参考数据:

# 创建 Fortran 测试程序
cat > test_expint.f << 'EOF'
      program test_expint
      IMPLICIT REAL*8(A-H,O-Z)
      do 10 x = 0.1, 10.0, 0.5
        y = expint(x)
        write(*,*) x, y
   10 continue
      end

      FUNCTION EXPINT(X)
      IMPLICIT REAL*8(A-H,O-Z)
      ... (复制原函数)
      END
EOF

gfortran -o test_expint test_expint.f
./test_expint > tests/fixtures/expint_expected.txt

7. 进度跟踪

创建文件 REFACTORING_PROGRESS.txt:

# 重构进度
# 格式: 函数名 - 行数 - 状态 - 完成日期

## 已完成
expo - 10 - ✓ - 2026-03-XX

## 进行中
(无)

## 待处理
yint - 18 - ⬜
tridag - 22 - ⬜
...

8. 下一步行动

新会话启动后:

  1. 读取本文档: cat REFACTORING_PLAN.md
  2. 查看进度: cat REFACTORING_PROGRESS.txt
  3. 选择下一个文件(从未完成的最小文件开始)
  4. 按照流程执行重构

第一个文件: expo.f (10行最简单) RYBMAT 0 0 0 0 0 ○ SETDRT 0 0 0 0 0 ○ TABINT 0 0 0 0 0 ○ TAUFR1 可能有问题

SETDRT 调用的 RHOEOS 可能被分析脚本漏掉了(因为 RHOEOS 是 FUNCTION 不是 SUBROUTINE 或者脚本认为 RHOEOS 不在调用依赖中