//! 计算双电子复合对光电离截面的修正。 //! //! 重构自 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 (离子 0,ia=1, io=1),dielrc 可能返回 0(没有双电子复合数据) // 对于 He I (离子 1,ia=2, io=1),可能有数据 // 对于 He II (离子 2,ia=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 ); } }