277 lines
5.3 KiB
Markdown
277 lines
5.3 KiB
Markdown
# 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. 推荐重构顺序
|
||
|
||
按文件大小从小到大排序(简单优先):
|
||
|
||
```bash
|
||
# 查看最小文件
|
||
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 源码
|
||
|
||
```bash
|
||
# 读取源文件
|
||
cat tlusty/extracted/expo.f
|
||
```
|
||
|
||
记录以下信息:
|
||
- 函数名/子程序名
|
||
- 输入参数及其类型
|
||
- 返回值
|
||
- 算法逻辑
|
||
- 边界条件
|
||
|
||
### Step 2: 创建 Rust 项目结构 (首次执行)
|
||
|
||
```bash
|
||
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 实现
|
||
|
||
```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
|
||
|
||
```rust
|
||
// src/lib.rs
|
||
pub mod math;
|
||
|
||
// 已完成的重构
|
||
pub mod expo;
|
||
```
|
||
|
||
### Step 5: 运行测试
|
||
|
||
```bash
|
||
cargo test expo
|
||
```
|
||
|
||
### Step 6: 记录进度
|
||
|
||
```bash
|
||
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]` |
|
||
|
||
### 控制结构
|
||
|
||
```fortran
|
||
IF (X .LT. 0) THEN
|
||
Y = -X
|
||
ELSE
|
||
Y = X
|
||
END IF
|
||
```
|
||
|
||
```rust
|
||
let y = if x < 0.0 { -x } else { x };
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 测试规范
|
||
|
||
### 单元测试
|
||
|
||
每个重构的函数必须有:
|
||
1. 正常值测试
|
||
2. 边界值测试
|
||
3. 特殊情况测试
|
||
|
||
### 回归测试
|
||
|
||
对于复杂函数,用 Fortran 生成参考数据:
|
||
|
||
```bash
|
||
# 创建 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行,最简单)
|