843 lines
24 KiB
Rust
843 lines
24 KiB
Rust
//! 不透明度采样模式下的频率设置。
|
||
//!
|
||
//! 重构自 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
|
||
}
|
||
}
|