SpectraRust/src/tlusty/math/utils/wnstor.rs
2026-06-03 14:11:10 +08:00

213 lines
5.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 存储氢能级占据概率。
//!
//! 重构自 TLUSTY `wnstor.f`
//!
//! 将氢能级的占据概率存储到 WNCOM 公共块中,以便后续使用。
use crate::tlusty::math::wn;
use crate::tlusty::state::constants::{MION, MLEVEL, NLMX, UN};
/// 存储氢能级占据概率。
///
/// 计算氢能级的占据概率,并将结果存储到相应数组中。
///
/// # 参数
///
/// * `id` - 深度索引 (0-based)
/// * `temp` - 温度数组
/// * `elec` - 电子密度数组
/// * `xi2` - XI2 系数数组
/// * `wnhint` - 输出:氢能级占据概率积分 [NLMX][深度]
/// * `wop` - 输出:能级权重 [MLEVEL][深度]
/// * `ifwop` - 能级权重标志
/// * `nlevel` - 能级数
/// * `nquant` - 主量子数数组
/// * `iz` - 原子序数数组
/// * `io_ptab` - 占据概率表标志
/// * `lte` - LTE 标志
///
/// # 示例
///
/// ```
/// use tlusty_rust::math::wnstor::wnstor;
///
/// let temp = vec![10000.0; 100];
/// let elec = vec![1e12; 100];
/// let xi2 = vec![1.0; 30];
/// let mut wnhint = vec![vec![0.0; 100]; 30];
/// let mut wop = vec![vec![0.0; 100]; 1134];
/// let ifwop = vec![1; 1134];
/// let nquant = vec![1; 1134];
/// let iz = vec![1; 1134];
///
/// wnstor(0, &temp, &elec, &xi2, &mut wnhint, &mut wop,
/// &ifwop, 10, &nquant, &iz, 0, false);
/// ```
pub fn wnstor(
id: usize,
temp: &[f64],
elec: &[f64],
xi2: &[f64],
wnhint: &mut [Vec<f64>],
wop: &mut [Vec<f64>],
ifwop: &[i32],
nlevel: usize,
nquant: &[i32],
iel: &[i32],
iz: &[i32],
io_ptab: i32,
lte: bool,
) {
// 常数参数
const P1: f64 = 0.1402;
const P2: f64 = 0.1285;
const P3: f64 = 1.0;
const P4: f64 = 3.15;
const P5: f64 = 4.0;
const TKN: f64 = 3.01;
const CKN: f64 = 5.33333333;
const CB0: f64 = 8.59e14;
const F23: f64 = -2.0 / 3.0;
if io_ptab < 0 {
return;
}
// 获取深度点数据
let ane = elec[id];
let t = temp[id];
// 计算 A 参数
let a = CKN * ane * (ane.ln() / 6.0).exp() / t.sqrt();
let z = UN;
let x = (UN + P3 * a).powf(P4);
let c1 = P1 * (x + P5 * (z - UN) * a * a * a);
let c2 = P2 * x;
let beta0 = CB0 * z * z * z * ane.powf(F23);
// 计算 WNHINT
for i in 1..=NLMX {
let xn = i as f64;
let xkn = if xn <= TKN {
UN
} else {
let xn1 = UN / (xn + UN);
CKN * xn * xn1 * xn1
};
// XI2 系数
let xi2_val = *xi2.get(i - 1).unwrap_or(&UN);
let beta = beta0 * xkn * xi2_val * xi2_val;
let f = (c1 * beta * beta * beta) / (UN + c2 * beta * beta.sqrt());
wnhint[i - 1][id] = f / (UN + f);
}
// 计算 WOP - 显式能级的占据概率
for ii in 0..nlevel {
let ifwop_val = ifwop[ii];
if ifwop_val <= 0 {
continue;
}
let nq = nquant[ii] as usize;
let iel_idx = iel[ii] as usize;
let iz_val = if iel_idx > 0 && iel_idx <= iz.len() { iz[iel_idx - 1] as f64 } else { 0.0 };
if iz_val == 1.0 {
// 氢:使用 WNHINT
if nq > 0 && nq <= NLMX {
wop[ii][id] = wnhint[nq - 1][id];
}
} else {
// 其他元素:使用 WN 函数
let xn = nq as f64;
// bergfc = 0.0 表示使用标准 Hummer-Mihalas 公式
wop[ii][id] = wn(xn, a, ane, iz_val, 0.0);
}
if ifwop_val > 1 && lte {
wop[ii][id] = UN;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const ND: usize = 10;
fn create_test_data() -> (
Vec<f64>,
Vec<f64>,
Vec<f64>,
Vec<Vec<f64>>,
Vec<Vec<f64>>,
Vec<i32>,
Vec<i32>,
Vec<i32>,
Vec<i32>,
) {
let temp = vec![10000.0; ND];
let elec = vec![1e12; ND];
let xi2 = vec![1.0; NLMX];
let wnhint = vec![vec![0.0; ND]; NLMX];
let wop = vec![vec![0.0; ND]; MLEVEL];
let ifwop = vec![1; MLEVEL];
let nquant = vec![1; MLEVEL];
let iel = vec![1; MLEVEL];
let iz = vec![1; MION];
(temp, elec, xi2, wnhint, wop, ifwop, nquant, iel, iz)
}
#[test]
fn test_wnstor_io_ptab_negative() {
let (temp, elec, xi2, mut wnhint, mut wop, ifwop, nquant, iel, iz) = create_test_data();
// io_ptab < 0 应该直接返回
wnstor(
0, &temp, &elec, &xi2, &mut wnhint, &mut wop,
&ifwop, 10, &nquant, &iel, &iz, -1, false,
);
// wnhint 应该保持为 0
assert!((wnhint[0][0] - 0.0).abs() < 1e-10);
}
#[test]
fn test_wnstor_basic() {
let (temp, elec, xi2, mut wnhint, mut wop, ifwop, nquant, iel, iz) = create_test_data();
wnstor(
0, &temp, &elec, &xi2, &mut wnhint, &mut wop,
&ifwop, 10, &nquant, &iel, &iz, 0, false,
);
// 检查 WNHINT 已被计算,值应该在 [0, 1] 范围内
for i in 0..NLMX {
let val = wnhint[i][0];
assert!(val >= 0.0 && val <= 1.0, "WNHINT[{}][0] = {} should be in [0,1]", i, val);
}
}
#[test]
fn test_wnstor_lte_flag() {
let (temp, elec, xi2, mut wnhint, mut wop, ifwop, nquant, iel, iz) = create_test_data();
wnstor(
0, &temp, &elec, &xi2, &mut wnhint, &mut wop,
&ifwop, 10, &nquant, &iel, &iz, 0, true, // lte = true
);
// 当 ifwop > 1 且 lte = true 时wop 应该是 1.0
for ii in 0..10 {
if ifwop[ii] > 1 {
assert!((wop[ii][0] - UN).abs() < 1e-10);
}
}
}
}