代码整理
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
//! 氢线 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user