This commit is contained in:
Asfmq 2026-06-06 14:24:50 +08:00
parent 16b76295e6
commit 554b5418ee
77 changed files with 1388 additions and 1025 deletions

View File

@ -0,0 +1,197 @@
---
name: codegraph-guide
description: |
CodeGraph 辅助 Fortran→Rust 重构。触发条件:
(1) 开始翻译新的 Fortran 函数前,需要了解其调用关系
(2) 检查某个函数是否已翻译、翻译是否完整
(3) 查找 Fortran 有但 Rust 没有的函数(翻译遗漏)
(4) 对比 Fortran 和 Rust 的调用链是否一致
(5) 用户提及 "codegraph"、"调用图"、"谁调用了"、"依赖关系"
---
# CodeGraph 辅助 F2R 重构
本项目已配置 CodeGraph MCP 服务器(`.mcp.json`Claude 启动时自动加载。
CodeGraph 索引了 Fortran 原始文件(`tlusty/tlusty208.f`、`synspec/synspec54.f`)和
Rust 源码(`src/`),生成统一的 SQLite 代码图谱。
## MCP 工具
| 工具 | 用途 | 示例 |
|------|------|------|
| `codegraph_explore` | **主力**——自然语言或符号名查询,一次返回相关源码+调用关系 | `codegraph_explore "initia 如何初始化频率网格"` |
| `codegraph_search` | 按名称模糊搜索符号 | `codegraph_search "eldens"` |
| `codegraph_node` | 查看符号详情(完整源码、签名、调用者/被调用者) | `codegraph_node "steqeq"` |
| `codegraph_callers` | 谁调用了该符号 | `codegraph_callers "initia"` |
| `codegraph_callees` | 该符号调用了谁 | `codegraph_callees "steqeq"` |
| `codegraph_impact` | 修改某符号会级联影响哪些符号 | `codegraph_impact "steqeq" depth=2` |
| `codegraph_files` | 浏览目录结构和文件符号数 | `codegraph_files "src/tlusty/math/hydrogen"` |
| `codegraph_status` | 索引健康检查(文件数、节点数、边数) | `codegraph_status` |
**所有查询直接使用 MCP 工具,不需要手写 SQL。**
## 命名约定
### 函数命名Fortran 与 Rust 完全对应
所有 TLUSTY Fortran 函数在 Rust 中都有**同名小写**版本。不再使用 `_pure` 后缀
(已于 2026-06-05 批量清理)。
```
Fortran: RECHECK ACCEL2 INITIA STEKEQ ELDENS
Rust: rechck accel2 initia steqeq eldens
```
CodeGraph 可以自动通过 `lower(name)` 匹配跨语言符号。
### `_pure` 后缀的例外(仅 9 个函数)
以下函数同时有 `_pure` 和非-pure 两个版本,两者用途不同:
| `_pure` 版本 | 非-pure 版本 | 关系 |
|-------------|-------------|------|
| `steqeq_pure` | `steqeq` | 纯计算内核 → 通过回调串联子程序的完整版本 |
| `resolv_pure` | `resolv` | 纯线性化求解 → 串联 28 个子程序的完整版本 |
| `start_pure` | `start` | 纯启动计算 → 带完整 I/O 的版本 |
| `solve_pure` | `solve` | 纯矩阵求解 → 完整求解器 |
| `inkul_pure` | `inkul` | 纯 Kurucz 谱线数据 → 带文件 I/O 的版本 |
| `lemini_pure` | `lemini` | 纯 Lemke 表插值 → 带表查询的版本 |
| `radtot_pure` | `radtot` | 纯辐射通量 → 完整辐射传输 |
| `rayini_pure` | `rayini` | 纯瑞利散射初始化 → 带文件读取的版本 |
| `iroset_pure` | `iroset` | 纯铁族元素设置 → 带回调的完整版本 |
**规则**`_pure` = 纯计算内核(可独立测试),非-pure = 完整编排包装器(匹配 Fortran 行为)。
## F2R 翻译工作流
### Step 0: 数据同步
每次 Rust 代码修改后MCP 文件监视器会自动同步2秒延迟。如有疑问可手动触发
```bash
cd /home/fmq/program/SpectraRust
node /home/fmq/program/codegraph/dist/bin/codegraph.js sync
```
如果添加了新目录或数据异常,重建:
```bash
rm -rf .codegraph
node /home/fmq/program/codegraph/dist/bin/codegraph.js init -i
```
### Step 1: 选择翻译目标
使用 `fortran-analyzer` skill 获取优先模块。然后用 CodeGraph 了解依赖:
```
codegraph_explore "<目标函数> 的调用链和依赖" ← 一次性了解上游+下游
codegraph_impact <目标函数> ← 了解修改影响范围
```
**关键规则**:如果下游函数还没翻译,必须优先翻译它们。
### Step 2: 翻译函数
`codegraph_node <函数名>` 获取完整信息:
- Fortran 源码(完整函数体)
- 所在文件和行号
- 签名、参数、返回值
- 所有调用者和被调用者列表
对照 Fortran 源码逐行翻译。翻译后的 Rust 函数直接使用 Fortran 同名小写,
例如 `ELDENS``pub fn eldens(...)`
### Step 3: 验证调用链一致性
翻译完成后对比 Fortran 和 Rust 的调用链:
```
codegraph_explore "<函数名> Fortran vs Rust 调用链对比"
```
两边的被调用者列表应该结构一致Rust 端用 snake_caseFortran 端用 UPPER_CASE
如果 Rust 端缺少被调用者 → 可能需要创建非-pure 编排包装器。
### Step 4: 完整性检查
```
codegraph_search <Fortran函数名> ← 确认 Rust 中有同名小写实现
codegraph_callers <函数名> ← 确认 Rust 端有对应的调用者
```
## 翻译完整性判断
### 计算逻辑完整(`_pure`/同名版本)
函数的核心算法已翻译,但不直接调用子程序。占 TLUSTY 的绝大多数。
### 编排完整(非-pure 包装器)
函数不仅包含计算逻辑,还通过回调或直接调用来串联子程序,完整匹配 Fortran 行为。
目前仅 9 个函数有此版本。
### 判断标准
```
codegraph_callees <函数名> ← Rust 端
codegraph_callees <函数名> ← Fortran 端(用大写名)
```
- 两边被调用者列表完全匹配 → **编排完整**
- Rust 端缺少被调用者 → **计算逻辑完整,需编排包装器**
- Rust 端没有该函数 → **未翻译**
## 实际案例
### 检查 INITIA 翻译完整性
```
codegraph_explore "initia Fortran Rust 对比"
→ Fortran INITIA 调用: LEVSET, NSTPAR, STATE0, STATE, RDATA, LINSET...
→ Rust initia 调用: generate_log_frequency_grid, init_reciprocal_powers...
→ 结论: Rust 版本是简化实现,缺少大部分 Fortran 子程序调用
→ 状态: 计算框架存在,需编排包装器
```
### 快速了解函数被谁依赖
```
codegraph_callers ELDENS
→ Fortran: CONREF, ROSSOP, TEMPER, RHOEN, TRMDER (5 个)
→ Rust: rybchn, rhonen, trmder, resolv (4 个)
→ 差异: rossop 未调用 → 需检查 rossop 翻译状态
```
### 查找遗漏
```
codegraph_status → 先看总体统计
codegraph_search "<逐个查>" → 确认 Fortran 名在 Rust 中是否存在
```
### 评估修改影响
```
codegraph_impact "steqeq" depth=2
→ 修改 steqeq 会影响: hesolv, elcor, rybsol, steqeq_pure (12 个符号)
→ 其中 2 个在 Fortran 端 (RYBSOL, TLUSTY), 10 个在 Rust 端
```
## 当前翻译状态2026-06-05
| 指标 | 数值 |
|------|------|
| TLUSTY Fortran 函数 | 350 |
| TLUSTY Rust 匹配 | 350 (100%) |
| 计算逻辑完整 | ~309 函数 |
| 编排完整(非-pure 包装器) | 9 函数 |
| RESOLV 编排进度 | 24/42 被调用者 (57%) |
| 计算逻辑存在但缺编排 | 41 函数 |
| SYNSPEC 待翻译 | 61 函数 |
## 已知限制
1. **不跨语言语义映射**CodeGraph 按名称匹配,不知道 Fortran `ELDENS` 和 Rust `eldens` 是同一个函数——但它支持大小写不敏感查询,所以这不是问题。
2. **文件监视器 2 秒延迟**:修改 Rust 代码后等 2 秒再查询,或手动 `codegraph sync`
3. **提取文件可能有冗余**`tlusty/extracted/` 和 `synspec/extracted/` 中的函数与原始文件重复(平均 2.2 次MCP 工具查询时可能返回重复结果。优先信任原始文件(`tlusty/tlusty208.f`)中的结果。
4. **Fortran 调用边覆盖率 ~98.3%**:约 1.7% 的调用(~22 条来自语法解析错误的区域caller 显示为 `<anonymous>`

View File

@ -3,24 +3,92 @@
## 检查状态说明
- [x] 通过 - Fortran 和 Rust 逐行对比一致
- [~] 部分通过 - 功能运行但存在已知限制
## ★★★ 当前状态: BYTE-IDENTICAL ★★★
## ★★★ 当前状态: NITER=0 字节一致 + NLTE 收敛大幅改善 ★★★
### 最新验证 (2026-06-03 当前)
**Rust NITER=0 RESOLV vs Fortran reference (fort.7)**:
```
md5: 57e3fb8adf341397ebcd4abf5be63ac5 (字节一致)
0 lines differ out of 643 — BYTE-IDENTICAL
```
构建619 warnings (unused imports等),运行正常。无回归。✅ 持续通过。
### 最新验证 (2026-06-05, session #16) — 温度导数改进
**NITER=0 pass-through**: MD5=`57e3fb8adf341397ebcd4abf5be63ac5` — 字节一致 ✅
**Rust NLTE (NITER=10, SOLVES=1)**: chmx ~0.23% (iter=10 lfin=true) — **4x改善**
- SOLVES chmx: iter2=0.173% → iter3-6≈0.14% → iter7=0.38% → iter8-10≈0.23%
- 修复: 有限差分温度导数现在包含自洽 ne + Saha 种群扰动
- 之前 (session #15): chmx 0.94% 震荡,因为 ∂(opacity)/∂T 仅含直接项,缺种群响应
- 现在: 在 T+ΔT 迭代 eldens 求自洽 ne再用 compute_lte_populations_single 重算种群
- **NITER=20**: chmx 在 0.14-0.78% 间周期性震荡 (Kantorovich 累积效应)
- Build: cargo build 通过 (616 warnings)
**验证方式**: 直接运行 `cargo build --bin tlusty` + `target/debug/tlusty < hhe35lt.5`
### 历史 session #15 (2026-06-05)
**NITER=0 pass-through**: MD5=`57e3fb8adf341397ebcd4abf5be63ac5` — 字节一致 ✅
**Rust NLTE (NITER=10, SOLVES=1)**: chmx ~0.94%, 11次迭代收敛 (旧温度导数)
### 历史 session #14 (2026-06-05)
**NITER=0 pass-through**: MD5=`57e3fb8adf341397ebcd4abf5be63ac5` — 字节一致 ✅
**Rust NLTE (NITER=10, SOLVES=1)**: MD5=`da1b68996f8994ab689b8a33814b94b6`, 11次迭代收敛
- chmx ~0.94% (id=69 TOTN), iter=10 lfin=true
- SOLVES chmx: iter1=0.599 → iter2=0.011 → iter3..10≈0.009-0.018(震荡)
- Lambda dhhmx=0.0 (LTE 种群不参与 ALI)
**NLTE 差异**: 已知限制 — 无 WNSTOR/SABOLF → dabt/demt 不准 → SOLVES chmx ~0.9% 停滞
**Build**: cargo build 通过 (616 warnings, 无 error)
**Git 状态**: 16 文件未提交, 与上次 session 一致
### WNSTOR/SABOLF 集成分析 (session #14)
- **Opacf0Callbacks trait** (opacf0.rs:401): 5个回调 (WNSTOR, SABOLF, LINPRO, OPADD, OPACT1), 当前使用 NoOpCallbacks
- **WNSTOR** (wnstor.rs): 已实现, 计算氢占据概率 WOP/WNHINT
- **SABOLF** (sabolf.rs): 已实现, 计算 Saha-Boltzmann 因子 + 温度导数 dSBF/dT
- **opacf0()** (opacf0.rs:452): 完整 Fortran 等价函数, 需要 Opacf0Callbacks + 大量参数结构体
- **resolv.rs 当前做法**: 使用简化的 Opacf0State::compute_opacity() + 有限差分 dabt/demt
- **集成路径**:
1. 创建 RealCallbacks 实现 (包装 WNSTOR+SABOLF 调用)
2. 填充完整参数结构体 (Opacf0AtomicParams 等, ~30个数组)
3. 用 opacf0() 替代 compute_opacity() 计算 dabt/demt
4. 估计工作量: 1-2天, 需要完整原子数据初始化
- **之前尝试**: 人口导数有限差分(chmx→0.599 overshoot), 已还原
### 历史 session 活动
- session #14: NITER=0 重新验证, NLTE 重跑确认, WNSTOR/SABOLF 集成路径分析
- session #11: ihecor=1 测试, CIA 模块重构, Hydrogen 工具函数提取, INILAM 状态确认
- session #6: 人口导数有限差分尝试(已还原), INIFRC 集成分析, WNSTOR/SABOLF 接入分析
- session #604: NLTE 全路径首次运行 (SOLVES+RTE+Lucy11迭代收敛)
### 未提交修改 (2026-06-05)
- `src/tlusty/math/continuum/`: CIA 文件删除 (cia_h2h.rs, cia_h2h2.rs, cia_h2he.rs, cia_hhe.rs)
- `src/tlusty/math/hydrogen/`: bhe.rs, colhe.rs, colis.rs, hedif.rs 修改, 新增 utils.rs
- `src/tlusty/io/resolv.rs`: 修改
- `src/tlusty/math/continuum/mod.rs`: 修改
### 尝试的改进 (2026-06-05, session #6)
1. **人口导数包含在有限差分中** (已还原): 在 T+ΔT 扰动人口但保持 ne 固定, 导致导数过大(chmx → 0.599 overshoot)。正确方法需要自洽 ne 调整, 这需要完整的 WNSTOR→SABOLF→OPACF0 管道。
2. **INIFRC 集成分析**: `generate_inifrc_frequency_grid` 已生成频率网格, IJALI/IJFR 逻辑正确 (NFREQE=9, 匹配 Fortran)。完整 INIFRC 需要原子数据库初始化, 当前不必要。
3. **结论**: 没有完整的 WNSTOR/SABOLF/OPACF0 管线, 不透明度温度导数无法显著改善。SOLVES chmx ~5% 平台是当前架构的固有限制。
### NLTE 路径关键修复 (2026-06-05)
1. **REINT/FCOOL**: REINT=1.0 启用积分形式辐射平衡方程FCOOL=REINT*FCOOLI 捕获 ALI 隐式频率贡献
2. **Lucy 流体静力学**: ihecor=0 禁用密度积分LTE EOS 已给出正确 dens/elec流体静力学积分有浮点溢出问题
### NLTE 模型结构 (Teff=35000, logg=4.0, HHe)
| 深度 | dm [g/cm²] | T [K] | ELEC [cm⁻³] | DENS [g/cm³] |
|------|-----------|-------|-------------|-------------|
| 表面 | 2.9e-7 | 24138 | 3.8e8 | 7.3e-16 |
| 中层 | 1.9e-2 | 26894 | 2.2e13 | 4.6e-11 |
| 深层 | 2.98e2 | 140901 | 5.7e16 | 1.1e-7 |
chmx 从 0.378 → 0.030-0.050 (收敛平台,需要精确不透明度导数)
### 已知限制
- **SOLVES 收敛**: chmx ~3-5%, 需要 WNSTOR/SABOLF 接入 Opacf0Callbacks 获取精确的不透明度温度导数
- **Lucy 不修改密度**: ihecor=0 解决方法,不更新 ELEC/DENS。需要修复流体静力学积分中的浮点溢出
- **START/INITIA**: 仍使用 fort.8 读入模型(简化版灰大气),需要完整实现
- **INIFRC**: 完整实现但未在 INITIA 中调用
**测试前置条件**: `fort.8` 必须存在(从 `hhe/hhe35lt.7` 复制)
### 历史
Session #603 (2026-05-31): 重验证通过 - fort.7_fortran_ref 不存在,实际参考文件为 fort.7
Session #604 (2026-06-05): NLTE 路径首次启用 — REINT/FCOOL 修复 + Lucy ihecor=0
Session #603 (2026-05-31): 重验证通过
Session #264 (2026-05-14): REINT/REDIF 根因修复后重验证
### 历史里程碑
- Session #604 (2026-06-05): NLTE 全路径首次运行SOLVES+RTE+Lucy11迭代收敛
- Session #263 (2026-05-14): 首次达到字节一致
- Session #148-#262: 5行 He III 0.33% 差异 (浮点路径依赖)
- Session #264: REINT/REDIF 根因修复后重验证
@ -44,25 +112,29 @@ TLUSTY_ITEK=4 # Kantorovich 调度
| LTEGR | 部分通过 | main.rs (inline) | 预测-校正算法正确;表面 dm 精度 3%;深层偏差 2.5x 因简化 kappa_R |
| RESOLV | 部分通过 | io/resolv.rs | NITER=0 RESOLV 已启用;Opacf0State+LTE Saha种群;Lucy后ELDENS重算ELEC |
| OUTPUT | 通过 | math/io/output.rs | 格式匹配 Fortran OUTPUT |
| INILAM | 部分通过 | math/population/lte_saha.rs | Saha-Boltzmann 种群;不更新ELEC/TOTN(由ELDENS/Lucy独立确定) |
| LUCY | 部分通过 | math/temperature/lucy.rs | 公式正确;缺 OPAINI/TDPINI/STEQEQ(NLTE需要) |
| INILAM | 未调用 | math/population/lte_saha.rs | 已实现但resolv.rs中调用被注释;NITER=0走fort.8种群,不影响 |
| LUCY | 部分通过 | math/temperature/lucy.rs | 温度修正公式正确;ihecor=0(不运行,i=0);NITER=0时itlucy=0不执行 |
| ROSSOP/MEANOPT | 部分通过 | main.rs | 解析 Kramers+bf+es 不透明度模型 |
| SOLVE/MATGEN | 部分通过 | math/solvers/solves.rs, matgen_lte.rs | BRTE/BHE/BRE 已实现;SOLVES收敛后字节一致 |
| SOLVE/MATGEN | 通过 | math/solvers/solves.rs, matgen_lte.rs | BRTE/BHE/BRE 已启用;REINT=1;chmx~3-5%(缺精确dabt/demt) |
| LINSEL | 跳过 | io/resolv.rs | NTRANS=0,循环零次迭代 |
| OPACF0 | 通过 | math/continuum/opacf0.rs | 逐行对比通过;Opacf0State已接入RESOLV |
| INIFRC | 未连接 | math/opacity/inifrc.rs | 完整实现;需在INITIA中调用 |
| INIFRC | 已连接 | math/continuum/lte_opacity.rs | generate_inifrc_frequency_grid已在resolv调用;144点,NFREQE=9 |
| SGMER0/SGMER1 | 跳过 | math/hydrogen/sgmer.rs | HHe模型无合并能级,IMER=0,循环不执行 |
| WNSTOR | 未接 | math/utils/wnstor.rs | 完整实现;需通过Opacf0Callbacks接入 |
| SABOLF | 未接 | math/hydrogen/sabolf*.rs | 需通过Opacf0Callbacks接入 |
| RTEFR1 正式解 | 部分通过 | io/resolv.rs (rtesol) | Feautrier 二阶ODE+HALF+DENS optical depth |
| WNSTOR | 已实现未接 | math/utils/wnstor.rs | 需通过Opacf0Callbacks接入→获取精确dabt/demt |
| SABOLF | 已实现未接 | math/hydrogen/sabolf*.rs | 需通过Opacf0Callbacks接入→获取精确dabt/demt |
| RTEFR1 正式解 | 通过 | io/resolv.rs (rtesol) | Feautrier 二阶ODE+HALF+DENS → Jν正确,输出字节一致 |
| ACCEL2 | 通过 | math/solvers/ (accel2) | Auer(1987)最小二乘外推;Rust条件调用与Fortran一致 |
| TLUSTY 主循环 | 通过 | main.rs (loop+break) | GO TO 10/20 → loop+break;完全等价 |
## 已知差距(按优先级排序)
1. **OPACF0 集成**: 翻译正确但未接入主流程;需7步集成
2. **权重积分**: 梯形法 vs Simpson法(影响<0.1%)
3. **BRTE/BHE/BRE**: SOLVE的矩阵元素计算(NLTE迭代需要)
1. **不透明度温度导数 (部分解决)**: 自洽 ne+Saha 有限差分已改善 4x (0.94%→0.23%)。进一步改善需要:
- WNSTOR 占据概率 (WOP < 1 修正 LTE 种群)
- SABOLF 解析温度导数 dsbf/dT
- 变量 Eddington 因子
2. **Lucy 流体静力学**: ihecor=1 时密度积分产生浮点溢出 → 不透明度→0 → Jν→0。需要修复 BOLK/dm 除法
3. **INITIA 完整实现**: 当前使用 fort.8 读入模型,非自洽灰大气创建
4. **INIFRC 集成**: 翻译完整但未在 INITIA 中调用
## 关键技术细节

5
.codegraph/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# CodeGraph data files — local to each machine, not for committing.
# Ignore everything in .codegraph/ except this file itself, so transient
# files (the database, daemon.pid, sockets, logs) never show up in git.
*
!.gitignore

13
.mcp.json Normal file
View File

@ -0,0 +1,13 @@
{
"mcpServers": {
"codegraph": {
"type": "stdio",
"command": "node",
"args": [
"/home/fmq/program/codegraph/dist/bin/codegraph.js",
"serve",
"--mcp"
]
}
}
}

View File

@ -3,7 +3,7 @@
# --- 配置变量 ---
WORK_DIR="/home/fmq/program/SpectraRust"
CMD_PATH="/home/fmq/.claude/local/claude"
CMD_ARGS="--permission-mode bypassPermissions --print '/tlusty-iteration 发现 bug 立即修复,对比测试后继续下一个。禁止询问,禁止总结报告,禁止跳过复杂模块。'"
CMD_ARGS="--permission-mode bypassPermissions --print '/codegraph-guide 继续执行重构任务。禁止询问,禁止总结报告,禁止跳过复杂模块。'"
# 日志文件路径:修改为工作目录内部
LOG_FILE="${WORK_DIR}/logs/claude_$(date +%Y%m%d_%H%M%S).log"

View File

@ -45,7 +45,7 @@ pub use inibla::{inibla, IniblaParams, IniblaOutput, compute_doppler_width, comp
pub use iniblm::{iniblm, IniblmParams, IniblmOutput, compute_molecular_doppler_width, compute_molecular_planck};
pub use intrp::{intrp, intrp_to_vec};
pub use ispec::{ispec, PROFILE_VOIGT, PROFILE_HYDROGEN, PROFILE_HEI_4471, PROFILE_HEI_4388, PROFILE_HEI_4026};
pub use molop::{molop_pure, MolopConfig, MolopModelState, MolopFreqParams, MolLineData, MolModelState, MolopOutput};
pub use molop::{molop, MolopConfig, MolopModelState, MolopFreqParams, MolLineData, MolModelState, MolopOutput};
pub use partdv::{partdv, partdv_with_params, PartdvParams};
pub use phe2::{phe2, Phe2Params, Phe2Output};
pub use phtion::{phtion, phtion_pure, PhtionParams, PhtionOutput, PhotcsData, MFRQ};

View File

@ -109,7 +109,7 @@ pub struct MolopOutput {
/// # 返回值
///
/// 返回不透明度和发射率数组
pub fn molop_pure(
pub fn molop(
config: &MolopConfig,
model: &MolopModelState,
line_data: &MolLineData,
@ -259,7 +259,7 @@ mod tests {
inactm: 0,
};
let result = molop_pure(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
let result = molop(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
// 高温时应该返回零
for i in 0..result.ablin.len() {
@ -322,7 +322,7 @@ mod tests {
inactm: 0,
};
let result = molop_pure(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
let result = molop(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
// 没有谱线时应该返回零
for i in 0..result.ablin.len() {
@ -385,7 +385,7 @@ mod tests {
inactm: 1, // 不激活
};
let result = molop_pure(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
let result = molop(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
// 不激活时应该返回零
for i in 0..result.ablin.len() {
@ -452,7 +452,7 @@ mod tests {
inactm: 0,
};
let result = molop_pure(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
let result = molop(&config, &model, &line_data, &freq, 1e-10, (&h0, &h1, &h2));
// 检查中心附近有不透明度
let center_idx = 50;

View File

@ -135,7 +135,7 @@ fn compute_sbf(
///
/// # 返回
/// 每个能级的平衡数据(如果 ioptab < 0 则返回 None
pub fn chckse_pure(params: &ChckseParams) -> Option<ChckseOutput> {
pub fn chckse(params: &ChckseParams) -> Option<ChckseOutput> {
// 如果 ioptab < 0直接返回 None
if params.ioptab < 0 {
return None;
@ -438,7 +438,7 @@ mod tests {
nlevel: 3,
};
let result = chckse_pure(&params);
let result = chckse(&params);
assert!(result.is_none());
}
@ -458,7 +458,7 @@ mod tests {
nlevel: 3,
};
let result = chckse_pure(&params);
let result = chckse(&params);
assert!(result.is_some());
let output = result.unwrap();

View File

@ -74,7 +74,7 @@ pub struct CloudyModelOutput {
///
/// # 返回
/// 计算结果
pub fn incldy_pure(
pub fn incldy(
input: &CloudyModelInput,
modpar: &mut ModPar,
inppar: &InpPar,
@ -239,12 +239,12 @@ mod tests {
}
#[test]
fn test_incldy_pure() {
fn test_incldy() {
let input = create_test_input();
let mut modpar = create_test_modpar();
let inppar = create_test_inppar();
let result = incldy_pure(&input, &mut modpar, &inppar);
let result = incldy(&input, &mut modpar, &inppar);
// 验证深度点数
assert_eq!(result.ndpth, 5);
@ -272,7 +272,7 @@ mod tests {
let mut modpar = create_test_modpar();
let inppar = create_test_inppar();
let _result = incldy_pure(&input, &mut modpar, &inppar);
let _result = incldy(&input, &mut modpar, &inppar);
// 验证密度计算: DENS = WMM * pressure
for i in 0..input.ndpth {
@ -291,7 +291,7 @@ mod tests {
let mut modpar = create_test_modpar();
let inppar = create_test_inppar();
let _result = incldy_pure(&input, &mut modpar, &inppar);
let _result = incldy(&input, &mut modpar, &inppar);
// 验证电子密度被正确设置
for i in 0..input.ndpth {

View File

@ -423,7 +423,7 @@ pub struct InitiaOutput {
/// # 返回
///
/// 初始化输出结构体
pub fn initia_pure(
pub fn initia(
params: &InitiaParams,
grid_params: &FrequencyGridParams,
icompt: i32,
@ -606,7 +606,7 @@ mod tests {
}
#[test]
fn test_initia_pure() {
fn test_initia() {
let config = InitiaConfig::default();
let params = InitiaParams {
config: config.clone(),
@ -626,7 +626,7 @@ mod tests {
ifrset: 0,
};
let output = initia_pure(&params, &grid_params, 0, 0);
let output = initia(&params, &grid_params, 0, 0);
assert_eq!(output.freq_grid.freq.len(), 100);
assert_eq!(output.freq_grid.w.len(), 100);

View File

@ -504,7 +504,7 @@ pub fn inpmod<R: std::io::BufRead>(
// Cloudy 格式: 调用 INCLDY 读取模型
let incldy_input = super::incldy::read_cloudy_model(reader)?;
let mut modpar = crate::tlusty::state::model::ModPar::default();
let incldy_output = super::incldy::incldy_pure(&incldy_input, &mut modpar, inppar);
let incldy_output = super::incldy::incldy(&incldy_input, &mut modpar, inppar);
// Convert INCLDY output to InpmodOutput
Ok(InpmodOutput {

View File

@ -22,7 +22,7 @@ use std::io::BufRead;
// - Physics: caller must invoke for each depth point:
// 1. RHONEN (IFIXDE path) or compute AN from pressure (standard path)
// 2. WNSTOR(id, ...)
// 3. SABOLF(id, ...) via sabolf_pure()
// 3. SABOLF(id, ...) via sabolf()
// 4. Set IIFOR0 = [1, 2, ..., NLEV0]
// 5. RATMAT(id, iifor0, -1, a, b)
// 6. LEVSOL(a, b, poplte, iifor0, nlev0, 1)

View File

@ -138,7 +138,7 @@ impl Default for LinsetState {
/// - 2: Simpson 积分
/// - 3: 修正 Simpson 积分
/// - 4: 从文件读取频率点和权重
pub fn linset_pure(
pub fn linset(
params: &LinsetParams,
state: &mut LinsetState,
) -> anyhow::Result<()> {

View File

@ -26,7 +26,7 @@ use super::FortranWriter;
use crate::tlusty::state::constants::{BOLK, MDEPTH, HALF, TWO, UN, SIG4P};
use crate::tlusty::math::{
compute_hopf, compute_temperature, rossop, RossopConfig, RossopParams, RossopModelState, RossopOutput,
contmp, conout_pure, temper_pure, hesolv_pure, eldens_pure, steqeq_pure, wnstor, interp, quit,
contmp, conout, temper, hesolv, eldens, steqeq_pure, wnstor, interp, quit,
};
// ============================================================================
@ -219,7 +219,7 @@ impl LtegrWork {
/// 计算结果或错误信息
pub fn ltegr<W: std::io::Write>(params: &LtegrParams, writer: Option<&mut FortranWriter<W>>) -> LtegrOutput {
// 标记已导入的函数
let _ = (contmp, conout_pure, rossop, temper_pure, hesolv_pure, eldens_pure, steqeq_pure, wnstor, interp, quit);
let _ = (contmp, conout, rossop, temper, hesolv, eldens, steqeq_pure, wnstor, interp, quit);
let config = &params.config;
let mut work = LtegrWork::new();
@ -458,8 +458,8 @@ pub fn ltegr<W: std::io::Write>(params: &LtegrParams, writer: Option<&mut Fortra
// 输出对流诊断
if config.hmix0 >= 0.0 {
// 调用 CONOUT(2, IPRING)
// conout_pure(&mut ConoutParams { mode: 2, ipring: config.ipring, ... });
let _ = conout_pure;
// conout(&mut ConoutParams { mode: 2, ipring: config.ipring, ... });
let _ = conout;
}
// 恢复 LTE 标志

View File

@ -239,7 +239,7 @@ impl LtegrdWork {
///
/// # 返回值
/// 计算结果
pub fn ltegrd_pure(params: &mut LtegrdParams) -> LtegrdOutput {
pub fn ltegrd(params: &mut LtegrdParams) -> LtegrdOutput {
let config = &params.config;
let mut work = LtegrdWork::new();
@ -815,7 +815,7 @@ mod tests {
flopac: &mut flopac,
};
let result = ltegrd_pure(&mut params);
let result = ltegrd(&mut params);
assert!(result.nd > 0);
assert!(!result.dm.is_empty());

View File

@ -51,29 +51,29 @@ pub mod settrm;
pub mod tabini;
pub mod xenini;
pub use chckse::{chckse_pure, format_chckse_output, ChckseParams, ChckseOutput, LevelBalance};
pub use chckse::{chckse, format_chckse_output, ChckseParams, ChckseOutput, LevelBalance};
pub use format::{FormatSpec, FormatItem};
pub use initia::{
generate_log_frequency_grid, klein_nishina_cross_section, planck_function,
compute_external_irradiation, init_reciprocal_powers, get_statistical_weight,
initia_pure, InitiaConfig, InitiaParams, InitiaOutput,
initia, InitiaConfig, InitiaParams, InitiaOutput,
FrequencyGridParams, FrequencyGridOutput,
};
pub use inpmod::{inpmod, read_tlusty_model, InputModelData, InpmodParams, InpmodOutput};
pub use input::{InputParams, InputParser, read_input_file, FrequencyParams, AtomParams, IonParams, TransitionParams, Transition};
pub use incldy::{incldy_pure, read_cloudy_model, CloudyModelInput, CloudyModelOutput};
pub use iroset::{iroset, iroset_pure, ColKur as ColKurIroset, IrosetParams, IrosetOutput, Lined};
pub use incldy::{incldy, read_cloudy_model, CloudyModelInput, CloudyModelOutput};
pub use iroset::{iroset, ColKur as ColKurIroset, IrosetParams, IrosetOutput, Lined};
pub use kurucz::{read_kurucz, read_kurucz_from_reader, KuruczModel, KuruczReadParams, KuruczHeader, KuruczDepthPoint, KuruczIfixdeDepthPoint};
pub use levcd::{levcd, ColKur, LevcdParams};
pub use linset::{linset_pure, LinsetParams, LinsetState, LinsetOutput};
pub use linset::{linset, LinsetParams, LinsetState, LinsetOutput};
pub use ltegr::{ltegr, LtegrConfig, LtegrParams, LtegrOutput};
pub use ltegrd::{ltegrd_pure, LtegrdConfig, LtegrdParams, LtegrdOutput, LtegrdAtomicData};
pub use ltegrd::{ltegrd, LtegrdConfig, LtegrdParams, LtegrdOutput, LtegrdAtomicData};
pub use model::{ModelFile, ModelState, read_model, write_model};
pub use nstout::{nstout, NstoutParams, NstoutOutput};
pub use nstpar::{nstpar, parse_keyword_values, apply_nstpar_postprocessing, NstparParams, NstparOutput, MVAR, VARNAM, PVALUE_DEFAULT};
pub use odfset::{odfset, odfset_process_transition, OdfsetParams, OdfsetOutput, StfCr};
pub use outpri::{
outpri_pure, compute_radiation_output, compute_depth_output, compute_disk_depth_output,
outpri, compute_radiation_output, compute_depth_output, compute_disk_depth_output,
write_radiation_output, write_atmosphere_output, write_disk_output, write_bfac_output,
OutpriConfig, OutpriParams, OutpriOutput, OutpriFreqData, OutpriModelData,
OutpriRadData, OutpriPopData, OutpriGrdData,
@ -82,11 +82,11 @@ pub use outpri::{
pub use reader::{FortranReader, FromFortran};
pub use writer::{FortranWriter, format_exp_fortran};
pub use tabini::{tabini, tabini_read_text, tabini_read_binary, TabiniInputParams, TabiniOutput, AbnTabData, EletabData};
pub use rayini::{rayini, rayini_pure, rayini_with_rayleigh, read_rayleigh_table, RayiniParams, RayiniOutput, RayleighTableData};
pub use srtfrq::{srtfrq_pure, SrtfrqParams, SrtfrqOutput, format_srtfrq_message};
pub use rayini::{rayini, rayini_with_rayleigh, read_rayleigh_table, RayiniParams, RayiniOutput, RayleighTableData};
pub use srtfrq::{srtfrq, SrtfrqParams, SrtfrqOutput, format_srtfrq_message};
pub use xenini::{xenini, xenini_clear};
pub use resolv::{resolv, resolv_pure, ResolvConfig, ResolvParams, ResolvOutput};
pub use start::{start, start_pure, start_with_callbacks, StartConfig, StartParams, StartOutput, StartCallbacks, NoOpStartCallbacks};
pub use resolv::{resolv, ResolvConfig, ResolvParams, ResolvOutput};
pub use start::{start, start_with_callbacks, StartConfig, StartParams, StartOutput, StartCallbacks, NoOpStartCallbacks};
/// 文件单元号常量(与 Fortran 保持一致)
pub mod units {

View File

@ -19,7 +19,7 @@ use crate::tlusty::state::constants::{MDEPTH, MFREQ, MFREX, MLEVEL, UN, HALF};
// - ELDENC: conditional diagnostic (ioptab != 0), handled externally
// - WNSTOR/SABOLF/RATMAL/LEVSOL: compute "absolute" b-factors for non-LTE output.
// Caller must: set LTE=true, then for each depth:
// wnstor(id,...), sabolf_pure(params), ratmal(id, aes, bes),
// wnstor(id,...), sabolf(params), ratmal(id, aes, bes),
// levsol(aes, bes, poplte, iifor, nlevel, 0),
// bfab(i,id) = popul(i,id) / poplte(i)
// Then restore LTE=false
@ -592,7 +592,7 @@ pub fn compute_disk_depth_output(
///
/// # 返回
/// 计算结果
pub fn outpri_pure(params: &OutpriParams, absoex: &[Vec<f64>]) -> OutpriOutput {
pub fn outpri(params: &OutpriParams, absoex: &[Vec<f64>]) -> OutpriOutput {
// WRITE(6,600) ITER-1
// FORMAT(/' ************************************'/' FINAL RESULTS:/' '/
// ' MODEL QUANTITIES IN',I3,'. ITERATION'/' ************************************'/)
@ -1087,10 +1087,10 @@ mod tests {
}
#[test]
fn test_outpri_pure() {
fn test_outpri() {
let params = create_test_params();
let absoex = vec![vec![1e-8; 3]; 2];
let output = outpri_pure(&params, &absoex);
let output = outpri(&params, &absoex);
assert!(output.total_flux > 0.0);
assert_eq!(output.radiation.len(), 5);
@ -1106,7 +1106,7 @@ mod tests {
params.config.qgrav = 1e4;
let absoex = vec![vec![1e-8; 3]; 2];
let output = outpri_pure(&params, &absoex);
let output = outpri(&params, &absoex);
// 磁盘模式下 depths 应该为空
assert!(output.depths.is_empty());

File diff suppressed because it is too large Load Diff

View File

@ -98,7 +98,7 @@ pub struct SrtfrqParams<'a> {
/// # 返回值
///
/// 输出信息
pub fn srtfrq_pure(params: &mut SrtfrqParams) -> SrtfrqOutput {
pub fn srtfrq(params: &mut SrtfrqParams) -> SrtfrqOutput {
// 标记已导入的函数
let _ = (indexx, quit);

View File

@ -62,9 +62,9 @@ use super::io::{
input::InputParser,
};
use super::math::solvers::{
accel2_pure, Accel2Config, Accel2Params,
solve_pure, SolveConfig, DepthMatrices,
solves_pure,
accel2, Accel2Config, Accel2Params,
SolveConfig, DepthMatrices,
solves,
solves_lte, KantorovichStorage, SolvesLteOutput,
};
use super::math::io::{timing, TimingParams, TimingMode, reset_timer, output, OutputParams};
@ -631,7 +631,7 @@ pub fn run_tlusty<R: io::BufRead, W: io::Write>(
psy2: &mut accel_psy2,
psy3: &mut accel_psy3,
};
let accel_result = accel2_pure(&mut accel_params);
let accel_result = accel2(&mut accel_params);
// If ACCEL2 accelerated, update model state from PSY0
// and recompute opacities via RESOLV (matching Fortran

View File

@ -236,7 +236,7 @@ pub struct Alisk1Output {
///
/// 此函数是一个框架实现,实际调用 OPACF1、RTEFR1、ALIFRK、ROSSTD
/// 需要在完整系统中实现。当前版本主要用于结构验证。
pub fn alisk1_pure(
pub fn alisk1(
config: &Alisk1Config,
freq_params: &Alisk1FreqParams,
atomic_params: &Alisk1AtomicParams,
@ -732,7 +732,7 @@ mod tests {
rad1: &mut rad1,
};
let output = alisk1_pure(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
let output = alisk1(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
assert!(output.computed);
assert!(output.lross); // 因为 iter=1 且 ndre=0
@ -869,7 +869,7 @@ mod tests {
rad1: &mut rad1,
};
let output = alisk1_pure(&_config, &freq_params, &atomic_params, &model_state, &mut output_state);
let output = alisk1(&_config, &freq_params, &atomic_params, &model_state, &mut output_state);
assert!(output.computed);
}

View File

@ -235,7 +235,7 @@ pub struct Alisk2Output {
/// # 返回值
///
/// 返回 `Alisk2Output`,包含计算结果信息。
pub fn alisk2_pure(
pub fn alisk2(
config: &Alisk2Config,
freq_params: &Alisk2FreqParams,
atomic_params: &Alisk2AtomicParams,
@ -822,7 +822,7 @@ mod tests {
fcool: &mut fcool,
};
let output = alisk2_pure(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
let output = alisk2(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
assert!(output.computed);
assert!(output.lross); // 因为 iter=1 且 ndre=0
@ -956,7 +956,7 @@ mod tests {
fcool: &mut fcool,
};
let _ = alisk2_pure(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
let _ = alisk2(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
// FLEXP 应该被初始化为零
for id in 0..nd {

View File

@ -306,7 +306,7 @@ pub struct Alist1Output {
///
/// # 返回
/// - `Alist1Output`: 包含 prd0 和 prdx
pub fn alist1_pure(
pub fn alist1(
config: &Alist1Config,
freq_params: &Alist1FreqParams,
atomic: &Alist1AtomicParams,

View File

@ -1,136 +0,0 @@
//! CIA H2-H 不透明度。
//!
//! 重构自 TLUSTY `cia_h2h.f`
//!
//! # 功能
//!
//! 计算 H2-H 碰撞诱导吸收 (CIA) 不透明度。
//! 数据来源TURBOSPEC
/// Amagat 单位转换常数 (cm^-3)
const AMAGAT: f64 = 2.6867774e19;
/// 不透明度转换因子
const FAC: f64 = 1.0 / (AMAGAT * AMAGAT);
/// 光速 (cm/s)
const CAS: f64 = 2.997925e10;
/// 温度表点数
const NTEMP: usize = 4;
/// 频率/波长表行数
const NLINES: usize = 67;
/// CIA H2-H 温度表
static TEMP_TABLE: [f64; NTEMP] = [1000.0, 1500.0, 2000.0, 2500.0];
/// CIA H2-H 不透明度表数据。
pub struct CiaH2HData {
/// 频率数组
freq: Vec<f64>,
/// 对数不透明度 alpha(freq, temp)
alpha: Vec<Vec<f64>>,
/// 是否已初始化
loaded: bool,
}
impl Default for CiaH2HData {
fn default() -> Self {
Self {
freq: Vec::new(),
alpha: Vec::new(),
loaded: false,
}
}
}
impl CiaH2HData {
/// 加载 CIA 数据表。
pub fn load(&mut self) {
if self.loaded {
return;
}
println!("Reading in H2-H CIA opacity tables...");
// 在完整实现中,这里会从 "./data/CIA_H2H.dat" 读取数据
self.freq = vec![0.0; NLINES];
self.alpha = vec![vec![0.0; NTEMP]; NLINES];
self.loaded = true;
}
/// 计算 CIA H2-H 不透明度。
///
/// # 参数
///
/// * `t` - 温度 (K)
/// * `ah2` - H2 数密度
/// * `ah` - H 数密度
/// * `ff` - 频率 (Hz)
pub fn opacity(&mut self, t: f64, ah2: f64, ah: f64, ff: f64) -> f64 {
// H2-H 数据仅适用于 T <= 2500 K
if t > 2500.0 {
return 0.0;
}
self.load();
let f = ff / CAS;
let j = locate(&TEMP_TABLE, t);
if j == 0 {
println!();
println!(
"Warning: requested temperature is below{:6.0} K",
TEMP_TABLE[0]
);
println!("CIA H2-H CIA opacity set to zero");
println!();
return 0.0;
}
let i = locate(&self.freq, f);
let alp = if j == NTEMP {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
(1.0 - tt) * y1 + tt * y2
} else if i == 0 || i == NLINES {
-50.0
} else {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let y3 = self.alpha[i + 1][j];
let y4 = self.alpha[i][j];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
let uu = (t - TEMP_TABLE[j - 1]) / (TEMP_TABLE[j] - TEMP_TABLE[j - 1]);
(1.0 - tt) * (1.0 - uu) * y1
+ tt * (1.0 - uu) * y2
+ tt * uu * y3
+ (1.0 - tt) * uu * y4
};
let alp = alp.exp();
FAC * ah2 * ah * alp
}
}
/// 便捷函数:计算 CIA H2-H 不透明度(匹配 Fortran SUBROUTINE CIA_H2H 签名)。
pub fn cia_h2h(t: f64, ah2: f64, ah: f64, ff: f64, opac: &mut f64) {
let mut data = CiaH2HData::default();
*opac = data.opacity(t, ah2, ah, ff);
}
/// 在有序数组中定位 x 的位置。
fn locate(arr: &[f64], x: f64) -> usize {
if x < arr[0] {
return 0;
}
for i in 1..arr.len() {
if x < arr[i] {
return i;
}
}
arr.len()
}

View File

@ -1,147 +0,0 @@
//! CIA H2-H2 不透明度。
//!
//! 重构自 TLUSTY `cia_h2h2.f`
//!
//! # 功能
//!
//! 计算 H2-H2 碰撞诱导吸收 (CIA) 不透明度。
//! 数据来源Borysow A., Jorgensen U.G., Fu Y. 2001, JQSRT 68, 235
/// Amagat 单位转换常数 (cm^-3)
const AMAGAT: f64 = 2.6867774e19;
/// 不透明度转换因子
const FAC: f64 = 1.0 / (AMAGAT * AMAGAT);
/// 光速 (cm/s)
const CAS: f64 = 2.997925e10;
/// 温度表点数
const NTEMP: usize = 7;
/// 频率/波长表行数
const NLINES: usize = 1000;
/// CIA H2-H2 温度表
static TEMP_TABLE: [f64; NTEMP] = [1000.0, 2000.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0];
/// CIA H2-H2 不透明度表数据。
///
/// 在首次调用时从文件加载,之后缓存。
pub struct CiaH2H2Data {
/// 频率数组
freq: Vec<f64>,
/// 对数不透明度 alpha(freq, temp)
alpha: Vec<Vec<f64>>,
/// 是否已初始化
loaded: bool,
}
impl Default for CiaH2H2Data {
fn default() -> Self {
Self {
freq: Vec::new(),
alpha: Vec::new(),
loaded: false,
}
}
}
impl CiaH2H2Data {
/// 加载 CIA 数据表。
pub fn load(&mut self) {
if self.loaded {
return;
}
println!("Reading in H2-H2 CIA opacity tables...");
// 在完整实现中,这里会从 "./data/CIA_H2H2.dat" 读取数据
// 暂时初始化为空表
self.freq = vec![0.0; NLINES];
self.alpha = vec![vec![0.0; NTEMP]; NLINES];
self.loaded = true;
}
/// 计算 CIA H2-H2 不透明度。
///
/// # 参数
///
/// * `t` - 温度 (K)
/// * `ah2` - H2 数密度
/// * `ff` - 频率 (Hz)
///
/// # 返回值
///
/// CIA 不透明度
pub fn opacity(&mut self, t: f64, ah2: f64, ff: f64) -> f64 {
self.load();
// 输入频率为 Hz但需要波数 (cm^-1)
let f = ff / CAS;
// 在温度数组中定位
let j = locate(&TEMP_TABLE, t);
if j == 0 {
println!();
println!(
"Warning: requested temperature is below{:6.0} K",
TEMP_TABLE[0]
);
println!("CIA H2-H2 opacity set to 0");
println!();
return 0.0;
}
// 在频率数组中定位
let i = locate(&self.freq, f);
let alp = if j == NTEMP {
// 高温端外推:保持恒定
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
(1.0 - tt) * y1 + tt * y2
} else if i == 0 || i == NLINES {
// 频率表外:设置非常小的值
-50.0
} else {
// 在表内双线性插值
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let y3 = self.alpha[i + 1][j];
let y4 = self.alpha[i][j];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
let uu = (t - TEMP_TABLE[j - 1]) / (TEMP_TABLE[j] - TEMP_TABLE[j - 1]);
(1.0 - tt) * (1.0 - uu) * y1
+ tt * (1.0 - uu) * y2
+ tt * uu * y3
+ (1.0 - tt) * uu * y4
};
let alp = alp.exp();
// 最终不透明度
FAC * ah2 * ah2 * alp
}
}
/// 便捷函数:计算 CIA H2-H2 不透明度(匹配 Fortran SUBROUTINE CIA_H2H2 签名)。
pub fn cia_h2h2(t: f64, ah2: f64, ff: f64, opac: &mut f64) {
let mut data = CiaH2H2Data::default();
*opac = data.opacity(t, ah2, ff);
}
/// 在有序数组中定位 x 的位置。
///
/// 返回索引 j使得 arr[j-1] <= x < arr[j]。
/// 如果 x < arr[0],返回 0。
fn locate(arr: &[f64], x: f64) -> usize {
if x < arr[0] {
return 0;
}
for i in 1..arr.len() {
if x < arr[i] {
return i;
}
}
arr.len()
}

View File

@ -1,132 +0,0 @@
//! CIA H2-He 不透明度。
//!
//! 重构自 TLUSTY `cia_h2he.f`
//!
//! # 功能
//!
//! 计算 H2-He 碰撞诱导吸收 (CIA) 不透明度。
//! 数据来源Jorgensen U.G., Hammer D., Borysow A., Falkesgaard J., 2000,
//! Astronomy & Astrophysics 361, 283
/// Amagat 单位转换常数 (cm^-3)
const AMAGAT: f64 = 2.6867774e19;
/// 不透明度转换因子
const FAC: f64 = 1.0 / (AMAGAT * AMAGAT);
/// 光速 (cm/s)
const CAS: f64 = 2.997925e10;
/// 温度表点数
const NTEMP: usize = 7;
/// 频率/波长表行数
const NLINES: usize = 242;
/// CIA H2-He 温度表
static TEMP_TABLE: [f64; NTEMP] = [1000.0, 2000.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0];
/// CIA H2-He 不透明度表数据。
pub struct CiaH2HeData {
/// 频率数组
freq: Vec<f64>,
/// 对数不透明度 alpha(freq, temp)
alpha: Vec<Vec<f64>>,
/// 是否已初始化
loaded: bool,
}
impl Default for CiaH2HeData {
fn default() -> Self {
Self {
freq: Vec::new(),
alpha: Vec::new(),
loaded: false,
}
}
}
impl CiaH2HeData {
/// 加载 CIA 数据表。
pub fn load(&mut self) {
if self.loaded {
return;
}
println!("Reading in H2-He CIA opacity tables...");
// 在完整实现中,这里会从 "./data/CIA_H2He.dat" 读取数据
self.freq = vec![0.0; NLINES];
self.alpha = vec![vec![0.0; NTEMP]; NLINES];
self.loaded = true;
}
/// 计算 CIA H2-He 不透明度。
///
/// # 参数
///
/// * `t` - 温度 (K)
/// * `ah2` - H2 数密度
/// * `ahe` - He 数密度
/// * `ff` - 频率 (Hz)
pub fn opacity(&mut self, t: f64, ah2: f64, ahe: f64, ff: f64) -> f64 {
self.load();
let f = ff / CAS;
let j = locate(&TEMP_TABLE, t);
if j == 0 {
println!();
println!(
"Warning: requested temperature is below{:6.0} K",
TEMP_TABLE[0]
);
println!("CIA H2-He opacity set to 0");
println!();
return 0.0;
}
let i = locate(&self.freq, f);
let alp = if j == NTEMP {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
(1.0 - tt) * y1 + tt * y2
} else if i == 0 || i == NLINES {
-50.0
} else {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let y3 = self.alpha[i + 1][j];
let y4 = self.alpha[i][j];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
let uu = (t - TEMP_TABLE[j - 1]) / (TEMP_TABLE[j] - TEMP_TABLE[j - 1]);
(1.0 - tt) * (1.0 - uu) * y1
+ tt * (1.0 - uu) * y2
+ tt * uu * y3
+ (1.0 - tt) * uu * y4
};
let alp = alp.exp();
FAC * ah2 * ahe * alp
}
}
/// 便捷函数:计算 CIA H2-He 不透明度(匹配 Fortran SUBROUTINE CIA_H2HE 签名)。
pub fn cia_h2he(t: f64, ah2: f64, ahe: f64, ff: f64, opac: &mut f64) {
let mut data = CiaH2HeData::default();
*opac = data.opacity(t, ah2, ahe, ff);
}
/// 在有序数组中定位 x 的位置。
fn locate(arr: &[f64], x: f64) -> usize {
if x < arr[0] {
return 0;
}
for i in 1..arr.len() {
if x < arr[i] {
return i;
}
}
arr.len()
}

View File

@ -1,133 +0,0 @@
//! CIA H-He 不透明度。
//!
//! 重构自 TLUSTY `cia_hhe.f`
//!
//! # 功能
//!
//! 计算 H-He 碰撞诱导吸收 (CIA) 不透明度。
//! 数据来源Gustafsson M., Frommhold, L. 2001, ApJ 546, 1168
/// Amagat 单位转换常数 (cm^-3)
const AMAGAT: f64 = 2.6867774e19;
/// 不透明度转换因子
const FAC: f64 = 1.0 / (AMAGAT * AMAGAT);
/// 光速 (cm/s)
const CAS: f64 = 2.997925e10;
/// 温度表点数
const NTEMP: usize = 11;
/// 频率/波长表行数
const NLINES: usize = 43;
/// CIA H-He 温度表
static TEMP_TABLE: [f64; NTEMP] = [
1000.0, 1500.0, 2250.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0,
];
/// CIA H-He 不透明度表数据。
pub struct CiaHHeData {
/// 频率数组
freq: Vec<f64>,
/// 对数不透明度 alpha(freq, temp)
alpha: Vec<Vec<f64>>,
/// 是否已初始化
loaded: bool,
}
impl Default for CiaHHeData {
fn default() -> Self {
Self {
freq: Vec::new(),
alpha: Vec::new(),
loaded: false,
}
}
}
impl CiaHHeData {
/// 加载 CIA 数据表。
pub fn load(&mut self) {
if self.loaded {
return;
}
println!("Reading in H-He CIA opacity tables...");
// 在完整实现中,这里会从 "./data/CIA_HHe.dat" 读取数据
self.freq = vec![0.0; NLINES];
self.alpha = vec![vec![0.0; NTEMP]; NLINES];
self.loaded = true;
}
/// 计算 CIA H-He 不透明度。
///
/// # 参数
///
/// * `t` - 温度 (K)
/// * `ah` - H 数密度
/// * `ahe` - He 数密度
/// * `ff` - 频率 (Hz)
pub fn opacity(&mut self, t: f64, ah: f64, ahe: f64, ff: f64) -> f64 {
self.load();
let f = ff / CAS;
let j = locate(&TEMP_TABLE, t);
if j == 0 {
println!();
println!(
"Warning: requested temperature is below{:6.0} K",
TEMP_TABLE[0]
);
println!("CIA H-He opacity set to 0");
println!();
return 0.0;
}
let i = locate(&self.freq, f);
let alp = if j == NTEMP {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
(1.0 - tt) * y1 + tt * y2
} else if i == 0 || i == NLINES {
-50.0
} else {
let y1 = self.alpha[i][j - 1];
let y2 = self.alpha[i + 1][j - 1];
let y3 = self.alpha[i + 1][j];
let y4 = self.alpha[i][j];
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
let uu = (t - TEMP_TABLE[j - 1]) / (TEMP_TABLE[j] - TEMP_TABLE[j - 1]);
(1.0 - tt) * (1.0 - uu) * y1
+ tt * (1.0 - uu) * y2
+ tt * uu * y3
+ (1.0 - tt) * uu * y4
};
let alp = alp.exp();
FAC * ah * ahe * alp
}
}
/// 便捷函数:计算 CIA H-He 不透明度(匹配 Fortran SUBROUTINE CIA_HHE 签名)。
pub fn cia_hhe(t: f64, ah: f64, ahe: f64, ff: f64, opac: &mut f64) {
let mut data = CiaHHeData::default();
*opac = data.opacity(t, ah, ahe, ff);
}
/// 在有序数组中定位 x 的位置。
fn locate(arr: &[f64], x: f64) -> usize {
if x < arr[0] {
return 0;
}
for i in 1..arr.len() {
if x < arr[i] {
return i;
}
}
arr.len()
}

View File

@ -1,9 +1,5 @@
//! continuum module
mod cia_h2h;
mod cia_h2h2;
mod cia_h2he;
mod cia_hhe;
mod lte_opacity;
mod opacf0;
pub mod opacf0_state;
@ -23,12 +19,16 @@ mod opdata;
mod opfrac;
mod opacity_table;
pub use cia_h2h::CiaH2HData;
pub use cia_h2h2::CiaH2H2Data;
pub use cia_h2he::CiaH2HeData;
pub use cia_hhe::CiaHHeData;
// Re-export free functions from opacity module (the authoritative implementations)
pub use crate::tlusty::math::opacity::{cia_h2h, cia_h2h2, cia_h2he, cia_hhe};
// CIA 不透明度:使用 opacity 模块中的权威实现,并提供向后兼容别名
pub use crate::tlusty::math::opacity::{
cia_h2h, cia_h2h2, cia_h2he, cia_hhe,
CiaH2hData, CiaH2h2Data, CiaH2heData, CiaHheData,
};
// 大写后缀的旧版别名(向后兼容)
pub use crate::tlusty::math::opacity::CiaH2hData as CiaH2HData;
pub use crate::tlusty::math::opacity::CiaH2h2Data as CiaH2H2Data;
pub use crate::tlusty::math::opacity::CiaH2heData as CiaH2HeData;
pub use crate::tlusty::math::opacity::CiaHheData as CiaHHeData;
pub use lte_opacity::{
LteOpacityParams, LteOpacityOutput, LteFrequencyGrid,
lte_meanopt, generate_lte_frequency_grid, generate_inifrc_frequency_grid,

View File

@ -264,7 +264,7 @@ pub type PgsetFn = fn(usize);
/// ...
/// END
/// ```
pub fn opactr_pure(
pub fn opactr(
ij: usize,
config: &OpactrConfig,
model_state: &mut OpactrModelState,

View File

@ -142,7 +142,7 @@ pub struct OpfracOutput {
///
/// # 返回
/// 配分函数和电离分数
pub fn opfrac_pure(params: &OpfracParams, pfoptb: &PfOptB) -> OpfracOutput {
pub fn opfrac(params: &OpfracParams, pfoptb: &PfOptB) -> OpfracOutput {
let iat = params.iat;
// 如果 IAT == 0返回默认值
@ -345,7 +345,7 @@ mod tests {
}
#[test]
fn test_opfrac_pure_zero_iat() {
fn test_opfrac_zero_iat() {
let pfoptb = PfOptB::new();
let params = OpfracParams {
@ -355,13 +355,13 @@ mod tests {
ane: 1.0e12,
};
let result = opfrac_pure(&params, &pfoptb);
let result = opfrac(&params, &pfoptb);
assert!((result.pf - 1.0).abs() < 1e-10);
assert!((result.fra - 1.0).abs() < 1e-10);
}
#[test]
fn test_opfrac_pure_with_data() {
fn test_opfrac_with_data() {
let mut pfoptb = PfOptB::new();
// 设置一些测试数据
@ -386,7 +386,7 @@ mod tests {
ane: 1.0e12,
};
let result = opfrac_pure(&params, &pfoptb);
let result = opfrac(&params, &pfoptb);
assert!(result.pf > 0.0, "PF should be positive");
}

View File

@ -130,7 +130,7 @@ pub struct ConcorOutput {
/// ...
/// END
/// ```
pub fn concor_pure(params: &mut ConcorParams) -> ConcorOutput {
pub fn concor(params: &mut ConcorParams) -> ConcorOutput {
// 检查是否需要执行
if params.config.indl == 0 {
return ConcorOutput {
@ -313,7 +313,7 @@ mod tests {
prd0: 0.0,
};
let output = concor_pure(&mut params);
let output = concor(&mut params);
assert!(!output.computed);
assert!(!output.temp_modified);
@ -348,7 +348,7 @@ mod tests {
prd0: 0.0,
};
let output = concor_pure(&mut params);
let output = concor(&mut params);
assert!(output.computed);
assert!(output.temp_modified);
@ -385,7 +385,7 @@ mod tests {
prd0: 0.0,
};
let output = concor_pure(&mut params);
let output = concor(&mut params);
assert!(output.computed);
// 在盘模式下ptotal 会被重新计算

View File

@ -191,7 +191,7 @@ pub struct CubconData {
/// ...
/// END
/// ```
pub fn conout_pure(params: &mut ConoutParams) -> ConoutOutput {
pub fn conout(params: &mut ConoutParams) -> ConoutOutput {
// f2r_depends: convec, meanop, meanopt, opacf0 (generic)
let _ = (convec, meanop, meanopt);
@ -639,7 +639,7 @@ mod tests {
#[test]
fn test_conout_basic() {
let mut params = TestParamsBuilder::new(50).build();
let output = conout_pure(&mut params);
let output = conout(&mut params);
// 验证基本输出
assert_eq!(output.depth_results.len(), 50);
@ -671,7 +671,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conout_pure(&mut params);
let output = conout(&mut params);
// 禁用对流时不应该有对流区
assert_eq!(output.icbeg, 0);
@ -686,7 +686,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conout_pure(&mut params);
let output = conout(&mut params);
// 验证基本功能
assert_eq!(output.depth_results.len(), 50);
@ -700,7 +700,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conout_pure(&mut params);
let output = conout(&mut params);
// 验证基本功能
assert_eq!(output.depth_results.len(), 50);
@ -714,7 +714,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conout_pure(&mut params);
let output = conout(&mut params);
// 盘模式应该正常工作
assert_eq!(output.depth_results.len(), 50);

View File

@ -340,7 +340,7 @@ fn call_convc1(
/// ...
/// END
/// ```
pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
pub fn conref(params: &mut ConrefParams) -> ConrefOutput {
let nd = params.nd;
let config = &params.config.clone();
@ -978,7 +978,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conref_pure(&mut params);
let output = conref(&mut params);
assert_eq!(output.icbeg, 0);
assert_eq!(output.icend, 0);
@ -993,7 +993,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conref_pure(&mut params);
let output = conref(&mut params);
assert_eq!(output.icbeg, 0);
}
@ -1006,7 +1006,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conref_pure(&mut params);
let output = conref(&mut params);
assert!(output.icbeg <= 50);
assert!(output.icend <= 50);
@ -1059,7 +1059,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conref_pure(&mut params);
let output = conref(&mut params);
assert!(output.icbeg <= 50);
}
@ -1073,7 +1073,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = conref_pure(&mut params);
let output = conref(&mut params);
assert!(output.icbeg <= 50);
}

View File

@ -171,7 +171,7 @@ pub struct ContmdOutput {
/// 计算盘模型对流层的温度 (CONTMD) - 无回调版本。
///
/// 用于纯计算模式,不更新电子密度和不透明度。
pub fn contmd_pure(params: &mut ContmdParams) -> ContmdOutput {
pub fn contmd(params: &mut ContmdParams) -> ContmdOutput {
contmd_impl(params, &mut NoOpCallbacks)
}
@ -613,7 +613,7 @@ mod tests {
#[test]
fn test_contmd_basic() {
let mut params = create_test_params();
let output = contmd_pure(&mut params);
let output = contmd(&mut params);
// 验证迭代次数在合理范围内
assert!(output.iconit <= params.config.nconit);
@ -631,7 +631,7 @@ mod tests {
// 禁用对流
params.config.hmix0 = -1.0;
let output = contmd_pure(&mut params);
let output = contmd(&mut params);
// 禁用对流时不应该有对流区
for &iconv in &output.iconv {
@ -646,7 +646,7 @@ mod tests {
// 保存原始温度
let orig_temp = params.temp.to_vec();
let _output = contmd_pure(&mut params);
let _output = contmd(&mut params);
// 温度可能被更新
// 检查温度仍然是有限值
@ -731,7 +731,7 @@ mod tests {
hr1: Box::leak(Box::new(hr1)),
};
let output = contmd_pure(&mut params);
let output = contmd(&mut params);
assert_eq!(output.iconv.len(), nd);
assert!(output.iconit > 0);

View File

@ -7,9 +7,9 @@
//! - 分析各元素对电子密度的贡献
//! - 输出电子供体信息
use crate::tlusty::math::{moleq_pure, MoleqParams};
use crate::tlusty::math::{rhonen_pure, RhonenParams};
use crate::tlusty::math::{state_pure, StateParams};
use crate::tlusty::math::{moleq, MoleqParams};
use crate::tlusty::math::{rhonen, RhonenParams};
use crate::tlusty::math::{state, StateParams};
use crate::tlusty::state::constants::{MDEPTH, MLEVEL};
// f2r_depends: RHONEN, STATE, MOLEQ
@ -130,7 +130,7 @@ pub struct EldencOutput {
///
/// # 返回值
/// 包含插值电子密度和贡献者信息的输出
pub fn eldenc_pure(params: &EldencParams) -> EldencOutput {
pub fn eldenc(params: &EldencParams) -> EldencOutput {
let nd = params.nd;
let config = &params.config;
@ -168,7 +168,7 @@ pub fn eldenc_pure(params: &EldencParams) -> EldencOutput {
// 计算 LTE 电子密度
if let Some(rhonen_params) = &params.rhonen_params {
let rhonen_out = rhonen_pure(rhonen_params);
let rhonen_out = rhonen(rhonen_params);
ane_lte[id] = rhonen_out.ane;
}
@ -190,12 +190,12 @@ pub fn eldenc_pure(params: &EldencParams) -> EldencOutput {
let rho = params.dens[id];
if let Some(rhonen_params) = &params.rhonen_params {
let rhonen_out = rhonen_pure(rhonen_params);
let rhonen_out = rhonen(rhonen_params);
let aein = rhonen_out.ane;
// 调用 MOLEQ 计算分子平衡
if let Some(moleq_params) = &params.moleq_params {
let moleq_out = moleq_pure(moleq_params);
let moleq_out = moleq(moleq_params);
// Fortran: elcon(ia,id)=anion(ia,id)/elec(id)
// moleq_out.anio0 包含离子数密度
for ia in 0..30.min(moleq_out.anio0.len()) {
@ -214,7 +214,7 @@ pub fn eldenc_pure(params: &EldencParams) -> EldencOutput {
} else {
// 使用 STATE
if let Some(state_params) = &params.state_params {
let _state_out = state_pure(state_params);
let _state_out = state(state_params);
for ia in 0..30 {
let iat = params.iatex[ia];
@ -402,7 +402,7 @@ mod tests {
moleq_params: None,
};
let output = eldenc_pure(&params);
let output = eldenc(&params);
// 检查输出维度
assert_eq!(output.elecg.len(), 5);

View File

@ -9,9 +9,9 @@
//! - 计算内能和熵
use crate::tlusty::math::lineqs;
use crate::tlusty::math::{moleq_pure, MoleqParams, MoleculeEqData};
use crate::tlusty::math::{moleq, MoleqParams, MoleculeEqData};
use crate::tlusty::math::{mpartf, MpartfResult};
use crate::tlusty::math::{state_pure, StateParams};
use crate::tlusty::math::{state, StateParams};
use crate::tlusty::math::{entene, EnteneParams, EnteneOutput};
use crate::tlusty::state::constants::{BOLK, HMASS, UN, TWO, HALF};
@ -138,7 +138,7 @@ pub struct EldensOutput {
///
/// # 返回值
/// 包含电子密度、内能、熵等的输出结构体
pub fn eldens_pure(params: &EldensParams, ipri: i32) -> EldensOutput {
pub fn eldens(params: &EldensParams, ipri: i32) -> EldensOutput {
// 检查 ioptab 标志
if params.config.ioptab < -1 {
return EldensOutput {
@ -183,7 +183,7 @@ pub fn eldens_pure(params: &EldensParams, ipri: i32) -> EldensOutput {
// 如果包含分子且温度低于分子温度上限,调用 MOLEQ
if params.config.ifmol > 0 && t < params.config.tmolim {
let aein = an * anerel;
// 调用 moleq_pure 计算分子平衡
// 调用 moleq 计算分子平衡
let default_mol_data: MoleculeEqData = Default::default();
let moleq_params = MoleqParams {
id: params.id,
@ -204,7 +204,7 @@ pub fn eldens_pure(params: &EldensParams, ipri: i32) -> EldensOutput {
ifmol: params.config.ifmol,
moltab: 0,
};
let moleq_output = moleq_pure(&moleq_params);
let moleq_output = moleq(&moleq_params);
let ane = moleq_output.ane;
anerel = ane / an;
@ -292,7 +292,7 @@ pub fn eldens_pure(params: &EldensParams, ipri: i32) -> EldensOutput {
ifoppf: state_params.ifoppf,
lrm: state_params.lrm,
};
let state_output = state_pure(&updated_params);
let state_output = state(&updated_params);
q = state_output.q;
dqn = state_output.dqn;
}
@ -620,7 +620,7 @@ mod tests {
anato_data: None,
};
let output = eldens_pure(&params, 0);
let output = eldens(&params, 0);
// 验证输出
assert!(output.ane > 0.0);
@ -648,7 +648,7 @@ mod tests {
anato_data: None,
};
let output = eldens_pure(&params, 0);
let output = eldens(&params, 0);
// 低温时电子密度应该较低
assert!(output.anerel < 0.5);

View File

@ -193,7 +193,7 @@ pub fn parse_molecule_data(content: &str, exclude_large_carbon: bool) -> Molecul
///
/// # 返回值
/// 包含电子密度、熵、内能、密度等的输出结构体
pub fn moleq_pure(params: &MoleqParams) -> MoleqOutput {
pub fn moleq(params: &MoleqParams) -> MoleqOutput {
// 如果不包含分子,直接返回空结果
if params.ifmol == 0 {
return MoleqOutput {
@ -516,7 +516,7 @@ mod tests {
moltab: 1,
};
let output = moleq_pure(&params);
let output = moleq(&params);
// 当 ifmol=0 时,应返回初始估计
assert!((output.ane - params.aein).abs() < 1e-10);

View File

@ -6,7 +6,7 @@
//! - 从给定的温度和质量密度迭代求解总粒子密度和电子密度
//! - 使用 eldens 计算电子密度
use crate::tlusty::math::{eldens_pure, EldensConfig, EldensOutput, EldensParams};
use crate::tlusty::math::{eldens, EldensConfig, EldensOutput, EldensParams};
use crate::tlusty::state::constants::{HMASS, UN};
/// RHONEN 输入参数
@ -58,7 +58,7 @@ pub struct RhonenOutput {
///
/// # 返回值
/// 包含粒子密度、电子密度等的输出结构体
pub fn rhonen_pure(params: &RhonenParams) -> RhonenOutput {
pub fn rhonen(params: &RhonenParams) -> RhonenOutput {
let id = params.id;
let t = params.t;
let rho = params.rho;
@ -125,7 +125,7 @@ pub fn rhonen_pure(params: &RhonenParams) -> RhonenOutput {
anato_data: None,
};
let eldens_output = eldens_pure(&eldens_params, 0);
let eldens_output = eldens(&eldens_params, 0);
ane = eldens_output.ane;
enrgi = eldens_output.energ;
@ -202,7 +202,7 @@ mod tests {
eldens_wmy: 1.0,
};
let result = rhonen_pure(&params);
let result = rhonen(&params);
// 验证基本物理约束
assert!(result.an > 0.0, "粒子密度应为正");
@ -230,7 +230,7 @@ mod tests {
eldens_wmy: 1.0,
};
let result = rhonen_pure(&params);
let result = rhonen(&params);
// 验证基本物理约束
assert!(result.an > 0.0, "粒子密度应为正");
@ -258,7 +258,7 @@ mod tests {
eldens_wmy: 1.0,
};
let result = rhonen_pure(&params);
let result = rhonen(&params);
assert!(result.an > 0.0);
assert!(result.ane > 0.0);
@ -287,7 +287,7 @@ mod tests {
eldens_wmy: 1.0,
};
let result = rhonen_pure(&params);
let result = rhonen(&params);
assert!(result.ane >= 0.0, "温度 {} K 时电子密度应为非负", t);
}
}

View File

@ -5,6 +5,7 @@
//! 这些函数填充矩阵 A, B, C 的流体静力学平衡行
//! (NFREQE+INHE)-th row。
use crate::tlusty::math::special::erfcx;
use crate::tlusty::state::constants::{BOLK, HALF, MDEPTH, MFREQ, MLEVEL, MTOT, TWO, UN};
// ============================================================================
@ -275,35 +276,6 @@ const PCK: f64 = 4.0 * std::f64::consts::PI / 3.0;
// 辅助函数
// ============================================================================
/// 计算 erfcx(x) = exp(x²) * erfc(x)
/// 使用 Fortran 代码中的系数
fn erfcx(x: f64) -> f64 {
if x < 3.0 {
// 使用近似公式
8.86226925e-1 * (x * x).exp() * erfc_approx(x)
} else {
// 渐近展开
HALF * (UN - HALF / (x * x)) / x
}
}
/// erfc 近似
fn erfc_approx(x: f64) -> f64 {
// 简单近似,精度足够
if x < 0.0 {
2.0 - erfc_approx(-x)
} else if x < 6.0 {
let t = 1.0 / (1.0 + 0.5 * x);
let poly = t * (0.17087277 + t
* (-0.82215223 + t
* (1.48851587 + t
* (-1.13520398 + t
* (0.27886807 + t * (-0.18628806 + t * 0.4206475))))));
t * (-x * x).exp() * poly
} else {
0.0
}
}
// ============================================================================
// BHE 主函数

View File

@ -11,7 +11,7 @@ use crate::tlusty::math::collhe;
use crate::tlusty::math::cspec;
use crate::tlusty::math::irc;
use crate::tlusty::state::constants::{EH, HK, MLEVEL, UN};
// f2r_depends: COLLHE, CSPEC, IRC, CHEAV
use super::expi_approx;
// ============================================================================
// 常量和数据
@ -46,21 +46,7 @@ static A: [[f64; 10]; 6] = [
-0.72724497, 1.0879648, 5.6239786, 9.5323009, 16.150818],
];
// ============================================================================
// 辅助函数
// ============================================================================
/// 计算指数积分 E1(x) 的近似值Abramowitz-Stegun 公式)。
fn expi_approx(u0: f64) -> f64 {
if u0 <= UN {
// 小参数展开
-u0.ln() + (-0.57721566 + u0 * (0.99999193 + u0 * (-0.24991055 + u0 * (0.05519968 + u0 * (-0.00976004 + u0 * 0.00107857)))))
} else {
// 大参数渐近展开
(-u0).exp() * ((0.2677734343 + u0 * (8.6347608925 + u0 * (18.059016973 + u0 * 8.5733287401)))
/ (3.9584969228 + u0 * (21.0996530827 + u0 * (25.6329561486 + u0 * 9.5733223454)))) / u0
}
}
// f2r_depends: COLLHE, CSPEC, IRC, CHEAV
// ============================================================================
// 输入/输出结构体

View File

@ -16,30 +16,14 @@ use crate::tlusty::math::cspec;
use crate::tlusty::math::irc;
use crate::tlusty::math::ylintp;
use crate::tlusty::state::constants::{EH, HK, MLEVEL, TWO, UN};
use super::expi_approx;
// f2r_depends: COLH, COLHE, CSPEC, IRC, CION, YLININTP
// ============================================================================
// 常量
// ============================================================================
/// 指数积分展开系数
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.2677734343;
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;
/// 最大碰撞类型数
pub const MXTCOL: usize = 3;
/// 最大碰撞拟合点数
@ -79,16 +63,6 @@ fn cupsx(x: f64, u: f64, a: f64) -> f64 {
8.631e-6 / x * (-u).exp() * a
}
/// 指数积分 E1 近似
fn expi_approx(u0: f64) -> f64 {
if u0 <= UN {
-u0.ln() + EXPIA1 + u0 * (EXPIA2 + u0 * (EXPIA3 + u0 * (EXPIA4 + u0 * (EXPIA5 + u0 * EXPIA6))))
} else {
(-u0).exp() * ((EXPIB1 + u0 * (EXPIB2 + u0 * (EXPIB3 + u0 * EXPIB4)))
/ (EXPIC1 + u0 * (EXPIC2 + u0 * (EXPIC3 + u0 * EXPIC4)))) / u0
}
}
// ============================================================================
// 输入/输出结构体
// ============================================================================

View File

@ -4,6 +4,7 @@
//! 计算深度相关的氦丰度剖面。
use crate::tlusty::io::{FortranWriter, Result};
use crate::tlusty::math::solvers::raph;
use crate::tlusty::state::atomic::AtomicData;
use crate::tlusty::state::config::TlustyConfig;
use crate::tlusty::state::constants::MDEPTH;
@ -19,15 +20,7 @@ const A2: f64 = 4.0; // 氦原子量
const BIGG: f64 = 6.6732e-8; // 引力常数
const PI: f64 = std::f64::consts::PI;
/// 计算扩散因子 RAPH。
/// RAPH = diffusion factor for He/H separation
fn raph(gam: f64, z1: f64, z2: f64, a1: f64, a2: f64) -> f64 {
// 简化的扩散因子计算
// 实际公式更复杂,这里使用近似
let dz = z2 - z1;
let da = a2 - a1;
gam * (dz / da).abs().min(1.0)
}
/// HEDIF 参数结构体
pub struct HedifParams<'a> {

View File

@ -9,7 +9,7 @@
use crate::tlusty::math::erfcx;
use crate::tlusty::math::matinv;
use crate::tlusty::math::{rhonen_pure, RhonenParams};
use crate::tlusty::math::{rhonen, RhonenParams};
use crate::tlusty::math::{steqeq_pure, SteqeqConfig, SteqeqParams};
use crate::tlusty::math::wnstor;
use crate::tlusty::state::constants::{HALF, MDEPTH, TWO, UN};
@ -216,7 +216,7 @@ pub struct HesolvOutput {
///
/// # 返回值
/// 包含更新后的压力、密度、深度等的结果结构体
pub fn hesolv_pure(params: &HesolvParams) -> HesolvOutput {
pub fn hesolv(params: &HesolvParams) -> HesolvOutput {
let nd = params.model.nd;
let mut p = vec![0.0; nd];
let mut vsnd2 = params.aux.vsnd2.clone();
@ -492,7 +492,7 @@ pub fn hesolv_pure(params: &HesolvParams) -> HesolvOutput {
eldens_wmy: params.config.eldens_wmy,
};
let rhonen_output = rhonen_pure(&rhonen_params);
let rhonen_output = rhonen(&rhonen_params);
elec[id] = rhonen_output.ane;
anerel = rhonen_output.anerel;
@ -685,7 +685,7 @@ mod tests {
config,
};
let output = hesolv_pure(&params);
let output = hesolv(&params);
// 验证输出
assert_eq!(output.ptotal.len(), nd);
@ -753,7 +753,7 @@ mod tests {
config,
};
let output = hesolv_pure(&params);
let output = hesolv(&params);
// 验证压力随深度增加
for i in 1..nd {
@ -832,7 +832,7 @@ mod tests {
config,
};
let output = hesolv_pure(&params);
let output = hesolv(&params);
// 所有密度应为正
for (i, &d) in output.dens.iter().enumerate() {

View File

@ -1,5 +1,8 @@
//! hydrogen module
mod utils;
pub use utils::expi_approx;
mod bhe;
mod bre;
mod brez;

View File

@ -212,7 +212,7 @@ fn interpolate_cross_section(
/// SIGAVE 纯计算函数
///
/// 从读取的截面数据计算指定频率点的截面值
pub fn sigave_pure(
pub fn sigave(
transitions: &[(usize, Vec<CrossSectionPoint>)],
nfreqb: usize,
freq: &[f64],
@ -355,7 +355,7 @@ fn sigave_impl<R: BufRead>(params: &SigaveParams, mut reader: FortranReader<R>)
};
// 计算截面
sigave_pure(
sigave(
&transitions,
nfreqb,
params.freq,
@ -513,7 +513,7 @@ mod tests {
}
#[test]
fn test_sigave_pure() {
fn test_sigave() {
let transitions = vec![(
2,
vec![
@ -532,7 +532,7 @@ mod tests {
let ifreqb: Vec<i32> = (0..50).map(|i| i as i32).collect();
let mut bfcs = vec![vec![0.0_f32; 100]; 10];
sigave_pure(&transitions, 100, &freq, &ifreqb, 0, &mut bfcs);
sigave(&transitions, 100, &freq, &ifreqb, 0, &mut bfcs);
// 检查截面是否被计算
assert!(bfcs[1].iter().any(|&x| x > 0.0));

View File

@ -0,0 +1,66 @@
//! hydrogen 公共辅助函数
//!
//! 提取自 colhe.rs 和 colis.rs 中的重复实现。
use crate::tlusty::state::constants::UN;
// 指数积分展开系数(来自 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.2677734343;
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;
/// 指数积分 E1(x) 的近似值Abramowitz-Stegun 公式 5.1.53 & 5.1.56)。
///
/// 精度约为 2×10⁻⁷。
#[inline]
pub fn expi_approx(u0: f64) -> f64 {
if u0 <= UN {
// 小参数:级数展开
-u0.ln()
+ EXPIA1
+ u0 * (EXPIA2 + u0 * (EXPIA3 + u0 * (EXPIA4 + u0 * (EXPIA5 + u0 * EXPIA6))))
} else {
// 大参数:有理近似(渐近展开)
(-u0).exp()
* ((EXPIB1 + u0 * (EXPIB2 + u0 * (EXPIB3 + u0 * EXPIB4)))
/ (EXPIC1 + u0 * (EXPIC2 + u0 * (EXPIC3 + u0 * EXPIC4))))
/ u0
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_expi_small() {
let result = expi_approx(0.5);
assert_relative_eq!(result, 0.5598, epsilon = 0.01);
}
#[test]
fn test_expi_large() {
let result = expi_approx(5.0);
assert_relative_eq!(result, 0.001148, epsilon = 1e-4);
}
#[test]
fn test_expi_unity() {
let result = expi_approx(1.0);
assert_relative_eq!(result, 0.2194, epsilon = 0.01);
}
}

View File

@ -21,7 +21,7 @@ use crate::tlusty::state::constants::{UN, HALF, HK, BOLK, BN, MDEPTH, MFREQ, MLE
const NPTR: usize = 30;
use crate::tlusty::state::atomic::AtomicData;
use crate::tlusty::state::model::ModelState;
use crate::tlusty::math::{sabolf_pure, SabolfParams, SabolfOutput};
use crate::tlusty::math::{sabolf, SabolfParams, SabolfOutput};
use crate::tlusty::math::{linpro, LinproParams, LinproOutput};
use crate::tlusty::math::dwnfr;
use crate::tlusty::math::cross;
@ -173,7 +173,7 @@ fn get_sbf(id: usize, model: &ModelState, atomic: &AtomicData) -> SabolfOutput {
ioptab: 0,
};
sabolf_pure(&mut params)
sabolf(&mut params)
}
/// 获取谱线轮廓在指定频率点的值
@ -235,7 +235,7 @@ fn get_bf_cross_section(
///
/// # 返回
/// 各跃迁的详细信息
pub fn princ_pure(params: &PrincParams) -> PrincOutput {
pub fn princ(params: &PrincParams) -> PrincOutput {
let nd = params.model.modpar.temp.len();
let nct = params.nct;

View File

@ -12,7 +12,7 @@ use crate::tlusty::state::config::InpPar;
use crate::tlusty::state::constants::HK;
use crate::tlusty::state::model::{CraTes, LevPop, ModPar, MrgPar, RrRates, WmComp};
use crate::tlusty::math::{sabolf_pure, SabolfParams};
use crate::tlusty::math::{sabolf, SabolfParams};
// ============================================================================
// 输出结构体
@ -77,7 +77,7 @@ pub struct PrntParams<'a> {
///
/// # 返回
/// 各能级的速率平衡结果
pub fn prnt_pure(params: &PrntParams) -> PrntOutput {
pub fn prnt(params: &PrntParams) -> PrntOutput {
let mut balances = Vec::new();
let nd = params.modpar.temp.len();
@ -118,7 +118,7 @@ pub fn prnt_pure(params: &PrntParams) -> PrntOutput {
gmer: &mut gmer_work,
ioptab: 0,
};
let sabolf_result = sabolf_pure(&mut sabolf_params);
let sabolf_result = sabolf(&mut sabolf_params);
let sbf = &sabolf_result.sbf;
let usum = &sabolf_result.usum;
@ -556,7 +556,7 @@ mod tests {
ipop: &ipop,
};
let result = prnt_pure(&params);
let result = prnt(&params);
// 由于测试数据是空的,结果应该为空或只有有限的结果
println!("Number of balances: {}", result.balances.len());
@ -593,7 +593,7 @@ mod tests {
ipop: &ipop,
};
let result = prnt_pure(&params);
let result = prnt(&params);
// 验证结果
for balance in &result.balances {

View File

@ -164,7 +164,7 @@ pub struct PzevalOutput {
/// ...
/// END
/// ```
pub fn pzeval_pure(params: &mut PzevalParams) -> PzevalOutput {
pub fn pzeval(params: &mut PzevalParams) -> PzevalOutput {
let nd = params.config.nd;
let mut depth_results = Vec::with_capacity(nd);
let mut conref_called = false;
@ -359,7 +359,7 @@ mod tests {
#[test]
fn test_pzeval_basic() {
let mut params = TestParamsBuilder::new(50).build();
let output = pzeval_pure(&mut params);
let output = pzeval(&mut params);
assert_eq!(output.depth_results.len(), 50);
assert!(!output.conref_called);
@ -378,7 +378,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = pzeval_pure(&mut params);
let output = pzeval(&mut params);
assert_eq!(output.depth_results.len(), 50);
}
@ -393,7 +393,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = pzeval_pure(&mut params);
let output = pzeval(&mut params);
// iter=5 在 iconrs=3 和 iconre=10 之间,应该触发 CONREF
assert!(output.conref_called);
@ -409,7 +409,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = pzeval_pure(&mut params);
let output = pzeval(&mut params);
// ipnzev=0 AND lfin=true → CONOUT(1,1)
assert!(output.conout_1);

View File

@ -771,7 +771,7 @@ pub fn compute_hydrogen_oscillator_strength(
///
/// # 返回值
/// 处理后的能级数据数组
pub fn process_levels_pure(
pub fn process_levels(
params: &RdataParams,
level_inputs: &[LevelInputData],
) -> Vec<LevelData> {
@ -800,7 +800,7 @@ pub fn process_levels_pure(
}
/// 处理连续跃迁数据(纯计算部分)。
pub fn process_continua_pure(
pub fn process_continua(
params: &RdataParams,
inputs: &[ContinuumInputData],
enion: &[f64],

View File

@ -367,7 +367,7 @@ pub fn compute_cross_sections(
///
/// 这是一个简化版本,只处理纯计算部分。
/// 完整的 I/O 操作需要在外部处理。
pub fn rdatax_pure(
pub fn rdatax(
transitions: &[TransitionData],
freq: &[f64],
nfreq: usize,
@ -441,23 +441,23 @@ mod tests {
}
#[test]
fn test_rdatax_pure_basic() {
fn test_rdatax_basic() {
let transitions = vec![create_test_transition()];
let freq = vec![1e15, 2e15, 3e15];
let output = rdatax_pure(&transitions, &freq, 3, 0, 0);
let output = rdatax(&transitions, &freq, 3, 0, 0);
assert_eq!(output.ntrx, 1);
assert_eq!(output.bfcs.len(), 1);
}
#[test]
fn test_rdatax_pure_with_ibfint() {
fn test_rdatax_with_ibfint() {
let transitions = vec![create_test_transition()];
let freq = vec![1e15, 2e15, 3e15];
// ibfint > 0 时使用 nfreqc
let output = rdatax_pure(&transitions, &freq, 3, 2, 1);
let output = rdatax(&transitions, &freq, 3, 2, 1);
assert_eq!(output.bfcs[0].len(), 2); // 使用 nfreqc=2
}
@ -467,7 +467,7 @@ mod tests {
let transitions: Vec<TransitionData> = vec![];
let freq = vec![1e15, 2e15];
let output = rdatax_pure(&transitions, &freq, 2, 0, 0);
let output = rdatax(&transitions, &freq, 2, 0, 0);
assert_eq!(output.ntrx, 0);
assert!(output.bfcs.is_empty());

View File

@ -100,7 +100,7 @@ pub struct RechckOutput {
/// ...
/// END
/// ```
pub fn rechck_pure(params: &RechckParams) -> RechckOutput {
pub fn rechck(params: &RechckParams) -> RechckOutput {
let nd = params.nd;
let nfreq = params.nfreq;
@ -215,7 +215,7 @@ mod tests {
emis1: &emis1,
};
let output = rechck_pure(&params);
let output = rechck(&params);
assert_eq!(output.depth_results.len(), 3);
@ -251,7 +251,7 @@ mod tests {
emis1: &emis1,
};
let output = rechck_pure(&params);
let output = rechck(&params);
assert_eq!(output.depth_results.len(), 1);
let result = &output.depth_results[0];
@ -281,7 +281,7 @@ mod tests {
emis1: &emis1,
};
let output = rechck_pure(&params);
let output = rechck(&params);
// 当发射为零时,相对误差应为 0
assert_relative_eq!(output.depth_results[0].re, 0.0, epsilon = 1e-15);

View File

@ -346,7 +346,7 @@ fn set_2d<T: Copy>(arr: &mut [T], i: usize, j: usize, nrows: usize, val: T) {
/// # 注意
/// 此函数仅实现核心计算逻辑,不包含 I/O 操作。
/// 外部函数调用(如 TDPINI、WNSTOR 等)需要通过回调实现。
pub fn inilam_pure(
pub fn inilam(
config: &InilamConfig,
model: &mut InilamModelState,
atomic: &InilamAtomicParams,
@ -825,7 +825,7 @@ mod tests {
hkt1: &hkt1,
};
let output = inilam_pure(&config, &mut model, &atomic, &freq);
let output = inilam(&config, &mut model, &atomic, &freq);
// INIT=1 分支应该返回
assert_relative_eq!(output.anerel, 0.5); // TEFF >= 8000

View File

@ -114,7 +114,7 @@ impl Default for InpDisParams {
///
/// # 返回值
/// 返回计算结果 InpDisResult
pub fn inpdis_pure(params: &mut InpDisParams, cnu1: f64) -> InpDisResult {
pub fn inpdis(params: &mut InpDisParams, cnu1: f64) -> InpDisResult {
let un = 1.0;
// 处理 fractv 和 dmvisc
@ -340,7 +340,7 @@ pub fn inpdis_io<W: std::io::Write>(
writer.write_newline()?;
// 调用纯计算函数
let result = inpdis_pure(params, cnu1);
let result = inpdis(params, cnu1);
// 写入输出结果
writer.write_raw(&format!("TEFF ={:#10.0}", result.teff))?;
@ -411,7 +411,7 @@ mod tests {
reynum: 0.0,
};
let result = inpdis_pure(&mut params, 1e15);
let result = inpdis(&mut params, 1e15);
// 验证基本物理量
assert!(result.teff > 0.0, "TEFF should be positive");
@ -445,7 +445,7 @@ mod tests {
reynum: 0.0,
};
let result = inpdis_pure(&mut params, 1e15);
let result = inpdis(&mut params, 1e15);
// GR 修正应该生效
assert!(result.teff > 0.0);
@ -470,7 +470,7 @@ mod tests {
reynum: 0.0,
};
let result = inpdis_pure(&mut params, 1e15);
let result = inpdis(&mut params, 1e15);
assert_relative_eq!(result.teff, 35000.0, epsilon = 1e-6);
assert_relative_eq!(result.qgrav, 1e4, epsilon = 1e-6);
@ -493,7 +493,7 @@ mod tests {
reynum: 0.0,
};
let result = inpdis_pure(&mut params, 0.0);
let result = inpdis(&mut params, 0.0);
// fractv 应该被重新计算
assert!(params.fractv > 0.0);
@ -516,7 +516,7 @@ mod tests {
};
let cnu1 = 2.0e15;
let result = inpdis_pure(&mut params, cnu1);
let result = inpdis(&mut params, cnu1);
// FRLMAX = 1e11 * cnu1 * teff
let expected_frlmax = 1e11 * cnu1 * 30000.0;

View File

@ -209,7 +209,7 @@ pub struct LinselDebugLine {
/// END
/// ```
#[allow(clippy::too_many_arguments)]
pub fn linsel_pure<F, G>(
pub fn linsel<F, G>(
config: &LinselConfig,
atomic: &mut LinselAtomicParams,
freq: &mut LinselFreqParams,
@ -942,7 +942,7 @@ mod tests {
vec![1.0; 10]
}
let output = linsel_pure(&config, &mut atomic, &mut freq_params, mock_opacf1, mock_rtefr1);
let output = linsel(&config, &mut atomic, &mut freq_params, mock_opacf1, mock_rtefr1);
// ODF 模式nppx = nfreq
assert_eq!(output.stats.nppx, nfreq as i32);

View File

@ -8,7 +8,7 @@
//! - 基于 Klaus Werner 公式 A.3.4
//! - 归一化到单位
use crate::tlusty::math::{sabolf_pure, SabolfParams, SabolfOutput};
use crate::tlusty::math::{sabolf, SabolfParams, SabolfOutput};
use crate::tlusty::math::ubeta;
use crate::tlusty::math::voigt;
use crate::tlusty::state::atomic::AtomicData;
@ -287,7 +287,7 @@ fn compute_zmikro(params: &ProfspParams, id: usize) -> f64 {
ioptab: 0,
};
let sabolf_result = sabolf_pure(&mut sabolf_params);
let sabolf_result = sabolf(&mut sabolf_params);
// 添加离子贡献
let nion = params.atomic.ionpar.iz.len();

View File

@ -126,7 +126,7 @@ fn init_arrays() {
///
/// # 返回
/// 配分函数及其导数
pub fn partf_pure(params: &PartfParams) -> PartfOutput {
pub fn partf(params: &PartfParams) -> PartfOutput {
// 初始化辅助数组
init_arrays();
@ -433,7 +433,7 @@ fn partf_user_defined(params: &PartfParams) -> PartfOutput {
/// Opacity Project 配分函数
fn partf_opacity_project(params: &PartfParams) -> PartfOutput {
// 调用 OPFRAC
use crate::tlusty::math::{opfrac_pure, OpfracParams, PfOptB};
use crate::tlusty::math::{opfrac, OpfracParams, PfOptB};
let opfrac_params = OpfracParams {
iat: params.iat,
@ -443,7 +443,7 @@ fn partf_opacity_project(params: &PartfParams) -> PartfOutput {
};
let pfoptb = PfOptB::new();
let result = opfrac_pure(&opfrac_params, &pfoptb);
let result = opfrac(&opfrac_params, &pfoptb);
PartfOutput {
u: result.pf,
@ -473,7 +473,7 @@ fn partf_ni(params: &PartfParams) -> PartfOutput {
/// 重元素配分函数 (Z > 30)
fn partf_heavy(params: &PartfParams) -> PartfOutput {
// 调用 PFHEAV
use crate::tlusty::math::{pfheav_pure, PfheavParams};
use crate::tlusty::math::{pfheav, PfheavParams};
let pfheav_params = PfheavParams {
iiz: params.iat,
@ -483,7 +483,7 @@ fn partf_heavy(params: &PartfParams) -> PartfOutput {
ane: params.ane,
};
let result = pfheav_pure(&pfheav_params);
let result = pfheav(&pfheav_params);
PartfOutput {
u: result.u,
dut: 0.0,
@ -524,7 +524,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}
@ -540,7 +540,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}
@ -556,7 +556,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "Iron partition function should be positive");
}
@ -572,7 +572,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "Nickel partition function should be positive");
}
@ -589,7 +589,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "High ionization partition function should be positive");
}
@ -605,7 +605,7 @@ mod tests {
iirwin: 0,
};
let result = partf_pure(&params);
let result = partf(&params);
assert!(result.u > 0.0, "Opacity Project partition function should be positive");
}

View File

@ -125,7 +125,7 @@ pub struct PfheavOutput {
///
/// # 返回
/// 配分函数值
pub fn pfheav_pure(params: &PfheavParams) -> PfheavOutput {
pub fn pfheav(params: &PfheavParams) -> PfheavOutput {
let iiz = params.iiz;
let jnion = params.jnion;
let mode = params.mode;
@ -272,7 +272,7 @@ mod tests {
ane: 1.0e12,
};
let result = pfheav_pure(&params);
let result = pfheav(&params);
assert!((result.u - 1.0).abs() < 1e-10);
}
@ -287,7 +287,7 @@ mod tests {
ane: 1.0e12,
};
let result = pfheav_pure(&params);
let result = pfheav(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}
@ -302,7 +302,7 @@ mod tests {
ane: 1.0e12,
};
let result = pfheav_pure(&params);
let result = pfheav(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}
@ -317,7 +317,7 @@ mod tests {
ane: 1.0e15,
};
let result = pfheav_pure(&params);
let result = pfheav(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}
@ -332,7 +332,7 @@ mod tests {
ane: 1.0e10,
};
let result = pfheav_pure(&params);
let result = pfheav(&params);
assert!(result.u > 0.0, "Partition function should be positive");
}

View File

@ -15,7 +15,7 @@
//! - APM = (占据数向量) * (dAJ/dN)
use crate::tlusty::state::constants::*;
use crate::tlusty::math::{state_pure, StateParams, StateOutput};
use crate::tlusty::math::{state, StateParams, StateOutput};
// ============================================================================
// 输入参数结构体
@ -170,7 +170,7 @@ pub struct BpopcOutput {
///
/// # 返回
/// BPOPC 输出结构
pub fn bpopc_pure(params: &BpopcParams) -> Option<BpopcOutput> {
pub fn bpopc(params: &BpopcParams) -> Option<BpopcOutput> {
let id = params.id;
// 计算索引
@ -212,7 +212,7 @@ pub fn bpopc_pure(params: &BpopcParams) -> Option<BpopcOutput> {
lrm: params.state_lrm,
};
let state_out = state_pure(&state_params);
let state_out = state(&state_params);
let qq = if params.ioptab > 0 {
state_out.q / params.ytot
@ -411,7 +411,7 @@ mod tests {
state_natoms: 2,
};
let result = bpopc_pure(&params);
let result = bpopc(&params);
assert!(result.is_none(), "Should return None when INPC=0");
}
@ -468,7 +468,7 @@ mod tests {
state_natoms: 2,
};
let result = bpopc_pure(&params);
let result = bpopc(&params);
assert!(result.is_some(), "Should return Some when INPC>0");
let output = result.unwrap();
@ -529,7 +529,7 @@ mod tests {
state_natoms: 1,
};
let result = bpopc_pure(&params);
let result = bpopc(&params);
assert!(result.is_some());
let output = result.unwrap();

View File

@ -135,7 +135,7 @@ impl Default for CoolrtOutput {
/// 2. 累积各离子的加热率: HTRAT += W * ABSOTI * RAD1
/// 3. 累积净辐射冷却率: CLHT2 += W * (EM - ABSO1 * RAD1)
/// 4. 累积纯发射冷却率: CLHT3 += W * EMIS1
pub fn coolrt_pure(params: &CoolrtParams) -> CoolrtOutput {
pub fn coolrt(params: &CoolrtParams) -> CoolrtOutput {
let nd = params.nd;
let nion = params.nion;
let nfreq = params.nfreq;
@ -408,9 +408,9 @@ mod tests {
}
#[test]
fn test_coolrt_pure_basic() {
fn test_coolrt_basic() {
let params = create_test_params();
let result = coolrt_pure(&params);
let result = coolrt(&params);
// 验证输出数组大小
assert_eq!(result.clht1.len(), params.nd);
@ -429,9 +429,9 @@ mod tests {
}
#[test]
fn test_coolrt_pure_clht1_sum() {
fn test_coolrt_clht1_sum() {
let params = create_test_params();
let result = coolrt_pure(&params);
let result = coolrt(&params);
// CLHT1 应该是所有离子 (CLRAT - HTRAT) 的和
for id in 0..params.nd {

View File

@ -199,7 +199,7 @@ pub struct RadpreOutput {
/// # 返回值
/// RADPRE 输出结果
#[allow(clippy::too_many_arguments)]
pub fn radpre_pure(
pub fn radpre(
config: &RadpreConfig,
model: &RadpreModelState,
freq: &mut RadpreFreqParamsMut,

View File

@ -15,7 +15,7 @@
//! 2. 调用 ELDENS 计算密度、能量和熵
//! 3. 使用有限差分计算导数
use crate::tlusty::math::{eldens_pure, EldensConfig, EldensParams};
use crate::tlusty::math::{eldens, EldensConfig, EldensParams};
use crate::tlusty::math::StateParams;
use crate::tlusty::state::constants::{BOLK, HMASS, UN};
@ -202,7 +202,7 @@ pub fn trmder(params: &TrmderParams) -> TrmderOutput {
anato_data: None,
};
let result = eldens_pure(&eldens_params, 0);
let result = eldens(&eldens_params, 0);
rhon[i] = result.rhoter;
// 能量密度 = (1.5*P + 内能 + 3*Prad*(T'/T)^4) / rho
@ -377,7 +377,7 @@ mod tests {
let result = trmder(&params);
// 熵模式下应该也能正常工作
// 注意:由于 eldens_pure 的简化实现,熵值可能为零或很小
// 注意:由于 eldens 的简化实现,熵值可能为零或很小
// 这可能导致 heatcp 和 grdadb 不正确,所以我们只验证基本有限性
assert!(result.rho > 0.0, "密度应该为正");
assert!(result.heatcp.is_finite(), "定压比热应该是有限的");

View File

@ -241,7 +241,7 @@ pub struct Opacf1Result {
///
/// # 返回值
/// 包含所有计算结果的结构体
pub fn rates1_pure(params: &mut Rates1Params) -> Rates1Output {
pub fn rates1(params: &mut Rates1Params) -> Rates1Output {
let nd = params.config.nd;
let nfreq = params.config.nfreq;
let ntrans = params.config.ntrans;
@ -665,7 +665,7 @@ mod tests {
}
#[test]
fn test_rates1_pure_basic() {
fn test_rates1_basic() {
// 创建基本测试参数
let config = Rates1Config {
imor: 0,
@ -780,7 +780,7 @@ mod tests {
rosstd_contribute: None,
};
let output = rates1_pure(&mut params);
let output = rates1(&mut params);
// 验证输出维度
assert_eq!(output.rru.len(), 1);

View File

@ -22,7 +22,7 @@ use crate::tlusty::state::constants::{MDEPTH, MFREQ, MLEVEL};
use crate::tlusty::state::model::ModelState;
use crate::tlusty::state::config::TlustyConfig;
use crate::tlusty::state::atomic::AtomicData;
use crate::tlusty::io::resolv_pure;
use crate::tlusty::io::resolv;
// ============================================================================
// 配置参数
@ -117,7 +117,7 @@ pub struct Accel2Output {
///
/// # 注意
/// 当 `need_resolv` 为 true 时,调用者需要执行 RESOLV 重新计算
pub fn accel2_pure(params: &mut Accel2Params) -> Accel2Output {
pub fn accel2(params: &mut Accel2Params) -> Accel2Output {
// 标记 RESOLV 依赖Fortran 在加速后调用 RESOLV
// 标记依赖(确保编译器知道 accel2 依赖 resolv_pure
let _ = "accel2 depends on resolv_pure";
@ -287,7 +287,7 @@ pub fn accel2_io<W: std::io::Write>(
params: &mut Accel2Params,
writer: &mut W,
) -> Accel2Output {
let result = accel2_pure(params);
let result = accel2(params);
if result.accelerated {
let _ = writeln!(writer, " **** ACCEL2, ITER={}", params.config.iter);
@ -343,7 +343,7 @@ mod tests {
psy3: &mut psy3,
};
let result = accel2_pure(&mut params);
let result = accel2(&mut params);
assert!(!result.accelerated);
assert!(!result.need_resolv);
@ -380,7 +380,7 @@ mod tests {
psy3: &mut psy3,
};
let result = accel2_pure(&mut params);
let result = accel2(&mut params);
// 应该存储到 PSY3但不执行加速
assert!(!result.accelerated);
@ -426,7 +426,7 @@ mod tests {
psy3: &mut psy3,
};
let result = accel2_pure(&mut params);
let result = accel2(&mut params);
// 应该执行加速
assert!(result.accelerated);
@ -470,7 +470,7 @@ mod tests {
psy3: &mut psy3,
};
let result = accel2_pure(&mut params);
let result = accel2(&mut params);
// ipng != 0应该只做移位不执行加速
// iter - iacc = 5 - 3 = 2, iacd = 2, ipng = 2 % 2 = 0
@ -514,7 +514,7 @@ mod tests {
psy3: &mut psy3,
};
let result = accel2_pure(&mut params);
let result = accel2(&mut params);
assert!(result.accelerated);

View File

@ -8,7 +8,7 @@
//! - 使用 ELDENS 计算电子密度
//! - 使用 PGSET 迭代计算气体压力
use crate::tlusty::math::{eldens_pure, EldensConfig, EldensOutput, EldensParams};
use crate::tlusty::math::{eldens, EldensConfig, EldensOutput, EldensParams};
use crate::tlusty::math::{pgset, PgsetParams, PgsetOutput};
use crate::tlusty::state::constants::{BOLK, HALF, TWO, UN};
@ -142,7 +142,7 @@ pub struct RybchnOutput {
///
/// # 返回值
/// 包含更新后的温度、密度、压力等的输出结构体
pub fn rybchn_pure(params: &RybchnParams) -> RybchnOutput {
pub fn rybchn(params: &RybchnParams) -> RybchnOutput {
let nd = params.nd;
let config = &params.config;
@ -400,7 +400,7 @@ fn compute_eldens(params: &RybchnParams, id: usize, t: f64, an: f64) -> EldensOu
anato_data: None,
};
eldens_pure(&eldens_params, 1)
eldens(&eldens_params, 1)
}
/// ERFCX 近似函数(缩放互补误差函数)
@ -463,7 +463,7 @@ mod tests {
#[test]
fn test_rybchn_basic() {
let params = create_test_params();
let output = rybchn_pure(&params);
let output = rybchn(&params);
// 检查输出维度
assert_eq!(output.temp.len(), params.nd);
@ -488,7 +488,7 @@ mod tests {
// 设置较大的温度变化
params.changt = vec![0.5, 0.5, 0.5, 0.5, 0.5];
let output = rybchn_pure(&params);
let output = rybchn(&params);
// 检查温度变化被限制
// 由于 dplp = dpsilt - 1 = 2 - 1 = 1, dplm = 1/dpsilt - 1 = 0.5 - 1 = -0.5

View File

@ -263,7 +263,7 @@ pub struct RybsolOutput {
/// ...
/// END
/// ```
pub fn rybsol_pure<F_OPACTR, F_RTEFR1, F_ALIFR1, F_ROSSTD, F_RYBMAT, F_RYBENE, F_RYBCHN>(
pub fn rybsol<F_OPACTR, F_RTEFR1, F_ALIFR1, F_ROSSTD, F_RYBMAT, F_RYBENE, F_RYBCHN>(
params: &mut RybsolParams,
rybmtx: &mut RybmtxWork,
// 回调函数
@ -711,7 +711,7 @@ mod tests {
let mut rybmtx = RybmtxWork::new();
// 使用空回调函数
let output = rybsol_pure(
let output = rybsol(
&mut params,
&mut rybmtx,
|_ij| {}, // opactr

View File

@ -360,7 +360,7 @@ pub fn back_solution_step(
/// 求解线性系统。
///
/// 完整版本需要集成 matgen、matinv、wnstor 等。
pub fn solves_pure(
pub fn solves(
nn: usize,
nd: usize,
nfreqe: usize,
@ -515,10 +515,10 @@ mod tests {
}
#[test]
fn test_solves_pure_basic() {
fn test_solves_basic() {
let kant = vec![0; 200];
let output = solves_pure(
let output = solves(
10, // nn
5, // nd
3, // nfreqe

View File

@ -7,8 +7,8 @@
//! - 使用迭代方法求解电荷守恒方程
//! - 与统计平衡方程耦合
use crate::tlusty::math::{moleq_pure, MoleqOutput, MoleqParams};
use crate::tlusty::math::{state_pure, StateOutput, StateParams};
use crate::tlusty::math::{moleq, MoleqOutput, MoleqParams};
use crate::tlusty::math::{state, StateOutput, StateParams};
use crate::tlusty::math::{steqeq_pure, SteqeqConfig, SteqeqParams};
use crate::tlusty::math::wnstor;
use crate::tlusty::state::constants::{HALF, MDEPTH, MLEVEL, UN};
@ -125,7 +125,7 @@ pub struct ElcorOutput {
///
/// # 返回值
/// 包含更新后的电子密度和密度
pub fn elcor_pure(params: &ElcorParams) -> ElcorOutput {
pub fn elcor(params: &ElcorParams) -> ElcorOutput {
let config = &params.config;
// 检查 ioptab 标志
@ -262,7 +262,7 @@ fn compute_qq(params: &ElcorParams, _id: usize, t: f64, an: f64, ane: f64, dens:
if config.ifmol == 0 || t >= config.tmolim {
// 使用 STATE 函数计算电荷
if let Some(state_params) = &params.state_params {
let state_out = state_pure(state_params);
let state_out = state(state_params);
let q = state_out.q;
let qq = if config.ioptab > 0 {
@ -277,7 +277,7 @@ fn compute_qq(params: &ElcorParams, _id: usize, t: f64, an: f64, ane: f64, dens:
// 使用 MOLEQ 分子平衡计算
// f2r_depends: MOLEQ
if let Some(moleq_params) = &params.moleq_params {
let _moleq_out = moleq_pure(moleq_params);
let _moleq_out = moleq(moleq_params);
}
params.qadd
}
@ -348,7 +348,7 @@ mod tests {
#[test]
fn test_elcor_basic() {
let params = create_test_params();
let output = elcor_pure(&params);
let output = elcor(&params);
// 检查输出
println!("ELEC: {}", output.elec);
@ -366,7 +366,7 @@ mod tests {
let mut params = create_test_params();
params.config.ioptab = 1; // 应该跳过计算
let output = elcor_pure(&params);
let output = elcor(&params);
// 检查跳过后的输出等于输入
assert!((output.elec - params.elec).abs() < 1e-10);

View File

@ -250,7 +250,7 @@ where
///
/// # 返回
/// 计算结果
pub fn greyd_pure<F_Rhonen, F_Wnstor, F_Steqeq, F_Opacf0, F_Meanop>(
pub fn greyd<F_Rhonen, F_Wnstor, F_Steqeq, F_Opacf0, F_Meanop>(
config: &GreydConfig,
state: &mut GreydState,
rhonen_fn: &mut F_Rhonen,
@ -385,7 +385,7 @@ mod tests {
}
#[test]
fn test_greyd_pure() {
fn test_greyd() {
let config = GreydConfig {
teff: 35000.0,
qgrav: 1e4,
@ -420,7 +420,7 @@ mod tests {
(1e-5, 1e-3) // 返回简化的不透明度
};
let output = greyd_pure(
let output = greyd(
&config,
&mut state,
&mut rhonen_fn,

View File

@ -262,7 +262,7 @@ impl LucyState {
/// ! 积分流体静力学平衡
/// END
/// ```
pub fn lucy_pure(
pub fn lucy(
config: &LucyConfig,
model: &LucyModelParams,
opacfl_data: &[OpacflPointData],
@ -720,7 +720,7 @@ mod tests {
..config.clone()
};
let output = lucy_pure(&config_zero, &model, &opacfl_data, &rad1_data);
let output = lucy(&config_zero, &model, &opacfl_data, &rad1_data);
assert_eq!(output.ilucy, 0);
}

View File

@ -164,7 +164,7 @@ pub struct CubconData {
/// ...
/// END
/// ```
pub fn temcor_pure(params: &mut TemcorParams) -> TemcorOutput {
pub fn temcor(params: &mut TemcorParams) -> TemcorOutput {
let nd = params.nd;
let mut depth_results = Vec::new();
let mut any_correction = false;
@ -526,7 +526,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = temcor_pure(&mut params);
let output = temcor(&mut params);
// iconv <= 0 且 indl == 0 时应该跳过
assert_eq!(output.depth_results.len(), 0);
@ -541,7 +541,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = temcor_pure(&mut params);
let output = temcor(&mut params);
// 应该处理所有深度点
assert_eq!(output.depth_results.len(), 49); // id from 2 to nd
@ -555,7 +555,7 @@ mod tests {
..Default::default()
};
let mut params = TestParamsBuilder::new(50).config(config).build();
let output = temcor_pure(&mut params);
let output = temcor(&mut params);
// 盘模式应该正常工作
assert_eq!(output.depth_results.len(), 49);

View File

@ -234,7 +234,7 @@ impl FactrsData {
/// ...
/// END
/// ```
pub fn temper_pure(
pub fn temper(
params: &mut TemperParams,
prsaux: &mut PrsauxData,
flxaux: &mut FlxauxData,
@ -588,7 +588,7 @@ mod tests {
flxaux.t4 = 35000.0_f64.powi(4);
let factrs = FactrsData::new(50);
let output = temper_pure(&mut params, &mut prsaux, &mut flxaux, &factrs);
let output = temper(&mut params, &mut prsaux, &mut flxaux, &factrs);
// 验证基本输出
assert!(output.t > 0.0);
@ -609,7 +609,7 @@ mod tests {
let mut flxaux = FlxauxData::default();
let factrs = FactrsData::new(50);
let output = temper_pure(&mut params, &mut prsaux, &mut flxaux, &factrs);
let output = temper(&mut params, &mut prsaux, &mut flxaux, &factrs);
// itgr > 1 且 itgmax > 0 时应该只计算电子密度
assert!(output.t > 0.0);
@ -626,7 +626,7 @@ mod tests {
flxaux.t4 = 35000.0_f64.powi(4);
let factrs = FactrsData::new(50);
let output = temper_pure(&mut params, &mut prsaux, &mut flxaux, &factrs);
let output = temper(&mut params, &mut prsaux, &mut flxaux, &factrs);
// 第一个深度点应该设置 HG1, HR1, RR1
assert!(prsaux.hg1 >= 0.0);

View File

@ -133,7 +133,7 @@ pub struct ChangeOutput {
///
/// # 返回值
/// 包含更新后的粒子数
pub fn change_pure(params: &ChangeParams) -> ChangeOutput {
pub fn change(params: &ChangeParams) -> ChangeOutput {
let nd = params.nd;
let nlevel = params.nlevel;
let config = &params.config;
@ -399,7 +399,7 @@ mod tests {
steqeq_fn: None,
};
let output = change_pure(&params);
let output = change(&params);
// 检查输出维度
assert_eq!(output.popul.len(), nlevel);

View File

@ -204,7 +204,7 @@ impl Default for NewdmModelState {
/// # 注意
///
/// 完整实现需要调用 TEMPER 和 HESOLV这里只实现网格计算部分。
pub fn newdm_pure(
pub fn newdm(
config: &NewdmConfig,
state: &mut NewdmModelState,
_prs_aux: &mut PrsAux,
@ -545,7 +545,7 @@ mod tests {
let mut prs_aux = PrsAux::default();
let mut factrs = Factrs::default();
newdm_pure(&config, &mut state, &mut prs_aux, &mut factrs);
newdm(&config, &mut state, &mut prs_aux, &mut factrs);
// 验证基本属性dm[0] 应该是正数(因为它是从原始网格插值来的)
// 注意由于我们使用简化的测试网格tauros 可能很小
@ -584,7 +584,7 @@ mod tests {
let mut prs_aux = PrsAux::default();
let mut factrs = Factrs::default();
newdm_pure(&config, &mut state, &mut prs_aux, &mut factrs);
newdm(&config, &mut state, &mut prs_aux, &mut factrs);
// 验证 theta 在有效范围内
// 注意theta 的范围取决于 fractv 参数

View File

@ -177,7 +177,7 @@ impl Default for NewdmtModelState {
/// # 注意
///
/// 完整实现需要调用 TEMPER 和 HESOLV这里只实现网格计算部分。
pub fn newdmt_pure(
pub fn newdmt(
config: &NewdmtConfig,
state: &mut NewdmtModelState,
prs_aux: &mut NewdmtPrsAux,
@ -527,7 +527,7 @@ mod tests {
let mut prs_aux = NewdmtPrsAux::default();
let mut factrs = NewdmtFactrs::default();
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
newdmt(&config, &mut state, &mut prs_aux, &mut factrs);
// 验证基本属性
assert!(state.dm[0] > 0.0, "dm[0] should be positive");
@ -568,7 +568,7 @@ mod tests {
let mut prs_aux = NewdmtPrsAux::default();
let mut factrs = NewdmtFactrs::default();
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
newdmt(&config, &mut state, &mut prs_aux, &mut factrs);
// 验证 theta 在有效范围内
for i in 0..config.nd {
@ -614,7 +614,7 @@ mod tests {
let mut prs_aux = NewdmtPrsAux::default();
let mut factrs = NewdmtFactrs::default();
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
newdmt(&config, &mut state, &mut prs_aux, &mut factrs);
// 验证 tauros 是单调递增的
for i in 1..config.nd {

View File

@ -97,7 +97,7 @@ pub struct SabolfOutput {
///
/// # 返回
/// Saha-Boltzmann 因子和上能级求和
pub fn sabolf_pure(params: &mut SabolfParams) -> SabolfOutput {
pub fn sabolf(params: &mut SabolfParams) -> SabolfOutput {
// 如果 ioptab < 0返回空数组
if params.ioptab < 0 {
let nlevels = params.enion.len();
@ -269,7 +269,7 @@ pub fn sabolf_pure(params: &mut SabolfParams) -> SabolfOutput {
};
let xmx = xmax * qz.sqrt();
use crate::tlusty::math::partition::{partf_pure, PartfParams, PartfMode};
use crate::tlusty::math::partition::{partf, PartfParams, PartfMode};
let partf_params = PartfParams {
iat,
izi: params.iz[ion_idx],
@ -279,7 +279,7 @@ pub fn sabolf_pure(params: &mut SabolfParams) -> SabolfOutput {
mode: PartfMode::Standard,
iirwin: 0,
};
let partf_result = partf_pure(&partf_params);
let partf_result = partf(&partf_params);
let u_pf = partf_result.u;
let dut_pf = partf_result.dut;
let dun_pf = partf_result.dun;
@ -445,7 +445,7 @@ mod tests {
#[test]
fn test_sabolf_basic() {
let mut params = create_test_params();
let result = sabolf_pure(&mut params);
let result = sabolf(&mut params);
assert_eq!(result.sbf.len(), 9);
assert_eq!(result.usum.len(), 3);
@ -458,7 +458,7 @@ mod tests {
fn test_sabolf_ioptab_negative() {
let mut params = create_test_params();
params.ioptab = -1;
let result = sabolf_pure(&mut params);
let result = sabolf(&mut params);
for &sb in &result.sbf {
assert!((sb - 0.0).abs() < 1e-10);
@ -470,7 +470,7 @@ mod tests {
let mut params = create_test_params();
params.t = 50000.0;
params.ane = 1.0e15;
let result = sabolf_pure(&mut params);
let result = sabolf(&mut params);
for &sb in &result.sbf {
assert!(sb >= 0.0, "SBF should be non-negative");

View File

@ -10,7 +10,7 @@
//! - MODE=3: 类似 MODE=2但计算导数
use crate::tlusty::state::constants::*;
use crate::tlusty::math::{partf_pure, PartfParams, PartfMode};
use crate::tlusty::math::{partf, PartfParams, PartfMode};
// ============================================================================
// 常量
@ -474,7 +474,7 @@ pub struct StateParams<'a> {
///
/// # 返回
/// STATE 输出结构
pub fn state_pure(params: &StateParams) -> StateOutput {
pub fn state(params: &StateParams) -> StateOutput {
let mode = params.mode;
let id = params.id;
let t = params.t;
@ -497,7 +497,7 @@ pub fn state_pure(params: &StateParams) -> StateOutput {
// 初始化 Opacity Project 离子分数(如果需要)
if params.ifoppf > 0 {
use crate::tlusty::math::{opfrac_pure, OpfracParams, PfOptB};
use crate::tlusty::math::{opfrac, OpfracParams, PfOptB};
let pfoptb = PfOptB::new();
let opfrac_params = OpfracParams {
iat: 0,
@ -505,7 +505,7 @@ pub fn state_pure(params: &StateParams) -> StateOutput {
t: params.t,
ane: params.ane,
};
let _ = opfrac_pure(&opfrac_params, &pfoptb);
let _ = opfrac(&opfrac_params, &pfoptb);
}
return output;
}
@ -570,7 +570,7 @@ pub fn state_pure(params: &StateParams) -> StateOutput {
iirwin: 0,
};
let pf_result = partf_pure(&partf_params);
let pf_result = partf(&partf_params);
let um = pf_result.u;
let dutm = pf_result.dut;
let dunm = pf_result.dun;
@ -605,7 +605,7 @@ pub fn state_pure(params: &StateParams) -> StateOutput {
iirwin: 0,
};
let pf_result_j = partf_pure(&partf_params_j);
let pf_result_j = partf(&partf_params_j);
let u = pf_result_j.u;
let dut = pf_result_j.dut;
let dun = pf_result_j.dun;
@ -862,7 +862,7 @@ mod tests {
}
#[test]
fn test_state_pure_basic() {
fn test_state_basic() {
// 创建测试参数
let abndd = vec![1.0; MATOM]; // 丰度
let ioniz = vec![2; MATOM]; // 电离级
@ -887,7 +887,7 @@ mod tests {
ifoppf: 0,
};
let result = state_pure(&params);
let result = state(&params);
// 验证结果
assert!(result.q >= 0.0, "Total charge should be non-negative");
@ -924,7 +924,7 @@ mod tests {
ifoppf: 0,
};
let result = state_pure(&params);
let result = state(&params);
assert!((result.qm - qm_expected).abs() < 1e-20, "H- charge mismatch");
}