178 lines
4.4 KiB
Rust
178 lines
4.4 KiB
Rust
//! Griem Stark 阻尼参数计算。
|
||
//!
|
||
//! 重构自 SYNSPEC `griem.f`
|
||
//!
|
||
//! 从输入的 Stark 宽度值计算 Stark 阻尼参数 (GAM)。
|
||
//! 输入值对应 T=5000, 10000, 20000, 40000 K,
|
||
//! 以及 NE=1e16 (中性原子) 或 NE=1e17 (离子)。
|
||
|
||
/// Griem 计算所需的模型层参数。
|
||
#[derive(Debug, Clone)]
|
||
pub struct GriemParams {
|
||
/// 温度插值索引 (JT)
|
||
pub jt: usize,
|
||
/// 温度插值系数 0
|
||
pub ti0: f64,
|
||
/// 温度插值系数 1
|
||
pub ti1: f64,
|
||
/// 温度插值系数 2
|
||
pub ti2: f64,
|
||
}
|
||
|
||
/// 计算 Griem Stark 阻尼参数 GAM。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `t` - 温度 (K),如果 <= 0 则返回 0
|
||
/// * `ane` - 电子数密度
|
||
/// * `ion` - 电离级数 (1=中性, 2=一次电离, ...)
|
||
/// * `fr` - 频率相关因子
|
||
/// * `wgr` - Stark 宽度数组 [W@5000K, W@10000K, W@20000K, W@40000K]
|
||
/// * `params` - 模型层插值参数
|
||
///
|
||
/// # 返回值
|
||
///
|
||
/// Stark 阻尼参数 GAM
|
||
///
|
||
/// # 算法
|
||
///
|
||
/// ```text
|
||
/// GAM = (插值后的WGR) * ANE * 1e-10 * FR * 1e-10 * FR * 4.2e-14
|
||
/// 如果 ION > 1: GAM = GAM * 0.1
|
||
/// 如果 GAM < 0: GAM = 0
|
||
/// ```
|
||
pub fn griem(t: f64, ane: f64, ion: i32, fr: f64, wgr: &[f64; 4], params: &GriemParams) -> f64 {
|
||
// 温度检查
|
||
if t <= 0.0 {
|
||
return 0.0;
|
||
}
|
||
|
||
// 温度插值
|
||
let jt_idx = params.jt; // 已是 0-indexed
|
||
|
||
// 插值计算 Stark 宽度
|
||
let w_interp = params.ti0 * wgr[jt_idx]
|
||
+ params.ti1 * wgr[jt_idx - 1]
|
||
+ params.ti2 * wgr[jt_idx - 2];
|
||
|
||
// 计算 GAM
|
||
let mut gam = w_interp * ane * 1e-10 * fr * 1e-10 * fr * 4.2e-14;
|
||
|
||
// 离子的修正
|
||
if ion > 1 {
|
||
gam *= 0.1;
|
||
}
|
||
|
||
// 确保非负
|
||
gam.max(0.0)
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
use approx::assert_relative_eq;
|
||
|
||
fn make_params(jt: usize) -> GriemParams {
|
||
GriemParams {
|
||
jt,
|
||
ti0: 1.0,
|
||
ti1: 0.0,
|
||
ti2: 0.0,
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_basic() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
assert!(gam >= 0.0);
|
||
assert!(gam.is_finite());
|
||
}
|
||
|
||
#[test]
|
||
fn test_zero_temperature() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam = griem(0.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
assert_relative_eq!(gam, 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_negative_temperature() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam = griem(-100.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
assert_relative_eq!(gam, 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_ion_correction() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam_neutral = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
let gam_ion = griem(10000.0, 1e13, 2, 1.0, &wgr, ¶ms);
|
||
|
||
// 离子的 GAM 应该是中性的 0.1 倍
|
||
assert_relative_eq!(gam_ion, 0.1 * gam_neutral, epsilon = 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_density_scaling() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam1 = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
let gam2 = griem(10000.0, 2e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
// 密度翻倍,GAM 应该翻倍
|
||
assert_relative_eq!(gam2, 2.0 * gam1, epsilon = 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_fr_scaling() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam1 = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
let gam2 = griem(10000.0, 1e13, 1, 2.0, &wgr, ¶ms);
|
||
|
||
// FR 翻倍,GAM 应该是 4 倍 (因为 FR^2)
|
||
assert_relative_eq!(gam2, 4.0 * gam1, epsilon = 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_temperature_interpolation() {
|
||
let params = make_params(2);
|
||
let wgr = [1.0, 2.0, 4.0, 8.0]; // 不同的温度宽度
|
||
|
||
let gam = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
// jt=2 使用 wgr[2]=4.0
|
||
assert!(gam > 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_negative_result_clamped() {
|
||
let params = GriemParams {
|
||
jt: 2,
|
||
ti0: -1.0, // 负系数
|
||
ti1: 0.0,
|
||
ti2: 0.0,
|
||
};
|
||
let wgr = [1.0, 1.0, 1.0, 1.0];
|
||
|
||
let gam = griem(10000.0, 1e13, 1, 1.0, &wgr, ¶ms);
|
||
|
||
// 负值应该被钳制为 0
|
||
assert_relative_eq!(gam, 0.0);
|
||
}
|
||
}
|