181 lines
4.9 KiB
Rust
181 lines
4.9 KiB
Rust
//! 氢线 Stark 展宽近似表达式。
|
||
//!
|
||
//! 重构自 TLUSTY `starka.f`。
|
||
//!
|
||
//! 当温度或电子密度超出 Lemke 表格范围时,使用近似表达式计算氢线 Stark 轮廓。
|
||
|
||
// ============================================================================
|
||
// 常量参数
|
||
// ============================================================================
|
||
|
||
const F0: f64 = -0.5758228;
|
||
const F1: f64 = 0.4796232;
|
||
const F2: f64 = 0.07209481;
|
||
const AL: f64 = 1.26;
|
||
|
||
const SD: f64 = 0.5641895;
|
||
const SLO: f64 = -2.5;
|
||
const THRA: f64 = 1.5;
|
||
const BL1: f64 = 1.14;
|
||
const BL2: f64 = 11.4;
|
||
|
||
const SAC: f64 = 0.08;
|
||
const PISQ1: f64 = 1.0 / 1.77245385090551; // 1 / sqrt(pi)
|
||
|
||
// ============================================================================
|
||
// STARKA - Stark 展宽近似表达式
|
||
// ============================================================================
|
||
|
||
/// 计算氢线 Stark 展宽的近似表达式。
|
||
///
|
||
/// 当温度或电子密度超出 Lemke 表格范围时使用。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// - `beta` - 以 β 单位表示的波长位移 (Δλ/β)
|
||
/// - `fac` - 乘法因子 (H I 为 2.0,He II 为 1.0)
|
||
/// - `adh` - 辅助参数 A = 1.5*ln(BETAD) - 1.761
|
||
/// - `betad` - 以 β 单位表示的 Doppler 宽度
|
||
/// - `divh` - Doppler 核心与 Stark 翼的分界点 (以 betad 为单位)
|
||
///
|
||
/// # 返回
|
||
///
|
||
/// Stark 轮廓值 S(β)
|
||
///
|
||
/// # Fortran 原始代码
|
||
///
|
||
/// ```fortran
|
||
/// FUNCTION STARKA(BETA,FAC)
|
||
/// ...
|
||
/// BETAD1=UN/BETAD
|
||
/// IF(ADH.GT.AL) THEN
|
||
/// XD=BETA*BETAD1
|
||
/// IF(XD.LE.DIVH) THEN
|
||
/// STARKA=EXP(-XD*XD)*BETAD1*PISQ1
|
||
/// ELSE
|
||
/// STARKA=THRA*FAC*EXP(SLO*LOG(BETA))
|
||
/// END IF
|
||
/// ELSE
|
||
/// IF(BETA.LE.BL1) THEN
|
||
/// STARKA=SAC
|
||
/// ELSE IF(BETA.LT.BL2) THEN
|
||
/// XL=LOG(BETA)
|
||
/// FL=(F0*XL+F1)*XL
|
||
/// STARKA=F2*EXP(FL)
|
||
/// ELSE
|
||
/// STARKA=THRA*FAC*EXP(SLO*LOG(BETA))
|
||
/// END IF
|
||
/// END IF
|
||
/// END
|
||
/// ```
|
||
pub fn starka(beta: f64, fac: f64, adh: f64, betad: f64, divh: f64) -> f64 {
|
||
let betad1 = 1.0 / betad;
|
||
|
||
if adh > AL {
|
||
// a > 1: Doppler 核心 + 渐近 Holtsmark 翼
|
||
let xd = beta * betad1;
|
||
if xd <= divh {
|
||
// Doppler 核心
|
||
(-xd * xd).exp() * betad1 * PISQ1
|
||
} else {
|
||
// 渐近 Holtsmark 翼
|
||
THRA * fac * beta.powf(SLO)
|
||
}
|
||
} else {
|
||
// a < 1: 经验公式
|
||
if beta <= BL1 {
|
||
SAC
|
||
} else if beta < BL2 {
|
||
let xl = beta.ln();
|
||
let fl = (F0 * xl + F1) * xl;
|
||
F2 * fl.exp()
|
||
} else {
|
||
THRA * fac * beta.powf(SLO)
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_starka_doppler_core() {
|
||
// a > 1, xd <= divh: Doppler 核心
|
||
let adh = 2.0; // > AL = 1.26
|
||
let betad = 10.0;
|
||
let divh = 5.0;
|
||
let beta = 30.0; // xd = 30/10 = 3 <= 5
|
||
|
||
let result = starka(beta, 2.0, adh, betad, divh);
|
||
|
||
// 应该是 Doppler 核心值
|
||
let xd = beta / betad;
|
||
let expected = (-xd * xd).exp() / betad * PISQ1;
|
||
assert!((result - expected).abs() < 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_starka_holtsmark_wing() {
|
||
// a > 1, xd > divh: Holtsmark 翼
|
||
let adh = 2.0;
|
||
let betad = 10.0;
|
||
let divh = 5.0;
|
||
let beta = 100.0; // xd = 100/10 = 10 > 5
|
||
|
||
let result = starka(beta, 2.0, adh, betad, divh);
|
||
|
||
// 应该是 Holtsmark 翼值
|
||
let expected = THRA * 2.0 * beta.powf(SLO);
|
||
assert!((result - expected).abs() < 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_starka_empirical_low_beta() {
|
||
// a <= 1, beta <= BL1
|
||
let adh = 0.5; // < AL
|
||
let result = starka(0.5, 2.0, adh, 10.0, 5.0);
|
||
assert!((result - SAC).abs() < 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_starka_empirical_mid_beta() {
|
||
// a <= 1, BL1 < beta < BL2
|
||
let adh = 0.5;
|
||
let beta = 5.0; // 1.14 < 5.0 < 11.4
|
||
let result = starka(beta, 2.0, adh, 10.0, 5.0);
|
||
|
||
let xl = beta.ln();
|
||
let fl = (F0 * xl + F1) * xl;
|
||
let expected = F2 * fl.exp();
|
||
assert!((result - expected).abs() < 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_starka_empirical_high_beta() {
|
||
// a <= 1, beta >= BL2
|
||
let adh = 0.5;
|
||
let beta = 20.0; // > 11.4
|
||
let result = starka(beta, 2.0, adh, 10.0, 5.0);
|
||
|
||
let expected = THRA * 2.0 * beta.powf(SLO);
|
||
assert!((result - expected).abs() < 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_starka_factor_difference() {
|
||
// 测试不同 fac 值的影响
|
||
let adh = 2.0;
|
||
let betad = 10.0;
|
||
let divh = 5.0;
|
||
let beta = 100.0;
|
||
|
||
let result_hi = starka(beta, 2.0, adh, betad, divh);
|
||
let result_he = starka(beta, 1.0, adh, betad, divh);
|
||
|
||
// fac 越大,结果越大
|
||
assert!(result_hi > result_he);
|
||
assert!((result_hi / result_he - 2.0).abs() < 1e-10);
|
||
}
|
||
}
|