SpectraRust/src/tlusty/math/solvers/rybmat.rs
2026-04-04 09:36:14 +08:00

991 lines
34 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.

//! 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<f64>,
pub rb: Vec<f64>,
pub rc: Vec<f64>,
pub vr: Vec<f64>,
pub ua: Vec<f64>,
pub ub: Vec<f64>,
pub uc: Vec<f64>,
pub va: Vec<f64>,
pub vb: Vec<f64>,
pub vc: Vec<f64>,
pub wr: Vec<f64>,
pub wm: Vec<Vec<f64>>,
}
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<f64> = (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<i32> = (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(&params);
assert!(result.rb[0].is_finite());
assert!(result.vr[0].is_finite());
}
#[test]
fn test_rybmat_with_extrad() {
let dm: Vec<f64> = (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<i32> = (0..100).map(|i| (i + 1) as i32).collect();
let extrad: Vec<f64> = (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(&params);
assert!(result.rb[0].is_finite());
assert!(result.vr[0].is_finite());
}
#[test]
fn test_rybmat_hermitian() {
let dm: Vec<f64> = (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<i32> = (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(&params);
assert!(result.rb[0].is_finite());
assert!(result.vr[0].is_finite());
}
#[test]
fn test_rybmat_centered_difference() {
let dm: Vec<f64> = (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<f64> = (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<i32> = (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(&params);
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<f64> = (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<i32> = (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(&params);
assert!(result.rb[0].is_finite());
assert!(result.vr[0].is_finite());
}
#[test]
fn test_rybmat_disk_mode() {
let dm: Vec<f64> = (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<i32> = (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(&params);
assert!(result.rb[0].is_finite());
assert!(result.vr[0].is_finite());
}
#[test]
fn test_rybmat_radiative_equilibrium() {
let dm: Vec<f64> = (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<f64> = (0..MDEPTH).map(|_| 0.1).collect();
let redif: Vec<f64> = (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<i32> = (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(&params);
// 检查辐射平衡相关输出
assert!(result.vb[0].is_finite());
assert!(result.wr[0].is_finite());
assert!(result.va[5].is_finite());
}
}