//! 不透明度采样模式下的频率设置。 //! //! 重构自 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, /// 频率权重 pub w: Vec, /// 谱线权重 pub wch: Vec, /// 每个频率点的谱线数 pub nlines: Vec, /// 频率索引数组 pub ifreqb: Vec, /// 跃迁起始频率索引 (ntrans) pub ifr0: Vec, /// 跃迁终止频率索引 (ntrans) pub ifr1: Vec, /// 线频率起始索引 (ntrans) pub kfr0: Vec, /// 线频率终止索引 (ntrans) pub kfr1: Vec, /// 跃迁中心索引 (ntrans) pub ijtc: Vec, /// ALI 频率索引 pub ijali: Vec, /// 频率索引 pub ijx: Vec, /// JIK 索引 pub jik: Vec, /// 频率总数 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 } }