//! 单深度点的吸收、发射和散射系数计算。 //! //! 重构自 TLUSTY `opacf0.f` //! //! 对于给定深度点 ID,计算所有频率点的吸收、发射和散射系数。 //! 这是计算不透明度的核心函数之一。 //! //! # 算法流程 //! //! 1. 初始化深度相关温度量 (类似 TDPINI) //! 2. 初始化电子密度相关量 (类似 OPAINI) //! 3. 计算束缚-自由不透明度预备量 //! 4. 计算自由-自由不透明度预备量 //! 5. 初始化 Mermerges 数据 (类似 SGMER0) //! 6. 初始化谱线不透明度 //! 7. 循环频率点计算总不透明度 use crate::state::constants::{HK, H, UN, SIGE, NLMX, MFREQ, MFREQL, MLEVEL, MTRANS, MION, MMER}; // 物理常数 (来自 opacf0.f) /// Rydberg 频率 const FRH: f64 = 3.28805e15; /// H⁻ 光电离截面常数 const PH2: f64 = 2.815e29 * 2.0; /// 氢结合能 const EHB: f64 = 157802.77355; /// H⁻ 自由-自由常数 1 const CFF1: f64 = 1.3727e-25; /// H⁻ 自由-自由常数 2 const CFF2: f64 = 4.3748e-10; /// H⁻ 自由-自由常数 3 const CFF3: f64 = 2.5993e-7; /// c * 1e14 (用于 Gaunt 因子) const C14: f64 = 2.99793e14; /// 自由-自由基准截面 const SGFF0: f64 = 3.694e8; // ============================================================================ // 参数结构体 // ============================================================================ /// OPACF0 输入配置 #[derive(Debug, Clone)] pub struct Opacf0Config { /// Compton 散射标志 (>0: 计算) pub icompt: i32, /// ODF 采样标志 (0: 标准模式, >=1: ODF 采样) pub ispodf: i32, /// 双电子复合标志 (0: 无, >0: 有) pub ifdiel: i32, /// 附加不透明度标志 (0: 无, !=0: 有) pub iopadd: i32, /// 密度缩放标志 (0: 已缩放, 1: 不缩放) pub izscal: i32, /// 表格不透明度标志 (>0: 使用 OPACT1) pub ioptab: i32, /// 当前迭代次数 pub iter: i32, /// 激光抑制迭代阈值 pub itlas: i32, /// 激光抑制阈值 pub qtlas: f64, } impl Default for Opacf0Config { fn default() -> Self { Self { icompt: 0, ispodf: 0, ifdiel: 0, iopadd: 0, izscal: 1, ioptab: 0, iter: 1, itlas: 100, qtlas: 0.1, } } } /// OPACF0 模型状态参数 #[derive(Debug)] pub struct Opacf0ModelState<'a> { /// 深度点数 pub nd: usize, /// 温度 (nd) pub temp: &'a [f64], /// 电子密度 (nd) pub elec: &'a [f64], /// 总粒子密度 (nd) pub dens: &'a [f64], /// 分子质量 (nd) pub wmm: &'a [f64], /// 占据数 (mlevel × nd) pub popul: &'a [f64], // 工作数组 (输入/输出) /// HKT1 (nd) - HK/T pub hkt1: &'a mut [f64], /// HKT21 (nd) - (HK/T)² pub hkt21: &'a mut [f64], /// TK1 (nd) - 1/(kT) pub tk1: &'a mut [f64], /// SQT1 (nd) - sqrt(T) pub sqt1: &'a mut [f64], /// TEMP1 (nd) - 1/T pub temp1: &'a mut [f64], /// ELEC1 (nd) - 1/ne pub elec1: &'a mut [f64], /// DENS1 (nd) - 1/n pub dens1: &'a mut [f64], /// DENSI (nd) - 密度倒数 pub densi: &'a mut [f64], /// DENSIM (nd) - 密度倒数 × 分子质量 pub densim: &'a mut [f64], /// ELSCAT (nd) - 电子散射系数 pub elscat: &'a mut [f64], } /// OPACF0 原子数据参数 #[derive(Debug)] pub struct Opacf0AtomicParams<'a> { /// 束缚-自由跃迁数 pub ntranc: usize, /// 离子数 pub nion: usize, /// 能级数 pub nlevel: usize, /// 跃迁数 pub ntrans: usize, /// 连续谱频率数 pub nfreqc: usize, // 跃迁索引 /// 束缚-自由跃迁索引 (ntranc), 1-indexed pub itrbf: &'a [i32], /// 低能级索引 (mtrans), 1-indexed pub ilow: &'a [i32], /// 高能级索引 (mtrans), 1-indexed pub iup: &'a [i32], /// 跃迁类型索引 (mlevel × mlevel), 1-indexed pub itra: &'a [i32], /// 指数索引 (mtrans) pub indexp: &'a [i32], /// Macfarlane 下沉修正索引 (mtrans) pub mcdw: &'a [i32], /// 频率起点 (mtrans), 1-indexed pub ifr0: &'a [i32], /// 频率终点 (mtrans), 1-indexed pub ifr1: &'a [i32], /// ODF 频率起点 (mtrans), 1-indexed pub kfr0: &'a [i32], /// ODF 频率终点 (mtrans), 1-indexed pub kfr1: &'a [i32], /// 阈值频率 (mtrans) pub fr0: &'a [f64], /// 积分模式 (mtrans) pub intmod: &'a [i32], /// 谱线标志 (mtrans) pub line: &'a [i32], // 能级相关 /// 能级对应的元素索引 (mlevel), 1-indexed pub iel: &'a [i32], /// 能级对应的原子索引 (mlevel), 1-indexed pub iatm: &'a [i32], /// Mermerges 处理标志 (mlevel), < 0 表示需要特殊处理 pub ifwop: &'a [i32], /// Mermerges 索引 (mlevel) pub imrg: &'a mut [i32], /// 主量子数 (mlevel) pub nquant: &'a [i32], /// 电离能 (mlevel) pub enion: &'a [f64], /// 统计权重 (mlevel) pub g: &'a [f64], /// 束缚-自由截面 (mlevel) pub sbf: &'a [f64], /// 束缚-自由权重 (mlevel × nd) pub wop: &'a [f64], // 离子相关 /// 离子对应的下一个能级索引 (mion), 1-indexed pub nnext: &'a [i32], /// 离子起始能级 (mion), 1-indexed pub nfirst: &'a [i32], /// 自由-自由阈值频率 (mion) pub ff: &'a [f64], /// 电荷² (mion) pub charg2: &'a [f64], /// 原子序数 Z (mion) pub iz: &'a [i32], /// H 元素索引 (1-indexed, 0 表示无) pub ielh: i32, /// H⁻ 元素索引 (1-indexed, 0 表示无) pub ielhm: i32, // 原子相关 /// 原子操作标志 (matom), 0=正常, >0=特殊 pub iadop: &'a [i32], } /// OPACF0 频率数据参数 #[derive(Debug)] pub struct Opacf0FreqParams<'a> { /// 频率点数 pub nfreq: usize, /// 频率数组 (nfreq) pub freq: &'a [f64], /// Planck 函数 (nfreq) pub bnue: &'a [f64], /// 主谱线索引 (nfreq), 0 表示无 pub ijlin: &'a [i32], /// 重叠谱线数 (nfreq) pub nlines: &'a [i32], /// 谱线索引 (mitj × nfreq) pub itrlin: &'a [i32], /// Compton 散射截面 (nfreq) pub sigec: &'a [f64], /// 表格最大频率 pub frtabm: f64, } /// OPACF0 输出状态 #[derive(Debug)] pub struct Opacf0Output<'a> { /// 吸收系数 (nfreq) pub abso: &'a mut [f64], /// 发射系数 (nfreq) pub emis: &'a mut [f64], /// 散射系数 (nfreq) pub scat: &'a mut [f64], // 工作数组 /// XKF (nd) - exp(-hν/kT) pub xkf: &'a mut [f64], /// XKF1 (nd) - 1 - XKF pub xkf1: &'a mut [f64], /// XKFB (nd) - XKF × Bν pub xkfb: &'a mut [f64], // 跃迁吸收/发射系数 (mtrans × nd) /// 吸收系数 pub abtra: &'a mut [f64], /// 发射系数 pub emtra: &'a mut [f64], // 自由-自由系数 /// SFF2 (mion × nd) pub sff2: &'a mut [f64], /// SFF3 (mion × nd) pub sff3: &'a mut [f64], /// H⁻ 自由-自由系数 (nd) pub cffn: &'a mut [f64], /// H⁻ 自由-自由温度因子 (nd) pub cfft: &'a mut [f64], // Mermerges 数据 /// Mermerges 频率 (mmer) pub frch: &'a mut [f64], /// Mermerges 截面基准 (mmer) pub sgm0: &'a mut [f64], /// Mermerges 截面求和 (nlmx × mmer × nd) pub sgmsum: &'a mut [f64], /// Mermerges 能级索引 (mlevel) pub iimer: &'a mut [i32], /// Mermerges 数量 pub imer: &'a mut i32, // 谱线轮廓 (nd × nfreql) pub prflin: &'a mut [f32], // 下沉修正因子 (mmcdw × nd) pub dwf1: &'a mut [f64], // 氢积分数据 /// WNHINT (nlmx × nd) - 氢波函数积分 pub wnhint: &'a [f64], /// XI2 (nlmx) - n² pub xi2: &'a [f64], /// XI3 (nlmx) - n³ pub xi3: &'a [f64], /// GMER (mmer × nd) - Mermerges 截面修正 pub gmer: &'a [f64], /// SGMG (mmer × nd) - Mermerges 截面 pub sgmg: &'a mut [f64], } /// 束缚-自由截面函数类型 pub type CrossFn = fn(ibft: usize, ij: usize) -> f64; /// 双电子截面函数类型 pub type CrossDFn = fn(ibft: usize, ij: usize, id: usize) -> f64; // ============================================================================ // 主函数 // ============================================================================ /// 计算单深度点的吸收、发射和散射系数。 /// /// 对于给定深度点 ID,计算所有频率点的不透明度。 /// /// # 参数 /// /// * `id` - 深度点索引 (1-indexed) /// * `nfrq` - 频率点数 /// * `config` - 配置参数 /// * `model` - 模型状态 /// * `atomic` - 原子数据 /// * `freq_params` - 频率数据 /// * `output` - 输出数组 pub fn opacf0( id: usize, nfrq: usize, config: &Opacf0Config, model: &mut Opacf0ModelState, atomic: &mut Opacf0AtomicParams, freq_params: &Opacf0FreqParams, output: &mut Opacf0Output, ) { let id_idx = id - 1; // 转换为 0-indexed let nd = model.nd; // ======================================================================== // 1. 初始化深度相关温度量 (类似 TDPINI) // ======================================================================== let t = model.temp[id_idx]; let t1 = UN / t; model.hkt1[id_idx] = HK * t1; model.hkt21[id_idx] = model.hkt1[id_idx] * t1; model.tk1[id_idx] = model.hkt1[id_idx] / H; model.sqt1[id_idx] = t.sqrt(); model.temp1[id_idx] = t1; // 调用 GFREE0 初始化自由-自由 Gaunt 因子 // CALL GFREE0(ID) - 由外部调用或在此调用 // ======================================================================== // 2. 初始化电子密度相关量 (类似 OPAINI) // ======================================================================== let ane = model.elec[id_idx]; model.elec1[id_idx] = UN / ane; model.dens1[id_idx] = UN / model.dens[id_idx]; model.densi[id_idx] = model.dens1[id_idx]; if config.izscal == 1 { model.densim[id_idx] = model.densi[id_idx] * model.wmm[id_idx]; } else { model.densim[id_idx] = 0.0; model.densi[id_idx] = UN; } model.elscat[id_idx] = ane * SIGE; // 调用辅助函数 // CALL DWNFR0(ID) - 下沉修正初始化 // CALL WNSTOR(ID) - 氢积分存储 // CALL SABOLF(ID) - 束缚-自由 Sa Boltzmann 因子 // ======================================================================== // 3. 计算束缚-自由不透明度预备量 // ======================================================================== for ibft in 0..atomic.ntranc { let itr = atomic.itrbf[ibft] as usize - 1; if atomic.indexp[itr] != 0 { let ii = atomic.ilow[itr] as usize - 1; let jj = atomic.iup[itr] as usize - 1; let it = atomic.itra[jj * MLEVEL + ii] as usize; if it > 0 { let ie = atomic.iel[ii] as usize - 1; let nke = atomic.nnext[ie] as usize - 1; let corr = if nke != jj { let g_ratio = atomic.g[nke] / atomic.g[jj]; let delta_e = atomic.enion[nke] - atomic.enion[jj]; g_ratio * (delta_e * model.tk1[id_idx]).exp() } else { UN }; // ABTRA(ITR,ID) = POPUL(II,ID) let popul_ii = get_popul(atomic.nlevel, id_idx, ii, model.popul); output.abtra[itr * nd + id_idx] = popul_ii; // EMTRA(ITR,ID) = POPUL(JJ,ID)*ANE*SBF(II)*WOP(II,ID)*CORR let popul_jj = get_popul(atomic.nlevel, id_idx, jj, model.popul); let wop_ii = get_wop(atomic.nlevel, id_idx, ii, atomic.wop); let emis_val = popul_jj * ane * atomic.sbf[ii] * wop_ii * corr; output.emtra[itr * nd + id_idx] = emis_val; } } } // ======================================================================== // 4. 计算自由-自由不透明度预备量 // ======================================================================== if atomic.ielhm > 0 { let nf_h = atomic.nfirst[(atomic.ielhm - 1) as usize] as usize - 1; let popul_h = get_popul(atomic.nlevel, id_idx, nf_h, model.popul); output.cffn[id_idx] = popul_h * ane; output.cfft[id_idx] = CFF2 - CFF3 / t; } let sgff = SGFF0 / model.sqt1[id_idx] * ane; for ion in 0..atomic.nion { let ion_idx = ion; let ff_val = atomic.ff[ion_idx]; output.sff2[ion_idx * nd + id_idx] = (ff_val * model.hkt1[id_idx]).exp(); let nnext_idx = atomic.nnext[ion_idx] as usize - 1; let popul_nnext = get_popul(atomic.nlevel, id_idx, nnext_idx, model.popul); let charg2 = atomic.charg2[ion_idx]; output.sff3[ion_idx * nd + id_idx] = popul_nnext * charg2 as f64 * sgff; } // ======================================================================== // 5. 初始化 Mermerges 数据 (类似 SGMER0) // ======================================================================== *output.imer = 0; for ii in 0..atomic.nlevel { if atomic.ifwop[ii] < 0 { *output.imer += 1; let imer_val = (*output.imer - 1) as usize; // 0-indexed atomic.imrg[ii] = (*output.imer) as i32; output.iimer[imer_val] = ii as i32; let ie = atomic.iel[ii] as usize - 1; let ch = (atomic.iz[ie] * atomic.iz[ie]) as f64; output.frch[imer_val] = FRH * ch; output.sgm0[imer_val] = PH2 * ch * ch; let ii0 = if ii > 0 { atomic.nquant[ii - 1] as usize } else { 0 } + 1; let ex = EHB * ch * model.temp1[id_idx]; // 计算积分 for i in ii0..NLMX { let sum_i = compute_sgmsum( i, ex, id_idx, nd, output.xi2, output.xi3, output.wnhint, output.gmer, output.sgm0[imer_val], atomic.nlevel, ); output.sgmsum[i * MMER * nd + imer_val * nd + id_idx] = sum_i; } } } // ======================================================================== // 6. 初始化谱线不透明度 (如果 nfrq > nfreqc) // ======================================================================== let laser = config.iter > config.itlas; if nfrq > atomic.nfreqc { // 初始化主谱线轮廓 for itr in 0..atomic.ntrans { if atomic.line[itr] == 0 { continue; } if atomic.intmod[itr] == 0 { continue; } let indxa = atomic.indexp[itr].abs(); let ijl0 = if config.ispodf >= 1 { atomic.kfr0[itr] as usize } else { atomic.ifr0[itr] as usize }; let ijl1 = if config.ispodf >= 1 { atomic.kfr1[itr] as usize } else { atomic.ifr1[itr] as usize }; if indxa < 2 || indxa > 4 { // 调用 LINPRO 计算谱线轮廓 // CALL LINPRO(ITR,ID,PRF) // 这里需要外部提供 LINPRO 实现 } } // 计算谱线吸收/发射系数 // (这部分在原代码中有 bug - 循环外的代码使用了循环内的变量) } // ======================================================================== // 7. 循环频率点计算不透明度 // ======================================================================== let icall = 1; for ij in 0..nfrq { let ij_idx = ij; // Compton 散射 if config.icompt > 0 && ij_idx < freq_params.sigec.len() { model.elscat[id_idx] = model.elec[id_idx] * freq_params.sigec[ij_idx]; } // 初始化 output.abso[ij_idx] = model.elscat[id_idx]; output.emis[ij_idx] = 0.0; output.scat[ij_idx] = model.elscat[id_idx]; // 基本频率量 let fr = freq_params.freq[ij_idx]; let frinv = UN / fr; let fr3inv = frinv * frinv * frinv; output.xkf[id_idx] = (-model.hkt1[id_idx] * fr).exp(); output.xkf1[id_idx] = UN - output.xkf[id_idx]; output.xkfb[id_idx] = output.xkf[id_idx] * freq_params.bnue[ij_idx]; // -------------------------------------------------------------------- // 7.1 束缚-自由贡献 // -------------------------------------------------------------------- for ibft in 0..atomic.ntranc { let itr = atomic.itrbf[ibft] as usize - 1; let ii = atomic.ilow[itr] as usize - 1; // 跳过特殊原子处理 let iatm_ii = atomic.iatm[ii] as usize - 1; if iatm_ii < atomic.iadop.len() && atomic.iadop[iatm_ii] > 0 && fr <= freq_params.frtabm { continue; } // 获取截面 let sg = if config.ifdiel == 0 { // SG = CROSS(IBFT,IJ) 0.0 // 需要外部截面函数 } else { // SG = CROSSD(IBFT,IJ,ID) 0.0 // 需要外部截面函数 }; // Mermerges 处理 if atomic.ifwop[ii] < 0 { let imer = atomic.imrg[ii] as usize - 1; // 调用 SGMER1 // CALL SGMER1(FRINV,FR3INV,IMER,ID,SGME1) // output.sgmg[imer * nd + id_idx] = sgme1; } if sg <= 0.0 { continue; } // Macfarlane 下沉修正 if atomic.mcdw[itr] > 0 { let izz = atomic.iz[atomic.iel[ii] as usize - 1]; // 调用 DWNFR1 // CALL DWNFR1(FR,FR0(ITR),ID,IZZ,DW1) // let dw1 = ...; // output.dwf1[(atomic.mcdw[itr] - 1) as usize * nd + id_idx] = dw1; // sg = sg * dw1; } let emis_bf = sg * output.emtra[itr * nd + id_idx]; output.abso[ij_idx] += sg * output.abtra[itr * nd + id_idx]; output.emis[ij_idx] += emis_bf; } // -------------------------------------------------------------------- // 7.2 自由-自由贡献 // -------------------------------------------------------------------- for ion in 0..atomic.nion { let nnext_idx = atomic.nnext[ion] as usize - 1; let it = atomic.itra[nnext_idx * MLEVEL + nnext_idx]; // 跳过特殊原子处理 if nnext_idx < atomic.nlevel { let iatm = atomic.iatm[nnext_idx] as usize - 1; if iatm < atomic.iadop.len() && atomic.iadop[iatm] > 0 && fr <= freq_params.frtabm { continue; } } let absoff = match it { 1 => { // 氢型 Gaunt = 1 let sf1 = output.sff3[ion * nd + id_idx] * fr3inv; let sf2 = if fr < atomic.ff[ion] { UN / output.xkf[id_idx] } else { output.sff2[ion * nd + id_idx] }; sf1 * sf2 } 2 => { // 氢型精确 Gaunt let sf1 = output.sff3[ion * nd + id_idx] * fr3inv; let sf2 = if fr < atomic.ff[ion] { UN / output.xkf[id_idx] } else { output.sff2[ion * nd + id_idx] }; let x = C14 * atomic.charg2[ion] as f64 / fr; // sf2 = sf2 - UN + GFREE1(ID,X) sf1 * sf2 } 3 => { // H⁻ 自由-自由 // SFFHMI(POPUL(NFIRST(IELH),ID),FR,TEMP(ID)) * ELEC(ID) let nf_h = atomic.nfirst[(atomic.ielh - 1) as usize] as usize - 1; let popul_h = get_popul(atomic.nlevel, id_idx, nf_h, model.popul); // 调用 sffhmi let sffhmi_val = compute_sffhmi(popul_h, fr, t); sffhmi_val * model.elec[id_idx] } _ if it < 0 => { // 特殊截面 // FFCROS(ION,IT,TEMP(ID),FR) * POPUL(NNEXT(ION),ID) * ELEC(ID) let popul_nnext = get_popul(atomic.nlevel, id_idx, nnext_idx, model.popul); // 调用 ffcros 0.0 * popul_nnext * model.elec[id_idx] } _ => 0.0, }; output.abso[ij_idx] += absoff; output.emis[ij_idx] += absoff; } // -------------------------------------------------------------------- // 7.3 附加不透明度 (OPADD) // -------------------------------------------------------------------- if config.iopadd != 0 { // 调用 OPADD // CALL OPADD(0,ICALL,IJ,ID) // output.abso[ij_idx] += abad; // output.emis[ij_idx] += emad; // output.scat[ij_idx] += scad; } // -------------------------------------------------------------------- // 7.4 谱线贡献 // -------------------------------------------------------------------- if config.ispodf == 0 { // 标准模式 if freq_params.ijlin[ij_idx] > 0 { let itr = (freq_params.ijlin[ij_idx] - 1) as usize; let iad = if atomic.ilow[itr] > 0 { let ilow_idx = atomic.ilow[itr] as usize - 1; let iatm = atomic.iatm[ilow_idx] as usize - 1; if iatm < atomic.iadop.len() { atomic.iadop[iatm] } else { 0 } } else { 0 }; let lfre = fr > freq_params.frtabm; if iad == 0 || (lfre && iad > 0) { let sg = get_prflin(id_idx, ij_idx, nd, output.prflin); output.abso[ij_idx] += sg as f64 * output.abtra[itr * nd + id_idx]; output.emis[ij_idx] += sg as f64 * output.emtra[itr * nd + id_idx]; } } // 重叠谱线 if freq_params.nlines[ij_idx] > 0 { for ilint in 0..freq_params.nlines[ij_idx] as usize { let itrlin_idx = ilint * freq_params.nfreq + ij_idx; let itr = freq_params.itrlin[itrlin_idx] as usize - 1; let iad = if atomic.ilow[itr] > 0 { let ilow_idx = atomic.ilow[itr] as usize - 1; let iatm = atomic.iatm[ilow_idx] as usize - 1; if iatm < atomic.iadop.len() { atomic.iadop[iatm] } else { 0 } } else { 0 }; let lfre = fr > freq_params.frtabm; if iad > 0 && !lfre { continue; } // 跳过展开谱线 // if linexp[itr] { continue; } // 插值计算轮廓 let ijl0 = atomic.ifr0[itr] as usize - 1; let ijl1 = atomic.ifr1[itr] as usize - 1; // 找到频率位置 let (ij0, ij1) = find_frequency_bounds( ij_idx, ijl0, ijl1, freq_params.freq, fr ); if ij0 > 0 && ij1 < freq_params.nfreq { let x = UN / (freq_params.freq[ij1] - freq_params.freq[ij0]); let a1 = (fr - freq_params.freq[ij0]) * x; let a2 = (freq_params.freq[ij1] - fr) * x; let sg_ij0 = get_prflin(id_idx, ij0, nd, output.prflin); let sg_ij1 = get_prflin(id_idx, ij1, nd, output.prflin); let sg = a1 * sg_ij0 as f64 + a2 * sg_ij1 as f64; output.abso[ij_idx] += sg as f64 * output.abtra[itr * nd + id_idx]; output.emis[ij_idx] += sg as f64 * output.emtra[itr * nd + id_idx]; } } } } else { // ODF 采样模式 if freq_params.nlines[ij_idx] > 0 { for ilint in 0..freq_params.nlines[ij_idx] as usize { let itrlin_idx = ilint * freq_params.nfreq + ij_idx; let itr = freq_params.itrlin[itrlin_idx] as usize - 1; let iad = if atomic.ilow[itr] > 0 { let ilow_idx = atomic.ilow[itr] as usize - 1; let iatm = atomic.iatm[ilow_idx] as usize - 1; if iatm < atomic.iadop.len() { atomic.iadop[iatm] } else { 0 } } else { 0 }; let lfre = fr > freq_params.frtabm; if iad > 0 && !lfre { continue; } let kj = ij - atomic.ifr0[itr] as usize + 1 + atomic.kfr0[itr] as usize - 1; let indxpa = atomic.indexp[itr].abs(); if indxpa != 3 && indxpa != 4 { let sg = get_prflin(id_idx, kj, nd, output.prflin); output.abso[ij_idx] += sg as f64 * output.abtra[itr * nd + id_idx]; output.emis[ij_idx] += sg as f64 * output.emtra[itr * nd + id_idx]; } // else: ODF 插值模式 - 需要更多数据 } } } // -------------------------------------------------------------------- // 7.5 最终不透明度计算 // -------------------------------------------------------------------- output.abso[ij_idx] = output.abso[ij_idx] - output.emis[ij_idx] * output.xkf[id_idx]; output.emis[ij_idx] = output.emis[ij_idx] * output.xkfb[id_idx]; // -------------------------------------------------------------------- // 7.6 表格不透明度 // -------------------------------------------------------------------- if config.ioptab > 0 { // 调用 OPACT1 // CALL OPACT1(IJ) } } } // ============================================================================ // 辅助函数 // ============================================================================ /// 获取占据数 #[inline] fn get_popul(nlevel: usize, id: usize, level: usize, popul: &[f64]) -> f64 { if level < nlevel { popul[level * 100 + id] // 假设 nd 最大为 100 } else { 0.0 } } /// 获取束缚-自由权重 #[inline] fn get_wop(nlevel: usize, id: usize, level: usize, wop: &[f64]) -> f64 { if level < nlevel { wop[level * 100 + id] } else { 1.0 } } /// 获取谱线轮廓 #[inline] fn get_prflin(id: usize, ij: usize, nd: usize, prflin: &[f32]) -> f32 { let idx = id * MFREQL + ij; if idx < prflin.len() { prflin[idx] } else { 0.0 } } /// 计算 Mermerges 截面积分 fn compute_sgmsum( i: usize, ex: f64, id: usize, nd: usize, xi2: &[f64], xi3: &[f64], wnhint: &[f64], gmer: &[f64], sgm0: f64, nlevel: usize, ) -> f64 { if i >= NLMX { return 0.0; } let exi = (ex * xi2[i]).exp(); let wnhint_val = if id < 100 && i < NLMX { wnhint[i * 100 + id] } else { 0.0 }; let s = exi * wnhint_val * xi3[i]; // 这里应该是一个递归求和,简化处理 s * sgm0 / if id < 100 { gmer[id] } else { 1.0 } } /// 计算 H⁻ 自由-自由截面 (简化版) fn compute_sffhmi(popul_h: f64, _fr: f64, _temp: f64) -> f64 { // 简化实现,实际应调用 sffhmi 模块 popul_h * CFF1 } /// 找到频率边界 fn find_frequency_bounds( ij: usize, ijl0: usize, ijl1: usize, freq: &[f64], fr: f64, ) -> (usize, usize) { let mut ij0 = ijl0; for ijt in ijl0..=ijl1 { if ijt < freq.len() && freq[ijt] <= fr { ij0 = ijt; } else { break; } } let ij1 = if ij0 > 0 { ij0 - 1 } else { ij0 }; (ij0, ij1) } // ============================================================================ // 测试 // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_opacf0_config_default() { let config = Opacf0Config::default(); assert_eq!(config.icompt, 0); assert_eq!(config.ispodf, 0); assert_eq!(config.iter, 1); } #[test] fn test_constants() { // 验证物理常数 assert!((FRH - 3.28805e15).abs() < 1e10); assert!((PH2 - 5.63e29).abs() < 1e27); assert!((SGFF0 - 3.694e8).abs() < 1e5); } #[test] fn test_helper_functions() { // 测试 get_popul - 使用正确大小的数组 // 假设 nlevel=2, nd=100, 需要 2*100=200 个元素 let mut popul = vec![0.0; 200]; popul[1 * 100 + 0] = 5.0; // level=1, id=0 let val = get_popul(2, 0, 1, &popul); assert_eq!(val, 5.0); // 越界测试 let val_oob = get_popul(2, 0, 5, &popul); // level=5 >= nlevel=2 assert_eq!(val_oob, 0.0); // 测试 find_frequency_bounds let freq = vec![1.0, 2.0, 3.0, 4.0, 5.0]; let (ij0, ij1) = find_frequency_bounds(2, 0, 4, &freq, 3.5); assert_eq!(ij0, 2); // freq[2] = 3.0 <= 3.5 assert_eq!(ij1, 1); // ij0 - 1 } }