238 lines
6.5 KiB
Rust
238 lines
6.5 KiB
Rust
//! 不透明度计算的深度无关量初始化。
|
||
//!
|
||
//! 重构自 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=5,ncdw 应该 > 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);
|
||
}
|
||
}
|
||
}
|