1054 lines
29 KiB
Rust
1054 lines
29 KiB
Rust
//! 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);
|
||
}
|
||
}
|
||
}
|
||
}
|