900 lines
26 KiB
Rust
900 lines
26 KiB
Rust
//! ALI (加速 Lambda 迭代) Kantorovich 迭代简化版本。
|
||
//!
|
||
//! 重构自 TLUSTY `alisk1.f`
|
||
//!
|
||
//! # 功能
|
||
//!
|
||
//! 简化版 ALIST1,用于 Kantorovich 迭代。
|
||
//! 计算所有必要的 ALI 参数和辐射跃迁率。
|
||
//!
|
||
//! # 算法
|
||
//!
|
||
//! 1. 初始化速率和其他量
|
||
//! 2. 确定是否计算 Rosseland 平均不透明度
|
||
//! 3. 遍历所有频率点:
|
||
//! - 计算不透明度 (OPACF1)
|
||
//! - 求解辐射转移方程 (RTEFR1)
|
||
//! - 计算 ALI 系数 (ALIFRK)
|
||
//! - 可选:计算 Rosseland 贡献 (ROSSTD)
|
||
//! - 处理连续谱跃迁
|
||
//! - 处理线跃迁
|
||
//! 4. 后处理:乘以频率无关常数
|
||
//! 5. 辐射压力计算
|
||
//! 6. Rosseland 平均不透明度
|
||
|
||
use crate::tlusty::state::constants::{MDEPTH, MFREQ, MTRANS, UN, HK, PCK};
|
||
|
||
// ============================================================================
|
||
// 配置结构体
|
||
// ============================================================================
|
||
|
||
/// ALISK1 配置参数。
|
||
#[derive(Debug, Clone)]
|
||
pub struct Alisk1Config {
|
||
/// 深度修正数(负值表示不计算 Rosseland)
|
||
pub ndre: i32,
|
||
/// 当前迭代次数
|
||
pub iter: i32,
|
||
/// 最终迭代标志
|
||
pub lfin: bool,
|
||
/// 混合参数 (>0 强制计算 Rosseland)
|
||
pub hmix0: f64,
|
||
/// 不透明度表格标志 (<0 跳过跃迁处理)
|
||
pub ioptab: i32,
|
||
/// 盘模式标志
|
||
pub idisk: i32,
|
||
}
|
||
|
||
impl Default for Alisk1Config {
|
||
fn default() -> Self {
|
||
Self {
|
||
ndre: 0,
|
||
iter: 1,
|
||
lfin: false,
|
||
hmix0: 0.0,
|
||
ioptab: 0,
|
||
idisk: 0,
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 输入/输出结构体
|
||
// ============================================================================
|
||
|
||
/// ALISK1 频率相关参数。
|
||
pub struct Alisk1FreqParams<'a> {
|
||
/// 频率数
|
||
pub nfreq: usize,
|
||
/// 频率数组 [nfreq]
|
||
pub freq: &'a [f64],
|
||
/// 频率权重 [nfreq]
|
||
pub w0e: &'a [f64],
|
||
/// 频率索引标志 (-1 表示跳过) [nfreq]
|
||
pub ijx: &'a [i32],
|
||
/// 扩展频率索引 (>0 表示扩展) [nfreq]
|
||
pub ijex: &'a [i32],
|
||
/// 线频率索引 (>0 表示有线) [nfreq]
|
||
pub ijlin: &'a [i32],
|
||
/// 重叠线数 [nfreq]
|
||
pub nlines: &'a [i32],
|
||
/// 普朗克函数 [nfreq × nd] - BNUE
|
||
pub bnue: &'a [f64],
|
||
}
|
||
|
||
/// ALISK1 原子参数。
|
||
pub struct Alisk1AtomicParams<'a> {
|
||
/// 连续谱跃迁数
|
||
pub ntranc: usize,
|
||
/// 总跃迁数
|
||
pub ntrans: usize,
|
||
/// 束缚-自由跃迁索引 [ntranc], 1-indexed
|
||
pub itrbf: &'a [i32],
|
||
/// 低能级索引 [ntrans], 1-indexed
|
||
pub ilow: &'a [i32],
|
||
/// 高能级索引 [ntrans], 1-indexed
|
||
pub iup: &'a [i32],
|
||
/// Macfarlane 下沉修正索引 [ntrans]
|
||
pub mcdw: &'a [i32],
|
||
/// 能级合并组索引 [mlevel]
|
||
pub imrg: &'a [i32],
|
||
/// 能级频率加权选项 [mlevel]
|
||
pub ifwop: &'a [i32],
|
||
/// 束缚-自由截面 [ntranc × nfreq]
|
||
pub cross: &'a [f64],
|
||
/// 线线型 [nfreq × nd] - PRFLIN
|
||
pub prflin: &'a [f64],
|
||
/// 重叠线跃迁索引 [maxlines × nfreq], 1-indexed
|
||
pub trlin: &'a [i32],
|
||
/// 跃迁起始频率索引 [ntrans]
|
||
pub ifr0: &'a [i32],
|
||
/// 跃迁结束频率索引 [ntrans]
|
||
pub ifr1: &'a [i32],
|
||
/// 线排除标志 [ntrans]
|
||
pub linexp: &'a [bool],
|
||
/// 合并 Gaunt 因子 [mmer × nd]
|
||
pub sgmg: &'a [f64],
|
||
/// 下沉因子 [maxcdw × nd]
|
||
pub dwf1: &'a [f64],
|
||
/// ITRA 索引矩阵 [mlevel × mlevel]
|
||
pub itra: &'a [i32],
|
||
}
|
||
|
||
/// ALISK1 模型状态参数。
|
||
pub struct Alisk1ModelState<'a> {
|
||
/// 深度点数
|
||
pub nd: usize,
|
||
/// 温度 [nd]
|
||
pub temp: &'a [f64],
|
||
/// 电子密度 [nd]
|
||
pub elec: &'a [f64],
|
||
/// 总粒子密度 [nd]
|
||
pub dens: &'a [f64],
|
||
/// 密度倒数 [nd]
|
||
pub dens1: &'a [f64],
|
||
/// 柱质量密度 [nd]
|
||
pub dm: &'a [f64],
|
||
/// HK/T [nd]
|
||
pub hkt1: &'a [f64],
|
||
/// 辐射等效积分 [nd]
|
||
pub reint: &'a [f64],
|
||
/// 辐射等效扩散 [nd]
|
||
pub redif: &'a [f64],
|
||
/// CRSW 修正因子 [nd]
|
||
pub crsw: &'a [f64],
|
||
/// 零占据数标志 [mlevel × nd]
|
||
pub ipzero: &'a [i32],
|
||
}
|
||
|
||
/// ALISK1 输出状态。
|
||
pub struct Alisk1OutputState<'a> {
|
||
// 累积量 [nd]
|
||
/// 冷却率积分
|
||
pub fcooli: &'a mut [f64],
|
||
/// 固定辐射通量
|
||
pub flfix: &'a mut [f64],
|
||
/// 辐射压力导数
|
||
pub fprd: &'a mut [f64],
|
||
/// 辐射通量红翼
|
||
pub flrd: &'a mut [f64],
|
||
/// 辐射压力总量
|
||
pub pradt: &'a mut [f64],
|
||
/// 辐射压力吸收
|
||
pub prada: &'a mut [f64],
|
||
/// 参考辐射压力 [输出]
|
||
pub prd0: &'a mut f64,
|
||
|
||
// 跃迁率 [ntrans × nd]
|
||
/// 向上跃迁率
|
||
pub rru: &'a mut [f64],
|
||
/// 向下跃迁率
|
||
pub rrd: &'a mut [f64],
|
||
|
||
// Rosseland 平均
|
||
/// Rosseland 平均不透明度 [nd]
|
||
pub abrosd: &'a mut [f64],
|
||
/// Rosseland 累加量 [nd]
|
||
pub sumdpl: &'a mut [f64],
|
||
|
||
// 扩展频率数据
|
||
/// 扩展吸收系数 [存储索引 × nd]
|
||
pub absoex: &'a mut [f64],
|
||
/// 扩展发射系数 [存储索引 × nd]
|
||
pub emisex: &'a mut [f64],
|
||
/// 扩展散射系数 [存储索引 × nd]
|
||
pub scatex: &'a mut [f64],
|
||
|
||
// 单频率工作数组(由 OPACF1/RTEFR1 填充)
|
||
/// 当前频率吸收系数 [nd]
|
||
pub abso1: &'a mut [f64],
|
||
/// 当前频率发射系数 [nd]
|
||
pub emis1: &'a mut [f64],
|
||
/// 当前频率散射系数 [nd]
|
||
pub scat1: &'a mut [f64],
|
||
/// 当前频率辐射强度 [nd]
|
||
pub rad1: &'a mut [f64],
|
||
}
|
||
|
||
/// ALISK1 输出结果。
|
||
#[derive(Debug, Clone)]
|
||
pub struct Alisk1Output {
|
||
/// 是否执行了计算
|
||
pub computed: bool,
|
||
/// Rosseland 标志
|
||
pub lross: bool,
|
||
/// 最小辐射压力比
|
||
pub prdx: f64,
|
||
}
|
||
|
||
// ============================================================================
|
||
// 核心计算函数
|
||
// ============================================================================
|
||
|
||
/// ALI Kantorovich 迭代简化版本 (ALISK1)。
|
||
///
|
||
/// 计算所有必要的 ALI 参数和辐射跃迁率。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `config` - 配置参数
|
||
/// * `freq_params` - 频率相关参数
|
||
/// * `atomic_params` - 原子参数
|
||
/// * `model_state` - 模型状态
|
||
/// * `output_state` - 输出状态(可变)
|
||
///
|
||
/// # 返回值
|
||
///
|
||
/// 返回 `Alisk1Output`,包含计算结果信息。
|
||
///
|
||
/// # 注意
|
||
///
|
||
/// 此函数是一个框架实现,实际调用 OPACF1、RTEFR1、ALIFRK、ROSSTD
|
||
/// 需要在完整系统中实现。当前版本主要用于结构验证。
|
||
pub fn alisk1_pure(
|
||
config: &Alisk1Config,
|
||
freq_params: &Alisk1FreqParams,
|
||
atomic_params: &Alisk1AtomicParams,
|
||
model_state: &Alisk1ModelState,
|
||
output_state: &mut Alisk1OutputState,
|
||
) -> Alisk1Output {
|
||
let nd = model_state.nd;
|
||
let nfreq = freq_params.nfreq;
|
||
let ntrans = atomic_params.ntrans;
|
||
|
||
// ========================================================================
|
||
// 1. 初始化速率和其他量
|
||
// ========================================================================
|
||
for id in 0..nd {
|
||
output_state.fcooli[id] = 0.0;
|
||
output_state.flfix[id] = 0.0;
|
||
output_state.fprd[id] = 0.0;
|
||
output_state.flrd[id] = 0.0;
|
||
output_state.pradt[id] = 0.0;
|
||
output_state.prada[id] = 0.0;
|
||
|
||
for itr in 0..ntrans {
|
||
output_state.rru[itr * nd + id] = 0.0;
|
||
output_state.rrd[itr * nd + id] = 0.0;
|
||
}
|
||
}
|
||
*output_state.prd0 = 0.0;
|
||
|
||
// ========================================================================
|
||
// 2. 确定 LROSS 标志
|
||
// ========================================================================
|
||
// LROSS = NDRE.LE.0.AND.ITER.EQ.1.OR.LFIN
|
||
// IF(HMIX0.GT.0.) LROSS=.TRUE.
|
||
let mut lross = (config.ndre <= 0 && config.iter == 1) || config.lfin;
|
||
if config.hmix0 > 0.0 {
|
||
lross = true;
|
||
}
|
||
|
||
if lross {
|
||
for id in 0..nd {
|
||
output_state.abrosd[id] = 0.0;
|
||
output_state.sumdpl[id] = 0.0;
|
||
}
|
||
}
|
||
|
||
// ========================================================================
|
||
// 3. 遍历频率点
|
||
// ========================================================================
|
||
for ij in 0..nfreq {
|
||
// 跳过标记为 -1 的频率
|
||
if freq_params.ijx[ij] == -1 {
|
||
continue;
|
||
}
|
||
|
||
let fr = freq_params.freq[ij];
|
||
let w0 = freq_params.w0e[ij];
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3a. 调用 OPACF1(IJ) - 计算不透明度
|
||
// ----------------------------------------------------------------
|
||
// 注意:实际实现需要调用 opacf1 函数
|
||
// 这里只是框架,假设 abso1, emis1, scat1 已填充
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3b. 存储扩展频率数据
|
||
// ----------------------------------------------------------------
|
||
let ije = freq_params.ijex[ij];
|
||
if ije > 0 {
|
||
let ije_idx = (ije - 1) as usize;
|
||
for id in 0..nd {
|
||
output_state.absoex[ije_idx * nd + id] = output_state.abso1[id];
|
||
output_state.emisex[ije_idx * nd + id] = output_state.emis1[id];
|
||
output_state.scatex[ije_idx * nd + id] = output_state.scat1[id];
|
||
}
|
||
}
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3c. 调用 RTEFR1(IJ) - 辐射转移
|
||
// ----------------------------------------------------------------
|
||
// 注意:实际实现需要调用 rtefr1 函数
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3d. 调用 ALIFRK(IJ) - ALI 系数
|
||
// ----------------------------------------------------------------
|
||
// 注意:实际实现需要调用 alifrk 函数
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3e. 可选:调用 ROSSTD(IJ) - Rosseland 贡献
|
||
// ----------------------------------------------------------------
|
||
// if lross { rosstd_contribute(...); }
|
||
|
||
// 跳过跃迁处理(如果 ioptab < 0)
|
||
if config.ioptab < 0 {
|
||
continue;
|
||
}
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3f. 处理连续谱跃迁
|
||
// ----------------------------------------------------------------
|
||
process_continuum_transitions(
|
||
ij,
|
||
fr,
|
||
w0,
|
||
nd,
|
||
freq_params,
|
||
atomic_params,
|
||
model_state,
|
||
output_state,
|
||
);
|
||
|
||
// ----------------------------------------------------------------
|
||
// 3g. 处理线跃迁
|
||
// ----------------------------------------------------------------
|
||
process_line_transitions(
|
||
ij,
|
||
fr,
|
||
w0,
|
||
nd,
|
||
freq_params,
|
||
atomic_params,
|
||
model_state,
|
||
output_state,
|
||
);
|
||
}
|
||
|
||
// ========================================================================
|
||
// 4. 后处理:乘以频率无关常数
|
||
// ========================================================================
|
||
for id in 0..nd {
|
||
// FCOOL(ID) = REINT(ID) * FCOOLI(ID) - REDIF(ID) * FLFIX(ID)
|
||
// 注意:这里更新的是 fcooli,完整的 fcool 计算在外部
|
||
|
||
// CRSW 修正
|
||
if (model_state.crsw[id] - UN).abs() > 1e-30 {
|
||
for itr in 0..ntrans {
|
||
output_state.rru[itr * nd + id] *= model_state.crsw[id];
|
||
output_state.rrd[itr * nd + id] *= model_state.crsw[id];
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========================================================================
|
||
// 5. 辐射压力计算
|
||
// ========================================================================
|
||
let mut prdx = 1.0;
|
||
for id in 0..nd {
|
||
output_state.pradt[id] *= PCK;
|
||
output_state.prada[id] *= PCK;
|
||
|
||
if output_state.prada[id] > 0.0 {
|
||
let prdr = output_state.pradt[id] / output_state.prada[id];
|
||
if prdr < prdx {
|
||
prdx = prdr;
|
||
}
|
||
}
|
||
}
|
||
|
||
// PRD0 = PRD0 / DENS1(1) * DM(1) * PCK
|
||
*output_state.prd0 = *output_state.prd0 / model_state.dens1[0] * model_state.dm[0] * PCK;
|
||
|
||
// ========================================================================
|
||
// 6. Rosseland 平均不透明度
|
||
// ========================================================================
|
||
if lross {
|
||
for id in 0..nd {
|
||
if output_state.abrosd[id] > 0.0 {
|
||
output_state.abrosd[id] =
|
||
output_state.sumdpl[id] / (output_state.abrosd[id] * model_state.dens[id]);
|
||
}
|
||
}
|
||
}
|
||
|
||
Alisk1Output {
|
||
computed: true,
|
||
lross,
|
||
prdx,
|
||
}
|
||
}
|
||
|
||
/// 处理连续谱跃迁。
|
||
fn process_continuum_transitions(
|
||
ij: usize,
|
||
fr: f64,
|
||
w0: f64,
|
||
nd: usize,
|
||
freq_params: &Alisk1FreqParams,
|
||
atomic_params: &Alisk1AtomicParams,
|
||
model_state: &Alisk1ModelState,
|
||
output_state: &mut Alisk1OutputState,
|
||
) {
|
||
let ntranc = atomic_params.ntranc;
|
||
|
||
// 工作数组 RBNU(MDEPTH)
|
||
let mut rbnu = vec![0.0; MDEPTH];
|
||
|
||
// 计算 RBNU = (RAD1 + BNUE) * EXP(-HKT1 * FR)
|
||
for id in 0..nd {
|
||
let bnue_ij = freq_params.bnue[ij * nd + id];
|
||
rbnu[id] = (output_state.rad1[id] + bnue_ij) * (-model_state.hkt1[id] * fr).exp();
|
||
}
|
||
|
||
// 遍历连续谱跃迁
|
||
for ibft in 0..ntranc {
|
||
let itr = (atomic_params.itrbf[ibft] - 1) as usize; // 1-indexed to 0-indexed
|
||
let sg = atomic_params.cross[ibft * freq_params.nfreq + ij];
|
||
|
||
if sg <= 0.0 {
|
||
continue;
|
||
}
|
||
|
||
let ii = (atomic_params.ilow[itr] - 1) as usize;
|
||
let jj = (atomic_params.iup[itr] - 1) as usize;
|
||
|
||
// 检查零占据数
|
||
for id in 0..nd {
|
||
if model_state.ipzero[ii * nd + id] != 0 || model_state.ipzero[jj * nd + id] != 0 {
|
||
continue;
|
||
}
|
||
|
||
let jc = (atomic_params.itra[jj * ii + jj] - 1) as usize; // ITRA(JJ, II)
|
||
let icdw = atomic_params.mcdw[itr];
|
||
let imer = atomic_params.imrg[ii] as usize;
|
||
|
||
let mut sg_local = sg;
|
||
|
||
// 频率加权修正
|
||
if atomic_params.ifwop[ii] >= 0 {
|
||
if icdw >= 1 {
|
||
let icdw_idx = (icdw - 1) as usize;
|
||
sg_local *= atomic_params.dwf1[icdw_idx * nd + id];
|
||
}
|
||
} else {
|
||
sg_local = atomic_params.sgmg[imer * nd + id];
|
||
}
|
||
|
||
let sgw0 = sg_local * w0;
|
||
|
||
// 累积跃迁率
|
||
output_state.rru[itr * nd + id] += sgw0 * output_state.rad1[id];
|
||
output_state.rrd[itr * nd + id] += sgw0 * rbnu[id];
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 处理线跃迁。
|
||
fn process_line_transitions(
|
||
ij: usize,
|
||
fr: f64,
|
||
w0: f64,
|
||
nd: usize,
|
||
freq_params: &Alisk1FreqParams,
|
||
atomic_params: &Alisk1AtomicParams,
|
||
model_state: &Alisk1ModelState,
|
||
output_state: &mut Alisk1OutputState,
|
||
) {
|
||
// 主线跃迁
|
||
let ijlin_ij = freq_params.ijlin[ij];
|
||
if ijlin_ij > 0 {
|
||
let itr = (ijlin_ij - 1) as usize; // 1-indexed to 0-indexed
|
||
|
||
for id in 0..nd {
|
||
let sgw0 = atomic_params.prflin[ij * nd + id] * w0;
|
||
let rbnu = output_state.rad1[id] * (-fr * HK / model_state.temp[id]).exp();
|
||
|
||
output_state.rru[itr * nd + id] += sgw0 * output_state.rad1[id];
|
||
output_state.rrd[itr * nd + id] += sgw0 * rbnu;
|
||
}
|
||
}
|
||
|
||
// 重叠线
|
||
let nlines_ij = freq_params.nlines[ij];
|
||
if nlines_ij <= 0 {
|
||
return;
|
||
}
|
||
|
||
for ilint in 0..nlines_ij as usize {
|
||
let itr = (atomic_params.trlin[ilint * freq_params.nfreq + ij] - 1) as usize;
|
||
|
||
// 检查线排除
|
||
if atomic_params.linexp[itr] {
|
||
continue;
|
||
}
|
||
|
||
let ij0 = atomic_params.ifr0[itr] as usize;
|
||
let ij1 = atomic_params.ifr1[itr] as usize;
|
||
|
||
// 查找插值位置
|
||
let mut ij0_idx = ij0;
|
||
for ijt in ij0..=ij1 {
|
||
if freq_params.freq[ijt] <= fr {
|
||
ij0_idx = ijt;
|
||
break;
|
||
}
|
||
}
|
||
|
||
let ij1_idx = if ij0_idx > 0 { ij0_idx - 1 } else { 0 };
|
||
|
||
// 插值系数
|
||
let freq_ij0 = freq_params.freq[ij0_idx];
|
||
let freq_ij1 = freq_params.freq[ij1_idx];
|
||
let denom = freq_ij1 - freq_ij0;
|
||
|
||
let (a1, a2) = if denom.abs() > 1e-30 {
|
||
let a1 = (fr - freq_ij0) / denom * w0;
|
||
(a1, w0 - a1)
|
||
} else {
|
||
(w0, 0.0)
|
||
};
|
||
|
||
// 累积跃迁率
|
||
for id in 0..nd {
|
||
let sgw0 = a1 * atomic_params.prflin[ij1_idx * nd + id]
|
||
+ a2 * atomic_params.prflin[ij0_idx * nd + id];
|
||
let rbnu = output_state.rad1[id] * (-fr * HK / model_state.temp[id]).exp();
|
||
|
||
output_state.rru[itr * nd + id] += sgw0 * output_state.rad1[id];
|
||
output_state.rrd[itr * nd + id] += sgw0 * rbnu;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 测试
|
||
// ============================================================================
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
fn create_test_config() -> Alisk1Config {
|
||
Alisk1Config {
|
||
ndre: 0,
|
||
iter: 1,
|
||
lfin: false,
|
||
hmix0: 0.0,
|
||
ioptab: -1, // 跳过跃迁处理
|
||
idisk: 0,
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_alisk1_initialization() {
|
||
let config = create_test_config();
|
||
|
||
// 创建最小测试数据
|
||
let nfreq = 10;
|
||
let nd = 5;
|
||
let ntrans = 3;
|
||
|
||
let freq = vec![1e14; nfreq];
|
||
let w0e = vec![1.0; nfreq];
|
||
let ijx = vec![0; nfreq];
|
||
let ijex = vec![0; nfreq];
|
||
let ijlin = vec![0; nfreq];
|
||
let nlines = vec![0; nfreq];
|
||
let bnue = vec![0.0; nfreq * nd];
|
||
|
||
let freq_params = Alisk1FreqParams {
|
||
nfreq,
|
||
freq: &freq,
|
||
w0e: &w0e,
|
||
ijx: &ijx,
|
||
ijex: &ijex,
|
||
ijlin: &ijlin,
|
||
nlines: &nlines,
|
||
bnue: &bnue,
|
||
};
|
||
|
||
let itrbf = vec![1, 2, 3];
|
||
let ilow = vec![1, 1, 2];
|
||
let iup = vec![2, 3, 3];
|
||
let mcdw = vec![0; ntrans];
|
||
let imrg = vec![0; 10];
|
||
let ifwop = vec![0; 10];
|
||
let cross = vec![0.0; 3 * nfreq];
|
||
let prflin = vec![0.0; nfreq * nd];
|
||
let trlin = vec![0; 10 * nfreq];
|
||
let ifr0 = vec![0; ntrans];
|
||
let ifr1 = vec![0; ntrans];
|
||
let linexp = vec![false; ntrans];
|
||
let sgmg = vec![1.0; 5 * nd];
|
||
let dwf1 = vec![1.0; 5 * nd];
|
||
let itra = vec![0; 100];
|
||
|
||
let atomic_params = Alisk1AtomicParams {
|
||
ntranc: 3,
|
||
ntrans,
|
||
itrbf: &itrbf,
|
||
ilow: &ilow,
|
||
iup: &iup,
|
||
mcdw: &mcdw,
|
||
imrg: &imrg,
|
||
ifwop: &ifwop,
|
||
cross: &cross,
|
||
prflin: &prflin,
|
||
trlin: &trlin,
|
||
ifr0: &ifr0,
|
||
ifr1: &ifr1,
|
||
linexp: &linexp,
|
||
sgmg: &sgmg,
|
||
dwf1: &dwf1,
|
||
itra: &itra,
|
||
};
|
||
|
||
let temp = vec![10000.0; nd];
|
||
let elec = vec![1e12; nd];
|
||
let dens = vec![1e14; nd];
|
||
let dens1 = vec![1e-14; nd];
|
||
let dm = vec![1e-3; nd];
|
||
let hkt1 = vec![4.8e-12; nd];
|
||
let reint = vec![1.0; nd];
|
||
let redif = vec![0.0; nd];
|
||
let crsw = vec![1.0; nd];
|
||
let ipzero = vec![0; 100 * nd];
|
||
|
||
let model_state = Alisk1ModelState {
|
||
nd,
|
||
temp: &temp,
|
||
elec: &elec,
|
||
dens: &dens,
|
||
dens1: &dens1,
|
||
dm: &dm,
|
||
hkt1: &hkt1,
|
||
reint: &reint,
|
||
redif: &redif,
|
||
crsw: &crsw,
|
||
ipzero: &ipzero,
|
||
};
|
||
|
||
let mut fcooli = vec![0.0; nd];
|
||
let mut flfix = vec![0.0; nd];
|
||
let mut fprd = vec![0.0; nd];
|
||
let mut flrd = vec![0.0; nd];
|
||
let mut pradt = vec![0.0; nd];
|
||
let mut prada = vec![0.0; nd];
|
||
let mut prd0 = 0.0;
|
||
let mut rru = vec![0.0; ntrans * nd];
|
||
let mut rrd = vec![0.0; ntrans * nd];
|
||
let mut abrosd = vec![0.0; nd];
|
||
let mut sumdpl = vec![0.0; nd];
|
||
let mut absoex = vec![0.0; 10 * nd];
|
||
let mut emisex = vec![0.0; 10 * nd];
|
||
let mut scatex = vec![0.0; 10 * nd];
|
||
let mut abso1 = vec![1.0; nd];
|
||
let mut emis1 = vec![0.5; nd];
|
||
let mut scat1 = vec![0.1; nd];
|
||
let mut rad1 = vec![0.8; nd];
|
||
|
||
let mut output_state = Alisk1OutputState {
|
||
fcooli: &mut fcooli,
|
||
flfix: &mut flfix,
|
||
fprd: &mut fprd,
|
||
flrd: &mut flrd,
|
||
pradt: &mut pradt,
|
||
prada: &mut prada,
|
||
prd0: &mut prd0,
|
||
rru: &mut rru,
|
||
rrd: &mut rrd,
|
||
abrosd: &mut abrosd,
|
||
sumdpl: &mut sumdpl,
|
||
absoex: &mut absoex,
|
||
emisex: &mut emisex,
|
||
scatex: &mut scatex,
|
||
abso1: &mut abso1,
|
||
emis1: &mut emis1,
|
||
scat1: &mut scat1,
|
||
rad1: &mut rad1,
|
||
};
|
||
|
||
let output = alisk1_pure(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
|
||
|
||
assert!(output.computed);
|
||
assert!(output.lross); // 因为 iter=1 且 ndre=0
|
||
}
|
||
|
||
#[test]
|
||
fn test_alisk1_skip_frequency() {
|
||
let mut config = create_test_config();
|
||
|
||
let nfreq = 5;
|
||
let nd = 3;
|
||
let ntrans = 2;
|
||
|
||
// 设置 IJX[0] = -1,应该跳过第一个频率
|
||
let freq = vec![1e14; nfreq];
|
||
let w0e = vec![1.0; nfreq];
|
||
let ijx = vec![-1, 0, 0, 0, 0];
|
||
let ijex = vec![0; nfreq];
|
||
let ijlin = vec![0; nfreq];
|
||
let nlines = vec![0; nfreq];
|
||
let bnue = vec![0.0; nfreq * nd];
|
||
|
||
let freq_params = Alisk1FreqParams {
|
||
nfreq,
|
||
freq: &freq,
|
||
w0e: &w0e,
|
||
ijx: &ijx,
|
||
ijex: &ijex,
|
||
ijlin: &ijlin,
|
||
nlines: &nlines,
|
||
bnue: &bnue,
|
||
};
|
||
|
||
let itrbf = vec![1, 2];
|
||
let ilow = vec![1, 2];
|
||
let iup = vec![2, 3];
|
||
let mcdw = vec![0; ntrans];
|
||
let imrg = vec![0; 10];
|
||
let ifwop = vec![0; 10];
|
||
let cross = vec![0.0; 2 * nfreq];
|
||
let prflin = vec![0.0; nfreq * nd];
|
||
let trlin = vec![0; 10 * nfreq];
|
||
let ifr0 = vec![0; ntrans];
|
||
let ifr1 = vec![0; ntrans];
|
||
let linexp = vec![false; ntrans];
|
||
let sgmg = vec![1.0; 5 * nd];
|
||
let dwf1 = vec![1.0; 5 * nd];
|
||
let itra = vec![0; 100];
|
||
|
||
let atomic_params = Alisk1AtomicParams {
|
||
ntranc: 2,
|
||
ntrans,
|
||
itrbf: &itrbf,
|
||
ilow: &ilow,
|
||
iup: &iup,
|
||
mcdw: &mcdw,
|
||
imrg: &imrg,
|
||
ifwop: &ifwop,
|
||
cross: &cross,
|
||
prflin: &prflin,
|
||
trlin: &trlin,
|
||
ifr0: &ifr0,
|
||
ifr1: &ifr1,
|
||
linexp: &linexp,
|
||
sgmg: &sgmg,
|
||
dwf1: &dwf1,
|
||
itra: &itra,
|
||
};
|
||
|
||
let temp = vec![10000.0; nd];
|
||
let elec = vec![1e12; nd];
|
||
let dens = vec![1e14; nd];
|
||
let dens1 = vec![1e-14; nd];
|
||
let dm = vec![1e-3; nd];
|
||
let hkt1 = vec![4.8e-12; nd];
|
||
let reint = vec![1.0; nd];
|
||
let redif = vec![0.0; nd];
|
||
let crsw = vec![1.0; nd];
|
||
let ipzero = vec![0; 100 * nd];
|
||
|
||
let model_state = Alisk1ModelState {
|
||
nd,
|
||
temp: &temp,
|
||
elec: &elec,
|
||
dens: &dens,
|
||
dens1: &dens1,
|
||
dm: &dm,
|
||
hkt1: &hkt1,
|
||
reint: &reint,
|
||
redif: &redif,
|
||
crsw: &crsw,
|
||
ipzero: &ipzero,
|
||
};
|
||
|
||
let mut fcooli = vec![0.0; nd];
|
||
let mut flfix = vec![0.0; nd];
|
||
let mut fprd = vec![0.0; nd];
|
||
let mut flrd = vec![0.0; nd];
|
||
let mut pradt = vec![0.0; nd];
|
||
let mut prada = vec![0.0; nd];
|
||
let mut prd0 = 0.0;
|
||
let mut rru = vec![0.0; ntrans * nd];
|
||
let mut rrd = vec![0.0; ntrans * nd];
|
||
let mut abrosd = vec![0.0; nd];
|
||
let mut sumdpl = vec![0.0; nd];
|
||
let mut absoex = vec![0.0; 10 * nd];
|
||
let mut emisex = vec![0.0; 10 * nd];
|
||
let mut scatex = vec![0.0; 10 * nd];
|
||
let mut abso1 = vec![1.0; nd];
|
||
let mut emis1 = vec![0.5; nd];
|
||
let mut scat1 = vec![0.1; nd];
|
||
let mut rad1 = vec![0.8; nd];
|
||
|
||
let mut output_state = Alisk1OutputState {
|
||
fcooli: &mut fcooli,
|
||
flfix: &mut flfix,
|
||
fprd: &mut fprd,
|
||
flrd: &mut flrd,
|
||
pradt: &mut pradt,
|
||
prada: &mut prada,
|
||
prd0: &mut prd0,
|
||
rru: &mut rru,
|
||
rrd: &mut rrd,
|
||
abrosd: &mut abrosd,
|
||
sumdpl: &mut sumdpl,
|
||
absoex: &mut absoex,
|
||
emisex: &mut emisex,
|
||
scatex: &mut scatex,
|
||
abso1: &mut abso1,
|
||
emis1: &mut emis1,
|
||
scat1: &mut scat1,
|
||
rad1: &mut rad1,
|
||
};
|
||
|
||
let output = alisk1_pure(&config, &freq_params, &atomic_params, &model_state, &mut output_state);
|
||
|
||
assert!(output.computed);
|
||
}
|
||
|
||
#[test]
|
||
fn test_lross_determination() {
|
||
// 测试 LROSS 标志的各种条件
|
||
|
||
// 条件 1: ndre <= 0 AND iter == 1
|
||
let config1 = Alisk1Config {
|
||
ndre: 0,
|
||
iter: 1,
|
||
lfin: false,
|
||
hmix0: 0.0,
|
||
ioptab: -1,
|
||
idisk: 0,
|
||
};
|
||
// LROSS 应该为 true
|
||
|
||
// 条件 2: lfin = true
|
||
let config2 = Alisk1Config {
|
||
ndre: 1,
|
||
iter: 2,
|
||
lfin: true,
|
||
hmix0: 0.0,
|
||
ioptab: -1,
|
||
idisk: 0,
|
||
};
|
||
// LROSS 应该为 true
|
||
|
||
// 条件 3: hmix0 > 0
|
||
let config3 = Alisk1Config {
|
||
ndre: 1,
|
||
iter: 2,
|
||
lfin: false,
|
||
hmix0: 1.0,
|
||
ioptab: -1,
|
||
idisk: 0,
|
||
};
|
||
// LROSS 应该为 true
|
||
|
||
// 条件 4: 所有条件都不满足
|
||
let config4 = Alisk1Config {
|
||
ndre: 1,
|
||
iter: 2,
|
||
lfin: false,
|
||
hmix0: 0.0,
|
||
ioptab: -1,
|
||
idisk: 0,
|
||
};
|
||
// LROSS 应该为 false
|
||
|
||
// 简单验证配置创建
|
||
assert!(config1.ndre <= 0 && config1.iter == 1);
|
||
assert!(config2.lfin);
|
||
assert!(config3.hmix0 > 0.0);
|
||
assert!(!(config4.ndre <= 0 && config4.iter == 1)
|
||
&& !config4.lfin
|
||
&& !(config4.hmix0 > 0.0));
|
||
}
|
||
}
|