//! 溶解分数计算 (所有频率)。 //! //! 重构自 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); } }