SpectraRust/src/tlusty/math/dmder.rs
2026-03-25 13:31:23 +08:00

135 lines
3.4 KiB
Rust

//! 深度导数计算。
//!
//! 重构自 TLUSTY `dmder.f`
use crate::tlusty::state::constants::{MDEPTH, UN};
/// 深度导数参数。
///
/// 对应 Fortran COMMON/DEPTDR/
#[derive(Debug, Clone)]
pub struct DepthDeriv {
/// DM(ID) - DM(ID-1)
pub ddm: Vec<f64>,
/// DM(ID+1) - DM(ID)
pub ddp: Vec<f64>,
/// DM(ID+1) - DM(ID-1)
pub dd0: Vec<f64>,
/// DDP / DD0
pub ddmin: Vec<f64>,
/// DDM / DD0
pub ddplu: Vec<f64>,
/// DDMIN / DDM
pub dda: Vec<f64>,
/// DDA - DDC
pub ddb: Vec<f64>,
/// DDPLU / DDP
pub ddc: Vec<f64>,
}
impl Default for DepthDeriv {
fn default() -> Self {
Self {
ddm: vec![0.0; MDEPTH],
ddp: vec![0.0; MDEPTH],
dd0: vec![0.0; MDEPTH],
ddmin: vec![0.0; MDEPTH],
ddplu: vec![0.0; MDEPTH],
dda: vec![0.0; MDEPTH],
ddb: vec![0.0; MDEPTH],
ddc: vec![0.0; MDEPTH],
}
}
}
/// 计算深度相关的导数。
///
/// # 参数
///
/// * `dm` - 深度质量数组 (1-indexed in Fortran, 0-indexed here)
/// * `nd` - 深度点数
///
/// # 返回值
///
/// 深度导数结构体
pub fn dmder(dm: &[f64], nd: usize) -> DepthDeriv {
let mut deriv = DepthDeriv::default();
// 内部点 (ID = 2 to ND-1, Fortran 1-indexed)
// Rust 0-indexed: id = 1 to nd-2
for id in 1..nd - 1 {
deriv.ddm[id] = dm[id] - dm[id - 1];
deriv.ddp[id] = dm[id + 1] - dm[id];
deriv.dd0[id] = dm[id + 1] - dm[id - 1];
deriv.ddmin[id] = deriv.ddp[id] / deriv.dd0[id];
deriv.ddplu[id] = deriv.ddm[id] / deriv.dd0[id];
deriv.dda[id] = deriv.ddmin[id] / deriv.ddm[id];
deriv.ddc[id] = deriv.ddplu[id] / deriv.ddp[id];
}
// 边界条件
// ID = 1 (Fortran) -> id = 0 (Rust)
deriv.ddm[0] = 0.0;
deriv.ddp[0] = dm[1] - dm[0];
deriv.ddmin[0] = 0.0;
deriv.ddplu[0] = 1.0;
deriv.dda[0] = 0.0;
deriv.ddc[0] = UN / deriv.ddp[0];
// ID = ND (Fortran) -> id = nd-1 (Rust)
let id_last = nd - 1;
deriv.ddm[id_last] = dm[id_last] - dm[id_last - 1];
deriv.ddp[id_last] = 0.0;
deriv.ddmin[id_last] = 1.0;
deriv.ddplu[id_last] = 0.0;
deriv.dda[id_last] = UN / deriv.ddm[id_last];
deriv.ddc[id_last] = 0.0;
// DDB = DDA - DDC
for id in 0..nd {
deriv.ddb[id] = deriv.dda[id] - deriv.ddc[id];
}
deriv
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dmder_uniform() {
// 均匀网格
let dm: Vec<f64> = (0..10).map(|i| i as f64).collect();
let deriv = dmder(&dm, 10);
// 检查内部点
assert!((deriv.ddm[5] - 1.0).abs() < 1e-10);
assert!((deriv.ddp[5] - 1.0).abs() < 1e-10);
assert!((deriv.dd0[5] - 2.0).abs() < 1e-10);
}
#[test]
fn test_dmder_boundary() {
let dm: Vec<f64> = (0..5).map(|i| i as f64 * 2.0).collect();
let deriv = dmder(&dm, 5);
// 边界条件
assert!((deriv.ddm[0] - 0.0).abs() < 1e-10);
assert!((deriv.ddp[0] - 2.0).abs() < 1e-10);
assert!((deriv.ddmin[0] - 0.0).abs() < 1e-10);
assert!((deriv.ddplu[0] - 1.0).abs() < 1e-10);
}
#[test]
fn test_dmder_consistency() {
let dm: Vec<f64> = vec![0.0, 1.0, 3.0, 6.0, 10.0];
let deriv = dmder(&dm, 5);
// 检查 DDB = DDA - DDC
for id in 0..5 {
assert!((deriv.ddb[id] - (deriv.dda[id] - deriv.ddc[id])).abs() < 1e-10);
}
}
}