214 lines
6.2 KiB
Rust
214 lines
6.2 KiB
Rust
//! H⁻ 自由-自由吸收截面。
|
|
//!
|
|
//! 重构自 TLUSTY `sffhmi.f`
|
|
//!
|
|
//! 来自 Bell and Berrington J.Phys.B, vol. 20, 801-806, 1987。
|
|
//! 取自 Kurucz ATLAS9。
|
|
|
|
use crate::math::ylintp;
|
|
|
|
use std::sync::OnceLock;
|
|
|
|
/// 初始化的自由-自由数据
|
|
struct FfData {
|
|
wfflog: [f64; 22],
|
|
fflog: [[f64; 11]; 22],
|
|
}
|
|
|
|
static FF_DATA: OnceLock<FfData> = OnceLock::new();
|
|
|
|
fn get_ff_data() -> &'static FfData {
|
|
FF_DATA.get_or_init(|| {
|
|
// 波长数据 (μm)
|
|
const WAVEK: [f64; 22] = [
|
|
0.50, 0.40, 0.35, 0.30, 0.25, 0.20, 0.18, 0.16, 0.14, 0.12, 0.10, 0.09, 0.08, 0.07,
|
|
0.06, 0.05, 0.04, 0.03, 0.02, 0.01, 0.008, 0.006,
|
|
];
|
|
const THETAFF: [f64; 11] = [
|
|
0.5, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.8, 3.6,
|
|
];
|
|
|
|
// FFCS 数据 (11 x 22)
|
|
const FFBEG: [[f64; 11]; 11] = [
|
|
[
|
|
1.0178, 0.0222, 0.0308, 0.0402, 0.0498, 0.0596, 0.0695, 0.0795, 0.0896, 0.131,
|
|
0.172,
|
|
],
|
|
[
|
|
0.0228, 0.0280, 0.0388, 0.0499, 0.0614, 0.0732, 0.0851, 0.0972, 0.110, 0.160,
|
|
0.211,
|
|
],
|
|
[
|
|
0.0277, 0.0342, 0.0476, 0.0615, 0.0760, 0.0908, 0.105, 0.121, 0.136, 0.199, 0.262,
|
|
],
|
|
[
|
|
0.0364, 0.0447, 0.0616, 0.0789, 0.0966, 0.114, 0.132, 0.150, 0.169, 0.243, 0.318,
|
|
],
|
|
[
|
|
0.0520, 0.0633, 0.0859, 0.108, 0.131, 0.154, 0.178, 0.201, 0.225, 0.321, 0.418,
|
|
],
|
|
[
|
|
0.0791, 0.0959, 0.129, 0.161, 0.194, 0.227, 0.260, 0.293, 0.327, 0.463, 0.602,
|
|
],
|
|
[
|
|
0.0965, 0.117, 0.157, 0.195, 0.234, 0.272, 0.311, 0.351, 0.390, 0.549, 0.711,
|
|
],
|
|
[
|
|
0.121, 0.146, 0.195, 0.241, 0.288, 0.334, 0.381, 0.428, 0.475, 0.667, 0.861,
|
|
],
|
|
[
|
|
0.154, 0.188, 0.249, 0.309, 0.367, 0.424, 0.482, 0.539, 0.597, 0.830, 1.07,
|
|
],
|
|
[
|
|
0.208, 0.250, 0.332, 0.409, 0.484, 0.557, 0.630, 0.702, 0.774, 1.06, 1.36,
|
|
],
|
|
[
|
|
0.293, 0.354, 0.468, 0.576, 0.677, 0.777, 0.874, 0.969, 1.06, 1.45, 1.83,
|
|
],
|
|
];
|
|
const FFEND: [[f64; 11]; 11] = [
|
|
[
|
|
0.358, 0.432, 0.572, 0.702, 0.825, 0.943, 1.06, 1.17, 1.28, 1.73, 2.17,
|
|
],
|
|
[
|
|
0.448, 0.539, 0.711, 0.871, 1.02, 1.16, 1.29, 1.43, 1.57, 2.09, 2.60,
|
|
],
|
|
[
|
|
0.579, 0.699, 0.924, 1.13, 1.33, 1.51, 1.69, 1.86, 2.02, 2.67, 3.31,
|
|
],
|
|
[
|
|
0.781, 0.940, 1.24, 1.52, 1.78, 2.02, 2.26, 2.48, 2.69, 3.52, 4.31,
|
|
],
|
|
[
|
|
1.11, 1.34, 1.77, 2.17, 2.53, 2.87, 3.20, 3.51, 3.80, 4.92, 5.97,
|
|
],
|
|
[
|
|
1.73, 2.08, 2.74, 3.37, 3.90, 4.50, 5.01, 5.50, 5.95, 7.59, 9.06,
|
|
],
|
|
[
|
|
3.04, 3.65, 4.80, 5.86, 6.86, 7.79, 8.67, 9.50, 10.3, 13.2, 15.6,
|
|
],
|
|
[
|
|
6.79, 8.16, 10.7, 13.1, 15.3, 17.4, 19.4, 21.2, 23.0, 29.5, 35.0,
|
|
],
|
|
[
|
|
27.0, 32.4, 42.6, 51.9, 60.7, 68.9, 76.8, 84.2, 91.4, 117., 140.,
|
|
],
|
|
[
|
|
42.3, 50.6, 66.4, 80.8, 94.5, 107., 120., 131., 142., 183., 219.,
|
|
],
|
|
[
|
|
75.1, 90.0, 118., 144., 168., 191., 212., 234., 253., 325., 388.,
|
|
],
|
|
];
|
|
|
|
// 合并 FFBEG 和 FFEND 成 FFCS (11 x 22)
|
|
// EQUIVALENCE (FFCS(1,1),FFBEG(1,1)),(FFCS(1,12),FFEND(1,1))
|
|
let mut ffcs = [[0.0; 22]; 11];
|
|
for i in 0..11 {
|
|
for j in 0..11 {
|
|
ffcs[i][j] = FFBEG[i][j];
|
|
}
|
|
for j in 0..11 {
|
|
ffcs[i][j + 11] = FFEND[i][j];
|
|
}
|
|
}
|
|
|
|
// 计算对数
|
|
let mut wfflog = [0.0; 22];
|
|
let mut fflog = [[0.0; 11]; 22];
|
|
|
|
for iwave in 0..22 {
|
|
wfflog[iwave] = (91.134 / WAVEK[iwave]).ln();
|
|
for itheta in 0..11 {
|
|
fflog[iwave][itheta] = (ffcs[itheta][iwave] * 1e-26).ln();
|
|
}
|
|
}
|
|
|
|
FfData { wfflog, fflog }
|
|
})
|
|
}
|
|
|
|
/// H⁻ 自由-自由吸收截面。
|
|
///
|
|
/// 计算负氢离子的自由-自由吸收截面。
|
|
///
|
|
/// # 参数
|
|
///
|
|
/// * `popi` - H⁻ 粒子数密度
|
|
/// * `fr` - 频率 (Hz)
|
|
/// * `t` - 温度 (K)
|
|
///
|
|
/// # 返回值
|
|
///
|
|
/// H⁻ 自由-自由吸收系数。
|
|
///
|
|
/// # 备注
|
|
///
|
|
/// 数据来自 Bell and Berrington J.Phys.B, vol. 20, 801-806, 1987。
|
|
pub fn sffhmi(popi: f64, fr: f64, t: f64) -> f64 {
|
|
const CONFF: f64 = 5040.0 * 1.380658e-16;
|
|
const CONTH: f64 = 5040.0;
|
|
const HK: f64 = 4.79928144e-11;
|
|
|
|
const THETAFF: [f64; 11] = [
|
|
0.5, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.8, 3.6,
|
|
];
|
|
|
|
let data = get_ff_data();
|
|
|
|
let wave = 2.99792458e17 / fr;
|
|
let wavelog = wave.ln();
|
|
|
|
// 对每个 theta 值进行插值
|
|
let mut fftt = [0.0; 11];
|
|
for itheta in 0..11 {
|
|
let fflog2: Vec<f64> = (0..22).map(|iw| data.fflog[iw][itheta]).collect();
|
|
let fftlog = ylintp(&data.wfflog, &fflog2, wavelog);
|
|
fftt[itheta] = fftlog.exp() / THETAFF[itheta] * CONFF;
|
|
}
|
|
|
|
// 对温度进行插值
|
|
let theta = CONTH / t;
|
|
let ffth = ylintp(&THETAFF, &fftt, theta);
|
|
|
|
ffth * popi / (1.0 - (-HK * fr / t).exp())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_sffhmi_basic() {
|
|
// 基本测试
|
|
let result = sffhmi(1e10, 5e14, 6000.0);
|
|
assert!(result.is_finite());
|
|
assert!(result > 0.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sffhmi_uv() {
|
|
// 紫外范围
|
|
let result = sffhmi(1e10, 1e15, 8000.0);
|
|
assert!(result.is_finite());
|
|
assert!(result > 0.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sffhmi_visible() {
|
|
// 可见光范围
|
|
let result = sffhmi(1e10, 5e14, 5000.0);
|
|
assert!(result.is_finite());
|
|
assert!(result > 0.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sffhmi_scaling() {
|
|
// 应随 popi 线性增加
|
|
let r1 = sffhmi(1e10, 5e14, 6000.0);
|
|
let r2 = sffhmi(2e10, 5e14, 6000.0);
|
|
assert!((r2 / r1 - 2.0).abs() < 0.01);
|
|
}
|
|
}
|