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

212 lines
5.8 KiB
Rust

//! 硫离子光电离截面 (Verner 1996)。
//!
//! 重构自 TLUSTY `vern16.f`
//!
//! 参考:
//! - Verner D.A. et al. 1996, ApJ 465
//! - Verner & Yakovlev 1995, A&AS 109, 125
use crate::tlusty::state::constants::{HALF, UN};
// ============================================================================
// VERN16 - 硫离子光电离截面
// ============================================================================
const T18: f64 = 1e-18;
const MVER: usize = 16;
// 1996 参数
static S0: [f64; MVER] = [
4.564e4, 3.136e2, 6.666, 2.606, 5.072e-4, 9.139, 5.703e-1,
3.161e1, 9.646e3, 5.364e1, 1.275e1, 3.49e-1, 2.294e4, 2.555e1,
2.453e1, 2.139e2
];
static E0: [f64; MVER] = [
18.08, 8.787, 2.027, 2.173, 0.1713, 14.13, 0.3757, 14.62, 0.1526,
10.4, 6.485, 2.443, 14.74, 33.1, 439., 110.4
];
static EMX: [f64; MVER] = [
170., 184.6, 199.5, 216.4, 235., 255.7, 2569., 2641., 2705.,
2782., 2859., 2941., 3029., 3107., 5e4, 5e4
];
static Y0: [f64; MVER] = [
0.9935, 2.782, 15.68, 19.75, 94.24, 0., 222.2, 18.69, 1.615e-3,
17.75, 34.26, 227.9, 2.203e-2, 0., 0., 0.
];
static Y1: [f64; MVER] = [
0.2486, 0.1788, 9.421, 3.361, 0.6265, 0., 4.606, 0.3037, 0.4049,
1.663, 0.137, 1.172, 1.073e-2, 0., 0., 0.
];
static YW: [f64; MVER] = [
0.6385, 0.7354, 4.109, 1.863, 0.788, 0., 1.503, 1.153e-3, 1.492,
2.31, 1.678, 0.7033, 27.38, 0., 0., 0.
];
static YA: [f64; MVER] = [
1., 3.442, 54.54, 66.41, 198.6, 1656., 146., 16.11, 1438., 36.41,
65.83, 541.1, 1.529, 38.21, 44.05, 32.88
];
static PV: [f64; MVER] = [
13.61, 12.81, 8.611, 8.655, 13.07, 3.626, 11.35, 8.642, 5.977,
7.09, 7.692, 7.769, 25.68, 5.037, 1.765, 2.963
];
// 1995 参数 (高能)
static S95: [f64; MVER] = [
1.883e2, 1.896e2, 1.780e2, 2.037e2, 2.919e2, 4.712e2, 1.916e1,
1.931e1, 1.946e1, 2.041e1, 2.101e1, 2.087e1, 2.233e1, 2.293e1,
2.453e1, 2.139e2
];
static E95: [f64; MVER] = [
91.52, 90.58, 92.46, 87.44, 74.11, 57.47, 495.2, 489.1, 493.7,
480.2, 475.8, 482.8, 466.9, 466.7, 439., 110.4
];
static Y95: [f64; MVER] = [
71.93, 75.38, 149.8, 93.1, 48.64, 36.1, 35.55, 50., 35.68, 50.,
50., 37.42, 50., 44.59, 44.05, 32.88
];
static YW95: [f64; MVER] = [
0.2485, 0.2934, 0.02142, 9.497e-3, 0.02785, 0.0248,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
];
static P95: [f64; MVER] = [
3.633, 3.635, 3.319, 3.565, 4.142, 4.742, 1.742, 1.65, 1.737,
1.65, 1.65, 1.72, 1.65, 1.668, 1.765, 2.963
];
/// 计算硫离子基态光电离截面。
///
/// # 参数
///
/// - `e` - 光子能量 (Rydberg)
/// - `izz` - 离子电荷 (1-16, 对应 S I - S XVI)
///
/// # 返回
///
/// 光电离截面 (cm²)
///
/// # Fortran 原始代码
///
/// ```fortran
/// FUNCTION VERN16(E,IZZ)
/// ...
/// IVER=IZZ
/// IF(E.LT.EMX(IVER)) THEN
/// ! 1996 Expression
/// XX=E/E0(IVER)-Y0(IVER)
/// YY=SQRT(XX*XX+Y1(IVER)*Y1(IVER))
/// AA=(XX-UN)*(XX-UN)+YW(IVER)*YW(IVER)
/// BB=YY**(HALF*PV(IVER)-5.5)
/// CC=(UN+SQRT(YY/YA(IVER)))**PV(IVER)
/// FY=AA*BB/CC
/// VERN16=S0(IVER)*T18*FY
/// ELSE
/// ! 1995 Expression for high energies
/// YY=E/E95(IVER)
/// XL=0.
/// IF(IZZ.LE.6) XL=UN
/// Q=HALF*P95(IVER)-5.5-XL
/// AA=(YY-UN)*(YY-UN)+YW95(IVER)*YW95(IVER)
/// BB=YY**Q
/// CC=(UN+SQRT(YY/Y95(IVER)))**P95(IVER)
/// FY=AA*BB/CC
/// VERN16=S95(IVER)*T18*FY
/// END IF
/// END
/// ```
pub fn vern16(e: f64, izz: usize) -> f64 {
// Fortran: IZZ = 1..16 → Rust: izz = 0..15
if izz == 0 || izz > MVER {
return 0.0;
}
let iver = izz - 1; // 转换为 0-indexed
if e < EMX[iver] {
// 1996 表达式
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 {
// 1995 高能表达式 (内壳层电离)
let yy = e / E95[iver];
let xl = if izz <= 6 { 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_vern16_s_ii() {
// S II (izz=2) 在阈值附近
let izz = 2;
let e = E0[izz - 1]; // 阈值能量
let sigma = vern16(e, izz);
assert!(sigma > 0.0, "sigma should be positive at threshold");
}
#[test]
fn test_vern16_s_i_low_energy() {
// S I (izz=1) 低能区
let izz = 1;
let e = 10.0; // 低于 EMX[0] = 170
let sigma = vern16(e, izz);
assert!(sigma > 0.0, "sigma should be positive");
}
#[test]
fn test_vern16_s_i_high_energy() {
// S I (izz=1) 高能区
let izz = 1;
let e = 200.0; // 高于 EMX[0] = 170
let sigma = vern16(e, izz);
assert!(sigma > 0.0, "sigma should be positive");
}
#[test]
fn test_vern16_zero_energy() {
// 零能量
let sigma = vern16(0.0, 1);
assert!(sigma >= 0.0);
}
#[test]
fn test_vern16_invalid_izz() {
// 无效的 izz
let sigma = vern16(10.0, 0); // 0 无效
assert_eq!(sigma, 0.0);
let sigma = vern16(10.0, 17); // 17 超出范围
assert_eq!(sigma, 0.0);
}
#[test]
fn test_vern16_decreasing_with_energy() {
// 截面应该随能量增加而减小
let izz = 1;
let sigma_low = vern16(20.0, izz);
let sigma_high = vern16(100.0, izz);
assert!(sigma_low > sigma_high, "sigma should decrease with energy");
}
}