Phase 1 翻译 (完成): - TLUSTY 350 函数 100% 翻译 - SYNSPEC 168 函数 100% 翻译 - ~495 Rust 模块 Phase 2 集成 (完成): - TLUSTY RESOLV 7 个 TODO 全部清除 - TLUSTY Runner IJALI 频率选择实现 - OPFRAC ioniz.dat 解析完整实现 - SYNSPEC Runner 编排流程连接完成 - SYNSPEC RESOLV OPAC→RTE→OUTPRI 调用链完整 Phase 3 验证 (完成, 修复 8 处 bug): - INITIA: compute_hydrogen_level_bounds 索引混合修复 - INILIN: GAMR0/GS0/GW0 展宽公式修复, 经典 VdW 公式修复 - INIBL0: CNM 常数 2.997925e18→e17 修复 - OPAC: Lyman IJ=2 修正缺失修复 - RTE: minv3 矩阵求逆符号错误修复 自动化脚本改进: - specf2r.sh: 添加 429 限流退避、完成检测、同步等待 - SKILL.md: 三阶段工作流 + 状态文件系统 - references/: Phase 1/2/3 独立参考文档 新增: - src/bin/synspec.rs: SYNSPEC 可执行文件入口 - .f2r_phase/.f2r_tasks/.f2r_complete: 状态管理文件 编译: 0 错误 | Clippy: 0 错误 | 测试: voigt 28 + eldens 5 通过 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
4.2 KiB
Rust
158 lines
4.2 KiB
Rust
//! Voigt 函数(Kurucz 版本)。
|
||
//!
|
||
//! 重构自 SYNSPEC `voigtk.f`
|
||
//!
|
||
//! 基于 Kurucz (Computational Astrophysics) 的算法。
|
||
|
||
/// Voigt 表格大小
|
||
pub const MVOI: usize = 2001;
|
||
|
||
/// 常量
|
||
const ONE: f64 = 1.0;
|
||
const THREE: f64 = 3.0;
|
||
const TEN: f64 = 10.0;
|
||
const FIFTN: f64 = 15.0;
|
||
const TWOH: f64 = 200.0;
|
||
const C14142: f64 = std::f64::consts::SQRT_2;
|
||
const C11283: f64 = std::f64::consts::FRAC_2_SQRT_PI;
|
||
const C15: f64 = 1.5;
|
||
const C32: f64 = 3.2;
|
||
const C05642: f64 = 0.5642;
|
||
const C79788: f64 = 0.79788;
|
||
const C02: f64 = 0.2;
|
||
const C14: f64 = 1.4;
|
||
const C37613: f64 = 0.37613;
|
||
const C23: f64 = 2.0 / 3.0;
|
||
const CV1: f64 = -0.122727278;
|
||
const CV2: f64 = 0.532770573;
|
||
const CV3: f64 = -0.96284325;
|
||
const CV4: f64 = 0.979895032;
|
||
|
||
/// Voigt 函数(Kurucz 版本)。
|
||
///
|
||
/// # 参数
|
||
///
|
||
/// * `a` - 阻尼参数
|
||
/// * `v` - 频率偏移(Doppler 宽度单位)
|
||
/// * `h0tab` - 预计算表格 H0
|
||
/// * `h1tab` - 预计算表格 H1
|
||
/// * `h2tab` - 预计算表格 H2
|
||
///
|
||
/// # 返回值
|
||
///
|
||
/// Voigt 函数值
|
||
pub fn voigtk(a: f64, v: f64, h0tab: &[f64; MVOI], h1tab: &[f64; MVOI], h2tab: &[f64; MVOI]) -> f64 {
|
||
let iv = (v * TWOH + C15) as usize;
|
||
let iv = iv.min(MVOI - 1); // 防止越界
|
||
|
||
if a < C02 {
|
||
if v <= TEN {
|
||
return (h2tab[iv] * a + h1tab[iv]) * a + h0tab[iv];
|
||
} else {
|
||
return C05642 * a / (v * v);
|
||
}
|
||
}
|
||
|
||
if a > C14 || a + v > C32 {
|
||
// 大 A 或大 V 的情况
|
||
let aa = a * a;
|
||
let vv = v * v;
|
||
let u = (aa + vv) * C14142;
|
||
let uu = u * u;
|
||
return ((((aa - TEN * vv) * aa * THREE + FIFTN * vv * vv) / uu + THREE * vv - aa) / uu
|
||
+ ONE)
|
||
* a
|
||
* C79788
|
||
/ u;
|
||
}
|
||
|
||
// 中等 A 和 V 的情况
|
||
let vv = v * v;
|
||
let hh1 = h1tab[iv] + h0tab[iv] * C11283;
|
||
let hh2 = h2tab[iv] + hh1 * C11283 - h0tab[iv];
|
||
let hh3 = (ONE - h2tab[iv]) * C37613 - hh1 * C23 * vv + hh2 * C11283;
|
||
let hh4 = (THREE * hh3 - hh1) * C37613 + h0tab[iv] * C23 * vv * vv;
|
||
|
||
((((hh4 * a + hh3) * a + hh2) * a + hh1) * a + h0tab[iv])
|
||
* (((CV1 * a + CV2) * a + CV3) * a + CV4)
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
use approx::assert_relative_eq;
|
||
|
||
const FRAC_1_SQRT_PI: f64 = 0.5641895835477563;
|
||
|
||
// 创建简单的测试表格(实际使用时需要预计算)
|
||
fn create_test_tables() -> ([f64; MVOI], [f64; MVOI], [f64; MVOI]) {
|
||
let mut h0 = [0.0; MVOI];
|
||
let mut h1 = [0.0; MVOI];
|
||
let mut h2 = [0.0; MVOI];
|
||
|
||
// 简单初始化:H(0,v) = 1/sqrt(pi) * exp(-v^2)
|
||
for i in 0..MVOI {
|
||
let v = (i as f64 - C15) / TWOH;
|
||
h0[i] = (-v * v).exp() / FRAC_1_SQRT_PI;
|
||
h1[i] = -2.0 * v * h0[i]; // H'(0,v)
|
||
h2[i] = (4.0 * v * v - 2.0) * h0[i]; // H''(0,v)
|
||
}
|
||
|
||
(h0, h1, h2)
|
||
}
|
||
|
||
#[test]
|
||
fn test_voigtk_basic() {
|
||
let (h0, h1, h2) = create_test_tables();
|
||
|
||
// 测试小 A 情况
|
||
let result = voigtk(0.1, 1.0, &h0, &h1, &h2);
|
||
assert!(result.is_finite());
|
||
assert!(result > 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_voigtk_large_v() {
|
||
let (h0, h1, h2) = create_test_tables();
|
||
|
||
// 大 V 情况 (v > 10)
|
||
let result = voigtk(0.1, 15.0, &h0, &h1, &h2);
|
||
assert!(result.is_finite());
|
||
assert!(result > 0.0);
|
||
|
||
// 应该近似 C05642 * a / v^2
|
||
let expected = C05642 * 0.1 / (15.0 * 15.0);
|
||
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
||
}
|
||
|
||
#[test]
|
||
fn test_voigtk_large_a() {
|
||
let (h0, h1, h2) = create_test_tables();
|
||
|
||
// 大 A 情况 (a > 1.4)
|
||
let result = voigtk(2.0, 1.0, &h0, &h1, &h2);
|
||
assert!(result.is_finite());
|
||
assert!(result > 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_voigtk_medium() {
|
||
let (h0, h1, h2) = create_test_tables();
|
||
|
||
// 中等 A 和 V 情况 (0.2 <= a <= 1.4, a+v <= 3.2)
|
||
let result = voigtk(0.5, 1.0, &h0, &h1, &h2);
|
||
assert!(result.is_finite());
|
||
assert!(result > 0.0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_voigtk_zero_v() {
|
||
let (h0, h1, h2) = create_test_tables();
|
||
|
||
// v = 0 的情况
|
||
let result = voigtk(0.5, 0.0, &h0, &h1, &h2);
|
||
assert!(result.is_finite());
|
||
assert!(result > 0.0);
|
||
}
|
||
}
|