包含 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>
620 lines
18 KiB
Rust
620 lines
18 KiB
Rust
//! 额外不透明度计算。
|
|
//!
|
|
//! 重构自 TLUSTY `OPADD.f`
|
|
//!
|
|
//! 计算各种额外的非标准不透明度来源:
|
|
//! - Rayleigh 散射 (HI, HeI, H2)
|
|
//! - H⁻ 束缚-自由和自由-自由不透明度
|
|
//! - H₂⁺ 束缚-自由和自由-自由不透明度
|
|
//! - He⁻ 自由-自由不透明度
|
|
//! - H₂⁻ 自由-自由不透明度
|
|
//! - CH 和 OH 连续不透明度
|
|
//! - CIA (碰撞诱导吸收) 不透明度
|
|
|
|
use super::{cia_h2h, cia_h2h2, cia_h2he, cia_hhe, h2minus, sbfch, sbfoh};
|
|
use crate::math::sffhmi::sffhmi;
|
|
|
|
// ============================================================================
|
|
// 常量
|
|
// ============================================================================
|
|
|
|
/// HI Rayleigh 散射阈值频率 (Hz)
|
|
const FRAY: f64 = 2.463e15;
|
|
/// HeI Rayleigh 散射阈值频率 (Hz)
|
|
const FRAYHE: f64 = 5.150e15;
|
|
/// H2 Rayleigh 散射阈值频率 (Hz)
|
|
const FRAYH2: f64 = 2.922e15;
|
|
/// 光速 (Å/s)
|
|
const CLS: f64 = 2.997925e18;
|
|
/// 光速 (cm/s)
|
|
const C18: f64 = 2.997925e18;
|
|
/// H⁻ 束缚-自由常数
|
|
const CR0: f64 = 5.799e-13;
|
|
const CR1: f64 = 1.422e-6;
|
|
const CR2: f64 = 2.784;
|
|
const TENM4: f64 = 1.0e-4;
|
|
/// H⁻ 束缚-自由阈值
|
|
const THM0: f64 = 8.7629e3;
|
|
/// Saha 常数
|
|
const SBHM: f64 = 1.0353e-16;
|
|
/// H₂⁺ 阈值比率
|
|
const TRHA: f64 = 1.5;
|
|
/// H⁻ 自由-自由常数
|
|
const SFF0: f64 = 1.3727e-25;
|
|
const SFF1: f64 = 4.3748e-10;
|
|
const SFFM2: f64 = -2.5993e-7;
|
|
/// HeI 阈值频率
|
|
const F0HE1: f64 = 3.29e15;
|
|
/// HeII 阈值频率
|
|
const F0HE2: f64 = 1.316e16;
|
|
/// Saha 常数
|
|
const SBH0: f64 = 4.1412e-16;
|
|
const SG01: f64 = 2.815e-16;
|
|
const SG02: f64 = 4.504e-15;
|
|
|
|
/// 普朗克常数 / 玻尔兹曼常数 (erg/K)
|
|
const HK: f64 = 6.626176e-27 / 1.380662e-16;
|
|
|
|
// ============================================================================
|
|
// OPADD 输入参数
|
|
// ============================================================================
|
|
|
|
/// OPADD 输入参数。
|
|
#[derive(Debug, Clone)]
|
|
pub struct OpaddInput {
|
|
/// 计算模式
|
|
/// - -1: 初始化(计算深度相关量)
|
|
/// - 0: 计算不透明度
|
|
/// - 1: 计算不透明度和导数
|
|
pub mode: i32,
|
|
/// 调用标志 (>0 表示需要初始化温度相关量)
|
|
pub icall: i32,
|
|
/// 频率索引 (0-indexed)
|
|
pub ij: usize,
|
|
/// 深度索引 (0-indexed)
|
|
pub id: usize,
|
|
}
|
|
|
|
/// OPADD 开关参数(来自 COMMON/OPCKEY)。
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct OpaddSwitches {
|
|
/// HI Rayleigh 散射开关
|
|
pub irsct: i32,
|
|
/// HeI Rayleigh 散射开关
|
|
pub irsche: i32,
|
|
/// H2 Rayleigh 散射开关
|
|
pub irsch2: i32,
|
|
/// H⁻ 不透明度开关
|
|
pub iophmi: i32,
|
|
/// H₂⁺ 不透明度开关
|
|
pub ioph2p: i32,
|
|
/// He⁻ 不透明度开关
|
|
pub iophem: i32,
|
|
/// H₂⁻ 不透明度开关
|
|
pub ioph2m: i32,
|
|
/// CH 不透明度开关
|
|
pub iopch: i32,
|
|
/// OH 不透明度开关
|
|
pub iopoh: i32,
|
|
/// CIA H2-H2 不透明度开关
|
|
pub ioh2h2: i32,
|
|
/// CIA H2-He 不透明度开关
|
|
pub ioh2he: i32,
|
|
/// CIA H2-H 不透明度开关
|
|
pub ioh2h: i32,
|
|
/// CIA H-He 不透明度开关
|
|
pub iohhe: i32,
|
|
/// 分子开关
|
|
pub ifmol: i32,
|
|
/// 分子温度极限
|
|
pub tmolim: f64,
|
|
}
|
|
|
|
/// OPADD 模型状态(所需变量)。
|
|
#[derive(Debug, Clone)]
|
|
pub struct OpaddModel<'a> {
|
|
/// 温度数组
|
|
pub temp: &'a [f64],
|
|
/// 电子密度数组
|
|
pub elec: &'a [f64],
|
|
/// 频率数组
|
|
pub freq: &'a [f64],
|
|
/// 深度数
|
|
pub nd: usize,
|
|
/// 能级数
|
|
pub nlevel: usize,
|
|
/// H 离子索引
|
|
pub ielh: i32,
|
|
/// He 离子索引
|
|
pub iathe: i32,
|
|
/// H 第一能级索引 (1-indexed in Fortran)
|
|
pub n0hn: i32,
|
|
/// H⁺ 索引
|
|
pub nkh: i32,
|
|
/// He 第一能级索引
|
|
pub n0ahe: i32,
|
|
/// 原子数密度数组 [物种][深度]
|
|
pub anato: &'a [Vec<f64>],
|
|
/// 离子数密度数组 [物种][深度]
|
|
pub anion: &'a [Vec<f64>],
|
|
/// 分子数密度数组 [物种][深度]
|
|
pub anmol: &'a [Vec<f64>],
|
|
/// 占据数数组 [能级][深度]
|
|
pub popul: &'a [Vec<f64>],
|
|
/// 光电离截面表 [跃迁][频率]
|
|
pub cross: &'a [Vec<f64>],
|
|
/// 连续跃迁计数
|
|
pub ncon: usize,
|
|
/// CIA H2-H2 数据
|
|
pub cia_h2h2_data: &'a cia_h2h2::CiaH2h2Data,
|
|
/// CIA H2-He 数据
|
|
pub cia_h2he_data: &'a cia_h2he::CiaH2heData,
|
|
/// CIA H2-H 数据
|
|
pub cia_h2h_data: &'a cia_h2h::CiaH2hData,
|
|
/// CIA H-He 数据
|
|
pub cia_hhe_data: &'a cia_hhe::CiaHheData,
|
|
}
|
|
|
|
/// OPADD 输出结果。
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct OpaddOutput {
|
|
/// 吸收系数
|
|
pub abad: f64,
|
|
/// 发射系数
|
|
pub emad: f64,
|
|
/// 散射系数
|
|
pub scad: f64,
|
|
/// 对温度的吸收导数
|
|
pub dat: f64,
|
|
/// 对电子密度的吸收导数
|
|
pub dan: f64,
|
|
/// 对温度的发射导数
|
|
pub det: f64,
|
|
/// 对电子密度的发射导数
|
|
pub den: f64,
|
|
/// 对温度的散射导数
|
|
pub dst: f64,
|
|
/// 对电子密度的散射导数
|
|
pub dsn: f64,
|
|
/// 对能级占据数的导数
|
|
pub ddn: Vec<f64>,
|
|
}
|
|
|
|
// ============================================================================
|
|
// 缓存状态(对应 Fortran SAVE 变量)
|
|
// ============================================================================
|
|
|
|
/// 缓存的温度相关量。
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct OpaddCache {
|
|
/// 温度
|
|
pub t: f64,
|
|
/// 0.0001 * T
|
|
pub deltat: f64,
|
|
/// 电子密度
|
|
pub ane: f64,
|
|
/// h/kT
|
|
pub hkt: f64,
|
|
/// 1/(T*sqrt(T))
|
|
pub t32: f64,
|
|
/// THM0/T
|
|
pub xhm: f64,
|
|
/// 中性氢占据数
|
|
pub popi: f64,
|
|
/// H⁻ Saha 因子
|
|
pub sb00: f64,
|
|
}
|
|
|
|
// ============================================================================
|
|
// OPADD 主函数
|
|
// ============================================================================
|
|
|
|
/// 计算额外不透明度。
|
|
///
|
|
/// # 参数
|
|
///
|
|
/// * `input` - 输入参数
|
|
/// * `switches` - 开关配置
|
|
/// * `model` - 模型状态
|
|
/// * `cache` - 缓存的温度相关量(可变引用)
|
|
///
|
|
/// # 返回值
|
|
///
|
|
/// 计算结果包含吸收、发射、散射系数及其导数。
|
|
///
|
|
/// # Fortran 原始代码
|
|
///
|
|
/// ```fortran
|
|
/// SUBROUTINE OPADD(MODE,ICALL,IJ,ID)
|
|
/// ```
|
|
pub fn opadd(
|
|
input: &OpaddInput,
|
|
switches: &OpaddSwitches,
|
|
model: &OpaddModel,
|
|
cache: &mut OpaddCache,
|
|
) -> OpaddOutput {
|
|
let mut output = OpaddOutput {
|
|
ddn: vec![0.0; model.nlevel],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut ab0 = 0.0_f64;
|
|
let mut ab1 = 0.0_f64;
|
|
let mut dab1 = 0.0_f64;
|
|
|
|
let fr = model.freq[input.ij];
|
|
let _al = CLS / fr; // 波长 (Å)
|
|
|
|
// 获取 H 和 He 相关变量
|
|
let (n0hn, nkh, n0ahe): (i32, i32, i32) = if model.ielh > 0 {
|
|
(
|
|
model.n0hn,
|
|
model.nkh,
|
|
if model.iathe > 0 { model.n0ahe } else { 0 },
|
|
)
|
|
} else {
|
|
(0, 0, 0)
|
|
};
|
|
|
|
// 初始化温度相关量
|
|
if input.icall > 0 {
|
|
let id = input.id;
|
|
cache.t = model.temp[id];
|
|
cache.deltat = TENM4 * cache.t;
|
|
cache.ane = model.elec[id];
|
|
cache.hkt = HK / cache.t;
|
|
cache.t32 = 1.0 / cache.t / cache.t.sqrt();
|
|
cache.xhm = THM0 / cache.t;
|
|
|
|
// 获取 H 和 H⁺ 数密度
|
|
let (ah, ahp): (f64, f64) = if model.ielh > 0 {
|
|
let ah = model.popul[(n0hn - 1) as usize][id];
|
|
let ahp = model.popul[(nkh - 1) as usize][id];
|
|
(ah, ahp)
|
|
} else {
|
|
(model.anato[0][id], model.anion[0][id])
|
|
};
|
|
cache.popi = ah;
|
|
|
|
// H⁻ Saha 因子
|
|
cache.sb00 = SBHM * cache.t32 * (cache.xhm.exp()) * cache.popi * cache.ane;
|
|
}
|
|
|
|
// 获取 He 数密度
|
|
let ahe: f64 = if model.iathe > 0 {
|
|
model.popul[(n0ahe - 1) as usize][input.id]
|
|
} else {
|
|
model.anato[1][input.id]
|
|
};
|
|
|
|
// 获取 H 数密度(用于散射)
|
|
let ah: f64 = if model.ielh > 0 {
|
|
model.popul[(n0hn - 1) as usize][input.id]
|
|
} else {
|
|
model.anato[0][input.id]
|
|
};
|
|
|
|
let t = cache.t;
|
|
let ane = cache.ane;
|
|
|
|
let mut it = model.ncon as i32;
|
|
|
|
// -----------------------------------------------------------------------
|
|
// HI Rayleigh 散射
|
|
// -----------------------------------------------------------------------
|
|
if switches.irsct != 0 {
|
|
it += 1;
|
|
output.scad = ah * model.cross[it as usize][input.ij];
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// HeI Rayleigh 散射
|
|
// -----------------------------------------------------------------------
|
|
if switches.irsche != 0 && input.mode >= 0 {
|
|
it += 1;
|
|
output.scad += ahe * model.cross[it as usize][input.ij];
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// H2 Rayleigh 散射
|
|
// -----------------------------------------------------------------------
|
|
if switches.irsch2 != 0 && input.mode >= 0 && switches.ifmol > 0 {
|
|
it += 1;
|
|
let sg = model.cross[it as usize][input.ij] * model.anmol[2][input.id];
|
|
if t < switches.tmolim {
|
|
output.scad += sg;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// H⁻ 束缚-自由和自由-自由
|
|
// -----------------------------------------------------------------------
|
|
if switches.iophmi > 0 {
|
|
it += 1;
|
|
if t < 20000.0 {
|
|
let sb = cache.sb00 * model.cross[it as usize][input.ij];
|
|
let sf = sffhmi(ah, fr, t) * ane;
|
|
ab0 = sb + sf;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// H₂⁺ 束缚-自由和自由-自由
|
|
// -----------------------------------------------------------------------
|
|
if switches.ioph2p > 0 {
|
|
it += 1;
|
|
let x2 = -model.cross[it as usize][input.ij] / t + model.cross[it as usize + 1][input.ij];
|
|
it += 1;
|
|
let mut sb = 0.0;
|
|
if x2 > -150.0 && fr < 3.28e15 && t <= 9000.0 {
|
|
let ahp = if model.ielh > 0 {
|
|
model.popul[(nkh - 1) as usize][input.id]
|
|
} else {
|
|
model.anion[0][input.id]
|
|
};
|
|
sb = ah * x2.exp() * ahp;
|
|
}
|
|
ab0 += sb;
|
|
dab1 = sb * model.cross[it as usize - 1][input.ij] / t / t;
|
|
if n0hn > 0 {
|
|
output.ddn[(n0hn - 1) as usize] += sb / cache.popi;
|
|
}
|
|
if nkh > 0 {
|
|
output.ddn[(nkh - 1) as usize] += sb / model.popul[(nkh - 1) as usize][input.id];
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// He⁻ 自由-自由
|
|
// -----------------------------------------------------------------------
|
|
if switches.iophem > 0 {
|
|
it += 1;
|
|
let sg = model.cross[it as usize][input.ij] * t
|
|
+ model.cross[it as usize + 1][input.ij]
|
|
+ model.cross[it as usize + 2][input.ij] / t;
|
|
ab0 += sg * ane * ahe;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// H₂⁻ 自由-自由
|
|
// -----------------------------------------------------------------------
|
|
if switches.ioph2m != 0 && input.mode >= 0 && switches.ifmol > 0 && t < switches.tmolim {
|
|
let oph2 = h2minus(t, model.anmol[2][input.id], ane, fr);
|
|
ab1 += oph2;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// CH 和 OH 连续不透明度
|
|
// -----------------------------------------------------------------------
|
|
if input.mode >= 0 && switches.ifmol > 0 && t < switches.tmolim {
|
|
if switches.iopch > 0 {
|
|
ab0 += sbfch(fr, t) * model.anmol[5][input.id];
|
|
}
|
|
if switches.iopoh > 0 {
|
|
ab0 += sbfoh(fr, t) * model.anmol[4][input.id];
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// CIA H2-H2 不透明度
|
|
// -------------------------------------------------------------------
|
|
if switches.ioh2h2 > 0 {
|
|
let oph2 = cia_h2h2(t, model.anmol[2][input.id], fr, model.cia_h2h2_data);
|
|
ab1 += oph2;
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// CIA H2-He 不透明度
|
|
// -------------------------------------------------------------------
|
|
if switches.ioh2he > 0 {
|
|
let oph2 = cia_h2he(t, model.anmol[2][input.id], ahe, fr, model.cia_h2he_data);
|
|
ab1 += oph2;
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// CIA H2-H 不透明度
|
|
// -------------------------------------------------------------------
|
|
if switches.ioh2h > 0 {
|
|
let oph2 = cia_h2h(t, model.anmol[2][input.id], ah, fr, model.cia_h2h_data);
|
|
ab1 += oph2;
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// CIA H-He 不透明度
|
|
// -------------------------------------------------------------------
|
|
if switches.iohhe > 0 {
|
|
let oph2 = cia_hhe(t, ah, ahe, fr, model.cia_hhe_data);
|
|
ab1 += oph2;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 最终计算吸收和发射系数及其导数
|
|
// -----------------------------------------------------------------------
|
|
if input.mode < 0 {
|
|
return output;
|
|
}
|
|
|
|
let x = (-cache.hkt * fr).exp();
|
|
let x1 = 1.0 - x;
|
|
let fr15 = fr * 1.0e-15;
|
|
let _bnx = 1.0e-22 * fr15 * fr15 * fr15 * x; // BN 常数(未使用)
|
|
|
|
ab1 /= x1;
|
|
output.abad = ab0 + ab1;
|
|
output.emad = ab0 + ab1;
|
|
|
|
if input.mode == 1 {
|
|
let hkft = cache.hkt * fr / t;
|
|
let _db = hkft * ab0; // 未使用
|
|
output.dat = dab1;
|
|
output.det = dab1;
|
|
output.dan = ab0 / ane;
|
|
output.den = ab0 / ane;
|
|
}
|
|
|
|
output
|
|
}
|
|
|
|
// ============================================================================
|
|
// 测试
|
|
// ============================================================================
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use approx::assert_relative_eq;
|
|
use std::sync::LazyLock;
|
|
|
|
/// 测试数据
|
|
static TEST_DATA: LazyLock<TestData> = LazyLock::new(|| {
|
|
TestData {
|
|
temp: vec![10000.0, 8000.0, 6000.0],
|
|
elec: vec![1.0e13, 1.0e12, 1.0e11],
|
|
freq: vec![1.0e15, 2.0e15, 3.0e15],
|
|
anato: vec![
|
|
vec![1.0e14, 1.0e14, 1.0e14], // H
|
|
vec![1.0e13, 1.0e13, 1.0e13], // He
|
|
],
|
|
anion: vec![
|
|
vec![1.0e12, 1.0e12, 1.0e12], // H+
|
|
],
|
|
anmol: vec![
|
|
vec![0.0; 3], // H2
|
|
vec![0.0; 3], // 索引 1
|
|
vec![0.0; 3], // 索引 2 (H2)
|
|
vec![0.0; 3], // OH (索引 3)
|
|
vec![0.0; 3], // 索引 4 (OH)
|
|
vec![0.0; 3], // CH (索引 5)
|
|
vec![0.0; 3], // 额外
|
|
],
|
|
popul: vec![vec![0.0; 3]; 10],
|
|
cross: vec![vec![0.0; 3]; 20],
|
|
cia_h2h2_data: cia_h2h2::CiaH2h2Data::default(),
|
|
cia_h2he_data: cia_h2he::CiaH2heData::default(),
|
|
cia_h2h_data: cia_h2h::CiaH2hData::default(),
|
|
cia_hhe_data: cia_hhe::CiaHheData::default(),
|
|
}
|
|
});
|
|
|
|
struct TestData {
|
|
temp: Vec<f64>,
|
|
elec: Vec<f64>,
|
|
freq: Vec<f64>,
|
|
anato: Vec<Vec<f64>>,
|
|
anion: Vec<Vec<f64>>,
|
|
anmol: Vec<Vec<f64>>,
|
|
popul: Vec<Vec<f64>>,
|
|
cross: Vec<Vec<f64>>,
|
|
cia_h2h2_data: cia_h2h2::CiaH2h2Data,
|
|
cia_h2he_data: cia_h2he::CiaH2heData,
|
|
cia_h2h_data: cia_h2h::CiaH2hData,
|
|
cia_hhe_data: cia_hhe::CiaHheData,
|
|
}
|
|
|
|
/// 创建测试用的模型状态
|
|
fn create_test_model() -> (OpaddModel<'static>, OpaddSwitches) {
|
|
let data = &*TEST_DATA;
|
|
|
|
let model = OpaddModel {
|
|
temp: &data.temp,
|
|
elec: &data.elec,
|
|
freq: &data.freq,
|
|
nd: 3,
|
|
nlevel: 10,
|
|
ielh: 0,
|
|
iathe: 0,
|
|
n0hn: 0,
|
|
nkh: 0,
|
|
n0ahe: 0,
|
|
anato: &data.anato,
|
|
anion: &data.anion,
|
|
anmol: &data.anmol,
|
|
popul: &data.popul,
|
|
cross: &data.cross,
|
|
ncon: 5,
|
|
cia_h2h2_data: &data.cia_h2h2_data,
|
|
cia_h2he_data: &data.cia_h2he_data,
|
|
cia_h2h_data: &data.cia_h2h_data,
|
|
cia_hhe_data: &data.cia_hhe_data,
|
|
};
|
|
|
|
let switches = OpaddSwitches {
|
|
irsct: 0,
|
|
irsche: 0,
|
|
irsch2: 0,
|
|
iophmi: 0,
|
|
ioph2p: 0,
|
|
iophem: 0,
|
|
ioph2m: 0,
|
|
iopch: 0,
|
|
iopoh: 0,
|
|
ioh2h2: 0,
|
|
ioh2he: 0,
|
|
ioh2h: 0,
|
|
iohhe: 0,
|
|
ifmol: 0,
|
|
tmolim: 5000.0,
|
|
};
|
|
|
|
(model, switches)
|
|
}
|
|
|
|
#[test]
|
|
fn test_opadd_basic() {
|
|
let (model, switches) = create_test_model();
|
|
let mut cache = OpaddCache::default();
|
|
|
|
let input = OpaddInput {
|
|
mode: 0,
|
|
icall: 1,
|
|
ij: 0,
|
|
id: 0,
|
|
};
|
|
|
|
let result = opadd(&input, &switches, &model, &mut cache);
|
|
|
|
// 当所有开关关闭时,结果应为 0
|
|
assert_relative_eq!(result.abad, 0.0, epsilon = 1e-20);
|
|
assert_relative_eq!(result.emad, 0.0, epsilon = 1e-20);
|
|
assert_relative_eq!(result.scad, 0.0, epsilon = 1e-20);
|
|
}
|
|
|
|
#[test]
|
|
fn test_opadd_mode_negative() {
|
|
let (model, switches) = create_test_model();
|
|
let mut cache = OpaddCache::default();
|
|
|
|
let input = OpaddInput {
|
|
mode: -1,
|
|
icall: 1,
|
|
ij: 0,
|
|
id: 0,
|
|
};
|
|
|
|
let result = opadd(&input, &switches, &model, &mut cache);
|
|
|
|
// mode < 0 应立即返回
|
|
assert_relative_eq!(result.abad, 0.0, epsilon = 1e-20);
|
|
}
|
|
|
|
#[test]
|
|
fn test_opadd_cache_initialization() {
|
|
let (model, switches) = create_test_model();
|
|
let mut cache = OpaddCache::default();
|
|
|
|
let input = OpaddInput {
|
|
mode: 0,
|
|
icall: 1,
|
|
ij: 0,
|
|
id: 0,
|
|
};
|
|
|
|
let _ = opadd(&input, &switches, &model, &mut cache);
|
|
|
|
// 验证缓存已初始化
|
|
assert_relative_eq!(cache.t, 10000.0, epsilon = 1e-10);
|
|
assert_relative_eq!(cache.ane, 1.0e13, epsilon = 1e-10);
|
|
assert!(cache.hkt > 0.0);
|
|
}
|
|
}
|