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

144 lines
3.8 KiB
Rust

//! 短特征辐射转移求解器
//!
//! 原始 Fortran: rte_sc.f
//! Short Characteristics 方法求解辐射转移方程
/// 短特征辐射转移求解器
///
/// 对已知源函数的辐射转移方程进行形式求解
///
/// # 参数
/// - `dtau`: 光学深度增量 (nd-1 个元素)
/// - `st0`: 总源函数 (nd 个元素)
/// - `rup`: 上边界强度 (id=1)
/// - `rdown`: 下边界强度 (id=nd)
/// - `amu0`: 传播角度余弦 (相对于法线)
/// - amu0 < 0: 入射辐射 (向下)
/// - amu0 >= 0: 出射辐射 (向上)
/// - `ri`: 辐射强度 (输出)
/// - `ali`: Lambda 算子对角元素 (输出)
/// - `nd`: 深度点数
///
/// # 算法
/// 使用短特征 (Short Characteristics) 方法
pub fn rte_sc(
dtau: &[f64],
st0: &[f64],
rup: f64,
rdown: f64,
amu0: f64,
ri: &mut [f64],
ali: &mut [f64],
nd: usize,
) {
// 工作数组
let mut dtx1 = vec![0.0; nd];
let mut dtx2 = vec![0.0; nd];
let mut dtx0 = vec![0.0; nd];
// 常量
let un = 1.0_f64;
// 预计算指数因子
for id in 0..nd - 1 {
dtx1[id] = (-dtau[id]).exp();
dtx2[id] = (un - dtx1[id]) / dtau[id];
dtx0[id] = un - dtx2[id];
}
// 入射强度 (向下传播)
if amu0 < 0.0 {
let id = 0;
ri[id] = rup;
for id in 0..nd - 1 {
ri[id + 1] = ri[id] * dtx1[id]
+ st0[id] * (dtx2[id] - dtx1[id])
+ st0[id + 1] * dtx0[id];
ali[id + 1] = dtx0[id];
}
ali[0] = 0.0;
} else {
// 出射强度 (向上传播)
ri[nd - 1] = rdown;
for id in (0..nd - 1).rev() {
ri[id] = ri[id + 1] * dtx1[id]
+ st0[id] * dtx0[id]
+ st0[id + 1] * (dtx2[id] - dtx1[id]);
ali[id] = dtx0[id];
}
ali[nd - 1] = 0.0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rte_sc_incoming() {
// 测试入射辐射
let nd = 5;
let dtau = vec![0.5; nd - 1];
let st0 = vec![1.0; nd];
let rup = 0.0;
let rdown = 0.0;
let amu0 = -1.0; // 入射
let mut ri = vec![0.0; nd];
let mut ali = vec![0.0; nd];
rte_sc(&dtau, &st0, rup, rdown, amu0, &mut ri, &mut ali, nd);
// 入射边界条件
assert!((ri[0] - 0.0).abs() < 1e-10);
assert!((ali[0] - 0.0).abs() < 1e-10);
// 强度应该随深度增加
assert!(ri[nd - 1] > ri[0]);
}
#[test]
fn test_rte_sc_outgoing() {
// 测试出射辐射
let nd = 5;
let dtau = vec![0.5; nd - 1];
let st0 = vec![1.0; nd];
let rup = 0.0;
let rdown = 0.0;
let amu0 = 1.0; // 出射
let mut ri = vec![0.0; nd];
let mut ali = vec![0.0; nd];
rte_sc(&dtau, &st0, rup, rdown, amu0, &mut ri, &mut ali, nd);
// 出射边界条件
assert!((ri[nd - 1] - 0.0).abs() < 1e-10);
assert!((ali[nd - 1] - 0.0).abs() < 1e-10);
// 强度应该随深度增加
assert!(ri[0] > ri[nd - 1]);
}
#[test]
fn test_rte_sc_consistency() {
// 测试源函数为常数时的渐进行为
let nd = 100;
let dtau = vec![0.1; nd - 1];
let st0 = vec![2.0; nd];
let rup = 0.0;
let rdown = 0.0;
let mut ri_in = vec![0.0; nd];
let mut ali_in = vec![0.0; nd];
let mut ri_out = vec![0.0; nd];
let mut ali_out = vec![0.0; nd];
rte_sc(&dtau, &st0, rup, rdown, -1.0, &mut ri_in, &mut ali_in, nd);
rte_sc(&dtau, &st0, rup, rdown, 1.0, &mut ri_out, &mut ali_out, nd);
// 在深部,入射和出射强度应趋近于源函数
// (对于光学厚介质)
assert!((ri_in[nd - 1] - st0[nd - 1]).abs() < 0.1);
assert!((ri_out[0] - st0[0]).abs() < 0.1);
}
}