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 crate::tlusty::math::{cia_h2h, cia_h2h2, cia_h2he, cia_hhe, h2minus, sbfch, sbfoh, CiaH2h2Data, CiaH2heData, CiaH2hData, CiaHheData};
|
||
use crate::tlusty::math::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 CiaH2h2Data,
|
||
/// CIA H2-He 数据
|
||
pub cia_h2he_data: &'a CiaH2heData,
|
||
/// CIA H2-H 数据
|
||
pub cia_h2h_data: &'a CiaH2hData,
|
||
/// CIA H-He 数据
|
||
pub cia_hhe_data: &'a 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);
|
||
}
|
||
}
|