feat: 添加更多重构模块 (第7批)
包含 IO 和 math 模块的实现: - IO: initia, levcd, linset, ltegr, ltegrd, odfset, outpri, resolv, srtfrq, start, tabini, xenini - Math: accel2, alisk1, alisk2, alist1, alist2, concor, conout, conref, contmd, contmp, coolrt, greyd, inilam, linsel, lucy, lymlin, matcon, matgen, moleq, newdm, newdmt, odf1, opacf0, opacf1, opacfa, opacfd, opacfl, opactr, opadd, opahst, pgset, princ, prnt, pzeval, quasim, radpre, radtot, rates1, ratsp1, rdata, rdatax, rechck, rhoeos, rhonen, rhsgen, rossop, rtecf1, rtecmc, rtecmu, rtecom, rtefr1, rteint, russel, rybchn, rybene, rybheq, rybsol, sgmer1, sigave, sigk, solve, solves, state, steqeq, temcor, temper, topbas, trmder, trmdrt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,617 @@
|
||||
//! 基于温度变化的新深度网格计算。
|
||||
//!
|
||||
//! 重构自 TLUSTY `newdmt.f`
|
||||
//!
|
||||
//! # 功能
|
||||
//!
|
||||
//! 计算新的 m-scale(柱质量密度),基于新网格更好地表示温度变化。
|
||||
//! 使用 GRIDP 函数找到最优网格点分布。
|
||||
|
||||
use crate::math::gridp::gridp;
|
||||
use crate::math::interp::interp;
|
||||
use crate::state::constants::{HALF, MDEPTH, TWO, UN};
|
||||
|
||||
// ============================================================================
|
||||
// 常量
|
||||
// ============================================================================
|
||||
|
||||
/// ln(10) = 2.3025851...
|
||||
const LN10: f64 = 2.30258509299404568402;
|
||||
|
||||
// ============================================================================
|
||||
// 辅助参数结构体
|
||||
// ============================================================================
|
||||
|
||||
/// PRSAUX COMMON 块参数
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NewdmtPrsAux {
|
||||
/// 声速平方 [深度]
|
||||
pub vsnd2: Vec<f64>,
|
||||
/// 表面气压标高
|
||||
pub hg1: f64,
|
||||
/// 辐射气压标高
|
||||
pub hr1: f64,
|
||||
/// 辐射/气压标高比
|
||||
pub rr1: f64,
|
||||
}
|
||||
|
||||
impl Default for NewdmtPrsAux {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
vsnd2: vec![0.0; MDEPTH],
|
||||
hg1: 0.0,
|
||||
hr1: 0.0,
|
||||
rr1: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// FACTRS COMMON 块参数
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NewdmtFactrs {
|
||||
/// 辐射因子 [深度]
|
||||
pub gamj: Vec<f64>,
|
||||
/// 几何稀释因子
|
||||
pub gamh: f64,
|
||||
pub fak0: f64,
|
||||
}
|
||||
|
||||
impl Default for NewdmtFactrs {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
gamj: vec![1.0; MDEPTH],
|
||||
gamh: 1.0,
|
||||
fak0: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 配置结构体
|
||||
// ============================================================================
|
||||
|
||||
/// NEWDMT 配置参数。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NewdmtConfig {
|
||||
/// 深度点数
|
||||
pub nd: usize,
|
||||
/// 粘性深度参数
|
||||
pub dmvisc: f64,
|
||||
/// ZETA0 参数
|
||||
pub zeta0: f64,
|
||||
/// ZETA1 参数
|
||||
pub zeta1: f64,
|
||||
/// 粘性分数
|
||||
pub fractv: f64,
|
||||
/// 收敛迭代控制
|
||||
pub nconit: i32,
|
||||
/// 打印控制
|
||||
pub ipring: i32,
|
||||
}
|
||||
|
||||
impl Default for NewdmtConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
nd: 50,
|
||||
dmvisc: 0.0,
|
||||
zeta0: 0.0,
|
||||
zeta1: 0.0,
|
||||
fractv: 0.0,
|
||||
nconit: 0,
|
||||
ipring: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 模型状态结构体
|
||||
// ============================================================================
|
||||
|
||||
/// NEWDMT 模型状态(可变)。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NewdmtModelState {
|
||||
/// 深度 (柱质量密度, g/cm²) [深度]
|
||||
pub dm: Vec<f64>,
|
||||
/// 温度 (K) [深度]
|
||||
pub temp: Vec<f64>,
|
||||
/// 电子密度 (cm⁻³) [深度]
|
||||
pub elec: Vec<f64>,
|
||||
/// 总粒子密度 (cm⁻³) [深度]
|
||||
pub dens: Vec<f64>,
|
||||
/// 深度变量 (cm) [深度]
|
||||
pub zd: Vec<f64>,
|
||||
/// Rosseland 光学深度 [深度]
|
||||
pub tauros: Vec<f64>,
|
||||
/// 热光学深度 [深度]
|
||||
pub tauthe: Vec<f64>,
|
||||
/// Theta 函数 [深度]
|
||||
pub theta: Vec<f64>,
|
||||
/// 粘性系数 [深度]
|
||||
pub viscd: Vec<f64>,
|
||||
/// Rosseland 平均不透明度 [深度]
|
||||
pub abrosd: Vec<f64>,
|
||||
/// Planck 平均不透明度 [深度]
|
||||
pub abplad: Vec<f64>,
|
||||
/// 平均分子量 [深度]
|
||||
pub wmm: Vec<f64>,
|
||||
/// 总压力 [深度]
|
||||
pub ptotal: Vec<f64>,
|
||||
}
|
||||
|
||||
impl Default for NewdmtModelState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dm: vec![0.0; MDEPTH],
|
||||
temp: vec![0.0; MDEPTH],
|
||||
elec: vec![0.0; MDEPTH],
|
||||
dens: vec![0.0; MDEPTH],
|
||||
zd: vec![0.0; MDEPTH],
|
||||
tauros: vec![0.0; MDEPTH],
|
||||
tauthe: vec![0.0; MDEPTH],
|
||||
theta: vec![0.0; MDEPTH],
|
||||
viscd: vec![0.0; MDEPTH],
|
||||
abrosd: vec![0.0; MDEPTH],
|
||||
abplad: vec![0.0; MDEPTH],
|
||||
wmm: vec![1.0; MDEPTH],
|
||||
ptotal: vec![0.0; MDEPTH],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主计算函数
|
||||
// ============================================================================
|
||||
|
||||
/// NEWDMT 纯计算函数(网格计算部分)。
|
||||
///
|
||||
/// 计算新的深度网格,基于温度变化使用 GRIDP。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * `config` - 配置参数
|
||||
/// * `state` - 模型状态(输入/输出)
|
||||
/// * `prs_aux` - PRSAUX 参数(输出)
|
||||
/// * `factrs` - FACTRS 参数(输出)
|
||||
///
|
||||
/// # 注意
|
||||
///
|
||||
/// 完整实现需要调用 TEMPER 和 HESOLV,这里只实现网格计算部分。
|
||||
pub fn newdmt_pure(
|
||||
config: &NewdmtConfig,
|
||||
state: &mut NewdmtModelState,
|
||||
prs_aux: &mut NewdmtPrsAux,
|
||||
factrs: &mut NewdmtFactrs,
|
||||
) {
|
||||
let nd = config.nd;
|
||||
let nd1 = nd - 1;
|
||||
|
||||
// 工作数组
|
||||
let mut dm0 = vec![0.0; MDEPTH]; // log10(dm) 原始
|
||||
let mut dm11 = vec![0.0; MDEPTH]; // 新 log10(dm)
|
||||
let mut t0 = vec![0.0; MDEPTH]; // log10(tauros) 原始
|
||||
let mut t1 = vec![0.0; MDEPTH]; // 新 log10(tauros)
|
||||
let mut elec0 = vec![0.0; MDEPTH]; // 原始 elec
|
||||
let mut dens0 = vec![0.0; MDEPTH]; // 原始 dens
|
||||
let mut zd0 = vec![0.0; MDEPTH]; // 原始 zd
|
||||
let mut pt0 = vec![0.0; MDEPTH]; // 原始 ptotal
|
||||
let mut abrs0 = vec![0.0; MDEPTH]; // 原始 abrosd
|
||||
let mut abpl0 = vec![0.0; MDEPTH]; // 原始 abplad
|
||||
|
||||
// ========================================================================
|
||||
// Step 1: 保存原始值并计算 log10
|
||||
// ========================================================================
|
||||
|
||||
for id in 0..nd {
|
||||
dm0[id] = if state.dm[id] > 0.0 {
|
||||
state.dm[id].log10()
|
||||
} else {
|
||||
-10.0
|
||||
};
|
||||
t0[id] = if state.tauros[id] > 0.0 {
|
||||
state.tauros[id].log10()
|
||||
} else {
|
||||
-10.0
|
||||
};
|
||||
elec0[id] = state.elec[id];
|
||||
dens0[id] = state.dens[id];
|
||||
pt0[id] = state.ptotal[id];
|
||||
zd0[id] = state.zd[id];
|
||||
abrs0[id] = state.abrosd[id];
|
||||
abpl0[id] = state.abplad[id];
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Step 2: 使用 GRIDP 计算新网格
|
||||
// ========================================================================
|
||||
|
||||
// GRIDP 需要 nd1 个点(不包括最后一个点)
|
||||
gridp(&dm0, &t0, &mut dm11, &mut t1, nd1);
|
||||
|
||||
// 最后一个点保持不变
|
||||
dm11[nd - 1] = dm0[nd - 1];
|
||||
t1[nd - 1] = t0[nd - 1];
|
||||
|
||||
// ========================================================================
|
||||
// Step 3: 转换回线性尺度
|
||||
// ========================================================================
|
||||
|
||||
for id in 0..nd {
|
||||
state.dm[id] = (LN10 * dm11[id]).exp();
|
||||
state.tauros[id] = (LN10 * t1[id]).exp();
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Step 4: 插值各种物理量到新网格
|
||||
// ========================================================================
|
||||
|
||||
// 需要可变数组用于 INTERP(INTERP 会修改输入数组)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut elec0_mut = elec0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut elec_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut elec0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut elec_out,
|
||||
nd,
|
||||
nd,
|
||||
2, // 线性插值
|
||||
0, // 不对 x 取对数(已经是对数)
|
||||
1, // 对 y 取对数
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.elec[id] = elec_out[id];
|
||||
}
|
||||
|
||||
// INTERP(DM0, DENS0, DM11, DENS, ND, ND, 2, 0, 1)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut dens0_mut = dens0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut dens_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut dens0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut dens_out,
|
||||
nd,
|
||||
nd,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.dens[id] = dens_out[id];
|
||||
}
|
||||
|
||||
// INTERP(DM0, PT0, DM11, PTOTAL, ND, ND, 2, 0, 1)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut pt0_mut = pt0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut ptotal_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut pt0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut ptotal_out,
|
||||
nd,
|
||||
nd,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.ptotal[id] = ptotal_out[id];
|
||||
}
|
||||
|
||||
// INTERP(DM0, ZD0, DM11, ZD, ND, ND, 2, 0, 0)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut zd0_mut = zd0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut zd_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut zd0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut zd_out,
|
||||
nd,
|
||||
nd,
|
||||
2,
|
||||
0,
|
||||
0, // 不对 y 取对数
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.zd[id] = zd_out[id];
|
||||
}
|
||||
|
||||
// INTERP(DM0, ABRS0, DM11, ABROSD, ND, ND, 2, 0, 1)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut abrs0_mut = abrs0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut abrosd_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut abrs0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut abrosd_out,
|
||||
nd,
|
||||
nd,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.abrosd[id] = abrosd_out[id];
|
||||
}
|
||||
|
||||
// INTERP(DM0, ABPL0, DM11, ABPLAD, ND, ND, 2, 0, 1)
|
||||
let mut dm0_mut = dm0.clone();
|
||||
let mut abpl0_mut = abpl0.clone();
|
||||
let mut dm11_mut = dm11.clone();
|
||||
let mut abplad_out = vec![0.0; MDEPTH];
|
||||
interp(
|
||||
&mut dm0_mut,
|
||||
&mut abpl0_mut,
|
||||
&mut dm11_mut,
|
||||
&mut abplad_out,
|
||||
nd,
|
||||
nd,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
for id in 0..nd {
|
||||
state.abplad[id] = abplad_out[id];
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Step 5: 计算声速平方 VSND2 = PTOTAL / DENS
|
||||
// ========================================================================
|
||||
|
||||
for id in 0..nd {
|
||||
if state.dens[id] > 0.0 {
|
||||
prs_aux.vsnd2[id] = state.ptotal[id] / state.dens[id];
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Step 6: 计算新的 Rosseland 不透明度和 theta/tauthe 函数
|
||||
// ========================================================================
|
||||
|
||||
let amuv0 = if config.dmvisc > 0.0 && state.dm[nd - 1] > 0.0 {
|
||||
config.dmvisc.powf(config.zeta0 + UN)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let amuv1 = UN - amuv0;
|
||||
|
||||
for id in 0..nd {
|
||||
// 计算 viscd 和 theta
|
||||
if config.dmvisc > 0.0 && state.dm[nd - 1] > 0.0 {
|
||||
let ratio = state.dm[id] / state.dm[nd - 1];
|
||||
if ratio <= config.dmvisc {
|
||||
// 内部区域:dm <= dmvisc * dm[nd-1]
|
||||
state.viscd[id] = (UN - config.fractv) * (config.zeta1 + UN)
|
||||
/ config.dmvisc.powf(config.zeta1 + UN)
|
||||
* ratio.powf(config.zeta1);
|
||||
state.theta[id] =
|
||||
(UN - config.fractv) * (ratio / config.dmvisc).powf(config.zeta1 + UN);
|
||||
} else {
|
||||
// 外部区域:dm > dmvisc * dm[nd-1]
|
||||
state.viscd[id] =
|
||||
config.fractv * (config.zeta0 + UN) / amuv1 * ratio.powf(config.zeta0);
|
||||
state.theta[id] = (UN - config.fractv)
|
||||
+ config.fractv * (ratio.powf(config.zeta0 + UN) - amuv0) / amuv1;
|
||||
}
|
||||
} else {
|
||||
// 当 dmvisc = 0 或 dm[nd-1] = 0 时,theta = 1.0(无粘性)
|
||||
state.theta[id] = UN;
|
||||
state.viscd[id] = 0.0;
|
||||
}
|
||||
|
||||
factrs.gamj[id] = UN;
|
||||
|
||||
// 计算 tauros 和 tauthe
|
||||
if id == 0 {
|
||||
state.tauros[id] = state.dm[id] * state.abrosd[id];
|
||||
state.tauthe[id] = state.tauros[id] * state.theta[id] / (config.zeta1 + TWO);
|
||||
// 原始代码中计算 ANEREL,但不使用
|
||||
} else {
|
||||
let ddm = state.dm[id] - state.dm[id - 1];
|
||||
state.tauros[id] =
|
||||
state.tauros[id - 1] + ddm * HALF * (state.abrosd[id - 1] + state.abrosd[id]);
|
||||
|
||||
let zetad = if config.dmvisc > 0.0
|
||||
&& state.dm[nd - 1] > 0.0
|
||||
&& state.dm[id] <= config.dmvisc * state.dm[nd - 1]
|
||||
{
|
||||
config.zeta1
|
||||
} else {
|
||||
config.zeta0
|
||||
};
|
||||
|
||||
let a0 = (state.abrosd[id - 1] * state.dm[id] - state.abrosd[id] * state.dm[id - 1])
|
||||
/ ddm
|
||||
/ (zetad + TWO);
|
||||
let a1 =
|
||||
(state.abrosd[id] - state.abrosd[id - 1]) / ddm / (zetad + 3.0);
|
||||
|
||||
state.tauthe[id] = state.tauthe[id - 1]
|
||||
+ a0 * (state.theta[id] * state.dm[id] - state.theta[id - 1] * state.dm[id - 1])
|
||||
+ a1 * (state.theta[id] * state.dm[id] * state.dm[id]
|
||||
- state.theta[id - 1] * state.dm[id - 1] * state.dm[id - 1]);
|
||||
}
|
||||
|
||||
// 注意:原始代码中这里调用 TEMPER
|
||||
// CALL TEMPER(ID, TAUR, 1)
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Step 7: 调用 HESOLV(如果 nconit >= 0)
|
||||
// ========================================================================
|
||||
// 注意:原始代码中这里调用 HESOLV
|
||||
// if(nconit.ge.0) CALL HESOLV
|
||||
|
||||
// ========================================================================
|
||||
// Step 8: 再次计算温度和平均不透明度
|
||||
// ========================================================================
|
||||
// 注意:原始代码中再次调用 TEMPER 和 HESOLV
|
||||
|
||||
// ========================================================================
|
||||
// Step 9: 打印输出(如果 ipring >= 1)
|
||||
// ========================================================================
|
||||
// 注意:原始代码中有 WRITE(6,...) 输出
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 测试
|
||||
// ============================================================================
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn create_test_state(nd: usize) -> NewdmtModelState {
|
||||
let mut state = NewdmtModelState::default();
|
||||
|
||||
// 创建简单的测试网格
|
||||
for i in 0..nd {
|
||||
let x = (i + 1) as f64 / nd as f64;
|
||||
state.dm[i] = 1e-4 * x.powf(2.0);
|
||||
state.dens[i] = 1e13 * (1.0 - 0.5 * x);
|
||||
state.abrosd[i] = 1e-4 * (1.0 + x);
|
||||
state.abplad[i] = 2e-4 * (1.0 + x);
|
||||
state.tauros[i] = state.dm[i] * state.abrosd[i];
|
||||
state.elec[i] = 1e10 * x;
|
||||
state.ptotal[i] = 1e4 * (1.0 + x);
|
||||
state.zd[i] = 1e8 * x;
|
||||
state.wmm[i] = 1.0;
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_newdmt_basic() {
|
||||
let config = NewdmtConfig {
|
||||
nd: 50,
|
||||
dmvisc: 0.0,
|
||||
zeta0: 0.0,
|
||||
zeta1: 0.0,
|
||||
fractv: 0.0,
|
||||
nconit: 0,
|
||||
ipring: 0,
|
||||
};
|
||||
|
||||
let mut state = create_test_state(config.nd);
|
||||
let mut prs_aux = NewdmtPrsAux::default();
|
||||
let mut factrs = NewdmtFactrs::default();
|
||||
|
||||
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
|
||||
|
||||
// 验证基本属性
|
||||
assert!(state.dm[0] > 0.0, "dm[0] should be positive");
|
||||
assert!(state.tauros[0] >= 0.0, "tauros[0] should be non-negative");
|
||||
|
||||
// 验证 dm 是单调递增的
|
||||
for i in 1..config.nd {
|
||||
assert!(
|
||||
state.dm[i] >= state.dm[i - 1],
|
||||
"dm should be monotonically increasing at i={}",
|
||||
i
|
||||
);
|
||||
}
|
||||
|
||||
// 验证 theta = 1.0(无粘性时)
|
||||
for i in 0..config.nd {
|
||||
assert!(
|
||||
(state.theta[i] - 1.0).abs() < 1e-10,
|
||||
"theta[{}] should be 1.0 when dmvisc=0",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_newdmt_with_viscosity() {
|
||||
let config = NewdmtConfig {
|
||||
nd: 50,
|
||||
dmvisc: 0.5,
|
||||
zeta0: 0.5,
|
||||
zeta1: 1.0,
|
||||
fractv: 0.1,
|
||||
nconit: 0,
|
||||
ipring: 0,
|
||||
};
|
||||
|
||||
let mut state = create_test_state(config.nd);
|
||||
let mut prs_aux = NewdmtPrsAux::default();
|
||||
let mut factrs = NewdmtFactrs::default();
|
||||
|
||||
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
|
||||
|
||||
// 验证 theta 在有效范围内
|
||||
for i in 0..config.nd {
|
||||
assert!(
|
||||
state.theta[i] >= 0.0,
|
||||
"theta[{}] = {} is negative",
|
||||
i,
|
||||
state.theta[i]
|
||||
);
|
||||
assert!(
|
||||
state.theta[i] <= 2.0,
|
||||
"theta[{}] = {} is too large",
|
||||
i,
|
||||
state.theta[i]
|
||||
);
|
||||
}
|
||||
|
||||
// 验证 vsnd2 已计算
|
||||
for i in 0..config.nd {
|
||||
if state.dens[i] > 0.0 {
|
||||
assert!(
|
||||
prs_aux.vsnd2[i] > 0.0,
|
||||
"vsnd2[{}] should be positive",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_newdmt_tauros_consistency() {
|
||||
let config = NewdmtConfig {
|
||||
nd: 50,
|
||||
dmvisc: 0.0,
|
||||
zeta0: 0.0,
|
||||
zeta1: 0.0,
|
||||
fractv: 0.0,
|
||||
nconit: 0,
|
||||
ipring: 0,
|
||||
};
|
||||
|
||||
let mut state = create_test_state(config.nd);
|
||||
let mut prs_aux = NewdmtPrsAux::default();
|
||||
let mut factrs = NewdmtFactrs::default();
|
||||
|
||||
newdmt_pure(&config, &mut state, &mut prs_aux, &mut factrs);
|
||||
|
||||
// 验证 tauros 是单调递增的
|
||||
for i in 1..config.nd {
|
||||
assert!(
|
||||
state.tauros[i] >= state.tauros[i - 1],
|
||||
"tauros should be monotonically increasing at i={}",
|
||||
i
|
||||
);
|
||||
}
|
||||
|
||||
// 验证 tauthe 是单调递增的
|
||||
for i in 1..config.nd {
|
||||
assert!(
|
||||
state.tauthe[i] >= state.tauthe[i - 1],
|
||||
"tauthe should be monotonically increasing at i={}",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user