SpectraRust/src/tlusty/math/hydrogen/colhe.rs
2026-03-25 18:34:41 +08:00

405 lines
11 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 氦原子碰撞速率计算。
//!
//! 重构自 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<f64>,
}
// ============================================================================
// 核心计算函数
// ============================================================================
/// 计算 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(&params);
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);
}
}