//! 对流区温度修正。 //! //! 重构自 TLUSTY `conref.f` //! //! # 功能 //! //! 对对流区进行温度修正: //! - 计算各深度点的温度梯度 DELTA //! - 使用混合长度理论计算对流通量 //! - 迭代修正温度以满足能量守恒 //! - 处理辐射/对流通量分配 use crate::state::constants::{HALF, SIG4P, UN}; // ============================================================================ // 常量 // ============================================================================ /// 2/3 (用于幂次计算) const TWO_THR: f64 = 0.6666666666666667; /// 1/3 (用于幂次计算) const ONE_THR: f64 = 0.3333333333333333; // ============================================================================ // 配置结构体 // ============================================================================ /// CONREF 配置参数。 #[derive(Debug, Clone)] pub struct ConrefConfig { /// 混合长度参数 (HMIX0) pub hmix0: f64, /// 对流模式 (ICONV) pub iconv: i32, /// 深度标志 (INDL) pub indl: i32, /// 对流通量限制 (CRFLIM) pub crflim: f64, /// 深对流模式 (IDEEPC) pub ideepc: i32, /// 对流区间隙允许 (NDCGAP) pub ndcgap: i32, /// 最小对流深度 (IDCONZ) pub idconz: i32, /// 对数梯度标志 (ILGDER) pub ilgder: i32, /// 盘模式标志 (IDISK) pub idisk: i32, /// 不透明度表标志 (IOPTAB) pub ioptab: i32, /// Rybicki 标志 (IFRYB) pub ifryb: i32, /// 迭代计数 (ITER) pub iter: i32, /// IMUCON 迭代阈值 pub imucon: i32, /// 打印标志 (IPCONF) pub ipconf: i32, /// 表面重力 (GRAV) pub grav: f64, /// 盘引力参数 (QGRAV) pub qgrav: f64, /// 对流常数 A (ACONML) pub aconml: f64, /// 对流常数 B (BCONML) pub bconml: f64, /// 对流常数 C (CCONML) pub cconml: f64, } impl Default for ConrefConfig { fn default() -> Self { Self { hmix0: 1.0, iconv: 0, indl: 0, crflim: 0.1, ideepc: 0, ndcgap: 2, idconz: 25, ilgder: 0, idisk: 0, ioptab: 0, ifryb: 0, iter: 0, imucon: 9999, ipconf: 0, grav: 1e4, qgrav: 0.0, aconml: 1.0, bconml: 1.0, cconml: 1.0, } } } // ============================================================================ // 输入/输出结构体 // ============================================================================ /// CONREF 输入参数。 pub struct ConrefParams<'a> { /// 深度点数 (ND) pub nd: usize, /// 有效温度 (TEFF) pub teff: f64, /// 配置 pub config: ConrefConfig, // 深度相关数组 (nd) /// 温度 (TEMP) pub temp: &'a mut [f64], /// 总压力 (PTOTAL) pub ptotal: &'a [f64], /// 气压 (PGS) pub pgs: &'a [f64], /// 总粒子密度 (DENS) pub dens: &'a [f64], /// 湍流速度 (VTURB) pub vturb: &'a [f64], /// Rosseland 不透明度 (ABROSD) pub abrosd: &'a [f64], /// 辐射通量 (FLRD) pub flrd: &'a [f64], /// 对流通量 (FLXC) - 输出 pub flxc: &'a mut [f64], /// Delta 温度梯度 (DELTA) - 输出 pub delta: &'a mut [f64], /// 分子质量 (WMM) pub wmm: &'a [f64], /// 电子密度 (ELEC) pub elec: &'a mut [f64], // 盘模式特定 /// 角速度参数 (THETAV) pub thetav: &'a [f64], /// 几何深度 (ZD) pub zd: &'a [f64], } /// CUBCON 通用块数据 (对流计算中间量)。 #[derive(Debug, Clone, Default)] pub struct CubconData { /// 对流常数 A pub a: f64, /// 对流常数 B (BCNV) pub b: f64, /// 有效梯度差 pub del: f64, /// 绝热梯度 (GRDADB) pub grdadb: f64, /// 中间变量 pub delmde: f64, /// 密度 pub rho: f64, /// 总通量 pub flxtot: f64, /// 引力加速度 pub gravd: f64, } /// CONREF 输出结果。 #[derive(Debug, Clone)] pub struct ConrefOutput { /// 对流区起始深度 (ICBEG, 1-based) pub icbeg: usize, /// 对流区结束深度 (ICEND, 1-based) pub icend: usize, /// 是否进行了修正 pub modified: bool, } // ============================================================================ // 核心计算函数 // ============================================================================ /// 对流区温度修正 (CONREF)。 /// /// # 参数 /// /// * `params` - 输入参数 /// /// # 返回值 /// /// 返回 `ConrefOutput`,包含对流区范围和修正状态。 /// /// # Fortran 原始代码 /// /// ```fortran /// SUBROUTINE CONREF /// INCLUDE 'IMPLIC.FOR' /// INCLUDE 'BASICS.FOR' /// INCLUDE 'MODELQ.FOR' /// INCLUDE 'ARRAY1.FOR' /// COMMON/CUBCON/ACNV,BCNV,DEL,GRDADB,DELMDE,RHO,FLXTOT,GRAVD /// ... /// END /// ``` pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput { let nd = params.nd; let config = ¶ms.config.clone(); // 检查是否需要处理 if config.iconv <= 0 && config.indl == 0 { return ConrefOutput { icbeg: 0, icend: 0, modified: false, }; } // 计算表面总通量 let flxto0 = SIG4P * params.teff.powi(4); let dltnd = params.delta[nd - 1]; // 临时数组 let mut idcon = vec![0i32; nd]; let mut flxtt = vec![0.0f64; nd]; let mut delta0 = vec![0.0f64; nd]; // 保存初始 delta for id in 0..nd { delta0[id] = params.delta[id]; } // 第一遍:计算对流梯度 let mut icbeg: usize = 0; let mut icend: usize = 0; let mut cubcon = CubconData::default(); for id in 1..nd { let t = params.temp[id]; let p = params.ptotal[id]; let pg = params.pgs[id]; let prad = p - pg - HALF * params.dens[id] * params.vturb[id].powi(2); let tm = params.temp[id - 1]; let pm = params.ptotal[id - 1]; let pgm = params.pgs[id - 1]; let pradm = pm - pgm - HALF * params.dens[id - 1] * params.vturb[id - 1].powi(2); // 计算中间点值 let (t0, p0, pg0, pr0, ab0, dlt) = if config.ilgder == 0 { // 线性平均 let t0 = HALF * (t + tm); let p0 = HALF * (p + pm); let pg0 = HALF * (pg + pgm); let pr0 = HALF * (prad + pradm); let ab0 = HALF * (params.abrosd[id] + params.abrosd[id - 1]); let dlt = if (p - pm).abs() > 1e-30 { (t - tm) / (p - pm) * p0 / t0 } else { 0.0 }; (t0, p0, pg0, pr0, ab0, dlt) } else { // 对数平均 let t0 = (t * tm).sqrt(); let p0 = (p * pm).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 && p > 0.0 && pm > 0.0 { (t / tm).ln() / (p / pm).ln() } else { 0.0 }; (t0, p0, pg0, pr0, ab0, dlt) }; params.delta[id] = dlt; // 计算总通量和引力 if config.idisk == 0 { cubcon.flxtot = flxto0; cubcon.gravd = config.grav; } else { cubcon.flxtot = flxto0 * (UN - params.thetav[id]); cubcon.gravd = config.qgrav * params.zd[id]; } flxtt[id] = cubcon.flxtot; // 简化的对流计算 let (flxcnv, _, grdadb) = compute_convection_simple( id + 1, t0, p0, pg0, pr0, ab0, dlt, config, cubcon.flxtot, cubcon.gravd, ); params.flxc[id] = flxcnv; cubcon.grdadb = grdadb; // 标记对流点 idcon[id] = if flxcnv > 0.0 { 1 } else { 0 }; // 检测对流区起始 if icbeg == 0 && params.flxc[id] > 0.0 && params.flxc[id - 1] == 0.0 && id > config.idconz as usize { icbeg = id + 1; // 1-based } if icbeg > 0 && params.flxc[id] > 0.0 { icend = id + 1; // 1-based } } // 修正算法:处理对流区中的间隙 let mut icbeg0 = icbeg; if config.ideepc > 0 { if icend == nd - 1 && config.ideepc == 2 { icend = nd; } // 从 icend 向前搜索对流区起始 let mut icbegd = icend; for id in ((config.idconz + 1) as usize..=icend).rev() { let idx = id - 1; // 转换为 0-indexed if idcon[idx] > 0 { icbegd = id; } else { // 检查是否有间隙 let mut igap = 0; let start = (idx as i32 - config.ndcgap).max(0) as usize; for idd in start..idx { if idcon[idd] > 0 { igap = 1; break; } } if igap > 0 { icbegd = id; } else { break; } } } icbeg0 = icbegd; } if config.ideepc == 3 { icend = nd; } // 如果没有对流区,直接返回 if icbeg0 == 0 || icend == 0 { return ConrefOutput { icbeg: 0, icend: 0, modified: false, }; } // 对流区温度修正 let mut modified = false; // 检查对流区起始点附近的温度振荡 if icbeg0 >= 3 { let t1 = params.temp[icbeg0 - 2]; let t2 = params.temp[icbeg0 - 1]; let t3 = params.temp[icbeg0]; if t2 < t1 && t2 < t3 { params.temp[icbeg0 - 1] = HALF * (t1 + t3); modified = true; } } // 对流区迭代修正 for id in icbeg0..=icend { let idx = id - 1; // 0-indexed let t = params.temp[idx]; let p = params.ptotal[idx]; let pg = params.pgs[idx]; let prad = p - pg - HALF * params.dens[idx] * params.vturb[idx].powi(2); let tm = params.temp[idx - 1]; let pm = params.ptotal[idx - 1]; let pgm = params.pgs[idx - 1]; let pradm = pm - pgm - HALF * params.dens[idx - 1] * params.vturb[idx - 1].powi(2); // 计算中间点值 let (t0, p0, pg0, pr0, ab0, ppd) = if config.ilgder == 0 { let t0 = HALF * (t + tm); let p0 = HALF * (p + pm); let pg0 = HALF * (pg + pgm); let pr0 = HALF * (prad + pradm); let ab0 = HALF * (params.abrosd[idx] + params.abrosd[idx - 1]); let ppd = (p + pm) / (p - pm); (t0, p0, pg0, pr0, ab0, ppd) } else { let t0 = (t * tm).sqrt(); let p0 = (p * pm).sqrt(); let pg0 = (pg * pgm).sqrt(); let pr0 = (prad * pradm).sqrt(); let ab0 = (params.abrosd[idx] * params.abrosd[idx - 1]).sqrt(); let ppd = 0.0; // 对数模式下不使用 (t0, p0, pg0, pr0, ab0, ppd) }; // 计算总通量 if config.idisk == 0 { cubcon.flxtot = flxto0; cubcon.gravd = config.grav; } else { cubcon.flxtot = flxto0 * (UN - params.thetav[idx]); cubcon.gravd = config.qgrav * params.zd[idx]; } // 所需对流通量 let mut fcnv = cubcon.flxtot - params.flrd[idx]; if fcnv <= 0.0 { fcnv = cubcon.flxtot * (UN - params.flrd[idx] / params.flrd[1]); } if fcnv < 0.0 { fcnv = 0.001 * cubcon.flxtot; } // 温度迭代 let mut t_iter = t; let mut dlt = params.delta[idx]; for _iic in 0..10 { let (t0_iter, dlt_iter) = if config.ilgder == 0 { let t0_iter = HALF * (t_iter + tm); let dlt_iter = (t_iter - tm) / (p - pm) * p0 / t0_iter; (t0_iter, dlt_iter) } else { let t0_iter = (t_iter * tm).sqrt(); let dlt_iter = (t_iter / tm).ln() / (p / pm).ln(); (t0_iter, dlt_iter) }; dlt = dlt_iter; params.delta[idx] = dlt; // 如果对流显著,计算修正 if params.flxc[idx] / cubcon.flxtot > config.crflim { let (_, fc0, grdadb) = compute_convc1_simple( idx + 1, t0_iter, p0, pg0, pr0, ab0, dlt, config, cubcon.flxtot, cubcon.gravd, ); cubcon.grdadb = grdadb; if fc0 > 0.0 { let deltae = (fcnv / fc0).powf(TWO_THR); let deltaa = deltae + cubcon.b * deltae.sqrt(); dlt = deltaa + cubcon.grdadb; } } let told = t_iter; if config.ilgder == 0 { let dlp = dlt / ppd; t_iter = tm * (UN + dlp) / (UN - dlp); } else { t_iter = tm * (p / pm).powf(dlt); } let dtt = (t_iter - told) / told; if dtt.abs() < 1e-9 { break; } } if (t_iter - params.temp[idx]).abs() > 1e-10 { modified = true; } params.delta[idx] = dlt; params.temp[idx] = t_iter; } // 高级修正过程 (iter >= imucon) if config.iter >= config.imucon { // 新的精细修正 for id in icbeg0..=nd { let idx = id - 1; let t = params.temp[idx]; let p = params.ptotal[idx]; let tm = params.temp[idx - 1]; let pm = params.ptotal[idx - 1]; let pg = params.pgs[idx]; let pgm = params.pgs[idx - 1]; let pg0 = (pg * pgm).sqrt(); let prad = p - pg - HALF * params.dens[idx] * params.vturb[idx].powi(2); let pradm = pm - pgm - HALF * params.dens[idx - 1] * params.vturb[idx - 1].powi(2); let pr0 = (prad * pradm).sqrt(); let t0 = (t * tm).sqrt(); let p0 = (p * pm).sqrt(); let ab0 = (params.abrosd[idx] * params.abrosd[idx - 1]).sqrt(); let dlt = (t / tm).ln() / (p / pm).ln(); let (_, fc0, grdadb) = compute_convc1_simple( idx + 1, t0, p0, pg0, pr0, ab0, dlt, config, flxtt[idx], cubcon.gravd, ); let alp = params.flrd[idx].min(flxtt[idx]) / t0.powi(4) / dlt; let fcnv = flxtt[idx] - params.flrd[idx]; if fcnv <= 0.0 || fc0 <= 0.0 { // 辐射主导 if flxtt[idx] < params.flrd[idx] { let alp_new = flxtt[idx] / params.flrd[idx] * t0.powi(4) * delta0[idx]; let mut t_iter = t; for _ in 0..20 { let t1 = UN / t_iter; let dltp = t1 / (p / pm).ln(); let dele = alp_new - t_iter.powi(4) * dlt; let delep = -t_iter.powi(4) * dlt * (2.0 * t1 + dltp / dlt); let dt = -dele / delep * t1; if dt.abs() < 1e-6 { break; } t_iter = t_iter * (UN + dt); } params.temp[idx] = t_iter; params.delta[idx] = (t_iter / tm).ln() / (p / pm).ln(); modified = true; } } else { // 对流主导 let bet = cubcon.b / t0.powi(3); let deltae = (fcnv / fc0).powf(TWO_THR); let deltaa = deltae + cubcon.b * deltae.sqrt(); let mut dlt_new = deltaa + grdadb; let mut t_iter = tm * (p / pm).powf(dlt_new); // Newton 迭代 for _ in 0..20 { let t1 = UN / t_iter; let t0_new = (t_iter * tm).sqrt(); let dlt_new = (t_iter / tm).ln() / (p / pm).ln(); let dele = (flxtt[idx] - alp * t0_new.powi(4) * dlt_new) / fc0; let dele3 = dele.powf(ONE_THR); let dltp = t1 / (p / pm).ln(); let delep = -alp * t0_new.powi(4) * dlt_new / fc0 * (2.0 * t1 + dltp / dlt_new); let vl = dlt_new - grdadb - dele3 * (dele3 + bet * t0_new.powi(3)); let bb = dltp - TWO_THR * delep / dele3 - bet * t0_new.powi(3) * dele3 * (1.5 * t1 + ONE_THR * delep / dele); let dt = -vl / bb * t1; if dt.abs() < 1e-9 { break; } t_iter = t_iter * (UN + dt); } params.delta[idx] = (t_iter / tm).ln() / (p / pm).ln(); params.temp[idx] = t_iter; modified = true; } } } ConrefOutput { icbeg: icbeg0, icend: icend, modified, } } /// 简化的对流计算 (内部使用)。 /// /// 返回 (flxcnv, vcon, grdadb) fn compute_convection_simple( _id: usize, t0: f64, pt0: f64, pg0: f64, _pr0: f64, ab0: f64, dlt: f64, config: &ConrefConfig, 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; // 对流速度 let vco = hmix * (config.aconml * pt0 / rho).abs().sqrt(); // 对流系数 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) } /// 简化的 CONVC1 计算 (返回 fc0)。 /// /// 返回 (flxcnv, fc0, grdadb) fn compute_convc1_simple( _id: usize, t0: f64, pt0: f64, pg0: f64, _pr0: f64, ab0: f64, dlt: f64, config: &ConrefConfig, flxtot: f64, gravd: f64, ) -> (f64, f64, f64) { // 如果对流被禁用 if config.hmix0 < 0.0 { return (0.0, 0.0, 0.0); } // 绝热梯度近似 let grdadb = 0.4; // 计算引力 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; // 对流速度 let vco = hmix * (config.aconml * pt0 / rho).abs().sqrt(); // 对流系数 let flco = config.bconml * rho * t0 * hmix / 12.5664; // FC0 = FLCO * VCO let fc0 = flco * vco; // 检查对流不稳定性 let ddel = dlt - grdadb; if ddel < 0.0 { return (0.0, fc0, grdadb); } // 光学厚度 let taue = hmix * ab0 * rho * hscale; // 辐射耗散因子 let fac = taue / (UN + HALF * taue * taue); // 参数 B 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, fc0, grdadb) } // ============================================================================ // I/O 函数 // ============================================================================ /// 格式化对流区信息。 pub fn format_convective_refinement(icbeg: usize, icend: usize) -> String { format!( "\n convective refinement between depths {:4}{:4}\n", icbeg, icend ) } // ============================================================================ // 测试 // ============================================================================ #[cfg(test)] mod tests { use super::*; /// 测试用的参数构建器 struct TestParamsBuilder { nd: usize, teff: f64, config: ConrefConfig, } impl TestParamsBuilder { fn new(nd: usize) -> Self { Self { nd, teff: 35000.0, config: ConrefConfig::default(), } } fn config(mut self, config: ConrefConfig) -> Self { self.config = config; self } fn build(self) -> ConrefParams<'static> { let nd = self.nd; // 创建拥有所有权的向量 let mut temp = vec![0.0; nd]; let mut ptotal = vec![0.0; nd]; let mut pgs = vec![0.0; nd]; let mut dens = 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 wmm = vec![0.0; nd]; let mut elec = vec![0.0; nd]; let mut thetav = vec![0.0; nd]; let mut zd = vec![0.0; nd]; // 填充测试数据 for i in 0..nd { temp[i] = 10000.0 + i as f64 * 100.0; ptotal[i] = 1e5 + i as f64 * 1e4; pgs[i] = ptotal[i] * 0.99; dens[i] = 1e-7; vturb[i] = 0.0; abrosd[i] = 0.1; flrd[i] = 1e10; flxc[i] = 0.0; delta[i] = 0.0; wmm[i] = 1.0; elec[i] = 1e12; thetav[i] = 0.0; zd[i] = 1e10 * (i + 1) as f64; } // 使用 Box::leak 创建 'static 引用 ConrefParams { nd, teff: self.teff, config: self.config, temp: Box::leak(temp.into_boxed_slice()), ptotal: Box::leak(ptotal.into_boxed_slice()), pgs: Box::leak(pgs.into_boxed_slice()), dens: Box::leak(dens.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()), wmm: Box::leak(wmm.into_boxed_slice()), elec: Box::leak(elec.into_boxed_slice()), thetav: Box::leak(thetav.into_boxed_slice()), zd: Box::leak(zd.into_boxed_slice()), } } } #[test] fn test_conref_no_convection() { let config = ConrefConfig { iconv: 0, indl: 0, ..Default::default() }; let mut params = TestParamsBuilder::new(50).config(config).build(); let output = conref_pure(&mut params); // iconv <= 0 且 indl == 0 时应该直接返回 assert_eq!(output.icbeg, 0); assert_eq!(output.icend, 0); assert!(!output.modified); } #[test] fn test_conref_disabled_hmix() { let config = ConrefConfig { hmix0: -1.0, iconv: 1, ..Default::default() }; let mut params = TestParamsBuilder::new(50).config(config).build(); let output = conref_pure(&mut params); // 对流被禁用时不应该有对流区 assert_eq!(output.icbeg, 0); } #[test] fn test_conref_basic() { let config = ConrefConfig { iconv: 1, hmix0: 1.0, ..Default::default() }; let mut params = TestParamsBuilder::new(50).config(config).build(); let output = conref_pure(&mut params); // 验证基本功能 // 由于简化实现,结果可能是没有对流区或有限对流 assert!(output.icbeg <= 50); assert!(output.icend <= 50); } #[test] fn test_compute_convection_simple_stable() { let config = ConrefConfig::default(); // dlt = 0.1 < grdadb = 0.4,稳定,无对流 let (flxcnv, vconv, grdadb) = compute_convection_simple( 1, 10000.0, 1e5, 1e5, 0.0, 0.1, 0.1, &config, 1e10, 0.0 ); assert_eq!(flxcnv, 0.0); assert_eq!(vconv, 0.0); assert!((grdadb - 0.4).abs() < 1e-10); } #[test] fn test_compute_convection_simple_disabled() { let config = ConrefConfig { hmix0: -1.0, ..Default::default() }; let (flxcnv, vconv, grdadb) = compute_convection_simple( 1, 10000.0, 1e5, 1e5, 0.0, 0.1, 0.5, &config, 1e10, 0.0 ); assert_eq!(flxcnv, 0.0); assert_eq!(vconv, 0.0); assert_eq!(grdadb, 0.0); } #[test] fn test_compute_convc1_simple() { let config = ConrefConfig::default(); let (flxcnv, fc0, grdadb) = compute_convc1_simple( 1, 10000.0, 1e5, 1e5, 0.0, 0.1, 0.1, &config, 1e10, 0.0 ); // fc0 应该被计算 assert!(fc0 >= 0.0); assert!((grdadb - 0.4).abs() < 1e-10); } #[test] fn test_format_convective_refinement() { let msg = format_convective_refinement(10, 40); assert!(msg.contains("10")); assert!(msg.contains("40")); } #[test] fn test_cubcon_data() { let data = CubconData::default(); assert_eq!(data.a, 0.0); assert_eq!(data.b, 0.0); assert_eq!(data.grdadb, 0.0); } #[test] fn test_conref_disk_mode() { let config = ConrefConfig { idisk: 1, iconv: 1, hmix0: 1.0, qgrav: 1e-10, ..Default::default() }; let mut params = TestParamsBuilder::new(50).config(config).build(); let output = conref_pure(&mut params); // 盘模式应该正常工作 assert!(output.icbeg <= 50); } #[test] fn test_conref_with_ilgder() { let config = ConrefConfig { ilgder: 1, iconv: 1, hmix0: 1.0, ..Default::default() }; let mut params = TestParamsBuilder::new(50).config(config).build(); let output = conref_pure(&mut params); // 对数平均模式应该正常工作 assert!(output.icbeg <= 50); } }