包含 IO 和 math 模块的实现: - IO: initia, levcd, linset, ltegr, ltegrd, odfset, outpri, resolv, srtfrq, start, tabini, xenini - Math: accel2, alisk1, alisk2, alist1, alist2, concor, conout, conref, contmd, contmp, coolrt, greyd, inilam, linsel, lucy, lymlin, matcon, matgen, moleq, newdm, newdmt, odf1, opacf0, opacf1, opacfa, opacfd, opacfl, opactr, opadd, opahst, pgset, princ, prnt, pzeval, quasim, radpre, radtot, rates1, ratsp1, rdata, rdatax, rechck, rhoeos, rhonen, rhsgen, rossop, rtecf1, rtecmc, rtecmu, rtecom, rtefr1, rteint, russel, rybchn, rybene, rybheq, rybsol, sgmer1, sigave, sigk, solve, solves, state, steqeq, temcor, temper, topbas, trmder, trmdrt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
801 lines
26 KiB
Rust
801 lines
26 KiB
Rust
//! 预条件化辐射速率计算 - RATSP1。
|
||
//!
|
||
//! 重构自 TLUSTY `ratsp1.f`
|
||
//!
|
||
//! 计算辐射跃迁的上下行速率,包括连续谱和谱线跃迁。
|
||
//! 支持标准模式和 ODF 采样模式。
|
||
|
||
use crate::state::constants::{UN, PCK, MDEPTH, MTRANS};
|
||
|
||
// 物理常数
|
||
/// 4π/c
|
||
const PGRD: f64 = 4.1916825e-10;
|
||
/// 谱线常数
|
||
const OSC_CONST: f64 = 0.02654;
|
||
|
||
// ============================================================================
|
||
// 参数结构体
|
||
// ============================================================================
|
||
|
||
/// RATSP1 配置参数
|
||
#[derive(Debug, Clone)]
|
||
pub struct Ratsp1Config {
|
||
/// 深度点数
|
||
pub nd: usize,
|
||
/// 频率点数
|
||
pub nfreq: usize,
|
||
/// 束缚-自由跃迁数
|
||
pub ntranc: usize,
|
||
/// 总跃迁数
|
||
pub ntrans: usize,
|
||
/// PRD 跃迁数
|
||
pub ntrprd: usize,
|
||
/// 当前迭代次数
|
||
pub iter: i32,
|
||
/// 最后一次迭代标志
|
||
pub lfin: bool,
|
||
/// ODF 采样标志 (0: 标准, >=1: ODF)
|
||
pub ispodf: i32,
|
||
/// 表格不透明度标志 (<0: 仅使用表格)
|
||
pub ioptab: i32,
|
||
/// 散射处理标志 (0: 包含散射, >0: 不包含)
|
||
pub ilpsct: i32,
|
||
/// 混合长度参数 (>0: 使用 Rosseland)
|
||
pub hmix0: f64,
|
||
/// 深度记录标志 (<=0: 计算完整 Rosseland)
|
||
pub ndre: i32,
|
||
}
|
||
|
||
impl Default for Ratsp1Config {
|
||
fn default() -> Self {
|
||
Self {
|
||
nd: 50,
|
||
nfreq: 100,
|
||
ntranc: 10,
|
||
ntrans: 100,
|
||
ntrprd: 0,
|
||
iter: 1,
|
||
lfin: false,
|
||
ispodf: 0,
|
||
ioptab: 0,
|
||
ilpsct: 0,
|
||
hmix0: 0.0,
|
||
ndre: 0,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// RATSP1 模型状态参数
|
||
#[derive(Debug)]
|
||
pub struct Ratsp1ModelState<'a> {
|
||
// 深度点数据 (nd 个元素)
|
||
/// 温度倒数倒数 h/kT
|
||
pub hkt1: &'a [f64],
|
||
/// 深度差分 deldmz
|
||
pub deldmz: &'a [f64],
|
||
/// 密度倒数 dens1
|
||
pub dens1: &'a [f64],
|
||
/// 柱质量密度
|
||
pub dm: &'a [f64],
|
||
/// 总粒子密度
|
||
pub dens: &'a [f64],
|
||
/// 散射修正因子 crsw
|
||
pub crsw: &'a [f64],
|
||
|
||
// 频率数据 (nfreq 个元素)
|
||
/// 频率数组
|
||
pub freq: &'a [f64],
|
||
/// 频率权重
|
||
pub w: &'a [f64],
|
||
/// 归一化权重
|
||
pub w0e: &'a [f64],
|
||
/// 频率索引标志 ijx
|
||
pub ijx: &'a [i32],
|
||
|
||
// 不透明度数据 (nd 个元素)
|
||
/// 总吸收系数
|
||
pub absot: &'a [f64],
|
||
/// 吸收系数 (单频率) - 可被回调函数修改
|
||
pub abso1: &'a mut [f64],
|
||
/// 电子散射系数
|
||
pub elscat: &'a [f64],
|
||
|
||
// 辐射场数据
|
||
/// 辐射强度 rad1 (nd)
|
||
pub rad1: &'a [f64],
|
||
/// 上边界强度 fh (nfreq)
|
||
pub fh: &'a [f64],
|
||
/// 氦外辐射 hextrd (nfreq)
|
||
pub hextrd: &'a [f64],
|
||
/// 辐射场积分 fak1 (nd)
|
||
pub fak1: &'a [f64],
|
||
/// 归一化普朗克函数 bnue (nfreq)
|
||
pub bnue: &'a [f64],
|
||
|
||
// Lambda 算子
|
||
/// Lambda 算子对角 ali1 (nd)
|
||
pub ali1: &'a [f64],
|
||
|
||
// 跃迁数据
|
||
/// 截面 cross (ntranc × nfreq)
|
||
pub cross: &'a [f64],
|
||
/// 低能级索引 ilow (ntrans)
|
||
pub ilow: &'a [i32],
|
||
/// 高能级索引 iup (ntrans)
|
||
pub iup: &'a [i32],
|
||
/// 跃迁索引 itra (mlevel × mlevel)
|
||
pub itra: &'a [i32],
|
||
/// 束缚-自由跃迁索引 itrbf (ntranc)
|
||
pub itrbf: &'a [i32],
|
||
/// 零占据标志 ipzero (mlevel × nd)
|
||
pub ipzero: &'a [i32],
|
||
/// Macfarlane 下沉修正索引 mcdw (ntrans)
|
||
pub mcdw: &'a [i32],
|
||
/// 合并能级索引 imrg (mlevel)
|
||
pub imrg: &'a [i32],
|
||
/// 占据概率修正标志 ifwop (mlevel)
|
||
pub ifwop: &'a [i32],
|
||
/// 下沉修正因子 dwf1 (mmcdw × nd)
|
||
pub dwf1: &'a [f64],
|
||
/// 合并能级截面 sgmrg (mmer × nd)
|
||
pub sgmg: &'a [f64],
|
||
/// 吸收系数 abtra (ntrans × nd)
|
||
pub abtra: &'a [f64],
|
||
/// 发射系数 emtra (ntrans × nd)
|
||
pub emtra: &'a [f64],
|
||
|
||
// 谱线数据
|
||
/// 主谱线索引 ijlin (nfreq)
|
||
pub ijlin: &'a [i32],
|
||
/// 谱线轮廓 prflin (nd × nfreq)
|
||
pub prflin: &'a [f64],
|
||
/// 重叠谱线数 nlines (nfreq)
|
||
pub nlines: &'a [i32],
|
||
/// 重叠谱线索引 itrlin (maxlines × nfreq)
|
||
pub itrlin: &'a [i16],
|
||
/// 频率起点 ifr0 (ntrans)
|
||
pub ifr0: &'a [i32],
|
||
/// 频率终点 ifr1 (ntrans)
|
||
pub ifr1: &'a [i32],
|
||
/// PRD 跃迁索引 iprd (ntrans)
|
||
pub iprd: &'a [i32],
|
||
/// 振子强度 osc0 (ntrans)
|
||
pub osc0: &'a [f64],
|
||
/// 显式谱线标志 linexp (ntrans)
|
||
pub linexp: &'a [bool],
|
||
|
||
// ODF 数据
|
||
/// 频率偏移 kfr0 (ntrans)
|
||
pub kfr0: &'a [i32],
|
||
/// 谱线索引 indexp (ntrans)
|
||
pub indexp: &'a [i32],
|
||
/// 铁截面 sigfe (ntab × nfreq)
|
||
pub sigfe: &'a [f64],
|
||
/// 深度相关索引 jidi (nd)
|
||
pub jidi: &'a [i32],
|
||
/// 插值因子 xjid (nd)
|
||
pub xjid: &'a [f64],
|
||
|
||
// 输出数组
|
||
/// 上行辐射速率 (ntrans × nd)
|
||
pub rru: &'a mut [f64],
|
||
/// 下行辐射速率 (ntrans × nd)
|
||
pub rrd: &'a mut [f64],
|
||
/// 总辐射压 (nd)
|
||
pub pradt: &'a mut [f64],
|
||
/// 吸收辐射压 (nd)
|
||
pub prada: &'a mut [f64],
|
||
/// 辐射通量 (nd)
|
||
pub flrd: &'a mut [f64],
|
||
/// PRD J 积分 (ntrprd × nd)
|
||
pub pjbar: &'a mut [f64],
|
||
/// Rosseland 平均不透明度 (nd)
|
||
pub abrosd: &'a mut [f64],
|
||
/// Rosseland 累积 (nd)
|
||
pub sumdpl: &'a mut [f64],
|
||
/// PRD 零点
|
||
pub prd0: &'a mut f64,
|
||
}
|
||
|
||
/// RATSP1 输出结构体
|
||
#[derive(Debug)]
|
||
pub struct Ratsp1Output {
|
||
/// 最小辐射压比
|
||
pub prdx: f64,
|
||
}
|
||
|
||
// ============================================================================
|
||
// 主函数
|
||
// ============================================================================
|
||
|
||
/// 计算预条件化辐射速率。
|
||
///
|
||
/// # 参数
|
||
/// - `config`: 配置参数
|
||
/// - `model`: 模型状态
|
||
/// - `opacf1_fn`: 不透明度计算函数
|
||
/// - `rtefr1_fn`: 辐射转移计算函数
|
||
/// - `rosstd_fn`: Rosseland 平均计算函数 (可选)
|
||
///
|
||
/// # 返回值
|
||
/// - `Ratsp1Output`: 包含最小辐射压比
|
||
#[allow(clippy::too_many_arguments)]
|
||
pub fn ratsp1<F, G, H>(
|
||
config: &Ratsp1Config,
|
||
model: &mut Ratsp1ModelState,
|
||
opacf1_fn: F,
|
||
rtefr1_fn: G,
|
||
rosstd_fn: Option<H>,
|
||
) -> Ratsp1Output
|
||
where
|
||
F: Fn(usize, &mut Ratsp1ModelState),
|
||
G: Fn(usize, &mut Ratsp1ModelState),
|
||
H: Fn(usize, &mut Ratsp1ModelState),
|
||
{
|
||
let nd = config.nd;
|
||
let nfreq = config.nfreq;
|
||
let ntranc = config.ntranc;
|
||
let ntrans = config.ntrans;
|
||
let ntrprd = config.ntrprd;
|
||
|
||
// 工作数组
|
||
let mut ehk = vec![0.0; nd];
|
||
let mut alab = vec![0.0; nd];
|
||
|
||
// 判断是否计算 Rosseland
|
||
let lross = (config.ndre <= 0 && config.iter == 1) || config.lfin || config.hmix0 > 0.0;
|
||
|
||
// ========================================================================
|
||
// 初始化输出数组
|
||
// ========================================================================
|
||
for id in 0..nd {
|
||
model.pradt[id] = 0.0;
|
||
model.prada[id] = 0.0;
|
||
model.flrd[id] = 0.0;
|
||
for itr in 0..ntrans {
|
||
model.rru[itr * nd + id] = 0.0;
|
||
model.rrd[itr * nd + id] = 0.0;
|
||
}
|
||
for itrp in 0..ntrprd {
|
||
model.pjbar[itrp * nd + id] = 0.0;
|
||
}
|
||
}
|
||
*model.prd0 = 0.0;
|
||
|
||
// 初始化 Rosseland 数组
|
||
if lross {
|
||
for id in 0..nd {
|
||
model.abrosd[id] = 0.0;
|
||
model.sumdpl[id] = 0.0;
|
||
}
|
||
}
|
||
|
||
// ========================================================================
|
||
// 频率循环
|
||
// ========================================================================
|
||
for ij in 0..nfreq {
|
||
// 跳过无效频率
|
||
if model.ijx[ij] == -1 {
|
||
continue;
|
||
}
|
||
|
||
let fr = model.freq[ij];
|
||
let w0 = model.w0e[ij];
|
||
let ww = model.w[ij];
|
||
|
||
// 计算不透明度和辐射转移
|
||
opacf1_fn(ij, model);
|
||
rtefr1_fn(ij, model);
|
||
|
||
// 计算 Rosseland 平均
|
||
if lross {
|
||
if let Some(ref ros_fn) = rosstd_fn {
|
||
ros_fn(ij, model);
|
||
}
|
||
}
|
||
|
||
// 通量梯度
|
||
let fluxw = model.w[ij] * model.rad1[0] * model.fh[ij];
|
||
// GRADF 在原代码中定义但未使用
|
||
|
||
// 上边界通量
|
||
model.flrd[0] += ww * model.fh[ij] * model.rad1[0] - ww * model.hextrd[ij];
|
||
|
||
// 深度点通量
|
||
for id in 1..nd {
|
||
let dt = UN / (model.absot[id] + model.absot[id - 1]) / model.deldmz[id - 1];
|
||
let fl = (model.rad1[id] * model.fak1[id] - model.rad1[id - 1] * model.fak1[id - 1]) * dt;
|
||
model.flrd[id] += ww * fl;
|
||
}
|
||
|
||
// 跳过仅表格模式
|
||
if config.ioptab < 0 {
|
||
continue;
|
||
}
|
||
|
||
// ====================================================================
|
||
// 连续谱跃迁
|
||
// ====================================================================
|
||
for id in 0..nd {
|
||
ehk[id] = (-model.hkt1[id] * fr).exp();
|
||
alab[id] = if config.ilpsct == 0 {
|
||
model.ali1[id] / (model.abso1[id] - model.elscat[id])
|
||
} else {
|
||
model.ali1[id] / model.abso1[id]
|
||
};
|
||
|
||
for ibft in 0..ntranc {
|
||
let itr = model.itrbf[ibft] as usize;
|
||
if itr == 0 {
|
||
continue;
|
||
}
|
||
let itr_idx = itr - 1;
|
||
|
||
let sg = model.cross[ibft * nfreq + ij];
|
||
if sg <= 0.0 {
|
||
continue;
|
||
}
|
||
|
||
let ii = model.ilow[itr_idx] as usize;
|
||
let jj = model.iup[itr_idx] as usize;
|
||
if ii == 0 || jj == 0 {
|
||
continue;
|
||
}
|
||
let ii_idx = ii - 1;
|
||
let jj_idx = jj - 1;
|
||
|
||
// 检查零占据
|
||
if model.ipzero[ii_idx * nd + id] != 0 || model.ipzero[jj_idx * nd + id] != 0 {
|
||
continue;
|
||
}
|
||
|
||
// 计算截面修正
|
||
let sg_final = if model.ifwop[ii_idx] >= 0 {
|
||
let icdw = model.mcdw[itr_idx];
|
||
if icdw >= 1 {
|
||
sg * model.dwf1[(icdw as usize - 1) * nd + id]
|
||
} else {
|
||
sg
|
||
}
|
||
} else {
|
||
let imer = model.imrg[ii_idx] as usize;
|
||
if imer > 0 {
|
||
sg * model.sgmg[(imer - 1) * nd + id]
|
||
} else {
|
||
sg
|
||
}
|
||
};
|
||
|
||
let sgw0 = sg_final * w0;
|
||
let rlam = sg_final * alab[id];
|
||
let elin = model.emtra[itr_idx * nd + id] * ehk[id];
|
||
let radres = model.rad1[id] - rlam * model.bnue[ij] * elin;
|
||
let bnures = model.bnue[ij] * (UN - rlam * (model.abtra[itr_idx * nd + id] - elin));
|
||
|
||
model.rru[itr_idx * nd + id] += sgw0 * radres;
|
||
model.rrd[itr_idx * nd + id] += sgw0 * (radres + bnures) * ehk[id];
|
||
}
|
||
}
|
||
|
||
// ====================================================================
|
||
// 谱线跃迁
|
||
// ====================================================================
|
||
if config.ispodf == 0 {
|
||
// 标准模式
|
||
if model.ijlin[ij] > 0 {
|
||
// 主谱线
|
||
let itr = (model.ijlin[ij] as usize) - 1;
|
||
let ii = model.ilow[itr] as usize;
|
||
let jj = model.iup[itr] as usize;
|
||
|
||
if ii > 0 && jj > 0 {
|
||
let ii_idx = ii - 1;
|
||
let jj_idx = jj - 1;
|
||
|
||
for id in 0..nd {
|
||
if model.ipzero[ii_idx * nd + id] != 0
|
||
|| model.ipzero[jj_idx * nd + id] != 0
|
||
{
|
||
continue;
|
||
}
|
||
|
||
let sg = model.prflin[id * nfreq + ij];
|
||
let sgw0 = sg * w0;
|
||
let rlam = sg * alab[id];
|
||
let elin = model.emtra[itr * nd + id] * ehk[id];
|
||
let radres = model.rad1[id] - rlam * model.bnue[ij] * elin;
|
||
let bnures =
|
||
model.bnue[ij] * (UN - rlam * (model.abtra[itr * nd + id] - elin));
|
||
|
||
model.rru[itr * nd + id] += sgw0 * radres;
|
||
model.rrd[itr * nd + id] += sgw0 * (radres + bnures) * ehk[id];
|
||
}
|
||
|
||
// PRD 贡献
|
||
let itrprd = model.iprd[itr];
|
||
if itrprd > 0 {
|
||
let s = UN / (OSC_CONST * model.osc0[itr]);
|
||
for id in 0..nd {
|
||
let sg = model.prflin[id * nfreq + ij] * s;
|
||
model.pjbar[(itrprd as usize - 1) * nd + id] +=
|
||
sg * model.w[ij] * model.rad1[id];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 重叠谱线
|
||
let nlines = model.nlines[ij];
|
||
if nlines > 0 {
|
||
for ilint in 0..nlines as usize {
|
||
let itr = model.itrlin[ilint * nfreq + ij] as usize;
|
||
if itr == 0 || model.linexp[itr - 1] {
|
||
continue;
|
||
}
|
||
let itr_idx = itr - 1;
|
||
|
||
// 频率插值
|
||
let ij0 = model.ifr0[itr_idx] as usize;
|
||
let mut ij0_adj = ij0;
|
||
for ijt in ij0..=model.ifr1[itr_idx] as usize {
|
||
if model.freq[ijt] <= fr {
|
||
ij0_adj = ijt;
|
||
break;
|
||
}
|
||
}
|
||
let ij1 = ij0_adj - 1;
|
||
|
||
let a1 = if ij1 < nfreq && ij0_adj < nfreq {
|
||
(fr - model.freq[ij0_adj]) / (model.freq[ij1] - model.freq[ij0_adj])
|
||
} else {
|
||
0.0
|
||
};
|
||
let a2 = UN - a1;
|
||
|
||
let ii = model.ilow[itr_idx] as usize;
|
||
let jj = model.iup[itr_idx] as usize;
|
||
if ii == 0 || jj == 0 {
|
||
continue;
|
||
}
|
||
let ii_idx = ii - 1;
|
||
let jj_idx = jj - 1;
|
||
|
||
for id in 0..nd {
|
||
if model.ipzero[ii_idx * nd + id] != 0
|
||
|| model.ipzero[jj_idx * nd + id] != 0
|
||
{
|
||
continue;
|
||
}
|
||
|
||
let sg = if ij1 < nfreq && ij0_adj < nfreq {
|
||
a1 * model.prflin[id * nfreq + ij1]
|
||
+ a2 * model.prflin[id * nfreq + ij0_adj]
|
||
} else {
|
||
0.0
|
||
};
|
||
|
||
let sgw0 = sg * w0;
|
||
let rlam = sg * alab[id];
|
||
let elin = model.emtra[itr_idx * nd + id] * ehk[id];
|
||
let radres = model.rad1[id] - rlam * model.bnue[ij] * elin;
|
||
let bnures =
|
||
model.bnue[ij] * (UN - rlam * (model.abtra[itr_idx * nd + id] - elin));
|
||
|
||
model.rru[itr_idx * nd + id] += sgw0 * radres;
|
||
model.rrd[itr_idx * nd + id] += sgw0 * (radres + bnures) * ehk[id];
|
||
}
|
||
|
||
// PRD 贡献
|
||
let itrprd = model.iprd[itr_idx];
|
||
if itrprd > 0 {
|
||
let s = UN / (OSC_CONST * model.osc0[itr_idx]);
|
||
for id in 0..nd {
|
||
let sg = if ij1 < nfreq && ij0_adj < nfreq {
|
||
(a1 * model.prflin[id * nfreq + ij1]
|
||
+ a2 * model.prflin[id * nfreq + ij0_adj])
|
||
* s
|
||
} else {
|
||
0.0
|
||
};
|
||
model.pjbar[(itrprd as usize - 1) * nd + id] +=
|
||
sg * model.w[ij] * model.rad1[id];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// ODF 采样模式
|
||
let nlines = model.nlines[ij];
|
||
if nlines > 0 {
|
||
for ilint in 0..nlines as usize {
|
||
let itr = model.itrlin[ilint * nfreq + ij] as usize;
|
||
if itr == 0 {
|
||
continue;
|
||
}
|
||
let itr_idx = itr - 1;
|
||
|
||
let kj = ij as i32 - model.ifr0[itr_idx] + model.kfr0[itr_idx];
|
||
let indxpa = model.indexp[itr_idx].abs();
|
||
|
||
let ii = model.ilow[itr_idx] as usize;
|
||
let jj = model.iup[itr_idx] as usize;
|
||
if ii == 0 || jj == 0 {
|
||
continue;
|
||
}
|
||
let ii_idx = ii - 1;
|
||
let jj_idx = jj - 1;
|
||
|
||
if indxpa != 3 && indxpa != 4 {
|
||
// 标准截面
|
||
for id in 0..nd {
|
||
if model.ipzero[ii_idx * nd + id] != 0
|
||
|| model.ipzero[jj_idx * nd + id] != 0
|
||
{
|
||
continue;
|
||
}
|
||
|
||
let sg = model.prflin[id * nfreq + kj as usize];
|
||
let sgw0 = sg * w0;
|
||
let rlam = sg * alab[id];
|
||
let elin = model.emtra[itr_idx * nd + id] * ehk[id];
|
||
let radres = model.rad1[id] - rlam * model.bnue[ij] * elin;
|
||
let bnures = model.bnue[ij]
|
||
* (UN - rlam * (model.abtra[itr_idx * nd + id] - elin));
|
||
|
||
model.rru[itr_idx * nd + id] += sgw0 * radres;
|
||
model.rrd[itr_idx * nd + id] += sgw0 * (radres + bnures) * ehk[id];
|
||
}
|
||
} else {
|
||
// 铁截面插值
|
||
for id in 0..nd {
|
||
if model.ipzero[ii_idx * nd + id] != 0
|
||
|| model.ipzero[jj_idx * nd + id] != 0
|
||
{
|
||
continue;
|
||
}
|
||
|
||
let kjd = model.jidi[id] as usize;
|
||
let xjid = model.xjid[id];
|
||
let sg = if kjd > 0 && (kjd + 1) < nd && (kj as usize) < nfreq {
|
||
(xjid * model.sigfe[kjd * nfreq + kj as usize]
|
||
+ (UN - xjid) * model.sigfe[(kjd + 1) * nfreq + kj as usize])
|
||
.exp()
|
||
} else {
|
||
1.0
|
||
};
|
||
|
||
let sgw0 = sg * w0;
|
||
let rlam = sg * alab[id];
|
||
let elin = model.emtra[itr_idx * nd + id] * ehk[id];
|
||
let radres = model.rad1[id] - rlam * model.bnue[ij] * elin;
|
||
let bnures =
|
||
model.bnue[ij] * (UN - rlam * (model.abtra[itr_idx * nd + id] - elin));
|
||
|
||
model.rru[itr_idx * nd + id] += sgw0 * radres;
|
||
model.rrd[itr_idx * nd + id] += sgw0 * (radres + bnures) * ehk[id];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========================================================================
|
||
// 散射修正
|
||
// ========================================================================
|
||
for id in 0..nd {
|
||
if model.crsw[id] != UN {
|
||
for itr in 0..ntrans {
|
||
model.rru[itr * nd + id] *= model.crsw[id];
|
||
model.rrd[itr * nd + id] *= model.crsw[id];
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========================================================================
|
||
// 辐射压
|
||
// ========================================================================
|
||
let mut prdx = 1.0;
|
||
for id in 0..nd {
|
||
model.pradt[id] *= PCK;
|
||
model.prada[id] *= PCK;
|
||
if model.prada[id] > 0.0 {
|
||
let prdr = model.pradt[id] / model.prada[id];
|
||
if prdr < prdx {
|
||
prdx = prdr;
|
||
}
|
||
}
|
||
}
|
||
*model.prd0 = *model.prd0 / model.dens1[0] * model.dm[0] * PCK;
|
||
|
||
// ========================================================================
|
||
// Rosseland 平均
|
||
// ========================================================================
|
||
if lross {
|
||
for id in 0..nd {
|
||
if model.abrosd[id] > 0.0 {
|
||
model.abrosd[id] = model.sumdpl[id] / (model.abrosd[id] * model.dens[id]);
|
||
}
|
||
}
|
||
}
|
||
|
||
Ratsp1Output { prdx }
|
||
}
|
||
|
||
// ============================================================================
|
||
// 测试
|
||
// ============================================================================
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_ratsp1_config_default() {
|
||
let config = Ratsp1Config::default();
|
||
assert_eq!(config.nd, 50);
|
||
assert_eq!(config.nfreq, 100);
|
||
assert_eq!(config.ntrans, 100);
|
||
}
|
||
|
||
#[test]
|
||
fn test_ratsp1_basic() {
|
||
let nd = 5;
|
||
let nfreq = 3;
|
||
let ntrans = 2;
|
||
|
||
let config = Ratsp1Config {
|
||
nd,
|
||
nfreq,
|
||
ntranc: 0,
|
||
ntrans,
|
||
ntrprd: 0,
|
||
iter: 1,
|
||
lfin: false,
|
||
ispodf: 0,
|
||
ioptab: -1, // 跳过跃迁计算
|
||
ilpsct: 0,
|
||
hmix0: 0.0,
|
||
ndre: 0,
|
||
};
|
||
|
||
// 创建简单的测试数据
|
||
let hkt1 = vec![1e-4; nd];
|
||
let deldmz = vec![0.01; nd];
|
||
let dens1 = vec![1e-14; nd];
|
||
let dm = vec![0.01; nd];
|
||
let dens = vec![1e14; nd];
|
||
let crsw = vec![1.0; nd];
|
||
|
||
let freq = vec![1e14, 2e14, 3e14];
|
||
let w = vec![0.5; nfreq];
|
||
let w0e = vec![1.0; nfreq];
|
||
let ijx = vec![0; nfreq];
|
||
|
||
let absot = vec![1e-8; nd];
|
||
let mut abso1 = vec![1e-8; nd];
|
||
let elscat = vec![1e-10; nd];
|
||
|
||
let rad1 = vec![1e-10; nd];
|
||
let fh = vec![0.0; nfreq];
|
||
let hextrd = vec![0.0; nfreq];
|
||
let fak1 = vec![1.0; nd];
|
||
let bnue = vec![1e-10; nfreq];
|
||
|
||
let ali1 = vec![1.0; nd];
|
||
|
||
let cross = vec![];
|
||
let ilow = vec![1, 2];
|
||
let iup = vec![2, 3];
|
||
let itra = vec![];
|
||
let itrbf = vec![];
|
||
let ipzero = vec![0; 100 * nd];
|
||
let mcdw = vec![0; ntrans];
|
||
let imrg = vec![0; 100];
|
||
let ifwop = vec![0; 100];
|
||
let dwf1 = vec![];
|
||
let sgmg = vec![];
|
||
let abtra = vec![1e-8; ntrans * nd];
|
||
let emtra = vec![1e-20; ntrans * nd];
|
||
|
||
let ijlin = vec![0; nfreq];
|
||
let prflin = vec![0.0; nd * nfreq];
|
||
let nlines = vec![0; nfreq];
|
||
let itrlin = vec![0; 100 * nfreq];
|
||
let ifr0 = vec![1; ntrans];
|
||
let ifr1 = vec![nfreq as i32; ntrans];
|
||
let iprd = vec![0; ntrans];
|
||
let osc0 = vec![0.1; ntrans];
|
||
let linexp = vec![false; ntrans];
|
||
|
||
let kfr0 = vec![0; ntrans];
|
||
let indexp = vec![0; ntrans];
|
||
let sigfe = vec![];
|
||
let jidi = vec![0; nd];
|
||
let xjid = vec![0.0; nd];
|
||
|
||
let mut rru = vec![0.0; ntrans * nd];
|
||
let mut rrd = vec![0.0; ntrans * nd];
|
||
let mut pradt = vec![0.0; nd];
|
||
let mut prada = vec![0.0; nd];
|
||
let mut flrd = vec![0.0; nd];
|
||
let mut pjbar = vec![];
|
||
let mut abrosd = vec![0.0; nd];
|
||
let mut sumdpl = vec![0.0; nd];
|
||
let mut prd0 = 0.0;
|
||
|
||
let mut model = Ratsp1ModelState {
|
||
hkt1: &hkt1,
|
||
deldmz: &deldmz,
|
||
dens1: &dens1,
|
||
dm: &dm,
|
||
dens: &dens,
|
||
crsw: &crsw,
|
||
freq: &freq,
|
||
w: &w,
|
||
w0e: &w0e,
|
||
ijx: &ijx,
|
||
absot: &absot,
|
||
abso1: &mut abso1,
|
||
elscat: &elscat,
|
||
rad1: &rad1,
|
||
fh: &fh,
|
||
hextrd: &hextrd,
|
||
fak1: &fak1,
|
||
bnue: &bnue,
|
||
ali1: &ali1,
|
||
cross: &cross,
|
||
ilow: &ilow,
|
||
iup: &iup,
|
||
itra: &itra,
|
||
itrbf: &itrbf,
|
||
ipzero: &ipzero,
|
||
mcdw: &mcdw,
|
||
imrg: &imrg,
|
||
ifwop: &ifwop,
|
||
dwf1: &dwf1,
|
||
sgmg: &sgmg,
|
||
abtra: &abtra,
|
||
emtra: &emtra,
|
||
ijlin: &ijlin,
|
||
prflin: &prflin,
|
||
nlines: &nlines,
|
||
itrlin: &itrlin,
|
||
ifr0: &ifr0,
|
||
ifr1: &ifr1,
|
||
iprd: &iprd,
|
||
osc0: &osc0,
|
||
linexp: &linexp,
|
||
kfr0: &kfr0,
|
||
indexp: &indexp,
|
||
sigfe: &sigfe,
|
||
jidi: &jidi,
|
||
xjid: &xjid,
|
||
rru: &mut rru,
|
||
rrd: &mut rrd,
|
||
pradt: &mut pradt,
|
||
prada: &mut prada,
|
||
flrd: &mut flrd,
|
||
pjbar: &mut pjbar,
|
||
abrosd: &mut abrosd,
|
||
sumdpl: &mut sumdpl,
|
||
prd0: &mut prd0,
|
||
};
|
||
|
||
// 简单的回调函数
|
||
let opacf1_fn = |_: usize, m: &mut Ratsp1ModelState| {
|
||
for id in 0..m.abso1.len() {
|
||
m.abso1[id] = 1e-8;
|
||
}
|
||
};
|
||
|
||
let rtefr1_fn = |_: usize, _m: &mut Ratsp1ModelState| {};
|
||
|
||
let output = ratsp1(&config, &mut model, opacf1_fn, rtefr1_fn, None::<fn(usize, &mut Ratsp1ModelState)>);
|
||
|
||
// 验证输出
|
||
assert_eq!(output.prdx, 1.0); // 由于所有 prada 为 0
|
||
assert_eq!(model.flrd.len(), nd);
|
||
}
|
||
}
|