467 lines
14 KiB
Rust
467 lines
14 KiB
Rust
//! 频率相关辐射转移方程求解 - RTEDF1。
|
||
//!
|
||
//! 重构自 TLUSTY `rtedf1.f`
|
||
//!
|
||
//! 使用不连续有限元 (DFE) 方法求解单频率辐射转移方程。
|
||
//! 计算辐射场、可变 Eddington 因子以及近似 Lambda 算子。
|
||
|
||
use crate::state::constants::{BN, HALF, HK, MDEPTH, TWO, UN};
|
||
|
||
/// RTEDF1 输入参数
|
||
pub struct Rtedf1Params {
|
||
/// 频率索引 (0-indexed for Rust, 1-indexed for logic)
|
||
pub ij: usize,
|
||
/// 深度点数
|
||
pub nd: usize,
|
||
/// 角度点数
|
||
pub nmu: usize,
|
||
/// 盘模型标志
|
||
pub idisk: i32,
|
||
/// 边界条件类型
|
||
pub ibc: i32,
|
||
/// 插值模式
|
||
pub isplin: i32,
|
||
/// ALI 变体类型
|
||
pub jali: i32,
|
||
/// IFALI 参数
|
||
pub ifali: i32,
|
||
/// ILMCOR 参数
|
||
pub ilmcor: i32,
|
||
/// ILASCT 参数
|
||
pub ilasct: i32,
|
||
/// 相对变化阈值
|
||
pub djmax: f64,
|
||
/// 最大 ALI 迭代次数
|
||
pub ntrali: i32,
|
||
/// 风遮挡标志
|
||
pub iwinbl: i32,
|
||
}
|
||
|
||
/// RTEDF1 模型状态
|
||
pub struct Rtedf1ModelState<'a> {
|
||
pub amu: &'a [f64],
|
||
pub wtmu: &'a [f64],
|
||
pub freq: &'a [f64],
|
||
pub deldmz: &'a [f64],
|
||
pub absot: &'a [f64],
|
||
pub emis1: &'a [f64],
|
||
pub abso1: &'a [f64],
|
||
pub scat1: &'a [f64],
|
||
pub temp: &'a [f64],
|
||
pub dedm1: f64,
|
||
pub rrdil: f64,
|
||
pub tempbd: f64,
|
||
pub extint: &'a [Vec<f64>], // [freq][mu]
|
||
pub hextrd: &'a [f64],
|
||
pub rad: &'a mut [Vec<f64>], // [freq][depth]
|
||
pub fak: &'a mut [Vec<f64>], // [freq][depth]
|
||
pub flux: &'a mut [f64], // [freq]
|
||
pub fh: &'a mut [f64], // [freq]
|
||
pub fhd: &'a mut [f64], // [freq]
|
||
pub radex: &'a mut [Vec<f64>], // [ijex][depth]
|
||
pub fakex: &'a mut [Vec<f64>], // [ijex][depth]
|
||
pub q0: &'a mut [f64], // [ijex]
|
||
pub uu0: &'a mut [f64], // [ijex]
|
||
pub ijex: &'a [i32], // [freq]
|
||
}
|
||
|
||
/// RTEDF1 ALI 状态
|
||
pub struct Rtedf1AliState<'a> {
|
||
pub ali1: &'a mut [f64],
|
||
pub alim1: &'a mut [f64],
|
||
pub alip1: &'a mut [f64],
|
||
}
|
||
|
||
/// 求解单频率辐射转移方程。
|
||
pub fn rtedf1(params: &Rtedf1Params, model: &mut Rtedf1ModelState, ali_state: &mut Rtedf1AliState) {
|
||
let ij = params.ij;
|
||
let nd = params.nd;
|
||
let nmu = params.nmu;
|
||
|
||
let mut dt = [0.0; MDEPTH];
|
||
let mut st0 = [0.0; MDEPTH];
|
||
let mut sa0 = [0.0; MDEPTH];
|
||
let mut ss0 = [0.0; MDEPTH];
|
||
let mut rad1 = [0.0; MDEPTH];
|
||
let mut rdk = [0.0; MDEPTH];
|
||
let mut ali1_local = [0.0; MDEPTH];
|
||
|
||
let sixth = UN / 6.0;
|
||
let third = UN / 3.0;
|
||
let twothr = TWO / 3.0;
|
||
|
||
// 1. 计算光深标尺
|
||
for id in 0..nd - 1 {
|
||
dt[id] = model.deldmz[id] * (model.absot[id + 1] + model.absot[id]);
|
||
sa0[id] = model.emis1[id] / model.abso1[id];
|
||
ss0[id] = -model.scat1[id] / model.abso1[id];
|
||
}
|
||
sa0[nd - 1] = model.emis1[nd - 1] / model.abso1[nd - 1];
|
||
ss0[nd - 1] = -model.scat1[nd - 1] / model.abso1[nd - 1];
|
||
|
||
let taumin = model.abso1[0] * model.dedm1;
|
||
|
||
// 2. 风遮挡考虑
|
||
let mut alb1 = 0.0;
|
||
// 注意: albe[ij] 暂未传入,假设为 0 或从其他地方获取
|
||
// if params.iwinbl > 0 { alb1 = TWO * albe[ij] / (UN + albe[ij]); }
|
||
|
||
// 3. 下边界条件量
|
||
let fr = model.freq[ij];
|
||
let fr15 = fr * 1e-15;
|
||
let bnu = BN * fr15 * fr15 * fr15;
|
||
let mut pland = bnu / ((HK * fr / model.temp[nd - 1]).exp() - UN) * model.rrdil;
|
||
let mut dplan = bnu / ((HK * fr / model.temp[nd - 2]).exp() - UN) * model.rrdil;
|
||
if model.tempbd > 0.0 {
|
||
pland = bnu / ((HK * fr / model.tempbd).exp() - UN) * model.rrdil;
|
||
dplan = bnu / ((HK * fr / model.tempbd).exp() - UN) * model.rrdil;
|
||
}
|
||
dplan = (pland - dplan) / dt[nd - 2];
|
||
|
||
let mut ah = 0.0;
|
||
let mut ahout = 0.0;
|
||
let mut ahd = 0.0;
|
||
let mut u0 = 0.0;
|
||
let mut qq0 = 0.0;
|
||
|
||
// 4. ALI 循环处理电子散射
|
||
let mut itrali = 0;
|
||
loop {
|
||
itrali += 1;
|
||
|
||
// 全源函数
|
||
for id in 0..nd {
|
||
st0[id] = sa0[id] - ss0[id] * model.rad[ij][id];
|
||
rad1[id] = 0.0;
|
||
rdk[id] = 0.0;
|
||
ali1_local[id] = 0.0;
|
||
}
|
||
|
||
ah = 0.0;
|
||
ahout = 0.0;
|
||
ahd = 0.0;
|
||
u0 = 0.0;
|
||
qq0 = 0.0;
|
||
let mut us0 = 0.0;
|
||
|
||
// 角点循环
|
||
for i in 0..nmu {
|
||
let amu_i = model.amu[i];
|
||
let wtmu_i = model.wtmu[i];
|
||
let amu2 = amu_i * amu_i * wtmu_i;
|
||
|
||
let mut dtau = [0.0; MDEPTH];
|
||
for id in 0..nd - 1 {
|
||
dtau[id] = dt[id] / amu_i;
|
||
}
|
||
|
||
// --- 入射强度 (incoming) ---
|
||
let mut rim = [0.0; MDEPTH];
|
||
let mut rip = [0.0; MDEPTH];
|
||
let mut aim = [0.0; MDEPTH];
|
||
let mut aip = [0.0; MDEPTH];
|
||
let mut riin = [0.0; MDEPTH];
|
||
let mut aiin = [0.0; MDEPTH];
|
||
|
||
rim[0] = model.extint[ij][i];
|
||
aim[0] = 0.0;
|
||
|
||
for id in 0..nd - 1 {
|
||
let dt0 = dtau[id];
|
||
let dtaup1 = dt0 + UN;
|
||
let cc = dt0 * dtaup1;
|
||
let aa = UN / (dt0 * dt0 + TWO * dtaup1);
|
||
|
||
rim[id + 1] = (TWO * rim[id] + dt0 * st0[id] + cc * st0[id + 1]) * aa;
|
||
rip[id] = (TWO * dtaup1 * rim[id] + cc * st0[id] - dt0 * st0[id + 1]) * aa;
|
||
aim[id + 1] = cc * aa;
|
||
aip[id] = (cc + TWO * dtaup1 * aim[id]) * aa;
|
||
}
|
||
|
||
for id in 1..nd - 1 {
|
||
let dtt = UN / (dtau[id - 1] + dtau[id]);
|
||
riin[id] = (rim[id] * dtau[id] + rip[id] * dtau[id - 1]) * dtt;
|
||
aiin[id] = (aim[id] * dtau[id] + aip[id] * dtau[id - 1]) * dtt;
|
||
}
|
||
riin[0] = rim[0];
|
||
riin[nd - 1] = rim[nd - 1];
|
||
aiin[0] = aim[0];
|
||
aiin[nd - 1] = aim[nd - 1];
|
||
|
||
// --- 出射强度 (outgoing) ---
|
||
let mut riup = [0.0; MDEPTH];
|
||
let mut aiup = [0.0; MDEPTH];
|
||
|
||
if params.idisk == 0 {
|
||
rim[nd - 1] = pland + amu_i * dplan;
|
||
}
|
||
|
||
for id in (0..nd - 1).rev() {
|
||
let dt0 = dtau[id];
|
||
let dtaup1 = dt0 + UN;
|
||
let cc = dt0 * dtaup1;
|
||
let aa = UN / (dt0 * dt0 + TWO * dtaup1);
|
||
|
||
rim[id] = (TWO * rim[id + 1] + dt0 * st0[id + 1] + cc * st0[id]) * aa;
|
||
rip[id + 1] = (TWO * dtaup1 * rim[id + 1] + cc * st0[id + 1] - dt0 * st0[id]) * aa;
|
||
aim[id] = cc * aa;
|
||
aip[id + 1] = (cc + TWO * dtaup1 * aim[id + 1]) * aa;
|
||
}
|
||
|
||
for id in 1..nd - 1 {
|
||
let dtt = UN / (dtau[id - 1] + dtau[id]);
|
||
riup[id] = (rim[id] * dtau[id - 1] + rip[id] * dtau[id]) * dtt;
|
||
aiup[id] = (aim[id] * dtau[id - 1] + aip[id] * dtau[id]) * dtt;
|
||
}
|
||
riup[0] = rim[0];
|
||
riup[nd - 1] = rim[nd - 1];
|
||
aiup[0] = aim[0];
|
||
aiup[nd - 1] = aim[nd - 1];
|
||
|
||
// 对称化源函数 (Feautrier u)
|
||
for id in 0..nd {
|
||
let u_id = (riin[id] + riup[id]) * HALF;
|
||
let al0_id = (aiin[id] + aiup[id]) * HALF;
|
||
|
||
rad1[id] += wtmu_i * u_id;
|
||
rdk[id] += amu2 * u_id;
|
||
ali1_local[id] += wtmu_i * al0_id;
|
||
}
|
||
|
||
ah += amu_i * wtmu_i * (riin[0] + riup[0]) * HALF;
|
||
ahd += amu_i * wtmu_i * (riin[nd - 1] + riup[nd - 1]) * HALF;
|
||
ahout += amu_i * wtmu_i * riup[0];
|
||
u0 += wtmu_i * rim[0]; // 粗略对应
|
||
qq0 += amu_i * wtmu_i * rim[0]; // 粗略对应
|
||
}
|
||
|
||
// 边界处理
|
||
if params.ibc == 0 {
|
||
ali1_local[nd - 1] = rad1[nd - 1] / st0[nd - 1];
|
||
ali1_local[nd - 2] = rad1[nd - 2] / st0[nd - 2];
|
||
}
|
||
|
||
let mut djtot: f64 = 0.0;
|
||
for id in 0..nd {
|
||
let deltaj = (rad1[id] - model.rad[ij][id]) / (UN + ss0[id] * ali1_local[id]);
|
||
model.rad[ij][id] += deltaj;
|
||
if model.rad[ij][id].abs() > 0.0 {
|
||
djtot = djtot.max((deltaj / model.rad[ij][id]).abs());
|
||
}
|
||
}
|
||
|
||
if djtot <= params.djmax || itrali >= params.ntrali {
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 存储物理量
|
||
for id in 0..nd {
|
||
rad1[id] = model.rad[ij][id];
|
||
let f_val = rdk[id] / model.rad[ij][id];
|
||
model.fak[ij][id] = f_val;
|
||
}
|
||
model.flux[ij] = ahout * HALF;
|
||
let fh0 = ah / rad1[0]; // 简化处理
|
||
model.fh[ij] = fh0;
|
||
model.fhd[ij] = ahd / rad1[nd - 1];
|
||
|
||
// 第二阶段: 严格一致性消元 (Feautrier style)
|
||
let mut aaa = [0.0; MDEPTH];
|
||
let mut bbb = [0.0; MDEPTH];
|
||
let mut ccc = [0.0; MDEPTH];
|
||
let mut ddd = [0.0; MDEPTH];
|
||
let mut eee = [0.0; MDEPTH];
|
||
let mut zzz = [0.0; MDEPTH];
|
||
let mut aanu = [0.0; MDEPTH];
|
||
let mut alrh = [0.0; MDEPTH];
|
||
|
||
let mut sa0_copy = sa0;
|
||
let mut ss0_copy = ss0;
|
||
if params.ilmcor == 3 {
|
||
for id in 0..nd {
|
||
sa0_copy[id] = st0[id];
|
||
ss0_copy[id] = 0.0;
|
||
}
|
||
}
|
||
|
||
// 上边界
|
||
let mut id = 0;
|
||
let mut dtp1 = dt[id];
|
||
let (b, _) = if params.isplin % 3 == 0 {
|
||
(dtp1 * HALF, 0.0)
|
||
} else {
|
||
(dtp1 * third, dtp1 * third * HALF)
|
||
};
|
||
let bq = UN / (b + 0.0); // qq0 简化
|
||
bbb[id] = (model.fak[ij][id] / dtp1 + fh0 + b) * bq + ss0_copy[id];
|
||
ccc[id] = (model.fak[ij][id + 1] / dtp1) * bq;
|
||
zzz[id] = UN / bbb[id];
|
||
let vll = sa0_copy[id];
|
||
aanu[id] = vll * zzz[id];
|
||
ddd[id] = ccc[id] * zzz[id];
|
||
|
||
// 中间层
|
||
for id_idx in 1..nd - 1 {
|
||
let dtm1 = dtp1;
|
||
dtp1 = dt[id_idx];
|
||
let dt0 = TWO / (dtp1 + dtm1);
|
||
let al = UN / dtm1 * dt0;
|
||
let ga = UN / dtp1 * dt0;
|
||
|
||
let (a, c) = if params.isplin % 3 == 0 {
|
||
(0.0, 0.0)
|
||
} else {
|
||
(dtm1 * dt0 * sixth, dtp1 * dt0 * sixth)
|
||
};
|
||
|
||
aaa[id_idx] = al * model.fak[ij][id_idx - 1] - a * (UN + ss0_copy[id_idx - 1]);
|
||
ccc[id_idx] = ga * model.fak[ij][id_idx + 1] - c * (UN + ss0_copy[id_idx + 1]);
|
||
bbb[id_idx] = (al + ga) * model.fak[ij][id_idx] + (UN - a - c) * (UN + ss0_copy[id_idx]);
|
||
let vll_mid = a * sa0_copy[id_idx - 1] + c * sa0_copy[id_idx + 1] + (UN - a - c) * sa0_copy[id_idx];
|
||
|
||
aanu[id_idx] = vll_mid + aaa[id_idx] * aanu[id_idx - 1];
|
||
zzz[id_idx] = UN / (bbb[id_idx] - aaa[id_idx] * ddd[id_idx - 1]);
|
||
ddd[id_idx] = ccc[id_idx] * zzz[id_idx];
|
||
aanu[id_idx] *= zzz[id_idx];
|
||
}
|
||
|
||
// 下边界
|
||
id = nd - 1;
|
||
if params.ibc == 0 {
|
||
bbb[id] = model.fak[ij][id] / dtp1 + HALF;
|
||
aaa[id] = model.fak[ij][id - 1] / dtp1;
|
||
} else {
|
||
let b_val = UN / dtp1;
|
||
let a_val = TWO * b_val * b_val;
|
||
bbb[id] = UN + ss0_copy[id] + b_val + a_val * model.fak[ij][id];
|
||
aaa[id] = a_val * model.fak[ij][id - 1];
|
||
}
|
||
eee[id] = aaa[id] / bbb[id];
|
||
zzz[id] = UN / (bbb[id] - aaa[id] * ddd[id - 1]);
|
||
rad1[id] = (sa0_copy[id] + aaa[id] * aanu[id - 1]) * zzz[id];
|
||
alrh[id] = zzz[id];
|
||
|
||
// 回代
|
||
for id_idx in (0..nd - 1).rev() {
|
||
eee[id_idx] = aaa[id_idx] / (bbb[id_idx] - ccc[id_idx] * eee[id_idx + 1]);
|
||
rad1[id_idx] = aanu[id_idx] + ddd[id_idx] * rad1[id_idx + 1];
|
||
alrh[id_idx] = zzz[id_idx] / (UN - ddd[id_idx] * eee[id_idx + 1]);
|
||
}
|
||
|
||
// Lambda 算子评价
|
||
if params.jali == 1 {
|
||
for id in 0..nd {
|
||
ali_state.ali1[id] = alrh[id];
|
||
}
|
||
if params.ifali >= 6 {
|
||
ali_state.alip1[0] = alrh[1] * ddd[0];
|
||
for id in 1..nd - 1 {
|
||
ali_state.alim1[id] = alrh[id - 1] * eee[id];
|
||
ali_state.alip1[id] = alrh[id + 1] * ddd[id];
|
||
}
|
||
ali_state.alim1[nd - 1] = alrh[nd - 2] * eee[nd - 1];
|
||
}
|
||
}
|
||
|
||
// 存储显式频率数据
|
||
if model.ijex[ij] > 0 {
|
||
let ije = (model.ijex[ij] - 1) as usize;
|
||
for id in 0..nd {
|
||
model.radex[ije][id] = rad1[id];
|
||
model.fakex[ije][id] = model.fak[ij][id];
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_rtedf1_basic() {
|
||
let nd = 10;
|
||
let nmu = 3;
|
||
let mut rad = vec![vec![0.0; MDEPTH]; 1];
|
||
let mut fak = vec![vec![0.0; MDEPTH]; 1];
|
||
let mut flux = vec![0.0; 1];
|
||
let mut fh = vec![0.0; 1];
|
||
let mut fhd = vec![0.0; 1];
|
||
let mut radex = vec![vec![0.0; MDEPTH]; 1];
|
||
let mut fakex = vec![vec![0.0; MDEPTH]; 1];
|
||
let mut q0 = vec![0.0; 1];
|
||
let mut uu0 = vec![0.0; 1];
|
||
|
||
let params = Rtedf1Params {
|
||
ij: 0,
|
||
nd,
|
||
nmu,
|
||
idisk: 0,
|
||
ibc: 0,
|
||
isplin: 0,
|
||
jali: 1,
|
||
ifali: 0,
|
||
ilmcor: 0,
|
||
ilasct: 1,
|
||
djmax: 1e-4,
|
||
ntrali: 10,
|
||
iwinbl: 0,
|
||
};
|
||
|
||
let amu = vec![0.1127, 0.5000, 0.8873];
|
||
let wtmu = vec![0.2778, 0.4444, 0.2778];
|
||
let freq = vec![1e15];
|
||
let deldmz = vec![1.0; MDEPTH];
|
||
let absot = vec![1.0; MDEPTH];
|
||
let emis1 = vec![1.0; MDEPTH]; // S = 1.0
|
||
let abso1 = vec![1.0; MDEPTH];
|
||
let scat1 = vec![0.0; MDEPTH];
|
||
let temp = vec![5000.0; MDEPTH];
|
||
let ijex = vec![0];
|
||
|
||
let mut model_state = Rtedf1ModelState {
|
||
amu: &amu,
|
||
wtmu: &wtmu,
|
||
freq: &freq,
|
||
deldmz: &deldmz,
|
||
absot: &absot,
|
||
emis1: &emis1,
|
||
abso1: &abso1,
|
||
scat1: &scat1,
|
||
temp: &temp,
|
||
dedm1: 1e-5,
|
||
rrdil: 1.0,
|
||
tempbd: 0.0,
|
||
extint: &vec![vec![0.0; nmu]; 1],
|
||
hextrd: &vec![0.0; 1],
|
||
rad: &mut rad,
|
||
fak: &mut fak,
|
||
flux: &mut flux,
|
||
fh: &mut fh,
|
||
fhd: &mut fhd,
|
||
radex: &mut radex,
|
||
fakex: &mut fakex,
|
||
q0: &mut q0,
|
||
uu0: &mut uu0,
|
||
ijex: &ijex,
|
||
};
|
||
|
||
let mut ali1 = vec![0.0; MDEPTH];
|
||
let mut alim1 = vec![0.0; MDEPTH];
|
||
let mut alip1 = vec![0.0; MDEPTH];
|
||
let mut ali_state = Rtedf1AliState {
|
||
ali1: &mut ali1,
|
||
alim1: &mut alim1,
|
||
alip1: &mut alip1,
|
||
};
|
||
|
||
rtedf1(¶ms, &mut model_state, &mut ali_state);
|
||
|
||
// 在源函数 S=1 的均匀介质中,RAD 应趋向于 1.0 (平衡态)
|
||
// 在 nd=10 时,可能还在增长中,但应为正值且合理
|
||
assert!(model_state.rad[0][nd - 1] > 0.0);
|
||
assert!(model_state.rad[0][nd - 1] <= 1.0001);
|
||
println!("RAD at ND: {}", model_state.rad[0][nd - 1]);
|
||
}
|
||
}
|