160 lines
3.8 KiB
Rust
160 lines
3.8 KiB
Rust
//! ODF Stark 展宽辅助函数。
|
||
//!
|
||
//! 重构自 TLUSTY `odfhst.f`
|
||
//!
|
||
//! 用于 ODF1 的辅助例程,替代多次调用 STARKA。
|
||
|
||
use crate::state::constants::{TWO, UN};
|
||
use crate::state::model::StrAux;
|
||
use crate::state::odfpar::MFRO;
|
||
|
||
/// ODF Stark 展宽辅助函数。
|
||
///
|
||
/// 用于 ODF1 的辅助例程,计算 Stark 展宽的线轮廓。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `n` - 频率点数
|
||
/// * `fxk` - 线宽参数
|
||
/// * `fid` - 振子强度
|
||
/// * `wp` - 权重
|
||
/// * `wl` - 波长
|
||
/// * `alam` - 频率数组
|
||
/// * `straux` - Stark 展宽参数
|
||
/// * `sg` - 输出:Stark 展宽数组
|
||
///
|
||
/// # 示例
|
||
///
|
||
/// ```
|
||
/// use tlusty_rust::math::odfhst::odfhst;
|
||
/// use tlusty_rust::state::model::StrAux;
|
||
///
|
||
/// let straux = StrAux::default();
|
||
/// let alam = vec![1.0, 2.0, 3.0];
|
||
/// let mut sg = vec![0.0; 3];
|
||
///
|
||
/// odfhst(3, 1.0, 0.5, 1.0, 1215.0, &alam, &straux, &mut sg);
|
||
/// ```
|
||
pub fn odfhst(
|
||
n: usize,
|
||
fxk: f64,
|
||
fid: f64,
|
||
wp: f64,
|
||
wl: f64,
|
||
alam: &[f64],
|
||
straux: &StrAux,
|
||
sg: &mut [f64],
|
||
) {
|
||
// 常数参数
|
||
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 THR: f64 = THRA * TWO;
|
||
|
||
let betad = straux.betad;
|
||
let adh = straux.adh;
|
||
let divh = straux.divh;
|
||
|
||
// 防止除零
|
||
let betad1 = if betad.abs() > 1e-30 { UN / betad } else { 0.0 };
|
||
let fxk1 = if fxk.abs() > 1e-30 { UN / fxk } else { 0.0 };
|
||
let fidwp = fid * wp;
|
||
|
||
// for a > 1 Doppler core + asymptotic Holtzmark wing with division point DIV
|
||
if adh > AL {
|
||
for ij in 0..n {
|
||
let beta = (alam[ij] - wl).abs() * fxk1;
|
||
let xd = beta * betad1;
|
||
|
||
let st = if xd <= divh {
|
||
SD * (-xd * xd).exp() * betad1
|
||
} else {
|
||
THR * beta.powf(SLO)
|
||
};
|
||
|
||
sg[ij] = st * fidwp;
|
||
}
|
||
} else {
|
||
// empirical formula for a < 1
|
||
for ij in 0..n {
|
||
let beta = (alam[ij] - wl).abs() * fxk1;
|
||
let xd = beta * betad1;
|
||
|
||
let st = if beta <= BL1 {
|
||
SAC
|
||
} else if beta < BL2 {
|
||
let xl = beta.ln();
|
||
let fl = (F0 * xl + F1) * xl;
|
||
F2 * fl.exp()
|
||
} else {
|
||
THR * beta.powf(SLO)
|
||
};
|
||
|
||
sg[ij] = st * fidwp;
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_odfhst_adh_gt_al() {
|
||
let mut straux = StrAux::default();
|
||
straux.adh = 2.0; // > AL = 1.26
|
||
straux.betad = 1.0;
|
||
straux.divh = 1.0;
|
||
|
||
let alam = vec![1200.0, 1215.0, 1230.0];
|
||
let mut sg = vec![0.0; 3];
|
||
|
||
odfhst(3, 1.0, 0.5, 1.0, 1215.0, &alam, &straux, &mut sg);
|
||
|
||
// 中间点(wl=1215.0)应该有最大值
|
||
assert!(sg[1] > sg[0]);
|
||
assert!(sg[1] > sg[2]);
|
||
}
|
||
|
||
#[test]
|
||
fn test_odfhst_adh_lt_al() {
|
||
let mut straux = StrAux::default();
|
||
straux.adh = 0.5; // < AL = 1.26
|
||
straux.betad = 1.0;
|
||
straux.divh = 1.0;
|
||
|
||
let alam = vec![1200.0, 1215.0, 1230.0];
|
||
let mut sg = vec![0.0; 3];
|
||
|
||
odfhst(3, 1.0, 0.5, 1.0, 1215.0, &alam, &straux, &mut sg);
|
||
|
||
// 所有值应该是正的
|
||
for &s in &sg {
|
||
assert!(s >= 0.0);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_odfhst_zero_betad() {
|
||
let mut straux = StrAux::default();
|
||
straux.adh = 2.0;
|
||
straux.betad = 0.0; // 零值
|
||
straux.divh = 1.0;
|
||
|
||
let alam = vec![1200.0, 1215.0, 1230.0];
|
||
let mut sg = vec![0.0; 3];
|
||
|
||
// 不应该 panic
|
||
odfhst(3, 1.0, 0.5, 1.0, 1215.0, &alam, &straux, &mut sg);
|
||
}
|
||
}
|