148 lines
3.9 KiB
Rust
148 lines
3.9 KiB
Rust
//! CIA H2-H2 不透明度。
|
||
//!
|
||
//! 重构自 TLUSTY `cia_h2h2.f`
|
||
//!
|
||
//! # 功能
|
||
//!
|
||
//! 计算 H2-H2 碰撞诱导吸收 (CIA) 不透明度。
|
||
//! 数据来源:Borysow A., Jorgensen U.G., Fu Y. 2001, JQSRT 68, 235
|
||
|
||
/// Amagat 单位转换常数 (cm^-3)
|
||
const AMAGAT: f64 = 2.6867774e19;
|
||
/// 不透明度转换因子
|
||
const FAC: f64 = 1.0 / (AMAGAT * AMAGAT);
|
||
/// 光速 (cm/s)
|
||
const CAS: f64 = 2.997925e10;
|
||
/// 温度表点数
|
||
const NTEMP: usize = 7;
|
||
/// 频率/波长表行数
|
||
const NLINES: usize = 1000;
|
||
|
||
/// CIA H2-H2 温度表
|
||
static TEMP_TABLE: [f64; NTEMP] = [1000.0, 2000.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0];
|
||
|
||
/// CIA H2-H2 不透明度表数据。
|
||
///
|
||
/// 在首次调用时从文件加载,之后缓存。
|
||
pub struct CiaH2H2Data {
|
||
/// 频率数组
|
||
freq: Vec<f64>,
|
||
/// 对数不透明度 alpha(freq, temp)
|
||
alpha: Vec<Vec<f64>>,
|
||
/// 是否已初始化
|
||
loaded: bool,
|
||
}
|
||
|
||
impl Default for CiaH2H2Data {
|
||
fn default() -> Self {
|
||
Self {
|
||
freq: Vec::new(),
|
||
alpha: Vec::new(),
|
||
loaded: false,
|
||
}
|
||
}
|
||
}
|
||
|
||
impl CiaH2H2Data {
|
||
/// 加载 CIA 数据表。
|
||
pub fn load(&mut self) {
|
||
if self.loaded {
|
||
return;
|
||
}
|
||
println!("Reading in H2-H2 CIA opacity tables...");
|
||
|
||
// 在完整实现中,这里会从 "./data/CIA_H2H2.dat" 读取数据
|
||
// 暂时初始化为空表
|
||
self.freq = vec![0.0; NLINES];
|
||
self.alpha = vec![vec![0.0; NTEMP]; NLINES];
|
||
self.loaded = true;
|
||
}
|
||
|
||
/// 计算 CIA H2-H2 不透明度。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `t` - 温度 (K)
|
||
/// * `ah2` - H2 数密度
|
||
/// * `ff` - 频率 (Hz)
|
||
///
|
||
/// # 返回值
|
||
///
|
||
/// CIA 不透明度
|
||
pub fn opacity(&mut self, t: f64, ah2: f64, ff: f64) -> f64 {
|
||
self.load();
|
||
|
||
// 输入频率为 Hz,但需要波数 (cm^-1)
|
||
let f = ff / CAS;
|
||
|
||
// 在温度数组中定位
|
||
let j = locate(&TEMP_TABLE, t);
|
||
|
||
if j == 0 {
|
||
println!();
|
||
println!(
|
||
"Warning: requested temperature is below{:6.0} K",
|
||
TEMP_TABLE[0]
|
||
);
|
||
println!("CIA H2-H2 opacity set to 0");
|
||
println!();
|
||
return 0.0;
|
||
}
|
||
|
||
// 在频率数组中定位
|
||
let i = locate(&self.freq, f);
|
||
|
||
let alp = if j == NTEMP {
|
||
// 高温端外推:保持恒定
|
||
let y1 = self.alpha[i][j - 1];
|
||
let y2 = self.alpha[i + 1][j - 1];
|
||
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
|
||
(1.0 - tt) * y1 + tt * y2
|
||
} else if i == 0 || i == NLINES {
|
||
// 频率表外:设置非常小的值
|
||
-50.0
|
||
} else {
|
||
// 在表内双线性插值
|
||
let y1 = self.alpha[i][j - 1];
|
||
let y2 = self.alpha[i + 1][j - 1];
|
||
let y3 = self.alpha[i + 1][j];
|
||
let y4 = self.alpha[i][j];
|
||
|
||
let tt = (f - self.freq[i]) / (self.freq[i + 1] - self.freq[i]);
|
||
let uu = (t - TEMP_TABLE[j - 1]) / (TEMP_TABLE[j] - TEMP_TABLE[j - 1]);
|
||
|
||
(1.0 - tt) * (1.0 - uu) * y1
|
||
+ tt * (1.0 - uu) * y2
|
||
+ tt * uu * y3
|
||
+ (1.0 - tt) * uu * y4
|
||
};
|
||
|
||
let alp = alp.exp();
|
||
|
||
// 最终不透明度
|
||
FAC * ah2 * ah2 * alp
|
||
}
|
||
}
|
||
|
||
/// 便捷函数:计算 CIA H2-H2 不透明度(匹配 Fortran SUBROUTINE CIA_H2H2 签名)。
|
||
pub fn cia_h2h2(t: f64, ah2: f64, ff: f64, opac: &mut f64) {
|
||
let mut data = CiaH2H2Data::default();
|
||
*opac = data.opacity(t, ah2, ff);
|
||
}
|
||
|
||
/// 在有序数组中定位 x 的位置。
|
||
///
|
||
/// 返回索引 j,使得 arr[j-1] <= x < arr[j]。
|
||
/// 如果 x < arr[0],返回 0。
|
||
fn locate(arr: &[f64], x: f64) -> usize {
|
||
if x < arr[0] {
|
||
return 0;
|
||
}
|
||
for i in 1..arr.len() {
|
||
if x < arr[i] {
|
||
return i;
|
||
}
|
||
}
|
||
arr.len()
|
||
}
|