diff --git a/src/tlusty/math/alifr1.rs b/src/tlusty/math/alifr1.rs index 8d3e57c..c398069 100644 --- a/src/tlusty/math/alifr1.rs +++ b/src/tlusty/math/alifr1.rs @@ -1458,26 +1458,113 @@ mod tests { use super::*; #[test] - fn test_alifr1_ifali_le_1() { - // 测试 IFALI <= 1 时直接返回 - let params = Alifr1Params { - ij: 1, - nd: 10, - nlvexp: 5, - ifali: 1, - irder: 1, - ilmcor: 3, - ilasct: 0, - ibc: 0, - idisk: 0, - ifalih: 0, - }; + fn test_alifr1_basic() { + // Setup minimal dimensions + const ND: usize = 3; + const NFREQ: usize = 2; + const NLVEXP: usize = 2; - // 创建空的 FixAlp(实际使用需要完整初始化) + let params = Alifr1Params { + ij: 1, nd: ND, nlvexp: NLVEXP, ifali: 3, irder: 3, + ilmcor: 3, ilasct: 0, ibc: 0, idisk: 0, ifalih: 0, + }; let mut fixalp = FixAlp::default(); - // 简单测试:确保函数不会 panic - // 实际测试需要完整的模型状态 - let _ = (¶ms, &mut fixalp); + let elec = vec![1.0; ND]; + let dens = vec![1.0; ND]; + let densi = vec![1.0; ND]; + let densim = vec![1.0; ND]; + let dens1 = vec![1.0; ND]; + let dm = vec![1.0; ND]; + let deldmz = vec![1.0; ND]; + let elscat = vec![0.1; ND]; + let absot = vec![1.0; ND]; + let hkt21 = vec![1.0; ND]; + let xkfb = vec![1.0; ND]; + let xkf1 = vec![1.0; ND]; + + let rad1 = vec![1.0; ND]; + let fak1 = vec![1.0; ND]; + + let freq = vec![1e15; NFREQ]; + let hextrd = vec![0.0; NFREQ]; + let sigec = vec![0.0; NFREQ]; + let sige = 0.0; + let extrad = vec![0.0; NFREQ]; + let fh = vec![1.0; NFREQ]; + let w = vec![1.0; NFREQ]; + let q0 = vec![0.0; NFREQ]; + + let lskip = vec![vec![0; NFREQ]; ND]; // 0 means false (don't skip) + + let reint = vec![1.0; ND]; + let redif = vec![1.0; ND]; + + let mut fprd = vec![0.0; ND]; + let mut flfix = vec![0.0; ND]; + let mut flrd = vec![0.0; ND]; + let mut fcooli = vec![0.0; ND]; + let mut heit = vec![0.0; ND]; + let mut hein = vec![0.0; ND]; + let mut heim = vec![0.0; ND]; + let mut heitm = vec![0.0; ND]; + let mut heinm = vec![0.0; ND]; + let mut heimm = vec![0.0; ND]; + let mut heip = vec![vec![0.0; ND]; NLVEXP]; + let mut heipm = vec![vec![0.0; ND]; NLVEXP]; + let mut redt = vec![0.0; ND]; + let mut redn = vec![0.0; ND]; + let mut redm = vec![0.0; ND]; + let mut redx = vec![0.0; ND]; + let mut redtm = vec![0.0; ND]; + let mut rednm = vec![0.0; ND]; + let mut redmm = vec![0.0; ND]; + let mut redxm = vec![0.0; ND]; + let mut redp = vec![vec![0.0; ND]; NLVEXP]; + let mut redpm = vec![vec![0.0; ND]; NLVEXP]; + let mut rein = vec![0.0; ND]; + let mut reit = vec![0.0; ND]; + let mut reim = vec![0.0; ND]; + let mut reip = vec![vec![0.0; ND]; NLVEXP]; + + let mut model = Alifr1ModelState { + elec: &elec, dens: &dens, densi: &densi, densim: &densim, dens1: &dens1, + dm: &dm, deldmz: &deldmz, elscat: &elscat, absot: &absot, hkt21: &hkt21, + xkfb: &xkfb, xkf1: &xkf1, rad1: &rad1, fak1: &fak1, + freq: &freq, hextrd: &hextrd, sigec: &sigec, sige, extrad: &extrad, fh: &fh, w: &w, q0: &q0, + lskip: &lskip, reint: &reint, redif: &redif, + fprd: &mut fprd, flfix: &mut flfix, flrd: &mut flrd, fcooli: &mut fcooli, + heit: &mut heit, hein: &mut hein, heim: &mut heim, + heitm: &mut heitm, heinm: &mut heinm, heimm: &mut heimm, + heip: &mut heip, heipm: &mut heipm, + redt: &mut redt, redn: &mut redn, redm: &mut redm, redx: &mut redx, + redtm: &mut redtm, rednm: &mut rednm, redmm: &mut redmm, redxm: &mut redxm, + redp: &mut redp, redpm: &mut redpm, + rein: &mut rein, reit: &mut reit, reim: &mut reim, reip: &mut reip, + }; + + let wc = vec![1.0; NFREQ]; + let emis1 = vec![1.0; ND]; + let abso1 = vec![1.0; ND]; + let scat1 = vec![0.1; ND]; + let demt1 = vec![0.1; ND]; + let demn1 = vec![0.1; ND]; + let demm1 = vec![0.1; ND]; + let dabt1 = vec![0.1; ND]; + let dabn1 = vec![0.1; ND]; + let dabm1 = vec![0.1; ND]; + let demp1 = vec![vec![0.1; ND]; NLVEXP]; + let dabp1 = vec![vec![0.1; ND]; NLVEXP]; + + let rad = Alifr1RadState { + wc: &wc, emis1: &emis1, abso1: &abso1, scat1: &scat1, + demt1: &demt1, demn1: &demn1, demm1: &demm1, + dabt1: &dabt1, dabn1: &dabn1, dabm1: &dabm1, + demp1: &demp1, dabp1: &dabp1, + }; + + let res = alifr1(¶ms, &mut fixalp, &mut model, &rad); + assert!(!res); + assert!(model.heit[0] != 0.0 || model.hein[0] != 0.0, "Heating rates should be updated"); } } diff --git a/src/tlusty/math/alifr6.rs b/src/tlusty/math/alifr6.rs index 7c184c3..91d503c 100644 --- a/src/tlusty/math/alifr6.rs +++ b/src/tlusty/math/alifr6.rs @@ -1000,19 +1000,130 @@ mod tests { use super::*; #[test] - fn test_alifr6_params_creation() { + fn test_alifr6_basic() { + // Setup minimal dimensions + const ND: usize = 3; + const NFREQ: usize = 2; + const NLVEXP: usize = 2; + let params = Alifr6Params { - ij: 1, - nd: 50, - nlvexp: 10, - ifali: 7, - irder: 3, - ilmcor: 0, - ilasct: 1, - ibc: 2, - idisk: 0, + ij: 1, nd: ND, nlvexp: NLVEXP, ifali: 7, irder: 3, + ilmcor: 3, ilasct: 0, ibc: 0, idisk: 0, }; - assert_eq!(params.ij, 1); - assert_eq!(params.nd, 50); + + // Input arrays + let elec = vec![1.0; ND]; + let densi = vec![1.0; ND]; + let densim = vec![1.0; ND]; + let dens1 = vec![1.0; ND]; + let fak1 = vec![1.0; ND]; + let deldmz = vec![1.0; ND]; + let absot = vec![1.0; ND]; + let hkt21 = vec![1.0; ND]; + let rad1 = vec![1.0; ND]; + let emis1 = vec![1.0; ND]; + let abso1 = vec![1.0; ND]; + let elscat = vec![0.1; ND]; + let wc = vec![1.0; NFREQ]; + let fh = vec![1.0; NFREQ]; + let freq = vec![1e15; NFREQ]; + let hextrd = vec![0.0; NFREQ]; + let sigec = vec![0.0; NFREQ]; + let lskip = vec![vec![0; NFREQ]; ND]; // 0 means false (don't skip) + let redif = vec![1.0; ND]; + let reint = vec![1.0; ND]; + let xkf1 = vec![1.0; ND]; + let xkfb = vec![1.0; ND]; + let ali1 = vec![1.0; ND]; + let alim1 = vec![1.0; ND]; + let alip1 = vec![1.0; ND]; + let demt1 = vec![0.1; ND]; + let demn1 = vec![0.1; ND]; + let dabt1 = vec![0.1; ND]; + let dabn1 = vec![0.1; ND]; + let demp1 = vec![vec![0.1; ND]; NLVEXP]; + let dabp1 = vec![vec![0.1; ND]; NLVEXP]; + + // Output arrays (mutable) + let mut heit = vec![0.0; ND]; + let mut hein = vec![0.0; ND]; + let mut heip = vec![vec![0.0; ND]; NLVEXP]; + let mut heitm = vec![0.0; ND]; + let mut heinm = vec![0.0; ND]; + let mut heipm = vec![vec![0.0; ND]; NLVEXP]; + let mut heitp = vec![0.0; ND]; + let mut heinp = vec![0.0; ND]; + let mut heipp = vec![vec![0.0; ND]; NLVEXP]; + let mut redt = vec![0.0; ND]; + let mut redn = vec![0.0; ND]; + let mut redp = vec![vec![0.0; ND]; NLVEXP]; + let mut redtm = vec![0.0; ND]; + let mut rednm = vec![0.0; ND]; + let mut redpm = vec![vec![0.0; ND]; NLVEXP]; + let mut redtp = vec![0.0; ND]; + let mut rednp = vec![0.0; ND]; + let mut redpp = vec![vec![0.0; ND]; NLVEXP]; + let mut redx = vec![0.0; ND]; + let mut redxm = vec![0.0; ND]; + let mut reit = vec![0.0; ND]; + let mut rein = vec![0.0; ND]; + let mut reip = vec![vec![0.0; ND]; NLVEXP]; + let mut areit = vec![0.0; ND]; + let mut arein = vec![0.0; ND]; + let mut areip = vec![vec![0.0; ND]; NLVEXP]; + let mut creit = vec![0.0; ND]; + let mut crein = vec![0.0; ND]; + let mut creip = vec![vec![0.0; ND]; NLVEXP]; + let mut ehet = vec![0.0; ND]; + let mut ehen = vec![0.0; ND]; + let mut ehep = vec![vec![0.0; ND]; NLVEXP]; + let mut eret = vec![0.0; ND]; + let mut eren = vec![0.0; ND]; + let mut erep = vec![vec![0.0; ND]; NLVEXP]; + let mut dsfdt = vec![0.0; ND]; + let mut dsfdn = vec![0.0; ND]; + let mut dsfdp = vec![vec![0.0; ND]; NLVEXP]; + let mut dsfdtm = vec![0.0; ND]; + let mut dsfdnm = vec![0.0; ND]; + let mut dsfdpm = vec![vec![0.0; ND]; NLVEXP]; + let mut dsfdtp = vec![0.0; ND]; + let mut dsfdnp = vec![0.0; ND]; + let mut dsfdpp = vec![vec![0.0; ND]; NLVEXP]; + let mut fprd = vec![0.0; ND]; + let mut flfix = vec![0.0; ND]; + let mut fcooli = vec![0.0; ND]; + + let mut state = Alifr6State { + elec: &elec, densi: &densi, densim: &densim, dens1: &dens1, + fak1: &fak1, deldmz: &deldmz, absot: &absot, hkt21: &hkt21, + rad1: &rad1, emis1: &emis1, abso1: &abso1, elscat: &elscat, + wc: &wc, fh: &fh, freq: &freq, hextrd: &hextrd, sigec: &sigec, + lskip: &lskip, redif: &redif, reint: &reint, xkf1: &xkf1, xkfb: &xkfb, + heit: &mut heit, hein: &mut hein, heip: &mut heip, + heitm: &mut heitm, heinm: &mut heinm, heipm: &mut heipm, + heitp: &mut heitp, heinp: &mut heinp, heipp: &mut heipp, + redt: &mut redt, redn: &mut redn, redp: &mut redp, + redtm: &mut redtm, rednm: &mut rednm, redpm: &mut redpm, + redtp: &mut redtp, rednp: &mut rednp, redpp: &mut redpp, + redx: &mut redx, redxm: &mut redxm, + reit: &mut reit, rein: &mut rein, reip: &mut reip, + areit: &mut areit, arein: &mut arein, areip: &mut areip, + creit: &mut creit, crein: &mut crein, creip: &mut creip, + ehet: &mut ehet, ehen: &mut ehen, ehep: &mut ehep, + eret: &mut eret, eren: &mut eren, erep: &mut erep, + dsfdt: &mut dsfdt, dsfdn: &mut dsfdn, dsfdp: &mut dsfdp, + dsfdtm: &mut dsfdtm, dsfdnm: &mut dsfdnm, dsfdpm: &mut dsfdpm, + dsfdtp: &mut dsfdtp, dsfdnp: &mut dsfdnp, dsfdpp: &mut dsfdpp, + fprd: &mut fprd, flfix: &mut flfix, fcooli: &mut fcooli, + ali1: &ali1, alim1: &alim1, alip1: &alip1, + demt1: &demt1, demn1: &demn1, dabt1: &dabt1, dabn1: &dabn1, + demp1: &demp1, dabp1: &dabp1, + }; + + // Call proper function + alifr6(¶ms, &mut state); + + // Verification that some arrays got mutated instead of just checking parameters + assert!(state.heit[0] != 0.0 || state.dsfdt[0] != 0.0, "State should be mutated by alifr6"); } } diff --git a/src/tlusty/math/alist1.rs b/src/tlusty/math/alist1.rs index 7a28987..c09d672 100644 --- a/src/tlusty/math/alist1.rs +++ b/src/tlusty/math/alist1.rs @@ -730,73 +730,165 @@ mod tests { use super::*; #[test] - fn test_zero_rates_simple() { - let nd = 5; - let nlvexp = 3; - let ntrans = 10; + fn test_alist1_pure_basic() { + const ND: usize = 2; + const NFREQ: usize = 2; + const NLVEXP: usize = 2; + const NTRANS: usize = 2; + const NTRANC: usize = 1; - // 创建简单的速率数组并验证清零 - let mut reit = vec![1.0; nd]; - let mut rein = vec![2.0; nd]; - let mut heip = vec![vec![3.0; nd]; nlvexp]; - let mut rru = vec![vec![4.0; nd]; ntrans]; + let config = Alist1Config { + nd: ND, nfreq: NFREQ, nlvexp: NLVEXP, ntrans: NTRANS, ntranc: NTRANC, + ispodf: 0, ioptab: 1, iter: 1, ndre: 0, hmix0: 0.0, lfin: false, + }; - // 直接测试清零逻辑(不使用完整结构体) - for id in 0..nd { - reit[id] = 0.0; - rein[id] = 0.0; - for ii in 0..nlvexp { - heip[ii][id] = 0.0; - } - for itr in 0..ntrans { - rru[itr][id] = 0.0; - } - } + // Freq params + let freq = vec![1e15; NFREQ]; + let w0e = vec![1.0; NFREQ]; + let ijx = vec![0; NFREQ]; // 0 means do not skip + let ijlin = vec![1, 0]; + let nlines = vec![0; NFREQ]; + let itrlin = vec![vec![0; 5]; NFREQ]; + let ifr0 = vec![1; NTRANS]; + let ifr1 = vec![NFREQ as i32; NTRANS]; + let kfr0 = vec![1; NTRANS]; + let linexp = vec![false; NTRANS]; + let prflin = vec![vec![1.0; NFREQ]; ND]; - // 验证 - for id in 0..nd { - assert_eq!(reit[id], 0.0); - assert_eq!(rein[id], 0.0); - } - for ii in 0..nlvexp { - for id in 0..nd { - assert_eq!(heip[ii][id], 0.0); - } - } - for itr in 0..ntrans { - for id in 0..nd { - assert_eq!(rru[itr][id], 0.0); - } - } - } + let freq_params = Alist1FreqParams { + freq: &freq, w0e: &w0e, ijx: &ijx, ijlin: &ijlin, nlines: &nlines, + itrlin: &itrlin, ifr0: &ifr0, ifr1: &ifr1, kfr0: &kfr0, linexp: &linexp, + prflin: &prflin, + }; - #[test] - fn test_rbnu_calculation() { - let hkt1: Vec = vec![4.8e-12, 6.0e-12, 8.0e-12]; - let rad1: Vec = vec![1.0, 0.5, 0.2]; - let bnue: Vec = vec![1.0e-10, 2.0e-10]; - let hkt21: Vec = vec![1.0e-12, 1.2e-12, 1.6e-12]; + // Atomic params + let ilow = vec![1; NTRANS]; + let iup = vec![2; NTRANS]; + let itrbf = vec![1; NTRANC]; + let cross = vec![vec![1e-18; NFREQ]; NTRANC]; + let ifwop = vec![1; NLVEXP]; + let mcdw = vec![0; NTRANS]; + let dwf1 = vec![vec![1.0; ND]; 10]; + let imrg = vec![0; NLVEXP]; + let sgmg = vec![vec![1.0; ND]; 10]; + let ipzero = vec![vec![0; ND]; NLVEXP]; + let itra = vec![vec![1; NLVEXP]; NLVEXP]; + let jidi = vec![0; ND]; + let xjid = vec![1.0; ND]; + let sigfe = vec![vec![1.0; NFREQ]; 5]; + let indexp = vec![1; NTRANS]; + let iiexp = vec![1; NLVEXP]; - let fr: f64 = 1.0e15; - let ij = 0; - let id = 0; + let atomic = Alist1AtomicParams { + ilow: &ilow, iup: &iup, itrbf: &itrbf, cross: &cross, ifwop: &ifwop, + mcdw: &mcdw, dwf1: &dwf1, imrg: &imrg, sgmg: &sgmg, ipzero: &ipzero, + itra: &itra, jidi: &jidi, xjid: &xjid, sigfe: &sigfe, indexp: &indexp, + iiexp: &iiexp, + }; - let exx: f64 = (-hkt1[id] * fr).exp(); - let rbnu: f64 = (rad1[id] + bnue[ij]) * exx; - let expected: f64 = (rad1[id] + bnue[ij]) * exx; + // Model state + let temp = vec![10000.0; ND]; + let elec = vec![1e12; ND]; + let dens = vec![1e14; ND]; + let dens1 = vec![1e-14; ND]; + let dm = vec![1.0; ND]; + let wmm = vec![1.0; ND]; + let hkt1 = vec![4.8e-15; ND]; + let hkt21 = vec![1.2e-15; ND]; + let rad1 = vec![1.0; ND]; + let bnue = vec![1.0; NFREQ]; + let crsw = vec![1.0; ND]; + let xkfb = vec![1.0; ND]; + let xkf1 = vec![1.0; ND]; + let abso1 = vec![1.0; ND]; + let scat1 = vec![0.1; ND]; - assert!((rbnu - expected).abs() < 1e-10_f64); + let model = Alist1ModelState { + temp: &temp, elec: &elec, dens: &dens, dens1: &dens1, dm: &dm, + wmm: &wmm, hkt1: &hkt1, hkt21: &hkt21, rad1: &rad1, bnue: &bnue, + crsw: &crsw, xkfb: &xkfb, xkf1: &xkf1, abso1: &abso1, scat1: &scat1, + }; - let rbnuf: f64 = rbnu * fr * hkt21[id]; - let expected_rbnuf: f64 = rbnu * fr * hkt21[id]; - assert!((rbnuf - expected_rbnuf).abs() < 1e-15_f64); - } + // Output state + let mut reit = vec![0.0; ND]; + let mut rein = vec![0.0; ND]; + let mut reix = vec![0.0; ND]; + let mut areit = vec![0.0; ND]; + let mut arein = vec![0.0; ND]; + let mut creit = vec![0.0; ND]; + let mut crein = vec![0.0; ND]; + let mut creix = vec![0.0; ND]; + let mut redt = vec![0.0; ND]; + let mut redtm = vec![0.0; ND]; + let mut redtp = vec![0.0; ND]; + let mut redn = vec![0.0; ND]; + let mut rednm = vec![0.0; ND]; + let mut rednp = vec![0.0; ND]; + let mut redx = vec![0.0; ND]; + let mut redxm = vec![0.0; ND]; + let mut redxp = vec![0.0; ND]; + let mut heit = vec![0.0; ND]; + let mut heitm = vec![0.0; ND]; + let mut heitp = vec![0.0; ND]; + let mut hein = vec![0.0; ND]; + let mut heinm = vec![0.0; ND]; + let mut heinp = vec![0.0; ND]; + let mut ehet = vec![0.0; ND]; + let mut ehen = vec![0.0; ND]; + let mut eret = vec![0.0; ND]; + let mut eren = vec![0.0; ND]; - #[test] - fn test_constants() { - // 验证使用的常量 - assert!(PCK > 0.0); - assert!((UN - 1.0_f64).abs() < 1e-15_f64); - assert!((HALF - 0.5_f64).abs() < 1e-15_f64); + let mut heip = vec![vec![0.0; ND]; NLVEXP]; + let mut reip = vec![vec![0.0; ND]; NLVEXP]; + let mut areip = vec![vec![0.0; ND]; NLVEXP]; + let mut creip = vec![vec![0.0; ND]; NLVEXP]; + let mut redp = vec![vec![0.0; ND]; NLVEXP]; + let mut redpm = vec![vec![0.0; ND]; NLVEXP]; + let mut heipm = vec![vec![0.0; ND]; NLVEXP]; + let mut redpp = vec![vec![0.0; ND]; NLVEXP]; + let mut heipp = vec![vec![0.0; ND]; NLVEXP]; + let mut ehep = vec![vec![0.0; ND]; NLVEXP]; + let mut erep = vec![vec![0.0; ND]; NLVEXP]; + + let mut fcooli = vec![0.0; ND]; + let mut flfix = vec![0.0; ND]; + let mut flexp = vec![0.0; ND]; + let mut flrd = vec![0.0; ND]; + let mut fprd = vec![0.0; ND]; + + let mut pradt = vec![0.0; ND]; + let mut prada = vec![0.0; ND]; + + let mut rru = vec![vec![0.0; ND]; NTRANS]; + let mut rrd = vec![vec![0.0; ND]; NTRANS]; + let mut drdt = vec![vec![0.0; ND]; NTRANS]; + + let mut abrosd = vec![0.0; ND]; + let mut sumdpl = vec![0.0; ND]; + + let reint = vec![1.0; ND]; + let redif = vec![1.0; ND]; + let mut fcool = vec![0.0; ND]; + + let mut output = Alist1OutputState { + reit: &mut reit, rein: &mut rein, reix: &mut reix, areit: &mut areit, arein: &mut arein, + creit: &mut creit, crein: &mut crein, creix: &mut creix, redt: &mut redt, redtm: &mut redtm, + redtp: &mut redtp, redn: &mut redn, rednm: &mut rednm, rednp: &mut rednp, redx: &mut redx, + redxm: &mut redxm, redxp: &mut redxp, heit: &mut heit, heitm: &mut heitm, heitp: &mut heitp, + hein: &mut hein, heinm: &mut heinm, heinp: &mut heinp, ehet: &mut ehet, ehen: &mut ehen, + eret: &mut eret, eren: &mut eren, heip: &mut heip, reip: &mut reip, areip: &mut areip, + creip: &mut creip, redp: &mut redp, redpm: &mut redpm, heipm: &mut heipm, redpp: &mut redpp, + heipp: &mut heipp, ehep: &mut ehep, erep: &mut erep, fcooli: &mut fcooli, flfix: &mut flfix, + flexp: &mut flexp, flrd: &mut flrd, fprd: &mut fprd, pradt: &mut pradt, prada: &mut prada, + rru: &mut rru, rrd: &mut rrd, drdt: &mut drdt, abrosd: &mut abrosd, sumdpl: &mut sumdpl, + reint: &reint, redif: &redif, fcool: &mut fcool, + }; + + // Call the functional test + let out = alist1_pure(&config, &freq_params, &atomic, &model, &mut output); + + // Verify mutations + assert!(output.rru[0][0] > 0.0 || output.redx[0] == 0.0); + assert_eq!(out.prdx, 1.0); // prada is initialized to 0, prdx remains 1.0 } } diff --git a/src/tlusty/math/chctab.rs b/src/tlusty/math/chctab.rs index a9721a2..da3b92b 100644 --- a/src/tlusty/math/chctab.rs +++ b/src/tlusty/math/chctab.rs @@ -350,16 +350,53 @@ fn check_opacity_simple( #[cfg(test)] mod tests { use super::*; + use std::io::Cursor; #[test] - fn test_element_symbols_count() { - assert_eq!(ELEMENT_SYMBOLS.len(), 99); - } + fn test_chctab_basic() { + let mut abndd = vec![vec![1.0; 1]; MATOM]; + let abunt = vec![1.0; MATOM]; + let abuno = vec![1.0; MATOM]; - #[test] - fn test_element_symbols_format() { - assert_eq!(ELEMENT_SYMBOLS[0], " H "); - assert_eq!(ELEMENT_SYMBOLS[1], " He "); - assert_eq!(ELEMENT_SYMBOLS[25], " Fe "); // Fe 是第 26 个元素,索引 25 + let mut params = ChctabParams { + abndd: &abndd, + abunt: &abunt, + abuno: &abuno, + ifmol: 1, + ifmolt: 2, // Different, should cause change if keepop == 0 + tmolim: 1000.0, + tmolit: 2000.0, + keepop: 0, // Will adopt op.table values + opacity_flags: OpacityFlags { + iophmi: 1, ielhm: 0, iophmt: 1, + ioph2p: 1, ioph2t: 1, + iophem: 0, iophet: 0, + iopch: 0, iopcht: 0, + iopoh: 0, iopoht: 0, + ioph2m: 0, ioh2mt: 0, + ioh2h2: 0, ih2h2t: 0, + ioh2he: 0, ih2het: 0, + ioh2h: 0, ioh2ht: 0, + iohhe: 0, iohhet: 0, + }, + }; + + let mut buf = Cursor::new(Vec::new()); + { + let mut writer = FortranWriter::new(&mut buf); + let result = chctab(&mut params, &mut writer).expect("chctab should succeed"); + + // Verify that ifmol was changed to ifmolt because keepop == 0 + assert_eq!(result.ifmol, 2); + assert_eq!(result.tmolim, 2000.0); + + // Verify opacity flags changes (iophmi and ioph2p should be set to 0 because keepop == 0 and both are > 0) + assert_eq!(result.iophmi, 0); + assert_eq!(result.ioph2p, 0); + } + + let output_str = String::from_utf8(buf.into_inner()).unwrap(); + assert!(output_str.contains("IFMOL and TMILIM changed")); + assert!(output_str.contains("so removed here")); } } diff --git a/src/tlusty/math/odfmer.rs b/src/tlusty/math/odfmer.rs index f5e4bb5..3569aa6 100644 --- a/src/tlusty/math/odfmer.rs +++ b/src/tlusty/math/odfmer.rs @@ -188,32 +188,70 @@ mod tests { } #[test] - fn test_odfmer_combined_logic() { - // 综合测试:验证跃迁和深度的组合筛选 - let ntrans = 4; - let nd = 3; - - let line = vec![true, true, false, true]; - let indexp: Vec = vec![2, 1, 2, -2]; - let chant: Vec = vec![0.0, 0.002, 0.001]; // 深度 1, 2 有变化 - let init: i32 = 0; - - // 计算应该被处理的 (跃迁, 深度) 对 - let mut expected_updates = 0; - for itr in 0..ntrans { - if line[itr] && indexp[itr].abs() == 2 { - for id in 0..nd { - if init == 1 || chant[id].abs() >= CHTL { - expected_updates += 1; - } - } - } - } - - // 跃迁 0, 3 应该被处理(满足 line=true 且 indexp=±2) - // 深度 1, 2 应该被处理(温度变化 >= CHTL) - // 所以预期更新次数 = 2 跃迁 × 2 深度 = 4 - assert_eq!(expected_updates, 4, - "Expected 4 ODF updates for the given configuration"); + fn test_odfmer_basic() { + use crate::tlusty::state::model::StrAux; + + let params = OdfmerParams { init: 1 }; + + let ntrans = 1; + let nd = 1; + + let line = vec![true]; + let indexp = vec![2]; + let atomic = OdfmerAtomicData { + line: &line, + indexp: &indexp, + }; + + let chant = vec![1.0]; + let model = OdfmerModelState { + chant: &chant, + }; + + let config = OdfhydConfig { + ispodf: 1, nlmx: 1, cas: 3e10, vtb: 2e5, + }; + + let ilow = vec![1]; + let iup = vec![2]; + let nquant = vec![1, 2]; + let nqlodf = vec![1, 2]; + let ifr0 = vec![1]; + let ifr1 = vec![1]; + let xkij = vec![1.0, 1.0]; + let fij = vec![1.0, 1.0]; + let jndodf = vec![1]; + + let odfhyd_atomic = OdfhydAtomicData { + ilow: &ilow, iup: &iup, nquant: &nquant, nqlodf: &nqlodf, + ifr0: &ifr0, ifr1: &ifr1, xkij: &xkij, fij: &fij, jndodf: &jndodf, + }; + + let temp = vec![5000.0]; + let elec = vec![1e12]; + let wnhint = vec![1e-4; 10]; + + let straux = StrAux::default(); + let mut odfhyd_model = OdfhydModelState { + temp: &temp, elec: &elec, wnhint: &wnhint, straux, + }; + + let nfrodf = vec![1]; + let fros = vec![1e15; 2000]; + let wnus = vec![1e13; 2000]; + let mut prflin = vec![0.0; 200000]; + let freq = vec![1e15]; + let kfr0 = vec![1]; + + let mut odfhyd_odf = OdfhydOdfData { + nfrodf: &nfrodf, fros: &fros, wnus: &wnus, prflin: &mut prflin, + freq: &freq, kfr0: &kfr0, indexp: &indexp, + }; + + // Should execute odfhyd and modify prflin or return without panic + odfmer(¶ms, &atomic, &model, &config, &odfhyd_atomic, &mut odfhyd_model, &mut odfhyd_odf); + + // Assert that we successfully called the function without panic + assert_eq!(odfhyd_odf.prflin.len(), 200000); } } diff --git a/src/tlusty/math/opacfd.rs b/src/tlusty/math/opacfd.rs index c00e8b2..a1f4d11 100644 --- a/src/tlusty/math/opacfd.rs +++ b/src/tlusty/math/opacfd.rs @@ -959,20 +959,176 @@ mod tests { use super::*; #[test] - fn test_opacfd_initialization() { - // 基本初始化测试 - let output = OpacfdOutput::default(); - assert_eq!(output.abso1.len(), MDEPTH); - assert_eq!(output.emis1.len(), MDEPTH); - assert_eq!(output.scat1.len(), MDEPTH); - } + fn test_opacfd_basic() { + // Minimal configuration to avoid out-of-bounds but still run some logic + let ij = 1; + let nd = 2; + let nlevel = 2; + let nion = 1; + let ntranc = 1; - #[test] - fn test_constants() { - // 验证常量 - assert!((C14 - 2.99793e14).abs() < 1e8); - assert!((CFF1 - 1.3727e-25).abs() < 1e-30); - assert!((DELT - 1e-3).abs() < 1e-10); - assert!((DELR - 1e-3).abs() < 1e-10); + // Ensure we allocate enough space to satisfy MDEPTH / MFREQ indexing + // We'll use safe small numbers, assuming MDEPTH > 2, MFREQ > 2, MLEVEL > 2 + let mdepth_size = MDEPTH.max(nd); + let mfreq_size = MFREQ.max(ij); + + let freq = vec![1e15; mfreq_size]; + let bnue = vec![1e-15; mfreq_size]; + + let temp = vec![5000.0; mdepth_size]; + let elec = vec![1e12; mdepth_size]; + let elec1 = vec![1e-12; mdepth_size]; + let dens = vec![1e14; mdepth_size]; + let hkt1 = vec![4.8e-15; mdepth_size]; + let hkt21 = vec![1.2e-15; mdepth_size]; + let temp1 = vec![2e-4; mdepth_size]; + + let sigec = vec![6.65e-25; mfreq_size]; + + let iel = vec![1; MLEVEL]; + let iz = vec![1; MLEVEL]; + let charg2 = vec![1.0; 10]; + let nnext = vec![1; 10]; + let itra = vec![1; MLEVEL * MLEVEL]; + + let itrbf = vec![1; 10]; + let ilow = vec![1; 10]; + let iup = vec![2; 10]; + let fr0 = vec![1e14; 10]; + let cross = vec![1e-18; 10 * mfreq_size]; + let crossd = vec![1e-18; 10 * mfreq_size * mdepth_size]; + + let abtra = vec![1.0; 10 * mdepth_size]; + let emtra = vec![1.0; 10 * mdepth_size]; + let demlt = vec![0.1; 10 * mdepth_size]; + + let popul = vec![1e10; MLEVEL * mdepth_size]; + let popinv = vec![1e-10; MLEVEL * mdepth_size]; + + let iatm = vec![1; MLEVEL]; + let iifix = vec![0; MLEVEL]; + let ipzero = vec![0; MLEVEL * mdepth_size]; + + let sff3 = vec![1.0; 10 * mdepth_size]; + let sff2 = vec![1.0; 10 * mdepth_size]; + let dsff = vec![0.1; 10 * mdepth_size]; + let ff = vec![1e10; 10]; + + let nfirst = vec![1; 10]; + let ielh = 1; + + let ijlin = vec![0; mfreq_size]; + let nlines = vec![0; mfreq_size]; + let itrlin = vec![0; 10 * mfreq_size]; + let prflin = vec![1.0; mdepth_size * mfreq_size]; + let ifr0 = vec![1; 10]; + let ifr1 = vec![2; 10]; + let kfr0 = vec![1; 10]; + let linexp = vec![false; 10]; + let indexp = vec![2; 10]; + + let imrg = vec![0; MLEVEL]; + let ifwop = vec![0; MLEVEL]; + let mcdw = vec![0; 10]; + + let iiexp = vec![1; MLEVEL]; + let iltref = vec![1; MLEVEL * mdepth_size]; + let imodl = vec![1; MLEVEL]; + let pt = vec![0.1; MLEVEL * mdepth_size]; + let pn = vec![0.1; MLEVEL * mdepth_size]; + let pp = vec![0.1; MLEVEL * mdepth_size]; + + let drhodt = vec![0.0; mdepth_size]; + let mut ijex = vec![1; mfreq_size]; + let mut iadop = vec![0; MLEVEL]; + + let mut jidi = vec![0; mdepth_size]; + let mut xjid = vec![1.0; mdepth_size]; + + // Fix 145GB allocation size to a more reasonable size based on usage + let mut sigfe = vec![0.0; 10 * mfreq_size]; + + + let params = OpacfdParams { + ij, nd, nlevel, nion, ntranc, + freq: &freq, bnue: &bnue, temp: &temp, elec: &elec, elec1: &elec1, + dens: &dens, hkt1: &hkt1, hkt21: &hkt21, temp1: &temp1, + sigec: &sigec, iel: &iel, iz: &iz, charg2: &charg2, nnext: &nnext, itra: &itra, + itrbf: &itrbf, ilow: &ilow, iup: &iup, fr0: &fr0, cross: &cross, crossd: &crossd, + abtra: &abtra, emtra: &emtra, demlt: &demlt, popul: &popul, popinv: &popinv, + ifdiel: 0, iopadd: 0, ioplym: 0, ifprd: 0, iter: 1, itlas: 1, + ispodf: 0, ioptab: 0, frtabm: 1e16, iatm: &iatm, iifix: &iifix, ipzero: &ipzero, + sff3: &sff3, sff2: &sff2, dsff: &dsff, ff: &ff, nfirst: &nfirst, ielh, + ijlin: &ijlin, nlines: &nlines, itrlin: &itrlin, prflin: &prflin, + ifr0: &ifr0, ifr1: &ifr1, kfr0: &kfr0, linexp: &linexp, indexp: &indexp, + imrg: &imrg, ifwop: &ifwop, mcdw: &mcdw, + nlvexp: 2, iiexp: &iiexp, iltref: &iltref, imodl: &imodl, pt: &pt, pn: &pn, pp: &pp, + inhe: 0, drhodt: &drhodt, izscal: 0, ifryb: 0, ijex: &mut ijex, iadop: &iadop, + jidi: &mut jidi, xjid: &mut xjid, sigfe: &mut sigfe, + }; + + // Mutable state arrays + let mut abso1 = vec![0.0; mdepth_size]; + let mut emis1 = vec![0.0; mdepth_size]; + let mut scat1 = vec![0.0; mdepth_size]; + let mut dabt1 = vec![0.0; mdepth_size]; + let mut demt1 = vec![0.0; mdepth_size]; + let mut dabn1 = vec![0.0; mdepth_size]; + let mut demn1 = vec![0.0; mdepth_size]; + let mut dabm1 = vec![0.0; mdepth_size]; + let mut demm1 = vec![0.0; mdepth_size]; + + let mut absff = vec![0.0; mdepth_size]; + let mut dabft = vec![0.0; mdepth_size]; + let mut dabfn = vec![0.0; mdepth_size]; + + let mut dabp1 = vec![0.0; MLEVEL * mdepth_size]; + let mut demp1 = vec![0.0; MLEVEL * mdepth_size]; + let mut elscat = vec![0.0; mdepth_size]; + + let mut xkf = vec![0.0; mdepth_size]; + let mut xkf1 = vec![0.0; mdepth_size]; + let mut xkfb = vec![0.0; mdepth_size]; + let mut dwf1 = vec![0.0; 10 * mdepth_size]; + let mut sgmg = vec![0.0; MLEVEL * mdepth_size]; + let mut absot = vec![0.0; mdepth_size]; + + let mut absoex = vec![0.0; 10 * mdepth_size]; + let mut emisex = vec![0.0; 10 * mdepth_size]; + let mut scatex = vec![0.0; 10 * mdepth_size]; + let mut dabtex = vec![0.0; 10 * mdepth_size]; + let mut demtex = vec![0.0; 10 * mdepth_size]; + let mut dabnex = vec![0.0; 10 * mdepth_size]; + let mut demnex = vec![0.0; 10 * mdepth_size]; + let mut dabmex = vec![0.0; 10 * mdepth_size]; + let mut demmex = vec![0.0; 10 * mdepth_size]; + let mut drchex = vec![0.0; 3 * MFREQ * MDEPTH]; + let mut dretex = vec![0.0; 3 * MFREQ * MDEPTH]; + + let mut dsct1 = vec![0.0; mdepth_size]; + let mut dscn1 = vec![0.0; mdepth_size]; + + let mut anh2 = vec![0.0; mdepth_size]; + let mut anhm = vec![0.0; mdepth_size]; + + let mut state = OpacfdState { + abso1: &mut abso1, emis1: &mut emis1, scat1: &mut scat1, + dabt1: &mut dabt1, demt1: &mut demt1, dabn1: &mut dabn1, + demn1: &mut demn1, dabm1: &mut dabm1, demm1: &mut demm1, + absff: &mut absff, dabft: &mut dabft, dabfn: &mut dabfn, + dabp1: &mut dabp1, demp1: &mut demp1, elscat: &mut elscat, + xkf: &mut xkf, xkf1: &mut xkf1, xkfb: &mut xkfb, + dwf1: &mut dwf1, sgmg: &mut sgmg, absot: &mut absot, + absoex: &mut absoex, emisex: &mut emisex, scatex: &mut scatex, + dabtex: &mut dabtex, demtex: &mut demtex, dabnex: &mut dabnex, + demnex: &mut demnex, dabmex: &mut dabmex, demmex: &mut demmex, + drchex: &mut drchex, dretex: &mut dretex, + dsct1: &mut dsct1, dscn1: &mut dscn1, anh2: &mut anh2, anhm: &mut anhm, + }; + + opacfd(¶ms, &mut state); + + // Core validation, verify the state was mutated meaningfully + assert!(state.abso1[0] > 0.0 || state.emis1[0] > 0.0 || state.scat1[0] > 0.0); } } diff --git a/src/tlusty/math/opdata.rs b/src/tlusty/math/opdata.rs index b480a15..101814e 100644 --- a/src/tlusty/math/opdata.rs +++ b/src/tlusty/math/opdata.rs @@ -135,9 +135,51 @@ pub fn opdata_check(file_path: &str) -> Result { #[cfg(test)] mod tests { use super::*; + use std::io::Write; + use std::fs; #[test] - fn test_opdata_params_default() { + fn test_opdata_functional() { + // Create a temporary mock file for RBF.DAT + let file_path = std::env::temp_dir().join("mock_rbf.dat"); + let mut file = File::create(&file_path).unwrap(); + + // FortranReader `read_line()` buffers the read line in `remaining` + // Then `read_value()` tokenizes `remaining`. + // opdata_check reads 21 lines, then calls `read_value()` for `neop`. + // This means `neop` comes from the 21st line! + + // Lines 1-20 (Indices 0..20) + for _ in 0..20 { + writeln!(file, "0").unwrap(); + } + + // Line 21: read by 21st `read_line`, parsed by `read_value` for `neop` + // We set it to "1" + writeln!(file, "1").unwrap(); + + // `opdata` skips 3 element lines, then calls `read_value` for `niop`. + // So the 3rd element line must be the value for `niop`. + writeln!(file, "0").unwrap(); // Line 22 + writeln!(file, "0").unwrap(); // Line 23 + writeln!(file, "1").unwrap(); // Line 24: parsed as niop = 1 + + // The following lines are parsed directly via read_line + split + // ionid, iatom, ielec, nlevel_op=1 (Line 25) + writeln!(file, "ION1 1 1 1").unwrap(); + + // idlvop, nop=2 (Line 26) + writeln!(file, "LEVEL1 2").unwrap(); + + // index, xop, sop (Lines 27-28) + writeln!(file, "1 0.1 1.0").unwrap(); + writeln!(file, "2 0.2 2.0").unwrap(); + + // Ensure buffers are flushed + file.sync_all().unwrap(); + + + // Structure init let mut sop = vec![vec![0.0; MMAXOP]; MOP]; let mut xop = vec![vec![0.0; MMAXOP]; MOP]; let mut nop = vec![0; MMAXOP]; @@ -145,7 +187,7 @@ mod tests { let mut ntotop = 0; let mut loprea = false; - let params = OpdataParams { + let mut params = OpdataParams { sop: &mut sop, xop: &mut xop, nop: &mut nop, @@ -154,9 +196,26 @@ mod tests { loprea: &mut loprea, }; - // 验证参数结构正确 - assert_eq!(params.sop.len(), MOP); - assert_eq!(params.xop.len(), MOP); - assert_eq!(params.nop.len(), MMAXOP); + // Test opdata_check + let check_res = opdata_check(file_path.to_str().unwrap()).unwrap(); + assert!(check_res); + + // Test opdata + let res = opdata(file_path.to_str().unwrap(), &mut params).unwrap(); + + // Verify changes + assert_eq!(res.ntotop, 1); + assert_eq!(*params.ntotop, 1); + assert!(*params.loprea); + + assert_eq!(params.idlvop[0], "LEVEL1"); + assert_eq!(params.nop[0], 2); + assert_eq!(params.xop[0][0], 0.1); + assert_eq!(params.sop[0][0], 1.0); + assert_eq!(params.xop[1][0], 0.2); + assert_eq!(params.sop[1][0], 2.0); + + // Cleanup + let _ = fs::remove_file(file_path); } }