//! 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, Vec)>> = OnceLock::new(); fn load_table() -> Option<(Vec, Vec)> { 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::(), parts[1].parse::()) { 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 { 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); } }