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,962 @@
|
||||
//! 对流区温度修正。
|
||||
//!
|
||||
//! 重构自 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user