SpectraRust/src/synspec/math/hidalg.rs
fmq 0f97c0b05b feat: 添加 TLUSTY 新模块 + 修复编译错误
新增 TLUSTY 模块:
- crossd: 光电离截面评估 (bound-free cross section)
- sgmer0: 合并能级光电离截面初始化
- sgmerd: 合并能级光电离截面计算
- dwnfr0: 频率网格下载 (continuum)
- convc1: 对流收敛控制 (radiative)
- chckse: 统计平衡检查 (rates)

扩展 RESOLV 编排器:
- 添加 Feautrier 形式解
- 添加 Lucy 温度修正
- 添加 ROSSTD/PZEVAL/CONOUT 调用
- 添加 IFPOPR=2 占据数更新
- 添加 HESOL6 流体静力平衡修正

修复:
- sgmer0.rs: 修复 config 未声明为 mut 的编译错误
- crossd.rs: 修复测试中使用错误字段路径的问题
  (frqall.ijbf/phoexp.aijbf/phoexp.bfcs 而非 obfpar)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:35:09 +08:00

164 lines
4.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 光致电离截面插值Hidalgo 1968
//!
//! 重构自 SYNSPEC `hidalg.f`
//!
//! 使用 Hidalgo (1968, Ap. J., 153, 981) 的波长和光致电离截面数据表,
//! 对给定频率进行线性插值。
/// 波长网格 1 (Å),用于 INDEX < 13 的物种
const WL1: [f64; 20] = [
39.1, 80.9, 97.6, 100.1, 104.3, 107.2, 108.7, 111.9, 113.6, 115.4,
117.1, 119.0, 124.8, 126.9, 129.1, 131.3, 133.6, 136.0, 138.5, 141.1,
];
/// 波长网格 2 (Å),用于 INDEX >= 13 的物种
const WL2: [f64; 20] = [
68.5, 80.9, 100.1, 120.9, 158.8, 165.7, 177.3, 190.6, 200.7, 206.2,
211.9, 218.0, 224.5, 231.3, 246.3, 0.0, 0.0, 0.0, 0.0, 0.0,
];
/// 光致电离截面数据 (Mbarn)20×24 矩阵(列优先存储)
const SIG0: [[f64; 20]; 24] = [
[0.0; 20], // col 1
[
0.0460, 0.2400, 0.3500, 0.3700, 0.4000, 0.4300, 0.4400, 0.4600, 0.4700, 0.4900,
0.5000, 0.5200, 0.5700, 0.6200, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
], // col 2
[0.0; 20], // col 3
[
0.0092, 0.1000, 0.1900, 0.2100, 0.2300, 0.2500, 0.2600, 0.2900, 0.3000, 0.3200,
0.3400, 0.3500, 0.4100, 0.4300, 0.4500, 0.4800, 0.5000, 0.5300, 0.5600, 0.5900,
], // col 4
[
0.3400, 0.4600, 0.6300, 0.7700, 0.9100, 1.080, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
], // col 5
[0.0; 20], // col 6
[
0.0064, 0.1100, 0.2200, 0.4100, 0.9400, 1.000, 1.300, 1.600, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
], // col 7
[0.0; 20], // col 8
[
0.0370, 0.0650, 0.1300, 0.2400, 0.5500, 0.6300, 0.7700, 0.9500, 1.100, 1.250,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
], // col 9
[0.0; 20], // col 10
[
0.0220, 0.0390, 0.0800, 0.1500, 0.3500, 0.4000, 0.4900, 0.6200, 0.7200, 0.7800,
0.8500, 0.9300, 1.020, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
], // col 11
[0.0; 20], // col 12
[0.0; 20], // col 13
[0.0; 20], // col 14
[0.0; 20], // col 15
[0.0; 20], // col 16
[0.0; 20], // col 17
[0.0; 20], // col 18
[0.0; 20], // col 19
[0.0; 20], // col 20
[0.0; 20], // col 21
[0.0; 20], // col 22
[0.0; 20], // col 23
[0.0; 20], // col 24
];
/// 光速 (cm/s)
const C_LIGHT: f64 = 2.997925e18;
/// 截面单位转换因子 (cm^2)
const SIG_FACTOR: f64 = 1.0e-18;
/// Hidalgo (1968) 光致电离截面插值。
///
/// 根据 Hidalgo 数据表,对给定频率进行线性插值。
///
/// # 参数
///
/// * `ib` - 物种标识(负值,`INDEX = -IB - 100`
/// * `fr` - 频率 (Hz)
///
/// # 返回值
///
/// 光致电离截面 (cm^2)
pub fn hidalg(ib: i32, fr: f64) -> f64 {
let index = (-ib - 101) as usize; // 转为 0-indexed
if index >= 24 {
return 0.0;
}
// 根据 INDEX 选择波长网格和数据
let num = if index < 12 { 20 } else { 15 };
let wli = if index < 12 { &WL1 } else { &WL2 };
let sigs = &SIG0[index];
// 将频率转换为波长 (Å)
let wlam = C_LIGHT / fr;
// 查找插值区间
let mut il = 0;
let mut ir = num - 1;
for i in 0..num - 1 {
if wlam >= wli[i] && wlam <= wli[i + 1] {
il = i;
ir = i + 1;
break;
}
}
// 线性插值
let mut sigm = if wli[ir] - wli[il] > 0.0 {
(sigs[ir] - sigs[il]) * (wlam - wli[il]) / (wli[ir] - wli[il]) + sigs[il]
} else {
sigs[il]
};
// 边界处理
if wlam <= wli[0] {
sigm = sigs[0];
}
if wlam >= wli[num - 1] {
sigm = sigs[num - 1];
}
sigm * SIG_FACTOR
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hidalg_in_range() {
// 测试 H I (IB=-101, INDEX=0) 在有效波长范围内
// 100 Å 对应频率
let fr = C_LIGHT / 100.0;
let result = hidalg(-101, fr);
// H I 数据全为 0所以结果应为 0
assert!(result >= 0.0);
}
#[test]
fn test_hidalg_species_2() {
// 测试物种 2 (IB=-102, INDEX=1)
let fr = C_LIGHT / 50.0; // 50 Å
let result = hidalg(-102, fr);
assert!(result >= 0.0);
assert!(result.is_finite());
}
#[test]
fn test_hidalg_invalid_index() {
let result = hidalg(-125, C_LIGHT / 100.0);
assert_eq!(result, 0.0);
}
#[test]
fn test_hidalg_above_range() {
// 高于波长范围时返回末值
let fr = C_LIGHT / 200.0;
let result = hidalg(-102, fr);
assert!(result >= 0.0);
}
}