SpectraRust/src/tlusty/math/utils/traini.rs
2026-03-25 18:34:41 +08:00

238 lines
6.5 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 `traini.f`
use crate::tlusty::state::atomic::{IonPar, LevPar, TraPar};
use crate::tlusty::state::config::BasNum;
use crate::tlusty::state::constants::MFREQ;
use crate::tlusty::state::model::{CompIf, DwnPar, LinFrq, LinOvr, ObfPar};
// ============================================================================
// TRAINI - 不透明度初始化
// ============================================================================
/// 初始化不透明度计算的深度无关量。
///
/// # 参数
///
/// - `basnum` - 基本数值计数器
/// - `ionpar` - 离子参数
/// - `levpar` - 能级参数
/// - `trapar` - 跃迁参数 (会被修改)
/// - `obfpar` - 束缚-自由参数
/// - `dwnpar` - 溶解分数参数 (会被修改)
/// - `linovr` - 谱线叠加参数 (会被修改)
/// - `linfrq` - 谱线频率参数 (会被修改)
/// - `compif` - 计算标志
///
/// # Fortran 原始代码
///
/// ```fortran
/// SUBROUTINE TRAINI
/// INCLUDE 'IMPLIC.FOR'
/// INCLUDE 'BASICS.FOR'
/// INCLUDE 'ATOMIC.FOR'
/// INCLUDE 'MODELQ.FOR'
/// INCLUDE 'ODFPAR.FOR'
///
/// do itr=1,ntrans
/// idiel(itr)=0
/// end do
///
/// NCDW=0
/// DO 10 IBFT=1,NTRANC
/// ITR=ITRBF(IBFT)
/// ii=ilow(itr)
/// if(ilk(iup(itr)).ne.0.and.nfirst(iel(ii)).eq.ii.
/// * and.IFDIEL.NE.0) idiel(itr)=1
/// MODW=IABS(INDEXP(ITR))
/// IF(MODW.NE.5.AND.MODW.NE.15) GO TO 10
/// NCDW=NCDW+1
/// MCDW(ITR)=NCDW
/// ITRCDW(NCDW)=ITR
/// 10 CONTINUE
/// IF(ISPODF.GE.1) RETURN
///
/// DO IJ=1,NFREQ
/// NLINES(IJ)=0
/// END DO
///
/// DO 100 ITR=1,NTRANS
/// IF(LINEXP(ITR)) GO TO 100
/// DO IJ=IFR0(ITR),IFR1(ITR)
/// IJLIN(IJ)=ITR
/// END DO
/// 100 CONTINUE
/// END
/// ```
pub fn traini(
basnum: &BasNum,
ionpar: &IonPar,
levpar: &LevPar,
trapar: &mut TraPar,
obfpar: &ObfPar,
dwnpar: &mut DwnPar,
linovr: &mut LinOvr,
linfrq: &mut LinFrq,
compif: &CompIf,
) {
let ntrans = basnum.ntrans as usize;
let ntranc = basnum.ntranc as usize;
let nfreq = basnum.nfreq as usize;
let ispodf = basnum.ispodf;
let ifdiel = basnum.ifdiel;
// 初始化 idiel
for itr in 0..ntrans {
trapar.idiel[itr] = 0;
}
// 束缚-自由跃迁处理
let mut ncdw: i32 = 0;
for ibft in 0..ntranc {
let itr = (obfpar.itrbf[ibft] - 1) as usize; // Fortran 1-indexed -> Rust 0-indexed
let ii = (trapar.ilow[itr] - 1) as usize;
let iup_idx = (trapar.iup[itr] - 1) as usize;
// 检查是否是电离能级
// if(ilk(iup(itr)).ne.0.and.nfirst(iel(ii)).eq.ii.and.IFDIEL.NE.0)
let iel_idx = (levpar.iel[ii] - 1) as usize;
if levpar.ilk[iup_idx] != 0
&& ionpar.nfirst[iel_idx] == (ii + 1) as i32
&& ifdiel != 0
{
trapar.idiel[itr] = 1;
}
// 检查模数
let modw = trapar.indexp[itr].abs();
if modw != 5 && modw != 15 {
continue;
}
ncdw += 1;
dwnpar.mcdw[itr] = ncdw;
dwnpar.itrcdw[(ncdw - 1) as usize] = (itr + 1) as i32;
}
dwnpar.ncdw = ncdw;
// 如果 ISPODF >= 1不处理束缚-束缚跃迁
if ispodf >= 1 {
return;
}
// 束缚-束缚跃迁处理
// 初始化 nlines
for ij in 0..nfreq {
linfrq.nlines[ij] = 0;
}
// 处理跃迁
for itr in 0..ntrans {
// 如果是经验线,跳过
if compif.linexp[itr] {
continue;
}
let ifr0 = (trapar.ifr0[itr] - 1) as usize; // Fortran 1-indexed
let ifr1 = (trapar.ifr1[itr] - 1) as usize;
for ij in ifr0..=ifr1.min(MFREQ - 1) {
linovr.ijlin[ij] = (itr + 1) as i32;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_data() -> (BasNum, IonPar, LevPar, TraPar, ObfPar, DwnPar, LinOvr, LinFrq, CompIf) {
let mut basnum = BasNum::default();
basnum.ntrans = 10;
basnum.ntranc = 5;
basnum.nfreq = 100;
basnum.ispodf = 0;
basnum.ifdiel = 0;
let ionpar = IonPar::default();
let mut levpar = LevPar::default();
// iel[ii] 表示能级 ii 属于哪个离子 (1-indexed)
// 在实际运行中iel 从原子数据文件读取
// 这里模拟有效数据:所有能级属于第一个离子
for i in 0..10 {
levpar.iel[i] = 1;
}
let mut trapar = TraPar::default();
let mut obfpar = ObfPar::new(); // 使用 new() 而不是 default()
// 设置一些跃迁
for i in 0..5 {
obfpar.itrbf[i] = (i + 1) as i32;
trapar.ilow[i] = (i + 1) as i32;
trapar.iup[i] = (i + 2) as i32;
trapar.indexp[i] = 5; // 模数 5
trapar.ifr0[i] = 1;
trapar.ifr1[i] = 10;
}
let dwnpar = DwnPar::default();
let linovr = LinOvr::default();
let linfrq = LinFrq::default();
let compif = CompIf::default();
(basnum, ionpar, levpar, trapar, obfpar, dwnpar, linovr, linfrq, compif)
}
#[test]
fn test_traini_basic() {
let (basnum, ionpar, levpar, mut trapar, obfpar, mut dwnpar, mut linovr, mut linfrq, compif) =
create_test_data();
traini(
&basnum, &ionpar, &levpar, &mut trapar, &obfpar, &mut dwnpar, &mut linovr, &mut linfrq,
&compif,
);
// 检查 idiel 被初始化
for itr in 0..basnum.ntrans as usize {
assert_eq!(trapar.idiel[itr], 0);
}
}
#[test]
fn test_traini_ncdw() {
let (basnum, ionpar, levpar, mut trapar, obfpar, mut dwnpar, mut linovr, mut linfrq, compif) =
create_test_data();
traini(
&basnum, &ionpar, &levpar, &mut trapar, &obfpar, &mut dwnpar, &mut linovr, &mut linfrq,
&compif,
);
// 由于所有跃迁都有 indexp=5ncdw 应该 > 0
assert!(dwnpar.ncdw > 0);
}
#[test]
fn test_traini_ispoft() {
let (mut basnum, ionpar, levpar, mut trapar, obfpar, mut dwnpar, mut linovr, mut linfrq, compif) =
create_test_data();
basnum.ispodf = 1; // 跳过束缚-束缚跃迁
traini(
&basnum, &ionpar, &levpar, &mut trapar, &obfpar, &mut dwnpar, &mut linovr, &mut linfrq,
&compif,
);
// linfrq.nlines 应该保持为 0
for ij in 0..basnum.nfreq as usize {
assert_eq!(linfrq.nlines[ij], 0);
}
}
}