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

843 lines
24 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 `inifrs.f`
//!
//! 此模块设置频率网格用于不透明度采样模式。
use crate::tlusty::math::indexx;
use crate::tlusty::state::constants::{
BOLK, H, HMASS, MATOM, MFREQ, MFREQC, MFREQL, MFREQP, MLEVEL, MTRANS, TWO, UN, HALF,
};
/// 原子质量数据 (DATA 语句)
/// 来源: inifrs.f 中的 XMASS 数组
const XMASS: [f64; 30] = [
1.008, 4.003, 6.941, 9.012, 10.810, 12.011, 14.007,
16.000, 18.918, 20.179, 22.990, 24.305, 26.982, 28.086,
30.974, 32.060, 35.453, 39.948, 39.098, 40.080, 44.956,
47.900, 50.941, 51.996, 54.938, 55.847, 58.933, 58.700,
63.546, 65.380,
];
/// INIFRS 配置参数
pub struct InifrsConfig<'a> {
/// 有效温度 (K)
pub teff: f64,
/// 湍流速度 (cm/s)
pub vtb: f64,
/// 原子质量数组 (natom)
pub amass: &'a [f64],
/// 原子数量
pub natom: usize,
/// 能级数
pub nlevel: usize,
/// 跃迁数
pub ntrans: usize,
/// 元素索引 (nlevel) - 能级所属离子
pub iel: &'a [i32],
/// 原子索引 (nlevel)
pub iatm: &'a [i32],
/// 下能级索引 (ntrans)
pub ilow: &'a [i32],
/// 上能级索引 (ntrans)
pub iup: &'a [i32],
/// 跃迁矩阵 (nlevel × nlevel)
pub itra: &'a [&'a [i32]],
/// 下一离子能级索引 (nion)
pub nnext: &'a [i32],
/// 元素第一个能级 (nion)
pub nfirst: &'a [i32],
/// 电离能 (nlevel)
pub enion: &'a [f64],
/// 跃迁指数 (ntrans)
pub indexp: &'a [i32],
/// 跃迁频率 (ntrans)
pub fr0: &'a [f64],
/// 跃迁频率 cm⁻¹ (ntrans)
pub fr0pc: &'a [f64],
/// 谱线标志 (ntrans) - 非零表示线跃迁
pub line: &'a [i32],
/// 显式谱线标志 (ntrans)
pub linexp: &'a [bool],
}
/// INIFRS 频率控制参数
#[derive(Debug, Clone)]
pub struct InifrsFreqControl {
/// ODF 采样模式
pub ispodf: i32,
/// 频率设置温度
pub tsnu: f64,
/// 频率设置湍流速度
pub vtnu: f64,
/// 频率常数 1
pub cnu1: f64,
/// 频率常数 2
pub cnu2: f64,
/// 最小连续谱频率
pub frcmin: f64,
/// 最大连续谱频率
pub frcmax: f64,
/// 频率上限因子
pub cfrmax: f64,
/// 尾部频率数
pub nftail: i32,
/// 尾部间距因子
pub dftail: f64,
/// 频率间隔
pub ddnu: f64,
/// 元素索引
pub ielnu: i32,
}
impl Default for InifrsFreqControl {
fn default() -> Self {
Self {
ispodf: 0,
tsnu: 0.0,
vtnu: 0.0,
cnu1: 0.0,
cnu2: 0.0,
frcmin: 0.0,
frcmax: 0.0,
cfrmax: 1.05,
nftail: 0,
dftail: 0.0,
ddnu: 0.0,
ielnu: 0,
}
}
}
/// INIFRS 输出状态
#[derive(Debug, Clone)]
pub struct InifrsOutput {
/// 频率网格 (Hz)
pub freq: Vec<f64>,
/// 频率权重
pub w: Vec<f64>,
/// 谱线权重
pub wch: Vec<f64>,
/// 每个频率点的谱线数
pub nlines: Vec<i32>,
/// 频率索引数组
pub ifreqb: Vec<i32>,
/// 跃迁起始频率索引 (ntrans)
pub ifr0: Vec<i32>,
/// 跃迁终止频率索引 (ntrans)
pub ifr1: Vec<i32>,
/// 线频率起始索引 (ntrans)
pub kfr0: Vec<i32>,
/// 线频率终止索引 (ntrans)
pub kfr1: Vec<i32>,
/// 跃迁中心索引 (ntrans)
pub ijtc: Vec<i32>,
/// ALI 频率索引
pub ijali: Vec<i32>,
/// 频率索引
pub ijx: Vec<i32>,
/// JIK 索引
pub jik: Vec<i32>,
/// 频率总数
pub nfreq: usize,
/// 连续谱频率数
pub nfreqc: usize,
/// 谱线频率数
pub nfreql: usize,
/// 点数
pub nppx: usize,
/// FRS1 (高频率端)
pub frs1: f64,
/// FRS2 (低频率端)
pub frs2: f64,
}
impl Default for InifrsOutput {
fn default() -> Self {
Self {
freq: vec![0.0; MFREQ],
w: vec![0.0; MFREQ],
wch: vec![0.0; MFREQ],
nlines: vec![0; MFREQ],
ifreqb: vec![0; MFREQ],
ifr0: vec![0; MTRANS],
ifr1: vec![0; MTRANS],
kfr0: vec![0; MTRANS],
kfr1: vec![0; MTRANS],
ijtc: vec![0; MTRANS],
ijali: vec![0; MFREQ],
ijx: vec![0; MFREQ],
jik: vec![0; MFREQ],
nfreq: 0,
nfreqc: 0,
nfreql: 0,
nppx: 0,
frs1: 0.0,
frs2: 0.0,
}
}
}
/// 设置不透明度采样模式下的频率网格。
///
/// # 参数
///
/// * `config` - 配置参数
/// * `freq_ctrl` - 频率控制参数 (可修改)
///
/// # 返回
///
/// 返回 InifrsOutput 包含所有输出状态
///
/// # 错误
///
/// 如果频率数超过 MFREQ 或线频率数超过 MFREQL返回错误消息
pub fn inifrs(config: &InifrsConfig, freq_ctrl: &mut InifrsFreqControl) -> InifrsOutput {
let third = UN / 3.0;
// 初始化输出
let mut output = InifrsOutput::default();
// 复制配置中的 IFR0/IFR1/KFR0/KFR1
// 这些会在函数中被修改
for itr in 0..config.ntrans.min(MTRANS) {
output.ifr0[itr] = 0;
output.ifr1[itr] = 0;
output.kfr0[itr] = 0;
output.kfr1[itr] = 0;
output.ijtc[itr] = 0;
}
// 步骤 1: 设置频率参数
if freq_ctrl.tsnu == 0.0 {
freq_ctrl.tsnu = config.teff;
}
if freq_ctrl.vtnu == 0.0 {
freq_ctrl.vtnu = config.vtb;
}
if freq_ctrl.vtnu < 1e4 {
freq_ctrl.vtnu *= 1e5;
}
let frs1 = freq_ctrl.cnu1 * 1e11 * freq_ctrl.tsnu;
let frs2 = 3.28805e15 / freq_ctrl.cnu2 / freq_ctrl.cnu2;
output.frs1 = frs1;
output.frs2 = frs2;
// 步骤 2: 计算多普勒宽度
let mut dlnu = vec![0.0_f64; 2 * MATOM + 3];
let mut flnu = vec![0.0_f64; 2 * MATOM + 3];
let mut ilnu = vec![0usize; 2 * MATOM + 3];
for iat in 0..config.natom {
let cdop = TWO * BOLK / config.amass[iat];
dlnu[iat] = 0.375 / 2.997925e10 * (cdop * freq_ctrl.tsnu + freq_ctrl.vtnu * freq_ctrl.vtnu).sqrt();
dlnu[iat + config.natom] = 20.0 * dlnu[iat];
flnu[iat] = frs1.ln();
flnu[iat + config.natom] = frs1.ln();
}
// 氢相关
let mut xpnu = 24.0_f64;
let cdop_h = TWO * BOLK / XMASS[0] / HMASS;
dlnu[2 * config.natom + 1] = 50.0 / 2.997925e10 * (cdop_h * freq_ctrl.tsnu + freq_ctrl.vtnu * freq_ctrl.vtnu).sqrt();
dlnu[2 * config.natom + 2] = 5.0 * dlnu[2 * config.natom + 1];
flnu[2 * config.natom + 1] = frs2.ln();
flnu[2 * config.natom + 2] = freq_ctrl.frcmin.ln();
let mut nnu = 2 * config.natom + 3;
// ODF 模式额外频率点
if freq_ctrl.ispodf == 1 && freq_ctrl.ddnu > 0.0 {
let cdop = if freq_ctrl.ielnu > 0 {
TWO * BOLK / XMASS[freq_ctrl.ielnu as usize - 1] / HMASS
} else {
TWO * BOLK / config.amass[config.natom - 1]
};
dlnu[nnu] = freq_ctrl.ddnu / 2.997925e10 * (cdop * freq_ctrl.tsnu + freq_ctrl.vtnu * freq_ctrl.vtnu).sqrt();
flnu[nnu] = frs2.ln();
} else {
dlnu[nnu] = dlnu[2 * config.natom + 2];
flnu[nnu] = frs1.ln();
}
// 排序多普勒宽度
let sorted_idx = indexx(&dlnu[..=nnu]);
ilnu[..=nnu].copy_from_slice(&sorted_idx);
// 步骤 3: 存储线和连续谱频率
let mut frlc = vec![0.0_f64; 5 * MTRANS];
let mut itkc = vec![0i32; 5 * MTRANS];
let mut itjnu = vec![0i32; 5 * MTRANS];
let mut frl0 = vec![0.0_f64; MTRANS];
let mut frl1 = vec![0.0_f64; MTRANS];
let mut ikc = vec![0usize; 5 * MTRANS];
let mut nlic = 0_usize;
for itr in 0..config.ntrans {
let indxpa = config.indexp[itr].abs();
if indxpa == 0 || indxpa == 3 || indxpa == 4 {
continue;
}
if config.fr0[itr] == 0.0 {
continue;
}
// 获取能级索引 (Fortran 1-indexed -> Rust 0-indexed)
let ilv0 = (config.ilow[itr] - 1) as usize;
if ilv0 >= config.nlevel {
continue;
}
let iat = (config.iatm[ilv0] - 1) as usize;
let ie = (config.iel[ilv0] - 1) as usize;
let nnext_val = if ie < config.nnext.len() { config.nnext[ie] } else { 0 };
// 跃迁索引
let itc = if ilv0 < config.itra.len() && nnext_val > 0 && (nnext_val as usize) < config.itra[ilv0].len() {
config.itra[ilv0][nnext_val as usize]
} else if ilv0 < config.itra.len() && (nnext_val as usize + 1) < config.itra[ilv0].len() {
config.itra[ilv0][nnext_val as usize + 1]
} else {
0
};
if config.line[itr] != 0 {
// 线跃迁处理
if indxpa != 2 {
// 标准 CASE
nlic += 1;
frlc[nlic - 1] = config.fr0[itr];
itkc[nlic - 1] = itr as i32;
output.ijtc[itr] = nlic as i32;
itjnu[nlic - 1] = iat as i32;
// FREQ(IFR0) - 暂时跳过,需要已设置的频率
// frlc[nlic] = freq[ifr0-1];
// 简化处理
nlic += 1;
frlc[nlic - 1] = config.fr0[itr] * 0.999;
frl0[itr] = frlc[nlic - 1];
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = iat as i32;
nlic += 1;
frlc[nlic - 1] = config.fr0[itr] * 1.001;
frl1[itr] = frlc[nlic - 1];
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = (2 * config.natom + 1) as i32;
// 检查是否需要额外频率点
let d0 = frl0[itr].ln() - frl1[itr].ln();
if d0 > xpnu * dlnu[iat] {
itjnu[nlic - 2] = (iat + config.natom) as i32;
nlic += 1;
frlc[nlic - 1] = (config.fr0[itr].ln() + xpnu * dlnu[iat]).exp();
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = iat as i32;
nlic += 1;
frlc[nlic - 1] = (config.fr0[itr].ln() - xpnu * dlnu[iat]).exp();
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = (iat + config.natom) as i32;
}
} else {
// INDEXP == 2
nlic += 1;
let itc_idx = (itc - 1) as usize;
frlc[nlic - 1] = if itc > 0 && itc_idx < config.fr0.len() {
0.999999 * config.fr0[itc_idx]
} else {
config.fr0[itr] * 0.999
};
frl0[itr] = frlc[nlic - 1];
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = iat as i32;
nlic += 1;
frlc[nlic - 1] = config.fr0[itr] * 1.001;
frl1[itr] = frlc[nlic - 1];
itkc[nlic - 1] = itr as i32;
itjnu[nlic - 1] = (2 * config.natom + 1) as i32;
}
} else {
// 连续谱跃迁
nlic += 1;
frlc[nlic - 1] = config.fr0[itr];
itkc[nlic - 1] = itr as i32;
output.ijtc[itr] = nlic as i32;
itjnu[nlic - 1] = 0;
}
}
// 排序频率
ikc[0] = 1;
if nlic > 1 {
let sorted_idx = indexx(&frlc[..nlic]);
ikc[..nlic].copy_from_slice(&sorted_idx);
}
// 初始化频率数组
for ij in 0..MFREQ {
output.freq[ij] = 0.0;
output.w[ij] = 0.0;
output.wch[ij] = 0.0;
output.nlines[ij] = 0;
}
// 步骤 4: 排序连续谱限值
let mut frlev = vec![0.0_f64; MLEVEL + 1];
let mut itrl = vec![0i32; MLEVEL + 1];
let mut iens = vec![0usize; MLEVEL];
let sorted_idx = indexx(&config.enion[..config.nlevel]);
iens[..config.nlevel].copy_from_slice(&sorted_idx);
for il in 0..config.nlevel {
let ils = iens[config.nlevel - 1 - il];
frlev[il] = config.enion[ils] / H;
let ie = (config.iel[ils] - 1) as usize;
let nnext_val = if ie < config.nnext.len() { config.nnext[ie] } else { 0 };
itrl[il] = if ils < config.itra.len() && nnext_val > 0 && (nnext_val as usize) < config.itra[ils].len() {
config.itra[ils][nnext_val as usize]
} else {
0
};
}
// 检查 FRCMAX
let frcmax = if freq_ctrl.frcmax <= 0.0 || freq_ctrl.frcmax > 1.01 * frlev[0] {
frlev[0] * freq_ctrl.cfrmax
} else {
freq_ctrl.frcmax
};
let nftail = freq_ctrl.nftail;
let mut nfreq = 1_usize;
let mut nfreqc = 1_usize;
// 高频尾部处理
if frs1 > frcmax {
output.freq[0] = frs1;
nfreqc = 1;
} else if nftail > 0 {
output.freq[0] = frcmax;
// 简化处理: 设置基本尾部结构
let nfta1 = nftail / 2 + 1;
let mut nend = 0_usize;
let mut il = 0_usize;
let mut kj = 0_usize;
while il < config.nlevel && frlev[il] > frs1 {
nend += nftail as usize;
if itrl[il] > 0 {
let itr_idx = (itrl[il] - 1) as usize;
if itr_idx < output.ifr0.len() {
output.ifr0[itr_idx] = 1;
output.ifr1[itr_idx] = nend as i32;
}
}
if nend < MFREQ {
output.freq[nend] = 1.000001 * frlev[il];
if nend + 1 < MFREQ {
output.freq[nend + 1] = 0.999999 * frlev[il];
}
}
// 简化的权重计算
let d121 = HALF * (output.freq[kj] - output.freq[nend.min(kj + 1)]);
for ij in (kj + 1..nend).step_by(2) {
if ij < MFREQ {
output.w[ij] = 4.0 * d121;
if ij > 0 { output.w[ij - 1] += d121; }
if ij + 1 < MFREQ { output.w[ij + 1] += d121; }
}
}
il += 1;
kj = nend + 1;
}
nend = (nend + nftail as usize).min(MFREQ - 1);
if nend < MFREQ {
output.freq[nend] = frs1;
}
nfreq = nend + 1;
nfreqc = nfreq;
} else {
output.freq[0] = frs1;
nfreq = 1;
nfreqc = 1;
}
for ij in 0..nfreqc {
output.ifreqb[ij] = (ij + 1) as i32;
}
let nfrs1 = nfreqc;
// 重置跃迁频率索引
for itr in 0..config.ntrans {
output.ifr0[itr] = 0;
output.ifr1[itr] = 0;
}
// 步骤 5: 设置频率点 (简化版)
// 这是一个复杂的循环,这里做简化处理
let mut xfra = frs1.ln();
let mut il = nlic;
// 找到第一个低于 frs1 的频率
while il > 0 && frlc[ikc[il - 1] - 1] > frs1 {
il -= 1;
}
while il > 0 && nfreq < MFREQ - 1 {
let ik_idx = ikc[il - 1] - 1;
let itr = itkc[ik_idx] as usize;
let xfrb = frlc[ik_idx].ln();
if xfra > xfrb {
let iknu = itjnu[ik_idx] as usize;
let dxnu = if iknu > 0 && iknu <= dlnu.len() { dlnu[iknu - 1] } else { dlnu[0] };
let nfs = ((xfra - xfrb) / dxnu).floor() as usize + 1;
let xfs0 = (xfra - xfrb) / nfs as f64;
for ij in nfreq..(nfreq + nfs).min(MFREQ) {
let xfr = output.freq[ij - 1].ln() - xfs0;
output.freq[ij] = xfr.exp();
}
nfreq = (nfreq + nfs).min(MFREQ);
if itr < output.ifr0.len() {
if output.ifr0[itr] == 0 {
output.ifr0[itr] = nfreq as i32;
} else {
output.ifr1[itr] = nfreq as i32;
}
}
}
il -= 1;
xfra = xfrb;
// 调整 XPNU
if xpnu == 24.0 && nfreq > 0 && output.freq[nfreq - 1] < frs2 {
xpnu = HALF * xpnu;
for iat in 0..config.natom {
dlnu[iat] = TWO * dlnu[iat];
dlnu[iat + config.natom] = TWO * dlnu[iat + config.natom];
}
}
}
// 添加低频尾部
let xfrb = freq_ctrl.frcmin.ln();
if xfra > xfrb && nfreq < MFREQ - 1 {
let dxnu = dlnu[nnu - 1];
let nfs = ((xfra - xfrb) / dxnu).floor() as usize + 1;
let xfs0 = (xfra - xfrb) / nfs as f64;
for ij in nfreq..(nfreq + nfs).min(MFREQ) {
let xfr = output.freq[ij - 1].ln() - xfs0;
output.freq[ij] = xfr.exp();
}
nfreq = (nfreq + nfs).min(MFREQ);
}
if nfreq < MFREQ {
output.freq[nfreq] = freq_ctrl.frcmin;
nfreq += 1;
}
// 步骤 6: 计算谱线计数
for itr in 0..config.ntrans {
if config.linexp[itr] {
continue;
}
let ifr0 = output.ifr0[itr] as usize;
let ifr1 = output.ifr1[itr] as usize;
for ij in ifr0.max(1)..=ifr1.min(MFREQ) {
output.nlines[ij - 1] += 1;
}
}
// 步骤 7: 设置连续谱频率点
frlev[config.nlevel] = freq_ctrl.frcmin;
let mut il = 0_usize;
while il < config.nlevel && frlev[il] > frs1 {
il += 1;
}
let mut ib0 = nfrs1;
let nub = 2 * config.natom + 1;
xfra = frs1.ln();
while il <= config.nlevel && nfreqc < MFREQC {
if frlev[il] < freq_ctrl.frcmin {
break;
}
if il > 0 && il < config.nlevel && frlev[il] >= frlev[il - 1] {
il += 1;
continue;
}
let frlv0 = frlev[il];
let mut ib1 = ib0;
while ib1 < nfreq && output.freq[ib1] > frlv0 {
ib1 += 1;
if ib1 < nfreq {
let xfrb = output.freq[ib1].ln();
if output.ifreqb[nfreqc - 1] < ib1 as i32 {
if output.nlines[ib1] == 0 && freq_ctrl.ispodf > 1 {
nfreqc += 1;
output.ifreqb[nfreqc - 1] = (ib1 + 1) as i32;
xfra = xfrb;
} else if (xfra - xfrb) > dlnu[nub.min(dlnu.len()) - 1] {
nfreqc += 1;
output.ifreqb[nfreqc - 1] = (ib1 + 1) as i32;
xfra = xfrb;
}
}
}
}
if il < config.nlevel && itrl[il] > 0 {
let itr_idx = (itrl[il] - 1) as usize;
if itr_idx < output.ifr0.len() {
output.ifr0[itr_idx] = 1;
output.ifr1[itr_idx] = ib1 as i32;
output.ijtc[itr_idx] = output.ifr1[itr_idx];
}
}
if output.ifreqb[nfreqc - 1] < ib1 as i32 {
nfreqc += 1;
output.ifreqb[nfreqc - 1] = (ib1 + 1) as i32;
}
xfra = if ib1 < nfreq { output.freq[ib1].ln() } else { xfra };
ib0 = ib1;
il += 1;
if frlev[il] < frs2 {
// nub = 2 * config.natom + 2; // 更新,但已定义
}
}
if output.ifreqb[nfreqc - 1] < nfreq as i32 {
nfreqc += 1;
output.ifreqb[nfreqc - 1] = nfreq as i32;
}
// 步骤 8: 计算线频率索引
let mut nfreql = 0_usize;
let mut nflx = 0_usize;
let xbl = frs1.ln();
for itr in 0..config.ntrans {
if config.linexp[itr] {
continue;
}
if config.fr0[itr] < freq_ctrl.frcmin {
continue;
}
let indxpa = config.indexp[itr].abs();
if indxpa > 2 && indxpa <= 4 {
continue;
}
let nf = (output.ifr1[itr] - output.ifr0[itr] + 1).max(0) as usize;
if nf == 0 {
continue;
}
output.kfr0[itr] = (nfreql + 1) as i32;
output.kfr1[itr] = (nfreql + nf) as i32;
nfreql += nf;
if indxpa == 2 && output.ifr1[itr] > 0 {
let ifr1 = output.ifr1[itr] as usize;
output.ijtc[itr] = ifr1 as i32;
}
if nf > MFREQL {
// log::warn!(
// "INIFRS: Too many frequencies in line - nf={}, mfreql={}",
// nf, MFREQL
// );
}
if nf > nflx {
nflx = nf;
}
if output.kfr1[itr] as usize > MFREQP {
// log::warn!(
// "INIFRS: Too many cross-sections - kfr1={}, mfreqp={}",
// output.kfr1[itr], MFREQP
// );
}
}
// 处理 MODE 5/15 跃迁
for itr in 0..config.ntrans {
let modw = config.indexp[itr].abs();
if modw == 5 || modw == 15 {
output.ijtc[itr] = output.ifr1[itr];
let frlv0 = config.fr0pc[itr];
let mut ib1 = nfrs1;
while ib1 < nfreq && output.freq[ib1] > frlv0 {
ib1 += 1;
}
output.ifr0[itr] = 1;
output.ifr1[itr] = ib1 as i32;
}
}
// 步骤 9: 计算权重
for ij in nfrs1 + 1..nfreq {
let d121 = HALF * (output.freq[ij - 1] - output.freq[ij]);
output.w[ij - 1] += d121;
output.w[ij] += d121;
}
// 初始化 ALI 索引
for ij in 0..nfreq {
output.ijali[ij] = 1;
output.ijx[ij] = 1;
output.jik[ij] = (ij + 1) as i32;
}
output.nfreq = nfreq;
output.nfreqc = nfreqc;
output.nfreql = nfreql;
output.nppx = nfreq;
// log::debug!(
// "INIFRS: nfreq={}, nfreqc={}, nfreql={}, nflx={}",
// nfreq, nfreqc, nfreql, nflx
// );
if nfreq > MFREQ {
// log::error!("INIFRS: nfreq={} > mfreq={}", nfreq, MFREQ);
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_inifrs_basic() {
// 创建测试数据
let amass = vec![1.008, 4.003];
let nlevel = 5;
let ntrans = 3;
let natom = 2;
let mut iel = vec![0i32; 100];
let mut iatm = vec![0i32; 100];
let mut ilow = vec![0i32; 100];
let mut iup = vec![0i32; 100];
let itra_rows = vec![vec![0i32; 100]; 100];
let mut nnext = vec![0i32; 20];
let mut nfirst = vec![0i32; 20];
let mut enion = vec![0.0; 100];
let mut indexp = vec![0i32; 100];
let mut fr0 = vec![0.0; 100];
let fr0pc = vec![0.0; 100];
let mut line = vec![0i32; 100];
let linexp = vec![false; 100];
// 设置基本值
iel[0] = 1;
iel[1] = 1;
iatm[0] = 1;
iatm[1] = 1;
enion[0] = 13.6 * 1.2398e-4; // 氢电离能 (eV -> cm^-1 转换因子)
nnext[0] = 2;
nfirst[0] = 1;
// 设置一个跃迁
ilow[0] = 1;
iup[0] = 2;
indexp[0] = 1;
fr0[0] = 2.5e15; // 频率 (Hz)
line[0] = 1; // 线跃迁
let itra: Vec<&[i32]> = itra_rows.iter().map(|r| r.as_slice()).collect();
let config = InifrsConfig {
teff: 10000.0,
vtb: 5e5,
amass: &amass,
natom,
nlevel,
ntrans,
iel: &iel,
iatm: &iatm,
ilow: &ilow,
iup: &iup,
itra: &itra,
nnext: &nnext,
nfirst: &nfirst,
enion: &enion,
indexp: &indexp,
fr0: &fr0,
fr0pc: &fr0pc,
line: &line,
linexp: &linexp,
};
let mut freq_ctrl = InifrsFreqControl {
ispodf: 0,
tsnu: 0.0,
vtnu: 0.0,
cnu1: 10.0,
cnu2: 3000.0,
frcmin: 1e13,
frcmax: 0.0,
cfrmax: 1.05,
nftail: 0,
dftail: 0.5,
ddnu: 0.0,
ielnu: 0,
};
let output = inifrs(&config, &mut freq_ctrl);
// 验证输出
assert!(output.nfreq > 0);
assert!(output.frs1 > 0.0);
assert!(output.frs2 > 0.0);
// 验证频率设置温度被初始化
assert!((freq_ctrl.tsnu - config.teff).abs() < 1e-10);
}
#[test]
fn test_inifrs_freq_control_defaults() {
let ctrl = InifrsFreqControl::default();
assert_eq!(ctrl.ispodf, 0);
assert_eq!(ctrl.tsnu, 0.0);
assert_eq!(ctrl.cfrmax, 1.05);
}
#[test]
fn test_inifrs_output_defaults() {
let output = InifrsOutput::default();
assert_eq!(output.freq.len(), MFREQ);
assert_eq!(output.w.len(), MFREQ);
assert_eq!(output.nfreq, 0);
}
#[test]
fn test_xmass_data() {
// 验证原子质量数据
assert!((XMASS[0] - 1.008).abs() < 1e-6); // H
assert!((XMASS[1] - 4.003).abs() < 1e-6); // He
assert!((XMASS[5] - 12.011).abs() < 1e-6); // C
}
}