SpectraRust/src/synspec/math/voigtk.rs
fmq e2c1a4580a feat: F2R 重构全部完成 + 自动化脚本改进
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>
2026-06-08 14:54:53 +08:00

158 lines
4.2 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.

//! 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);
}
}