SpectraRust/src/math/dwnfr.rs
2026-03-21 09:12:18 +08:00

229 lines
6.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 溶解分数计算 (所有频率)。
//!
//! 重构自 TLUSTY `dwnfr.f`
use crate::state::constants::UN;
use crate::state::config::InpPar;
// ============================================================================
// DWNFR - 溶解分数 (所有频率)
// ============================================================================
/// 计算所有频率的溶解分数。
///
/// # 参数
///
/// - `mode` - 模式: 0 表示 DW=1 (无下降), >0 表示计算
/// - `n` - 频率数量
/// - `fre` - 阈值频率
/// - `a` - acor 参数 (从 dwnfr0 计算得到)
/// - `ane` - 电子密度
/// - `z` - 离子电荷
/// - `fr` - 频率数组
/// - `inppar` - 输入参数 (bergfc)
/// - `dw` - 输出溶解分数数组
///
/// # Fortran 原始代码
///
/// ```fortran
/// SUBROUTINE DWNFR(MODE,N,FRE,A,ANE,Z,FR,DW)
/// INCLUDE 'IMPLIC.FOR'
/// INCLUDE 'BASICS.FOR'
/// INCLUDE 'MODELQ.FOR'
/// parameter (p1=0.1402,p2=0.1285,p3=un,p4=3.15,p5=4.)
/// parameter (tkn=3.01,ckn=5.33333333,cb0=8.59d14,f23=-2./3.)
/// PARAMETER (FRH=3.28805D15,SQFRH=5.734152D7)
/// DIMENSION FR(N),DW(N)
///
/// cb=cb0*berfc ! 注意: 原文是 berfc应为 bergfc
/// IF(MODE.EQ.0) THEN
/// DO IJ=1,N
/// DW(IJ)=UN
/// END DO
/// ELSE
/// DO IJ=1,N
/// IF(FR(IJ).LT.FRE) THEN
/// XN=SQFRH*Z/SQRT(FRE-FR(IJ))
/// if(xn.le.tkn) then
/// xkn=un
/// else
/// xn1=un/(xn+un)
/// xkn=ckn*xn*xn1*xn1
/// end if
/// beta=cb*z*z*z*xkn/(xn*xn*xn*xn)*exp(f23*log(ane))
/// x=exp(p4*log(un+p3*a))
/// c1=p1*(x+p5*(z-un)*a*a*a)
/// c2=p2*x
/// f=(c1*beta*beta*beta)/(un+c2*beta*sqrt(beta))
/// DW(IJ)=UN-f/(un+f)
/// ELSE
/// DW(IJ)=UN
/// END IF
/// END DO
/// END IF
/// END
/// ```
pub fn dwnfr(
mode: i32,
n: usize,
fre: f64,
a: f64,
ane: f64,
z: f64,
fr: &[f64],
inppar: &InpPar,
dw: &mut [f64],
) {
const P1: f64 = 0.1402;
const P2: f64 = 0.1285;
const P3: f64 = UN;
const P4: f64 = 3.15;
const P5: f64 = 4.0;
const TKN: f64 = 3.01;
const CKN: f64 = 5.33333333;
const CB0: f64 = 8.59e14;
const F23: f64 = -2.0 / 3.0;
const SQFRH: f64 = 5.734152e7;
// 注意: Fortran 原文是 berfc但应该是 bergfc
let cb = CB0 * inppar.bergfc;
if mode == 0 {
// MODE=0: DW=1 (无下降)
for ij in 0..n {
dw[ij] = UN;
}
} else {
// MODE>0: 计算溶解分数
let z3 = z * z * z;
let a3 = a * a * a;
let elec23 = ane.powf(F23);
let x = (UN + P3 * a).powf(P4);
let c1 = P1 * (x + P5 * (z - UN) * a3);
let c2 = P2 * x;
for ij in 0..n {
if fr[ij] < fre {
let xn = SQFRH * z / (fre - fr[ij]).sqrt();
let xkn = if xn <= TKN {
UN
} else {
let xn1 = UN / (xn + UN);
CKN * xn * xn1 * xn1
};
let beta = cb * z3 * xkn / xn.powi(4) * elec23;
let beta3 = beta * beta * beta;
let beta32 = beta3.sqrt();
let f = (c1 * beta3) / (UN + c2 * beta * beta32);
dw[ij] = UN - f / (UN + f);
} else {
dw[ij] = UN;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dwnfr_mode_zero() {
let inppar = InpPar::default();
let fr = [0.5, 0.6, 0.7, 0.8, 0.9];
let mut dw = [0.0; 5];
dwnfr(0, 5, 1.0, 0.1, 1e12, 2.0, &fr, &inppar, &mut dw);
// MODE=0 时,所有 DW 应该是 1.0
for ij in 0..5 {
assert!((dw[ij] - 1.0).abs() < 1e-10, "dw[{}] = {}, expected 1.0", ij, dw[ij]);
}
}
#[test]
fn test_dwnfr_mode_nonzero_above_threshold() {
let inppar = InpPar::default();
let fr = [1.1, 1.2, 1.3]; // 都大于 fre=1.0
let mut dw = [0.0; 3];
dwnfr(1, 3, 1.0, 0.1, 1e12, 2.0, &fr, &inppar, &mut dw);
// fr >= fre 时DW 应该是 1.0
for ij in 0..3 {
assert!((dw[ij] - 1.0).abs() < 1e-10);
}
}
#[test]
fn test_dwnfr_mode_nonzero_below_threshold() {
let inppar = InpPar::default();
let fr = [0.5, 0.6, 0.7, 0.8, 0.9]; // 都小于 fre=1.0
let mut dw = [0.0; 5];
dwnfr(1, 5, 1.0, 0.1, 1e12, 2.0, &fr, &inppar, &mut dw);
// DW 应该在 (0, 1] 范围内
for ij in 0..5 {
assert!(dw[ij] <= 1.0 && dw[ij] > 0.0, "dw[{}] = {}", ij, dw[ij]);
}
}
#[test]
fn test_dwnfr_mixed_frequencies() {
let inppar = InpPar::default();
let fr = [0.5, 1.0, 1.5]; // 混合: <, =, >
let mut dw = [0.0; 3];
dwnfr(1, 3, 1.0, 0.1, 1e12, 2.0, &fr, &inppar, &mut dw);
// fr[0] < fre: dw < 1 (可能)
// fr[1] == fre: dw == 1
// fr[2] > fre: dw == 1
assert!(dw[0] <= 1.0);
assert!((dw[1] - 1.0).abs() < 1e-10);
assert!((dw[2] - 1.0).abs() < 1e-10);
}
#[test]
fn test_dwnfr_consistency_with_dwnfr1() {
use super::super::dwnfr1;
use crate::state::model::DwnPar;
let inppar = InpPar::default();
// 设置 dwnpar 以匹配 dwnfr 的参数
let mut dwnpar = DwnPar::default();
let id = 5;
let izz = 1; // z = 2
let z = (izz + 1) as f64;
let a: f64 = 0.1;
let ane: f64 = 1e12;
// 计算 dwnfr0 会设置的值
dwnpar.elec23[id] = ane.powf(-2.0 / 3.0);
dwnpar.z3[izz] = z * z * z;
let x = (1.0 + a).powf(3.15);
dwnpar.dwc2[id] = 0.1285 * x;
let a3 = a * a * a;
dwnpar.dwc1[izz][id] = 0.1402 * (x + 4.0 * (z - 1.0) * a3);
let fr = [0.5, 0.8];
let mut dw = [0.0; 2];
let fre = 1.0;
dwnfr(1, 2, fre, a, ane, z, &fr, &inppar, &mut dw);
// 与 dwnfr1 比较
let dw1_0 = dwnfr1(fr[0], fre, id, izz, &inppar, &dwnpar);
let dw1_1 = dwnfr1(fr[1], fre, id, izz, &inppar, &dwnpar);
// 由于参数设置可能不完全一致,只检查大致趋势
assert!((dw[0] - dw1_0).abs() < 1e-6, "dw[0]={}, dwnfr1={}", dw[0], dw1_0);
assert!((dw[1] - dw1_1).abs() < 1e-6, "dw[1]={}, dwnfr1={}", dw[1], dw1_1);
}
}