//! 氢线 Stark 展宽近似表达式。 //! //! 重构自 TLUSTY `starka.f`。 //! //! 当温度或电子密度超出 Lemke 表格范围时,使用近似表达式计算氢线 Stark 轮廓。 // ============================================================================ // 常量参数 // ============================================================================ const F0: f64 = -0.5758228; const F1: f64 = 0.4796232; const F2: f64 = 0.07209481; const AL: f64 = 1.26; const SD: f64 = 0.5641895; const SLO: f64 = -2.5; const THRA: f64 = 1.5; const BL1: f64 = 1.14; const BL2: f64 = 11.4; const SAC: f64 = 0.08; const PISQ1: f64 = 1.0 / 1.77245385090551; // 1 / sqrt(pi) // ============================================================================ // STARKA - Stark 展宽近似表达式 // ============================================================================ /// 计算氢线 Stark 展宽的近似表达式。 /// /// 当温度或电子密度超出 Lemke 表格范围时使用。 /// /// # 参数 /// /// - `beta` - 以 β 单位表示的波长位移 (Δλ/β) /// - `fac` - 乘法因子 (H I 为 2.0,He II 为 1.0) /// - `adh` - 辅助参数 A = 1.5*ln(BETAD) - 1.761 /// - `betad` - 以 β 单位表示的 Doppler 宽度 /// - `divh` - Doppler 核心与 Stark 翼的分界点 (以 betad 为单位) /// /// # 返回 /// /// Stark 轮廓值 S(β) /// /// # Fortran 原始代码 /// /// ```fortran /// FUNCTION STARKA(BETA,FAC) /// ... /// BETAD1=UN/BETAD /// IF(ADH.GT.AL) THEN /// XD=BETA*BETAD1 /// IF(XD.LE.DIVH) THEN /// STARKA=EXP(-XD*XD)*BETAD1*PISQ1 /// ELSE /// STARKA=THRA*FAC*EXP(SLO*LOG(BETA)) /// END IF /// ELSE /// IF(BETA.LE.BL1) THEN /// STARKA=SAC /// ELSE IF(BETA.LT.BL2) THEN /// XL=LOG(BETA) /// FL=(F0*XL+F1)*XL /// STARKA=F2*EXP(FL) /// ELSE /// STARKA=THRA*FAC*EXP(SLO*LOG(BETA)) /// END IF /// END IF /// END /// ``` pub fn starka(beta: f64, fac: f64, adh: f64, betad: f64, divh: f64) -> f64 { let betad1 = 1.0 / betad; if adh > AL { // a > 1: Doppler 核心 + 渐近 Holtsmark 翼 let xd = beta * betad1; if xd <= divh { // Doppler 核心 (-xd * xd).exp() * betad1 * PISQ1 } else { // 渐近 Holtsmark 翼 THRA * fac * beta.powf(SLO) } } else { // a < 1: 经验公式 if beta <= BL1 { SAC } else if beta < BL2 { let xl = beta.ln(); let fl = (F0 * xl + F1) * xl; F2 * fl.exp() } else { THRA * fac * beta.powf(SLO) } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_starka_doppler_core() { // a > 1, xd <= divh: Doppler 核心 let adh = 2.0; // > AL = 1.26 let betad = 10.0; let divh = 5.0; let beta = 30.0; // xd = 30/10 = 3 <= 5 let result = starka(beta, 2.0, adh, betad, divh); // 应该是 Doppler 核心值 let xd = beta / betad; let expected = (-xd * xd).exp() / betad * PISQ1; assert!((result - expected).abs() < 1e-10); } #[test] fn test_starka_holtsmark_wing() { // a > 1, xd > divh: Holtsmark 翼 let adh = 2.0; let betad = 10.0; let divh = 5.0; let beta = 100.0; // xd = 100/10 = 10 > 5 let result = starka(beta, 2.0, adh, betad, divh); // 应该是 Holtsmark 翼值 let expected = THRA * 2.0 * beta.powf(SLO); assert!((result - expected).abs() < 1e-10); } #[test] fn test_starka_empirical_low_beta() { // a <= 1, beta <= BL1 let adh = 0.5; // < AL let result = starka(0.5, 2.0, adh, 10.0, 5.0); assert!((result - SAC).abs() < 1e-10); } #[test] fn test_starka_empirical_mid_beta() { // a <= 1, BL1 < beta < BL2 let adh = 0.5; let beta = 5.0; // 1.14 < 5.0 < 11.4 let result = starka(beta, 2.0, adh, 10.0, 5.0); let xl = beta.ln(); let fl = (F0 * xl + F1) * xl; let expected = F2 * fl.exp(); assert!((result - expected).abs() < 1e-10); } #[test] fn test_starka_empirical_high_beta() { // a <= 1, beta >= BL2 let adh = 0.5; let beta = 20.0; // > 11.4 let result = starka(beta, 2.0, adh, 10.0, 5.0); let expected = THRA * 2.0 * beta.powf(SLO); assert!((result - expected).abs() < 1e-10); } #[test] fn test_starka_factor_difference() { // 测试不同 fac 值的影响 let adh = 2.0; let betad = 10.0; let divh = 5.0; let beta = 100.0; let result_hi = starka(beta, 2.0, adh, betad, divh); let result_he = starka(beta, 1.0, adh, betad, divh); // fac 越大,结果越大 assert!(result_hi > result_he); assert!((result_hi / result_he - 2.0).abs() < 1e-10); } }