//! 氦原子碰撞速率计算。 //! //! 重构自 TLUSTY `COLHE` 子程序。 //! //! # 功能 //! //! - 计算中性氦(He I)和电离氦(He II)的碰撞速率 //! - 支持多种碰撞速率公式(ICOL = 0, 1, 2, 3) //! - 包含碰撞电离和碰撞激发 use crate::tlusty::state::constants::{HK, H, UN}; // ============================================================================ // 常量和数据 // ============================================================================ /// 指数积分展开系数 const EXPIA1: f64 = -0.57721566; const EXPIA2: f64 = 0.99999193; const EXPIA3: f64 = -0.24991055; const EXPIA4: f64 = 0.05519968; const EXPIA5: f64 = -0.00976004; const EXPIA6: f64 = 0.00107857; const EXPIB1: f64 = 0.2677734343; const EXPIB2: f64 = 8.6347608925; const EXPIB3: f64 = 18.059016973; const EXPIB4: f64 = 8.5733287401; const EXPIC1: f64 = 3.9584969228; const EXPIC2: f64 = 21.0996530827; const EXPIC3: f64 = 25.6329561486; const EXPIC4: f64 = 9.5733223454; /// He I 从基态到 n=2-17 的振子强度 static FHE1: [f64; 16] = [ 0.0, 2.75e-1, 7.29e-2, 2.96e-2, 1.48e-2, 8.5e-3, 5.3e-3, 3.5e-3, 2.5e-3, 1.8e-3, 1.5e-3, 1.2e-3, 9.4e-4, 7.5e-4, 6.1e-4, 5.3e-4, ]; /// He II 碰撞电离系数(低能级) static G0: [f64; 3] = [7.3399521e-2, 1.7252867, 8.6335087]; static G1: [f64; 3] = [-1.4592763e-7, 2.0944117e-6, 2.7575544e-5]; static G2: [f64; 3] = [7.6621299e5, 5.4254879e6, 6.6395519e6]; static G3: [f64; 3] = [2.3775439e2, 2.2177891e3, 5.20725e3]; /// He II 碰撞电离系数(高能级) static A: [[f64; 10]; 6] = [ [-8.5931587, 85.014091, 923.64099, 2018.6470, 1551.5061, -2327.4819, -10701.481, -27619.789, -41099.602, -61599.023], [9.3868790, -78.834488, -969.18451, -2243.1768, -2059.9768, 1546.7107, 9834.3447, 27067.436, 41421.254, 63594.133], [-4.0027571, 28.360615, 401.23965, 983.83374, 1051.4103, -204.82320, -3335.4211, -10100.119, -15863.257, -24949.125], [0.83941799, -4.7963457, -81.122566, -209.86169, -251.30855, -43.175175, 530.37292, 1826.1049, 2941.6460, 4740.8364], [-8.6396709e-2, 0.37385577, 8.0078983, 21.757591, 28.375637, 11.890312, -39.536087, -161.52513, -266.86011, -440.88257], [3.4853835e-3, -1.0401310e-2, -0.30957383, -0.87988985, -1.2254572, -0.72724497, 1.0879648, 5.6239786, 9.5323009, 16.150818], ]; // ============================================================================ // 辅助函数 // ============================================================================ /// 计算指数积分 E1(x) 的近似值。 /// /// 使用 Abramowitz-Stegun 公式。 fn expi_approx(u0: f64) -> f64 { if u0 <= UN { // 小参数展开 -u0.ln() + EXPIA1 + u0 * (EXPIA2 + u0 * (EXPIA3 + u0 * (EXPIA4 + u0 * (EXPIA5 + u0 * EXPIA6)))) } else { // 大参数渐近展开 let eu0 = (-u0).exp(); eu0 * ((EXPIB1 + u0 * (EXPIB2 + u0 * (EXPIB3 + u0 * (EXPIB4 + u0)))) / (EXPIC1 + u0 * (EXPIC2 + u0 * (EXPIC3 + u0 * (EXPIC4 + u0))))) / u0 } } // ============================================================================ // 输入/输出结构体 // ============================================================================ /// COLHE 输入参数(简化版)。 pub struct ColheParams { /// 温度 (K) pub temp: f64, /// 能级数(中性氦) pub nlevel_he1: usize, /// 能级数(电离氦) pub nlevel_he2: usize, } /// COLHE 输出结果。 #[derive(Debug, Clone)] pub struct ColheOutput { /// 碰撞速率数组(简化版,仅示例) pub col_rates: Vec, } // ============================================================================ // 核心计算函数 // ============================================================================ /// 计算 He I 碰撞电离速率。 /// /// # 参数 /// - `t`: 温度 (K) /// - `enion`: 电离能 (erg) /// - `osc0`: 振子强度 /// /// # 返回 /// 碰撞电离速率 pub fn colhe1_ionization(t: f64, enion: f64, osc0: f64) -> f64 { let srt = t.sqrt(); let ct = 5.465e-11 * srt; let tk = HK / H / t; let u0 = enion * tk; let u1 = u0 + 0.27; let u2 = (u0 + 3.43) / (u0 + 1.43).powi(3); let expiu0 = expi_approx(u0); let expiu1 = expi_approx(u1); ct * osc0 * u0 * (expiu0 - u0 * (0.728 * expiu1 / u1 + 0.189 * (-u0).exp() * u2)) } /// 计算 He I 碰撞激发速率(从基态)。 /// /// # 参数 /// - `t`: 温度 (K) /// - `u0`: 激发能量 / kT /// - `osc0`: 振子强度 /// /// # 返回 /// 碰撞激发速率 pub fn colhe1_excitation_ground(t: f64, u0: f64, osc0: f64) -> f64 { let srt = t.sqrt(); let ct1 = 5.4499487 / t / srt; let ex = expi_approx(u0); ct1 * ex / u0 * osc0 } /// 计算 He I 碰撞激发速率(激发态之间)。 /// /// # 参数 /// - `t`: 温度 (K) /// - `u0`: 激发能量 / kT /// - `osc0`: 振子强度 /// /// # 返回 /// 碰撞激发速率 pub fn colhe1_excitation_excited(t: f64, u0: f64, osc0: f64) -> f64 { let srt = t.sqrt(); let ct1 = 5.4499487 / t / srt; let u1 = u0 + 0.2; let ex = expi_approx(u0); let expiu1 = expi_approx(u1); ct1 / u0 * (ex - u0 / u1 * 0.81873 * expiu1) * osc0 } /// 计算 He II 碰撞电离速率。 /// /// # 参数 /// - `t`: 温度 (K) /// - `level_index`: 能级索引 (1-based, 1-10) /// - `u0`: 电离能量 / kT /// /// # 返回 /// 碰撞电离速率 pub fn colhe2_ionization(t: f64, level_index: usize, u0: f64) -> f64 { let srt = t.sqrt(); let ct = 5.465e-11 * srt; let x = t.log10(); let x2 = x * x; let x3 = x2 * x; let x4 = x3 * x; let x5 = x4 * x; let gam = if level_index <= 3 { let i = level_index - 1; G0[i] - G1[i] * t + (G2[i] / t - G3[i]) / t } else if level_index == 4 { -95.23828 + (62.656249 - 8.1454078 * x) * x } else if level_index == 5 { 472.99219 - 74.144287 * x - 1869.6562 / x2 } else if level_index == 6 { 825.17186 - 134.23096 * x - 2739.4375 / x2 } else if level_index == 7 { 1181.3516 - 200.71191 * x - 2810.7812 / x2 } else if level_index == 8 { 1440.1016 - 259.75781 * x - 1283.5625 / x2 } else if level_index == 9 { 2492.1250 - 624.84375 * x + 30.101562 * x2 } else if level_index == 10 { 4663.3129 - 1390.1250 * x + 97.671874 * x2 } else { // IC >= 1: 使用多项式拟合 let i = level_index - 1; if i < 10 { A[0][i] + A[1][i] * x + A[2][i] * x2 + A[3][i] * x3 + A[4][i] * x4 + A[5][i] * x5 } else { (level_index * level_index * level_index) as f64 } }; ct * (-u0).exp() * gam } /// 计算 He II 碰撞激发速率。 /// /// # 参数 /// - `t`: 温度 (K) /// - `i`: 下能级主量子数 /// - `j`: 上能级主量子数 /// - `u0`: 激发能量 / kT /// - `osh`: 振子强度因子 /// /// # 返回 /// 碰撞激发速率 pub fn colhe2_excitation(t: f64, i: usize, j: usize, u0: f64, osh: f64) -> f64 { let srt = t.sqrt(); let ct2 = 3.7036489 / t / srt; let xi = i as f64; let xj = j as f64; // 振子强度 let c1 = if j <= 20 { osh } else { osh * (20.0 / xj).powi(3) }; // Gaunt 因子 let mut gam = xi - (xi - 1.0) / (xj - xi); if gam > xj - xi { gam = xj - xi; } if i > 1 { gam *= 1.1; } let expiu0 = expi_approx(u0); ct2 / u0 * c1 * (0.693 * (-u0).exp() + expiu0) * gam } /// 执行 COLHE 主计算(简化版)。 /// /// # 参数 /// - `params`: 输入参数 /// /// # 返回 /// 碰撞速率结果 pub fn colhe(params: &ColheParams) -> ColheOutput { let t = params.temp; let srt = t.sqrt(); let hkt = HK / t; let tk = hkt / H; // 初始化输出 let mut col_rates = Vec::new(); // He I 碰撞电离示例(从基态) let enion_he1 = 24.587 * 1.602e-12; // eV -> erg let osc0 = 1.0; let col_ion_he1 = colhe1_ionization(t, enion_he1, osc0); col_rates.push(col_ion_he1); // He II 碰撞电离示例(从 n=1) let u0_he2 = 4.0 * 13.6 * 1.602e-12 * tk; // He II 电离能 = 4 * H let col_ion_he2 = colhe2_ionization(t, 1, u0_he2); col_rates.push(col_ion_he2); ColheOutput { col_rates } } // ============================================================================ // 测试 // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_expi_approx_small() { // 小参数 let result = expi_approx(0.5); assert!(result > 0.0); assert!(result < 2.0); // E1(0.5) ≈ 0.56 } #[test] fn test_expi_approx_large() { // 大参数 let result = expi_approx(5.0); assert!(result > 0.0); assert!(result < 0.01); // E1(5) 很小 } #[test] fn test_colhe1_ionization() { let t = 10000.0; let enion = 24.587 * 1.602e-12; // He I 电离能 let osc0 = 1.0; let result = colhe1_ionization(t, enion, osc0); assert!(result > 0.0); assert!(result.is_finite()); } #[test] fn test_colhe1_excitation_ground() { let t = 10000.0; let u0 = 20.0; // 典型激发能量 let osc0 = 0.1; let result = colhe1_excitation_ground(t, u0, osc0); assert!(result > 0.0); assert!(result.is_finite()); } #[test] fn test_colhe1_excitation_excited() { let t = 10000.0; let u0 = 5.0; // 激发态之间的跃迁 let osc0 = 0.5; let result = colhe1_excitation_excited(t, u0, osc0); assert!(result > 0.0); assert!(result.is_finite()); } #[test] fn test_colhe2_ionization() { let t = 20000.0; let tk = HK / H / t; let u0 = 4.0 * 13.6 * 1.602e-12 * tk; for level in 1..=10 { let result = colhe2_ionization(t, level, u0); assert!(result > 0.0); assert!(result.is_finite()); } } #[test] fn test_colhe2_excitation() { let t = 20000.0; let tk = HK / H / t; let u0 = 3.0; // 典型值 let osh = 1.0; let result = colhe2_excitation(t, 1, 2, u0, osh); assert!(result > 0.0); assert!(result.is_finite()); } #[test] fn test_colhe_basic() { let params = ColheParams { temp: 15000.0, nlevel_he1: 19, nlevel_he2: 10, }; let result = colhe(¶ms); assert_eq!(result.col_rates.len(), 2); assert!(result.col_rates[0] > 0.0); // He I assert!(result.col_rates[1] > 0.0); // He II } #[test] fn test_temperature_dependence() { let enion = 24.587 * 1.602e-12; let osc0 = 1.0; let col_low = colhe1_ionization(5000.0, enion, osc0); let col_high = colhe1_ionization(20000.0, enion, osc0); // 较高温度应该有更高的碰撞速率 assert!(col_high > col_low); } #[test] fn test_colhe2_level_dependence() { let t = 20000.0; let tk = HK / H / t; let u0_base = 4.0 * 13.6 * 1.602e-12 * tk; // 不同能级应该有不同的速率 let col_n1 = colhe2_ionization(t, 1, u0_base); let col_n2 = colhe2_ionization(t, 2, u0_base / 4.0); // n=2 电离能是 n=1 的 1/4 assert!(col_n1 > 0.0); assert!(col_n2 > 0.0); } }