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,729 @@
|
||||
//! 对流诊断输出模块。
|
||||
//!
|
||||
//! 重构自 TLUSTY `conout.f`
|
||||
//!
|
||||
//! # 功能
|
||||
//!
|
||||
//! 计算并输出温度梯度、对流通量及其导数的诊断信息:
|
||||
//! - 计算各深度点的 DELTA (温度梯度参数)
|
||||
//! - 调用 CONVEC 计算对流通量
|
||||
//! - 确定对流区的起始和结束深度
|
||||
//! - 根据 ICONV 参数调整 NDRE 和 REDIF/REINT 数组
|
||||
|
||||
use crate::state::constants::{HALF, SIG4P, UN};
|
||||
|
||||
// ============================================================================
|
||||
// 配置结构体
|
||||
// ============================================================================
|
||||
|
||||
/// CONOUT 配置参数。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConoutConfig {
|
||||
/// 混合长度参数 (HMIX0)
|
||||
pub hmix0: f64,
|
||||
/// 对流模式 (ICONV)
|
||||
/// - 2: 在对流区使用 REDIF=1
|
||||
/// - 3: 在对流区使用 REDIF=1, REINT=0 (差分形式)
|
||||
pub iconv: i32,
|
||||
/// 盘模式标志 (IDISK)
|
||||
pub idisk: i32,
|
||||
/// 不透明度表标志 (IOPTAB)
|
||||
pub ioptab: i32,
|
||||
/// 对数梯度标志 (ILGDER)
|
||||
/// - 0: 线性平均
|
||||
/// - 1: 对数平均
|
||||
pub ilgder: i32,
|
||||
/// 表面重力加速度 (GRAV)
|
||||
pub grav: f64,
|
||||
/// 对流常数 A (ACONML)
|
||||
pub aconml: f64,
|
||||
/// 对流常数 B (BCONML)
|
||||
pub bconml: f64,
|
||||
/// 对流常数 C (CCONML)
|
||||
pub cconml: f64,
|
||||
}
|
||||
|
||||
impl Default for ConoutConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hmix0: 1.0,
|
||||
iconv: 0,
|
||||
idisk: 0,
|
||||
ioptab: 0,
|
||||
ilgder: 0,
|
||||
grav: 1e4,
|
||||
aconml: 1.0,
|
||||
bconml: 1.0,
|
||||
cconml: 1.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 输入/输出结构体
|
||||
// ============================================================================
|
||||
|
||||
/// CONOUT 输入参数。
|
||||
pub struct ConoutParams<'a> {
|
||||
/// 模式标志 (IMOD)
|
||||
/// - 2: 计算平均不透明度
|
||||
pub imod: i32,
|
||||
/// 打印标志 (IPRIN)
|
||||
/// - >0: 输出诊断信息
|
||||
pub iprin: i32,
|
||||
/// 深度点数 (ND)
|
||||
pub nd: usize,
|
||||
/// 有效温度 (TEFF)
|
||||
pub teff: f64,
|
||||
/// 配置
|
||||
pub config: ConoutConfig,
|
||||
// 深度相关数组 (nd)
|
||||
/// 温度 (TEMP)
|
||||
pub temp: &'a [f64],
|
||||
/// 电子密度 (ELEC)
|
||||
pub elec: &'a [f64],
|
||||
/// 总粒子密度 (DENS)
|
||||
pub dens: &'a [f64],
|
||||
/// 分子质量 (WMM)
|
||||
pub wmm: &'a [f64],
|
||||
/// 深度 (柱质量密度, DM)
|
||||
pub dm: &'a [f64],
|
||||
/// 深度变量 (ZD) - 盘模式使用
|
||||
pub zd: &'a [f64],
|
||||
/// 总压力 (PTOTAL)
|
||||
pub ptotal: &'a [f64],
|
||||
/// 气压 (PGS)
|
||||
pub pgs: &'a [f64],
|
||||
/// 湍流速度 (VTURB)
|
||||
pub vturb: &'a [f64],
|
||||
/// Rosseland 不透明度/密度 (ABROSD)
|
||||
pub abrosd: &'a mut [f64],
|
||||
/// 辐射通量 (FLRD)
|
||||
pub flrd: &'a [f64],
|
||||
/// 对流通量 (FLXC) - 输出
|
||||
pub flxc: &'a mut [f64],
|
||||
/// Delta 温度梯度 (DELTA) - 输出
|
||||
pub delta: &'a mut [f64],
|
||||
/// 辐射等效积分 (REINT) - 输出
|
||||
pub reint: &'a mut [f64],
|
||||
/// 辐射等效差分 (REDIF) - 输出
|
||||
pub redif: &'a mut [f64],
|
||||
// 盘模式特定
|
||||
/// 角速度参数 (THETAV)
|
||||
pub thetav: &'a [f64],
|
||||
/// 引力参数 (QGRAV)
|
||||
pub qgrav: f64,
|
||||
/// 辐射压 (PRADT) - 盘模式
|
||||
pub pradt: &'a [f64],
|
||||
}
|
||||
|
||||
/// 单深度点计算结果。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DepthResult {
|
||||
/// 深度索引 (1-based)
|
||||
pub id: usize,
|
||||
/// Rosseland 光学深度
|
||||
pub tau: f64,
|
||||
/// 温度
|
||||
pub t: f64,
|
||||
/// Delta 温度梯度
|
||||
pub delta: f64,
|
||||
/// 绝热梯度 (GRDADB)
|
||||
pub grdadb: f64,
|
||||
/// 对流/总通量比
|
||||
pub conrel: f64,
|
||||
/// 辐射/总通量比
|
||||
pub radrel: f64,
|
||||
}
|
||||
|
||||
/// CONOUT 输出结果。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConoutOutput {
|
||||
/// 各深度点计算结果
|
||||
pub depth_results: Vec<DepthResult>,
|
||||
/// 对流区起始深度 (ICBEG, 1-based)
|
||||
pub icbeg: usize,
|
||||
/// 对流区结束深度 (ICEND, 1-based)
|
||||
pub icend: usize,
|
||||
/// 更新后的 NDRE
|
||||
pub ndre: usize,
|
||||
}
|
||||
|
||||
/// CUBCON 通用块数据 (对流计算中间量)。
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CubconData {
|
||||
pub a: f64,
|
||||
pub b: f64,
|
||||
pub del: f64,
|
||||
pub grdadb: f64,
|
||||
pub delmde: f64,
|
||||
pub rho: f64,
|
||||
pub flxtot: f64,
|
||||
pub gravd: f64,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 核心计算函数
|
||||
// ============================================================================
|
||||
|
||||
/// 计算对流诊断信息 (CONOUT)。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * `params` - 输入参数
|
||||
///
|
||||
/// # 返回值
|
||||
///
|
||||
/// 返回 `ConoutOutput`,包含各深度点的诊断信息和对流区范围。
|
||||
///
|
||||
/// # Fortran 原始代码
|
||||
///
|
||||
/// ```fortran
|
||||
/// SUBROUTINE CONOUT(IMOD,IPRIN)
|
||||
/// INCLUDE 'IMPLIC.FOR'
|
||||
/// INCLUDE 'BASICS.FOR'
|
||||
/// INCLUDE 'MODELQ.FOR'
|
||||
/// INCLUDE 'ALIPAR.FOR'
|
||||
/// COMMON/CUBCON/A,B,DEL,GRDADB,DELMDE,RHO,FLXTOT,GRAVD
|
||||
/// ...
|
||||
/// END
|
||||
/// ```
|
||||
pub fn conout_pure(params: &mut ConoutParams) -> ConoutOutput {
|
||||
let nd = params.nd;
|
||||
let mut depth_results = Vec::with_capacity(nd);
|
||||
let mut icbeg: usize = 0;
|
||||
let mut icend: usize = 0;
|
||||
let mut ndre = 0;
|
||||
|
||||
// 计算总通量
|
||||
let flxto0 = SIG4P * params.teff.powi(4);
|
||||
|
||||
// 初始化变量
|
||||
let mut taum = 0.0;
|
||||
let mut grdadb = 0.0;
|
||||
|
||||
// 遍历所有深度点
|
||||
for id in 0..nd {
|
||||
let t = params.temp[id];
|
||||
let ptot = params.ptotal[id];
|
||||
let pg = params.pgs[id];
|
||||
|
||||
// 计算辐射压
|
||||
let mut prad = ptot - pg - HALF * params.dens[id] * params.vturb[id].powi(2);
|
||||
if prad < 0.0 {
|
||||
prad = 0.0;
|
||||
}
|
||||
|
||||
// 计算总通量和引力
|
||||
let mut flxtot = flxto0;
|
||||
let mut gravd = 0.0;
|
||||
if params.config.idisk == 1 {
|
||||
flxtot = flxto0 * (UN - params.thetav[id]);
|
||||
gravd = params.zd[id] * params.qgrav;
|
||||
prad = params.pradt[id];
|
||||
}
|
||||
|
||||
// 第一个深度点特殊处理
|
||||
let (delta_val, flxcnv) = if id == 0 {
|
||||
let tau = params.dm[0] * params.abrosd[0];
|
||||
params.delta[0] = 0.0;
|
||||
params.flxc[0] = 0.0;
|
||||
taum = tau;
|
||||
|
||||
depth_results.push(DepthResult {
|
||||
id: 1,
|
||||
tau,
|
||||
t,
|
||||
delta: 0.0,
|
||||
grdadb: 0.0,
|
||||
conrel: 0.0,
|
||||
radrel: if flxtot > 0.0 { params.flrd[0] / flxtot } else { 1.0 },
|
||||
});
|
||||
(0.0, 0.0)
|
||||
} else {
|
||||
// 计算光学深度和温度梯度
|
||||
let tm = params.temp[id - 1];
|
||||
let tau = taum + HALF * (params.dm[id] - params.dm[id - 1])
|
||||
* (params.abrosd[id] + params.abrosd[id - 1]);
|
||||
|
||||
let ptotm = params.ptotal[id - 1];
|
||||
let pgm = params.pgs[id - 1];
|
||||
let mut pradm = ptotm - pgm - HALF * params.dens[id - 1] * params.vturb[id - 1].powi(2);
|
||||
if params.config.idisk == 1 {
|
||||
pradm = params.pradt[id - 1];
|
||||
}
|
||||
if pradm < 0.0 {
|
||||
pradm = 0.0;
|
||||
}
|
||||
|
||||
// 计算中间点值
|
||||
let (t0, pt0, pg0, pr0, ab0, dlt) = if params.config.ilgder == 0 {
|
||||
// 线性平均
|
||||
let t0 = HALF * (t + tm);
|
||||
let pt0 = HALF * (ptot + ptotm);
|
||||
let pg0 = HALF * (pg + pgm);
|
||||
let pr0 = HALF * (prad + pradm);
|
||||
let ab0 = HALF * (params.abrosd[id] + params.abrosd[id - 1]);
|
||||
let dlt = (t - tm) / (ptot - ptotm) * pt0 / t0;
|
||||
(t0, pt0, pg0, pr0, ab0, dlt)
|
||||
} else {
|
||||
// 对数平均
|
||||
let t0 = (t * tm).sqrt();
|
||||
let pt0 = (ptot * ptotm).sqrt();
|
||||
let pg0 = (pg * pgm).sqrt();
|
||||
let pr0 = (prad * pradm).sqrt();
|
||||
let ab0 = (params.abrosd[id] * params.abrosd[id - 1]).sqrt();
|
||||
let dlt = if t > 0.0 && tm > 0.0 && ptot > 0.0 && ptotm > 0.0 {
|
||||
(t / tm).ln() / (ptot / ptotm).ln()
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
(t0, pt0, pg0, pr0, ab0, dlt)
|
||||
};
|
||||
|
||||
params.delta[id] = dlt;
|
||||
|
||||
// 计算对流通量
|
||||
let mut flxcnv = 0.0;
|
||||
let mut vcon = 0.0;
|
||||
|
||||
if params.config.idisk != 1 || id < nd - 1 {
|
||||
// 调用简化对流计算
|
||||
let convec_result = compute_convection(
|
||||
id + 1, // 1-based
|
||||
t0,
|
||||
pt0,
|
||||
pg0,
|
||||
pr0,
|
||||
ab0,
|
||||
dlt,
|
||||
¶ms.config,
|
||||
flxtot,
|
||||
gravd,
|
||||
);
|
||||
flxcnv = convec_result.0;
|
||||
vcon = convec_result.1;
|
||||
grdadb = convec_result.2;
|
||||
}
|
||||
|
||||
if params.config.hmix0 > 0.0 {
|
||||
params.flxc[id] = flxcnv;
|
||||
}
|
||||
|
||||
// 检测对流区起始
|
||||
if icbeg == 0
|
||||
&& params.flxc[id] > 0.0
|
||||
&& params.flxc[id - 1] == 0.0
|
||||
&& id > 24
|
||||
{
|
||||
icbeg = id + 1; // 1-based
|
||||
}
|
||||
if icbeg > 0 && params.flxc[id] > 0.0 {
|
||||
icend = id + 1; // 1-based
|
||||
}
|
||||
|
||||
// 计算通量比
|
||||
let (conrel, radrel) = if flxtot > 0.0 {
|
||||
(flxcnv / flxtot, params.flrd[id] / flxtot)
|
||||
} else {
|
||||
(0.0, 1.0)
|
||||
};
|
||||
|
||||
// 记录结果
|
||||
depth_results.push(DepthResult {
|
||||
id: id + 1,
|
||||
tau,
|
||||
t,
|
||||
delta: dlt,
|
||||
grdadb,
|
||||
conrel,
|
||||
radrel,
|
||||
});
|
||||
|
||||
taum = tau;
|
||||
(dlt, flxcnv)
|
||||
};
|
||||
}
|
||||
|
||||
// 根据 ICONV 调整 NDRE 和 REDIF/REINT
|
||||
if icbeg > 3 {
|
||||
if params.config.iconv == 3 {
|
||||
ndre = icbeg - 1;
|
||||
for id in 0..nd {
|
||||
if id >= ndre - 1 {
|
||||
params.reint[id] = 0.0;
|
||||
params.redif[id] = 1.0;
|
||||
} else {
|
||||
params.reint[id] = 1.0;
|
||||
params.redif[id] = 0.0;
|
||||
}
|
||||
}
|
||||
} else if params.config.iconv == 2 {
|
||||
ndre = icbeg - 1;
|
||||
for id in 0..nd {
|
||||
if id >= ndre - 1 {
|
||||
params.redif[id] = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConoutOutput {
|
||||
depth_results,
|
||||
icbeg,
|
||||
icend,
|
||||
ndre,
|
||||
}
|
||||
}
|
||||
|
||||
/// 简化的对流计算 (内部使用)。
|
||||
///
|
||||
/// 返回 (flxcnv, vcon, grdadb)
|
||||
fn compute_convection(
|
||||
_id: usize,
|
||||
t0: f64,
|
||||
pt0: f64,
|
||||
pg0: f64,
|
||||
pr0: f64,
|
||||
ab0: f64,
|
||||
dlt: f64,
|
||||
config: &ConoutConfig,
|
||||
flxtot: f64,
|
||||
gravd: f64,
|
||||
) -> (f64, f64, f64) {
|
||||
// 如果对流被禁用
|
||||
if config.hmix0 < 0.0 {
|
||||
return (0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
// 绝热梯度近似 (单原子理想气体 = 0.4)
|
||||
let grdadb = 0.4;
|
||||
|
||||
// 检查对流不稳定性
|
||||
let ddel = dlt - grdadb;
|
||||
if ddel < 0.0 {
|
||||
return (0.0, 0.0, grdadb);
|
||||
}
|
||||
|
||||
// 简化的对流计算
|
||||
let grav = if config.idisk == 1 { gravd } else { config.grav };
|
||||
if grav == 0.0 {
|
||||
return (0.0, 0.0, grdadb);
|
||||
}
|
||||
|
||||
// 粗略估计密度
|
||||
let rho = if t0 > 0.0 {
|
||||
pt0 / (t0 * 1.38e-16 * grav)
|
||||
} else {
|
||||
1e-7
|
||||
};
|
||||
|
||||
// 混合长度
|
||||
let hmix = if config.hmix0 == 0.0 { 1.0 } else { config.hmix0 };
|
||||
|
||||
// 压力标高
|
||||
let hscale = pt0 / rho / grav;
|
||||
|
||||
// 简化的对流速度 (基于混合长度理论)
|
||||
// vco ~ hmix * sqrt(aconml * pt0 / rho * dlrdlt)
|
||||
// 这里简化处理,假设 dlrdlt ~ 1.0
|
||||
let vco = hmix * (config.aconml * pt0 / rho).abs().sqrt();
|
||||
|
||||
// 简化的对流系数
|
||||
// flco ~ bconml * rho * heatcp * t0 * hmix / 4pi
|
||||
// 这里假设 heatcp ~ 1.0
|
||||
let flco = config.bconml * rho * t0 * hmix / 12.5664;
|
||||
|
||||
// 光学厚度
|
||||
let taue = hmix * ab0 * rho * hscale;
|
||||
|
||||
// 辐射耗散因子
|
||||
let fac = taue / (UN + HALF * taue * taue);
|
||||
|
||||
// 参数 B (参考 Mihalas)
|
||||
let b = 5.67e-5 * t0.powi(3) / (rho * vco) * fac * config.cconml * HALF;
|
||||
|
||||
// 参数 D
|
||||
let d = b * b / 2.0;
|
||||
let disc = d / 2.0 + ddel;
|
||||
|
||||
// 计算有效 DLT
|
||||
let dlt_eff = if disc >= 0.0 {
|
||||
let val = d + ddel - b * disc.sqrt();
|
||||
if val < 0.0 { 0.0 } else { val }
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
// 对流速度和通量
|
||||
let vconv = vco * dlt_eff.sqrt();
|
||||
let flxcnv = flco * vconv * dlt_eff;
|
||||
|
||||
(flxcnv, vconv, grdadb)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// I/O 函数
|
||||
// ============================================================================
|
||||
|
||||
/// 格式化输出诊断信息表头。
|
||||
pub fn format_conout_header() -> String {
|
||||
"\n\n ID TAUR TEMP DELTA DELTA(AD) CON/TOT RAD/TOT (C+R)/TOT\n\n".to_string()
|
||||
}
|
||||
|
||||
/// 格式化单行输出。
|
||||
pub fn format_depth_line(result: &DepthResult) -> String {
|
||||
format!(
|
||||
"{:4}{:9.2}{:9.1}{:10.2}{:10.2}{:10.2}{:10.2}{:10.2}\n",
|
||||
result.id,
|
||||
result.tau,
|
||||
result.t,
|
||||
result.delta,
|
||||
result.grdadb,
|
||||
result.conrel,
|
||||
result.radrel,
|
||||
result.conrel + result.radrel
|
||||
)
|
||||
}
|
||||
|
||||
/// 格式化对流区信息。
|
||||
pub fn format_convective_zone(icbeg: usize, icend: usize) -> String {
|
||||
format!(
|
||||
"\n convective zone between depths (inclusive) {:4}{:4}\n",
|
||||
icbeg, icend
|
||||
)
|
||||
}
|
||||
|
||||
/// 格式化 NDRE 重置信息。
|
||||
pub fn format_ndre_reset(ndre: usize) -> String {
|
||||
format!(
|
||||
"\n\n NDRE IS RESET IN CONOUT DUE TO THE EXISTENCE OF CONVECTIVE ZONE\n NDRE= {:3}\n",
|
||||
ndre
|
||||
)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 测试
|
||||
// ============================================================================
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// 测试用的参数构建器
|
||||
struct TestParamsBuilder {
|
||||
nd: usize,
|
||||
imod: i32,
|
||||
iprin: i32,
|
||||
teff: f64,
|
||||
config: ConoutConfig,
|
||||
}
|
||||
|
||||
impl TestParamsBuilder {
|
||||
fn new(nd: usize) -> Self {
|
||||
Self {
|
||||
nd,
|
||||
imod: 0,
|
||||
iprin: 1,
|
||||
teff: 35000.0,
|
||||
config: ConoutConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn config(mut self, config: ConoutConfig) -> Self {
|
||||
self.config = config;
|
||||
self
|
||||
}
|
||||
|
||||
fn build(self) -> ConoutParams<'static> {
|
||||
let nd = self.nd;
|
||||
let mut temp = vec![0.0; nd];
|
||||
let mut elec = vec![0.0; nd];
|
||||
let mut dens = vec![0.0; nd];
|
||||
let mut wmm = vec![0.0; nd];
|
||||
let mut dm = vec![0.0; nd];
|
||||
let mut zd = vec![0.0; nd];
|
||||
let mut ptotal = vec![0.0; nd];
|
||||
let mut pgs = vec![0.0; nd];
|
||||
let mut vturb = vec![0.0; nd];
|
||||
let mut abrosd = vec![0.0; nd];
|
||||
let mut flrd = vec![0.0; nd];
|
||||
let mut flxc = vec![0.0; nd];
|
||||
let mut delta = vec![0.0; nd];
|
||||
let mut reint = vec![0.0; nd];
|
||||
let mut redif = vec![0.0; nd];
|
||||
let mut thetav = vec![0.0; nd];
|
||||
let mut pradt = vec![0.0; nd];
|
||||
|
||||
for i in 0..nd {
|
||||
temp[i] = 10000.0 - i as f64 * 100.0;
|
||||
elec[i] = 1e12;
|
||||
dens[i] = 1e-7;
|
||||
wmm[i] = 1.0;
|
||||
dm[i] = 1e-2 * (i + 1) as f64;
|
||||
zd[i] = 1e10 * (i + 1) as f64;
|
||||
ptotal[i] = 1e5;
|
||||
pgs[i] = 1e5;
|
||||
vturb[i] = 0.0;
|
||||
abrosd[i] = 0.1;
|
||||
flrd[i] = 1e10;
|
||||
flxc[i] = 0.0;
|
||||
delta[i] = 0.0;
|
||||
reint[i] = 1.0;
|
||||
redif[i] = 0.0;
|
||||
thetav[i] = 0.0;
|
||||
pradt[i] = 0.0;
|
||||
}
|
||||
|
||||
// 使用 Box::leak 来创建 'static 引用
|
||||
ConoutParams {
|
||||
imod: self.imod,
|
||||
iprin: self.iprin,
|
||||
nd,
|
||||
teff: self.teff,
|
||||
config: self.config,
|
||||
temp: Box::leak(temp.into_boxed_slice()),
|
||||
elec: Box::leak(elec.into_boxed_slice()),
|
||||
dens: Box::leak(dens.into_boxed_slice()),
|
||||
wmm: Box::leak(wmm.into_boxed_slice()),
|
||||
dm: Box::leak(dm.into_boxed_slice()),
|
||||
zd: Box::leak(zd.into_boxed_slice()),
|
||||
ptotal: Box::leak(ptotal.into_boxed_slice()),
|
||||
pgs: Box::leak(pgs.into_boxed_slice()),
|
||||
vturb: Box::leak(vturb.into_boxed_slice()),
|
||||
abrosd: Box::leak(abrosd.into_boxed_slice()),
|
||||
flrd: Box::leak(flrd.into_boxed_slice()),
|
||||
flxc: Box::leak(flxc.into_boxed_slice()),
|
||||
delta: Box::leak(delta.into_boxed_slice()),
|
||||
reint: Box::leak(reint.into_boxed_slice()),
|
||||
redif: Box::leak(redif.into_boxed_slice()),
|
||||
thetav: Box::leak(thetav.into_boxed_slice()),
|
||||
qgrav: 1e-10,
|
||||
pradt: Box::leak(pradt.into_boxed_slice()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conout_basic() {
|
||||
let mut params = TestParamsBuilder::new(50).build();
|
||||
let output = conout_pure(&mut params);
|
||||
|
||||
// 验证基本输出
|
||||
assert_eq!(output.depth_results.len(), 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_output() {
|
||||
let header = format_conout_header();
|
||||
assert!(header.contains("TAUR"));
|
||||
assert!(header.contains("TEMP"));
|
||||
|
||||
let result = DepthResult {
|
||||
id: 1,
|
||||
tau: 1e-4,
|
||||
t: 10000.0,
|
||||
delta: 0.3,
|
||||
grdadb: 0.4,
|
||||
conrel: 0.1,
|
||||
radrel: 0.9,
|
||||
};
|
||||
let line = format_depth_line(&result);
|
||||
assert!(line.contains("1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conout_no_convection() {
|
||||
let config = ConoutConfig {
|
||||
hmix0: -1.0, // 禁用对流
|
||||
..Default::default()
|
||||
};
|
||||
let mut params = TestParamsBuilder::new(50).config(config).build();
|
||||
let output = conout_pure(&mut params);
|
||||
|
||||
// 禁用对流时不应该有对流区
|
||||
assert_eq!(output.icbeg, 0);
|
||||
assert_eq!(output.icend, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conout_iconv_mode_2() {
|
||||
let config = ConoutConfig {
|
||||
iconv: 2,
|
||||
hmix0: 1.0,
|
||||
..Default::default()
|
||||
};
|
||||
let mut params = TestParamsBuilder::new(50).config(config).build();
|
||||
let output = conout_pure(&mut params);
|
||||
|
||||
// 验证基本功能
|
||||
assert_eq!(output.depth_results.len(), 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conout_iconv_mode_3() {
|
||||
let config = ConoutConfig {
|
||||
iconv: 3,
|
||||
hmix0: 1.0,
|
||||
..Default::default()
|
||||
};
|
||||
let mut params = TestParamsBuilder::new(50).config(config).build();
|
||||
let output = conout_pure(&mut params);
|
||||
|
||||
// 验证基本功能
|
||||
assert_eq!(output.depth_results.len(), 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conout_disk_mode() {
|
||||
let config = ConoutConfig {
|
||||
idisk: 1,
|
||||
hmix0: 1.0,
|
||||
..Default::default()
|
||||
};
|
||||
let mut params = TestParamsBuilder::new(50).config(config).build();
|
||||
let output = conout_pure(&mut params);
|
||||
|
||||
// 盘模式应该正常工作
|
||||
assert_eq!(output.depth_results.len(), 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_convection_disabled() {
|
||||
let config = ConoutConfig {
|
||||
hmix0: -1.0,
|
||||
..Default::default()
|
||||
};
|
||||
let (flxcnv, vconv, _) = compute_convection(
|
||||
1, 10000.0, 1e5, 1e5, 0.0, 0.1, 0.3, &config, 1e10, 0.0
|
||||
);
|
||||
assert_eq!(flxcnv, 0.0);
|
||||
assert_eq!(vconv, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_convection_stable() {
|
||||
let config = ConoutConfig::default();
|
||||
let (flxcnv, vconv, grdadb) = compute_convection(
|
||||
1, 10000.0, 1e5, 1e5, 0.0, 0.1, 0.1, &config, 1e10, 0.0
|
||||
);
|
||||
// dlt < grdadb (0.1 < 0.4),稳定,无对流
|
||||
assert_eq!(flxcnv, 0.0);
|
||||
assert_eq!(vconv, 0.0);
|
||||
assert!((grdadb - 0.4).abs() < 1e-10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_convective_zone() {
|
||||
let msg = format_convective_zone(10, 40);
|
||||
assert!(msg.contains("10"));
|
||||
assert!(msg.contains("40"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_ndre_reset() {
|
||||
let msg = format_ndre_reset(15);
|
||||
assert!(msg.contains("15"));
|
||||
assert!(msg.contains("NDRE"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user