SpectraRust/src/tlusty/math/atomic/dietot.rs
2026-04-01 16:35:36 +08:00

189 lines
5.7 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 `dietot.f`
//! 遍历所有离子和深度点,计算双电子复合速率和伪截面。
use crate::tlusty::math::dielrc;
use crate::tlusty::state::atomic::{AtoPar, IonPar, LevPar};
use crate::tlusty::state::config::{BasNum, InpPar};
use crate::tlusty::state::model::{LevAdd, ModPar};
/// DIETOT 参数结构体
pub struct DietotParams<'a> {
/// 基本数值
pub basnum: &'a BasNum,
/// 输入参数(包含 wmm, ytot
pub inppar: &'a InpPar,
/// 原子参数
pub atopar: &'a AtoPar,
/// 离子参数
pub ionpar: &'a IonPar,
/// 能级参数
pub levpar: &'a LevPar,
/// 模型参数(包含 temp, dens
pub modpar: &'a ModPar,
/// 能级附加数据(包含 diesig 输出)
pub levadd: &'a mut LevAdd,
}
/// 计算双电子复合截面修正。
///
/// 遍历所有离子和深度点,调用 `dielrc` 计算双电子复合速率和伪截面。
/// 结果存储在 `levadd.diesig[ion][id]` 中。
///
/// # 参数
/// * `params` - 参数结构体
pub fn dietot(params: &mut DietotParams) {
let nion = params.basnum.nion as usize;
let nd = params.basnum.nd as usize;
for ion in 0..nion {
// 获取离子的第一个能级索引
let i = (params.ionpar.nfirst[ion] - 1) as usize; // 转换为 0-indexed
// 获取原子序数和离子电荷
let iatm_idx = (params.levpar.iatm[i] - 1) as usize;
let ia = params.atopar.numat[iatm_idx] as usize;
let io = params.ionpar.iz[ion] as usize;
for id in 0..nd {
let t = params.modpar.temp[id];
let xpx = params.modpar.dens[id] / params.inppar.wmm[id] / params.inppar.ytot[id];
// 调用 dielrc 计算双电子复合速率和伪截面
let (dirt, sig0) = dielrc(ia, io, t, xpx);
// 存储结果
params.levadd.diesig[ion][id] = sig0;
if id == 0 || id == 34 || id == nd - 1 {
eprintln!("{:5}{:5}{:5}{:5}{:5}{:5}{:12.4}{:12.4}",
ion + 1, ia, io, id + 1, i + 1,
params.ionpar.nnext[ion], dirt, sig0);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tlusty::state::atomic::{AtoPar, IonPar, LevPar};
use crate::tlusty::state::config::{BasNum, InpPar};
use crate::tlusty::state::constants::{MDEPTH, MION, MLEVEL, MATOM};
use crate::tlusty::state::model::{LevAdd, ModPar};
fn create_test_state() -> (
BasNum,
InpPar,
AtoPar,
IonPar,
LevPar,
ModPar,
LevAdd,
) {
let mut basnum = BasNum::default();
basnum.nion = 3;
basnum.nd = 5;
let mut inppar = InpPar::new();
for i in 0..5 {
inppar.wmm[i] = 1.0 + i as f64 * 0.1;
inppar.ytot[i] = 1.0;
}
let mut atopar = AtoPar::default();
// 设置原子序数H=1, He=2
atopar.numat[0] = 1; // H
atopar.numat[1] = 2; // He
let mut ionpar = IonPar::default();
// 设置离子 0: H I (nfirst=1, iz=1)
ionpar.nfirst[0] = 1;
ionpar.iz[0] = 1;
// 设置离子 1: He I (nfirst=2, iz=1)
ionpar.nfirst[1] = 2;
ionpar.iz[1] = 1;
// 设置离子 2: He II (nfirst=3, iz=2)
ionpar.nfirst[2] = 3;
ionpar.iz[2] = 2;
let mut levpar = LevPar::default();
// 设置能级的原子归属
levpar.iatm[0] = 1; // 能级 1 属于原子 1 (H)
levpar.iatm[1] = 2; // 能级 2 属于原子 2 (He)
levpar.iatm[2] = 2; // 能级 3 属于原子 2 (He)
let mut modpar = ModPar::default();
for i in 0..5 {
modpar.temp[i] = 10000.0 + i as f64 * 1000.0;
modpar.dens[i] = 1e-10 + i as f64 * 1e-11;
}
let levadd = LevAdd::new();
(basnum, inppar, atopar, ionpar, levpar, modpar, levadd)
}
#[test]
fn test_dietot_basic() {
let (basnum, inppar, atopar, ionpar, levpar, modpar, mut levadd) = create_test_state();
let mut params = DietotParams {
basnum: &basnum,
inppar: &inppar,
atopar: &atopar,
ionpar: &ionpar,
levpar: &levpar,
modpar: &modpar,
levadd: &mut levadd,
};
dietot(&mut params);
// 验证结果已存储
for ion in 0..3 {
for id in 0..5 {
// diesig 应该有一些值(可能是 0.0 如果没有数据)
assert!(
params.levadd.diesig[ion][id].is_finite(),
"diesig[{}][{}] should be finite",
ion,
id
);
}
}
}
#[test]
fn test_dietot_values() {
let (basnum, inppar, atopar, ionpar, levpar, modpar, mut levadd) = create_test_state();
let mut params = DietotParams {
basnum: &basnum,
inppar: &inppar,
atopar: &atopar,
ionpar: &ionpar,
levpar: &levpar,
modpar: &modpar,
levadd: &mut levadd,
};
dietot(&mut params);
// 验证某些已知离子的值
// 对于 H I (离子 0ia=1, io=1)dielrc 可能返回 0没有双电子复合数据
// 对于 He I (离子 1ia=2, io=1),可能有数据
// 对于 He II (离子 2ia=2, io=2),可能有数据
// 验证 H I 的第一个深度点
let diesig_h1 = params.levadd.diesig[0][0];
// H I 的双电子复合通常为 0氢没有双电子复合
assert!(
diesig_h1 >= 0.0,
"H I diesig should be non-negative, got {}",
diesig_h1
);
}
}