//! 氢线 Stark 展宽表格插值。 //! //! 重构自 TLUSTY `inthyd.f`。 //! //! 从 Lemke 表格中插值计算氢线的 Stark 展宽轮廓。 use crate::tlusty::math::{divstr, starka, yint}; use crate::tlusty::state::HydPrf; // ============================================================================ // INTHYD - 氢线表格插值 // ============================================================================ /// 从 Lemke 表格插值计算氢线 Stark 展宽轮廓。 /// /// 在温度和电子密度方向上进行二维插值。 /// /// # 参数 /// /// - `x0` - log10(温度) /// - `z0` - log10(电子密度) /// - `iwl` - 波长索引 (0-indexed) /// - `iline` - 谱线索引 (0-indexed) /// - `hydprf` - 氢线表格数据 /// - `dbeta` - Doppler 宽度 (β 单位) /// - `xk` - 参考波数 /// /// # 返回 /// /// log10(轮廓值) /// /// # Fortran 原始代码 /// /// ```fortran /// SUBROUTINE INTHYD(W0,X0,Z0,IWL,ILINE) /// ... /// END /// ``` pub fn inthyd( x0: f64, z0: f64, iwl: usize, iline: usize, hydprf: &HydPrf, dbeta: f64, xk: f64, ) -> f64 { let nt = hydprf.nth[iline] as usize; let ne = hydprf.neh[iline] as usize; let beta = hydprf.get_wlh(iwl, iline) / xk; let izh = 1; // H I // 检查是否低于最低电子密度网格值 // 对于低于最低网格值的情况,使用近似表达式 (starka) let xnelem_min = hydprf.get_xnelem(0, iline); if z0 < xnelem_min * 0.99 { let (adh, divh) = divstr(dbeta, izh); let stark_val = starka(beta, 2.0, adh, dbeta, divh); return (stark_val * dbeta).log10(); } // 查找电子密度插值区间 let mut ipz = 0; for izz in 0..(ne - 1) { ipz = izz; if z0 <= hydprf.get_xnelem(izz + 1, iline) { break; } } // 确定插值窗口 let nz = 2; let mut n0z = ipz as i32 - (nz as i32 / 2) + 1; if n0z < 1 { n0z = 1; } if n0z > (ne - nz + 1) as i32 { n0z = (ne - nz + 1) as i32; } let n1z = n0z + nz as i32 - 1; // 准备插值数组 let mut zz = [0.0; 3]; let mut wz = [0.0; 3]; for izz in n0z..=n1z { let i0z = (izz - n0z) as usize; zz[i0z] = hydprf.get_xnelem((izz - 1) as usize, iline); // 检查是否超过最高温度网格值 let xtlem_max = hydprf.get_xtlem(nt - 1, iline); if x0 > 1.01 * xtlem_max { let (adh, divh) = divstr(dbeta, izh); let stark_val = starka(beta, 2.0, adh, dbeta, divh); return (stark_val * dbeta).log10(); } // 温度方向插值 let nx = 2; let mut ipx = 0; for ix in 0..(nt - 1) { ipx = ix; if x0 <= hydprf.get_xtlem(ix + 1, iline) { break; } } let mut n0x = ipx as i32 - (nx as i32 / 2) + 1; if n0x < 1 { n0x = 1; } if n0x > (nt - nx + 1) as i32 { n0x = (nt - nx + 1) as i32; } let n1x = n0x + nx as i32 - 1; let mut xx = [0.0; 3]; let mut wx = [0.0; 3]; for ix in n0x..=n1x { let i0 = (ix - n0x) as usize; xx[i0] = hydprf.get_xtlem((ix - 1) as usize, iline); wx[i0] = hydprf.get_prfhyd(iline, iwl, (ix - 1) as usize, (izz - 1) as usize); } // 检查是否有无效值 if wx[0] < -99.0 || wx[1] < -99.0 || wx[2] < -99.0 { let (adh, divh) = divstr(dbeta, izh); let stark_val = starka(beta, 2.0, adh, dbeta, divh); return (stark_val * dbeta).log10(); } else { wz[i0z] = yint(&xx, &wx, x0); } } // 电子密度方向插值 yint(&zz, &wz, z0) } #[cfg(test)] mod tests { use super::*; fn create_test_hydprf() -> HydPrf { let mut hydprf = HydPrf::default(); // 设置谱线 0 的参数 hydprf.nth[0] = 7; hydprf.neh[0] = 20; // 设置温度网格 (log10) for it in 0..7 { hydprf.xtlem[it] = 4.0 + it as f64 * 0.1; // 10^4.0 到 10^4.6 } // 设置电子密度网格 (log10) for ie in 0..20 { hydprf.xnelem[ie] = 12.0 + ie as f64 * 0.2; // 10^12 到 10^15.8 } // 设置波长网格 for iwl in 0..90 { hydprf.wlh[iwl] = 4000.0 + iwl as f64 * 10.0; // 4000 Å 到 4900 Å } // 设置轮廓数据 (简单的测试值) for it in 0..7 { for ie in 0..20 { hydprf.set_prfhyd(0, 0, it, ie, -2.0 + it as f64 * 0.1 + ie as f64 * 0.01); } } hydprf } #[test] fn test_inthyd_basic() { let hydprf = create_test_hydprf(); let dbeta = 10.0; let xk = 1.0; // 在表格范围内的插值 let x0 = 4.3; // log10(T) let z0 = 13.5; // log10(Ne) let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk); // 结果应该是有限值 assert!(result.is_finite()); } #[test] fn test_inthyd_low_ne() { let hydprf = create_test_hydprf(); let dbeta = 10.0; let xk = 1.0; // 低于最低电子密度,应该使用近似表达式 let x0 = 4.3; let z0 = 10.0; // 低于 10^12 let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk); // 结果应该是有限值 assert!(result.is_finite()); } #[test] fn test_inthyd_high_temp() { let hydprf = create_test_hydprf(); let dbeta = 10.0; let xk = 1.0; // 高于最高温度,应该使用近似表达式 let x0 = 5.0; // 高于 10^4.6 let z0 = 13.5; let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk); // 结果应该是有限值 assert!(result.is_finite()); } }