144 lines
3.8 KiB
Rust
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);
|
|
}
|
|
}
|