SpectraRust/src/math/tdpini.rs
2026-03-21 09:12:18 +08:00

180 lines
4.9 KiB
Rust

//! 温度依赖量初始化。
//!
//! 重构自 TLUSTY `tdpini.f`
use crate::state::config::BasNum;
use crate::state::constants::{HALF, H, HK, MDEPTH, UN};
use crate::state::model::{CurOpa, GffPar, ModPar};
use super::gfree0;
// ============================================================================
// TDPINI - 温度依赖量初始化
// ============================================================================
/// 初始化仅依赖温度的量。
///
/// # 参数
///
/// - `basnum` - 基本数值
/// - `modpar` - 模型参数 (会被修改)
/// - `gffpar` - Gaunt 因子参数 (会被修改)
/// - `curopa` - 当前不透明度 (会被修改)
///
/// # Fortran 原始代码
///
/// ```fortran
/// SUBROUTINE TDPINI
/// DO ID=1,ND
/// T=TEMP(ID)
/// T1=UN/T
/// HKT1(ID)=HK*T1
/// HKT21(ID)=HKT1(ID)*T1
/// TK1(ID)=HKT1(ID)/H
/// SQT1(ID)=SQRT(T)
/// TEMP1(ID)=T1
/// CALL GFREE0(ID)
/// EMEL1(ID)=UN
/// END DO
/// DO ID=1,ND-1
/// DELDM(ID)=HALF*(DM(ID+1)-DM(ID))
/// deldmz(id)=deldm(id)
/// if(izscal.eq.1) deldmz(id)=half*(zd(id)-zd(id+1))
/// END DO
/// DEDM1=DM(1)/DENS(1)
/// END
/// ```
pub fn tdpini(
basnum: &BasNum,
modpar: &mut ModPar,
gffpar: &mut GffPar,
curopa: &mut CurOpa,
) {
let nd = basnum.nd as usize;
let izscal = basnum.izscal;
// 温度依赖量
for id in 0..nd {
let t = modpar.temp[id];
let t1 = UN / t;
modpar.hkt1[id] = HK * t1;
modpar.hkt21[id] = modpar.hkt1[id] * t1;
modpar.tk1[id] = modpar.hkt1[id] / H;
modpar.sqt1[id] = t.sqrt();
modpar.temp1[id] = t1;
// Gaunt 因子初始化
gfree0(id, &modpar.temp, gffpar);
// 电子发射系数初始化
curopa.emel1[id] = UN;
}
// 深度差分 (用于光学深度评估)
for id in 0..(nd - 1) {
modpar.deldm[id] = HALF * (modpar.dm[id + 1] - modpar.dm[id]);
modpar.deldmz[id] = modpar.deldm[id];
// 如果使用几何深度缩放
if izscal == 1 {
modpar.deldmz[id] = HALF * (modpar.zd[id] - modpar.zd[id + 1]);
}
}
// 第一个深度的密度/质量比
modpar.dedm1 = modpar.dm[0] / modpar.dens[0];
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_data() -> (BasNum, ModPar, GffPar, CurOpa) {
let mut basnum = BasNum::default();
basnum.nd = 5;
basnum.izscal = 0;
let mut modpar = ModPar::default();
// 设置温度和密度
for id in 0..5 {
modpar.temp[id] = 10000.0 + id as f64 * 1000.0;
modpar.dm[id] = (id + 1) as f64 * 0.1;
modpar.dens[id] = 1e-7;
}
let gffpar = GffPar::new();
let curopa = CurOpa::default();
(basnum, modpar, gffpar, curopa)
}
#[test]
fn test_tdpini_basic() {
let (basnum, mut modpar, mut gffpar, mut curopa) = create_test_data();
tdpini(&basnum, &mut modpar, &mut gffpar, &mut curopa);
// 检查温度相关量
let t0 = 10000.0;
let t1 = UN / t0;
assert!((modpar.hkt1[0] - HK * t1).abs() < 1e-10);
assert!((modpar.sqt1[0] - t0.sqrt()).abs() < 1e-10);
assert!((modpar.temp1[0] - t1).abs() < 1e-10);
}
#[test]
fn test_tdpini_delta_m() {
let (basnum, mut modpar, mut gffpar, mut curopa) = create_test_data();
tdpini(&basnum, &mut modpar, &mut gffpar, &mut curopa);
// 检查深度差分
// DELDM[0] = 0.5 * (DM[1] - DM[0]) = 0.5 * (0.2 - 0.1) = 0.05
assert!((modpar.deldm[0] - 0.05).abs() < 1e-10);
assert!((modpar.deldmz[0] - 0.05).abs() < 1e-10); // izscal = 0
}
#[test]
fn test_tdpini_emel1() {
let (basnum, mut modpar, mut gffpar, mut curopa) = create_test_data();
tdpini(&basnum, &mut modpar, &mut gffpar, &mut curopa);
// 检查 EMEL1 被初始化为 1
for id in 0..basnum.nd as usize {
assert!((curopa.emel1[id] - UN).abs() < 1e-10);
}
}
#[test]
fn test_tdpini_dedm1() {
let (basnum, mut modpar, mut gffpar, mut curopa) = create_test_data();
tdpini(&basnum, &mut modpar, &mut gffpar, &mut curopa);
// DEDM1 = DM[0] / DENS[0] = 0.1 / 1e-7 = 1e6
let expected = 0.1 / 1e-7;
assert!((modpar.dedm1 - expected).abs() < 1e-5);
}
#[test]
fn test_tdpini_with_zscal() {
let (mut basnum, mut modpar, mut gffpar, mut curopa) = create_test_data();
basnum.izscal = 1;
// 设置几何深度
for id in 0..5 {
modpar.zd[id] = (5 - id) as f64 * 1e5; // 从表面向内递减
}
tdpini(&basnum, &mut modpar, &mut gffpar, &mut curopa);
// 检查使用几何深度计算的 DELDMZ
// DELDMZ[0] = 0.5 * (ZD[0] - ZD[1]) = 0.5 * (5e5 - 4e5) = 5e4
let expected_z = 0.5 * (5e5 - 4e5);
assert!((modpar.deldmz[0] - expected_z).abs() < 1e-5);
}
}