SpectraRust/src/synspec/math/h2opf.rs
fmq e2c1a4580a feat: F2R 重构全部完成 + 自动化脚本改进
Phase 1 翻译 (完成):
- TLUSTY 350 函数 100% 翻译
- SYNSPEC 168 函数 100% 翻译
- ~495 Rust 模块

Phase 2 集成 (完成):
- TLUSTY RESOLV 7 个 TODO 全部清除
- TLUSTY Runner IJALI 频率选择实现
- OPFRAC ioniz.dat 解析完整实现
- SYNSPEC Runner 编排流程连接完成
- SYNSPEC RESOLV OPAC→RTE→OUTPRI 调用链完整

Phase 3 验证 (完成, 修复 8 处 bug):
- INITIA: compute_hydrogen_level_bounds 索引混合修复
- INILIN: GAMR0/GS0/GW0 展宽公式修复, 经典 VdW 公式修复
- INIBL0: CNM 常数 2.997925e18→e17 修复
- OPAC: Lyman IJ=2 修正缺失修复
- RTE: minv3 矩阵求逆符号错误修复

自动化脚本改进:
- specf2r.sh: 添加 429 限流退避、完成检测、同步等待
- SKILL.md: 三阶段工作流 + 状态文件系统
- references/: Phase 1/2/3 独立参考文档

新增:
- src/bin/synspec.rs: SYNSPEC 可执行文件入口
- .f2r_phase/.f2r_tasks/.f2r_complete: 状态管理文件

编译: 0 错误 | Clippy: 0 错误 | 测试: voigt 28 + eldens 5 通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:54:53 +08:00

57 lines
1.6 KiB
Rust

//! Partition function for H2O from EXOMOL data.
//!
//! Translated from SYNSPEC `h2opf` subroutine.
use std::sync::OnceLock;
const TABLE_SIZE: usize = 10000;
const DATA_FILE: &str = "./data/h2o_exomol.pf";
static TABLE: OnceLock<Option<(Vec<f64>, Vec<f64>)>> = OnceLock::new();
fn load_table() -> Option<(Vec<f64>, Vec<f64>)> {
let content = std::fs::read_to_string(DATA_FILE).ok()?;
let mut ttab = Vec::with_capacity(TABLE_SIZE);
let mut pftab = Vec::with_capacity(TABLE_SIZE);
for line in content.lines().take(TABLE_SIZE) {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() >= 2
&& let (Ok(t), Ok(pf)) = (parts[0].parse::<f64>(), parts[1].parse::<f64>()) {
ttab.push(t);
pftab.push(pf);
}
}
Some((ttab, pftab))
}
/// Evaluate H2O partition function at temperature `t` by linear interpolation.
///
/// Returns `None` if the data file cannot be loaded.
pub fn h2opf(t: f64) -> Option<f64> {
let table = TABLE.get_or_init(load_table).as_ref()?;
let (ref ttab, ref pftab) = *table;
let n = ttab.len();
if n < 2 || t < ttab[0] || t > ttab[n - 1] {
return None;
}
let itab = t.floor() as usize;
if itab >= n - 1 {
return None;
}
let idx = itab.min(n - 2);
let pf = pftab[idx] + (t - ttab[idx]) * (pftab[idx + 1] - pftab[idx]);
Some(pf)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_h2opf_basic() {
// Without the data file, should return None
// This test just verifies the function compiles and runs
let _ = h2opf(5000.0);
}
}