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>
57 lines
1.6 KiB
Rust
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);
|
|
}
|
|
}
|