SpectraRust/src/tlusty/math/odf/odfhyd.rs
2026-03-25 18:34:41 +08:00

299 lines
8.0 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.

//! 氢线系列的 ODFOpacity Distribution Function计算。
//!
//! 重构自 TLUSTY `odfhyd.f`
//!
//! 计算氢线系列的不透明度分布函数。
use crate::tlusty::math::divstr;
use crate::tlusty::math::indexx;
use crate::tlusty::math::odfhst;
use crate::tlusty::state::constants::{HALF, TWO, UN};
use crate::tlusty::state::model::StrAux;
// 物理常量
/// 玻尔兹曼常数 / 氢质量
const CDOP: f64 = 2.0 * 1.38054e-16 / 1.6726e-24;
/// 光速 (Angstrom/s)
const CA: f64 = 2.997925e18;
/// 转换因子
const CCM: f64 = CA / 1.0e8;
/// 氢的 Rydberg 频率
const FRH: f64 = 3.28805e15;
/// Rydberg 波长 (Angstrom)
const RYDEL: f64 = 911.764;
/// 2/3
const TTW: f64 = 2.0 / 3.0;
/// Stark 加宽常量
const C00: f64 = 1.25e-9;
/// 仪器加宽常量
const CID: f64 = 0.02654;
/// ODFHYD 输入参数
pub struct OdfhydParams {
/// 深度索引 (1-indexed)
pub id: usize,
/// 跃迁索引 (1-indexed)
pub itr: usize,
}
/// ODFHYD 配置参数
pub struct OdfhydConfig {
/// ODF 采样标志 (0: 标准 ODF, >0: 采样 ODF)
pub ispodf: i32,
/// 最大谱线数
pub nlmx: usize,
/// 光速 (Angstrom/s)
pub cas: f64,
/// 湍流速度 (cm/s)
pub vtb: f64,
}
/// ODFHYD 原子数据
pub struct OdfhydAtomicData<'a> {
/// 下能级索引 (ntrans)
pub ilow: &'a [i32],
/// 上能级索引 (ntrans)
pub iup: &'a [i32],
/// 主量子数 (nlevel)
pub nquant: &'a [i32],
/// ODF 的下量子数 (nlevel)
pub nqlodf: &'a [i32],
/// 跃迁起始频率索引 (ntrans)
pub ifr0: &'a [i32],
/// 跃迁结束频率索引 (ntrans)
pub ifr1: &'a [i32],
/// XKIJ 系数 (ntrans × nlmx)
pub xkij: &'a [f64],
/// FIJ 系数 (ntrans × nlmx)
pub fij: &'a [f64],
/// ODF 索引 (ntrans)
pub jndodf: &'a [i32],
}
/// ODFHYD 模型状态
pub struct OdfhydModelState<'a> {
/// 温度 (nd)
pub temp: &'a [f64],
/// 电子密度 (nd)
pub elec: &'a [f64],
/// WNHINT 数组 (nlmx × nd)
pub wnhint: &'a [f64],
/// Stark 展宽参数
pub straux: StrAux,
}
/// ODFHYD ODF 数据
pub struct OdfhydOdfData<'a> {
/// ODF 频率数 (ntrans)
pub nfrodf: &'a [i32],
/// ODF 频率 (mfro × ntrans)
pub fros: &'a [f64],
/// ODF 频率宽度 (mfro × ntrans)
pub wnus: &'a [f64],
/// 谱线轮廓 (nd × nfreq 或其他)
pub prflin: &'a mut [f64],
/// 频率数组 (nfreq)
pub freq: &'a [f64],
/// KFR0 索引 (ntrans)
pub kfr0: &'a [i32],
/// INDEXP 标志 (ntrans)
pub indexp: &'a [i32],
}
/// XI2 函数:计算 1/n^2
fn xi2(n: i32) -> f64 {
1.0 / (n as f64 * n as f64)
}
/// 计算氢线系列的 ODF。
///
/// # 参数
///
/// * `params` - 输入参数id, itr
/// * `config` - 配置参数
/// * `atomic` - 原子数据
/// * `model` - 模型状态
/// * `odf_data` - ODF 数据
///
/// # 返回值
///
/// 更新后的 PRFLIN 数组
pub fn odfhyd(
params: &OdfhydParams,
config: &OdfhydConfig,
atomic: &OdfhydAtomicData,
model: &mut OdfhydModelState,
odf_data: &mut OdfhydOdfData,
) {
let id = params.id;
let id_idx = id - 1;
let itr = params.itr;
let itr_idx = itr - 1;
let jo = atomic.jndodf[itr_idx] as usize - 1;
let ispodf = config.ispodf;
// 确定频率点数和初始化数组
let nf = if ispodf == 0 {
odf_data.nfrodf[jo] as usize
} else {
(atomic.ifr1[itr_idx] - atomic.ifr0[itr_idx] + 1) as usize
};
let mut sig = vec![0.0; nf];
let mut sgt = vec![0.0; nf];
let mut odf = vec![0.0; nf];
let mut iodf = vec![0; nf];
let mut ynus = vec![0.0; nf];
let mut alam = vec![0.0; nf];
// 初始化频率和波长
if ispodf == 0 {
for ij in 0..nf {
iodf[ij] = 0;
sig[ij] = 0.0;
odf[ij] = 0.0;
ynus[ij] = odf_data.fros[ij + jo * 1000]; // 假设 MFRO = 1000
alam[ij] = config.cas / ynus[ij];
}
} else {
let ifr0 = atomic.ifr0[itr_idx] as usize - 1;
for ij in 0..nf {
sig[ij] = 0.0;
ynus[ij] = odf_data.freq[ifr0 + ij];
alam[ij] = config.cas / ynus[ij];
}
}
// 获取能级索引
let ii = atomic.ilow[itr_idx] as usize - 1;
let jj = atomic.iup[itr_idx] as usize - 1;
// 计算电子密度因子
let anes = (TTW * model.elec[id_idx].ln()).exp();
let f00 = C00 * anes;
// 计算跃迁频率
let nquant_ii = atomic.nquant[ii];
let nquant_jj = atomic.nquant[jj];
let fra = FRH * (xi2(nquant_ii) - xi2(nquant_jj));
// 计算 Doppler 宽度
let dopo = fra / CCM * (CDOP * model.temp[id_idx] + config.vtb * config.vtb).sqrt();
// 遍历谱线系列
let nqlodf_ii = atomic.nqlodf[ii] as usize;
for j in nqlodf_ii..=config.nlmx {
let wl = RYDEL / (xi2(nquant_ii) - xi2(j as i32));
let fxk = f00 * atomic.xkij[jo * config.nlmx + j];
let dbeta = wl * wl / CA / fxk;
let betad = dbeta * dopo;
let fid = CID * atomic.fij[jo * config.nlmx + j] * dbeta;
// 调用 DIVSTR
let (adh, divh) = divstr(betad, 1);
// 获取 Stark 宽度
let wprob = model.wnhint[j * id + id_idx];
// 更新 straux 中的参数
model.straux.betad = betad;
model.straux.adh = adh;
model.straux.divh = divh;
// 调用 ODFHST
odfhst(nf, fxk, fid, wprob, wl, &alam, &model.straux, &mut sgt);
// 累加截面
for ij in 0..nf {
sig[ij] += sgt[ij];
}
}
// 后处理(仅对标准 ODF
if ispodf == 0 {
// 排序
iodf = indexx(&sig);
// 重新排列 ODF
for ij in 0..nf {
odf[ij] = sig[iodf[ij]];
}
// 计算频率网格
let i0 = atomic.ifr0[itr_idx] as usize;
let i1 = atomic.ifr1[itr_idx] as usize;
if odf_data.indexp[itr_idx].abs() == 2 {
ynus[0] = odf_data.freq[i0 - 1];
}
let mut iw1 = iodf[0];
for ij in 1..nf {
let iw2 = iodf[ij];
if ij > 1 && ij < nf - 1 {
ynus[ij] = ynus[ij - 1]
- HALF * (odf_data.wnus[iw1 + jo * 1000] + odf_data.wnus[iw2 + jo * 1000]);
} else if ij == 1 {
ynus[ij] = ynus[ij - 1]
- HALF * (TWO * odf_data.wnus[iw1 + jo * 1000] + odf_data.wnus[iw2 + jo * 1000]);
} else if ij == nf - 1 {
ynus[ij] = ynus[ij - 1]
- HALF * (odf_data.wnus[iw1 + jo * 1000] + TWO * odf_data.wnus[iw2 + jo * 1000]);
}
iw1 = iw2;
}
// 插值到频率网格
odf_data.prflin[id_idx * 100000 + i1 - 1] = 1e-35;
for ij0 in i0..i1 {
let mut ji = 1;
for ij in 1..nf {
ji = ij;
if ynus[ij] <= odf_data.freq[ij0 - 1] {
break;
}
}
let prfln = if ji > 0 && ji < nf {
odf[ji - 1]
+ (odf[ji] - odf[ji - 1]) * (odf_data.freq[ij0 - 1] - ynus[ji - 1])
/ (ynus[ji] - ynus[ji - 1])
} else {
0.0
};
odf_data.prflin[id_idx * 100000 + ij0 - 1] = prfln;
}
} else {
// 采样 ODF 情况
let kfr0 = odf_data.kfr0[itr_idx] as usize;
for ij in 0..nf {
odf_data.prflin[id_idx * 100000 + kfr0 + ij - 1] = sig[ij];
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xi2() {
assert!((xi2(1) - 1.0).abs() < 1e-15);
assert!((xi2(2) - 0.25).abs() < 1e-15);
assert!((xi2(3) - 1.0 / 9.0).abs() < 1e-15);
}
#[test]
fn test_odfhyd_constants() {
// CDOP = 2 * BOLK / HMASS = 2 * 1.38054e-16 / 1.6726e-24 ≈ 1.65e8
// 注意Fortran 中的 BOLK 可能是 1.38054e-16HMASS 是 1.6726e-24
// CDOP ≈ 1.65e8 cm/s/K^0.5
assert!(CDOP > 1e7 && CDOP < 1e9);
assert!((CA - 2.997925e18).abs() < 1e13);
assert!((FRH - 3.28805e15).abs() < 1e10);
}
}