SpectraRust/.claude/skills/fortran-to-rust/SKILL.md
2026-03-23 15:45:52 +08:00

466 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: fortran-to-rust
description: "Fortran 到 Rust 的重构指南和工作流。触发条件:(1) 刚使用过fortran-analyzer skills 获得需要重构的模块2用户提到重构 Fortran 到 Rust(3) 开始新的 Fortran 函数重构。4) 继续重构下一个fortran模块。提供完整重构流程、常见陷阱、测试规范。"
---
# Fortran → Rust 重构指南
将 TLUSTY/SYNSPEC 的 Fortran 函数重构为 Rust。
---
## 重构流程
### Step 1: 选择目标函数
注意:使用 fortran-analyzer skills 获取需要重构的模块。
**选择原则**
- **必须**选择fortran-analyzer skills推荐的第一个模块
- 不要因为行数多、复杂或者 COMMON 依赖就回避它们,不要回避复杂函数,它们往往是重构重点。
### Step 2: 分析 Fortran 源码
```bash
cat tlusty/extracted/TARGET.f
```
**检查清单**
```
[ ] INCLUDE 文件COMMON 块 → src/state/
[ ] 函数参数和返回值
[ ] 调用的其他函数(是否已实现?)
[ ] 是否有 I/O 操作READ/WRITE/OPEN
[ ] DATA 语句(已预提取到 src/data.rs
```
**重要**:不要删减任何逻辑,完整实现 Fortran 功能。
### Step 3: 创建 Rust 模块
```bash
touch src/math/TARGET.rs
```
### Step 4: 实现函数
**命名映射**:
| Fortran | Rust |
|---------|------|
| `FUNCTION` | `pub fn` |
| `SUBROUTINE` | `pub fn`(返回值用元组或结构体)|
| COMMON 块 | 结构体参数 |
### Step 5: 添加到 mod.rs
```rust
// src/math/mod.rs 或 src/io/mod.rs
mod target;
pub use target::target;
```
### Step 6: 编写测试
**注意**: 需要编写完整的真实的函数测试,而不只是测试变量
```rust
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_basic() {
// 基本功能测试
}
}
```
### Step 7: 运行测试
```bash
# 推荐:静默警告
RUSTFLAGS="-A warnings" cargo test target 2>&1 | tail -10
# 或简洁输出
cargo test target -- --quiet 2>&1 | grep -E "^test|^running|^test result"
```
---
## I/O 模块重构
### 何时使用 I/O 兼容层
当模块包含以下操作时:
- `READ(unit, ...)` - 从文件/标准输入读取
- `WRITE(unit, ...)` - 写入文件/标准输出
- `OPEN(...)` - 打开文件
### I/O 模块分类
| 类别 | 策略 | 示例 |
|------|------|------|
| **调试输出** | 删除或用 `log::debug!` | fort.10, fort.14, fort.18 |
| **进度输出** | 保留,用 `FortranWriter` | fort.6, fort.9 |
| **模型 I/O** | 必须兼容,用 `model.rs` | fort.7, fort.8 |
| **参数文件** | 用 `FortranReader` | fort.5, fort.55 |
### I/O 重构模式
#### 模式 1: 分离计算与 I/O
```rust
// ❌ 混合(难以测试)
pub fn read_and_calculate() -> Result<f64> {
let input = read_from_file()?; // I/O
let result = calculate(input); // 计算
write_to_file(result)?; // I/O
Ok(result)
}
// ✅ 分离(可独立测试)
pub fn calculate(params: &CalcParams) -> CalcResult {
// 纯计算,无 I/O
}
pub fn run(input_path: &str, output_path: &str) -> Result<()> {
let reader = FortranReader::from_file(input_path)?;
let params = parse_input(reader)?;
let result = calculate(&params);
let mut writer = FortranWriter::to_file(output_path)?;
write_result(&mut writer, &result)?;
Ok(())
}
```
#### 模式 2: 使用 I/O 兼容层
```rust
use crate::io::{FortranReader, FortranWriter, ModelFile};
// 读取输入
let mut reader = FortranReader::from_file("fort.5")?;
let teff: f64 = reader.read_value()?;
let grav: f64 = reader.read_value()?;
// 读取模型
let model = ModelFile::read(FortranReader::from_file("fort.8")?)?;
// 写入模型(与 Fortran 字节级兼容)
ModelFile::write(&model, BufWriter::new(File::create("fort.7")?))?;
```
### Fortran I/O 特性处理
| Fortran 特性 | Rust 处理 |
|-------------|----------|
| `READ(*,*)` 自由格式 | `FortranReader::read_value()` |
| `READ(IBUFF,*)` 缓冲区 | `FortranReader` 从字符串创建 |
| `WRITE(6,601)` FORMAT | `FortranWriter` + `format_exp_fortran` |
| `!` 行内注释 | `FortranReader::read_line()` 自动跳过 |
| `*` 固定格式注释 | `FortranReader::read_line()` 自动跳过 |
| `'string'` 引号字符串 | `FortranReader::read_string()` |
| `D` 指数符号 | `FromFortran::from_fortran_str()` 自动转换 |
### 单元号映射
```rust
// src/io/mod.rs
pub mod units {
pub const STDIN: u8 = 5;
pub const STDOUT: u8 = 6;
pub const MODEL_OUT: u8 = 7;
pub const MODEL_IN: u8 = 8;
pub const CONV_HIST: u8 = 9;
pub const SCRATCH: [u8; 3] = [91, 92, 93];
}
```
### 有 I/O 的模块列表
| 模块 | 主要 I/O | 重构策略 |
|------|---------|---------|
| **INITIA** | 打开所有输入文件 | 高:入口点 |
| **OUTPUT** | fort.7, fort.12, fort.22 | 高:模型输出 |
| **READBF** | 原子数据文件 | 中:用 FortranReader |
| **KURUCZ** | Kurucz 格式模型 | 中:格式转换 |
| **NSTPAR** | 非标准参数 | 低:可选 |
| **TIMING** | fort.69 | 低:调试 |
---
## 常见陷阱
### 索引和表达式
| 问题 | Fortran | Rust |
|------|---------|------|
| 数组索引 | `arr(i)` 1-indexed | `arr[i-1]` 0-indexed |
| 负对数 | `-LOG(X)` | `-ln(X)` 不是 `ln(-X)` |
| 幂运算 | `x**2` | `(x)*(x)` 避免类型歧义 |
| 递减循环 | `DO I=N,1,-1` | 用 `isize` 不用 `usize` |
### 矩阵存储
```rust
// Fortran 列优先: A(j,i) = a[(i-1)*N + (j-1)]
// 读取时:
for i in 0..n {
for j in 0..m {
a[i * m + j] = reader.read_value()?;
}
}
```
### 类型推断
```rust
// ❌ 编译错误
let result = (z1 - z2).powi(2);
// ✅ 显式乘法
let result = (z1 - z2) * (z1 - z2);
```
### I/O 生命周期
```rust
// ❌ 返回引用,但修改了源
fn extract_token(&mut self) -> Result<&str> {
let token = &self.remaining[..];
self.remaining = "...".to_string(); // 借用冲突!
Ok(token)
}
// ✅ 返回 String
fn extract_token(&mut self) -> Result<String> {
let token = self.remaining[..end].to_string();
self.remaining = self.remaining[end..].to_string();
Ok(token)
}
```
---
## 测试规范
### 精度要求
| 函数类型 | 容差 | 示例 |
|---------|------|------|
| 简单数学运算 | `1e-10` | `exp`, `log` |
| 多项式近似 | `1e-7` | Abramowitz-Stegun |
| f32 数组 | `1e-24` | Voigt 轮廓 |
| I/O 读写 | `1e-6` | 模型文件往返 |
```rust
use approx::assert_relative_eq;
#[test]
fn test_calculation() {
let result = calculate(35000.0);
assert_relative_eq!(result, expected, epsilon = 1e-7);
}
```
### I/O 测试模式
```rust
#[test]
fn test_model_roundtrip() {
// 创建测试模型
let mut model = ModelState::new(3, 3);
model.temp = vec![10000.0, 8000.0, 5000.0];
// 写入内存
let mut buffer = Vec::new();
ModelFile::write(&model, BufWriter::new(&mut buffer)).unwrap();
// 读回
let cursor = Cursor::new(buffer);
let reader = FortranReader::new(BufReader::new(cursor));
let model2 = ModelFile::read(reader).unwrap();
// 验证
for i in 0..model.nd {
assert_relative_eq!(model2.temp[i], model.temp[i], epsilon = 1e-6);
}
}
```
### 测试命令
```bash
# 单模块测试(推荐)
RUSTFLAGS="-A warnings" cargo test target 2>&1 | tail -10
# I/O 模块测试
cargo test io:: 2>&1 | grep -E "^test |^test result"
# 全量测试(谨慎!可能卡死)
# cargo test
```
---
## 代码规范
### 文件头注释
```rust
//! 模块简要说明。
//!
//! 重构自 TLUSTY `filename.f`
```
### 函数注释
```rust
/// 函数功能说明。
///
/// # 参数
/// * `x` - 参数说明
///
/// # 返回值
/// 返回值说明
pub fn func(x: f64) -> f64 { ... }
```
### I/O 模块结构
```rust
// src/io/TARGET.rs
//! 模块说明
use super::{FortranReader, FortranWriter, Result};
/// 参数结构体
pub struct TargetParams<'a> {
pub input: &'a [f64],
}
/// 输出结构体
pub struct TargetOutput {
pub result: f64,
}
/// 纯计算函数(可测试)
pub fn target_pure(params: &TargetParams) -> TargetOutput {
// 实现
}
/// 带 I/O 的入口(调用纯计算)
pub fn target(input_path: &str, output_path: &str) -> Result<TargetOutput> {
let reader = FortranReader::from_file(input_path)?;
let params = parse_params(reader)?;
let result = target_pure(&params);
// 可选:写输出
Ok(result)
}
```
---
## 快速命令参考
```bash
# === 分析 ===
# 查看重构进度
python3 .claude/skills/fortran-analyzer/scripts/analyze_fortran.py --priority | head -20
# 查看函数依赖树
python3 .claude/skills/fortran-analyzer/scripts/analyze_fortran.py --tree FUNCTION_NAME
# === 编译 ===
# 编译检查
cargo build 2>&1 | grep error
# 编译检查(静默警告)
RUSTFLAGS="-A warnings" cargo build 2>&1 | tail -5
# === 测试 ===
# 单模块测试(推荐)
RUSTFLAGS="-A warnings" cargo test target 2>&1 | tail -10
# I/O 模块测试
cargo test io:: 2>&1 | grep -E "^test |^test result"
```
---
## 项目结构
```
rust/src/
├── io/ # I/O 兼容层
│ ├── mod.rs # 模块入口,单元号常量
│ ├── reader.rs # FortranReader自由格式
│ ├── writer.rs # FortranWriter格式化输出
│ ├── model.rs # fort.7/8 模型文件
│ ├── input.rs # fort.5 主输入
│ └── format.rs # FORMAT 解析
├── math/ # 纯计算函数 (120+ 个 .rs 文件)
├── state/ # COMMON 块 (8 个模块)
│ ├── constants.rs # BASICS.FOR
│ ├── atomic.rs # ATOMIC.FOR
│ ├── model.rs # MODELQ.FOR
│ ├── arrays.rs # ARRAY1.FOR
│ ├── iterat.rs # ITERAT.FOR
│ ├── alipar.rs # ALIPAR.FOR
│ └── odfpar.rs # ODFPAR.FOR
└── data.rs # 静态数据DATA 语句)
```
---
## 相关文档
| 文档 | 内容 |
|------|------|
| `.learnings/LEARNINGS.md` | 14 个实际案例索引、表达式、COMMON 等) |
| `docs/TLUSTY_IO_FILES.md` | 完整 I/O 文件映射 |
| `docs/SYNSPEC_IO_FILES.md` | SYNSPEC I/O 文件 |
| `docs/IO_COMPATIBILITY_LAYER.md` | I/O 兼容层设计 |
---
## 相关 Skills
| Skill | 用途 | 状态 |
|-------|------|------|
| `fortran-extractor` | 提取 Fortran 文件 | ✅ 已完成 |
| `fortran-analyzer` | 分析依赖关系 | 活跃使用 |
| `fortran-to-rust` | 执行重构 | 本 skill |
| `self-improving-agent` | 记录经验教训 | 建议配合使用 |
---
## 经验记录
重构过程中遇到问题或发现新模式时,使用 self-improving-agent 记录:
```bash
# 记录到 .learnings/LEARNINGS.md
# 格式:
## [LRN-YYYYMMDD-XXX] category
**Priority**: high | medium | low
**Status**: pending | resolved | promoted
### Summary
一句话总结
### Details
详细说明
### Metadata
- Source: 模块名
- Tags: 关键词
```