SpectraRust/src/math/vern20.rs
2026-03-21 09:12:18 +08:00

175 lines
4.8 KiB
Rust

//! 钙离子光电离截面 (Verner 1996)。
//!
//! 重构自 TLUSTY `vern20.f`
//!
//! 参考:
//! - Verner D.A. et al. 1996, ApJ 465
//! - Verner & Yakovlev 1995, A&AS 109, 125
use crate::state::constants::{HALF, UN};
// ============================================================================
// VERN20 - 钙离子光电离截面
// ============================================================================
const T18: f64 = 1e-18;
const MVER: usize = 20;
// 1996 参数
static S0: [f64; MVER] = [
5.37e5, 1.064e7, 3.815e1, 7.736, 1.523e-1, 7.642e1, 4.76e-1,
6.641e-1, 2.076e2, 1.437e1, 9.384e-1, 1.227e1, 1.849e3,
1.116, 5.513e1, 1.293, 2.028e4, 1.105e1, 1.936e1, 1.369e2
];
static E0: [f64; MVER] = [
12.78, 15.53, 24.36, 4.255, 0.6882, 9.515, 0.808, 1.366, 0.0552,
16.05, 0.2288, 23.45, 10.08, 9.98, 130.9, 4.293, 26.18, 94.72,
629.7, 172.9
];
static EMX: [f64; MVER] = [
34.43, 40.9, 373.1, 394.4, 417.5, 442.3, 468.7, 496.7, 527.,
556.9, 4265., 4362., 4453., 4555., 4659., 4767., 4880., 4982.,
5e4, 5e4
];
static Y0: [f64; MVER] = [
1.012e-3, 2.161e-3, 1.802, 14.67, 121., 4.829, 148.7, 103.9,
2.826e-4, 0., 24.78, 24.17, 6.138e-3, 71.04, 1.833e-2, 0.9363,
2.402e-2, 0., 0., 0.
];
static Y1: [f64; MVER] = [
1.851e-2, 6.706e-2, 1.233, 3.298e-2, 3.876, 5.824, 1.283, 3.329,
1.657, 0., 3.1, 0.5469, 69.31, 5.311, 0.9359, 4.589e-2, 9.323e-3,
0., 0., 0.
];
static YW: [f64; MVER] = [
0.4477, 0.6453, 0.3126, 1.369, 8.277, 2.471, 0.572, 0.2806,
1.843e-3, 0., 1.39, 6.842e-4, 241., 3.879, 9.084e-2, 3.461e-5,
28.03, 0., 0., 0.
];
static YA: [f64; MVER] = [
0.3162, 0.779, 293.1, 13.55, 150.2, 89.73, 368.2, 318.8, 1.79e4,
698.9, 254.9, 13.12, 1.792e4, 59.18, 382.8, 16.91, 1.456, 38.18,
39.21, 32.88
];
static PV: [f64; MVER] = [
12.42, 21.3, 3.944, 12.36, 10.61, 5.141, 8.634, 8.138, 5.893,
3.857, 11.03, 9.771, 2.868, 9.005, 2.023, 14.38, 25.6, 4.192,
1.862, 2.963
];
// 1995 参数 (高能)
static S95: [f64; MVER] = [
9.017e1, 7.314e1, 1.945e2, 1.542e2, 1.622e2, 1.855e2, 2.181e2,
2.788e2, 1.934e2, 6.616e2, 1.547e1, 1.324e1, 1.57e1, 1.384e1,
1.417e1, 1.665e1, 1.486e1, 1.82e1, 1.936e1, 1.369e2
];
static E95: [f64; MVER] = [
44.87, 44.98, 126., 141.3, 138.4, 130.3, 120.8, 107., 129.3,
65.11, 701., 750.3, 698.9, 739.6, 734.2, 686.2, 723.5, 664.,
629.7, 172.9
];
static Y95: [f64; MVER] = [
14.65, 18.98, 68.19, 99.06, 88.11, 69.93, 58.16, 47.68, 70.,
43.71, 31.97, 50., 32.18, 50., 50., 34.43, 50., 39.79, 39.21,
32.88
];
static YW95: [f64; MVER] = [
0.2754, 0.2735, 4.791e-4, 1.107e-3, 4.384e-4, 1.4e-5,
4.346e-6, 4.591e-6, 0.1, 7.881e-6, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
];
static P95: [f64; MVER] = [
7.498, 7.152, 3.77, 3.446, 3.521, 3.707, 3.907, 4.2, 3.7, 4.937,
1.858, 1.65, 1.851, 1.65, 1.65, 1.823, 1.65, 1.777, 1.862,
2.963
];
/// 计算钙离子基态光电离截面。
///
/// # 参数
///
/// - `e` - 光子能量 (Rydberg)
/// - `izz` - 离子电荷 (1-20, 对应 Ca I - Ca XX)
///
/// # 返回
///
/// 光电离截面 (cm²)
pub fn vern20(e: f64, izz: usize) -> f64 {
if izz == 0 || izz > MVER {
return 0.0;
}
let iver = izz - 1;
if e < EMX[iver] {
let xx = e / E0[iver] - Y0[iver];
let yy = (xx * xx + Y1[iver] * Y1[iver]).sqrt();
let aa = (xx - UN) * (xx - UN) + YW[iver] * YW[iver];
let bb = yy.powf(HALF * PV[iver] - 5.5);
let cc = (UN + (yy / YA[iver]).sqrt()).powf(PV[iver]);
let fy = aa * bb / cc;
S0[iver] * T18 * fy
} else {
let yy = e / E95[iver];
let xl = if izz <= 10 { UN } else { 0.0 };
let q = HALF * P95[iver] - 5.5 - xl;
let aa = (yy - UN) * (yy - UN) + YW95[iver] * YW95[iver];
let bb = yy.powf(q);
let cc = (UN + (yy / Y95[iver]).sqrt()).powf(P95[iver]);
let fy = aa * bb / cc;
S95[iver] * T18 * fy
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vern20_ca_ii() {
let izz = 2;
let e = E0[izz - 1];
let sigma = vern20(e, izz);
assert!(sigma > 0.0);
}
#[test]
fn test_vern20_ca_i_low_energy() {
let izz = 1;
let e = 10.0;
let sigma = vern20(e, izz);
assert!(sigma > 0.0);
}
#[test]
fn test_vern20_ca_i_high_energy() {
let izz = 1;
let e = 50.0; // 高于 EMX[0] = 34.43
let sigma = vern20(e, izz);
assert!(sigma > 0.0);
}
#[test]
fn test_vern20_invalid_izz() {
assert_eq!(vern20(10.0, 0), 0.0);
assert_eq!(vern20(10.0, 21), 0.0);
}
#[test]
fn test_vern20_decreasing_with_energy() {
let izz = 3;
let sigma_low = vern20(50.0, izz);
let sigma_high = vern20(200.0, izz);
assert!(sigma_low > sigma_high);
}
}