This commit is contained in:
Asfmq 2026-04-01 19:11:27 +08:00
parent 418e487c2f
commit cb218e0d5b
4 changed files with 199 additions and 96 deletions

View File

@ -232,10 +232,8 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
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];
}
// Fortran: delta0(mdepth) 未初始化(-fno-automatic 下全为 0.0
// Rust: vec![0.0; nd] 已初始化为 0.0,无需额外赋值
// 第一遍:计算对流梯度
let mut icbeg: usize = 0;
@ -362,7 +360,7 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
}
// Fortran: icbegp=icbeg0; icendp=icend — 保存状态用于下次调用
let icbegp_save = icbeg0;
let icendp_save = icend;
let mut icendp_save = icend;
// 如果没有对流区,直接返回
if icbeg0 == 0 || icend == 0 {
@ -524,6 +522,7 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
// Fortran: icbeg0=icbeg; icend=nd; icendp=nd
let imucon_icbeg0 = icbeg;
let imucon_icend = nd;
icendp_save = nd; // Fortran: icendp=nd (overwrites earlier icendp=icend)
// FORMAT 674: modification with imucon
eprintln!("\n modification with imucon: icbeg0,icend{:4}{:4}{:4}", config.imucon, imucon_icbeg0, imucon_icend);
@ -559,51 +558,71 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
cubcon.b = bcnv;
cubcon.grdadb = grdadb;
let alp = params.flrd[idx].min(flxtt[idx]) / t0.powi(4) / dlt;
let mut 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 {
// 辐射主导 — Fortran label 200-220
if flxtt[idx] < params.flrd[idx] {
let mut alp_val = flxtt[idx] / params.flrd[idx] * t0.powi(4) * delta0[idx];
let mut t_iter = t;
let mut t0_i = t0;
let mut dlt_i = dlt;
// Fortran: 同一作用域的 t, t0, dlt 在 Newton 循环中被修改
let mut t_loc = t;
let mut t0_loc = t0;
let mut dlt_loc = dlt;
let mut last_dele = 0.0f64;
for iter_idx in 0..20 {
if flxtt[idx] < params.flrd[idx] {
// Fortran line 272: alp=flxtt(id)/flrd(id)*t0**4*delta0(id)
alp = flxtt[idx] / params.flrd[idx] * t0_loc.powi(4) * delta0[idx];
let mut t_iter = t_loc;
let mut t0_i = t0_loc;
let mut dlt_i = dlt_loc;
// Fortran label 210: Newton iteration (itrnrc=1..21)
for iter_idx in 0..21 {
let t1 = UN / t_iter;
let dltp = t1 / (p / pm).ln();
// Fortran: dele=alp-t0**4*dlt (使用 t0 和 dlt 而非 t_iter)
let dele = alp_val - t0_i.powi(4) * dlt_i;
let dele = alp - t0_i.powi(4) * dlt_i;
last_dele = dele;
let delep = -t0_i.powi(4) * dlt_i * (2.0 * t1 + dltp / dlt_i);
let dt = -dele / delep * t1;
// Fortran: t=t*(un+dt) BEFORE convergence check
t_iter = t_iter * (UN + dt);
// FORMAT 645: Newton iteration progress
eprintln!("{:4}{:4}{:11.3e}{:8.2}", id, iter_idx + 1, dt, t_iter);
if dt.abs() < 1e-6 {
if dt.abs() < 1e-6 || iter_idx >= 20 {
// Fortran: exit with updated t but old t0, dlt
break;
}
t_iter = t_iter * (UN + dt);
// Fortran: 更新 t0 和 dlt 用于下一次迭代
t0_i = (t_iter * tm).sqrt();
dlt_i = (t_iter / tm).ln() / (p / pm).ln();
}
// Fortran: alp=flrd(id)/t0**4/dlt
alp_val = params.flrd[idx] / t0_i.powi(4) / dlt_i;
params.delta[idx] = dlt_i;
params.temp[idx] = t_iter;
modified = true;
// Fortran line 289: alp=flrd(id)/t0**4/dlt (old t0, dlt)
alp = params.flrd[idx] / t0_i.powi(4) / dlt_i;
// Fortran label 230: temp(id)=t (new), delta(id)=dlt (old)
t_loc = t_iter; // new t
t0_loc = t0_i; // old t0
dlt_loc = dlt_i; // old dlt
}
// Fortran label 230: flr=alp*t0**4*dlt
let dlt_val = params.delta[idx];
let t0_diag = (params.temp[idx] * tm).sqrt();
let flr_diag = alp * t0_diag.powi(4) * dlt_val;
if dlt_val < cubcon.grdadb {
eprintln!("{:4}{:4}{:8.1}{:12.4e}{:12.4e}{:12.4e}{:12.4e}",
id, 0, params.temp[idx], dlt_val, cubcon.grdadb,
params.flrd[idx] / flxtt[idx], flr_diag / flxtt[idx]);
// Fortran label 230: delta(id)=dlt, temp(id)=t, flr=alp*t0**4*dlt
params.delta[idx] = dlt_loc;
params.temp[idx] = t_loc;
modified = true;
{
// Fortran label 230: flr=alp*t0**4*dlt (old t0, old dlt, new alp)
let flr = alp * t0_loc.powi(4) * dlt_loc;
if dlt_loc >= cubcon.grdadb {
// Fortran: flc=fc0*dele (dele from Newton iteration)
let flc = fc0 * last_dele;
eprintln!("{:4}{:4}{:8.1}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}",
id, 0, params.temp[idx], dlt_loc, cubcon.grdadb,
params.flrd[idx] / flxtt[idx], flr / flxtt[idx], flc / flxtt[idx],
0.0_f64, (flr + 0.0_f64) / flxtt[idx]);
} else {
eprintln!("{:4}{:4}{:8.1}{:12.4e}{:12.4e}{:12.4e}{:12.4e}",
id, 0, params.temp[idx], dlt_loc, cubcon.grdadb,
params.flrd[idx] / flxtt[idx], flr / flxtt[idx]);
}
}
} else {
// 对流主导 — Fortran label 100 (Newton 迭代)
@ -616,6 +635,7 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
let mut t0_i = (t_iter * tm).sqrt();
let mut dlt_i = (t_iter / tm).ln() / (p / pm).ln();
let mut fc0_i = fc0;
let mut flxcn0_conv = 0.0f64;
let mut itrnrc = 0;
// Fortran: label 100 Newton 迭代循环
@ -639,7 +659,7 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
t0_i = (t_iter * tm).sqrt();
dlt_i = (t_iter / tm).ln() / (p / pm).ln();
// Fortran: call convc1(id,t0,p0,pg0,prad0,ab0,dlt,flxcn0,fc0)
let (_, fc0_new, _, _) = compute_convc1_simple(
let (flxcn0_conv, fc0_new, _, _) = compute_convc1_simple(
idx + 1, t0_i, p0, pg0, pr0, ab0, dlt_i, config, flxtt[idx], cubcon.gravd,
);
fc0_i = fc0_new;
@ -654,13 +674,13 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
modified = true;
// Fortran label 230: flr=alp*t0**4*dlt
let flr = alp * t0_i.powi(4) * dlt_i;
// Fortran: flc=fc0*dele (使用最后迭代值)
let flc = fc0_i * (flxtt[idx] - alp * t0_i.powi(4) * dlt_i) / fc0_i;
// Fortran: flc=fc0*dele
let flc = flxtt[idx] - alp * t0_i.powi(4) * dlt_i;
// FORMAT 646: convection-dominant depth result
eprintln!("{:4}{:4}{:8.1}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}{:12.4e}",
id, itrnrc, params.temp[idx], dlt_i, cubcon.grdadb,
params.flrd[idx] / flxtt[idx], flr / flxtt[idx], flc / flxtt[idx],
0.0_f64, (flr + 0.0_f64) / flxtt[idx]);
flxcn0_conv / flxtt[idx], (flr + flxcn0_conv) / flxtt[idx]);
}
}
}
@ -695,12 +715,13 @@ pub fn conref_pure(params: &mut ConrefParams) -> ConrefOutput {
/// 简化的对流计算 (内部使用)。
///
/// 返回 (flxcnv, vcon, grdadb, bcnv)
/// 使用理想气体近似替代 TRMDER 热力学导数。
/// 返回 (flxcnv, vconv, grdadb, bcnv)
fn compute_convection_simple(
_id: usize,
t0: f64,
pt0: f64,
_pg0: f64,
pg0: f64,
_pr0: f64,
ab0: f64,
dlt: f64,
@ -713,7 +734,13 @@ fn compute_convection_simple(
return (0.0, 0.0, 0.0, 0.0);
}
// 绝热梯度近似 (单原子理想气体 = 0.4)
// 理想气体近似热力学量 (替代 Fortran TRMDER 输出)
const KB: f64 = 1.380649e-16; // Boltzmann constant (erg/K)
const MH: f64 = 1.6726e-24; // proton mass (g)
const HEATCP_IDEAL: f64 = 2.07e8; // 5/2 * KB/MH (erg/K/g)
const DLRDLT_IDEAL: f64 = 1.0; // d(ln rho)/d(ln T) for ideal gas
// 绝热梯度 (单原子理想气体, gamma=5/3, ∇_ad = 1 - 1/gamma = 0.4)
let grdadb = 0.4;
// 检查对流不稳定性
@ -722,15 +749,18 @@ fn compute_convection_simple(
return (0.0, 0.0, grdadb, 0.0);
}
// 计算引力
let grav = if config.idisk == 1 { gravd } else { config.grav };
if grav == 0.0 {
// 计算引力 (Fortran: if(idisk.eq.0) use GRAV, else use GRAVD)
let grav_val = if config.idisk == 1 { gravd } else { config.grav };
if grav_val == 0.0 {
return (0.0, 0.0, grdadb, 0.0);
}
// 粗略估计密度
let rho = if t0 > 0.0 {
pt0 / (t0 * 1.38e-16 * grav)
// 密度估计: rho = P_gas * m_H / (k_B * T) (理想气体状态方程)
// Fortran TRMDER 从完整 EOS 计算密度
let rho = if t0 > 0.0 && pg0 > 0.0 {
pg0 * MH / (KB * t0)
} else if t0 > 0.0 {
pt0 * MH / (KB * t0)
} else {
1e-7
};
@ -738,29 +768,29 @@ fn compute_convection_simple(
// 混合长度
let hmix = if config.hmix0 == 0.0 { 1.0 } else { config.hmix0 };
// 压力标高
let hscale = pt0 / rho / grav;
// 压力标高: HSCALE = PTOT / (RHO * GRAV)
let hscale = pt0 / rho / grav_val;
// 对流速度
let vco = hmix * (config.aconml * pt0 / rho).abs().sqrt();
// 对流速度: VCO = HMIX * sqrt(|ACONML * PTOT / RHO * DLRDLT|)
let vco = hmix * (config.aconml * pt0 / rho * DLRDLT_IDEAL).abs().sqrt();
// 对流系数
let flco = config.bconml * rho * t0 * hmix / 12.5664;
// 对流系数: FLCO = BCONML * RHO * HEATCP * T * HMIX / (4*PI)
let flco = config.bconml * rho * HEATCP_IDEAL * t0 * hmix / 12.5664;
// 光学厚度
// 光学厚度: TAUE = HMIX * ABROS * RHO * HSCALE
let taue = hmix * ab0 * rho * hscale;
// 辐射耗散因子
// 辐射耗散因子: FAC = TAUE / (1 + 0.5*TAUE^2)
let fac = taue / (UN + HALF * taue * taue);
// 参数 B (参考 Mihalas) — 这是 COMMON/CUBCON/ 中的 BCNV
let b = 5.67e-5 * t0.powi(3) / (rho * vco) * fac * config.cconml * HALF;
// 参数 B: B = sigma * T^3 / (RHO * HEATCP * VCO) * FAC * CCONML * 0.5
let b = 5.67e-5 * t0.powi(3) / (rho * HEATCP_IDEAL * vco) * fac * config.cconml * HALF;
// 参数 D
let d = b * b / 2.0;
let disc = d / 2.0 + ddel;
// 计算有效 DLT
// 计算有效 DLT = D + DDEL - B * sqrt(D/2 + DDEL)
let dlt_eff = if disc >= 0.0 {
let val = d + ddel - b * disc.sqrt();
if val < 0.0 { 0.0 } else { val }
@ -777,12 +807,13 @@ fn compute_convection_simple(
/// 简化的 CONVC1 计算 (返回 fc0)。
///
/// 与 CONVEC 类似,但在检查不稳定性之前计算 FC0 = FLCO * VCO。
/// 返回 (flxcnv, fc0, grdadb, bcnv)
fn compute_convc1_simple(
_id: usize,
t0: f64,
pt0: f64,
_pg0: f64,
pg0: f64,
_pr0: f64,
ab0: f64,
dlt: f64,
@ -795,18 +826,26 @@ fn compute_convc1_simple(
return (0.0, 0.0, 0.0, 0.0);
}
// 绝热梯度近似
// 理想气体近似热力学量
const KB: f64 = 1.380649e-16;
const MH: f64 = 1.6726e-24;
const HEATCP_IDEAL: f64 = 2.07e8;
const DLRDLT_IDEAL: f64 = 1.0;
// 绝热梯度
let grdadb = 0.4;
// 计算引力
let grav = if config.idisk == 1 { gravd } else { config.grav };
if grav == 0.0 {
let grav_val = if config.idisk == 1 { gravd } else { config.grav };
if grav_val == 0.0 {
return (0.0, 0.0, grdadb, 0.0);
}
// 估计密度
let rho = if t0 > 0.0 {
pt0 / (t0 * 1.38e-16 * grav)
// 密度估计 (理想气体状态方程)
let rho = if t0 > 0.0 && pg0 > 0.0 {
pg0 * MH / (KB * t0)
} else if t0 > 0.0 {
pt0 * MH / (KB * t0)
} else {
1e-7
};
@ -815,15 +854,15 @@ fn compute_convc1_simple(
let hmix = if config.hmix0 == 0.0 { 1.0 } else { config.hmix0 };
// 压力标高
let hscale = pt0 / rho / grav;
let hscale = pt0 / rho / grav_val;
// 对流速度
let vco = hmix * (config.aconml * pt0 / rho).abs().sqrt();
let vco = hmix * (config.aconml * pt0 / rho * DLRDLT_IDEAL).abs().sqrt();
// 对流系数
let flco = config.bconml * rho * t0 * hmix / 12.5664;
let flco = config.bconml * rho * HEATCP_IDEAL * t0 * hmix / 12.5664;
// FC0 = FLCO * VCO
// CONVC1 特有: FC0 = FLCO * VCO (在检查不稳定性之前计算)
let fc0 = flco * vco;
// 检查对流不稳定性
@ -839,7 +878,7 @@ fn compute_convc1_simple(
let fac = taue / (UN + HALF * taue * taue);
// 参数 B
let b = 5.67e-5 * t0.powi(3) / (rho * vco) * fac * config.cconml * HALF;
let b = 5.67e-5 * t0.powi(3) / (rho * HEATCP_IDEAL * vco) * fac * config.cconml * HALF;
// 参数 D
let d = b * b / 2.0;

View File

@ -11,11 +11,12 @@
use crate::tlusty::math::cion;
use crate::tlusty::math::{colh, ColhAtomicData, ColhOutput, ColhParams};
use crate::tlusty::math::{colhe, ColheParams};
use crate::tlusty::math::cspec;
use crate::tlusty::math::irc;
use crate::tlusty::math::ylintp;
use crate::tlusty::state::constants::{EH, HK, TWO, UN};
// f2r_depends: COLH, COLHE, CSPEC, IRC
use crate::tlusty::state::constants::{EH, HK, MLEVEL, TWO, UN};
// f2r_depends: COLH, COLHE, CSPEC, IRC, CION, YLININTP
// ============================================================================
// 常量
@ -187,6 +188,8 @@ pub struct ColisParams<'a> {
pub colh_params: Option<ColhParams>,
/// COLH 原子数据
pub colh_atomic: Option<ColhAtomicData<'a>>,
/// COLHE 参数(如果需要调用 COLHE
pub colhe_params: Option<ColheParams>,
}
/// COLIS 输出结果
@ -232,11 +235,27 @@ pub fn colis(params: &ColisParams) -> ColisOutput {
};
// 调用 COLH 和 COLHE如果有氢和氦
if params.iath != 0 || params.iathe != 0 {
// 注意COLH 和 COLHE 的结果需要乘以电子密度
// 这里我们假设调用者已经处理了这些
// Fortran: IF(IATH.NE.0) CALL COLH(ID,T,COL)
// IF(IATHE.NE.0) CALL COLHE(T,COL)
if params.iath != 0 {
if let (Some(colh_p), Some(colh_a)) = (&params.colh_params, &params.colh_atomic) {
let mut colh_out = ColhOutput { col: &mut col[..] };
colh(colh_p, colh_a, &mut colh_out);
}
}
if params.iathe != 0 {
if let Some(colhe_p) = &params.colhe_params {
let colhe_result = colhe(colhe_p);
for (it, val) in colhe_result.col_rates.iter().enumerate() {
if it < col.len() {
col[it] += *val;
}
}
}
}
// 计算 CLOC 数组
// Fortran: IF(IATH.NE.0.OR.IATHE.NE.0) THEN — 计算 CLOC 数组
if params.iath != 0 || params.iathe != 0 {
for it in 1..=params.ntrans {
let it_idx = it - 1;
if col[it_idx] != 0.0 {
@ -406,8 +425,11 @@ pub fn colis(params: &ColisParams) -> ColisOutput {
let cs = creger(t32, u0_new, cc1, gg) * params.ane;
col[it_idx] += cs;
// 注意:这里需要 WOP 数组
// cloc[it_idx] += cs * params.ane * params.sbf[i - 1] * params.wop[i - 1 + (id - 1) * ?] * corr;
// Fortran: CLOC(IT)=CLOC(IT)+CS*ANE*SBF(I)*WOP(I,ID)*CORR
// WOP(MLEVEL,MDEPTH) column-major: linear index (ID-1)*MLEVEL + (I-1)
let wop_idx = (params.id - 1) * MLEVEL + (i - 1);
let wop_val = params.wop.get(wop_idx).copied().unwrap_or(0.0);
cloc[it_idx] += cs * params.ane * params.sbf[i - 1] * wop_val * corr;
}
}
} else {
@ -439,7 +461,15 @@ pub fn colis(params: &ColisParams) -> ColisOutput {
} else if ic == 4 {
cupsx(srt, u0, c2 / params.g[i - 1]) * params.ane
} else if ic == 9 {
params.omecol[it_idx] * srt0 * (-u0 * tt0).exp() * params.ane
// Fortran: CS=OMECOL(I,J)*SRT0*EXP(-U0*TT0) * ANE
// OMECOL(MLEVEL,MLEVEL) — column-major: (I-1) + (J-1)*MLEVEL
let omecol_idx = (i - 1) + (j - 1) * MLEVEL;
let omecol_val = if omecol_idx < params.omecol.len() {
params.omecol[omecol_idx]
} else {
0.0
};
omecol_val * srt0 * (-u0 * tt0).exp() * params.ane
} else if ic < 0 {
cspec(i as i32, j as i32, ic, c1, c2, u0, t) * params.ane
} else {
@ -457,10 +487,10 @@ pub fn colis(params: &ColisParams) -> ColisOutput {
}
/// 从 ITRA 数组获取跃迁索引
/// Fortran: ITRA(I,J) — column-major array ITRA(MLEVEL,MLEVEL)
/// Linear index: (I-1) + (J-1)*MLEVEL
fn get_itra(itra: &[i32], i: usize, j: usize, _nki: usize) -> i32 {
// 简化:假设 itra 是二维数组展平的
// 实际索引方式取决于 Fortran 原始代码
let idx = (i - 1) * 1000 + (j - 1); // 简化索引
let idx = (i - 1) + (j - 1) * MLEVEL;
if idx < itra.len() {
itra[idx]
} else {
@ -469,10 +499,10 @@ fn get_itra(itra: &[i32], i: usize, j: usize, _nki: usize) -> i32 {
}
/// 获取 OSH 振子强度
/// Fortran: OSH(IQ,JQ) — column-major array OSH(20,20)
/// Linear index: (IQ-1) + (JQ-1)*20
fn get_osh(osh: &[f64], i: usize, j: usize) -> f64 {
// OSH(I, J) - 从能级 i 到 j 的振子强度
// 假设是 (nlevel x 20) 的数组
let idx = (i - 1) * 20 + (j - 1);
let idx = (i - 1) + (j - 1) * 20;
if idx < osh.len() {
osh[idx]
} else {
@ -867,6 +897,7 @@ mod tests {
ctemp_tab: &[[[0.0; MCFIT]; MXTCOL]],
colh_params: None,
colh_atomic: None,
colhe_params: None,
};
let result = colis(&params);

View File

@ -88,23 +88,27 @@ fn read_element_data<R: BufRead>(
itra: &[Vec<i32>],
iup: &[i32],
ilow: &[i32],
ibf: &[i32],
_ibf: &[i32],
enion: &[f64],
ierr: i32,
izrr: i32,
ie: usize,
) -> Result<Vec<(usize, Vec<CrossSectionPoint>)>> {
let mut transitions = Vec::new();
let mut itr = 0;
for i in nl1..=nl2 {
itr += 1;
// Fortran: ITR = I in the inner loop (ITR starts at NL1-1, increments to NL1, ..., NL2)
let itr = i; // ITR = I always holds
if indexp.get(itr - 1).copied().unwrap_or(0) == 0 {
continue;
}
// Fortran: ITRA(IUP(ITR), ILOW(ITR)) — column-major
// Rust row-major: swap indices → itra[ILOW-1][IUP-1]
let ic = itra
.get(iup.get(itr - 1).copied().unwrap_or(0) as usize - 1)
.and_then(|row| row.get(ilow.get(itr - 1).copied().unwrap_or(0) as usize - 1).copied())
.get(ilow.get(itr - 1).copied().unwrap_or(0) as usize - 1)
.and_then(|row| row.get(iup.get(itr - 1).copied().unwrap_or(0) as usize - 1).copied())
.unwrap_or(0) as usize;
// 读取跃迁数据
@ -116,9 +120,22 @@ fn read_element_data<R: BufRead>(
// Fe 特殊处理:能量校准
if ierr == 26 {
ecmr = XIFE.get(izrr as usize - 1).copied().unwrap_or(0.0) - ecmr;
// Fortran: DE=ABS((ENION(ILOW(ITR))-HCCM*ECMR)/ENION(ILOW(ITR)))
let ilow_itr = ilow.get(itr - 1).copied().unwrap_or(0) as usize;
if ilow_itr > 0 {
let enion_val = enion.get(ilow_itr - 1).copied().unwrap_or(0.0);
if enion_val.abs() > 1e-30 {
let de = ((enion_val - HCCM * ecmr) / enion_val).abs();
if de > 2e-2 {
eprintln!(" SIGAVE: energy discrepancy at ie={}, itr={}, i={}: DE={:.3e}", ie, itr, i, de);
}
}
}
}
// 读取截面数据点(按频率递减顺序)
// 读取截面数据点
// Fortran: DO IJ=1,NFIS; JI=NFIS-IJ+1; READ FRINSG(JI),CRIN(JI)
// Fortran reverses the data — read into descending frequency order
let mut points = Vec::with_capacity(nfis);
for _ in 0..nfis {
let fr: f64 = reader.read_value()?;
@ -128,6 +145,8 @@ fn read_element_data<R: BufRead>(
cross_section: cr,
});
}
// Fortran reversal: file has ascending freq, Fortran stores descending
points.reverse();
transitions.push((ic, points));
}
@ -265,10 +284,12 @@ fn sigave_impl<R: BufRead>(params: &SigaveParams, mut reader: FortranReader<R>)
// 获取跃迁索引
let iup_val = params.iup.get(itr - 1).copied().unwrap_or(0) as usize;
let ilow_val = params.ilow.get(itr - 1).copied().unwrap_or(0) as usize;
// Fortran: ITRA(IUP(ITR), ILOW(ITR)) — column-major
// Rust row-major: swap → itra[ILOW-1][IUP-1]
let ic = params
.itra
.get(iup_val - 1)
.and_then(|row| row.get(ilow_val - 1).copied())
.get(ilow_val - 1)
.and_then(|row| row.get(iup_val - 1).copied())
.unwrap_or(0) as usize;
if ic == 0 {
@ -318,6 +339,7 @@ fn sigave_impl<R: BufRead>(params: &SigaveParams, mut reader: FortranReader<R>)
params.enion,
ierr,
izrr,
ie,
) {
Ok(t) => t,
Err(e) => {
@ -343,6 +365,10 @@ fn sigave_impl<R: BufRead>(params: &SigaveParams, mut reader: FortranReader<R>)
);
transitions_read += transitions.len();
// Fortran: after inner DO 100 loop, ITR has been incremented (NL2-NL1+1) times
// Advance outer itr past all processed transitions
itr += nl2 - nl1 + 1;
}
SigaveOutput {

View File

@ -52,8 +52,8 @@ pub struct CoolrtParams<'a> {
// 深度数据
/// 密度 (nd)
pub dens: &'a [f64],
/// dm1 导数 (nd)
pub dedm1: &'a [f64],
/// dm1 导数(标量,来自 MODELQ COMMON/MODPAR/
pub dedm1: f64,
/// 深度间隔 (nd-1)
pub deldmz: &'a [f64],
@ -192,6 +192,11 @@ pub fn coolrt_pure(params: &CoolrtParams) -> CoolrtOutput {
// WRITE(87,686) ij,freq(ij)
// FORMAT 686: i5,1pe15.7
eprintln!("{:5}{:15.7e}", ij + 1, params.freq[ij]);
// Fortran lines 53-57: taud 计算(结果未输出,仅内部使用)
let _taud = compute_taud(
nd, params.abso1[0], params.dedm1,
params.deldmz, params.absot,
);
}
}
@ -293,6 +298,8 @@ pub fn find_fe2_ion(
numat: &[i32],
iz: &[i32],
) -> Option<usize> {
// Fortran iterates ALL ions and takes the LAST match (IOFE2 is overwritten)
let mut iofe2 = None;
for ion in 0..nion {
let nn1 = nfirst[ion];
if nn1 == 0 || nn1 > iatm.len() {
@ -300,10 +307,10 @@ pub fn find_fe2_ion(
}
let iat2 = iatm[nn1 - 1]; // Fortran 1-indexed -> Rust 0-indexed
if iat2 > 0 && iat2 <= numat.len() && numat[iat2 - 1] == 26 && iz[ion] == 2 {
return Some(ion);
iofe2 = Some(ion);
}
}
None
iofe2
}
// ============================================================================
@ -347,7 +354,7 @@ mod tests {
let w = vec![0.25, 0.25, 0.25, 0.25];
let freq = vec![1.0e14, 2.0e14, 3.0e14, 4.0e14];
let dens = vec![1.0e-6, 1.0e-5, 1.0e-4];
let dedm1 = vec![1.0, 2.0, 3.0];
let dedm1 = 1.0;
let deldmz = vec![0.1, 0.2];
let abso1 = vec![0.1, 0.2, 0.3];
let emis1 = vec![0.01, 0.02, 0.03];
@ -383,7 +390,7 @@ mod tests {
w: Box::leak(w.into_boxed_slice()),
freq: Box::leak(freq.into_boxed_slice()),
dens: Box::leak(dens.into_boxed_slice()),
dedm1: Box::leak(dedm1.into_boxed_slice()),
dedm1,
deldmz: Box::leak(deldmz.into_boxed_slice()),
abso1: Box::leak(abso1.into_boxed_slice()),
emis1: Box::leak(emis1.into_boxed_slice()),