This commit is contained in:
Asfmq 2026-03-22 00:30:20 +08:00
parent 497e62e13c
commit 59404207c3
27 changed files with 4035 additions and 4352 deletions

9
.learnings/ERRORS.md Normal file
View File

@ -0,0 +1,9 @@
# Errors
Command failures, exceptions, and unexpected behavior captured during development.
**Areas**: frontend | backend | infra | tests | docs | config
**Statuses**: pending | in_progress | resolved | wont_fix
---

View File

@ -0,0 +1,9 @@
# Feature Requests
User-requested capabilities and enhancements.
**Areas**: frontend | backend | infra | tests | docs | config
**Statuses**: pending | in_progress | resolved | wont_fix
---

446
.learnings/LEARNINGS.md Normal file
View File

@ -0,0 +1,446 @@
# Learnings
Corrections, insights, and knowledge gaps captured during development.
**Categories**: correction | insight | knowledge_gap | best_practice
**Areas**: frontend | backend | infra | tests | docs | config
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
## Status Definitions
| Status | Meaning |
|--------|---------|
| `pending` | Not yet addressed |
| `in_progress` | Actively being worked on |
| `resolved` | Issue fixed or knowledge integrated |
| `wont_fix` | Decided not to address (reason in Resolution) |
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
| `promoted_to_skill` | Extracted as a reusable skill |
---
## [LRN-20260321-F01] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
Fortran 1-indexed 转 Rust 0-indexed 的关键规则
### Details
- 数组访问: `arr(i)``arr[i-1]`
- 循环范围: `DO I=1,N``for i in 0..n`
- 边界条件: Fortran jl=0 表示"在第一个有效索引之前"Rust jl=0 就是第一个有效索引
### Suggested Action
重构时删除类似 `IF (J.EQ.0) J = J+1` 的调整逻辑
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: ylintp.f, locate.f
- Tags: indexing, fortran, rust
---
## [LRN-20260321-F02] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
Fortran 表达式 `-LOG(X)``-(LOG(X))`,不是 `LOG(-X)`
### Details
`XL=-LOG(X)` 应翻译为 `let xl = -x.ln()`,不是 `let xl = (-x).ln()`
后者对 x>0 会返回 NaN
### Suggested Action
翻译数学表达式时注意运算符优先级
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: erfcin.f
- Tags: expression, fortran, rust
---
## [LRN-20260321-F03] insight
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: backend
### Summary
`(z1 - z2).powi(2)` 编译错误 - 类型推断失败
### Details
编译器无法推断中间表达式的类型,使用显式乘法 `(z1 - z2) * (z1 - z2)` 代替
### Metadata
- Source: fortran-to-rust refactoring
- Tags: rust, type_inference, powi
---
## [LRN-20260321-F04] best_practice
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: tests
### Summary
多项式近似精度容差:简单函数 1e-10多项式 1e-7
### Details
Abramowitz-Stegun 多项式近似本身精度有限
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: eint.f
- Tags: precision, polynomial, testing
---
## [LRN-20260321-F05] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
递减循环变量用 isize 不用 usize避免溢出
### Details
当循环变量递减到负数时,无符号整数会溢出
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: collhe.f
- Tags: overflow, rust, loop
---
## [LRN-20260321-F06] best_practice
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
重构前必须检查所有 INCLUDE 语句,不仅是 IMPLIC.FOR
### Details
已确认有 COMMON 依赖的"纯函数"文件:
gamsp.f, sgmer1.f, sgmerd.f, cross.f, gfree0.f, gfreed.f, gfree1.f, wn.f, crossd.f, dopgam.f, verner.f, sbfhe1.f
### Suggested Action
添加新结构体前先 grep 检查是否已存在
### Metadata
- Source: fortran-to-rust refactoring
- Tags: common, fortran, dependency
---
## [LRN-20260321-F07] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: tests
### Summary
测试数组值不能全部相同,会导致除零
### Details
```rust
// 错误:全部相同 → ddm = 0 → dtm = 1/0 = inf
let dm = vec![0.01; MDEPTH];
// 正确:递增模拟物理分布
let dm: Vec<f64> = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect();
```
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: rybmat.rs
- Tags: testing, data_design
---
## [LRN-20260321-F08] insight
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: backend
### Summary
Fortran 修改 COMMON 块数组 → Rust 需要 &mut 引用
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: tabint.f
- Tags: rust, mutability, reference
---
## [LRN-20260321-F09] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: config
### Summary
analyze_fortran.py 只匹配 CALL 语句,漏掉 FUNCTION 调用
### Details
需要两遍扫描1) 收集所有已定义函数名 2) 只匹配已知函数名
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: scripts/analyze_fortran.py
- Tags: dependency, analysis, python
---
## [LRN-20260321-F10] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: tests
### Summary
测试参数设置时避免矩阵列重叠
### Details
主循环更新列和温度/密度列可能重叠,设置 inre=0, inpc=0 避免重叠
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: bpopf.rs
- Tags: testing, matrix, indexing
---
## [LRN-20260321-F11] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
公式中 `1/x``x` 的顺序要仔细核对
### Details
`5.484e-14 / x2 * (...)` 其中 x2=1/x²等于乘以 x²不是除以
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: rayleig.f
- Tags: formula, rust, physics
---
## [LRN-20260321-F12] best_practice
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: backend
### Summary
大型 COMMON 块函数使用生命周期结构体
### Details
```rust
pub struct Alifr3ModelState<'a> {
pub elec: &'a [f64], // 输入
pub heit: &'a mut [f64], // 输出
}
```
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: alifr3.rs, alifr6.rs
- Tags: rust, struct, lifetime
---
## [LRN-20260321-F13] insight
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: backend
### Summary
Fortran GOTO 分支 → Rust if-else + early return
### Details
每个 GOTO 标签对应一个 if 块
### Metadata
- Source: fortran-to-rust refactoring
- Tags: fortran, goto, control_flow
---
## [LRN-20260321-F14] correction
**Logged**: 2026-03-21T19:55:00Z
**Priority**: medium
**Status**: resolved
**Area**: backend
### Summary
循环中重新赋值的变量必须声明为 mut
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: alifr6.rs
- Tags: rust, mutability
---
## [LRN-20260321-F15] correction
**Logged**: 2026-03-21T12:00:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
Fortran 3D 数组转 Rust 扁平数组时,必须知道所有维度才能正确计算索引
### Details
Fortran `absopac(jt,jr,jf)` 是 3D 数组 (numtemp × numrh × nfreq),转 Rust 扁平数组时:
- **错误**: 用 `jt_idx * numtemp * nfreq` (用了 numtemp 作为第二维度)
- **正确**: 用 `jt_idx * max_numrh * nfreq` (必须用实际维度 max_numrh)
类似地2D 数组 `rhomat(jt,jr)` 转扁平时:
- **错误**: `rhomat[jt_idx * numtemp]`
- **正确**: `rhomat[jt_idx * max_numrh]`
### Suggested Action
重构多维数组时,结构体必须包含所有维度信息,特别是可能变化的维度(如每个温度有不同的密度数)
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: opctab.rs, opctab.f
- Tags: array, indexing, fortran, rust, multi-dimensional
---
## [LRN-20260321-F16] correction
**Logged**: 2026-03-21T12:00:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
Fortran 条件 `if(a.eq.b)` 转 Rust 时不要误用其他变量
### Details
Fortran `if(numtemp.eq.nd)` 检查表温度数是否等于总深度数:
- **错误**: `if table.numtemp == params.id` (用了当前深度索引)
- **正确**: `if table.numtemp == table.nd` (用总深度数)
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: opctab.rs, opctab.f
- Tags: condition, variable, fortran, rust
---
## [LRN-20260321-F17] correction
**Logged**: 2026-03-21T12:00:00Z
**Priority**: high
**Status**: resolved
**Area**: backend
### Summary
分支条件相同代码是 bug必须对照 Fortran 完整实现
### Details
`if params.ibc == 0 { ... } else { ... }` 两个分支代码完全相同时是错误的。
Fortran 原代码 ELSE 分支有额外项:
```fortran
REIT(ID)=REIT(ID)+WW*(D0*(DSFT1-DBDT)+E0*DABT1(ID)+
* RAD1(ID)*DABT1(ID)-DEMT1(ID)+
* ALI1(ID)/ABST*DBDT)
```
变量 `DBDT``E0` 在边界条件块中计算,需要在更大作用域中声明才能在积分方程块中使用。
### Suggested Action
重构时如果看到 if-else 分支代码相同,立即检查 Fortran 原代码
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: alifr1.rs, alifr1.f
- Tags: branch, bug, fortran, rust
---
## [LRN-20260321-F18] best_practice
**Logged**: 2026-03-21T12:00:00Z
**Priority**: medium
**Status**: resolved
**Area**: docs
### Summary
模块文档应完整描述所有功能,不仅是主要功能
### Details
opctab.rs 原文档只提到"插值计算",漏掉了:
- Rayleigh 散射计算(简单公式或调用 rayleigh 函数)
- 电子散射计算
### Suggested Action
重构完成后对照 Fortran 原代码检查文档是否完整
### Metadata
- Source: fortran-to-rust refactoring
- Related Files: opctab.rs, opctab.f
- Tags: documentation, completeness
---
## Quick Reference - Refactoring Checklist
重构新函数前检查:
- [ ] 是否有 INCLUDE 语句 (除 IMPLIC.FOR 外)
- [ ] 是否使用 COMMON 块
- [ ] COMMON 块结构体是否已存在于其他模块
- [ ] 是否有文件 I/O (OPEN, READ, WRITE)
- [ ] 数组索引是否需要 -1 调整
- [ ] 循环变量是否可能变负 (用 isize/i32)
- [ ] 多项式近似精度是否需要放宽
- [ ] 是否有嵌套 IF 分支遗漏
- [ ] 矩阵列索引是否可能与温度/密度列重叠
- [ ] 公式中 `1/x``x` 的顺序是否正确
- [ ] 大型 COMMON 块函数是否需要创建综合输入结构体
- [ ] 多分支 GOTO 是否正确转换为 if-else
- [ ] 循环中重新赋值的变量是否声明为 mut
- [ ] 多维数组扁平化时是否使用了正确的维度(不是第一个维度)
- [ ] 条件语句中的变量是否与 Fortran 原代码一致
- [ ] 模块文档是否描述了所有功能(包括次要功能)
- [ ] if-else 分支代码是否完全相同(相同则是 bug
- [ ] 边界条件块中计算的变量是否在积分方程块中可用(作用域问题)

101
CLAUDE.md
View File

@ -6,8 +6,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
Fortran stellar atmosphere modeling suite being refactored to Rust. Strategy: **split Fortran into modules first, then incrementally rewrite in Rust**.
- **TLUSTY 208**: Non-LTE stellar atmosphere calculator (50,009 lines → 304 modules)
- **SYNSPEC 54**: Synthetic spectrum evaluator (23,917 lines → 168 modules)
- **TLUSTY 208**: Non-LTE stellar atmosphere calculator (~50,000 lines → 304 modules)
- **SYNSPEC 54**: Synthetic spectrum evaluator (~24,000 lines → 168 modules)
- **Progress**: 120/~472 Fortran units translated to Rust
## Environment Variables
@ -21,60 +22,106 @@ export OPTABLES=$TL208/optables
## Build Commands
### Rust
```bash
cargo build # Debug build
cargo build --release # Release build
cargo test # Run all tests (includes Fortran comparison tests)
cargo test test_expo # Run specific test
```
### Fortran
```bash
# Production (single file)
gfortran -O3 -fno-automatic -mcmodel=large -o tlusty/tlusty.exe tlusty/tlusty208.f
gfortran -O3 -fno-automatic -mcmodel=large -o synspec/synspec.exe synspec/synspec54.f
# Development (modular)
python3 extract_fortran.py tlusty/tlusty208.f tlusty/extracted/
cp tlusty/*.FOR tlusty/extracted/
cd tlusty/extracted && make # Output: build/tlusty_extracted
cd rust/tlusty/extracted && make # Output: build/tlusty_extracted
```
**Compile flags:**
**Fortran compile flags:**
- `-mcmodel=large`: Required for large COMMON blocks (>2GB address space)
- `-fno-automatic`: Static storage (old Fortran compatibility)
- **Never use** `-ffixed-line-length-none`: Breaks columns 73-80 handling
## Rust Architecture
```
src/
├── lib.rs # Module exports
├── data.rs # Static data arrays (translated from BLOCK DATA)
├── math/ # Pure math functions (no COMMON dependency) - 120 modules
│ ├── expint.rs # Exponential integrals
│ ├── voigt.rs # Voigt profile
│ ├── tridag.rs # Tridiagonal solver
│ └── ...
├── state/ # COMMON block translations as structs
│ ├── constants.rs # Physical/math constants, array dimensions
│ ├── config.rs # Runtime config
│ ├── atomic.rs # Atomic/ion/level data
│ ├── model.rs # Atmosphere model state (largest struct)
│ ├── arrays.rs # Main linear equation arrays
│ ├── iterat.rs # Iteration control
│ ├── alipar.rs # ALI (Accelerated Lambda Iteration) arrays
│ └── odfpar.rs # ODF (Opacity Distribution Function) data
└── physics/ # Physics calculations (placeholder)
```
## Running Tests
### Rust Tests
```bash
cargo test # All unit tests
cargo test --test fortran_comparison # Fortran comparison tests only
```
### Fortran Integration Tests
```bash
# TLUSTY: H-He model test
cd tests/tlusty/hhe
cd $TLUSTY/tests/tlusty/hhe
$TLUSTY/tlusty/tlusty.exe < hhe35lt.5 > hhe35lt.6
cp fort.7 hhe35lt.7
diff hhe35lt.7 hhe35lt.7.bak # Verify against expected
diff hhe35lt.7 hhe35lt.7.bak
# SYNSPEC: spectrum test
cd tests/synspec/hhe
ln -sf $TLUSTY/data data # MUST be symlink, not file
cd $TLUSTY/tests/synspec/hhe
ln -sf $TLUSTY/data data
cp hhe35nl.7 fort.8
ln -sf fort.55.con fort.55
$TLUSTY/synspec/synspec.exe < hhe35nl.5
# Output: fort.7 (spectrum), fort.17 (continuum)
```
## Module Extraction
## Refactoring Workflow
`extract_fortran.py` splits monolithic Fortran into individual `.f` files:
- Generates Makefile with correct flags
- Analyzes COMMON block dependencies
- Identifies pure functions (no COMMON) for independent testing
- Handles unnamed BLOCK DATA units
1. **Find pure functions**: Check `rust/tlusty/extracted/_PURE_UNITS.txt` for units without COMMON dependencies
2. **Translate**: Create `src/math/<name>.rs`, add to `src/math/mod.rs`
3. **Verify**: Add test case in `tests/fortran_comparison.rs` with Fortran reference values
## Key Architecture
**TLUSTY include files** define COMMON blocks shared across subroutines:
- `BASICS.FOR`: Array dimensions (`MDEPTH`=100, `MFREQ`=135000, `MLEVEL`=1134)
- `ATOMIC.FOR`: Atomic masses, abundances, energy levels
- `MODELQ.FOR`: Temperature, density, populations
- `ARRAY1.FOR`: Main linear equation arrays
**TLUSTY COMMON blocks** (mapped to `src/state/` structs):
- `BASICS.FOR``constants.rs`: Array dimensions (`MDEPTH`=100, `MFREQ`=135000, `MLEVEL`=1134)
- `ATOMIC.FOR``atomic.rs`: Atomic masses, abundances, energy levels
- `MODELQ.FOR``model.rs`: Temperature, density, populations
- `ARRAY1.FOR``arrays.rs`: Main linear equation arrays
**SYNSPEC** reads model atmosphere from `fort.8`, outputs spectrum to `fort.7`.
**SYNSPEC** reads model atmosphere from `fort.8`, outputs spectrum to `fort.7`
## Refactoring Notes
## Fortran → Rust Translation Notes
- Pure functions (no COMMON dependency) can be rewritten independently
- TLUSTY has 195 pure units, SYNSPEC has 93
- See `memory/MEMORY.md` for detailed extraction results and test procedures
Critical patterns to avoid mistakes:
- **Index conversion**: Fortran 1-indexed → Rust 0-indexed. `arr(i)``arr[i-1]`, `DO I=1,N``for i in 0..n`
- **Expression precedence**: `-LOG(X)` is `-(LOG(X))`, not `LOG(-X)`
- **Decrementing loops**: Use `isize`/`i32` when loop variable may become negative
- **COMMON dependency**: Check INCLUDE statements before assuming a function is pure
- **Large structs**: Functions with many COMMON dependencies use lifetime structs:
```rust
pub struct Params<'a> {
pub input: &'a [f64],
pub output: &'a mut [f64],
}
```
- **Type inference**: `(z1 - z2).powi(2)` may fail; use `(z1 - z2) * (z1 - z2)`
- **Test tolerance**: Polynomial approximations (Abramowitz-Stegun) need relaxed tolerance (~1e-7)

View File

@ -1,337 +0,0 @@
# Fortran 重构追踪表
> 自动生成,请勿手动修改。运行 `python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md` 更新。
## 统计
| 指标 | 数量 |
|------|------|
| 总单元数 | 304 |
| 已完成 | 125 |
| 待处理 | 179 |
| 纯函数 | 67 |
| 有文件 I/O | 117 |
| 完成率 | 41.1% |
## 状态说明
- ✅ `done` - 已重构为 Rust
- ⬜ `pending` - 待处理
- 🔄 `in_progress` - 进行中
- ⏭️ `skip` - 跳过 (I/O 依赖或暂不处理)
## 类型说明
- **纯函数**: 无 COMMON 依赖、无文件 I/O、无外部调用依赖
- **COMMON 依赖**: 需要状态结构体
- **调用依赖**: 调用其他子程序,需要先实现依赖
## 完整追踪表
| Fortran 文件 | 单元名 | 类型 | 纯函数 | COMMON 依赖 | 调用依赖 | I/O | Rust 模块 | 状态 |
|-------------|--------|------|--------|-------------|----------|-----|-----------|------|
| _unnamed_block_data_.f | C | BLOCK DATA | | BASICS, ATOMIC | | | | ⬜ |
| accel2.f | ACCEL2 | SUBROUTINE | | BASICS, ITERAT, MODELQ | | 📁 | | ⬜ |
| accelp.f | ACCELP | SUBROUTINE | | BASICS, MODELQ, ITERAT, POPULS | | 📁 | | ⬜ |
| alifr1.f | ALIFR1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | ALIFR3 | | | ⬜ |
| alifr3.f | ALIFR3 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | | | alifr3.rs | ✅ |
| alifr6.f | ALIFR6 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | | | alifr6.rs | ✅ |
| alifrk.f | ALIFRK | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | | | alifrk.rs | ✅ |
| alisk1.f | ALISK1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT | ALIFRK, ROSSTD, OPACF1, RTEFR1 | 📁 | | ⬜ |
| alisk2.f | ALISK2 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT | ALIFRK, ROSSTD, OPACF1, RTEFR1 | 📁 | | ⬜ |
| alist1.f | ALIST1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ITERAT | OPACFD, ALIFR1, ROSSTD, RTEFR1 | 📁 | | ⬜ |
| alist2.f | ALIST2 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT | RTEFR1, ROSSTD, ALIFR1, QUIT, OPACFD | 📁 | | ⬜ |
| allard.f | ALLARD | SUBROUTINE | | BASICS, calphatd, callarda, callardc, callardg, callardb, quasun | ALLARDT | 📁 | | ⬜ |
| allardt.f | ALLARDT | SUBROUTINE | | BASICS, calphatd | | | allardt.rs | ✅ |
| angset.f | ANGSET | SUBROUTINE | ✓ | BASICS | GAULEG | | angset.rs | ✅ |
| betah.f | BETAH | FUNCTION | ✓ | | BETAH | | betah.rs | ✅ |
| bhe.f | BHE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR | | | bhe.rs | ✅ |
| bhed.f | BHED | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, CMATZD, SURFEX | | | bhe.rs | ✅ |
| bhez.f | BHEZ | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, SURFEX | | | bhe.rs | ✅ |
| bkhsgo.f | BKHSGO | SUBROUTINE | ✓ | | | | bkhsgo.rs | ✅ |
| bpop.f | BPOP | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, ODFPAR, ITERAT | MATINV, BPOPT, BPOPF, LEVSOL, RATMAT, BPOPC, BPOPE, LEVGRP | | | ⬜ |
| bpopc.f | BPOPC | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, ODFPAR, ADCHAR | STATE | | | ⬜ |
| bpope.f | BPOPE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ITERAT, ARRAY1 | SGMER1, DWNFR1 | | | ⬜ |
| bpopf.f | BPOPF | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, ODFPAR | | | bpopf.rs | ✅ |
| bpopt.f | BPOPT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, ODFPAR | COLIS | | | ⬜ |
| bre.f | BRE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR | COMPT0 | | | ⬜ |
| brez.f | BREZ | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR | COMPT0 | | | ⬜ |
| brte.f | BRTE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR, ARRAY1 | COMPT0 | | | ⬜ |
| brtez.f | BRTEZ | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR, ARRAY1 | COMPT0 | | | ⬜ |
| butler.f | BUTLER | SUBROUTINE | ✓ | | | | butler.rs | ✅ |
| carbon.f | CARBON | SUBROUTINE | ✓ | | | | carbon.rs | ✅ |
| ceh12.f | CEH12 | FUNCTION | ✓ | | CEH12 | | ceh12.rs | ✅ |
| change.f | CHANGE | SUBROUTINE | | BASICS, ATOMIC, MODELQ | STEQEQ, READBF | 📁 | | ⬜ |
| chckse.f | CHCKSE | SUBROUTINE | | BASICS, ATOMIC, MODELQ | SABOLF | 📁 | | ⬜ |
| chctab.f | CHCTAB | SUBROUTINE | | BASICS, MODELQ, abntab | | 📁 | | ⬜ |
| cheav.f | CHEAV | FUNCTION | | BASICS, ATOMIC | CHEAV, QUIT | 📁 | | ⬜ |
| cheavj.f | CHEAVJ | FUNCTION | | BASICS, ATOMIC | QUIT, CHEAVJ | 📁 | | ⬜ |
| cia_h2h.f | CIA_H2H | SUBROUTINE | | | LOCATE, IF | 📁 | | ⬜ |
| cia_h2h2.f | CIA_H2H2 | SUBROUTINE | | | LOCATE, IF | 📁 | | ⬜ |
| cia_h2he.f | CIA_H2HE | SUBROUTINE | | | LOCATE, IF | 📁 | | ⬜ |
| cia_hhe.f | CIA_HHE | SUBROUTINE | | | LOCATE, IF | 📁 | | ⬜ |
| cion.f | CION | FUNCTION | ✓ | | CION | | cion.rs | ✅ |
| ckoest.f | CKOEST | FUNCTION | ✓ | BASICS | CKOEST | | ckoest.rs | ✅ |
| colh.f | COLH | SUBROUTINE | | BASICS, ATOMIC, MODELQ | CSPEC, BUTLER, IRC | | | ⬜ |
| colhe.f | COLHE | SUBROUTINE | | BASICS, ATOMIC | COLLHE, CSPEC, IRC | | | ⬜ |
| colis.f | COLIS | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, CTRTEMP | CSPEC, COLH, COLHE, IRC | | | ⬜ |
| collhe.f | COLLHE | SUBROUTINE | ✓ | | | | collhe.rs | ✅ |
| column.f | COLUMN | SUBROUTINE | | BASICS, MODELQ, relcor | | 📁 | | ⬜ |
| compt0.f | COMPT0 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, auxcbc | | | compt0.rs | ✅ |
| comset.f | COMSET | SUBROUTINE | | BASICS, MODELQ, comgfs, auxcbc | | | comset.rs | ✅ |
| concor.f | CONCOR | SUBROUTINE | | BASICS, MODELQ | CONOUT | 📁 | | ⬜ |
| conout.f | CONOUT | SUBROUTINE | | BASICS, MODELQ, ALIPAR, CUBCON | MEANOP, MEANOPT, CONVEC, OPACF0 | 📁 | | ⬜ |
| conref.f | CONREF | SUBROUTINE | | BASICS, MODELQ, ARRAY1, imucnn, CUBCON | CONVC1, WNSTOR, STEQEQ, ELDENS, CONVEC, CONOUT | 📁 | | ⬜ |
| contmd.f | CONTMD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR, PRSAUX, CUBCON | MEANOP, WNSTOR, STEQEQ, OPACF0, CONVEC, CONOUT, CUBIC | 📁 | | ⬜ |
| contmp.f | CONTMP | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR, ichndm, CUBCON | MEANOP, WNSTOR, STEQEQ, ELDENS, OPACF0, CONVEC, MEANOPT, CONOUT, CUBIC | 📁 | | ⬜ |
| convc1.f | CONVC1 | SUBROUTINE | | BASICS, CUBCON | TRMDER, TRMDRT | | | ⬜ |
| convec.f | CONVEC | SUBROUTINE | | BASICS, CUBCON | TRMDER, TRMDRT | | | ⬜ |
| coolrt.f | COOLRT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT, COOLCO | OPACFA, RTEFR1 | 📁 | | ⬜ |
| corrwm.f | CORRWM | SUBROUTINE | | BASICS, ATOMIC, MODELQ | QUIT | 📁 | | ⬜ |
| cross.f | CROSS | FUNCTION | | BASICS, ATOMIC, MODELQ | CROSS | | cross.rs | ✅ |
| crossd.f | CROSSD | FUNCTION | | BASICS, ATOMIC, MODELQ | CROSSD | | cross.rs | ✅ |
| cspec.f | CSPEC | SUBROUTINE | | BASICS, ATOMIC | QUIT | | | ⬜ |
| ctdata.f | CTDATA | BLOCK DATA | | CTIon, CTRecomb | | | ctdata.rs | ✅ |
| cubic.f | CUBIC | SUBROUTINE | | BASICS, CUBCON | | | cubic.rs | ✅ |
| dielrc.f | DIELRC | SUBROUTINE | ✓ | | | | dielrc.rs | ✅ |
| dietot.f | DIETOT | SUBROUTINE | | BASICS, ATOMIC, MODELQ | DIELRC | 📁 | | ⬜ |
| divstr.f | DIVSTR | SUBROUTINE | | BASICS, MODELQ | | | divstr.rs | ✅ |
| dmder.f | DMDER | SUBROUTINE | | BASICS, ATOMIC, MODELQ, DEPTDR | | | dmder.rs | ✅ |
| dmeval.f | DMEVAL | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ARRAY1 | | 📁 | | ⬜ |
| dopgam.f | DOPGAM | SUBROUTINE | | BASICS, ATOMIC, MODELQ | GAMSP | | dopgam.rs | ✅ |
| dwnfr.f | DWNFR | SUBROUTINE | | BASICS, MODELQ | | | dwnfr.rs | ✅ |
| dwnfr0.f | DWNFR0 | SUBROUTINE | | BASICS, MODELQ | | | dwnfr0.rs | ✅ |
| dwnfr1.f | DWNFR1 | SUBROUTINE | | BASICS, MODELQ | | | dwnfr1.rs | ✅ |
| eint.f | EINT | SUBROUTINE | ✓ | | EXPINX | | expint.rs | ✅ |
| elcor.f | ELCOR | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ADCHAR | WNSTOR, STEQEQ, STATE, MOLEQ | 📁 | | ⬜ |
| eldenc.f | ELDENC | SUBROUTINE | | BASICS, MODELQ, ATOMIC, eletab, hmolab, eospar | RHONEN, STATE, MOLEQ | 📁 | | ⬜ |
| eldens.f | ELDENS | SUBROUTINE | | BASICS, MODELQ, ATOMIC, terden, eospar | ENTENE, STATE, MPARTF, LINEQS, MOLEQ | 📁 | | ⬜ |
| emat.f | EMAT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR | | | emat.rs | ✅ |
| entene.f | ENTENE | SUBROUTINE | | BASICS, ATOMIC, MODELQ | MPARTF | | | ⬜ |
| erfcin.f | ERFCIN | FUNCTION | ✓ | | ERFCIN | | erfcx.rs | ✅ |
| erfcx.f | ERFCX | FUNCTION | ✓ | | ERFCX | | erfcx.rs | ✅ |
| expint.f | EXPINT | FUNCTION | ✓ | | EXPINT | | expint.rs | ✅ |
| expinx.f | EXPINX | SUBROUTINE | ✓ | | | | expint.rs | ✅ |
| expo.f | EXPO | FUNCTION | ✓ | | EXPO | | expo.rs | ✅ |
| ffcros.f | FFCROS | FUNCTION | ✓ | | FFCROS | | ffcros.rs | ✅ |
| gami.f | GAMI | FUNCTION | ✓ | | GAMI | | gami.rs | ✅ |
| gamsp.f | GAMSP | SUBROUTINE | ✓ | BASICS | | | gamsp.rs | ✅ |
| gauleg.f | GAULEG | SUBROUTINE | ✓ | | | | gauleg.rs | ✅ |
| gaunt.f | GAUNT | FUNCTION | ✓ | | GAUNT | | gaunt.rs | ✅ |
| getlal.f | GETLAL | SUBROUTINE | | BASICS, callardc, callarda, calphatd, callardg, callardb, quasun | | 📁 | | ⬜ |
| getwrd.f | GETWRD | SUBROUTINE | ✓ | | | | getwrd.rs | ✅ |
| gfree0.f | GFREE0 | SUBROUTINE | | BASICS, MODELQ | | | gfree.rs | ✅ |
| gfree1.f | GFREE1 | FUNCTION | | BASICS, MODELQ | GFREE1 | | gfree.rs | ✅ |
| gfreed.f | GFREED | SUBROUTINE | | BASICS, MODELQ | | | gfree.rs | ✅ |
| ghydop.f | GHYDOP | SUBROUTINE | | BASICS, MODELQ, ATOMIC, intcfg | | | ghydop.rs | ✅ |
| gntk.f | GNTK | FUNCTION | ✓ | | GNTK | | gntk.rs | ✅ |
| gomini.f | GOMINI | SUBROUTINE | | BASICS, MODELQ, intcfg | | 📁 | | ⬜ |
| grcor.f | GRCOR | SUBROUTINE | ✓ | | | | grcor.rs | ✅ |
| greyd.f | GREYD | SUBROUTINE | | BASICS, MODELQ, ATOMIC, ALIPAR | WNSTOR, RHONEN, STEQEQ, OPACF0, MEANOP | 📁 | | ⬜ |
| gridp.f | GRIDP | SUBROUTINE | ✓ | BASICS | | | gridp.rs | ✅ |
| h2minus.f | H2MINUS | SUBROUTINE | | BASICS | LOCATE | 📁 | | ⬜ |
| hction.f | HCTION | FUNCTION | | CTRTEMP, CTIon | HCTION | | ctdata.rs | ✅ |
| hctrecom.f | HCTRECOM | FUNCTION | | CTRTEMP, CTRecomb | HCTRECOM | | ctdata.rs | ✅ |
| hedif.f | HEDIF | SUBROUTINE | | BASICS, MODELQ, ATOMIC, hediff | | 📁 | | ⬜ |
| hephot.f | HEPHOT | FUNCTION | ✓ | | HEPHOT | | hephot.rs | ✅ |
| hesol6.f | HESOL6 | SUBROUTINE | | BASICS, MODELQ, PRSAUX | MATINV | | | ⬜ |
| hesolv.f | HESOLV | SUBROUTINE | | BASICS, MODELQ, PRSAUX | MATINV, RHONEN, STEQEQ, WNSTOR | 📁 | | ⬜ |
| hidalg.f | HIDALG | FUNCTION | ✓ | | HIDALG | | hidalg.rs | ✅ |
| ijali2.f | IJALI2 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | QUIT | 📁 | | ⬜ |
| ijalis.f | IJALIS | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | 📁 | | ⬜ |
| incldy.f | INCLDY | SUBROUTINE | | BASICS, ATOMIC, MODELQ | LEVSOL, RATMAT, WNSTOR, QUIT, SABOLF | 📁 | | ⬜ |
| indexx.f | INDEXX | SUBROUTINE | ✓ | | | | indexx.rs | ✅ |
| inicom.f | INICOM | SUBROUTINE | | BASICS, ATOMIC, MODELQ, comgfs | | | inicom.rs | ✅ |
| inifrc.f | INIFRC | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ijflar | INDEXX | 📁 | | ⬜ |
| inifrs.f | INIFRS | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | INDEXX, QUIT | 📁 | | ⬜ |
| inifrt.f | INIFRT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ijflar | INDEXX | 📁 | | ⬜ |
| inilam.f | INILAM | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ALIPAR | OPACF1, RTEFR1, COLIS, OPAINI, WNSTOR, STEQEQ, SABOLF, ELCOR, RATES1 | | | ⬜ |
| initia.f | INITIA | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ODFPAR, ALIPAR, STRPAR, INUNIT, freqcl | RDATA, RDATAX, OPADD0, STATE, DOPGAM, ODFHYS, INTERP, LINSET, NSTPAR, QUIT, LINSPL, INIFRC, READBF | 📁 | | ⬜ |
| inkul.f | INKUL | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, COLKUR, LINED | | 📁 | | ⬜ |
| inpdis.f | INPDIS | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ODFPAR, ALIPAR, relcor | GRCOR | 📁 | | ⬜ |
| inpmod.f | INPMOD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, eospar | LEVSOL, RATMAT, WNSTOR, QUIT, SABOLF, MOLEQ, KURUCZ, INCLDY | 📁 | | ⬜ |
| interp.f | INTERP | SUBROUTINE | ✓ | BASICS | | | interp.rs | ✅ |
| inthyd.f | INTHYD | SUBROUTINE | | BASICS, MODELQ | DIVSTR | | inthyd.rs | ✅ |
| intlem.f | INTLEM | SUBROUTINE | | BASICS, MODELQ | INTHYD | | intlem.rs | ✅ |
| intxen.f | INTXEN | SUBROUTINE | | BASICS, MODELQ | | | intxen.rs | ✅ |
| irc.f | IRC | SUBROUTINE | ✓ | | EXPINX, SZIRC | | irc.rs | ✅ |
| iroset.f | IROSET | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, LINED | LEVCD, QUIT, INKUL | 📁 | | ⬜ |
| kurucz.f | KURUCZ | SUBROUTINE | | BASICS, ATOMIC, MODELQ, temlim | LEVSOL, RATMAT, WNSTOR, RHONEN, QUIT, SABOLF, MOLEQ | 📁 | | ⬜ |
| lagran.f | LAGRAN | SUBROUTINE | ✓ | | | | interpolate.rs | ✅ |
| laguer.f | LAGUER | SUBROUTINE | | | | 📁 | laguer.rs | ✅ |
| lemini.f | LEMINI | SUBROUTINE | | BASICS, MODELQ | | 📁 | | ⬜ |
| levcd.f | LEVCD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, COLKUR | INDEXX, QUIT | 📁 | | ⬜ |
| levgrp.f | LEVGRP | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | | | levgrp.rs | ✅ |
| levset.f | LEVSET | SUBROUTINE | | BASICS, ATOMIC, MODELQ | QUIT | | | ⬜ |
| levsol.f | LEVSOL | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | LINEQS | | levsol.rs | ✅ |
| lineqs.f | LINEQS | SUBROUTINE | ✓ | BASICS | | | lineqs.rs | ✅ |
| linpro.f | LINPRO | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, quasun | STARK0, DOPGAM, INTLEM, DIVSTR, INTXEN | | | ⬜ |
| linsel.f | LINSEL | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR | OPAINI, QUIT, OPACF1, RTEFR1 | 📁 | | ⬜ |
| linset.f | LINSET | SUBROUTINE | | BASICS, ATOMIC, MODELQ | IJALIS, STARK0, QUIT, DIVSTR | 📁 | | ⬜ |
| linspl.f | LINSPL | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | linspl.rs | ✅ |
| locate.f | LOCATE | SUBROUTINE | ✓ | | | | locate.rs | ✅ |
| ltegr.f | LTEGR | SUBROUTINE | | BASICS, ATOMIC, MODELQ | INTERP, WNSTOR, STEQEQ, QUIT, ROSSOP, CONOUT | 📁 | | ⬜ |
| ltegrd.f | LTEGRD | SUBROUTINE | | BASICS, MODELQ, FACTRS, CUBCON, TOTJHK, FLXAUX, PRSAUX | TEMPER, INTERP, ZMRHO, WNSTOR, STEQEQ, ELDENS, QUIT, CONOUT | 📁 | | ⬜ |
| lucy.f | LUCY | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ITERAT, ALIPAR, ARRAY1 | OPACFL, RTEFR1, COLIS, WNSTOR, STEQEQ, SABOLF, ELCOR, OPAINI | 📁 | | ⬜ |
| lymlin.f | LYMLIN | SUBROUTINE | | BASICS, ATOMIC, MODELQ | STARK0, DIVSTR | 📁 | | ⬜ |
| matcon.f | MATCON | SUBROUTINE | | BASICS, MODELQ, ARRAY1, CUBCON | CONVEC | | | ⬜ |
| matgen.f | MATGEN | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR | BHED, BRTE, BHEZ, BREZ, MATCON, BRTEZ, EMAT, BHE, SABOLF, BPOP, BRE | | | ⬜ |
| matinv.f | MATINV | SUBROUTINE | ✓ | BASICS | | | matinv.rs | ✅ |
| meanop.f | MEANOP | SUBROUTINE | | BASICS, MODELQ, ATOMIC | | | meanop.rs | ✅ |
| meanopt.f | MEANOPT | SUBROUTINE | | BASICS, MODELQ | OPCTAB | | | ⬜ |
| minv3.f | MINV3 | SUBROUTINE | ✓ | | | | minv3.rs | ✅ |
| moleq.f | MOLEQ | SUBROUTINE | | BASICS, MODELQ, ATOMIC, COMFH1, entrop, moldat, eospar, adchar, ioniz2, terden, hmolab | RUSSEL, MPARTF | 📁 | | ⬜ |
| mpartf.f | MPARTF | SUBROUTINE | | moldat | | 📁 | | ⬜ |
| newdm.f | NEWDM | SUBROUTINE | | BASICS, MODELQ, FACTRS, PRSAUX, FLXAUX | INTERP, TEMPER | 📁 | | ⬜ |
| newdmt.f | NEWDMT | SUBROUTINE | | BASICS, MODELQ, FACTRS, PRSAUX, FLXAUX | GRIDP, INTERP, TEMPER | 📁 | | ⬜ |
| newpop.f | NEWPOP | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | | 📁 | | ⬜ |
| nstout.f | NSTOUT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ODFPAR, ALIPAR | QUIT | 📁 | | ⬜ |
| nstpar.f | NSTPAR | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ODFPAR, ALIPAR, imucnn, temlim, adiaba, ifpzpa, derdif, ichndm, ipricr, deridt, hediff, FLXAUX, irwint, moldat, quasun, freqcl, icnrsp | QUIT, GETWRD | 📁 | | ⬜ |
| odf1.f | ODF1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | DWNFR, ODFHST, DIVSTR | 📁 | | ⬜ |
| odffr.f | ODFFR | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | QUIT | | | ⬜ |
| odfhst.f | ODFHST | SUBROUTINE | | BASICS, MODELQ, ODFPAR | | | odfhst.rs | ✅ |
| odfhyd.f | ODFHYD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | INDEXX, ODFHST, DIVSTR | | | ⬜ |
| odfhys.f | ODFHYS | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | IJALIS, STARK0, ODFFR | | | ⬜ |
| odfmer.f | ODFMER | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | ODFHYD | | | ⬜ |
| odfset.f | ODFSET | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, STFCR | IJALIS, QUIT | 📁 | | ⬜ |
| opacf0.f | OPACF0 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, hmolab | GFREE0, DWNFR1, DWNFR0, WNSTOR, LINPRO, SABOLF, SGMER1, OPADD, OPACT1 | | | ⬜ |
| opacf1.f | OPACF1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ipricr, hmolab | QUASIM, GHYDOP, DWNFR1, LYMLIN, SGMER1, OPADD, PRD, OPACT1 | 📁 | | ⬜ |
| opacfa.f | OPACFA | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, COOLCO | SGMER1, OPADD, PRD, DWNFR1 | | | ⬜ |
| opacfd.f | OPACFD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT, dsctva, hmolab, rhoder | OPACTD, QUASIM, DWNFR1, LYMLIN, OPCTAB, SGMER1, OPADD, PRD, GFREED | 📁 | | ⬜ |
| opacfl.f | OPACFL | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR | SGMER1, OPADD, DWNFR1 | | | ⬜ |
| opact1.f | OPACT1 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, hmolab | OPCTAB | | | ⬜ |
| opactd.f | OPACTD | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ARRAY1, ITERAT, dsctva, hmolab, rhoder | OPCTAB | | | ⬜ |
| opactr.f | OPACTR | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ATOMIC, dsctva, hmolab, grdpra | RATMAL, OPACF1, LEVSOL, WNSTOR, STEQEQ, ELDENS, SABOLF, OPAINI, PGSET | | | ⬜ |
| opadd.f | OPADD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, eospar | CIA_H2H, CIA_H2HE, CIA_HHE, H2MINUS, CIA_H2H2 | | | ⬜ |
| opadd0.f | OPADD0 | SUBROUTINE | | BASICS, ATOMIC, MODELQ | QUIT | | | ⬜ |
| opahst.f | OPAHST | SUBROUTINE | | BASICS, ODFPAR | STARK0 | 📁 | | ⬜ |
| opaini.f | OPAINI | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR | DWNFR0, REFLEV, WNSTOR, LINPRO, SABOLF, LEVGRP | | | ⬜ |
| opctab.f | OPCTAB | SUBROUTINE | | BASICS, MODELQ | RAYLEIGH | | | ⬜ |
| opdata.f | OPDATA | SUBROUTINE | | TOPB | | 📁 | | ⬜ |
| opfrac.f | OPFRAC | SUBROUTINE | | pfoptb | | 📁 | | ⬜ |
| osccor.f | OSCCOR | SUBROUTINE | | BASICS, MODELQ, ITERAT | | 📁 | | ⬜ |
| outpri.f | OUTPRI | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, grdpra | RATMAL, OPACF1, LEVSOL, WNSTOR, SABOLF | 📁 | | ⬜ |
| output.f | OUTPUT | SUBROUTINE | | BASICS, MODELQ | | 📁 | | ⬜ |
| partf.f | PARTF | SUBROUTINE | | BASICS, irwint, PFSTDS | PFFE, PFNI, OPFRAC, MPARTF, PFHEAV, PFSPEC, PFCNO | | | ⬜ |
| pfcno.f | PFCNO | SUBROUTINE | ✓ | BASICS | | | pfcno.rs | ✅ |
| pffe.f | PFFE | SUBROUTINE | ✓ | | | | pffe.rs | ✅ |
| pfheav.f | PFHEAV | SUBROUTINE | | | | 📁 | | ⬜ |
| pfni.f | PFNI | SUBROUTINE | ✓ | | | | pfni.rs | ✅ |
| pfspec.f | PFSPEC | SUBROUTINE | ✓ | | | | pfspec.rs | ✅ |
| pgset.f | PGSET | SUBROUTINE | | BASICS, ITERAT, MODELQ, rybpgs, grdpra | TRIDAG | 📁 | | ⬜ |
| prchan.f | PRCHAN | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | | 📁 | | ⬜ |
| prd.f | PRD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | DOPGAM | | | ⬜ |
| prdini.f | PRDINI | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | prdini.rs | ✅ |
| princ.f | PRINC | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | LINPRO, DWNFR, OPACF1, SABOLF | 📁 | | ⬜ |
| prnt.f | PRNT | SUBROUTINE | | BASICS, ATOMIC, MODELQ | SABOLF | 📁 | | ⬜ |
| profil.f | PROFIL | FUNCTION | | BASICS, ATOMIC, MODELQ, quasun | PROFIL, STARK0, DIVSTR | | profil.rs | ✅ |
| profsp.f | PROFSP | FUNCTION | | BASICS, ATOMIC, MODELQ | PROFSP, SABOLF | | | ⬜ |
| prsent.f | PRSENT | SUBROUTINE | | tdflag, tdedge, THERM, TABLTD | | 📁 | | ⬜ |
| psolve.f | PSOLVE | SUBROUTINE | | BASICS, MODELQ | | | psolve.rs | ✅ |
| pzert.f | PZERT | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | pzert.rs | ✅ |
| pzeval.f | PZEVAL | SUBROUTINE | | BASICS, MODELQ, ALIPAR, icnrsp | CONOUT | 📁 | | ⬜ |
| pzevld.f | PZEVLD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR, ARRAY1, ifpzpa, PRSAUX, grdpra, DEPTDR | | | pzevld.rs | ✅ |
| quartc.f | QUARTC | SUBROUTINE | | | | 📁 | quartc.rs | ✅ |
| quasim.f | QUASIM | SUBROUTINE | | BASICS, ATOMIC, MODELQ, quasun | ALLARD | | | ⬜ |
| quit.f | QUIT | SUBROUTINE | | | | 📁 | quit.rs | ✅ |
| radpre.f | RADPRE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR | QUIT, INDEXX, OPACF1, RTEFR1 | 📁 | | ⬜ |
| radtot.f | RADTOT | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ITERAT, OPTDPT, TOTJHK, SURFEX | OPAINI, OPACF1, RTEFR1 | | | ⬜ |
| raph.f | RAPH | FUNCTION | ✓ | | RAPH | | raph.rs | ✅ |
| rates1.f | RATES1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ITERAT | ROSSTD, OPACF1, RTEFR1 | | | ⬜ |
| ratmal.f | RATMAL | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | ratmal.rs | ✅ |
| ratmat.f | RATMAT | SUBROUTINE | | BASICS, ATOMIC, MODELQ | REFLEV | | | ⬜ |
| ratsp1.f | RATSP1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR, ARRAY1, ITERAT | ROSSTD, OPACF1, RTEFR1 | 📁 | | ⬜ |
| rayini.f | RAYINI | SUBROUTINE | | BASICS, MODELQ, ATOMIC | RAYLEIGH | 📁 | | ⬜ |
| rayleigh.f | RAYLEIGH | SUBROUTINE | | BASICS, ATOMIC, MODELQ, RAYSCT, eospar | | | rayleigh.rs | ✅ |
| rayset.f | RAYSET | SUBROUTINE | | BASICS, MODELQ | | | rayset.rs | ✅ |
| rdata.f | RDATA | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ODFPAR, ALIPAR, STRPAR, INUNIT, imodlc | RDATAX, LINSET, QUIT, DOPGAM | 📁 | | ⬜ |
| rdatax.f | RDATAX | SUBROUTINE | | BASICS, ATOMIC, MODELQ | BKHSGO | 📁 | | ⬜ |
| readbf.f | READBF | SUBROUTINE | | BASICS | | 📁 | | ⬜ |
| rechck.f | RECHCK | SUBROUTINE | | BASICS, ATOMIC, MODELQ | OPACF1, RTEFR1 | 📁 | | ⬜ |
| reflev.f | REFLEV | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | | | | ⬜ |
| reiman.f | REIMAN | FUNCTION | ✓ | | REIMAN | | reiman.rs | ✅ |
| resolv.f | RESOLV | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ALIPAR, ARRAY1, icnrsp | NEWPOP, TAUFR1, TIMING, OPACF1, RTEFR1, ROSSTD, STEQEQ, CONOUT, ELCOR, OPAINI, RATES1, PRD | 📁 | | ⬜ |
| rhoeos.f | RHOEOS | FUNCTION | | BASICS, MODELQ | PRSENT, RHOEOS | | | ⬜ |
| rhonen.f | RHONEN | SUBROUTINE | | BASICS, MODELQ | ELDENS | | | ⬜ |
| rhsgen.f | RHSGEN | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ARRAY1, ALIPAR, CUBCON | MATINV, STATE, RATMAT, COMPT0, SABOLF, CONVEC, LEVGRP | | | ⬜ |
| rossop.f | ROSSOP | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ALIPAR | WNSTOR, STEQEQ, ELDENS, OPACF0, MEANOP, MEANOPT | | | ⬜ |
| rosstd.f | ROSSTD | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, ALIPAR | | 📁 | | ⬜ |
| rte_sc.f | RTE_SC | SUBROUTINE | ✓ | BASICS | | | rte_sc.rs | ✅ |
| rteang.f | RTEANG | SUBROUTINE | | BASICS, MODELQ, ALIPAR, EXTINT, SURFEX | GAULEG | | | ⬜ |
| rtecf0.f | RTECF0 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT, auxcbc, AUXRTE | | | | ⬜ |
| rtecf1.f | RTECF1 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT, comgfs, AUXRTE, EXTINT, SURFEX | RTEFE2, RTESOL, RTECF0 | 📁 | | ⬜ |
| rtecmc.f | RTECMC | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, comgfs, AUXRTE | MATINV, OPACF1, RTECF0 | | | ⬜ |
| rtecmu.f | RTECMU | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT, AUXRTE | RTESOL, OPACF1, RTECF0, GAULEG | 📁 | | ⬜ |
| rtecom.f | RTECOM | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT, comgfs, AUXRTE | OPACF1, RTECF0, RTECF1 | | | ⬜ |
| rtedf1.f | RTEDF1 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, OPTDPT | | | rtedf1.rs | ✅ |
| rtedf2.f | RTEDF2 | SUBROUTINE | | BASICS, MODELQ, ALIPAR | | | | ⬜ |
| rtefe2.f | RTEFE2 | SUBROUTINE | ✓ | BASICS | | | rtefe2.rs | ✅ |
| rtefr1.f | RTEFR1 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT | MATINV, RTESOL, RTEDF1, RTECF1, RTEDF2, MINV3 | 📁 | | ⬜ |
| rteint.f | RTEINT | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT | MATINV, OPACF1 | 📁 | | ⬜ |
| rtesol.f | RTESOL | SUBROUTINE | ✓ | BASICS | | | rtesol.rs | ✅ |
| russel.f | RUSSEL | SUBROUTINE | | BASICS, MODELQ, COMFH1 | MPARTF | 📁 | | ⬜ |
| rybchn.f | RYBCHN | SUBROUTINE | | BASICS, ITERAT, MODELQ, ALIPAR, ARRAY1, rybpgs, grdpra | PGSET, ELDENS | 📁 | | ⬜ |
| rybene.f | RYBENE | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ARRAY1, RYBMTX, deridt, CUBCON | CONVEC | | | ⬜ |
| rybheq.f | RYBHEQ | SUBROUTINE | | BASICS, MODELQ, rybpgs, grdpra | OPACF1, RTEFR1, WNSTOR, STEQEQ, ELDENS, ELCOR, OPAINI, PGSET | 📁 | | ⬜ |
| rybmat.f | RYBMAT | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ARRAY1, dsctva, RYBMTX | | | | ⬜ |
| rybsol.f | RYBSOL | SUBROUTINE | | BASICS, MODELQ, ATOMIC, ALIPAR, ARRAY1, ITERAT, imodlc, RYBMTX | RYBMAT, RTEFR1, ROSSTD, OPACTR, LINEQS, STEQEQ, ALIFR1, TRIDAG, RYBCHN, OPACFD | 📁 | | ⬜ |
| sabolf.f | SABOLF | SUBROUTINE | | BASICS, ATOMIC, MODELQ | PARTF | | | ⬜ |
| sbfch.f | SBFCH | FUNCTION | ✓ | | SBFCH | | sbfch.rs | ✅ |
| sbfhe1.f | SBFHE1 | FUNCTION | | BASICS, ATOMIC | SBFHE1, QUIT | 📁 | sbfhe1.rs | ✅ |
| sbfhmi.f | SBFHMI | FUNCTION | ✓ | | SBFHMI | | sbfhmi.rs | ✅ |
| sbfhmi_old.f | SBFHMI_OLD | FUNCTION | ✓ | | SBFHMI_OLD | | sbfhmi_old.rs | ✅ |
| sbfoh.f | SBFOH | FUNCTION | ✓ | | SBFOH | | sbfoh.rs | ✅ |
| setdrt.f | SETDRT | SUBROUTINE | | BASICS, MODELQ, RHODER | | | | ⬜ |
| settrm.f | SETTRM | SUBROUTINE | | tdflag, tdedge, THERM, TABLTD | PRSENT | 📁 | | ⬜ |
| sffhmi.f | SFFHMI | FUNCTION | ✓ | | SFFHMI | | sffhmi.rs | ✅ |
| sffhmi_add.f | SFFHMI_ADD | FUNCTION | ✓ | | SFFHMI_ADD | | sffhmi_add.rs | ✅ |
| sghe12.f | SGHE12 | FUNCTION | ✓ | | SGHE12 | | sghe12.rs | ✅ |
| sgmer0.f | SGMER0 | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | sgmer.rs | ✅ |
| sgmer1.f | SGMER1 | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | sgmer.rs | ✅ |
| sgmerd.f | SGMERD | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | sgmer.rs | ✅ |
| sigave.f | SIGAVE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | | 📁 | | ⬜ |
| sigk.f | SIGK | FUNCTION | | BASICS, ATOMIC | SPSIGK, SIGK | | | ⬜ |
| sigmar.f | SIGMAR | FUNCTION | | BASICS | SIGMAR, LAGUER | 📁 | | ⬜ |
| solve.f | SOLVE | SUBROUTINE | | BASICS, ITERAT, MODELQ, ARRAY1, ALIPAR, CMATZD | MATINV, PRCHAN, RHSGEN, WNSTOR, MATGEN | 📁 | | ⬜ |
| solves.f | SOLVES | SUBROUTINE | | BASICS, ITERAT, MODELQ, ARRAY1, ALIPAR, STOMAT, CMATZD | MATINV, PRCHAN, RHSGEN, WNSTOR, MATGEN | 📁 | | ⬜ |
| spsigk.f | SPSIGK | SUBROUTINE | ✓ | | CARBON | | spsigk.rs | ✅ |
| srtfrq.f | SRTFRQ | SUBROUTINE | | BASICS, ATOMIC, MODELQ | INDEXX, QUIT | 📁 | | ⬜ |
| stark0.f | STARK0 | SUBROUTINE | ✓ | | | | stark0.rs | ✅ |
| starka.f | STARKA | FUNCTION | | BASICS, MODELQ | STARKA | | starka.rs | ✅ |
| start.f | START | SUBROUTINE | | BASICS, hediff | | 📁 | | ⬜ |
| state.f | STATE | SUBROUTINE | | BASICS, ATOMIC, MODELQ, terden, PFSTDS | OPFRAC, PARTF | 📁 | | ⬜ |
| steqeq.f | STEQEQ | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT, POPSTR, PPAPAR | LEVSOL, RATMAT, SABOLF, MOLEQ | | | ⬜ |
| switch.f | SWITCH | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | 📁 | | ⬜ |
| szirc.f | SZIRC | SUBROUTINE | ✓ | | EINT | | szirc.rs | ✅ |
| tabini.f | TABINI | SUBROUTINE | | BASICS, MODELQ, ATOMIC, eletab, abntab, intcff | | 📁 | | ⬜ |
| tabint.f | TABINT | SUBROUTINE | | BASICS, MODELQ, ATOMIC, intcff | | | | ⬜ |
| taufr1.f | TAUFR1 | SUBROUTINE | | BASICS, MODELQ, ALIPAR, ITERAT, OPTDPT | | | | ⬜ |
| tdpini.f | TDPINI | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR, ALIPAR | GFREE0 | | tdpini.rs | ✅ |
| temcor.f | TEMCOR | SUBROUTINE | | BASICS, MODELQ, ARRAY1, ALIPAR, CUBCON | MEANOP, WNSTOR, STEQEQ, ELDENS, OPACF0, CONVEC | 📁 | | ⬜ |
| temper.f | TEMPER | SUBROUTINE | | BASICS, MODELQ, ALIPAR, FACTRS, PRSAUX, FLXAUX | WNSTOR, TLOCAL, STEQEQ, ELDENS, OPACF0, MEANOP, MEANOPT | 📁 | | ⬜ |
| timing.f | TIMING | SUBROUTINE | | | | 📁 | | ⬜ |
| tiopf.f | TIOPF | SUBROUTINE | ✓ | | | | tiopf.rs | ✅ |
| tlocal.f | TLOCAL | SUBROUTINE | | BASICS, MODELQ, FACTRS, FLXAUX | QUARTC | | | ⬜ |
| tlusty.f | TLUSTY | UNKNOWN | | BASICS, ITERAT, ALIPAR | TIMING | 📁 | | ⬜ |
| topbas.f | TOPBAS | FUNCTION | | TOPB | TOPBAS | 📁 | | ⬜ |
| traini.f | TRAINI | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ODFPAR | | | traini.rs | ✅ |
| tridag.f | TRIDAG | SUBROUTINE | ✓ | | | | tridag.rs | ✅ |
| trmder.f | TRMDER | SUBROUTINE | | BASICS, derdif, terden, adiaba | ELDENS | | | ⬜ |
| trmdrt.f | TRMDRT | SUBROUTINE | | BASICS, tdedge, CC, tdflag, CONVOUT | PRSENT | | | ⬜ |
| ubeta.f | UBETA | FUNCTION | ✓ | | UBETA, LAGRAN | | ubeta.rs | ✅ |
| vern16.f | VERN16 | FUNCTION | ✓ | BASICS | VERN16 | | vern16.rs | ✅ |
| vern18.f | VERN18 | FUNCTION | ✓ | BASICS | VERN18 | | vern18.rs | ✅ |
| vern20.f | VERN20 | FUNCTION | ✓ | BASICS | VERN20 | | vern20.rs | ✅ |
| vern26.f | VERN26 | FUNCTION | ✓ | BASICS | VERN26 | | vern26.rs | ✅ |
| verner.f | VERNER | FUNCTION | | BASICS, ATOMIC | QUIT, VERNER | | verner.rs | ✅ |
| visini.f | VISINI | SUBROUTINE | | BASICS, ATOMIC, MODELQ, ITERAT | | 📁 | | ⬜ |
| voigt.f | VOIGT | FUNCTION | ✓ | | VOIGT | | voigt.rs | ✅ |
| voigte.f | VOIGTE | FUNCTION | ✓ | | VOIGTE | | voigte.rs | ✅ |
| wn.f | WN | FUNCTION | ✓ | BASICS | WN | | wn.rs | ✅ |
| wnstor.f | WNSTOR | SUBROUTINE | | BASICS, ATOMIC, MODELQ | | | wnstor.rs | ✅ |
| xenini.f | XENINI | SUBROUTINE | | BASICS, MODELQ | | 📁 | | ⬜ |
| xk2dop.f | XK2DOP | FUNCTION | ✓ | | XK2DOP | | xk2dop.rs | ✅ |
| yint.f | YINT | FUNCTION | ✓ | | YINT | | interpolate.rs | ✅ |
| ylintp.f | YLINTP | FUNCTION | ✓ | | YLINTP | | ylintp.rs | ✅ |
| zmrho.f | ZMRHO | SUBROUTINE | | BASICS, MODELQ | | | zmrho.rs | ✅ |

View File

@ -1,110 +0,0 @@
# TLUSTY/SYNSPEC Rust 重构项目记忆
注意用中文回复
重要!!!:不要进行全量测试 `cargo test`,系统会卡死,需要时一个个来测
## 分离子模块(已经完成)
```bash
cd /home/fmq/program/tlusty/tl208-s54/rust
python3 extract_fortran.py tlusty/tlusty208.f tlusty/extracted/
cp tlusty/*.FOR tlusty/extracted/
```
分离后的子文件在tlusty/extracted/下
## common模块
common模块×.FOR已经重构到src/state目录下
## 重构追踪系统
```bash
# 更新追踪表 (必须按顺序执行)
python3 scripts/analyze_fortran.py > MEMORY/fortran_analysis.csv
python3 scripts/generate_tracking.py > MEMORY/FORTRAN_TRACKING.md
# 依赖树分析命令
python3 scripts/analyze_fortran.py --priority # 按未实现依赖排序的重构优先级只显示pending
python3 scripts/analyze_fortran.py --tree UNIT # 输出依赖树(含未实现依赖数)
python3 scripts/analyze_fortran.py --full # 输出完整传递依赖
```
| 指标 | 数量 |
|------|------|
| 总单元 | 305 |
| 已完成 | 107 |
| 待处理 | 198 |
| 完成率 | 35.1% |
## 重构流程
DATA 语句硬编码的数据表已经由scripts/extract_fortran_data.py生成到src/data.rs中
详细规范见 [MEMORY/REFACTORING_GUIDE.md](MEMORY/REFACTORING_GUIDE.md)
**步骤:**
1. `python3 scripts/analyze_fortran.py --priority` - 找未实现依赖少的函数
2. 分析tlusty/extracted/文件夹下对应的 Fortran 源码 (INCLUDE/COMMON/调用/I/O)
3. 创建 `src/math/TARGET.rs`
4. 实现函数 + 测试
5. 添加到 `mod.rs`
6. `cargo test target` (单个测试!)
7. 更新追踪表
**SPECIAL_MAPPINGS** (`scripts/analyze_fortran.py` 第 72 行):
```python
SPECIAL_MAPPINGS = {
'gfree': ['gfree0', 'gfreed', 'gfree1'],
'interpolate': ['yint', 'lagran'],
'sgmer': ['sgmer0', 'sgmer1', 'sgmerd'],
'ctdata': ['hction', 'hctrecom'],
'cross': ['cross', 'crossd'],
'expint': ['eint', 'expinx'],
'erfcx': ['erfcx', 'erfcin'],
'lineqs': ['lineqs', 'lineqs_nr'],
# 新增映射...
}
```
## 当前状态 (2026-03-20)
- **已完成**: 107 个函数 + 15 个状态模块
- **测试通过**: 421+ 个
- **最新完成**: alifrk.rs (Kantorovich 迭代简化版)
**查看实时进度**: `cat FORTRAN_TRACKING.md | head -20`
## 项目结构
```
rust/src/
├── math/ # 函数 (85+ 个 .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 # 静态数据
```
## 关键陷阱
| 问题 | 解决方案 |
|------|----------|
| Fortran 1-indexed | `arr(i)``arr[i-1]` |
| `-LOG(X)` | 是 `-ln(X)` 不是 `ln(-X)` |
| powi 类型歧义 | 用显式乘法 `(a)*(a)` |
| 循环变量变负 | 用 `isize` 不用 `usize` |
| 多项式近似精度 | 放宽到 1e-7 |
| 矩阵列优先 | `A(j,i)``a[(i-1)*N + (j-1)]` |
| COMMON 块冲突 | 添加前 grep 检查是否已存在 |
| 循环变量重赋值 | 声明为 `mut` |
## 详细文档
- [MEMORY/REFACTORING_GUIDE.md](MEMORY/REFACTORING_GUIDE.md) - 重构规范 ⭐
- [MEMORY/FORTRAN_TRACKING.md](MEMORY/FORTRAN_TRACKING.md) - 函数追踪表
- [MEMORY/refactoring_notes.md](MEMORY/refactoring_notes.md) - 重构过程中遇到的问题及解决方法

View File

@ -1,374 +0,0 @@
# TLUSTY Rust 重构规范
## 1. 选定下一个重构目标
优先处理依赖少无io的函数
注意DATA 语句硬编码的数据表已经由scripts/extract_fortran_data.py生成到src/data.rs中
不要管复杂不复杂和有无common依赖
按python3 scripts/analyze_fortran.py --priority | head -10 的顺序来
分离出来的原始fortran函数在/home/fmq/program/tlusty/tl208-s54/rust/tlusty/extracted文件夹下
### 优先级排序
**核心原则**: 优先处理"传递未实现依赖=0"的函数,它们不依赖其他未完成的函数。
按以下顺序选择待重构函数:
1. **无未实现依赖** (传递未实现=0)
- 可立即开始,无需等待其他函数
- 包括纯函数和只有 COMMON 依赖的函数
2. **少量未实现依赖** (传递未实现=1~3)
- 需要先完成少数依赖函数
- 用 `--tree` 查看具体依赖链
3. **多未实现依赖** (传递未实现>3)
- 依赖链较长,最后处理
- 或考虑整体重构策略
4. **有 I/O 依赖的函数**
- 最后处理,可能需要设计新的 I/O 抽象层
### 查询命令
CSV 列结构: `fortran_file,unit_name,unit_type,is_pure,common_deps,call_deps,has_io,rust_module,status`
#### 依赖树分析
```bash
# 输出重构优先级列表(按未实现依赖排序,推荐!)
python3 scripts/analyze_fortran.py --priority
# 输出指定单元的依赖树
python3 scripts/analyze_fortran.py --tree UNIT_NAME
# 输出完整传递依赖的 CSV
python3 scripts/analyze_fortran.py --full > fortran_analysis_full.csv
```
**优先级列表说明:**
```
重构优先级列表 (按未实现依赖排序)
====================================================================================================
单元名 未实现 传递未实现 深度 直接调用 传递调用 IO
----------------------------------------------------------------------------------------------------
C 0 0 0 0 0 ○
ALIFR3 0 0 0 0 0 ○
```
- **未实现**: 直接依赖中未完成的函数数
- **传递未实现**: 所有递归依赖中未完成的函数数(关键指标!)
- **排序**: 传递未实现少 → 深度低 → 依赖少
- 只显示未完成pending的函数
- IO 列: ○ = 无IO, ✓ = 有IO
**依赖树输出示例:**
```
依赖树: ALISK1 ○
============================================================
直接依赖: 4, 传递依赖: 27, 未实现: 20
未实现依赖: ALIFRK, OPACF1, OPADD, ROSSTD, ...
------------------------------------------------------------
○ ALISK1 (4未实现)
├── ○ OPACF1 (6未实现)
│ ├── ○ OPADD (5未实现)
│ │ ├── ○ cia_h2h2 (1未实现)
│ │ │ └── if [未找到/未实现]
│ │ └── ✓ locate
│ └── ...
└── ○ ALIFRK
```
- ✓ = 已完成, ○ = 待处理
- `(N未实现)` = 该节点有 N 个直接依赖未完成
- 顶部汇总:传递未实现依赖数及列表
- 子节点按未实现依赖数排序(多的在前)
#### 按纯度筛选
无io的纯函数已经全部实现重构
#### 按 I/O 筛选
```bash
# 有 I/O 的未完成函数 (最后处理)
awk -F, '$7=="True" && $9=="pending"' fortran_analysis.csv
# 无 I/O 的未完成函数 (优先处理)
awk -F, '$7=="False" && $9=="pending"' fortran_analysis.csv
# 无 I/O 且无调用依赖的未完成函数
awk -F, '$6=="" && $7=="False" && $9=="pending"' fortran_analysis.csv
```
#### 按 COMMON 依赖筛选
```bash
# 只依赖 BASICS 的未完成函数
awk -F, '$5=="BASICS" && $9=="pending"' fortran_analysis.csv
# 依赖 BASICS 和 ATOMIC但无其他依赖
awk -F, '$5 ~ /^BASICS\|ATOMIC$/ && $9=="pending"' fortran_analysis.csv
# 不依赖 MODELQ 的未完成函数 (MODELQ 最复杂)
awk -F, '$5 !~ /MODELQ/ && $9=="pending"' fortran_analysis.csv
# 列出所有不同的 COMMON 依赖组合
awk -F, '{print $5}' fortran_analysis.csv | sort | uniq -c | sort -rn
```
#### 按状态筛选
```bash
# 所有已完成函数
awk -F, '$9=="done"' fortran_analysis.csv
# 所有进行中函数
awk -F, '$9=="in_progress"' fortran_analysis.csv
# 统计各状态数量
awk -F, '{print $9}' fortran_analysis.csv | sort | uniq -c
```
#### 组合筛选
```bash
# 最佳候选:无 I/O + 无调用依赖 + 纯函数或简单 COMMON
awk -F, '$6=="" && $7=="False" && $9=="pending"' fortran_analysis.csv
# 次优候选:无 I/O + 有调用依赖但依赖已完成
awk -F, '$6!="" && $7=="False" && $9=="pending"' fortran_analysis.csv
# 查看特定函数的依赖信息
awk -F, '$2=="TARGET"' fortran_analysis.csv
```
#### 按代码大小排序
```bash
# 按行数排序(选小的先做)
cd tlusty/extracted
wc -l *.f | sort -n | head -30
# 查看小文件 + 纯函数
for f in $(ls *.f); do
lines=$(wc -l < "$f")
name=$(basename "$f" .f)
if grep -q "True.*pending" ../../fortran_analysis.csv && [ $lines -lt 100 ]; then
echo "$lines $name"
fi
done | sort -n
```
#### 快速查看
```bash
# 查看重构进度摘要
echo "已完成: $(awk -F, '$9=="done"' fortran_analysis.csv | wc -l)"
echo "待处理: $(awk -F, '$9=="pending"' fortran_analysis.csv | wc -l)"
echo "纯函数待处理: $(awk -F, '$4=="True" && $9=="pending"' fortran_analysis.csv | wc -l)"
echo "无IO待处理: $(awk -F, '$7=="False" && $9=="pending"' fortran_analysis.csv | wc -l)"
```
## 2. 重构流程
### Step 1: 分析 Fortran 源码
```bash
# 查看源码
cat tlusty/extracted/TARGET.f
```
检查:
- [ ] INCLUDE 文件列表
- [ ] COMMON 块
- [ ] 调用的其他函数
- [ ] 是否有 I/O
### Step 2: 创建 Rust 模块
```bash
# 创建文件
touch src/math/TARGET.rs
```
### Step 3: 实现函数
遵循命名规范:
- Fortran `FUNCTION` → Rust `pub fn`
- Fortran `SUBROUTINE` → Rust `pub fn` (返回值用参数或元组)
- COMMON 块 → 结构体参数
### Step 4: 添加到 mod.rs
```rust
// src/math/mod.rs
mod target;
pub use target::target;
```
### Step 5: 编写测试
```rust
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_target_basic() {
// 基本测试
}
}
```
### Step 6: 运行测试
```bash
# 单个模块测试 (不要 cargo test 全量!)
cargo test target
```
### Step 7: 更新追踪表
```bash
# 如果是一对一映射,脚本自动识别
python3 scripts/analyze_fortran.py > fortran_analysis.csv
python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md
# 如果是一对多映射,先更新 SPECIAL_MAPPINGS
```
## 3. SPECIAL_MAPPINGS 维护
### 何时需要更新
当一个 Rust 文件实现多个 Fortran 函数时,需要添加映射。
### 位置
`scripts/analyze_fortran.py` 第 72 行
### 格式
```python
SPECIAL_MAPPINGS = {
# Rust 文件名 -> [Fortran 函数名列表]
'gfree': ['gfree0', 'gfreed', 'gfree1'],
'interpolate': ['yint', 'lagran'],
'sgmer': ['sgmer0', 'sgmer1', 'sgmerd'],
'ctdata': ['hction', 'hctrecom'],
'cross': ['cross', 'crossd'],
'expint': ['eint', 'expinx'],
'erfcx': ['erfcx', 'erfcin'],
# 新增映射...
}
```
### 添加新映射后执行
```bash
python3 scripts/analyze_fortran.py > fortran_analysis.csv
python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md
```
## 4. 状态更新流程
### 手动更新状态
如需手动标记状态,编辑 `fortran_analysis.csv`
```csv
# status 列: done, pending, in_progress, skip
filename.f,UNIT,SUBROUTINE,False,"...",...,False,src/math/xxx.rs,done
```
然后重新生成 Markdown
```bash
python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md
```
## 5. 代码规范
### 文件头注释
```rust
//! 模块简要说明。
//!
//! 重构自 TLUSTY `filename.f`
```
### 函数注释
```rust
/// 函数功能说明。
///
/// # 参数
///
/// * `x` - 参数说明
///
/// # 返回值
///
/// 返回值说明
///
/// # 示例
///
/// ```
/// use tlusty_rust::math::func;
/// assert!((func(1.0) - 2.0).abs() < 1e-10);
/// ```
pub fn func(x: f64) -> f64 { ... }
```
### 精度要求
| 函数类型 | 容差 |
|---------|------|
| 简单数学运算 | 1e-10 |
| 多项式近似 | 1e-7 |
| f32 数组 | 1e-24 |
### 常见陷阱
| 问题 | 解决方案 |
|------|----------|
| Fortran 1-indexed | `arr(i)``arr[i-1]` |
| `-LOG(X)` | 是 `-ln(X)` 不是 `ln(-X)` |
| powi 类型歧义 | 用显式乘法 `(a)*(a)` |
| 矩阵列优先 | `A(j,i)``a[(i-1)*N + (j-1)]` |
## 6. 快速命令参考
```bash
# 查看重构进度
cat FORTRAN_TRACKING.md | head -20
# 进度统计
echo "已完成: $(awk -F, '$9=="done"' fortran_analysis.csv | wc -l)"
echo "待处理: $(awk -F, '$9=="pending"' fortran_analysis.csv | wc -l)"
# 推荐方式:查看优先级列表(按未实现依赖排序)
python3 scripts/analyze_fortran.py --priority | head -30
# 查看函数依赖树(含未实现依赖数)
python3 scripts/analyze_fortran.py --tree FUNCTION_NAME
# 找最佳候选无IO + 无调用依赖
awk -F, '$6=="" && $7=="False" && $9=="pending"' fortran_analysis.csv | head -5
# 找纯函数
grep "True.*pending" fortran_analysis.csv | head -5
# 找无IO的函数
awk -F, '$7=="False" && $9=="pending"' fortran_analysis.csv | head -5
# 测试单个模块
cargo test module_name
# 更新追踪表
python3 scripts/analyze_fortran.py > fortran_analysis.csv && \
python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md
# 编译检查
cargo build 2>&1 | grep error
```

View File

@ -1,305 +0,0 @@
fortran_file,unit_name,unit_type,is_pure,common_deps,call_deps,has_io,rust_module,status
_unnamed_block_data_.f,C,BLOCK DATA,False,"BASICS|ATOMIC","",False,,pending
accel2.f,ACCEL2,SUBROUTINE,False,"BASICS|ITERAT|MODELQ","",True,,pending
accelp.f,ACCELP,SUBROUTINE,False,"BASICS|MODELQ|ITERAT|POPULS","",True,,pending
alifr1.f,ALIFR1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","ALIFR3",False,,pending
alifr3.f,ALIFR3,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifr3.rs,done
alifr6.f,ALIFR6,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifr6.rs,done
alifrk.f,ALIFRK,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifrk.rs,done
alisk1.f,ALISK1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","RTEFR1|ALIFRK|ROSSTD|OPACF1",True,,pending
alisk2.f,ALISK2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","RTEFR1|ALIFRK|ROSSTD|OPACF1",True,,pending
alist1.f,ALIST1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT","RTEFR1|ALIFR1|OPACFD|ROSSTD",True,,pending
alist2.f,ALIST2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","QUIT|OPACFD|RTEFR1|ALIFR1|ROSSTD",True,,pending
allard.f,ALLARD,SUBROUTINE,False,"BASICS|callardb|callardc|callarda|quasun|callardg|calphatd","ALLARDT",True,,pending
allardt.f,ALLARDT,SUBROUTINE,False,"BASICS|calphatd","",False,src/math/allardt.rs,done
angset.f,ANGSET,SUBROUTINE,True,"BASICS","GAULEG",False,src/math/angset.rs,done
betah.f,BETAH,FUNCTION,True,"","",False,src/math/betah.rs,done
bhe.f,BHE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","",False,src/math/bhe.rs,done
bhed.f,BHED,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CMATZD|SURFEX","",False,src/math/bhe.rs,done
bhez.f,BHEZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|SURFEX","",False,src/math/bhe.rs,done
bkhsgo.f,BKHSGO,SUBROUTINE,True,"","",False,src/math/bkhsgo.rs,done
bpop.f,BPOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ITERAT","LEVGRP|BPOPE|RATMAT|BPOPT|MATINV|BPOPC|LEVSOL|BPOPF",False,,pending
bpopc.f,BPOPC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ADCHAR","STATE",False,,pending
bpope.f,BPOPE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|ARRAY1","DWNFR1|SGMER1",False,,pending
bpopf.f,BPOPF,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR","",False,src/math/bpopf.rs,done
bpopt.f,BPOPT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR","COLIS",False,,pending
bre.f,BRE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","COMPT0",False,,pending
brez.f,BREZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","COMPT0",False,,pending
brte.f,BRTE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1","COMPT0",False,,pending
brtez.f,BRTEZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1","COMPT0",False,,pending
butler.f,BUTLER,SUBROUTINE,True,"","",False,src/math/butler.rs,done
carbon.f,CARBON,SUBROUTINE,True,"","",False,src/math/carbon.rs,done
ceh12.f,CEH12,FUNCTION,True,"","",False,src/math/ceh12.rs,done
change.f,CHANGE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","READBF|STEQEQ",True,,pending
chckse.f,CHCKSE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","SABOLF",True,,pending
chctab.f,CHCTAB,SUBROUTINE,False,"BASICS|MODELQ|abntab","",True,,pending
cheav.f,CHEAV,FUNCTION,False,"BASICS|ATOMIC","QUIT",True,,pending
cheavj.f,CHEAVJ,FUNCTION,False,"BASICS|ATOMIC","QUIT",True,,pending
cia_h2h.f,CIA_H2H,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_h2h2.f,CIA_H2H2,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_h2he.f,CIA_H2HE,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_hhe.f,CIA_HHE,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cion.f,CION,FUNCTION,True,"","",False,src/math/cion.rs,done
ckoest.f,CKOEST,FUNCTION,True,"BASICS","",False,src/math/ckoest.rs,done
colh.f,COLH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","IRC|CSPEC|BUTLER",False,,pending
colhe.f,COLHE,SUBROUTINE,False,"BASICS|ATOMIC","IRC|COLLHE|CSPEC",False,,pending
colis.f,COLIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|CTRTEMP","IRC|COLHE|CSPEC|COLH",False,,pending
collhe.f,COLLHE,SUBROUTINE,True,"","",False,src/math/collhe.rs,done
column.f,COLUMN,SUBROUTINE,False,"BASICS|MODELQ|relcor","",True,,pending
compt0.f,COMPT0,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|auxcbc","",False,src/math/compt0.rs,done
comset.f,COMSET,SUBROUTINE,False,"BASICS|MODELQ|auxcbc|comgfs","",False,src/math/comset.rs,done
concor.f,CONCOR,SUBROUTINE,False,"BASICS|MODELQ","CONOUT",True,,pending
conout.f,CONOUT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|CUBCON","MEANOPT|MEANOP|CONVEC|OPACF0",True,,pending
conref.f,CONREF,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|imucnn|CUBCON","WNSTOR|ELDENS|CONVC1|STEQEQ|CONOUT|CONVEC",True,,pending
contmd.f,CONTMD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|PRSAUX|CUBCON","MEANOP|CUBIC|OPACF0|STEQEQ|WNSTOR|CONOUT|CONVEC",True,,pending
contmp.f,CONTMP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ichndm|CUBCON","MEANOPT|MEANOP|CUBIC|OPACF0|STEQEQ|ELDENS|WNSTOR|CONOUT|CONVEC",True,,pending
convc1.f,CONVC1,SUBROUTINE,False,"BASICS|CUBCON","TRMDER|TRMDRT",False,,pending
convec.f,CONVEC,SUBROUTINE,False,"BASICS|CUBCON","TRMDER|TRMDRT",False,,pending
coolrt.f,COOLRT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|COOLCO","RTEFR1|OPACFA",True,,pending
corrwm.f,CORRWM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",True,,pending
cross.f,CROSS,FUNCTION,False,"BASICS|ATOMIC|MODELQ","",False,src/math/cross.rs,done
crossd.f,CROSSD,FUNCTION,False,"BASICS|ATOMIC|MODELQ","",False,src/math/cross.rs,done
cspec.f,CSPEC,SUBROUTINE,False,"BASICS|ATOMIC","QUIT",False,,pending
ctdata.f,CTDATA,BLOCK DATA,False,"CTIon|CTRecomb","",False,src/math/ctdata.rs,done
cubic.f,CUBIC,SUBROUTINE,False,"BASICS|CUBCON","",False,src/math/cubic.rs,done
dielrc.f,DIELRC,SUBROUTINE,True,"","",False,src/math/dielrc.rs,done
dietot.f,DIETOT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","DIELRC",True,,pending
divstr.f,DIVSTR,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/divstr.rs,done
dmder.f,DMDER,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|DEPTDR","",False,src/math/dmder.rs,done
dmeval.f,DMEVAL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ARRAY1","",True,,pending
dopgam.f,DOPGAM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","GAMSP",False,src/math/dopgam.rs,done
dwnfr.f,DWNFR,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr.rs,done
dwnfr0.f,DWNFR0,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr0.rs,done
dwnfr1.f,DWNFR1,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr1.rs,done
eint.f,EINT,SUBROUTINE,True,"","EXPINX",False,src/math/expint.rs,done
elcor.f,ELCOR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ADCHAR","WNSTOR|STEQEQ|STATE|MOLEQ",True,,pending
eldenc.f,ELDENC,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|eospar|hmolab|eletab","RHONEN|STATE|MOLEQ",True,,pending
eldens.f,ELDENS,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|eospar|terden","ENTENE|LINEQS|MPARTF|STATE|MOLEQ",True,,pending
emat.f,EMAT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","",False,src/math/emat.rs,done
entene.f,ENTENE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","MPARTF",False,,pending
erfcin.f,ERFCIN,FUNCTION,True,"","",False,src/math/erfcx.rs,done
erfcx.f,ERFCX,FUNCTION,True,"","",False,src/math/erfcx.rs,done
expint.f,EXPINT,FUNCTION,True,"","",False,src/math/expint.rs,done
expinx.f,EXPINX,SUBROUTINE,True,"","",False,src/math/expint.rs,done
expo.f,EXPO,FUNCTION,True,"","",False,src/math/expo.rs,done
ffcros.f,FFCROS,FUNCTION,True,"","",False,src/math/ffcros.rs,done
gami.f,GAMI,FUNCTION,True,"","",False,src/math/gami.rs,done
gamsp.f,GAMSP,SUBROUTINE,True,"BASICS","",False,src/math/gamsp.rs,done
gauleg.f,GAULEG,SUBROUTINE,True,"","",False,src/math/gauleg.rs,done
gaunt.f,GAUNT,FUNCTION,True,"","",False,src/math/gaunt.rs,done
getlal.f,GETLAL,SUBROUTINE,False,"BASICS|callardb|callardc|callarda|quasun|callardg|calphatd","",True,,pending
getwrd.f,GETWRD,SUBROUTINE,True,"","",False,src/math/getwrd.rs,done
gfree0.f,GFREE0,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/gfree.rs,done
gfree1.f,GFREE1,FUNCTION,False,"BASICS|MODELQ","",False,src/math/gfree.rs,done
gfreed.f,GFREED,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/gfree.rs,done
ghydop.f,GHYDOP,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|intcfg","",False,src/math/ghydop.rs,done
gntk.f,GNTK,FUNCTION,True,"","",False,src/math/gntk.rs,done
gomini.f,GOMINI,SUBROUTINE,False,"BASICS|MODELQ|intcfg","",True,,pending
grcor.f,GRCOR,SUBROUTINE,True,"","",False,src/math/grcor.rs,done
greyd.f,GREYD,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|ALIPAR","WNSTOR|MEANOP|OPACF0|STEQEQ|RHONEN",True,,pending
gridp.f,GRIDP,SUBROUTINE,True,"BASICS","",False,src/math/gridp.rs,done
h2minus.f,H2MINUS,SUBROUTINE,False,"BASICS","LOCATE",True,,pending
hction.f,HCTION,FUNCTION,False,"CTIon|CTRTEMP","",False,src/math/ctdata.rs,done
hctrecom.f,HCTRECOM,FUNCTION,False,"CTRTEMP|CTRecomb","",False,src/math/ctdata.rs,done
hedif.f,HEDIF,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|hediff","",True,,pending
hephot.f,HEPHOT,FUNCTION,True,"","",False,src/math/hephot.rs,done
hesol6.f,HESOL6,SUBROUTINE,False,"BASICS|MODELQ|PRSAUX","MATINV",False,,pending
hesolv.f,HESOLV,SUBROUTINE,False,"BASICS|MODELQ|PRSAUX","WNSTOR|STEQEQ|RHONEN|MATINV",True,,pending
hidalg.f,HIDALG,FUNCTION,True,"","",False,src/math/hidalg.rs,done
ijali2.f,IJALI2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","QUIT",True,,pending
ijalis.f,IJALIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",True,,pending
incldy.f,INCLDY,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT|RATMAT|SABOLF|WNSTOR|LEVSOL",True,,pending
indexx.f,INDEXX,SUBROUTINE,True,"","",False,src/math/indexx.rs,done
inicom.f,INICOM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|comgfs","",False,src/math/inicom.rs,done
inifrc.f,INIFRC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ijflar","INDEXX",True,,pending
inifrs.f,INIFRS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","QUIT|INDEXX",True,,pending
inifrt.f,INIFRT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ijflar","INDEXX",True,,pending
inilam.f,INILAM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR","WNSTOR|RTEFR1|RATES1|ELCOR|COLIS|SABOLF|STEQEQ|OPAINI|OPACF1",False,,pending
initia.f,INITIA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|freqcl|INUNIT|STRPAR","OPADD0|QUIT|ODFHYS|LINSPL|NSTPAR|INIFRC|READBF|RDATA|STATE|DOPGAM|LINSET|RDATAX|INTERP",True,,pending
inkul.f,INKUL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR|LINED","",True,,pending
inpdis.f,INPDIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|relcor","GRCOR",True,,pending
inpmod.f,INPMOD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|eospar","QUIT|RATMAT|KURUCZ|INCLDY|MOLEQ|SABOLF|WNSTOR|LEVSOL",True,,pending
interp.f,INTERP,SUBROUTINE,True,"BASICS","",False,src/math/interp.rs,done
inthyd.f,INTHYD,SUBROUTINE,False,"BASICS|MODELQ","DIVSTR",False,src/math/inthyd.rs,done
intlem.f,INTLEM,SUBROUTINE,False,"BASICS|MODELQ","INTHYD",False,src/math/intlem.rs,done
intxen.f,INTXEN,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/intxen.rs,done
irc.f,IRC,SUBROUTINE,True,"","EXPINX|SZIRC",False,src/math/irc.rs,done
iroset.f,IROSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|LINED","QUIT|LEVCD|INKUL",True,,pending
kurucz.f,KURUCZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|temlim","QUIT|RATMAT|MOLEQ|SABOLF|WNSTOR|LEVSOL|RHONEN",True,,pending
lagran.f,LAGRAN,SUBROUTINE,True,"","",False,src/math/interpolate.rs,done
laguer.f,LAGUER,SUBROUTINE,False,"","",True,src/math/laguer.rs,done
lemini.f,LEMINI,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
levcd.f,LEVCD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR","QUIT|INDEXX",True,,pending
levgrp.f,LEVGRP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",False,src/math/levgrp.rs,done
levset.f,LEVSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",False,,pending
levsol.f,LEVSOL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","LINEQS",False,src/math/levsol.rs,done
lineqs.f,LINEQS,SUBROUTINE,True,"BASICS","",False,src/math/lineqs.rs,done
linpro.f,LINPRO,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|quasun","DIVSTR|STARK0|DOPGAM|INTLEM|INTXEN",False,,pending
linsel.f,LINSEL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","RTEFR1|QUIT|OPAINI|OPACF1",True,,pending
linset.f,LINSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","DIVSTR|QUIT|IJALIS|STARK0",True,,pending
linspl.f,LINSPL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/linspl.rs,done
locate.f,LOCATE,SUBROUTINE,True,"","",False,src/math/locate.rs,done
ltegr.f,LTEGR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT|CONOUT|ROSSOP|WNSTOR|STEQEQ|INTERP",True,,pending
ltegrd.f,LTEGRD,SUBROUTINE,False,"BASICS|MODELQ|PRSAUX|CUBCON|TOTJHK|FACTRS|FLXAUX","QUIT|TEMPER|CONOUT|ELDENS|WNSTOR|STEQEQ|INTERP|ZMRHO",True,,pending
lucy.f,LUCY,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ITERAT|ALIPAR|ARRAY1","OPACFL|RTEFR1|ELCOR|COLIS|SABOLF|WNSTOR|STEQEQ|OPAINI",True,,pending
lymlin.f,LYMLIN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","DIVSTR|STARK0",True,,pending
matcon.f,MATCON,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|CUBCON","CONVEC",False,,pending
matgen.f,MATGEN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","BHED|MATCON|BREZ|BRE|BRTEZ|BHE|BRTE|SABOLF|BHEZ|EMAT|BPOP",False,,pending
matinv.f,MATINV,SUBROUTINE,True,"BASICS","",False,src/math/matinv.rs,done
meanop.f,MEANOP,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC","",False,src/math/meanop.rs,done
meanopt.f,MEANOPT,SUBROUTINE,False,"BASICS|MODELQ","OPCTAB",False,,pending
minv3.f,MINV3,SUBROUTINE,True,"","",False,src/math/minv3.rs,done
moleq.f,MOLEQ,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|adchar|eospar|hmolab|terden|ioniz2|COMFH1|moldat|entrop","MPARTF|RUSSEL",True,,pending
mpartf.f,MPARTF,SUBROUTINE,False,"moldat","",True,,pending
newdm.f,NEWDM,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX","INTERP|TEMPER",True,,pending
newdmt.f,NEWDMT,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX","INTERP|GRIDP|TEMPER",True,,pending
newpop.f,NEWPOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
nstout.f,NSTOUT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR","QUIT",True,,pending
nstpar.f,NSTPAR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|deridt|irwint|icnrsp|imucnn|ichndm|derdif|hediff|freqcl|temlim|moldat|ifpzpa|quasun|ipricr|adiaba|FLXAUX","QUIT|GETWRD",True,,pending
odf1.f,ODF1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","DIVSTR|ODFHST|DWNFR",True,,pending
odffr.f,ODFFR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","QUIT",False,,pending
odfhst.f,ODFHST,SUBROUTINE,False,"BASICS|MODELQ|ODFPAR","",False,src/math/odfhst.rs,done
odfhyd.f,ODFHYD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","DIVSTR|ODFHST|INDEXX",False,,pending
odfhys.f,ODFHYS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","ODFFR|STARK0|IJALIS",False,,pending
odfmer.f,ODFMER,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","ODFHYD",False,,pending
odfset.f,ODFSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|STFCR","QUIT|IJALIS",True,,pending
opacf0.f,OPACF0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab","OPACT1|OPADD|SGMER1|GFREE0|DWNFR0|DWNFR1|SABOLF|WNSTOR|LINPRO",False,,pending
opacf1.f,OPACF1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab|ipricr","OPACT1|OPADD|QUASIM|LYMLIN|GHYDOP|DWNFR1|PRD|SGMER1",True,,pending
opacfa.f,OPACFA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|COOLCO","DWNFR1|OPADD|PRD|SGMER1",False,,pending
opacfd.f,OPACFD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|dsctva|rhoder|hmolab","OPADD|OPACTD|QUASIM|LYMLIN|OPCTAB|DWNFR1|PRD|SGMER1|GFREED",True,,pending
opacfl.f,OPACFL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","DWNFR1|OPADD|SGMER1",False,,pending
opact1.f,OPACT1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|hmolab","OPCTAB",False,,pending
opactd.f,OPACTD,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|ITERAT|dsctva|rhoder|hmolab","OPCTAB",False,,pending
opactr.f,OPACTR,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ATOMIC|grdpra|dsctva|hmolab","STEQEQ|PGSET|ELDENS|SABOLF|RATMAL|WNSTOR|LEVSOL|OPAINI|OPACF1",False,,pending
opadd.f,OPADD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|eospar","H2MINUS|CIA_H2H|CIA_H2HE|CIA_H2H2|CIA_HHE",False,,pending
opadd0.f,OPADD0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",False,,pending
opahst.f,OPAHST,SUBROUTINE,False,"BASICS|ODFPAR","STARK0",True,,pending
opaini.f,OPAINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","LEVGRP|DWNFR0|REFLEV|SABOLF|WNSTOR|LINPRO",False,,pending
opctab.f,OPCTAB,SUBROUTINE,False,"BASICS|MODELQ","RAYLEIGH",False,,pending
opdata.f,OPDATA,SUBROUTINE,False,"TOPB","",True,,pending
opfrac.f,OPFRAC,SUBROUTINE,False,"pfoptb","",True,,pending
osccor.f,OSCCOR,SUBROUTINE,False,"BASICS|MODELQ|ITERAT","",True,,pending
outpri.f,OUTPRI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|grdpra","SABOLF|RATMAL|WNSTOR|LEVSOL|OPACF1",True,,pending
output.f,OUTPUT,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
partf.f,PARTF,SUBROUTINE,False,"BASICS|PFSTDS|irwint","OPFRAC|MPARTF|PFNI|PFFE|PFCNO|PFHEAV|PFSPEC",False,,pending
pfcno.f,PFCNO,SUBROUTINE,True,"BASICS","",False,src/math/pfcno.rs,done
pffe.f,PFFE,SUBROUTINE,True,"","",False,src/math/pffe.rs,done
pfheav.f,PFHEAV,SUBROUTINE,False,"","",True,,pending
pfni.f,PFNI,SUBROUTINE,True,"","",False,src/math/pfni.rs,done
pfspec.f,PFSPEC,SUBROUTINE,True,"","",False,src/math/pfspec.rs,done
pgset.f,PGSET,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|grdpra|rybpgs","TRIDAG",True,,pending
prchan.f,PRCHAN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
prd.f,PRD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","DOPGAM",False,,pending
prdini.f,PRDINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/prdini.rs,done
princ.f,PRINC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","DWNFR|LINPRO|SABOLF|OPACF1",True,,pending
prnt.f,PRNT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","SABOLF",True,,pending
profil.f,PROFIL,FUNCTION,False,"BASICS|ATOMIC|MODELQ|quasun","DIVSTR|STARK0",False,src/math/profil.rs,done
profsp.f,PROFSP,FUNCTION,False,"BASICS|ATOMIC|MODELQ","SABOLF",False,,pending
prsent.f,PRSENT,SUBROUTINE,False,"tdedge|TABLTD|tdflag|THERM","",True,,pending
psolve.f,PSOLVE,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/psolve.rs,done
pzert.f,PZERT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/pzert.rs,done
pzeval.f,PZEVAL,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|icnrsp","CONOUT",True,,pending
pzevld.f,PZEVLD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1|grdpra|DEPTDR|ifpzpa|PRSAUX","",False,src/math/pzevld.rs,done
quartc.f,QUARTC,SUBROUTINE,False,"","",True,src/math/quartc.rs,done
quasim.f,QUASIM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|quasun","ALLARD",False,,pending
quit.f,QUIT,SUBROUTINE,False,"","",True,src/math/quit.rs,done
radpre.f,RADPRE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","RTEFR1|INDEXX|QUIT|OPACF1",True,,pending
radtot.f,RADTOT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|TOTJHK|SURFEX|OPTDPT","RTEFR1|OPAINI|OPACF1",False,,pending
raph.f,RAPH,FUNCTION,True,"","",False,src/math/raph.rs,done
rates1.f,RATES1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT","RTEFR1|ROSSTD|OPACF1",False,,pending
ratmal.f,RATMAL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/ratmal.rs,done
ratmat.f,RATMAT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","REFLEV",False,,pending
ratsp1.f,RATSP1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","RTEFR1|ROSSTD|OPACF1",True,,pending
rayini.f,RAYINI,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC","RAYLEIGH",True,,pending
rayleigh.f,RAYLEIGH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|eospar|RAYSCT","",False,src/math/rayleigh.rs,done
rayset.f,RAYSET,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/rayset.rs,done
rdata.f,RDATA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|INUNIT|STRPAR|imodlc","QUIT|DOPGAM|LINSET|RDATAX",True,,pending
rdatax.f,RDATAX,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","BKHSGO",True,,pending
readbf.f,READBF,SUBROUTINE,False,"BASICS","",True,,pending
rechck.f,RECHCK,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","RTEFR1|OPACF1",True,,pending
reflev.f,REFLEV,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",False,src/math/reflev.rs,done
reiman.f,REIMAN,FUNCTION,True,"","",False,src/math/reiman.rs,done
resolv.f,RESOLV,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR|ARRAY1|icnrsp","NEWPOP|RTEFR1|RATES1|TAUFR1|ELCOR|ROSSTD|PRD|STEQEQ|CONOUT|OPAINI|TIMING|OPACF1",True,,pending
rhoeos.f,RHOEOS,FUNCTION,False,"BASICS|MODELQ","PRSENT",False,,pending
rhonen.f,RHONEN,SUBROUTINE,False,"BASICS|MODELQ","ELDENS",False,,pending
rhsgen.f,RHSGEN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CUBCON","LEVGRP|RATMAT|MATINV|STATE|SABOLF|CONVEC|COMPT0",False,,pending
rossop.f,ROSSOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","WNSTOR|MEANOPT|MEANOP|OPACF0|ELDENS|STEQEQ",False,,pending
rosstd.f,ROSSTD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR","",True,,pending
rte_sc.f,RTE_SC,SUBROUTINE,True,"BASICS","",False,src/math/rte_sc.rs,done
rteang.f,RTEANG,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|SURFEX|EXTINT","GAULEG",False,,pending
rtecf0.f,RTECF0,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|auxcbc|AUXRTE|OPTDPT","",False,src/math/rtecf0.rs,done
rtecf1.f,RTECF1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|SURFEX|comgfs|AUXRTE|EXTINT|OPTDPT","RTECF0|RTEFE2|RTESOL",True,,pending
rtecmc.f,RTECMC,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|comgfs","RTECF0|MATINV|OPACF1",False,,pending
rtecmu.f,RTECMU,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|OPTDPT","GAULEG|RTESOL|RTECF0|OPACF1",True,,pending
rtecom.f,RTECOM,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|comgfs|OPTDPT","RTECF1|RTECF0|OPACF1",False,,pending
rtedf1.f,RTEDF1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|OPTDPT","",False,src/math/rtedf1.rs,done
rtedf2.f,RTEDF2,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR","",False,src/math/rtedf2.rs,done
rtefe2.f,RTEFE2,SUBROUTINE,True,"BASICS","",False,src/math/rtefe2.rs,done
rtefr1.f,RTEFR1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","RTEDF2|RTESOL|MATINV|RTECF1|MINV3|RTEDF1",True,,pending
rteint.f,RTEINT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","MATINV|OPACF1",True,,pending
rtesol.f,RTESOL,SUBROUTINE,True,"BASICS","",False,src/math/rtesol.rs,done
russel.f,RUSSEL,SUBROUTINE,False,"BASICS|MODELQ|COMFH1","MPARTF",True,,pending
rybchn.f,RYBCHN,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ALIPAR|ARRAY1|grdpra|rybpgs","ELDENS|PGSET",True,,pending
rybene.f,RYBENE,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|deridt|RYBMTX|CUBCON","CONVEC",False,,pending
rybheq.f,RYBHEQ,SUBROUTINE,False,"BASICS|MODELQ|grdpra|rybpgs","RTEFR1|ELCOR|PGSET|ELDENS|WNSTOR|STEQEQ|OPAINI|OPACF1",True,,pending
rybmat.f,RYBMAT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|dsctva|RYBMTX","",False,src/math/rybmat.rs,done
rybsol.f,RYBSOL,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|ALIPAR|ARRAY1|ITERAT|imodlc|RYBMTX","OPACTR|OPACFD|RYBMAT|RYBCHN|LINEQS|RTEFR1|ALIFR1|ROSSTD|TRIDAG|STEQEQ",True,,pending
sabolf.f,SABOLF,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","PARTF",False,,pending
sbfch.f,SBFCH,FUNCTION,True,"","",False,src/math/sbfch.rs,done
sbfhe1.f,SBFHE1,FUNCTION,False,"BASICS|ATOMIC","QUIT",True,src/math/sbfhe1.rs,done
sbfhmi.f,SBFHMI,FUNCTION,True,"","",False,src/math/sbfhmi.rs,done
sbfhmi_old.f,SBFHMI_OLD,FUNCTION,True,"","",False,src/math/sbfhmi_old.rs,done
sbfoh.f,SBFOH,FUNCTION,True,"","",False,src/math/sbfoh.rs,done
setdrt.f,SETDRT,SUBROUTINE,False,"BASICS|MODELQ|RHODER","",False,src/math/setdrt.rs,done
settrm.f,SETTRM,SUBROUTINE,False,"tdedge|TABLTD|tdflag|THERM","PRSENT",True,,pending
sffhmi.f,SFFHMI,FUNCTION,True,"","",False,src/math/sffhmi.rs,done
sffhmi_add.f,SFFHMI_ADD,FUNCTION,True,"","",False,src/math/sffhmi_add.rs,done
sghe12.f,SGHE12,FUNCTION,True,"","",False,src/math/sghe12.rs,done
sgmer0.f,SGMER0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sgmer1.f,SGMER1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sgmerd.f,SGMERD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sigave.f,SIGAVE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","",True,,pending
sigk.f,SIGK,FUNCTION,False,"BASICS|ATOMIC","SPSIGK",False,,pending
sigmar.f,SIGMAR,FUNCTION,False,"BASICS","LAGUER",True,,pending
solve.f,SOLVE,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD","MATGEN|PRCHAN|MATINV|WNSTOR|RHSGEN",True,,pending
solves.f,SOLVES,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD|STOMAT","MATGEN|PRCHAN|MATINV|WNSTOR|RHSGEN",True,,pending
spsigk.f,SPSIGK,SUBROUTINE,True,"","CARBON",False,src/math/spsigk.rs,done
srtfrq.f,SRTFRQ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT|INDEXX",True,,pending
stark0.f,STARK0,SUBROUTINE,True,"","",False,src/math/stark0.rs,done
starka.f,STARKA,FUNCTION,False,"BASICS|MODELQ","",False,src/math/starka.rs,done
start.f,START,SUBROUTINE,False,"BASICS|hediff","",True,,pending
state.f,STATE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|PFSTDS|terden","OPFRAC|PARTF",True,,pending
steqeq.f,STEQEQ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|POPSTR|PPAPAR","LEVSOL|RATMAT|SABOLF|MOLEQ",False,,pending
switch.f,SWITCH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",True,,pending
szirc.f,SZIRC,SUBROUTINE,True,"","EINT",False,src/math/szirc.rs,done
tabini.f,TABINI,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|intcff|abntab|eletab","",True,,pending
tabint.f,TABINT,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|intcff","",False,src/math/tabint.rs,done
taufr1.f,TAUFR1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","",False,src/math/taufr1.rs,done
tdpini.f,TDPINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","GFREE0",False,src/math/tdpini.rs,done
temcor.f,TEMCOR,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|ALIPAR|CUBCON","WNSTOR|MEANOP|OPACF0|ELDENS|STEQEQ|CONVEC",True,,pending
temper.f,TEMPER,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|FACTRS|PRSAUX|FLXAUX","WNSTOR|MEANOPT|TLOCAL|MEANOP|OPACF0|ELDENS|STEQEQ",True,,pending
timing.f,TIMING,SUBROUTINE,False,"","",True,,pending
tiopf.f,TIOPF,SUBROUTINE,True,"","",False,src/math/tiopf.rs,done
tlocal.f,TLOCAL,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|FLXAUX","QUARTC",False,,pending
tlusty.f,TLUSTY,UNKNOWN,False,"BASICS|ITERAT|ALIPAR","TIMING",True,,pending
topbas.f,TOPBAS,FUNCTION,False,"TOPB","",True,,pending
traini.f,TRAINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","",False,src/math/traini.rs,done
tridag.f,TRIDAG,SUBROUTINE,True,"","",False,src/math/tridag.rs,done
trmder.f,TRMDER,SUBROUTINE,False,"BASICS|terden|adiaba|derdif","ELDENS",False,,pending
trmdrt.f,TRMDRT,SUBROUTINE,False,"BASICS|CC|CONVOUT|tdedge|tdflag","PRSENT",False,,pending
ubeta.f,UBETA,FUNCTION,True,"","LAGRAN",False,src/math/ubeta.rs,done
vern16.f,VERN16,FUNCTION,True,"BASICS","",False,src/math/vern16.rs,done
vern18.f,VERN18,FUNCTION,True,"BASICS","",False,src/math/vern18.rs,done
vern20.f,VERN20,FUNCTION,True,"BASICS","",False,src/math/vern20.rs,done
vern26.f,VERN26,FUNCTION,True,"BASICS","",False,src/math/vern26.rs,done
verner.f,VERNER,FUNCTION,False,"BASICS|ATOMIC","QUIT",False,src/math/verner.rs,done
visini.f,VISINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
voigt.f,VOIGT,FUNCTION,True,"","",False,src/math/voigt.rs,done
voigte.f,VOIGTE,FUNCTION,True,"","",False,src/math/voigte.rs,done
wn.f,WN,FUNCTION,True,"BASICS","",False,src/math/wn.rs,done
wnstor.f,WNSTOR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/wnstor.rs,done
xenini.f,XENINI,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
xk2dop.f,XK2DOP,FUNCTION,True,"","",False,src/math/xk2dop.rs,done
yint.f,YINT,FUNCTION,True,"","",False,src/math/interpolate.rs,done
ylintp.f,YLINTP,FUNCTION,True,"","",False,src/math/ylintp.rs,done
zmrho.f,ZMRHO,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/zmrho.rs,done
1 fortran_file unit_name unit_type is_pure common_deps call_deps has_io rust_module status
2 _unnamed_block_data_.f C BLOCK DATA False BASICS|ATOMIC False pending
3 accel2.f ACCEL2 SUBROUTINE False BASICS|ITERAT|MODELQ True pending
4 accelp.f ACCELP SUBROUTINE False BASICS|MODELQ|ITERAT|POPULS True pending
5 alifr1.f ALIFR1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR ALIFR3 False pending
6 alifr3.f ALIFR3 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifr3.rs done
7 alifr6.f ALIFR6 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifr6.rs done
8 alifrk.f ALIFRK SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifrk.rs done
9 alisk1.f ALISK1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT RTEFR1|ALIFRK|ROSSTD|OPACF1 True pending
10 alisk2.f ALISK2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT RTEFR1|ALIFRK|ROSSTD|OPACF1 True pending
11 alist1.f ALIST1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT RTEFR1|ALIFR1|OPACFD|ROSSTD True pending
12 alist2.f ALIST2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT QUIT|OPACFD|RTEFR1|ALIFR1|ROSSTD True pending
13 allard.f ALLARD SUBROUTINE False BASICS|callardb|callardc|callarda|quasun|callardg|calphatd ALLARDT True pending
14 allardt.f ALLARDT SUBROUTINE False BASICS|calphatd False src/math/allardt.rs done
15 angset.f ANGSET SUBROUTINE True BASICS GAULEG False src/math/angset.rs done
16 betah.f BETAH FUNCTION True False src/math/betah.rs done
17 bhe.f BHE SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR False src/math/bhe.rs done
18 bhed.f BHED SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CMATZD|SURFEX False src/math/bhe.rs done
19 bhez.f BHEZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|SURFEX False src/math/bhe.rs done
20 bkhsgo.f BKHSGO SUBROUTINE True False src/math/bkhsgo.rs done
21 bpop.f BPOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ITERAT LEVGRP|BPOPE|RATMAT|BPOPT|MATINV|BPOPC|LEVSOL|BPOPF False pending
22 bpopc.f BPOPC SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ADCHAR STATE False pending
23 bpope.f BPOPE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|ARRAY1 DWNFR1|SGMER1 False pending
24 bpopf.f BPOPF SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR False src/math/bpopf.rs done
25 bpopt.f BPOPT SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR COLIS False pending
26 bre.f BRE SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR COMPT0 False pending
27 brez.f BREZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR COMPT0 False pending
28 brte.f BRTE SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1 COMPT0 False pending
29 brtez.f BRTEZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1 COMPT0 False pending
30 butler.f BUTLER SUBROUTINE True False src/math/butler.rs done
31 carbon.f CARBON SUBROUTINE True False src/math/carbon.rs done
32 ceh12.f CEH12 FUNCTION True False src/math/ceh12.rs done
33 change.f CHANGE SUBROUTINE False BASICS|ATOMIC|MODELQ READBF|STEQEQ True pending
34 chckse.f CHCKSE SUBROUTINE False BASICS|ATOMIC|MODELQ SABOLF True pending
35 chctab.f CHCTAB SUBROUTINE False BASICS|MODELQ|abntab True pending
36 cheav.f CHEAV FUNCTION False BASICS|ATOMIC QUIT True pending
37 cheavj.f CHEAVJ FUNCTION False BASICS|ATOMIC QUIT True pending
38 cia_h2h.f CIA_H2H SUBROUTINE False LOCATE|IF True pending
39 cia_h2h2.f CIA_H2H2 SUBROUTINE False LOCATE|IF True pending
40 cia_h2he.f CIA_H2HE SUBROUTINE False LOCATE|IF True pending
41 cia_hhe.f CIA_HHE SUBROUTINE False LOCATE|IF True pending
42 cion.f CION FUNCTION True False src/math/cion.rs done
43 ckoest.f CKOEST FUNCTION True BASICS False src/math/ckoest.rs done
44 colh.f COLH SUBROUTINE False BASICS|ATOMIC|MODELQ IRC|CSPEC|BUTLER False pending
45 colhe.f COLHE SUBROUTINE False BASICS|ATOMIC IRC|COLLHE|CSPEC False pending
46 colis.f COLIS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|CTRTEMP IRC|COLHE|CSPEC|COLH False pending
47 collhe.f COLLHE SUBROUTINE True False src/math/collhe.rs done
48 column.f COLUMN SUBROUTINE False BASICS|MODELQ|relcor True pending
49 compt0.f COMPT0 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|auxcbc False src/math/compt0.rs done
50 comset.f COMSET SUBROUTINE False BASICS|MODELQ|auxcbc|comgfs False src/math/comset.rs done
51 concor.f CONCOR SUBROUTINE False BASICS|MODELQ CONOUT True pending
52 conout.f CONOUT SUBROUTINE False BASICS|MODELQ|ALIPAR|CUBCON MEANOPT|MEANOP|CONVEC|OPACF0 True pending
53 conref.f CONREF SUBROUTINE False BASICS|MODELQ|ARRAY1|imucnn|CUBCON WNSTOR|ELDENS|CONVC1|STEQEQ|CONOUT|CONVEC True pending
54 contmd.f CONTMD SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|PRSAUX|CUBCON MEANOP|CUBIC|OPACF0|STEQEQ|WNSTOR|CONOUT|CONVEC True pending
55 contmp.f CONTMP SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ichndm|CUBCON MEANOPT|MEANOP|CUBIC|OPACF0|STEQEQ|ELDENS|WNSTOR|CONOUT|CONVEC True pending
56 convc1.f CONVC1 SUBROUTINE False BASICS|CUBCON TRMDER|TRMDRT False pending
57 convec.f CONVEC SUBROUTINE False BASICS|CUBCON TRMDER|TRMDRT False pending
58 coolrt.f COOLRT SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|COOLCO RTEFR1|OPACFA True pending
59 corrwm.f CORRWM SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT True pending
60 cross.f CROSS FUNCTION False BASICS|ATOMIC|MODELQ False src/math/cross.rs done
61 crossd.f CROSSD FUNCTION False BASICS|ATOMIC|MODELQ False src/math/cross.rs done
62 cspec.f CSPEC SUBROUTINE False BASICS|ATOMIC QUIT False pending
63 ctdata.f CTDATA BLOCK DATA False CTIon|CTRecomb False src/math/ctdata.rs done
64 cubic.f CUBIC SUBROUTINE False BASICS|CUBCON False src/math/cubic.rs done
65 dielrc.f DIELRC SUBROUTINE True False src/math/dielrc.rs done
66 dietot.f DIETOT SUBROUTINE False BASICS|ATOMIC|MODELQ DIELRC True pending
67 divstr.f DIVSTR SUBROUTINE False BASICS|MODELQ False src/math/divstr.rs done
68 dmder.f DMDER SUBROUTINE False BASICS|ATOMIC|MODELQ|DEPTDR False src/math/dmder.rs done
69 dmeval.f DMEVAL SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ARRAY1 True pending
70 dopgam.f DOPGAM SUBROUTINE False BASICS|ATOMIC|MODELQ GAMSP False src/math/dopgam.rs done
71 dwnfr.f DWNFR SUBROUTINE False BASICS|MODELQ False src/math/dwnfr.rs done
72 dwnfr0.f DWNFR0 SUBROUTINE False BASICS|MODELQ False src/math/dwnfr0.rs done
73 dwnfr1.f DWNFR1 SUBROUTINE False BASICS|MODELQ False src/math/dwnfr1.rs done
74 eint.f EINT SUBROUTINE True EXPINX False src/math/expint.rs done
75 elcor.f ELCOR SUBROUTINE False BASICS|ATOMIC|MODELQ|ADCHAR WNSTOR|STEQEQ|STATE|MOLEQ True pending
76 eldenc.f ELDENC SUBROUTINE False BASICS|MODELQ|ATOMIC|eospar|hmolab|eletab RHONEN|STATE|MOLEQ True pending
77 eldens.f ELDENS SUBROUTINE False BASICS|MODELQ|ATOMIC|eospar|terden ENTENE|LINEQS|MPARTF|STATE|MOLEQ True pending
78 emat.f EMAT SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR False src/math/emat.rs done
79 entene.f ENTENE SUBROUTINE False BASICS|ATOMIC|MODELQ MPARTF False pending
80 erfcin.f ERFCIN FUNCTION True False src/math/erfcx.rs done
81 erfcx.f ERFCX FUNCTION True False src/math/erfcx.rs done
82 expint.f EXPINT FUNCTION True False src/math/expint.rs done
83 expinx.f EXPINX SUBROUTINE True False src/math/expint.rs done
84 expo.f EXPO FUNCTION True False src/math/expo.rs done
85 ffcros.f FFCROS FUNCTION True False src/math/ffcros.rs done
86 gami.f GAMI FUNCTION True False src/math/gami.rs done
87 gamsp.f GAMSP SUBROUTINE True BASICS False src/math/gamsp.rs done
88 gauleg.f GAULEG SUBROUTINE True False src/math/gauleg.rs done
89 gaunt.f GAUNT FUNCTION True False src/math/gaunt.rs done
90 getlal.f GETLAL SUBROUTINE False BASICS|callardb|callardc|callarda|quasun|callardg|calphatd True pending
91 getwrd.f GETWRD SUBROUTINE True False src/math/getwrd.rs done
92 gfree0.f GFREE0 SUBROUTINE False BASICS|MODELQ False src/math/gfree.rs done
93 gfree1.f GFREE1 FUNCTION False BASICS|MODELQ False src/math/gfree.rs done
94 gfreed.f GFREED SUBROUTINE False BASICS|MODELQ False src/math/gfree.rs done
95 ghydop.f GHYDOP SUBROUTINE False BASICS|MODELQ|ATOMIC|intcfg False src/math/ghydop.rs done
96 gntk.f GNTK FUNCTION True False src/math/gntk.rs done
97 gomini.f GOMINI SUBROUTINE False BASICS|MODELQ|intcfg True pending
98 grcor.f GRCOR SUBROUTINE True False src/math/grcor.rs done
99 greyd.f GREYD SUBROUTINE False BASICS|MODELQ|ATOMIC|ALIPAR WNSTOR|MEANOP|OPACF0|STEQEQ|RHONEN True pending
100 gridp.f GRIDP SUBROUTINE True BASICS False src/math/gridp.rs done
101 h2minus.f H2MINUS SUBROUTINE False BASICS LOCATE True pending
102 hction.f HCTION FUNCTION False CTIon|CTRTEMP False src/math/ctdata.rs done
103 hctrecom.f HCTRECOM FUNCTION False CTRTEMP|CTRecomb False src/math/ctdata.rs done
104 hedif.f HEDIF SUBROUTINE False BASICS|MODELQ|ATOMIC|hediff True pending
105 hephot.f HEPHOT FUNCTION True False src/math/hephot.rs done
106 hesol6.f HESOL6 SUBROUTINE False BASICS|MODELQ|PRSAUX MATINV False pending
107 hesolv.f HESOLV SUBROUTINE False BASICS|MODELQ|PRSAUX WNSTOR|STEQEQ|RHONEN|MATINV True pending
108 hidalg.f HIDALG FUNCTION True False src/math/hidalg.rs done
109 ijali2.f IJALI2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR QUIT True pending
110 ijalis.f IJALIS SUBROUTINE False BASICS|ATOMIC|MODELQ True pending
111 incldy.f INCLDY SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT|RATMAT|SABOLF|WNSTOR|LEVSOL True pending
112 indexx.f INDEXX SUBROUTINE True False src/math/indexx.rs done
113 inicom.f INICOM SUBROUTINE False BASICS|ATOMIC|MODELQ|comgfs False src/math/inicom.rs done
114 inifrc.f INIFRC SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ijflar INDEXX True pending
115 inifrs.f INIFRS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR QUIT|INDEXX True pending
116 inifrt.f INIFRT SUBROUTINE False BASICS|ATOMIC|MODELQ|ijflar INDEXX True pending
117 inilam.f INILAM SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR WNSTOR|RTEFR1|RATES1|ELCOR|COLIS|SABOLF|STEQEQ|OPAINI|OPACF1 False pending
118 initia.f INITIA SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|freqcl|INUNIT|STRPAR OPADD0|QUIT|ODFHYS|LINSPL|NSTPAR|INIFRC|READBF|RDATA|STATE|DOPGAM|LINSET|RDATAX|INTERP True pending
119 inkul.f INKUL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR|LINED True pending
120 inpdis.f INPDIS SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|relcor GRCOR True pending
121 inpmod.f INPMOD SUBROUTINE False BASICS|ATOMIC|MODELQ|eospar QUIT|RATMAT|KURUCZ|INCLDY|MOLEQ|SABOLF|WNSTOR|LEVSOL True pending
122 interp.f INTERP SUBROUTINE True BASICS False src/math/interp.rs done
123 inthyd.f INTHYD SUBROUTINE False BASICS|MODELQ DIVSTR False src/math/inthyd.rs done
124 intlem.f INTLEM SUBROUTINE False BASICS|MODELQ INTHYD False src/math/intlem.rs done
125 intxen.f INTXEN SUBROUTINE False BASICS|MODELQ False src/math/intxen.rs done
126 irc.f IRC SUBROUTINE True EXPINX|SZIRC False src/math/irc.rs done
127 iroset.f IROSET SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|LINED QUIT|LEVCD|INKUL True pending
128 kurucz.f KURUCZ SUBROUTINE False BASICS|ATOMIC|MODELQ|temlim QUIT|RATMAT|MOLEQ|SABOLF|WNSTOR|LEVSOL|RHONEN True pending
129 lagran.f LAGRAN SUBROUTINE True False src/math/interpolate.rs done
130 laguer.f LAGUER SUBROUTINE False True src/math/laguer.rs done
131 lemini.f LEMINI SUBROUTINE False BASICS|MODELQ True pending
132 levcd.f LEVCD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR QUIT|INDEXX True pending
133 levgrp.f LEVGRP SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT False src/math/levgrp.rs done
134 levset.f LEVSET SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT False pending
135 levsol.f LEVSOL SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT LINEQS False src/math/levsol.rs done
136 lineqs.f LINEQS SUBROUTINE True BASICS False src/math/lineqs.rs done
137 linpro.f LINPRO SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|quasun DIVSTR|STARK0|DOPGAM|INTLEM|INTXEN False pending
138 linsel.f LINSEL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR RTEFR1|QUIT|OPAINI|OPACF1 True pending
139 linset.f LINSET SUBROUTINE False BASICS|ATOMIC|MODELQ DIVSTR|QUIT|IJALIS|STARK0 True pending
140 linspl.f LINSPL SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/linspl.rs done
141 locate.f LOCATE SUBROUTINE True False src/math/locate.rs done
142 ltegr.f LTEGR SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT|CONOUT|ROSSOP|WNSTOR|STEQEQ|INTERP True pending
143 ltegrd.f LTEGRD SUBROUTINE False BASICS|MODELQ|PRSAUX|CUBCON|TOTJHK|FACTRS|FLXAUX QUIT|TEMPER|CONOUT|ELDENS|WNSTOR|STEQEQ|INTERP|ZMRHO True pending
144 lucy.f LUCY SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ITERAT|ALIPAR|ARRAY1 OPACFL|RTEFR1|ELCOR|COLIS|SABOLF|WNSTOR|STEQEQ|OPAINI True pending
145 lymlin.f LYMLIN SUBROUTINE False BASICS|ATOMIC|MODELQ DIVSTR|STARK0 True pending
146 matcon.f MATCON SUBROUTINE False BASICS|MODELQ|ARRAY1|CUBCON CONVEC False pending
147 matgen.f MATGEN SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR BHED|MATCON|BREZ|BRE|BRTEZ|BHE|BRTE|SABOLF|BHEZ|EMAT|BPOP False pending
148 matinv.f MATINV SUBROUTINE True BASICS False src/math/matinv.rs done
149 meanop.f MEANOP SUBROUTINE False BASICS|MODELQ|ATOMIC False src/math/meanop.rs done
150 meanopt.f MEANOPT SUBROUTINE False BASICS|MODELQ OPCTAB False pending
151 minv3.f MINV3 SUBROUTINE True False src/math/minv3.rs done
152 moleq.f MOLEQ SUBROUTINE False BASICS|MODELQ|ATOMIC|adchar|eospar|hmolab|terden|ioniz2|COMFH1|moldat|entrop MPARTF|RUSSEL True pending
153 mpartf.f MPARTF SUBROUTINE False moldat True pending
154 newdm.f NEWDM SUBROUTINE False BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX INTERP|TEMPER True pending
155 newdmt.f NEWDMT SUBROUTINE False BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX INTERP|GRIDP|TEMPER True pending
156 newpop.f NEWPOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
157 nstout.f NSTOUT SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR QUIT True pending
158 nstpar.f NSTPAR SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|deridt|irwint|icnrsp|imucnn|ichndm|derdif|hediff|freqcl|temlim|moldat|ifpzpa|quasun|ipricr|adiaba|FLXAUX QUIT|GETWRD True pending
159 odf1.f ODF1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR DIVSTR|ODFHST|DWNFR True pending
160 odffr.f ODFFR SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR QUIT False pending
161 odfhst.f ODFHST SUBROUTINE False BASICS|MODELQ|ODFPAR False src/math/odfhst.rs done
162 odfhyd.f ODFHYD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR DIVSTR|ODFHST|INDEXX False pending
163 odfhys.f ODFHYS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR ODFFR|STARK0|IJALIS False pending
164 odfmer.f ODFMER SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR ODFHYD False pending
165 odfset.f ODFSET SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|STFCR QUIT|IJALIS True pending
166 opacf0.f OPACF0 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab OPACT1|OPADD|SGMER1|GFREE0|DWNFR0|DWNFR1|SABOLF|WNSTOR|LINPRO False pending
167 opacf1.f OPACF1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab|ipricr OPACT1|OPADD|QUASIM|LYMLIN|GHYDOP|DWNFR1|PRD|SGMER1 True pending
168 opacfa.f OPACFA SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|COOLCO DWNFR1|OPADD|PRD|SGMER1 False pending
169 opacfd.f OPACFD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|dsctva|rhoder|hmolab OPADD|OPACTD|QUASIM|LYMLIN|OPCTAB|DWNFR1|PRD|SGMER1|GFREED True pending
170 opacfl.f OPACFL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR DWNFR1|OPADD|SGMER1 False pending
171 opact1.f OPACT1 SUBROUTINE False BASICS|MODELQ|ALIPAR|hmolab OPCTAB False pending
172 opactd.f OPACTD SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|ITERAT|dsctva|rhoder|hmolab OPCTAB False pending
173 opactr.f OPACTR SUBROUTINE False BASICS|MODELQ|ALIPAR|ATOMIC|grdpra|dsctva|hmolab STEQEQ|PGSET|ELDENS|SABOLF|RATMAL|WNSTOR|LEVSOL|OPAINI|OPACF1 False pending
174 opadd.f OPADD SUBROUTINE False BASICS|ATOMIC|MODELQ|eospar H2MINUS|CIA_H2H|CIA_H2HE|CIA_H2H2|CIA_HHE False pending
175 opadd0.f OPADD0 SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT False pending
176 opahst.f OPAHST SUBROUTINE False BASICS|ODFPAR STARK0 True pending
177 opaini.f OPAINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR LEVGRP|DWNFR0|REFLEV|SABOLF|WNSTOR|LINPRO False pending
178 opctab.f OPCTAB SUBROUTINE False BASICS|MODELQ RAYLEIGH False pending
179 opdata.f OPDATA SUBROUTINE False TOPB True pending
180 opfrac.f OPFRAC SUBROUTINE False pfoptb True pending
181 osccor.f OSCCOR SUBROUTINE False BASICS|MODELQ|ITERAT True pending
182 outpri.f OUTPRI SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|grdpra SABOLF|RATMAL|WNSTOR|LEVSOL|OPACF1 True pending
183 output.f OUTPUT SUBROUTINE False BASICS|MODELQ True pending
184 partf.f PARTF SUBROUTINE False BASICS|PFSTDS|irwint OPFRAC|MPARTF|PFNI|PFFE|PFCNO|PFHEAV|PFSPEC False pending
185 pfcno.f PFCNO SUBROUTINE True BASICS False src/math/pfcno.rs done
186 pffe.f PFFE SUBROUTINE True False src/math/pffe.rs done
187 pfheav.f PFHEAV SUBROUTINE False True pending
188 pfni.f PFNI SUBROUTINE True False src/math/pfni.rs done
189 pfspec.f PFSPEC SUBROUTINE True False src/math/pfspec.rs done
190 pgset.f PGSET SUBROUTINE False BASICS|ITERAT|MODELQ|grdpra|rybpgs TRIDAG True pending
191 prchan.f PRCHAN SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
192 prd.f PRD SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT DOPGAM False pending
193 prdini.f PRDINI SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/prdini.rs done
194 princ.f PRINC SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR DWNFR|LINPRO|SABOLF|OPACF1 True pending
195 prnt.f PRNT SUBROUTINE False BASICS|ATOMIC|MODELQ SABOLF True pending
196 profil.f PROFIL FUNCTION False BASICS|ATOMIC|MODELQ|quasun DIVSTR|STARK0 False src/math/profil.rs done
197 profsp.f PROFSP FUNCTION False BASICS|ATOMIC|MODELQ SABOLF False pending
198 prsent.f PRSENT SUBROUTINE False tdedge|TABLTD|tdflag|THERM True pending
199 psolve.f PSOLVE SUBROUTINE False BASICS|MODELQ False src/math/psolve.rs done
200 pzert.f PZERT SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/pzert.rs done
201 pzeval.f PZEVAL SUBROUTINE False BASICS|MODELQ|ALIPAR|icnrsp CONOUT True pending
202 pzevld.f PZEVLD SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1|grdpra|DEPTDR|ifpzpa|PRSAUX False src/math/pzevld.rs done
203 quartc.f QUARTC SUBROUTINE False True src/math/quartc.rs done
204 quasim.f QUASIM SUBROUTINE False BASICS|ATOMIC|MODELQ|quasun ALLARD False pending
205 quit.f QUIT SUBROUTINE False True src/math/quit.rs done
206 radpre.f RADPRE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR RTEFR1|INDEXX|QUIT|OPACF1 True pending
207 radtot.f RADTOT SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|TOTJHK|SURFEX|OPTDPT RTEFR1|OPAINI|OPACF1 False pending
208 raph.f RAPH FUNCTION True False src/math/raph.rs done
209 rates1.f RATES1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT RTEFR1|ROSSTD|OPACF1 False pending
210 ratmal.f RATMAL SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/ratmal.rs done
211 ratmat.f RATMAT SUBROUTINE False BASICS|ATOMIC|MODELQ REFLEV False pending
212 ratsp1.f RATSP1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT RTEFR1|ROSSTD|OPACF1 True pending
213 rayini.f RAYINI SUBROUTINE False BASICS|MODELQ|ATOMIC RAYLEIGH True pending
214 rayleigh.f RAYLEIGH SUBROUTINE False BASICS|ATOMIC|MODELQ|eospar|RAYSCT False src/math/rayleigh.rs done
215 rayset.f RAYSET SUBROUTINE False BASICS|MODELQ False src/math/rayset.rs done
216 rdata.f RDATA SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|INUNIT|STRPAR|imodlc QUIT|DOPGAM|LINSET|RDATAX True pending
217 rdatax.f RDATAX SUBROUTINE False BASICS|ATOMIC|MODELQ BKHSGO True pending
218 readbf.f READBF SUBROUTINE False BASICS True pending
219 rechck.f RECHCK SUBROUTINE False BASICS|ATOMIC|MODELQ RTEFR1|OPACF1 True pending
220 reflev.f REFLEV SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT False src/math/reflev.rs done
221 reiman.f REIMAN FUNCTION True False src/math/reiman.rs done
222 resolv.f RESOLV SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR|ARRAY1|icnrsp NEWPOP|RTEFR1|RATES1|TAUFR1|ELCOR|ROSSTD|PRD|STEQEQ|CONOUT|OPAINI|TIMING|OPACF1 True pending
223 rhoeos.f RHOEOS FUNCTION False BASICS|MODELQ PRSENT False pending
224 rhonen.f RHONEN SUBROUTINE False BASICS|MODELQ ELDENS False pending
225 rhsgen.f RHSGEN SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CUBCON LEVGRP|RATMAT|MATINV|STATE|SABOLF|CONVEC|COMPT0 False pending
226 rossop.f ROSSOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR WNSTOR|MEANOPT|MEANOP|OPACF0|ELDENS|STEQEQ False pending
227 rosstd.f ROSSTD SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR True pending
228 rte_sc.f RTE_SC SUBROUTINE True BASICS False src/math/rte_sc.rs done
229 rteang.f RTEANG SUBROUTINE False BASICS|MODELQ|ALIPAR|SURFEX|EXTINT GAULEG False pending
230 rtecf0.f RTECF0 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|auxcbc|AUXRTE|OPTDPT False src/math/rtecf0.rs done
231 rtecf1.f RTECF1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|SURFEX|comgfs|AUXRTE|EXTINT|OPTDPT RTECF0|RTEFE2|RTESOL True pending
232 rtecmc.f RTECMC SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|comgfs RTECF0|MATINV|OPACF1 False pending
233 rtecmu.f RTECMU SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|OPTDPT GAULEG|RTESOL|RTECF0|OPACF1 True pending
234 rtecom.f RTECOM SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|AUXRTE|comgfs|OPTDPT RTECF1|RTECF0|OPACF1 False pending
235 rtedf1.f RTEDF1 SUBROUTINE False BASICS|MODELQ|ALIPAR|OPTDPT False src/math/rtedf1.rs done
236 rtedf2.f RTEDF2 SUBROUTINE False BASICS|MODELQ|ALIPAR False src/math/rtedf2.rs done
237 rtefe2.f RTEFE2 SUBROUTINE True BASICS False src/math/rtefe2.rs done
238 rtefr1.f RTEFR1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT RTEDF2|RTESOL|MATINV|RTECF1|MINV3|RTEDF1 True pending
239 rteint.f RTEINT SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT MATINV|OPACF1 True pending
240 rtesol.f RTESOL SUBROUTINE True BASICS False src/math/rtesol.rs done
241 russel.f RUSSEL SUBROUTINE False BASICS|MODELQ|COMFH1 MPARTF True pending
242 rybchn.f RYBCHN SUBROUTINE False BASICS|ITERAT|MODELQ|ALIPAR|ARRAY1|grdpra|rybpgs ELDENS|PGSET True pending
243 rybene.f RYBENE SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|deridt|RYBMTX|CUBCON CONVEC False pending
244 rybheq.f RYBHEQ SUBROUTINE False BASICS|MODELQ|grdpra|rybpgs RTEFR1|ELCOR|PGSET|ELDENS|WNSTOR|STEQEQ|OPAINI|OPACF1 True pending
245 rybmat.f RYBMAT SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|dsctva|RYBMTX False src/math/rybmat.rs done
246 rybsol.f RYBSOL SUBROUTINE False BASICS|MODELQ|ATOMIC|ALIPAR|ARRAY1|ITERAT|imodlc|RYBMTX OPACTR|OPACFD|RYBMAT|RYBCHN|LINEQS|RTEFR1|ALIFR1|ROSSTD|TRIDAG|STEQEQ True pending
247 sabolf.f SABOLF SUBROUTINE False BASICS|ATOMIC|MODELQ PARTF False pending
248 sbfch.f SBFCH FUNCTION True False src/math/sbfch.rs done
249 sbfhe1.f SBFHE1 FUNCTION False BASICS|ATOMIC QUIT True src/math/sbfhe1.rs done
250 sbfhmi.f SBFHMI FUNCTION True False src/math/sbfhmi.rs done
251 sbfhmi_old.f SBFHMI_OLD FUNCTION True False src/math/sbfhmi_old.rs done
252 sbfoh.f SBFOH FUNCTION True False src/math/sbfoh.rs done
253 setdrt.f SETDRT SUBROUTINE False BASICS|MODELQ|RHODER False src/math/setdrt.rs done
254 settrm.f SETTRM SUBROUTINE False tdedge|TABLTD|tdflag|THERM PRSENT True pending
255 sffhmi.f SFFHMI FUNCTION True False src/math/sffhmi.rs done
256 sffhmi_add.f SFFHMI_ADD FUNCTION True False src/math/sffhmi_add.rs done
257 sghe12.f SGHE12 FUNCTION True False src/math/sghe12.rs done
258 sgmer0.f SGMER0 SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
259 sgmer1.f SGMER1 SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
260 sgmerd.f SGMERD SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
261 sigave.f SIGAVE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR True pending
262 sigk.f SIGK FUNCTION False BASICS|ATOMIC SPSIGK False pending
263 sigmar.f SIGMAR FUNCTION False BASICS LAGUER True pending
264 solve.f SOLVE SUBROUTINE False BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD MATGEN|PRCHAN|MATINV|WNSTOR|RHSGEN True pending
265 solves.f SOLVES SUBROUTINE False BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD|STOMAT MATGEN|PRCHAN|MATINV|WNSTOR|RHSGEN True pending
266 spsigk.f SPSIGK SUBROUTINE True CARBON False src/math/spsigk.rs done
267 srtfrq.f SRTFRQ SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT|INDEXX True pending
268 stark0.f STARK0 SUBROUTINE True False src/math/stark0.rs done
269 starka.f STARKA FUNCTION False BASICS|MODELQ False src/math/starka.rs done
270 start.f START SUBROUTINE False BASICS|hediff True pending
271 state.f STATE SUBROUTINE False BASICS|ATOMIC|MODELQ|PFSTDS|terden OPFRAC|PARTF True pending
272 steqeq.f STEQEQ SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|POPSTR|PPAPAR LEVSOL|RATMAT|SABOLF|MOLEQ False pending
273 switch.f SWITCH SUBROUTINE False BASICS|ATOMIC|MODELQ True pending
274 szirc.f SZIRC SUBROUTINE True EINT False src/math/szirc.rs done
275 tabini.f TABINI SUBROUTINE False BASICS|MODELQ|ATOMIC|intcff|abntab|eletab True pending
276 tabint.f TABINT SUBROUTINE False BASICS|MODELQ|ATOMIC|intcff False src/math/tabint.rs done
277 taufr1.f TAUFR1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT False src/math/taufr1.rs done
278 tdpini.f TDPINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR GFREE0 False src/math/tdpini.rs done
279 temcor.f TEMCOR SUBROUTINE False BASICS|MODELQ|ARRAY1|ALIPAR|CUBCON WNSTOR|MEANOP|OPACF0|ELDENS|STEQEQ|CONVEC True pending
280 temper.f TEMPER SUBROUTINE False BASICS|MODELQ|ALIPAR|FACTRS|PRSAUX|FLXAUX WNSTOR|MEANOPT|TLOCAL|MEANOP|OPACF0|ELDENS|STEQEQ True pending
281 timing.f TIMING SUBROUTINE False True pending
282 tiopf.f TIOPF SUBROUTINE True False src/math/tiopf.rs done
283 tlocal.f TLOCAL SUBROUTINE False BASICS|MODELQ|FACTRS|FLXAUX QUARTC False pending
284 tlusty.f TLUSTY UNKNOWN False BASICS|ITERAT|ALIPAR TIMING True pending
285 topbas.f TOPBAS FUNCTION False TOPB True pending
286 traini.f TRAINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR False src/math/traini.rs done
287 tridag.f TRIDAG SUBROUTINE True False src/math/tridag.rs done
288 trmder.f TRMDER SUBROUTINE False BASICS|terden|adiaba|derdif ELDENS False pending
289 trmdrt.f TRMDRT SUBROUTINE False BASICS|CC|CONVOUT|tdedge|tdflag PRSENT False pending
290 ubeta.f UBETA FUNCTION True LAGRAN False src/math/ubeta.rs done
291 vern16.f VERN16 FUNCTION True BASICS False src/math/vern16.rs done
292 vern18.f VERN18 FUNCTION True BASICS False src/math/vern18.rs done
293 vern20.f VERN20 FUNCTION True BASICS False src/math/vern20.rs done
294 vern26.f VERN26 FUNCTION True BASICS False src/math/vern26.rs done
295 verner.f VERNER FUNCTION False BASICS|ATOMIC QUIT False src/math/verner.rs done
296 visini.f VISINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
297 voigt.f VOIGT FUNCTION True False src/math/voigt.rs done
298 voigte.f VOIGTE FUNCTION True False src/math/voigte.rs done
299 wn.f WN FUNCTION True BASICS False src/math/wn.rs done
300 wnstor.f WNSTOR SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/wnstor.rs done
301 xenini.f XENINI SUBROUTINE False BASICS|MODELQ True pending
302 xk2dop.f XK2DOP FUNCTION True False src/math/xk2dop.rs done
303 yint.f YINT FUNCTION True False src/math/interpolate.rs done
304 ylintp.f YLINTP FUNCTION True False src/math/ylintp.rs done
305 zmrho.f ZMRHO SUBROUTINE False BASICS|MODELQ False src/math/zmrho.rs done

View File

@ -1,77 +0,0 @@
# TLUSTY/SYNSPEC 重构计划
> **实时追踪见 [FORTRAN_TRACKING.md](../../FORTRAN_TRACKING.md)**
> 本文档提供重构优先级和阶段划分参考。
## 优先级原则
1. **纯函数优先** - 无 COMMON/I/O 依赖,独立测试
2. **依赖少的优先** - 只依赖 BASICS 的函数
3. **小型函数优先** - 行数少,风险低
4. **核心功能优先** - 辐射转移、不透明度
## 阶段划分
### 阶段 1: 纯函数 (is_pure=True)
已完成大部分,剩余查看:
```bash
grep "True.*pending" fortran_analysis.csv
```
### 阶段 2: 简单 COMMON 依赖
只依赖 BASICS 或已有状态结构体的函数。
### 阶段 3: 复杂 COMMON 依赖
依赖多个 COMMON 块的函数。
### 阶段 4: I/O 依赖 (117个)
最后处理,可能需要设计 I/O 抽象层。
## 核心函数分类
### 辐射转移 (RTE)
- `bre.f`, `brez.f` - 基本辐射转移
- `brte.f`, `brtez.f` - 扩展辐射转移
- `rte_sc.f`, `rtedf*.f` - 深度/角度积分
### 不透明度 (Opacity)
- `opacfl.f` - 核心不透明度计算
- `opctab.f` - 不透明度表插值
- `opadd*.f` - 不透明度叠加
### 统计平衡 (Statistical Equilibrium)
- `bpop*.f` - 束缚态占据数
- `levsol.f` - 能级求解 ✅
- `ratmat.f` - 速率矩阵
### ALI 求解器
- `alifr1.f`, `alifr3.f`, `alifr6.f` - ALI 迭代
## 推荐执行顺序
```
1. 完成剩余纯函数
2. 简单 COMMON 函数 (setdrt, cubic, dmder ✅)
3. 辐射转移核心
4. 不透明度核心
5. 统计平衡核心
6. I/O 封装
7. 主程序集成
```
## 查询命令
```bash
# 未完成的纯函数
grep "True.*pending" fortran_analysis.csv
# 只依赖 BASICS 的待处理函数
grep "BASICS.*pending" fortran_analysis.csv | grep -v "ATOMIC\|MODELQ"
# 按行数排序
cd tlusty/extracted && wc -l *.f | sort -n | head -30
```

View File

@ -1,670 +0,0 @@
# Fortran → Rust 重构问题与解决方案
记录重构过程中遇到的问题,避免重复踩坑。
---
## 1. Fortran 1-indexed 转 Rust 0-indexed
### 问题
Fortran 数组从 1 开始索引Rust 从 0 开始。
### 解决方案
```rust
// 数组访问
arr(i) → arr[i-1]
// 循环范围
DO I=1,N → for i in 0..n
// 边界条件 (locate, ylintp 等)
// Fortran: jl=0 表示"在第一个有效索引之前"
// Rust: jl=0 就是第一个有效索引,无需调整
```
### 示例 (ylintp.f)
```fortran
! Fortran: jl=0 需要调整
IF (J.EQ.0) J = J+1 ! 调整到 J=1
```
```rust
// Rust: jl=0 就是第一个有效索引,直接使用
// 删除 IF (J.EQ.0) 的调整逻辑
```
---
## 2. Fortran 表达式解析错误
### 问题
`XL=-LOG(X)` 被误解为 `(-x).ln()` 而不是 `-x.ln()`
### 示例 (erfcin.f)
```fortran
XL=-LOG(X) ! 意思是: XL = -ln(X)
```
```rust
// 错误:
let xl = (-x).ln(); // ln(-x) = NaN for x>0
// 正确:
let xl = -x.ln(); // -ln(x)
```
### 教训
Fortran 中 `-LOG(X)``-(LOG(X))`,不是 `LOG(-X)`
---
## 3. powi 类型歧义
### 问题
`(z1 - z2).powi(2)` 编译错误,类型不明确
### 解决方案
```rust
// 错误:
(z1 - z2).powi(2) // 编译器无法推断类型
// 方案1: 显式乘法 (推荐)
(z1 - z2) * (z1 - z2)
// 方案2: 显式类型标注
((z1 - z2): f64).powi(2)
```
---
## 4. 多项式近似精度
### 问题
eint 函数 Rust 与 Fortran 结果差异 ~1.3e-8
### 原因
Abramowitz-Stegun 多项式近似本身精度有限
### 解决方案
放宽 epsilon 到 1e-7
```rust
// 简单函数: epsilon = 1e-10
// 多项式近似: epsilon = 1e-7
assert_relative_eq!(e1, exp_e1, epsilon = 1e-7);
```
---
## 5. 数组索引越界
### 问题
`locate` 函数无限循环
### 原因
Fortran 中 ju=N+1 (越界值)Rust 直接用导致越界访问
### 解决方案
使用 i64 允许负值,或调整边界逻辑
```rust
// 使用 i64 支持 jl=-1
let mut jl: i64 = -1;
let mut ju: i64 = n as i64;
```
---
## 6. voigte 索引偏移
### 问题
voigte 返回负值
### 原因
Fortran m 值是 1-indexedRust 中直接用导致索引偏移
### 解决方案
```rust
// Fortran: m=6 表示第6个元素
// Rust: 需要用 m-1
let (m, quo) = if v < 2.4 {
(5, 1.0) // Fortran m=6 → 0-indexed m=5
} else {
(10, 1.0) // Fortran m=11 → 0-indexed m=10
};
```
---
## 7. 条件分支遗漏
### 问题
voigte 某些参数组合返回错误值
### 原因
漏掉了 Fortran 中的嵌套条件判断
### 教训
仔细对比 Fortran 的所有分支,特别是嵌套 IF
---
## 8. COMMON 依赖误判
### 问题
某些标记为"纯函数"的文件实际有 COMMON 依赖
### 已确认有依赖的文件
```
gamsp.f - 使用 VOIPAR COMMON
sgmer1.f - 使用 COMMON
sgmerd.f - 使用 COMMON
cross.f - 使用 COMMON
gfree1.f - 使用 COMMON
gfree0.f - 使用 BASICS, MODELQ COMMON
gfreed.f - 使用 BASICS, MODELQ COMMON
wn.f - 使用 BASICS COMMON
crossd.f - 使用 BASICS, ATOMIC, MODELQ COMMON
dopgam.f - 使用 BASICS, ATOMIC, MODELQ COMMON
verner.f - 使用 BASICS, ATOMIC COMMON
sbfhe1.f - 使用 BASICS, ATOMIC COMMON
rayini.f - 有文件 I/O + COMMON
```
### 解决方案
重构前检查所有 INCLUDE 语句,不仅是 IMPLIC.FOR
---
## 9. Clenshaw 求和整数溢出
### 问题
collhe 中递减循环溢出
### 原因
`ir``jj` 递减到负数时,无符号整数溢出
### 解决方案
```rust
// 错误: 用 usize
let mut ir: usize = ...;
ir -= 1; // 当 ir=0 时溢出!
// 正确: 用有符号整数
let mut ir: isize = ...;
ir -= 1; // 正常变为 -1
```
---
## 10. 索引计算中间结果溢出
### 问题
collhe 的索引计算 `((iu+1)^2 - 3*(iu+1) + 4)/2` 溢出
### 原因
中间结果超出 usize 范围
### 解决方案
```rust
// 使用 i32 避免中间结果溢出
let idx = (((iu + 1) * (iu + 1) - 3 * (iu + 1) + 4) / 2 - 1) as usize;
```
---
## 11. 数组变量命名冲突
### 问题
不同 Fortran 文件中同名变量冲突
### 原因
Fortran 文件局部作用域Rust 需要唯一名称
### 解决方案
修改 `extract_fortran_data.py`:所有变量添加文件名前缀
```rust
// 旧: ADI, BDENS (冲突)
// 新: DIELRC_ADI, DIELRC_BDENS
pub const DIELRC_ADI: [f64; 18] = [...];
```
---
## 12. 2D 数组存储顺序
### 问题
Fortran 列优先Rust 行优先
### 解决方案
脚本自动转置,访问方式改变
```rust
// Fortran: ARR(j, i) 列优先
// Rust: ARR[i][j] 行优先 (已转置)
```
---
## 13. DATA 语句数值解析
### 问题
负数和科学计数法中有空格
### 示例
```fortran
DATA A / - 14.2, 1.48 D-2 /
```
### 解决方案
```python
# 修复负数空格
val = re.sub(r'-\s+(\d)', r'-\1', val)
# 修复科学计数法空格
val = re.sub(r'(\d)\s+([eEdD])', r'\1\2', val)
```
---
## 14. BPOPF 测试失败 - 温度列与主循环列重叠
### 问题
BPOPF 函数测试中B[20][21] 的值是 -0.12 而不是预期的 -0.02。
### 原因
测试参数设置导致温度列 (NRE) 与主循环的某一列 (NSE+II) 重叠:
- 主循环更新列 NSE+1 到 NSE+NLVEXP (Fortran 1-indexed: 21-23)
- 温度列是 NRE (Fortran 1-indexed: 22)
- 当 II=2 时,列 NSE+II = 22 = NRE两者写入同一列
### 解决方案
测试参数设置时避免列重叠:
```rust
let params = BpopfParams {
nfreqe: 10,
inse: 11, // NSE = 10 + 11 - 1 = 20
inre: 0, // 不更新温度列,避免与主循环列重叠
inpc: 0, // 不更新电子密度列
// ...
};
```
### Fortran 索引转换注意事项
- `NSE = NFREQE + INSE - 1` (Fortran 起始列索引)
- `NRE = NFREQE + INRE` (温度列1-indexed)
- Rust 主循环: `col = nse + ii` (nse 已经是 0-indexed 起始点)
- Rust 温度列: `col = (nre - 1) as usize` (需要减 1 转换为 0-indexed)
### 调试技巧
1. 添加 `#[cfg(test)]` 条件编译的调试输出
2. 打印 ESEMAT 矩阵验证是否为单位矩阵
3. 打印每次 B 矩阵更新的行、列、值
4. 检查温度列和电子密度列是否与主循环列重叠
---
## 15. RAYLEIGH 氦散射截面公式错误
### 问题
Rayleigh 氦散射截面计算结果不正确。
### 原因
公式理解错误:
- 错误: `5.484e-14 / x2 * (...)` 其中 `x2 = 1/x²`
- 正确: `5.484e-14 / (x * x) * (...)`
### 解决方案
```rust
// 错误写法
let x2 = 1.0 / (x * x);
raysct.rche[ik] = 5.484e-14 / x2 * (...); // 这等于 5.484e-14 *
// 正确写法
raysct.rche[ik] = 5.484e-14 / (x * x) * (...); // 这等于 5.484e-14 / x²
```
---
## 16. ALIFR3 - 大型 COMMON 块函数重构策略
### 问题
ALIFR3 函数依赖大量 COMMON 块变量(来自 FIXALP, MODELQ, ALIPAR 等)。
### 解决方案
创建综合的输入结构体,使用生命周期参数引用数据:
```rust
/// 输入状态结构体 (使用生命周期引用数据)
pub struct Alifr3ModelState<'a> {
// 深度相关 (MDEPTH)
pub elec: &'a [f64],
pub densi: &'a [f64],
// ... 其他字段
// 输出累积变量 (可变引用)
pub heit: &'a mut [f64],
pub hein: &'a mut [f64],
// ... 其他字段
}
```
### 多分支条件处理
Fortran 使用 GOTO 分支Rust 使用 if-else
```fortran
IF(ILMCOR.NE.3) GO TO 199
! ... ILMCOR==3 的代码
199 IF(ILASCT.NE.0) GO TO 299
! ... ILASCT==0 的代码
299 ! ... ILASCT!=0 的代码
```
```rust
if params.ilmcor == 3 {
// ... ILMCOR==3 的代码
return;
}
if params.ilasct == 0 {
// ... ILASCT==0 的代码
return;
}
// ... ILASCT!=0 的代码
```
### 注意事项
- ABST 的计算方式在不同分支中不同:
- ILMCOR==3: `ABST = UN/ABSO1(ID)`
- ILASCT==0: `ABST = UN/(ABSO1(ID)-ELSCAT(ID))`
- ILASCT!=0: `ABST = UN/ABSO1(ID)`
- DSFN1 的计算在不同分支也有差异(是否包含 SIGEC 项)
---
## 17. ALIFR6 - COMMON 块结构体命名冲突
### 问题
添加新的 COMMON 块结构体时,编译器报错 `ambiguous glob re-exports: the name 'Comptn'`
### 原因
`Comptn` 结构体同时存在于:
- `src/state/config.rs` - Compton 散射角度参数(已有)
- `src/state/model.rs` - 新添加的重复定义
两个模块都通过 `pub use *` 重新导出,导致名称冲突。
### 解决方案
添加新结构体前,先搜索是否已存在:
```bash
grep -r "pub struct Comptn" src/state/
```
如果已存在,扩展现有结构体而不是创建新的。
---
## 18. ALIFR6 - 循环中可变变量重新赋值
### 问题
在循环中重新赋值 `s0p = s0p_new` 报错 `cannot assign twice to immutable variable`
### 原因
变量在 if-else 块中首次定义后,无法在循环中重新赋值。
### 解决方案
```rust
// 错误:不可变变量
let (s0p, dsft1p, dsfn1p) = if ... { ... };
// 正确:声明为可变
let (mut s0p, mut dsft1p, mut dsfn1p) = if ... { ... };
```
---
## 19. ALIFR6/ALIFR3 - 大型函数三段式处理模式
### 模式
ALIFR6 和 ALIFR3 类函数有三个独立处理部分:
1. **第一个深度点 (ID=1)**
- 特殊边界条件
- DSFT1M/DSFN1M 初始化为 0
2. **深度循环 (ID=2 到 ND-1)**
- 保存前一步值 (DSFTMM, DSFNMM)
- 更新当前值
- 计算下一步值 (DSFT1P, DSFN1P)
3. **最深点 (ID=ND)**
- IBC 下边界条件处理
- 可能的额外导数 (DSFT1D, DSFN1D)
### IBC 下边界条件
| IBC | 说明 |
|-----|------|
| 0 | 无特殊处理 |
| 1 | 简单 Planck 函数修正 |
| 2 | 改进边界条件 |
| 3 | 完整边界条件 + DSFT1D/DSFN1D |
---
## 20. ALIFR6 - 三对角 Lambda* 算子
### 特点
ALIFR6 与 ALIFR3 的主要区别是额外计算三对角算子:
- **下对角线**: AREIT, AREIN, AREIP (使用 ALIM1)
- **上对角线**: CREIT, CREIN, CREIP (使用 ALIP1)
- **对角线**: REIT, REIN, REIP (使用 ALI1)
### IFALI >= 7 额外计算
- HEITP, HEINP, HEIPP (He 相关)
- REDTP, REDNP, REDPP (Red 相关)
- EHET, EHEN, EHEP (Ehe 相关)
- ERET, EREN, EREP (Ere 相关)
---
## 快速检查清单
重构新函数前检查:
- [ ] 是否有 INCLUDE 语句 (除 IMPLIC.FOR 外)
- [ ] 是否使用 COMMON 块
- [ ] COMMON 块结构体是否已存在于其他模块 (grep 检查)
- [ ] 是否有文件 I/O (OPEN, READ, WRITE)
- [ ] 数组索引是否需要 -1 调整
- [ ] 循环变量是否可能变负 (用 isize/i32)
- [ ] 多项式近似精度是否需要放宽
- [ ] 是否有嵌套 IF 分支遗漏
- [ ] 矩阵列索引是否可能与温度/密度列重叠
- [ ] 公式中 `1/x``x` 的顺序是否正确
- [ ] 大型 COMMON 块函数是否需要创建综合输入结构体
- [ ] 多分支 GOTO 是否正确转换为 if-else
- [ ] 循环中重新赋值的变量是否声明为 mut
- [ ] 变量字段在哪个 COMMON 块 → 对应哪个 Rust 结构体 (查 `.FOR` 原文)
- [ ] 测试初始化用 `ModelState::new()` 而非 `::default()`
- [ ] 二维数组内层维度是否是深度/角度/频率 (不要默认 MDEPTH)
- [ ] loop 内部积分变量是否在 loop 外声明以便 break 后使用
---
## 21. COMMON 块变量所属结构体查找
### 问题
Fortran COMMON 块变量(如 `IDISK`、`IBC`、`ICHCOO`、`IJORIG`)应放在哪个 Rust 结构体中?
### 解决方案
通过查阅 `.FOR` 中的 COMMON 定义来确认:
- `IDISK`、`IBC` → `BASICS.FOR``COMMON/BASNUM/``config.basnum`
- `ICHCOO`、`ICOMST`、`ICOMDE` → `BASICS.FOR``common/compti/``config.compti`
- `IJORIG``BASICS.FOR``common/comptn/``config.comptn.ijorig`
- `IWINBL``MODELQ.FOR``COMMON/WINDBL/``model.windbl.iwinbl`
- `IFZ0``BASICS.FOR``COMMON/CENTRL/``config.centrl.ifz0`
```bash
# 快速查找变量所在 COMMON 块
grep -i "变量名" tlusty/extracted/*.FOR
```
### 教训
编译报错 `no field 'xxx' on type 'Accel'` 时,不要盲目添加字段——先查原始 `.FOR` 确认 COMMON 归属。
---
## 22. 循环外变量对 break 后可见
### 问题
`ah`、`qq0`、`u0` 在 ALI 循环内定义,循环 `break` 后用于写回结果时编译报 `cannot find value`
### 原因
Rust 变量作用域严格,`loop {}` 块内 `let` 声明的变量在块外不可见。
### 解决方案
```rust
// 正确:循环前提前声明,循环内用 _inner 临时变量
let mut ah = 0.0f64;
let mut qq0 = 0.0f64;
loop {
let mut ah_inner = 0.0f64;
let mut qq0_inner = 0.0f64;
// 积分计算...
if converged {
ah = ah_inner; // break 前赋值回外部变量
qq0 = qq0_inner;
break;
}
}
model.surfac.flux[ij] = ah; // 此处可用
```
### 常见错误(变量被遮蔽)
```rust
let mut ah = 0.0f64;
loop {
let mut ah = 0.0; // ← 遮蔽外层 ah外层永远是 0
if converged { break; }
}
// ah 还是 0
```
---
## 23. 测试初始化:`ModelState::new()` vs `::default()`
### 问题
测试报错 `index out of bounds: the len is 0 but the index is 0`,即便访问 `model.totrad.rad[0][0]`
### 原因
`ModelState``#[derive(Default)]`,但 `CurRad` 等子结构体**只有 `new()` 方法,没有手动 `Default` 实现**。
`derive(Default)``Vec` 产生空 Vec访问任意元素都越界。
### 解决方案
```rust
// ❌ 错误CurRad::default() 产生空 Vec
let mut model = ModelState::default();
// ✅ 正确ModelState::new() 调用 CurRad::new(),正确分配数组
let mut model = ModelState::new();
```
---
## 24. `extint` 索引:内层是角度维度
### 问题
`model.totrad.extint[ij][i]``for i in 0..MDEPTH` 循环中越界len=6, index=6
### 原因
`extint` 对应 Fortran `EXTINT(MFREQ, MMU)`
- 外层频率索引MFREQ
- **内层角度索引MMU = 6不是深度**
### 解决方案
```rust
// 正确:遍历角度 (MMU=6)
use crate::state::constants::MMU;
for i in 0..MMU {
model.totrad.extint[0][i] = 0.0;
}
```
---
## 25. 常用二维数组维度汇总
| 变量 | 外层维度 | 内层维度 |
|------|---------|---------|
| `totrad.rad[ij][id]` | 频率 MFREQ | 深度 MDEPTH |
| `totrad.extint[ij][i]` | 频率 MFREQ | **角度 MMU** |
| `totrad.fak[ij][id]` | 频率 MFREQ | 深度 MDEPTH |
| `comptf.delj[iji][id]` | 频率 MFREQ | 深度 MDEPTH |
| `expraf.radex[ije][id]` | 显式频率 MFREX | 深度 MDEPTH |
| `angles.amu[i]` / `wtmu[i]` | 角度 MMU | — |
### 教训
看到二维数组前,确认两个维度各是什么,不要默认都是 MDEPTH。
---
## 26. 2026-03-21 新增模块完整性检查
### SETDRT (密度对温度的导数)
- **状态**: ✅ 完整
- 原版 Fortran 调用 RHOEOS 函数
- Rust 版使用泛型函数参数 `rhoeos_fn`,设计更灵活
- 有限差分计算完全一致
### TAUFR1 (光学深度计算)
- **状态**: ✅ 完整
- `ss0` 数组在原版中也计算但未使用,与 Fortran 一致
- `XCON` 常量在原版定义但未使用,已忽略
- 核心逻辑光学深度计算、参考深度插值、Planck 函数计算
### TABINT (频率表插值)
- **状态**: ⚠️ 部分实现
- **问题**: `interpolate_opacity` 函数中未实际修改 `absopac` 数组
- 代码中有注释 "暂时跳过实际修改"
- 二分查找和插值系数计算完整
**待修复**:
```rust
// 当前代码 (错误):
let opac = rc * (params.freq[ij] / frtab[j - 1]).log10() + absort[j - 1];
let _ = opac; // 计算了但没有写回
// 应该:
// 需要设计一个可变引用来修改 absopac
```
### RYBMAT (Rybicki矩阵)
- **状态**: ⚠️ 简化实现
- 原版 ~390 行 → Rust 375 行
- **问题**: 测试失败 `result.rb[0].is_finite()` 返回 NaN
**可能原因**:
1. 边界条件 `id=0``dm[id+1] - dm[id]` 可能为零
2. `abso1` 数组可能包含零值导致除零
3. Hermitian 方法 (`isplin=2`) 被简化
**待修复**:
```rust
// 需要添加边界检查
let ddm = (params.dm[id + 1] - params.dm[id]) * HALF;
if ddm.abs() < 1e-30 {
continue; // 跳过无效深度点
}
let dtm = UN / ((params.abso1[id] + params.abso1[id + 1]) * ddm);
```
---
## 27. 优先级列表注意事项
优先级列表 (`python3 scripts/analyze_fortran.py --priority`) 显示"传递未实现=0"的函数可能有隐藏依赖:
- **SETDRT** 调用 RHOEOS标记为 pending但通过函数参数传入解决了
- **TABINT** 无外部调用,真正独立
- **TAUFR1** 无外部调用,真正独立
- **RYBMAT** 无外部调用,但依赖大量 COMMON 块变量
**教训**: 优先级列表只检查显式的 SUBROUTINE/FUNCTION 调用,不检查:
1. COMMON 块依赖
2. 通过参数传入的函数指针
3. 隐式的外部函数引用

View File

@ -1,283 +0,0 @@
# 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行最简单)
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 不在调用依赖中

View File

@ -1,403 +0,0 @@
---
## TLUSTY208.F 拆分工作 (2026-03-18)
### 任务:将单文件拆分为多个独立模块
**执行流程:**
```bash
cd /home/fmq/program/tlusty/tl208-s54/rust
python3 extract_fortran.py tlusty/tlusty208.f tlusty/extracted/
cp tlusty/*.FOR tlusty/extracted/
```
### 提取结果
| 项目 | 数量 |
|------|------|
| 程序单元 | **304** |
| 子程序 (SUBROUTINE) | 269 |
| 函数 (FUNCTION) | 32 |
| 主程序 (PROGRAM) | 1 |
| BLOCK DATA | **2** (含1个无名) |
| 无 COMMON 依赖的纯函数 | 195 |
> 注意: 2026-03-19 修复了无名 BLOCK DATA 提取问题,单元数从 303 增加到 304
### Include 文件
```
tlusty/extracted/*.FOR
├── IMPLIC.FOR # 隐式类型声明
├── BASICS.FOR # 基本参数和物理常数
├── ITERAT.FOR # 迭代控制参数
├── ALIPAR.FOR # ALI 参数
├── ATOMIC.FOR # 原子数据
├── MODELQ.FOR # 模型物理量
├── ODFPAR.FOR # ODF 参数
└── ARRAY1.FOR # 主工作数组
```
### 编译配置
**关键编译选项**:
```makefile
FFLAGS = -O3 -fno-automatic -mcmodel=large
```
- `-mcmodel=large`: 支持 >2GB 地址空间
- `-fno-automatic`: 所有变量默认为静态存储兼容旧Fortran代码
- **不要使用** `-ffixed-line-length-none`: 会将第73-80列的注释区当作代码解析
### 编译验证
```bash
cd tlusty/extracted && make clean && make
# 生成: tlusty_extracted (1,940,488 bytes)
# 直接编译
gfortran -fno-automatic -mcmodel=large -O3 -o tlusty.exe tlusty208.f
# 生成: tlusty.exe (1,997,416 bytes)
```
**结论**: 功能等价,拆分编译文件更小 (-2.9%)
### 拆分编译 vs 直接编译对比
| 方面 | 直接编译 | 拆分编译 |
|------|---------|---------|
| 文件大小 | 1,997,416 B | 1,940,488 B |
| 功能 | 相同 | 相同 |
| 增量编译 | ❌ | ✅ |
| 代码定位 | 困难 | 简单 |
### 无 COMMON 依赖的纯函数 (198个)
可独立测试和重构的单元:
```
ACCEL2, ALIFR1, ALIFR3, ALIFR6, ALIFRK, ALISK1, ALISK2, ALIST1, ALIST2,
ANGSET, BETAH, BHE, BKHSGO, BPOP, BPOPE, BPOPF, BPOPT, BRE, BREZ,
BRTE, BRTEZ, BUTLER, CARBON, CEH12, CHANGE, CHCKSE, CHEAV, CHEAVJ,
CIA_H2H, CIA_H2H2, CIA_H2HE, CIA_HHE, CION, CKOEST, COLH, COLHE,
COLLHE, CONCOR, CORRWM, CROSS, CROSSD, CSPEC, DIELRC, DIETOT, DIVSTR,
DMEVAL, DOPGAM, DWNFR, DWNFR0, DWNFR1, EINT, EMAT, ENTENE, ERFCIN,
ERFCX, EXPINT, EXPINX, EXPO, FFCROS, GAMI, GAMSP, GAULEG, GAUNT,
GETWRD, GFREE0, GFREE1, GFREED, GNTK, GRCOR, GREYD, GRIDP, H2MINUS,
HEPHOT, HIDALG, IJALI2, IJALIS, INCLDY, INDEXX, INIFRS, INILAM, INTERP,
INTHYD, INTLEM, INTXEN, IRC, LAGRAN, LAGUER, LEMINI, LEVGRP, LEVSET,
LEVSOL, LINEQS, LINSEL, LINSET, LINSPL, LOCATE, LTEGR, LUCY, LYMLIN,
MATGEN, MATINV, MEANOP, MEANOPT, MINV3, NEWPOP, NSTOUT, ODF1, ODFFR,
ODFHST, ODFHYD, ODFHYS, ODFMER, OPACFL, OPADD0, OPAHST, OPAINI, OPCTAB,
OSCCOR, OUTPUT, PFCNO, PFFE, PFHEAV, PFNI, PFSPEC, PRCHAN, PRD, PRDINI,
PRINC, PRNT, PROFSP, PSOLVE, PZERT, QUARTC, QUIT, RADPRE, RAPH, RATES1,
RATMAL, RATMAT, RATSP1, RAYINI, RAYSET, RDATAX, READBF, RECHCK, REFLEV,
REIMAN, RHOEOS, RHONEN, ROSSOP, ROSSTD, RTEDF2, RTEFE2, RTESOL, RTE_SC,
SABOLF, SBFCH, SBFHE1, SBFHMI, SBFHMI_OLD, SBFOH, SFFHMI, SFFHMI_ADD,
SGHE12, SGMER0, SGMER1, SGMERD, SIGAVE, SIGK, SIGMAR, SPSIGK, SRTFRQ,
STARK0, STARKA, SWITCH, SZIRC, TDPINI, TIMING, TIOPF, TLUSTY, TRAINI,
TRIDAG, UBETA, VERN16, VERN18, VERN20, VERN26, VERNER, VISINI, VOIGT,
VOIGTE, WN, WNSTOR, XENINI, XK2DOP, YINT, YLINTP, ZMRHO
```
---
## SYNSPEC54.F 拆分工作 (2026-03-18)
### 任务:将单文件拆分为多个独立模块
**执行流程:**
#### 1. 创建提取脚本 `extract_fortran.py`
```python
# 核心功能:
# - 正则匹配 SUBROUTINE/FUNCTION/PROGRAM/BLOCK DATA
# - 查找对应的 END 语句确定边界
# - 提取到独立 .f 文件
# - 分析 COMMON 块依赖
# - 生成 Makefile
```
#### 2. 运行提取
```bash
cd /home/fmq/program/tlusty/tl208-s54/rust
python3 extract_fortran.py synspec/synspec54.f synspec/extracted/
cp synspec/*.FOR synspec/extracted/
```
#### 3. 提取结果
| 项目 | 数量 |
|------|------|
| 程序单元 | 168 |
| 子程序 (SUBROUTINE) | 134 |
| 函数 (FUNCTION) | 33 |
| 主程序 (PROGRAM) | 1 |
| 总代码行数 | 23,050 |
| 无 COMMON 依赖的纯函数 | 93 |
#### 4. 编译配置
**关键编译选项** (解决大型 COMMON 数组链接问题):
```makefile
FFLAGS = -O3 -fno-automatic -mcmodel=large
```
- `-mcmodel=large`: 支持 >2GB 地址空间
- `-fno-automatic`: 所有变量默认为静态存储兼容旧Fortran代码
- **不要使用** `-ffixed-line-length-none`: 会将第73-80列的注释区当作代码解析
#### 5. 编译验证
```bash
cd synspec/extracted && make clean && make
# 生成: synspec_extracted (1,000,408 bytes)
```
**对比原始编译:**
```bash
gfortran -O3 -fno-automatic -mcmodel=large -o synspec_direct.exe synspec54.f
# 生成: synspec_direct.exe (1,044,928 bytes)
```
**结论**: 功能完全等价,拆分编译更小 (-4.3%)
### 生成的文件结构
```
synspec/extracted/
├── synspec.f # 主程序 (174行)
├── start.f # 子程序 (107行)
├── sbfhmi.f # H⁻ 光电离截面函数 (42行)
├── expint.f # 指数积分函数 (18行)
├── ... # 共168个 .f 文件
├── PARAMS.FOR # 参数定义 (include)
├── MODELP.FOR # 模型参数 (include)
├── LINDAT.FOR # 谱线数据 (include)
├── SYNTHP.FOR # 合成谱参数 (include)
├── WINCOM.FOR # 窗口通信 (include)
├── Makefile # 自动构建
├── _SUMMARY.txt # 提取摘要
├── _COMMON_ANALYSIS.txt # COMMON 依赖分析
└── _PURE_UNITS.txt # 纯函数列表
```
### COMMON 块分析结果
**有 COMMON 依赖的单元**: 75 个
**唯一 COMMON 块**: 68 个
主要 COMMON 块:
- `BLAPAR`, `LIMPAR` - 谱线参数
- `EMFLUX` - 辐射流
- `RTEOPA` - 辐射转移不透明度
- `NLTPOP` - 非LTE布居数
- `lasers` - 激光数据处理
### 拆分编译 vs 直接编译对比
| 方面 | 直接编译 | 拆分编译 |
|------|---------|---------|
| 文件大小 | 1,044,928 B | 1,000,408 B |
| 功能 | 相同 | 相同 |
| 增量编译 | ❌ | ✅ |
| 代码定位 | 困难 | 简单 |
| 模块化重构 | 困难 | 容易 |
### 提取脚本位置
```
extract_fortran.py
```
### 推荐用法
```bash
# 开发/调试/重构
cd synspec/extracted && make
# 生产环境/快速编译
cd synspec && gfortran -O3 -fno-automatic -mcmodel=large -o synspec.exe synspec54.f
```
### 无 COMMON 依赖的纯函数 (93个)
可独立测试和重构的函数:
```
CARBON, CHANGE, CHCKAB, CIA_H2H, CIA_H2H2, CIA_H2HE, CIA_HHE,
COUNT_WORDS, DENSIT, DIVHE2, DIVSTR, DWNFR0, DWNFR1, EPS,
EXOPF, EXPINT, EXTPRF, FEAUTR, GAMHE, GAUNT, GETWRD, GFREE,
GNTK, GRIEM, H2MINUS, H2OPF, HE2SET, HE2SEW, HEPHOT, HESET,
HIDALG, HYDINI, HYDTAB, HYLSET, HYLSEW, INIBLM, INKUR, INPBF,
INTERP, INTHYD, INTRP, INTXEN, IRWPF, ISPEC, LEVSOL, LINEQS,
LOCATE, LYMLIN, MATINV, MOLOP, MPARTF, OPADD, PARTDV, PARTF,
PFFE, PFHEAV, PFNI, PFSPEC, PHTX, QUIT, RATMAT, READBF,
REIMAN, SABOLF, SBFCH, SBFHE1, SBFHMI, SBFHMI_OLD, SBFOH,
SETRAY, SFFHMI, SFFHMI_OLD, SGHE12, SGMERG, SPSIGK, STARK0,
STARKA, STARKIR, STATE0, SYNSPEC, TINT, TRIDAG, VELSET,
VOIGTE, VOPF, WGTJH1, WN, WNSTOR, WTOT, XENINI, XK2DOP, YINT, YLINTP
```
---
## 功能验证测试 (2026-03-19)
### 测试环境变量
```bash
export TL208=/home/fmq/program/tlusty
export TLUSTY=$TL208/tl208-s54
export LINELIST=$TL208/linelist
export IRON=$TL208/irondata
export OPTABLES=$TL208/optables
```
### 测试目录
```
tests/tlusty/hhe/ # H-He 模型测试用例
├── hhe35lt.5 # LTE 模型输入
├── hhe35nc.5 # NLTE continua 模型输入
├── hhe35nl.5 # NLTE with lines 模型输入
└── hhe35*.7,9,14 # 预期输出文件
```
### 测试流程
```bash
cd /home/fmq/program/tlusty/tl208-s54/rust/tests/tlusty
# 创建测试目录
mkdir -p test_extracted
cd test_extracted
cp ../hhe/*.5 .
ln -sf $TLUSTY/data data
# 设置环境变量
export TL208=/home/fmq/program/tlusty
export TLUSTY=$TL208/tl208-s54
export LINELIST=$TL208/linelist
export IRON=$TL208/irondata
export OPTABLES=$TL208/optables
# 可执行文件路径
EXE=../../tlusty/extracted/build/tlusty_extracted
# 测试1: LTE 模型 (从零开始)
$EXE < hhe35lt.5 > hhe35lt.6
cp fort.7 hhe35lt.7; cp fort.9 hhe35lt.9; cp fort.14 hhe35lt.14
# 测试2: NLTE continua (使用 LTE 作为初始模型)
cp hhe35lt.7 fort.8
$EXE < hhe35nc.5 > hhe35nc.6
cp fort.7 hhe35nc.7; cp fort.9 hhe35nc.9; cp fort.14 hhe35nc.14
# 测试3: NLTE with lines (使用 NC 作为初始模型)
cp hhe35nc.7 fort.8
$EXE < hhe35nl.5 > hhe35nl.6
cp fort.7 hhe35nl.7; cp fort.9 hhe35nl.9; cp fort.14 hhe35nl.14
# 验证: 与原始结果比较
diff hhe35lt.7 ../hhe/hhe35lt.7
diff hhe35nc.7 ../hhe/hhe35nc.7
diff hhe35nl.7 ../hhe/hhe35nl.7
```
### 测试结果
| 测试用例 | 拆分编译 | 直接编译 | 原始结果 |
|----------|----------|----------|----------|
| hhe35lt (LTE) | ✓ 通过 | ✓ 通过 | ✓ 相同 |
| hhe35nc (NLTE continua) | ✓ 通过 | ✓ 通过 | ✓ 相同 |
| hhe35nl (NLTE lines) | ✓ 通过 | ✓ 通过 | ✓ 相同 |
**MD5 校验和 (hhe35nl.7)**:
```
01f3169947ca24bf1c989619b83ae8f2
```
**结论**: 拆分编译与直接编译输出完全相同,功能验证通过
---
## SYNSPEC54 功能验证测试 (2026-03-19)
### 测试目录
```
tests/synspec/hhe/
├── hhe35nl.5 # 输入文件
├── hhe35nl.7 # 模型大气 (来自 TLUSTY 测试)
├── fort.55.con # 附加输入文件
├── data # 数据目录路径文件 (内容: $TLUSTY/data)
└── results/ # 预期输出
├── hhe35nl.spec # 合成光谱
├── hhe35nl.cont # 连续谱
└── hhe35nl.iden # 谱线标识
```
### 测试流程
```bash
cd /home/fmq/program/tlusty/tl208-s54/rust/tests/synspec/hhe
# 设置环境变量
export TL208=/home/fmq/program/tlusty
export TLUSTY=$TL208/tl208-s54
export LINELIST=$TL208/linelist
export IRON=$TL208/irondata
export OPTABLES=$TL208/optables
# 准备输入文件
cp hhe35nl.7 fort.8
ln -sf fort.55.con fort.55
ln -sf $TLUSTY/data/gfATO.dat fort.19
# 关键: data 必须是符号链接指向数据目录
rm -f data
ln -sf $TLUSTY/data data
# 可执行文件路径
EXE_ORIG=$TLUSTY/synspec/synspec.exe
EXE_DIRECT=../../synspec/synspec_direct.exe
EXE_EXTRACTED=../../synspec/extracted/build/synspec_extracted
# 测试原始版本
$EXE_ORIG < hhe35nl.5 > hhe35nl_orig.log
cp fort.7 hhe35nl_orig.spec; cp fort.17 hhe35nl_orig.cont
# 测试直接编译版本
rm -f fort.7 fort.17 fort.12
$EXE_DIRECT < hhe35nl.5 > hhe35nl_direct.log
cp fort.7 hhe35nl_direct.spec; cp fort.17 hhe35nl_direct.cont
# 测试拆分编译版本
rm -f fort.7 fort.17 fort.12
$EXE_EXTRACTED < hhe35nl.5 > hhe35nl_extracted.log
cp fort.7 hhe35nl_extracted.spec; cp fort.17 hhe35nl_extracted.cont
# 验证
diff hhe35nl_orig.spec hhe35nl_direct.spec
diff hhe35nl_orig.spec hhe35nl_extracted.spec
# 恢复 data 文件
rm -f data
echo "/home/fmq/program/tlusty/tl208-s54/data" > data
```
### 测试结果
| 测试用例 | 原始程序 | 直接编译 | 拆分编译 |
|----------|----------|----------|----------|
| hhe35nl (NLTE lines) | ✓ 通过 | ✓ 通过 | ✓ 相同 |
**MD5 校验和 (hhe35nl.spec)**:
```
7925533b21b16d6bcdfff40e626cab83
```
**注意事项**:
- `data` 文件/符号链接必须正确设置,否则报错 `Cannot open file './data/h1.dat': Not a directory`
- 拆分编译程序与原始程序输出完全相同,功能验证通过

View File

@ -1,302 +0,0 @@
#!/usr/bin/env python3
"""
提取 synspec54.f 中的各个子程序/函数到独立文件
"""
import re
import os
import sys
from pathlib import Path
def extract_units(source_file, output_dir):
"""提取 Fortran 程序单元到独立文件"""
with open(source_file, 'r') as f:
content = f.read()
lines = content.split('\n')
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 匹配程序单元开始的正则表达式
# 注意: BLOCK DATA 和 PROGRAM 可以是无名的
# 使用 \s* 允许名称前没有空格(无名情况)
unit_pattern = re.compile(
r'^\s*('
r'SUBROUTINE\s+(\w+)|'
r'FUNCTION\s+(\w+)|'
r'PROGRAM\s*(\w*)|'
r'BLOCK\s+DATA\s*(\w*)'
r')',
re.IGNORECASE
)
# 找到所有单元的起始位置
units = []
for i, line in enumerate(lines):
match = unit_pattern.match(line)
if match:
groups = match.groups()
# groups: (整体匹配, SUBROUTINE名, FUNCTION名, PROGRAM名, BLOCK DATA名)
if groups[1]: # SUBROUTINE
name, unit_type = groups[1], 'SUBROUTINE'
elif groups[2]: # FUNCTION
name, unit_type = groups[2], 'FUNCTION'
elif groups[3]: # PROGRAM (非空)
name, unit_type = groups[3], 'PROGRAM'
elif groups[3] is not None: # PROGRAM (空字符串,无名)
name, unit_type = None, 'PROGRAM'
elif groups[4]: # BLOCK DATA (非空)
name, unit_type = groups[4], 'BLOCK DATA'
elif groups[4] is not None: # BLOCK DATA (空字符串,无名)
name, unit_type = None, 'BLOCK DATA'
else:
name, unit_type = None, 'UNKNOWN'
# 处理无名单元
if not name:
name = f"_UNNAMED_{unit_type.replace(' ', '_')}_"
units.append((i, name.upper(), unit_type))
print(f"找到 {len(units)} 个程序单元")
# 提取每个单元
extracted = []
for idx, (start_line, name, unit_type) in enumerate(units):
# 确定结束位置
if idx + 1 < len(units):
end_line = units[idx + 1][0]
else:
end_line = len(lines)
# 提取单元内容
unit_lines = lines[start_line:end_line]
# 查找实际的 END 语句
actual_end = end_line
for i in range(len(unit_lines) - 1, -1, -1):
if re.match(r'^\s*END\s*$', unit_lines[i], re.IGNORECASE):
actual_end = start_line + i + 1
break
unit_content = '\n'.join(lines[start_line:actual_end])
# 写入文件
filename = f"{name.lower()}.f"
filepath = os.path.join(output_dir, filename)
with open(filepath, 'w') as f:
f.write(unit_content)
if not unit_content.endswith('\n'):
f.write('\n')
extracted.append({
'name': name,
'type': unit_type,
'file': filename,
'start': start_line + 1,
'end': actual_end,
'lines': actual_end - start_line
})
print(f" 提取: {name} ({unit_type}) -> {filename} ({actual_end - start_line} 行)")
# 生成摘要文件
summary_path = os.path.join(output_dir, '_SUMMARY.txt')
with open(summary_path, 'w') as f:
f.write(f"SYNSPEC54.F 提取摘要\n")
f.write(f"{'='*60}\n\n")
f.write(f"源文件: {source_file}\n")
f.write(f"总单元数: {len(extracted)}\n")
f.write(f"总行数: {len(lines)}\n\n")
f.write(f"{'名称':<20} {'类型':<12} {'文件':<20} {'行数':>8}\n")
f.write(f"{'-'*60}\n")
for unit in extracted:
f.write(f"{unit['name']:<20} {unit['type']:<12} {unit['file']:<20} {unit['lines']:>8}\n")
# 按类型统计
types = {}
for unit in extracted:
types[unit['type']] = types.get(unit['type'], 0) + 1
f.write(f"\n按类型统计:\n")
for t, c in types.items():
f.write(f" {t}: {c}\n")
print(f"\n摘要已保存到: {summary_path}")
return extracted
def analyze_commons(output_dir):
"""分析 COMMON 块依赖"""
# 命名COMMON块: COMMON /NAME/ ...
named_common_pattern = re.compile(r'COMMON\s*/\s*(\w+)\s*/', re.IGNORECASE)
# 空白COMMON块: COMMON varname (不带斜杠)
blank_common_pattern = re.compile(r'^\s*COMMON\s+[A-Z]', re.IGNORECASE | re.MULTILINE)
include_pattern = re.compile(r'INCLUDE\s*[\'"]([^\'"]+)[\'"]', re.IGNORECASE)
commons = {}
includes = {}
for filepath in Path(output_dir).glob('*.f'):
if filepath.name.startswith('_'):
continue
with open(filepath, 'r') as f:
content = f.read()
unit_name = filepath.stem.upper()
found_commons = named_common_pattern.findall(content)
found_includes = include_pattern.findall(content)
# 检查空白COMMON块
if blank_common_pattern.search(content):
found_commons.append('BLANK') # 添加空白COMMON块标识
if found_commons:
commons[unit_name] = list(set(found_commons))
if found_includes:
includes[unit_name] = list(set(found_includes))
# 写入 COMMON 分析
common_path = os.path.join(output_dir, '_COMMON_ANALYSIS.txt')
with open(common_path, 'w') as f:
f.write("COMMON 块依赖分析\n")
f.write(f"{'='*60}\n\n")
f.write("有 COMMON 依赖的单元:\n")
f.write(f"{'-'*60}\n")
for unit, common_list in sorted(commons.items()):
f.write(f"{unit}: {', '.join(common_list)}\n")
f.write(f"\n{len(commons)} 个单元有 COMMON 依赖\n")
f.write(f"{len([u for u in commons.values()])} 个 COMMON 块被引用\n")
# 找出所有唯一的 COMMON 块
all_commons = set()
for c in commons.values():
all_commons.update(c)
f.write(f"\n唯一的 COMMON 块: {sorted(all_commons)}\n")
f.write(f"\n\nINCLUDE 文件依赖:\n")
f.write(f"{'-'*60}\n")
for unit, inc_list in sorted(includes.items()):
f.write(f"{unit}: {', '.join(inc_list)}\n")
print(f"COMMON 分析已保存到: {common_path}")
# 返回无 COMMON 依赖的纯函数
pure_units = []
for filepath in Path(output_dir).glob('*.f'):
if filepath.name.startswith('_'):
continue
unit_name = filepath.stem.upper()
if unit_name not in commons:
pure_units.append(unit_name)
return pure_units, commons, includes
def generate_makefile(output_dir, extracted, source_file):
"""生成 Makefile 用于编译所有提取的文件"""
# 根据源文件名确定程序名称
source_name = os.path.basename(source_file).lower()
if 'tlusty' in source_name:
prog_name = 'tlusty'
elif 'synspec' in source_name:
prog_name = 'synspec'
else:
prog_name = os.path.splitext(os.path.basename(source_file))[0].lower()
makefile_path = os.path.join(output_dir, 'Makefile')
with open(makefile_path, 'w') as f:
f.write(f"# Makefile for {prog_name.upper()} extracted modules\n")
f.write("# 使用大内存模型支持大型 COMMON 数组\n\n")
f.write("FC = gfortran\n")
f.write("FFLAGS = -O3 -fno-automatic -mcmodel=large\n\n")
f.write("# 编译输出目录\n")
f.write("BUILD_DIR = build\n\n")
f.write("# 目标可执行文件\n")
f.write(f"MAIN = $(BUILD_DIR)/{prog_name}_extracted\n\n")
f.write("# 所有 .f 源文件\n")
f.write("SRCS = $(wildcard *.f)\n\n")
f.write("# 目标文件放在build目录\n")
f.write("OBJS = $(patsubst %.f,$(BUILD_DIR)/%.o,$(notdir $(SRCS)))\n\n")
f.write("# 默认目标\n")
f.write("all: $(BUILD_DIR) $(MAIN)\n")
f.write("\t@echo \"==========================================\"\n")
f.write("\t@echo \"编译成功: $(MAIN)\"\n")
f.write("\t@echo \"==========================================\"\n\n")
f.write("# 创建build目录\n")
f.write("$(BUILD_DIR):\n")
f.write("\tmkdir -p $(BUILD_DIR)\n\n")
f.write("# 链接所有目标文件\n")
f.write("$(MAIN): $(OBJS)\n")
f.write("\t$(FC) $(FFLAGS) -o $@ $(OBJS)\n\n")
f.write("# 编译规则\n")
f.write("$(BUILD_DIR)/%.o: %.f | $(BUILD_DIR)\n")
f.write("\t$(FC) $(FFLAGS) -c $< -o $@\n\n")
f.write("# 清理\n")
f.write("clean:\n")
f.write("\trm -rf $(BUILD_DIR)\n\n")
f.write("# 只编译不链接(检查语法)\n")
f.write("compile-only: $(OBJS)\n")
f.write("\t@echo \"所有文件编译完成(未链接)\"\n\n")
f.write("# 统计信息\n")
f.write("stats:\n")
f.write("\t@echo \"=== 编译统计 ===\"\n")
f.write("\t@echo \"源文件数: $(words $(SRCS))\"\n")
f.write("\t@echo \"目标文件数: $(words $(OBJS))\"\n")
f.write("\t@wc -l *.f | tail -1\n\n")
f.write(".PHONY: all clean compile-only stats\n")
print(f"Makefile 已生成: {makefile_path}")
def main():
if len(sys.argv) < 2:
source_file = "/home/fmq/program/tlusty/tl208-s54/rust/synspec/synspec54.f"
output_dir = "/home/fmq/program/tlusty/tl208-s54/rust/synspec/extracted"
else:
source_file = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else "extracted"
print(f"源文件: {source_file}")
print(f"输出目录: {output_dir}\n")
# 提取单元
extracted = extract_units(source_file, output_dir)
# 分析 COMMON 依赖
print("\n分析 COMMON 依赖...")
pure_units, commons, includes = analyze_commons(output_dir)
print(f"\n无 COMMON 依赖的纯函数/子程序: {len(pure_units)}")
for u in sorted(pure_units):
print(f" {u}")
# 生成 Makefile
generate_makefile(output_dir, extracted, source_file)
# 保存纯函数列表
pure_path = os.path.join(output_dir, '_PURE_UNITS.txt')
with open(pure_path, 'w') as f:
f.write("无 COMMON 依赖的纯函数/子程序\n")
f.write(f"{'='*40}\n\n")
for u in sorted(pure_units):
f.write(f"{u}\n")
print(f"\n纯函数列表已保存到: {pure_path}")
if __name__ == '__main__':
main()

View File

@ -1,305 +0,0 @@
fortran_file,unit_name,unit_type,is_pure,common_deps,call_deps,has_io,rust_module,status
_unnamed_block_data_.f,C,BLOCK DATA,False,"BASICS|ATOMIC","",False,,pending
accel2.f,ACCEL2,SUBROUTINE,False,"BASICS|ITERAT|MODELQ","",True,,pending
accelp.f,ACCELP,SUBROUTINE,False,"BASICS|MODELQ|ITERAT|POPULS","",True,,pending
alifr1.f,ALIFR1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","ALIFR3",False,,pending
alifr3.f,ALIFR3,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifr3.rs,done
alifr6.f,ALIFR6,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifr6.rs,done
alifrk.f,ALIFRK,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","",False,src/math/alifrk.rs,done
alisk1.f,ALISK1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","ALIFRK|ROSSTD|OPACF1|RTEFR1",True,,pending
alisk2.f,ALISK2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","ALIFRK|ROSSTD|OPACF1|RTEFR1",True,,pending
alist1.f,ALIST1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT","OPACFD|ALIFR1|ROSSTD|RTEFR1",True,,pending
alist2.f,ALIST2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","RTEFR1|ROSSTD|ALIFR1|QUIT|OPACFD",True,,pending
allard.f,ALLARD,SUBROUTINE,False,"BASICS|calphatd|callarda|callardc|callardg|callardb|quasun","ALLARDT",True,,pending
allardt.f,ALLARDT,SUBROUTINE,False,"BASICS|calphatd","",False,src/math/allardt.rs,done
angset.f,ANGSET,SUBROUTINE,True,"BASICS","GAULEG",False,src/math/angset.rs,done
betah.f,BETAH,FUNCTION,True,"","BETAH",False,src/math/betah.rs,done
bhe.f,BHE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","",False,src/math/bhe.rs,done
bhed.f,BHED,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CMATZD|SURFEX","",False,src/math/bhe.rs,done
bhez.f,BHEZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|SURFEX","",False,src/math/bhe.rs,done
bkhsgo.f,BKHSGO,SUBROUTINE,True,"","",False,src/math/bkhsgo.rs,done
bpop.f,BPOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ITERAT","MATINV|BPOPT|BPOPF|LEVSOL|RATMAT|BPOPC|BPOPE|LEVGRP",False,,pending
bpopc.f,BPOPC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ADCHAR","STATE",False,,pending
bpope.f,BPOPE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|ARRAY1","SGMER1|DWNFR1",False,,pending
bpopf.f,BPOPF,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR","",False,src/math/bpopf.rs,done
bpopt.f,BPOPT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR","COLIS",False,,pending
bre.f,BRE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","COMPT0",False,,pending
brez.f,BREZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","COMPT0",False,,pending
brte.f,BRTE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1","COMPT0",False,,pending
brtez.f,BRTEZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1","COMPT0",False,,pending
butler.f,BUTLER,SUBROUTINE,True,"","",False,src/math/butler.rs,done
carbon.f,CARBON,SUBROUTINE,True,"","",False,src/math/carbon.rs,done
ceh12.f,CEH12,FUNCTION,True,"","CEH12",False,src/math/ceh12.rs,done
change.f,CHANGE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","STEQEQ|READBF",True,,pending
chckse.f,CHCKSE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","SABOLF",True,,pending
chctab.f,CHCTAB,SUBROUTINE,False,"BASICS|MODELQ|abntab","",True,,pending
cheav.f,CHEAV,FUNCTION,False,"BASICS|ATOMIC","CHEAV|QUIT",True,,pending
cheavj.f,CHEAVJ,FUNCTION,False,"BASICS|ATOMIC","QUIT|CHEAVJ",True,,pending
cia_h2h.f,CIA_H2H,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_h2h2.f,CIA_H2H2,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_h2he.f,CIA_H2HE,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cia_hhe.f,CIA_HHE,SUBROUTINE,False,"","LOCATE|IF",True,,pending
cion.f,CION,FUNCTION,True,"","CION",False,src/math/cion.rs,done
ckoest.f,CKOEST,FUNCTION,True,"BASICS","CKOEST",False,src/math/ckoest.rs,done
colh.f,COLH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","CSPEC|BUTLER|IRC",False,,pending
colhe.f,COLHE,SUBROUTINE,False,"BASICS|ATOMIC","COLLHE|CSPEC|IRC",False,,pending
colis.f,COLIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|CTRTEMP","CSPEC|COLH|COLHE|IRC",False,,pending
collhe.f,COLLHE,SUBROUTINE,True,"","",False,src/math/collhe.rs,done
column.f,COLUMN,SUBROUTINE,False,"BASICS|MODELQ|relcor","",True,,pending
compt0.f,COMPT0,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|auxcbc","",False,src/math/compt0.rs,done
comset.f,COMSET,SUBROUTINE,False,"BASICS|MODELQ|comgfs|auxcbc","",False,src/math/comset.rs,done
concor.f,CONCOR,SUBROUTINE,False,"BASICS|MODELQ","CONOUT",True,,pending
conout.f,CONOUT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|CUBCON","MEANOP|MEANOPT|CONVEC|OPACF0",True,,pending
conref.f,CONREF,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|imucnn|CUBCON","CONVC1|WNSTOR|STEQEQ|ELDENS|CONVEC|CONOUT",True,,pending
contmd.f,CONTMD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|PRSAUX|CUBCON","MEANOP|WNSTOR|STEQEQ|OPACF0|CONVEC|CONOUT|CUBIC",True,,pending
contmp.f,CONTMP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ichndm|CUBCON","MEANOP|WNSTOR|STEQEQ|ELDENS|OPACF0|CONVEC|MEANOPT|CONOUT|CUBIC",True,,pending
convc1.f,CONVC1,SUBROUTINE,False,"BASICS|CUBCON","TRMDER|TRMDRT",False,,pending
convec.f,CONVEC,SUBROUTINE,False,"BASICS|CUBCON","TRMDER|TRMDRT",False,,pending
coolrt.f,COOLRT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|COOLCO","OPACFA|RTEFR1",True,,pending
corrwm.f,CORRWM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",True,,pending
cross.f,CROSS,FUNCTION,False,"BASICS|ATOMIC|MODELQ","CROSS",False,src/math/cross.rs,done
crossd.f,CROSSD,FUNCTION,False,"BASICS|ATOMIC|MODELQ","CROSSD",False,src/math/cross.rs,done
cspec.f,CSPEC,SUBROUTINE,False,"BASICS|ATOMIC","QUIT",False,,pending
ctdata.f,CTDATA,BLOCK DATA,False,"CTIon|CTRecomb","",False,src/math/ctdata.rs,done
cubic.f,CUBIC,SUBROUTINE,False,"BASICS|CUBCON","",False,src/math/cubic.rs,done
dielrc.f,DIELRC,SUBROUTINE,True,"","",False,src/math/dielrc.rs,done
dietot.f,DIETOT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","DIELRC",True,,pending
divstr.f,DIVSTR,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/divstr.rs,done
dmder.f,DMDER,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|DEPTDR","",False,src/math/dmder.rs,done
dmeval.f,DMEVAL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ARRAY1","",True,,pending
dopgam.f,DOPGAM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","GAMSP",False,src/math/dopgam.rs,done
dwnfr.f,DWNFR,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr.rs,done
dwnfr0.f,DWNFR0,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr0.rs,done
dwnfr1.f,DWNFR1,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/dwnfr1.rs,done
eint.f,EINT,SUBROUTINE,True,"","EXPINX",False,src/math/expint.rs,done
elcor.f,ELCOR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ADCHAR","WNSTOR|STEQEQ|STATE|MOLEQ",True,,pending
eldenc.f,ELDENC,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|eletab|hmolab|eospar","RHONEN|STATE|MOLEQ",True,,pending
eldens.f,ELDENS,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|terden|eospar","ENTENE|STATE|MPARTF|LINEQS|MOLEQ",True,,pending
emat.f,EMAT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","",False,src/math/emat.rs,done
entene.f,ENTENE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","MPARTF",False,,pending
erfcin.f,ERFCIN,FUNCTION,True,"","ERFCIN",False,src/math/erfcx.rs,done
erfcx.f,ERFCX,FUNCTION,True,"","ERFCX",False,src/math/erfcx.rs,done
expint.f,EXPINT,FUNCTION,True,"","EXPINT",False,src/math/expint.rs,done
expinx.f,EXPINX,SUBROUTINE,True,"","",False,src/math/expint.rs,done
expo.f,EXPO,FUNCTION,True,"","EXPO",False,src/math/expo.rs,done
ffcros.f,FFCROS,FUNCTION,True,"","FFCROS",False,src/math/ffcros.rs,done
gami.f,GAMI,FUNCTION,True,"","GAMI",False,src/math/gami.rs,done
gamsp.f,GAMSP,SUBROUTINE,True,"BASICS","",False,src/math/gamsp.rs,done
gauleg.f,GAULEG,SUBROUTINE,True,"","",False,src/math/gauleg.rs,done
gaunt.f,GAUNT,FUNCTION,True,"","GAUNT",False,src/math/gaunt.rs,done
getlal.f,GETLAL,SUBROUTINE,False,"BASICS|callardc|callarda|calphatd|callardg|callardb|quasun","",True,,pending
getwrd.f,GETWRD,SUBROUTINE,True,"","",False,src/math/getwrd.rs,done
gfree0.f,GFREE0,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/gfree.rs,done
gfree1.f,GFREE1,FUNCTION,False,"BASICS|MODELQ","GFREE1",False,src/math/gfree.rs,done
gfreed.f,GFREED,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/gfree.rs,done
ghydop.f,GHYDOP,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|intcfg","",False,src/math/ghydop.rs,done
gntk.f,GNTK,FUNCTION,True,"","GNTK",False,src/math/gntk.rs,done
gomini.f,GOMINI,SUBROUTINE,False,"BASICS|MODELQ|intcfg","",True,,pending
grcor.f,GRCOR,SUBROUTINE,True,"","",False,src/math/grcor.rs,done
greyd.f,GREYD,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|ALIPAR","WNSTOR|RHONEN|STEQEQ|OPACF0|MEANOP",True,,pending
gridp.f,GRIDP,SUBROUTINE,True,"BASICS","",False,src/math/gridp.rs,done
h2minus.f,H2MINUS,SUBROUTINE,False,"BASICS","LOCATE",True,,pending
hction.f,HCTION,FUNCTION,False,"CTRTEMP|CTIon","HCTION",False,src/math/ctdata.rs,done
hctrecom.f,HCTRECOM,FUNCTION,False,"CTRTEMP|CTRecomb","HCTRECOM",False,src/math/ctdata.rs,done
hedif.f,HEDIF,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|hediff","",True,,pending
hephot.f,HEPHOT,FUNCTION,True,"","HEPHOT",False,src/math/hephot.rs,done
hesol6.f,HESOL6,SUBROUTINE,False,"BASICS|MODELQ|PRSAUX","MATINV",False,,pending
hesolv.f,HESOLV,SUBROUTINE,False,"BASICS|MODELQ|PRSAUX","MATINV|RHONEN|STEQEQ|WNSTOR",True,,pending
hidalg.f,HIDALG,FUNCTION,True,"","HIDALG",False,src/math/hidalg.rs,done
ijali2.f,IJALI2,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","QUIT",True,,pending
ijalis.f,IJALIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",True,,pending
incldy.f,INCLDY,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","LEVSOL|RATMAT|WNSTOR|QUIT|SABOLF",True,,pending
indexx.f,INDEXX,SUBROUTINE,True,"","",False,src/math/indexx.rs,done
inicom.f,INICOM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|comgfs","",False,src/math/inicom.rs,done
inifrc.f,INIFRC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ijflar","INDEXX",True,,pending
inifrs.f,INIFRS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","INDEXX|QUIT",True,,pending
inifrt.f,INIFRT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ijflar","INDEXX",True,,pending
inilam.f,INILAM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR","OPACF1|RTEFR1|COLIS|OPAINI|WNSTOR|STEQEQ|SABOLF|ELCOR|RATES1",False,,pending
initia.f,INITIA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|STRPAR|INUNIT|freqcl","RDATA|RDATAX|OPADD0|STATE|DOPGAM|ODFHYS|INTERP|LINSET|NSTPAR|QUIT|LINSPL|INIFRC|READBF",True,,pending
inkul.f,INKUL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR|LINED","",True,,pending
inpdis.f,INPDIS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|relcor","GRCOR",True,,pending
inpmod.f,INPMOD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|eospar","LEVSOL|RATMAT|WNSTOR|QUIT|SABOLF|MOLEQ|KURUCZ|INCLDY",True,,pending
interp.f,INTERP,SUBROUTINE,True,"BASICS","",False,src/math/interp.rs,done
inthyd.f,INTHYD,SUBROUTINE,False,"BASICS|MODELQ","DIVSTR",False,src/math/inthyd.rs,done
intlem.f,INTLEM,SUBROUTINE,False,"BASICS|MODELQ","INTHYD",False,src/math/intlem.rs,done
intxen.f,INTXEN,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/intxen.rs,done
irc.f,IRC,SUBROUTINE,True,"","EXPINX|SZIRC",False,src/math/irc.rs,done
iroset.f,IROSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|LINED","LEVCD|QUIT|INKUL",True,,pending
kurucz.f,KURUCZ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|temlim","LEVSOL|RATMAT|WNSTOR|RHONEN|QUIT|SABOLF|MOLEQ",True,,pending
lagran.f,LAGRAN,SUBROUTINE,True,"","",False,src/math/interpolate.rs,done
laguer.f,LAGUER,SUBROUTINE,False,"","",True,src/math/laguer.rs,done
lemini.f,LEMINI,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
levcd.f,LEVCD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR","INDEXX|QUIT",True,,pending
levgrp.f,LEVGRP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",False,src/math/levgrp.rs,done
levset.f,LEVSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",False,,pending
levsol.f,LEVSOL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","LINEQS",False,src/math/levsol.rs,done
lineqs.f,LINEQS,SUBROUTINE,True,"BASICS","",False,src/math/lineqs.rs,done
linpro.f,LINPRO,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|quasun","STARK0|DOPGAM|INTLEM|DIVSTR|INTXEN",False,,pending
linsel.f,LINSEL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","OPAINI|QUIT|OPACF1|RTEFR1",True,,pending
linset.f,LINSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","IJALIS|STARK0|QUIT|DIVSTR",True,,pending
linspl.f,LINSPL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/linspl.rs,done
locate.f,LOCATE,SUBROUTINE,True,"","",False,src/math/locate.rs,done
ltegr.f,LTEGR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","INTERP|WNSTOR|STEQEQ|QUIT|ROSSOP|CONOUT",True,,pending
ltegrd.f,LTEGRD,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|CUBCON|TOTJHK|FLXAUX|PRSAUX","TEMPER|INTERP|ZMRHO|WNSTOR|STEQEQ|ELDENS|QUIT|CONOUT",True,,pending
lucy.f,LUCY,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ITERAT|ALIPAR|ARRAY1","OPACFL|RTEFR1|COLIS|WNSTOR|STEQEQ|SABOLF|ELCOR|OPAINI",True,,pending
lymlin.f,LYMLIN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","STARK0|DIVSTR",True,,pending
matcon.f,MATCON,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|CUBCON","CONVEC",False,,pending
matgen.f,MATGEN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR","BHED|BRTE|BHEZ|BREZ|MATCON|BRTEZ|EMAT|BHE|SABOLF|BPOP|BRE",False,,pending
matinv.f,MATINV,SUBROUTINE,True,"BASICS","",False,src/math/matinv.rs,done
meanop.f,MEANOP,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC","",False,src/math/meanop.rs,done
meanopt.f,MEANOPT,SUBROUTINE,False,"BASICS|MODELQ","OPCTAB",False,,pending
minv3.f,MINV3,SUBROUTINE,True,"","",False,src/math/minv3.rs,done
moleq.f,MOLEQ,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|COMFH1|entrop|moldat|eospar|adchar|ioniz2|terden|hmolab","RUSSEL|MPARTF",True,,pending
mpartf.f,MPARTF,SUBROUTINE,False,"moldat","",True,,pending
newdm.f,NEWDM,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX","INTERP|TEMPER",True,,pending
newdmt.f,NEWDMT,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX","GRIDP|INTERP|TEMPER",True,,pending
newpop.f,NEWPOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
nstout.f,NSTOUT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR","QUIT",True,,pending
nstpar.f,NSTPAR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|imucnn|temlim|adiaba|ifpzpa|derdif|ichndm|ipricr|deridt|hediff|FLXAUX|irwint|moldat|quasun|freqcl|icnrsp","QUIT|GETWRD",True,,pending
odf1.f,ODF1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","DWNFR|ODFHST|DIVSTR",True,,pending
odffr.f,ODFFR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","QUIT",False,,pending
odfhst.f,ODFHST,SUBROUTINE,False,"BASICS|MODELQ|ODFPAR","",False,src/math/odfhst.rs,done
odfhyd.f,ODFHYD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","INDEXX|ODFHST|DIVSTR",False,,pending
odfhys.f,ODFHYS,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","IJALIS|STARK0|ODFFR",False,,pending
odfmer.f,ODFMER,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","ODFHYD",False,,pending
odfset.f,ODFSET,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|STFCR","IJALIS|QUIT",True,,pending
opacf0.f,OPACF0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab","GFREE0|DWNFR1|DWNFR0|WNSTOR|LINPRO|SABOLF|SGMER1|OPADD|OPACT1",False,,pending
opacf1.f,OPACF1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ipricr|hmolab","QUASIM|GHYDOP|DWNFR1|LYMLIN|SGMER1|OPADD|PRD|OPACT1",True,,pending
opacfa.f,OPACFA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|COOLCO","SGMER1|OPADD|PRD|DWNFR1",False,,pending
opacfd.f,OPACFD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|dsctva|hmolab|rhoder","OPACTD|QUASIM|DWNFR1|LYMLIN|OPCTAB|SGMER1|OPADD|PRD|GFREED",True,,pending
opacfl.f,OPACFL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","SGMER1|OPADD|DWNFR1",False,,pending
opact1.f,OPACT1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|hmolab","OPCTAB",False,,pending
opactd.f,OPACTD,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|ITERAT|dsctva|hmolab|rhoder","OPCTAB",False,,pending
opactr.f,OPACTR,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ATOMIC|dsctva|hmolab|grdpra","RATMAL|OPACF1|LEVSOL|WNSTOR|STEQEQ|ELDENS|SABOLF|OPAINI|PGSET",False,,pending
opadd.f,OPADD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|eospar","CIA_H2H|CIA_H2HE|CIA_HHE|H2MINUS|CIA_H2H2",False,,pending
opadd0.f,OPADD0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","QUIT",False,,pending
opahst.f,OPAHST,SUBROUTINE,False,"BASICS|ODFPAR","STARK0",True,,pending
opaini.f,OPAINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","DWNFR0|REFLEV|WNSTOR|LINPRO|SABOLF|LEVGRP",False,,pending
opctab.f,OPCTAB,SUBROUTINE,False,"BASICS|MODELQ","RAYLEIGH",False,,pending
opdata.f,OPDATA,SUBROUTINE,False,"TOPB","",True,,pending
opfrac.f,OPFRAC,SUBROUTINE,False,"pfoptb","",True,,pending
osccor.f,OSCCOR,SUBROUTINE,False,"BASICS|MODELQ|ITERAT","",True,,pending
outpri.f,OUTPRI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|grdpra","RATMAL|OPACF1|LEVSOL|WNSTOR|SABOLF",True,,pending
output.f,OUTPUT,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
partf.f,PARTF,SUBROUTINE,False,"BASICS|irwint|PFSTDS","PFFE|PFNI|OPFRAC|MPARTF|PFHEAV|PFSPEC|PFCNO",False,,pending
pfcno.f,PFCNO,SUBROUTINE,True,"BASICS","",False,src/math/pfcno.rs,done
pffe.f,PFFE,SUBROUTINE,True,"","",False,src/math/pffe.rs,done
pfheav.f,PFHEAV,SUBROUTINE,False,"","",True,,pending
pfni.f,PFNI,SUBROUTINE,True,"","",False,src/math/pfni.rs,done
pfspec.f,PFSPEC,SUBROUTINE,True,"","",False,src/math/pfspec.rs,done
pgset.f,PGSET,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|rybpgs|grdpra","TRIDAG",True,,pending
prchan.f,PRCHAN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
prd.f,PRD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","DOPGAM",False,,pending
prdini.f,PRDINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/prdini.rs,done
princ.f,PRINC,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","LINPRO|DWNFR|OPACF1|SABOLF",True,,pending
prnt.f,PRNT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","SABOLF",True,,pending
profil.f,PROFIL,FUNCTION,False,"BASICS|ATOMIC|MODELQ|quasun","PROFIL|STARK0|DIVSTR",False,src/math/profil.rs,done
profsp.f,PROFSP,FUNCTION,False,"BASICS|ATOMIC|MODELQ","PROFSP|SABOLF",False,,pending
prsent.f,PRSENT,SUBROUTINE,False,"tdflag|tdedge|THERM|TABLTD","",True,,pending
psolve.f,PSOLVE,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/psolve.rs,done
pzert.f,PZERT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/pzert.rs,done
pzeval.f,PZEVAL,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|icnrsp","CONOUT",True,,pending
pzevld.f,PZEVLD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1|ifpzpa|PRSAUX|grdpra|DEPTDR","",False,src/math/pzevld.rs,done
quartc.f,QUARTC,SUBROUTINE,False,"","",True,src/math/quartc.rs,done
quasim.f,QUASIM,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|quasun","ALLARD",False,,pending
quit.f,QUIT,SUBROUTINE,False,"","",True,src/math/quit.rs,done
radpre.f,RADPRE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","QUIT|INDEXX|OPACF1|RTEFR1",True,,pending
radtot.f,RADTOT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|OPTDPT|TOTJHK|SURFEX","OPAINI|OPACF1|RTEFR1",False,,pending
raph.f,RAPH,FUNCTION,True,"","RAPH",False,src/math/raph.rs,done
rates1.f,RATES1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT","ROSSTD|OPACF1|RTEFR1",False,,pending
ratmal.f,RATMAL,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/ratmal.rs,done
ratmat.f,RATMAT,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","REFLEV",False,,pending
ratsp1.f,RATSP1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT","ROSSTD|OPACF1|RTEFR1",True,,pending
rayini.f,RAYINI,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC","RAYLEIGH",True,,pending
rayleigh.f,RAYLEIGH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|RAYSCT|eospar","",False,src/math/rayleigh.rs,done
rayset.f,RAYSET,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/rayset.rs,done
rdata.f,RDATA,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|STRPAR|INUNIT|imodlc","RDATAX|LINSET|QUIT|DOPGAM",True,,pending
rdatax.f,RDATAX,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","BKHSGO",True,,pending
readbf.f,READBF,SUBROUTINE,False,"BASICS","",True,,pending
rechck.f,RECHCK,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","OPACF1|RTEFR1",True,,pending
reflev.f,REFLEV,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",False,,pending
reiman.f,REIMAN,FUNCTION,True,"","REIMAN",False,src/math/reiman.rs,done
resolv.f,RESOLV,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR|ARRAY1|icnrsp","NEWPOP|TAUFR1|TIMING|OPACF1|RTEFR1|ROSSTD|STEQEQ|CONOUT|ELCOR|OPAINI|RATES1|PRD",True,,pending
rhoeos.f,RHOEOS,FUNCTION,False,"BASICS|MODELQ","PRSENT|RHOEOS",False,,pending
rhonen.f,RHONEN,SUBROUTINE,False,"BASICS|MODELQ","ELDENS",False,,pending
rhsgen.f,RHSGEN,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CUBCON","MATINV|STATE|RATMAT|COMPT0|SABOLF|CONVEC|LEVGRP",False,,pending
rossop.f,ROSSOP,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ALIPAR","WNSTOR|STEQEQ|ELDENS|OPACF0|MEANOP|MEANOPT",False,,pending
rosstd.f,ROSSTD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR","",True,,pending
rte_sc.f,RTE_SC,SUBROUTINE,True,"BASICS","",False,src/math/rte_sc.rs,done
rteang.f,RTEANG,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|EXTINT|SURFEX","GAULEG",False,,pending
rtecf0.f,RTECF0,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|auxcbc|AUXRTE","",False,,pending
rtecf1.f,RTECF1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|comgfs|AUXRTE|EXTINT|SURFEX","RTEFE2|RTESOL|RTECF0",True,,pending
rtecmc.f,RTECMC,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|comgfs|AUXRTE","MATINV|OPACF1|RTECF0",False,,pending
rtecmu.f,RTECMU,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|AUXRTE","RTESOL|OPACF1|RTECF0|GAULEG",True,,pending
rtecom.f,RTECOM,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|comgfs|AUXRTE","OPACF1|RTECF0|RTECF1",False,,pending
rtedf1.f,RTEDF1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|OPTDPT","",False,src/math/rtedf1.rs,done
rtedf2.f,RTEDF2,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR","",False,,pending
rtefe2.f,RTEFE2,SUBROUTINE,True,"BASICS","",False,src/math/rtefe2.rs,done
rtefr1.f,RTEFR1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","MATINV|RTESOL|RTEDF1|RTECF1|RTEDF2|MINV3",True,,pending
rteint.f,RTEINT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","MATINV|OPACF1",True,,pending
rtesol.f,RTESOL,SUBROUTINE,True,"BASICS","",False,src/math/rtesol.rs,done
russel.f,RUSSEL,SUBROUTINE,False,"BASICS|MODELQ|COMFH1","MPARTF",True,,pending
rybchn.f,RYBCHN,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ALIPAR|ARRAY1|rybpgs|grdpra","PGSET|ELDENS",True,,pending
rybene.f,RYBENE,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|RYBMTX|deridt|CUBCON","CONVEC",False,,pending
rybheq.f,RYBHEQ,SUBROUTINE,False,"BASICS|MODELQ|rybpgs|grdpra","OPACF1|RTEFR1|WNSTOR|STEQEQ|ELDENS|ELCOR|OPAINI|PGSET",True,,pending
rybmat.f,RYBMAT,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ARRAY1|dsctva|RYBMTX","",False,,pending
rybsol.f,RYBSOL,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|ALIPAR|ARRAY1|ITERAT|imodlc|RYBMTX","RYBMAT|RTEFR1|ROSSTD|OPACTR|LINEQS|STEQEQ|ALIFR1|TRIDAG|RYBCHN|OPACFD",True,,pending
sabolf.f,SABOLF,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","PARTF",False,,pending
sbfch.f,SBFCH,FUNCTION,True,"","SBFCH",False,src/math/sbfch.rs,done
sbfhe1.f,SBFHE1,FUNCTION,False,"BASICS|ATOMIC","SBFHE1|QUIT",True,src/math/sbfhe1.rs,done
sbfhmi.f,SBFHMI,FUNCTION,True,"","SBFHMI",False,src/math/sbfhmi.rs,done
sbfhmi_old.f,SBFHMI_OLD,FUNCTION,True,"","SBFHMI_OLD",False,src/math/sbfhmi_old.rs,done
sbfoh.f,SBFOH,FUNCTION,True,"","SBFOH",False,src/math/sbfoh.rs,done
setdrt.f,SETDRT,SUBROUTINE,False,"BASICS|MODELQ|RHODER","",False,,pending
settrm.f,SETTRM,SUBROUTINE,False,"tdflag|tdedge|THERM|TABLTD","PRSENT",True,,pending
sffhmi.f,SFFHMI,FUNCTION,True,"","SFFHMI",False,src/math/sffhmi.rs,done
sffhmi_add.f,SFFHMI_ADD,FUNCTION,True,"","SFFHMI_ADD",False,src/math/sffhmi_add.rs,done
sghe12.f,SGHE12,FUNCTION,True,"","SGHE12",False,src/math/sghe12.rs,done
sgmer0.f,SGMER0,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sgmer1.f,SGMER1,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sgmerd.f,SGMERD,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/sgmer.rs,done
sigave.f,SIGAVE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","",True,,pending
sigk.f,SIGK,FUNCTION,False,"BASICS|ATOMIC","SPSIGK|SIGK",False,,pending
sigmar.f,SIGMAR,FUNCTION,False,"BASICS","SIGMAR|LAGUER",True,,pending
solve.f,SOLVE,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD","MATINV|PRCHAN|RHSGEN|WNSTOR|MATGEN",True,,pending
solves.f,SOLVES,SUBROUTINE,False,"BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|STOMAT|CMATZD","MATINV|PRCHAN|RHSGEN|WNSTOR|MATGEN",True,,pending
spsigk.f,SPSIGK,SUBROUTINE,True,"","CARBON",False,src/math/spsigk.rs,done
srtfrq.f,SRTFRQ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","INDEXX|QUIT",True,,pending
stark0.f,STARK0,SUBROUTINE,True,"","",False,src/math/stark0.rs,done
starka.f,STARKA,FUNCTION,False,"BASICS|MODELQ","STARKA",False,src/math/starka.rs,done
start.f,START,SUBROUTINE,False,"BASICS|hediff","",True,,pending
state.f,STATE,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|terden|PFSTDS","OPFRAC|PARTF",True,,pending
steqeq.f,STEQEQ,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT|POPSTR|PPAPAR","LEVSOL|RATMAT|SABOLF|MOLEQ",False,,pending
switch.f,SWITCH,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",True,,pending
szirc.f,SZIRC,SUBROUTINE,True,"","EINT",False,src/math/szirc.rs,done
tabini.f,TABINI,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|eletab|abntab|intcff","",True,,pending
tabint.f,TABINT,SUBROUTINE,False,"BASICS|MODELQ|ATOMIC|intcff","",False,,pending
taufr1.f,TAUFR1,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT","",False,,pending
tdpini.f,TDPINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR","GFREE0",False,src/math/tdpini.rs,done
temcor.f,TEMCOR,SUBROUTINE,False,"BASICS|MODELQ|ARRAY1|ALIPAR|CUBCON","MEANOP|WNSTOR|STEQEQ|ELDENS|OPACF0|CONVEC",True,,pending
temper.f,TEMPER,SUBROUTINE,False,"BASICS|MODELQ|ALIPAR|FACTRS|PRSAUX|FLXAUX","WNSTOR|TLOCAL|STEQEQ|ELDENS|OPACF0|MEANOP|MEANOPT",True,,pending
timing.f,TIMING,SUBROUTINE,False,"","",True,,pending
tiopf.f,TIOPF,SUBROUTINE,True,"","",False,src/math/tiopf.rs,done
tlocal.f,TLOCAL,SUBROUTINE,False,"BASICS|MODELQ|FACTRS|FLXAUX","QUARTC",False,,pending
tlusty.f,TLUSTY,UNKNOWN,False,"BASICS|ITERAT|ALIPAR","TIMING",True,,pending
topbas.f,TOPBAS,FUNCTION,False,"TOPB","TOPBAS",True,,pending
traini.f,TRAINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ODFPAR","",False,src/math/traini.rs,done
tridag.f,TRIDAG,SUBROUTINE,True,"","",False,src/math/tridag.rs,done
trmder.f,TRMDER,SUBROUTINE,False,"BASICS|derdif|terden|adiaba","ELDENS",False,,pending
trmdrt.f,TRMDRT,SUBROUTINE,False,"BASICS|tdedge|CC|tdflag|CONVOUT","PRSENT",False,,pending
ubeta.f,UBETA,FUNCTION,True,"","UBETA|LAGRAN",False,src/math/ubeta.rs,done
vern16.f,VERN16,FUNCTION,True,"BASICS","VERN16",False,src/math/vern16.rs,done
vern18.f,VERN18,FUNCTION,True,"BASICS","VERN18",False,src/math/vern18.rs,done
vern20.f,VERN20,FUNCTION,True,"BASICS","VERN20",False,src/math/vern20.rs,done
vern26.f,VERN26,FUNCTION,True,"BASICS","VERN26",False,src/math/vern26.rs,done
verner.f,VERNER,FUNCTION,False,"BASICS|ATOMIC","QUIT|VERNER",False,src/math/verner.rs,done
visini.f,VISINI,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ|ITERAT","",True,,pending
voigt.f,VOIGT,FUNCTION,True,"","VOIGT",False,src/math/voigt.rs,done
voigte.f,VOIGTE,FUNCTION,True,"","VOIGTE",False,src/math/voigte.rs,done
wn.f,WN,FUNCTION,True,"BASICS","WN",False,src/math/wn.rs,done
wnstor.f,WNSTOR,SUBROUTINE,False,"BASICS|ATOMIC|MODELQ","",False,src/math/wnstor.rs,done
xenini.f,XENINI,SUBROUTINE,False,"BASICS|MODELQ","",True,,pending
xk2dop.f,XK2DOP,FUNCTION,True,"","XK2DOP",False,src/math/xk2dop.rs,done
yint.f,YINT,FUNCTION,True,"","YINT",False,src/math/interpolate.rs,done
ylintp.f,YLINTP,FUNCTION,True,"","YLINTP",False,src/math/ylintp.rs,done
zmrho.f,ZMRHO,SUBROUTINE,False,"BASICS|MODELQ","",False,src/math/zmrho.rs,done
1 fortran_file unit_name unit_type is_pure common_deps call_deps has_io rust_module status
2 _unnamed_block_data_.f C BLOCK DATA False BASICS|ATOMIC False pending
3 accel2.f ACCEL2 SUBROUTINE False BASICS|ITERAT|MODELQ True pending
4 accelp.f ACCELP SUBROUTINE False BASICS|MODELQ|ITERAT|POPULS True pending
5 alifr1.f ALIFR1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR ALIFR3 False pending
6 alifr3.f ALIFR3 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifr3.rs done
7 alifr6.f ALIFR6 SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifr6.rs done
8 alifrk.f ALIFRK SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR False src/math/alifrk.rs done
9 alisk1.f ALISK1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT ALIFRK|ROSSTD|OPACF1|RTEFR1 True pending
10 alisk2.f ALISK2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT ALIFRK|ROSSTD|OPACF1|RTEFR1 True pending
11 alist1.f ALIST1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT OPACFD|ALIFR1|ROSSTD|RTEFR1 True pending
12 alist2.f ALIST2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT RTEFR1|ROSSTD|ALIFR1|QUIT|OPACFD True pending
13 allard.f ALLARD SUBROUTINE False BASICS|calphatd|callarda|callardc|callardg|callardb|quasun ALLARDT True pending
14 allardt.f ALLARDT SUBROUTINE False BASICS|calphatd False src/math/allardt.rs done
15 angset.f ANGSET SUBROUTINE True BASICS GAULEG False src/math/angset.rs done
16 betah.f BETAH FUNCTION True BETAH False src/math/betah.rs done
17 bhe.f BHE SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR False src/math/bhe.rs done
18 bhed.f BHED SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CMATZD|SURFEX False src/math/bhe.rs done
19 bhez.f BHEZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|SURFEX False src/math/bhe.rs done
20 bkhsgo.f BKHSGO SUBROUTINE True False src/math/bkhsgo.rs done
21 bpop.f BPOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ITERAT MATINV|BPOPT|BPOPF|LEVSOL|RATMAT|BPOPC|BPOPE|LEVGRP False pending
22 bpopc.f BPOPC SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR|ADCHAR STATE False pending
23 bpope.f BPOPE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|ARRAY1 SGMER1|DWNFR1 False pending
24 bpopf.f BPOPF SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR False src/math/bpopf.rs done
25 bpopt.f BPOPT SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|ODFPAR COLIS False pending
26 bre.f BRE SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR COMPT0 False pending
27 brez.f BREZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR COMPT0 False pending
28 brte.f BRTE SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1 COMPT0 False pending
29 brtez.f BRTEZ SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1 COMPT0 False pending
30 butler.f BUTLER SUBROUTINE True False src/math/butler.rs done
31 carbon.f CARBON SUBROUTINE True False src/math/carbon.rs done
32 ceh12.f CEH12 FUNCTION True CEH12 False src/math/ceh12.rs done
33 change.f CHANGE SUBROUTINE False BASICS|ATOMIC|MODELQ STEQEQ|READBF True pending
34 chckse.f CHCKSE SUBROUTINE False BASICS|ATOMIC|MODELQ SABOLF True pending
35 chctab.f CHCTAB SUBROUTINE False BASICS|MODELQ|abntab True pending
36 cheav.f CHEAV FUNCTION False BASICS|ATOMIC CHEAV|QUIT True pending
37 cheavj.f CHEAVJ FUNCTION False BASICS|ATOMIC QUIT|CHEAVJ True pending
38 cia_h2h.f CIA_H2H SUBROUTINE False LOCATE|IF True pending
39 cia_h2h2.f CIA_H2H2 SUBROUTINE False LOCATE|IF True pending
40 cia_h2he.f CIA_H2HE SUBROUTINE False LOCATE|IF True pending
41 cia_hhe.f CIA_HHE SUBROUTINE False LOCATE|IF True pending
42 cion.f CION FUNCTION True CION False src/math/cion.rs done
43 ckoest.f CKOEST FUNCTION True BASICS CKOEST False src/math/ckoest.rs done
44 colh.f COLH SUBROUTINE False BASICS|ATOMIC|MODELQ CSPEC|BUTLER|IRC False pending
45 colhe.f COLHE SUBROUTINE False BASICS|ATOMIC COLLHE|CSPEC|IRC False pending
46 colis.f COLIS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|CTRTEMP CSPEC|COLH|COLHE|IRC False pending
47 collhe.f COLLHE SUBROUTINE True False src/math/collhe.rs done
48 column.f COLUMN SUBROUTINE False BASICS|MODELQ|relcor True pending
49 compt0.f COMPT0 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|auxcbc False src/math/compt0.rs done
50 comset.f COMSET SUBROUTINE False BASICS|MODELQ|comgfs|auxcbc False src/math/comset.rs done
51 concor.f CONCOR SUBROUTINE False BASICS|MODELQ CONOUT True pending
52 conout.f CONOUT SUBROUTINE False BASICS|MODELQ|ALIPAR|CUBCON MEANOP|MEANOPT|CONVEC|OPACF0 True pending
53 conref.f CONREF SUBROUTINE False BASICS|MODELQ|ARRAY1|imucnn|CUBCON CONVC1|WNSTOR|STEQEQ|ELDENS|CONVEC|CONOUT True pending
54 contmd.f CONTMD SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|PRSAUX|CUBCON MEANOP|WNSTOR|STEQEQ|OPACF0|CONVEC|CONOUT|CUBIC True pending
55 contmp.f CONTMP SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ichndm|CUBCON MEANOP|WNSTOR|STEQEQ|ELDENS|OPACF0|CONVEC|MEANOPT|CONOUT|CUBIC True pending
56 convc1.f CONVC1 SUBROUTINE False BASICS|CUBCON TRMDER|TRMDRT False pending
57 convec.f CONVEC SUBROUTINE False BASICS|CUBCON TRMDER|TRMDRT False pending
58 coolrt.f COOLRT SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|COOLCO OPACFA|RTEFR1 True pending
59 corrwm.f CORRWM SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT True pending
60 cross.f CROSS FUNCTION False BASICS|ATOMIC|MODELQ CROSS False src/math/cross.rs done
61 crossd.f CROSSD FUNCTION False BASICS|ATOMIC|MODELQ CROSSD False src/math/cross.rs done
62 cspec.f CSPEC SUBROUTINE False BASICS|ATOMIC QUIT False pending
63 ctdata.f CTDATA BLOCK DATA False CTIon|CTRecomb False src/math/ctdata.rs done
64 cubic.f CUBIC SUBROUTINE False BASICS|CUBCON False src/math/cubic.rs done
65 dielrc.f DIELRC SUBROUTINE True False src/math/dielrc.rs done
66 dietot.f DIETOT SUBROUTINE False BASICS|ATOMIC|MODELQ DIELRC True pending
67 divstr.f DIVSTR SUBROUTINE False BASICS|MODELQ False src/math/divstr.rs done
68 dmder.f DMDER SUBROUTINE False BASICS|ATOMIC|MODELQ|DEPTDR False src/math/dmder.rs done
69 dmeval.f DMEVAL SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ARRAY1 True pending
70 dopgam.f DOPGAM SUBROUTINE False BASICS|ATOMIC|MODELQ GAMSP False src/math/dopgam.rs done
71 dwnfr.f DWNFR SUBROUTINE False BASICS|MODELQ False src/math/dwnfr.rs done
72 dwnfr0.f DWNFR0 SUBROUTINE False BASICS|MODELQ False src/math/dwnfr0.rs done
73 dwnfr1.f DWNFR1 SUBROUTINE False BASICS|MODELQ False src/math/dwnfr1.rs done
74 eint.f EINT SUBROUTINE True EXPINX False src/math/expint.rs done
75 elcor.f ELCOR SUBROUTINE False BASICS|ATOMIC|MODELQ|ADCHAR WNSTOR|STEQEQ|STATE|MOLEQ True pending
76 eldenc.f ELDENC SUBROUTINE False BASICS|MODELQ|ATOMIC|eletab|hmolab|eospar RHONEN|STATE|MOLEQ True pending
77 eldens.f ELDENS SUBROUTINE False BASICS|MODELQ|ATOMIC|terden|eospar ENTENE|STATE|MPARTF|LINEQS|MOLEQ True pending
78 emat.f EMAT SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR False src/math/emat.rs done
79 entene.f ENTENE SUBROUTINE False BASICS|ATOMIC|MODELQ MPARTF False pending
80 erfcin.f ERFCIN FUNCTION True ERFCIN False src/math/erfcx.rs done
81 erfcx.f ERFCX FUNCTION True ERFCX False src/math/erfcx.rs done
82 expint.f EXPINT FUNCTION True EXPINT False src/math/expint.rs done
83 expinx.f EXPINX SUBROUTINE True False src/math/expint.rs done
84 expo.f EXPO FUNCTION True EXPO False src/math/expo.rs done
85 ffcros.f FFCROS FUNCTION True FFCROS False src/math/ffcros.rs done
86 gami.f GAMI FUNCTION True GAMI False src/math/gami.rs done
87 gamsp.f GAMSP SUBROUTINE True BASICS False src/math/gamsp.rs done
88 gauleg.f GAULEG SUBROUTINE True False src/math/gauleg.rs done
89 gaunt.f GAUNT FUNCTION True GAUNT False src/math/gaunt.rs done
90 getlal.f GETLAL SUBROUTINE False BASICS|callardc|callarda|calphatd|callardg|callardb|quasun True pending
91 getwrd.f GETWRD SUBROUTINE True False src/math/getwrd.rs done
92 gfree0.f GFREE0 SUBROUTINE False BASICS|MODELQ False src/math/gfree.rs done
93 gfree1.f GFREE1 FUNCTION False BASICS|MODELQ GFREE1 False src/math/gfree.rs done
94 gfreed.f GFREED SUBROUTINE False BASICS|MODELQ False src/math/gfree.rs done
95 ghydop.f GHYDOP SUBROUTINE False BASICS|MODELQ|ATOMIC|intcfg False src/math/ghydop.rs done
96 gntk.f GNTK FUNCTION True GNTK False src/math/gntk.rs done
97 gomini.f GOMINI SUBROUTINE False BASICS|MODELQ|intcfg True pending
98 grcor.f GRCOR SUBROUTINE True False src/math/grcor.rs done
99 greyd.f GREYD SUBROUTINE False BASICS|MODELQ|ATOMIC|ALIPAR WNSTOR|RHONEN|STEQEQ|OPACF0|MEANOP True pending
100 gridp.f GRIDP SUBROUTINE True BASICS False src/math/gridp.rs done
101 h2minus.f H2MINUS SUBROUTINE False BASICS LOCATE True pending
102 hction.f HCTION FUNCTION False CTRTEMP|CTIon HCTION False src/math/ctdata.rs done
103 hctrecom.f HCTRECOM FUNCTION False CTRTEMP|CTRecomb HCTRECOM False src/math/ctdata.rs done
104 hedif.f HEDIF SUBROUTINE False BASICS|MODELQ|ATOMIC|hediff True pending
105 hephot.f HEPHOT FUNCTION True HEPHOT False src/math/hephot.rs done
106 hesol6.f HESOL6 SUBROUTINE False BASICS|MODELQ|PRSAUX MATINV False pending
107 hesolv.f HESOLV SUBROUTINE False BASICS|MODELQ|PRSAUX MATINV|RHONEN|STEQEQ|WNSTOR True pending
108 hidalg.f HIDALG FUNCTION True HIDALG False src/math/hidalg.rs done
109 ijali2.f IJALI2 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR QUIT True pending
110 ijalis.f IJALIS SUBROUTINE False BASICS|ATOMIC|MODELQ True pending
111 incldy.f INCLDY SUBROUTINE False BASICS|ATOMIC|MODELQ LEVSOL|RATMAT|WNSTOR|QUIT|SABOLF True pending
112 indexx.f INDEXX SUBROUTINE True False src/math/indexx.rs done
113 inicom.f INICOM SUBROUTINE False BASICS|ATOMIC|MODELQ|comgfs False src/math/inicom.rs done
114 inifrc.f INIFRC SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ijflar INDEXX True pending
115 inifrs.f INIFRS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR INDEXX|QUIT True pending
116 inifrt.f INIFRT SUBROUTINE False BASICS|ATOMIC|MODELQ|ijflar INDEXX True pending
117 inilam.f INILAM SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR OPACF1|RTEFR1|COLIS|OPAINI|WNSTOR|STEQEQ|SABOLF|ELCOR|RATES1 False pending
118 initia.f INITIA SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|STRPAR|INUNIT|freqcl RDATA|RDATAX|OPADD0|STATE|DOPGAM|ODFHYS|INTERP|LINSET|NSTPAR|QUIT|LINSPL|INIFRC|READBF True pending
119 inkul.f INKUL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR|LINED True pending
120 inpdis.f INPDIS SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|relcor GRCOR True pending
121 inpmod.f INPMOD SUBROUTINE False BASICS|ATOMIC|MODELQ|eospar LEVSOL|RATMAT|WNSTOR|QUIT|SABOLF|MOLEQ|KURUCZ|INCLDY True pending
122 interp.f INTERP SUBROUTINE True BASICS False src/math/interp.rs done
123 inthyd.f INTHYD SUBROUTINE False BASICS|MODELQ DIVSTR False src/math/inthyd.rs done
124 intlem.f INTLEM SUBROUTINE False BASICS|MODELQ INTHYD False src/math/intlem.rs done
125 intxen.f INTXEN SUBROUTINE False BASICS|MODELQ False src/math/intxen.rs done
126 irc.f IRC SUBROUTINE True EXPINX|SZIRC False src/math/irc.rs done
127 iroset.f IROSET SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|LINED LEVCD|QUIT|INKUL True pending
128 kurucz.f KURUCZ SUBROUTINE False BASICS|ATOMIC|MODELQ|temlim LEVSOL|RATMAT|WNSTOR|RHONEN|QUIT|SABOLF|MOLEQ True pending
129 lagran.f LAGRAN SUBROUTINE True False src/math/interpolate.rs done
130 laguer.f LAGUER SUBROUTINE False True src/math/laguer.rs done
131 lemini.f LEMINI SUBROUTINE False BASICS|MODELQ True pending
132 levcd.f LEVCD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|COLKUR INDEXX|QUIT True pending
133 levgrp.f LEVGRP SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT False src/math/levgrp.rs done
134 levset.f LEVSET SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT False pending
135 levsol.f LEVSOL SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT LINEQS False src/math/levsol.rs done
136 lineqs.f LINEQS SUBROUTINE True BASICS False src/math/lineqs.rs done
137 linpro.f LINPRO SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|quasun STARK0|DOPGAM|INTLEM|DIVSTR|INTXEN False pending
138 linsel.f LINSEL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR OPAINI|QUIT|OPACF1|RTEFR1 True pending
139 linset.f LINSET SUBROUTINE False BASICS|ATOMIC|MODELQ IJALIS|STARK0|QUIT|DIVSTR True pending
140 linspl.f LINSPL SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/linspl.rs done
141 locate.f LOCATE SUBROUTINE True False src/math/locate.rs done
142 ltegr.f LTEGR SUBROUTINE False BASICS|ATOMIC|MODELQ INTERP|WNSTOR|STEQEQ|QUIT|ROSSOP|CONOUT True pending
143 ltegrd.f LTEGRD SUBROUTINE False BASICS|MODELQ|FACTRS|CUBCON|TOTJHK|FLXAUX|PRSAUX TEMPER|INTERP|ZMRHO|WNSTOR|STEQEQ|ELDENS|QUIT|CONOUT True pending
144 lucy.f LUCY SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ITERAT|ALIPAR|ARRAY1 OPACFL|RTEFR1|COLIS|WNSTOR|STEQEQ|SABOLF|ELCOR|OPAINI True pending
145 lymlin.f LYMLIN SUBROUTINE False BASICS|ATOMIC|MODELQ STARK0|DIVSTR True pending
146 matcon.f MATCON SUBROUTINE False BASICS|MODELQ|ARRAY1|CUBCON CONVEC False pending
147 matgen.f MATGEN SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR BHED|BRTE|BHEZ|BREZ|MATCON|BRTEZ|EMAT|BHE|SABOLF|BPOP|BRE False pending
148 matinv.f MATINV SUBROUTINE True BASICS False src/math/matinv.rs done
149 meanop.f MEANOP SUBROUTINE False BASICS|MODELQ|ATOMIC False src/math/meanop.rs done
150 meanopt.f MEANOPT SUBROUTINE False BASICS|MODELQ OPCTAB False pending
151 minv3.f MINV3 SUBROUTINE True False src/math/minv3.rs done
152 moleq.f MOLEQ SUBROUTINE False BASICS|MODELQ|ATOMIC|COMFH1|entrop|moldat|eospar|adchar|ioniz2|terden|hmolab RUSSEL|MPARTF True pending
153 mpartf.f MPARTF SUBROUTINE False moldat True pending
154 newdm.f NEWDM SUBROUTINE False BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX INTERP|TEMPER True pending
155 newdmt.f NEWDMT SUBROUTINE False BASICS|MODELQ|FACTRS|PRSAUX|FLXAUX GRIDP|INTERP|TEMPER True pending
156 newpop.f NEWPOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
157 nstout.f NSTOUT SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR QUIT True pending
158 nstpar.f NSTPAR SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|imucnn|temlim|adiaba|ifpzpa|derdif|ichndm|ipricr|deridt|hediff|FLXAUX|irwint|moldat|quasun|freqcl|icnrsp QUIT|GETWRD True pending
159 odf1.f ODF1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR DWNFR|ODFHST|DIVSTR True pending
160 odffr.f ODFFR SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR QUIT False pending
161 odfhst.f ODFHST SUBROUTINE False BASICS|MODELQ|ODFPAR False src/math/odfhst.rs done
162 odfhyd.f ODFHYD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR INDEXX|ODFHST|DIVSTR False pending
163 odfhys.f ODFHYS SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR IJALIS|STARK0|ODFFR False pending
164 odfmer.f ODFMER SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR ODFHYD False pending
165 odfset.f ODFSET SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|STFCR IJALIS|QUIT True pending
166 opacf0.f OPACF0 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|hmolab GFREE0|DWNFR1|DWNFR0|WNSTOR|LINPRO|SABOLF|SGMER1|OPADD|OPACT1 False pending
167 opacf1.f OPACF1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ipricr|hmolab QUASIM|GHYDOP|DWNFR1|LYMLIN|SGMER1|OPADD|PRD|OPACT1 True pending
168 opacfa.f OPACFA SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|COOLCO SGMER1|OPADD|PRD|DWNFR1 False pending
169 opacfd.f OPACFD SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT|dsctva|hmolab|rhoder OPACTD|QUASIM|DWNFR1|LYMLIN|OPCTAB|SGMER1|OPADD|PRD|GFREED True pending
170 opacfl.f OPACFL SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR SGMER1|OPADD|DWNFR1 False pending
171 opact1.f OPACT1 SUBROUTINE False BASICS|MODELQ|ALIPAR|hmolab OPCTAB False pending
172 opactd.f OPACTD SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|ITERAT|dsctva|hmolab|rhoder OPCTAB False pending
173 opactr.f OPACTR SUBROUTINE False BASICS|MODELQ|ALIPAR|ATOMIC|dsctva|hmolab|grdpra RATMAL|OPACF1|LEVSOL|WNSTOR|STEQEQ|ELDENS|SABOLF|OPAINI|PGSET False pending
174 opadd.f OPADD SUBROUTINE False BASICS|ATOMIC|MODELQ|eospar CIA_H2H|CIA_H2HE|CIA_HHE|H2MINUS|CIA_H2H2 False pending
175 opadd0.f OPADD0 SUBROUTINE False BASICS|ATOMIC|MODELQ QUIT False pending
176 opahst.f OPAHST SUBROUTINE False BASICS|ODFPAR STARK0 True pending
177 opaini.f OPAINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR DWNFR0|REFLEV|WNSTOR|LINPRO|SABOLF|LEVGRP False pending
178 opctab.f OPCTAB SUBROUTINE False BASICS|MODELQ RAYLEIGH False pending
179 opdata.f OPDATA SUBROUTINE False TOPB True pending
180 opfrac.f OPFRAC SUBROUTINE False pfoptb True pending
181 osccor.f OSCCOR SUBROUTINE False BASICS|MODELQ|ITERAT True pending
182 outpri.f OUTPRI SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|grdpra RATMAL|OPACF1|LEVSOL|WNSTOR|SABOLF True pending
183 output.f OUTPUT SUBROUTINE False BASICS|MODELQ True pending
184 partf.f PARTF SUBROUTINE False BASICS|irwint|PFSTDS PFFE|PFNI|OPFRAC|MPARTF|PFHEAV|PFSPEC|PFCNO False pending
185 pfcno.f PFCNO SUBROUTINE True BASICS False src/math/pfcno.rs done
186 pffe.f PFFE SUBROUTINE True False src/math/pffe.rs done
187 pfheav.f PFHEAV SUBROUTINE False True pending
188 pfni.f PFNI SUBROUTINE True False src/math/pfni.rs done
189 pfspec.f PFSPEC SUBROUTINE True False src/math/pfspec.rs done
190 pgset.f PGSET SUBROUTINE False BASICS|ITERAT|MODELQ|rybpgs|grdpra TRIDAG True pending
191 prchan.f PRCHAN SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
192 prd.f PRD SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT DOPGAM False pending
193 prdini.f PRDINI SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/prdini.rs done
194 princ.f PRINC SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR LINPRO|DWNFR|OPACF1|SABOLF True pending
195 prnt.f PRNT SUBROUTINE False BASICS|ATOMIC|MODELQ SABOLF True pending
196 profil.f PROFIL FUNCTION False BASICS|ATOMIC|MODELQ|quasun PROFIL|STARK0|DIVSTR False src/math/profil.rs done
197 profsp.f PROFSP FUNCTION False BASICS|ATOMIC|MODELQ PROFSP|SABOLF False pending
198 prsent.f PRSENT SUBROUTINE False tdflag|tdedge|THERM|TABLTD True pending
199 psolve.f PSOLVE SUBROUTINE False BASICS|MODELQ False src/math/psolve.rs done
200 pzert.f PZERT SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/pzert.rs done
201 pzeval.f PZEVAL SUBROUTINE False BASICS|MODELQ|ALIPAR|icnrsp CONOUT True pending
202 pzevld.f PZEVLD SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR|ARRAY1|ifpzpa|PRSAUX|grdpra|DEPTDR False src/math/pzevld.rs done
203 quartc.f QUARTC SUBROUTINE False True src/math/quartc.rs done
204 quasim.f QUASIM SUBROUTINE False BASICS|ATOMIC|MODELQ|quasun ALLARD False pending
205 quit.f QUIT SUBROUTINE False True src/math/quit.rs done
206 radpre.f RADPRE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR QUIT|INDEXX|OPACF1|RTEFR1 True pending
207 radtot.f RADTOT SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT|OPTDPT|TOTJHK|SURFEX OPAINI|OPACF1|RTEFR1 False pending
208 raph.f RAPH FUNCTION True RAPH False src/math/raph.rs done
209 rates1.f RATES1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ITERAT ROSSTD|OPACF1|RTEFR1 False pending
210 ratmal.f RATMAL SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/ratmal.rs done
211 ratmat.f RATMAT SUBROUTINE False BASICS|ATOMIC|MODELQ REFLEV False pending
212 ratsp1.f RATSP1 SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR|ARRAY1|ITERAT ROSSTD|OPACF1|RTEFR1 True pending
213 rayini.f RAYINI SUBROUTINE False BASICS|MODELQ|ATOMIC RAYLEIGH True pending
214 rayleigh.f RAYLEIGH SUBROUTINE False BASICS|ATOMIC|MODELQ|RAYSCT|eospar False src/math/rayleigh.rs done
215 rayset.f RAYSET SUBROUTINE False BASICS|MODELQ False src/math/rayset.rs done
216 rdata.f RDATA SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ODFPAR|ALIPAR|STRPAR|INUNIT|imodlc RDATAX|LINSET|QUIT|DOPGAM True pending
217 rdatax.f RDATAX SUBROUTINE False BASICS|ATOMIC|MODELQ BKHSGO True pending
218 readbf.f READBF SUBROUTINE False BASICS True pending
219 rechck.f RECHCK SUBROUTINE False BASICS|ATOMIC|MODELQ OPACF1|RTEFR1 True pending
220 reflev.f REFLEV SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT False pending
221 reiman.f REIMAN FUNCTION True REIMAN False src/math/reiman.rs done
222 resolv.f RESOLV SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR|ARRAY1|icnrsp NEWPOP|TAUFR1|TIMING|OPACF1|RTEFR1|ROSSTD|STEQEQ|CONOUT|ELCOR|OPAINI|RATES1|PRD True pending
223 rhoeos.f RHOEOS FUNCTION False BASICS|MODELQ PRSENT|RHOEOS False pending
224 rhonen.f RHONEN SUBROUTINE False BASICS|MODELQ ELDENS False pending
225 rhsgen.f RHSGEN SUBROUTINE False BASICS|ATOMIC|MODELQ|ARRAY1|ALIPAR|CUBCON MATINV|STATE|RATMAT|COMPT0|SABOLF|CONVEC|LEVGRP False pending
226 rossop.f ROSSOP SUBROUTINE False BASICS|ATOMIC|MODELQ|ALIPAR WNSTOR|STEQEQ|ELDENS|OPACF0|MEANOP|MEANOPT False pending
227 rosstd.f ROSSTD SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|ALIPAR True pending
228 rte_sc.f RTE_SC SUBROUTINE True BASICS False src/math/rte_sc.rs done
229 rteang.f RTEANG SUBROUTINE False BASICS|MODELQ|ALIPAR|EXTINT|SURFEX GAULEG False pending
230 rtecf0.f RTECF0 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|auxcbc|AUXRTE False pending
231 rtecf1.f RTECF1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|comgfs|AUXRTE|EXTINT|SURFEX RTEFE2|RTESOL|RTECF0 True pending
232 rtecmc.f RTECMC SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|comgfs|AUXRTE MATINV|OPACF1|RTECF0 False pending
233 rtecmu.f RTECMU SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|AUXRTE RTESOL|OPACF1|RTECF0|GAULEG True pending
234 rtecom.f RTECOM SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT|comgfs|AUXRTE OPACF1|RTECF0|RTECF1 False pending
235 rtedf1.f RTEDF1 SUBROUTINE False BASICS|MODELQ|ALIPAR|OPTDPT False src/math/rtedf1.rs done
236 rtedf2.f RTEDF2 SUBROUTINE False BASICS|MODELQ|ALIPAR False pending
237 rtefe2.f RTEFE2 SUBROUTINE True BASICS False src/math/rtefe2.rs done
238 rtefr1.f RTEFR1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT MATINV|RTESOL|RTEDF1|RTECF1|RTEDF2|MINV3 True pending
239 rteint.f RTEINT SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT MATINV|OPACF1 True pending
240 rtesol.f RTESOL SUBROUTINE True BASICS False src/math/rtesol.rs done
241 russel.f RUSSEL SUBROUTINE False BASICS|MODELQ|COMFH1 MPARTF True pending
242 rybchn.f RYBCHN SUBROUTINE False BASICS|ITERAT|MODELQ|ALIPAR|ARRAY1|rybpgs|grdpra PGSET|ELDENS True pending
243 rybene.f RYBENE SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|RYBMTX|deridt|CUBCON CONVEC False pending
244 rybheq.f RYBHEQ SUBROUTINE False BASICS|MODELQ|rybpgs|grdpra OPACF1|RTEFR1|WNSTOR|STEQEQ|ELDENS|ELCOR|OPAINI|PGSET True pending
245 rybmat.f RYBMAT SUBROUTINE False BASICS|MODELQ|ALIPAR|ARRAY1|dsctva|RYBMTX False pending
246 rybsol.f RYBSOL SUBROUTINE False BASICS|MODELQ|ATOMIC|ALIPAR|ARRAY1|ITERAT|imodlc|RYBMTX RYBMAT|RTEFR1|ROSSTD|OPACTR|LINEQS|STEQEQ|ALIFR1|TRIDAG|RYBCHN|OPACFD True pending
247 sabolf.f SABOLF SUBROUTINE False BASICS|ATOMIC|MODELQ PARTF False pending
248 sbfch.f SBFCH FUNCTION True SBFCH False src/math/sbfch.rs done
249 sbfhe1.f SBFHE1 FUNCTION False BASICS|ATOMIC SBFHE1|QUIT True src/math/sbfhe1.rs done
250 sbfhmi.f SBFHMI FUNCTION True SBFHMI False src/math/sbfhmi.rs done
251 sbfhmi_old.f SBFHMI_OLD FUNCTION True SBFHMI_OLD False src/math/sbfhmi_old.rs done
252 sbfoh.f SBFOH FUNCTION True SBFOH False src/math/sbfoh.rs done
253 setdrt.f SETDRT SUBROUTINE False BASICS|MODELQ|RHODER False pending
254 settrm.f SETTRM SUBROUTINE False tdflag|tdedge|THERM|TABLTD PRSENT True pending
255 sffhmi.f SFFHMI FUNCTION True SFFHMI False src/math/sffhmi.rs done
256 sffhmi_add.f SFFHMI_ADD FUNCTION True SFFHMI_ADD False src/math/sffhmi_add.rs done
257 sghe12.f SGHE12 FUNCTION True SGHE12 False src/math/sghe12.rs done
258 sgmer0.f SGMER0 SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
259 sgmer1.f SGMER1 SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
260 sgmerd.f SGMERD SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/sgmer.rs done
261 sigave.f SIGAVE SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR True pending
262 sigk.f SIGK FUNCTION False BASICS|ATOMIC SPSIGK|SIGK False pending
263 sigmar.f SIGMAR FUNCTION False BASICS SIGMAR|LAGUER True pending
264 solve.f SOLVE SUBROUTINE False BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|CMATZD MATINV|PRCHAN|RHSGEN|WNSTOR|MATGEN True pending
265 solves.f SOLVES SUBROUTINE False BASICS|ITERAT|MODELQ|ARRAY1|ALIPAR|STOMAT|CMATZD MATINV|PRCHAN|RHSGEN|WNSTOR|MATGEN True pending
266 spsigk.f SPSIGK SUBROUTINE True CARBON False src/math/spsigk.rs done
267 srtfrq.f SRTFRQ SUBROUTINE False BASICS|ATOMIC|MODELQ INDEXX|QUIT True pending
268 stark0.f STARK0 SUBROUTINE True False src/math/stark0.rs done
269 starka.f STARKA FUNCTION False BASICS|MODELQ STARKA False src/math/starka.rs done
270 start.f START SUBROUTINE False BASICS|hediff True pending
271 state.f STATE SUBROUTINE False BASICS|ATOMIC|MODELQ|terden|PFSTDS OPFRAC|PARTF True pending
272 steqeq.f STEQEQ SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT|POPSTR|PPAPAR LEVSOL|RATMAT|SABOLF|MOLEQ False pending
273 switch.f SWITCH SUBROUTINE False BASICS|ATOMIC|MODELQ True pending
274 szirc.f SZIRC SUBROUTINE True EINT False src/math/szirc.rs done
275 tabini.f TABINI SUBROUTINE False BASICS|MODELQ|ATOMIC|eletab|abntab|intcff True pending
276 tabint.f TABINT SUBROUTINE False BASICS|MODELQ|ATOMIC|intcff False pending
277 taufr1.f TAUFR1 SUBROUTINE False BASICS|MODELQ|ALIPAR|ITERAT|OPTDPT False pending
278 tdpini.f TDPINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR|ALIPAR GFREE0 False src/math/tdpini.rs done
279 temcor.f TEMCOR SUBROUTINE False BASICS|MODELQ|ARRAY1|ALIPAR|CUBCON MEANOP|WNSTOR|STEQEQ|ELDENS|OPACF0|CONVEC True pending
280 temper.f TEMPER SUBROUTINE False BASICS|MODELQ|ALIPAR|FACTRS|PRSAUX|FLXAUX WNSTOR|TLOCAL|STEQEQ|ELDENS|OPACF0|MEANOP|MEANOPT True pending
281 timing.f TIMING SUBROUTINE False True pending
282 tiopf.f TIOPF SUBROUTINE True False src/math/tiopf.rs done
283 tlocal.f TLOCAL SUBROUTINE False BASICS|MODELQ|FACTRS|FLXAUX QUARTC False pending
284 tlusty.f TLUSTY UNKNOWN False BASICS|ITERAT|ALIPAR TIMING True pending
285 topbas.f TOPBAS FUNCTION False TOPB TOPBAS True pending
286 traini.f TRAINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ODFPAR False src/math/traini.rs done
287 tridag.f TRIDAG SUBROUTINE True False src/math/tridag.rs done
288 trmder.f TRMDER SUBROUTINE False BASICS|derdif|terden|adiaba ELDENS False pending
289 trmdrt.f TRMDRT SUBROUTINE False BASICS|tdedge|CC|tdflag|CONVOUT PRSENT False pending
290 ubeta.f UBETA FUNCTION True UBETA|LAGRAN False src/math/ubeta.rs done
291 vern16.f VERN16 FUNCTION True BASICS VERN16 False src/math/vern16.rs done
292 vern18.f VERN18 FUNCTION True BASICS VERN18 False src/math/vern18.rs done
293 vern20.f VERN20 FUNCTION True BASICS VERN20 False src/math/vern20.rs done
294 vern26.f VERN26 FUNCTION True BASICS VERN26 False src/math/vern26.rs done
295 verner.f VERNER FUNCTION False BASICS|ATOMIC QUIT|VERNER False src/math/verner.rs done
296 visini.f VISINI SUBROUTINE False BASICS|ATOMIC|MODELQ|ITERAT True pending
297 voigt.f VOIGT FUNCTION True VOIGT False src/math/voigt.rs done
298 voigte.f VOIGTE FUNCTION True VOIGTE False src/math/voigte.rs done
299 wn.f WN FUNCTION True BASICS WN False src/math/wn.rs done
300 wnstor.f WNSTOR SUBROUTINE False BASICS|ATOMIC|MODELQ False src/math/wnstor.rs done
301 xenini.f XENINI SUBROUTINE False BASICS|MODELQ True pending
302 xk2dop.f XK2DOP FUNCTION True XK2DOP False src/math/xk2dop.rs done
303 yint.f YINT FUNCTION True YINT False src/math/interpolate.rs done
304 ylintp.f YLINTP FUNCTION True YLINTP False src/math/ylintp.rs done
305 zmrho.f ZMRHO SUBROUTINE False BASICS|MODELQ False src/math/zmrho.rs done

View File

@ -1,434 +0,0 @@
#!/usr/bin/env python3
"""
分析 TLUSTY Fortran 文件提取函数依赖信息
用法:
python3 analyze_fortran.py # 输出 CSV带完整依赖
python3 analyze_fortran.py --tree # 输出依赖树(文本格式)
python3 analyze_fortran.py --priority # 输出重构优先级列表
"""
import os
import re
import glob
import argparse
from collections import defaultdict
def extract_includes(content):
"""提取 INCLUDE 文件列表"""
includes = re.findall(r"INCLUDE\s*'([^']+)\.FOR'", content, re.IGNORECASE)
return [inc for inc in includes if inc.upper() != 'IMPLIC']
def extract_commons(content):
"""提取 COMMON 块名称"""
# 匹配 COMMON/NAME/ 或 common/name/
commons = re.findall(r'(?i)^\s*COMMON\s*/(\w+)/', content, re.MULTILINE)
return list(set(commons))
# Fortran 内置函数列表(不需要追踪)
FORTRAN_INTRINSICS = {
'SIN', 'COS', 'TAN', 'ASIN', 'ACOS', 'ATAN', 'ATAN2',
'SINH', 'COSH', 'TANH',
'EXP', 'LOG', 'LOG10', 'LOG2',
'SQRT', 'ABS', 'MOD', 'SIGN',
'MAX', 'MIN', 'MAX0', 'MIN0', 'MAX1', 'MIN1', 'AMAX0', 'AMIN0',
'INT', 'IFIX', 'IDINT', 'FLOAT', 'SNGL', 'DBLE', 'CMPLX',
'REAL', 'AIMAG', 'CONJG',
'ICHAR', 'CHAR', 'INDEX', 'LEN', 'LGE', 'LGT', 'LLE', 'LLT',
'DOT_PRODUCT', 'MATMUL', 'TRANSPOSE', 'RESHAPE',
'SIZE', 'SHAPE', 'LBOUND', 'UBOUND',
'ALLOCATED', 'ALLOCATE', 'DEALLOCATE',
'KIND', 'SELECTED_REAL_KIND', 'SELECTED_INT_KIND',
'DIGITS', 'EPSILON', 'HUGE', 'TINY', 'PRECISION', 'RANGE',
'FLOOR', 'CEILING', 'NINT', 'ANINT',
'ADJUSTL', 'ADJUSTR', 'TRIM', 'REPEAT', 'SCAN', 'VERIFY',
'PRESENT', 'ASSOCIATED',
# TLUSTY 常用数学函数
'ERF', 'ERFC', 'GAMMA', 'LOG_GAMMA',
}
def extract_calls(content, known_functions=None):
"""提取 CALL 语句和 FUNCTION 调用
Args:
content: Fortran 源码
known_functions: 已知的函数名集合用于区分函数调用和数组访问
"""
calls = set()
# 1. 提取 CALL 语句(支持有括号和无括号两种形式)
# CALL NAME(...) 或 CALL NAME
call_stmts = re.findall(r'(?i)CALL\s+(\w+)(?:\s*\(|\s*$|\s*\n)', content)
calls.update(c.upper() for c in call_stmts)
# 2. 提取可能的 FUNCTION 调用
if known_functions:
# 只匹配已知函数名
func_assign = re.findall(r'(?i)=\s*([A-Z][A-Z0-9]*)\s*\(', content)
calls.update(f.upper() for f in func_assign
if f.upper() in known_functions and f.upper() not in FORTRAN_INTRINSICS)
func_expr = re.findall(r'(?i)[=(,]\s*([A-Z][A-Z0-9]*)\s*\(', content)
calls.update(f.upper() for f in func_expr
if f.upper() in known_functions and f.upper() not in FORTRAN_INTRINSICS)
return list(calls)
def has_file_io(content):
"""检查是否有文件 I/O"""
patterns = [
r'OPEN\s*\(',
r'READ\s*\(\s*\d+',
r'WRITE\s*\(\s*\d+',
r'write\s*\(',
r'read\s*\(',
]
for p in patterns:
if re.search(p, content, re.IGNORECASE):
return True
return False
def extract_unit_info(content, filename):
"""提取单元信息"""
units = []
# 匹配 SUBROUTINE
sub_match = re.search(r'(?i)^\s*SUBROUTINE\s+(\w+)', content, re.MULTILINE)
if sub_match:
units.append(('SUBROUTINE', sub_match.group(1).upper()))
# 匹配 FUNCTION
func_match = re.search(r'(?i)^\s*(?:REAL(?:\*\d+)?|INTEGER(?:\*\d+)?|DOUBLE\s*PRECISION)?\s*FUNCTION\s+(\w+)', content, re.MULTILINE)
if func_match:
units.append(('FUNCTION', func_match.group(1).upper()))
# 匹配 BLOCK DATA
block_match = re.search(r'(?i)^\s*BLOCK\s*DATA\s+(\w+)?', content, re.MULTILINE)
if block_match:
name = block_match.group(1).upper() if block_match.group(1) else '_UNNAMED_'
units.append(('BLOCK DATA', name))
# 如果都没匹配到,使用文件名
if not units:
base = os.path.splitext(filename)[0]
units.append(('UNKNOWN', base.upper()))
return units
# 特殊映射:一个 Rust 文件实现多个 Fortran 函数
SPECIAL_MAPPINGS = {
# Rust 文件名 -> [Fortran 函数名列表]
'gfree': ['gfree0', 'gfreed', 'gfree1'],
'interpolate': ['yint', 'lagran'],
'sgmer': ['sgmer0', 'sgmer1', 'sgmerd'],
'ctdata': ['hction', 'hctrecom'],
'cross': ['cross', 'crossd'],
'expint': ['eint', 'expinx'],
'erfcx': ['erfcx', 'erfcin'],
'lineqs': ['lineqs', 'lineqs_nr'],
'gamsp': ['gamsp'], # alias
'bhe': ['bhe', 'bhed', 'bhez'], # 流体静力学平衡方程
'comset': ['comset'], # Compton 散射参数设置
'ghydop': ['ghydop'], # 氢不透明度 (Gomez 表)
'levgrp': ['levgrp'], # 能级分组
'profil': ['profil'], # 标准吸收轮廓
'linspl': ['linspl'], # 谱线轮廓设置
}
def find_rust_module(fortran_name, rust_dir):
"""查找对应的 Rust 模块"""
# 先检查直接匹配
rust_file = os.path.join(rust_dir, f"{fortran_name}.rs")
if os.path.exists(rust_file):
return f"src/math/{fortran_name}.rs"
# 检查特殊映射
for rust_mod, fortran_funcs in SPECIAL_MAPPINGS.items():
if fortran_name in fortran_funcs:
return f"src/math/{rust_mod}.rs"
return ""
def get_transitive_deps(unit_name, units_dict, visited=None):
"""递归获取所有传递调用依赖"""
if visited is None:
visited = set()
if unit_name in visited:
return set()
visited.add(unit_name)
if unit_name not in units_dict:
return set()
direct_calls = units_dict[unit_name].get('call_deps', [])
all_deps = set(direct_calls)
for dep in direct_calls:
all_deps.update(get_transitive_deps(dep, units_dict, visited.copy()))
return all_deps
def get_pending_deps(unit_name, units_dict, visited=None):
"""获取尚未实现的直接依赖"""
if unit_name not in units_dict:
return []
calls = units_dict[unit_name].get('call_deps', [])
pending = [d for d in calls if d not in units_dict or units_dict[d].get('status') != 'done']
return pending
def get_transitive_pending_deps(unit_name, units_dict, visited=None):
"""递归获取所有传递的未实现依赖"""
if visited is None:
visited = set()
if unit_name in visited:
return set()
visited.add(unit_name)
if unit_name not in units_dict:
return set()
direct_calls = units_dict[unit_name].get('call_deps', [])
# 未实现的直接依赖
pending_deps = set(d for d in direct_calls if d not in units_dict or units_dict[d].get('status') != 'done')
# 递归获取所有依赖的未实现依赖
for dep in direct_calls:
pending_deps.update(get_transitive_pending_deps(dep, units_dict, visited.copy()))
return pending_deps
def get_transitive_commons(unit_name, units_dict, visited=None):
"""递归获取所有传递 COMMON 依赖"""
if visited is None:
visited = set()
if unit_name in visited:
return set()
visited.add(unit_name)
if unit_name not in units_dict:
return set()
direct_commons = set(units_dict[unit_name].get('common_deps', []))
direct_calls = units_dict[unit_name].get('call_deps', [])
all_commons = direct_commons.copy()
for dep in direct_calls:
all_commons.update(get_transitive_commons(dep, units_dict, visited.copy()))
return all_commons
def calculate_depth(unit_name, units_dict, memo=None):
"""计算依赖深度叶子节点深度为0"""
if memo is None:
memo = {}
if unit_name in memo:
return memo[unit_name]
if unit_name not in units_dict:
return 0
calls = units_dict[unit_name].get('call_deps', [])
if not calls:
memo[unit_name] = 0
return 0
max_dep_depth = 0
for dep in calls:
if dep != unit_name: # 避免自引用
max_dep_depth = max(max_dep_depth, calculate_depth(dep, units_dict, memo))
depth = max_dep_depth + 1
memo[unit_name] = depth
return depth
def print_dependency_tree(unit_name, units_dict, indent=0, visited=None, prefix="", show_pending_count=True):
"""打印依赖树(文本格式)"""
if visited is None:
visited = set()
if unit_name in visited:
print(f"{prefix}[循环引用: {unit_name}]")
return
visited.add(unit_name)
if unit_name not in units_dict:
print(f"{prefix}{unit_name} [未找到/未实现]")
return
unit = units_dict[unit_name]
status = unit.get('status', 'pending')
status_mark = "" if status == "done" else ""
# 计算未实现依赖数
pending_count = len(get_pending_deps(unit_name, units_dict))
pending_str = f" ({pending_count}未实现)" if show_pending_count and pending_count > 0 else ""
print(f"{prefix}{status_mark} {unit_name}{pending_str}")
calls = unit.get('call_deps', [])
# 按未实现依赖数排序(未实现多的在前,因为更紧迫)
pending_sorted = sorted(calls, key=lambda d: -len(get_pending_deps(d, units_dict) if d in units_dict else []))
for i, dep in enumerate(pending_sorted):
is_last = (i == len(pending_sorted) - 1)
connector = "└── " if is_last else "├── "
print_dependency_tree(dep, units_dict, indent + 1, visited.copy(), prefix + connector, show_pending_count)
def main():
parser = argparse.ArgumentParser(description='分析 TLUSTY Fortran 文件依赖')
parser.add_argument('--tree', metavar='UNIT', help='输出指定单元的依赖树')
parser.add_argument('--priority', action='store_true', help='输出重构优先级列表')
parser.add_argument('--full', action='store_true', help='输出完整传递依赖')
args = parser.parse_args()
extracted_dir = "/home/fmq/program/tlusty/tl208-s54/rust/tlusty/extracted"
rust_dir = "/home/fmq/program/tlusty/tl208-s54/rust/src/math"
# 第一遍:收集所有已定义的 SUBROUTINE 和 FUNCTION 名称
all_defined_units = set()
fortran_files = sorted(glob.glob(os.path.join(extracted_dir, "*.f")))
for fpath in fortran_files:
with open(fpath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
units = extract_unit_info(content, os.path.basename(fpath))
for unit_type, unit_name in units:
all_defined_units.add(unit_name)
# 第二遍:收集所有单元信息(使用已知函数名来过滤调用)
units_dict = {}
for fpath in fortran_files:
fname = os.path.basename(fpath)
base_name = os.path.splitext(fname)[0]
with open(fpath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
includes = extract_includes(content)
commons = extract_commons(content)
calls = extract_calls(content, known_functions=all_defined_units)
io = has_file_io(content)
units = extract_unit_info(content, fname)
is_pure = len(includes) <= 1 and len(commons) == 0 and not io
rust_mod = find_rust_module(base_name, rust_dir)
status = "done" if rust_mod else "pending"
for unit_type, unit_name in units:
units_dict[unit_name] = {
'fortran_file': fname,
'unit_type': unit_type,
'is_pure': is_pure,
'common_deps': includes + commons,
'call_deps': calls,
'has_io': io,
'rust_module': rust_mod,
'status': status,
}
# --tree 模式:输出依赖树
if args.tree:
unit_name = args.tree.upper()
if unit_name in units_dict:
unit = units_dict[unit_name]
trans_pending = get_transitive_pending_deps(unit_name, units_dict)
trans_calls = get_transitive_deps(unit_name, units_dict)
status_mark = "" if unit['status'] == "done" else ""
print(f"依赖树: {unit_name} {status_mark}")
print("=" * 60)
print(f"直接依赖: {len(unit['call_deps'])}, 传递依赖: {len(trans_calls)}, "
f"未实现: {len(trans_pending)}")
if trans_pending:
print(f"未实现依赖: {', '.join(sorted(trans_pending)[:10])}")
if len(trans_pending) > 10:
print(f" ... 还有 {len(trans_pending) - 10}")
print("-" * 60)
print_dependency_tree(unit_name, units_dict)
else:
print(f"未找到单元: {unit_name}")
# 尝试模糊匹配
matches = [u for u in units_dict if args.tree.lower() in u.lower()]
if matches:
print(f"可能的匹配: {', '.join(matches[:10])}")
return
# --priority 模式:输出重构优先级
if args.priority:
# 计算每个单元的依赖深度和传递依赖数
priority_list = []
memo = {}
for unit_name, unit in units_dict.items():
if unit['status'] == 'done':
continue
# 跳过无法识别程序单元的文件(如纯注释文件)
if unit['unit_type'] == 'UNKNOWN':
continue
depth = calculate_depth(unit_name, units_dict, memo)
trans_calls = len(get_transitive_deps(unit_name, units_dict))
trans_commons = len(get_transitive_commons(unit_name, units_dict))
pending_deps = len(get_pending_deps(unit_name, units_dict))
trans_pending = len(get_transitive_pending_deps(unit_name, units_dict))
priority_list.append({
'name': unit_name,
'depth': depth,
'direct_calls': len(unit['call_deps']),
'trans_calls': trans_calls,
'direct_commons': len(unit['common_deps']),
'trans_commons': trans_commons,
'pending_deps': pending_deps,
'trans_pending': trans_pending,
'has_io': unit['has_io'],
'is_pure': unit['is_pure'],
})
# 按优先级排序无IO > 未实现依赖少 > 深度低
priority_list.sort(key=lambda x: (x['has_io'], x['trans_pending'], x['depth'], x['trans_calls']))
print("重构优先级列表 (优先无IO按未实现依赖排序)")
print("=" * 100)
print(f"{'单元名':<20} {'未实现':>6} {'传递未实现':>10} {'深度':>4} {'直接调用':>8} {'传递调用':>8} {'IO':>4}")
print("-" * 100)
for item in priority_list[:100]: # 显示前100个
io_mark = "" if item['has_io'] else ""
print(f"{item['name']:<20} {item['pending_deps']:>6} {item['trans_pending']:>10} "
f"{item['depth']:>4} {item['direct_calls']:>8} {item['trans_calls']:>8} {io_mark:>4}")
return
# 默认模式:输出 CSV带完整依赖
if args.full:
print("fortran_file,unit_name,unit_type,is_pure,common_deps,call_deps,"
"trans_commons,trans_calls,has_io,rust_module,status")
else:
print("fortran_file,unit_name,unit_type,is_pure,common_deps,call_deps,has_io,rust_module,status")
memo = {}
for unit_name, unit in units_dict.items():
if args.full:
trans_commons = get_transitive_commons(unit_name, units_dict)
trans_calls = get_transitive_deps(unit_name, units_dict)
print(f"{unit['fortran_file']},{unit_name},{unit['unit_type']},{unit['is_pure']},"
f"\"{'|'.join(unit['common_deps'])}\",\"{'|'.join(unit['call_deps'])}\","
f"\"{'|'.join(trans_commons)}\",\"{'|'.join(trans_calls)}\","
f"{unit['has_io']},{unit['rust_module']},{unit['status']}")
else:
print(f"{unit['fortran_file']},{unit_name},{unit['unit_type']},{unit['is_pure']},"
f"\"{'|'.join(unit['common_deps'])}\",\"{'|'.join(unit['call_deps'])}\","
f"{unit['has_io']},{unit['rust_module']},{unit['status']}")
if __name__ == "__main__":
main()

View File

@ -1,438 +0,0 @@
#!/usr/bin/env python3
"""
Fortran 源文件提取数组数据生成 Rust data.rs
用法:
python3 scripts/extract_fortran_data.py
输出: src/data.rs
"""
import re
from pathlib import Path
def parse_fortran_file(filepath: Path, global_params: dict = None) -> list[dict]:
"""解析单个 Fortran 文件中的数组
Args:
filepath: Fortran 文件路径
global_params: include 文件中提取的全局参数表
"""
if global_params is None:
global_params = {}
with open(filepath, 'r') as f:
content = f.read()
arrays = {}
# 0. 预处理
# 先清理每行的 Fortran 注释 (! 后面的内容)
# 同时移除 Fortran 77 风格的注释行 (以 C 或 * 开头)
lines = content.split('\n')
cleaned_lines = []
for line in lines:
# Fortran 77 注释行 (第1列是 C, c, *, 或完全空行)
if len(line) > 0 and line[0] in 'Cc*':
continue # 跳过整行注释
# Fortran 90 行内注释
if '!' in line:
line = line.split('!')[0]
cleaned_lines.append(line)
# 再合并 Fortran 续行 (第6列是 *, +, &, 数字, 或字母)
# Fortran 允许使用字母作为续行标记 (A, B, C, ... 用于超过9个续行)
merged_lines = []
for line in cleaned_lines:
# 检查是否是续行 (第6列是 *, +, &, 数字, 或非空格字符)
if len(line) >= 6 and line[5] != ' ' and line[5] not in '\n\r\t':
# 续行: 追加到上一行 (去掉前6列)
if merged_lines:
merged_lines[-1] += ' ' + line[6:].strip()
else:
merged_lines.append(line)
content = '\n'.join(merged_lines)
# 1. 首先解析所有 parameter 语句,建立局部常量表
# 合并全局参数和局部参数
param_table = dict(global_params) # 复制全局参数
param_pattern = r'parameter\s*\(([^)]+)\)'
for match in re.finditer(param_pattern, content, re.IGNORECASE):
params_str = match.group(1)
for param in params_str.split(','):
param = param.strip()
if '=' in param:
name, val = param.split('=', 1)
name = name.strip().lower()
val = val.strip().lower()
# 尝试解析为整数或浮点数
try:
# 先尝试整数
if '.' not in val and 'e' not in val and 'd' not in val:
param_table[name] = int(val)
else:
# 浮点数,转换为整数(用于数组维度)
val = val.replace('d', 'e')
param_table[name] = int(float(val))
except ValueError:
pass
# 2. 解析 dimension 语句
# dimension p4a(22), p4b(10,28), adi(nni), ...
# 注意: 使用 [ \t] 代替 \s 避免跨行匹配
dim_pattern = r'dimension[ \t]+([a-z0-9_,() \t]+)'
for match in re.finditer(dim_pattern, content, re.IGNORECASE):
dim_str = match.group(1)
# 清理 dim_str - 移除可能包含的下一个关键字
for keyword in ['\nreal', '\ninteger', '\ncomplex', '\nlogical', '\ncharacter',
'\ndimension', '\ndata', '\nparameter', '\nequivalence']:
if keyword in dim_str.lower():
dim_str = dim_str[:dim_str.lower().find(keyword)]
break
arr_pattern = r'(\w+)\s*\(([^)]+)\)'
for arr_match in re.finditer(arr_pattern, dim_str):
name = arr_match.group(1).lower()
dims_str = arr_match.group(2)
# 解析维度,支持常量和 parameter 变量
dims = []
valid = True
for d in dims_str.split(','):
d = d.strip().lower()
if d in param_table:
dims.append(param_table[d])
else:
try:
dims.append(int(d))
except ValueError:
valid = False
break
if valid and dims:
arrays[name] = {"name": name, "dims": dims, "data": None, "source": filepath.name}
# 2.5 解析类型声明中的数组
# REAL frac(MR), INTEGER arr(10), REAL*4 arr(10), CHARACTER*10 str(5), etc.
# 注意: 使用 [ \t] 代替 \s 避免跨行匹配
type_decl_pattern = r'(real(?:\*[\d]+)?|integer(?:\*[\d]+)?|complex(?:\*[\d]+)?|logical(?:\*[\d]+)?|character(?:\*[\d]+)?)[ \t]+([a-z0-9_,() \t]+)'
for match in re.finditer(type_decl_pattern, content, re.IGNORECASE):
decl_str = match.group(2)
# 清理 decl_str - 移除可能包含的下一个类型声明
for keyword in ['\nreal', '\ninteger', '\ncomplex', '\nlogical', '\ncharacter',
'\ndimension', '\ndata', '\nparameter', '\nequivalence']:
if keyword in decl_str.lower():
decl_str = decl_str[:decl_str.lower().find(keyword)]
break
# 匹配变量名(维度)
arr_pattern = r'(\w+)\s*\(([^)]+)\)'
for arr_match in re.finditer(arr_pattern, decl_str):
name = arr_match.group(1).lower()
if name in arrays:
continue # 已有定义
dims_str = arr_match.group(2)
# 解析维度
dims = []
valid = True
for d in dims_str.split(','):
d = d.strip().lower()
if d in param_table:
dims.append(param_table[d])
else:
try:
dims.append(int(d))
except ValueError:
valid = False
break
if valid and dims:
arrays[name] = {"name": name, "dims": dims, "data": None, "source": filepath.name}
# 3. 解析 data 语句 (支持多行)
# data name / val1, val2, ... /
data_pattern = r'data\s+(\w+)\s*/\s*([^/]+)\s*/'
for match in re.finditer(data_pattern, content, re.IGNORECASE | re.DOTALL):
name = match.group(1).lower()
data_str = match.group(2)
if name not in arrays:
arrays[name] = {"name": name, "dims": [], "data": None, "source": filepath.name}
values = parse_data_values(data_str)
arrays[name]["data"] = values
# 4. 处理 parameter 语句中的标量常量(用于导出)
for match in re.finditer(param_pattern, content, re.IGNORECASE):
params_str = match.group(1)
for param in params_str.split(','):
param = param.strip()
if '=' in param:
name, val = param.split('=', 1)
name = name.strip().lower()
val = val.strip().lower()
if name not in arrays:
try:
val = val.replace('d', 'e')
arrays[name] = {"name": name, "dims": [], "data": [float(val)], "source": filepath.name, "is_param": True}
except ValueError:
pass
return list(arrays.values())
def parse_data_values(data_str: str) -> list[float]:
"""解析 DATA 语句中的数值,处理重复语法如 7*1.387"""
values = []
# 清理
lines = data_str.split('\n')
cleaned_lines = []
for line in lines:
line = line.strip()
if line.startswith('*'):
line = line[1:].strip()
cleaned_lines.append(line)
data_str = ' '.join(cleaned_lines)
for part in data_str.split(','):
part = part.strip()
if not part:
continue
# 移除末尾的 / (DATA 语句结束符)
part = part.rstrip('/')
# 处理重复语法: "7*1.387"
if '*' in part and not part.startswith('-'):
match = re.match(r'(\d+)\s*\*\s*(-?[\d.]+)', part)
if match:
count = int(match.group(1))
val = float(match.group(2))
values.extend([val] * count)
continue
try:
# 处理 Fortran 科学计数法
# 处理 "- 14.2" 这种中间有空格的负数
val = part.replace('d', 'e').replace('D', 'e')
# 移除负号和数字之间的空格
val = re.sub(r'-\s+(\d)', r'-\1', val)
# 移除科学计数法中的多余空格 (如 "1.48 e-2" -> "1.48e-2")
val = re.sub(r'(\d)\s+([eEdD])', r'\1\2', val)
values.append(float(val))
except ValueError:
pass
return values
def generate_data_rs(all_arrays: dict[str, list[dict]]) -> str:
"""生成 src/data.rs 内容"""
lines = []
lines.append("//! Fortran 数据数组自动导出")
lines.append("//!")
lines.append("//! 由 extract_fortran_data.py 自动生成,请勿手动修改")
lines.append("")
# 收集已使用的名称,避免重复
used_names = set()
# 按源文件分组
for source, arrays in sorted(all_arrays.items()):
# 过滤有数据的数组
valid_arrays = [a for a in arrays if a.get("data") and len(a["data"]) > 0]
if not valid_arrays:
continue
lines.append(f"// ========== {source} ==========")
lines.append("")
for arr in valid_arrays:
base_name = arr["name"].upper()
# 清理名称中的特殊字符
base_name = re.sub(r'[^A-Z0-9_]', '', base_name)
# 所有变量都添加文件名前缀,避免命名冲突
prefix = Path(source).stem.upper()[:8] # 取文件名前8个字符
name = f"{prefix}_{base_name}"
# 如果加上前缀后仍有冲突,添加序号
if name in used_names:
counter = 1
while f"{name}_{counter}" in used_names:
counter += 1
name = f"{name}_{counter}"
used_names.add(name)
dims = arr["dims"]
data = arr["data"]
if not data:
continue
total_size = len(data)
# 跳过单值 parameter
if arr.get("is_param") and total_size == 1:
lines.append(f"/// {arr['name']} (from {source})")
lines.append(f"pub const {name}: f64 = {data[0]};")
lines.append("")
continue
if len(dims) == 0:
# 未知维度,用 Vec 格式输出以便检查
lines.append(f"/// {arr['name']} (from {source}, 未知维度,共 {len(data)} 个值)")
lines.append(f"pub const {name}: [f64; {len(data)}] = [")
for i, val in enumerate(data):
if i % 10 == 0:
lines.append(" ")
lines[-1] += f"{val},"
lines.append("];")
lines.append("")
elif len(dims) == 1:
# 1D 数组 - 检查数据量是否匹配
expected_size = dims[0]
if len(data) != expected_size:
print(f"警告: {name} 期望 {expected_size} 个值,实际 {len(data)} 个,跳过")
continue
lines.append(f"/// {arr['name']}({dims[0]}) from {source}")
lines.append(f"pub const {name}: [f64; {dims[0]}] = [")
for i, val in enumerate(data):
if i % 10 == 0:
lines.append(" ")
lines[-1] += f"{val},"
lines.append("];")
lines.append("")
elif len(dims) == 2:
# 2D 数组 - 直接转换为 Rust 行优先格式
nj, ni = dims[0], dims[1]
expected_size = nj * ni
if len(data) < expected_size:
print(f"警告: {name} 期望 {expected_size} 个值,实际 {len(data)} 个,跳过")
continue
lines.append(f"/// {arr['name']}({nj}, {ni}) from {source}")
lines.append(f"/// 已转换为 Rust 行优先格式")
lines.append(f"pub const {name}: [[f64; {ni}]; {nj}] = [")
# 列优先 → 行优先 转换
for j in range(nj):
row = []
for i in range(ni):
idx = j + i * nj # Fortran 列优先索引
row.append(str(data[idx]))
lines.append(f" [{','.join(row)}],")
lines.append("];")
lines.append("")
# 不再需要转换函数和 getter2D 数组直接生成为 const
return '\n'.join(lines)
def parse_include_files(extracted_dir: Path) -> dict:
"""解析 .FOR include 文件中的全局参数"""
global_params = {}
# 扫描 .FOR 文件
for for_file in extracted_dir.glob("*.FOR"):
try:
content = for_file.read_text()
except:
# 也尝试 tlusty/ 根目录
for_file = Path("tlusty") / for_file.name
if for_file.exists():
content = for_file.read_text()
else:
continue
# 清理注释
lines = []
for line in content.split('\n'):
if '!' in line:
line = line.split('!')[0]
lines.append(line)
content = '\n'.join(lines)
# 解析 parameter 语句
param_pattern = r'parameter\s*\(([^)]+)\)'
for match in re.finditer(param_pattern, content, re.IGNORECASE):
params_str = match.group(1)
for param in params_str.split(','):
param = param.strip()
if '=' in param:
name, val = param.split('=', 1)
name = name.strip().lower()
val = val.strip().lower()
try:
if '.' not in val and 'e' not in val and 'd' not in val:
global_params[name] = int(val)
else:
val = val.replace('d', 'e')
global_params[name] = int(float(val))
except ValueError:
pass
return global_params
def main():
# 扫描 tlusty/extracted 目录
extracted_dir = Path("tlusty/extracted")
if not extracted_dir.exists():
print(f"错误: 目录不存在: {extracted_dir}")
return
# 首先解析 include 文件中的全局参数
global_params = parse_include_files(extracted_dir)
print(f"从 .FOR include 文件中提取了 {len(global_params)} 个全局参数")
all_arrays = {}
# 扫描所有 .f 文件
for fortran_file in sorted(extracted_dir.glob("*.f")):
arrays = parse_fortran_file(fortran_file, global_params)
if arrays:
all_arrays[fortran_file.name] = arrays
print(f"解析: {fortran_file.name} -> {len(arrays)} 个数组")
# 统计
total_arrays = sum(len(arrs) for arrs in all_arrays.values())
arrays_with_data = sum(
1 for arrs in all_arrays.values()
for a in arrs if a.get("data") and len(a["data"]) > 0
)
arrays_2d = sum(
1 for arrs in all_arrays.values()
for a in arrs if len(a.get("dims", [])) == 2 and a.get("data")
)
print()
print("=" * 60)
print(f"总计: {total_arrays} 个数组, {arrays_with_data} 个有数据, {arrays_2d} 个 2D 数组")
print("=" * 60)
# 生成 data.rs
output_path = Path("src/data.rs")
rust_code = generate_data_rs(all_arrays)
with open(output_path, 'w') as f:
f.write(rust_code)
print(f"已生成: {output_path}")
print()
print("在 lib.rs 或 main.rs 中添加:")
print(" pub mod data;")
print()
print("使用方法:")
print(" use crate::data::{TT, PN, get_p4b};")
print(" let p4b = get_p4b(); // 自动初始化并返回 2D 数组")
if __name__ == "__main__":
main()

View File

@ -1,205 +0,0 @@
#!/usr/bin/env python3
"""
Fortran DATA 语句转换为 Rust 2D 数组
用法:
python3 scripts/fortran_to_rust_array.py tlusty/extracted/pffe.f
输出: Rust 代码片段可直接复制到 .rs 文件中
"""
import re
import sys
from pathlib import Path
def parse_fortran_arrays(filepath: str) -> list[dict]:
"""
解析 Fortran 文件中的数组定义和 DATA 语句
返回: [{"name": "p4a", "dims": [22], "data": [...]}, ...]
"""
with open(filepath, 'r') as f:
content = f.read()
arrays = {}
# 1. 解析 dimension 语句
# dimension p4a(22), p4b(10,28), ...
dim_pattern = r'dimension\s+([a-z0-9_,()\s]+)'
for match in re.finditer(dim_pattern, content, re.IGNORECASE):
dim_str = match.group(1)
# 解析每个数组
arr_pattern = r'(\w+)\s*\(([^)]+)\)'
for arr_match in re.finditer(arr_pattern, dim_str):
name = arr_match.group(1).lower()
dims = [int(d.strip()) for d in arr_match.group(2).split(',')]
arrays[name] = {"name": name, "dims": dims, "data": None}
# 2. 解析 data 语句
# data p4a / val1, val2, ... /
# 或多行:
# data p4b /
# * val1, val2, ...,
# * val3, ... /
# 先找到所有 data 块
data_pattern = r'data\s+(\w+)\s*/\s*([^/]+)\s*/'
for match in re.finditer(data_pattern, content, re.IGNORECASE | re.DOTALL):
name = match.group(1).lower()
data_str = match.group(2)
if name not in arrays:
arrays[name] = {"name": name, "dims": [], "data": None}
# 解析数值
values = parse_data_values(data_str)
arrays[name]["data"] = values
return list(arrays.values())
def parse_data_values(data_str: str) -> list[float]:
"""解析 DATA 语句中的数值,处理重复语法如 7*1.387"""
values = []
# 清理: 移除注释、换行,但保留 * 用于重复语法
data_str = re.sub(r'[cC]\s*$', '', data_str) # 行尾注释
# 移除 Fortran 续行符 * (行首的 *),但保留数据中的 *
lines = data_str.split('\n')
cleaned_lines = []
for line in lines:
line = line.strip()
if line.startswith('*'):
line = line[1:].strip()
cleaned_lines.append(line)
data_str = ' '.join(cleaned_lines)
for part in data_str.split(','):
part = part.strip()
if not part:
continue
# 处理重复语法: "7*1.387" 或 "7*1.387"
if '*' in part and not part.startswith('-'): # 避免把负数当重复
# 检查是否真的是重复语法
match = re.match(r'(\d+)\s*\*\s*(-?[\d.]+)', part)
if match:
count = int(match.group(1))
val = float(match.group(2))
values.extend([val] * count)
continue
try:
values.append(float(part))
except ValueError:
# 跳过无法解析的部分
pass
return values
def generate_rust_code(arrays: list[dict]) -> str:
"""生成 Rust 代码"""
lines = []
lines.append("// 自动生成的数组数据")
lines.append("")
for arr in arrays:
name = arr["name"].upper()
dims = arr["dims"]
data = arr["data"]
if not data:
continue
total_size = len(data)
if len(dims) == 1:
# 1D 数组
lines.append(f"const {name}_RAW: [f64; {total_size}] = [")
for i, val in enumerate(data):
if i % 10 == 0:
lines.append(" ",)
lines[-1] += f"{val},"
lines.append("];")
lines.append(f"static {name}: OnceLock<[f64; {dims[0]}]> = OnceLock::new();")
lines.append("")
elif len(dims) == 2:
# 2D 数组
nj, ni = dims[0], dims[1]
lines.append(f"// {name}: Fortran {name.lower()}({nj}, {ni})")
lines.append(f"const {name}_RAW: [f64; {total_size}] = [")
for i, val in enumerate(data):
if i % 10 == 0:
lines.append(" ")
lines[-1] += f"{val},"
lines.append("];")
lines.append(f"static {name}: OnceLock<[[f64; {ni}]; {nj}]> = OnceLock::new();")
lines.append("")
# 添加转换函数
lines.append("")
lines.append("/// Fortran 列优先 → Rust 行优先")
lines.append("const fn fortran_to_rust_2d<const NJ: usize, const NI: usize>(")
lines.append(" data: &[f64; NJ * NI],")
lines.append(") -> [[f64; NI]; NJ] {")
lines.append(" let mut result = [[0.0; NI]; NJ];")
lines.append(" let mut i = 0;")
lines.append(" while i < NI {")
lines.append(" let mut j = 0;")
lines.append(" while j < NJ {")
lines.append(" result[j][i] = data[j + i * NJ];")
lines.append(" j += 1;")
lines.append(" }")
lines.append(" i += 1;")
lines.append(" }")
lines.append(" result")
lines.append("}")
lines.append("")
# 添加初始化代码
lines.append("// 初始化函数中调用:")
for arr in arrays:
name = arr["name"].upper()
dims = arr["dims"]
if len(dims) == 2 and arr["data"]:
nj, ni = dims[0], dims[1]
lines.append(f"let {name.lower()} = {name}.get_or_init(|| fortran_to_rust_2d::<{nj}, {ni}>(&{name}_RAW));")
return '\n'.join(lines)
def main():
if len(sys.argv) < 2:
print("用法: python3 scripts/fortran_to_rust_array.py <fortran_file>")
print("示例: python3 scripts/fortran_to_rust_array.py tlusty/extracted/pffe.f")
sys.exit(1)
filepath = sys.argv[1]
if not Path(filepath).exists():
print(f"错误: 文件不存在: {filepath}")
sys.exit(1)
print(f"解析: {filepath}")
print("=" * 60)
arrays = parse_fortran_arrays(filepath)
print(f"找到 {len(arrays)} 个数组:")
for arr in arrays:
dims_str = ', '.join(str(d) for d in arr['dims'])
data_count = len(arr['data']) if arr['data'] else 0
print(f" - {arr['name']}({dims_str}): {data_count} 个值")
print()
print("=" * 60)
print("生成的 Rust 代码:")
print("=" * 60)
print(generate_rust_code(arrays))
if __name__ == "__main__":
main()

View File

@ -1,82 +0,0 @@
#!/usr/bin/env python3
"""
生成 Fortran 重构追踪 Markdown 文档
用法: python3 generate_tracking.py > FORTRAN_TRACKING.md
"""
import csv
import os
def main():
csv_path = "/home/fmq/program/tlusty/tl208-s54/rust/fortran_analysis.csv"
with open(csv_path, 'r') as f:
reader = csv.DictReader(f)
rows = list(reader)
# 统计
total = len(rows)
done = sum(1 for r in rows if r['status'] == 'done')
pending = sum(1 for r in rows if r['status'] == 'pending')
pure = sum(1 for r in rows if r['is_pure'] == 'True')
has_io = sum(1 for r in rows if r['has_io'] == 'True')
# 打印 Markdown 头
print("""# Fortran 重构追踪表
> 自动生成请勿手动修改运行 `python3 scripts/generate_tracking.py > FORTRAN_TRACKING.md` 更新
## 统计
| 指标 | 数量 |
|------|------|
| 总单元数 | {total} |
| 已完成 | {done} |
| 待处理 | {pending} |
| 纯函数 | {pure} |
| 有文件 I/O | {has_io} |
| 完成率 | {rate:.1f}% |
## 状态说明
- `done` - 已重构为 Rust
- `pending` - 待处理
- 🔄 `in_progress` - 进行中
- `skip` - 跳过 (I/O 依赖或暂不处理)
## 类型说明
- **纯函数**: COMMON 依赖无文件 I/O无外部调用依赖
- **COMMON 依赖**: 需要状态结构体
- **调用依赖**: 调用其他子程序需要先实现依赖
## 完整追踪表
""".format(total=total, done=done, pending=pending, pure=pure, has_io=has_io, rate=100*done/total))
# 表格头
print("| Fortran 文件 | 单元名 | 类型 | 纯函数 | COMMON 依赖 | 调用依赖 | I/O | Rust 模块 | 状态 |")
print("|-------------|--------|------|--------|-------------|----------|-----|-----------|------|")
for r in rows:
# 状态图标
status_icon = "" if r['status'] == 'done' else ""
# 纯函数标记
pure_mark = "" if r['is_pure'] == 'True' else ""
# I/O 标记
io_mark = "📁" if r['has_io'] == 'True' else ""
# 依赖显示
common_deps = r['common_deps'].replace('|', ', ') if r['common_deps'] else ""
call_deps = r['call_deps'].replace('|', ', ') if r['call_deps'] else ""
# Rust 模块链接
rust_mod = r['rust_module'].replace('src/math/', '') if r['rust_module'] else ""
print(f"| {r['fortran_file']} | {r['unit_name']} | {r['unit_type']} | {pure_mark} | {common_deps} | {call_deps} | {io_mark} | {rust_mod} | {status_icon} |")
if __name__ == "__main__":
main()

1483
src/math/alifr1.rs Normal file

File diff suppressed because it is too large Load Diff

199
src/math/cspec.rs Normal file
View File

@ -0,0 +1,199 @@
//! 碰撞强度计算。
//!
//! 重构自 TLUSTY `cspec.f`
//!
//! 使用 Van Regemorter 公式计算非标准的碰撞率,
//! 遵循 Mihalas (1978, Stellar Atmospheres, 2nd edition) 的建议。
//!
//! ## 碰撞类型 (IC)
//!
//! - IC = -1: 中性粒子Neutrals
//! - IC = -2: 离子Ions
//! - IC = -11: 特殊处理
//! - IC = -12: He I 禁戒跃迁
use crate::state::constants::UN;
/// He I 禁戒跃迁的系数 (CHE1FB)
/// 原始 Fortran DATA 语句:
/// CHE1FB(1,1-4) = 9.63675, -2.22941, -17.30103
/// CHE1FB(2,1-4) = 10.85578, -2.40931, -27.00903
/// CHE1FB(3,1-4) = 8.38043, -2.04791, -7.36621
const CHE1FB: [[f64; 4]; 3] = [
[9.63675, -2.22941, -17.30103, 0.0], // IFORB = 1
[10.85578, -2.40931, -27.00903, 0.0], // IFORB = 2
[8.38043, -2.04791, -7.36621, 0.0], // IFORB = 3
];
/// 指数积分近似系数 (Abramowitz & Stegun)
const EXPIA1: f64 = -0.57721566;
const EXPIA2: f64 = 0.99999193;
const EXPIA3: f64 = -0.24991055;
const EXPIA4: f64 = 0.05519968;
const EXPIA5: f64 = -0.00976004;
const EXPIA6: f64 = 0.00107857;
const EXPIB1: f64 = 0.2677737343;
const EXPIB2: f64 = 8.6347608925;
const EXPIB3: f64 = 18.059016973;
const EXPIB4: f64 = 8.5733287401;
const EXPIC1: f64 = 3.9584969228;
const EXPIC2: f64 = 21.0996530827;
const EXPIC3: f64 = 25.6329561486;
const EXPIC4: f64 = 9.5733223454;
/// 计算碰撞强度。
///
/// # 参数
///
/// * `i` - 下能级索引 (1-indexed)
/// * `j` - 上能级索引 (1-indexed)
/// * `ic` - 碰撞类型:
/// - -1: 中性粒子
/// - -2: 离子
/// - -11: 特殊处理
/// - -12: He I 禁戒跃迁
/// * `os` - 振子强度
/// * `cp` - 碰撞参数(用于离子)
/// * `u0` - 约化能量 (E/kT)
/// * `t` - 温度 (K)
///
/// # 返回值
///
/// 碰撞强度 CS
#[allow(clippy::too_many_arguments)]
pub fn cspec(i: i32, j: i32, ic: i32, os: f64, cp: f64, u0: f64, t: f64) -> f64 {
let mut cs = 0.0;
if ic > -10 {
// 计算指数积分 E1(U0)
let expiu0 = if u0 <= UN {
// U0 <= 1: 使用级数展开
(-u0.ln()) + EXPIA1
+ u0 * (EXPIA2 + u0 * (EXPIA3 + u0 * (EXPIA4 + u0 * (EXPIA5 + u0 * EXPIA6))))
} else {
// U0 > 1: 使用连分式近似
let num = EXPIB1 + u0 * (EXPIB2 + u0 * (EXPIB3 + u0 * EXPIB4));
let den = EXPIC1 + u0 * (EXPIC2 + u0 * (EXPIC3 + u0 * EXPIC4));
(-u0).exp() * num / den / u0
};
let gg = if ic == -1 {
// 中性粒子 (Auer & Mihalas 1973)
if u0 <= 14.0 {
0.276 * u0.exp() * expiu0
} else {
0.066 * (1.0 + 1.5 / u0) / u0.sqrt()
}
} else if ic == -2 {
// 离子 (Mihalas 1972)
let gg0 = 0.276 * u0.exp() * expiu0;
if gg0 > cp { gg0 } else { cp }
} else {
0.0
};
let t32 = t.powf(-1.5);
cs += 19.7363 * t32 * (-u0).exp() / u0 * gg * os;
return cs;
}
if ic == -11 {
// 特殊处理
let xr = -1.68_f64;
cs += 2.16 * u0.powf(xr) / t / t.sqrt() * (-u0).exp() * os;
return cs;
}
if ic == -12 {
// He I 禁戒跃迁 (from Klaus Werner)
// 确定跃迁类型
let iforb = match (i, j) {
(2, 3) => 1,
(2, 5) => 2,
(3, 4) => 3,
(4, 5) => 4,
_ => {
panic!("Inconsistent ICOL - CSPEC: i={}, j={}, iforb=0", i, j);
}
};
let xt = t.log10();
let gam = if iforb <= 3 {
CHE1FB[0][iforb as usize - 1]
+ CHE1FB[1][iforb as usize - 1] * xt
+ CHE1FB[2][iforb as usize - 1] / xt / xt
} else {
0.0
};
let gam = (2.30258509299405_f64 * gam).exp();
cs += 5.465e-11 * t.sqrt() * (-u0).exp() * gam;
}
cs
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_cspec_neutral_low_u0() {
// 中性粒子U0 <= 1
let cs = cspec(1, 2, -1, 0.5, 0.0, 0.5, 10000.0);
assert!(cs > 0.0);
}
#[test]
fn test_cspec_neutral_high_u0() {
// 中性粒子U0 > 14
let cs = cspec(1, 2, -1, 0.5, 0.0, 15.0, 10000.0);
assert!(cs > 0.0);
}
#[test]
fn test_cspec_ion() {
// 离子
let cs = cspec(1, 2, -2, 0.5, 0.1, 2.0, 10000.0);
assert!(cs > 0.0);
}
#[test]
fn test_cspec_special() {
// IC = -11
let cs = cspec(1, 2, -11, 0.5, 0.0, 2.0, 10000.0);
assert!(cs > 0.0);
}
#[test]
fn test_cspec_hei_forbidden() {
// He I 禁戒跃迁 (2->3)
let cs = cspec(2, 3, -12, 0.0, 0.0, 2.0, 10000.0);
assert!(cs > 0.0);
}
#[test]
fn test_expiu0_low() {
// 测试指数积分 U0 <= 1
let u0: f64 = 0.5;
let expiu0 = (-u0.ln()) + EXPIA1
+ u0 * (EXPIA2 + u0 * (EXPIA3 + u0 * (EXPIA4 + u0 * (EXPIA5 + u0 * EXPIA6))));
// E1(0.5) ≈ 0.5598
assert_relative_eq!(expiu0, 0.5598, epsilon = 1e-3);
}
#[test]
fn test_expiu0_high() {
// 测试指数积分 U0 > 1
let u0: f64 = 2.0;
let num = EXPIB1 + u0 * (EXPIB2 + u0 * (EXPIB3 + u0 * EXPIB4));
let den = EXPIC1 + u0 * (EXPIC2 + u0 * (EXPIC3 + u0 * EXPIC4));
let expiu0 = (-u0).exp() * num / den / u0;
// E1(2.0) ≈ 0.0477 (Abramowitz & Stegun 近似)
assert_relative_eq!(expiu0, 0.0477, epsilon = 1e-3);
}
}

427
src/math/levset.rs Normal file
View File

@ -0,0 +1,427 @@
//! 能级参数设置。
//!
//! 重构自 TLUSTY `levset.f`
//!
//! 设置能级参数 IIEXP 和 IIFOR控制能级的处理方式。
//!
//! ## 能级模式 (IMODL)
//!
//! - 0: 显式处理,完全 NLTE
//! - 1, 3: 跳过
//! - 4, 5: LTE
//! - -1, -3: 跳过,禁戒跃迁
//! - 6: 跳过
//! - -5, -6: 跳过,禁戒跃迁
//! - < -100: 分组处理
//! - < -200: 分组处理(不同方式)
use crate::state::constants::{MLEVEL, MDEPTH, MLVEXP};
/// LEVSET 的输入参数
pub struct LevsetParams {
/// 是否启用 LTE 模式
pub lte: bool,
/// 能级处理模式 (0: 自动, 其他: 由 IMODL 决定)
pub iflev: i32,
/// 选项表标志
pub ioptab: i32,
}
/// LEVSET 的模型状态
pub struct LevsetModelState<'a> {
/// 深度点数
pub nd: usize,
/// 原子数
pub natom: usize,
/// 能级数
pub nlevel: usize,
/// 能级模式 (NLEVEL)
pub imodl: &'a mut [i32],
/// 能级所属原子 (NLEVEL)
pub iatm: &'a [i32],
/// 能级所属元素/离子 (NLEVEL)
pub iel: &'a [i32],
/// 原子固定标志 (NATOM)
pub iifix: &'a [i32],
/// 原子起始能级 (NATOM)
pub n0a: &'a [i32],
/// 原子结束能级 (NATOM)
pub nka: &'a [i32],
/// 离子第一个能级 (NLEVEL)
pub nfirst: &'a [i32],
/// 离子最后一个能级 (NLEVEL)
pub nnext: &'a [i32],
/// LTE 能级标志 (NLEVEL)
pub iltlev: &'a [i32],
}
/// LEVSET 的输出状态
pub struct LevsetOutputState<'a> {
/// 显式能级索引 (NLEVEL) - 正值表示显式处理
pub iiexp: &'a mut [i32],
/// 禁戒能级索引 (NLEVEL)
pub iifor: &'a mut [i32],
/// 显式能级对应的实际能级 (MLVEXP)
pub indlev: &'a mut [i32],
/// LTE 参考能级 (NLEVEL × MDEPTH)
pub iltref: &'a mut [i32],
/// B 因子 (NLEVEL × MDEPTH)
pub bfac: &'a mut [f64],
/// 积分零标志 (MLVEXP × MDEPTH)
pub igzero: &'a mut [i32],
/// 种群零标志 (NLEVEL × MDEPTH)
pub ipzero: &'a mut [i32],
/// 显式能级数
pub nlvexp: &'a mut i32,
/// 禁戒能级数
pub nlvfor: &'a mut i32,
}
/// 设置能级参数。
///
/// # 参数
///
/// * `params` - 输入参数
/// * `model` - 模型状态
/// * `output` - 输出状态
pub fn levset(
params: &LevsetParams,
model: &mut LevsetModelState,
output: &mut LevsetOutputState,
) {
// 如果 IOPTAB < 0直接返回
if params.ioptab < 0 {
return;
}
let nd = model.nd;
let natom = model.natom;
let nlevel = model.nlevel;
// 初始化 B 因子
for i in 0..nlevel {
for id in 0..nd {
output.bfac[i * nd + id] = 1.0;
}
}
if params.iflev == 0 {
// 情况 1: 由 IMODL 决定处理方式
process_by_imodl(params, model, output, natom, nlevel, nd);
} else {
// 情况 2: 自动处理 - 所有 ILK=0 的能级在更新的 LTE 模式下
process_automatic(params, model, output, nlevel, nd);
}
// 初始化 IGZERO 和 IPZERO
let nlvexp = *output.nlvexp as usize;
for ii in 0..nlvexp.min(MLVEXP) {
output.indlev[ii] = 0;
for id in 0..nd {
output.igzero[ii * nd + id] = 0;
}
}
for i in 0..nlevel {
for id in 0..nd {
output.ipzero[i * nd + id] = 0;
}
if model.imodl[i].abs() <= 6 {
if output.iiexp[i] > 0 {
let ii_idx = (output.iiexp[i] - 1) as usize;
if ii_idx < MLVEXP {
output.indlev[ii_idx] = (i + 1) as i32;
}
}
}
}
}
/// 按能级模式处理
#[allow(clippy::too_many_arguments)]
fn process_by_imodl(
params: &LevsetParams,
model: &mut LevsetModelState,
output: &mut LevsetOutputState,
natom: usize,
nlevel: usize,
nd: usize,
) {
// 初始化
for i in 0..nlevel {
output.iiexp[i] = 0;
output.iifor[i] = 0;
}
let mut iie: i32 = 0;
let mut iif: i32 = 0;
let mut igrp: i32 = 0;
for iat in 0..natom {
igrp = 0;
if model.iifix[iat] == 1 {
continue;
}
let n0a = model.n0a[iat] as usize;
let nka = model.nka[iat] as usize;
for i in n0a..=nka {
let imodl = model.imodl[i];
let mut inew = 1;
if imodl == 0 {
// 显式处理
iie += 1;
iif += 1;
output.iiexp[i] = iie;
output.iifor[i] = iif;
output.indlev[(iie - 1) as usize] = (i + 1) as i32;
} else if imodl > 0 {
// 正模式
iif += 1;
output.iifor[i] = iif;
if model.iltlev[i] >= 1 {
iie += 1;
output.iiexp[i] = iie;
}
let nfirst = model.nfirst[model.iel[i] as usize] as usize;
let nnext = model.nnext[model.iel[i] as usize] as usize;
if i + 1 == nfirst || i + 1 == nnext {
iie += 1;
output.iiexp[i] = iie;
}
} else if imodl < -100 {
// 分组处理 (IMODL < -100)
if i > n0a {
if model.imodl[i] == model.imodl[i - 1] {
inew = 0;
}
}
output.iiexp[i] = -iie;
if inew == 1 {
iie += 1;
output.iiexp[i] = -iie;
let nfirst = model.nfirst[model.iel[i] as usize] as usize;
let mut im = nfirst;
let mut lml = true;
while im < i && lml {
if model.imodl[i] == model.imodl[im] {
output.iiexp[i] = output.iiexp[im];
iie -= 1;
lml = false;
}
im += 1;
}
}
igrp = 1;
iif += 1;
output.iifor[i] = iif;
} else if imodl < -200 {
// 分组处理 (IMODL < -200)
if i > n0a {
if model.imodl[i] == model.imodl[i - 1] {
inew = 0;
}
}
if inew == 1 {
iie += 1;
}
if inew == 1 {
iif += 1;
}
output.iiexp[i] = -iie;
output.iifor[i] = -iif;
igrp = 1;
}
}
// 处理分组
if igrp == 1 {
for i in n0a..=nka {
if output.iiexp[i] > 0 {
output.iiexp[i] = -output.iiexp[i];
}
if model.imodl[i] == 0 {
model.imodl[i] = 7;
}
}
}
}
*output.nlvexp = iie.abs();
if *output.nlvexp > MLVEXP as i32 {
panic!("nlvexp.gt.mlvexp: {} > {}", *output.nlvexp, MLVEXP);
}
*output.nlvfor = iif.abs();
// 清理特定模式
for i in 0..nlevel {
let imodl = model.imodl[i];
if imodl == 1 || imodl == 3 {
output.iiexp[i] = 0;
} else if imodl == 4 || imodl == 5 {
output.iiexp[i] = 0;
} else if imodl == -1 || imodl == -3 {
output.iiexp[i] = 0;
output.iifor[i] = 0;
} else if imodl == 6 {
output.iiexp[i] = 0;
} else if imodl == -5 || imodl == -6 {
output.iiexp[i] = 0;
output.iifor[i] = 0;
} else if imodl < -100 {
model.imodl[i] = 7;
} else if imodl < -200 {
model.imodl[i] = -7;
}
// 设置 ILTREF
let nnext = model.nnext[model.iel[i] as usize];
for id in 0..nd {
output.iltref[i * nd + id] = nnext;
}
}
// 如果有分组,将所有能级设为模式 7
if igrp == 1 {
for iat in 0..natom {
if model.iifix[iat] == 1 {
continue;
}
let n0a = model.n0a[iat] as usize;
let nka = model.nka[iat] as usize;
for i in n0a..=nka {
model.imodl[i] = 7;
}
}
}
}
/// 自动处理模式
fn process_automatic(
params: &LevsetParams,
model: &mut LevsetModelState,
output: &mut LevsetOutputState,
nlevel: usize,
nd: usize,
) {
let mut iif: i32 = 0;
for i in 0..nlevel {
if model.iifix[model.iatm[i] as usize] == 1 {
continue;
}
model.imodl[i] = 5;
let nfirst = model.nfirst[model.iel[i] as usize] as usize;
let nnext = model.nnext[model.iel[i] as usize] as usize;
if i + 1 == nfirst || i + 1 == nnext {
iif += 1;
output.iifor[i] = iif;
}
}
*output.nlvexp = iif;
if *output.nlvexp > MLVEXP as i32 {
panic!("nlvexp.gt.mlvexp: {} > {}", *output.nlvexp, MLVEXP);
}
*output.nlvfor = iif;
// 清理非第一/最后能级的 IIFOR
for i in 0..nlevel {
let nfirst = model.nfirst[model.iel[i] as usize] as usize;
let nnext = model.nnext[model.iel[i] as usize] as usize;
if i + 1 != nfirst && i + 1 != nnext {
output.iifor[i] = 0;
}
}
// 设置 IIEXP 和 INDLEV
for i in 0..nlevel {
output.iiexp[i] = output.iifor[i];
if output.iiexp[i] > 0 {
output.indlev[(output.iiexp[i] - 1) as usize] = (i + 1) as i32;
}
let nnext = model.nnext[model.iel[i] as usize];
for id in 0..nd {
output.iltref[i * nd + id] = nnext;
}
}
// 非 LTE 模式下,所有能级都是显式的
if !params.lte {
for i in 0..nlevel {
output.iifor[i] = (i + 1) as i32;
}
*output.nlvfor = nlevel as i32;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_levset_ioptab_negative() {
// IOPTAB < 0 时应直接返回
let params = LevsetParams {
lte: false,
iflev: 0,
ioptab: -1,
};
// 创建简单的模型状态
let mut imodl = vec![0i32; 10];
let iatm = vec![1i32; 10];
let iel = vec![1i32; 10];
let iifix = vec![0i32; 2];
let n0a = vec![0i32; 2];
let nka = vec![9i32; 2];
let nfirst = vec![0i32; 10];
let nnext = vec![9i32; 10];
let iltlev = vec![0i32; 10];
let mut model = LevsetModelState {
nd: 5,
natom: 2,
nlevel: 10,
imodl: &mut imodl,
iatm: &iatm,
iel: &iel,
iifix: &iifix,
n0a: &n0a,
nka: &nka,
nfirst: &nfirst,
nnext: &nnext,
iltlev: &iltlev,
};
let mut iiexp = vec![0i32; 10];
let mut iifor = vec![0i32; 10];
let mut indlev = vec![0i32; MLVEXP];
let mut iltref = vec![0i32; 10 * 5];
let mut bfac = vec![1.0; 10 * 5];
let mut igzero = vec![0i32; MLVEXP * 5];
let mut ipzero = vec![0i32; 10 * 5];
let mut nlvexp = 0i32;
let mut nlvfor = 0i32;
let mut output = LevsetOutputState {
iiexp: &mut iiexp,
iifor: &mut iifor,
indlev: &mut indlev,
iltref: &mut iltref,
bfac: &mut bfac,
igzero: &mut igzero,
ipzero: &mut ipzero,
nlvexp: &mut nlvexp,
nlvfor: &mut nlvfor,
};
levset(&params, &mut model, &mut output);
// IOPTAB < 0 时nlvexp 应该保持为 0
assert_eq!(*output.nlvexp, 0);
}
}

View File

@ -1,5 +1,6 @@
//! 数学工具函数,重构自 TLUSTY Fortran。
mod alifr1;
mod alifr3;
mod alifr6;
mod alifrk;
@ -18,6 +19,7 @@ mod collhe;
mod compt0;
mod comset;
mod cross;
mod cspec;
mod ctdata;
mod cubic;
mod dielrc;
@ -54,6 +56,7 @@ mod irc;
mod interpolate;
mod laguer;
mod levsol;
mod levset;
mod levgrp;
mod lineqs;
mod linspl;
@ -62,6 +65,9 @@ mod matinv;
mod meanop;
mod minv3;
mod odfhst;
mod odffr;
mod opadd0;
mod opctab;
mod pfcno;
mod pffe;
mod prdini;
@ -76,6 +82,7 @@ mod quit;
mod reflev;
mod raph;
mod ratmal;
mod ratmat;
mod rayleigh;
mod rybmat;
mod rayset;
@ -120,6 +127,7 @@ mod xk2dop;
mod ylintp;
mod zmrho;
pub use alifr1::{alifr1, Alifr1Params, Alifr1ModelState, Alifr1RadState};
pub use alifr3::{alifr3, Alifr3Params};
pub use alifr6::{alifr6, Alifr6Params, Alifr6State};
pub use alifrk::{alifrk, AlifrkParams, AlifrkState};
@ -137,6 +145,7 @@ pub use ckoest::ckoest;
pub use collhe::collhe;
pub use comset::{comset, ComsetParams, ComsetResult};
pub use cross::{cross, crossd};
pub use cspec::cspec;
pub use ctdata::{hction, hctrecom, CTION, CTRECOMB};
pub use cubic::{cubic, CubicCon};
pub use dielrc::dielrc;
@ -173,6 +182,7 @@ pub use irc::irc;
pub use interpolate::{lagran, yint};
pub use laguer::laguer;
pub use levsol::levsol;
pub use levset::{levset, LevsetParams, LevsetModelState, LevsetOutputState};
pub use levgrp::{levgrp, LevgrpParams, LevgrpResult};
pub use lineqs::{lineqs, lineqs_nr};
pub use linspl::{linspl, LinsplParams};
@ -180,7 +190,10 @@ pub use locate::locate;
pub use matinv::matinv;
pub use meanop::meanop;
pub use minv3::minv3;
pub use opadd0::{opadd0, Opadd0Params, Opadd0FreqData, Opadd0OutputState};
pub use opctab::{opctab, OpctabParams, OpctabTableData, OpctabModelState, OpctabOutput};
pub use odfhst::odfhst;
pub use odffr::{odffr, OdffrParams, OdffrAtomicData, OdffrModelData, OdffrOutputState};
pub use pfcno::pfcno;
pub use pffe::pffe;
pub use prdini::prdini;
@ -195,6 +208,7 @@ pub use reflev::reflev;
pub use quit::{quit, quit_error};
pub use raph::raph;
pub use ratmal::ratmal;
pub use ratmat::{ratmat, RatmatParams, RatmatOutput};
pub use rayleigh::{
rayleigh, rayleigh_h2_cross_section, rayleigh_h_cross_section, rayleigh_he_cross_section,
RayleighParams, RayleighResult,

307
src/math/odffr.rs Normal file
View File

@ -0,0 +1,307 @@
//! ODF 频率设置。
//!
//! 重构自 TLUSTY `odffr.f`
//!
//! 为 ODFOpacity Distribution Function设置内部频率
//! 用于处理系限附近的重叠谱线。
//!
//! ## 算法说明
//!
//! 谱线向连续跃迁 (IL - IU) 的边缘收敛。
//! - IL: 下能级索引
//! - IU: 上能级索引(通常是下一离子的基态或 ODF 形式中的平均能级)
use crate::state::constants::{HALF, MFRO};
/// 常量 (从 Fortran PARAMETER 语句)
/// FRH = 3.28805D15
const FRH: f64 = 3.28805e15;
/// CDOP = 2.84511D-7
const CDOP: f64 = 2.84511e-7;
/// CDOM = 14.
const CDOM: f64 = 14.0;
/// SIX = 6.
const SIX: f64 = 6.0;
/// SEPT = 7.
const SEPT: f64 = 7.0;
/// ODFFR 输入参数
pub struct OdffrParams {
/// 下能级索引 (1-indexed)
pub il: usize,
/// 上能级索引 (1-indexed)
pub iu: usize,
/// 有效温度 (K)
pub teff: f64,
/// 最大主量子数
pub nlmx: usize,
}
/// ODFFR 原子数据
pub struct OdffrAtomicData<'a> {
/// 元素索引 (NLEVEL)
pub iel: &'a [i32],
/// 电荷数 (NATOM)
pub iz: &'a [f64],
/// 电离能 (NLEVEL)
pub enion: &'a [f64],
/// 主量子数 (NLEVEL)
pub nquant: &'a [i32],
}
/// ODFFR 模型数据
pub struct OdffrModelData<'a> {
/// 跃迁索引 (NLEVEL × NLEVEL)
pub itra: &'a [i32],
/// ODF 索引
pub jndodf: &'a [i32],
}
/// ODFFR 输出状态
pub struct OdffrOutputState<'a> {
/// ODF 频率点数 (MODF)
pub nfrodf: &'a mut [i32],
/// ODF 频率 (MFRO × MODF)
pub fros: &'a mut [f64],
/// ODF 权重 (MFRO × MODF)
pub wnus: &'a mut [f64],
}
/// 普朗克常数 (从 TLUSTY 常量)
const H: f64 = 6.626176e-27;
/// UN = 1.0 (里德伯常数的倍数)
const UN: f64 = 1.0;
/// 为 ODF 设置内部频率。
///
/// # 参数
///
/// * `params` - 输入参数
/// * `atomic` - 原子数据
/// * `model` - 模型数据
/// * `output` - 输出状态
///
/// # Panics
///
/// 当频率点数超过 MFRO 时 panic。
#[allow(clippy::too_many_arguments)]
pub fn odffr(
params: &OdffrParams,
atomic: &OdffrAtomicData,
model: &OdffrModelData,
output: &mut OdffrOutputState,
) {
let il = params.il;
let iu = params.iu;
let il_idx = il - 1;
let iu_idx = iu - 1;
// 计算电荷平方
let iel_idx = atomic.iel[il_idx] as usize;
let ch = atomic.iz[iel_idx - 1] * atomic.iz[iel_idx - 1];
let frion = ch * FRH;
// 电离频率
let fre = atomic.enion[il_idx] / H;
// 临时频率数组
let mut ffro = vec![0.0_f64; MFRO];
let mut nf: usize = 1;
let nq1 = atomic.nquant[iu_idx] as usize;
let xl2 = UN / (atomic.nquant[il_idx] as f64 * atomic.nquant[il_idx] as f64);
let xu1 = UN / ((atomic.nquant[iu_idx] - 1) as f64 * (atomic.nquant[iu_idx] - 1) as f64);
let xu2 = UN / (atomic.nquant[iu_idx] as f64 * atomic.nquant[iu_idx] as f64);
let frc = frion * (xl2 - xu2);
ffro[nf - 1] = HALF * (frc + frion * (xl2 - xu1));
let kt = model.itra[il_idx * atomic.iel.len() + iu_idx] as usize;
let kl = model.jndodf[kt - 1] as usize;
let dopo = CDOP * params.teff.sqrt() * frc;
let dopm = CDOM * dopo;
let mut fr1 = ffro[0];
// 遍历主量子数
for i in nq1..=params.nlmx {
let ii = (i * i) as f64;
let fr2 = fre - frion / ii;
let df = fr2 - fr1;
if df > dopm {
// 大间隔:添加密集点
for j in 1..=7 {
nf += 1;
if nf > MFRO {
nf -= 1;
goto_end(&ffro, nf, kl, output);
return;
}
ffro[nf - 1] = fr1 + j as f64 * dopo;
}
let df_inner = fr2 - SEPT * dopo - ffro[nf - 1];
let ni = (df_inner / (SIX * dopo)) as usize;
let ddf = df_inner / ((ni + 1) as f64);
for j in 1..=ni {
nf += 1;
if nf > MFRO - 3 {
nf -= 1;
goto_end(&ffro, nf, kl, output);
return;
}
ffro[nf - 1] = fr1 + SEPT * dopo + j as f64 * ddf;
}
for j in (0..=7).rev() {
nf += 1;
if nf > MFRO {
nf -= 1;
goto_end(&ffro, nf, kl, output);
return;
}
ffro[nf - 1] = fr2 - j as f64 * dopo;
}
fr1 = fr2;
} else {
// 小间隔:均匀分布
let ni = (df / dopo) as usize;
let ddf = df / ((ni + 1) as f64);
for j in 1..=ni {
nf += 1;
if nf > MFRO - 3 {
nf -= 1;
goto_end(&ffro, nf, kl, output);
return;
}
ffro[nf - 1] = fr1 + j as f64 * ddf;
}
nf += 1;
if nf > MFRO {
nf -= 1;
goto_end(&ffro, nf, kl, output);
return;
}
ffro[nf - 1] = fr2;
fr1 = fr2;
}
}
goto_end(&ffro, nf, kl, output);
}
/// 完成频率设置并计算权重
fn goto_end(ffro: &[f64], nf: usize, kl: usize, output: &mut OdffrOutputState) {
let mut nf = nf;
nf += 1;
if nf > MFRO {
panic!(
"too many points for hydrogen ODF - nf.gt.mfro: {} > {}",
nf, MFRO
);
}
// 添加最后一个点(略低于电离限)
let kl_idx = kl - 1;
let mut fros_local = vec![0.0; nf];
// 逆序复制
let fre = ffro[0] / 0.999999999_f64; // 从第一个点估算 fre
fros_local[nf - 1] = fre * 0.999999999;
for i in 0..nf - 1 {
fros_local[i] = ffro[nf - 2 - i];
}
output.nfrodf[kl_idx] = nf as i32;
if nf > MFRO {
panic!(
"too many points for hydrogen ODF - nf.gt.mfro: {} > {}",
nf, MFRO
);
}
// 复制到输出
for i in 0..nf {
output.fros[i * output.nfrodf.len() + kl_idx] = fros_local[i];
}
// 计算权重
// 第一个点
output.wnus[kl_idx] = HALF * (fros_local[0] - fros_local[1]);
// 最后一个点
output.wnus[(nf - 1) * output.nfrodf.len() + kl_idx] =
HALF * (fros_local[nf - 2] - fros_local[nf - 1]);
// 中间点
for i in 2..nf {
output.wnus[(i - 1) * output.nfrodf.len() + kl_idx] =
HALF * (fros_local[i - 2] - fros_local[i]);
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_odffr_constants() {
// 验证常量
assert_relative_eq!(FRH, 3.28805e15, epsilon = 1e10);
assert_relative_eq!(CDOP, 2.84511e-7, epsilon = 1e-12);
assert_relative_eq!(CDOM, 14.0, epsilon = 1e-10);
}
#[test]
fn test_odffr_basic() {
// 基本测试
let params = OdffrParams {
il: 2,
iu: 10,
teff: 10000.0,
nlmx: 10,
};
let iel = vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let iz = vec![1.0];
let enion = vec![13.6, 13.5, 13.4, 13.3, 13.2, 13.1, 13.0, 12.9, 12.8, 12.7];
let nquant = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let atomic = OdffrAtomicData {
iel: &iel,
iz: &iz,
enion: &enion,
nquant: &nquant,
};
let itra = vec![1i32; 100]; // 所有跃迁索引设为 1
let jndodf = vec![1i32]; // ODF 索引
let model = OdffrModelData {
itra: &itra,
jndodf: &jndodf,
};
let mut nfrodf = vec![0i32; 10];
let mut fros = vec![0.0; MFRO * 10];
let mut wnus = vec![0.0; MFRO * 10];
let mut output = OdffrOutputState {
nfrodf: &mut nfrodf,
fros: &mut fros,
wnus: &mut wnus,
};
odffr(&params, &atomic, &model, &mut output);
// 验证输出
assert!(output.nfrodf[0] > 0);
}
}

271
src/math/opadd0.rs Normal file
View File

@ -0,0 +1,271 @@
//! 附加不透明度源截面设置。
//!
//! 重构自 TLUSTY `opadd0.f`
//!
//! 设置各种附加不透明度源的截面,包括:
//! - H I Rayleigh 散射
//! - He I Rayleigh 散射
//! - H2 Rayleigh 散射
//! - H- 束缚-自由和自由-自由
//! - H2+ 束缚-自由和自由-自由
//! - He- 自由-自由
use crate::math::sbfhmi::sbfhmi;
/// 常量 (从 Fortran PARAMETER 语句)
/// H I Rayleigh 散射阈值频率
const FRRAY: f64 = 2.463e15;
/// He I Rayleigh 散射阈值频率
const FRAYHE: f64 = 5.150e15;
/// H2 Rayleigh 散射阈值频率
const FRAYH2: f64 = 2.922e15;
/// 光速 (Angstrom/s)
const CLS: f64 = 2.997925e18;
/// H I Rayleigh 散射系数
const CR0: f64 = 5.799e-13;
const CR1: f64 = 1.422e-6;
const CR2: f64 = 2.784;
/// OPADD0 输入参数
pub struct Opadd0Params {
/// 频率索引 (1-indexed)
pub ij: usize,
/// 连续谱数
pub ncon: usize,
/// 最大截面数
pub mcross: usize,
/// H I Rayleigh 散射标志
pub irsct: i32,
/// He I Rayleigh 散射标志
pub irsche: i32,
/// H2 Rayleigh 散射标志
pub irsch2: i32,
/// 分子标志
pub ifmol: i32,
/// H- 不透明度标志
pub iophmi: i32,
/// H2+ 不透明度标志
pub ioph2p: i32,
/// He- 不透明度标志
pub iophem: i32,
/// ODF 标志
pub ispodf: i32,
}
/// OPADD0 频率数据
pub struct Opadd0FreqData<'a> {
/// 频率数组
pub freq: &'a [f64],
/// ODF 频率映射 (可选)
pub ifreqb: Option<&'a [i32]>,
}
/// OPADD0 输出状态
pub struct Opadd0OutputState<'a> {
/// 截面数组 (MCROSS × MFREQ)
pub bfcs: &'a mut [f32],
/// 频率维度
pub mfreq: usize,
}
/// 设置附加不透明度源的截面。
///
/// # 参数
///
/// * `params` - 输入参数
/// * `freq_data` - 频率数据
/// * `output` - 输出状态
///
/// # Panics
///
/// 当 IT > MCROSS 时 panic。
pub fn opadd0(
params: &Opadd0Params,
freq_data: &Opadd0FreqData,
output: &mut Opadd0OutputState,
) {
let ij = params.ij;
let ij_idx = ij - 1;
// 获取频率
let fr = if params.ispodf >= 1 {
let ifreqb = freq_data.ifreqb.expect("ifreqb required for ODF mode");
freq_data.freq[ifreqb[ij_idx] as usize - 1]
} else {
freq_data.freq[ij_idx]
};
let mut it = params.ncon;
// H I Rayleigh 散射
if params.irsct != 0 {
it += 1;
if it > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let frm = fr.min(FRRAY);
let x = (CLS / frm).powi(2);
let cs = (CR0 + (CR1 + CR2 / x) / x) / x / x / x;
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs as f32;
}
// He I Rayleigh 散射
if params.irsche != 0 {
it += 1;
if it > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let x = (CLS / fr.min(FRAYHE)).powi(2);
let cs = 5.484e-14 / x / x * (1.0 + (2.44e5 + 5.94e10 / (x - 2.90e5)) / x).powi(2);
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs as f32;
}
// H2 Rayleigh 散射
if params.irsch2 != 0 && params.ifmol > 0 {
it += 1;
if it > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let x = (CLS / fr.min(FRAYH2)).powi(2);
let x2 = 1.0 / x / x;
let cs = (8.14e-13 + 1.28e-6 / x + 1.61 * x2) * x2;
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs as f32;
}
// H- 束缚-自由和自由-自由
if params.iophmi > 0 {
it += 1;
if it > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let cs = sbfhmi(fr);
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs as f32;
}
// H2+ 束缚-自由和自由-自由
if params.ioph2p > 0 {
it += 1;
if it + 1 > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let x = fr * 1e-15;
// H2+ bound-free
let cs_bf = (-7.342e-3 + (-2.409 + (1.028 + (-4.23e-1 + (1.224e-1 - 1.351e-2 * x) * x) * x) * x) * x)
* 1.602e-12
/ 1.3806e-16; // BOLK
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs_bf as f32;
it += 1;
let x = fr.ln();
// H2+ free-free
let cs_ff = -3.0233e3 + (3.7797e2 + (-1.82496e1 + (3.9207e-1 - 3.1672e-3 * x) * x) * x) * x;
output.bfcs[(it - 1) * output.mfreq + ij_idx] = cs_ff as f32;
}
// He- 自由-自由
if params.iophem > 0 {
it += 1;
if it + 2 > params.mcross {
panic!("it.gt.mcross in opadd: {} > {}", it, params.mcross);
}
let a = 3.397e-46 + (-5.216e-31 + 7.039e-15 / fr) / fr;
let b = -4.116e-42 + (1.067e-26 + 8.135e-11 / fr) / fr;
let c = 5.081e-37 + (-8.724e-23 - 5.659e-8 / fr) / fr;
output.bfcs[(it - 1) * output.mfreq + ij_idx] = a as f32;
output.bfcs[it * output.mfreq + ij_idx] = b as f32;
output.bfcs[(it + 1) * output.mfreq + ij_idx] = c as f32;
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_opadd0_constants() {
assert_relative_eq!(FRRAY, 2.463e15, epsilon = 1e10);
assert_relative_eq!(FRAYHE, 5.150e15, epsilon = 1e10);
assert_relative_eq!(FRAYH2, 2.922e15, epsilon = 1e10);
assert_relative_eq!(CLS, 2.997925e18, epsilon = 1e13);
}
#[test]
fn test_opadd0_hi_rayleigh() {
let params = Opadd0Params {
ij: 1,
ncon: 0,
mcross: 10,
irsct: 1,
irsche: 0,
irsch2: 0,
ifmol: 0,
iophmi: 0,
ioph2p: 0,
iophem: 0,
ispodf: 0,
};
let freq = vec![1e15];
let freq_data = Opadd0FreqData {
freq: &freq,
ifreqb: None,
};
let mut bfcs = vec![0.0f32; 10 * 1];
let mut output = Opadd0OutputState {
bfcs: &mut bfcs,
mfreq: 1,
};
opadd0(&params, &freq_data, &mut output);
// 验证 H I Rayleigh 截面被设置
assert!(output.bfcs[0] > 0.0);
}
#[test]
fn test_opadd0_all_sources() {
let params = Opadd0Params {
ij: 1,
ncon: 0,
mcross: 20,
irsct: 1,
irsche: 1,
irsch2: 1,
ifmol: 1,
iophmi: 1,
ioph2p: 1,
iophem: 1,
ispodf: 0,
};
let freq = vec![1e15];
let freq_data = Opadd0FreqData {
freq: &freq,
ifreqb: None,
};
let mut bfcs = vec![0.0f32; 20 * 1];
let mut output = Opadd0OutputState {
bfcs: &mut bfcs,
mfreq: 1,
};
opadd0(&params, &freq_data, &mut output);
// 验证所有截面都被设置
// H I Rayleigh (1)
assert!(output.bfcs[0] > 0.0);
// He I Rayleigh (2)
assert!(output.bfcs[1] > 0.0);
// H2 Rayleigh (3)
assert!(output.bfcs[2] > 0.0);
// H- (4)
assert!(output.bfcs[3] > 0.0);
// H2+ bf (5)
// H2+ ff (6)
// He- (7,8,9)
}
}

418
src/math/opctab.rs Normal file
View File

@ -0,0 +1,418 @@
//! 不透明度表插值与散射计算。
//!
//! 重构自 TLUSTY `opctab.f`
//!
//! 通过对预计算的不透明度表进行二维线性插值(温度-密度)来计算给定温度和密度下的吸收不透明度。
//! 同时计算散射不透明度,包括:
//! - Rayleigh 散射(简单公式或完整 rayleigh 函数)
//! - 电子散射
//!
//! 这是一个简化版本所有插值都是线性的fortran中也是线性插值。
use crate::math::rayleigh::{rayleigh, RayleighParams};
use crate::state::model::{EosPar, RaySct};
/// 参考频率 (FRRAY0)
const FRRAY0: f64 = 5.0872638e14;
/// OPCTAB 输入参数
pub struct OpctabParams<'a> {
/// 频率 (Hz)
pub fr: f64,
/// 频率索引 (1-indexed)
pub ij: usize,
/// 深度索引 (1-indexed)
pub id: usize,
/// 温度 (K)
pub t: f64,
/// 密度 (g cm^-3)
pub rho: f64,
/// 克拉马标志 (0: 返回每克, 1: 返回每体积)
pub igram: i32,
/// 迭代次数
pub iter: i32,
/// Rayleigh 散射标志 (<0: 使用简单公式, >0: 调用 rayleigh, =0: 关闭)
pub ifrayl: i32,
/// 选项表标志 (<0: 添加电子散射)
pub ioptab: i32,
/// Rayleigh 参数 (当 ifrayl > 0 时需要)
pub rayleigh_params: Option<&'a RayleighParams<'a>>,
}
/// OPCTAB 表数据
pub struct OpctabTableData<'a> {
/// 温度数
pub numtemp: usize,
/// 深度点数
pub nd: usize,
/// 频率数
pub nfreq: usize,
/// 最大密度点数 (用于数组维度)
pub max_numrh: usize,
/// 温度向量 (numtemp)
pub tempvec: &'a [f64],
/// 温度下限 (ln T)
pub ttab1: f64,
/// 温度上限 (ln T)
pub ttab2: f64,
/// 每个温度的密度数 (numtemp)
pub numrh: &'a [i32],
/// 密度矩阵 (numtemp × max_numrh) - 存储 ln(rho)
pub rhomat: &'a [f64],
/// 吸收不透明度表 (numtemp × max_numrh × nfreq) - 存储 ln(opacity)
pub absopac: &'a [f64],
/// Rayleigh 散射系数 (nd)
pub raysc: &'a [f64],
/// 频率数组 (nfreq)
pub freq: &'a [f64],
/// 电子散射系数
pub sige: f64,
}
/// OPCTAB 模型状态
pub struct OpctabModelState<'a> {
/// 电子密度 (nd)
pub elec: &'a [f64],
/// 密度 (nd)
pub dens: &'a [f64],
/// Rayleigh 散射截面 (当 ifrayl > 0 时需要)
pub raysct: Option<&'a mut RaySct>,
/// EOS 粒子数密度 (当 ifrayl > 0 时需要)
pub eospar: Option<&'a EosPar>,
}
/// OPCTAB 输出
pub struct OpctabOutput {
/// 吸收不透明度
pub ab: f64,
/// 散射不透明度
pub sc: f64,
/// 总散射
pub sct: f64,
}
/// 通过插值计算不透明度。
///
/// # 参数
///
/// * `params` - 输入参数
/// * `table` - 表数据
/// * `model` - 模型状态
///
/// # 返回值
///
/// 不透明度输出结构
///
/// # Panics
///
/// 当 `ifrayl > 0` 但 `rayleigh_params`、`raysct` 或 `eospar` 为 `None` 时 panic。
pub fn opctab(
params: &OpctabParams,
table: &OpctabTableData,
model: &mut OpctabModelState,
) -> OpctabOutput {
let jf = params.ij;
let id = params.id;
let id_idx = id - 1;
// 检查是否直接使用预计算的值 (numtemp == nd)
// Fortran: if(numtemp.eq.nd) then
let opac = if table.numtemp == table.nd {
// 直接使用当前深度点的值
// Fortran: opac=absopac(id,1,jf)
table.absopac[id_idx * table.max_numrh * table.nfreq + jf - 1]
} else {
compute_interpolated_opacity(params, table, jf)
};
let ab = opac.exp();
// 散射计算
let mut sct = 0.0;
// 1. Rayleigh 散射
if params.ifrayl < 0 {
// 简单公式: sct = raysc(id) * (freq(jf) / frray0)^4
sct = table.raysc[id_idx] * (table.freq[jf - 1] / FRRAY0).powi(4);
} else if params.ifrayl > 0 {
// 调用完整的 rayleigh 函数
let rayleigh_params = params
.rayleigh_params
.expect("rayleigh_params required when ifrayl > 0");
let raysct = model
.raysct
.as_mut()
.expect("raysct required when ifrayl > 0");
let eospar = model
.eospar
.as_ref()
.expect("eospar required when ifrayl > 0");
let scr = rayleigh(1, params.ij, params.id, rayleigh_params, raysct, eospar);
sct = scr / model.dens[id_idx];
}
// 电子散射
if params.ioptab < 0 {
sct = sct + table.sige * model.elec[id_idx] / params.rho;
}
// 如果迭代次数 <= 0直接返回
if params.iter <= 0 {
return OpctabOutput { ab, sc: sct, sct };
}
// 根据 IGRAM 标志调整
let (ab_out, sc_out, sct_out) = if params.igram == 0 {
(ab * params.rho, sct * params.rho, sct * params.rho)
} else {
(ab, sct, sct)
};
OpctabOutput {
ab: ab_out,
sc: sc_out,
sct: sct_out,
}
}
/// 计算插值不透明度(内部函数)
fn compute_interpolated_opacity(params: &OpctabParams, table: &OpctabTableData, jf: usize) -> f64 {
let tl = params.t.ln();
let deltat = (tl - table.ttab1) / (table.ttab2 - table.ttab1) * (table.numtemp - 1) as f64;
let mut jt = (1.0 + deltat.floor()) as isize;
if jt < 1 {
jt = 1;
}
if jt > table.numtemp as isize - 1 {
jt = table.numtemp as isize - 1;
}
let jt = jt as usize;
let jt_idx = jt - 1;
let t1i = table.tempvec[jt_idx];
let t2i = table.tempvec[jt_idx + 1];
let mut dti = (tl - t1i) / (t2i - t1i);
if deltat < 0.0 {
dti = 0.0;
}
// 检查是否需要密度插值
// Fortran: if(numrh(1).ne.1) then
if table.numrh[0] != 1 {
compute_2d_interpolation(params, table, jf, jt_idx, dti)
} else {
// 单密度情况: jr = 1 (Fortran), 所以 jr_idx = 0
// Fortran: opac=absopac(jt,jr,jf)+(absopac(ju,jr,jf)-absopac(jt,jr,jf))*dti
let jr_idx = 0; // jr = 1 in Fortran
let idx_jt = jt_idx * table.max_numrh * table.nfreq + jr_idx * table.nfreq + (jf - 1);
let idx_ju = (jt_idx + 1) * table.max_numrh * table.nfreq + jr_idx * table.nfreq + (jf - 1);
table.absopac[idx_jt] + (table.absopac[idx_ju] - table.absopac[idx_jt]) * dti
}
}
/// 二维插值(温度和密度)
fn compute_2d_interpolation(
params: &OpctabParams,
table: &OpctabTableData,
jf: usize,
jt_idx: usize,
dti: f64,
) -> f64 {
let rl = params.rho.ln();
// 低温下的密度插值
// Fortran: numrho=numrh(jt), rtab1=rhomat(jt,1), rtab2=rhomat(jt,numrho)
let numrho = table.numrh[jt_idx] as usize;
let rtab1 = table.rhomat[jt_idx * table.max_numrh];
let rtab2 = table.rhomat[jt_idx * table.max_numrh + numrho - 1];
let deltar = (rl - rtab1) / (rtab2 - rtab1) * (numrho - 1) as f64;
let mut jr = (1.0 + deltar.floor()) as isize;
if jr < 1 {
jr = 1;
}
if jr > numrho as isize - 1 {
jr = numrho as isize - 1;
}
let jr = jr as usize;
let jr_idx = jr - 1;
// Fortran: r1i=rhomat(jt,jr), r2i=rhomat(jt,jr+1)
let r1i = table.rhomat[jt_idx * table.max_numrh + jr_idx];
let r2i = table.rhomat[jt_idx * table.max_numrh + jr_idx + 1];
let mut dri = (rl - r1i) / (r2i - r1i);
if deltar < 0.0 {
dri = 0.0;
}
// Fortran: opr1=absopac(jt,jr,jf)+dri*(absopac(jt,jr+1,jf)-absopac(jt,jr,jf))
let idx_jt_jr = jt_idx * table.max_numrh * table.nfreq + jr_idx * table.nfreq + (jf - 1);
let idx_jt_jrp1 = jt_idx * table.max_numrh * table.nfreq + (jr_idx + 1) * table.nfreq + (jf - 1);
let opr1 =
table.absopac[idx_jt_jr] + dri * (table.absopac[idx_jt_jrp1] - table.absopac[idx_jt_jr]);
// 高温下的密度插值
// Fortran: ju=jt+1, numrho=numrh(ju)
let ju_idx = jt_idx + 1;
let numrho_h = table.numrh[ju_idx] as usize;
let rtab1_h = table.rhomat[ju_idx * table.max_numrh];
let rtab2_h = table.rhomat[ju_idx * table.max_numrh + numrho_h - 1];
let deltar_h = (rl - rtab1_h) / (rtab2_h - rtab1_h) * (numrho_h - 1) as f64;
let mut jr_h = (1.0 + deltar_h.floor()) as isize;
if jr_h < 1 {
jr_h = 1;
}
if jr_h > numrho_h as isize - 1 {
jr_h = numrho_h as isize - 1;
}
let jr_h = jr_h as usize;
let jr_h_idx = jr_h - 1;
let r1i_h = table.rhomat[ju_idx * table.max_numrh + jr_h_idx];
let r2i_h = table.rhomat[ju_idx * table.max_numrh + jr_h_idx + 1];
let mut dri_h = (rl - r1i_h) / (r2i_h - r1i_h);
if deltar_h < 0.0 {
dri_h = 0.0;
}
// Fortran: opr2=absopac(ju,jr,jf)+dri*(absopac(ju,jr+1,jf)-absopac(ju,jr,jf))
let idx_ju_jr = ju_idx * table.max_numrh * table.nfreq + jr_h_idx * table.nfreq + (jf - 1);
let idx_ju_jrp1 = ju_idx * table.max_numrh * table.nfreq + (jr_h_idx + 1) * table.nfreq + (jf - 1);
let opr2 = table.absopac[idx_ju_jr]
+ dri_h * (table.absopac[idx_ju_jrp1] - table.absopac[idx_ju_jr]);
// Fortran: opac=opr1+(opr2-opr1)*dti
opr1 + (opr2 - opr1) * dti
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_opctab_constants() {
assert_relative_eq!(FRRAY0, 5.0872638e14, epsilon = 1e9);
}
#[test]
fn test_opctab_direct_value() {
let params = OpctabParams {
fr: 1e15,
ij: 1,
id: 1,
t: 10000.0,
rho: 1e-7,
igram: 0,
iter: 1,
ifrayl: -1,
ioptab: 0,
rayleigh_params: None,
};
let numtemp = 1;
let nd = 1;
let nfreq = 1;
let max_numrh = 1;
let tempvec = vec![9.2103];
let numrh = vec![1];
let rhomat = vec![-16.1181];
let absopac = vec![0.0];
let raysc = vec![1e-20];
let freq = vec![5.0872638e14];
let table = OpctabTableData {
numtemp,
nd,
nfreq,
max_numrh,
tempvec: &tempvec,
ttab1: 8.0,
ttab2: 11.0,
numrh: &numrh,
rhomat: &rhomat,
absopac: &absopac,
raysc: &raysc,
freq: &freq,
sige: 6.65e-25,
};
let elec = vec![1e-10];
let dens = vec![1e-7];
let mut model = OpctabModelState {
elec: &elec,
dens: &dens,
raysct: None,
eospar: None,
};
let result = opctab(&params, &table, &mut model);
// 当 numtemp == nd 时,直接使用 absopac(id, 1, jf) = 0.0
// ab = exp(0.0) * rho = 1.0 * 1e-7 = 1e-7
assert_relative_eq!(result.ab, 1e-7, epsilon = 1e-10);
}
#[test]
fn test_opctab_rayleigh_scattering() {
let params = OpctabParams {
fr: 1e15,
ij: 1,
id: 1,
t: 10000.0,
rho: 1e-7,
igram: 0,
iter: 1,
ifrayl: -1,
ioptab: 0,
rayleigh_params: None,
};
let numtemp = 1;
let nd = 1;
let nfreq = 1;
let max_numrh = 1;
let tempvec = vec![9.2103];
let numrh = vec![1];
let rhomat = vec![-16.1181];
let absopac = vec![0.0];
let raysc = vec![1e-20];
let freq = vec![5.0872638e14];
let table = OpctabTableData {
numtemp,
nd,
nfreq,
max_numrh,
tempvec: &tempvec,
ttab1: 8.0,
ttab2: 11.0,
numrh: &numrh,
rhomat: &rhomat,
absopac: &absopac,
raysc: &raysc,
freq: &freq,
sige: 6.65e-25,
};
let elec = vec![1e-10];
let dens = vec![1e-7];
let mut model = OpctabModelState {
elec: &elec,
dens: &dens,
raysct: None,
eospar: None,
};
let result = opctab(&params, &table, &mut model);
// Rayleigh 散射 = raysc * (freq/frray0)^4 * rho
// = 1e-20 * 1.0^4 * 1e-7 = 1e-27
assert_relative_eq!(result.sct, 1e-27, epsilon = 1e-30);
}
}

369
src/math/ratmat.rs Normal file
View File

@ -0,0 +1,369 @@
//! 速率矩阵计算 - RATMAT。
//!
//! 重构自 TLUSTY `ratmat.f`
//!
//! 计算统计平衡方程的速率矩阵 A 和右端向量 B。
//!
//! 方程形式为A * n = B其中 n 是能级占据数向量。
//!
//! 参考Mihalas, 1978, pp.138-139
use crate::math::reflev::reflev;
use crate::state::atomic::AtomicData;
use crate::state::config::TlustyConfig;
use crate::state::constants::{HK, MLEVEL, UN};
use crate::state::iterat::IterControl;
use crate::state::model::ModelState;
/// RATMAT 输入参数
pub struct RatmatParams<'a> {
/// 深度索引 (1-indexed)
pub id: usize,
/// 能级索引数组 (可能为负)
pub iical: &'a mut [i32],
/// 模式标志 (<0: 特殊模式, 0: 正常, >0: 调用 REFLEV)
pub imode: i32,
}
/// RATMAT 输出
pub struct RatmatOutput {
/// 速率矩阵 A (MLEVEL × MLEVEL)
pub a: Vec<Vec<f64>>,
/// 右端向量 B (MLEVEL)
pub b: Vec<f64>,
}
/// 计算速率矩阵。
///
/// # 参数
///
/// * `params` - 输入参数
/// * `config` - 配置
/// * `atomic` - 原子数据
/// * `model` - 模型状态
/// * `iterat` - 迭代控制
///
/// # 返回值
///
/// 速率矩阵 A 和右端向量 B
pub fn ratmat(
params: &mut RatmatParams,
config: &mut TlustyConfig,
atomic: &mut AtomicData,
model: &mut ModelState,
iterat: &IterControl,
) -> RatmatOutput {
let id = params.id;
let id_idx = id - 1;
// 检查选项表标志
if config.basnum.ioptab < 0 {
return RatmatOutput {
a: vec![vec![0.0; MLEVEL]; MLEVEL],
b: vec![0.0; MLEVEL],
};
}
let nlevel = config.basnum.nlevel as usize;
let ntrans = config.basnum.ntrans as usize;
let natom = config.basnum.natom as usize;
let lte = config.inppar.lte;
let ipslte = config.inppar.ipslte;
// 如果使用 Slater 迭代,清零辐射速率
if ipslte != 0 {
for itr in 0..ntrans {
model.rrrates.rru[itr][id_idx] = 0.0;
model.rrrates.rrd[itr][id_idx] = 0.0;
model.rrrates.drdt[itr][id_idx] = 0.0;
}
}
// 初始化输出
let mut a = vec![vec![0.0; MLEVEL]; MLEVEL];
let mut b = vec![0.0; MLEVEL];
// 工作数组
let mut aij = vec![0.0; ntrans.max(1)];
let mut aji = vec![0.0; ntrans.max(1)];
let mut sbw = vec![0.0; MLEVEL];
let mut llte = vec![false; MLEVEL];
// 获取物理量
let t = model.modpar.temp[id_idx];
let ane = model.modpar.elec[id_idx];
let hkt = HK / t;
let tk = hkt / HK;
// 初始化
for i in 0..nlevel {
b[i] = 0.0;
sbw[i] = ane * model.levpop.sbf[i] * model.wmcomp.wop[i][id_idx];
llte[i] = false;
// 设置 LTE 标志
let iel_i = atomic.levpar.iel[i] as usize;
let ilt = atomic.ionpar.iltion[iel_i];
let llt = ilt == 1 && params.imode == 0;
llte[i] = llt || lte || atomic.ionpar.iltlev[i] >= 1 || ilt >= 2;
llte[i] = llte[i] || id >= config.inppar.idlte as usize;
for j in 0..nlevel {
a[j][i] = 0.0;
}
}
// 确定参考能级
if params.imode != 0 {
reflev(id, params.imode.abs(), config, atomic, model, iterat);
}
// 第一部分LTE 情况下的简化表达式
for iat in 0..natom {
if atomic.atopar.iifix[iat] != 1 || params.imode < 0 {
let nrefi = atomic.atopar.nrefs[iat][id_idx] as usize;
let n0 = atomic.atopar.n0a[iat] as usize;
let nk = atomic.atopar.nka[iat] as usize;
for i in n0..=nk {
let ii = params.iical[i].abs() as usize;
if i != nrefi && ii != 0 && llte[i] {
a[ii][ii] = UN;
let n = params.iical[model.levref.ilterf[i][id_idx] as usize].abs() as usize;
a[ii][n] = a[ii][n] - model.levref.sblpsi[i][id_idx];
}
}
}
}
// 第二部分NLTE 速率方程
if !lte {
// 计算跃迁速率
for itr in 0..ntrans {
let i = atomic.trapar.ilow[itr] as usize;
if atomic.atopar.iifix[atomic.trapar.iatm[i] as usize] == 1 {
continue;
}
let j = atomic.trapar.iup[itr] as usize;
let nke = atomic.ionpar.nnext[atomic.levpar.iel[i] as usize] as usize;
// 向上总速率
aij[itr] = (model.rrrates.colrat[itr][id_idx] + model.rrrates.rru[itr][id_idx])
* model.wmcomp.wop[j][id_idx];
// 向下总速率
if atomic.trapar.line[itr] {
// 束缚-束缚跃迁
aji[itr] = (model.rrrates.coltar[itr][id_idx]
+ model.rrrates.rrd[itr][id_idx]
* atomic.levpar.g[i] / atomic.levpar.g[j]
* (hkt * atomic.trapar.fr0[itr]).exp())
* model.wmcomp.wop[i][id_idx];
} else {
// 束缚-自由跃迁
let corr = if nke != j {
atomic.levpar.g[nke] / atomic.levpar.g[j]
* ((atomic.levpar.enion[nke] - atomic.levpar.enion[j]) * tk).exp()
} else {
UN
};
aji[itr] = model.rrrates.coltar[itr][id_idx] * model.wmcomp.wop[i][id_idx]
+ model.rrrates.rrd[itr][id_idx] * sbw[i] * corr;
}
// 处理负索引
if params.iical[i] < 0 && params.iical[j] < 0 {
aij[itr] *= model.levref.sbpsi[i][id_idx];
aji[itr] *= model.levref.sbpsi[j][id_idx];
}
}
// 填充速率矩阵
for itr in 0..ntrans {
let i = atomic.trapar.ilow[itr] as usize;
if atomic.atopar.iifix[atomic.trapar.iatm[i] as usize] == 1 {
continue;
}
let nrefi = atomic.atopar.nrefs[atomic.trapar.iatm[i] as usize][id_idx] as usize;
let j = atomic.trapar.iup[itr] as usize;
let ii = params.iical[i].abs() as usize;
let jj = params.iical[j].abs() as usize;
if model.popzr0.ipzero[i][id_idx] != 0 || model.popzr0.ipzero[j][id_idx] != 0 {
continue;
}
// 下能级贡献
if i != nrefi && ii > 0 && !llte[i] {
a[ii][ii] += aij[itr];
if jj > 0 {
a[ii][jj] -= aji[itr];
} else {
let jjj = params.iical[model.levref.iltref[j][id_idx] as usize] as usize;
a[ii][jjj] -= aji[itr] * model.levref.sbpsi[j][id_idx];
}
}
// 上能级贡献
if j != nrefi && jj > 0 && !llte[j] {
a[jj][jj] += aji[itr];
if ii > 0 {
a[jj][ii] -= aij[itr];
} else {
let iii = params.iical[model.levref.iltref[i][id_idx] as usize] as usize;
a[jj][iii] -= aij[itr] * model.levref.sbpsi[i][id_idx];
}
}
}
}
// 重置"小"占据数的速率矩阵元素
for i in 0..nlevel {
let ii = params.iical[i];
if ii > 0 {
let ii_idx = ii as usize;
if model.popzr0.ipzero[i][id_idx] > 0 {
for j in 0..nlevel {
a[ii_idx][j] = 0.0;
}
a[ii_idx][ii_idx] = 1.0;
}
} else if ii < 0 {
let ii_idx = (-ii) as usize;
if model.popzr0.igzero[ii_idx - 1][id_idx] > 0 {
for j in 0..nlevel {
a[ii_idx - 1][j] = 0.0;
}
a[ii_idx - 1][ii_idx - 1] = 1.0;
}
}
}
// 第三部分:丰度定义方程
for iat in 0..natom {
if atomic.atopar.iifix[iat] == 1 && params.imode >= 0 {
continue;
}
let nrefii = params.iical[atomic.atopar.nrefs[iat][id_idx] as usize].abs() as usize;
let n0 = atomic.atopar.n0a[iat] as usize;
let nk = atomic.atopar.nka[iat] as usize;
for i in n0..=nk {
let il = atomic.levpar.ilk[i];
let ii = params.iical[i];
if ii > 0 {
let ii_idx = ii as usize;
a[nrefii][ii_idx] += UN;
if il != 0 {
a[nrefii][ii_idx] += ane * model.levpop.usum[il as usize];
}
} else if ii < 0 {
let ii_idx = (-ii) as usize;
a[nrefii][ii_idx - 1] += model.levref.sbpsi[i][id_idx];
if il != 0 {
a[nrefii][ii_idx - 1] +=
ane * model.levpop.usum[il as usize] * model.levref.sbpsi[i][id_idx];
}
} else {
let iii = params.iical[model.levref.iltref[i][id_idx] as usize] as usize;
if iii > 0 && iii <= nlevel {
a[nrefii][iii - 1] += model.levref.sbpsi[i][id_idx];
}
}
}
b[nrefii] += model.modpar.dens[id_idx]
/ model.modpar.wmm[id_idx]
/ model.modpar.ytot[id_idx]
* atomic.atopar.abund[iat][id_idx];
}
RatmatOutput { a, b }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ratmat_ioptab_negative() {
let mut config = TlustyConfig::default();
let mut atomic = AtomicData::default();
let mut model = ModelState::default();
let iterat = IterControl::default();
config.basnum.ioptab = -1;
config.basnum.nlevel = 10;
config.basnum.ntrans = 5;
config.basnum.natom = 1;
let mut iical = vec![0; MLEVEL];
let mut params = RatmatParams {
id: 1,
iical: &mut iical,
imode: 0,
};
let result = ratmat(&mut params, &mut config, &mut atomic, &mut model, &iterat);
// 当 ioptab < 0 时,应返回零矩阵
assert_eq!(result.a.len(), MLEVEL);
assert_eq!(result.b.len(), MLEVEL);
for i in 0..MLEVEL {
assert_relative_eq!(result.b[i], 0.0);
}
}
#[test]
fn test_ratmat_basic_lte() {
let mut config = TlustyConfig::default();
let mut atomic = AtomicData::default();
let mut model = ModelState::default();
let iterat = IterControl::default();
config.basnum.ioptab = 0;
config.basnum.nlevel = 5;
config.basnum.ntrans = 3;
config.basnum.natom = 1;
config.inppar.lte = true;
atomic.atopar.n0a[0] = 0;
atomic.atopar.nka[0] = 4;
atomic.atopar.nrefs[0][0] = 2;
atomic.atopar.iifix[0] = 0;
atomic.levpar.iel[0] = 0;
atomic.levpar.iel[1] = 0;
atomic.levpar.iel[2] = 1;
atomic.levpar.iel[3] = 1;
atomic.levpar.iel[4] = 1;
atomic.levpar.ilk[0] = 0;
atomic.levpar.ilk[1] = 0;
atomic.levpar.ilk[2] = 1;
atomic.levpar.ilk[3] = 0;
atomic.levpar.ilk[4] = 0;
atomic.ionpar.iltion[0] = 1;
atomic.ionpar.iltion[1] = 1;
model.modpar.temp[0] = 10000.0;
model.modpar.elec[0] = 1e12;
model.modpar.dens[0] = 1e14;
model.modpar.wmm[0] = 1.0;
model.modpar.ytot[0] = 1.0;
atomic.atopar.abund[0][0] = 1.0;
let mut iical = vec![1, 2, 3, 4, 5];
let mut params = RatmatParams {
id: 1,
iical: &mut iical,
imode: 0,
};
let result = ratmat(&mut params, &mut config, &mut atomic, &mut model, &iterat);
// 验证矩阵维度
assert_eq!(result.a.len(), MLEVEL);
assert_eq!(result.b.len(), MLEVEL);
}
}

View File

@ -144,14 +144,20 @@ pub struct FixAlp {
pub dsfdt: Vec<f64>,
/// 源函数 N 导数
pub dsfdn: Vec<f64>,
/// 源函数 M 导数
pub dsfdm: Vec<f64>,
/// 前深度源函数 T 导数
pub dsfdtm: Vec<f64>,
/// 前深度源函数 N 导数
pub dsfdnm: Vec<f64>,
/// 前深度源函数 M 导数
pub dsfdmm: Vec<f64>,
/// 后深度源函数 T 导数
pub dsfdtp: Vec<f64>,
/// 后深度源函数 N 导数
pub dsfdnp: Vec<f64>,
/// 后深度源函数 M 导数
pub dsfdmp: Vec<f64>,
// 源函数能级导数 (MLVEXP × MDEPTH)
/// 源函数能级导数
@ -271,10 +277,13 @@ impl Default for FixAlp {
// 源函数导数
dsfdt: vec![0.0; MDEPTH],
dsfdn: vec![0.0; MDEPTH],
dsfdm: vec![0.0; MDEPTH],
dsfdtm: vec![0.0; MDEPTH],
dsfdnm: vec![0.0; MDEPTH],
dsfdmm: vec![0.0; MDEPTH],
dsfdtp: vec![0.0; MDEPTH],
dsfdnp: vec![0.0; MDEPTH],
dsfdmp: vec![0.0; MDEPTH],
// 源函数能级导数
dsfdp: vec![vec![0.0; MDEPTH]; MLVEXP],