221 lines
5.8 KiB
Rust
221 lines
5.8 KiB
Rust
//! 氢线 Stark 展宽表格插值。
|
|
//!
|
|
//! 重构自 TLUSTY `inthyd.f`。
|
|
//!
|
|
//! 从 Lemke 表格中插值计算氢线的 Stark 展宽轮廓。
|
|
|
|
use crate::tlusty::math::{divstr, starka, yint};
|
|
use crate::tlusty::state::HydPrf;
|
|
|
|
// ============================================================================
|
|
// INTHYD - 氢线表格插值
|
|
// ============================================================================
|
|
|
|
/// 从 Lemke 表格插值计算氢线 Stark 展宽轮廓。
|
|
///
|
|
/// 在温度和电子密度方向上进行二维插值。
|
|
///
|
|
/// # 参数
|
|
///
|
|
/// - `x0` - log10(温度)
|
|
/// - `z0` - log10(电子密度)
|
|
/// - `iwl` - 波长索引 (0-indexed)
|
|
/// - `iline` - 谱线索引 (0-indexed)
|
|
/// - `hydprf` - 氢线表格数据
|
|
/// - `dbeta` - Doppler 宽度 (β 单位)
|
|
/// - `xk` - 参考波数
|
|
///
|
|
/// # 返回
|
|
///
|
|
/// log10(轮廓值)
|
|
///
|
|
/// # Fortran 原始代码
|
|
///
|
|
/// ```fortran
|
|
/// SUBROUTINE INTHYD(W0,X0,Z0,IWL,ILINE)
|
|
/// ...
|
|
/// END
|
|
/// ```
|
|
pub fn inthyd(
|
|
x0: f64,
|
|
z0: f64,
|
|
iwl: usize,
|
|
iline: usize,
|
|
hydprf: &HydPrf,
|
|
dbeta: f64,
|
|
xk: f64,
|
|
) -> f64 {
|
|
let nt = hydprf.nth[iline] as usize;
|
|
let ne = hydprf.neh[iline] as usize;
|
|
let beta = hydprf.get_wlh(iwl, iline) / xk;
|
|
let izh = 1; // H I
|
|
|
|
// 检查是否低于最低电子密度网格值
|
|
// 对于低于最低网格值的情况,使用近似表达式 (starka)
|
|
let xnelem_min = hydprf.get_xnelem(0, iline);
|
|
if z0 < xnelem_min * 0.99 {
|
|
let (adh, divh) = divstr(dbeta, izh);
|
|
let stark_val = starka(beta, 2.0, adh, dbeta, divh);
|
|
return (stark_val * dbeta).log10();
|
|
}
|
|
|
|
// 查找电子密度插值区间
|
|
let mut ipz = 0;
|
|
for izz in 0..(ne - 1) {
|
|
ipz = izz;
|
|
if z0 <= hydprf.get_xnelem(izz + 1, iline) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 确定插值窗口
|
|
let nz = 2;
|
|
let mut n0z = ipz as i32 - (nz as i32 / 2) + 1;
|
|
if n0z < 1 {
|
|
n0z = 1;
|
|
}
|
|
if n0z > (ne - nz + 1) as i32 {
|
|
n0z = (ne - nz + 1) as i32;
|
|
}
|
|
let n1z = n0z + nz as i32 - 1;
|
|
|
|
// 准备插值数组
|
|
let mut zz = [0.0; 3];
|
|
let mut wz = [0.0; 3];
|
|
|
|
for izz in n0z..=n1z {
|
|
let i0z = (izz - n0z) as usize;
|
|
zz[i0z] = hydprf.get_xnelem((izz - 1) as usize, iline);
|
|
|
|
// 检查是否超过最高温度网格值
|
|
let xtlem_max = hydprf.get_xtlem(nt - 1, iline);
|
|
if x0 > 1.01 * xtlem_max {
|
|
let (adh, divh) = divstr(dbeta, izh);
|
|
let stark_val = starka(beta, 2.0, adh, dbeta, divh);
|
|
return (stark_val * dbeta).log10();
|
|
}
|
|
|
|
// 温度方向插值
|
|
let nx = 2;
|
|
let mut ipx = 0;
|
|
for ix in 0..(nt - 1) {
|
|
ipx = ix;
|
|
if x0 <= hydprf.get_xtlem(ix + 1, iline) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let mut n0x = ipx as i32 - (nx as i32 / 2) + 1;
|
|
if n0x < 1 {
|
|
n0x = 1;
|
|
}
|
|
if n0x > (nt - nx + 1) as i32 {
|
|
n0x = (nt - nx + 1) as i32;
|
|
}
|
|
let n1x = n0x + nx as i32 - 1;
|
|
|
|
let mut xx = [0.0; 3];
|
|
let mut wx = [0.0; 3];
|
|
|
|
for ix in n0x..=n1x {
|
|
let i0 = (ix - n0x) as usize;
|
|
xx[i0] = hydprf.get_xtlem((ix - 1) as usize, iline);
|
|
wx[i0] = hydprf.get_prfhyd(iline, iwl, (ix - 1) as usize, (izz - 1) as usize);
|
|
}
|
|
|
|
// 检查是否有无效值
|
|
if wx[0] < -99.0 || wx[1] < -99.0 || wx[2] < -99.0 {
|
|
let (adh, divh) = divstr(dbeta, izh);
|
|
let stark_val = starka(beta, 2.0, adh, dbeta, divh);
|
|
return (stark_val * dbeta).log10();
|
|
} else {
|
|
wz[i0z] = yint(&xx, &wx, x0);
|
|
}
|
|
}
|
|
|
|
// 电子密度方向插值
|
|
yint(&zz, &wz, z0)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn create_test_hydprf() -> HydPrf {
|
|
let mut hydprf = HydPrf::default();
|
|
|
|
// 设置谱线 0 的参数
|
|
hydprf.nth[0] = 7;
|
|
hydprf.neh[0] = 20;
|
|
|
|
// 设置温度网格 (log10)
|
|
for it in 0..7 {
|
|
hydprf.xtlem[it] = 4.0 + it as f64 * 0.1; // 10^4.0 到 10^4.6
|
|
}
|
|
|
|
// 设置电子密度网格 (log10)
|
|
for ie in 0..20 {
|
|
hydprf.xnelem[ie] = 12.0 + ie as f64 * 0.2; // 10^12 到 10^15.8
|
|
}
|
|
|
|
// 设置波长网格
|
|
for iwl in 0..90 {
|
|
hydprf.wlh[iwl] = 4000.0 + iwl as f64 * 10.0; // 4000 Å 到 4900 Å
|
|
}
|
|
|
|
// 设置轮廓数据 (简单的测试值)
|
|
for it in 0..7 {
|
|
for ie in 0..20 {
|
|
hydprf.set_prfhyd(0, 0, it, ie, -2.0 + it as f64 * 0.1 + ie as f64 * 0.01);
|
|
}
|
|
}
|
|
|
|
hydprf
|
|
}
|
|
|
|
#[test]
|
|
fn test_inthyd_basic() {
|
|
let hydprf = create_test_hydprf();
|
|
let dbeta = 10.0;
|
|
let xk = 1.0;
|
|
|
|
// 在表格范围内的插值
|
|
let x0 = 4.3; // log10(T)
|
|
let z0 = 13.5; // log10(Ne)
|
|
let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk);
|
|
|
|
// 结果应该是有限值
|
|
assert!(result.is_finite());
|
|
}
|
|
|
|
#[test]
|
|
fn test_inthyd_low_ne() {
|
|
let hydprf = create_test_hydprf();
|
|
let dbeta = 10.0;
|
|
let xk = 1.0;
|
|
|
|
// 低于最低电子密度,应该使用近似表达式
|
|
let x0 = 4.3;
|
|
let z0 = 10.0; // 低于 10^12
|
|
let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk);
|
|
|
|
// 结果应该是有限值
|
|
assert!(result.is_finite());
|
|
}
|
|
|
|
#[test]
|
|
fn test_inthyd_high_temp() {
|
|
let hydprf = create_test_hydprf();
|
|
let dbeta = 10.0;
|
|
let xk = 1.0;
|
|
|
|
// 高于最高温度,应该使用近似表达式
|
|
let x0 = 5.0; // 高于 10^4.6
|
|
let z0 = 13.5;
|
|
let result = inthyd(x0, z0, 0, 0, &hydprf, dbeta, xk);
|
|
|
|
// 结果应该是有限值
|
|
assert!(result.is_finite());
|
|
}
|
|
}
|