SpectraRust/src/tlusty/math/alist2.rs
2026-03-25 13:31:23 +08:00

1054 lines
29 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.

//! ALI 参数和辐射跃迁率计算 - 变体 2用于速率矩阵对占据数的导数
//!
//! 重构自 TLUSTY `alist2.f`
//!
//! 计算所有必要的 ALI 参数和辐射跃迁率。
//! 这是 RATES1 的类似函数,用于速率矩阵对占据数的导数计算。
//!
//! ## IRDER 模式
//! - IRDER = 1: 计算 APT, APN (T 和 N 导数)
//! - IRDER = 2: 计算 APP (能级导数)
//! - IRDER = 3: 计算 APT, APN, APP (所有导数)
use crate::tlusty::state::constants::{MDEPTH, MFREQ, MLEVEL, MTRANS, MLVEXP, UN};
/// ALIST2 输入参数(只读)
pub struct Alist2Params<'a> {
// 维度参数
/// 深度点数
pub nd: usize,
/// 频率点数
pub nfreq: usize,
/// 能级数
pub nlevel: usize,
/// 离子数
pub nion: usize,
/// 束缚-自由跃迁数
pub ntranc: usize,
/// 束缚-束缚跃迁数
pub ntrans: usize,
/// 线性化能级数
pub nlvexp: usize,
// 控制参数
/// 辐射导数模式 (1, 2, 3)
pub irder: i32,
/// 迭代次数
pub iter: i32,
/// ODF/OS 选项
pub ispodf: i32,
/// 不透明度表选项
pub ioptab: i32,
/// 最终迭代标志
pub lfin: bool,
/// 混合长度参数
pub hmix0: f64,
/// 对流开关
pub crsw: &'a [f64],
// 频率相关
/// 频率数组 [nfreq]
pub freq: &'a [f64],
/// 频率权重 [nfreq]
pub w0e: &'a [f64],
/// 跳过标志 [nfreq]
pub ijx: &'a [i32],
/// ALI 索引 [nfreq]
pub ijali: &'a [i32],
/// 普朗克函数 [nfreq]
pub bnue: &'a [f64],
// 模型状态
/// 温度 [nd]
pub temp: &'a [f64],
/// 电子密度 [nd]
pub elec: &'a [f64],
/// 总粒子密度 [nd]
pub dens: &'a [f64],
/// 1/密度 [nd]
pub dens1: &'a [f64],
/// 柱质量 [nd]
pub dm: &'a [f64],
/// 深度差分 [nd-1]
pub deldmz: &'a [f64],
/// h/kT [nd]
pub hkt1: &'a [f64],
/// h/(kT)² [nd]
pub hkt21: &'a [f64],
// 原子/能级数据
/// 元素索引 [nlevel]
pub iel: &'a [i32],
/// 原子索引 [nlevel]
pub iatm: &'a [i32],
/// 能级类型 [nlevel]
pub ilk: &'a [i32],
/// 模型能级 [nlevel]
pub imodl: &'a [i32],
/// LTE 能级标志 [nlevel]
pub iltlev: &'a [i32],
/// 显式能级索引 [nlevel]
pub iiexp: &'a [i32],
/// 固定原子标志 [nlevel]
pub iifix: &'a [i32],
/// 零占据数标志 [nlevel × nd]
pub ipzero: &'a [i32],
/// 参考原子 [nd × natom]
pub nrefs: &'a [i32],
// 跃迁数据
/// 束缚-自由跃迁索引 [ntranc]
pub itrbf: &'a [i32],
/// 跃迁下能级 [ntrans]
pub ilow: &'a [i32],
/// 跃迁上能级 [ntrans]
pub iup: &'a [i32],
/// 跃迁阈值频率 [ntrans]
pub fr0: &'a [i32],
/// 跃迁频率范围起点 [ntrans]
pub ifr0: &'a [i32],
/// 跃迁频率范围终点 [ntrans]
pub ifr1: &'a [i32],
/// 跃迁频率偏移 [ntrans]
pub kfr0: &'a [i32],
/// 跃迁索引类型 [ntrans]
pub indexp: &'a [i32],
/// 截面 [ntranc × nfreq]
pub cross: &'a [f64],
/// 跃迁吸收 [ntrans × nd]
pub abtra: &'a [f64],
/// 跃迁发射 [ntrans × nd]
pub emtra: &'a [f64],
/// Van der Waals 宽化因子索引 [ntrans]
pub mcdw: &'a [i32],
/// Van der Waals 宽化因子 [nion × nd]
pub dwf1: &'a [f64],
/// 合并截面 [nion × nd]
pub sgmg: &'a [f64],
/// 能级合并索引 [nlevel]
pub imrg: &'a [i32],
/// 线显式标志 [ntrans]
pub linexp: &'a [bool],
// 线数据
/// 频率对应的主线索引 [nfreq]
pub ijlin: &'a [i32],
/// 频率对应的重叠线数 [nfreq]
pub nlines: &'a [i32],
/// 重叠线索引 [nfreq × nlines_max]
pub itrlin: &'a [i32],
/// 线轮廓 [nd × nfreq]
pub prflin: &'a [f64],
// 辐射场
/// 辐射强度 [nd]
pub rad1: &'a [f64],
/// Eddington 因子 [nd]
pub fak1: &'a [f64],
// ALI 导数
/// 源函数 T 导数 [nd]
pub dsfdt: &'a [f64],
/// 源函数 N 导数 [nd]
pub dsfdn: &'a [f64],
/// 源函数能级导数 [nlvexp × nd]
pub dsfdp: &'a [f64],
// ODF/OS 特定
/// J 迭代索引 [nd]
pub jidi: &'a [i32],
/// XJ 迭代 [nd]
pub xjid: &'a [f64],
/// Fe 线截面 [njd × nkj]
pub sigfe: &'a [f64],
// 对流相关
/// 对流能量 [nd]
pub reint: &'a [f64],
/// 辐射扩散 [nd]
pub redif: &'a [f64],
/// 质量权重 [nd]
pub wmm: &'a [f64],
}
/// ALIST2 可变状态
pub struct Alist2State<'a> {
// 速率数组 [ntrans × nd]
/// 向上跃迁率
pub rru: &'a mut [f64],
/// 向下跃迁率
pub rrd: &'a mut [f64],
/// 速率温度导数
pub drdt: &'a mut [f64],
// ALI 参数 [nd]
pub reit: &'a mut [f64],
pub rein: &'a mut [f64],
pub reix: &'a mut [f64],
pub areit: &'a mut [f64],
pub arein: &'a mut [f64],
pub creit: &'a mut [f64],
pub crein: &'a mut [f64],
pub creix: &'a mut [f64],
pub redt: &'a mut [f64],
pub redtm: &'a mut [f64],
pub redtp: &'a mut [f64],
pub redn: &'a mut [f64],
pub rednm: &'a mut [f64],
pub rednp: &'a mut [f64],
pub redx: &'a mut [f64],
pub redxm: &'a mut [f64],
pub redxp: &'a mut [f64],
pub heit: &'a mut [f64],
pub heitm: &'a mut [f64],
pub heitp: &'a mut [f64],
pub hein: &'a mut [f64],
pub heinm: &'a mut [f64],
pub heinp: &'a mut [f64],
pub ehet: &'a mut [f64],
pub ehen: &'a mut [f64],
pub eret: &'a mut [f64],
pub eren: &'a mut [f64],
pub fcooli: &'a mut [f64],
pub flfix: &'a mut [f64],
pub flexp: &'a mut [f64],
pub flrd: &'a mut [f64],
pub fprd: &'a mut [f64],
pub pradt: &'a mut [f64],
pub prada: &'a mut [f64],
// 能级导数 [nlvexp × nd]
pub heip: &'a mut [f64],
pub reip: &'a mut [f64],
pub areip: &'a mut [f64],
pub creip: &'a mut [f64],
pub redp: &'a mut [f64],
pub redpm: &'a mut [f64],
pub heipm: &'a mut [f64],
pub redpp: &'a mut [f64],
pub heipp: &'a mut [f64],
// AP 矩阵 [nlvexp × nd]
pub apt: &'a mut [f64],
pub apn: &'a mut [f64],
// APP 矩阵 [nlvexp × nlvexp × nd]
pub app: &'a mut [f64],
// Rosseland 相关 [nd]
pub abrosd: &'a mut [f64],
pub sumdpl: &'a mut [f64],
// 辐射压力表面值
pub prd0: &'a mut f64,
}
/// ALIST2 输出结果
pub struct Alist2Output {
/// 辐射压力最小比值
pub prdx: f64,
}
/// 常量
const PCK: f64 = 1.5e-4; // h/c 常数因子
/// 执行 ALIST2 计算。
///
/// # 参数
/// - `params`: 输入参数
/// - `state`: 可变状态
///
/// # 返回
/// 计算结果
pub fn alist2(params: &Alist2Params, state: &mut Alist2State) -> Alist2Output {
let nd = params.nd;
let nfreq = params.nfreq;
let ntranc = params.ntranc;
let ntrans = params.ntrans;
let nlvexp = params.nlvexp;
// 零初始化所有速率和其他量
zero_rates(state, nd, ntrans, nlvexp);
// 计算 dedm1
let dedm1 = params.dm[0] / params.dens[0];
let mut prdx = 1.0;
match params.irder {
1 => {
// IRDER = 1: 只计算 APT, APN
process_irder1(params, state, nd, nfreq, ntranc, nlvexp);
}
2 => {
// IRDER = 2: 只计算 APP
process_irder2(params, state, nd, nfreq, ntranc, nlvexp);
}
3 => {
// IRDER = 3: 计算所有导数
process_irder3(params, state, nd, nfreq, ntranc, nlvexp);
}
_ => {
panic!("Invalid IRDER - ALIST2: {}", params.irder);
}
}
// 乘以频率无关常数
for id in 0..nd {
state.redx[id] *= params.wmm[id] * params.dens1[id] * params.dens1[id];
if id > 0 {
state.redxm[id] *= params.wmm[id] * params.dens1[id - 1] * params.dens1[id - 1];
}
// 对流冷却
state.flfix[id] = params.reint[id] * state.fcooli[id] - params.redif[id] * state.flfix[id];
// CRSW 缩放
if (params.crsw[id] - UN).abs() > 1e-10 {
for itr in 0..ntrans {
state.rru[itr * nd + id] *= params.crsw[id];
state.rrd[itr * nd + id] *= params.crsw[id];
state.drdt[itr * nd + id] *= params.crsw[id];
}
if params.irder > 0 {
for ii in 0..nlvexp {
state.apt[ii * nd + id] *= params.crsw[id];
state.apn[ii * nd + id] *= params.crsw[id];
for jj in 0..nlvexp {
state.app[(jj * nlvexp + ii) * nd + id] *= params.crsw[id];
}
}
}
}
}
// 辐射压力
for id in 0..nd {
state.pradt[id] *= PCK;
state.prada[id] *= PCK;
if state.prada[id] > 0.0 {
let prdr = state.pradt[id] / state.prada[id];
if prdr < prdx {
prdx = prdr;
}
}
}
*state.prd0 = *state.prd0 / params.dens1[0] * params.dm[0] * PCK;
// Rosseland 平均不透明度
let lross = (params.ioptab < 0 && dedm1 > 0.0) && (params.iter == 1 || params.lfin) || params.hmix0 > 0.0;
if lross {
for id in 0..nd {
state.abrosd[id] = state.sumdpl[id] / (state.abrosd[id] * params.dens[id]);
}
if params.ioptab < 0 {
// rosstd 函数调用 (待实现)
// rosstd(0);
}
}
Alist2Output { prdx }
}
/// 零初始化所有速率数组
fn zero_rates(state: &mut Alist2State, nd: usize, ntrans: usize, nlvexp: usize) {
for id in 0..nd {
state.reit[id] = 0.0;
state.rein[id] = 0.0;
state.reix[id] = 0.0;
state.areit[id] = 0.0;
state.arein[id] = 0.0;
state.creit[id] = 0.0;
state.crein[id] = 0.0;
state.creix[id] = 0.0;
state.redt[id] = 0.0;
state.redtm[id] = 0.0;
state.redtp[id] = 0.0;
state.redn[id] = 0.0;
state.rednm[id] = 0.0;
state.rednp[id] = 0.0;
state.redx[id] = 0.0;
state.redxm[id] = 0.0;
state.redxp[id] = 0.0;
state.heit[id] = 0.0;
state.heitm[id] = 0.0;
state.heitp[id] = 0.0;
state.hein[id] = 0.0;
state.heinm[id] = 0.0;
state.heinp[id] = 0.0;
state.ehet[id] = 0.0;
state.ehen[id] = 0.0;
state.eret[id] = 0.0;
state.eren[id] = 0.0;
state.fcooli[id] = 0.0;
state.flfix[id] = 0.0;
state.flexp[id] = 0.0;
state.flrd[id] = 0.0;
state.fprd[id] = 0.0;
state.pradt[id] = 0.0;
state.prada[id] = 0.0;
for ii in 0..nlvexp {
state.heip[ii * nd + id] = 0.0;
state.reip[ii * nd + id] = 0.0;
state.areip[ii * nd + id] = 0.0;
state.creip[ii * nd + id] = 0.0;
state.redp[ii * nd + id] = 0.0;
state.redpm[ii * nd + id] = 0.0;
state.heipm[ii * nd + id] = 0.0;
state.redpp[ii * nd + id] = 0.0;
state.heipp[ii * nd + id] = 0.0;
state.apt[ii * nd + id] = 0.0;
state.apn[ii * nd + id] = 0.0;
for jj in 0..nlvexp {
state.app[(jj * nlvexp + ii) * nd + id] = 0.0;
}
}
for itr in 0..ntrans {
state.rru[itr * nd + id] = 0.0;
state.rrd[itr * nd + id] = 0.0;
state.drdt[itr * nd + id] = 0.0;
}
}
*state.prd0 = 0.0;
}
/// IRDER = 3 的处理(计算所有导数)
fn process_irder3(
params: &Alist2Params,
state: &mut Alist2State,
nd: usize,
nfreq: usize,
ntranc: usize,
nlvexp: usize,
) {
let lross = (params.ioptab < 0 && params.dm[0] / params.dens[0] > 0.0)
&& (params.iter == 1 || params.lfin)
|| params.hmix0 > 0.0;
if lross {
for id in 0..nd {
state.abrosd[id] = 0.0;
state.sumdpl[id] = 0.0;
}
}
// 工作数组
let mut exx = vec![0.0; MDEPTH];
let mut rbnu = vec![0.0; MDEPTH];
let mut rbnuf = vec![0.0; MDEPTH];
for ij in 0..nfreq {
if params.ijx[ij] == -1 {
continue;
}
let fr = params.freq[ij];
let w0 = params.w0e[ij];
let lrder = params.ijali[ij] > 0;
// 注意:这里需要调用 OPACFD, RTEFR1, ALIFR1
// 由于这些函数有复杂的参数,这里用占位符表示
// call opacfd(ij);
// call rtefr1(ij);
// call alifr1(ij);
// if lross: call rosstd(ij);
if params.ioptab < 0 {
continue;
}
// 连续谱跃迁
process_continuum_transitions(
params,
state,
ij,
fr,
w0,
lrder,
nd,
ntranc,
nlvexp,
&mut exx,
&mut rbnu,
&mut rbnuf,
true, // compute_apt_apn_app
);
// 线跃迁
if params.ispodf == 0 {
process_line_transitions_standard(
params,
state,
ij,
fr,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
true, // compute_apt_apn_app
);
} else {
process_line_transitions_odf(
params,
state,
ij,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
true, // compute_apt_apn_app
);
}
}
}
/// IRDER = 1 的处理(只计算 APT, APN
fn process_irder1(
params: &Alist2Params,
state: &mut Alist2State,
nd: usize,
nfreq: usize,
ntranc: usize,
nlvexp: usize,
) {
let mut exx = vec![0.0; MDEPTH];
let mut rbnu = vec![0.0; MDEPTH];
let mut rbnuf = vec![0.0; MDEPTH];
for ij in 0..nfreq {
if params.ijx[ij] == -1 {
continue;
}
let fr = params.freq[ij];
let w0 = params.w0e[ij];
let lrder = params.ijali[ij] > 0;
// call opacfd(ij);
// call rtefr1(ij);
// call alifr1(ij);
// 连续谱跃迁
process_continuum_transitions(
params,
state,
ij,
fr,
w0,
lrder,
nd,
ntranc,
nlvexp,
&mut exx,
&mut rbnu,
&mut rbnuf,
true, // compute_apt_apn
);
// 线跃迁
if params.ispodf == 0 {
process_line_transitions_standard(
params,
state,
ij,
fr,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
true, // compute_apt_apn
);
} else {
process_line_transitions_odf(
params,
state,
ij,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
true, // compute_apt_apn
);
}
}
}
/// IRDER = 2 的处理(只计算 APP
fn process_irder2(
params: &Alist2Params,
state: &mut Alist2State,
nd: usize,
nfreq: usize,
ntranc: usize,
nlvexp: usize,
) {
let mut exx = vec![0.0; MDEPTH];
let mut rbnu = vec![0.0; MDEPTH];
let mut rbnuf = vec![0.0; MDEPTH];
for ij in 0..nfreq {
if params.ijx[ij] == -1 {
continue;
}
let fr = params.freq[ij];
let w0 = params.w0e[ij];
let lrder = params.ijali[ij] > 0;
// call opacfd(ij);
// call rtefr1(ij);
// call alifr1(ij);
// 连续谱跃迁
process_continuum_transitions(
params,
state,
ij,
fr,
w0,
lrder,
nd,
ntranc,
nlvexp,
&mut exx,
&mut rbnu,
&mut rbnuf,
false, // 不计算 apt/apn只计算 app
);
// 线跃迁
if params.ispodf == 0 {
process_line_transitions_standard(
params,
state,
ij,
fr,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
false, // 不计算 apt/apn只计算 app
);
} else {
process_line_transitions_odf(
params,
state,
ij,
w0,
lrder,
nd,
nlvexp,
&exx,
&rbnu,
&rbnuf,
false, // 不计算 apt/apn只计算 app
);
}
}
}
/// 处理连续谱跃迁
#[allow(clippy::too_many_arguments)]
fn process_continuum_transitions(
params: &Alist2Params,
state: &mut Alist2State,
_ij: usize,
fr: f64,
w0: f64,
lrder: bool,
nd: usize,
ntranc: usize,
nlvexp: usize,
exx: &mut [f64],
rbnu: &mut [f64],
rbnuf: &mut [f64],
compute_apt_apn: bool,
) {
// 计算辅助量
for id in 0..nd {
exx[id] = (-params.hkt1[id] * fr).exp();
rbnu[id] = (params.rad1[id] + params.bnue[_ij]) * exx[id];
rbnuf[id] = rbnu[id] * fr * params.hkt21[id];
}
// 遍历束缚-自由跃迁
for ibft in 0..ntranc {
let itr = (params.itrbf[ibft] - 1) as usize;
let ii = (params.ilow[itr] - 1) as usize;
let jj = (params.iup[itr] - 1) as usize;
for id in 0..nd {
// 检查零占据数
if params.ipzero[ii * nd + id] != 0 || params.ipzero[jj * nd + id] != 0 {
continue;
}
// 获取截面
let mut sg = get_cross_section(params, ibft, _ij, nd, id);
if sg <= 0.0 {
continue;
}
// 应用 Van der Waals 宽化或合并截面
let icdw = params.mcdw[itr];
let imer = params.imrg[ii];
if params.iifix[ii] >= 0 {
if icdw >= 1 {
sg *= params.dwf1[icdw as usize * nd + id];
}
} else {
sg = params.sgmg[imer as usize * nd + id];
}
let sgw0 = sg * w0;
// 更新跃迁率
state.rru[itr * nd + id] += sgw0 * params.rad1[id];
state.rrd[itr * nd + id] += sgw0 * rbnu[id];
state.drdt[itr * nd + id] += sgw0 * rbnuf[id];
if lrder {
let apfr = (params.abtra[itr * nd + id] - params.emtra[itr * nd + id] * exx[id]) * sgw0;
let ie = (params.iiexp[ii].abs()) as usize;
let je = (params.iiexp[jj].abs()) as usize;
let nrefi = params.nrefs[params.iatm[ii] as usize * nd + id] as usize;
// 更新 AP 矩阵
update_ap_matrices(
state,
id,
ie,
je,
ii,
jj,
nrefi,
apfr,
nd,
nlvexp,
params.dsfdt,
params.dsfdn,
params.dsfdp,
compute_apt_apn,
);
}
}
}
}
/// 获取截面(占位符)
fn get_cross_section(_params: &Alist2Params, _ibft: usize, _ij: usize, _nd: usize, _id: usize) -> f64 {
// 实际实现需要从 params.cross 数组读取
0.0
}
/// 更新 AP 矩阵
#[allow(clippy::too_many_arguments)]
fn update_ap_matrices(
state: &mut Alist2State,
id: usize,
ie: usize,
je: usize,
ii: usize,
jj: usize,
nrefi: usize,
apfr: f64,
nd: usize,
nlvexp: usize,
dsfdt: &[f64],
dsfdn: &[f64],
dsfdp: &[f64],
compute_apt_apn: bool,
) {
// 下能级贡献
if ie > 0 && ii != nrefi {
// 注意:需要检查 iltlev[ii] <= 0
if compute_apt_apn {
state.apt[ie * nd + id] += apfr * dsfdt[id];
state.apn[ie * nd + id] += apfr * dsfdn[id];
}
for kk in 0..nlvexp {
state.app[(kk * nlvexp + ie) * nd + id] += apfr * dsfdp[kk * nd + id];
}
}
// 上能级贡献
if je > 0 && jj != nrefi {
// 注意:需要检查 iltlev[jj] <= 0 && imodl[ii] != ±4
if compute_apt_apn {
state.apt[je * nd + id] -= apfr * dsfdt[id];
state.apn[je * nd + id] -= apfr * dsfdn[id];
}
for kk in 0..nlvexp {
state.app[(kk * nlvexp + je) * nd + id] -= apfr * dsfdp[kk * nd + id];
}
}
}
/// 处理标准线跃迁(非 ODF
#[allow(clippy::too_many_arguments)]
fn process_line_transitions_standard(
params: &Alist2Params,
state: &mut Alist2State,
ij: usize,
fr: f64,
w0: f64,
lrder: bool,
nd: usize,
nlvexp: usize,
exx: &[f64],
rbnu: &[f64],
rbnuf: &[f64],
compute_apt_apn: bool,
) {
// 主线
if params.ijlin[ij] > 0 {
let itr = (params.ijlin[ij] - 1) as usize;
let ii = (params.ilow[itr] - 1) as usize;
let jj = (params.iup[itr] - 1) as usize;
let ie = (params.iiexp[ii].abs()) as usize;
let je = (params.iiexp[jj].abs()) as usize;
for id in 0..nd {
if params.ipzero[ii * nd + id] != 0 || params.ipzero[jj * nd + id] != 0 {
continue;
}
// 获取线轮廓
let sgw0 = params.prflin[id * params.nfreq + ij] * w0;
// 更新跃迁率
state.rru[itr * nd + id] += sgw0 * params.rad1[id];
state.rrd[itr * nd + id] += sgw0 * rbnu[id];
state.drdt[itr * nd + id] += sgw0 * rbnuf[id];
if lrder {
let apfr = (params.abtra[itr * nd + id] - params.emtra[itr * nd + id] * exx[id]) * sgw0;
let nrefi = params.nrefs[params.iatm[ii] as usize * nd + id] as usize;
update_ap_matrices(
state, id, ie, je, ii, jj, nrefi, apfr, nd, nlvexp,
params.dsfdt, params.dsfdn, params.dsfdp, compute_apt_apn,
);
}
}
}
// 重叠线
if params.nlines[ij] <= 0 {
return;
}
for ilint in 0..params.nlines[ij] as usize {
let itr = (params.itrlin[ij * 100 + ilint] - 1) as usize; // 假设最大 100 条重叠线
if params.linexp[itr] {
continue;
}
let ii = (params.ilow[itr] - 1) as usize;
let jj = (params.iup[itr] - 1) as usize;
let ie = (params.iiexp[ii].abs()) as usize;
let je = (params.iiexp[jj].abs()) as usize;
// 频率插值
let ij0 = (params.ifr0[itr] - 1) as usize;
let ij1 = if ij0 > 0 { ij0 - 1 } else { 0 };
let a1 = if ij1 != ij0 {
(fr - params.freq[ij0]) / (params.freq[ij1] - params.freq[ij0]) * w0
} else {
0.0
};
let a2 = w0 - a1;
for id in 0..nd {
if params.ipzero[ii * nd + id] != 0 || params.ipzero[jj * nd + id] != 0 {
continue;
}
let sgw0 = a1 * params.prflin[id * params.nfreq + ij1] + a2 * params.prflin[id * params.nfreq + ij0];
state.rru[itr * nd + id] += sgw0 * params.rad1[id];
state.rrd[itr * nd + id] += sgw0 * rbnu[id];
state.drdt[itr * nd + id] += sgw0 * rbnuf[id];
if lrder {
let apfr = (params.abtra[itr * nd + id] - params.emtra[itr * nd + id] * exx[id]) * sgw0;
let nrefi = params.nrefs[params.iatm[ii] as usize * nd + id] as usize;
update_ap_matrices(
state, id, ie, je, ii, jj, nrefi, apfr, nd, nlvexp,
params.dsfdt, params.dsfdn, params.dsfdp, compute_apt_apn,
);
}
}
}
}
/// 处理 ODF 线跃迁
#[allow(clippy::too_many_arguments)]
fn process_line_transitions_odf(
params: &Alist2Params,
state: &mut Alist2State,
ij: usize,
w0: f64,
lrder: bool,
nd: usize,
nlvexp: usize,
exx: &[f64],
rbnu: &[f64],
rbnuf: &[f64],
compute_apt_apn: bool,
) {
if params.nlines[ij] <= 0 {
return;
}
for ilint in 0..params.nlines[ij] as usize {
let itr = (params.itrlin[ij * 100 + ilint] - 1) as usize;
let ii = (params.ilow[itr] - 1) as usize;
let jj = (params.iup[itr] - 1) as usize;
let ie = (params.iiexp[ii].abs()) as usize;
let je = (params.iiexp[jj].abs()) as usize;
let kj = ij - (params.ifr0[itr] - 1) as usize + (params.kfr0[itr] - 1) as usize;
let indxpa = (params.indexp[itr].abs()) as i32;
for id in 0..nd {
if params.ipzero[ii * nd + id] != 0 || params.ipzero[jj * nd + id] != 0 {
continue;
}
let sgw0 = if indxpa != 3 && indxpa != 4 {
// 标准 ODF
params.prflin[id * params.nfreq + kj] * w0
} else {
// Fe 线特殊处理
let kjd = (params.jidi[id] - 1) as usize;
let sg = (params.xjid[id] * params.sigfe[kjd * 1000 + kj]
+ (UN - params.xjid[id]) * params.sigfe[(kjd + 1) * 1000 + kj]).exp();
sg * w0
};
state.rru[itr * nd + id] += sgw0 * params.rad1[id];
state.rrd[itr * nd + id] += sgw0 * rbnu[id];
state.drdt[itr * nd + id] += sgw0 * rbnuf[id];
if lrder {
let apfr = (params.abtra[itr * nd + id] - params.emtra[itr * nd + id] * exx[id]) * sgw0;
let nrefi = params.nrefs[params.iatm[ii] as usize * nd + id] as usize;
update_ap_matrices(
state, id, ie, je, ii, jj, nrefi, apfr, nd, nlvexp,
params.dsfdt, params.dsfdn, params.dsfdp, compute_apt_apn,
);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alist2_zero_rates() {
let nd = 5;
let ntrans = 10;
let nlvexp = 3;
let mut reit = vec![0.0; MDEPTH];
let mut rru = vec![0.0; MTRANS * MDEPTH];
let mut apt = vec![0.0; MLVEXP * MDEPTH];
let mut state = Alist2State {
reit: &mut reit,
rein: &mut vec![0.0; MDEPTH],
reix: &mut vec![0.0; MDEPTH],
areit: &mut vec![0.0; MDEPTH],
arein: &mut vec![0.0; MDEPTH],
creit: &mut vec![0.0; MDEPTH],
crein: &mut vec![0.0; MDEPTH],
creix: &mut vec![0.0; MDEPTH],
redt: &mut vec![0.0; MDEPTH],
redtm: &mut vec![0.0; MDEPTH],
redtp: &mut vec![0.0; MDEPTH],
redn: &mut vec![0.0; MDEPTH],
rednm: &mut vec![0.0; MDEPTH],
rednp: &mut vec![0.0; MDEPTH],
redx: &mut vec![0.0; MDEPTH],
redxm: &mut vec![0.0; MDEPTH],
redxp: &mut vec![0.0; MDEPTH],
heit: &mut vec![0.0; MDEPTH],
heitm: &mut vec![0.0; MDEPTH],
heitp: &mut vec![0.0; MDEPTH],
hein: &mut vec![0.0; MDEPTH],
heinm: &mut vec![0.0; MDEPTH],
heinp: &mut vec![0.0; MDEPTH],
ehet: &mut vec![0.0; MDEPTH],
ehen: &mut vec![0.0; MDEPTH],
eret: &mut vec![0.0; MDEPTH],
eren: &mut vec![0.0; MDEPTH],
fcooli: &mut vec![0.0; MDEPTH],
flfix: &mut vec![0.0; MDEPTH],
flexp: &mut vec![0.0; MDEPTH],
flrd: &mut vec![0.0; MDEPTH],
fprd: &mut vec![0.0; MDEPTH],
pradt: &mut vec![0.0; MDEPTH],
prada: &mut vec![0.0; MDEPTH],
heip: &mut vec![0.0; MLVEXP * MDEPTH],
reip: &mut vec![0.0; MLVEXP * MDEPTH],
areip: &mut vec![0.0; MLVEXP * MDEPTH],
creip: &mut vec![0.0; MLVEXP * MDEPTH],
redp: &mut vec![0.0; MLVEXP * MDEPTH],
redpm: &mut vec![0.0; MLVEXP * MDEPTH],
heipm: &mut vec![0.0; MLVEXP * MDEPTH],
redpp: &mut vec![0.0; MLVEXP * MDEPTH],
heipp: &mut vec![0.0; MLVEXP * MDEPTH],
apt: &mut apt,
apn: &mut vec![0.0; MLVEXP * MDEPTH],
app: &mut vec![0.0; MLVEXP * MLVEXP * MDEPTH],
abrosd: &mut vec![0.0; MDEPTH],
sumdpl: &mut vec![0.0; MDEPTH],
rru: &mut rru,
rrd: &mut vec![0.0; MTRANS * MDEPTH],
drdt: &mut vec![0.0; MTRANS * MDEPTH],
prd0: &mut 0.0,
};
// 初始化一些非零值
state.reit[0] = 1.0;
state.rru[0] = 1.0;
zero_rates(&mut state, nd, ntrans, nlvexp);
// 验证所有值都被清零
for id in 0..nd {
assert_eq!(state.reit[id], 0.0);
}
for itr in 0..ntrans {
for id in 0..nd {
assert_eq!(state.rru[itr * nd + id], 0.0);
}
}
}
}