//! Rybicki 形式完全线性化矩阵计算。 //! //! 重构自 TLUSTY `rybmat.f` use crate::tlusty::state::constants::{HALF, MDEPTH, TWO, UN}; /// 物理常数 const BN: f64 = 1.4743e-2; // Planck 常数前因子 const HK: f64 = 4.79928144e-11; // h/k (s·K) /// Rybicki 矩阵输入参数。 pub struct RybmatParams<'a> { /// 频率索引 (0-indexed) pub ij: usize, /// 深度点数 pub nd: usize, // 深度相关数组 pub dm: &'a [f64], pub temp: &'a [f64], pub dens: &'a [f64], // ALIPAR 相关 pub abso1: &'a [f64], pub scat1: &'a [f64], pub emis1: &'a [f64], pub fak1: &'a [f64], pub rad1: &'a [f64], pub dabt1: &'a [f64], pub demt1: &'a [f64], pub deldm: &'a [f64], // 配置参数 pub isplin: i32, pub iubc: i32, pub ibc: i32, pub idisk: i32, pub ifryb: i32, pub reint: &'a [f64], pub redif: &'a [f64], pub w: &'a [f64], pub freq: &'a [f64], pub fh: &'a [f64], pub fhd: &'a [f64], pub icentr: i32, pub ilbc: i32, pub nretc: usize, // DSCTVA pub dsct1: &'a [f64], pub dscn1: &'a [f64], // 频率索引映射 (1-indexed) pub ijfr: &'a [i32], // 上边界条件额外参数 pub extrad: &'a [f64], // EXTRAD(IJ): 外部辐射 pub q0: &'a [f64], // Q0(IJ): 边界条件参数 pub uu0: &'a [f64], // UU0(IJ): 边界条件参数 } /// Rybicki 矩阵输出结构体。 #[derive(Debug, Clone)] pub struct RybmatResult { pub ra: Vec, pub rb: Vec, pub rc: Vec, pub vr: Vec, pub ua: Vec, pub ub: Vec, pub uc: Vec, pub va: Vec, pub vb: Vec, pub vc: Vec, pub wr: Vec, pub wm: Vec>, } impl Default for RybmatResult { fn default() -> Self { Self { ra: vec![0.0; MDEPTH], rb: vec![0.0; MDEPTH], rc: vec![0.0; MDEPTH], vr: vec![0.0; MDEPTH], ua: vec![0.0; MDEPTH], ub: vec![0.0; MDEPTH], uc: vec![0.0; MDEPTH], va: vec![0.0; MDEPTH], vb: vec![0.0; MDEPTH], vc: vec![0.0; MDEPTH], wr: vec![0.0; MDEPTH], wm: vec![vec![0.0; MDEPTH]; MDEPTH], } } } /// 计算 Rybicki 形式完全线性化矩阵。 pub fn rybmat(params: &RybmatParams) -> RybmatResult { let mut result = RybmatResult::default(); const SIXTH: f64 = UN / 6.0; const THIRD: f64 = UN / 3.0; const TWOTHR: f64 = TWO / 3.0; let nd = params.nd; let ijt = (params.ijfr[params.ij] - 1) as usize; // Fortran 1-indexed 转 0-indexed // ============================================================== // 1. 上边界条件 (Fortran ID=1, Rust ID=0) // ============================================================== let id = 0; let ddm = (params.dm[id + 1] - params.dm[id]) * HALF; let dtm = UN / ((params.abso1[id] + params.abso1[id + 1]) * ddm); let dtm2 = dtm * dtm; let alf = dtm * ddm; let fd = TWO * params.fh[ijt]; let exti = params.extrad[params.ij]; let bet = (exti - fd * params.rad1[id]) * dtm; let gam = (params.fak1[id] * params.rad1[id] - params.fak1[id + 1] * params.rad1[id + 1]) * TWO * dtm2; let s0 = (params.emis1[id] + params.scat1[id] * params.rad1[id]) / params.abso1[id]; let c1 = alf * (TWO * gam - bet); let b1 = c1 - s0 / params.abso1[id]; let q0_ij = params.q0[params.ij]; let uu0_ij = params.uu0[params.ij]; let unq = UN + TWO * dtm * q0_ij; result.rb[id] = -(UN + dtm * (fd + TWO * params.fak1[id] * dtm)) + params.scat1[id] / params.abso1[id] * unq; result.rc[id] = TWO * params.fak1[id + 1] * dtm2; result.vr[id] = gam - bet + params.rad1[id] - s0 * unq; // UB, UC 完整计算 result.ub[id] = b1 * params.dabt1[id] + (params.demt1[id] + params.dsct1[id] * params.rad1[id]) / params.abso1[id] * unq - params.emis1[id] / params.abso1[id] / params.abso1[id] * params.dabt1[id] * TWO * dtm * q0_ij + dtm * s0 * (uu0_ij * params.dm[0] * params.dabt1[id] - TWO * q0_ij * dtm * ddm * params.dabt1[id]); result.uc[id] = c1 * params.dabt1[id + 1] - TWO * dtm * q0_ij * s0 * dtm * ddm * params.dabt1[id + 1]; // IUBC 边界条件修正 if params.iubc > 0 { let corf = HALF / dtm; result.rb[id] *= corf; result.rc[id] *= corf; result.vr[id] *= corf; let c1 = (gam - params.rad1[id] + s0) * corf * alf; let b1 = c1 - corf * s0 / params.abso1[id]; result.ub[id] = b1 * params.dabt1[id] + (params.demt1[id] + params.dsct1[id] * params.rad1[id]) / params.abso1[id] * corf; result.uc[id] = c1 * params.dabt1[id + 1]; } // ============================================================== // 2. 深度循环 (Fortran ID=2 到 ND-1, Rust ID=1 到 ND-2) // ============================================================== for id in 1..nd - 1 { let ddm = (params.dm[id] - params.dm[id - 1]) * HALF; let ddp = (params.dm[id + 1] - params.dm[id]) * HALF; let dzm = params.abso1[id] + params.abso1[id - 1]; let dzp = params.abso1[id] + params.abso1[id + 1]; let dtaup = dzp * ddp; let dtaum = dzm * ddm; let dtau0 = HALF * (dtaup + dtaum); let frd = params.fak1[id] * params.rad1[id]; let alf1 = (frd - params.fak1[id + 1] * params.rad1[id + 1]) / dtaup / dtau0; let gam1 = (frd - params.fak1[id - 1] * params.rad1[id - 1]) / dtaum / dtau0; let bet1 = alf1 + gam1; let x1 = HALF * bet1 / dtau0; let mut a1 = (gam1 + x1 * dtaum) / dzm; let mut c1 = (alf1 + x1 * dtaup) / dzp; let mut b1 = a1 + c1; let chielm = params.scat1[id - 1]; let chiel0 = params.scat1[id]; let chielp = params.scat1[id + 1]; let s0 = (params.emis1[id] + chiel0 * params.rad1[id]) / params.abso1[id]; // 初始化 spline/hermitian 参数 let (as_val, cs_val, bs_val, bet2, a2, c2, sm, sp) = if params.isplin % 3 == 0 { // 简单一阶差分 (0.0, 0.0, UN, 0.0, 0.0, 0.0, 0.0, 0.0) } else { let sm = (params.emis1[id - 1] + params.rad1[id - 1] * chielm) / params.abso1[id - 1]; let sp = (params.emis1[id + 1] + params.rad1[id + 1] * chielp) / params.abso1[id + 1]; if params.isplin == 1 { // Spline collocation let as_val = dtaum / dtau0 * SIXTH; let cs_val = dtaup / dtau0 * SIXTH; let bs_val = TWOTHR; // 0.666666666666667 let alf2 = as_val * (params.rad1[id - 1] - sm); let gam2 = cs_val * (params.rad1[id + 1] - sp); let bet2 = alf2 + gam2; let x = HALF * bet2 / dtau0; let a2 = (gam2 - x * dtaum) / dzm; let c2 = (alf2 - x * dtaup) / dzp; (as_val, cs_val, bs_val, bet2, a2, c2, sm, sp) } else { // Hermitian method (ISPLIN=2) let as_init = dtaup * dtaup / dtaum / dtau0; let cs_init = dtaum * dtaum / dtaup / dtau0; let al3 = (params.rad1[id + 1] - sp - params.rad1[id] + s0) * SIXTH; let ga3 = (params.rad1[id - 1] - sm - params.rad1[id] + s0) * SIXTH; let av = al3 * cs_init; let cv = ga3 * as_init; let as_val = (UN - HALF * as_init) * SIXTH; let cs_val = (UN - HALF * cs_init) * SIXTH; let bs_val = UN - as_val - cs_val; let x = (av + cv) / dtau0 / 4.0; let a2 = (x * dtaum + HALF * cv - av) / dzm; let c2 = (x * dtaup + HALF * av - cv) / dzp; let bet2 = as_val * (params.rad1[id - 1] - sm) + cs_val * (params.rad1[id + 1] - sp); (as_val, cs_val, bs_val, bet2, a2, c2, sm, sp) } }; // 辅助量 b1 = b1 - (a2 + c2); a1 = a1 - a2; c1 = c1 - c2; let a2_coeff = as_val / params.abso1[id - 1]; let c2_coeff = cs_val / params.abso1[id + 1]; let a3 = a2_coeff * sm; let c3 = c2_coeff * sp; let b2 = bs_val / params.abso1[id]; let b3 = b2 * s0; let a1 = a1 - a3; let b1 = b1 - b3; let c1 = c1 - c3; // 矩阵元素 result.ra[id] = params.fak1[id - 1] / dtaum / dtau0 - as_val * (UN - chielm / params.abso1[id - 1]); result.rb[id] = -params.fak1[id] / dtau0 * (UN / dtaup + UN / dtaum) - bs_val * (UN - chiel0 / params.abso1[id]); result.rc[id] = params.fak1[id + 1] / dtaup / dtau0 - cs_val * (UN - chielp / params.abso1[id + 1]); result.vr[id] = bet1 + bet2 + bs_val * (params.rad1[id] - s0); result.ua[id] = a1 * params.dabt1[id - 1] + a2_coeff * (params.demt1[id - 1] + params.dsct1[id - 1] * params.rad1[id - 1]); result.ub[id] = b1 * params.dabt1[id] + b2 * (params.demt1[id] + params.dsct1[id] * params.rad1[id]); result.uc[id] = c1 * params.dabt1[id + 1] + c2_coeff * (params.demt1[id + 1] + params.dsct1[id + 1] * params.rad1[id + 1]); } // ============================================================== // 3. 下边界条件 (Fortran ID=ND, Rust ID=ND-1) // ============================================================== let id = nd - 1; let ddm = HALF * (params.dm[id] - params.dm[id - 1]); let t0 = params.temp[id]; let tm = params.temp[id - 1]; if params.ibc > 0 && params.ibc < 4 && params.idisk == 0 { // Planck 函数边界条件 let dtm = UN / ((params.abso1[id - 1] + params.abso1[id]) * ddm); let dtm2 = dtm * dtm; let fd = TWO * params.fhd[ijt]; let fr = params.freq[ijt]; let fr15 = fr * 1e-15; let bnu = BN * fr15 * fr15 * fr15; let x0 = HK * fr / t0; let xm = HK * fr / tm; let pland = bnu / (x0.exp() - UN); let planm = bnu / (xm.exp() - UN); let dpldt0 = pland / (UN - (-x0).exp()) * x0 / t0; let dpldtm = planm / (UN - (-xm).exp()) * xm / tm; let alf = dtm * ddm; let bet = (pland - fd * params.rad1[id]) * dtm; let gam = (params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1] - THIRD * (pland - planm)) * TWO * dtm2; let s0 = (params.emis1[id] + params.scat1[id] * params.rad1[id]) / params.abso1[id]; let a1 = alf * (TWO * gam - bet); let b1 = a1 - s0 / params.abso1[id]; result.ra[id] = TWO * params.fak1[id - 1] * dtm2; result.rb[id] = -(UN + dtm * (fd + TWO * params.fak1[id] * dtm)) + params.scat1[id] / params.abso1[id]; result.vr[id] = gam - bet + params.rad1[id] - s0; result.ua[id] = b1 * params.dabt1[id - 1] + (params.demt1[id - 1] + params.dsct1[id - 1] * params.rad1[id - 1]) / params.abso1[id - 1] - dpldtm * dtm2 * TWOTHR; result.ub[id] = b1 * params.dabt1[id] + (params.demt1[id] + params.dsct1[id] * params.rad1[id]) / params.abso1[id] + dpldt0 * dtm * (UN + TWOTHR * dtm); // IFRYB > 0 分支:Rybicki 特殊边界条件 if params.ifryb > 0 { let dtm = UN / ((params.abso1[id - 1] + params.abso1[id]) * ddm); let fr = params.freq[ijt]; let fr15 = fr * 1e-15; let bnu = BN * fr15 * fr15 * fr15; let x0 = HK * fr / t0; let xm = HK * fr / tm; let pland = bnu / (x0.exp() - UN); let planm = bnu / (xm.exp() - UN); let dpldt0 = pland / (UN - (-x0).exp()) * x0 / t0; let dpldtm = planm / (UN - (-xm).exp()) * xm / tm; let gam = (params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1] - THIRD * (pland - planm)) * dtm; let s0 = (params.emis1[id] + params.scat1[id] * params.rad1[id]) / params.abso1[id]; let bs = HALF / dtm; let bet = bs * (params.rad1[id] - s0); let a1 = (gam - bet) * dtm * ddm; let b1 = a1 - bs * s0 / params.abso1[id]; result.ra[id] = params.fak1[id - 1] * dtm; result.rb[id] = -params.fak1[id] * dtm - bs * (UN - params.scat1[id] / params.abso1[id]) - params.fhd[ijt]; result.vr[id] = gam + bet - HALF * pland + params.fhd[ijt] * params.rad1[id]; result.ua[id] = a1 * params.dabt1[id - 1] - dpldtm * dtm * THIRD; result.ub[id] = b1 * params.dabt1[id] + bs * (params.demt1[id] + params.dsct1[id] * params.rad1[id]) / params.abso1[id] + (HALF + THIRD * dtm) * dpldt0; } } else { // 磁盘模式:I(taumax,-mu,nu) = I(taumax,+mu,nu) let dzm = params.abso1[id] + params.abso1[id - 1]; let frd = params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1]; let dtaum = dzm * ddm; let gam1 = frd / dtaum; let a2 = 0.0; // AS = 0 in this branch let a1 = gam1 / dzm; let bs = dtaum * HALF; let s0 = (params.emis1[id] + params.scat1[id] * params.rad1[id]) / params.abso1[id]; let gam2 = bs * (params.rad1[id] - s0); let x1 = gam2 / dzm; let a1 = a1 - x1; let b2 = bs / params.abso1[id]; let b1 = a1 - b2 * s0; result.ra[id] = params.fak1[id - 1] / dtaum - a2 * (UN - params.scat1[id - 1] / params.abso1[id - 1]); result.rb[id] = -params.fak1[id] / dtaum - bs * (UN - params.scat1[id] / params.abso1[id]); result.ua[id] = a1 * params.dabt1[id - 1] + a2 / params.abso1[id - 1] * (params.demt1[id - 1] + params.dsct1[id - 1] * params.rad1[id - 1]); result.ub[id] = b1 * params.dabt1[id] + b2 * (params.demt1[id] + params.dsct1[id] * params.rad1[id]); result.vr[id] = gam1 + gam2; } // ============================================================== // 4. 辐射平衡部分 // ============================================================== // 4a. 积分方程部分 for id in 0..nd { if params.reint[id] > 0.0 { let heat = params.abso1[id] - params.scat1[id]; let dheat = (params.dabt1[id] - params.dsct1[id]) * params.rad1[id]; let wdr = params.w[params.ij] * params.dens[id] * params.reint[id]; result.vb[id] = heat * wdr; result.wm[id][id] += (dheat - params.demt1[id]) * wdr; result.wr[id] -= (heat * params.rad1[id] - params.emis1[id]) * wdr; } } // 4b. 微分方程部分 - ID=0 (Fortran ID=1) 特殊处理 let id = 0; if params.redif[id] > 0.0 { let wf = params.w[params.ij] * params.fh[ijt] * params.redif[id]; result.vb[id] += wf; result.wr[id] -= wf * params.rad1[id]; } // 4c. 微分方程部分 - 主循环 if params.icentr == 0 { // 一阶中点差分格式 let nd1 = if params.ilbc != 0 { nd - 1 } else { nd }; for id in 1..nd1 { if params.redif[id] > 0.0 { let ddm = (params.dm[id] - params.dm[id - 1]) * HALF; let omeg0 = params.abso1[id]; let omegm = params.abso1[id - 1]; let dtaum = (omeg0 + omegm) * ddm; let frd = params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1]; let gamr = frd / dtaum * params.redif[id]; let a1 = gamr / (omeg0 + omegm); result.va[id] -= params.w[params.ij] * params.fak1[id - 1] / dtaum * params.redif[id]; result.vb[id] += params.w[params.ij] * params.fak1[id] / dtaum * params.redif[id]; result.wm[id][id - 1] -= a1 * params.w[params.ij] * params.dabt1[id - 1]; result.wm[id][id] -= a1 * params.w[params.ij] * params.dabt1[id]; result.wr[id] -= params.w[params.ij] * gamr; } } // ILBC 边界条件处理 if params.ilbc > 0 { let id = nd - 1; if params.redif[id] > 0.0 { let ddm = (params.dm[id] - params.dm[id - 1]) * HALF; let dtaum = (params.abso1[id] + params.abso1[id - 1]) * ddm * 3.0; let fr = params.freq[ijt]; let fr15 = fr * 1e-15; let bnu = BN * fr15 * fr15 * fr15; let x0 = HK * fr / params.temp[id]; let xm = HK * fr / params.temp[id - 1]; let pland = bnu / (x0.exp() - UN); let planm = bnu / (xm.exp() - UN); let dpldt0 = pland / (UN - (-x0).exp()) * x0 / params.temp[id]; let dpldtm = planm / (UN - (-xm).exp()) * xm / params.temp[id - 1]; let flx = (pland - planm) / dtaum * params.redif[id]; let a1 = flx / (params.abso1[id] + params.abso1[id - 1]); result.wm[id][id - 1] += params.w[params.ij] * (dpldtm - a1 * params.dabt1[id - 1]); result.wm[id][id] += params.w[params.ij] * (dpldt0 - a1 * params.dabt1[id]); result.wr[id] -= params.w[params.ij] * flx; } } } else { // 中心差分格式 (ICENTR != 0) for id in 1..nd - 1 { if params.redif[id] > 0.0 { let wwr = params.w[params.ij] * params.redif[id]; let ddm = HALF * (params.dm[id] - params.dm[id - 1]); let ddp = HALF * (params.dm[id + 1] - params.dm[id]); let dtm = (params.abso1[id - 1] + params.abso1[id]) * ddm; let dtp = (params.abso1[id + 1] + params.abso1[id]) * ddp; let dt0 = dtm + dtp; let frm = params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1]; let frp = params.fak1[id + 1] * params.rad1[id + 1] - params.fak1[id] * params.rad1[id]; let alp = dtp / dtm / dt0; let gam = dtm / dtp / dt0; let flx = alp * frm + gam * frp; // 矩阵元素 result.va[id] -= wwr * params.fak1[id - 1] * alp; result.vb[id] += wwr * params.fak1[id] * (alp - gam); result.vc[id] = wwr * params.fak1[id + 1] * gam; let dmtm = ddm / (dtm * dtm); let dmtp = ddp / (dtp * dtp); let rm = dtm / dt0; let rp = dtp / dt0; result.wm[id][id - 1] += wwr * params.dabt1[id - 1] * dmtm * (rm * rm * frp - (UN + rm) * frm); result.wm[id][id] += wwr * params.dabt1[id] * ((dmtp * rp * rp - dmtm * rp * (UN + rm)) * frm + (dmtm * rm * rm - dmtp * rm * (UN + rp)) * frp); result.wr[id] -= wwr * flx; } } // 下边界 (ID=ND-1) let id = nd - 1; if params.redif[id] > 0.0 { let ddm = HALF * (params.dm[id] - params.dm[id - 1]); let dtaum = (params.abso1[id] + params.abso1[id - 1]) * ddm; let frd = params.fak1[id] * params.rad1[id] - params.fak1[id - 1] * params.rad1[id - 1]; let flx = frd / dtaum * params.redif[id]; let a1 = flx / (params.abso1[id] + params.abso1[id - 1]); result.va[id] -= params.w[params.ij] * params.fak1[id - 1] / dtaum * params.redif[id]; result.vb[id] += params.w[params.ij] * params.fak1[id] / dtaum * params.redif[id]; result.wm[id][id - 1] -= a1 * params.w[params.ij] * params.dabt1[id - 1]; result.wm[id][id] -= a1 * params.w[params.ij] * params.dabt1[id]; result.wr[id] -= params.w[params.ij] * flx; } } // 4d. 辐射平衡温度点修正 if params.nretc > 0 { for id in 0..params.nretc { result.wr[id] = 0.0; result.vb[id] = 0.0; result.va[id] = 0.0; result.wm[id][id] = 1.0; if id > 0 { result.wm[id][id - 1] = 0.0; } } } result } #[cfg(test)] mod tests { use super::*; #[test] fn test_rybmat_result_default() { let result = RybmatResult::default(); assert_eq!(result.ra.len(), MDEPTH); assert_eq!(result.rb.len(), MDEPTH); assert_eq!(result.wm.len(), MDEPTH); } #[test] fn test_rybmat_basic() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif = vec![0.0; MDEPTH]; let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 1, idisk: 0, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); } #[test] fn test_rybmat_with_extrad() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif = vec![0.0; MDEPTH]; let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad: Vec = (0..100).map(|i| 1e10 * (i as f64 + 1.0)).collect(); let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 1, idisk: 0, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); } #[test] fn test_rybmat_hermitian() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif = vec![0.0; MDEPTH]; let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 2, // Hermitian method iubc: 0, ibc: 1, idisk: 0, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); } #[test] fn test_rybmat_centered_difference() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif: Vec = (0..MDEPTH).map(|_| 0.1).collect(); let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 1, idisk: 0, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 1, // 使用中心差分 ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); assert!(result.vc[5].is_finite()); } #[test] fn test_rybmat_ifryb_branch() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif = vec![0.0; MDEPTH]; let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 1, idisk: 0, ifryb: 1, // 启用 Rybicki 特殊边界条件 reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); } #[test] fn test_rybmat_disk_mode() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint = vec![0.0; MDEPTH]; let redif = vec![0.0; MDEPTH]; let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 4, // 磁盘模式 idisk: 1, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); assert!(result.rb[0].is_finite()); assert!(result.vr[0].is_finite()); } #[test] fn test_rybmat_radiative_equilibrium() { let dm: Vec = (0..MDEPTH).map(|i| 0.01 + i as f64 * 0.01).collect(); let temp = vec![10000.0; MDEPTH]; let dens = vec![1e15; MDEPTH]; let abso1 = vec![1e-8; MDEPTH]; let scat1 = vec![1e-9; MDEPTH]; let emis1 = vec![1e-10; MDEPTH]; let fak1 = vec![0.5; MDEPTH]; let rad1 = vec![1e10; MDEPTH]; let dabt1 = vec![1e-12; MDEPTH]; let demt1 = vec![1e-14; MDEPTH]; let deldm = vec![0.001; MDEPTH]; let reint: Vec = (0..MDEPTH).map(|_| 0.1).collect(); let redif: Vec = (0..MDEPTH).map(|_| 0.1).collect(); let w = vec![0.01; 100]; let fh = vec![0.5; 100]; let fhd = vec![0.5; 100]; let freq = vec![1e15; 100]; let dsct1 = vec![1e-11; MDEPTH]; let dscn1 = vec![1e-16; MDEPTH]; let ijfr: Vec = (0..100).map(|i| (i + 1) as i32).collect(); let extrad = vec![0.0; 100]; let q0 = vec![0.0; 100]; let uu0 = vec![0.0; 100]; let params = RybmatParams { ij: 0, nd: 10, dm: &dm, temp: &temp, dens: &dens, abso1: &abso1, scat1: &scat1, emis1: &emis1, fak1: &fak1, rad1: &rad1, dabt1: &dabt1, demt1: &demt1, deldm: &deldm, isplin: 1, iubc: 0, ibc: 1, idisk: 0, ifryb: 0, reint: &reint, redif: &redif, w: &w, freq: &freq, fh: &fh, fhd: &fhd, icentr: 0, ilbc: 0, nretc: 0, dsct1: &dsct1, dscn1: &dscn1, ijfr: &ijfr, extrad: &extrad, q0: &q0, uu0: &uu0, }; let result = rybmat(¶ms); // 检查辐射平衡相关输出 assert!(result.vb[0].is_finite()); assert!(result.wr[0].is_finite()); assert!(result.va[5].is_finite()); } }