From 8e21522d2da8efaad21410e7aa733bbdf4ca0bd0 Mon Sep 17 00:00:00 2001 From: Asfmq <2696428814@qq.com> Date: Thu, 19 Mar 2026 22:16:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=841?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + REFACTORING_PROGRESS.txt | 258 +- docs/sp_fortran.md | 403 ++ scripts/extract_fortran_data.py | 438 +++ scripts/fortran_to_rust_array.py | 205 + src/data.rs | 5981 ++++++++++++++++++++++++++++++ src/lib.rs | 14 + src/math/angset.rs | 168 + src/math/butler.rs | 271 ++ src/math/cion.rs | 231 ++ src/math/ckoest.rs | 137 + src/math/collhe.rs | 378 ++ src/math/cross.rs | 307 ++ src/math/dielrc.rs | 228 ++ src/math/gamsp.rs | 61 + src/math/getwrd.rs | 110 + src/math/gfree.rs | 351 ++ src/math/irc.rs | 117 + src/math/mod.rs | 44 + src/math/pffe.rs | 193 + src/math/pfni.rs | 126 + src/math/pfspec.rs | 152 + src/math/sbfch.rs | 215 ++ src/math/sbfhe1.rs | 213 ++ src/math/sbfhmi_old.rs | 109 + src/math/sbfoh.rs | 185 + src/math/spsigk.rs | 114 + src/math/tiopf.rs | 204 + src/math/verner.rs | 298 ++ src/math/wn.rs | 138 + src/state/alipar.rs | 250 ++ src/state/arrays.rs | 329 ++ src/state/atomic.rs | 422 +++ src/state/config.rs | 428 +++ src/state/constants.rs | 164 + src/state/iterat.rs | 246 ++ src/state/mod.rs | 32 + src/state/model.rs | 524 +++ src/state/odfpar.rs | 466 +++ tlusty/extracted/sbfch.f | 4 +- tlusty/extracted/sbfoh.f | 8 +- 41 files changed, 14497 insertions(+), 26 deletions(-) create mode 100644 docs/sp_fortran.md create mode 100644 scripts/extract_fortran_data.py create mode 100644 scripts/fortran_to_rust_array.py create mode 100644 src/data.rs create mode 100644 src/math/angset.rs create mode 100644 src/math/butler.rs create mode 100644 src/math/cion.rs create mode 100644 src/math/ckoest.rs create mode 100644 src/math/collhe.rs create mode 100644 src/math/cross.rs create mode 100644 src/math/dielrc.rs create mode 100644 src/math/gamsp.rs create mode 100644 src/math/getwrd.rs create mode 100644 src/math/gfree.rs create mode 100644 src/math/irc.rs create mode 100644 src/math/pffe.rs create mode 100644 src/math/pfni.rs create mode 100644 src/math/pfspec.rs create mode 100644 src/math/sbfch.rs create mode 100644 src/math/sbfhe1.rs create mode 100644 src/math/sbfhmi_old.rs create mode 100644 src/math/sbfoh.rs create mode 100644 src/math/spsigk.rs create mode 100644 src/math/tiopf.rs create mode 100644 src/math/verner.rs create mode 100644 src/math/wn.rs create mode 100644 src/state/alipar.rs create mode 100644 src/state/arrays.rs create mode 100644 src/state/atomic.rs create mode 100644 src/state/config.rs create mode 100644 src/state/constants.rs create mode 100644 src/state/iterat.rs create mode 100644 src/state/mod.rs create mode 100644 src/state/model.rs create mode 100644 src/state/odfpar.rs diff --git a/.gitignore b/.gitignore index e491275..b50766b 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,5 @@ desktop.ini *.log *.tmp +__pycache__ .claude/ \ No newline at end of file diff --git a/REFACTORING_PROGRESS.txt b/REFACTORING_PROGRESS.txt index 9293e4e..4043903 100644 --- a/REFACTORING_PROGRESS.txt +++ b/REFACTORING_PROGRESS.txt @@ -9,8 +9,71 @@ ## 当前状态 -- **已完成重构**: 28 个函数 -- **测试通过**: 102 个 (单元测试 + Fortran 对比测试 + 文档测试) +- **已完成重构**: 62 个函数 + 8 个状态模块 + 1 个数据文件 (src/data.rs) +- **测试通过**: 281 个 +- **最后更新**: 2026-03-19 +- **TLUSTY 纯函数重构基本完成** (剩余 4 个有复杂依赖) + +### 已完成模块列表 + +| 模块 | 说明 | +|------|------| +| angset | Compton 散射角度设置 | +| betah | 压力标高 | +| bkhsgo | K/L 壳层光电离截面 | +| butler | H 碰撞激发速率 | +| carbon | C 光电离截面 | +| ceh12 | H I Lyman-α 碰撞速率 | +| cion | 碰撞电离速率 | +| ckoest | Koester He I 光电离拟合 | +| collhe | He 碰撞速率系数 | +| dielrc | 双电子复合速率 | +| erfcx | 余误差函数 | +| expint | 指数积分 E₁ | +| expo | 安全指数函数 | +| ffcros | 自由-自由截面 (桩) | +| gami | γ 函数 | +| gamsp | 用户自定义展宽参数 (占位) | +| gauleg | Gauss-Legendre 积分 | +| gaunt | Gaunt 因子 | +| getwrd | 文本单词提取 | +| gfree | 氢自由-自由 Gaunt 因子 | +| gntk | Kramers-Gaunt 截面 | +| grcor | 广义相对论修正因子 | +| hephot | He I 光电离截面 | +| hidalg | Hidalgo 光电离数据 | +| indexx | 堆排序索引 | +| interpolate | Lagrange/线性插值 | +| irc | 氢原子碰撞电离速率 | +| laguer | Laguerre 根 | +| locate | 二分查找 | +| minv3 | 3x3 矩阵求逆 | +| pffe | Fe IV-IX 配分函数 | +| pfni | Ni IV-IX 配分函数 | +| pfspec | 特殊元素配分函数 | +| quartc | 四次方程求根 | +| quit | 退出处理 | +| raph | Newton-Raphson 迭代 | +| reiman | Reilman-Manson 光电离 | +| sbfch | CH 束缚-自由截面 | +| sbfhe1 | He I 束缚-自由截面 | +| sbfhmi | H⁻ 束缚-自由截面 | +| sbfhmi_old | H⁻ 束缚-自由截面 (旧版) | +| sbfoh | OH 束缚-自由截面 | +| sffhmi | H⁻ 自由-自由截面 | +| sghe12 | He I 截面 | +| spsigk | 特殊光电离截面 | +| stark0 | Stark 轮廓参数 | +| szirc | 电子碰撞电离速率 | +| tiopf | Ti 光电离截面 | +| tridag | 三对角矩阵求解 | +| ubeta | U(β) 函数插值 | +| voigt | Voigt 轮廓 | +| voigte | Voigt 轮廓 (替代) | +| verner | Verner 光电离 (有 COMMON 依赖) | +| wn | 占据概率 (有 COMMON 依赖) | +| xk2dop | Doppler 宽度转换 | +| ylintp | 对数插值 | ## 状态说明 @@ -30,22 +93,22 @@ | expo.f | 10 | ✅ | 2026-03-19 | 安全指数函数 | | quit.f | 10 | ✅ | 2026-03-19 | 退出子程序 | | ffcros.f | 13 | ✅ | 2026-03-19 | 自由-自由截面 (占位) | -| gamsp.f | 14 | ⬜ | | 展宽因子 (有 COMMON) | -| sgmer1.f | 14 | ⬜ | | Stark展宽 (有 COMMON) | -| sgmerd.f | 15 | ⬜ | | Stark展宽 (有 COMMON) | +| gamsp.f | 14 | ✅ | 2026-03-19 | 展宽因子 (有 COMMON) | +| sgmer1.f | 14 | ❌ | | Stark展宽 (有 COMMON) | +| sgmerd.f | 15 | ❌ | | Stark展宽 (有 COMMON) | | lagran.f | 16 | ✅ | 2026-03-19 | Lagrange插值 | | gntk.f | 17 | ✅ | 2026-03-19 | Gaunt因子 | | raph.f | 17 | ✅ | 2026-03-19 | hedif辅助函数 | -| cross.f | 18 | ⬜ | | 截面计算 (有 COMMON) | +| cross.f | 18 | ✅ | 2026-03-19 | 截面计算 (有 COMMON) | | eint.f | 18 | ✅ | 2026-03-19 | 指数积分 (含 expinx) | | sghe12.f | 18 | ✅ | 2026-03-19 | He展宽 | | yint.f | 18 | ✅ | 2026-03-19 | 二次插值 | | erfcin.f | 20 | ✅ | 2026-03-19 | 误差函数补 | | erfcx.f | 20 | ✅ | 2026-03-19 | 缩放误差函数 | -| gfree1.f | 21 | ⬜ | | Gaunt自由 (有 COMMON) | -| sbfhmi_old.f | 22 | ⬜ | | H-截面 | +| gfree1.f | 21 | ✅ | 2026-03-19 | Gaunt自由 (有 COMMON) | +| sbfhmi_old.f | 22 | ✅ | 2026-03-19 | H-截面 | | tridag.f | 22 | ✅ | 2026-03-19 | 三对角矩阵 | -| timing.f | 24 | ⬜ | | 计时 | +| timing.f | 24 | ❌ | | 计时 (有 I/O) | | expint.f | 30 | ✅ | 2026-03-19 | 指数积分 | ### 优先级 P1 (中等大小) @@ -58,19 +121,19 @@ | gauleg.f | 34 | ✅ | 2026-03-19 | Gauss-Legendre积分 | | quartc.f | 35 | ✅ | 2026-03-19 | 四次方程求解 | | minv3.f | 37 | ✅ | 2026-03-19 | 3x3矩阵求逆 | -| crossd.f | 31 | ⬜ | | | -| wn.f | 41 | ⬜ | | | -| sbfhmi.f | 42 | ⬜ | | H-截面 | -| angset.f | 44 | ⬜ | | | +| crossd.f | 31 | ✅ | 2026-03-19 | 截面计算+双电子复合 (有 COMMON) | +| wn.f | 41 | ✅ | 2026-03-19 | 占据概率 (有 COMMON) | +| sbfhmi.f | 42 | ✅ | 2026-03-19 | H-截面 | +| angset.f | 44 | ✅ | 2026-03-19 | 角度设置 (有 COMMON) | | gami.f | 45 | ✅ | 2026-03-19 | 微扰展宽 | -| gaunt.f | 45 | ⬜ | | Gaunt因子 | -| ubeta.f | 40 | ⬜ | | | -| rayini.f | 42 | ⬜ | | | +| gaunt.f | 45 | ✅ | 2026-03-19 | Gaunt因子 | +| ubeta.f | 40 | ✅ | 2026-03-19 | U(β) 函数 | +| rayini.f | 42 | ❌ | | 射线初始化 (有 I/O) | | indexx.f | 45 | ✅ | 2026-03-19 | 索引排序 | | laguer.f | 59 | ✅ | 2026-03-19 | Laguerre多项式求根 | -| sbfhe1.f | 157 | ⬜ | | He截面 | -| hephot.f | 163 | ⬜ | | He光电离 | -| verner.f | 237 | ⬜ | | Verner截面 | +| sbfhe1.f | 157 | ✅ | 2026-03-19 | He截面 (有 COMMON) | +| hephot.f | 163 | ✅ | 2026-03-19 | He光电离 | +| verner.f | 237 | ✅ | 2026-03-19 | Verner截面 (有 COMMON) | | voigt.f | 64 | ✅ | 2026-03-19 | Voigt线型 | | voigte.f | 92 | ✅ | 2026-03-19 | Voigt线型 | | locate.f | 25 | ✅ | 2026-03-19 | 二分查找 | @@ -112,8 +175,30 @@ - 重构 xk2dop.f → src/math/xk2dop.rs - 重构 minv3.f → src/math/minv3.rs - 重构 laguer.f → src/math/laguer.rs +- 重构 collhe.f → src/math/collhe.rs (He 碰撞速率, 929 元素大数组) +- 重构 butler.f → src/math/butler.rs (H 碰撞激发) +- 重构 cion.f → src/math/cion.rs (碰撞电离) +- 重构 irc.f → src/math/irc.rs (H 碰撞电离速率) +- 重构 getwrd.f → src/math/getwrd.rs (文本解析) +- 重构 spsigk.f → src/math/spsigk.rs (特殊光电离) +- 重构 tiopf.f → src/math/tiopf.rs (Ti 光电离) +- 重构 sbfhmi_old.f → src/math/sbfhmi_old.rs (H- 束缚-自由旧版) +- 重构 bkhsgo.f → src/math/bkhsgo.rs (K/L 壳层光电离) +- 重构 carbon.f → src/math/carbon.rs (C 光电离) +- 重构 hephot.f → src/math/hephot.rs (He 光电离) +- 重构 hidalg.f → src/math/hidalg.rs (Hidalgo 光电离) +- 重构 reiman.f → src/math/reiman.rs (Reilman-Manson 光电离) +- 重构 sbfhmi.f → src/math/sbfhmi.rs (H- 束缚-自由) +- 重构 sffhmi.f → src/math/sffhmi.rs (H- 自由-自由) +- 重构 grcor.f → src/math/grcor.rs (广义相对论修正) +- 重构 gaunt.f → src/math/gaunt.rs (Gaunt 因子) +- 重构 stark0.f → src/math/stark0.rs (Stark 轮廓) +- 重构 szirc.f → src/math/szirc.rs (电子碰撞电离) +- 重构 ubeta.f → src/math/ubeta.rs (U(β) 函数) +- 重构 dielrc.f → src/math/dielrc.rs (双电子复合速率, 18 个大型数组) +- 重构 pfni.f → src/math/pfni.rs (Ni IV-IX 配分函数, 12 个数组) - 创建 Fortran 对比测试框架 (tests/fortran_ref/, tests/fortran_comparison.rs) -- **102 个测试通过** (75 单元测试 + 12 Fortran 对比测试 + 4 文档测试) +- **224 个测试通过** (208 单元测试 + 12 Fortran 对比测试 + 4 文档测试) **规范:** - 代码注释使用中文 @@ -125,3 +210,136 @@ - Fortran 1-indexed 数组转 Rust 0-indexed 时要特别注意边界条件 - `erfcin` 中 `XL=-LOG(X)` 是 `-ln(X)`,不是 `ln(-X)` - `ylintp` 在 0-indexed 中 jl=0 是有效索引,不需要调整 +- `collhe` 中 Clenshaw 求和的 `ir` 和 `jj` 必须用有符号整数 (`isize`),否则递减时会溢出 +- `collhe` 的索引计算 `((iu+1)^2 - 3*(iu+1) + 4)/2` 在 Rust 中需用 `i32` 避免中间结果溢出 + +### 2026-03-19 (续) + +**修复:** +- 修复 `pffe.rs` 中的数组引用错误:`P6A/P6B` 应使用 `PFFE_P6A/PFFE_P6B` + +**待重构的纯函数分析:** +- `SBFCH` (278行): CH 束缚-自由截面,有 1575 个数据点 +- `SBFOH` (327行): OH 束缚-自由截面,有 1950 个数据点 +- `TIMING` (24行): 有 I/O 依赖,不适合纯函数 +- `CIA_*` (89-90行): 有文件 I/O,需要特别处理 + +**当前模块统计:** +- 49 个 Rust 模块 (不含 mod.rs) +- 218 个单元测试 +- 12 个 Fortran 对比测试 +- 4 个文档测试 + +**新增模块:** +- 重构 sbfch.f → src/math/sbfch.rs (CH 束缚-自由截面, 1575 个数据点) +- 重构 sbfoh.f → src/math/sbfoh.rs (OH 束缚-自由截面, 1950 个数据点) + +**脚本改进:** +- 修改 `extract_fortran_data.py`: 所有变量都添加文件名前缀 (如 `SBFCH_C1`, `DIELRC_ADI`) +- 避免不同文件中同名变量冲突 + +### 2026-03-19 (进度总结) + +**当前状态:** +- **49 个 Rust 模块**已完成 +- **234 个测试通过** (218 单元测试 + 12 Fortran 对比测试 + 4 文档测试) + +**纯函数重构完成度分析:** + +TLUSTY 原有 195 个无 COMMON 依赖的纯函数,其中大部分已经重构。剩余的函数可分为两类: + +1. **有 COMMON/IO 依赖的函数** (暂时不重构): + - `gamsp.f`, `sgmer1.f`, `sgmerd.f` - Stark 展宽 + - `cross.f`, `crossd.f` - 截面计算 + - `gfree1.f` - Gaunt 自由 + - `wn.f` - 占据概率 + - `angset.f` - 角度设置 + - `rayini.f` - 射线初始化 (有文件 I/O) + - `sbfhe1.f` - He 截面 + - `verner.f`, `vern16/18/20/26.f` - Verner 截面 + - `timing.f` - 计时 (有 I/O) + - `CIA_*` - 碰撞诱导吸收 (有文件 I/O) + +2. **可能遗漏的纯函数**: + - 需要进一步检查 `gfree0.f`, `gfreed.f` 等函数 + +**下一步计划:** +1. 检查 `gfree0.f`, `gfreed.f` 是否为纯函数 +2. 如果是纯函数,继续重构 +3. 考虑 SYNSPEC 纯函数的重构 + +**图例说明:** +- ✅ 已完成 +- ❌ 有 COMMON/IO 依赖 (暂不处理) +- ⬜ 待处理 + +### 2026-03-19 (状态模块重构) + +**新增 state 模块** - 将 Fortran COMMON 块转换为 Rust struct + +| 文件 | 对应 Fortran | 说明 | +|------|-------------|------| +| src/state/mod.rs | - | 模块入口 | +| src/state/constants.rs | BASICS.FOR | 物理常数和维度参数 | +| src/state/config.rs | BASICS.FOR | 运行时配置 (BASNUM, INPPAR 等) | +| src/state/atomic.rs | ATOMIC.FOR | 原子/离子/能级数据 (ATOPAR, IONPAR 等) | +| src/state/model.rs | MODELQ.FOR | 大气模型状态 (MODPAR, LEVPOP 等) | +| src/state/arrays.rs | ARRAY1.FOR | 大型计算数组 | + +**COMMON 块映射:** + +| Fortran COMMON | Rust struct | 文件 | +|----------------|-------------|------| +| /BASNUM/ | BasNum | config.rs | +| /INPPAR/ | InpPar | config.rs | +| /MATKEY/ | MatKey | config.rs | +| /RUNKEY/ | RunKey | config.rs | +| /CONKEY/ | ConKey | config.rs | +| /OPCPAR/ | OpcPar | config.rs | +| /ANGLES/ | Angles | config.rs | +| /ATOPAR/ | AtoPar | atomic.rs | +| /IONPAR/ | IonPar | atomic.rs | +| /LEVPAR/ | LevPar | atomic.rs | +| /TRAPAR/ | TraPar | atomic.rs | +| /PHOSET/ | PhoSet | atomic.rs | +| /VOIPAR/ | VoiPar | atomic.rs | +| /MODPAR/ | ModPar | model.rs | +| /LEVPOP/ | LevPop | model.rs | +| /GFFPAR/ | GffPar | model.rs | +| /TOTRAD/ | TotRad | model.rs | +| /CURRAD/ | CurRad | model.rs | +| /FRQALL/ | FrqAll | model.rs | +| 无标签 COMMON | MainArrays | arrays.rs | +| /EXPRAD/ | ExpRad | arrays.rs | +| /BPOCOM/ | BpoCom | arrays.rs | + +**综合结构:** +- `TlustyConfig` - 综合配置 (包含所有控制参数) +- `AtomicData` - 综合原子数据 +- `ModelState` - 综合模型状态 +- `ComputeArrays` - 综合计算数组 + +**测试更新:** +- 255 个测试通过 (239 单元测试 + 12 Fortran 对比测试 + 4 文档测试) + +### 2026-03-19 (完成 .FOR 文件重构) + +**完成所有 TLUSTY .FOR 文件重构:** + +| 文件 | Rust 模块 | COMMON 块 | +|------|-----------|-----------| +| ITERAT.FOR | iterat.rs | LAMBDA, CHNMAT, ACCEL, ACCLP, ACCLT, CHNAD | +| ALIPAR.FOR | alipar.rs | FIXALP (ALI 数组) | +| ODFPAR.FOR | odfpar.rs | ODFION, ODFCTR, ODFFRQ, ODFMOD, ODFSTK, SPLCOM, OPALIM, OPLIMT, LEVCOM | + +**新增常量:** +- MLEVE3, MLVEX3, MTRAN3 (对角/三对角预处理) +- MCROSS, MBF (截面和束缚-自由跃迁) + +**内存估算:** +- SplCom (Fe 线数据): ~90 MB +- LevCom (Kurucz 能级): ~0.5 MB +- FixAlp (ALI 数组): ~数百 MB (取决于 MLVEXP) + +**所有 TLUSTY .FOR 文件已重构完成!** + diff --git a/docs/sp_fortran.md b/docs/sp_fortran.md new file mode 100644 index 0000000..bab0380 --- /dev/null +++ b/docs/sp_fortran.md @@ -0,0 +1,403 @@ + +--- + +## TLUSTY208.F 拆分工作 (2026-03-18) + +### 任务:将单文件拆分为多个独立模块 + +**执行流程:** + +```bash +cd /home/fmq/program/tlusty/tl208-s54/rust +python3 extract_fortran.py tlusty/tlusty208.f tlusty/extracted/ +cp tlusty/*.FOR tlusty/extracted/ +``` + +### 提取结果 + +| 项目 | 数量 | +|------|------| +| 程序单元 | **304** | +| 子程序 (SUBROUTINE) | 269 | +| 函数 (FUNCTION) | 32 | +| 主程序 (PROGRAM) | 1 | +| BLOCK DATA | **2** (含1个无名) | +| 无 COMMON 依赖的纯函数 | 195 | + +> 注意: 2026-03-19 修复了无名 BLOCK DATA 提取问题,单元数从 303 增加到 304 + +### Include 文件 + +``` +tlusty/extracted/*.FOR +├── IMPLIC.FOR # 隐式类型声明 +├── BASICS.FOR # 基本参数和物理常数 +├── ITERAT.FOR # 迭代控制参数 +├── ALIPAR.FOR # ALI 参数 +├── ATOMIC.FOR # 原子数据 +├── MODELQ.FOR # 模型物理量 +├── ODFPAR.FOR # ODF 参数 +└── ARRAY1.FOR # 主工作数组 +``` + +### 编译配置 + +**关键编译选项**: +```makefile +FFLAGS = -O3 -fno-automatic -mcmodel=large +``` + +- `-mcmodel=large`: 支持 >2GB 地址空间 +- `-fno-automatic`: 所有变量默认为静态存储(兼容旧Fortran代码) +- **不要使用** `-ffixed-line-length-none`: 会将第73-80列的注释区当作代码解析 + +### 编译验证 + +```bash +cd tlusty/extracted && make clean && make +# 生成: tlusty_extracted (1,940,488 bytes) + +# 直接编译 +gfortran -fno-automatic -mcmodel=large -O3 -o tlusty.exe tlusty208.f +# 生成: tlusty.exe (1,997,416 bytes) +``` + +**结论**: 功能等价,拆分编译文件更小 (-2.9%) + +### 拆分编译 vs 直接编译对比 + +| 方面 | 直接编译 | 拆分编译 | +|------|---------|---------| +| 文件大小 | 1,997,416 B | 1,940,488 B | +| 功能 | 相同 | 相同 | +| 增量编译 | ❌ | ✅ | +| 代码定位 | 困难 | 简单 | + +### 无 COMMON 依赖的纯函数 (198个) + +可独立测试和重构的单元: +``` +ACCEL2, ALIFR1, ALIFR3, ALIFR6, ALIFRK, ALISK1, ALISK2, ALIST1, ALIST2, +ANGSET, BETAH, BHE, BKHSGO, BPOP, BPOPE, BPOPF, BPOPT, BRE, BREZ, +BRTE, BRTEZ, BUTLER, CARBON, CEH12, CHANGE, CHCKSE, CHEAV, CHEAVJ, +CIA_H2H, CIA_H2H2, CIA_H2HE, CIA_HHE, CION, CKOEST, COLH, COLHE, +COLLHE, CONCOR, CORRWM, CROSS, CROSSD, CSPEC, DIELRC, DIETOT, DIVSTR, +DMEVAL, DOPGAM, DWNFR, DWNFR0, DWNFR1, EINT, EMAT, ENTENE, ERFCIN, +ERFCX, EXPINT, EXPINX, EXPO, FFCROS, GAMI, GAMSP, GAULEG, GAUNT, +GETWRD, GFREE0, GFREE1, GFREED, GNTK, GRCOR, GREYD, GRIDP, H2MINUS, +HEPHOT, HIDALG, IJALI2, IJALIS, INCLDY, INDEXX, INIFRS, INILAM, INTERP, +INTHYD, INTLEM, INTXEN, IRC, LAGRAN, LAGUER, LEMINI, LEVGRP, LEVSET, +LEVSOL, LINEQS, LINSEL, LINSET, LINSPL, LOCATE, LTEGR, LUCY, LYMLIN, +MATGEN, MATINV, MEANOP, MEANOPT, MINV3, NEWPOP, NSTOUT, ODF1, ODFFR, +ODFHST, ODFHYD, ODFHYS, ODFMER, OPACFL, OPADD0, OPAHST, OPAINI, OPCTAB, +OSCCOR, OUTPUT, PFCNO, PFFE, PFHEAV, PFNI, PFSPEC, PRCHAN, PRD, PRDINI, +PRINC, PRNT, PROFSP, PSOLVE, PZERT, QUARTC, QUIT, RADPRE, RAPH, RATES1, +RATMAL, RATMAT, RATSP1, RAYINI, RAYSET, RDATAX, READBF, RECHCK, REFLEV, +REIMAN, RHOEOS, RHONEN, ROSSOP, ROSSTD, RTEDF2, RTEFE2, RTESOL, RTE_SC, +SABOLF, SBFCH, SBFHE1, SBFHMI, SBFHMI_OLD, SBFOH, SFFHMI, SFFHMI_ADD, +SGHE12, SGMER0, SGMER1, SGMERD, SIGAVE, SIGK, SIGMAR, SPSIGK, SRTFRQ, +STARK0, STARKA, SWITCH, SZIRC, TDPINI, TIMING, TIOPF, TLUSTY, TRAINI, +TRIDAG, UBETA, VERN16, VERN18, VERN20, VERN26, VERNER, VISINI, VOIGT, +VOIGTE, WN, WNSTOR, XENINI, XK2DOP, YINT, YLINTP, ZMRHO +``` +--- + +## SYNSPEC54.F 拆分工作 (2026-03-18) + +### 任务:将单文件拆分为多个独立模块 + +**执行流程:** + +#### 1. 创建提取脚本 `extract_fortran.py` + +```python +# 核心功能: +# - 正则匹配 SUBROUTINE/FUNCTION/PROGRAM/BLOCK DATA +# - 查找对应的 END 语句确定边界 +# - 提取到独立 .f 文件 +# - 分析 COMMON 块依赖 +# - 生成 Makefile +``` + +#### 2. 运行提取 + +```bash +cd /home/fmq/program/tlusty/tl208-s54/rust +python3 extract_fortran.py synspec/synspec54.f synspec/extracted/ +cp synspec/*.FOR synspec/extracted/ +``` + +#### 3. 提取结果 + +| 项目 | 数量 | +|------|------| +| 程序单元 | 168 | +| 子程序 (SUBROUTINE) | 134 | +| 函数 (FUNCTION) | 33 | +| 主程序 (PROGRAM) | 1 | +| 总代码行数 | 23,050 | +| 无 COMMON 依赖的纯函数 | 93 | + +#### 4. 编译配置 + +**关键编译选项** (解决大型 COMMON 数组链接问题): +```makefile +FFLAGS = -O3 -fno-automatic -mcmodel=large +``` + +- `-mcmodel=large`: 支持 >2GB 地址空间 +- `-fno-automatic`: 所有变量默认为静态存储(兼容旧Fortran代码) +- **不要使用** `-ffixed-line-length-none`: 会将第73-80列的注释区当作代码解析 + +#### 5. 编译验证 + +```bash +cd synspec/extracted && make clean && make +# 生成: synspec_extracted (1,000,408 bytes) +``` + +**对比原始编译:** +```bash +gfortran -O3 -fno-automatic -mcmodel=large -o synspec_direct.exe synspec54.f +# 生成: synspec_direct.exe (1,044,928 bytes) +``` + +**结论**: 功能完全等价,拆分编译更小 (-4.3%) + +### 生成的文件结构 + +``` +synspec/extracted/ +├── synspec.f # 主程序 (174行) +├── start.f # 子程序 (107行) +├── sbfhmi.f # H⁻ 光电离截面函数 (42行) +├── expint.f # 指数积分函数 (18行) +├── ... # 共168个 .f 文件 +├── PARAMS.FOR # 参数定义 (include) +├── MODELP.FOR # 模型参数 (include) +├── LINDAT.FOR # 谱线数据 (include) +├── SYNTHP.FOR # 合成谱参数 (include) +├── WINCOM.FOR # 窗口通信 (include) +├── Makefile # 自动构建 +├── _SUMMARY.txt # 提取摘要 +├── _COMMON_ANALYSIS.txt # COMMON 依赖分析 +└── _PURE_UNITS.txt # 纯函数列表 +``` + +### COMMON 块分析结果 + +**有 COMMON 依赖的单元**: 75 个 +**唯一 COMMON 块**: 68 个 + +主要 COMMON 块: +- `BLAPAR`, `LIMPAR` - 谱线参数 +- `EMFLUX` - 辐射流 +- `RTEOPA` - 辐射转移不透明度 +- `NLTPOP` - 非LTE布居数 +- `lasers` - 激光数据处理 + +### 拆分编译 vs 直接编译对比 + +| 方面 | 直接编译 | 拆分编译 | +|------|---------|---------| +| 文件大小 | 1,044,928 B | 1,000,408 B | +| 功能 | 相同 | 相同 | +| 增量编译 | ❌ | ✅ | +| 代码定位 | 困难 | 简单 | +| 模块化重构 | 困难 | 容易 | + +### 提取脚本位置 + +``` +extract_fortran.py +``` + +### 推荐用法 + +```bash +# 开发/调试/重构 +cd synspec/extracted && make + +# 生产环境/快速编译 +cd synspec && gfortran -O3 -fno-automatic -mcmodel=large -o synspec.exe synspec54.f +``` + +### 无 COMMON 依赖的纯函数 (93个) + +可独立测试和重构的函数: +``` +CARBON, CHANGE, CHCKAB, CIA_H2H, CIA_H2H2, CIA_H2HE, CIA_HHE, +COUNT_WORDS, DENSIT, DIVHE2, DIVSTR, DWNFR0, DWNFR1, EPS, +EXOPF, EXPINT, EXTPRF, FEAUTR, GAMHE, GAUNT, GETWRD, GFREE, +GNTK, GRIEM, H2MINUS, H2OPF, HE2SET, HE2SEW, HEPHOT, HESET, +HIDALG, HYDINI, HYDTAB, HYLSET, HYLSEW, INIBLM, INKUR, INPBF, +INTERP, INTHYD, INTRP, INTXEN, IRWPF, ISPEC, LEVSOL, LINEQS, +LOCATE, LYMLIN, MATINV, MOLOP, MPARTF, OPADD, PARTDV, PARTF, +PFFE, PFHEAV, PFNI, PFSPEC, PHTX, QUIT, RATMAT, READBF, +REIMAN, SABOLF, SBFCH, SBFHE1, SBFHMI, SBFHMI_OLD, SBFOH, +SETRAY, SFFHMI, SFFHMI_OLD, SGHE12, SGMERG, SPSIGK, STARK0, +STARKA, STARKIR, STATE0, SYNSPEC, TINT, TRIDAG, VELSET, +VOIGTE, VOPF, WGTJH1, WN, WNSTOR, WTOT, XENINI, XK2DOP, YINT, YLINTP +``` + +--- + +## 功能验证测试 (2026-03-19) + +### 测试环境变量 + +```bash +export TL208=/home/fmq/program/tlusty +export TLUSTY=$TL208/tl208-s54 +export LINELIST=$TL208/linelist +export IRON=$TL208/irondata +export OPTABLES=$TL208/optables +``` + +### 测试目录 + +``` +tests/tlusty/hhe/ # H-He 模型测试用例 +├── hhe35lt.5 # LTE 模型输入 +├── hhe35nc.5 # NLTE continua 模型输入 +├── hhe35nl.5 # NLTE with lines 模型输入 +└── hhe35*.7,9,14 # 预期输出文件 +``` + +### 测试流程 + +```bash +cd /home/fmq/program/tlusty/tl208-s54/rust/tests/tlusty + +# 创建测试目录 +mkdir -p test_extracted +cd test_extracted +cp ../hhe/*.5 . +ln -sf $TLUSTY/data data + +# 设置环境变量 +export TL208=/home/fmq/program/tlusty +export TLUSTY=$TL208/tl208-s54 +export LINELIST=$TL208/linelist +export IRON=$TL208/irondata +export OPTABLES=$TL208/optables + +# 可执行文件路径 +EXE=../../tlusty/extracted/build/tlusty_extracted + +# 测试1: LTE 模型 (从零开始) +$EXE < hhe35lt.5 > hhe35lt.6 +cp fort.7 hhe35lt.7; cp fort.9 hhe35lt.9; cp fort.14 hhe35lt.14 + +# 测试2: NLTE continua (使用 LTE 作为初始模型) +cp hhe35lt.7 fort.8 +$EXE < hhe35nc.5 > hhe35nc.6 +cp fort.7 hhe35nc.7; cp fort.9 hhe35nc.9; cp fort.14 hhe35nc.14 + +# 测试3: NLTE with lines (使用 NC 作为初始模型) +cp hhe35nc.7 fort.8 +$EXE < hhe35nl.5 > hhe35nl.6 +cp fort.7 hhe35nl.7; cp fort.9 hhe35nl.9; cp fort.14 hhe35nl.14 + +# 验证: 与原始结果比较 +diff hhe35lt.7 ../hhe/hhe35lt.7 +diff hhe35nc.7 ../hhe/hhe35nc.7 +diff hhe35nl.7 ../hhe/hhe35nl.7 +``` + +### 测试结果 + +| 测试用例 | 拆分编译 | 直接编译 | 原始结果 | +|----------|----------|----------|----------| +| hhe35lt (LTE) | ✓ 通过 | ✓ 通过 | ✓ 相同 | +| hhe35nc (NLTE continua) | ✓ 通过 | ✓ 通过 | ✓ 相同 | +| hhe35nl (NLTE lines) | ✓ 通过 | ✓ 通过 | ✓ 相同 | + +**MD5 校验和 (hhe35nl.7)**: +``` +01f3169947ca24bf1c989619b83ae8f2 +``` + +**结论**: 拆分编译与直接编译输出完全相同,功能验证通过 + +--- + +## SYNSPEC54 功能验证测试 (2026-03-19) + +### 测试目录 + +``` +tests/synspec/hhe/ +├── hhe35nl.5 # 输入文件 +├── hhe35nl.7 # 模型大气 (来自 TLUSTY 测试) +├── fort.55.con # 附加输入文件 +├── data # 数据目录路径文件 (内容: $TLUSTY/data) +└── results/ # 预期输出 + ├── hhe35nl.spec # 合成光谱 + ├── hhe35nl.cont # 连续谱 + └── hhe35nl.iden # 谱线标识 +``` + +### 测试流程 + +```bash +cd /home/fmq/program/tlusty/tl208-s54/rust/tests/synspec/hhe + +# 设置环境变量 +export TL208=/home/fmq/program/tlusty +export TLUSTY=$TL208/tl208-s54 +export LINELIST=$TL208/linelist +export IRON=$TL208/irondata +export OPTABLES=$TL208/optables + +# 准备输入文件 +cp hhe35nl.7 fort.8 +ln -sf fort.55.con fort.55 +ln -sf $TLUSTY/data/gfATO.dat fort.19 + +# 关键: data 必须是符号链接指向数据目录 +rm -f data +ln -sf $TLUSTY/data data + +# 可执行文件路径 +EXE_ORIG=$TLUSTY/synspec/synspec.exe +EXE_DIRECT=../../synspec/synspec_direct.exe +EXE_EXTRACTED=../../synspec/extracted/build/synspec_extracted + +# 测试原始版本 +$EXE_ORIG < hhe35nl.5 > hhe35nl_orig.log +cp fort.7 hhe35nl_orig.spec; cp fort.17 hhe35nl_orig.cont + +# 测试直接编译版本 +rm -f fort.7 fort.17 fort.12 +$EXE_DIRECT < hhe35nl.5 > hhe35nl_direct.log +cp fort.7 hhe35nl_direct.spec; cp fort.17 hhe35nl_direct.cont + +# 测试拆分编译版本 +rm -f fort.7 fort.17 fort.12 +$EXE_EXTRACTED < hhe35nl.5 > hhe35nl_extracted.log +cp fort.7 hhe35nl_extracted.spec; cp fort.17 hhe35nl_extracted.cont + +# 验证 +diff hhe35nl_orig.spec hhe35nl_direct.spec +diff hhe35nl_orig.spec hhe35nl_extracted.spec + +# 恢复 data 文件 +rm -f data +echo "/home/fmq/program/tlusty/tl208-s54/data" > data +``` + +### 测试结果 + +| 测试用例 | 原始程序 | 直接编译 | 拆分编译 | +|----------|----------|----------|----------| +| hhe35nl (NLTE lines) | ✓ 通过 | ✓ 通过 | ✓ 相同 | + +**MD5 校验和 (hhe35nl.spec)**: +``` +7925533b21b16d6bcdfff40e626cab83 +``` + +**注意事项**: +- `data` 文件/符号链接必须正确设置,否则报错 `Cannot open file './data/h1.dat': Not a directory` +- 拆分编译程序与原始程序输出完全相同,功能验证通过 diff --git a/scripts/extract_fortran_data.py b/scripts/extract_fortran_data.py new file mode 100644 index 0000000..5bc017d --- /dev/null +++ b/scripts/extract_fortran_data.py @@ -0,0 +1,438 @@ +#!/usr/bin/env python3 +""" +从 Fortran 源文件提取数组数据,生成 Rust data.rs + +用法: + python3 scripts/extract_fortran_data.py + +输出: src/data.rs +""" + +import re +from pathlib import Path + + +def parse_fortran_file(filepath: Path, global_params: dict = None) -> list[dict]: + """解析单个 Fortran 文件中的数组 + + Args: + filepath: Fortran 文件路径 + global_params: 从 include 文件中提取的全局参数表 + """ + if global_params is None: + global_params = {} + + with open(filepath, 'r') as f: + content = f.read() + + arrays = {} + + # 0. 预处理 + # 先清理每行的 Fortran 注释 (! 后面的内容) + # 同时移除 Fortran 77 风格的注释行 (以 C 或 * 开头) + lines = content.split('\n') + cleaned_lines = [] + for line in lines: + # Fortran 77 注释行 (第1列是 C, c, *, 或完全空行) + if len(line) > 0 and line[0] in 'Cc*': + continue # 跳过整行注释 + # Fortran 90 行内注释 + if '!' in line: + line = line.split('!')[0] + cleaned_lines.append(line) + + # 再合并 Fortran 续行 (第6列是 *, +, &, 数字, 或字母) + # Fortran 允许使用字母作为续行标记 (A, B, C, ... 用于超过9个续行) + merged_lines = [] + for line in cleaned_lines: + # 检查是否是续行 (第6列是 *, +, &, 数字, 或非空格字符) + if len(line) >= 6 and line[5] != ' ' and line[5] not in '\n\r\t': + # 续行: 追加到上一行 (去掉前6列) + if merged_lines: + merged_lines[-1] += ' ' + line[6:].strip() + else: + merged_lines.append(line) + content = '\n'.join(merged_lines) + + # 1. 首先解析所有 parameter 语句,建立局部常量表 + # 合并全局参数和局部参数 + param_table = dict(global_params) # 复制全局参数 + param_pattern = r'parameter\s*\(([^)]+)\)' + for match in re.finditer(param_pattern, content, re.IGNORECASE): + params_str = match.group(1) + for param in params_str.split(','): + param = param.strip() + if '=' in param: + name, val = param.split('=', 1) + name = name.strip().lower() + val = val.strip().lower() + # 尝试解析为整数或浮点数 + try: + # 先尝试整数 + if '.' not in val and 'e' not in val and 'd' not in val: + param_table[name] = int(val) + else: + # 浮点数,转换为整数(用于数组维度) + val = val.replace('d', 'e') + param_table[name] = int(float(val)) + except ValueError: + pass + + # 2. 解析 dimension 语句 + # dimension p4a(22), p4b(10,28), adi(nni), ... + # 注意: 使用 [ \t] 代替 \s 避免跨行匹配 + dim_pattern = r'dimension[ \t]+([a-z0-9_,() \t]+)' + for match in re.finditer(dim_pattern, content, re.IGNORECASE): + dim_str = match.group(1) + # 清理 dim_str - 移除可能包含的下一个关键字 + for keyword in ['\nreal', '\ninteger', '\ncomplex', '\nlogical', '\ncharacter', + '\ndimension', '\ndata', '\nparameter', '\nequivalence']: + if keyword in dim_str.lower(): + dim_str = dim_str[:dim_str.lower().find(keyword)] + break + arr_pattern = r'(\w+)\s*\(([^)]+)\)' + for arr_match in re.finditer(arr_pattern, dim_str): + name = arr_match.group(1).lower() + dims_str = arr_match.group(2) + # 解析维度,支持常量和 parameter 变量 + dims = [] + valid = True + for d in dims_str.split(','): + d = d.strip().lower() + if d in param_table: + dims.append(param_table[d]) + else: + try: + dims.append(int(d)) + except ValueError: + valid = False + break + if valid and dims: + arrays[name] = {"name": name, "dims": dims, "data": None, "source": filepath.name} + + # 2.5 解析类型声明中的数组 + # REAL frac(MR), INTEGER arr(10), REAL*4 arr(10), CHARACTER*10 str(5), etc. + # 注意: 使用 [ \t] 代替 \s 避免跨行匹配 + type_decl_pattern = r'(real(?:\*[\d]+)?|integer(?:\*[\d]+)?|complex(?:\*[\d]+)?|logical(?:\*[\d]+)?|character(?:\*[\d]+)?)[ \t]+([a-z0-9_,() \t]+)' + for match in re.finditer(type_decl_pattern, content, re.IGNORECASE): + decl_str = match.group(2) + # 清理 decl_str - 移除可能包含的下一个类型声明 + for keyword in ['\nreal', '\ninteger', '\ncomplex', '\nlogical', '\ncharacter', + '\ndimension', '\ndata', '\nparameter', '\nequivalence']: + if keyword in decl_str.lower(): + decl_str = decl_str[:decl_str.lower().find(keyword)] + break + + # 匹配变量名(维度) + arr_pattern = r'(\w+)\s*\(([^)]+)\)' + for arr_match in re.finditer(arr_pattern, decl_str): + name = arr_match.group(1).lower() + if name in arrays: + continue # 已有定义 + dims_str = arr_match.group(2) + # 解析维度 + dims = [] + valid = True + for d in dims_str.split(','): + d = d.strip().lower() + if d in param_table: + dims.append(param_table[d]) + else: + try: + dims.append(int(d)) + except ValueError: + valid = False + break + if valid and dims: + arrays[name] = {"name": name, "dims": dims, "data": None, "source": filepath.name} + + # 3. 解析 data 语句 (支持多行) + # data name / val1, val2, ... / + data_pattern = r'data\s+(\w+)\s*/\s*([^/]+)\s*/' + for match in re.finditer(data_pattern, content, re.IGNORECASE | re.DOTALL): + name = match.group(1).lower() + data_str = match.group(2) + + if name not in arrays: + arrays[name] = {"name": name, "dims": [], "data": None, "source": filepath.name} + + values = parse_data_values(data_str) + arrays[name]["data"] = values + + # 4. 处理 parameter 语句中的标量常量(用于导出) + for match in re.finditer(param_pattern, content, re.IGNORECASE): + params_str = match.group(1) + for param in params_str.split(','): + param = param.strip() + if '=' in param: + name, val = param.split('=', 1) + name = name.strip().lower() + val = val.strip().lower() + if name not in arrays: + try: + val = val.replace('d', 'e') + arrays[name] = {"name": name, "dims": [], "data": [float(val)], "source": filepath.name, "is_param": True} + except ValueError: + pass + + return list(arrays.values()) + + +def parse_data_values(data_str: str) -> list[float]: + """解析 DATA 语句中的数值,处理重复语法如 7*1.387""" + values = [] + + # 清理 + lines = data_str.split('\n') + cleaned_lines = [] + for line in lines: + line = line.strip() + if line.startswith('*'): + line = line[1:].strip() + cleaned_lines.append(line) + data_str = ' '.join(cleaned_lines) + + for part in data_str.split(','): + part = part.strip() + if not part: + continue + + # 移除末尾的 / (DATA 语句结束符) + part = part.rstrip('/') + + # 处理重复语法: "7*1.387" + if '*' in part and not part.startswith('-'): + match = re.match(r'(\d+)\s*\*\s*(-?[\d.]+)', part) + if match: + count = int(match.group(1)) + val = float(match.group(2)) + values.extend([val] * count) + continue + + try: + # 处理 Fortran 科学计数法 + # 处理 "- 14.2" 这种中间有空格的负数 + val = part.replace('d', 'e').replace('D', 'e') + # 移除负号和数字之间的空格 + val = re.sub(r'-\s+(\d)', r'-\1', val) + # 移除科学计数法中的多余空格 (如 "1.48 e-2" -> "1.48e-2") + val = re.sub(r'(\d)\s+([eEdD])', r'\1\2', val) + values.append(float(val)) + except ValueError: + pass + + return values + + +def generate_data_rs(all_arrays: dict[str, list[dict]]) -> str: + """生成 src/data.rs 内容""" + lines = [] + lines.append("//! Fortran 数据数组自动导出") + lines.append("//!") + lines.append("//! 由 extract_fortran_data.py 自动生成,请勿手动修改") + lines.append("") + + # 收集已使用的名称,避免重复 + used_names = set() + + # 按源文件分组 + for source, arrays in sorted(all_arrays.items()): + # 过滤有数据的数组 + valid_arrays = [a for a in arrays if a.get("data") and len(a["data"]) > 0] + if not valid_arrays: + continue + + lines.append(f"// ========== {source} ==========") + lines.append("") + + for arr in valid_arrays: + base_name = arr["name"].upper() + # 清理名称中的特殊字符 + base_name = re.sub(r'[^A-Z0-9_]', '', base_name) + + # 所有变量都添加文件名前缀,避免命名冲突 + prefix = Path(source).stem.upper()[:8] # 取文件名前8个字符 + name = f"{prefix}_{base_name}" + + # 如果加上前缀后仍有冲突,添加序号 + if name in used_names: + counter = 1 + while f"{name}_{counter}" in used_names: + counter += 1 + name = f"{name}_{counter}" + + used_names.add(name) + + dims = arr["dims"] + data = arr["data"] + + if not data: + continue + + total_size = len(data) + + # 跳过单值 parameter + if arr.get("is_param") and total_size == 1: + lines.append(f"/// {arr['name']} (from {source})") + lines.append(f"pub const {name}: f64 = {data[0]};") + lines.append("") + continue + + if len(dims) == 0: + # 未知维度,用 Vec 格式输出以便检查 + lines.append(f"/// {arr['name']} (from {source}, 未知维度,共 {len(data)} 个值)") + lines.append(f"pub const {name}: [f64; {len(data)}] = [") + for i, val in enumerate(data): + if i % 10 == 0: + lines.append(" ") + lines[-1] += f"{val}," + lines.append("];") + lines.append("") + + elif len(dims) == 1: + # 1D 数组 - 检查数据量是否匹配 + expected_size = dims[0] + if len(data) != expected_size: + print(f"警告: {name} 期望 {expected_size} 个值,实际 {len(data)} 个,跳过") + continue + + lines.append(f"/// {arr['name']}({dims[0]}) from {source}") + lines.append(f"pub const {name}: [f64; {dims[0]}] = [") + for i, val in enumerate(data): + if i % 10 == 0: + lines.append(" ") + lines[-1] += f"{val}," + lines.append("];") + lines.append("") + + elif len(dims) == 2: + # 2D 数组 - 直接转换为 Rust 行优先格式 + nj, ni = dims[0], dims[1] + expected_size = nj * ni + + if len(data) < expected_size: + print(f"警告: {name} 期望 {expected_size} 个值,实际 {len(data)} 个,跳过") + continue + + lines.append(f"/// {arr['name']}({nj}, {ni}) from {source}") + lines.append(f"/// 已转换为 Rust 行优先格式") + lines.append(f"pub const {name}: [[f64; {ni}]; {nj}] = [") + + # 列优先 → 行优先 转换 + for j in range(nj): + row = [] + for i in range(ni): + idx = j + i * nj # Fortran 列优先索引 + row.append(str(data[idx])) + lines.append(f" [{','.join(row)}],") + + lines.append("];") + lines.append("") + + # 不再需要转换函数和 getter,2D 数组直接生成为 const + + return '\n'.join(lines) + + +def parse_include_files(extracted_dir: Path) -> dict: + """解析 .FOR include 文件中的全局参数""" + global_params = {} + + # 扫描 .FOR 文件 + for for_file in extracted_dir.glob("*.FOR"): + try: + content = for_file.read_text() + except: + # 也尝试 tlusty/ 根目录 + for_file = Path("tlusty") / for_file.name + if for_file.exists(): + content = for_file.read_text() + else: + continue + + # 清理注释 + lines = [] + for line in content.split('\n'): + if '!' in line: + line = line.split('!')[0] + lines.append(line) + content = '\n'.join(lines) + + # 解析 parameter 语句 + param_pattern = r'parameter\s*\(([^)]+)\)' + for match in re.finditer(param_pattern, content, re.IGNORECASE): + params_str = match.group(1) + for param in params_str.split(','): + param = param.strip() + if '=' in param: + name, val = param.split('=', 1) + name = name.strip().lower() + val = val.strip().lower() + try: + if '.' not in val and 'e' not in val and 'd' not in val: + global_params[name] = int(val) + else: + val = val.replace('d', 'e') + global_params[name] = int(float(val)) + except ValueError: + pass + + return global_params + + +def main(): + # 扫描 tlusty/extracted 目录 + extracted_dir = Path("tlusty/extracted") + + if not extracted_dir.exists(): + print(f"错误: 目录不存在: {extracted_dir}") + return + + # 首先解析 include 文件中的全局参数 + global_params = parse_include_files(extracted_dir) + print(f"从 .FOR include 文件中提取了 {len(global_params)} 个全局参数") + + all_arrays = {} + + # 扫描所有 .f 文件 + for fortran_file in sorted(extracted_dir.glob("*.f")): + arrays = parse_fortran_file(fortran_file, global_params) + if arrays: + all_arrays[fortran_file.name] = arrays + print(f"解析: {fortran_file.name} -> {len(arrays)} 个数组") + + # 统计 + total_arrays = sum(len(arrs) for arrs in all_arrays.values()) + arrays_with_data = sum( + 1 for arrs in all_arrays.values() + for a in arrs if a.get("data") and len(a["data"]) > 0 + ) + arrays_2d = sum( + 1 for arrs in all_arrays.values() + for a in arrs if len(a.get("dims", [])) == 2 and a.get("data") + ) + + print() + print("=" * 60) + print(f"总计: {total_arrays} 个数组, {arrays_with_data} 个有数据, {arrays_2d} 个 2D 数组") + print("=" * 60) + + # 生成 data.rs + output_path = Path("src/data.rs") + rust_code = generate_data_rs(all_arrays) + + with open(output_path, 'w') as f: + f.write(rust_code) + + print(f"已生成: {output_path}") + print() + print("在 lib.rs 或 main.rs 中添加:") + print(" pub mod data;") + print() + print("使用方法:") + print(" use crate::data::{TT, PN, get_p4b};") + print(" let p4b = get_p4b(); // 自动初始化并返回 2D 数组") + + +if __name__ == "__main__": + main() diff --git a/scripts/fortran_to_rust_array.py b/scripts/fortran_to_rust_array.py new file mode 100644 index 0000000..7681b4a --- /dev/null +++ b/scripts/fortran_to_rust_array.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python3 +""" +将 Fortran DATA 语句转换为 Rust 2D 数组 + +用法: + python3 scripts/fortran_to_rust_array.py tlusty/extracted/pffe.f + +输出: Rust 代码片段,可直接复制到 .rs 文件中 +""" + +import re +import sys +from pathlib import Path + + +def parse_fortran_arrays(filepath: str) -> list[dict]: + """ + 解析 Fortran 文件中的数组定义和 DATA 语句 + + 返回: [{"name": "p4a", "dims": [22], "data": [...]}, ...] + """ + with open(filepath, 'r') as f: + content = f.read() + + arrays = {} + + # 1. 解析 dimension 语句 + # dimension p4a(22), p4b(10,28), ... + dim_pattern = r'dimension\s+([a-z0-9_,()\s]+)' + for match in re.finditer(dim_pattern, content, re.IGNORECASE): + dim_str = match.group(1) + # 解析每个数组 + arr_pattern = r'(\w+)\s*\(([^)]+)\)' + for arr_match in re.finditer(arr_pattern, dim_str): + name = arr_match.group(1).lower() + dims = [int(d.strip()) for d in arr_match.group(2).split(',')] + arrays[name] = {"name": name, "dims": dims, "data": None} + + # 2. 解析 data 语句 + # data p4a / val1, val2, ... / + # 或多行: + # data p4b / + # * val1, val2, ..., + # * val3, ... / + + # 先找到所有 data 块 + data_pattern = r'data\s+(\w+)\s*/\s*([^/]+)\s*/' + for match in re.finditer(data_pattern, content, re.IGNORECASE | re.DOTALL): + name = match.group(1).lower() + data_str = match.group(2) + + if name not in arrays: + arrays[name] = {"name": name, "dims": [], "data": None} + + # 解析数值 + values = parse_data_values(data_str) + arrays[name]["data"] = values + + return list(arrays.values()) + + +def parse_data_values(data_str: str) -> list[float]: + """解析 DATA 语句中的数值,处理重复语法如 7*1.387""" + values = [] + + # 清理: 移除注释、换行,但保留 * 用于重复语法 + data_str = re.sub(r'[cC]\s*$', '', data_str) # 行尾注释 + # 移除 Fortran 续行符 * (行首的 *),但保留数据中的 * + lines = data_str.split('\n') + cleaned_lines = [] + for line in lines: + line = line.strip() + if line.startswith('*'): + line = line[1:].strip() + cleaned_lines.append(line) + data_str = ' '.join(cleaned_lines) + + for part in data_str.split(','): + part = part.strip() + if not part: + continue + + # 处理重复语法: "7*1.387" 或 "7*1.387" + if '*' in part and not part.startswith('-'): # 避免把负数当重复 + # 检查是否真的是重复语法 + match = re.match(r'(\d+)\s*\*\s*(-?[\d.]+)', part) + if match: + count = int(match.group(1)) + val = float(match.group(2)) + values.extend([val] * count) + continue + + try: + values.append(float(part)) + except ValueError: + # 跳过无法解析的部分 + pass + + return values + + +def generate_rust_code(arrays: list[dict]) -> str: + """生成 Rust 代码""" + lines = [] + lines.append("// 自动生成的数组数据") + lines.append("") + + for arr in arrays: + name = arr["name"].upper() + dims = arr["dims"] + data = arr["data"] + + if not data: + continue + + total_size = len(data) + + if len(dims) == 1: + # 1D 数组 + lines.append(f"const {name}_RAW: [f64; {total_size}] = [") + for i, val in enumerate(data): + if i % 10 == 0: + lines.append(" ",) + lines[-1] += f"{val}," + lines.append("];") + lines.append(f"static {name}: OnceLock<[f64; {dims[0]}]> = OnceLock::new();") + lines.append("") + + elif len(dims) == 2: + # 2D 数组 + nj, ni = dims[0], dims[1] + lines.append(f"// {name}: Fortran {name.lower()}({nj}, {ni})") + lines.append(f"const {name}_RAW: [f64; {total_size}] = [") + for i, val in enumerate(data): + if i % 10 == 0: + lines.append(" ") + lines[-1] += f"{val}," + lines.append("];") + lines.append(f"static {name}: OnceLock<[[f64; {ni}]; {nj}]> = OnceLock::new();") + lines.append("") + + # 添加转换函数 + lines.append("") + lines.append("/// Fortran 列优先 → Rust 行优先") + lines.append("const fn fortran_to_rust_2d(") + lines.append(" data: &[f64; NJ * NI],") + lines.append(") -> [[f64; NI]; NJ] {") + lines.append(" let mut result = [[0.0; NI]; NJ];") + lines.append(" let mut i = 0;") + lines.append(" while i < NI {") + lines.append(" let mut j = 0;") + lines.append(" while j < NJ {") + lines.append(" result[j][i] = data[j + i * NJ];") + lines.append(" j += 1;") + lines.append(" }") + lines.append(" i += 1;") + lines.append(" }") + lines.append(" result") + lines.append("}") + lines.append("") + + # 添加初始化代码 + lines.append("// 初始化函数中调用:") + for arr in arrays: + name = arr["name"].upper() + dims = arr["dims"] + if len(dims) == 2 and arr["data"]: + nj, ni = dims[0], dims[1] + lines.append(f"let {name.lower()} = {name}.get_or_init(|| fortran_to_rust_2d::<{nj}, {ni}>(&{name}_RAW));") + + return '\n'.join(lines) + + +def main(): + if len(sys.argv) < 2: + print("用法: python3 scripts/fortran_to_rust_array.py ") + print("示例: python3 scripts/fortran_to_rust_array.py tlusty/extracted/pffe.f") + sys.exit(1) + + filepath = sys.argv[1] + + if not Path(filepath).exists(): + print(f"错误: 文件不存在: {filepath}") + sys.exit(1) + + print(f"解析: {filepath}") + print("=" * 60) + + arrays = parse_fortran_arrays(filepath) + + print(f"找到 {len(arrays)} 个数组:") + for arr in arrays: + dims_str = ', '.join(str(d) for d in arr['dims']) + data_count = len(arr['data']) if arr['data'] else 0 + print(f" - {arr['name']}({dims_str}): {data_count} 个值") + + print() + print("=" * 60) + print("生成的 Rust 代码:") + print("=" * 60) + print(generate_rust_code(arrays)) + + +if __name__ == "__main__": + main() diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..f256d99 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,5981 @@ +//! Fortran 数据数组自动导出 +//! +//! 由 extract_fortran_data.py 自动生成,请勿手动修改 + +// ========== allard.f ========== + +/// nxmax (from allard.f) +pub const ALLARD_NXMAX: f64 = 1400.0; + +/// nnmax (from allard.f) +pub const ALLARD_NNMAX: f64 = 5.0; + +/// ntamax (from allard.f) +pub const ALLARD_NTAMAX: f64 = 6.0; + +// ========== allardt.f ========== + +/// nxmax (from allardt.f) +pub const ALLARDT_NXMAX: f64 = 1400.0; + +/// nnmax (from allardt.f) +pub const ALLARDT_NNMAX: f64 = 5.0; + +/// ntamax (from allardt.f) +pub const ALLARDT_NTAMAX: f64 = 6.0; + +// ========== angset.f ========== + +/// three (from angset.f) +pub const ANGSET_THREE: f64 = 3.0; + +/// five (from angset.f) +pub const ANGSET_FIVE: f64 = 5.0; + +/// zero (from angset.f) +pub const ANGSET_ZERO: f64 = 0.0; + +// ========== betah.f ========== + +/// un (from betah.f) +pub const BETAH_UN: f64 = 1.0; + +/// pisq (from betah.f) +pub const BETAH_PISQ: f64 = 1.77245385090551; + +// ========== bkhsgo.f ========== + +/// sigth (from bkhsgo.f, 未知维度,共 1 个值) +pub const BKHSGO_SIGTH: [f64; 1] = [ + 1e-34, +]; + +// ========== bpopt.f ========== + +/// trha (from bpopt.f) +pub const BPOPT_TRHA: f64 = 1.5; + +/// ccor (from bpopt.f) +pub const BPOPT_CCOR: f64 = 0.09; + +// ========== brte.f ========== + +/// xcon (from brte.f) +pub const BRTE_XCON: f64 = 8.0935e-21; + +/// ycon (from brte.f) +pub const BRTE_YCON: f64 = 1.68638e-10; + +// ========== brtez.f ========== + +/// xcon (from brtez.f) +pub const BRTEZ_XCON: f64 = 8.0935e-21; + +/// ycon (from brtez.f) +pub const BRTEZ_YCON: f64 = 1.68638e-10; + +// ========== carbon.f ========== + +/// fr2(34) from carbon.f +pub const CARBON_FR2: [f64; 34] = [ + 0.74,0.75,0.76,0.77,0.78,0.79,0.8,0.81,0.82,0.83, + 0.85,0.86,0.87,0.88,0.89,0.9,0.91,0.92,0.93,0.94, + 0.95,0.96,0.97,0.98,0.99,1.0,1.1,1.2,1.3,1.45, + 1.5,1.6,1.8,2.0, +]; + +/// sg2(34) from carbon.f +pub const CARBON_SG2: [f64; 34] = [ + 12.04,12.03,12.09,12.26,12.6,13.24,14.36,16.24,19.28,23.94, + 37.41,42.88,44.76,43.41,40.46,37.19,34.26,31.82,29.96,28.57, + 27.68,27.37,27.84,29.69,34.45,46.35,13.8,11.54,10.4,8.96, + 8.54,7.47,6.53,5.66, +]; + +/// fr3(45) from carbon.f +pub const CARBON_FR3: [f64; 45] = [ + 0.66,0.68,0.7,0.72,0.74,0.76,0.78,0.8,0.82,0.84, + 0.86,0.864,0.866,0.868,0.87,0.874,0.876,0.88,0.882,0.884, + 0.886,0.888,0.89,0.894,0.896,0.898,0.9,0.904,0.908,0.91, + 0.92,0.94,0.98,1.0,1.1,1.2,1.26,1.34,1.36,1.4, + 1.46,1.6,1.7,1.8,2.0, +]; + +/// sg3(45) from carbon.f +pub const CARBON_SG3: [f64; 45] = [ + 13.94,13.29,12.56,11.73,10.82,10.18,8.62,7.27,5.74,4.14, + 4.61,5.92,6.94,8.34,10.21,16.12,20.64,34.56,44.82,57.71, + 73.09,89.99,106.38,127.08,128.38,124.44,117.17,99.32,82.95,76.05, + 52.65,33.23,21.29,18.69,12.62,11.44,9.77,7.53,10.47,9.65, + 10.19,7.28,6.7,6.11,4.96, +]; + +/// fr0 (from carbon.f) +pub const CARBON_FR0: f64 = 3288050000000000.0; + +/// nc2 (from carbon.f) +pub const CARBON_NC2: f64 = 34.0; + +/// nc3 (from carbon.f) +pub const CARBON_NC3: f64 = 45.0; + +// ========== ceh12.f ========== + +/// a(6) from ceh12.f +pub const CEH12_A: [f64; 6] = [ + 2.579997e-10,-1.629166e-10,7.713069e-11,-2.668768e-11,6.642513e-12,-9.422885e-13, +]; + +/// c (from ceh12.f) +pub const CEH12_C: f64 = -118353.41; + +// ========== change.f ========== + +/// s (from change.f) +pub const CHANGE_S: f64 = 2.0706e-16; + +// ========== cia_h2h.f ========== + +/// temp(4) from cia_h2h.f +pub const CIA_H2H_TEMP: [f64; 4] = [ + 1000.0,1500.0,2000.0,2500.0, +]; + +/// ntemp (from cia_h2h.f, 未知维度,共 1 个值) +pub const CIA_H2H_NTEMP: [f64; 1] = [ + 4.0, +]; + +/// ifirst (from cia_h2h.f, 未知维度,共 1 个值) +pub const CIA_H2H_IFIRST: [f64; 1] = [ + 0.0, +]; + +/// nlines (from cia_h2h.f) +pub const CIA_H2H_NLINES: f64 = 67.0; + +/// amagat (from cia_h2h.f) +pub const CIA_H2H_AMAGAT: f64 = 2.6867774e+19; + +/// cas (from cia_h2h.f) +pub const CIA_H2H_CAS: f64 = 29979250000.0; + +// ========== cia_h2h2.f ========== + +/// temp(7) from cia_h2h2.f +pub const CIA_H2H2_TEMP: [f64; 7] = [ + 1000.0,2000.0,3000.0,4000.0,5000.0,6000.0,7000.0, +]; + +/// ntemp (from cia_h2h2.f, 未知维度,共 1 个值) +pub const CIA_H2H2_NTEMP: [f64; 1] = [ + 7.0, +]; + +/// ifirst (from cia_h2h2.f, 未知维度,共 1 个值) +pub const CIA_H2H2_IFIRST: [f64; 1] = [ + 0.0, +]; + +/// nlines (from cia_h2h2.f) +pub const CIA_H2H2_NLINES: f64 = 1000.0; + +/// amagat (from cia_h2h2.f) +pub const CIA_H2H2_AMAGAT: f64 = 2.6867774e+19; + +/// cas (from cia_h2h2.f) +pub const CIA_H2H2_CAS: f64 = 29979250000.0; + +// ========== cia_h2he.f ========== + +/// temp(7) from cia_h2he.f +pub const CIA_H2HE_TEMP: [f64; 7] = [ + 1000.0,2000.0,3000.0,4000.0,5000.0,6000.0,7000.0, +]; + +/// ntemp (from cia_h2he.f, 未知维度,共 1 个值) +pub const CIA_H2HE_NTEMP: [f64; 1] = [ + 7.0, +]; + +/// ifirst (from cia_h2he.f, 未知维度,共 1 个值) +pub const CIA_H2HE_IFIRST: [f64; 1] = [ + 0.0, +]; + +/// nlines (from cia_h2he.f) +pub const CIA_H2HE_NLINES: f64 = 242.0; + +/// amagat (from cia_h2he.f) +pub const CIA_H2HE_AMAGAT: f64 = 2.6867774e+19; + +/// cas (from cia_h2he.f) +pub const CIA_H2HE_CAS: f64 = 29979250000.0; + +// ========== cia_hhe.f ========== + +/// temp(11) from cia_hhe.f +pub const CIA_HHE_TEMP: [f64; 11] = [ + 1000.0,1500.0,2250.0,3000.0,4000.0,5000.0,6000.0,7000.0,8000.0,9000.0, + 10000.0, +]; + +/// ntemp (from cia_hhe.f, 未知维度,共 1 个值) +pub const CIA_HHE_NTEMP: [f64; 1] = [ + 11.0, +]; + +/// ifirst (from cia_hhe.f, 未知维度,共 1 个值) +pub const CIA_HHE_IFIRST: [f64; 1] = [ + 0.0, +]; + +/// nlines (from cia_hhe.f) +pub const CIA_HHE_NLINES: f64 = 43.0; + +/// amagat (from cia_hhe.f) +pub const CIA_HHE_AMAGAT: f64 = 2.6867774e+19; + +/// cas (from cia_hhe.f) +pub const CIA_HHE_CAS: f64 = 29979250000.0; + +// ========== cion.f ========== + +/// a0(30) from cion.f +pub const CION_A0: [f64; 30] = [ + 13.5,27.0,9.07,11.8,20.2,28.6,37.0,45.4,53.8,62.2, + 11.7,38.8,37.27,46.7,57.4,67.0,77.8,90.1,106.0,120.8, + 135.6,150.4,165.2,180.0,194.8,209.6,224.4,239.2,154.0,268.8, +]; + +/// a1(30) from cion.f +pub const CION_A1: [f64; 30] = [ + -14.2,-60.1,4.3,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// a2(30) from cion.f +pub const CION_A2: [f64; 30] = [ + 40.6,140.0,7.69,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// a3(30) from cion.f +pub const CION_A3: [f64; 30] = [ + -17.1,-89.8,-7.53,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// b0(30) from cion.f +pub const CION_B0: [f64; 30] = [ + -4.81,-9.62,-2.47,-3.28,-5.96,-8.64,-11.32,-14.0,-16.68,-19.36, + -4.29,-16.7,-14.58,-16.95,-19.93,-23.05,-26.0,-29.45,-34.25,-38.92, + -43.59,-48.26,-52.93,-57.6,-62.27,-66.94,-71.62,-76.29,-80.96,-85.63, +]; + +/// b1(30) from cion.f +pub const CION_B1: [f64; 30] = [ + 9.77,33.1,-3.78,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// b2(30) from cion.f +pub const CION_B2: [f64; 30] = [ + -28.3,-82.5,-3.59,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// b3(30) from cion.f +pub const CION_B3: [f64; 30] = [ + 11.4,54.6,3.34,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// c0(30) from cion.f +pub const CION_C0: [f64; 30] = [ + 1.85,3.69,1.34,1.64,2.31,2.984,3.656,4.328,5.0,5.672, + 1.061,1.87,3.26,5.07,6.67,8.1,9.92,11.79,7.953,8.408, + 8.863,9.318,9.773,10.228,10.683,11.138,11.593,12.048,12.505,12.96, +]; + +/// c1(30) from cion.f +pub const CION_C1: [f64; 30] = [ + 0.0,4.32,0.343,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// c2(30) from cion.f +pub const CION_C2: [f64; 30] = [ + 0.0,-2.527,-2.46,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// c3(30) from cion.f +pub const CION_C3: [f64; 30] = [ + 0.0,0.262,1.38,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// d0(30) from cion.f +pub const CION_D0: [f64; 30] = [ + -10.9,-21.7,-5.37,-7.58,-12.66,-17.74,-22.82,-27.9,-32.98,-38.06, + -7.34,-28.8,-24.87,-30.5,-37.9,-45.3,-53.8,-64.6,-54.54,-61.7, + -68.86,-76.02,-83.18,-90.34,-97.5,-104.66,-111.82,-118.98,-126.14,-133.32, +]; + +/// d1(30) from cion.f +pub const CION_D1: [f64; 30] = [ + 8.9,42.5,-12.4,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// d2(30) from cion.f +pub const CION_D2: [f64; 30] = [ + -35.7,-131.0,-8.09,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// d3(30) from cion.f +pub const CION_D3: [f64; 30] = [ + 16.5,87.4,1.23,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +// ========== ckoest.f ========== + +/// coef(3, 11) from ckoest.f +/// 已转换为 Rust 行优先格式 +pub const CKOEST_COEF: [[f64; 11]; 3] = [ + [-58.229,-68.438,-67.31,-92.02,-68.936,-63.408,-63.778,-76.903,-61.027,-83.287,-83.287], + [4.3965,5.7453,6.1831,10.313,5.2666,3.8797,4.5102,6.3639,3.1833,7.1751,7.1751], + [-0.22134,-0.26277,-0.32244,-0.4509,-0.15812,-0.12479,-0.18213,-0.21565,-0.043675,-0.20821,-0.20821], +]; + +/// ist(3) from ckoest.f +pub const CKOEST_IST: [f64; 3] = [ + 1.0,2.0,6.0, +]; + +/// phot0 (from ckoest.f) +pub const CKOEST_PHOT0: f64 = 2.815e+29; + +// ========== colh.f ========== + +/// cc0 (from colh.f) +pub const COLH_CC0: f64 = 5.465e-11; + +/// cex1 (from colh.f) +pub const COLH_CEX1: f64 = -30.20581; + +/// cex2 (from colh.f) +pub const COLH_CEX2: f64 = 3.8608704; + +/// cex3 (from colh.f) +pub const COLH_CEX3: f64 = 305.63574; + +/// ci1 (from colh.f) +pub const COLH_CI1: f64 = 0.3; + +/// ci2 (from colh.f) +pub const COLH_CI2: f64 = 0.435; + +/// ca1 (from colh.f) +pub const COLH_CA1: f64 = 54444160.0; + +/// ca2 (from colh.f) +pub const COLH_CA2: f64 = -28185.937; + +/// ca3 (from colh.f) +pub const COLH_CA3: f64 = 19.987261; + +/// ca4 (from colh.f) +pub const COLH_CA4: f64 = -5.8906298e-05; + +/// cb1 (from colh.f) +pub const COLH_CB1: f64 = 1393.5312; + +/// cb2 (from colh.f) +pub const COLH_CB2: f64 = -168.05859; + +/// cb3 (from colh.f) +pub const COLH_CB3: f64 = -2539.0; + +/// cc1 (from colh.f) +pub const COLH_CC1: f64 = 2068.4609; + +/// cc2 (from colh.f) +pub const COLH_CC2: f64 = -334.1582; + +/// cc3 (from colh.f) +pub const COLH_CC3: f64 = -7644.0625; + +/// cd1 (from colh.f) +pub const COLH_CD1: f64 = 3217.4844; + +/// cd2 (from colh.f) +pub const COLH_CD2: f64 = -558.82422; + +/// cd3 (from colh.f) +pub const COLH_CD3: f64 = -6863.25; + +/// ce1 (from colh.f) +pub const COLH_CE1: f64 = 5759.125; + +/// ce2 (from colh.f) +pub const COLH_CE2: f64 = 81.75; + +/// ce3 (from colh.f) +pub const COLH_CE3: f64 = -1516.3; + +/// cf1 (from colh.f) +pub const COLH_CF1: f64 = 14614.75; + +/// cf2 (from colh.f) +pub const COLH_CF2: f64 = 393.4; + +/// cf3 (from colh.f) +pub const COLH_CF3: f64 = -4828.4; + +/// alf0 (from colh.f) +pub const COLH_ALF0: f64 = 1.8; + +/// alf1 (from colh.f) +pub const COLH_ALF1: f64 = 0.4; + +/// bet0 (from colh.f) +pub const COLH_BET0: f64 = 3.0; + +/// bet1 (from colh.f) +pub const COLH_BET1: f64 = 1.2; + +/// o148 (from colh.f) +pub const COLH_O148: f64 = 0.148; + +/// chmi (from colh.f) +pub const COLH_CHMI: f64 = 5.59e-15; + +/// expia1 (from colh.f) +pub const COLH_EXPIA1: f64 = -0.57721566; + +/// expia2 (from colh.f) +pub const COLH_EXPIA2: f64 = 0.99999193; + +/// expia3 (from colh.f) +pub const COLH_EXPIA3: f64 = -0.24991055; + +/// expia4 (from colh.f) +pub const COLH_EXPIA4: f64 = 0.05519968; + +/// expia5 (from colh.f) +pub const COLH_EXPIA5: f64 = -0.00976004; + +/// expia6 (from colh.f) +pub const COLH_EXPIA6: f64 = 0.00107857; + +/// expib1 (from colh.f) +pub const COLH_EXPIB1: f64 = 0.2677734343; + +/// expib2 (from colh.f) +pub const COLH_EXPIB2: f64 = 8.6347608925; + +/// expib3 (from colh.f) +pub const COLH_EXPIB3: f64 = 18.059016973; + +/// expib4 (from colh.f) +pub const COLH_EXPIB4: f64 = 8.5733287401; + +/// expic1 (from colh.f) +pub const COLH_EXPIC1: f64 = 3.9584969228; + +/// expic2 (from colh.f) +pub const COLH_EXPIC2: f64 = 21.0996530827; + +/// expic3 (from colh.f) +pub const COLH_EXPIC3: f64 = 25.6329561486; + +/// expic4 (from colh.f) +pub const COLH_EXPIC4: f64 = 9.5733223454; + +// ========== colhe.f ========== + +/// fhe1(16) from colhe.f +pub const COLHE_FHE1: [f64; 16] = [ + 0.0,0.275,0.0729,0.0296,0.0148,0.0085,0.0053,0.0035,0.0025,0.0018, + 0.0015,0.0012,0.00094,0.00075,0.00061,0.00053, +]; + +/// g0(3) from colhe.f +pub const COLHE_G0: [f64; 3] = [ + 0.073399521,1.7252867,8.6335087, +]; + +/// expia1 (from colhe.f) +pub const COLHE_EXPIA1: f64 = -0.57721566; + +/// expia2 (from colhe.f) +pub const COLHE_EXPIA2: f64 = 0.99999193; + +/// expia3 (from colhe.f) +pub const COLHE_EXPIA3: f64 = -0.24991055; + +/// expia4 (from colhe.f) +pub const COLHE_EXPIA4: f64 = 0.05519968; + +/// expia5 (from colhe.f) +pub const COLHE_EXPIA5: f64 = -0.00976004; + +/// expia6 (from colhe.f) +pub const COLHE_EXPIA6: f64 = 0.00107857; + +/// expib1 (from colhe.f) +pub const COLHE_EXPIB1: f64 = 0.2677734343; + +/// expib2 (from colhe.f) +pub const COLHE_EXPIB2: f64 = 8.6347608925; + +/// expib3 (from colhe.f) +pub const COLHE_EXPIB3: f64 = 18.059016973; + +/// expib4 (from colhe.f) +pub const COLHE_EXPIB4: f64 = 8.5733287401; + +/// expic1 (from colhe.f) +pub const COLHE_EXPIC1: f64 = 3.9584969228; + +/// expic2 (from colhe.f) +pub const COLHE_EXPIC2: f64 = 21.0996530827; + +/// expic3 (from colhe.f) +pub const COLHE_EXPIC3: f64 = 25.6329561486; + +/// expic4 (from colhe.f) +pub const COLHE_EXPIC4: f64 = 9.5733223454; + +// ========== colis.f ========== + +/// expia1 (from colis.f) +pub const COLIS_EXPIA1: f64 = -0.57721566; + +/// expia2 (from colis.f) +pub const COLIS_EXPIA2: f64 = 0.99999193; + +/// expia3 (from colis.f) +pub const COLIS_EXPIA3: f64 = -0.24991055; + +/// expia4 (from colis.f) +pub const COLIS_EXPIA4: f64 = 0.05519968; + +/// expia5 (from colis.f) +pub const COLIS_EXPIA5: f64 = -0.00976004; + +/// expia6 (from colis.f) +pub const COLIS_EXPIA6: f64 = 0.00107857; + +/// expib1 (from colis.f) +pub const COLIS_EXPIB1: f64 = 0.2677734343; + +/// expib2 (from colis.f) +pub const COLIS_EXPIB2: f64 = 8.6347608925; + +/// expib3 (from colis.f) +pub const COLIS_EXPIB3: f64 = 18.059016973; + +/// expib4 (from colis.f) +pub const COLIS_EXPIB4: f64 = 8.5733287401; + +/// expic1 (from colis.f) +pub const COLIS_EXPIC1: f64 = 3.9584969228; + +/// expic2 (from colis.f) +pub const COLIS_EXPIC2: f64 = 21.0996530827; + +/// expic3 (from colis.f) +pub const COLIS_EXPIC3: f64 = 25.6329561486; + +/// expic4 (from colis.f) +pub const COLIS_EXPIC4: f64 = 9.5733223454; + +// ========== collhe.f ========== + +/// ener(19) from collhe.f +pub const COLLHE_ENER: [f64; 19] = [ + 0.0,19.8198,20.616,20.96432,21.2182,22.7187,22.9206,23.00731,23.0739,23.0743, + 23.0873,23.5942,23.6738,23.7081,23.7363,23.7366,23.7373,23.7373,23.7423, +]; + +/// nstart(172) from collhe.f +pub const COLLHE_NSTART: [f64; 172] = [ + 1.0,6.0,11.0,16.0,20.0,28.0,32.0,40.0,44.0,52.0, + 57.0,62.0,67.0,72.0,77.0,82.0,88.0,92.0,98.0,104.0, + 110.0,114.0,120.0,125.0,129.0,135.0,139.0,147.0,151.0,157.0, + 164.0,170.0,177.0,183.0,190.0,195.0,202.0,208.0,213.0,220.0, + 225.0,232.0,236.0,243.0,247.0,251.0,260.0,266.0,273.0,278.0, + 285.0,290.0,300.0,304.0,309.0,316.0,320.0,324.0,329.0,333.0, + 338.0,343.0,347.0,352.0,357.0,362.0,367.0,372.0,376.0,382.0, + 386.0,391.0,395.0,401.0,405.0,410.0,414.0,421.0,425.0,431.0, + 435.0,440.0,445.0,449.0,454.0,459.0,465.0,470.0,475.0,480.0, + 487.0,491.0,497.0,503.0,508.0,515.0,520.0,525.0,530.0,536.0, + 542.0,547.0,552.0,559.0,564.0,571.0,576.0,581.0,587.0,592.0, + 598.0,603.0,608.0,613.0,617.0,623.0,630.0,635.0,642.0,646.0, + 650.0,655.0,660.0,666.0,671.0,677.0,683.0,689.0,695.0,702.0, + 707.0,713.0,718.0,723.0,728.0,732.0,737.0,741.0,745.0,750.0, + 754.0,759.0,765.0,771.0,777.0,782.0,789.0,796.0,801.0,805.0, + 810.0,815.0,819.0,824.0,831.0,837.0,844.0,850.0,856.0,861.0, + 868.0,873.0,877.0,882.0,890.0,895.0,905.0,909.0,913.0,920.0, + 925.0,930.0, +]; + +/// stwt(19) from collhe.f +pub const COLLHE_STWT: [f64; 19] = [ + 1.0,3.0,1.0,9.0,3.0,3.0,1.0,9.0,15.0,5.0, + 3.0,3.0,1.0,9.0,15.0,5.0,21.0,7.0,3.0, +]; + +/// un (from collhe.f) +pub const COLLHE_UN: f64 = 1.0; + +/// c1 (from collhe.f) +pub const COLLHE_C1: f64 = 3.849485; + +/// c2 (from collhe.f) +pub const COLLHE_C2: f64 = 0.849485002; + +/// n (from collhe.f) +pub const COLLHE_N: f64 = 19.0; + +// ========== column.f ========== + +/// xmdsun (from column.f) +pub const COLUMN_XMDSUN: f64 = 6.3029e+25; + +/// xmsun (from column.f) +pub const COLUMN_XMSUN: f64 = 1.989e+33; + +/// rsun (from column.f) +pub const COLUMN_RSUN: f64 = 69598000000.0; + +/// grcon (from column.f) +pub const COLUMN_GRCON: f64 = 6.668e-08; + +/// velc (from column.f) +pub const COLUMN_VELC: f64 = 29979250000.0; + +/// rgas (from column.f) +pub const COLUMN_RGAS: f64 = 130000000.0; + +/// xkram0 (from column.f) +pub const COLUMN_XKRAM0: f64 = 7e+25; + +/// xkap0 (from column.f) +pub const COLUMN_XKAP0: f64 = 6.4e+24; + +/// chiel (from column.f) +pub const COLUMN_CHIEL: f64 = 0.39; + +/// pi (from column.f) +pub const COLUMN_PI: f64 = 3.14159265; + +// ========== compt0.f ========== + +/// xcon (from compt0.f) +pub const COMPT0_XCON: f64 = 8.0935e-21; + +/// ycon (from compt0.f) +pub const COMPT0_YCON: f64 = 1.68638e-10; + +// ========== comset.f ========== + +/// xcon (from comset.f) +pub const COMSET_XCON: f64 = 8.0935e-21; + +/// ycon (from comset.f) +pub const COMSET_YCON: f64 = 1.68638e-10; + +/// t15 (from comset.f) +pub const COMSET_T15: f64 = 1e-15; + +// ========== contmd.f ========== + +/// errt (from contmd.f) +pub const CONTMD_ERRT: f64 = 0.001; + +// ========== contmp.f ========== + +/// errt (from contmp.f) +pub const CONTMP_ERRT: f64 = 0.001; + +// ========== corrwm.f ========== + +/// t15 (from corrwm.f) +pub const CORRWM_T15: f64 = 1e-15; + +// ========== cspec.f ========== + +/// che1fb(3, 4) from cspec.f +/// 已转换为 Rust 行优先格式 +pub const CSPEC_CHE1FB: [[f64; 4]; 3] = [ + [9.63675,10.85578,8.38043,6.95825], + [-2.22941,-2.40931,-2.04791,-2.01967], + [-17.30103,-27.00903,-7.36621,-5.98779], +]; + +/// expia1 (from cspec.f) +pub const CSPEC_EXPIA1: f64 = -0.57721566; + +/// expia2 (from cspec.f) +pub const CSPEC_EXPIA2: f64 = 0.99999193; + +/// expia3 (from cspec.f) +pub const CSPEC_EXPIA3: f64 = -0.24991055; + +/// expia4 (from cspec.f) +pub const CSPEC_EXPIA4: f64 = 0.05519968; + +/// expia5 (from cspec.f) +pub const CSPEC_EXPIA5: f64 = -0.00976004; + +/// expia6 (from cspec.f) +pub const CSPEC_EXPIA6: f64 = 0.00107857; + +/// expib1 (from cspec.f) +pub const CSPEC_EXPIB1: f64 = 0.2677734343; + +/// expib2 (from cspec.f) +pub const CSPEC_EXPIB2: f64 = 8.6347608925; + +/// expib3 (from cspec.f) +pub const CSPEC_EXPIB3: f64 = 18.059016973; + +/// expib4 (from cspec.f) +pub const CSPEC_EXPIB4: f64 = 8.5733287401; + +/// expic1 (from cspec.f) +pub const CSPEC_EXPIC1: f64 = 3.9584969228; + +/// expic2 (from cspec.f) +pub const CSPEC_EXPIC2: f64 = 21.0996530827; + +/// expic3 (from cspec.f) +pub const CSPEC_EXPIC3: f64 = 25.6329561486; + +/// expic4 (from cspec.f) +pub const CSPEC_EXPIC4: f64 = 9.5733223454; + +// ========== cubic.f ========== + +/// ipri (from cubic.f, 未知维度,共 1 个值) +pub const CUBIC_IPRI: [f64; 1] = [ + 0.0, +]; + +/// third (from cubic.f) +pub const CUBIC_THIRD: f64 = 0.333333333333333; + +// ========== dielrc.f ========== + +/// inid(28, 28) from dielrc.f +/// 已转换为 Rust 行优先格式 +pub const DIELRC_INID: [[f64; 28]; 28] = [ + [1.0,2.0,0.0,0.0,0.0,4.0,10.0,17.0,0.0,25.0,0.0,35.0,0.0,47.0,0.0,61.0,0.0,77.0,0.0,95.0,0.0,0.0,0.0,0.0,0.0,115.0,0.0,141.0], + [0.0,3.0,0.0,0.0,0.0,5.0,11.0,18.0,0.0,26.0,0.0,36.0,0.0,48.0,0.0,62.0,0.0,78.0,0.0,96.0,0.0,0.0,0.0,0.0,0.0,116.0,0.0,142.0], + [0.0,0.0,0.0,0.0,0.0,6.0,12.0,19.0,0.0,27.0,0.0,37.0,0.0,49.0,0.0,63.0,0.0,79.0,0.0,97.0,0.0,0.0,0.0,0.0,0.0,117.0,0.0,143.0], + [0.0,0.0,0.0,0.0,0.0,7.0,13.0,20.0,0.0,28.0,0.0,38.0,0.0,50.0,0.0,64.0,0.0,80.0,0.0,98.0,0.0,0.0,0.0,0.0,0.0,118.0,0.0,144.0], + [0.0,0.0,0.0,0.0,0.0,8.0,14.0,21.0,0.0,29.0,0.0,39.0,0.0,51.0,0.0,65.0,0.0,81.0,0.0,99.0,0.0,0.0,0.0,0.0,0.0,119.0,0.0,145.0], + [0.0,0.0,0.0,0.0,0.0,9.0,15.0,22.0,0.0,30.0,0.0,40.0,0.0,52.0,0.0,66.0,0.0,82.0,0.0,100.0,0.0,0.0,0.0,0.0,0.0,120.0,0.0,146.0], + [0.0,0.0,0.0,0.0,0.0,0.0,16.0,23.0,0.0,31.0,0.0,41.0,0.0,53.0,0.0,67.0,0.0,83.0,0.0,101.0,0.0,0.0,0.0,0.0,0.0,121.0,0.0,147.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,24.0,0.0,32.0,0.0,42.0,0.0,54.0,0.0,68.0,0.0,84.0,0.0,102.0,0.0,0.0,0.0,0.0,0.0,122.0,0.0,148.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,33.0,0.0,43.0,0.0,55.0,0.0,69.0,0.0,85.0,0.0,103.0,0.0,0.0,0.0,0.0,0.0,123.0,0.0,149.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,34.0,0.0,44.0,0.0,56.0,0.0,70.0,0.0,86.0,0.0,104.0,0.0,0.0,0.0,0.0,0.0,124.0,0.0,150.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,45.0,0.0,57.0,0.0,71.0,0.0,87.0,0.0,105.0,0.0,0.0,0.0,0.0,0.0,125.0,0.0,151.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,46.0,0.0,58.0,0.0,72.0,0.0,88.0,0.0,106.0,0.0,0.0,0.0,0.0,0.0,126.0,0.0,152.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,59.0,0.0,73.0,0.0,89.0,0.0,107.0,0.0,0.0,0.0,0.0,0.0,127.0,0.0,153.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,60.0,0.0,74.0,0.0,90.0,0.0,108.0,0.0,0.0,0.0,0.0,0.0,128.0,0.0,154.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,75.0,0.0,91.0,0.0,109.0,0.0,0.0,0.0,0.0,0.0,129.0,0.0,155.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,76.0,0.0,92.0,0.0,110.0,0.0,0.0,0.0,0.0,0.0,130.0,0.0,156.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,93.0,0.0,111.0,0.0,0.0,0.0,0.0,0.0,131.0,0.0,157.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,94.0,0.0,112.0,0.0,0.0,0.0,0.0,0.0,132.0,0.0,158.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,113.0,0.0,0.0,0.0,0.0,0.0,133.0,0.0,159.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,114.0,0.0,0.0,0.0,0.0,0.0,134.0,0.0,160.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,135.0,0.0,161.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,136.0,0.0,162.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,137.0,0.0,163.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,138.0,0.0,164.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,139.0,0.0,165.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,140.0,0.0,166.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,167.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,168.0], +]; + +/// uu(28, 28) from dielrc.f +/// 已转换为 Rust 行优先格式 +pub const DIELRC_UU: [[f64; 28]; 28] = [ + [109.6787,198.3108,0.0,0.0,0.0,90.82,117.225,109.837,0.0,173.93,0.0,61.671,0.0,65.748,0.0,83.558,0.0,127.11,0.0,49.306,0.0,0.0,0.0,0.0,0.0,63.737,0.0,61.6], + [0.0,438.9089,0.0,0.0,0.0,196.665,238.751,283.24,0.0,330.391,0.0,121.268,0.0,131.838,0.0,188.2,0.0,222.848,0.0,95.752,0.0,0.0,0.0,0.0,0.0,130.563,0.0,146.542], + [0.0,0.0,0.0,0.0,0.0,386.241,382.704,443.086,0.0,511.8,0.0,646.41,0.0,270.139,0.0,280.9,0.0,328.6,0.0,410.642,0.0,0.0,0.0,0.0,0.0,247.22,0.0,283.8], + [0.0,0.0,0.0,0.0,0.0,520.178,624.866,624.384,0.0,783.3,0.0,881.1,0.0,364.093,0.0,381.541,0.0,482.4,0.0,542.6,0.0,0.0,0.0,0.0,0.0,442.0,0.0,443.0], + [0.0,0.0,0.0,0.0,0.0,3162.395,789.537,918.657,0.0,1018.0,0.0,1139.4,0.0,1345.1,0.0,586.2,0.0,605.1,0.0,681.6,0.0,0.0,0.0,0.0,0.0,605.0,0.0,613.5], + [0.0,0.0,0.0,0.0,0.0,3952.06,4452.758,1114.008,0.0,1273.8,0.0,1504.3,0.0,1653.9,0.0,710.184,0.0,734.04,0.0,877.4,0.0,0.0,0.0,0.0,0.0,799.0,0.0,870.0], + [0.0,0.0,0.0,0.0,0.0,0.0,5380.089,5963.135,0.0,1671.792,0.0,1814.3,0.0,1988.4,0.0,2265.9,0.0,1002.73,0.0,1026.0,0.0,0.0,0.0,0.0,0.0,1008.0,0.0,1070.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,7028.393,0.0,1928.462,0.0,2144.7,0.0,2445.3,0.0,2647.4,0.0,1157.08,0.0,1187.6,0.0,0.0,0.0,0.0,0.0,1218.38,0.0,1310.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9645.005,0.0,2645.2,0.0,2831.9,0.0,3057.7,0.0,3407.3,0.0,1520.64,0.0,0.0,0.0,0.0,0.0,1884.0,0.0,1560.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,10986.876,0.0,2964.4,0.0,3237.8,0.0,3606.1,0.0,3860.9,0.0,1704.047,0.0,0.0,0.0,0.0,0.0,2114.0,0.0,1812.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,14210.261,0.0,3839.8,0.0,4071.4,0.0,4347.0,0.0,4774.0,0.0,0.0,0.0,0.0,0.0,2341.0,0.0,2589.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,15829.951,0.0,4222.4,0.0,4554.3,0.0,4986.6,0.0,5301.0,0.0,0.0,0.0,0.0,0.0,2668.0,0.0,2840.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,19661.693,0.0,5255.9,0.0,5533.8,0.0,5861.0,0.0,0.0,0.0,0.0,0.0,2912.0,0.0,3100.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,21560.63,0.0,5703.6,0.0,6095.5,0.0,6595.0,0.0,0.0,0.0,0.0,0.0,3163.0,0.0,3470.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,26002.663,0.0,6894.2,0.0,7215.0,0.0,0.0,0.0,0.0,0.0,3686.0,0.0,3740.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,28182.535,0.0,7404.4,0.0,7860.0,0.0,0.0,0.0,0.0,0.0,3946.82,0.0,4020.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,33237.173,0.0,8770.0,0.0,0.0,0.0,0.0,0.0,10180.0,0.0,4606.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,35699.936,0.0,9338.0,0.0,0.0,0.0,0.0,0.0,10985.0,0.0,4896.2], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,41366.0,0.0,0.0,0.0,0.0,0.0,11850.0,0.0,12430.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,44177.4,0.0,0.0,0.0,0.0,0.0,12708.0,0.0,13290.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,13620.0,0.0,14160.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,14510.0,0.0,15280.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,15797.0,0.0,16220.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,16500.0,0.0,17190.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,71203.0,0.0,18510.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,74829.0,0.0,19351.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,82984.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,86909.4], +]; + +/// adi(168) from dielrc.f +pub const DIELRC_ADI: [f64; 168] = [ + 0.0,0.0019,0.0,0.00069,0.007,0.0038,0.048,0.048,0.0,0.00052, + 0.0017,0.012,0.0055,0.076,0.066,0.0,0.0014,0.0014,0.0028,0.017, + 0.0071,0.11,0.086,0.0,0.0013,0.0031,0.0075,0.0057,0.01,0.04, + 0.011,0.18,0.13,0.0,0.0017,0.0035,0.0039,0.0093,0.015,0.012, + 0.014,0.038,0.014,0.26,0.17,0.0,0.0062,0.014,0.011,0.014, + 0.0078,0.016,0.023,0.011,0.011,0.048,0.018,0.34,0.21,0.0, + 7.3e-05,0.0049,0.0091,0.043,0.025,0.031,0.013,0.021,0.035,0.03, + 0.031,0.063,0.023,0.42,0.25,0.0,0.0001,0.011,0.034,0.0685, + 0.09,0.0635,0.026,0.017,0.021,0.035,0.054,0.0713,0.096,0.085, + 0.017,0.476,0.297,0.0,0.000328,0.0584,0.112,0.132,0.133,0.126, + 0.139,0.0955,0.402,0.0419,0.0257,0.0445,0.0548,0.0713,0.0903,0.11, + 0.0205,0.549,0.355,0.0,0.0018,0.036,0.078,0.22,0.14,0.14, + 0.11,0.63,0.55,0.36,0.26,0.16,0.066,0.25,0.12,5.0, + 0.037,0.063,0.07,0.11,0.1,0.11,0.036,0.75,0.52,0.0, + 0.00141,0.0052,0.0138,0.023,0.0419,0.0683,0.122,0.3,0.15,0.697, + 0.709,0.644,0.525,0.446,0.363,0.302,0.102,0.27,0.0467,0.0835, + 0.0996,0.199,0.24,0.115,0.0316,0.803,0.575,0.0, +]; + +/// bdi(168) from dielrc.f +pub const DIELRC_BDI: [f64; 168] = [ + 0.0,0.3,0.0,3.0,0.5,2.0,0.2,0.2,0.0,3.8, + 4.1,1.4,3.0,0.2,0.2,0.0,2.5,3.3,6.0,2.0, + 3.2,0.2,0.2,0.0,1.9,0.6,0.7,4.3,4.8,1.6, + 5.0,0.2,0.2,0.0,0.0,0.0,3.0,3.2,3.2,6.7, + 4.4,3.5,10.0,0.2,0.2,0.0,0.0,0.0,0.0,0.0, + 10.0,4.0,8.0,6.3,6.0,5.0,10.5,0.2,0.2,0.0, + 0.0,2.5,6.0,0.0,0.0,0.0,22.0,6.4,13.0,6.8, + 6.3,4.1,12.0,0.2,0.2,0.0,0.005,0.045,0.057,0.087, + 0.0769,0.14,0.12,0.1,1.92,1.66,1.67,1.4,1.31,1.02, + 0.245,0.294,0.277,0.0,0.0907,0.11,0.0174,0.132,0.114,0.162, + 0.0878,0.263,0.0627,0.0616,2.77,2.23,2.0,1.82,0.424,0.243, + 0.185,0.292,0.275,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 1.3,0.4,0.4,0.4,0.4,0.8,2.7,0.1,1.9,0.1, + 26.0,23.0,17.0,8.0,11.7,15.4,29.0,0.3,0.3,0.0, + 0.469,0.357,0.281,0.128,0.0417,0.0558,0.0346,0.0,1.9,0.277, + 0.135,0.134,0.192,0.332,0.337,0.121,0.0514,0.183,7.56,4.55, + 4.87,2.19,1.15,1.23,0.132,0.289,0.286,0.0, +]; + +/// t0(168) from dielrc.f +pub const DIELRC_T0: [f64; 168] = [ + 0.0,47.0,0.0,11.0,15.0,9.1,340.0,410.0,0.0,13.0, + 14.0,18.0,11.0,470.0,540.0,0.0,17.0,17.0,18.0,22.0, + 13.0,620.0,700.0,0.0,31.0,29.0,26.0,24.0,24.0,29.0, + 17.0,980.0,1100.0,0.0,5.1,61.0,44.0,39.0,34.0,31.0, + 31.0,36.0,21.0,1400.0,1500.0,0.0,11.0,12.0,10.0,120.0, + 55.0,49.0,42.0,38.0,37.0,42.0,25.0,1900.0,2000.0,0.0, + 11.0,12.0,13.0,18.0,15.0,190.0,67.0,59.0,55.0,47.0, + 42.0,50.0,30.0,2400.0,2500.0,0.0,32.0,29.0,23.9,25.6, + 25.0,21.0,18.0,270.0,83.0,69.5,60.5,66.8,65.0,53.0, + 35.5,3010.0,3130.0,0.0,3.46,38.5,40.8,38.2,35.3,31.9, + 32.2,24.7,22.9,373.0,92.6,79.6,69.0,67.0,47.2,56.7, + 42.1,3650.0,3780.0,0.0,5.8,13.0,28.0,37.0,49.0,63.0, + 68.0,77.0,73.0,71.0,68.0,61.0,59.0,43.0,35.0,770.0, + 100.0,87.0,62.0,69.0,68.0,67.0,41.0,5800.0,5900.0,0.0, + 9.82,20.1,30.5,42.0,55.6,67.2,79.3,90.0,100.0,78.1, + 76.4,74.4,66.5,59.7,52.4,49.6,44.6,849.0,136.0,123.0, + 106.0,125.0,123.0,33.2,64.5,6650.0,6810.0,0.0, +]; + +/// t1(168) from dielrc.f +pub const DIELRC_T1: [f64; 168] = [ + 0.0,9.4,0.0,4.9,23.0,37.0,51.0,76.0,0.0,4.8, + 6.8,38.0,59.0,72.0,98.0,0.0,13.0,5.8,9.1,59.0, + 80.0,95.0,130.0,0.0,15.0,17.0,45.0,17.0,35.0,110.0, + 130.0,140.0,260.0,0.0,0.0,0.0,41.0,87.0,100.0,54.0, + 36.0,160.0,210.0,240.0,350.0,0.0,0.0,0.0,0.0,0.0, + 100.0,130.0,170.0,60.0,110.0,250.0,280.0,310.0,440.0,0.0, + 0.0,8.8,15.0,0.0,0.0,0.0,180.0,200.0,230.0,120.0, + 130.0,340.0,360.0,460.0,550.0,0.0,31.0,55.0,60.0,38.1, + 33.0,21.5,21.5,330.0,350.0,360.0,380.0,290.0,360.0,280.0, + 110.0,605.0,654.0,0.0,1.64,24.5,42.7,69.2,87.8,74.3, + 69.9,44.3,28.1,584.0,489.0,462.0,452.0,332.0,137.0,441.0, + 227.0,725.0,768.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 36.0,63.0,85.0,89.0,100.0,120.0,190.0,190.0,250.0,90.0, + 630.0,770.0,620.0,510.0,870.0,990.0,1000.0,980.0,1200.0,0.0, + 10.1,19.1,23.2,31.8,45.5,55.1,52.8,0.0,55.0,88.7, + 180.0,125.0,189.0,88.4,129.0,62.4,159.0,801.0,932.0,945.0, + 945.0,801.0,757.0,264.0,193.0,1190.0,908.0,0.0, +]; + +/// cdd(168) from dielrc.f +pub const DIELRC_CDD: [f64; 168] = [ + 0.0024,0.0143,0.0009094,0.035,0.0305,0.009043,0.01077,0.0002585,0.0001953,0.08, + 0.008715,0.01346,0.004753,0.006304,0.0001601,0.0001574,0.056,0.0161,0.004081,0.007718, + 0.00291,0.00407,0.0001059,0.0001306,0.0337,0.01023,0.004726,0.00341,0.00166,0.003649, + 0.001412,0.00204,5.28e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,9.555e-05,0.081,0.04168,0.02792,0.02585, + 0.002137,0.0007325,0.0008059,0.0007821,0.0006306,0.001501,0.0005546,0.0007711,1.76e-05,5.965e-05, + 0.066,0.02842,0.0174,0.01579,0.01355,0.01221,0.001272,0.0003673,0.0004921,0.0004976, + 0.0004592,0.001108,0.0003973,0.0005326,1.098e-05,4.948e-05,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.00203,0.002299,0.002313,0.002233,0.002734,0.002934,0.002319, + 0.0003406,5.245e-05,0.0001246,0.000132,0.0001711,0.0004206,0.0001339,0.0001461,1.015e-06,2.508e-05, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// dcfe(26, 4) from dielrc.f +/// 已转换为 Rust 行优先格式 +pub const DIELRC_DCFE: [[f64; 4]; 26] = [ + [0.00022,0.0001,0.0,0.0], + [0.0023,0.0027,0.0,0.0], + [0.015,0.0047,0.0,0.0], + [0.038,0.016,0.0,0.0], + [0.08,0.024,0.0,0.0], + [0.092,0.041,0.0,0.0], + [0.16,0.036,0.0,0.0], + [0.18,0.07,0.0,0.0], + [0.14,0.26,0.0,0.0], + [0.1,0.28,0.0,0.0], + [0.225,0.231,0.0,0.0], + [0.24,0.17,0.0,0.0], + [0.26,0.16,0.0,0.0], + [0.19,0.09,0.0,0.0], + [0.12,0.12,0.6,0.0], + [1.23,0.0,0.0,0.0], + [0.00253,0.0336,0.181,1.92], + [0.00567,0.0782,0.0318,1.26], + [0.016,0.0717,0.0906,0.739], + [0.0185,0.0953,0.079,1.23], + [0.00092,0.129,0.192,0.912], + [0.131,0.0849,0.613,0.0], + [0.011,0.0488,0.0801,0.529], + [0.256,0.452,0.0,0.0], + [0.43,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0], +]; + +/// defe(26, 4) from dielrc.f +/// 已转换为 Rust 行优先格式 +pub const DIELRC_DEFE: [[f64; 4]; 26] = [ + [5.12,12.9,0.0,0.0], + [16.7,31.4,0.0,0.0], + [28.6,52.1,0.0,0.0], + [37.3,67.4,0.0,0.0], + [54.2,100.0,0.0,0.0], + [45.5,360.0,0.0,0.0], + [66.7,123.0,0.0,0.0], + [66.1,129.0,0.0,0.0], + [21.6,136.0,0.0,0.0], + [22.2,144.0,0.0,0.0], + [59.6,362.0,0.0,0.0], + [75.0,205.0,0.0,0.0], + [36.3,193.0,0.0,0.0], + [39.4,198.0,0.0,0.0], + [24.6,248.0,560.0,0.0], + [560.0,0.0,0.0,0.0], + [22.5,117.0,341.0,683.0], + [16.2,96.0,330.0,729.0], + [23.7,85.1,329.0,787.0], + [13.2,66.6,297.0,714.0], + [39.1,80.3,392.0,919.0], + [73.2,316.0,877.0,0.0], + [0.1,36.2,306.0,928.0], + [4625.0,6000.0,0.0,0.0], + [5300.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0], +]; + +/// gli(20) from dielrc.f +pub const DIELRC_GLI: [f64; 20] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,2.0,1.0, +]; + +/// gfe(26) from dielrc.f +pub const DIELRC_GFE: [f64; 26] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,30.0,25.0, +]; + +/// gni(28) from dielrc.f +pub const DIELRC_GNI: [f64; 28] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,28.0,21.0,10.0,21.0, +]; + +/// istorey(13) from dielrc.f +pub const DIELRC_ISTOREY: [f64; 13] = [ + 5.0,6.0,7.0,11.0,12.0,13.0,14.0,18.0,19.0,20.0, + 21.0,22.0,0.0, +]; + +/// rstorey(5, 13) from dielrc.f +/// 已转换为 Rust 行优先格式 +pub const DIELRC_RSTOREY: [[f64; 13]; 5] = [ + [0.0108,1.8267,2.3196,0.0,0.032,-0.8806,0.4134,0.0,-0.0036,0.0,0.0061,-2.8425,0.0], + [-0.1075,4.1012,10.7328,0.631,-0.6624,11.2406,-4.6319,0.0238,0.7519,21.879,0.2269,0.2283,0.0], + [0.281,4.8443,6.883,0.199,4.3191,30.7066,25.9172,0.0659,1.5252,16.273,32.1419,40.4072,0.0], + [-0.0193,0.2261,-0.1824,-0.0197,0.0003,-1.1721,-2.229,0.0349,-0.0838,-0.702,1.9939,-3.4956,0.0], + [-0.1127,0.596,0.4101,0.4398,0.5946,0.6127,-0.236,0.5334,0.2769,1.1899,-0.0646,1.7558,0.0], +]; + +/// hfrac (from dielrc.f, 未知维度,共 1 个值) +pub const DIELRC_HFRAC: [f64; 1] = [ + 1.0, +]; + +/// ergsev (from dielrc.f, 未知维度,共 1 个值) +pub const DIELRC_ERGSEV: [f64; 1] = [ + 1.602192e-12, +]; + +/// cc1 (from dielrc.f, 未知维度,共 1 个值) +pub const DIELRC_CC1: [f64; 1] = [ + 1e-06, +]; + +/// nni (from dielrc.f) +pub const DIELRC_NNI: f64 = 168.0; + +// ========== divstr.f ========== + +/// unq (from divstr.f) +pub const DIVSTR_UNQ: f64 = 1.25; + +/// unh (from divstr.f) +pub const DIVSTR_UNH: f64 = 1.5; + +/// twh (from divstr.f) +pub const DIVSTR_TWH: f64 = 2.5; + +/// fo (from divstr.f) +pub const DIVSTR_FO: f64 = 4.0; + +/// fi (from divstr.f) +pub const DIVSTR_FI: f64 = 5.0; + +/// ca (from divstr.f) +pub const DIVSTR_CA: f64 = 1.671; + +/// bl (from divstr.f) +pub const DIVSTR_BL: f64 = 5.821; + +/// al (from divstr.f) +pub const DIVSTR_AL: f64 = 1.26; + +/// cx (from divstr.f) +pub const DIVSTR_CX: f64 = 0.28; + +/// dx (from divstr.f) +pub const DIVSTR_DX: f64 = 0.0001; + +/// ca2 (from divstr.f) +pub const DIVSTR_CA2: f64 = 0.978; + +/// xa2 (from divstr.f) +pub const DIVSTR_XA2: f64 = 0.69314718; + +// ========== dopgam.f ========== + +/// bol2 (from dopgam.f) +pub const DOPGAM_BOL2: f64 = 2.76108e-16; + +/// r02 (from dopgam.f) +pub const DOPGAM_R02: f64 = 2.5; + +/// r12 (from dopgam.f) +pub const DOPGAM_R12: f64 = 45.0; + +/// op4 (from dopgam.f) +pub const DOPGAM_OP4: f64 = 0.4; + +/// vw0 (from dopgam.f) +pub const DOPGAM_VW0: f64 = 4.5e-09; + +// ========== dwnfr.f ========== + +/// p1 (from dwnfr.f) +pub const DWNFR_P1: f64 = 0.1402; + +/// p2 (from dwnfr.f) +pub const DWNFR_P2: f64 = 0.1285; + +/// p4 (from dwnfr.f) +pub const DWNFR_P4: f64 = 3.15; + +/// p5 (from dwnfr.f) +pub const DWNFR_P5: f64 = 4.0; + +/// tkn (from dwnfr.f) +pub const DWNFR_TKN: f64 = 3.01; + +/// ckn (from dwnfr.f) +pub const DWNFR_CKN: f64 = 5.33333333; + +/// cb0 (from dwnfr.f) +pub const DWNFR_CB0: f64 = 859000000000000.0; + +/// frh (from dwnfr.f) +pub const DWNFR_FRH: f64 = 3288050000000000.0; + +/// sqfrh (from dwnfr.f) +pub const DWNFR_SQFRH: f64 = 57341520.0; + +// ========== dwnfr0.f ========== + +/// ccor (from dwnfr0.f) +pub const DWNFR0_CCOR: f64 = 0.09; + +/// p1 (from dwnfr0.f) +pub const DWNFR0_P1: f64 = 0.1402; + +/// p2 (from dwnfr0.f) +pub const DWNFR0_P2: f64 = 0.1285; + +/// p4 (from dwnfr0.f) +pub const DWNFR0_P4: f64 = 3.15; + +/// p5 (from dwnfr0.f) +pub const DWNFR0_P5: f64 = 4.0; + +// ========== dwnfr1.f ========== + +/// tkn (from dwnfr1.f) +pub const DWNFR1_TKN: f64 = 3.01; + +/// ckn (from dwnfr1.f) +pub const DWNFR1_CKN: f64 = 5.33333333; + +/// cb0 (from dwnfr1.f) +pub const DWNFR1_CB0: f64 = 859000000000000.0; + +/// sqfrh (from dwnfr1.f) +pub const DWNFR1_SQFRH: f64 = 57341520.0; + +// ========== entene.f ========== + +/// ev2erg (from entene.f) +pub const ENTENE_EV2ERG: f64 = 1.6018e-12; + +/// entcon (from entene.f) +pub const ENTENE_ENTCON: f64 = 103.973; + +// ========== erfcin.f ========== + +/// pisq (from erfcin.f) +pub const ERFCIN_PISQ: f64 = 1.77245385090551; + +// ========== erfcx.f ========== + +/// p (from erfcx.f) +pub const ERFCX_P: f64 = 0.3275911; + +/// a1 (from erfcx.f) +pub const ERFCX_A1: f64 = 0.254829592; + +/// a2 (from erfcx.f) +pub const ERFCX_A2: f64 = -0.284496736; + +/// a3 (from erfcx.f) +pub const ERFCX_A3: f64 = 1.421413741; + +/// a4 (from erfcx.f) +pub const ERFCX_A4: f64 = -1.453152027; + +/// a5 (from erfcx.f) +pub const ERFCX_A5: f64 = 1.061405429; + +/// un (from erfcx.f) +pub const ERFCX_UN: f64 = 1.0; + +// ========== expint.f ========== + +/// a1 (from expint.f) +pub const EXPINT_A1: f64 = -0.57721566; + +/// a2 (from expint.f) +pub const EXPINT_A2: f64 = 0.99999193; + +/// a3 (from expint.f) +pub const EXPINT_A3: f64 = -0.24991055; + +/// a4 (from expint.f) +pub const EXPINT_A4: f64 = 0.05519968; + +/// a5 (from expint.f) +pub const EXPINT_A5: f64 = -0.00976004; + +/// a6 (from expint.f) +pub const EXPINT_A6: f64 = 0.00107857; + +/// b1 (from expint.f) +pub const EXPINT_B1: f64 = 0.2677734343; + +/// b2 (from expint.f) +pub const EXPINT_B2: f64 = 8.6347608925; + +/// b3 (from expint.f) +pub const EXPINT_B3: f64 = 18.059016973; + +/// b4 (from expint.f) +pub const EXPINT_B4: f64 = 8.5733287401; + +/// c1 (from expint.f) +pub const EXPINT_C1: f64 = 3.9584969228; + +/// c2 (from expint.f) +pub const EXPINT_C2: f64 = 21.0996530827; + +/// c3 (from expint.f) +pub const EXPINT_C3: f64 = 25.6329561486; + +/// c4 (from expint.f) +pub const EXPINT_C4: f64 = 9.5733223454; + +/// un (from expint.f) +pub const EXPINT_UN: f64 = 1.0; + +// ========== gami.f ========== + +/// xx(3) from gami.f +pub const GAMI_XX: [f64; 3] = [ + 0.0,50.6205,68.6112, +]; + +// ========== gauleg.f ========== + +/// eps (from gauleg.f) +pub const GAULEG_EPS: f64 = 3e-14; + +/// half (from gauleg.f) +pub const GAULEG_HALF: f64 = 0.5; + +/// pi (from gauleg.f) +pub const GAULEG_PI: f64 = 3.141592654; + +/// quart (from gauleg.f) +pub const GAULEG_QUART: f64 = 0.25; + +/// un (from gauleg.f) +pub const GAULEG_UN: f64 = 1.0; + +/// two (from gauleg.f) +pub const GAULEG_TWO: f64 = 2.0; + +// ========== gaunt.f ========== + +/// cgt(7, 10) from gaunt.f +/// 已转换为 Rust 行优先格式 +pub const GAUNT_CGT: [[f64; 10]; 7] = [ + [0.0,-2.0244141,-0.23387146,-0.054418565,-0.0089182854,-0.0055303574,-0.0022752881,-0.00097200274,-0.00049576163,-0.00029467046], + [12.803223,2.1325684,0.52471924,0.19683564,0.055545091,0.041921183,0.023350812,0.013298411,0.0085139736,0.0061516856], + [-5.5759888,-1.2709045,-0.55936432,-0.3119073,-0.16051018,-0.13075417,-0.095441161,-0.07101056,-0.05604656,-0.04732637], + [1.2302628,1.1595421,1.1450949,1.1306695,1.1190904,1.1168376,1.1128632,1.1093137,1.1078717,1.1052734], + [-0.0029094219,-0.002073586,-0.0019366592,-0.0013482273,-0.0010401085,-0.00089466573,-0.0007483326,-0.00062619148,-0.00054837392,-0.0004434157], + [7.3993579e-06,2.7033384e-06,2.3572356e-06,-4.6949424e-06,-6.9943488e-06,-8.8393133e-06,-1.0244504e-05,-1.1342068e-05,-1.2157943e-05,-1.3235905e-05], + [-8.7356966e-09,0.0,0.0,2.3548636e-08,2.8496742e-08,3.4696768e-08,3.8595771e-08,4.1477731e-08,4.3796716e-08,4.700314e-08], +]; + +/// frkw(10) from gaunt.f +pub const GAUNT_FRKW: [f64; 10] = [ + 6600000000000000.0,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3,3.3, +]; + +/// un (from gaunt.f) +pub const GAUNT_UN: f64 = 1.0; + +// ========== getlal.f ========== + +/// nxmax (from getlal.f) +pub const GETLAL_NXMAX: f64 = 1400.0; + +/// nnmax (from getlal.f) +pub const GETLAL_NNMAX: f64 = 5.0; + +/// ntamax (from getlal.f) +pub const GETLAL_NTAMAX: f64 = 6.0; + +// ========== getwrd.f ========== + +/// msepar (from getwrd.f) +pub const GETWRD_MSEPAR: f64 = 7.0; + +// ========== gfree0.f ========== + +/// thet0 (from gfree0.f) +pub const GFREE0_THET0: f64 = 5040.4; + +/// a0 (from gfree0.f) +pub const GFREE0_A0: f64 = 1.0823; + +/// b0 (from gfree0.f) +pub const GFREE0_B0: f64 = 0.0298; + +/// c0 (from gfree0.f) +pub const GFREE0_C0: f64 = 0.0067; + +/// d0 (from gfree0.f) +pub const GFREE0_D0: f64 = 0.0112; + +/// a1 (from gfree0.f) +pub const GFREE0_A1: f64 = 0.0039999187; + +/// b1 (from gfree0.f) +pub const GFREE0_B1: f64 = -7.8622889e-05; + +/// c1 (from gfree0.f) +pub const GFREE0_C1: f64 = 1.070192; + +/// a2 (from gfree0.f) +pub const GFREE0_A2: f64 = 0.064628601; + +/// b2 (from gfree0.f) +pub const GFREE0_B2: f64 = -0.00061953813; + +/// c2 (from gfree0.f) +pub const GFREE0_C2: f64 = 0.26061249; + +/// a3 (from gfree0.f) +pub const GFREE0_A3: f64 = 0.037542343; + +/// b3 (from gfree0.f) +pub const GFREE0_B3: f64 = 1.3983474e-05; + +/// c3 (from gfree0.f) +pub const GFREE0_C3: f64 = 0.57917786; + +/// a4 (from gfree0.f) +pub const GFREE0_A4: f64 = 0.34169006; + +/// b4 (from gfree0.f) +pub const GFREE0_B4: f64 = 0.011852264; + +/// xmin (from gfree0.f) +pub const GFREE0_XMIN: f64 = 0.2; + +/// thmin (from gfree0.f) +pub const GFREE0_THMIN: f64 = 0.04; + +// ========== gfree1.f ========== + +/// xmin (from gfree1.f) +pub const GFREE1_XMIN: f64 = 0.2; + +// ========== gfreed.f ========== + +/// c14 (from gfreed.f) +pub const GFREED_C14: f64 = 299792500000000.0; + +/// xmin (from gfreed.f) +pub const GFREED_XMIN: f64 = 0.2; + +// ========== grcor.f ========== + +/// pi3 (from grcor.f) +pub const GRCOR_PI3: f64 = 1.0471976; + +// ========== greyd.f ========== + +/// errm0 (from greyd.f) +pub const GREYD_ERRM0: f64 = 0.001; + +/// ntrm (from greyd.f) +pub const GREYD_NTRM: f64 = 50.0; + +// ========== h2minus.f ========== + +/// ffthet(9) from h2minus.f +pub const H2MINUS_FFTHET: [f64; 9] = [ + 0.5,0.8,1.0,1.2,1.6,2.0,2.8,3.6,10.0, +]; + +/// fflamb(18) from h2minus.f +pub const H2MINUS_FFLAMB: [f64; 18] = [ + 151883.0,113913.0,91130.0,60753.0,45565.0,36452.0,30377.0,22783.0,18226.0,15188.0, + 11391.0,9113.0,7594.0,6509.0,5696.0,5063.0,4142.0,3505.0, +]; + +/// ffkapp(18, 9) from h2minus.f +/// 已转换为 Rust 行优先格式 +pub const H2MINUS_FFKAPP: [[f64; 9]; 18] = [ + [71.6,92.3,101.0,108.0,118.0,126.0,138.0,147.0,219.0], + [40.3,52.0,57.0,60.8,66.5,70.8,77.6,83.0,126.0], + [25.8,33.3,36.5,39.0,42.7,45.4,49.8,53.3,81.3], + [11.5,14.8,16.3,17.4,19.1,20.4,22.4,24.0,36.8], + [6.47,8.37,9.2,9.84,10.8,11.6,12.8,13.8,21.8], + [4.15,5.38,5.92,6.35,6.99,7.5,8.32,9.02,14.6], + [2.89,3.76,4.14,4.44,4.91,5.28,5.9,6.44,10.8], + [1.63,2.14,2.36,2.55,2.84,3.07,3.49,3.9,7.18], + [1.05,1.39,1.54,1.66,1.87,2.04,2.36,2.68,5.24], + [0.736,0.975,1.09,1.18,1.34,1.48,1.74,2.01,4.17], + [0.42,0.564,0.635,0.697,0.806,0.909,1.11,1.32,3.0], + [0.273,0.371,0.422,0.467,0.552,0.633,0.797,0.963,2.29], + [0.192,0.264,0.303,0.339,0.408,0.476,0.613,0.751,1.86], + [0.143,0.198,0.23,0.259,0.317,0.375,0.492,0.609,1.55], + [0.11,0.154,0.18,0.206,0.255,0.305,0.406,0.507,1.32], + [0.087,0.124,0.146,0.167,0.21,0.253,0.339,0.427,1.13], + [0.0584,0.0843,0.101,0.117,0.149,0.182,0.249,0.316,0.852], + [0.0417,0.061,0.0734,0.0859,0.111,0.137,0.187,0.24,0.664], +]; + +/// nthet (from h2minus.f, 未知维度,共 1 个值) +pub const H2MINUS_NTHET: [f64; 1] = [ + 9.0, +]; + +/// nlamb (from h2minus.f, 未知维度,共 1 个值) +pub const H2MINUS_NLAMB: [f64; 1] = [ + 18.0, +]; + +// ========== hephot.f ========== + +/// ist(3, 2) from hephot.f +/// 已转换为 Rust 行优先格式 +pub const HEPHOT_IST: [[f64; 2]; 3] = [ + [1.0,11.0], + [36.0,45.0], + [20.0,28.0], +]; + +/// n0(3, 2) from hephot.f +/// 已转换为 Rust 行优先格式 +pub const HEPHOT_N0: [[f64; 2]; 3] = [ + [1.0,2.0], + [2.0,2.0], + [3.0,3.0], +]; + +/// fl0(53) from hephot.f +pub const HEPHOT_FL0: [f64; 53] = [ + 0.2521,-0.5381,-0.9139,-1.175,-1.375,-1.537,-1.674,-1.792,-1.896,-1.989, + -0.4555,-0.8622,-1.137,-1.345,-1.512,-1.653,-1.774,-1.88,-1.974,-0.9538, + -1.204,-1.398,-1.556,-1.69,-1.806,-1.909,-2.0,-0.9537,-1.204,-1.398, + -1.556,-1.69,-1.806,-1.909,-2.0,-0.6065,-0.9578,-1.207,-1.4,-1.558, + -1.692,-1.808,-1.91,-2.002,-0.5749,-0.9352,-1.19,-1.386,-1.547,-1.682, + -1.799,-1.902,-1.995, +]; + +/// a(53) from hephot.f +pub const HEPHOT_A: [f64; 53] = [ + 0.695319,1.13101,1.36313,1.51684,1.64767,1.75643,1.84458,1.87243,1.85628,1.90889, + 0.901802,1.25389,1.39033,1.55226,1.60658,1.6593,1.68855,1.62477,1.66726,1.83599, + 2.50403,3.08564,3.56545,4.25922,4.61346,4.91417,5.19211,1.74181,2.25756,2.95625, + 3.65899,4.04397,4.1341,4.43538,4.19583,1.79027,2.23543,2.63942,3.02461,3.35018, + 3.62067,3.85218,3.76689,3.49318,1.16294,1.86467,2.0211,2.24231,2.4424,2.76594, + 2.9323,3.08109,3.21069, +]; + +/// b(53) from hephot.f +pub const HEPHOT_B: [f64; 53] = [ + -1.29,-2.15771,-2.13263,-2.10272,-2.10861,-2.11507,-2.1171,-2.08531,-2.03296,-2.03441, + -1.85905,-2.04057,-2.02189,-2.0593,-2.03403,-2.02071,-1.99956,-1.92851,-1.92905,-4.58608, + -4.40022,-4.39154,-4.39676,-4.57631,-4.5712,-4.56188,-4.55915,-4.41218,-4.1294,-4.24401, + -4.40783,-4.3993,-4.25981,-4.26804,-4.00419,-4.47251,-3.8796,-3.71668,-3.68461,-3.67173, + -3.65991,-3.64968,-3.48666,-3.23985,-2.95758,-3.0711,-2.87157,-2.83137,-2.82132,-2.91084, + -2.91159,-2.91336,-2.91296, +]; + +/// xfitm(53) from hephot.f +pub const HEPHOT_XFITM: [f64; 53] = [ + 0.3262,0.6135,0.9233,0.8438,1.02,1.169,1.298,1.411,1.512,1.602, + 0.7228,1.076,1.206,1.404,1.481,1.464,1.581,1.685,1.777,0.9586, + 1.187,1.371,1.524,1.74,1.854,1.955,2.046,0.9585,1.041,1.371, + 1.608,1.739,1.768,1.869,1.803,0.736,1.041,1.272,1.457,1.611, + 1.741,1.855,1.87,1.804,0.9302,1.144,1.028,1.21,1.362,1.646, + 1.761,1.863,1.954, +]; + +/// tenm18 (from hephot.f) +pub const HEPHOT_TENM18: f64 = 1e-18; + +/// frh (from hephot.f) +pub const HEPHOT_FRH: f64 = 3288050000000000.0; + +/// two (from hephot.f) +pub const HEPHOT_TWO: f64 = 2.0; + +/// tenlg (from hephot.f) +pub const HEPHOT_TENLG: f64 = 2.302585093; + +/// phot0 (from hephot.f) +pub const HEPHOT_PHOT0: f64 = 2.815e+29; + +// ========== hesol6.f ========== + +/// error (from hesol6.f, 未知维度,共 1 个值) +pub const HESOL6_ERROR: [f64; 1] = [ + 0.0001, +]; + +/// mp (from hesol6.f) +pub const HESOL6_MP: f64 = 6.0; + +/// np (from hesol6.f) +pub const HESOL6_NP: f64 = 6.0; + +/// ip (from hesol6.f) +pub const HESOL6_IP: f64 = 1.0; + +/// ig (from hesol6.f) +pub const HESOL6_IG: f64 = 2.0; + +/// ir (from hesol6.f) +pub const HESOL6_IR: f64 = 3.0; + +/// in (from hesol6.f) +pub const HESOL6_IN: f64 = 4.0; + +/// ie (from hesol6.f) +pub const HESOL6_IE: f64 = 5.0; + +/// iz (from hesol6.f) +pub const HESOL6_IZ: f64 = 6.0; + +/// niterh (from hesol6.f) +pub const HESOL6_NITERH: f64 = 15.0; + +// ========== hesolv.f ========== + +/// error (from hesolv.f, 未知维度,共 1 个值) +pub const HESOLV_ERROR: [f64; 1] = [ + 0.0001, +]; + +// ========== hidalg.f ========== + +/// wl1(20) from hidalg.f +pub const HIDALG_WL1: [f64; 20] = [ + 39.1,80.9,97.6,100.1,104.3,107.2,108.7,111.9,113.6,115.4, + 117.1,119.0,124.8,126.9,129.1,131.3,133.6,136.0,138.5,141.1, +]; + +/// wl2(20) from hidalg.f +pub const HIDALG_WL2: [f64; 20] = [ + 68.5,80.9,100.1,120.9,158.8,165.7,177.3,190.6,200.7,206.2, + 211.9,218.0,224.5,231.3,246.3,0.0,0.0,0.0,0.0,0.0, +]; + +/// sig0(20, 24) from hidalg.f +/// 已转换为 Rust 行优先格式 +pub const HIDALG_SIG0: [[f64; 24]; 20] = [ + [0.0,0.0,0.0,0.0,0.0,0.0,0.046,0.0,0.0,0.0,0.0,0.0092,0.0,0.34,0.0,0.0064,0.0,0.0,0.0,0.0,0.037,0.0,0.0,0.022], + [0.0,0.0,0.0,0.0,0.0,0.0,0.24,0.0,0.0,0.0,0.0,0.1,0.0,0.46,0.0,0.11,0.0,0.0,0.0,0.0,0.065,0.0,0.0,0.039], + [0.0,0.0,0.0,0.0,0.0,0.0,0.35,0.0,0.0,0.0,0.0,0.19,0.0,0.63,0.0,0.22,0.0,0.0,0.0,0.0,0.13,0.0,0.0,0.08], + [0.0,0.0,0.0,0.0,0.0,0.0,0.37,0.0,0.0,0.0,0.0,0.21,0.0,0.77,0.0,0.41,0.0,0.0,0.0,0.0,0.24,0.0,0.0,0.15], + [0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.0,0.0,0.0,0.0,0.23,0.0,0.91,0.0,0.94,0.0,0.0,0.0,0.0,0.55,0.0,0.0,0.35], + [0.0,0.0,0.0,0.0,0.0,0.0,0.43,0.0,0.0,0.0,0.0,0.25,0.0,1.08,0.0,1.0,0.0,0.0,0.0,0.0,0.63,0.0,0.0,0.4], + [0.0,0.0,0.0,0.0,0.0,0.0,0.44,0.0,0.0,0.0,0.0,0.26,0.0,0.0,0.0,1.3,0.0,0.0,0.0,0.0,0.77,0.0,0.0,0.49], + [0.0,0.0,0.0,0.0,0.0,0.0,0.46,0.0,0.0,0.0,0.0,0.29,0.0,0.0,0.0,1.6,0.0,0.0,0.0,0.0,0.95,0.0,0.0,0.62], + [0.0,0.0,0.0,0.0,0.0,0.0,0.47,0.0,0.0,0.0,0.0,0.3,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1,0.0,0.0,0.72], + [0.0,0.0,0.0,0.0,0.0,0.0,0.49,0.0,0.0,0.0,0.0,0.32,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25,0.0,0.0,0.78], + [0.0,0.0,0.0,0.0,0.0,0.0,0.5,0.0,0.0,0.0,0.0,0.34,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.85], + [0.0,0.0,0.0,0.0,0.0,0.0,0.52,0.0,0.0,0.0,0.0,0.35,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.93], + [0.0,0.0,0.0,0.0,0.0,0.0,0.57,0.0,0.0,0.0,0.0,0.41,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02], + [0.0,0.0,0.0,0.0,0.0,0.0,0.62,0.0,0.0,0.0,0.0,0.43,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.45,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.48,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.53,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.56,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.59,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], +]; + +// ========== incldy.f ========== + +/// minput (from incldy.f) +pub const INCLDY_MINPUT: f64 = 6.0; + +// ========== inifrc.f ========== + +/// tenlg (from inifrc.f) +pub const INIFRC_TENLG: f64 = 2.302585093; + +// ========== inifrs.f ========== + +/// xmass(30) from inifrs.f +pub const INIFRS_XMASS: [f64; 30] = [ + 1.008,4.003,6.941,9.012,10.81,12.011,14.007,16.0,18.918,20.179, + 22.99,24.305,26.982,28.086,30.974,32.06,35.453,39.948,39.098,40.08, + 44.956,47.9,50.941,51.996,54.938,55.847,58.933,58.7,63.546,65.38, +]; + +// ========== initia.f ========== + +/// igle(18) from initia.f +pub const INITIA_IGLE: [f64; 18] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, +]; + +/// igmn(25) from initia.f +pub const INITIA_IGMN: [f64; 25] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,7.0,6.0, +]; + +/// igfe(26) from initia.f +pub const INITIA_IGFE: [f64; 26] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,30.0,25.0, +]; + +/// igni(28) from initia.f +pub const INITIA_IGNI: [f64; 28] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,28.0,21.0,10.0,21.0, +]; + +/// t15 (from initia.f) +pub const INITIA_T15: f64 = 1e-15; + +/// xcon (from initia.f) +pub const INITIA_XCON: f64 = 8.0935e-21; + +// ========== inkul.f ========== + +/// e0fe(10) from inkul.f +pub const INKUL_E0FE: [f64; 10] = [ + 63480.0,130563.0,247220.0,442000.0,605000.0,799000.0,1008000.0,1218380.0,1884000.0,2114000.0, +]; + +/// e0ni(10) from inkul.f +pub const INKUL_E0NI: [f64; 10] = [ + 61590.0,146560.0,283700.0,443000.0,613500.0,871000.0,1070000.0,1310000.0,1560000.0,1812000.0, +]; + +/// e0cr(10) from inkul.f +pub const INKUL_E0CR: [f64; 10] = [ + 54576.0,132966.0,249700.0,396500.0,560200.0,731020.0,1291900.0,1490000.0,1688000.0,1971000.0, +]; + +/// ten (from inkul.f) +pub const INKUL_TEN: f64 = 10.0; + +/// tenlg (from inkul.f) +pub const INKUL_TENLG: f64 = 2.302585093; + +/// ges (from inkul.f) +pub const INKUL_GES: f64 = 0.05; + +/// bol2 (from inkul.f) +pub const INKUL_BOL2: f64 = 2.76108e-16; + +/// cstk (from inkul.f) +pub const INKUL_CSTK: f64 = 3.54; + +/// cvdw (from inkul.f) +pub const INKUL_CVDW: f64 = 3.74; + +/// pvdw (from inkul.f) +pub const INKUL_PVDW: f64 = 0.4; + +/// tvdw (from inkul.f) +pub const INKUL_TVDW: f64 = 0.3; + +/// csig (from inkul.f) +pub const INKUL_CSIG: f64 = 0.0149736; + +/// expia1 (from inkul.f) +pub const INKUL_EXPIA1: f64 = -0.57721566; + +/// expia2 (from inkul.f) +pub const INKUL_EXPIA2: f64 = 0.99999193; + +/// expia3 (from inkul.f) +pub const INKUL_EXPIA3: f64 = -0.24991055; + +/// expia4 (from inkul.f) +pub const INKUL_EXPIA4: f64 = 0.05519968; + +/// expia5 (from inkul.f) +pub const INKUL_EXPIA5: f64 = -0.00976004; + +/// expia6 (from inkul.f) +pub const INKUL_EXPIA6: f64 = 0.00107857; + +/// expib1 (from inkul.f) +pub const INKUL_EXPIB1: f64 = 0.2677734343; + +/// expib2 (from inkul.f) +pub const INKUL_EXPIB2: f64 = 8.6347608925; + +/// expib3 (from inkul.f) +pub const INKUL_EXPIB3: f64 = 18.059016973; + +/// expib4 (from inkul.f) +pub const INKUL_EXPIB4: f64 = 8.5733287401; + +/// expic1 (from inkul.f) +pub const INKUL_EXPIC1: f64 = 3.9584969228; + +/// expic2 (from inkul.f) +pub const INKUL_EXPIC2: f64 = 21.0996530827; + +/// expic3 (from inkul.f) +pub const INKUL_EXPIC3: f64 = 25.6329561486; + +/// expic4 (from inkul.f) +pub const INKUL_EXPIC4: f64 = 9.5733223454; + +// ========== inpdis.f ========== + +/// velc (from inpdis.f) +pub const INPDIS_VELC: f64 = 29979250000.0; + +/// pi4 (from inpdis.f) +pub const INPDIS_PI4: f64 = 12.5663706; + +/// grcon (from inpdis.f) +pub const INPDIS_GRCON: f64 = 6.668e-08; + +// ========== intlem.f ========== + +/// foc1 (from intlem.f) +pub const INTLEM_FOC1: f64 = 1.25e-09; + +/// vtbc (from intlem.f) +pub const INTLEM_VTBC: f64 = 6.06e-09; + +// ========== iroset.f ========== + +/// csig (from iroset.f) +pub const IROSET_CSIG: f64 = 0.0149736; + +// ========== kurucz.f ========== + +/// minput (from kurucz.f) +pub const KURUCZ_MINPUT: f64 = 7.0; + +// ========== laguer.f ========== + +/// frac(8) from laguer.f +pub const LAGUER_FRAC: [f64; 8] = [ + 0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0, +]; + +/// epss (from laguer.f) +pub const LAGUER_EPSS: f64 = 2e-07; + +/// mr (from laguer.f) +pub const LAGUER_MR: f64 = 8.0; + +/// mt (from laguer.f) +pub const LAGUER_MT: f64 = 10.0; + +// ========== levcd.f ========== + +/// e0fe(10) from levcd.f +pub const LEVCD_E0FE: [f64; 10] = [ + 63480.0,130563.0,247220.0,442000.0,605000.0,799000.0,1008000.0,1218380.0,1884000.0,2114000.0, +]; + +/// e0ni(10) from levcd.f +pub const LEVCD_E0NI: [f64; 10] = [ + 61590.0,146560.0,283700.0,443000.0,613500.0,871000.0,1070000.0,1310000.0,1560000.0,1812000.0, +]; + +/// e0cr(10) from levcd.f +pub const LEVCD_E0CR: [f64; 10] = [ + 54576.0,132966.0,249700.0,396500.0,560200.0,731020.0,1291900.0,1490000.0,1688000.0,1971000.0, +]; + +/// ccor (from levcd.f) +pub const LEVCD_CCOR: f64 = 0.09; + +/// ges (from levcd.f) +pub const LEVCD_GES: f64 = 0.05; + +// ========== linpro.f ========== + +/// bol2 (from linpro.f) +pub const LINPRO_BOL2: f64 = 2.76108e-16; + +/// os0 (from linpro.f) +pub const LINPRO_OS0: f64 = 0.02654; + +/// f0c1 (from linpro.f) +pub const LINPRO_F0C1: f64 = 1.25e-09; + +/// f0c2 (from linpro.f) +pub const LINPRO_F0C2: f64 = 3.906e-11; + +/// cca (from linpro.f) +pub const LINPRO_CCA: f64 = 2.997925e+18; + +/// al10 (from linpro.f) +pub const LINPRO_AL10: f64 = 2.3025851; + +// ========== linset.f ========== + +/// bol2 (from linset.f) +pub const LINSET_BOL2: f64 = 2.76108e-16; + +/// os0 (from linset.f) +pub const LINSET_OS0: f64 = 0.02654; + +/// f0c1 (from linset.f) +pub const LINSET_F0C1: f64 = 1.25e-09; + +/// f0c2 (from linset.f) +pub const LINSET_F0C2: f64 = 3.906e-11; + +// ========== linspl.f ========== + +/// os0 (from linspl.f) +pub const LINSPL_OS0: f64 = 0.02654; + +// ========== ltegrd.f ========== + +/// errt (from ltegrd.f) +pub const LTEGRD_ERRT: f64 = 0.001; + +/// four (from ltegrd.f) +pub const LTEGRD_FOUR: f64 = 4.0; + +// ========== lucy.f ========== + +/// ilinit (from lucy.f, 未知维度,共 1 个值) +pub const LUCY_ILINIT: [f64; 1] = [ + 0.0, +]; + +// ========== lymlin.f ========== + +/// inip (from lymlin.f, 未知维度,共 1 个值) +pub const LYMLIN_INIP: [f64; 1] = [ + 1.0, +]; + +/// os0 (from lymlin.f) +pub const LYMLIN_OS0: f64 = 0.02654; + +/// cpp (from lymlin.f) +pub const LYMLIN_CPP: f64 = 4.1412e-16; + +/// cpj (from lymlin.f) +pub const LYMLIN_CPJ: f64 = 157803.0; + +/// c00 (from lymlin.f) +pub const LYMLIN_C00: f64 = 1.25e-09; + +/// c18 (from lymlin.f) +pub const LYMLIN_C18: f64 = 2.997925e+18; + +/// mlevl (from lymlin.f) +pub const LYMLIN_MLEVL: f64 = 30.0; + +// ========== minv3.f ========== + +/// un (from minv3.f) +pub const MINV3_UN: f64 = 1.0; + +// ========== moleq.f ========== + +/// nmetal (from moleq.f, 未知维度,共 1 个值) +pub const MOLEQ_NMETAL: [f64; 1] = [ + 92.0, +]; + +/// iread (from moleq.f, 未知维度,共 1 个值) +pub const MOLEQ_IREAD: [f64; 1] = [ + 1.0, +]; + +// ========== mpartf.f ========== + +/// indtsu(324) from mpartf.f +pub const MPARTF_INDTSU: [f64; 324] = [ + 2.0,5.0,12.0,4.0,8.0,7.0,6.0,9.0,11.0,10.0, + 29.0,50.0,59.0,46.0,133.0,52.0,19.0,13.0,42.0,38.0, + 39.0,37.0,44.0,36.0,14.0,118.0,33.0,3.0,16.0,57.0, + 32.0,49.0,60.0,54.0,41.0,107.0,304.0,148.0,152.0,153.0, + 155.0,303.0,17.0,24.0,25.0,28.0,51.0,112.0,119.0,102.0, + 0.0,21.0,15.0,43.0,22.0,478.0,64.0,47.0,65.0,414.0, + 61.0,191.0,62.0,109.0,40.0,66.0,214.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,30.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0, +]; + +/// igle(28) from mpartf.f +pub const MPARTF_IGLE: [f64; 28] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,28.0,21.0,10.0,21.0, +]; + +/// iread (from mpartf.f, 未知维度,共 1 个值) +pub const MPARTF_IREAD: [f64; 1] = [ + 0.0, +]; + +// ========== newdm.f ========== + +/// ten (from newdm.f) +pub const NEWDM_TEN: f64 = 10.0; + +// ========== nstpar.f ========== + +/// mvar (from nstpar.f) +pub const NSTPAR_MVAR: f64 = 236.0; + +/// inpfi (from nstpar.f) +pub const NSTPAR_INPFI: f64 = 4.0; + +// ========== odf1.f ========== + +/// frh (from odf1.f) +pub const ODF1_FRH: f64 = 3288050000000000.0; + +/// cqt (from odf1.f) +pub const ODF1_CQT: f64 = 1284523000000.0; + +/// ccor (from odf1.f) +pub const ODF1_CCOR: f64 = 0.09; + +/// c00 (from odf1.f) +pub const ODF1_C00: f64 = 1.25e-09; + +/// cid (from odf1.f) +pub const ODF1_CID: f64 = 0.02654; + +// ========== odffr.f ========== + +/// frh (from odffr.f) +pub const ODFFR_FRH: f64 = 3288050000000000.0; + +/// cdop (from odffr.f) +pub const ODFFR_CDOP: f64 = 2.84511e-07; + +/// cdom (from odffr.f) +pub const ODFFR_CDOM: f64 = 14.0; + +/// six (from odffr.f) +pub const ODFFR_SIX: f64 = 6.0; + +/// sept (from odffr.f) +pub const ODFFR_SEPT: f64 = 7.0; + +// ========== odfhst.f ========== + +/// f0 (from odfhst.f) +pub const ODFHST_F0: f64 = -0.5758228; + +/// f1 (from odfhst.f) +pub const ODFHST_F1: f64 = 0.4796232; + +/// f2 (from odfhst.f) +pub const ODFHST_F2: f64 = 0.07209481; + +/// al (from odfhst.f) +pub const ODFHST_AL: f64 = 1.26; + +/// sd (from odfhst.f) +pub const ODFHST_SD: f64 = 0.5641895; + +/// slo (from odfhst.f) +pub const ODFHST_SLO: f64 = -2.5; + +/// thra (from odfhst.f) +pub const ODFHST_THRA: f64 = 1.5; + +/// bl1 (from odfhst.f) +pub const ODFHST_BL1: f64 = 1.14; + +/// bl2 (from odfhst.f) +pub const ODFHST_BL2: f64 = 11.4; + +/// sac (from odfhst.f) +pub const ODFHST_SAC: f64 = 0.08; + +// ========== odfhyd.f ========== + +/// ca (from odfhyd.f) +pub const ODFHYD_CA: f64 = 2.997925e+18; + +/// frh (from odfhyd.f) +pub const ODFHYD_FRH: f64 = 3288050000000000.0; + +/// rydel (from odfhyd.f) +pub const ODFHYD_RYDEL: f64 = 911.764; + +/// c00 (from odfhyd.f) +pub const ODFHYD_C00: f64 = 1.25e-09; + +/// cid (from odfhyd.f) +pub const ODFHYD_CID: f64 = 0.02654; + +// ========== odfhys.f ========== + +/// frh (from odfhys.f) +pub const ODFHYS_FRH: f64 = 3288050000000000.0; + +// ========== odfmer.f ========== + +/// chtl (from odfmer.f) +pub const ODFMER_CHTL: f64 = 0.001; + +// ========== opacf0.f ========== + +/// frh (from opacf0.f) +pub const OPACF0_FRH: f64 = 3288050000000000.0; + +/// ehb (from opacf0.f) +pub const OPACF0_EHB: f64 = 157802.77355; + +/// cff1 (from opacf0.f) +pub const OPACF0_CFF1: f64 = 1.3727e-25; + +/// cff2 (from opacf0.f) +pub const OPACF0_CFF2: f64 = 4.3748e-10; + +/// cff3 (from opacf0.f) +pub const OPACF0_CFF3: f64 = 2.5993e-07; + +/// c14 (from opacf0.f) +pub const OPACF0_C14: f64 = 299793000000000.0; + +/// sgff0 (from opacf0.f) +pub const OPACF0_SGFF0: f64 = 369400000.0; + +// ========== opacf1.f ========== + +/// c14 (from opacf1.f) +pub const OPACF1_C14: f64 = 299793000000000.0; + +/// cff1 (from opacf1.f) +pub const OPACF1_CFF1: f64 = 1.3727e-25; + +// ========== opacfa.f ========== + +/// c14 (from opacfa.f) +pub const OPACFA_C14: f64 = 299793000000000.0; + +/// cff1 (from opacfa.f) +pub const OPACFA_CFF1: f64 = 1.3727e-25; + +// ========== opacfd.f ========== + +/// c14 (from opacfd.f) +pub const OPACFD_C14: f64 = 299793000000000.0; + +/// cff1 (from opacfd.f) +pub const OPACFD_CFF1: f64 = 1.3727e-25; + +/// delt (from opacfd.f) +pub const OPACFD_DELT: f64 = 0.001; + +/// delr (from opacfd.f) +pub const OPACFD_DELR: f64 = 0.001; + +// ========== opacfl.f ========== + +/// c14 (from opacfl.f) +pub const OPACFL_C14: f64 = 299793000000000.0; + +/// cff1 (from opacfl.f) +pub const OPACFL_CFF1: f64 = 1.3727e-25; + +// ========== opactd.f ========== + +/// delt (from opactd.f) +pub const OPACTD_DELT: f64 = 0.001; + +/// delr (from opactd.f) +pub const OPACTD_DELR: f64 = 0.001; + +// ========== opactr.f ========== + +/// delt (from opactr.f) +pub const OPACTR_DELT: f64 = 0.01; + +// ========== opadd.f ========== + +/// frray (from opadd.f) +pub const OPADD_FRRAY: f64 = 2463000000000000.0; + +/// frayhe (from opadd.f) +pub const OPADD_FRAYHE: f64 = 5150000000000000.0; + +/// frayh2 (from opadd.f) +pub const OPADD_FRAYH2: f64 = 2922000000000000.0; + +/// cls (from opadd.f) +pub const OPADD_CLS: f64 = 2.997925e+18; + +/// c18 (from opadd.f) +pub const OPADD_C18: f64 = 2.997925e+18; + +/// cr0 (from opadd.f) +pub const OPADD_CR0: f64 = 5.799e-13; + +/// cr1 (from opadd.f) +pub const OPADD_CR1: f64 = 1.422e-06; + +/// cr2 (from opadd.f) +pub const OPADD_CR2: f64 = 2.784; + +/// tenm4 (from opadd.f) +pub const OPADD_TENM4: f64 = 0.0001; + +/// thm0 (from opadd.f) +pub const OPADD_THM0: f64 = 8762.9; + +/// sbhm (from opadd.f) +pub const OPADD_SBHM: f64 = 1.0353e-16; + +/// trha (from opadd.f) +pub const OPADD_TRHA: f64 = 1.5; + +/// sff0 (from opadd.f) +pub const OPADD_SFF0: f64 = 1.3727e-25; + +/// sff1 (from opadd.f) +pub const OPADD_SFF1: f64 = 4.3748e-10; + +/// sffm2 (from opadd.f) +pub const OPADD_SFFM2: f64 = -2.5993e-07; + +/// f0he1 (from opadd.f) +pub const OPADD_F0HE1: f64 = 3290000000000000.0; + +/// f0he2 (from opadd.f) +pub const OPADD_F0HE2: f64 = 1.316e+16; + +/// sbh0 (from opadd.f) +pub const OPADD_SBH0: f64 = 4.1412e-16; + +/// sg01 (from opadd.f) +pub const OPADD_SG01: f64 = 2.815e-16; + +/// sg02 (from opadd.f) +pub const OPADD_SG02: f64 = 4.504e-15; + +// ========== opadd0.f ========== + +/// frray (from opadd0.f) +pub const OPADD0_FRRAY: f64 = 2463000000000000.0; + +/// frayhe (from opadd0.f) +pub const OPADD0_FRAYHE: f64 = 5150000000000000.0; + +/// frayh2 (from opadd0.f) +pub const OPADD0_FRAYH2: f64 = 2922000000000000.0; + +/// cls (from opadd0.f) +pub const OPADD0_CLS: f64 = 2.997925e+18; + +/// cr0 (from opadd0.f) +pub const OPADD0_CR0: f64 = 5.799e-13; + +/// cr1 (from opadd0.f) +pub const OPADD0_CR1: f64 = 1.422e-06; + +/// cr2 (from opadd0.f) +pub const OPADD0_CR2: f64 = 2.784; + +// ========== opaini.f ========== + +/// icomp (from opaini.f, 未知维度,共 1 个值) +pub const OPAINI_ICOMP: [f64; 1] = [ + 0.0, +]; + +/// cff1 (from opaini.f) +pub const OPAINI_CFF1: f64 = 1.3727e-25; + +/// cff2 (from opaini.f) +pub const OPAINI_CFF2: f64 = 4.3748e-10; + +/// cff3 (from opaini.f) +pub const OPAINI_CFF3: f64 = 2.5993e-07; + +/// ccor (from opaini.f) +pub const OPAINI_CCOR: f64 = 0.09; + +/// t32 (from opaini.f) +pub const OPAINI_T32: f64 = 1.5; + +/// sgff0 (from opaini.f) +pub const OPAINI_SGFF0: f64 = 369400000.0; + +// ========== opctab.f ========== + +/// frray0 (from opctab.f) +pub const OPCTAB_FRRAY0: f64 = 508726380000000.0; + +// ========== opdata.f ========== + +/// mmaxop (from opdata.f) +pub const OPDATA_MMAXOP: f64 = 200.0; + +/// mop (from opdata.f) +pub const OPDATA_MOP: f64 = 15.0; + +// ========== opfrac.f ========== + +/// idat(30) from opfrac.f +pub const OPFRAC_IDAT: [f64; 30] = [ + 1.0,2.0,0.0,0.0,0.0,3.0,4.0,5.0,0.0,6.0, + 7.0,8.0,9.0,10.0,0.0,11.0,0.0,12.0,0.0,13.0, + 0.0,0.0,0.0,14.0,15.0,16.0,0.0,17.0,0.0,0.0, +]; + +/// gg(30, 17) from opfrac.f +/// 已转换为 Rust 行优先格式 +pub const OPFRAC_GG: [[f64; 17]; 30] = [ + [2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0], + [0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0], + [0.0,0.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0], + [0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0], + [0.0,0.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0], + [0.0,0.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0], + [0.0,0.0,0.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0], + [0.0,0.0,0.0,0.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0], + [0.0,0.0,0.0,0.0,0.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0], + [0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0], + [0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.0,9.0,9.0,9.0,9.0,9.0,9.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.0,6.0,6.0,6.0,6.0,6.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.0,1.0,1.0,1.0,1.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,10.0,10.0,10.0,10.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,21.0,21.0,21.0,21.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,28.0,28.0,28.0,28.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,25.0,25.0,25.0,25.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.0,6.0,6.0,6.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0,7.0,25.0,25.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.0,30.0,28.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,25.0,21.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,10.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,21.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], +]; + +/// indxat(30, 17) from opfrac.f +/// 已转换为 Rust 行优先格式 +pub const OPFRAC_INDXAT: [[f64; 17]; 30] = [ + [1.0,3.0,6.0,13.0,21.0,30.0,41.0,53.0,66.0,80.0,95.0,112.0,131.0,152.0,177.0,203.0,230.0], + [2.0,4.0,7.0,14.0,22.0,31.0,42.0,54.0,67.0,81.0,96.0,113.0,132.0,153.0,178.0,204.0,231.0], + [0.0,5.0,8.0,15.0,23.0,32.0,43.0,55.0,68.0,82.0,97.0,114.0,133.0,154.0,179.0,205.0,232.0], + [0.0,0.0,9.0,16.0,24.0,33.0,44.0,56.0,69.0,83.0,98.0,115.0,134.0,155.0,180.0,206.0,233.0], + [0.0,0.0,10.0,17.0,25.0,34.0,45.0,57.0,70.0,84.0,99.0,116.0,135.0,156.0,181.0,207.0,234.0], + [0.0,0.0,11.0,18.0,26.0,35.0,46.0,58.0,71.0,85.0,100.0,117.0,136.0,157.0,182.0,208.0,235.0], + [0.0,0.0,12.0,19.0,27.0,36.0,47.0,59.0,72.0,86.0,101.0,118.0,137.0,158.0,183.0,209.0,236.0], + [0.0,0.0,0.0,20.0,28.0,37.0,48.0,60.0,73.0,87.0,102.0,119.0,138.0,159.0,184.0,210.0,237.0], + [0.0,0.0,0.0,0.0,29.0,38.0,49.0,61.0,74.0,88.0,103.0,120.0,139.0,160.0,185.0,211.0,238.0], + [0.0,0.0,0.0,0.0,0.0,39.0,50.0,62.0,75.0,89.0,104.0,121.0,140.0,161.0,186.0,212.0,239.0], + [0.0,0.0,0.0,0.0,0.0,40.0,51.0,63.0,76.0,90.0,105.0,122.0,141.0,162.0,187.0,213.0,240.0], + [0.0,0.0,0.0,0.0,0.0,0.0,52.0,64.0,77.0,91.0,106.0,123.0,142.0,163.0,188.0,214.0,241.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,65.0,78.0,92.0,107.0,124.0,143.0,164.0,189.0,215.0,242.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,79.0,93.0,108.0,125.0,144.0,165.0,190.0,216.0,243.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,94.0,109.0,126.0,145.0,166.0,191.0,217.0,244.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,110.0,127.0,146.0,167.0,192.0,218.0,245.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,111.0,128.0,147.0,168.0,193.0,219.0,246.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,129.0,148.0,169.0,194.0,220.0,247.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,130.0,149.0,170.0,195.0,221.0,248.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,150.0,171.0,196.0,222.0,249.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,151.0,172.0,197.0,223.0,250.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,173.0,198.0,224.0,251.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,174.0,199.0,225.0,252.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,175.0,200.0,226.0,253.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,176.0,201.0,227.0,254.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,202.0,228.0,255.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,229.0,256.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,257.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,258.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], +]; + +/// u6(6) from opfrac.f +pub const OPFRAC_U6: [f64; 6] = [ + 90.82,196.665,386.241,520.178,3162.395,3952.061, +]; + +/// u7(7) from opfrac.f +pub const OPFRAC_U7: [f64; 7] = [ + 117.225,238.751,382.704,624.866,789.537,4452.758,5380.089, +]; + +/// u8(8) from opfrac.f +pub const OPFRAC_U8: [f64; 8] = [ + 109.837,283.24,443.086,624.384,918.657,1114.008,5963.135,7028.393, +]; + +/// u10(10) from opfrac.f +pub const OPFRAC_U10: [f64; 10] = [ + 173.93,330.391,511.8,783.3,1018.0,1273.8,1671.792,1928.462,9645.005,10986.876, +]; + +/// u11(11) from opfrac.f +pub const OPFRAC_U11: [f64; 11] = [ + 41.449,381.395,577.8,797.8,1116.2,1388.5,1681.5,2130.8,2418.7,11817.061, + 13297.676, +]; + +/// u12(12) from opfrac.f +pub const OPFRAC_U12: [f64; 12] = [ + 61.671,121.268,646.41,881.1,1139.4,1504.3,1814.3,2144.7,2645.2,2964.4, + 14210.261,15829.951, +]; + +/// u13(13) from opfrac.f +pub const OPFRAC_U13: [f64; 13] = [ + 48.278,151.86,229.446,967.8,1239.8,1536.3,1947.3,2295.4,2663.4,3214.8, + 3565.6,16825.022,18584.138, +]; + +/// u14(14) from opfrac.f +pub const OPFRAC_U14: [f64; 14] = [ + 65.748,131.838,270.139,364.093,1345.1,1653.9,1988.4,2445.3,2831.9,3237.8, + 3839.8,4222.4,19661.693,21560.63, +]; + +/// u16(16) from opfrac.f +pub const OPFRAC_U16: [f64; 16] = [ + 83.558,188.2,280.9,381.541,586.2,710.184,2265.9,2647.4,3057.7,3606.1, + 4071.4,4554.3,5255.9,5703.6,26002.663,28182.535, +]; + +/// u18(18) from opfrac.f +pub const OPFRAC_U18: [f64; 18] = [ + 127.11,222.848,328.6,482.4,605.1,734.04,1002.73,1157.08,3407.3,3860.9, + 4347.0,4986.6,5533.8,6095.5,6894.2,7404.4,33237.173,35699.936, +]; + +/// u20(20) from opfrac.f +pub const OPFRAC_U20: [f64; 20] = [ + 49.306,95.752,410.642,542.6,681.6,877.4,1026.0,1187.6,1520.64,1704.047, + 4774.0,5301.0,5861.0,6595.0,7215.0,7860.0,8770.0,9338.0,41366.0,44177.41, +]; + +/// u24(24) from opfrac.f +pub const OPFRAC_U24: [f64; 24] = [ + 54.576,132.966,249.7,396.5,560.2,731.02,1291.9,1490.0,1688.0,1971.0, + 2184.0,2404.0,2862.0,3098.52,8151.0,8850.0,9560.0,10480.0,11260.0,12070.0, + 13180.0,13882.0,60344.0,63675.9, +]; + +/// u25(25) from opfrac.f +pub const OPFRAC_U25: [f64; 25] = [ + 59.959,126.145,271.55,413.0,584.0,771.1,961.44,1569.0,1789.0,2003.0, + 2307.0,2536.0,2771.0,3250.0,3509.82,9152.0,9872.0,10620.0,11590.0,12410.0, + 13260.0,14420.0,15162.0,65660.0,69137.4, +]; + +/// u26(26) from opfrac.f +pub const OPFRAC_U26: [f64; 26] = [ + 63.737,130.563,247.22,442.0,605.0,799.0,1008.0,1218.38,1884.0,2114.0, + 2341.0,2668.0,2912.0,3163.0,3686.0,3946.82,10180.0,10985.0,11850.0,12708.0, + 13620.0,14510.0,15797.0,16500.0,71203.0,74829.6, +]; + +/// u28(28) from opfrac.f +pub const OPFRAC_U28: [f64; 28] = [ + 61.6,146.542,283.8,443.0,613.5,870.0,1070.0,1310.0,1560.0,1812.0, + 2589.0,2840.0,3100.0,3470.0,3740.0,4020.0,4606.0,4896.2,12430.0,13290.0, + 14160.0,15280.0,16220.0,17190.0,18510.0,19351.0,82984.0,86909.4, +]; + +/// mtemp (from opfrac.f) +pub const OPFRAC_MTEMP: f64 = 100.0; + +/// melec (from opfrac.f) +pub const OPFRAC_MELEC: f64 = 60.0; + +/// mion1 (from opfrac.f) +pub const OPFRAC_MION1: f64 = 30.0; + +/// mion2 (from opfrac.f) +pub const OPFRAC_MION2: f64 = 32.0; + +/// mdat (from opfrac.f) +pub const OPFRAC_MDAT: f64 = 17.0; + +/// mstag (from opfrac.f) +pub const OPFRAC_MSTAG: f64 = 258.0; + +/// inp (from opfrac.f) +pub const OPFRAC_INP: f64 = 71.0; + +// ========== partf.f ========== + +/// igle(28) from partf.f +pub const PARTF_IGLE: [f64; 28] = [ + 2.0,1.0,2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0, + 2.0,1.0,6.0,9.0,4.0,9.0,6.0,1.0,10.0,21.0, + 28.0,25.0,6.0,25.0,28.0,21.0,10.0,21.0, +]; + +/// ahh(6) from partf.f +pub const PARTF_AHH: [f64; 6] = [ + 20.4976,747.5023,28.1703,527.8296,22.2809,987.7189, +]; + +/// alb(12) from partf.f +pub const PARTF_ALB: [f64; 12] = [ + 8.4915,97.5015,23.3299,192.6701,9.1849,32.9263,183.8887,19.9563,88.0437,6.0478, + 35.9723,233.9798, +]; + +/// ab(11) from partf.f +pub const PARTF_AB: [f64; 11] = [ + 4.0086,19.6741,402.311,9.7257,30.9262,186.3466,44.1629,60.8371,6.0084,23.5767, + 76.4149, +]; + +/// ac(19) from partf.f +pub const PARTF_AC: [f64; 19] = [ + 8.0158,5.8833,33.7521,595.3432,4.0003,17.0841,82.9154,15.9808,48.2044,435.8093, + 10.0281,15.7574,186.2109,15.4127,55.9559,243.6311,6.0057,23.5757,76.4185, +]; + +/// an(30) from partf.f +pub const PARTF_AN: [f64; 30] = [ + 14.0499,30.8008,883.1443,10.0,16.0,64.0,8.0462,6.2669,17.8696,282.8084, + 7.3751,33.139,215.4829,4.0003,19.3533,80.6462,13.0998,19.6425,94.3035,370.9539, + 16.0,38.0,10.3289,14.5021,187.1624,108.1615,191.8383,6.0044,23.5612,76.4344, +]; + +/// ao(49) from partf.f +pub const PARTF_AO: [f64; 49] = [ + 4.0029,5.3656,36.2853,1044.3447,131.0217,868.9779,14.8533,93.1466,12.7843,5.6828, + 98.0919,829.4396,50.9878,199.012,2.0,6.0,10.0,10.0,30.0,50.0, + 8.0703,5.7144,84.1156,529.0927,5.6609,28.9355,111.362,494.0413,45.5249,134.4751, + 4.0003,21.2937,78.7058,12.8293,16.273,123.6578,327.2396,48.7883,102.2117,20.006, + 161.9903,28.4184,61.5816,10.5563,13.295,188.139,14.656,129.4922,470.8512, +]; + +/// af(34) from partf.f +pub const PARTF_AF: [f64; 34] = [ + 2.0001,39.9012,122.0986,10.0,30.0,50.0,4.0199,5.5741,22.1839,190.2179, + 53.0383,126.9616,31.6894,75.3105,13.5014,7.9936,55.7981,298.7039,26.2496,63.7503, + 2.0,6.0,10.0,28.715,71.285,8.0153,6.1931,21.7287,48.778,278.2782, + 178.556,421.4435,51.7632,95.2368, +]; + +/// ann(23) from partf.f +pub const PARTF_ANN: [f64; 23] = [ + 34.508,365.4919,16.5768,183.4231,2.0007,89.5607,380.4381,26.4473,63.5527,4.0342, + 5.6162,11.5176,72.8273,48.5684,131.4315,31.171,76.829,14.0482,13.3077,52.7897, + 467.8487,54.2196,195.78, +]; + +/// ana(19) from partf.f +pub const PARTF_ANA: [f64; 19] = [ + 11.6348,158.3593,21.0453,50.9546,10.1389,25.8611,2.0019,38.0569,137.9398,28.3106, + 61.6893,4.0334,5.856,18.1786,208.9142,93.6895,406.3095,60.4276,239.5719, +]; + +/// amg(15) from partf.f +pub const PARTF_AMG: [f64; 15] = [ + 10.7445,291.5057,53.7488,6.227,31.1291,132.6438,40.4379,159.5618,20.3845,79.6154, + 2.0007,106.8977,343.101,10.1326,237.8581, +]; + +/// aal(17) from partf.f +pub const PARTF_AAL: [f64; 17] = [ + 4.0009,11.7804,142.2179,13.6585,96.3371,10.0807,49.5843,285.3343,14.6872,59.3122, + 6.3277,29.5086,134.1634,46.3164,153.6833,22.9896,77.0103, +]; + +/// asi(23) from partf.f +pub const PARTF_ASI: [f64; 23] = [ + 7.9658,4.6762,1.3512,123.2267,443.7797,4.0,7.4186,24.1754,60.406,14.4695, + 11.9721,26.5062,269.0521,9.1793,4.8766,29.1442,52.7998,13.2674,36.0417,180.691, + 6.4839,27.6851,135.8301, +]; + +/// ap(19) from partf.f +pub const PARTF_AP: [f64; 19] = [ + 13.5211,22.213,353.2583,10.0,150.0,8.0241,5.8085,51.7542,252.4002,4.0021, + 20.7985,62.4194,200.7786,11.7414,63.5124,179.742,6.8835,32.7777,228.3366, +]; + +/// as(29) from partf.f +pub const PARTF_AS: [f64; 29] = [ + 3.9615,5.078,15.0944,362.8588,51.5995,268.4002,12.0,276.0,11.4377,5.5126, + 141.0009,254.0478,33.0518,126.9479,4.0707,4.0637,5.7245,144.6376,106.4909,4.0011, + 19.2813,27.599,35.1179,94.7454,283.2486,10.5474,28.7137,65.7378,24.0, +]; + +/// acl(28) from partf.f +pub const PARTF_ACL: [f64; 28] = [ + 2.0007,62.5048,669.4942,29.0259,130.974,3.9064,0.3993,5.357,60.3424,119.9913, + 138.1567,278.8418,102.3681,158.6314,12.6089,5.9527,110.5635,262.8715,69.2035,100.796, + 7.3458,5.6638,44.1256,202.7846,4.0037,21.8663,40.5363,57.5919, +]; + +/// aar(25) from partf.f +pub const PARTF_AAR: [f64; 25] = [ + 43.6623,324.3375,20.8298,163.1701,2.0026,137.4515,258.5445,62.8129,149.1867,4.0495, + 14.4466,46.8234,124.6651,151.9828,268.0157,101.1302,150.8691,13.3718,8.6528,60.4614, + 285.5072,6.7655,4.7684,12.8631,54.526, +]; + +/// ak(30) from partf.f +pub const PARTF_AK: [f64; 30] = [ + 12.9782,148.6673,6.3493,66.3444,101.6553,4.0001,13.4465,46.5534,2.0171,116.4767, + 713.4965,63.5907,396.4079,2.0,10.0,30.0,4.0702,5.7791,52.6795,327.4539, + 62.8604,357.1331,55.9337,196.0646,10.9275,5.5398,43.2761,76.256,42.0,18.0, +]; + +/// aca(17) from partf.f +pub const PARTF_ACA: [f64; 17] = [ + 18.2366,27.5012,149.2617,94.5242,705.4711,11.8706,14.071,106.0547,57.2414,110.7567, + 29.8121,54.1874,2.0184,97.5784,282.3939,209.1871,252.8129, +]; + +/// asc(24) from partf.f +pub const PARTF_ASC: [f64; 24] = [ + 6.0014,83.1958,67.3666,329.4354,44.0793,169.9969,533.9195,34.1642,124.8475,228.9879, + 11.9979,16.928,28.4778,82.0418,234.536,6.0042,2.7101,13.9801,65.3039,12.0, + 12.0,2.0051,2.9621,29.0306, +]; + +/// ati(33) from partf.f +pub const PARTF_ATI: [f64; 33] = [ + 7.0887,8.9186,17.5633,206.6832,438.5735,654.1721,38.0462,69.6271,364.2845,832.0408, + 98.8562,57.9934,442.1498,19.7843,32.0637,37.0895,110.6682,288.4946,521.8837,10.0, + 34.0,120.0,16.1691,22.355,24.1646,83.5128,222.7963,6.002,4.6177,25.2636, + 52.1162,12.0,8.0, +]; + +/// av(33) from partf.f +pub const PARTF_AV: [f64; 33] = [ + 15.2627,23.9869,51.3053,570.3384,1650.9417,162.2829,298.8303,908.8852,23.6736,37.1624, + 86.8011,300.744,864.588,57.8961,79.4605,214.9007,864.7425,61.8508,64.0845,192.8298, + 718.2349,23.8116,68.2495,135.0613,536.7632,15.9543,22.5542,71.4921,248.9544,6.0006, + 5.8785,50.5077,97.6129, +]; + +/// acr(29) from partf.f +pub const PARTF_ACR: [f64; 29] = [ + 30.1842,79.2847,149.5293,215.3696,119.1974,741.4321,184.9946,1352.5038,784.4937,46.6191, + 160.1361,488.0449,657.1928,47.1742,267.0275,441.1324,150.665,24.3768,122.8359,285.5092, + 794.1654,24.2296,75.0258,172.9452,543.6511,15.9819,17.68,95.2003,225.0947, +]; + +/// amn(28) from partf.f +pub const PARTF_AMN: [f64; 28] = [ + 53.9107,81.3931,546.6945,144.1893,407.8029,45.6177,298.4423,2410.9335,22.6382,93.8419, + 183.9367,907.5765,137.0409,168.6783,329.0287,773.2513,70.1925,72.3372,213.9512,539.5165, + 24.2373,93.5415,456.6167,506.5484,24.7687,66.9896,264.1853,484.0161, +]; + +/// afe(35) from partf.f +pub const PARTF_AFE: [f64; 35] = [ + 14.4102,2.705,421.6612,940.1484,36.2187,22.8883,239.5997,825.2919,110.0242,992.304, + 640.6715,17.0494,32.3783,34.3184,420.9626,1067.2064,154.0059,462.1117,329.8618,15.7906, + 47.1186,279.9292,692.1005,91.0206,206.3082,706.9927,836.6689,40.079,27.6965,28.2243, + 18.0001,24.0899,89.634,51.5756,241.698, +]; + +/// aco(29) from partf.f +pub const PARTF_ACO: [f64; 29] = [ + 11.912,20.4424,28.3863,132.5038,600.7461,33.3092,237.4331,977.2502,55.5396,318.8169, + 619.6366,32.69,83.8694,107.4378,11.2593,38.2239,22.9964,261.3486,637.1485,23.0233, + 41.6599,264.646,181.6699,16.0356,7.8633,70.3158,423.3512,742.3553,0.0, +]; + +/// ani(23) from partf.f +pub const PARTF_ANI: [f64; 23] = [ + 7.1268,12.4486,11.9953,10.0546,114.1658,391.2064,26.3908,213.8081,938.7927,4.1421, + 37.3781,25.9712,333.3397,311.1633,33.1031,184.1854,136.7072,11.1915,5.4174,53.6793, + 460.6781,380.0056,0.0, +]; + +/// acu(20) from partf.f +pub const PARTF_ACU: [f64; 20] = [ + 11.0549,238.9423,10.3077,126.299,1073.3876,30.0,50.0,60.0,19.2984,50.5974, + 240.2021,1216.9016,48.3048,583.2011,320.4931,4.0155,70.3264,313.1213,536.5331,0.0, +]; + +/// azn(18) from partf.f +pub const PARTF_AZN: [f64; 18] = [ + 15.988,484.0042,18.5863,123.4134,3.0,189.0,6.1902,38.9317,204.878,10.2588, + 89.3771,370.364,30.0,128.0,24.6904,106.7491,439.5586,0.0, +]; + +/// ghh(6) from partf.f +pub const PARTF_GHH: [f64; 6] = [ + 10.853,13.342,21.17,24.125,43.708,53.542, +]; + +/// glb(12) from partf.f +pub const PARTF_GLB: [f64; 12] = [ + 2.022,4.604,62.032,72.624,2.735,6.774,8.569,10.75,11.672,3.967, + 12.758,16.692, +]; + +/// gb(11) from partf.f +pub const PARTF_GB: [f64; 11] = [ + 0.002,3.971,7.882,4.72,13.477,22.103,23.056,24.734,6.0,24.54, + 32.3, +]; + +/// gc(19) from partf.f +pub const PARTF_GC: [f64; 19] = [ + 0.004,1.359,6.454,10.376,0.008,16.546,21.614,5.688,15.801,26.269, + 6.691,25.034,40.975,17.604,36.18,47.133,8.005,40.804,54.492, +]; + +/// gn(30) from partf.f +pub const PARTF_GN: [f64; 30] = [ + 2.554,9.169,13.651,12.353,13.784,14.874,0.014,2.131,15.745,24.949, + 6.376,14.246,29.465,0.022,31.259,41.428,7.212,15.228,34.387,46.708, + 46.475,49.468,8.693,37.65,65.479,61.155,79.196,9.999,60.991,82.262, +]; + +/// go(49) from partf.f +pub const PARTF_GO: [f64; 49] = [ + 0.022,2.019,9.812,13.087,13.804,16.061,14.293,16.114,3.472,7.437, + 22.579,32.035,27.774,33.678,28.118,31.019,34.204,30.892,33.189,36.181, + 0.032,2.76,35.328,48.277,7.662,16.786,42.657,54.522,50.204,56.044, + 0.048,50.089,66.604,8.954,18.031,57.755,72.594,68.388,82.397,31.96, + 76.876,75.686,80.388,10.747,52.323,94.976,27.405,86.35,109.917, +]; + +/// gf(34) from partf.f +pub const PARTF_GF: [f64; 34] = [ + 0.05,13.317,15.692,15.361,17.128,18.498,0.048,2.735,20.079,30.277, + 27.548,32.532,30.391,34.707,4.479,12.072,31.662,51.432,44.283,50.964, + 46.193,50.436,54.88,50.816,57.479,0.058,3.434,14.892,37.472,69.883, + 67.81,83.105,72.435,79.747, +]; + +/// gnn(23) from partf.f +pub const PARTF_GNN: [f64; 23] = [ + 17.796,20.73,17.879,20.855,0.097,29.878,37.221,31.913,37.551,0.092, + 3.424,24.806,46.616,45.643,54.147,48.359,57.42,5.453,18.56,46.583, + 80.101,70.337,85.789, +]; + +/// gna(19) from partf.f +pub const PARTF_GNA: [f64; 19] = [ + 2.4,4.552,34.367,40.566,34.676,40.764,0.17,44.554,57.142,51.689, + 60.576,0.152,4.26,36.635,83.254,72.561,89.475,75.839,92.582, +]; + +/// gmg(15) from partf.f +pub const PARTF_GMG: [f64; 15] = [ + 2.805,6.777,9.254,4.459,9.789,13.137,57.413,71.252,58.01,71.66, + 0.276,74.44,94.447,54.472,95.858, +]; + +/// gal(17) from partf.f +pub const PARTF_GAL: [f64; 17] = [ + 0.014,3.841,5.42,3.727,8.833,4.749,11.902,16.719,11.31,18.268, + 6.751,16.681,24.151,83.551,104.787,84.293,105.171, +]; + +/// gsi(23) from partf.f +pub const PARTF_GSI: [f64; 23] = [ + 0.02,0.752,1.614,5.831,7.431,0.036,8.795,11.208,13.835,5.418, + 7.825,14.44,19.412,6.572,11.449,18.424,25.457,15.682,27.01,34.599, + 9.042,24.101,37.445, +]; + +/// gp(19) from partf.f +pub const PARTF_GP: [f64; 19] = [ + 1.514,5.575,9.247,8.076,10.735,0.043,1.212,8.545,15.525,0.074, + 7.674,16.639,25.118,8.992,24.473,40.704,11.464,33.732,55.455, +]; + +/// gs(29) from partf.f +pub const PARTF_GS: [f64; 29] = [ + 0.053,1.121,5.812,9.425,8.936,11.277,9.6,12.551,1.892,3.646, + 13.55,19.376,16.253,21.062,0.043,0.123,1.59,13.712,22.05,0.118, + 9.545,18.179,31.441,30.664,56.15,10.704,27.075,50.599,43.034, +]; + +/// gcl(28) from partf.f +pub const PARTF_GCL: [f64; 28] = [ + 0.11,9.919,12.28,11.017,13.532,0.092,0.581,1.62,13.121,19.787, + 16.365,21.988,18.065,23.594,2.358,5.708,19.084,30.683,24.88,33.229, + 0.102,1.391,14.709,36.968,0.185,11.783,25.653,44.698, +]; + +/// gar(25) from partf.f +pub const PARTF_GAR: [f64; 25] = [ + 12.638,14.958,12.833,15.139,0.178,17.522,23.584,20.464,25.15,0.151, + 1.561,17.399,30.871,24.684,33.978,27.091,36.481,2.81,8.877,24.351, + 44.489,0.144,1.16,10.21,27.178, +]; + +/// gk(30) from partf.f +pub const PARTF_GK: [f64; 30] = [ + 1.871,3.713,18.172,21.185,27.705,2.059,23.709,28.542,0.273,26.709, + 39.64,31.22,41.865,29.955,37.557,42.862,0.228,2.274,21.703,50.191, + 32.145,49.262,34.155,51.718,3.043,5.479,20.547,30.68,36.275,47.345, +]; + +/// gca(17) from partf.f +pub const PARTF_GCA: [f64; 17] = [ + 2.05,3.349,5.321,4.873,7.017,1.769,5.109,9.524,27.271,41.561, + 29.172,42.14,0.394,28.93,52.618,38.593,49.646, +]; + +/// gsc(24) from partf.f +pub const PARTF_GSC: [f64; 24] = [ + 0.021,2.056,3.551,5.465,1.535,3.797,6.203,2.389,4.858,7.141, + 0.011,0.43,1.156,3.711,8.863,0.025,3.499,10.463,18.606,41.779, + 57.217,0.539,24.442,51.079, +]; + +/// gti(33) from partf.f +pub const PARTF_GTI: [f64; 33] = [ + 0.021,0.048,1.029,2.183,4.109,5.785,0.846,1.792,3.836,5.787, + 2.561,4.869,6.34,0.023,0.124,0.774,1.81,4.98,9.585,1.082, + 4.928,11.279,0.041,1.375,4.768,10.985,19.769,0.048,11.577,24.531, + 36.489,54.436,75.373, +]; + +/// gv(33) from partf.f +pub const PARTF_GV: [f64; 33] = [ + 0.026,0.145,0.718,2.586,5.458,2.171,4.153,6.097,0.009,0.366, + 1.504,5.294,10.126,1.796,2.353,6.068,12.269,2.56,3.674,6.593, + 12.88,0.045,1.684,8.162,21.262,0.065,1.746,15.158,33.141,0.077, + 21.229,44.134,60.203, +]; + +/// gcr(29) from partf.f +pub const PARTF_GCR: [f64; 29] = [ + 0.993,3.07,5.673,3.339,4.801,7.198,2.829,4.99,7.643,1.645, + 3.727,7.181,12.299,2.902,4.273,8.569,14.912,0.047,2.566,9.441, + 21.198,0.078,2.242,15.638,32.725,0.103,2.146,26.153,49.381, +]; + +/// gmn(28) from partf.f +pub const PARTF_GMN: [f64; 28] = [ + 2.527,4.204,6.602,4.155,7.321,2.285,5.631,8.448,1.496,3.839, + 7.751,13.484,3.681,6.054,9.934,14.936,3.531,6.967,15.222,25.069, + 0.071,2.896,20.725,37.383,0.126,2.66,28.528,53.413, +]; + +/// gfe(35) from partf.f +pub const PARTF_GFE: [f64; 35] = [ + 0.066,0.339,2.897,6.585,0.923,1.679,4.62,7.053,4.249,5.875, + 7.781,0.062,0.283,1.504,5.43,11.21,2.792,7.627,13.623,0.077, + 3.723,12.137,23.7,2.688,7.595,15.444,25.587,3.982,4.677,6.453, + 23.561,0.102,3.354,22.954,33.796, +]; + +/// gco(29) from partf.f +pub const PARTF_GCO: [f64; 29] = [ + 0.112,0.341,0.809,3.808,6.723,2.057,3.484,7.21,2.405,5.133, + 8.097,2.084,5.291,8.426,0.135,0.517,1.606,6.772,12.622,2.512, + 4.348,8.253,15.377,0.132,0.863,3.086,11.789,23.263,0.0, +]; + +/// gni(23) from partf.f +pub const PARTF_GNI: [f64; 23] = [ + 0.026,0.137,0.315,1.778,4.029,6.621,2.249,4.042,7.621,0.191, + 1.235,3.358,8.429,17.096,3.472,9.065,16.556,0.194,1.305,5.813, + 14.172,26.169,0.0, +]; + +/// gcu(20) from partf.f +pub const PARTF_GCU: [f64; 20] = [ + 4.212,7.227,1.493,5.859,9.709,7.081,9.362,10.13,2.865,8.26, + 14.431,18.292,9.65,14.64,24.32,0.337,8.52,16.925,28.342,0.0, +]; + +/// gzn(18) from partf.f +pub const PARTF_GZN: [f64; 18] = [ + 4.546,8.84,10.247,16.62,11.175,16.321,6.113,12.964,16.444,7.926, + 13.633,24.353,16.286,24.91,10.291,20.689,32.077,0.0, +]; + +/// xl1(99) from partf.f +pub const PARTF_XL1: [f64; 99] = [ + 11.0,8.0,12.0,6.0,6.0,6.0,4.0,8.0,9.0,6.0, + 4.0,6.0,6.0,6.0,5.0,6.1,5.0,6.0,6.1,4.0, + 5.0,3.9,6.0,5.0,4.0,6.0,6.3,6.0,8.0,6.0, + 3.4,6.0,5.0,3.9,3.9,6.0,4.9,4.0,5.9,5.0, + 4.9,4.0,4.0,6.0,6.0,4.0,4.0,5.0,4.0,4.0, + 5.0,4.0,3.9,4.0,5.0,5.0,4.0,6.0,6.0,5.0, + 4.0,3.9,4.0,4.0,5.0,5.0,7.0,4.0,4.0,4.0, + 4.0,5.0,5.0,5.0,7.0,7.0,5.0,5.0,5.0,5.0, + 7.0,4.0,7.0,4.0,7.0,5.0,5.0,6.1,5.9,5.0, + 5.0,5.0,7.0,5.0,5.0,5.0,7.0,8.6,8.0, +]; + +/// xl2(123) from partf.f +pub const PARTF_XL2: [f64; 123] = [ + 6.0,5.0,5.0,5.0,5.0,3.5,5.0,14.4,5.0,4.0, + 6.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.2,6.0, + 6.0,5.1,5.0,5.0,5.0,5.0,5.0,4.0,7.0,5.0, + 5.0,6.0,6.0,5.0,6.0,5.0,5.0,3.6,4.0,5.9, + 6.0,7.0,5.0,4.9,5.0,4.3,4.9,4.9,5.0,5.0, + 6.0,4.6,3.8,5.0,4.7,5.0,5.0,5.0,5.0,6.0, + 4.8,5.0,5.0,5.0,5.0,5.0,5.0,5.0,11.2,5.0, + 5.0,5.0,5.0,5.0,5.0,5.0,5.2,6.0,5.0,6.0, + 7.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0, + 6.0,5.0,3.6,3.8,5.0,5.0,5.0,5.0,5.0,5.0, + 5.0,3.0,5.4,5.0,9.0,5.0,5.0,3.0,8.0,6.0, + 5.0,7.0,5.0,5.0,2.9,8.0,5.0,5.0,8.0,5.0, + 5.0,5.0,2.8, +]; + +/// ch1(66) from partf.f +pub const PARTF_CH1: [f64; 66] = [ + 13.595,24.58,54.403,5.39,75.619,9.32,13.278,18.206,8.296,25.149, + 31.146,37.92,11.256,24.376,30.868,47.871,55.873,64.476,14.529,16.428, + 29.593,36.693,47.426,55.765,63.626,77.45,87.445,97.863,13.614,16.938, + 18.63,35.108,37.621,40.461,42.584,54.886,63.733,70.556,77.394,87.609, + 97.077,103.911,106.116,113.873,125.863,17.418,20.009,34.977,39.204,41.368, + 62.646,65.774,69.282,71.882,87.139,97.852,106.089,21.559,21.656,41.071, + 44.274,63.729,68.806,71.434,97.162,100.917, +]; + +/// ch2(72) from partf.f +pub const PARTF_CH2: [f64; 72] = [ + 5.138,47.29,47.459,71.647,75.504,98.88,104.778,107.864,7.644,15.031, + 80.117,80.393,109.294,113.799,5.984,10.634,18.823,25.496,28.441,119.957, + 120.383,8.149,16.339,22.894,33.459,42.333,45.13,10.474,11.585,19.72, + 30.156,51.354,65.007,10.357,12.2,13.401,23.405,24.807,35.047,47.292, + 57.681,72.474,85.701,13.014,14.458,23.798,26.041,27.501,39.904,41.61, + 53.45,67.801,15.755,15.933,27.619,29.355,40.899,42.407,45.234,59.793, + 75.002,4.339,31.81,32.079,45.738,47.768,50.515,60.897,63.89,65.849, + 82.799,85.15, +]; + +/// ch3(55) from partf.f +pub const PARTF_CH3: [f64; 55] = [ + 6.111,7.808,11.868,51.207,51.596,67.181,69.536,6.538,7.147,8.042, + 12.891,24.752,74.09,91.847,6.818,6.953,7.411,13.635,14.685,28.137, + 43.236,100.083,6.738,7.101,14.205,15.67,16.277,29.748,48.464,65.198, + 6.763,8.285,9.221,16.493,18.662,30.95,49.58,73.093,7.432,8.606, + 9.24,15.636,18.963,33.69,53.001,76.006,7.896,8.195,8.927,16.178, + 18.662,30.64,34.607,56.001,79.001, +]; + +/// ch4(29) from partf.f +pub const PARTF_CH4: [f64; 29] = [ + 7.863,8.378,9.16,9.519,17.052,18.958,33.491,53.001,7.633,8.793, + 18.147,20.233,35.161,56.025,7.724,10.532,10.98,20.286,27.985,36.826, + 61.975,9.391,17.503,17.166,17.959,27.757,28.31,39.701,65.074, +]; + +/// ii1(5, 15) from partf.f +/// 已转换为 Rust 行优先格式 +pub const PARTF_II1: [[f64; 15]; 5] = [ + [1.0,2.0,4.0,6.0,8.0,11.0,15.0,20.0,25.0,29.0,33.0,37.0,41.0,45.0,49.0], + [-1.0,3.0,5.0,7.0,9.0,12.0,16.0,21.0,26.0,30.0,34.0,38.0,42.0,46.0,50.0], + [0.0,-1.0,-2.0,-1.0,10.0,13.0,17.0,22.0,27.0,31.0,35.0,39.0,43.0,47.0,51.0], + [0.0,0.0,-1.0,-2.0,-1.0,14.0,18.0,23.0,28.0,32.0,36.0,40.0,44.0,48.0,52.0], + [0.0,0.0,0.0,-1.0,-2.0,-1.0,19.0,24.0,-6.0,-9.0,-4.0,-9.0,-6.0,-1.0,53.0], +]; + +/// ii2(5, 15) from partf.f +/// 已转换为 Rust 行优先格式 +pub const PARTF_II2: [[f64; 15]; 5] = [ + [54.0,59.0,64.0,69.0,74.0,78.0,83.0,88.0,93.0,98.0,103.0,108.0,112.0,116.0,120.0], + [55.0,60.0,65.0,70.0,75.0,76.0,84.0,89.0,94.0,99.0,104.0,109.0,113.0,117.0,121.0], + [56.0,61.0,66.0,71.0,76.0,80.0,85.0,90.0,95.0,100.0,105.0,110.0,114.0,118.0,122.0], + [57.0,62.0,67.0,72.0,77.0,81.0,86.0,91.0,96.0,101.0,106.0,111.0,115.0,119.0,123.0], + [58.0,63.0,68.0,73.0,-9.0,82.0,87.0,92.0,97.0,102.0,107.0,-25.0,-1.0,-1.0,-1.0], +]; + +/// is1(53) from partf.f +pub const PARTF_IS1: [f64; 53] = [ + 1.0,1.0,1.0,1.0,1.0,2.0,1.0,1.0,2.0,1.0, + 1.0,2.0,2.0,1.0,2.0,2.0,3.0,2.0,1.0,3.0, + 4.0,3.0,5.0,2.0,2.0,3.0,4.0,3.0,2.0,2.0, + 3.0,2.0,1.0,2.0,2.0,3.0,1.0,1.0,2.0,2.0, + 2.0,2.0,1.0,2.0,1.0,2.0,2.0,1.0,2.0,1.0, + 1.0,1.0,1.0, +]; + +/// is2(70) from partf.f +pub const PARTF_IS2: [f64; 70] = [ + 3.0,2.0,1.0,2.0,2.0,2.0,3.0,2.0,1.0,1.0, + 2.0,2.0,3.0,1.0,1.0,1.0,2.0,3.0,3.0,2.0, + 2.0,1.0,2.0,2.0,3.0,1.0,1.0,1.0,1.0,3.0, + 2.0,1.0,1.0,1.0,2.0,3.0,1.0,1.0,1.0,3.0, + 2.0,1.0,1.0,1.0,3.0,2.0,1.0,1.0,1.0,3.0, + 2.0,2.0,1.0,1.0,4.0,2.0,1.0,1.0,2.0,2.0, + 1.0,1.0,3.0,2.0,1.0,1.0,3.0,3.0,1.0,1.0, +]; + +/// im1(99) from partf.f +pub const PARTF_IM1: [f64; 99] = [ + 2.0,2.0,2.0,2.0,2.0,3.0,2.0,3.0,3.0,3.0, + 2.0,3.0,4.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0, + 4.0,3.0,3.0,4.0,2.0,3.0,2.0,3.0,4.0,2.0, + 2.0,4.0,2.0,3.0,3.0,4.0,4.0,2.0,3.0,4.0, + 2.0,2.0,2.0,3.0,3.0,3.0,3.0,4.0,2.0,2.0, + 4.0,2.0,3.0,2.0,5.0,2.0,2.0,2.0,2.0,3.0, + 2.0,4.0,2.0,2.0,4.0,2.0,2.0,2.0,2.0,3.0, + 2.0,4.0,2.0,2.0,3.0,3.0,2.0,2.0,3.0,2.0, + 3.0,2.0,3.0,2.0,3.0,2.0,2.0,5.0,4.0,4.0, + 4.0,3.0,3.0,3.0,2.0,4.0,4.0,3.0,3.0, +]; + +/// im2(123) from partf.f +pub const PARTF_IM2: [f64; 123] = [ + 4.0,2.0,2.0,4.0,2.0,5.0,4.0,2.0,3.0,1.0, + 3.0,2.0,5.0,2.0,2.0,4.0,2.0,4.0,4.0,2.0, + 2.0,3.0,2.0,4.0,2.0,2.0,4.0,4.0,3.0,2.0, + 3.0,3.0,2.0,3.0,4.0,2.0,2.0,4.0,2.0,3.0, + 2.0,3.0,2.0,2.0,3.0,2.0,4.0,3.0,3.0,5.0, + 4.0,2.0,3.0,6.0,4.0,3.0,6.0,3.0,5.0,4.0, + 2.0,5.0,3.0,5.0,4.0,4.0,4.0,4.0,4.0,3.0, + 3.0,3.0,4.0,4.0,4.0,4.0,4.0,3.0,2.0,3.0, + 4.0,4.0,4.0,4.0,4.0,4.0,4.0,3.0,5.0,3.0, + 4.0,4.0,4.0,4.0,5.0,3.0,3.0,3.0,5.0,4.0, + 5.0,1.0,6.0,3.0,5.0,3.0,5.0,1.0,2.0,3.0, + 3.0,4.0,3.0,4.0,1.0,2.0,2.0,2.0,3.0,3.0, + 2.0,3.0,1.0, +]; + +/// igp1(99) from partf.f +pub const PARTF_IGP1: [f64; 99] = [ + 2.0,4.0,2.0,2.0,4.0,4.0,12.0,2.0,2.0,4.0, + 12.0,2.0,12.0,2.0,18.0,4.0,12.0,2.0,18.0,10.0, + 12.0,24.0,2.0,18.0,6.0,4.0,12.0,2.0,8.0,20.0, + 12.0,18.0,10.0,2.0,10.0,12.0,24.0,20.0,2.0,18.0, + 6.0,18.0,10.0,4.0,12.0,18.0,10.0,8.0,20.0,12.0, + 18.0,10.0,2.0,10.0,12.0,24.0,20.0,8.0,4.0,18.0, + 10.0,8.0,20.0,12.0,18.0,10.0,2.0,8.0,4.0,18.0, + 10.0,8.0,20.0,12.0,4.0,2.0,8.0,4.0,18.0,10.0, + 2.0,18.0,4.0,12.0,2.0,8.0,4.0,12.0,2.0,18.0, + 4.0,12.0,2.0,18.0,10.0,12.0,2.0,4.0,2.0, +]; + +/// igp2(123) from partf.f +pub const PARTF_IGP2: [f64; 123] = [ + 8.0,20.0,12.0,18.0,10.0,12.0,2.0,18.0,4.0,12.0, + 18.0,10.0,8.0,20.0,12.0,18.0,10.0,12.0,2.0,8.0, + 4.0,18.0,10.0,8.0,20.0,12.0,18.0,12.0,2.0,8.0, + 4.0,18.0,10.0,2.0,8.0,20.0,12.0,18.0,10.0,4.0, + 20.0,2.0,8.0,4.0,18.0,10.0,30.0,42.0,18.0,20.0, + 2.0,12.0,18.0,56.0,56.0,28.0,42.0,10.0,20.0,2.0, + 12.0,50.0,70.0,56.0,72.0,64.0,42.0,20.0,2.0,12.0, + 60.0,40.0,50.0,18.0,56.0,42.0,20.0,14.0,10.0,50.0, + 12.0,72.0,50.0,56.0,42.0,60.0,56.0,40.0,50.0,18.0, + 12.0,72.0,50.0,56.0,42.0,70.0,42.0,18.0,56.0,24.0, + 50.0,12.0,20.0,56.0,42.0,18.0,56.0,50.0,2.0,30.0, + 10.0,20.0,56.0,42.0,56.0,4.0,8.0,12.0,2.0,30.0, + 10.0,20.0,42.0, +]; + +/// ig01(53) from partf.f +pub const PARTF_IG01: [f64; 53] = [ + 2.0,1.0,2.0,2.0,1.0,1.0,2.0,2.0,1.0,2.0, + 1.0,2.0,1.0,2.0,4.0,1.0,2.0,1.0,2.0,5.0, + 4.0,1.0,2.0,1.0,4.0,5.0,4.0,1.0,1.0,4.0, + 5.0,4.0,2.0,1.0,4.0,5.0,1.0,2.0,1.0,4.0, + 2.0,1.0,2.0,1.0,1.0,2.0,1.0,2.0,4.0,1.0, + 2.0,1.0,2.0, +]; + +/// ig02(70) from partf.f +pub const PARTF_IG02: [f64; 70] = [ + 5.0,4.0,1.0,2.0,1.0,4.0,5.0,4.0,1.0,2.0, + 1.0,4.0,5.0,4.0,1.0,2.0,1.0,4.0,5.0,4.0, + 1.0,2.0,1.0,4.0,4.0,3.0,4.0,1.0,4.0,5.0, + 4.0,5.0,4.0,1.0,4.0,1.0,4.0,5.0,4.0,7.0, + 6.0,1.0,4.0,5.0,6.0,7.0,6.0,1.0,4.0,9.0, + 10.0,9.0,6.0,1.0,10.0,9.0,10.0,20.0,9.0,6.0, + 9.0,28.0,2.0,1.0,6.0,21.0,1.0,2.0,1.0,10.0, +]; + +/// icomp (from partf.f, 未知维度,共 1 个值) +pub const PARTF_ICOMP: [f64; 1] = [ + 0.0, +]; + +/// nions (from partf.f) +pub const PARTF_NIONS: f64 = 123.0; + +/// nss (from partf.f) +pub const PARTF_NSS: f64 = 222.0; + +/// trha (from partf.f) +pub const PARTF_TRHA: f64 = 1.5; + +// ========== pfcno.f ========== + +/// tt(35) from pfcno.f +pub const PFCNO_TT: [f64; 35] = [ + 18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0, + 28.0,29.0,30.0,32.0,34.0,36.0,38.0,40.0,42.0,44.0, + 46.0,48.0,50.0,55.0,60.0,65.0,70.0,75.0,80.0,85.0, + 90.0,95.0,100.0,125.0,150.0, +]; + +/// pn(10) from pfcno.f +pub const PFCNO_PN: [f64; 10] = [ + -2.0,-1.0,0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0, +]; + +/// p6a(24) from pfcno.f +pub const PFCNO_P6A: [f64; 24] = [ + 0.302,0.302,0.302,0.303,0.303,0.304,0.305,0.306,0.307,0.308, + 0.31,0.312,0.313,0.318,0.322,0.327,0.333,0.339,0.346,0.353, + 0.36,0.367,0.375,0.394, +]; + +/// p6b(10, 11) from pfcno.f +/// 已转换为 Rust 行优先格式 +pub const PFCNO_P6B: [[f64; 11]; 10] = [ + [0.414,0.436,0.472,0.56,0.762,1.09,1.478,1.867,2.233,3.665,4.633], + [0.413,0.433,0.458,0.499,0.593,0.782,1.07,1.408,1.752,3.166,4.133], + [0.413,0.433,0.453,0.478,0.522,0.611,0.775,1.018,1.306,2.668,3.633], + [0.413,0.432,0.451,0.471,0.497,0.539,0.615,0.749,0.944,2.176,3.134], + [0.413,0.432,0.451,0.469,0.489,0.513,0.55,0.612,0.713,1.7,2.636], + [0.413,0.432,0.451,0.468,0.486,0.505,0.527,0.557,0.604,1.269,2.146], + [0.413,0.432,0.451,0.468,0.485,0.502,0.519,0.539,0.564,0.934,1.674], + [0.413,0.432,0.451,0.468,0.485,0.501,0.517,0.533,0.55,0.735,1.254], + [0.413,0.432,0.451,0.468,0.485,0.501,0.516,0.531,0.545,0.648,0.942], + [0.413,0.432,0.451,0.468,0.485,0.501,0.516,0.53,0.544,0.616,0.763], +]; + +/// p1 (from pfcno.f) +pub const PFCNO_P1: f64 = 0.1402; + +/// p2 (from pfcno.f) +pub const PFCNO_P2: f64 = 0.1285; + +/// p3 (from pfcno.f) +pub const PFCNO_P3: f64 = 1.0; + +/// p4 (from pfcno.f) +pub const PFCNO_P4: f64 = 3.15; + +/// p5 (from pfcno.f) +pub const PFCNO_P5: f64 = 4.0; + +// ========== pffe.f ========== + +/// tt(50) from pffe.f +pub const PFFE_TT: [f64; 50] = [ + 3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0, + 13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0, + 23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,32.0,34.0, + 36.0,38.0,40.0,42.0,44.0,46.0,48.0,50.0,55.0,60.0, + 65.0,70.0,75.0,80.0,85.0,90.0,95.0,100.0,125.0,150.0, +]; + +/// pn(10) from pffe.f +pub const PFFE_PN: [f64; 10] = [ + -2.0,-1.0,0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0, +]; + +/// nca(9) from pffe.f +pub const PFFE_NCA: [f64; 9] = [ + 0.0,0.0,0.0,22.0,30.0,37.0,40.0,41.0,45.0, +]; + +/// p4a(22) from pffe.f +pub const PFFE_P4A: [f64; 22] = [ + 0.778,0.778,0.778,0.779,0.783,0.789,0.801,0.818,0.842,0.871, + 0.906,0.945,0.987,1.03,1.074,1.117,1.16,1.201,1.242,1.28, + 1.317,1.353, +]; + +/// p4b(10, 28) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P4B: [[f64; 28]; 10] = [ + [1.406,1.464,1.546,1.665,1.826,2.024,2.48,2.945,3.379,3.774,4.133,4.46,4.757,5.029,5.279,5.51,6.014,6.435,6.794,7.102,7.37,7.606,7.815,8.001,8.168,8.319,8.9,9.294], + [1.393,1.434,1.483,1.547,1.636,1.755,2.087,2.489,2.897,3.283,3.637,3.962,4.258,4.53,4.78,5.01,5.514,5.935,6.294,6.602,6.87,7.106,7.315,7.501,7.668,7.819,8.399,8.794], + [1.389,1.424,1.461,1.503,1.553,1.618,1.814,2.105,2.452,2.808,3.15,3.468,3.762,4.032,4.281,4.511,5.014,5.435,5.794,6.102,6.37,6.606,6.814,7.001,7.168,7.319,7.899,8.294], + [1.387,1.421,1.454,1.488,1.524,1.564,1.674,1.846,2.089,2.381,2.688,2.989,3.274,3.539,3.785,4.013,4.515,4.936,5.294,5.602,5.87,6.106,6.314,6.5,6.668,6.819,7.399,7.793], + [1.387,1.42,1.451,1.482,1.514,1.546,1.619,1.717,1.859,2.054,2.292,2.549,2.809,3.061,3.299,3.522,4.018,4.437,4.794,5.102,5.37,5.605,5.814,6.0,6.168,6.319,6.899,7.293], + [1.387,1.419,1.451,1.481,1.51,1.54,1.599,1.667,1.751,1.864,2.015,2.199,2.406,2.624,2.84,3.05,3.53,3.943,4.297,4.604,4.871,5.106,5.314,5.5,5.667,5.818,6.398,6.793], + [1.387,1.419,1.45,1.48,1.509,1.538,1.593,1.649,1.71,1.782,1.871,1.984,2.121,2.279,2.45,2.628,3.065,3.46,3.807,4.11,4.375,4.608,4.816,5.001,5.168,5.319,5.898,6.292], + [1.387,1.419,1.45,1.48,1.509,1.537,1.591,1.643,1.696,1.751,1.814,1.886,1.972,2.073,2.189,2.318,2.666,3.022,3.343,3.638,3.892,4.125,4.333,4.511,4.68,4.832,5.405,5.799], + [1.387,1.419,1.45,1.48,1.509,1.537,1.59,1.641,1.691,1.741,1.793,1.848,1.908,1.976,2.051,2.136,2.381,2.658,2.939,3.194,3.439,3.661,3.851,4.032,4.197,4.347,4.917,5.306], + [1.387,1.419,1.45,1.48,1.509,1.537,1.59,1.64,1.689,1.738,1.786,1.835,1.886,1.939,1.996,2.057,2.228,2.422,2.631,2.845,3.052,3.249,3.418,3.586,3.741,3.884,4.431,4.824], +]; + +/// p5a(30) from pffe.f +pub const PFFE_P5A: [f64; 30] = [ + 1.235,1.276,1.301,1.321,1.339,1.359,1.381,1.405,1.432,1.46, + 1.489,1.518,1.546,1.574,1.601,1.627,1.652,1.675,1.697,1.718, + 1.738,1.757,1.775,1.792,1.808,1.823,1.838,1.851,1.877,1.9, +]; + +/// p5b(10, 20) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P5B: [[f64; 20]; 10] = [ + [1.943,2.011,2.144,2.361,2.646,2.96,3.274,3.575,4.251,4.822,5.308,5.725,6.088,6.407,6.689,6.94,7.166,7.37,8.15,8.677], + [1.928,1.964,2.025,2.137,2.315,2.553,2.823,3.101,3.757,4.324,4.808,5.225,5.589,5.907,6.189,6.44,6.666,6.87,7.649,8.177], + [1.923,1.947,1.98,2.032,2.121,2.26,2.45,2.674,3.275,3.829,4.31,4.726,5.089,5.407,5.689,5.94,6.166,6.369,7.149,7.676], + [1.921,1.942,1.965,1.993,2.035,2.102,2.205,2.348,2.829,3.346,3.816,4.228,4.59,4.908,5.189,5.44,5.666,5.869,6.649,7.176], + [1.921,1.941,1.96,1.98,2.004,2.037,2.086,2.158,2.466,2.895,3.334,3.736,4.093,4.409,4.69,4.941,5.166,5.369,6.149,6.676], + [1.921,1.94,1.958,1.976,1.994,2.015,2.04,2.075,2.234,2.522,2.888,3.26,3.604,3.915,4.193,4.443,4.667,4.87,5.649,6.176], + [1.921,1.94,1.957,1.975,1.991,2.007,2.025,2.045,2.124,2.278,2.525,2.828,3.139,3.433,3.704,3.949,4.171,4.373,5.149,5.676], + [1.921,1.94,1.957,1.974,1.99,2.005,2.02,2.036,2.083,2.161,2.297,2.496,2.733,2.988,3.236,3.469,3.684,3.882,4.651,5.176], + [1.921,1.94,1.957,1.974,1.989,2.004,2.018,2.032,2.069,2.116,2.187,2.294,2.447,2.629,2.832,3.038,3.237,3.417,4.167,4.687], + [1.921,1.94,1.957,1.974,1.989,2.004,2.018,2.031,2.064,2.1,2.145,2.206,2.291,2.399,2.535,2.687,2.847,3.008,3.7,4.203], +]; + +/// p6a(37) from pffe.f +pub const PFFE_P6A: [f64; 37] = [ + 1.218,1.273,1.309,1.335,1.358,1.379,1.4,1.421,1.442,1.463, + 1.484,1.504,1.523,1.542,1.56,1.577,1.594,1.609,1.624,1.638, + 1.652,1.664,1.677,1.688,1.699,1.709,1.719,1.729,1.746,1.762, + 1.777,1.79,1.803,1.814,1.825,1.834,1.843, +]; + +/// p6b(10, 13) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P6B: [[f64; 13]; 10] = [ + [1.862,1.958,2.264,2.776,3.321,3.821,4.266,4.662,5.015,5.332,5.618,6.71,7.446], + [1.855,1.9,2.045,2.386,2.856,3.333,3.771,4.164,4.516,4.832,5.118,6.21,6.946], + [1.853,1.88,1.944,2.119,2.453,2.868,3.285,3.67,4.019,4.344,4.619,5.71,6.446], + [1.852,1.874,1.906,1.984,2.165,2.465,2.825,3.187,3.527,3.838,4.121,5.21,5.946], + [1.852,1.872,1.894,1.93,2.012,2.178,2.434,2.739,3.052,3.351,3.628,4.711,5.446], + [1.852,1.871,1.89,1.912,1.949,2.025,2.164,2.372,2.624,2.889,3.149,4.213,4.946], + [1.852,1.871,1.888,1.906,1.927,1.963,2.027,2.135,2.295,2.493,2.711,3.719,4.447], + [1.852,1.871,1.888,1.904,1.92,1.941,1.972,2.022,2.102,2.217,2.364,3.241,3.952], + [1.852,1.871,1.888,1.903,1.918,1.934,1.953,1.98,2.019,2.075,2.155,2.807,3.474], + [1.852,1.871,1.888,1.903,1.917,1.932,1.947,1.965,1.988,2.017,2.058,2.462,3.022], +]; + +/// p7a(40) from pffe.f +pub const PFFE_P7A: [f64; 40] = [ + 1.074,1.13,1.167,1.194,1.215,1.234,1.25,1.266,1.28,1.293, + 1.306,1.318,1.329,1.34,1.35,1.36,1.369,1.378,1.386,1.394, + 1.401,1.408,1.415,1.421,1.427,1.433,1.439,1.444,1.454,1.463, + 1.471,1.479,1.486,1.492,1.498,1.504,1.509,1.514,1.525,1.534, +]; + +/// p7b(10, 10) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P7B: [[f64; 10]; 10] = [ + [1.555,1.617,1.798,2.134,2.55,2.968,3.359,3.718,5.097,6.026], + [1.546,1.572,1.648,1.832,2.138,2.504,2.875,3.224,4.598,5.526], + [1.544,1.557,1.587,1.666,1.836,2.102,2.419,2.745,4.098,5.026], + [1.543,1.552,1.566,1.597,1.671,1.816,2.037,2.305,3.601,4.527], + [1.542,1.55,1.559,1.573,1.602,1.665,1.779,1.953,3.11,4.028], + [1.542,1.55,1.557,1.565,1.578,1.603,1.651,1.736,2.638,3.531], + [1.542,1.549,1.556,1.563,1.57,1.582,1.601,1.636,2.217,3.042], + [1.542,1.549,1.556,1.562,1.568,1.575,1.584,1.599,1.899,2.576], + [1.542,1.549,1.556,1.561,1.567,1.572,1.579,1.586,1.719,2.17], + [1.542,1.549,1.556,1.561,1.567,1.572,1.577,1.582,1.643,1.885], +]; + +/// p8a(41) from pffe.f +pub const PFFE_P8A: [f64; 41] = [ + 0.809,0.849,0.875,0.894,0.908,0.918,0.927,0.934,0.939,0.944, + 0.948,0.952,0.955,0.958,0.96,0.962,0.964,0.966,0.967,0.969, + 0.97,0.971,0.973,0.974,0.975,0.975,0.976,0.977,0.978,0.98, + 0.981,0.982,0.983,0.984,0.984,0.985,0.986,0.986,0.987,0.988, + 0.989, +]; + +/// p8b(10, 9) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P8B: [[f64; 9]; 10] = [ + [0.992,1.0,1.032,1.129,1.335,1.64,1.987,3.514,4.569], + [0.991,0.994,1.005,1.04,1.132,1.312,1.573,3.017,4.069], + [0.99,0.992,0.996,1.008,1.042,1.121,1.269,2.526,3.569], + [0.99,0.991,0.993,0.997,1.009,1.038,1.101,2.053,3.072], + [0.99,0.991,0.992,0.993,0.998,1.007,1.03,1.628,2.58], + [0.99,0.991,0.991,0.992,0.994,0.998,1.005,1.305,2.103], + [0.99,0.991,0.991,0.992,0.993,0.994,0.997,1.119,1.671], + [0.99,0.991,0.991,0.992,0.993,0.993,0.994,1.039,1.336], + [0.99,0.991,0.991,0.992,0.992,0.993,0.994,1.01,1.136], + [0.99,0.991,0.991,0.992,0.992,0.993,0.993,1.0,1.048], +]; + +/// p9a(45) from pffe.f +pub const PFFE_P9A: [f64; 45] = [ + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.001, + 0.002,0.005,0.008,0.014,0.021, +]; + +/// p9b(10, 5) from pffe.f +/// 已转换为 Rust 行优先格式 +pub const PFFE_P9B: [[f64; 5]; 10] = [ + [0.032,0.048,0.076,1.128,2.696], + [0.032,0.045,0.065,0.722,2.2], + [0.031,0.044,0.061,0.429,1.712], + [0.031,0.044,0.06,0.271,1.249], + [0.031,0.044,0.059,0.207,0.848], + [0.031,0.044,0.059,0.184,0.564], + [0.031,0.044,0.059,0.177,0.415], + [0.031,0.044,0.059,0.174,0.354], + [0.031,0.044,0.059,0.173,0.333], + [0.031,0.044,0.059,0.173,0.327], +]; + +/// xen (from pffe.f) +pub const PFFE_XEN: f64 = 2.302585093; + +/// xmil (from pffe.f) +pub const PFFE_XMIL: f64 = 0.001; + +/// xbtz (from pffe.f) +pub const PFFE_XBTZ: f64 = 1.38054e-16; + +// ========== pfheav.f ========== + +/// scale(4) from pfheav.f +pub const PFHEAV_SCALE: [f64; 4] = [ + 0.001,0.01,0.1,1.0, +]; + +/// nnn16(54) from pfheav.f +pub const PFHEAV_NNN16: [f64; 54] = [ + 227027622.0,306233052.0,356839222.0,446052912.0,652382292.0,763314.0,108416342.0,222428472.0,353944332.0,577378932.0, + 110314303.0,1814900.0,198724282.0,293236452.0,468362702.0,86511123.0,136016073.0,3516000.0,279836622.0,461857562.0, + 720693022.0,124915873.0,192522633.0,5600000.0,262136422.0,501167232.0,87911303.0,138916483.0,190721673.0,7900000.0, + 201620781.0,231026761.0,314737361.0,450555381.0,692386911.0,772301.0,109415761.0,247938311.0,58910042.0,190937022.0, + 68311693.0,2028903.0,897195961.0,107212972.0,165021182.0,260230862.0,356940532.0,3682900.0,100010001.0,100410231.0, + 108712611.0,167124841.0,388460411.0,939102.0, +]; + +/// nnn17(54) from pfheav.f +pub const PFHEAV_NNN17: [f64; 54] = [ + 200020021.0,201620761.0,223726341.0,351352061.0,80812472.0,1796001.0,100610471.0,122617301.0,300566361.0,149924112.0, + 332342352.0,3970000.0,403245601.0,493151431.0,529654331.0,559358091.0,611065171.0,600000.0,99710051.0,104511541.0, + 135016501.0,208226431.0,321837921.0,2050900.0,199820071.0,204521391.0,229124761.0,266028451.0,302932131.0,3070000.0, + 502665261.0,755183501.0,901496201.0,102410942.0,117912812.0,787900.0,422848161.0,512153401.0,557458941.0,636270361.0, + 794489061.0,1593000.0,100010261.0,114613921.0,175221251.0,249828711.0,324436181.0,3421000.0,403143241.0,491856701.0, + 649173781.0,840396751.0,113013392.0,981000.0, +]; + +/// nnn18(54) from pfheav.f +pub const PFHEAV_NNN18: [f64; 54] = [ + 593676641.0,884697521.0,105911572.0,129515012.0,180322212.0,1858700.0,484470541.0,91510972.0,125614082.0,157017612.0, + 199722912.0,2829900.0,630172361.0,799686381.0,919797221.0,102810942.0,117712832.0,975000.0,438055511.0,691582151.0, + 94510732.0,121413672.0,152016732.0,2150000.0,651982921.0,94610382.0,113212492.0,139515462.0,169718482.0,3200000.0, + 437347431.0,498951671.0,538559501.0,74710812.0,169126672.0,1183910.0,705183611.0,93510092.0,111614162.0,222932532.0, + 427652992.0,2160000.0,510869921.0,87410312.0,123116552.0,236530712.0,377744832.0,3590000.0,100010001.0,100010051.0, + 105012781.0,198535971.0,65911422.0,1399507.0, +]; + +/// nnn19(54) from pfheav.f +pub const PFHEAV_NNN19: [f64; 54] = [ + 461049811.0,522254261.0,609088131.0,168935052.0,68612253.0,2455908.0,759990901.0,101911142.0,129017782.0,302856642.0, + 99414333.0,3690000.0,200020011.0,200720361.0,211523021.0,269434141.0,459163351.0,417502.0,100010001.0,100110321.0, + 129524961.0,61014202.0,291753192.0,2750004.0,473650891.0,533156051.0,66810932.0,232950852.0,99915303.0,4000000.0, + 100110041.0,104111741.0,146019721.0,281941411.0,607785251.0,569202.0,202621931.0,255331271.0,384347931.0,624085761.0, + 122417632.0,1102600.0,100010001.0,100110321.0,129524961.0,61014202.0,291753192.0,4300000.0,791587851.0,100012192.0, + 155119942.0,254031782.0,389946932.0,637900.0, +]; + +/// nnn20(54) from pfheav.f +pub const PFHEAV_NNN20: [f64; 54] = [ + 118217102.0,220827002.0,319036792.0,416646512.0,513256072.0,1223000.0,92510012.0,104710862.0,112311612.0,120212472.0, + 132814282.0,2050000.0,141320802.0,291439702.0,531170262.0,92712273.0,162521053.0,684000.0,354454352.0,724689652.0, + 107212643.0,148517093.0,193321573.0,1312900.0,209727032.0,324537052.0,415446282.0,510255752.0,604965222.0,2298000.0, + 256636022.0,465759302.0,749693962.0,116514243.0,171520333.0,687900.0,335157222.0,84511463.0,147718363.0,221826083.0, + 299933893.0,1431900.0,223725352.0,280830972.0,340937362.0,406844002.0,473150632.0,2503900.0,703972941.0,82610822.0, + 154822682.0,327244912.0,571469372.0,709900.0, +]; + +/// nnn21(54) from pfheav.f +pub const PFHEAV_NNN21: [f64; 54] = [ + 75714552.0,274347322.0,718897632.0,123414913.0,174920063.0,1614900.0,267645462.0,669890262.0,115514323.0,173620673.0, + 242528083.0,2714900.0,90613732.0,184823562.0,291735332.0,419949102.0,565764332.0,728000.0,131318312.0,227126932.0, + 311735452.0,397644072.0,483852692.0,1525900.0,204721673.0,234725733.0,284031463.0,348738613.0,426546943.0,3000000.0, + 176824122.0,318941082.0,515263202.0,761790472.0,106112303.0,736400.0,221934642.0,501968372.0,88911173.0,136316243.0, + 189221613.0,1675900.0,210622722.0,241025422.0,267928262.0,297731272.0,327834282.0,2846000.0,148520202.0,255230902.0, + 364942462.0,489656082.0,638872352.0,746000.0, +]; + +/// nnn22(54) from pfheav.f +pub const PFHEAV_NNN22: [f64; 54] = [ + 153421292.0,288137912.0,484660322.0,720187062.0,101011483.0,1807000.0,254537212.0,492362292.0,770592182.0,107312243.0, + 137615273.0,3104900.0,115919651.0,320746011.0,607576761.0,95011642.0,141817172.0,832900.0,755087211.0,105913442.0, + 173122222.0,282034722.0,412247732.0,1941900.0,180223462.0,289735212.0,414247632.0,538460052.0,662672472.0,3292000.0, + 200020001.0,200220141.0,206422141.0,257633021.0,455164681.0,757403.0,100810581.0,125817401.0,260641031.0,66210072.0, + 135316982.0,2148000.0,795887491.0,97711762.0,156620252.0,248329422.0,340038582.0,3481900.0,100010001.0,100410241.0, + 109212891.0,176827421.0,444268771.0,899003.0, +]; + +/// nnn23(54) from pfheav.f +pub const PFHEAV_NNN23: [f64; 54] = [ + 200020021.0,201720921.0,233329881.0,451475371.0,127520782.0,1690301.0,100310281.0,114815371.0,246138311.0,519265531.0, + 791492761.0,3747000.0,252431921.0,368440461.0,433746521.0,512259221.0,723389021.0,578400.0,100110071.0,104611651.0, + 146118581.0,225426511.0,304734431.0,1886000.0,200120111.0,205021611.0,243628031.0,317035371.0,390442701.0,2802900.0, + 232637101.0,488058571.0,669074381.0,816189091.0,97210632.0,734200.0,286335941.0,408144471.0,479351961.0,571862901.0, + 686274341.0,1462700.0,100010251.0,114013811.0,175321601.0,256829751.0,338337901.0,3049000.0,404043481.0,494656811.0, + 646772781.0,813490751.0,101411372.0,863900.0, +]; + +/// nnn24(54) from pfheav.f +pub const PFHEAV_NNN24: [f64; 54] = [ + 303147981.0,618472951.0,827392621.0,103711702.0,131214532.0,1650000.0,313037601.0,429347901.0,536260591.0,689477591.0, + 862494881.0,2529900.0,526258801.0,657372351.0,784284071.0,897095741.0,102711082.0,900900.0,440855541.0,686481251.0, + 93810792.0,125414792.0,176321132.0,1860000.0,349054751.0,699883081.0,96611302.0,134216202.0,197724212.0,2800000.0, + 405342041.0,438645621.0,475751071.0,587974491.0,102214572.0,1045404.0,568567471.0,773485861.0,94510362.0,112712182.0, + 130914002.0,1909000.0,514269581.0,86910562.0,130716652.0,215327742.0,351843662.0,3200000.0,100010001.0,100010091.0, + 109515351.0,291060661.0,119621482.0,1212716.0, +]; + +/// nnn25(54) from pfheav.f +pub const PFHEAV_NNN25: [f64; 54] = [ + 414844131.0,465649111.0,538464651.0,87112232.0,158019362.0,2120000.0,615475101.0,867797531.0,112213462.0,157618062.0, + 203622662.0,3209900.0,200020001.0,201020501.0,215623871.0,283536181.0,462756261.0,389300.0,100010001.0,100310371.0, + 119016501.0,269146361.0,77912412.0,2510000.0,424445601.0,481750061.0,516953311.0,549356551.0,581759791.0,3500000.0, + 101210791.0,135119351.0,282340571.0,574580391.0,111015062.0,521002.0,262638611.0,504160621.0,698579371.0,91010692.0, + 129115952.0,1000000.0,100010001.0,100310351.0,118416321.0,264945521.0,76512182.0,3700000.0,71111992.0,172323592.0, + 312540402.0,510763182.0,765791012.0,558000.0, +]; + +/// nnn26(54) from pfheav.f +pub const PFHEAV_NNN26: [f64; 54] = [ + 204529582.0,383647882.0,582469262.0,807992692.0,104911723.0,1106000.0,94712552.0,148416582.0,179819212.0,203621522.0, + 227424042.0,1916900.0,295959132.0,103515693.0,215527593.0,335939413.0,449650223.0,565000.0,79718153.0,289639443.0, + 495159253.0,686877533.0,863794813.0,1085000.0,298640242.0,475053692.0,596965912.0,725379692.0,872094692.0,2008000.0, + 460693672.0,158523823.0,327242303.0,519661563.0,709379783.0,541900.0,455480232.0,114014653.0,178521013.0,240927073.0, + 299232633.0,1055000.0,46410533.0,183826893.0,354443773.0,518459633.0,674375243.0,2320000.0,139623042.0,364860002.0, + 96114603.0,209828633.0,373446973.0,549000.0, +]; + +/// nnn27(54) from pfheav.f +pub const PFHEAV_NNN27: [f64; 54] = [ + 460493692.0,158523823.0,327142303.0,519661563.0,709279783.0,1073000.0,455480232.0,114014653.0,178521013.0,240927073.0, + 299232633.0,2000000.0,131720482.0,280535692.0,441254492.0,676583972.0,103412583.0,555000.0,139623042.0,364860002.0, + 96114603.0,209828633.0,373446973.0,1089900.0,460493682.0,158523823.0,327142303.0,519661563.0,709279783.0,2000000.0, + 92915672.0,222431062.0,444763802.0,89612173.0,159520253.0,562900.0,315059662.0,97114563.0,204627093.0,342541693.0, + 490556383.0,1106900.0,269037812.0,520270372.0,91111273.0,133915483.0,172719093.0,2000000.0,800080571.0,851699301.0, + 127617362.0,240433032.0,444958442.0,568000.0, +]; + +/// nnn28(54) from pfheav.f +pub const PFHEAV_NNN28: [f64; 54] = [ + 125416052.0,211828182.0,375549622.0,644381732.0,101112213.0,1125000.0,800080571.0,851699301.0,127617362.0,240433032.0, + 444958442.0,2000000.0,240432982.0,427555202.0,708489962.0,112613853.0,167319843.0,615900.0,534793262.0,139219123.0, + 247730843.0,371043333.0,495055893.0,1210000.0,364145232.0,514756362.0,604864112.0,673870372.0,732276072.0,2000000.0, + 480767202.0,89011393.0,144118243.0,230028753.0,354142883.0,584900.0,480767192.0,89011393.0,144118243.0,230028753.0, + 354142883.0,1151900.0,480767202.0,89011393.0,144118243.0,230028753.0,354142883.0,2000000.0,343147532.0,645887152.0, + 115314793.0,183322063.0,257729373.0,593000.0, +]; + +/// nnn29(54) from pfheav.f +pub const PFHEAV_NNN29: [f64; 54] = [ + 343147532.0,645887142.0,115314793.0,183322063.0,257729373.0,1167000.0,343147532.0,645887142.0,115314793.0,183322063.0, + 257729373.0,2000000.0,222635002.0,542276772.0,100312353.0,145716713.0,187020703.0,602000.0,222635002.0,542276772.0, + 100312353.0,145716713.0,187020703.0,1180000.0,222635002.0,542276772.0,100312353.0,145716713.0,187020703.0,2000000.0, + 133715382.0,209130152.0,429859382.0,79410293.0,129815983.0,609900.0,265934782.0,497877532.0,120517733.0,245032063.0, + 400448073.0,1193000.0,265934782.0,497877532.0,120517733.0,245032063.0,400448073.0,2000000.0,800381111.0,87510702.0, + 147621462.0,310343462.0,585475982.0,618000.0, +]; + +/// nnn30(54) from pfheav.f +pub const PFHEAV_NNN30: [f64; 54] = [ + 156718872.0,279244452.0,678196342.0,128316243.0,197823443.0,1205000.0,93517192.0,364666132.0,103414613.0,192624193.0, + 293334613.0,2370000.0,100010011.0,101310651.0,118613951.0,169120661.0,250629971.0,625000.0,200120901.0,270345231.0, + 81714042.0,223533112.0,461959862.0,1217000.0,100312561.0,250851931.0,91914182.0,198626022.0,323638692.0,2000000.0, + 514664441.0,759086851.0,99211442.0,133315612.0,182721252.0,609900.0,125924831.0,438667801.0,98714112.0,199727872.0, + 380850742.0,1389900.0,323948621.0,661297271.0,158626482.0,426865032.0,93712843.0,1900000.0,659294081.0,128016962.0, + 222528952.0,372047062.0,585171462.0,700000.0, +]; + +/// nnn31(54) from pfheav.f +pub const PFHEAV_NNN31: [f64; 54] = [ + 99117882.0,274638812.0,520867322.0,84410313.0,123314453.0,1489900.0,187427702.0,343739872.0,448049452.0,539358282.0, + 625266642.0,2329900.0,65210892.0,171325762.0,373552252.0,705192012.0,116414343.0,787900.0,192837842.0,600784802.0, + 111113823.0,165419233.0,218524383.0,1620000.0,99117872.0,274638812.0,520867312.0,84410313.0,123314453.0,2400000.0, + 398981651.0,130019172.0,273438022.0,516168382.0,88411163.0,797900.0,131429482.0,523279952.0,111414623.0,183422233.0, + 262130233.0,1770000.0,192837842.0,600784792.0,111113823.0,165419233.0,218524383.0,2500000.0,600963001.0,75910412.0, + 150121572.0,301940972.0,539168952.0,787000.0, +]; + +/// nnn32(54) from pfheav.f +pub const PFHEAV_NNN32: [f64; 54] = [ + 73710852.0,190731262.0,464964142.0,83810503.0,127315053.0,1660000.0,131429482.0,523279952.0,111414623.0,183422233.0, + 262130233.0,2600000.0,110815502.0,216829732.0,398752322.0,672484682.0,104612673.0,850000.0,168225972.0,362046562.0, + 566766422.0,757484612.0,93010103.0,1700000.0,73710852.0,190731262.0,464964142.0,83810503.0,127315053.0,2700000.0, + 129117892.0,239430882.0,388748292.0,596173252.0,89510843.0,910000.0,110815502.0,216829732.0,398752322.0,672484682.0, + 104612673.0,2000000.0,168225972.0,362046562.0,566766422.0,757484612.0,93010103.0,2800000.0,158918512.0,207523002.0, + 254328242.0,316335762.0,407246582.0,900000.0, +]; + +/// nnn33(54) from pfheav.f +pub const PFHEAV_NNN33: [f64; 54] = [ + 98115462.0,224930742.0,401150612.0,623475412.0,89910583.0,1855900.0,146323292.0,354651802.0,74810923.0,161723953.0, + 348749363.0,3322700.0,203222611.0,265731251.0,364042301.0,494958601.0,702084731.0,922000.0,120521331.0,357753801.0, + 75310062.0,130516572.0,206925452.0,2050000.0,651780821.0,108814772.0,195925252.0,316338622.0,460853882.0,3000000.0, + 100010001.0,100110111.0,105211851.0,152122101.0,341552811.0,1043002.0,200320211.0,210023021.0,268834231.0,480472341.0, + 111416912.0,1875000.0,104012871.0,186129471.0,458664151.0,82410072.0,119013732.0,3420000.0,200420711.0,222424271.0, + 265429161.0,325637371.0,442853911.0,610500.0, +]; + +/// nnn34(54) from pfheav.f +pub const PFHEAV_NNN34: [f64; 54] = [ + 100010021.0,101910801.0,121414641.0,189525811.0,358949721.0,2041900.0,200020311.0,216624611.0,296337451.0,489064791.0, + 85711212.0,2979900.0,103411711.0,147819101.0,244331781.0,434862751.0,93113762.0,741404.0,204122231.0,248227841.0, + 311535621.0,429153941.0,651976431.0,1502800.0,100210131.0,106812201.0,154522671.0,381665951.0,95512512.0,3192900.0, + 400140351.0,416944121.0,474851591.0,564362181.0,690477231.0,728700.0,106814451.0,204427341.0,350744811.0,586879131.0, + 108314772.0,1667900.0,205523051.0,264830231.0,345439921.0,469156001.0,675281671.0,2555900.0,500950661.0,518153561.0, + 559058941.0,628968071.0,748483501.0,843000.0, +]; + +/// nnn35(54) from pfheav.f +pub const PFHEAV_NNN35: [f64; 54] = [ + 443756241.0,696282451.0,95411012.0,128615262.0,182922012.0,1900000.0,336953201.0,682481011.0,93810882.0,127915272.0, + 184622442.0,2700000.0,402841621.0,431544771.0,463148311.0,520059491.0,734896851.0,930000.0,576168741.0,788387631.0, + 96910642.0,116012552.0,135014462.0,2000000.0,490265341.0,812797201.0,116614322.0,179622692.0,285035302.0,2900000.0, + 100010001.0,100010031.0,102311051.0,133018071.0,264539391.0,1074500.0,402841621.0,431544771.0,463148311.0,520059491.0, + 734996851.0,2000000.0,576168741.0,788387631.0,96910642.0,116012552.0,135014462.0,3000000.0,200020011.0,201220591.0, + 218124481.0,296538611.0,488859141.0,400000.0, +]; + +/// nnn36(54) from pfheav.f +pub const PFHEAV_NNN36: [f64; 54] = [ + 100010001.0,100010031.0,102311051.0,133018071.0,264539401.0,2200000.0,421645151.0,477449611.0,511852711.0,542455761.0, + 572958821.0,3300000.0,100010041.0,105212131.0,153220271.0,270435641.0,460258111.0,527600.0,201221791.0,258131471.0, + 381645781.0,546365131.0,777592781.0,1014400.0,100010001.0,100010031.0,102311051.0,133018071.0,264539391.0,3400000.0, + 510064491.0,82710872.0,142718412.0,232328712.0,348341572.0,690000.0,228951571.0,88513232.0,183324132.0,305537492.0, + 448152402.0,1210000.0,723989131.0,103511752.0,130814352.0,155416652.0,177018682.0,2000000.0,620099241.0,162725772.0, + 391457072.0,80110833.0,141818023.0,600000.0, +]; + +/// nnn37(54) from pfheav.f +pub const PFHEAV_NNN37: [f64; 54] = [ + 620099241.0,162725772.0,391457072.0,80110833.0,141818023.0,1200000.0,620099251.0,162725772.0,391457072.0,80110833.0, + 141818023.0,2000000.0,347877992.0,129318323.0,240730533.0,380546863.0,570368573.0,600000.0,347877992.0,129318323.0, + 240730533.0,380546863.0,570368573.0,1200000.0,347777992.0,129318323.0,240730533.0,380546863.0,570368573.0,2000000.0, + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,600000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,2000000.0,209530092.0,450866762.0, + 96613623.0,186524763.0,318839893.0,600000.0, +]; + +/// nnn38(54) from pfheav.f +pub const PFHEAV_NNN38: [f64; 54] = [ + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,2000000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,600000.0,209530092.0,450866762.0, + 96613623.0,186524763.0,318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,2000000.0, + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,600000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,2000000.0,209530092.0,450866762.0, + 96613623.0,186524763.0,318839893.0,600000.0, +]; + +/// nnn39(54) from pfheav.f +pub const PFHEAV_NNN39: [f64; 54] = [ + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,2000000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,600000.0,209530092.0,450866762.0, + 96613623.0,186524763.0,318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,2000000.0, + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,600000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,2000000.0,209530092.0,450866762.0, + 96613623.0,186524763.0,318839893.0,600000.0, +]; + +/// nnn40(12) from pfheav.f +pub const PFHEAV_NNN40: [f64; 12] = [ + 209530092.0,450866762.0,96613623.0,186524763.0,318839893.0,1200000.0,209530092.0,450866762.0,96613623.0,186524763.0, + 318839893.0,2000000.0, +]; + +/// tvcon (from pfheav.f) +pub const PFHEAV_TVCON: f64 = 8.6171e-05; + +/// hionev (from pfheav.f) +pub const PFHEAV_HIONEV: f64 = 13.595; + +/// one (from pfheav.f) +pub const PFHEAV_ONE: f64 = 1.0; + +/// half (from pfheav.f) +pub const PFHEAV_HALF: f64 = 0.5; + +// ========== pfni.f ========== + +/// g0(6) from pfni.f +pub const PFNI_G0: [f64; 6] = [ + 28.0,25.0,6.0,25.0,28.0,21.0, +]; + +/// p4a(190) from pfni.f +pub const PFNI_P4A: [f64; 190] = [ + 1.447,1.464,1.482,1.501,1.518,1.535,1.551,1.567,1.582,1.596, + 1.61,1.623,1.636,1.648,1.659,1.671,1.681,1.692,1.702,1.711, + 1.721,1.73,1.739,1.748,1.757,1.765,1.774,1.782,1.791,1.799, + 1.808,1.816,1.824,1.833,1.841,1.85,1.859,1.868,1.877,1.886, + 1.895,1.905,1.914,1.924,1.934,1.945,1.955,1.966,1.977,1.989, + 2.0,2.012,2.025,2.037,2.05,2.063,2.077,2.091,2.105,2.119, + 2.134,2.149,2.164,2.179,2.195,2.211,2.227,2.243,2.26,2.276, + 2.293,2.31,2.327,2.344,2.362,2.379,2.397,2.414,2.432,2.449, + 2.467,2.484,2.502,2.519,2.537,2.554,2.571,2.588,2.606,2.623, + 2.64,2.657,2.674,2.69,2.707,2.723,2.74,2.756,2.772,2.788, + 2.804,2.819,2.835,2.85,2.866,2.881,2.896,2.911,2.925,2.94, + 2.954,2.969,2.983,2.997,3.01,3.024,3.038,3.051,3.064,3.077, + 3.09,3.103,3.116,3.128,3.141,3.153,3.165,3.177,3.189,3.201, + 3.213,3.224,3.235,3.247,3.258,3.269,3.28,3.291,3.301,3.312, + 3.322,3.332,3.343,3.353,3.363,3.373,3.382,3.392,3.402,3.411, + 3.421,3.43,3.439,3.448,3.457,3.466,3.475,3.484,3.492,3.501, + 3.509,3.518,3.526,3.534,3.542,3.55,3.558,3.566,3.574,3.582, + 3.589,3.597,3.604,3.612,3.619,3.626,3.634,3.641,3.648,3.655, + 3.662,3.669,3.676,3.682,3.689,3.696,3.702,3.709,3.715,3.722, +]; + +/// p4b(170) from pfni.f +pub const PFNI_P4B: [f64; 170] = [ + 3.589,3.597,3.604,3.612,3.619,3.626,3.634,3.641,3.648,3.655, + 3.662,3.669,3.676,3.682,3.689,3.696,3.702,3.709,3.715,3.722, + 3.728,3.734,3.74,3.747,3.753,3.759,3.765,3.771,3.777,3.782, + 3.788,3.794,3.8,3.805,3.811,3.816,3.822,3.827,3.833,3.838, + 3.843,3.849,3.854,3.859,3.864,3.869,3.874,3.879,3.884,3.889, + 3.894,3.899,3.904,3.909,3.913,3.918,3.923,3.927,3.932,3.936, + 3.941,3.945,3.95,3.954,3.959,3.963,3.967,3.972,3.976,3.98, + 3.984,3.988,3.993,3.997,4.001,4.005,4.009,4.013,4.017,4.021, + 4.024,4.028,4.032,4.036,4.04,4.043,4.047,4.051,4.055,4.058, + 4.062,4.065,4.069,4.072,4.076,4.079,4.083,4.086,4.09,4.093, + 4.097,4.1,4.103,4.107,4.11,4.113,4.116,4.12,4.123,4.126, + 4.129,4.132,4.135,4.138,4.141,4.144,4.148,4.151,4.154,4.157, + 4.159,4.162,4.165,4.168,4.171,4.174,4.177,4.18,4.182,4.185, + 4.188,4.191,4.193,4.196,4.199,4.202,4.204,4.207,4.21,4.212, + 4.215,4.217,4.22,4.223,4.225,4.228,4.23,4.233,4.235,4.238, + 4.24,4.243,4.245,4.247,4.25,4.252,4.255,4.257,4.259,4.262, + 4.264,4.266,4.268,4.271,4.273,4.275,4.278,4.28,4.282,4.284, +]; + +/// p5a(190) from pfni.f +pub const PFNI_P5A: [f64; 190] = [ + 1.398,1.408,1.427,1.446,1.466,1.486,1.506,1.526,1.545,1.564, + 1.583,1.601,1.619,1.636,1.652,1.668,1.683,1.698,1.712,1.725, + 1.738,1.751,1.763,1.775,1.786,1.797,1.808,1.818,1.828,1.837, + 1.846,1.855,1.864,1.873,1.881,1.889,1.897,1.904,1.912,1.919, + 1.926,1.933,1.94,1.946,1.953,1.96,1.966,1.972,1.979,1.985, + 1.991,1.997,2.003,2.009,2.016,2.022,2.028,2.034,2.04,2.046, + 2.052,2.058,2.065,2.071,2.077,2.084,2.09,2.097,2.103,2.11, + 2.117,2.124,2.131,2.138,2.145,2.152,2.16,2.167,2.175,2.183, + 2.191,2.199,2.207,2.216,2.224,2.233,2.241,2.25,2.259,2.268, + 2.278,2.287,2.297,2.306,2.316,2.326,2.336,2.346,2.356,2.367, + 2.377,2.387,2.398,2.409,2.419,2.43,2.441,2.452,2.463,2.474, + 2.485,2.497,2.508,2.519,2.53,2.542,2.553,2.564,2.576,2.587, + 2.599,2.61,2.621,2.633,2.644,2.655,2.667,2.678,2.689,2.701, + 2.712,2.723,2.734,2.745,2.757,2.768,2.779,2.79,2.801,2.812, + 2.822,2.833,2.844,2.855,2.865,2.876,2.886,2.897,2.907,2.918, + 2.928,2.938,2.948,2.958,2.968,2.978,2.988,2.998,3.008,3.018, + 3.027,3.037,3.046,3.056,3.065,3.075,3.084,3.093,3.102,3.111, + 3.12,3.129,3.138,3.147,3.156,3.164,3.173,3.182,3.19,3.198, + 3.207,3.215,3.223,3.232,3.24,3.248,3.256,3.264,3.272,3.279, +]; + +/// p5b(170) from pfni.f +pub const PFNI_P5B: [f64; 170] = [ + 3.12,3.129,3.138,3.147,3.156,3.164,3.173,3.182,3.19,3.198, + 3.207,3.215,3.223,3.232,3.24,3.248,3.256,3.264,3.272,3.279, + 3.287,3.295,3.303,3.31,3.318,3.325,3.333,3.34,3.347,3.355, + 3.362,3.369,3.376,3.383,3.39,3.397,3.404,3.411,3.417,3.424, + 3.431,3.438,3.444,3.451,3.457,3.464,3.47,3.476,3.483,3.489, + 3.495,3.501,3.507,3.514,3.52,3.526,3.531,3.537,3.543,3.549, + 3.555,3.561,3.566,3.572,3.578,3.583,3.589,3.594,3.6,3.605, + 3.61,3.616,3.621,3.626,3.632,3.637,3.642,3.647,3.652,3.657, + 3.662,3.667,3.672,3.677,3.682,3.687,3.692,3.697,3.701,3.706, + 3.711,3.716,3.72,3.725,3.729,3.734,3.738,3.743,3.747,3.752, + 3.756,3.761,3.765,3.769,3.774,3.778,3.782,3.786,3.79,3.795, + 3.799,3.803,3.807,3.811,3.815,3.819,3.823,3.827,3.831,3.835, + 3.839,3.843,3.846,3.85,3.854,3.858,3.862,3.865,3.869,3.873, + 3.876,3.88,3.884,3.887,3.891,3.894,3.898,3.901,3.905,3.908, + 3.912,3.915,3.918,3.922,3.925,3.929,3.932,3.935,3.939,3.942, + 3.945,3.948,3.951,3.955,3.958,3.961,3.964,3.967,3.97,3.974, + 3.977,3.98,3.983,3.986,3.989,3.992,3.995,3.998,4.001,4.004, +]; + +/// p6a(190) from pfni.f +pub const PFNI_P6A: [f64; 190] = [ + 0.778,0.804,0.817,0.834,0.854,0.876,0.901,0.928,0.957,0.987, + 1.017,1.048,1.079,1.109,1.139,1.169,1.197,1.225,1.253,1.279, + 1.304,1.329,1.353,1.376,1.398,1.419,1.44,1.459,1.478,1.497, + 1.515,1.532,1.548,1.564,1.58,1.594,1.609,1.623,1.636,1.649, + 1.662,1.674,1.686,1.698,1.709,1.72,1.73,1.74,1.75,1.76, + 1.769,1.779,1.788,1.796,1.805,1.813,1.821,1.829,1.837,1.845, + 1.852,1.86,1.867,1.874,1.881,1.888,1.894,1.901,1.907,1.914, + 1.92,1.926,1.932,1.938,1.944,1.95,1.956,1.962,1.968,1.974, + 1.979,1.985,1.991,1.996,2.002,2.007,2.013,2.018,2.024,2.029, + 2.035,2.041,2.046,2.052,2.057,2.063,2.068,2.074,2.08,2.086, + 2.091,2.097,2.103,2.109,2.115,2.121,2.127,2.133,2.139,2.145, + 2.152,2.158,2.164,2.171,2.177,2.184,2.19,2.197,2.204,2.211, + 2.218,2.225,2.232,2.239,2.246,2.253,2.261,2.268,2.276,2.283, + 2.291,2.298,2.306,2.314,2.322,2.33,2.338,2.346,2.354,2.362, + 2.37,2.379,2.387,2.395,2.404,2.412,2.42,2.429,2.438,2.446, + 2.455,2.463,2.472,2.481,2.489,2.498,2.507,2.516,2.524,2.533, + 2.542,2.551,2.56,2.569,2.577,2.586,2.595,2.604,2.613,2.622, + 2.631,2.639,2.648,2.657,2.666,2.675,2.683,2.692,2.701,2.71, + 2.718,2.727,2.736,2.744,2.753,2.761,2.77,2.779,2.787,2.796, +]; + +/// p6b(170) from pfni.f +pub const PFNI_P6B: [f64; 170] = [ + 2.631,2.639,2.648,2.657,2.666,2.675,2.683,2.692,2.701,2.71, + 2.718,2.727,2.736,2.744,2.753,2.761,2.77,2.779,2.787,2.796, + 2.804,2.812,2.821,2.829,2.838,2.846,2.854,2.862,2.871,2.879, + 2.887,2.895,2.903,2.911,2.919,2.927,2.935,2.943,2.951,2.958, + 2.966,2.974,2.982,2.989,2.997,3.005,3.012,3.02,3.027,3.035, + 3.042,3.049,3.057,3.064,3.071,3.078,3.086,3.093,3.1,3.107, + 3.114,3.121,3.128,3.135,3.141,3.148,3.155,3.162,3.169,3.175, + 3.182,3.188,3.195,3.202,3.208,3.214,3.221,3.227,3.234,3.24, + 3.246,3.252,3.259,3.265,3.271,3.277,3.283,3.289,3.295,3.301, + 3.307,3.313,3.319,3.325,3.33,3.336,3.342,3.348,3.353,3.359, + 3.364,3.37,3.376,3.381,3.386,3.392,3.397,3.403,3.408,3.413, + 3.419,3.424,3.429,3.434,3.44,3.445,3.45,3.455,3.46,3.465, + 3.47,3.475,3.48,3.485,3.49,3.495,3.499,3.504,3.509,3.514, + 3.518,3.523,3.528,3.533,3.537,3.542,3.546,3.551,3.555,3.56, + 3.564,3.569,3.573,3.578,3.582,3.586,3.591,3.595,3.599,3.604, + 3.608,3.612,3.616,3.621,3.625,3.629,3.633,3.637,3.641,3.645, + 3.649,3.653,3.657,3.661,3.665,3.669,3.673,3.677,3.681,3.685, +]; + +/// p7a(190) from pfni.f +pub const PFNI_P7A: [f64; 190] = [ + 1.398,1.398,1.398,1.398,1.406,1.425,1.443,1.461,1.48,1.498, + 1.516,1.534,1.551,1.568,1.585,1.601,1.616,1.631,1.646,1.66, + 1.674,1.687,1.7,1.712,1.724,1.736,1.747,1.758,1.768,1.778, + 1.788,1.797,1.806,1.815,1.824,1.832,1.84,1.848,1.855,1.863, + 1.87,1.877,1.883,1.89,1.896,1.902,1.908,1.914,1.92,1.925, + 1.931,1.936,1.941,1.946,1.951,1.956,1.96,1.965,1.969,1.974, + 1.978,1.982,1.986,1.99,1.994,1.998,2.001,2.005,2.009,2.012, + 2.016,2.019,2.022,2.026,2.029,2.032,2.035,2.038,2.041,2.044, + 2.047,2.05,2.053,2.056,2.059,2.061,2.064,2.067,2.069,2.072, + 2.075,2.077,2.08,2.082,2.085,2.088,2.09,2.093,2.095,2.098, + 2.1,2.103,2.105,2.107,2.11,2.112,2.115,2.117,2.12,2.122, + 2.125,2.127,2.13,2.132,2.135,2.137,2.14,2.142,2.145,2.148, + 2.15,2.153,2.155,2.158,2.161,2.163,2.166,2.169,2.172,2.175, + 2.178,2.18,2.183,2.186,2.189,2.192,2.195,2.198,2.202,2.205, + 2.208,2.211,2.215,2.218,2.221,2.225,2.228,2.232,2.235,2.239, + 2.243,2.246,2.25,2.254,2.258,2.261,2.265,2.269,2.273,2.277, + 2.282,2.286,2.29,2.294,2.299,2.303,2.307,2.312,2.316,2.321, + 2.325,2.33,2.335,2.339,2.344,2.349,2.354,2.359,2.364,2.369, + 2.374,2.379,2.384,2.389,2.394,2.399,2.405,2.41,2.415,2.42, +]; + +/// p7b(170) from pfni.f +pub const PFNI_P7B: [f64; 170] = [ + 2.325,2.33,2.335,2.339,2.344,2.349,2.354,2.359,2.364,2.369, + 2.374,2.379,2.384,2.389,2.394,2.399,2.405,2.41,2.415,2.42, + 2.426,2.431,2.437,2.442,2.448,2.453,2.459,2.464,2.47,2.476, + 2.481,2.487,2.493,2.498,2.504,2.51,2.516,2.521,2.527,2.533, + 2.539,2.545,2.551,2.556,2.562,2.568,2.574,2.58,2.586,2.592, + 2.598,2.604,2.61,2.616,2.622,2.628,2.634,2.64,2.646,2.652, + 2.658,2.664,2.67,2.676,2.682,2.687,2.693,2.699,2.705,2.711, + 2.717,2.723,2.729,2.735,2.741,2.747,2.753,2.759,2.764,2.77, + 2.776,2.782,2.788,2.794,2.799,2.805,2.811,2.817,2.823,2.828, + 2.834,2.84,2.846,2.851,2.857,2.863,2.868,2.874,2.879,2.885, + 2.891,2.896,2.902,2.907,2.913,2.918,2.924,2.929,2.935,2.94, + 2.945,2.951,2.956,2.962,2.967,2.972,2.978,2.983,2.988,2.993, + 2.999,3.004,3.009,3.014,3.019,3.025,3.03,3.035,3.04,3.045, + 3.05,3.055,3.06,3.065,3.07,3.075,3.08,3.085,3.09,3.095, + 3.099,3.104,3.109,3.114,3.119,3.123,3.128,3.133,3.138,3.142, + 3.147,3.152,3.156,3.161,3.165,3.17,3.175,3.179,3.184,3.188, + 3.193,3.197,3.202,3.206,3.21,3.215,3.219,3.224,3.228,3.232, +]; + +/// p8a(190) from pfni.f +pub const PFNI_P8A: [f64; 190] = [ + 1.447,1.447,1.447,1.447,1.447,1.447,1.459,1.475,1.489,1.504, + 1.518,1.531,1.544,1.556,1.568,1.58,1.591,1.602,1.612,1.622, + 1.631,1.64,1.649,1.658,1.666,1.674,1.682,1.689,1.696,1.703, + 1.71,1.716,1.722,1.728,1.734,1.74,1.745,1.751,1.756,1.761, + 1.766,1.77,1.775,1.779,1.784,1.788,1.792,1.796,1.8,1.804, + 1.807,1.811,1.814,1.818,1.821,1.824,1.827,1.831,1.834,1.836, + 1.839,1.842,1.845,1.848,1.85,1.853,1.855,1.858,1.86,1.863, + 1.865,1.867,1.87,1.872,1.874,1.876,1.878,1.88,1.882,1.884, + 1.886,1.888,1.89,1.892,1.894,1.896,1.898,1.9,1.902,1.903, + 1.905,1.907,1.909,1.911,1.912,1.914,1.916,1.917,1.919,1.921, + 1.923,1.924,1.926,1.928,1.929,1.931,1.933,1.934,1.936,1.938, + 1.939,1.941,1.943,1.945,1.946,1.948,1.95,1.951,1.953,1.955, + 1.957,1.959,1.96,1.962,1.964,1.966,1.968,1.97,1.971,1.973, + 1.975,1.977,1.979,1.981,1.983,1.985,1.987,1.989,1.991,1.993, + 1.995,1.998,2.0,2.002,2.004,2.006,2.009,2.011,2.013,2.015, + 2.018,2.02,2.023,2.025,2.027,2.03,2.032,2.035,2.037,2.04, + 2.043,2.045,2.048,2.051,2.053,2.056,2.059,2.062,2.064,2.067, + 2.07,2.073,2.076,2.079,2.082,2.085,2.088,2.091,2.094,2.097, + 2.1,2.103,2.107,2.11,2.113,2.116,2.12,2.123,2.126,2.13, +]; + +/// p8b(170) from pfni.f +pub const PFNI_P8B: [f64; 170] = [ + 2.07,2.073,2.076,2.079,2.082,2.085,2.088,2.091,2.094,2.097, + 2.1,2.103,2.107,2.11,2.113,2.116,2.12,2.123,2.126,2.13, + 2.133,2.137,2.14,2.143,2.147,2.151,2.154,2.158,2.161,2.165, + 2.168,2.172,2.176,2.18,2.183,2.187,2.191,2.195,2.198,2.202, + 2.206,2.21,2.214,2.218,2.222,2.226,2.23,2.233,2.237,2.241, + 2.245,2.25,2.254,2.258,2.262,2.266,2.27,2.274,2.278,2.282, + 2.286,2.291,2.295,2.299,2.303,2.307,2.312,2.316,2.32,2.324, + 2.329,2.333,2.337,2.341,2.346,2.35,2.354,2.359,2.363,2.367, + 2.371,2.376,2.38,2.384,2.389,2.393,2.397,2.402,2.406,2.41, + 2.415,2.419,2.423,2.428,2.432,2.436,2.441,2.445,2.449,2.454, + 2.458,2.462,2.467,2.471,2.475,2.48,2.484,2.488,2.493,2.497, + 2.501,2.506,2.51,2.514,2.519,2.523,2.527,2.531,2.536,2.54, + 2.544,2.548,2.553,2.557,2.561,2.565,2.57,2.574,2.578,2.582, + 2.586,2.591,2.595,2.599,2.603,2.607,2.611,2.616,2.62,2.624, + 2.628,2.632,2.636,2.64,2.644,2.648,2.652,2.656,2.661,2.665, + 2.669,2.673,2.677,2.681,2.685,2.689,2.693,2.696,2.7,2.704, + 2.708,2.712,2.716,2.72,2.724,2.728,2.732,2.736,2.739,2.743, +]; + +/// p9a(190) from pfni.f +pub const PFNI_P9A: [f64; 190] = [ + 1.322,1.322,1.322,1.322,1.322,1.322,1.322,1.322,1.322,1.325, + 1.334,1.342,1.351,1.358,1.366,1.373,1.38,1.386,1.392,1.398, + 1.404,1.409,1.415,1.42,1.425,1.429,1.434,1.438,1.442,1.446, + 1.45,1.454,1.457,1.461,1.464,1.467,1.47,1.473,1.476,1.479, + 1.482,1.485,1.487,1.49,1.492,1.495,1.497,1.499,1.501,1.503, + 1.505,1.507,1.509,1.511,1.513,1.515,1.517,1.519,1.52,1.522, + 1.524,1.525,1.527,1.528,1.53,1.531,1.533,1.534,1.535,1.537, + 1.538,1.539,1.541,1.542,1.543,1.545,1.546,1.547,1.548,1.549, + 1.551,1.552,1.553,1.554,1.555,1.556,1.558,1.559,1.56,1.561, + 1.562,1.563,1.565,1.566,1.567,1.568,1.569,1.57,1.571,1.573, + 1.574,1.575,1.576,1.577,1.579,1.58,1.581,1.582,1.584,1.585, + 1.586,1.588,1.589,1.59,1.592,1.593,1.594,1.596,1.597,1.599, + 1.6,1.602,1.603,1.605,1.606,1.608,1.609,1.611,1.612,1.614, + 1.616,1.617,1.619,1.621,1.622,1.624,1.626,1.628,1.63,1.631, + 1.633,1.635,1.637,1.639,1.641,1.643,1.645,1.647,1.649,1.651, + 1.653,1.655,1.657,1.659,1.661,1.664,1.666,1.668,1.67,1.673, + 1.675,1.677,1.679,1.682,1.684,1.686,1.689,1.691,1.694,1.696, + 1.699,1.701,1.704,1.706,1.709,1.711,1.714,1.716,1.719,1.722, + 1.724,1.727,1.729,1.732,1.735,1.738,1.74,1.743,1.746,1.749, +]; + +/// p9b(170) from pfni.f +pub const PFNI_P9B: [f64; 170] = [ + 1.699,1.701,1.704,1.706,1.709,1.711,1.714,1.716,1.719,1.722, + 1.724,1.727,1.729,1.732,1.735,1.738,1.74,1.743,1.746,1.749, + 1.751,1.754,1.757,1.76,1.763,1.765,1.768,1.771,1.774,1.777, + 1.78,1.783,1.786,1.789,1.792,1.795,1.798,1.801,1.804,1.807, + 1.81,1.813,1.816,1.819,1.822,1.825,1.828,1.831,1.834,1.837, + 1.84,1.843,1.847,1.85,1.853,1.856,1.859,1.862,1.865,1.869, + 1.872,1.875,1.878,1.881,1.884,1.888,1.891,1.894,1.897,1.901, + 1.904,1.907,1.91,1.913,1.917,1.92,1.923,1.926,1.93,1.933, + 1.936,1.939,1.943,1.946,1.949,1.952,1.956,1.959,1.962,1.965, + 1.969,1.972,1.975,1.978,1.982,1.985,1.988,1.992,1.995,1.998, + 2.001,2.005,2.008,2.011,2.014,2.018,2.021,2.024,2.027,2.031, + 2.034,2.037,2.04,2.044,2.047,2.05,2.053,2.057,2.06,2.063, + 2.066,2.07,2.073,2.076,2.079,2.083,2.086,2.089,2.092,2.095, + 2.099,2.102,2.105,2.108,2.111,2.115,2.118,2.121,2.124,2.127, + 2.131,2.134,2.137,2.14,2.143,2.146,2.149,2.153,2.156,2.159, + 2.162,2.165,2.168,2.171,2.175,2.178,2.181,2.184,2.187,2.19, + 2.193,2.196,2.199,2.202,2.205,2.208,2.212,2.215,2.218,2.221, +]; + +/// xen (from pfni.f) +pub const PFNI_XEN: f64 = 2.302585093; + +/// xmil (from pfni.f) +pub const PFNI_XMIL: f64 = 0.001; + +// ========== prd.f ========== + +/// a21 (from prd.f) +pub const PRD_A21: f64 = 469900000.0; + +/// pi2 (from prd.f) +pub const PRD_PI2: f64 = 6.28318531; + +// ========== princ.f ========== + +/// nptr (from princ.f) +pub const PRINC_NPTR: f64 = 30.0; + +/// ccor (from princ.f) +pub const PRINC_CCOR: f64 = 0.09; + +// ========== prnt.f ========== + +/// ipop(4) from prnt.f +pub const PRNT_IPOP: [f64; 4] = [ + 98.0,99.0,100.0,115.0, +]; + +// ========== profil.f ========== + +/// pisq (from profil.f) +pub const PROFIL_PISQ: f64 = 1.77245385090551; + +// ========== radpre.f ========== + +/// xgrd0(10) from radpre.f +pub const RADPRE_XGRD0: [f64; 10] = [ + 0.1,0.3,0.5,0.7,0.9,0.92,0.94,0.96,0.98,0.99, +]; + +/// xgrd1(20) from radpre.f +pub const RADPRE_XGRD1: [f64; 20] = [ + 0.1,0.2,0.3,0.4,0.5,0.6,0.65,0.7,0.75,0.8, + 0.85,0.9,0.92,0.94,0.96,0.98,0.99,0.99,0.99,0.99, +]; + +/// xgrd2(20) from radpre.f +pub const RADPRE_XGRD2: [f64; 20] = [ + 0.1,0.2,0.3,0.4,0.45,0.5,0.55,0.6,0.65,0.7, + 0.75,0.8,0.84,0.87,0.9,0.93,0.95,0.97,0.98,0.99, +]; + +/// pgrd (from radpre.f) +pub const RADPRE_PGRD: f64 = 4.1916825e-10; + +// ========== ratsp1.f ========== + +/// pgrd (from ratsp1.f) +pub const RATSP1_PGRD: f64 = 4.1916825e-10; + +// ========== rayleigh.f ========== + +/// frray (from rayleigh.f) +pub const RAYLEIGH_FRRAY: f64 = 2463000000000000.0; + +/// frayhe (from rayleigh.f) +pub const RAYLEIGH_FRAYHE: f64 = 5150000000000000.0; + +/// frayh2 (from rayleigh.f) +pub const RAYLEIGH_FRAYH2: f64 = 2922000000000000.0; + +/// c18 (from rayleigh.f) +pub const RAYLEIGH_C18: f64 = 2.997925e+18; + +/// cr0 (from rayleigh.f) +pub const RAYLEIGH_CR0: f64 = 5.799e-13; + +/// cr1 (from rayleigh.f) +pub const RAYLEIGH_CR1: f64 = 1.422e-06; + +/// cr2 (from rayleigh.f) +pub const RAYLEIGH_CR2: f64 = 2.784; + +// ========== rdata.f ========== + +/// t15 (from rdata.f) +pub const RDATA_T15: f64 = 1e-15; + +// ========== rdatax.f ========== + +/// mtrx (from rdatax.f) +pub const RDATAX_MTRX: f64 = 1000.0; + +// ========== reiman.f ========== + +/// hev(30) from reiman.f +pub const REIMAN_HEV: [f64; 30] = [ + 130.0,160.0,190.0,210.0,240.0,270.0,300.0,330.0,360.0,390.0, + 420.0,450.0,480.0,510.0,540.0,570.0,600.0,630.0,660.0,690.0, + 720.0,750.0,780.0,810.0,840.0,870.0,900.0,930.0,960.0,990.0, +]; + +/// sig0(30, 2) from reiman.f +/// 已转换为 Rust 行优先格式 +pub const REIMAN_SIG0: [[f64; 2]; 30] = [ + [0.0,0.0], + [0.0,0.0], + [0.0,0.0], + [0.4422,0.0], + [0.3478,0.1981], + [0.2794,0.1584], + [0.2286,0.129], + [0.1899,0.1066], + [0.1598,0.08932], + [0.136,0.07567], + [0.1169,0.06475], + [0.1013,0.05589], + [0.08845,0.04862], + [0.07776,0.04259], + [0.06877,0.03754], + [0.06114,0.03329], + [0.05463,0.02966], + [0.04904,0.02656], + [0.04419,0.02388], + [0.03998,0.02157], + [0.03629,0.01954], + [0.03305,0.01777], + [0.03019,0.01621], + [0.02766,0.01484], + [0.0254,0.01362], + [0.02339,0.01253], + [0.02158,0.01155], + [0.01996,0.01067], + [0.0185,0.009888], + [0.01718,0.009179], +]; + +// ========== rhoeos.f ========== + +/// inirea (from rhoeos.f, 未知维度,共 1 个值) +pub const RHOEOS_INIREA: [f64; 1] = [ + 0.0, +]; + +// ========== rhsgen.f ========== + +/// xcon (from rhsgen.f) +pub const RHSGEN_XCON: f64 = 8.0935e-21; + +/// ycon (from rhsgen.f) +pub const RHSGEN_YCON: f64 = 1.68638e-10; + +// ========== rossop.f ========== + +/// a(5) from rossop.f +pub const ROSSOP_A: [f64; 5] = [ + 0.71044609,-0.2830385,0.57975839,-0.75751038,0.45026781, +]; + +// ========== rteang.f ========== + +/// nmu3 (from rteang.f) +pub const RTEANG_NMU3: f64 = 3.0; + +/// nmu5 (from rteang.f) +pub const RTEANG_NMU5: f64 = 5.0; + +/// zero (from rteang.f) +pub const RTEANG_ZERO: f64 = 0.0; + +// ========== rtecf0.f ========== + +/// xcon (from rtecf0.f) +pub const RTECF0_XCON: f64 = 8.0935e-21; + +/// ycon (from rtecf0.f) +pub const RTECF0_YCON: f64 = 1.68638e-10; + +// ========== rtecmu.f ========== + +/// xcon (from rtecmu.f) +pub const RTECMU_XCON: f64 = 8.0935e-21; + +/// ycon (from rtecmu.f) +pub const RTECMU_YCON: f64 = 1.68638e-10; + +/// mw (from rtecmu.f) +pub const RTECMU_MW: f64 = 3.0; + +/// nw (from rtecmu.f) +pub const RTECMU_NW: f64 = 3.0; + +/// zero (from rtecmu.f) +pub const RTECMU_ZERO: f64 = 0.0; + +// ========== rtedf2.f ========== + +/// three (from rtedf2.f) +pub const RTEDF2_THREE: f64 = 3.0; + +/// quart (from rtedf2.f) +pub const RTEDF2_QUART: f64 = 0.25; + +// ========== rtefe2.f ========== + +/// one (from rtefe2.f) +pub const RTEFE2_ONE: f64 = 1.0; + +// ========== rteint.f ========== + +/// mma (from rteint.f) +pub const RTEINT_MMA: f64 = 20.0; + +// ========== rtesol.f ========== + +/// one (from rtesol.f) +pub const RTESOL_ONE: f64 = 1.0; + +// ========== sabolf.f ========== + +/// uh (from sabolf.f) +pub const SABOLF_UH: f64 = 1.5; + +/// cmax (from sabolf.f) +pub const SABOLF_CMAX: f64 = 21540.0; + +/// ccon (from sabolf.f) +pub const SABOLF_CCON: f64 = 2.0706e-16; + +// ========== sbfch.f ========== + +/// partch(41) from sbfch.f +pub const SBFCH_PARTCH: [f64; 41] = [ + 203.741,249.643,299.341,353.477,412.607,477.237,547.817,624.786,708.543,799.463, + 897.912,1004.227,1118.738,1241.761,1373.588,1514.481,1664.677,1824.394,1993.801,2173.05, + 2362.234,2561.424,2770.674,2989.93,3219.204,3458.378,3707.355,3966.005,4234.155,4511.604, + 4798.135,5093.554,5397.593,5709.948,6030.401,6358.646,6694.379,7037.313,7387.147,7743.579, + 8106.313, +]; + +/// c1(150) from sbfch.f +pub const SBFCH_C1: [f64; 150] = [ + -38.0,-38.0,-38.0,-38.0,-38.0,-38.0,-38.0,-38.0,-38.0,-38.0, + -38.0,-38.0,-38.0,-38.0,-38.0,-32.727,-31.151,-30.133,-29.432,-28.925, + -28.547,-28.257,-28.03,-27.848,-27.701,-27.58,-27.479,-27.395,-27.322,-27.261, + -31.588,-30.011,-28.993,-28.29,-27.784,-27.405,-27.115,-26.887,-26.705,-26.558, + -26.437,-26.336,-26.251,-26.179,-26.117,-30.407,-28.83,-27.811,-27.108,-26.601, + -26.223,-25.932,-25.705,-25.523,-25.376,-25.255,-25.154,-25.069,-24.997,-24.935, + -29.513,-27.937,-26.92,-26.218,-25.712,-25.334,-25.043,-24.816,-24.635,-24.487, + -24.366,-24.266,-24.181,-24.109,-24.047,-28.91,-27.341,-26.327,-25.628,-25.123, + -24.746,-24.457,-24.23,-24.049,-23.902,-23.782,-23.681,-23.597,-23.525,-23.464, + -28.517,-26.961,-25.955,-25.261,-24.76,-24.385,-24.098,-23.873,-23.694,-23.548, + -23.429,-23.329,-23.245,-23.174,-23.113,-28.213,-26.675,-25.68,-24.993,-24.497, + -24.127,-23.843,-23.62,-23.443,-23.299,-23.181,-23.082,-22.999,-22.929,-22.869, + -27.942,-26.427,-25.446,-24.769,-24.28,-23.915,-23.635,-23.416,-23.241,-23.1, + -22.983,-22.887,-22.805,-22.736,-22.677,-27.706,-26.21,-25.241,-24.572,-24.088, + -23.728,-23.451,-23.235,-23.063,-22.923,-22.808,-22.713,-22.633,-22.565,-22.507, +]; + +/// c2(150) from sbfch.f +pub const SBFCH_C2: [f64; 150] = [ + -27.475,-26.0,-25.043,-24.382,-23.905,-23.548,-23.275,-23.062,-22.891,-22.753, + -22.64,-22.546,-22.467,-22.4,-22.343,-27.221,-25.783,-24.844,-24.193,-23.723, + -23.372,-23.102,-22.892,-22.724,-22.588,-22.476,-22.384,-22.306,-22.24,-22.184, + -26.863,-25.506,-24.607,-23.979,-23.523,-23.182,-22.919,-22.714,-22.55,-22.417, + -22.309,-22.218,-22.142,-22.078,-22.023,-26.685,-25.347,-24.457,-23.835,-23.382, + -23.044,-22.784,-22.58,-22.418,-22.286,-22.178,-22.089,-22.014,-21.95,-21.896, + -26.085,-24.903,-24.105,-23.538,-23.12,-22.805,-22.561,-22.37,-22.217,-22.093, + -21.991,-21.906,-21.835,-21.775,-21.723,-25.902,-24.727,-23.936,-23.376,-22.964, + -22.654,-22.415,-22.227,-22.076,-21.955,-21.855,-21.772,-21.702,-21.644,-21.593, + -25.215,-24.196,-23.51,-23.019,-22.655,-22.378,-22.163,-21.992,-21.855,-21.744, + -21.653,-21.577,-21.513,-21.459,-21.412,-24.914,-23.937,-23.284,-22.82,-22.475, + -22.212,-22.007,-21.845,-21.715,-21.609,-21.522,-21.449,-21.388,-21.336,-21.292, + -24.519,-23.637,-23.039,-22.606,-22.281,-22.03,-21.834,-21.678,-21.552,-21.45, + -21.365,-21.295,-21.236,-21.185,-21.142,-24.086,-23.222,-22.65,-22.246,-21.948, + -21.722,-21.546,-21.407,-21.296,-21.205,-21.131,-21.07,-21.018,-20.974,-20.937, +]; + +/// c3(150) from sbfch.f +pub const SBFCH_C3: [f64; 150] = [ + -23.85,-23.018,-22.472,-22.088,-21.805,-21.59,-21.422,-21.289,-21.182,-21.095, + -21.024,-20.964,-20.914,-20.872,-20.835,-23.136,-22.445,-21.994,-21.676,-21.44, + -21.259,-21.117,-21.004,-20.912,-20.837,-20.775,-20.723,-20.679,-20.642,-20.611, + -23.199,-22.433,-21.927,-21.573,-21.314,-21.119,-20.969,-20.851,-20.758,-20.682, + -20.621,-20.571,-20.529,-20.493,-20.463,-22.696,-22.02,-21.585,-21.286,-21.071, + -20.912,-20.791,-20.697,-20.622,-20.563,-20.514,-20.475,-20.442,-20.414,-20.391, + -22.119,-21.557,-21.194,-20.943,-20.761,-20.624,-20.518,-20.434,-20.367,-20.313, + -20.268,-20.231,-20.201,-20.175,-20.153,-21.855,-21.3,-20.931,-20.673,-20.485, + -20.344,-20.235,-20.151,-20.084,-20.031,-19.988,-19.953,-19.924,-19.9,-19.88, + -21.126,-20.673,-20.382,-20.184,-20.044,-19.943,-19.868,-19.811,-19.769,-19.736, + -19.71,-19.69,-19.674,-19.662,-19.652,-20.502,-20.15,-19.922,-19.766,-19.657, + -19.578,-19.52,-19.478,-19.446,-19.422,-19.404,-19.39,-19.379,-19.371,-19.365, + -20.03,-19.724,-19.53,-19.399,-19.309,-19.245,-19.199,-19.166,-19.142,-19.125, + -19.112,-19.103,-19.096,-19.091,-19.088,-19.64,-19.364,-19.189,-19.074,-18.996, + -18.943,-18.906,-18.881,-18.863,-18.852,-18.844,-18.839,-18.837,-18.836,-18.836, +]; + +/// c4(150) from sbfch.f +pub const SBFCH_C4: [f64; 150] = [ + -19.333,-19.092,-18.939,-18.838,-18.77,-18.725,-18.695,-18.675,-18.662,-18.655, + -18.651,-18.649,-18.649,-18.651,-18.653,-19.07,-18.88,-18.756,-18.674,-18.621, + -18.585,-18.562,-18.548,-18.54,-18.536,-18.536,-18.537,-18.539,-18.542,-18.546, + -18.851,-18.708,-18.617,-18.558,-18.521,-18.498,-18.484,-18.477,-18.475,-18.476, + -18.478,-18.482,-18.487,-18.493,-18.498,-18.709,-18.599,-18.533,-18.494,-18.471, + -18.459,-18.454,-18.454,-18.457,-18.462,-18.469,-18.476,-18.483,-18.49,-18.498, + -18.656,-18.572,-18.524,-18.497,-18.485,-18.48,-18.482,-18.486,-18.493,-18.501, + -18.51,-18.519,-18.527,-18.536,-18.544,-18.67,-18.613,-18.582,-18.566,-18.561, + -18.562,-18.568,-18.575,-18.583,-18.592,-18.601,-18.61,-18.619,-18.627,-18.635, + -18.728,-18.7,-18.687,-18.683,-18.685,-18.691,-18.698,-18.706,-18.715,-18.723, + -18.731,-18.739,-18.745,-18.752,-18.758,-18.839,-18.835,-18.836,-18.842,-18.849, + -18.857,-18.865,-18.872,-18.878,-18.883,-18.888,-18.892,-18.895,-18.898,-18.9, + -19.034,-19.041,-19.049,-19.057,-19.064,-19.069,-19.071,-19.071,-19.07,-19.068, + -19.065,-19.061,-19.058,-19.054,-19.051,-19.372,-19.378,-19.382,-19.38,-19.372, + -19.359,-19.341,-19.321,-19.3,-19.28,-19.261,-19.243,-19.227,-19.212,-19.199, +]; + +/// c5(150) from sbfch.f +pub const SBFCH_C5: [f64; 150] = [ + -19.78,-19.777,-19.763,-19.732,-19.686,-19.631,-19.573,-19.517,-19.465,-19.419, + -19.379,-19.344,-19.314,-19.288,-19.265,-20.151,-20.133,-20.087,-20.009,-19.911, + -19.81,-19.715,-19.631,-19.559,-19.497,-19.446,-19.402,-19.365,-19.333,-19.306, + -20.525,-20.454,-20.312,-20.138,-19.97,-19.825,-19.705,-19.607,-19.528,-19.464, + -19.411,-19.367,-19.33,-19.3,-19.274,-20.869,-20.655,-20.366,-20.104,-19.894, + -19.731,-19.604,-19.505,-19.426,-19.363,-19.312,-19.271,-19.236,-19.208,-19.184, + -21.179,-20.768,-20.38,-20.081,-19.856,-19.686,-19.556,-19.454,-19.375,-19.311, + -19.26,-19.218,-19.184,-19.155,-19.131,-21.167,-20.601,-20.206,-19.925,-19.719, + -19.565,-19.447,-19.355,-19.283,-19.226,-19.18,-19.143,-19.112,-19.087,-19.066, + -20.918,-20.348,-19.976,-19.72,-19.536,-19.401,-19.299,-19.22,-19.159,-19.112, + -19.073,-19.043,-19.018,-18.998,-18.981,-20.753,-20.204,-19.847,-19.602,-19.427, + -19.299,-19.203,-19.129,-19.072,-19.028,-18.993,-18.965,-18.942,-18.924,-18.909, + -20.456,-19.987,-19.677,-19.46,-19.302,-19.186,-19.098,-19.03,-18.978,-18.937, + -18.904,-18.878,-18.857,-18.841,-18.827,-20.154,-19.734,-19.461,-19.272,-19.136, + -19.035,-18.96,-18.902,-18.858,-18.824,-18.797,-18.775,-18.759,-18.745,-18.735, +]; + +/// c6(150) from sbfch.f +pub const SBFCH_C6: [f64; 150] = [ + -19.941,-19.544,-19.288,-19.114,-18.992,-18.903,-18.837,-18.788,-18.751,-18.723, + -18.701,-18.684,-18.671,-18.661,-18.654,-19.657,-19.321,-19.104,-18.956,-18.853, + -18.779,-18.724,-18.684,-18.655,-18.632,-18.615,-18.602,-18.592,-18.585,-18.579, + -19.388,-19.109,-18.93,-18.81,-18.725,-18.664,-18.62,-18.586,-18.562,-18.543, + -18.529,-18.518,-18.51,-18.503,-18.498,-19.201,-18.953,-18.794,-18.686,-18.611, + -18.556,-18.515,-18.485,-18.462,-18.446,-18.433,-18.423,-18.416,-18.41,-18.406, + -18.923,-18.719,-18.588,-18.5,-18.439,-18.396,-18.365,-18.344,-18.328,-18.318, + -18.311,-18.307,-18.304,-18.303,-18.302,-18.614,-18.458,-18.361,-18.298,-18.258, + -18.232,-18.216,-18.206,-18.202,-18.201,-18.202,-18.205,-18.208,-18.213,-18.218, + -18.419,-18.295,-18.222,-18.178,-18.153,-18.139,-18.132,-18.131,-18.133,-18.138, + -18.143,-18.15,-18.157,-18.164,-18.172,-18.296,-18.201,-18.148,-18.118,-18.101, + -18.094,-18.091,-18.093,-18.096,-18.101,-18.107,-18.113,-18.12,-18.126,-18.132, + -18.021,-17.992,-17.977,-17.97,-17.967,-17.968,-17.97,-17.974,-17.978,-17.983, + -17.989,-17.994,-18.0,-18.005,-18.011,-17.694,-17.686,-17.686,-17.691,-17.698, + -17.708,-17.718,-17.729,-17.74,-17.75,-17.761,-17.771,-17.781,-17.79,-17.798, +]; + +/// c7(150) from sbfch.f +pub const SBFCH_C7: [f64; 150] = [ + -17.374,-17.384,-17.4,-17.42,-17.44,-17.462,-17.483,-17.503,-17.523,-17.541, + -17.558,-17.575,-17.59,-17.603,-17.616,-17.169,-17.199,-17.23,-17.262,-17.293, + -17.323,-17.351,-17.378,-17.404,-17.427,-17.449,-17.469,-17.488,-17.505,-17.52, + -17.151,-17.184,-17.217,-17.25,-17.282,-17.313,-17.342,-17.369,-17.395,-17.418, + -17.44,-17.461,-17.48,-17.497,-17.513,-17.23,-17.26,-17.29,-17.32,-17.348, + -17.375,-17.401,-17.425,-17.448,-17.469,-17.489,-17.508,-17.525,-17.541,-17.556, + -17.379,-17.403,-17.425,-17.446,-17.467,-17.486,-17.505,-17.524,-17.541,-17.558, + -17.574,-17.588,-17.602,-17.615,-17.627,-17.596,-17.604,-17.609,-17.612,-17.616, + -17.622,-17.628,-17.636,-17.644,-17.652,-17.661,-17.67,-17.679,-17.687,-17.695, + -17.846,-17.823,-17.795,-17.77,-17.75,-17.735,-17.725,-17.719,-17.716,-17.715, + -17.716,-17.719,-17.722,-17.726,-17.73,-18.089,-18.015,-17.942,-17.882,-17.836, + -17.802,-17.777,-17.76,-17.748,-17.74,-17.736,-17.734,-17.733,-17.734,-17.736, + -18.299,-18.156,-18.038,-17.947,-17.881,-17.833,-17.798,-17.774,-17.757,-17.745, + -17.738,-17.733,-17.73,-17.729,-17.729,-18.441,-18.243,-18.096,-17.991,-17.915, + -17.86,-17.821,-17.792,-17.772,-17.757,-17.746,-17.738,-17.733,-17.73,-17.728, +]; + +/// c8(150) from sbfch.f +pub const SBFCH_C8: [f64; 150] = [ + -18.474,-18.262,-18.111,-18.004,-17.926,-17.869,-17.826,-17.795,-17.771,-17.753, + -17.74,-17.73,-17.722,-17.717,-17.713,-18.387,-18.191,-18.053,-17.952,-17.878, + -17.823,-17.782,-17.752,-17.729,-17.711,-17.698,-17.689,-17.681,-17.676,-17.672, + -18.161,-17.99,-17.874,-17.793,-17.736,-17.696,-17.668,-17.648,-17.634,-17.625, + -17.619,-17.616,-17.614,-17.614,-17.615,-17.908,-17.774,-17.69,-17.637,-17.604, + -17.583,-17.572,-17.567,-17.566,-17.568,-17.571,-17.576,-17.581,-17.587,-17.593, + -17.681,-17.589,-17.54,-17.515,-17.506,-17.505,-17.511,-17.52,-17.53,-17.542, + -17.554,-17.566,-17.578,-17.589,-17.6,-17.647,-17.606,-17.584,-17.575,-17.573, + -17.576,-17.582,-17.589,-17.597,-17.605,-17.614,-17.623,-17.631,-17.639,-17.646, + -17.3,-17.291,-17.291,-17.297,-17.307,-17.319,-17.333,-17.347,-17.361,-17.375, + -17.389,-17.402,-17.415,-17.427,-17.438,-16.786,-16.802,-16.825,-16.853,-16.883, + -16.914,-16.944,-16.974,-17.003,-17.03,-17.055,-17.079,-17.101,-17.122,-17.141, + -16.489,-16.533,-16.579,-16.625,-16.67,-16.713,-16.754,-16.793,-16.83,-16.864, + -16.896,-16.925,-16.952,-16.977,-17.0,-16.694,-16.724,-16.756,-16.789,-16.823, + -16.856,-16.888,-16.919,-16.949,-16.976,-17.002,-17.026,-17.048,-17.069,-17.088, +]; + +/// c9(150) from sbfch.f +pub const SBFCH_C9: [f64; 150] = [ + -16.935,-16.951,-16.971,-16.993,-17.016,-17.04,-17.064,-17.088,-17.111,-17.132, + -17.153,-17.172,-17.19,-17.206,-17.222,-17.2,-17.208,-17.22,-17.235,-17.251, + -17.269,-17.286,-17.304,-17.322,-17.338,-17.354,-17.369,-17.384,-17.397,-17.409, + -17.597,-17.591,-17.589,-17.59,-17.594,-17.6,-17.608,-17.617,-17.626,-17.635, + -17.645,-17.654,-17.662,-17.671,-17.679,-18.166,-18.134,-18.107,-18.085,-18.068, + -18.056,-18.047,-18.041,-18.038,-18.036,-18.035,-18.035,-18.036,-18.038,-18.039, + -19.0,-18.917,-18.838,-18.77,-18.714,-18.669,-18.632,-18.603,-18.579,-18.56, + -18.545,-18.532,-18.522,-18.514,-18.507,-20.313,-19.982,-19.754,-19.592,-19.472, + -19.38,-19.309,-19.253,-19.208,-19.172,-19.143,-19.119,-19.099,-19.083,-19.069, + -19.751,-19.611,-19.52,-19.461,-19.423,-19.398,-19.382,-19.372,-19.366,-19.364, + -19.363,-19.364,-19.366,-19.368,-19.371,-19.581,-19.431,-19.337,-19.277,-19.24, + -19.218,-19.207,-19.202,-19.203,-19.207,-19.212,-19.22,-19.228,-19.236,-19.245, + -19.685,-19.506,-19.389,-19.311,-19.258,-19.222,-19.199,-19.184,-19.175,-19.17, + -19.168,-19.169,-19.171,-19.174,-19.177,-19.977,-19.756,-19.606,-19.501,-19.425, + -19.37,-19.33,-19.3,-19.278,-19.262,-19.25,-19.241,-19.235,-19.23,-19.227, +]; + +/// c10(150) from sbfch.f +pub const SBFCH_C10: [f64; 150] = [ + -20.445,-20.158,-19.958,-19.815,-19.711,-19.633,-19.574,-19.528,-19.493,-19.465, + -19.442,-19.425,-19.41,-19.398,-19.389,-20.98,-20.625,-20.391,-20.229,-20.11, + -20.02,-19.949,-19.892,-19.846,-19.807,-19.775,-19.748,-19.724,-19.704,-19.687, + -21.404,-21.023,-20.771,-20.594,-20.461,-20.358,-20.274,-20.205,-20.148,-20.099, + -20.058,-20.022,-19.991,-19.965,-19.942,-21.309,-20.97,-20.753,-20.603,-20.495, + -20.412,-20.348,-20.295,-20.252,-20.215,-20.185,-20.158,-20.135,-20.115,-20.098, + -21.221,-20.906,-20.707,-20.574,-20.48,-20.412,-20.361,-20.322,-20.292,-20.268, + -20.249,-20.233,-20.221,-20.21,-20.201,-21.441,-21.097,-20.878,-20.728,-20.623, + -20.546,-20.489,-20.446,-20.413,-20.387,-20.368,-20.352,-20.34,-20.33,-20.322, + -21.668,-21.305,-21.071,-20.911,-20.797,-20.713,-20.65,-20.602,-20.565,-20.536, + -20.514,-20.496,-20.481,-20.47,-20.46,-21.926,-21.556,-21.316,-21.15,-21.031, + -20.942,-20.874,-20.822,-20.782,-20.75,-20.724,-20.704,-20.687,-20.674,-20.663, + -22.319,-21.937,-21.686,-21.51,-21.38,-21.282,-21.206,-21.147,-21.099,-21.061, + -21.031,-21.006,-20.985,-20.968,-20.954,-22.969,-22.561,-22.288,-22.092,-21.945, + -21.832,-21.743,-21.672,-21.616,-21.57,-21.533,-21.503,-21.477,-21.457,-21.439, +]; + +/// c11(75) from sbfch.f +pub const SBFCH_C11: [f64; 75] = [ + -24.001,-23.527,-23.199,-22.957,-22.772,-22.629,-22.516,-22.427,-22.355,-22.297, + -22.25,-22.212,-22.18,-22.153,-22.131,-24.233,-23.774,-23.477,-23.273,-23.128, + -23.022,-22.943,-22.883,-22.837,-22.802,-22.774,-22.752,-22.735,-22.721,-22.71, + -24.55,-23.913,-23.521,-23.266,-23.094,-22.976,-22.893,-22.836,-22.796,-22.768, + -22.75,-22.737,-22.73,-22.726,-22.725,-24.301,-23.665,-23.274,-23.019,-22.848, + -22.73,-22.648,-22.591,-22.552,-22.525,-22.507,-22.495,-22.489,-22.485,-22.485, + -24.519,-23.883,-23.491,-23.237,-23.065,-22.948,-22.866,-22.809,-22.77,-22.743, + -22.724,-22.713,-22.706,-22.703,-22.702, +]; + +/// freq1 (from sbfch.f, 未知维度,共 1 个值) +pub const SBFCH_FREQ1: [f64; 1] = [ + 0.0, +]; + +/// fihu (from sbfch.f) +pub const SBFCH_FIHU: f64 = 500.0; + +/// twhu (from sbfch.f) +pub const SBFCH_TWHU: f64 = 200.0; + +/// tenl (from sbfch.f) +pub const SBFCH_TENL: f64 = 2.30258509299405; + +// ========== sbfhmi.f ========== + +/// wbf(85) from sbfhmi.f +pub const SBFHMI_WBF: [f64; 85] = [ + 18.0,19.6,21.4,23.6,26.4,29.8,34.3,40.4,49.1,62.6, + 111.3,112.1,112.67,112.95,113.05,113.1,113.2,113.23,113.5,114.4, + 121.0,139.0,164.0,175.0,200.0,225.0,250.0,275.0,300.0,325.0, + 350.0,375.0,400.0,425.0,450.0,475.0,500.0,525.0,550.0,575.0, + 600.0,625.0,650.0,675.0,700.0,725.0,750.0,775.0,800.0,825.0, + 850.0,875.0,900.0,925.0,950.0,975.0,1000.0,1025.0,1050.0,1075.0, + 1100.0,1125.0,1150.0,1175.0,1200.0,1225.0,1250.0,1275.0,1300.0,1325.0, + 1350.0,1375.0,1400.0,1425.0,1450.0,1475.0,1500.0,1525.0,1550.0,1575.0, + 1600.0,1610.0,1620.0,1630.0,1643.91, +]; + +/// bf(85) from sbfhmi.f +pub const SBFHMI_BF: [f64; 85] = [ + 0.067,0.088,0.117,0.155,0.206,0.283,0.414,0.703,1.24,2.33, + 11.6,13.9,24.3,66.7,95.0,56.6,20.0,14.6,8.5,7.1, + 5.43,5.91,7.29,7.918,9.453,11.08,12.75,14.46,16.19,17.92, + 19.65,21.35,23.02,24.65,26.24,27.77,29.23,30.62,31.94,33.17, + 34.32,35.37,36.32,37.17,37.91,38.54,39.07,39.48,39.77,39.95, + 40.01,39.95,39.77,39.48,39.06,38.53,37.89,37.13,36.25,35.28, + 34.19,33.01,31.72,30.34,28.87,27.33,25.71,24.02,22.26,20.46, + 18.62,16.74,14.85,12.95,11.07,9.211,7.407,5.677,4.052,2.575, + 1.302,0.8697,0.4974,0.1989,0.0, +]; + +// ========== sbfhmi_old.f ========== + +/// un (from sbfhmi_old.f) +pub const SBFHMI_O_UN: f64 = 1.0; + +// ========== sbfoh.f ========== + +/// partoh(41) from sbfoh.f +pub const SBFOH_PARTOH: [f64; 41] = [ + 145.979,178.033,211.618,247.053,284.584,324.398,366.639,411.425,458.854,509.012, + 561.976,617.823,676.626,738.448,803.363,871.437,942.735,1017.33,1095.284,1176.654, + 1261.51,1349.898,1441.875,1537.483,1636.753,1739.733,1846.434,1956.883,2071.08,2189.029, + 2310.724,2436.155,2565.283,2698.103,2834.571,2974.627,3118.242,3265.366,3415.912,3569.837, + 3727.077, +]; + +/// c1(150) from sbfoh.f +pub const SBFOH_C1: [f64; 150] = [ + -30.855,-29.121,-27.976,-27.166,-26.566,-26.106,-25.742,-25.448,-25.207,-25.006, + -24.836,-24.691,-24.566,-24.457,-24.363,-30.494,-28.76,-27.615,-26.806,-26.206, + -25.745,-25.381,-25.088,-24.846,-24.645,-24.475,-24.33,-24.205,-24.097,-24.002, + -30.157,-28.425,-27.28,-26.472,-25.872,-25.411,-25.048,-24.754,-24.513,-24.312, + -24.142,-23.997,-23.872,-23.764,-23.669,-29.848,-28.117,-26.974,-26.165,-25.566, + -25.105,-24.742,-24.448,-24.207,-24.006,-23.836,-23.692,-23.567,-23.458,-23.364, + -29.567,-27.837,-26.693,-25.885,-25.286,-24.826,-24.462,-24.169,-23.928,-23.727, + -23.557,-23.412,-23.287,-23.179,-23.084,-29.307,-27.578,-26.436,-25.628,-25.029, + -24.569,-24.205,-23.912,-23.671,-23.47,-23.3,-23.155,-23.031,-22.922,-22.828, + -29.068,-27.341,-26.199,-25.391,-24.792,-24.332,-23.969,-23.676,-23.435,-23.234, + -23.064,-22.92,-22.795,-22.687,-22.592,-28.82,-27.115,-25.978,-25.172,-24.574, + -24.115,-23.752,-23.459,-23.218,-23.017,-22.848,-22.703,-22.579,-22.47,-22.376, + -28.54,-26.891,-25.768,-24.968,-24.372,-23.914,-23.552,-23.259,-23.019,-22.818, + -22.649,-22.504,-22.38,-22.272,-22.177,-28.275,-26.681,-25.574,-24.779,-24.186, + -23.729,-23.368,-23.076,-22.836,-22.636,-22.467,-22.322,-22.198,-22.09,-21.996, +]; + +/// c2(150) from sbfoh.f +pub const SBFOH_C2: [f64; 150] = [ + -27.993,-26.47,-25.388,-24.602,-24.014,-23.56,-23.2,-22.909,-22.669,-22.47, + -22.301,-22.157,-22.033,-21.925,-21.831,-27.698,-26.252,-25.204,-24.433,-23.851, + -23.401,-23.043,-22.754,-22.515,-22.316,-22.148,-22.005,-21.881,-21.773,-21.679, + -27.398,-26.026,-25.019,-24.267,-23.696,-23.251,-22.896,-22.609,-22.372,-22.174, + -22.007,-21.864,-21.741,-21.634,-21.54,-27.1,-25.791,-24.828,-24.102,-23.543, + -23.106,-22.756,-22.472,-22.238,-22.041,-21.875,-21.733,-21.611,-21.504,-21.411, + -26.807,-25.549,-24.631,-23.933,-23.391,-22.964,-22.621,-22.341,-22.109,-21.915, + -21.751,-21.61,-21.488,-21.383,-21.29,-26.531,-25.31,-24.431,-23.761,-23.238, + -22.823,-22.488,-22.214,-21.986,-21.795,-21.633,-21.494,-21.374,-21.269,-21.178, + -26.239,-25.066,-24.225,-23.585,-23.082,-22.681,-22.356,-22.089,-21.866,-21.679, + -21.52,-21.383,-21.265,-21.162,-21.072,-25.945,-24.824,-24.017,-23.405,-22.923, + -22.538,-22.223,-21.964,-21.748,-21.565,-21.41,-21.276,-21.16,-21.059,-20.97, + -25.663,-24.587,-23.81,-23.222,-22.761,-22.391,-22.088,-21.838,-21.629,-21.452, + -21.3,-21.17,-21.057,-20.958,-20.872,-25.372,-24.35,-23.603,-23.038,-22.596, + -22.241,-21.95,-21.71,-21.508,-21.337,-21.19,-21.064,-20.954,-20.858,-20.774, +]; + +/// c3(150) from sbfoh.f +pub const SBFOH_C3: [f64; 150] = [ + -25.076,-24.111,-23.396,-22.853,-22.429,-22.088,-21.809,-21.578,-21.384,-21.22, + -21.078,-20.957,-20.851,-20.758,-20.676,-24.779,-23.87,-23.189,-22.669,-22.261, + -21.934,-21.667,-21.445,-21.259,-21.101,-20.965,-20.848,-20.746,-20.656,-20.578, + -24.486,-23.629,-22.983,-22.486,-22.095,-21.781,-21.524,-21.311,-21.132,-20.98, + -20.85,-20.737,-20.639,-20.553,-20.478,-24.183,-23.382,-22.774,-22.302,-21.928, + -21.627,-21.381,-21.177,-21.005,-20.859,-20.734,-20.625,-20.531,-20.449,-20.376, + -23.867,-23.127,-22.561,-22.116,-21.761,-21.474,-21.238,-21.043,-20.878,-20.738, + -20.617,-20.513,-20.423,-20.344,-20.274,-23.538,-22.862,-22.34,-21.926,-21.592, + -21.32,-21.096,-20.909,-20.751,-20.617,-20.502,-20.402,-20.315,-20.239,-20.172, + -23.234,-22.604,-22.12,-21.734,-21.422,-21.166,-20.953,-20.776,-20.625,-20.497, + -20.387,-20.291,-20.208,-20.135,-20.071,-22.934,-22.347,-21.898,-21.541,-21.25, + -21.01,-20.811,-20.643,-20.5,-20.378,-20.273,-20.182,-20.102,-20.033,-19.971, + -22.637,-22.092,-21.676,-21.345,-21.075,-20.853,-20.666,-20.508,-20.374,-20.259, + -20.159,-20.073,-19.997,-19.931,-19.872,-22.337,-21.835,-21.452,-21.147,-20.899, + -20.693,-20.52,-20.373,-20.247,-20.139,-20.046,-19.964,-19.892,-19.83,-19.774, +]; + +/// c4(150) from sbfoh.f +pub const SBFOH_C4: [f64; 150] = [ + -22.049,-21.584,-21.23,-20.95,-20.721,-20.531,-20.372,-20.236,-20.119,-20.019, + -19.931,-19.855,-19.788,-19.729,-19.676,-21.768,-21.337,-21.011,-20.754,-20.544, + -20.37,-20.223,-20.098,-19.991,-19.898,-19.817,-19.746,-19.683,-19.628,-19.579, + -21.494,-21.096,-20.796,-20.559,-20.367,-20.208,-20.074,-19.96,-19.861,-19.776, + -19.701,-19.636,-19.578,-19.527,-19.482,-21.233,-20.861,-20.585,-20.368,-20.193, + -20.048,-19.926,-19.821,-19.732,-19.654,-19.586,-19.526,-19.473,-19.426,-19.384, + -20.983,-20.635,-20.38,-20.181,-20.021,-19.889,-19.778,-19.683,-19.602,-19.531, + -19.469,-19.415,-19.367,-19.324,-19.286,-20.743,-20.418,-20.182,-19.999,-19.853, + -19.733,-19.633,-19.547,-19.474,-19.41,-19.354,-19.305,-19.261,-19.223,-19.189, + -20.515,-20.21,-19.991,-19.824,-19.69,-19.581,-19.49,-19.413,-19.347,-19.29, + -19.24,-19.196,-19.157,-19.122,-19.092,-20.297,-20.011,-19.808,-19.654,-19.532, + -19.434,-19.352,-19.282,-19.223,-19.172,-19.127,-19.088,-19.054,-19.023,-18.996, + -20.09,-19.822,-19.633,-19.491,-19.381,-19.291,-19.218,-19.156,-19.103,-19.057, + -19.018,-18.983,-18.952,-18.925,-18.901,-19.893,-19.642,-19.467,-19.337,-19.236, + -19.155,-19.089,-19.034,-18.987,-18.946,-18.912,-18.881,-18.854,-18.831,-18.81, +]; + +/// c5(150) from sbfoh.f +pub const SBFOH_C5: [f64; 150] = [ + -19.705,-19.472,-19.309,-19.19,-19.098,-19.025,-18.966,-18.917,-18.876,-18.84, + -18.81,-18.783,-18.76,-18.739,-18.721,-19.527,-19.31,-19.161,-19.051,-18.968, + -18.903,-18.851,-18.807,-18.771,-18.74,-18.713,-18.69,-18.67,-18.653,-18.637, + -19.357,-19.159,-19.022,-18.922,-18.847,-18.789,-18.743,-18.704,-18.673,-18.646, + -18.623,-18.603,-18.586,-18.571,-18.558,-19.195,-19.016,-18.892,-18.803,-18.736, + -18.684,-18.643,-18.61,-18.583,-18.56,-18.54,-18.523,-18.509,-18.496,-18.485, + -19.042,-18.883,-18.772,-18.693,-18.634,-18.589,-18.553,-18.525,-18.501,-18.481, + -18.465,-18.451,-18.438,-18.428,-18.419,-18.894,-18.758,-18.662,-18.593,-18.542, + -18.503,-18.473,-18.448,-18.428,-18.412,-18.398,-18.386,-18.376,-18.367,-18.359, + -18.752,-18.639,-18.559,-18.501,-18.458,-18.426,-18.4,-18.38,-18.363,-18.35, + -18.338,-18.328,-18.32,-18.313,-18.306,-18.611,-18.523,-18.46,-18.415,-18.381, + -18.355,-18.334,-18.318,-18.304,-18.293,-18.284,-18.276,-18.269,-18.263,-18.258, + -18.471,-18.408,-18.362,-18.329,-18.304,-18.285,-18.269,-18.257,-18.247,-18.238, + -18.231,-18.224,-18.219,-18.214,-18.21,-18.33,-18.29,-18.261,-18.239,-18.223, + -18.211,-18.201,-18.192,-18.185,-18.179,-18.174,-18.169,-18.165,-18.162,-18.159, +]; + +/// c6(150) from sbfoh.f +pub const SBFOH_C6: [f64; 150] = [ + -18.19,-18.168,-18.154,-18.143,-18.135,-18.129,-18.124,-18.12,-18.116,-18.112, + -18.109,-18.106,-18.104,-18.102,-18.1,-18.055,-18.047,-18.043,-18.042,-18.04, + -18.039,-18.039,-18.038,-18.037,-18.036,-18.035,-18.034,-18.033,-18.033,-18.032, + -17.929,-17.931,-17.935,-17.939,-17.943,-17.946,-17.948,-17.95,-17.952,-17.953, + -17.955,-17.956,-17.957,-17.958,-17.959,-17.818,-17.826,-17.834,-17.842,-17.849, + -17.855,-17.86,-17.865,-17.869,-17.872,-17.875,-17.878,-17.881,-17.883,-17.886, + -17.724,-17.736,-17.747,-17.758,-17.767,-17.775,-17.782,-17.788,-17.793,-17.798, + -17.803,-17.807,-17.811,-17.815,-17.819,-17.651,-17.665,-17.678,-17.69,-17.701, + -17.71,-17.718,-17.725,-17.732,-17.738,-17.744,-17.749,-17.755,-17.76,-17.765, + -17.601,-17.615,-17.629,-17.642,-17.653,-17.663,-17.672,-17.68,-17.688,-17.695, + -17.701,-17.708,-17.714,-17.72,-17.726,-17.572,-17.587,-17.602,-17.614,-17.626, + -17.636,-17.645,-17.654,-17.662,-17.67,-17.677,-17.684,-17.691,-17.698,-17.704, + -17.565,-17.581,-17.595,-17.607,-17.619,-17.629,-17.638,-17.647,-17.656,-17.664, + -17.671,-17.679,-17.686,-17.693,-17.7,-17.58,-17.594,-17.608,-17.62,-17.63, + -17.64,-17.65,-17.658,-17.667,-17.675,-17.682,-17.69,-17.697,-17.704,-17.711, +]; + +/// c7(150) from sbfoh.f +pub const SBFOH_C7: [f64; 150] = [ + -17.613,-17.626,-17.639,-17.649,-17.659,-17.669,-17.677,-17.686,-17.694,-17.701, + -17.709,-17.716,-17.723,-17.73,-17.737,-17.663,-17.675,-17.685,-17.695,-17.703, + -17.711,-17.719,-17.727,-17.734,-17.741,-17.748,-17.755,-17.761,-17.768,-17.774, + -17.728,-17.737,-17.745,-17.752,-17.759,-17.766,-17.772,-17.778,-17.785,-17.791, + -17.797,-17.803,-17.808,-17.814,-17.82,-17.803,-17.809,-17.814,-17.818,-17.823, + -17.828,-17.832,-17.837,-17.842,-17.847,-17.852,-17.856,-17.861,-17.866,-17.871, + -17.884,-17.886,-17.888,-17.889,-17.891,-17.893,-17.896,-17.899,-17.902,-17.905, + -17.908,-17.912,-17.915,-17.919,-17.922,-17.966,-17.964,-17.961,-17.959,-17.958, + -17.958,-17.958,-17.959,-17.96,-17.961,-17.963,-17.964,-17.966,-17.968,-17.97, + -18.04,-18.034,-18.028,-18.023,-18.019,-18.016,-18.013,-18.012,-18.01,-18.01, + -18.009,-18.009,-18.009,-18.009,-18.01,-18.096,-18.087,-18.078,-18.071,-18.065, + -18.059,-18.055,-18.051,-18.047,-18.045,-18.042,-18.04,-18.039,-18.037,-18.036, + -18.125,-18.115,-18.105,-18.097,-18.089,-18.082,-18.076,-18.07,-18.065,-18.061, + -18.057,-18.053,-18.051,-18.048,-18.046,-18.12,-18.112,-18.103,-18.095,-18.087, + -18.079,-18.072,-18.066,-18.06,-18.055,-18.05,-18.046,-18.042,-18.039,-18.036, +]; + +/// c8(150) from sbfoh.f +pub const SBFOH_C8: [f64; 150] = [ + -18.083,-18.078,-18.071,-18.064,-18.057,-18.05,-18.044,-18.037,-18.032,-18.026, + -18.022,-18.017,-18.014,-18.01,-18.007,-18.025,-18.022,-18.017,-18.012,-18.006, + -18.0,-17.994,-17.989,-17.984,-17.979,-17.975,-17.971,-17.968,-17.965,-17.963, + -17.957,-17.955,-17.952,-17.948,-17.943,-17.938,-17.934,-17.929,-17.925,-17.922, + -17.918,-17.916,-17.913,-17.911,-17.91,-17.89,-17.889,-17.886,-17.882,-17.879, + -17.875,-17.871,-17.867,-17.864,-17.862,-17.86,-17.858,-17.857,-17.856,-17.855, + -17.831,-17.829,-17.826,-17.822,-17.819,-17.815,-17.812,-17.81,-17.807,-17.806, + -17.804,-17.803,-17.803,-17.803,-17.803,-17.786,-17.782,-17.777,-17.773,-17.769, + -17.766,-17.763,-17.761,-17.759,-17.758,-17.757,-17.757,-17.757,-17.758,-17.759, + -17.753,-17.747,-17.741,-17.735,-17.731,-17.727,-17.724,-17.722,-17.721,-17.72, + -17.72,-17.72,-17.721,-17.722,-17.724,-17.733,-17.724,-17.716,-17.709,-17.703, + -17.699,-17.696,-17.694,-17.693,-17.692,-17.692,-17.693,-17.694,-17.695,-17.697, + -17.723,-17.711,-17.7,-17.691,-17.685,-17.68,-17.676,-17.674,-17.673,-17.672, + -17.673,-17.673,-17.675,-17.676,-17.678,-17.718,-17.702,-17.689,-17.679,-17.672, + -17.667,-17.663,-17.66,-17.659,-17.659,-17.659,-17.66,-17.661,-17.663,-17.665, +]; + +/// c9(150) from sbfoh.f +pub const SBFOH_C9: [f64; 150] = [ + -17.713,-17.695,-17.681,-17.67,-17.662,-17.656,-17.653,-17.65,-17.649,-17.649, + -17.649,-17.65,-17.651,-17.653,-17.655,-17.705,-17.686,-17.671,-17.66,-17.652, + -17.647,-17.643,-17.641,-17.64,-17.64,-17.64,-17.641,-17.643,-17.645,-17.647, + -17.69,-17.671,-17.657,-17.647,-17.64,-17.635,-17.632,-17.63,-17.63,-17.63, + -17.631,-17.632,-17.634,-17.636,-17.639,-17.667,-17.649,-17.637,-17.629,-17.623, + -17.619,-17.618,-17.617,-17.617,-17.618,-17.619,-17.621,-17.623,-17.626,-17.628, + -17.635,-17.621,-17.611,-17.605,-17.601,-17.6,-17.599,-17.599,-17.601,-17.602, + -17.604,-17.607,-17.609,-17.612,-17.615,-17.596,-17.585,-17.579,-17.576,-17.575, + -17.575,-17.576,-17.578,-17.58,-17.582,-17.585,-17.588,-17.591,-17.595,-17.598, + -17.55,-17.544,-17.542,-17.542,-17.544,-17.546,-17.548,-17.552,-17.555,-17.558, + -17.562,-17.566,-17.57,-17.573,-17.577,-17.501,-17.5,-17.501,-17.504,-17.508, + -17.513,-17.517,-17.521,-17.526,-17.53,-17.535,-17.539,-17.544,-17.548,-17.553, + -17.449,-17.452,-17.457,-17.463,-17.47,-17.476,-17.482,-17.488,-17.493,-17.499, + -17.504,-17.509,-17.514,-17.519,-17.524,-17.396,-17.403,-17.412,-17.42,-17.429, + -17.437,-17.444,-17.451,-17.458,-17.464,-17.47,-17.476,-17.481,-17.487,-17.492, +]; + +/// c10(150) from sbfoh.f +pub const SBFOH_C10: [f64; 150] = [ + -17.344,-17.355,-17.366,-17.377,-17.387,-17.396,-17.405,-17.413,-17.42,-17.427, + -17.434,-17.44,-17.446,-17.452,-17.458,-17.295,-17.307,-17.321,-17.333,-17.345, + -17.355,-17.365,-17.373,-17.382,-17.389,-17.397,-17.404,-17.41,-17.417,-17.423, + -17.249,-17.264,-17.278,-17.292,-17.304,-17.316,-17.326,-17.335,-17.344,-17.352, + -17.36,-17.368,-17.375,-17.382,-17.389,-17.209,-17.225,-17.241,-17.255,-17.268, + -17.28,-17.291,-17.301,-17.31,-17.319,-17.327,-17.335,-17.343,-17.35,-17.357, + -17.177,-17.194,-17.21,-17.225,-17.239,-17.251,-17.262,-17.272,-17.282,-17.291, + -17.3,-17.308,-17.316,-17.324,-17.331,-17.154,-17.172,-17.189,-17.204,-17.218, + -17.23,-17.242,-17.252,-17.262,-17.272,-17.28,-17.289,-17.298,-17.306,-17.314, + -17.144,-17.162,-17.179,-17.194,-17.208,-17.22,-17.232,-17.242,-17.253,-17.262, + -17.271,-17.28,-17.289,-17.297,-17.306,-17.146,-17.164,-17.181,-17.196,-17.21, + -17.222,-17.234,-17.245,-17.255,-17.265,-17.274,-17.283,-17.292,-17.301,-17.309, + -17.163,-17.18,-17.197,-17.212,-17.225,-17.237,-17.249,-17.26,-17.27,-17.28, + -17.289,-17.298,-17.307,-17.316,-17.325,-17.193,-17.211,-17.227,-17.241,-17.254, + -17.266,-17.277,-17.288,-17.298,-17.308,-17.317,-17.327,-17.336,-17.345,-17.353, +]; + +/// c11(150) from sbfoh.f +pub const SBFOH_C11: [f64; 150] = [ + -17.239,-17.256,-17.271,-17.284,-17.297,-17.309,-17.32,-17.33,-17.34,-17.35, + -17.359,-17.369,-17.378,-17.387,-17.395,-17.299,-17.315,-17.329,-17.342,-17.354, + -17.365,-17.376,-17.386,-17.396,-17.405,-17.415,-17.424,-17.433,-17.442,-17.451, + -17.373,-17.388,-17.402,-17.414,-17.425,-17.436,-17.446,-17.456,-17.466,-17.475, + -17.484,-17.493,-17.502,-17.511,-17.52,-17.462,-17.476,-17.489,-17.5,-17.511, + -17.521,-17.531,-17.541,-17.55,-17.559,-17.569,-17.578,-17.587,-17.595,-17.604, + -17.567,-17.581,-17.592,-17.603,-17.613,-17.623,-17.632,-17.641,-17.651,-17.66, + -17.669,-17.678,-17.686,-17.695,-17.704,-17.689,-17.701,-17.712,-17.722,-17.732, + -17.741,-17.75,-17.759,-17.768,-17.777,-17.786,-17.795,-17.803,-17.812,-17.821, + -17.829,-17.84,-17.851,-17.86,-17.869,-17.878,-17.887,-17.896,-17.904,-17.913, + -17.922,-17.93,-17.939,-17.948,-17.956,-17.988,-18.0,-18.01,-18.019,-18.028, + -18.036,-18.045,-18.053,-18.062,-18.07,-18.079,-18.087,-18.096,-18.104,-18.112, + -18.171,-18.183,-18.192,-18.201,-18.21,-18.218,-18.227,-18.235,-18.243,-18.252, + -18.26,-18.268,-18.277,-18.285,-18.293,-18.381,-18.393,-18.403,-18.413,-18.422, + -18.43,-18.438,-18.447,-18.455,-18.463,-18.471,-18.479,-18.487,-18.495,-18.503, +]; + +/// c12(150) from sbfoh.f +pub const SBFOH_C12: [f64; 150] = [ + -18.625,-18.638,-18.65,-18.66,-18.669,-18.678,-18.687,-18.695,-18.703,-18.711, + -18.719,-18.726,-18.734,-18.742,-18.75,-18.912,-18.929,-18.943,-18.955,-18.966, + -18.975,-18.984,-18.993,-19.001,-19.008,-19.016,-19.023,-19.031,-19.038,-19.045, + -19.26,-19.283,-19.303,-19.32,-19.333,-19.345,-19.355,-19.364,-19.372,-19.38, + -19.387,-19.394,-19.4,-19.407,-19.413,-19.704,-19.74,-19.771,-19.796,-19.816, + -19.832,-19.845,-19.855,-19.863,-19.87,-19.876,-19.882,-19.887,-19.892,-19.897, + -20.339,-20.386,-20.424,-20.454,-20.476,-20.492,-20.502,-20.509,-20.513,-20.516, + -20.518,-20.52,-20.521,-20.523,-20.524,-21.052,-21.075,-21.093,-21.105,-21.114, + -21.12,-21.123,-21.125,-21.126,-21.127,-21.128,-21.13,-21.131,-21.133,-21.135, + -21.174,-21.203,-21.23,-21.255,-21.278,-21.299,-21.32,-21.339,-21.357,-21.375, + -21.392,-21.408,-21.424,-21.439,-21.454,-21.285,-21.317,-21.346,-21.372,-21.395, + -21.416,-21.435,-21.452,-21.468,-21.483,-21.497,-21.511,-21.524,-21.536,-21.548, + -21.396,-21.429,-21.459,-21.486,-21.511,-21.532,-21.551,-21.569,-21.585,-21.6, + -21.614,-21.627,-21.64,-21.652,-21.663,-21.516,-21.549,-21.58,-21.609,-21.635, + -21.658,-21.678,-21.696,-21.713,-21.728,-21.742,-21.755,-21.767,-21.779,-21.79, +]; + +/// c13(150) from sbfoh.f +pub const SBFOH_C13: [f64; 150] = [ + -21.651,-21.681,-21.711,-21.738,-21.763,-21.785,-21.804,-21.821,-21.837,-21.851, + -21.864,-21.876,-21.887,-21.898,-21.908,-21.81,-21.831,-21.853,-21.874,-21.893, + -21.91,-21.925,-21.938,-21.95,-21.961,-21.971,-21.98,-21.989,-21.998,-22.006, + -22.009,-22.016,-22.026,-22.037,-22.048,-22.058,-22.066,-22.074,-22.081,-22.088, + -22.094,-22.099,-22.105,-22.111,-22.117,-22.353,-22.317,-22.296,-22.284,-22.276, + -22.27,-22.266,-22.262,-22.26,-22.258,-22.257,-22.257,-22.257,-22.258,-22.259, + -22.705,-22.609,-22.552,-22.515,-22.488,-22.468,-22.451,-22.438,-22.427,-22.418, + -22.41,-22.405,-22.4,-22.397,-22.395,-22.889,-22.791,-22.731,-22.69,-22.659, + -22.634,-22.612,-22.594,-22.579,-22.566,-22.555,-22.546,-22.539,-22.533,-22.528, + -23.211,-23.109,-23.041,-22.989,-22.945,-22.906,-22.872,-22.842,-22.816,-22.793, + -22.774,-22.757,-22.743,-22.732,-22.722,-25.312,-24.669,-24.25,-23.959,-23.746, + -23.587,-23.463,-23.366,-23.288,-23.225,-23.173,-23.131,-23.095,-23.066,-23.041, + -25.394,-24.752,-24.333,-24.041,-23.829,-23.669,-23.546,-23.449,-23.371,-23.308, + -23.256,-23.214,-23.178,-23.149,-23.124,-25.43,-24.787,-24.369,-24.077,-23.865, + -23.705,-23.582,-23.484,-23.407,-23.344,-23.292,-23.249,-23.214,-23.185,-23.16, +]; + +/// freq1 (from sbfoh.f, 未知维度,共 1 个值) +pub const SBFOH_FREQ1: [f64; 1] = [ + 0.0, +]; + +/// fihu (from sbfoh.f) +pub const SBFOH_FIHU: f64 = 500.0; + +/// twhu (from sbfoh.f) +pub const SBFOH_TWHU: f64 = 200.0; + +/// tenl (from sbfoh.f) +pub const SBFOH_TENL: f64 = 2.30258509299405; + +// ========== setdrt.f ========== + +/// ddtmin (from setdrt.f) +pub const SETDRT_DDTMIN: f64 = 0.0; + +/// ddtplu (from setdrt.f) +pub const SETDRT_DDTPLU: f64 = 0.001; + +// ========== settrm.f ========== + +/// rcon (from settrm.f) +pub const SETTRM_RCON: f64 = 83143400.0; + +// ========== sffhmi.f ========== + +/// ffbeg(11, 11) from sffhmi.f +/// 已转换为 Rust 行优先格式 +pub const SFFHMI_FFBEG: [[f64; 11]; 11] = [ + [0.0178,0.0228,0.0277,0.0364,0.052,0.0791,0.0965,0.121,0.154,0.208,0.293], + [0.0222,0.028,0.0342,0.0447,0.0633,0.0959,0.117,0.146,0.188,0.25,0.354], + [0.0308,0.0388,0.0476,0.0616,0.0859,0.129,0.157,0.195,0.249,0.332,0.468], + [0.0402,0.0499,0.0615,0.0789,0.108,0.161,0.195,0.241,0.309,0.409,0.576], + [0.0498,0.0614,0.076,0.0966,0.131,0.194,0.234,0.288,0.367,0.484,0.677], + [0.0596,0.0732,0.0908,0.114,0.154,0.227,0.272,0.334,0.424,0.557,0.777], + [0.0695,0.0851,0.105,0.132,0.178,0.26,0.311,0.381,0.482,0.63,0.874], + [0.0795,0.0972,0.121,0.15,0.201,0.293,0.351,0.428,0.539,0.702,0.969], + [0.0896,0.11,0.136,0.169,0.225,0.327,0.39,0.475,0.597,0.774,1.06], + [0.131,0.16,0.199,0.243,0.321,0.463,0.549,0.667,0.83,1.06,1.45], + [0.172,0.211,0.262,0.318,0.418,0.602,0.711,0.861,1.07,1.36,1.83], +]; + +/// ffend(11, 11) from sffhmi.f +/// 已转换为 Rust 行优先格式 +pub const SFFHMI_FFEND: [[f64; 11]; 11] = [ + [0.358,0.448,0.579,0.781,1.11,1.73,3.04,6.79,27.0,42.3,75.1], + [0.432,0.539,0.699,0.94,1.34,2.08,3.65,8.16,32.4,50.6,90.0], + [0.572,0.711,0.924,1.24,1.77,2.74,4.8,10.7,42.6,66.4,118.0], + [0.702,0.871,1.13,1.52,2.17,3.37,5.86,13.1,51.9,80.8,144.0], + [0.825,1.02,1.33,1.78,2.53,3.9,6.86,15.3,60.7,94.5,168.0], + [0.943,1.16,1.51,2.02,2.87,4.5,7.79,17.4,68.9,107.0,191.0], + [1.06,1.29,1.69,2.26,3.2,5.01,8.67,19.4,76.8,120.0,212.0], + [1.17,1.43,1.86,2.48,3.51,5.5,9.5,21.2,84.2,131.0,234.0], + [1.28,1.57,2.02,2.69,3.8,5.95,10.3,23.0,91.4,142.0,253.0], + [1.73,2.09,2.67,3.52,4.92,7.59,13.2,29.5,117.0,183.0,325.0], + [2.17,2.6,3.31,4.31,5.97,9.06,15.6,35.0,140.0,219.0,388.0], +]; + +/// thetaff(11) from sffhmi.f +pub const SFFHMI_THETAFF: [f64; 11] = [ + 0.5,0.6,0.8,1.0,1.2,1.4,1.6,1.8,2.0,2.8, + 3.6, +]; + +/// wavek(22) from sffhmi.f +pub const SFFHMI_WAVEK: [f64; 22] = [ + 0.5,0.4,0.35,0.3,0.25,0.2,0.18,0.16,0.14,0.12, + 0.1,0.09,0.08,0.07,0.06,0.05,0.04,0.03,0.02,0.01, + 0.008,0.006, +]; + +/// istart (from sffhmi.f, 未知维度,共 1 个值) +pub const SFFHMI_ISTART: [f64; 1] = [ + 0.0, +]; + +/// conth (from sffhmi.f) +pub const SFFHMI_CONTH: f64 = 5040.0; + +/// hk (from sffhmi.f) +pub const SFFHMI_HK: f64 = 4.79928144e-11; + +// ========== sffhmi_add.f ========== + +/// ffbeg(11, 11) from sffhmi_add.f +/// 已转换为 Rust 行优先格式 +pub const SFFHMI_A_FFBEG: [[f64; 11]; 11] = [ + [0.0178,0.0228,0.0277,0.0364,0.052,0.0791,0.0965,0.121,0.154,0.208,0.293], + [0.0222,0.028,0.0342,0.0447,0.0633,0.0959,0.117,0.146,0.188,0.25,0.354], + [0.0308,0.0388,0.0476,0.0616,0.0859,0.129,0.157,0.195,0.249,0.332,0.468], + [0.0402,0.0499,0.0615,0.0789,0.108,0.161,0.195,0.241,0.309,0.409,0.576], + [0.0498,0.0614,0.076,0.0966,0.131,0.194,0.234,0.288,0.367,0.484,0.677], + [0.0596,0.0732,0.0908,0.114,0.154,0.227,0.272,0.334,0.424,0.557,0.777], + [0.0695,0.0851,0.105,0.132,0.178,0.26,0.311,0.381,0.482,0.63,0.874], + [0.0795,0.0972,0.121,0.15,0.201,0.293,0.351,0.428,0.539,0.702,0.969], + [0.0896,0.11,0.136,0.169,0.225,0.327,0.39,0.475,0.597,0.774,1.06], + [0.131,0.16,0.199,0.243,0.321,0.463,0.549,0.667,0.83,1.06,1.45], + [0.172,0.211,0.262,0.318,0.418,0.602,0.711,0.861,1.07,1.36,1.83], +]; + +/// ffend(11, 11) from sffhmi_add.f +/// 已转换为 Rust 行优先格式 +pub const SFFHMI_A_FFEND: [[f64; 11]; 11] = [ + [0.358,0.448,0.579,0.781,1.11,1.73,3.04,6.79,27.0,42.3,75.1], + [0.432,0.539,0.699,0.94,1.34,2.08,3.65,8.16,32.4,50.6,90.0], + [0.572,0.711,0.924,1.24,1.77,2.74,4.8,10.7,42.6,66.4,118.0], + [0.702,0.871,1.13,1.52,2.17,3.37,5.86,13.1,51.9,80.8,144.0], + [0.825,1.02,1.33,1.78,2.53,3.9,6.86,15.3,60.7,94.5,168.0], + [0.943,1.16,1.51,2.02,2.87,4.5,7.79,17.4,68.9,107.0,191.0], + [1.06,1.29,1.69,2.26,3.2,5.01,8.67,19.4,76.8,120.0,212.0], + [1.17,1.43,1.86,2.48,3.51,5.5,9.5,21.2,84.2,131.0,234.0], + [1.28,1.57,2.02,2.69,3.8,5.95,10.3,23.0,91.4,142.0,253.0], + [1.73,2.09,2.67,3.52,4.92,7.59,13.2,29.5,117.0,183.0,325.0], + [2.17,2.6,3.31,4.31,5.97,9.06,15.6,35.0,140.0,219.0,388.0], +]; + +/// thetaff(11) from sffhmi_add.f +pub const SFFHMI_A_THETAFF: [f64; 11] = [ + 0.5,0.6,0.8,1.0,1.2,1.4,1.6,1.8,2.0,2.8, + 3.6, +]; + +/// wavek(22) from sffhmi_add.f +pub const SFFHMI_A_WAVEK: [f64; 22] = [ + 0.5,0.4,0.35,0.3,0.25,0.2,0.18,0.16,0.14,0.12, + 0.1,0.09,0.08,0.07,0.06,0.05,0.04,0.03,0.02,0.01, + 0.008,0.006, +]; + +/// istart (from sffhmi_add.f, 未知维度,共 1 个值) +pub const SFFHMI_A_ISTART: [f64; 1] = [ + 0.0, +]; + +/// conth (from sffhmi_add.f) +pub const SFFHMI_A_CONTH: f64 = 5040.0; + +/// hk (from sffhmi_add.f) +pub const SFFHMI_A_HK: f64 = 4.79928144e-11; + +// ========== sghe12.f ========== + +/// c1 (from sghe12.f) +pub const SGHE12_C1: f64 = 3.0; + +/// c2 (from sghe12.f) +pub const SGHE12_C2: f64 = 9.0; + +/// c3 (from sghe12.f) +pub const SGHE12_C3: f64 = 16.0; + +/// t15 (from sghe12.f) +pub const SGHE12_T15: f64 = 1e-15; + +/// a1 (from sghe12.f) +pub const SGHE12_A1: f64 = 6.45105e-18; + +/// a2 (from sghe12.f) +pub const SGHE12_A2: f64 = 3.02e-19; + +/// a3 (from sghe12.f) +pub const SGHE12_A3: f64 = 9.9847e-18; + +/// a4 (from sghe12.f) +pub const SGHE12_A4: f64 = 1.1763673e-17; + +/// a5 (from sghe12.f) +pub const SGHE12_A5: f64 = 3.63662e-19; + +/// a6 (from sghe12.f) +pub const SGHE12_A6: f64 = -278.3; + +/// a7 (from sghe12.f) +pub const SGHE12_A7: f64 = 14.88; + +/// a8 (from sghe12.f) +pub const SGHE12_A8: f64 = -0.2311; + +/// e1 (from sghe12.f) +pub const SGHE12_E1: f64 = 3.5; + +/// e2 (from sghe12.f) +pub const SGHE12_E2: f64 = 3.6; + +/// e3 (from sghe12.f) +pub const SGHE12_E3: f64 = 1.91; + +/// e4 (from sghe12.f) +pub const SGHE12_E4: f64 = 2.9; + +/// e5 (from sghe12.f) +pub const SGHE12_E5: f64 = 3.3; + +// ========== sgmer0.f ========== + +/// frh (from sgmer0.f) +pub const SGMER0_FRH: f64 = 3288050000000000.0; + +/// ehb (from sgmer0.f) +pub const SGMER0_EHB: f64 = 157802.77355; + +// ========== sigave.f ========== + +/// xife(8) from sigave.f +pub const SIGAVE_XIFE: [f64; 8] = [ + 63480.0,130563.0,247220.0,442000.0,605000.0,799000.0,1008000.0,1218380.0, +]; + +/// tx (from sigave.f) +pub const SIGAVE_TX: f64 = 2.30258509299405; + +/// bam (from sigave.f) +pub const SIGAVE_BAM: f64 = 1e-18; + +// ========== sigk.f ========== + +/// sih0 (from sigk.f) +pub const SIGK_SIH0: f64 = 2.815e+29; + +/// e10 (from sigk.f) +pub const SIGK_E10: f64 = 2.3025851; + +// ========== sigmar.f ========== + +/// zero (from sigmar.f) +pub const SIGMAR_ZERO: f64 = 0.0; + +/// one (from sigmar.f) +pub const SIGMAR_ONE: f64 = 1.0; + +/// tres (from sigmar.f) +pub const SIGMAR_TRES: f64 = 3.0; + +/// four (from sigmar.f) +pub const SIGMAR_FOUR: f64 = 4.0; + +/// fourth (from sigmar.f) +pub const SIGMAR_FOURTH: f64 = 0.25; + +/// eps (from sigmar.f) +pub const SIGMAR_EPS: f64 = 1e-05; + +/// c (from sigmar.f) +pub const SIGMAR_C: f64 = 29979000000.0; + +/// sigmab (from sigmar.f) +pub const SIGMAR_SIGMAB: f64 = 5.6703e-05; + +/// bk (from sigmar.f) +pub const SIGMAR_BK: f64 = 1.3807e-16; + +// ========== srtfrq.f ========== + +/// v0x (from srtfrq.f) +pub const SRTFRQ_V0X: f64 = 0.0004; + +// ========== stark0.f ========== + +/// fstark(10, 4) from stark0.f +/// 已转换为 Rust 行优先格式 +pub const STARK0_FSTARK: [[f64; 4]; 10] = [ + [0.1387,0.3921,0.6103,0.8163], + [0.0791,0.1193,0.1506,0.1788], + [0.02126,0.03766,0.04931,0.05985], + [0.01394,0.02209,0.02768,0.03189], + [0.00642,0.01139,0.01485,0.01762], + [0.004814,0.008036,0.01023,0.01196], + [0.002779,0.005007,0.006588,0.007825], + [0.002216,0.00385,0.004996,0.005882], + [0.001443,0.002658,0.003524,0.004233], + [0.001201,0.002151,0.002838,0.003375], +]; + +/// xkijt(5, 4) from stark0.f +/// 已转换为 Rust 行优先格式 +pub const STARK0_XKIJT: [[f64; 4]; 5] = [ + [0.000356,0.0125,0.124,0.683], + [0.000523,0.0177,0.171,0.866], + [0.00109,0.028,0.223,1.02], + [0.00149,0.0348,0.261,1.19], + [0.00225,0.0493,0.342,1.46], +]; + +/// ryd1 (from stark0.f) +pub const STARK0_RYD1: f64 = 911.763811; + +/// cxkij (from stark0.f) +pub const STARK0_CXKIJ: f64 = 5.5e-05; + +/// wi1 (from stark0.f) +pub const STARK0_WI1: f64 = 911.753578; + +/// wi2 (from stark0.f) +pub const STARK0_WI2: f64 = 227.837832; + +/// un (from stark0.f) +pub const STARK0_UN: f64 = 1.0; + +/// ten (from stark0.f) +pub const STARK0_TEN: f64 = 10.0; + +/// twen (from stark0.f) +pub const STARK0_TWEN: f64 = 20.0; + +/// hund (from stark0.f) +pub const STARK0_HUND: f64 = 100.0; + +// ========== starka.f ========== + +/// f0 (from starka.f) +pub const STARKA_F0: f64 = -0.5758228; + +/// f1 (from starka.f) +pub const STARKA_F1: f64 = 0.4796232; + +/// f2 (from starka.f) +pub const STARKA_F2: f64 = 0.07209481; + +/// al (from starka.f) +pub const STARKA_AL: f64 = 1.26; + +/// sd (from starka.f) +pub const STARKA_SD: f64 = 0.5641895; + +/// slo (from starka.f) +pub const STARKA_SLO: f64 = -2.5; + +/// thra (from starka.f) +pub const STARKA_THRA: f64 = 1.5; + +/// bl1 (from starka.f) +pub const STARKA_BL1: f64 = 1.14; + +/// bl2 (from starka.f) +pub const STARKA_BL2: f64 = 11.4; + +/// sac (from starka.f) +pub const STARKA_SAC: f64 = 0.08; + +// ========== state.f ========== + +/// d(3, 99) from state.f +/// 已转换为 Rust 行优先格式 +pub const STATE_D: [[f64; 99]; 3] = [ + [1.008,4.003,6.941,9.012,10.81,12.011,14.007,16.0,18.918,20.179,22.99,24.305,26.982,28.086,30.974,32.06,35.453,39.948,39.098,40.08,44.956,47.9,50.941,51.996,54.938,55.847,58.933,58.7,63.546,65.38,69.72,72.6,74.92,78.96,79.91,83.8,85.48,87.63,88.91,91.22,92.91,95.95,99.0,101.1,102.9,106.4,107.9,112.4,114.8,118.7,121.8,127.6,126.9,131.3,132.9,137.4,138.9,140.1,140.9,144.3,147.0,150.4,152.0,157.3,158.9,162.5,164.9,167.3,168.9,173.0,175.0,178.5,181.0,183.9,186.3,190.2,192.2,195.1,197.0,200.6,204.4,207.2,209.0,210.0,211.0,222.0,223.0,226.1,227.1,232.0,231.0,238.0,237.0,244.0,243.0,247.0,247.0,251.0,254.0], + [1.0,0.1,1.26e-11,2.51e-11,5e-10,0.000331,8.32e-05,0.000676,3.16e-08,0.00012,2.14e-06,3.8e-05,2.95e-06,3.55e-05,2.82e-07,2.14e-05,3.16e-07,2.52e-06,1.32e-07,2.29e-06,1.48e-09,1.05e-07,1e-08,4.68e-07,2.45e-07,3.16e-05,8.32e-08,1.78e-06,1.62e-08,3.98e-08,1.34896324e-09,4.26579633e-09,2.34422821e-10,2.23872066e-09,4.26579633e-10,1.69824373e-09,2.51188699e-10,8.51138173e-10,1.65958702e-10,4.07380181e-10,2.5118863e-11,9.12010923e-11,1e-24,6.60693531e-11,1.23026887e-11,5.01187291e-11,1.73780087e-11,5.75439927e-11,6.6069344e-12,1.3803846e-10,1.0964781e-11,1.73780087e-10,3.23593651e-11,1.69824373e-10,1.31825676e-11,1.62181025e-10,1.58489337e-11,4.07380293e-11,6.02559549e-12,2.95120943e-11,1e-24,9.33254366e-12,3.46736869e-12,1.1748977e-11,2.13796216e-12,1.41253747e-11,3.16227767e-12,8.91250917e-12,1.34896287e-12,8.91250917e-12,1.31825674e-12,5.37031822e-12,1.34896287e-12,4.78630102e-12,1.86208719e-12,2.3988329e-11,2.34422885e-11,4.78630036e-11,6.76082952e-12,1.23026887e-11,6.6069344e-12,1.12201834e-10,5.12861361e-12,1e-24,1e-24,1e-24,1e-24,1e-24,1e-24,1.20226443e-12,1e-24,3.23593651e-13,1e-24,1e-24,1e-24,1e-24,1e-24,1e-24,1e-24], + [2.0,3.0,3.0,3.0,4.0,5.0,5.0,5.0,4.0,4.0,4.0,4.0,4.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0,3.0], +]; + +/// xio(8, 99) from state.f +/// 已转换为 Rust 行优先格式 +pub const STATE_XIO: [[f64; 99]; 8] = [ + [13.595,24.58,5.392,9.322,8.296,11.264,14.53,13.614,17.418,21.559,5.138,7.664,5.984,8.151,10.484,10.357,12.97,15.755,4.339,6.111,6.56,6.83,6.74,6.763,7.432,7.87,7.86,7.635,7.726,9.394,6.0,7.89944,9.7887,9.75,11.839,13.995,4.175,5.692,6.2171,6.6339,6.879,7.099,7.28,7.364,7.46,8.329,7.574,8.99,5.784,7.342,8.639,9.0096,10.454,12.12984,3.893,5.21,5.58,5.65,5.419,5.49,5.55,5.629,5.68,6.159,5.849,5.93,6.02,6.099,6.18,6.25,6.099,7.0,7.879,7.86404,7.87,8.5,9.1,8.95868,9.22,10.43,6.10829,7.416684,7.285519,8.43,9.3,10.745,4.0,5.276,6.9,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0], + [0.0,54.4,75.619,18.206,25.149,24.376,29.593,35.108,34.98,41.07,47.29,15.03,18.823,16.35,19.72,23.4,23.8,27.62,31.81,11.87,12.89,13.63,14.2,16.49,15.64,16.183,17.06,18.168,20.292,17.964,20.509,15.93462,18.5892,21.5,21.6,24.559,27.5,11.026,12.2236,13.13,14.319,16.149,15.259,16.759,18.07,19.419,21.48,16.903,18.86,14.627,16.5,18.6,19.09,20.975,25.1,10.0,11.06,10.85,10.55,10.73,10.899,11.069,11.25,12.1,11.519,11.67,11.8,11.93,12.05,12.17,13.899,14.899,16.2,17.7,16.6,17.0,20.0,18.563,20.5,18.75,20.4283,15.0325,16.679,19.0,20.0,20.0,22.0,10.144,12.1,12.0,12.0,12.0,12.0,12.0,12.0,12.0,12.0,12.0,12.0], + [0.0,0.0,122.451,153.85,37.92,47.864,47.426,54.886,62.646,63.5,71.65,80.12,28.44,33.46,30.156,35.0,39.9,40.9,46.0,51.21,24.75,28.14,29.7,30.95,33.69,30.652,33.49,35.17,36.83,39.722,30.7,34.058,28.351,32.0,35.9,36.9,40.0,43.0,20.5244,23.17,25.039,27.149,30.0,28.46,31.049,32.92,34.819,37.47,28.029,30.49,25.299,27.96,32.0,31.05,35.0,37.0,19.169,20.08,23.2,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,23.7,20.0,19.0,23.299,24.0,25.0,26.0,27.0,28.0,33.227,30.0,34.2,29.852,31.9373,25.563,27.0,29.0,30.0,33.0,34.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0,20.0], + [0.0,0.0,0.0,217.713,259.298,64.476,77.45,77.394,87.14,97.02,98.88,102.29,119.96,45.14,51.354,47.29,53.5,59.79,60.9,67.7,73.9,43.24,48.0,49.6,53.0,54.8,51.3,54.9,55.2,59.4,99.99,45.715,99.99,99.99,99.99,99.99,99.99,99.99,60.607,34.418,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,72.3,44.2,37.4,99.99,45.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,50.72,42.33,45.32,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99], + [0.0,0.0,0.0,0.0,340.22,391.99,97.86,113.87,114.21,126.3,138.37,141.23,153.77,166.73,65.01,72.5,67.8,75.0,82.6,84.39,92.0,99.8,65.2,73.0,76.0,75.0,79.5,75.5,79.9,82.6,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,80.348,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,55.7,58.7,99.99,54.14,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,69.0,56.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99], + [0.0,0.0,0.0,0.0,0.0,489.98,551.93,138.08,157.12,157.91,172.09,186.49,190.42,205.11,220.41,88.03,96.7,91.3,99.7,109.0,111.1,120.0,128.9,90.6,97.0,99.1,102.0,108.0,103.0,108.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,88.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99], + [0.0,0.0,0.0,0.0,0.0,0.0,667.03,739.11,185.14,207.21,208.44,224.9,241.38,246.41,263.31,280.99,114.27,124.0,118.0,128.0,138.0,140.8,151.0,161.1,119.24,125.0,129.0,133.0,139.0,134.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,871.39,953.6,239.0,264.16,265.96,284.53,303.07,309.26,328.8,348.3,143.46,155.0,147.0,158.7,168.5,173.7,184.7,196.46,151.06,157.0,162.0,166.0,174.0,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99,99.99], +]; + +/// abun0(99) from state.f +pub const STATE_ABUN0: [f64; 99] = [ + 12.0,10.93,1.05,1.38,2.7,8.39,7.78,8.66,4.56,7.84, + 6.17,7.53,6.37,7.51,5.36,7.14,5.5,6.18,5.08,6.31, + 3.05,4.9,4.0,5.64,5.39,7.45,4.92,6.23,4.21,4.6, + 2.88,3.58,2.29,3.33,2.56,3.28,2.6,2.92,2.21,2.59, + 1.42,1.92,-9.99,1.84,1.12,1.69,0.94,1.77,1.6,2.0, + 1.0,2.19,1.51,2.27,1.07,2.17,1.13,1.58,0.71,1.45, + -9.99,1.01,0.52,1.12,0.28,1.14,0.51,0.93,0.0,1.08, + 0.06,0.88,-0.17,1.11,0.23,1.45,1.38,1.64,1.01,1.13, + 0.9,2.0,0.65,-9.99,-9.99,-9.99,-9.99,-9.99,9.99,0.06, + -9.99,-0.52,-9.99,-9.99,-9.99,-9.99,-9.99,-9.99,-9.99, +]; + +/// abun1(99) from state.f +pub const STATE_ABUN1: [f64; 99] = [ + 12.0,10.93,3.26,1.38,2.79,8.43,7.83,8.69,4.56,7.93, + 6.24,7.6,6.45,7.51,5.41,7.12,5.5,6.4,5.08,6.34, + 3.15,4.95,3.93,5.64,5.43,7.5,4.99,6.22,4.19,4.56, + 3.04,3.65,2.3,3.34,2.54,3.25,2.36,2.87,2.21,2.58, + 1.46,1.88,-9.99,1.75,1.06,1.65,1.2,1.71,0.76,2.04, + 1.01,2.18,1.55,2.24,1.08,2.18,1.1,1.58,0.72,1.42, + -9.99,0.96,0.52,1.07,0.3,1.1,0.48,0.92,0.1,0.92, + 0.1,0.85,-0.12,0.65,0.26,1.4,1.38,1.62,0.8,1.17, + 0.77,2.04,0.65,-9.99,-9.99,-9.99,-9.99,-9.99,-9.99,0.06, + -9.99,-0.54,-9.99,-9.99,-9.99,-9.99,-9.99,-9.99,-9.99, +]; + +/// xio2(9, 22) from state.f +/// 已转换为 Rust 行优先格式 +pub const STATE_XIO2: [[f64; 22]; 9] = [ + [1103.0,1196.0,300.0,328.0,330.0,351.0,372.0,379.0,400.0,422.0,176.0,188.0,180.0,193.0,206.0,209.0,222.0,235.0,186.0,193.0,199.0,203.0], + [0.0,1362.0,1465.0,367.0,398.0,401.0,424.0,447.0,456.0,479.0,503.0,211.0,225.0,216.0,230.0,244.0,248.0,262.0,276.0,224.0,232.0,238.0], + [0.0,0.0,1649.0,1762.0,442.0,476.0,480.0,505.0,529.0,539.0,564.0,591.0,250.0,265.0,255.0,271.0,286.0,290.0,305.0,321.0,266.0,274.0], + [0.0,0.0,0.0,1963.0,2085.0,523.0,560.0,565.0,592.0,618.0,629.0,656.0,686.0,291.0,308.0,298.0,314.0,331.0,336.0,352.0,369.0,311.0], + [0.0,0.0,0.0,0.0,2304.0,2438.0,612.0,652.0,657.0,686.0,714.0,726.0,755.0,787.0,336.0,355.0,344.0,361.0,379.0,384.0,401.0,420.0], + [0.0,0.0,0.0,0.0,0.0,2673.0,2816.0,707.0,750.0,756.0,787.0,817.0,830.0,861.0,896.0,384.0,404.0,392.0,411.0,430.0,435.0,454.0], + [0.0,0.0,0.0,0.0,0.0,0.0,3069.0,3223.0,809.0,854.0,862.0,895.0,926.0,940.0,974.0,1010.0,435.0,457.0,444.0,464.0,484.0,490.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,3494.0,3658.0,918.0,968.0,974.0,1010.0,1042.0,1060.0,1095.0,1136.0,490.0,512.0,499.0,520.0,542.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3946.0,4121.0,1034.0,1087.0,1094.0,1132.0,1165.0,1185.0,1222.0,1266.0,547.0,571.0,557.0,579.0], +]; + +/// xio3(9, 13) from state.f +/// 已转换为 Rust 行优先格式 +pub const STATE_XIO3: [[f64; 13]; 9] = [ + [4426.0,4611.0,1158.0,1206.0,1222.0,1261.0,1294.0,1318.0,1357.0,1396.0,606.0,628.0,616.0], + [0.0,4934.0,5129.0,1288.0,1346.0,1356.0,1397.0,1431.0,1459.0,1496.0,1538.0,670.0,693.0], + [0.0,0.0,5470.0,5675.0,1425.0,1480.0,1497.0,1540.0,1574.0,1603.0,1643.0,1688.0,737.0], + [0.0,0.0,0.0,6034.0,6249.0,1569.0,1627.0,1645.0,1689.0,1723.0,1756.0,1797.0,1844.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,1782.0,1799.0,1847.0,1880.0,1915.0,1958.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1958.0,1963.0,2011.0,2043.0,2082.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2346.0,2112.0,2133.0,2183.0,2214.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8828.0,0.0,2288.0,2310.0,2362.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9278.0,0.0,0.0,2472.0,2494.0], +]; + +/// idat(30) from state.f +pub const STATE_IDAT: [f64; 30] = [ + 1.0,2.0,0.0,0.0,0.0,3.0,4.0,5.0,0.0,6.0, + 7.0,8.0,9.0,10.0,0.0,11.0,0.0,12.0,0.0,13.0, + 0.0,0.0,0.0,14.0,15.0,16.0,0.0,17.0,0.0,0.0, +]; + +/// u10(10) from state.f +pub const STATE_U10: [f64; 10] = [ + 173.93,330.391,511.8,783.3,1018.0,1273.8,1671.792,1928.462,9645.005,10986.876, +]; + +/// u11(11) from state.f +pub const STATE_U11: [f64; 11] = [ + 41.449,381.395,577.8,797.8,1116.2,1388.5,1681.5,2130.8,2418.7,11817.061, + 13297.676, +]; + +/// u12(12) from state.f +pub const STATE_U12: [f64; 12] = [ + 61.671,121.268,646.41,881.1,1139.4,1504.3,1814.3,2144.7,2645.2,2964.4, + 14210.261,15829.951, +]; + +/// u13(13) from state.f +pub const STATE_U13: [f64; 13] = [ + 48.278,151.86,229.446,967.8,1239.8,1536.3,1947.3,2295.4,2663.4,3214.8, + 3565.6,16825.022,18584.138, +]; + +/// u14(14) from state.f +pub const STATE_U14: [f64; 14] = [ + 65.748,131.838,270.139,364.093,1345.1,1653.9,1988.4,2445.3,2831.9,3237.8, + 3839.8,4222.4,19661.693,21560.63, +]; + +/// u16(16) from state.f +pub const STATE_U16: [f64; 16] = [ + 83.558,188.2,280.9,381.541,586.2,710.184,2265.9,2647.4,3057.7,3606.1, + 4071.4,4554.3,5255.9,5703.6,26002.663,28182.535, +]; + +/// u18(18) from state.f +pub const STATE_U18: [f64; 18] = [ + 127.11,222.848,328.6,482.4,605.1,734.04,1002.73,1157.08,3407.3,3860.9, + 4347.0,4986.6,5533.8,6095.5,6894.2,7404.4,33237.173,35699.936, +]; + +/// u20(20) from state.f +pub const STATE_U20: [f64; 20] = [ + 49.306,95.752,410.642,542.6,681.6,877.4,1026.0,1187.6,1520.64,1704.047, + 4774.0,5301.0,5861.0,6595.0,7215.0,7860.0,8770.0,9338.0,41366.0,44177.41, +]; + +/// u24(24) from state.f +pub const STATE_U24: [f64; 24] = [ + 54.576,132.966,249.7,396.5,560.2,731.02,1291.9,1490.0,1688.0,1971.0, + 2184.0,2404.0,2862.0,3098.52,8151.0,8850.0,9560.0,10480.0,11260.0,12070.0, + 13180.0,13882.0,60344.0,63675.9, +]; + +/// u25(25) from state.f +pub const STATE_U25: [f64; 25] = [ + 59.959,126.145,271.55,413.0,584.0,771.1,961.44,1569.0,1789.0,2003.0, + 2307.0,2536.0,2771.0,3250.0,3509.82,9152.0,9872.0,10620.0,11590.0,12410.0, + 13260.0,14420.0,15162.0,65660.0,69137.4, +]; + +/// u26(26) from state.f +pub const STATE_U26: [f64; 26] = [ + 63.737,130.563,247.22,442.0,605.0,799.0,1008.0,1218.38,1884.0,2114.0, + 2341.0,2668.0,2912.0,3163.0,3686.0,3946.82,10180.0,10985.0,11850.0,12708.0, + 13620.0,14510.0,15797.0,16500.0,71203.0,74829.6, +]; + +/// u28(28) from state.f +pub const STATE_U28: [f64; 28] = [ + 61.6,146.542,283.8,443.0,613.5,870.0,1070.0,1310.0,1560.0,1812.0, + 2589.0,2840.0,3100.0,3470.0,3740.0,4020.0,4606.0,4896.2,12430.0,13290.0, + 14160.0,15280.0,16220.0,17190.0,18510.0,19351.0,82984.0,86909.4, +]; + +/// th0 (from state.f) +pub const STATE_TH0: f64 = 5040.4; + +/// xmx0 (from state.f) +pub const STATE_XMX0: f64 = 21540.0; + +/// thl0 (from state.f) +pub const STATE_THL0: f64 = 2.3025851; + +/// fi0 (from state.f) +pub const STATE_FI0: f64 = 36.113; + +/// trha (from state.f) +pub const STATE_TRHA: f64 = 1.5; + +/// c1qm (from state.f) +pub const STATE_C1QM: f64 = 1.0353e-16; + +/// c2qm (from state.f) +pub const STATE_C2QM: f64 = 8762.9; + +/// ev2erg (from state.f) +pub const STATE_EV2ERG: f64 = 1.6018e-12; + +// ========== tabini.f ========== + +/// mtabto (from tabini.f) +pub const TABINI_MTABTO: f64 = 100.0; + +/// mtabro (from tabini.f) +pub const TABINI_MTABRO: f64 = 100.0; + +// ========== taufr1.f ========== + +/// tauref (from taufr1.f) +pub const TAUFR1_TAUREF: f64 = 1.0; + +/// xcon (from taufr1.f) +pub const TAUFR1_XCON: f64 = 8.0935e-21; + +/// ycon (from taufr1.f) +pub const TAUFR1_YCON: f64 = 1.68638e-10; + +// ========== tdpini.f ========== + +/// cff1 (from tdpini.f) +pub const TDPINI_CFF1: f64 = 1.3727e-25; + +/// cff2 (from tdpini.f) +pub const TDPINI_CFF2: f64 = 4.3748e-10; + +/// cff3 (from tdpini.f) +pub const TDPINI_CFF3: f64 = 2.5993e-07; + +/// sgff0 (from tdpini.f) +pub const TDPINI_SGFF0: f64 = 369400000.0; + +// ========== temper.f ========== + +/// errt (from temper.f) +pub const TEMPER_ERRT: f64 = 0.001; + +// ========== timing.f ========== + +/// t0 (from timing.f, 未知维度,共 1 个值) +pub const TIMING_T0: [f64; 1] = [ + 0.0, +]; + +// ========== tiopf.f ========== + +/// pf0(800) from tiopf.f +pub const TIOPF_PF0: [f64; 800] = [ + 29.107,55.425,82.417,111.19,142.564,176.916,214.34,254.774,298.065,344.021, + 392.431,443.089,495.795,550.365,606.632,664.449,723.686,784.23,845.981,908.862, + 972.8,1037.739,1103.636,1170.451,1238.155,1306.723,1376.144,1446.403,1517.492,1589.409, + 1662.152,1735.724,1810.122,1885.352,1961.428,2038.351,2116.119,2194.758,2274.26,2354.633, + 2435.907,2518.063,2601.125,2685.096,2769.992,2855.809,2942.56,3030.257,3118.897,3208.496, + 3299.067,3390.598,3483.106,3576.598,3671.095,3766.569,3863.048,3960.522,4059.035,4158.545, + 4259.074,4360.642,4463.259,4566.905,4671.582,4777.321,4884.105,4991.937,5100.852,5210.813, + 5321.838,5433.972,5547.154,5661.417,5776.789,5893.211,6010.774,6129.422,6249.173,6370.026, + 6491.973,6615.042,6739.24,6864.542,6990.959,7118.533,7247.214,7377.053,7508.012,7640.121, + 7773.37,7907.764,8043.309,8180.032,8317.835,8456.861,8597.055,8738.396,8880.926,9024.672, + 9169.57,9315.61,9462.927,9611.339,9760.963,9911.798,10063.9,10217.148,10371.572,10527.253, + 10684.109,10842.173,11001.469,11161.97,11323.751,11486.758,11650.978,11816.415,11983.159,12151.134, + 12320.243,12490.668,12662.333,12835.234,13009.47,13184.926,13361.601,13539.66,13718.891,13899.456, + 14081.252,14264.326,14448.643,14634.341,14821.225,15009.476,15199.021,15389.829,15581.955,15775.377, + 15970.188,16166.239,16363.513,16562.006,16761.93,16963.301,17165.906,17369.881,17575.236,17781.814, + 17989.816,18198.996,18409.707,18621.68,18835.068,19049.715,19265.768,19483.375,19702.006,19922.209, + 20143.668,20366.555,20590.742,20816.402,21043.338,21271.672,21501.369,21732.563,21965.119,22199.068, + 22434.432,22671.266,22909.307,23148.898,23389.893,23632.322,23875.969,24121.16,24367.707,24615.848, + 24865.471,25116.32,25368.604,25622.342,25877.512,26134.055,26392.404,26651.764,26912.826,27175.25, + 27439.197,27704.539,27971.287,28239.572,28509.373,28780.707,29053.516,29327.602,29603.338,29880.539, + 30159.105,30439.322,30721.055,31004.254,31288.818,31575.061,31862.693,32151.781,32442.586,32734.619, + 33027.777,33323.023,33619.535,33917.707,34217.711,34518.996,34821.676,35126.195,35432.141,35739.602, + 36048.926,36359.488,36672.023,36985.633,37300.863,37617.965,37936.469,38256.309,38578.074,38901.668, + 39226.461,39552.969,39880.852,40210.785,40541.852,40874.691,41209.359,41545.535,41883.602,42222.715, + 42563.895,42906.508,43250.656,43596.902,43944.355,44293.695,44644.504,44997.621,45351.59,45707.242, + 46065.008,46424.367,46785.605,47148.023,47512.496,47878.418,48246.426,48615.895,48987.336,49360.082, + 49734.758,50111.004,50489.383,50868.996,51250.25,51633.691,52018.945,52405.715,52794.09,53184.34, + 53576.375,53970.605,54366.176,54763.148,55162.43,55563.215,55966.391,56371.0,56777.176,57185.57, + 57596.074,58007.617,58421.418,58837.172,59254.539,59673.418,60094.066,60517.41,60941.844,61368.66, + 61797.395,62227.59,62659.789,63094.238,63529.695,63967.488,64407.887,64849.496,65292.867,65735.922, + 66182.0,66631.266,67082.055,67534.391,67988.992,68446.117,68904.789,69365.18,69827.914,70292.781, + 70759.352,71228.5,71699.375,72171.672,72647.086,73123.984,73603.023,74083.516,74566.359,75050.555, + 75537.758,76027.258,76518.125,77012.008,77507.063,78003.813,78503.977,79006.125,79509.32,80015.375, + 80522.461,81031.938,81544.164,82058.313,82574.352,83093.914,83614.367,84136.82,84662.211,85188.867, + 85719.375,86249.977,86783.781,87319.219,87857.18,88396.797,88939.805,89484.266,90032.023,90580.93, + 91132.563,91686.148,92242.742,92799.406,93360.016,93923.453,94488.313,95055.211,95625.297,96197.477, + 96771.531,97348.156,97926.922,98507.453,99091.563,99677.938,100267.234,100856.438,101449.828,102045.75, + 102643.094,103244.117,103846.969,104450.313,105057.641,105667.188,106279.516,106894.937,107512.789,108133.117, + 108754.758,109377.687,110005.039,110634.602,111266.141,111902.133,112537.984,113178.891,113819.766,114464.312, + 115110.969,115760.687,116412.469,117068.055,117724.547,118384.383,119047.469,119712.469,120380.187,121051.336, + 121724.102,122399.25,123076.266,123756.977,124441.195,125126.406,125816.453,126506.766,127202.367,127899.086, + 128598.266,129299.969,130004.969,130712.016,131409.266,132117.719,132828.969,133544.016,134262.75,134986.344, + 135712.891,136439.937,137170.969,137905.562,138641.578,139380.266,140122.937,140868.641,141615.484,142366.703, + 143123.078,143880.0,144638.484,145401.594,146168.125,146935.359,147707.484,148482.641,149256.578,150037.281, + 150821.953,151606.75,152396.094,153188.766,153983.391,154782.141,155582.203,156387.234,157192.719,158003.156, + 158815.125,159632.437,160450.766,161274.75,162098.172,162926.0,163756.609,164593.141,165430.859,166270.937, + 167114.75,167960.797,168811.562,169663.906,170517.203,171376.531,172239.469,173105.891,173975.25,174847.203, + 175721.453,176597.25,177480.984,178366.094,179253.828,180145.734,181038.0,181936.031,182837.969,183739.922, + 184645.937,185558.281,186470.844,187387.422,188307.234,189232.281,190156.0,191088.234,192022.062,192957.25, + 193899.328,194842.984,195788.391,196736.156,197687.828,198645.719,199603.422,200569.234,201536.437,202508.641, + 203481.0,204459.016,205438.75,206424.312,207409.953,208398.734,209393.234,210391.047,211390.984,212395.516, + 213401.547,214420.141,215431.812,216453.453,217476.734,218501.266,219530.219,220560.719,221597.891,222637.875, + 223677.75,224725.5,225777.406,226829.297,227893.125,228954.547,230020.969,231086.453,232157.469,233233.047, + 234315.406,235395.625,236480.953,237572.125,238666.484,239765.125,240863.281,241969.75,243079.25,244191.719, + 245304.812,246427.937,247548.234,248673.562,249804.984,250942.781,252078.953,253222.812,254369.641,255519.359, + 256671.406,257827.906,258988.859,260154.734,261322.281,262458.781,263606.437,264770.625,265947.75,267125.156, + 268314.125,269507.687,270702.344,271905.156,273110.156,274318.937,275531.687,276751.344,277970.781,279198.531, + 280425.75,281663.25,282897.469,284138.906,285383.594,286637.031,287891.156,289147.625,290413.312,291678.719, + 292946.031,294225.875,295501.344,296782.656,298070.094,299363.875,300652.25,301953.75,303260.062,304563.781, + 305874.375,307191.437,308517.031,309835.75,311159.375,312490.937,313827.469,315166.781,316511.031,317860.406, + 319214.969,320565.875,321929.344,323296.906,324660.219,326035.687,327413.844,328794.406,330173.156,331566.156, + 332953.469,334356.187,335757.625,337165.562,338566.094,339984.75,341402.937,342828.125,344257.562,345686.75, + 347123.125,348564.25,350008.906,351453.219,352908.062,354361.469,355828.0,357292.5,358765.719,360233.687, + 361713.562,363200.187,364685.656,366174.5,367673.594,369174.906,370678.969,372191.125,373708.937,375225.281, + 376743.719,378270.406,379804.5,381334.25,382879.125,384420.812,385969.531,387519.812,389078.937,390639.781, + 392213.875,393782.437,395359.156,396943.625,398527.625,400110.937,401711.75,403310.344,404908.937,406513.875, + 408125.781,409741.906,411356.875,412979.5,414613.125,416245.5,417889.094,419530.0,421179.906,422831.531, + 424484.344,426153.187,427816.406,429489.094,431161.312,432840.656,434517.0,436215.281,437896.0,439602.594, + 441300.625,443016.156,444722.906,446445.437,448164.812,449885.937,451615.094,453351.594,455090.125,456833.281, + 458582.719,460335.344,462094.844,463857.094,465629.906,467402.781,469178.406,470963.75,472745.906,474539.594, + 476333.312,478131.125,479934.0,481740.75,483557.844,485376.625,487202.937,489033.562,490868.031,492709.281, + 494547.375,496401.094,498249.594,500110.25,501966.594,503836.062,505704.437,507580.687,509469.187,511349.781, + 513239.0,515137.187,517038.812,518942.906,520858.156,522767.094,524610.625,526433.812,528331.062,530253.437, + 532185.5,534127.875,536073.937,538028.312,539983.375,541954.687,543916.312,545902.5,547874.812,549857.125, + 551850.937,553839.937,555836.625,557838.5,559849.937,561859.375,563880.625,565889.875,567916.0,569953.625, + 571990.375,574034.937,576085.062,578127.375,580188.937,582251.0,584328.812,586385.562,588464.062,590551.875, + 592644.625,594722.25,596829.937,598931.375,601029.687,603142.812,605262.812,607384.625,609513.125,611644.0, + 613775.875,615930.375,618073.75,620218.437,622381.937,624524.312,626697.5,628869.0,631040.937,633223.562, + 635409.187,637597.562,639800.187,642002.125,644212.562,646416.25,648633.562,650864.187,653083.687,655315.312, + 657549.687,659795.5,662032.25,664292.875,666542.312,668806.25,671071.312,673340.937,675626.938,677898.75, +]; + +// ========== tlocal.f ========== + +/// c1 (from tlocal.f) +pub const TLOCAL_C1: f64 = 0.8112; + +/// c2 (from tlocal.f) +pub const TLOCAL_C2: f64 = 396600000000000.0; + +/// c3 (from tlocal.f) +pub const TLOCAL_C3: f64 = 6.745e-10; + +/// c4 (from tlocal.f) +pub const TLOCAL_C4: f64 = 0.96; + +// ========== topbas.f ========== + +/// e10 (from topbas.f) +pub const TOPBAS_E10: f64 = 2.3025851; + +/// mmaxop (from topbas.f) +pub const TOPBAS_MMAXOP: f64 = 200.0; + +/// mop (from topbas.f) +pub const TOPBAS_MOP: f64 = 15.0; + +// ========== trmdrt.f ========== + +/// rcon (from trmdrt.f) +pub const TRMDRT_RCON: f64 = 83143400.0; + +// ========== vern16.f ========== + +/// s0(16) from vern16.f +pub const VERN16_S0: [f64; 16] = [ + 45640.0,313.6,6.666,2.606,0.0005072,9.139,0.5703,31.61,9646.0,53.64, + 12.75,0.349,22940.0,25.55,24.53,213.9, +]; + +/// e0(16) from vern16.f +pub const VERN16_E0: [f64; 16] = [ + 18.08,8.787,2.027,2.173,0.1713,14.13,0.3757,14.62,0.1526,10.4, + 6.485,2.443,14.74,33.1,439.0,110.4, +]; + +/// emx(16) from vern16.f +pub const VERN16_EMX: [f64; 16] = [ + 170.0,184.6,199.5,216.4,235.0,255.7,2569.0,2641.0,2705.0,2782.0, + 2859.0,2941.0,3029.0,3107.0,50000.0,50000.0, +]; + +/// y0(16) from vern16.f +pub const VERN16_Y0: [f64; 16] = [ + 0.9935,2.782,15.68,19.75,94.24,0.0,222.2,18.69,0.001615,17.75, + 34.26,227.9,0.02203,0.0,0.0,0.0, +]; + +/// y1(16) from vern16.f +pub const VERN16_Y1: [f64; 16] = [ + 0.2486,0.1788,9.421,3.361,0.6265,0.0,4.606,0.3037,0.4049,1.663, + 0.137,1.172,0.01073,0.0,0.0,0.0, +]; + +/// yw(16) from vern16.f +pub const VERN16_YW: [f64; 16] = [ + 0.6385,0.7354,4.109,1.863,0.788,0.0,1.503,0.001153,1.492,2.31, + 1.678,0.7033,27.38,0.0,0.0,0.0, +]; + +/// ya(16) from vern16.f +pub const VERN16_YA: [f64; 16] = [ + 1.0,3.442,54.54,66.41,198.6,1656.0,146.0,16.11,1438.0,36.41, + 65.83,541.1,1.529,38.21,44.05,32.88, +]; + +/// pv(16) from vern16.f +pub const VERN16_PV: [f64; 16] = [ + 13.61,12.81,8.611,8.655,13.07,3.626,11.35,8.642,5.977,7.09, + 7.692,7.769,25.68,5.037,1.765,2.963, +]; + +/// s95(16) from vern16.f +pub const VERN16_S95: [f64; 16] = [ + 188.3,189.6,178.0,203.7,291.9,471.2,19.16,19.31,19.46,20.41, + 21.01,20.87,22.33,22.93,24.53,213.9, +]; + +/// e95(16) from vern16.f +pub const VERN16_E95: [f64; 16] = [ + 91.52,90.58,92.46,87.44,74.11,57.47,495.2,489.1,493.7,480.2, + 475.8,482.8,466.9,466.7,439.0,110.4, +]; + +/// y95(16) from vern16.f +pub const VERN16_Y95: [f64; 16] = [ + 71.93,75.38,149.8,93.1,48.64,36.1,35.55,50.0,35.68,50.0, + 50.0,37.42,50.0,44.59,44.05,32.88, +]; + +/// yw95(16) from vern16.f +pub const VERN16_YW95: [f64; 16] = [ + 0.2485,0.2934,0.02142,0.009497,0.02785,0.0248,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// p95(16) from vern16.f +pub const VERN16_P95: [f64; 16] = [ + 3.633,3.635,3.319,3.565,4.142,4.742,1.742,1.65,1.737,1.65, + 1.65,1.72,1.65,1.668,1.765,2.963, +]; + +/// t18 (from vern16.f) +pub const VERN16_T18: f64 = 1e-18; + +/// mver (from vern16.f) +pub const VERN16_MVER: f64 = 16.0; + +// ========== vern18.f ========== + +/// s0(18) from vern18.f +pub const VERN18_S0: [f64; 18] = [ + 21.06,25.03,35.8,20.35,9.946,1.08,3.693,32.95,0.8279,8.204, + 1760.0,0.7018,0.02459,0.04997,25710.0,21.35,31.08,169.0, +]; + +/// e0(18) from vern18.f +pub const VERN18_E0: [f64; 18] = [ + 17.09,24.94,14.17,6.953,10.31,0.544,0.02966,3.844,0.1926,10.4, + 0.1257,5.31,0.3209,1.557,18.88,41.54,446.8,139.9, +]; + +/// emx(18) from vern18.f +pub const VERN18_EMX: [f64; 18] = [ + 249.2,266.2,280.1,298.7,320.0,342.6,366.7,392.5,3361.0,3446.0, + 3523.0,3613.0,3702.0,3798.0,3898.0,3988.0,50000.0,50000.0, +]; + +/// y0(18) from vern18.f +pub const VERN18_Y0: [f64; 18] = [ + 1.688,0.9299,2.384,7.501,6.406,170.0,0.0004383,0.0,38.14,38.04, + 0.003286,109.9,2068.0,455.2,0.02445,0.0,0.0,0.0, +]; + +/// y1(18) from vern18.f +pub const VERN18_Y1: [f64; 18] = [ + 0.8943,0.7195,1.794,0.1806,0.003659,15.87,2.513,0.0,4.649,0.639, + 0.3226,0.2202,21.13,6.459,0.01054,0.0,0.0,0.0, +]; + +/// yw(18) from vern18.f +pub const VERN18_YW: [f64; 18] = [ + 0.4185,0.5108,0.6316,0.8842,0.4885,11.07,0.01363,0.0,1.434,0.0009203, + 1.975,0.4987,0.6692,0.2938,29.09,0.0,0.0,0.0, +]; + +/// ya(18) from vern18.f +pub const VERN18_YA: [f64; 18] = [ + 264.5,127.2,37.76,14.0,74.44,941.9,9951.0,708.2,239.2,14.95, + 1579.0,100.1,2285.0,503.1,1.475,41.18,30.39,32.88, +]; + +/// pv(18) from vern18.f +pub const VERN18_PV: [f64; 18] = [ + 4.796,4.288,5.742,9.595,6.261,7.582,7.313,4.645,11.21,11.15, + 6.714,8.939,8.81,8.966,26.34,4.945,2.092,2.963, +]; + +/// s95(18) from vern18.f +pub const VERN18_S95: [f64; 18] = [ + 83.72,193.7,228.1,200.7,247.4,278.6,320.4,419.8,29.31,15.85, + 27.96,16.66,28.88,28.74,28.83,30.03,31.08,169.0, +]; + +/// e95(18) from vern18.f +pub const VERN18_E95: [f64; 18] = [ + 164.7,108.5,102.5,107.3,98.35,92.33,85.63,73.68,467.9,612.6, + 478.9,602.8,473.1,474.9,475.6,468.0,466.8,139.9, +]; + +/// y95(18) from vern18.f +pub const VERN18_Y95: [f64; 18] = [ + 54.52,70.0,43.8,70.0,42.84,42.2,42.3,44.19,17.44,50.0, + 19.17,50.0,20.42,22.35,26.15,28.54,30.39,32.88, +]; + +/// yw95(18) from vern18.f +pub const VERN18_YW95: [f64; 18] = [ + 0.627,0.1,0.007167,0.1,0.007283,0.007408,0.007258,0.007712,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// p95(18) from vern18.f +pub const VERN18_P95: [f64; 18] = [ + 3.328,3.7,4.046,3.7,4.125,4.227,4.329,4.492,2.362,1.65, + 2.271,1.65,2.234,2.171,2.074,2.037,2.092,2.963, +]; + +/// t18 (from vern18.f) +pub const VERN18_T18: f64 = 1e-18; + +/// mver (from vern18.f) +pub const VERN18_MVER: f64 = 18.0; + +// ========== vern20.f ========== + +/// s0(20) from vern20.f +pub const VERN20_S0: [f64; 20] = [ + 537000.0,10640000.0,38.15,7.736,0.1523,76.42,0.476,0.6641,207.6,14.37, + 0.9384,12.27,1849.0,1.116,55.13,1.293,20280.0,11.05,19.36,136.9, +]; + +/// e0(20) from vern20.f +pub const VERN20_E0: [f64; 20] = [ + 12.78,15.53,24.36,4.255,0.6882,9.515,0.808,1.366,0.0552,16.05, + 0.2288,23.45,10.08,9.98,130.9,4.293,26.18,94.72,629.7,172.9, +]; + +/// emx(20) from vern20.f +pub const VERN20_EMX: [f64; 20] = [ + 34.43,40.9,373.1,394.4,417.5,442.3,468.7,496.7,527.0,556.9, + 4265.0,4362.0,4453.0,4555.0,4659.0,4767.0,4880.0,4982.0,50000.0,50000.0, +]; + +/// y0(20) from vern20.f +pub const VERN20_Y0: [f64; 20] = [ + 0.001012,0.002161,1.802,14.67,121.0,4.829,148.7,103.9,0.0002826,0.0, + 24.78,24.17,0.006138,71.04,0.01833,0.9363,0.02402,0.0,0.0,0.0, +]; + +/// y1(20) from vern20.f +pub const VERN20_Y1: [f64; 20] = [ + 0.01851,0.06706,1.233,0.03298,3.876,5.824,1.283,3.329,1.657,0.0, + 3.1,0.5469,69.31,5.311,0.9359,0.04589,0.009323,0.0,0.0,0.0, +]; + +/// yw(20) from vern20.f +pub const VERN20_YW: [f64; 20] = [ + 0.4477,0.6453,0.3126,1.369,8.277,2.471,0.572,0.2806,0.001843,0.0, + 1.39,0.0006842,241.0,3.879,0.09084,3.461e-05,28.03,0.0,0.0,0.0, +]; + +/// ya(20) from vern20.f +pub const VERN20_YA: [f64; 20] = [ + 0.3162,0.779,293.1,13.55,150.2,89.73,368.2,318.8,17900.0,698.9, + 254.9,13.12,17920.0,59.18,382.8,16.91,1.456,38.18,39.21,32.88, +]; + +/// pv(20) from vern20.f +pub const VERN20_PV: [f64; 20] = [ + 12.42,21.3,3.944,12.36,10.61,5.141,8.634,8.138,5.893,3.857, + 11.03,9.771,2.868,9.005,2.023,14.38,25.6,4.192,1.862,2.963, +]; + +/// s95(20) from vern20.f +pub const VERN20_S95: [f64; 20] = [ + 90.17,73.14,194.5,154.2,162.2,185.5,218.1,278.8,193.4,661.6, + 15.47,13.24,15.7,13.84,14.17,16.65,14.86,18.2,19.36,136.9, +]; + +/// e95(20) from vern20.f +pub const VERN20_E95: [f64; 20] = [ + 44.87,44.98,126.0,141.3,138.4,130.3,120.8,107.0,129.3,65.11, + 701.0,750.3,698.9,739.6,734.2,686.2,723.5,664.0,629.7,172.9, +]; + +/// y95(20) from vern20.f +pub const VERN20_Y95: [f64; 20] = [ + 14.65,18.98,68.19,99.06,88.11,69.93,58.16,47.68,70.0,43.71, + 31.97,50.0,32.18,50.0,50.0,34.43,50.0,39.79,39.21,32.88, +]; + +/// yw95(20) from vern20.f +pub const VERN20_YW95: [f64; 20] = [ + 0.2754,0.2735,0.0004791,0.001107,0.0004384,1.4e-05,4.346e-06,4.591e-06,0.1,7.881e-06, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// p95(20) from vern20.f +pub const VERN20_P95: [f64; 20] = [ + 7.498,7.152,3.77,3.446,3.521,3.707,3.907,4.2,3.7,4.937, + 1.858,1.65,1.851,1.65,1.65,1.823,1.65,1.777,1.862,2.963, +]; + +/// t18 (from vern20.f) +pub const VERN20_T18: f64 = 1e-18; + +/// mver (from vern20.f) +pub const VERN20_MVER: f64 = 20.0; + +// ========== vern26.f ========== + +/// s0(26) from vern26.f +pub const VERN26_S0: [f64; 26] = [ + 0.3062,4365.0,6.107,365.3,0.001523,0.5259,24200.0,19.79,26.87,64.7, + 3.281,1.738,0.002791,0.1454,210.8,12.07,1.452,2.388,6.066e-05,0.4455, + 10.98,0.07204,25800.0,12.76,11.95,80.99, +]; + +/// e0(26) from vern26.f +pub const VERN26_E0: [f64; 26] = [ + 0.05461,0.1761,0.1698,25.44,0.7256,2.656,5.059,0.07098,6.741,68.86, + 8.284,6.295,0.1317,0.8509,0.05555,28.73,0.3444,31.9,0.0007519,20.11, + 9.243,9.713,45.75,73.26,1057.0,293.2, +]; + +/// emx(26) from vern26.f +pub const VERN26_EMX: [f64; 26] = [ + 66.0,76.17,87.05,106.7,128.8,152.7,178.3,205.5,921.1,959.0, + 998.3,1039.0,1081.0,1125.0,1181.0,1216.0,7651.0,7769.0,7918.0,8041.0, + 8184.0,8350.0,8484.0,8638.0,50000.0,50000.0, +]; + +/// y0(26) from vern26.f +pub const VERN26_Y0: [f64; 26] = [ + 138.2,92.72,176.0,0.0,88.71,33.61,0.4546,2542.0,24.94,1.19e-05, + 29.71,46.71,2170.0,450.5,0.0002706,0.0,28.91,38.05,1915000.0,68.47, + 44.46,170.2,0.03582,0.0,0.0,0.0, +]; + +/// y1(26) from vern26.f +pub const VERN26_Y1: [f64; 26] = [ + 0.2481,107.5,18.47,0.0,0.0528,0.003743,26.83,467.2,8.251,0.00657, + 0.522,0.1425,0.006852,2.504,1.628,0.0,3.404,0.4805,31.4,3.989, + 3.512,4.263,0.008712,0.0,0.0,0.0, +]; + +/// yw(26) from vern26.f +pub const VERN26_YW: [f64; 26] = [ + 20.69,11.41,8.698,0.5602,50.64,15.58,0.002516,215.8,0.0002387,0.0002778, + 0.3279,0.3096,0.6938,0.4937,0.001885,0.0,1.264,0.02902,4.398,2.757, + 1.748,0.009551,27.23,0.0,0.0,0.0, +]; + +/// ya(26) from vern26.f +pub const VERN26_YA: [f64; 26] = [ + 26710000.0,6298.0,1555.0,8.913,37.36,14.5,48500.0,17450.0,180.7,20.62, + 53.6,113.0,2487.0,1239.0,20450.0,515.0,396.0,21.86,1606000.0,42.36, + 76.37,185.3,1.358,49.14,57.69,32.88, +]; + +/// pv(26) from vern26.f +pub const VERN26_PV: [f64; 26] = [ + 7.923,5.204,8.055,6.538,17.67,16.32,2.374,6.75,6.29,4.111, + 8.571,8.037,9.791,8.066,6.033,3.846,10.13,9.589,8.813,9.724, + 7.962,8.843,26.04,4.941,1.718,2.963, +]; + +/// s95(26) from vern26.f +pub const VERN26_S95: [f64; 26] = [ + 62.98,46.24,44.22,48.1,51.43,52.46,52.1,53.36,220.5,239.2, + 244.9,332.5,331.6,336.7,149.6,338.3,11.5,8.327,11.55,8.619, + 8.773,11.81,90.98,11.57,11.95,80.99, +]; + +/// e95(26) from vern26.f +pub const VERN26_E95: [f64; 26] = [ + 76.3,77.5,77.77,76.25,72.73,72.6,74.33,75.56,171.5,164.7, + 163.2,138.3,139.2,138.7,213.6,139.6,1067.0,1249.0,1068.0,1235.0, + 1228.0,1066.0,1215.0,1087.0,1057.0,293.2, +]; + +/// y95(26) from vern26.f +pub const VERN26_Y95: [f64; 26] = [ + 14.79,21.55,23.36,22.86,24.28,27.51,33.06,38.55,52.98,52.76, + 54.52,50.9,52.37,52.79,70.0,54.59,34.12,50.0,35.78,50.0, + 50.0,41.16,50.0,50.86,57.69,32.88, +]; + +/// yw95(26) from vern26.f +pub const VERN26_YW95: [f64; 26] = [ + 0.2646,0.2599,0.2557,0.2449,0.1365,0.02105,0.02404,0.02667,1.508e-05,1.574e-05, + 0.0001594,1.114e-05,1.107e-05,1.111e-05,0.1,1.179e-05,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0, +]; + +/// p95(26) from vern26.f +pub const VERN26_P95: [f64; 26] = [ + 7.672,7.138,7.017,7.043,7.028,6.823,6.509,6.265,4.154,4.204, + 4.187,4.446,4.41,4.407,3.7,4.366,1.922,1.65,1.895,1.65, + 1.65,1.827,1.65,1.722,1.718,2.963, +]; + +/// t18 (from vern26.f) +pub const VERN26_T18: f64 = 1e-18; + +/// mver (from vern26.f) +pub const VERN26_MVER: f64 = 26.0; + +// ========== verner.f ========== + +/// s0(105) from verner.f +pub const VERNER_S0: [f64; 105] = [ + 54750.0,949.2,13690.0,62.45,320.1,6083.0,293200.0,267.8,545.8,3422.0, + 5.466,18590.0,53.93,284.6,2190.0,502.7,8.709,15390.0,106.8,234.4, + 1521.0,823.5,1.944,0.9375,16900.0,83.76,151.9,1117.0,1745.0,59.67, + 675.3,0.8659,16420.0,68.64,132.9,855.4,3803.0,80.13,154.1,3.165, + 0.469,11570.0,69.3,103.9,675.9,4287.0,1583.0,5.708,1685.0,2.43, + 0.9854,11980.0,56.31,66.95,547.5,1.601,1040.0,1885.0,2.33,23.46, + 71.01,1.609,7215.0,47.29,39.95,452.5,137200000.0,3.278,537.7,1394.0, + 1.728,2.185,3.104,0.06344,900.8,44.27,61.4,380.2,7.195,0.06948, + 4.915,15.13,292.5,0.01962,188.9,0.235,0.4982,17740.0,33.88,40.36, + 323.9,25.06,4.14,0.000579,6.083,0.8863,72.93,0.0668,0.3477,0.1465, + 0.195,19920.0,25.39,47.54,279.3, +]; + +/// e0(105) from verner.f +pub const VERNER_E0: [f64; 105] = [ + 0.4298,13.61,1.72,3.107,20.06,3.871,9.539,1.181,17.6,6.879, + 0.5213,2.869,1.041,33.36,10.75,2.144,0.4058,4.614,3.506,46.24, + 15.48,4.034,0.06128,0.242,5.494,4.471,69.43,21.08,1.24,1.386, + 0.1723,0.2044,2.854,7.824,87.09,27.54,12.97,1.763,2.542,0.7744, + 0.7286,4.008,2.563,113.1,34.85,4.87,12.47,0.7753,5.566,1.248, + 1.499,4.888,10.03,158.6,43.04,6.139,8.203,10.69,0.669,5.408, + 48.46,2.096,153.5,13.91,226.8,52.11,11.97,8.139,10.86,29.12, + 0.9762,1.711,3.57,0.4884,34.82,14.52,204.2,62.03,13.81,0.2048, + 10.27,3.13,24.14,0.3483,2.636,0.4866,1.842,8.044,23.55,273.8, + 72.81,23.17,2.556,0.1659,1.288,0.7761,63.05,0.3277,0.7655,0.3343, + 0.8787,12.05,35.6,275.2,84.47, +]; + +/// emx(105) from verner.f +pub const VERNER_EMX: [f64; 105] = [ + 50000.0,50000.0,50000.0,64.39,50000.0,50000.0,11.93,12.99,50000.0,50000.0, + 194.0,209.8,227.4,50000.0,50000.0,291.0,307.6,328.9,352.2,50000.0, + 50000.0,404.8,423.6,447.3,475.3,504.3,50000.0,50000.0,538.0,558.1, + 584.0,614.4,649.1,683.7,50000.0,50000.0,694.0,712.2,739.2,770.9, + 809.1,850.2,890.5,50000.0,50000.0,870.1,883.1,913.1,948.0,987.3, + 1031.0,1078.0,1125.0,50000.0,50000.0,38.14,1074.0,1110.0,1143.0,1185.0, + 1230.0,1281.0,1335.0,1386.0,50000.0,50000.0,54.9,65.69,1317.0,1356.0, + 1400.0,1449.0,1501.0,1558.0,1618.0,1675.0,50000.0,50000.0,80.4,89.97, + 102.6,1588.0,1634.0,1688.0,1739.0,1799.0,1862.0,1929.0,1992.0,50000.0, + 50000.0,106.0,118.6,131.1,146.6,1887.0,1946.0,2001.0,2058.0,2125.0, + 2194.0,2268.0,2336.0,50000.0,50000.0, +]; + +/// y0(105) from verner.f +pub const VERNER_Y0: [f64; 105] = [ + 0.0,0.4434,0.0,0.0,0.0,0.0,0.0008278,0.0,0.0,0.0, + 13.19,0.00496,0.0,0.0,0.0,1.133,49.29,0.004378,0.0,0.0, + 0.0,0.8598,428.0,187.7,0.006415,0.0,0.0,0.0,8.698,21.31, + 0.003839,332.8,0.03036,0.0,0.0,0.0,0.0001701,17.15,16.41,95.31, + 150.6,0.02071,0.0,0.0,0.0,0.04236,1.52,76.54,5.149,91.69, + 104.2,0.02536,0.0,0.0,0.0,0.0,3.375,3.725,138.3,22.04, + 0.0009603,99.4,0.1667,0.0,0.0,0.0,0.0,0.0,4.86,0.9402, + 127.6,100.7,54.52,534.8,5.444,0.0,0.0,0.0,0.2041,91.49, + 0.0,39.94,3.495,0.05675,35.52,570.4,171.9,0.02538,0.0,0.0, + 0.0,1.672e-05,6.634,96.13,0.0,200.9,1.115,0.01149,385.0,1036.0, + 452.8,0.0199,0.0,0.0,0.0, +]; + +/// y1(105) from verner.f +pub const VERNER_Y1: [f64; 105] = [ + 0.0,2.136,0.0,0.0,0.0,0.0,0.01269,0.0,0.0,0.0, + 4.556,0.034,0.0,0.0,0.0,1.607,3.234,0.02528,0.0,0.0, + 0.0,2.325,20.3,3.999,0.01937,0.0,0.0,0.0,0.1271,0.01503, + 0.4569,42.85,0.05554,0.0,0.0,0.0,0.01345,0.7724,5.124,9.781, + 0.2574,0.03998,0.0,0.0,0.0,5.873,0.1084,2.023,6.687,0.3702, + 1.435,0.04417,0.0,0.0,0.0,0.0,4.01,0.2279,4.26,0.7577, + 0.006378,3.278,0.01766,0.0,0.0,0.0,0.0,0.0,3.722,0.1135, + 3.979,1.729,2.078,0.003997,0.07918,0.0,0.0,0.0,0.4753,0.6565, + 0.0,4.803,0.2701,0.2768,0.008223,0.158,6.595,0.01203,0.0,0.0, + 0.0,0.4207,0.1272,0.6442,0.0,4.537,0.08051,0.6396,0.08999,0.2936, + 1.015,0.01007,0.0,0.0,0.0, +]; + +/// yw(105) from verner.f +pub const VERNER_YW: [f64; 105] = [ + 0.0,2.039,0.0,0.0,0.0,0.0,0.3655,0.0,0.0,0.0, + 18.87,3.503,0.0,0.0,0.0,0.09157,2.093,5.922,0.0,0.0, + 0.0,0.09097,10.43,1.85,7.904,0.0,0.0,0.0,0.07589,0.01934, + 0.1191,3.143,28.36,0.0,0.0,0.0,0.00217,0.5103,1.115,6.812, + 0.257,24.11,0.0,0.0,0.0,0.2434,0.06558,0.4633,0.00829,0.6855, + 1.656,28.11,0.0,0.0,0.0,0.0,2.328,0.08579,0.7365,0.9275, + 0.01285,1.895,0.9121,0.0,0.0,0.0,0.2805,0.0,2.604,0.04326, + 0.809,0.6325,1.422,0.6666,2.751,0.0,0.0,0.0,0.3166,0.4615, + 0.0,5.342,0.1,8.839,1.836,0.2773,0.6945,29.53,0.0,0.0, + 0.0,0.2837,1.57,0.8626,0.0,1.303,0.002989,3.28,0.001476,1.646, + 0.4489,23.92,0.0,0.0,0.0, +]; + +/// ya(105) from verner.f +pub const VERNER_YA: [f64; 105] = [ + 32.88,1.469,32.88,15.01,7.391,32.88,0.4301,5.645,17.19,32.88, + 8.618,1.783,17.67,21.63,32.88,62.16,126.1,1.737,14.36,21.83, + 32.88,80.33,816.3,278.8,1.714,32.97,26.27,32.88,3.784,31.75, + 385.2,493.1,1.792,32.1,25.35,32.88,2.587,16.67,57.42,109.9, + 140.0,1.848,75.47,26.57,32.88,5.798,3.935,67.25,640.9,106.6, + 135.0,1.788,36.28,33.52,32.88,6148.0,8.259,3.613,120.5,29.13, + 39.45,247.3,0.3886,38.89,53.15,32.88,0.2228,43410000.0,9.779,2.895, + 91.84,93.5,60.6,508.5,1.823,38.26,27.78,32.88,1621.0,567.5, + 1990000.0,16.74,6.973,18.56,133.8,721.6,256.8,1.653,34.32,35.67, + 32.88,20.57,13.37,147.4,1356000.0,154.1,155.8,41.32,373.3,1404.0, + 746.1,1.582,33.07,28.48,32.88, +]; + +/// pv(105) from verner.f +pub const VERNER_PV: [f64; 105] = [ + 2.963,31.88,2.963,4.895,2.916,2.963,10.52,11.7,3.157,2.963, + 17.28,16.18,9.54,2.624,2.963,5.101,8.578,15.93,7.457,2.581, + 2.963,3.928,8.773,9.156,17.06,6.003,2.315,2.963,17.64,8.943, + 6.822,8.785,26.47,5.495,2.336,2.963,7.275,10.5,6.614,9.203, + 9.718,24.46,6.448,2.255,2.963,8.355,7.81,10.05,3.056,8.999, + 8.836,25.5,5.585,2.002,2.963,3.839,7.362,9.803,9.714,8.26, + 2.832,7.681,8.476,5.265,1.678,2.963,15.74,3.61,7.117,6.487, + 10.06,9.202,8.857,9.385,14.44,5.46,2.161,2.963,3.642,9.049, + 3.477,11.8,6.724,20.84,6.204,8.659,8.406,26.55,5.085,1.915, + 2.963,3.546,11.91,13.36,3.353,9.98,2.4,16.06,8.986,8.503, + 8.302,24.25,4.728,2.135,2.963, +]; + +/// s95(105) from verner.f +pub const VERNER_S95: [f64; 105] = [ + 54750.0,4470.0,13690.0,156.4,320.1,6083.0,130.6,97.96,545.8,3422.0, + 96.98,103.7,86.05,284.6,2190.0,74.21,66.49,80.67,81.11,234.4, + 1521.0,47.48,50.02,52.35,70.46,73.04,151.9,1117.0,32.37,35.84, + 39.39,41.23,57.35,60.29,132.9,855.4,22.95,47.98,31.44,53.02, + 36.8,46.68,48.9,103.9,675.9,16.64,27.83,29.43,30.27,30.97, + 32.32,50.11,37.19,66.95,547.5,248.6,18.89,34.66,25.51,37.53, + 26.54,27.45,36.13,38.5,39.95,452.5,202.3,204.9,18.77,22.12, + 23.5,32.78,34.07,27.21,36.99,32.9,61.4,380.2,173.5,184.2, + 199.0,24.94,25.72,27.86,26.53,29.89,28.57,32.23,32.72,40.36, + 323.9,153.2,183.2,219.7,232.6,31.0,23.98,24.74,31.35,26.41, + 33.43,28.32,38.8,47.54,279.3, +]; + +/// e95(105) from verner.f +pub const VERNER_E95: [f64; 105] = [ + 0.4298,5.996,1.72,27.4,20.06,3.871,40.93,47.59,17.6,6.879, + 61.55,59.84,65.92,33.36,10.75,86.55,91.13,83.7,84.12,46.24, + 15.48,127.0,124.2,122.0,107.0,106.0,69.43,21.08,177.4,169.0, + 162.0,159.3,137.7,135.4,87.09,27.54,239.0,166.0,205.5,160.3, + 192.5,173.7,171.1,113.1,34.85,314.4,245.2,238.7,236.0,234.3, + 230.8,188.6,219.3,158.6,43.04,36.55,326.6,242.6,284.1,236.0, + 280.6,277.7,246.4,240.6,226.8,52.11,49.37,49.4,360.7,334.5, + 325.9,277.7,274.2,308.2,267.1,285.8,204.2,62.03,64.45,61.54, + 60.16,348.2,343.2,326.8,339.6,319.3,330.5,311.7,313.7,273.8, + 72.81,78.08,71.54,66.52,64.82,346.0,379.9,375.9,344.2,367.9, + 335.6,359.9,315.0,275.2,84.47, +]; + +/// y95(105) from verner.f +pub const VERNER_Y95: [f64; 105] = [ + 32.88,2.199,32.88,33.82,7.391,32.88,121.2,1166.0,17.19,32.88, + 73.54,79.15,190.6,21.63,32.88,54.98,96.09,74.71,74.59,21.83, + 32.88,138.0,91.0,94.28,53.42,55.47,26.27,32.88,381.2,189.4, + 110.4,114.1,54.86,56.82,25.35,32.88,1257.0,50.0,123.0,50.0, + 79.33,58.76,61.37,26.57,32.88,204200.0,60.75,65.25,67.34,69.07, + 71.67,50.0,81.81,33.52,32.88,322.2,252.7,50.0,69.77,50.0, + 72.37,75.12,49.68,51.98,53.15,32.88,10790.0,41120.0,140.1,71.47, + 61.73,50.0,50.0,51.08,50.0,53.84,27.78,32.88,11310.0,2404.0, + 508.2,32.6,33.76,50.0,34.78,50.0,36.6,50.0,42.95,35.67, + 32.88,5765000.0,353.7,116.9,118.8,19.79,50.0,50.0,22.6,50.0, + 24.87,50.0,30.34,28.48,32.88, +]; + +/// yw95(105) from verner.f +pub const VERNER_YW95: [f64; 105] = [ + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.1465,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.01463,2.223e-05,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.02337,0.007839, + 0.02016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0002774,0.000287,0.0008658,0.0008417,0.0,0.0,0.0,0.0,0.0, + 0.0,0.0,0.0,0.0,0.0, +]; + +/// p95(105) from verner.f +pub const VERNER_P95: [f64; 105] = [ + 2.963,6.098,2.963,1.49,2.916,2.963,1.348,1.022,3.157,2.963, + 1.438,1.436,1.21,2.624,2.963,1.503,1.338,1.442,1.428,2.581, + 2.963,1.252,1.335,1.335,1.552,1.538,2.315,2.963,1.083,1.185, + 1.289,1.287,1.54,1.533,2.336,2.963,0.9638,1.65,1.263,1.65, + 1.377,1.511,1.501,2.255,2.963,0.845,1.42,1.424,1.422,1.416, + 1.411,1.65,1.396,2.002,2.963,3.57,1.12,1.65,1.414,1.65, + 1.405,1.397,1.579,1.575,1.678,2.963,2.96,2.995,1.238,1.413, + 1.464,1.65,1.65,1.539,1.65,1.56,2.161,2.963,2.762,2.92, + 3.11,1.732,1.73,1.65,1.721,1.65,1.712,1.65,1.676,1.915, + 2.963,2.639,3.133,3.529,3.547,2.094,1.65,1.65,2.02,1.65, + 1.982,1.65,1.925,2.135,2.963, +]; + +/// iv0(14) from verner.f +pub const VERNER_IV0: [f64; 14] = [ + 0.0,1.0,3.0,6.0,10.0,15.0,21.0,28.0,36.0,45.0, + 55.0,66.0,78.0,91.0, +]; + +/// t18 (from verner.f) +pub const VERNER_T18: f64 = 1e-18; + +/// mver (from verner.f) +pub const VERNER_MVER: f64 = 105.0; + +// ========== voigt.f ========== + +/// icomp (from voigt.f, 未知维度,共 1 个值) +pub const VOIGT_ICOMP: [f64; 1] = [ + 0.0, +]; + +/// pi (from voigt.f) +pub const VOIGT_PI: f64 = 3.141592653589793; + +/// m (from voigt.f) +pub const VOIGT_M: f64 = 12.0; + +/// hh (from voigt.f) +pub const VOIGT_HH: f64 = 0.5; + +/// un (from voigt.f) +pub const VOIGT_UN: f64 = 1.0; + +/// pisq (from voigt.f) +pub const VOIGT_PISQ: f64 = 1.77245385090551; + +// ========== voigte.f ========== + +/// ak(19) from voigte.f +pub const VOIGTE_AK: [f64; 19] = [ + -1.12470432,-0.15516677,3.28867591,-2.34357915,0.42139162,-4.48480194,9.39456063,-6.61487486,1.98919585,-0.2204165, + 0.554153432,0.278711796,-0.188325687,0.042991293,-0.003278278,0.979895023,-0.962846325,0.532770573,-0.122727278, +]; + +/// sqp (from voigte.f, 未知维度,共 1 个值) +pub const VOIGTE_SQP: [f64; 1] = [ + 1.772453851, +]; + +/// un (from voigte.f) +pub const VOIGTE_UN: f64 = 1.0; + +/// two (from voigte.f) +pub const VOIGTE_TWO: f64 = 2.0; + +// ========== wn.f ========== + +/// p1 (from wn.f) +pub const WN_P1: f64 = 0.1402; + +/// p2 (from wn.f) +pub const WN_P2: f64 = 0.1285; + +/// p4 (from wn.f) +pub const WN_P4: f64 = 3.15; + +/// p5 (from wn.f) +pub const WN_P5: f64 = 4.0; + +/// tkn (from wn.f) +pub const WN_TKN: f64 = 3.01; + +/// ckn (from wn.f) +pub const WN_CKN: f64 = 5.33333333; + +/// cb0 (from wn.f) +pub const WN_CB0: f64 = 859000000000000.0; + +// ========== wnstor.f ========== + +/// ccor (from wnstor.f) +pub const WNSTOR_CCOR: f64 = 0.09; + +/// p1 (from wnstor.f) +pub const WNSTOR_P1: f64 = 0.1402; + +/// p2 (from wnstor.f) +pub const WNSTOR_P2: f64 = 0.1285; + +/// p4 (from wnstor.f) +pub const WNSTOR_P4: f64 = 3.15; + +/// p5 (from wnstor.f) +pub const WNSTOR_P5: f64 = 4.0; + +/// tkn (from wnstor.f) +pub const WNSTOR_TKN: f64 = 3.01; + +/// ckn (from wnstor.f) +pub const WNSTOR_CKN: f64 = 5.33333333; + +/// cb0 (from wnstor.f) +pub const WNSTOR_CB0: f64 = 859000000000000.0; + +// ========== xk2dop.f ========== + +/// pi2sq (from xk2dop.f) +pub const XK2DOP_PI2SQ: f64 = 2.506628275; + +/// pisq (from xk2dop.f) +pub const XK2DOP_PISQ: f64 = 1.772453851; + +/// un (from xk2dop.f) +pub const XK2DOP_UN: f64 = 1.0; + +/// a1 (from xk2dop.f) +pub const XK2DOP_A1: f64 = -0.1117897; + +/// a2 (from xk2dop.f) +pub const XK2DOP_A2: f64 = -0.1249099917; + +/// a3 (from xk2dop.f) +pub const XK2DOP_A3: f64 = -0.009136358767; + +/// a4 (from xk2dop.f) +pub const XK2DOP_A4: f64 = -0.0003370280896; + +/// b1 (from xk2dop.f) +pub const XK2DOP_B1: f64 = 0.1566124168; + +/// b2 (from xk2dop.f) +pub const XK2DOP_B2: f64 = 0.00901326166; + +/// b3 (from xk2dop.f) +pub const XK2DOP_B3: f64 = 0.0001908481163; + +/// b4 (from xk2dop.f) +pub const XK2DOP_B4: f64 = -1.54741775e-07; + +/// b5 (from xk2dop.f) +pub const XK2DOP_B5: f64 = -6.657439727e-09; + +/// c1 (from xk2dop.f) +pub const XK2DOP_C1: f64 = 19.15049608; + +/// c2 (from xk2dop.f) +pub const XK2DOP_C2: f64 = 100.7986843; + +/// c3 (from xk2dop.f) +pub const XK2DOP_C3: f64 = 129.5307533; + +/// c4 (from xk2dop.f) +pub const XK2DOP_C4: f64 = -31.43372468; + +/// d1 (from xk2dop.f) +pub const XK2DOP_D1: f64 = 19.68910391; + +/// d2 (from xk2dop.f) +pub const XK2DOP_D2: f64 = 110.2576321; + +/// d3 (from xk2dop.f) +pub const XK2DOP_D3: f64 = 169.4911399; + +/// d4 (from xk2dop.f) +pub const XK2DOP_D4: f64 = -16.69969409; + +/// d5 (from xk2dop.f) +pub const XK2DOP_D5: f64 = -36.66448; + +// ========== zmrho.f ========== + +/// pisq (from zmrho.f) +pub const ZMRHO_PISQ: f64 = 1.77245385090551; diff --git a/src/lib.rs b/src/lib.rs index c71407a..7eafd07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,20 @@ //! //! A progressive refactoring of the TLUSTY stellar atmosphere modeling //! software from Fortran to Rust. +//! +//! # 模块结构 +//! +//! - `state`: 状态管理 (COMMON 块转换) +//! - `constants`: 物理常数和维度参数 +//! - `config`: 运行时配置 +//! - `atomic`: 原子/离子/能级数据 +//! - `model`: 大气模型状态 +//! - `arrays`: 大型计算数组 +//! - `math`: 数学工具函数 +//! - `data`: 静态数据数组 +//! - `physics`: 物理计算模块 +pub mod data; pub mod math; pub mod physics; +pub mod state; diff --git a/src/math/angset.rs b/src/math/angset.rs new file mode 100644 index 0000000..74269ea --- /dev/null +++ b/src/math/angset.rs @@ -0,0 +1,168 @@ +//! Compton 散射角度设置。 +//! +//! 重构自 TLUSTY `angset.f`。 +//! +//! 设置角度点和角度相关量,用于处理 Compton 散射。 + +use crate::state::{Comptn, MMUC}; + +// ============================================================================ +// 常量 +// ============================================================================ + +const THREE: f64 = 3.0; +const FIVE: f64 = 5.0; +const ZERO: f64 = 0.0; +const TR16: f64 = 3.0 / 16.0; + +// ============================================================================ +// ANGSET - 角度设置 +// ============================================================================ + +/// 设置 Compton 散射的角度点和角度相关量。 +/// +/// 使用 Gauss-Legendre 积分在区间 μ=[0,1] 上设置角度点, +/// 然后扩展到 μ=[-1,1] 区间。 +/// +/// # 参数 +/// +/// - `comptn` - Compton 散射参数结构 (会被修改) +/// - `nmuc_init` - 初始角度点数 (在 μ=[0,1] 区间) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// subroutine angset +/// call gauleg(zero,un,amu0,wtmu0,nmuc,mmuc) +/// do i=1,nmuc +/// amuc(i)=-amu0(nmuc-i+1) +/// amuc(i+nmuc)=amu0(i) +/// wtmuc(i)=wtmu0(nmuc-i+1) +/// wtmuc(i+nmuc)=wtmu0(i) +/// end do +/// nmuc=2*nmuc +/// ... +/// end +/// ``` +pub fn angset(comptn: &mut Comptn, nmuc_init: usize) { + let nmuc0 = nmuc_init; + + // 检查数组边界 + if 2 * nmuc0 > MMUC { + panic!( + "ANGSET: nmuc_init={} too large, max is {}", + nmuc0, + MMUC / 2 + ); + } + + // 在 [0, 1] 区间上设置 Gauss-Legendre 积分点 + let (amu0, wtmu0) = super::gauleg(ZERO, 1.0, nmuc0); + + // 扩展到 [-1, 1] 区间 + // Fortran: amuc(i) = -amu0(nmuc-i+1), amuc(i+nmuc) = amu0(i) + // 这意味着先放负值(从大到小),再放正值(从小到大) + for i in 0..nmuc0 { + let j = nmuc0 - 1 - i; // Fortran nmuc-i+1 转换为 0-indexed + comptn.amuc[i] = -amu0[j]; + comptn.amuc[i + nmuc0] = amu0[i]; + comptn.wtmuc[i] = wtmu0[j]; + comptn.wtmuc[i + nmuc0] = wtmu0[i]; + } + + // 更新角度点数 + comptn.nmuc = (2 * nmuc0) as i32; + let nmuc = comptn.nmuc as usize; + + // 计算角度乘积 + for i in 0..nmuc { + let a1 = comptn.amuc[i]; + comptn.amuc1[i] = a1 * comptn.wtmuc[i]; + comptn.amuc2[i] = a1 * a1 * comptn.wtmuc[i]; + comptn.amuc3[i] = a1 * a1 * a1 * comptn.wtmuc[i]; + } + + // 计算 Compton 散射系数 + for i in 0..nmuc { + let a1 = comptn.amuc[i]; + let a2 = a1 * a1; + let a3 = a1 * a2; + + for i1 in 0..nmuc { + let b1 = comptn.amuc[i1]; + let b2 = b1 * b1; + let b3 = b1 * b2; + let trw = TR16 * comptn.wtmuc[i1]; + + comptn.calph[i][i1] = (THREE * a2 * b2 - a2 - b2 + THREE) * trw; + comptn.cbeta[i][i1] = + (FIVE * (a1 * b1 + a3 * b3) - THREE * (a3 * b1 + a1 * b3)) * trw; + comptn.cgamm[i][i1] = a1 * b1 * trw; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::state::MFREQ; + + fn create_test_comptn() -> Comptn { + Comptn::default() + } + + #[test] + fn test_angset_basic() { + let mut comptn = create_test_comptn(); + angset(&mut comptn, 1); + + // 检查角度点数翻倍 + assert_eq!(comptn.nmuc, 2); + + // 检查所有数组已填充 + for i in 0..comptn.nmuc as usize { + assert!(comptn.amuc[i].abs() <= 1.0); + assert!(comptn.wtmuc[i] > 0.0); + } + } + + #[test] + fn test_angset_symmetry() { + let mut comptn = create_test_comptn(); + angset(&mut comptn, 1); + + let nmuc = comptn.nmuc as usize; + + // 检查角度对称性: amuc[0] = -amuc[1] + assert!((comptn.amuc[0] + comptn.amuc[1]).abs() < 1e-10); + + // 检查权重对称性 + assert!((comptn.wtmuc[0] - comptn.wtmuc[1]).abs() < 1e-10); + } + + #[test] + fn test_angset_coefficients() { + let mut comptn = create_test_comptn(); + angset(&mut comptn, 1); + + let nmuc = comptn.nmuc as usize; + + // 检查系数矩阵已填充 + for i in 0..nmuc { + for j in 0..nmuc { + // 系数应该是有界值 + assert!(comptn.calph[i][j].abs() < 10.0); + assert!(comptn.cbeta[i][j].abs() < 10.0); + assert!(comptn.cgamm[i][j].abs() < 10.0); + } + } + } + + #[test] + #[should_panic] + fn test_angset_too_large() { + let mut comptn = create_test_comptn(); + // nmuc_init > MMUC/2 应该 panic + angset(&mut comptn, MMUC + 1); + } +} diff --git a/src/math/butler.rs b/src/math/butler.rs new file mode 100644 index 0000000..4af31f1 --- /dev/null +++ b/src/math/butler.rs @@ -0,0 +1,271 @@ +//! 氢原子碰撞激发速率。 +//! +//! 重构自 TLUSTY `butler.f` +//! +//! 基于 Przybilla & Butler (2004, ApJ) 表3的插值。 + +use std::sync::OnceLock; + +/// Butler 数据。 +struct ButlerData { + tref: [f64; 16], + colstr: [[f64; 21]; 16], +} + +static BUTLER_DATA: OnceLock = OnceLock::new(); + +fn get_butler_data() -> &'static ButlerData { + BUTLER_DATA.get_or_init(|| { + // 参考温度 (K) + let tref = [ + 2.5e3, 5e3, 7.5e3, 1e4, 1.5e4, 2e4, 2.5e4, 3e4, 4e4, 5e4, 6e4, 8e4, 1e5, 1.5e5, 2e5, + 2.5e5, + ]; + + // 碰撞强度数据 (16个温度 x 21个跃迁) + // J=1,21 对应 (NI,NJ)={(1,2),(1,3),...,(1,7),(2,3),...,(6,7)} + // I=1,16 对应 T={2.5e3,...,2.5e5} + let colstr = [ + // T = 2500 K + [ + 6.40e-1, 2.20e-1, 9.93e-2, 4.92e-2, 2.97e-2, 5.03e-2, 2.35e1, 1.07e1, 5.22e0, + 2.91e0, 5.25e0, 1.50e2, 7.89e1, 4.13e1, 7.60e1, 5.90e2, 2.94e2, 4.79e2, 1.93e3, + 1.95e3, 6.81e3, + ], + // T = 5000 K + [ + 6.98e-1, 2.40e-1, 1.02e-1, 5.84e-2, 4.66e-2, 6.72e-2, 2.78e1, 1.15e1, 5.90e0, + 4.53e0, 7.26e0, 1.90e2, 9.01e1, 6.11e1, 1.07e2, 8.17e2, 4.21e2, 7.06e2, 2.91e3, + 3.24e3, 1.17e4, + ], + // T = 7500 K + [ + 7.57e-1, 2.50e-1, 1.10e-1, 7.17e-2, 6.28e-2, 7.86e-2, 3.09e1, 1.23e1, 6.96e0, + 6.06e0, 8.47e0, 2.28e2, 1.07e2, 8.21e1, 1.25e2, 1.07e3, 5.78e2, 8.56e2, 4.00e3, + 4.20e3, 1.50e4, + ], + // T = 10000 K + [ + 8.09e-1, 2.61e-1, 1.22e-1, 8.58e-2, 7.68e-2, 8.74e-2, 3.38e1, 1.34e1, 8.15e0, + 7.32e0, 9.27e0, 2.70e2, 1.26e2, 1.01e2, 1.37e2, 1.35e3, 7.36e2, 9.66e2, 5.04e3, + 4.95e3, 1.73e4, + ], + // T = 15000 K + [ + 8.97e-1, 2.88e-1, 1.51e-1, 1.12e-1, 9.82e-2, 1.00e-1, 4.01e1, 1.62e1, 1.04e1, + 9.17e0, 1.03e1, 3.64e2, 1.66e2, 1.31e2, 1.52e2, 1.93e3, 1.02e3, 1.11e3, 6.81e3, + 6.02e3, 2.03e4, + ], + // T = 20000 K + [ + 9.78e-1, 3.22e-1, 1.80e-1, 1.33e-1, 1.14e-1, 1.10e-1, 4.71e1, 1.90e1, 1.23e1, + 1.05e1, 1.08e1, 4.66e2, 2.03e2, 1.54e2, 1.61e2, 2.47e3, 1.26e3, 1.21e3, 8.20e3, + 6.76e3, 2.21e4, + ], + // T = 25000 K + [ + 1.06e0, 3.59e-1, 2.06e-1, 1.50e-1, 1.25e-1, 1.16e-1, 5.45e1, 2.18e1, 1.39e1, + 1.14e1, 1.12e1, 5.70e2, 2.37e2, 1.72e2, 1.68e2, 2.96e3, 1.46e3, 1.29e3, 9.29e3, + 7.29e3, 2.33e4, + ], + // T = 30000 K + [ + 1.15e0, 3.96e-1, 2.28e-1, 1.64e-1, 1.33e-1, 1.21e-1, 6.20e1, 2.44e1, 1.52e1, + 1.21e1, 1.14e1, 6.72e2, 2.68e2, 1.86e2, 1.72e2, 3.40e3, 1.64e3, 1.34e3, 1.02e4, + 7.70e3, 2.41e4, + ], + // T = 40000 K + [ + 1.32e0, 4.64e-1, 2.66e-1, 1.85e-1, 1.45e-1, 1.27e-1, 7.71e1, 2.89e1, 1.74e1, + 1.31e1, 1.17e1, 8.66e2, 3.19e2, 2.08e2, 1.78e2, 4.14e3, 1.92e3, 1.41e3, 1.15e4, + 8.26e3, 2.52e4, + ], + // T = 50000 K + [ + 1.51e0, 5.26e-1, 2.95e-1, 2.01e-1, 1.53e-1, 1.31e-1, 9.14e1, 3.27e1, 1.90e1, + 1.38e1, 1.18e1, 1.04e3, 3.62e2, 2.24e2, 1.81e2, 4.75e3, 2.15e3, 1.46e3, 1.26e4, + 8.63e3, 2.60e4, + ], + // T = 60000 K + [ + 1.68e0, 5.79e-1, 3.18e-1, 2.12e-1, 1.58e-1, 1.34e-1, 1.05e2, 3.60e1, 2.03e1, + 1.44e1, 1.19e1, 1.19e3, 3.98e2, 2.36e2, 1.83e2, 5.25e3, 2.33e3, 1.50e3, 1.34e4, + 8.88e3, 2.69e4, + ], + // T = 80000 K + [ + 2.02e0, 6.70e-1, 3.55e-1, 2.29e-1, 1.65e-1, 1.35e-1, 1.29e2, 4.14e1, 2.23e1, + 1.51e1, 1.19e1, 1.46e3, 4.53e2, 2.53e2, 1.85e2, 6.08e3, 2.61e3, 1.55e3, 1.49e4, + 9.21e3, 2.90e4, + ], + // T = 100000 K + [ + 2.33e0, 7.43e-1, 3.83e-1, 2.39e-1, 1.70e-1, 1.37e-1, 1.51e2, 4.56e1, 2.37e1, + 1.56e1, 1.20e1, 1.67e3, 4.95e2, 2.65e2, 1.86e2, 6.76e3, 2.81e3, 1.57e3, 1.63e4, + 9.43e3, 3.17e4, + ], + // T = 150000 K + [ + 2.97e0, 8.80e-1, 4.30e-1, 2.59e-1, 1.77e-1, 1.39e-1, 1.93e2, 5.31e1, 2.61e1, + 1.63e1, 1.19e1, 2.08e3, 5.68e2, 2.83e2, 1.87e2, 8.08e3, 3.15e3, 1.61e3, 1.97e4, + 9.78e3, 3.94e4, + ], + // T = 200000 K + [ + 3.50e0, 9.79e-1, 4.63e-1, 2.71e-1, 1.82e-1, 1.39e-1, 2.26e2, 5.83e1, 2.78e1, + 1.68e1, 1.19e1, 2.39e3, 6.16e2, 2.94e2, 1.86e2, 9.13e3, 3.36e3, 1.62e3, 2.27e4, + 1.00e4, 4.73e4, + ], + // T = 250000 K (not used, for completeness) + [ + 3.95e0, 1.06e0, 4.88e-1, 2.81e-1, 1.85e-1, 1.40e-1, 2.52e2, 6.23e1, 2.89e1, + 1.71e1, 1.19e1, 2.62e3, 6.51e2, 3.02e2, 1.87e2, 1.00e4, 3.51e3, 1.63e3, 2.54e4, + 1.02e4, 5.50e4, + ], + ]; + + ButlerData { tref, colstr } + }) +} + +/// 氢原子碰撞激发速率。 +/// +/// 基于 Przybilla & Butler (2004, ApJ) 表3的插值计算电子碰撞激发速率。 +/// +/// # 参数 +/// +/// * `ni` - 下能级主量子数 (1-6) +/// * `nj` - 上能级主量子数 (2-7) +/// * `t` - 温度 (K) +/// * `u0` - hν/kT +/// +/// # 返回值 +/// +/// `(col, ierr)` 元组: +/// - `col`: 碰撞速率 (cm³/s) +/// - `ierr`: 错误码 (0=正常, 1=温度超出范围, 2=量子数超出范围) +/// +/// # 备注 +/// +/// 基于 Przybilla & Butler (2004, ApJ) 表3。 +pub fn butler(ni: i32, nj: i32, t: f64, u0: f64) -> (f64, i32) { + const NL: i32 = 7; + + let mut ierr = 0; + let mut col = 0.0; + + // 检查温度范围 + if t < 2.5e3 || t >= 2.5e5 { + ierr = 1; + } + + // 检查量子数范围 + if ni < 1 || ni > NL - 1 || nj < 2 || nj > NL { + ierr = 2; + } + + if ierr == 0 { + // 计算 J 索引 (跃迁索引) + let mut j: usize = 0; + for _i in 1..ni { + j += (NL - _i) as usize; + } + for _k in (ni + 1)..=nj { + j += 1; + } + + let data = get_butler_data(); + + // 找到最近的温度点 + let mut ilow: usize = 0; + while ilow < 15 && t >= data.tref[ilow + 1] { + ilow += 1; + } + + let mut ihig: usize = 15; + while ihig > 0 && t < data.tref[ihig - 1] { + ihig -= 1; + } + + if ihig == ilow { + ihig += 1; + } + + // 对数-对数线性插值碰撞强度 + let sl = (data.colstr[ihig][j - 1].log10() - data.colstr[ilow][j - 1].log10()) + / (data.tref[ihig].log10() - data.tref[ilow].log10()); + let or = data.colstr[ihig][j - 1].log10() - sl * data.tref[ihig].log10(); + col = 10f64.powf(t.log10() * sl + or); + + // 计算速率 + col = 8.631e-6 / (2.0 * (ni as f64).powi(2)) / t.sqrt() * (-u0).exp() * col; + } + + (col, ierr) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_butler_lyman_alpha() { + // Lyman-α: n=1 → n=2 + let (col, ierr) = butler(1, 2, 10000.0, 11.87); + assert_eq!(ierr, 0); + assert!(col > 0.0); + } + + #[test] + fn test_butler_balmer_alpha() { + // Balmer-α: n=2 → n=3 + let (col, ierr) = butler(2, 3, 10000.0, 1.89); + assert_eq!(ierr, 0); + assert!(col > 0.0); + } + + #[test] + fn test_butler_low_temp() { + // 低温边界 + let (col, ierr) = butler(1, 2, 3000.0, 10.0); + assert_eq!(ierr, 0); + assert!(col > 0.0); + } + + #[test] + fn test_butler_high_temp() { + // 高温边界 + let (col, ierr) = butler(1, 2, 200000.0, 0.5); + assert_eq!(ierr, 0); + assert!(col > 0.0); + } + + #[test] + fn test_butler_temp_out_of_range_low() { + // 温度过低 + let (_, ierr) = butler(1, 2, 1000.0, 10.0); + assert_eq!(ierr, 1); + } + + #[test] + fn test_butler_temp_out_of_range_high() { + // 温度过高 + let (_, ierr) = butler(1, 2, 300000.0, 0.5); + assert_eq!(ierr, 1); + } + + #[test] + fn test_butler_quantum_out_of_range() { + // 量子数超出范围 + let (_, ierr) = butler(7, 8, 10000.0, 1.0); + assert_eq!(ierr, 2); + } + + #[test] + fn test_butler_n6_to_n7() { + // n=6 → n=7 跃迁 + let (col, ierr) = butler(6, 7, 10000.0, 0.1); + assert_eq!(ierr, 0); + assert!(col > 0.0); + } +} diff --git a/src/math/cion.rs b/src/math/cion.rs new file mode 100644 index 0000000..532cd59 --- /dev/null +++ b/src/math/cion.rs @@ -0,0 +1,231 @@ +//! 碰撞电离速率。 +//! +//! 重构自 TLUSTY `cion.f` +//! +//! 基于 Raymond 的方法,使用 Tim Kallman 的程序。 + +use crate::math::expo; + +/// 碰撞电离速率系数数组。 +struct CionData { + a0: [f64; 30], + a1: [f64; 30], + a2: [f64; 30], + a3: [f64; 30], + b0: [f64; 30], + b1: [f64; 30], + b2: [f64; 30], + b3: [f64; 30], + c0: [f64; 30], + c1: [f64; 30], + c2: [f64; 30], + c3: [f64; 30], + d0: [f64; 30], + d1: [f64; 30], + d2: [f64; 30], + d3: [f64; 30], +} + +use std::sync::OnceLock; + +static CION_DATA: OnceLock = OnceLock::new(); + +fn get_cion_data() -> &'static CionData { + CION_DATA.get_or_init(|| { + // 来自 Summers 等人的拟合系数 + // sm younger jqsrt 26, 329; 27, 541; 29, 61 with moores for undone + // a0 for b-like ion has twice 2s plus one 2p as in summers et al + CionData { + a0: [ + 13.5, 27.0, 9.07, 11.80, 20.2, 28.6, 37.0, 45.4, 53.8, 62.2, 11.7, 38.8, 37.27, + 46.7, 57.4, 67.0, 77.8, 90.1, 106.0, 120.8, 135.6, 150.4, 165.2, 180.0, 194.8, + 209.6, 224.4, 239.2, 154.0, 268.8, + ], + a1: [ + -14.2, -60.1, 4.30, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + a2: [ + 40.6, 140.0, 7.69, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + a3: [ + -17.1, -89.8, -7.53, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + b0: [ + -4.81, -9.62, -2.47, -3.28, -5.96, -8.64, -11.32, -14.00, -16.68, -19.36, -4.29, + -16.7, -14.58, -16.95, -19.93, -23.05, -26.00, -29.45, -34.25, -38.92, -43.59, + -48.26, -52.93, -57.60, -62.27, -66.94, -71.62, -76.29, -80.96, -85.63, + ], + b1: [ + 9.77, 33.1, -3.78, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + b2: [ + -28.3, -82.5, -3.59, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + b3: [ + 11.4, 54.6, 3.34, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + c0: [ + 1.85, 3.69, 1.34, 1.64, 2.31, 2.984, 3.656, 4.328, 5.00, 5.672, 1.061, 1.87, 3.26, + 5.07, 6.67, 8.10, 9.92, 11.79, 7.953, 8.408, 8.863, 9.318, 9.773, 10.228, 10.683, + 11.138, 11.593, 12.048, 12.505, 12.96, + ], + c1: [ + 0.0, 4.32, 0.343, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + c2: [ + 0.0, -2.527, -2.46, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + c3: [ + 0.0, 0.262, 1.38, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + d0: [ + -10.9, -21.7, -5.37, -7.58, -12.66, -17.74, -22.82, -27.9, -32.98, -38.06, -7.34, + -28.8, -24.87, -30.5, -37.9, -45.3, -53.8, -64.6, -54.54, -61.70, -68.86, -76.02, + -83.18, -90.34, -97.50, -104.66, -111.82, -118.98, -126.14, -133.32, + ], + d1: [ + 8.90, 42.5, -12.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + d2: [ + -35.7, -131.0, -8.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + d3: [ + 16.5, 87.4, 1.23, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + ], + } + }) +} + +/// 碰撞电离速率。 +/// +/// 基于 Raymond 的方法计算碰撞电离速率。 +/// +/// # 参数 +/// +/// * `n` - 核电荷数 +/// * `j` - 电离级 (1 = 中性) +/// * `e` - 价壳层电离阈值 (eV) +/// * `t` - 温度 (K) +/// +/// # 返回值 +/// +/// 碰撞电离速率 (cm³/s)。 +/// +/// # 备注 +/// +/// 使用 Tim Kallman 的程序,基于 Summers 等人的拟合系数。 +/// 注意:此程序只考虑价壳层电离。 +/// 对于每个电离级应只调用一次,使用最低的价壳层电离阈值。 +pub fn cion(n: i32, j: i32, e: f64, t: f64) -> f64 { + let chir = t / (11590.0 * e); + + // 低温下返回 0 + if chir <= 0.0115 { + return 0.0; + } + + let chi = chir; + let ch2 = chi * chi; + let ch3 = ch2 * chi; + + // 计算 alpha 和 beta + let alpha = (0.001193 + 0.9764 * chi + 0.6604 * ch2 + 0.02590 * ch3) + / (1.0 + 1.488 * chi + 0.2972 * ch2 + 0.004925 * ch3); + let beta = (-0.0005725 + 0.01345 * chi + 0.8691 * ch2 + 0.03404 * ch3) + / (1.0 + 2.197 * chi + 0.2457 * ch2 + 0.002503 * ch3); + + let j2 = (j * j) as f64; + let j3 = j2 * j as f64; + let jf = j as f64; + let iso = (n - j + 1) as usize; + + // 索引检查 + if iso < 1 || iso > 30 { + return 0.0; + } + let iso_idx = iso - 1; // 转换为 0-indexed + + let data = get_cion_data(); + + // 计算系数 a, b, c, d + let (a, b, c, d) = if n == 26 && j == 2 { + // Fe II 实验电离 (Montague et al.), D. Neufeld 拟合 + (-13.825, -11.0395, 21.07262, 0.0) + } else { + let a = data.a0[iso_idx] + data.a1[iso_idx] / jf + data.a2[iso_idx] / j2 + data.a3[iso_idx] / j3; + let b = data.b0[iso_idx] + data.b1[iso_idx] / jf + data.b2[iso_idx] / j2 + data.b3[iso_idx] / j3; + let c = data.c0[iso_idx] + data.c1[iso_idx] / jf + data.c2[iso_idx] / j2 + data.c3[iso_idx] / j3; + let d = data.d0[iso_idx] + data.d1[iso_idx] / jf + data.d2[iso_idx] / j2 + data.d3[iso_idx] / j3; + (a, b, c, d) + }; + + let ch = 1.0 / chi; + let fchi = 0.3 * ch * (a + b * (1.0 + ch) + (c - (a + b * (2.0 + ch)) * ch) * alpha + d * beta * ch); + + 2.2e-6 * chir.sqrt() * fchi * expo(-1.0 / chir) / (e * e.sqrt()) +} + +#[cfg(test)] +mod tests { + use super::*; + use approx::assert_relative_eq; + + #[test] + fn test_cion_hydrogen() { + // H I 电离 (n=1, j=1, e=13.6 eV) + let result = cion(1, 1, 13.6, 10000.0); + assert!(result.is_finite()); + assert!(result >= 0.0); + } + + #[test] + fn test_cion_helium() { + // He I 电离 (n=2, j=1, e=24.6 eV) + let result = cion(2, 1, 24.6, 20000.0); + assert!(result.is_finite()); + assert!(result >= 0.0); + } + + #[test] + fn test_cion_low_temp() { + // 低温下应返回 0 + let result = cion(1, 1, 13.6, 1000.0); + assert_relative_eq!(result, 0.0, epsilon = 1e-30); + } + + #[test] + fn test_cion_fe_ii() { + // Fe II 特殊情况 (n=26, j=2) + let result = cion(26, 2, 7.9, 10000.0); + assert!(result.is_finite()); + assert!(result >= 0.0); + } + + #[test] + fn test_cion_high_temp() { + // 高温 + let result = cion(1, 1, 13.6, 50000.0); + assert!(result.is_finite()); + assert!(result > 0.0); + } + + #[test] + fn test_cion_carbon() { + // C I 电离 (n=6, j=1, e=11.26 eV) + let result = cion(6, 1, 11.26, 15000.0); + assert!(result.is_finite()); + assert!(result >= 0.0); + } +} diff --git a/src/math/ckoest.rs b/src/math/ckoest.rs new file mode 100644 index 0000000..0c50f51 --- /dev/null +++ b/src/math/ckoest.rs @@ -0,0 +1,137 @@ +//! Koester 拟合的 He I 光电离截面。 +//! +//! 重构自 TLUSTY `ckoest.f`。 +//! +//! 参考:Koester (1985, AA 149, 423) + +use crate::state::CAS; + +/// 基本光子截面常数 +const PHOT0: f64 = 2.815e29; + +/// Koester 拟合系数表 +/// COEF(3, 11) - 每组 3 个系数,共 11 组 +const COEF: [[f64; 11]; 3] = [ + // COEF(1, *) + [ + -58.229, -68.438, -67.310, -92.020, -68.936, -63.408, -63.778, -76.903, -61.027, -83.287, + -83.287, + ], + // COEF(2, *) + [ + 4.3965, 5.7453, 6.1831, 10.313, 5.2666, 3.8797, 4.5102, 6.3639, 3.1833, 7.1751, 7.1751, + ], + // COEF(3, *) + [ + -0.22134, -0.26277, -0.32244, -0.45090, -0.15812, -0.12479, -0.18213, -0.21565, + -0.043675, -0.20821, -0.20821, + ], +]; + +/// 每个主量子数 n 的起始索引 +/// n=1: 索引 1, n=2: 索引 2, n=3: 索引 6, n=4: 索引 10 +const IST: [i32; 3] = [1, 2, 6]; + +/// 计算 He I 光电离截面 (Koester 拟合)。 +/// +/// # 参数 +/// +/// - `s` - 多重性 (1 或 3) +/// - `l` - 角动量量子数 (0, 1, 2; L > 2 使用类氢公式) +/// - `n` - 主量子数 +/// - `freq` - 频率 (Hz) +/// - `gg` - 统计权重 +/// +/// # 返回 +/// +/// 光电离截面 (cm²) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION CKOEST(S,L,N,FREQ,GG) +/// ... +/// X=LOG(CAS/FREQ) +/// CKOEST=EXP(COEF(1,NSL)+X*(COEF(2,NSL)+X*COEF(3,NSL)))/GG +/// END +/// ``` +pub fn ckoest(s: i32, l: i32, n: i32, freq: f64, gg: f64) -> f64 { + if l > 2 { + // L > 2: 类氢公式 + let n_f = n as f64; + let gn = 2.0 * n_f * n_f; + PHOT0 / freq.powi(3) / n_f.powi(5) * (2 * l + 1) as f64 * (s as f64) / gn + } else { + // L <= 2: Koester 拟合 + let ss = (s - 1) / 2; + let ll = 2 * l; + + // 计算 n 对应的索引偏移 + let n_offset = if n <= 1 { + IST[0] + } else if n <= 2 { + IST[1] + } else if n <= 3 { + IST[2] + } else { + // n=4 时索引从 10 开始 + 10 + }; + + // NSL 是 1-indexed,转换为 0-indexed + let nsl = (n_offset + ll + ss - 1) as usize; + + // 计算 X = ln(CAS / freq) + let x = (CAS / freq).ln(); + + // 计算 σ = exp(COEF(1) + X * (COEF(2) + X * COEF(3))) / GG + let log_sigma = COEF[0][nsl] + x * (COEF[1][nsl] + x * COEF[2][nsl]); + log_sigma.exp() / gg + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ckoest_singlet_s() { + // 1S 态 (s=1, l=0, n=1) + let freq = 1e16; // 高于电离阈值 + let result = ckoest(1, 0, 1, freq, 1.0); + assert!(result > 0.0, "Cross section should be positive"); + } + + #[test] + fn test_ckoest_triplet_s() { + // 3S 态 (s=3, l=0, n=2) + let freq = 1e16; + let result = ckoest(3, 0, 2, freq, 3.0); + assert!(result > 0.0); + } + + #[test] + fn test_ckoest_high_l() { + // L > 2 使用类氢公式 + let freq = 1e16; + let result = ckoest(1, 3, 4, freq, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_ckoest_frequency_dependence() { + // 频率越高,截面越小 + let result_low = ckoest(1, 0, 2, 1e15, 1.0); + let result_high = ckoest(1, 0, 2, 1e17, 1.0); + assert!(result_low > result_high); + } + + #[test] + fn test_ckoest_n2_states() { + // n=2 的不同 L 态 + let freq = 1e15; + let result_s = ckoest(1, 0, 2, freq, 1.0); // 2S + let result_p = ckoest(1, 1, 2, freq, 3.0); // 2P + assert!(result_s > 0.0 && result_p > 0.0); + } +} diff --git a/src/math/collhe.rs b/src/math/collhe.rs new file mode 100644 index 0000000..a1108d1 --- /dev/null +++ b/src/math/collhe.rs @@ -0,0 +1,378 @@ +//! 氦原子碰撞速率系数。 +//! +//! 重构自 TLUSTY `collhe.f` +//! +//! 基于 Berrington & Kingston (J. Phys. B 20, 6631, 1987)。 +//! +//! 能级顺序(按能量递增): +//! 1: 1^1S, 2: 2^3S, 3: 2^1S, 4: 2^3P, 5: 2^1P, 6: 3^3S, 7: 3^1S, 8: 3^3P, 9: 3^3D, +//! 10: 3^1D, 11: 3^1P, 12: 4^3S, 13: 4^1S, 14: 4^3P, 15: 4^3D, 16: 4^1D, 17: 4^3F, 18: 4^1F, 19: 4^1P + +use std::sync::OnceLock; + + +/// 氦原子能级能量 (eV)。 +static ENER: OnceLock<[f64; 19]> = OnceLock::new(); + +/// 统计权重。 +static STWT: OnceLock<[f64; 19]> = OnceLock::new(); + +/// 多项式系数起始索引。 +static NSTART: OnceLock<[i32; 172]> = OnceLock::new(); + +/// 多项式系数。 +static A_DATA: OnceLock<[f64; 929]> = OnceLock::new(); + +fn get_ener() -> &'static [f64; 19] { + ENER.get_or_init(|| { + [ + 0.0,19.8198,20.6160,20.96432,21.2182, + 22.7187,22.9206,23.00731,23.0739,23.0743,23.0873, + 23.5942,23.6738,23.7081,23.7363,23.7366,23.7373, + 23.7373,23.7423, + ] + }) +} + +fn get_stwt() -> &'static [f64; 19] { + STWT.get_or_init(|| { + [ + 1.0,3.0,1.0,9.0,3.0,3.0,1.0,9.0, + 1.5e1,5.0,3.0,3.0,1.0,9.0,1.5e1,5.0,2.1e1, + 7.0,3.0, + ] + }) +} + +fn get_nstart() -> &'static [i32; 172] { + NSTART.get_or_init(|| { + [ + 1, 6, 11, 16, 20, 28, 32, 40, 44, 52, 57, 62, 67, 72, 77, 82, + 88, 92, 98,104,110,114,120,125,129,135,139,147,151,157,164,170, + 177,183,190,195,202,208,213,220,225,232,236,243,247,251,260,266, + 273,278,285,290,300,304,309,316,320,324,329,333,338,343,347,352, + 357,362,367,372,376,382,386,391,395,401,405,410,414,421,425,431, + 435,440,445,449,454,459,465,470,475,480,487,491,497,503,508,515, + 520,525,530,536,542,547,552,559,564,571,576,581,587,592,598,603, + 608,613,617,623,630,635,642,646,650,655,660,666,671,677,683,689, + 695,702,707,713,718,723,728,732,737,741,745,750,754,759,765,771, + 777,782,789,796,801,805,810,815,819,824,831,837,844,850,856,861, + 868,873,877,882,890,895,905,909,913,920,925,930, + ] + }) +} + +fn get_a_data() -> &'static [f64; 929] { + A_DATA.get_or_init(|| { + [ + 1.7339e-07, 2.7997e-08,-1.3812e-08, 2.6639e-09, 1.7776e-09, + 2.9820e-07, 7.5210e-08,-3.5975e-09, 3.2270e-09, 1.5245e-09, + 1.5601e-05, 1.5340e-06,-2.2122e-06,-1.1073e-07, 1.9249e-07, + 2.3682e-08, 1.0638e-08, 2.0959e-09, 2.8381e-10, 3.0497e-05, + 1.9252e-05, 6.3109e-06, 6.9098e-07,-2.8039e-07,-2.1128e-07, + -1.2192e-07,-4.4417e-08, 1.3896e-06, 1.5715e-07,-8.4358e-08, + -2.8800e-08, 5.9599e-08, 3.4756e-08, 1.2183e-08, 3.7999e-09, + 8.5500e-10,-3.9428e-10,-5.3999e-10,-2.2962e-10, 2.2510e-06, + 6.1436e-07,-1.2437e-07,-7.1718e-08, 5.9026e-05, 3.8150e-05, + 1.1426e-05, 9.2886e-07,-6.4827e-07,-4.4270e-07,-1.8611e-07, + -5.6403e-08, 5.8752e-06, 2.5167e-06, 2.0787e-07,-2.3353e-07, + -8.9900e-08, 5.6334e-08, 2.9313e-09, 1.7775e-09, 5.5494e-10, + -5.8914e-10, 8.1939e-06, 2.4014e-07, 3.8681e-07, 2.8446e-07, + -6.1936e-08, 1.8173e-06,-4.7530e-07,-6.6432e-08, 5.4898e-08, + -1.2377e-08, 2.0732e-05, 6.5991e-07, 1.5840e-06, 4.9920e-07, + -1.8332e-07, 3.2273e-06,-4.9880e-07,-2.4929e-07, 1.1964e-07, + -2.1996e-08, 9.7096e-08, 1.3557e-08, 7.4404e-09, 1.3858e-09, + -1.3778e-09,-8.4885e-10, 3.5068e-06,-5.0675e-07,-1.2252e-07, + 6.0514e-08, 7.0524e-06, 1.4454e-06, 8.3966e-07, 2.7203e-07, + -2.3854e-08,-8.6693e-08, 7.1193e-06, 8.3111e-09,-9.3916e-07, + -2.7944e-08, 1.7803e-07,-3.9216e-08, 9.2760e-06, 2.4761e-06, + 1.0095e-06, 3.4039e-07,-8.6900e-08,-1.1156e-07, 2.5036e-05, + -5.7791e-06,-1.8197e-06, 1.0630e-06, 9.8746e-09, 3.1048e-09, + 1.2172e-09, 1.8411e-10,-1.5835e-10,-1.4443e-10, 1.9240e-06, + 1.5012e-07, 7.9741e-08, 2.9323e-08,-1.2796e-08, 5.0457e-07, + -5.5146e-08,-2.7506e-08, 1.4341e-09, 1.3321e-05, 2.6960e-06, + 2.8059e-07, 1.7548e-08,-2.3623e-07,-1.4619e-07, 1.5294e-06, + -9.4925e-08,-1.1347e-07, 8.1980e-09, 1.3324e-04, 7.8068e-05, + 2.9238e-05, 4.2718e-06,-1.6556e-06,-1.4529e-06,-8.6046e-07, + -2.1062e-07, 2.8510e-06,-4.7936e-07,-2.4042e-07, 6.2333e-08, + 1.3493e-09, 3.5113e-10,-4.7269e-11, 2.4872e-11,-9.7136e-12, + -1.4217e-11, 1.5680e-06, 8.9272e-07, 2.8313e-07, 5.2456e-08, + -2.3404e-08,-2.7304e-08,-8.4539e-09, 1.7967e-07, 6.2133e-08, + -3.2814e-09,-3.7299e-09,-1.9587e-09,-1.6685e-09, 1.2707e-05, + 7.5029e-06, 2.8330e-06, 6.7478e-07,-1.5012e-07,-2.3916e-07, + -8.9594e-08, 7.6160e-07, 2.0422e-07,-2.5881e-08,-1.7624e-08, + -8.3518e-09,-4.1743e-09, 4.6044e-05, 2.2425e-05, 3.3079e-06, + 3.6752e-07,-8.4476e-08,-4.8455e-07,-2.5391e-07, 7.0824e-07, + 1.4917e-07,-1.2005e-07,-1.6983e-08, 1.1545e-08, 7.2866e-04, + 3.8907e-04, 9.6365e-05, 2.3153e-05, 1.8462e-07,-9.0627e-06, + -5.4332e-06, 1.0458e-08, 1.6430e-09, 5.6453e-10, 2.0276e-10, + -1.6501e-10,-1.0656e-10, 5.2198e-07, 4.2898e-08,-1.0332e-08, + -5.6754e-09,-7.1960e-09, 3.0390e-06, 1.5385e-06, 6.2110e-07, + 1.4111e-07,-3.7415e-08,-4.8395e-08,-1.7219e-08, 2.7227e-06, + 1.4381e-07,-5.5030e-08,-2.2192e-10,-2.8583e-08, 1.8417e-05, + 9.3860e-06, 3.9999e-06, 1.0424e-06,-2.1337e-07,-3.3271e-07, + -1.2684e-07, 4.6063e-06,-6.7185e-07,-2.5830e-07, 2.9976e-08, + 7.8012e-05, 3.4921e-05, 8.3012e-06, 1.5643e-06,-4.3892e-07, + -9.5318e-07,-4.6534e-07, 1.7584e-05,-2.8817e-06,-1.0081e-06, + 1.3259e-07, 1.8561e-05, 2.6602e-06,-1.7243e-06,-3.5533e-07, + 2.3315e-08, 1.6239e-08, 7.3739e-09, 1.9570e-09,-2.5667e-10, + -5.8101e-10,-2.3947e-10, 4.5821e-12, 4.5024e-11, 3.8796e-07, + 1.1239e-07,-2.9033e-08,-5.7237e-09, 2.4186e-09,-2.9670e-09, + 1.0887e-06, 4.3737e-07, 8.3753e-08, 3.6771e-08, 1.6545e-09, + -1.3849e-08,-5.8855e-09, 2.1028e-06, 4.3725e-07,-1.7621e-07, + -3.0743e-08, 1.7119e-08, 8.4698e-06, 4.5395e-06, 1.5774e-06, + 4.1647e-07,-7.9865e-08,-1.6003e-07,-6.0171e-08, 3.1692e-06, + 3.6965e-07,-4.9333e-07,-2.8856e-08, 4.2819e-08, 2.0492e-04, + 1.3705e-04, 4.0972e-05, 2.9565e-06,-1.4061e-06,-1.8775e-06, + -1.6306e-06,-3.6380e-07, 3.1213e-07, 2.0912e-07, 1.1965e-05, + 9.9088e-07,-1.3565e-06,-2.3128e-07, 1.1379e-05, 2.6632e-06, + -1.6877e-06,-4.0541e-07, 9.8921e-08, 5.9262e-03, 3.2332e-03, + 9.2954e-04, 1.6597e-04,-3.7972e-05,-7.1646e-05,-4.0073e-05, + 2.5789e-08, 5.2124e-09,-2.2517e-10,-7.9400e-10, 3.3181e-06, + 1.9117e-07, 1.0299e-07,-7.7443e-08, 2.2953e-06,-1.0879e-06, + 3.4368e-07,-1.1230e-07, 1.6826e-08, 6.9774e-06, 9.2721e-07, + -1.8983e-08,-1.6068e-07, 1.5843e-06,-3.5616e-08,-1.1262e-07, + -4.3051e-08, 8.8140e-09, 3.4244e-05, 8.0163e-06, 2.9703e-06, + -1.6480e-07,-6.3282e-07, 2.3791e-06,-4.9305e-07,-1.7122e-07, + 1.2147e-07, 7.2131e-05, 1.7699e-05, 8.4281e-06,-9.3966e-07, + -6.8048e-07, 5.3785e-05, 6.9745e-06,-2.3554e-06,-7.2141e-07, + 3.8501e-07, 4.4794e-06,-6.2435e-07,-2.7340e-07, 2.3127e-08, + 4.2314e-08, 3.3784e-06,-5.1356e-07,-2.4321e-07,-6.2698e-09, + 3.0812e-08, 5.6419e-08, 1.6889e-08, 2.7037e-09,-1.7433e-09, + -9.4507e-10, 1.9714e-06, 4.2743e-08,-7.4114e-08,-2.9304e-08, + 2.8973e-06, 1.0079e-06, 2.9561e-07,-6.2977e-09,-4.5782e-08, + -2.4331e-08, 4.3284e-06, 2.8398e-07,-3.2705e-07,-1.5079e-07, + 5.2686e-06, 1.6539e-06, 3.6079e-07,-1.1589e-07,-5.4904e-08, + 7.0939e-06,-1.9534e-06, 3.2391e-08, 5.5702e-08, 3.9072e-05, + 1.7299e-05, 5.1530e-06,-6.0911e-07,-1.2652e-06,-4.6507e-07, + 1.1506e-05,-2.0422e-06,-6.1195e-07, 5.8641e-08, 1.0150e-05, + -4.6977e-07,-6.9446e-07, 2.2516e-08, 1.1109e-07, 3.6715e-05, + 5.6186e-06,-3.2309e-06,-1.6403e-06, 4.1051e-05, 2.3335e-05, + 7.8106e-06, 2.0279e-07,-8.1139e-07,-3.7619e-07,-1.4982e-07, + 2.5621e-05,-1.0798e-05, 1.4607e-06, 3.2421e-07, 6.5478e-09, + 2.7233e-09, 3.8646e-10,-1.9143e-10,-1.0483e-10,-4.8664e-11, + 1.0698e-06, 2.7752e-07,-2.6636e-08,-3.7583e-08, 2.6989e-07, + 3.0325e-08,-2.4613e-08,-1.0828e-08, 2.2522e-09, 8.0777e-06, + 2.2558e-06, 7.4760e-08,-2.4140e-07,-5.4292e-08, 8.8362e-07, + 9.5045e-08,-5.0543e-08,-1.9134e-08, 1.1284e-05, 4.0659e-06, + 7.6246e-07,-9.0394e-08,-8.7408e-08, 1.2192e-06,-2.0362e-07, + -1.0700e-07, 2.1990e-08, 1.2519e-08, 5.2758e-05, 2.0175e-05, + 3.6690e-06,-4.9014e-07,-7.0474e-07,-3.9931e-07, 4.7638e-05, + 1.5546e-05, 6.2294e-07,-1.3428e-06,-1.8177e-07, 4.1203e-06, + -4.9340e-07,-3.0198e-07,-1.5902e-08, 2.8567e-08, 2.2397e-06, + -2.1306e-08,-1.7897e-07, 2.8178e-08, 4.1722e-08, 2.0594e-04, + 1.2838e-04, 5.8219e-05, 1.1735e-05,-6.9778e-06,-6.2486e-06, + -1.3800e-06, 2.9170e-06,-7.0833e-07,-1.2673e-07, 4.5069e-08, + 1.0974e-09, 4.7908e-10, 3.0294e-11,-7.0815e-11,-1.2039e-11, + 5.6357e-12, 8.1274e-07, 4.5158e-07, 1.1655e-07,-2.1481e-08, + -2.2493e-08,-6.5884e-09, 9.8696e-08, 3.6499e-08, 1.4768e-09, + -8.0141e-09,-2.8147e-09, 5.8287e-06, 3.2469e-06, 9.4927e-07, + -7.2550e-08,-1.4231e-07,-5.8408e-08,-1.4468e-08, 4.6070e-07, + 1.5956e-07,-3.2311e-09,-3.3487e-08,-7.9013e-09, 4.0092e-06, + 1.2195e-06, 1.1192e-07,-1.3870e-07,-6.2194e-08, 5.4918e-07, + -5.1133e-08,-5.4844e-08,-3.1054e-09, 6.1049e-09, 2.4833e-05, + 1.1280e-05, 2.2680e-06,-4.4637e-07,-2.8942e-07,-1.2382e-07, + 6.8223e-05, 3.6505e-05, 7.8792e-06,-1.7946e-06,-1.4925e-06, + -4.6018e-07, 2.5677e-06,-7.2440e-08,-2.2441e-07,-4.1769e-08, + 2.3833e-08, 1.1885e-06, 4.0457e-09,-1.2273e-07,-2.3271e-08, + 1.5149e-08, 9.1912e-05, 5.6621e-05, 1.4338e-05,-2.6072e-06, + -2.3688e-06,-6.2490e-07,-1.4386e-07, 1.0821e-06,-1.6304e-07, + -7.9756e-08,-4.9881e-09, 9.9527e-09, 1.5288e-03, 9.8517e-04, + 3.4966e-04, 3.4238e-05,-4.3610e-05,-3.2734e-05,-8.3676e-06, + 9.6630e-09, 3.2976e-09, 2.1545e-10,-3.3938e-10,-1.4397e-10, + 3.4140e-07, 7.6536e-08,-2.2485e-08,-1.8244e-08,-2.0611e-09, + 1.3128e-06, 6.4165e-07, 1.4728e-07,-2.7600e-08,-3.0125e-08, + -1.0320e-08, 1.6295e-06, 3.3697e-07,-5.7547e-08,-7.3134e-08, + -1.5301e-08, 8.0375e-06, 4.0695e-06, 1.1441e-06,-5.8423e-08, + -1.6488e-07,-7.5920e-08, 2.1173e-06,-1.9184e-07,-2.4986e-07, + 7.2656e-09, 2.7560e-08, 7.9040e-06, 3.3963e-06, 4.8082e-07, + -3.1619e-07,-1.6501e-07, 5.8017e-06,-5.5173e-07,-6.3613e-07, + 1.9633e-08, 7.8681e-08, 9.4568e-06, 9.8227e-08,-7.8983e-07, + -2.0343e-07, 7.0351e-05, 3.6017e-05, 8.0504e-06,-1.7276e-06, + -1.5329e-06,-4.7799e-07, 3.5263e-05, 1.8639e-05, 4.2070e-06, + -4.2643e-07,-5.2726e-07,-2.5481e-07,-1.0144e-07, 4.4613e-06, + -8.7802e-07,-3.9633e-07, 6.7953e-08, 4.1539e-08, 1.8780e-04, + 1.0547e-04, 2.0983e-05,-3.7076e-06,-3.7090e-06,-1.5934e-06, + -2.6146e-07, 1.6384e-05,-3.3765e-06,-7.8390e-07, 1.2382e-07, + 1.5748e-05,-9.4352e-07,-4.8936e-07,-4.9967e-07, 3.8177e-10, + 9.6781e-11,-1.9622e-11,-1.7859e-11,-4.4781e-12, 3.0310e-07, + 1.1193e-07,-5.4059e-09,-1.4249e-08,-1.9549e-09, 4.7664e-08, + 8.5684e-09,-5.0948e-09,-3.1313e-09, 4.9557e-10, 4.2702e-10, + 2.3433e-06, 8.3824e-07, 2.6585e-08,-7.5944e-08,-1.5093e-08, + 1.8775e-07, 2.7614e-08,-2.1193e-08,-1.0264e-08, 1.9660e-09, + 1.1637e-09, 7.7890e-06, 3.2901e-06,-2.9753e-07,-5.3153e-07, + -5.2098e-08, 3.3947e-08, 5.5937e-07, 5.1363e-08,-8.5390e-08, + -2.2580e-08, 1.0857e-08, 3.5157e-09, 4.1303e-05, 2.1947e-05, + 3.9480e-06,-1.4234e-06,-9.0220e-07,-2.4485e-07, 1.1031e-04, + 6.6726e-05, 1.9581e-05,-4.3637e-07,-2.8911e-06,-1.4332e-06, + -3.2332e-07, 3.0922e-06, 2.0624e-07,-4.0771e-07,-1.0402e-07, + 4.8807e-08, 1.2491e-06, 2.1187e-07,-1.5951e-07,-7.2537e-08, + 1.4035e-08, 9.6514e-09, 2.5146e-05,-9.4490e-08,-3.4103e-06, + 2.4020e-07, 2.9564e-07, 6.6566e-07,-3.0772e-08,-1.0055e-07, + -3.1082e-09, 1.4897e-08, 7.7189e-04, 3.3710e-04, 3.9258e-05, + -1.5271e-05,-6.0652e-06, 2.1986e-04,-3.3135e-05,-8.5682e-06, + -9.2988e-07, 3.8085e-06,-1.3259e-07,-3.8517e-07,-5.7276e-08, + 3.7226e-08, 2.0825e-09, 1.6707e-10,-1.2443e-10,-3.9117e-11, + 1.0068e-07, 6.2278e-09,-5.9169e-09,-3.9535e-09, 5.3334e-07, + 2.2022e-07, 1.4522e-08,-2.8440e-08,-8.1406e-09, 6.0187e-07, + 5.8318e-08,-2.7772e-08,-2.6639e-08, 3.0929e-06, 1.0648e-06, + 1.2317e-07,-9.9233e-08,-4.0796e-08, 1.5217e-06, 8.3095e-08, + -1.9819e-07,-6.0417e-08, 2.9553e-08, 9.0905e-09, 8.6651e-06, + 3.9125e-06,-2.2871e-07,-6.4651e-07,-7.4440e-08, 4.3543e-08, + 4.4505e-06, 2.7350e-07,-4.6428e-07,-2.2293e-07, 5.5275e-08, + 3.6505e-08, 8.3471e-06, 5.0215e-07,-1.1189e-06,-2.5404e-07, + 1.3175e-07, 1.1687e-04, 7.0674e-05, 2.0219e-05,-1.2136e-06, + -3.2299e-06,-1.3981e-06,-2.8271e-07, 3.7298e-05, 2.2054e-05, + 5.5510e-06,-9.1515e-07,-1.0832e-06,-3.6657e-07,-4.8581e-08, + 2.2506e-06,-2.9469e-07,-2.1641e-07,-3.9630e-08, 5.2879e-08, + 2.7894e-05,-3.9312e-06,-2.6413e-06, 5.5848e-07, 8.7829e-06, + -1.4800e-06,-7.0982e-07,-2.1645e-08, 1.3258e-07, 1.2248e-05, + -1.4244e-06,-7.6696e-07,-1.5029e-07, 6.8467e-08, 1.9392e-04, + -2.6676e-05,-8.0536e-06,-6.3609e-07, 2.3074e-05, 7.2856e-07, + -2.3751e-06,-5.8464e-07, 1.3685e-07, 1.9646e-08, 1.2918e-08, + 4.6924e-09, 5.1593e-10,-4.4715e-10,-3.4091e-10,-9.7254e-11, + 3.4117e-07, 1.2731e-07,-2.2300e-08,-2.5297e-08,-1.1877e-10, + 2.3436e-09, 9.4463e-07, 4.9464e-07, 8.9138e-08,-2.2158e-08, + -1.2008e-08,-4.3715e-09,-2.8719e-09, 1.4091e-06, 4.8184e-07, + -9.6135e-08,-1.0945e-07,-9.3174e-09, 9.0166e-09, 4.3747e-06, + 2.1053e-06, 1.7702e-07,-3.0956e-07,-1.2902e-07,-8.9418e-09, + 1.4297e-06, 7.7612e-08,-1.7188e-07, 6.4348e-10, 1.1572e-08, + 7.4828e-06, 4.0177e-06, 1.0890e-06, 8.6393e-08,-5.4701e-08, + -5.7656e-08,-3.3030e-08, 5.0379e-06, 1.2861e-07,-7.1313e-07, + -3.3703e-09, 7.9367e-08, 6.2235e-06, 9.8196e-07,-4.6416e-07, + -2.3278e-07, 2.9519e-05, 1.5275e-05, 3.1448e-06,-6.4571e-07, + -3.4445e-07, 3.6508e-05, 2.0524e-05, 3.1203e-06,-2.3606e-06, + -1.5012e-06,-2.5807e-07, 1.3807e-07, 9.9656e-08, 3.1628e-06, + -5.6361e-08,-3.8861e-07,-1.0385e-09, 2.9930e-08, 3.1351e-04, + 2.3774e-04, 1.0342e-04, 1.2429e-05,-1.4107e-05,-9.2597e-06, + -1.7338e-06, 8.4903e-07, 7.3795e-07, 2.2065e-07, 1.2134e-05, + 4.6651e-07,-9.3659e-07,-2.7485e-07, 1.2462e-05, 6.2559e-07, + -6.1634e-07,-5.1080e-07, 1.2493e-02, 8.2057e-03, 2.9562e-03, + 3.3090e-04,-3.7349e-04,-2.8886e-04,-7.4606e-05, 1.2726e-05, + -1.6480e-07,-1.5006e-06,-1.1181e-07, 1.4846e-07, 8.7160e-03, + 4.2652e-03, 5.2455e-04,-2.6363e-04,-7.9836e-05, + ] + }) +} +/// 氦原子碰撞速率系数。 +/// +/// 计算氦原子 19 个能级 (n=1,2,3,4) 之间的碰撞跃迁速率。 +/// +/// # 参数 +/// +/// * `temp` - 温度 (K) +/// +/// # 返回值 +/// +/// 19x19 矩阵 `colhe1`,其中 `colhe1[i][j]` 是从能级 i+1 到能级 j+1 的碰撞速率 (cm^3/s)。 +pub fn collhe(temp: f64) -> [[f64; 19]; 19] { + const C1: f64 = 3.849485; + const C2: f64 = 0.849485002; + const N: usize = 19; + + let ener = get_ener(); + let stwt = get_stwt(); + let nstart = get_nstart(); + let a = get_a_data(); + + let mut colhe1 = [[0.0; 19]; 19]; + + // 计算 Gamma 系数的变量 + let xxx = 2.0 * (temp.log10() - C1) / C2; + let tfac = 1.0 / temp.sqrt(); + + // 遍历所有能级对 + for il in 0..N - 1 { + for iu in il + 1..N { + // 计算跃迁索引 j (Fortran 1-indexed) + // Fortran: J=((IU*IU-3*IU+4)/2)+IL-1 + // IU=iu+1, IL=il+1 (转换到 1-indexed) + // 展开简化: (iu^2 - iu + 2) / 2 + il + let iu_i32 = iu as i32; + let j = ((iu_i32 * iu_i32 - iu_i32 + 2) / 2 + il as i32) as usize; + + // 边界检查 + if j + 1 >= nstart.len() { + continue; + } + + let n1 = (nstart[j] - 1) as usize; + let nf = (nstart[j + 1] - 1) as usize; + let nt = nf - n1 + 1; + if nt < 2 || nt > 10 { + continue; + } + let ntm2 = nt - 2; + + // 边界检查 a 数组 + if nf >= a.len() { + continue; + } + + // Clenshaw 求和 + let mut b = [0.0; 10]; + b[nt - 1] = a[nf]; + b[nt - 2] = xxx * b[nt - 1] + a[nf - 1]; + + let mut ir = (nt as isize) - 3; + let mut jj = (nf as isize) - 3; + for _ in 0..ntm2 { + if ir >= 0 && (ir as usize) < 10 && jj >= 0 && (jj as usize) < a.len() { + let ir_usize = ir as usize; + let jj_usize = jj as usize; + b[ir_usize] = xxx * b[ir_usize + 1] - b[ir_usize + 2] + a[jj_usize]; + } + ir -= 1; + jj -= 1; + } + + colhe1[iu][il] = (b[0] - b[2]) * tfac; + + // 详细平衡计算逆跃迁 + let x = (ener[il] - ener[iu]) / 8.62e-5 / temp; + colhe1[il][iu] = colhe1[iu][il] * stwt[iu] / stwt[il] * x.exp(); + } + } + + colhe1 +} + +#[cfg(test)] +mod tests { + use super::*; + use approx::assert_relative_eq; + + #[test] + fn test_collhe_10000k() { + let result = collhe(10000.0); + // 检查对角线元素为 0 + for i in 0..19 { + assert_relative_eq!(result[i][i], 0.0, epsilon = 1e-30); + } + // 检查非对角线元素有正值 + assert!(result[1][0] > 0.0); // 2^3S -> 1^1S + assert!(result[0][1] > 0.0); // 1^1S -> 2^3S + } + + #[test] + fn test_collhe_detailed_balance() { + let result = collhe(10000.0); + let ener = get_ener(); + let stwt = get_stwt(); + + for il in 0..5 { + for iu in il + 1..5 { + let x = (ener[il] - ener[iu]) / 8.62e-5 / 10000.0; + let ratio = result[il][iu] / result[iu][il]; + let expected = stwt[iu] / stwt[il] * x.exp(); + assert_relative_eq!(ratio, expected, epsilon = 1e-6); + } + } + } + + #[test] + fn test_collhe_high_temp() { + let result = collhe(50000.0); + assert!(result[1][0] > 0.0); + } +} diff --git a/src/math/cross.rs b/src/math/cross.rs new file mode 100644 index 0000000..3a7f458 --- /dev/null +++ b/src/math/cross.rs @@ -0,0 +1,307 @@ +//! 光电离截面计算。 +//! +//! 重构自 TLUSTY `cross.f` 和 `crossd.f`。 + +use crate::state::{AtomicData, BasNum, ModelState}; + +// ============================================================================ +// CROSS - 基本光电离截面 +// ============================================================================ + +/// 计算光电离截面。 +/// +/// 使用频率插值计算束缚-自由跃迁的光电离截面。 +/// +/// # 参数 +/// +/// - `ibft` - 束缚-自由跃迁索引 (0-indexed) +/// - `ij` - 频率索引 (0-indexed) +/// - `model` - 模型状态 (包含 IJBF, AIJBF, BFCS) +/// +/// # 返回 +/// +/// 光电离截面 (cm²) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION CROSS(IBFT,IJ) +/// IJ0=IJBF(IJ) +/// A1=AIJBF(IJ) +/// CROSS=A1*BFCS(IBFT,IJ0)+(UN-A1)*BFCS(IBFT,IJ0+1) +/// END +/// ``` +pub fn cross(ibft: usize, ij: usize, model: &ModelState) -> f64 { + let ij0 = model.frqall.ijbf[ij] as usize; + let a1 = model.phoexp.aijbf[ij]; + + // 线性插值 + let sig0 = model.phoexp.bfcs[ibft][ij0] as f64; + let sig1 = model.phoexp.bfcs[ibft][ij0 + 1] as f64; + + a1 * sig0 + (1.0 - a1) * sig1 +} + +// ============================================================================ +// CROSSD - 含双电子复合的光电离截面 +// ============================================================================ + +/// 计算光电离截面(含双电子复合贡献)。 +/// +/// 在基本光电离截面的基础上,添加双电子复合的贡献。 +/// 双电子复合只在特定条件下添加: +/// 1. ifdiel 标志非零 +/// 2. 对应跃迁有双电子复合标志 (idiel > 0) +/// 3. 深度索引有效 (id > 0) +/// 4. 能级满足特定条件 (基态到第一激发态) +/// 5. 频率在阈值频率附近 (fr0 到 1.1*fr0) +/// +/// # 参数 +/// +/// - `ibft` - 束缚-自由跃迁索引 (0-indexed) +/// - `ij` - 频率索引 (0-indexed) +/// - `id` - 深度索引 (1-indexed in Fortran, 0 表示不添加双电子复合) +/// - `model` - 模型状态 +/// - `atomic` - 原子数据 +/// - `config` - 配置参数 +/// +/// # 返回 +/// +/// 光电离截面 (cm²) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION CROSSD(IBFT,IJ,ID) +/// IJ0=IJBF(IJ) +/// A1=AIJBF(IJ) +/// CROSSD=A1*BFCS(IBFT,IJ0)+(UN-A1)*BFCS(IBFT,IJ0+1) +/// if(ifdiel.eq.0) return +/// ITR=ITRBF(IBFT) +/// if(idiel(itr).gt.0.and.id.gt.0) then +/// i=ilow(itr) +/// ion=iel(i) +/// if(i.eq.nfirst(ion).and.iup(itr).eq.nnext(ion)) then +/// if(freq(ij).ge.fr0(itr).and.freq(ij).le.fr0(itr)*1.1) +/// * crossd=crossd+diesig(ion,id) +/// end if +/// end if +/// END +/// ``` +pub fn crossd( + ibft: usize, + ij: usize, + id: i32, + model: &ModelState, + atomic: &AtomicData, + basnum: &BasNum, +) -> f64 { + // 基本截面 + let mut sigma = cross(ibft, ij, model); + + // 检查是否启用双电子复合 + if basnum.ifdiel == 0 { + return sigma; + } + + // 检查深度索引有效性 (Fortran: id > 0) + if id <= 0 { + return sigma; + } + + // 获取跃迁索引 (Fortran: ITR = ITRBF(IBFT)) + let itr = model.obfpar.itrbf[ibft] as usize; + + // 检查跃迁是否有双电子复合标志 + if atomic.trapar.idiel[itr] <= 0 { + return sigma; + } + + // 获取下能级索引 (Fortran: i = ilow(itr)) + let i = atomic.trapar.ilow[itr] as usize; + + // 获取该能级所属离子 (Fortran: ion = iel(i)) + let ion = atomic.levpar.iel[i] as usize; + + // 检查能级条件: + // 下能级是离子的基态 (i == nfirst(ion)) + // 上能级是离子的第一激发态 (iup(itr) == nnext(ion)) + let nfirst = atomic.ionpar.nfirst[ion]; + let nnext = atomic.ionpar.nnext[ion]; + let iup = atomic.trapar.iup[itr]; + + if (i as i32) != nfirst || iup != nnext { + return sigma; + } + + // 检查频率范围 (Fortran: freq(ij) >= fr0(itr) .and. freq(ij) <= fr0(itr)*1.1) + let freq_ij = model.frqall.freq[ij]; + let fr0 = atomic.trapar.fr0[itr]; + let fr0_upper = fr0 * 1.1; + + if freq_ij >= fr0 && freq_ij <= fr0_upper { + // 添加双电子复合截面贡献 + // Fortran: id 是 1-indexed + let id_idx = (id - 1) as usize; + sigma += model.levadd.diesig[ion][id_idx]; + } + + sigma +} + +#[cfg(test)] +mod tests { + use super::*; + + fn create_test_model() -> ModelState { + let mut model = ModelState::new(); + + // 设置测试数据 + model.frqall.ijbf[0] = 10; + model.frqall.ijbf[1] = 20; + model.phoexp.aijbf[0] = 0.5; + model.phoexp.aijbf[1] = 0.3; + + // 设置截面数据 + model.phoexp.bfcs[0][10] = 1e-18; + model.phoexp.bfcs[0][11] = 2e-18; + model.phoexp.bfcs[0][20] = 3e-18; + model.phoexp.bfcs[0][21] = 4e-18; + + // 设置频率数据 + model.frqall.freq[0] = 3.0e15; // Hz + + // 设置跃迁索引 + model.obfpar.itrbf[0] = 5; + + model + } + + fn create_test_atomic() -> AtomicData { + let mut atomic = AtomicData::new(); + + // 设置跃迁 5 的参数 + atomic.trapar.ilow[5] = 10; // 下能级索引 + atomic.trapar.iup[5] = 11; // 上能级索引 + atomic.trapar.idiel[5] = 1; // 启用双电子复合 + atomic.trapar.fr0[5] = 2.0e15; // 阈值频率 + + // 设置能级 10 的离子索引 + atomic.levpar.iel[10] = 2; // 离子索引 2 + + // 设置离子 2 的参数 + atomic.ionpar.nfirst[2] = 10; // 基态能级 + atomic.ionpar.nnext[2] = 11; // 第一激发态 + + atomic + } + + fn create_test_basnum() -> BasNum { + let mut basnum = BasNum::default(); + basnum.ifdiel = 1; // 启用双电子复合 + basnum + } + + #[test] + fn test_cross_basic() { + let model = create_test_model(); + + // 测试基本插值 + let result = cross(0, 0, &model); + // 0.5 * 1e-18 + 0.5 * 2e-18 = 1.5e-18 + // 注意:bfcs 是 f32,精度约为 1e-24 + assert!((result - 1.5e-18).abs() < 1e-24); + } + + #[test] + fn test_cross_different_freq() { + let model = create_test_model(); + + let result = cross(0, 1, &model); + // 0.3 * 3e-18 + 0.7 * 4e-18 = 3.7e-18 + // 注意:bfcs 是 f32,精度约为 1e-24 + assert!((result - 3.7e-18).abs() < 1e-24); + } + + #[test] + fn test_crossd_no_diel_flag() { + let model = create_test_model(); + let atomic = create_test_atomic(); + let mut basnum = create_test_basnum(); + basnum.ifdiel = 0; // 禁用双电子复合 + + let result = crossd(0, 0, 1, &model, &atomic, &basnum); + let expected = cross(0, 0, &model); + assert!((result - expected).abs() < 1e-24); + } + + #[test] + fn test_crossd_negative_id() { + let model = create_test_model(); + let atomic = create_test_atomic(); + let basnum = create_test_basnum(); + + // id <= 0 时不添加双电子复合 + let result = crossd(0, 0, 0, &model, &atomic, &basnum); + let expected = cross(0, 0, &model); + assert!((result - expected).abs() < 1e-25); + + let result = crossd(0, 0, -1, &model, &atomic, &basnum); + assert!((result - expected).abs() < 1e-25); + } + + #[test] + fn test_crossd_with_diel_contribution() { + let mut model = create_test_model(); + let atomic = create_test_atomic(); + let basnum = create_test_basnum(); + + // 设置双电子复合截面 + model.levadd.diesig[2][0] = 5e-19; // 离子 2, 深度 1 (id=1 -> idx=0) + + // 频率 2.1e15 在 [2e15, 2.2e15] 范围内 + model.frqall.freq[0] = 2.1e15; + + let result = crossd(0, 0, 1, &model, &atomic, &basnum); + + // 应该是基本截面 + 双电子复合贡献 + let base = cross(0, 0, &model); // 1.5e-18 + let expected = base + 5e-19; // 2.0e-18 + assert!((result - expected).abs() < 1e-24); + } + + #[test] + fn test_crossd_freq_outside_range() { + let mut model = create_test_model(); + let atomic = create_test_atomic(); + let basnum = create_test_basnum(); + + // 设置双电子复合截面 + model.levadd.diesig[2][0] = 5e-19; + + // 修改频率到范围外 (fr0*1.1 = 2.2e15) + model.frqall.freq[0] = 3.0e15; // 超过上限 + + let result = crossd(0, 0, 1, &model, &atomic, &basnum); + + // 频率超出范围,不应添加双电子复合 + let expected = cross(0, 0, &model); + assert!((result - expected).abs() < 1e-24); + } + + #[test] + fn test_crossd_wrong_level_condition() { + let model = create_test_model(); + let mut atomic = create_test_atomic(); + let basnum = create_test_basnum(); + + // 修改 nnext 使条件不满足 + atomic.ionpar.nnext[2] = 12; // 不是 11 + + let result = crossd(0, 0, 1, &model, &atomic, &basnum); + + // 能级条件不满足,不应添加双电子复合 + let expected = cross(0, 0, &model); + assert!((result - expected).abs() < 1e-24); + } +} diff --git a/src/math/dielrc.rs b/src/math/dielrc.rs new file mode 100644 index 0000000..fffe876 --- /dev/null +++ b/src/math/dielrc.rs @@ -0,0 +1,228 @@ +//! 双电子复合速率计算。 +//! +//! 重构自 TLUSTY `dielrc.f` +//! 参考: Tim Kallman 的 XSTAR 程序,由 Omer Blaes 修改 +//! +//! 计算 H, He, C, N, O, Ne, Mg, Si, S, Ar, Ca, Fe, Ni 的双电子复合速率。 + +use crate::data::{ + DIELRC_ADI as ADI, DIELRC_BDI as BDI, DIELRC_CDD as CDD, DIELRC_DCFE as DCFE, + DIELRC_DEFE as DEFE, DIELRC_GFE as GFE, DIELRC_GLI as GLI, DIELRC_GNI as GNI, + DIELRC_INID as INID, DIELRC_ISTOREY as ISTOREY, DIELRC_RSTOREY as RSTOREY, DIELRC_T0 as T0, + DIELRC_T1 as T1, DIELRC_UU as UU, +}; +use crate::math::expo; + +// 常量 +const CONS: f64 = 0.1239529 * 3.28805e15 / 13.595; +const HFRAC: f64 = 1.0; +const ERGSEV: f64 = 1.602192e-12; + +/// 计算双电子复合速率和伪截面。 +/// +/// # 参数 +/// +/// * `iatom` - 原子序数 (1=H, 2=He, 6=C, 等) +/// * `iont` - 电离态 (1=中性, 2=一次电离, 等) +/// * `temp` - 温度 (K) +/// * `xpx` - 原子核密度 (cm^-3) +/// +/// # 返回值 +/// +/// * `dirt` - 双电子复合速率 (cm^3/s) +/// * `sig0` - 伪截面 σ₀ +/// +/// # 离子编号 +/// +/// 离子编号从 1-168: +/// - 1=HI, 2=HeI, 3=HeII +/// - 4-9=C I 到 C VI +/// - 10-16=N I 到 N VII +/// - 17-24=O I 到 O VIII +/// - 25-34=Ne I 到 Ne X +/// - 35-46=Mg I 到 Mg XII +/// - 47-60=Si I 到 Si XIV +/// - 61-76=S I 到 S XVI +/// - 77-94=Ar I 到 Ar XVIII +/// - 95-114=Ca I 到 Ca XX +/// - 115-140=Fe I 到 Fe XXVI +/// - 141-168=Ni I 到 Ni XXVIII +pub fn dielrc(iatom: usize, iont: usize, temp: f64, xpx: f64) -> (f64, f64) { + // 温度单位转换: K -> 10^4 K + let t = temp / 1.0e4; + + // 获取离子索引 + // Fortran 1-indexed: inid(iont, iatom) -> Rust 0-indexed: INID[iont-1][iatom-1] + // 注意: 提取脚本已将 Fortran 列优先转换为 Rust 行优先 + let ini = INID[iont - 1][iatom - 1] as usize; + + // 如果没有数据,返回 0 + if ini == 0 || ini > 168 { + return (0.0, 0.0); + } + + let ekt = t * 0.861707; + let xst = t.sqrt(); + let _hconst = HFRAC * ekt * ERGSEV; + let t3s2 = 1.0 / (t * xst); + let tmr = 1.0e-6 * t3s2; + + let mut dirt = 0.0; + + // Fe 离子的双电子复合 (离子编号 115-139) + if ini >= 115 && ini <= 139 { + // Fe 离子的 kk 索引 (1-25 对应离子 115-139) + let kk = ini - 114; // 1-25 + + // 对 4 个项求和 + for n in 0..4 { + // Fortran: dcfe(kk, n) -> Rust: DCFE[kk-1][n] + // DCFE 是 [[f64; 4]; 26],所以 DCFE[kk-1][n] + dirt += DCFE[kk - 1][n] * expo(-DEFE[kk - 1][n] / ekt); + } + dirt *= tmr; + } else { + // Aldrovandi 和 Pequignot 速率 + // 密度修正因子 + let enn = xpx.powf(0.2); + // Fortran 1-indexed: cdd(ini) -> Rust: CDD[ini-1] + let ap = 1.0 / (1.0 + CDD[ini - 1] * enn); + + // 复合速率公式 + // Fortran 1-indexed -> Rust 0-indexed + dirt = ADI[ini - 1] * ap * 1.0e-6 * expo(-T0[ini - 1] / t) + * (1.0 + BDI[ini - 1] * expo(-T1[ini - 1] / t)) + / (t * t.sqrt()); + + // Storey 修正 (仅对特定离子) + let mut ist = 0; + + // 检查是否需要 Storey 修正 + // Fortran: istorey(ist) 是离子编号,我们需要检查 ini == istorey(ist) - 1 + // 但原代码检查 j.ne.(istorey(ist)-1),所以实际上 ini == istorey(ist) - 1 才会进入 + while ist < 13 { + let storey_ion = ISTOREY[ist] as usize; + if storey_ion == 0 { + break; + } + // 原代码: if ((j.ne.(istorey(ist)-1))... + // j = ini, 所以条件是 ini == istorey(ist) - 1 + if ini == storey_ion - 1 && t <= 6.0 { + // RSTOREY 是 [[f64; 13]; 5] + let dirtemp = 1.0e-12 + * (RSTOREY[0][ist] / t + + RSTOREY[1][ist] + + t * (RSTOREY[2][ist] + t * RSTOREY[3][ist])) + * t3s2 + * expo(-RSTOREY[4][ist] / t); + dirt += dirtemp; + } + ist += 1; + } + } + + // 计算伪截面 + let sig0 = if dirt > 0.0 { + compute_sig0(iatom, iont, temp, dirt) + } else { + 0.0 + }; + + (dirt, sig0) +} + +/// 计算伪截面 σ₀ +fn compute_sig0(iatom: usize, iont: usize, temp: f64, dirt: f64) -> f64 { + // 获取统计权重比 + let gg = if iatom <= 20 { + // Li 系列统计权重 + let gp = if iont < 20 { + let g = GLI[iont]; // iont+1 在 Fortran 中是 iont 索引 + if g > 0.0 { g } else { 1.0 } + } else { + 1.0 + }; + let g_curr = GLI[iont - 1]; + if g_curr > 0.0 { gp / g_curr } else { gp } + } else if iatom <= 26 { + // Fe 系列统计权重 + let gp = if iont < 26 { + let g = GFE[iont]; + if g > 0.0 { g } else { 1.0 } + } else { + 1.0 + }; + let g_curr = GFE[iont - 1]; + if g_curr > 0.0 { gp / g_curr } else { gp } + } else if iatom <= 28 { + // Ni 系列统计权重 + let gp = if iont < 28 { + let g = GNI[iont]; + if g > 0.0 { g } else { 1.0 } + } else { + 1.0 + }; + let g_curr = GNI[iont - 1]; + if g_curr > 0.0 { gp / g_curr } else { gp } + } else { + 1.0 + }; + + // 计算阈值频率 + // Fortran 1-indexed: uu(iont, iatom) -> Rust: UU[iont-1][iatom-1] + let frq0 = CONS * UU[iont - 1][iatom - 1]; + let frq1 = 1.1 * frq0; + let delfr = frq1 - frq0; + let fra = 0.5 * (frq0 + frq1); + + let x = 1.0 - expo(-4.79928e-11 * delfr / temp); + let sig0 = dirt * 8.47272e24 * gg * temp.sqrt() / (fra * fra) / x; + + sig0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dielrc_he() { + // He+ 双电子复合 (iont=2, iatom=2) + let (dirt, sig0) = dielrc(2, 2, 20000.0, 1e10); + // He+ 应该有有效的双电子复合 + assert!(dirt >= 0.0); + assert!(sig0 >= 0.0); + } + + #[test] + fn test_dielrc_c() { + // C IV 双电子复合 (iont=4, iatom=6) + let (dirt, sig0) = dielrc(6, 4, 20000.0, 1e10); + assert!(dirt > 0.0); + assert!(sig0 >= 0.0); + } + + #[test] + fn test_dielrc_fe() { + // Fe XIV 双电子复合 (iont=14, iatom=26, 离子编号约 128) + let (dirt, sig0) = dielrc(26, 14, 200000.0, 1e10); + assert!(dirt > 0.0); + assert!(sig0 >= 0.0); + } + + #[test] + fn test_dielrc_h_zero() { + // H 没有双电子复合 + let (dirt, sig0) = dielrc(1, 1, 20000.0, 1e10); + assert_eq!(dirt, 0.0); + assert_eq!(sig0, 0.0); + } + + #[test] + fn test_dielrc_o() { + // O VI 双电子复合 (iont=6, iatom=8) + let (dirt, sig0) = dielrc(8, 6, 50000.0, 1e10); + assert!(dirt > 0.0); + assert!(sig0 >= 0.0); + } +} diff --git a/src/math/gamsp.rs b/src/math/gamsp.rs new file mode 100644 index 0000000..e279dd4 --- /dev/null +++ b/src/math/gamsp.rs @@ -0,0 +1,61 @@ +//! 用户自定义展宽参数。 +//! +//! 重构自 TLUSTY `gamsp.f`。 +//! +//! 这是一个占位函数,用于用户自定义展宽参数表达式。 + +/// 计算自定义展宽参数。 +/// +/// 这是一个占位函数,默认返回零。 +/// 用户可以修改此函数来实现自定义的展宽参数表达式。 +/// +/// # 参数 +/// +/// - `itr` - 跃迁索引 +/// - `t` - 温度 +/// - `ane` - 电子密度 +/// +/// # 返回 +/// +/// 展宽参数值 (默认为 0) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// SUBROUTINE GAMSP(ITR,T,ANE,AGAM) +/// INCLUDE 'BASICS.FOR' +/// AGAM=0. +/// if(itr.le.0) return +/// t1=t +/// ane1=ane +/// RETURN +/// END +/// ``` +pub fn gamsp(itr: i32, _t: f64, _ane: f64) -> f64 { + // 默认返回零 + if itr <= 0 { + return 0.0; + } + // 原始代码中有 t1=t 和 ane1=ane,但没有使用这些值 + // 这可能是为用户预留的接口 + 0.0 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_gamsp_zero_itr() { + // ITR <= 0 应该返回 0 + assert_eq!(gamsp(0, 10000.0, 1e14), 0.0); + assert_eq!(gamsp(-1, 10000.0, 1e14), 0.0); + } + + #[test] + fn test_gamsp_positive_itr() { + // 默认实现返回 0 + assert_eq!(gamsp(1, 10000.0, 1e14), 0.0); + assert_eq!(gamsp(10, 5000.0, 1e12), 0.0); + } +} diff --git a/src/math/getwrd.rs b/src/math/getwrd.rs new file mode 100644 index 0000000..5cabcc5 --- /dev/null +++ b/src/math/getwrd.rs @@ -0,0 +1,110 @@ +//! 文本单词提取。 +//! +//! 重构自 TLUSTY `getwrd.f` +//! +//! 来自 MULTI - M. Carlsson (1976)。 + +/// 分隔符字符列表。 +const SEPARATORS: [char; 7] = [' ', '(', ')', '=', '*', '/', ',']; + +/// 从文本中查找下一个单词。 +/// +/// 从索引 `k0` 开始查找下一个单词,返回单词的起始和结束索引。 +/// 单词从第一个非分隔符字符开始,到最后一个连续非分隔符字符结束。 +/// +/// # 参数 +/// +/// * `text` - 输入文本 +/// * `k0` - 开始查找的索引 (0-indexed) +/// +/// # 返回值 +/// +/// `Some((k1, k2))` - 单词的起始和结束索引 (包含,0-indexed) +/// `None` - 未找到新单词 +/// +/// # 备注 +/// +/// 来自 MULTI - M. Carlsson (1976)。 +pub fn getwrd(text: &str, k0: usize) -> Option<(usize, usize)> { + let chars: Vec = text.chars().collect(); + let len = chars.len(); + + if k0 >= len { + return None; + } + + let mut k1: Option = None; + + for i in k0..len { + if k1.is_none() { + // 查找单词开始 + if !SEPARATORS.contains(&chars[i]) { + k1 = Some(i); + } + } else { + // 查找单词结束 + if SEPARATORS.contains(&chars[i]) { + // 单词在 i-1 结束 + return Some((k1.unwrap(), i - 1)); + } + } + } + + // 如果找到了开始但没有遇到分隔符,单词到文本末尾 + if let Some(start) = k1 { + Some((start, len - 1)) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_getwrd_simple() { + let text = "hello world"; + assert_eq!(getwrd(text, 0), Some((0, 4))); // "hello" + } + + #[test] + fn test_getwrd_second_word() { + let text = "hello world"; + assert_eq!(getwrd(text, 5), Some((6, 10))); // "world" + } + + #[test] + fn test_getwrd_no_word() { + let text = " "; + assert_eq!(getwrd(text, 0), None); + } + + #[test] + fn test_getwrd_with_separators() { + let text = "a(b)=c"; + assert_eq!(getwrd(text, 0), Some((0, 0))); // "a" + assert_eq!(getwrd(text, 1), Some((2, 2))); // "b" + assert_eq!(getwrd(text, 4), Some((5, 5))); // "c" + } + + #[test] + fn test_getwrd_empty() { + let text = ""; + assert_eq!(getwrd(text, 0), None); + } + + #[test] + fn test_getwrd_out_of_bounds() { + let text = "hello"; + assert_eq!(getwrd(text, 10), None); + } + + #[test] + fn test_getwrd_comma_separator() { + let text = "a,b,c"; + assert_eq!(getwrd(text, 0), Some((0, 0))); // "a" + assert_eq!(getwrd(text, 1), Some((2, 2))); // "b" + assert_eq!(getwrd(text, 3), Some((4, 4))); // "c" + } +} diff --git a/src/math/gfree.rs b/src/math/gfree.rs new file mode 100644 index 0000000..4ed04f1 --- /dev/null +++ b/src/math/gfree.rs @@ -0,0 +1,351 @@ +//! 氢自由-自由 Gaunt 因子计算。 +//! +//! 重构自 TLUSTY `gfree0.f`, `gfree1.f` 和 `gfreed.f`。 + +// ============================================================================ +// 常量参数 +// ============================================================================ + +const THET0: f64 = 5.0404e3; +const A0: f64 = 1.0823; +const B0: f64 = 2.98e-2; +const C0: f64 = 6.70e-3; +const D0: f64 = 1.12e-2; +const A1: f64 = 3.9999187e-3; +const B1: f64 = -7.8622889e-5; +const C1: f64 = 1.070192; +const A2: f64 = 6.4628601e-2; +const B2: f64 = -6.1953813e-4; +const C2: f64 = 2.6061249e-1; +const A3: f64 = 3.7542343e-2; +const B3: f64 = 1.3983474e-5; +const C3: f64 = 5.7917786e-1; +const A4: f64 = 3.4169006e-1; +const B4: f64 = 1.1852264e-2; +const XMIN: f64 = 0.2; +const THMIN: f64 = 4.0e-2; + +const C14: f64 = 2.997925e14; + +// ============================================================================ +// GFREE0 - 深度相关量预计算 +// ============================================================================ + +/// 计算深度相关的氢自由-自由 Gaunt 因子参数。 +/// +/// 此函数预计算并填充 GffPar 结构中的 GF0-GF6 和 GF0D-GF6D 数组。 +/// +/// # 参数 +/// +/// - `id` - 深度索引 (0-indexed) +/// - `temp` - 温度数组 +/// - `gffpar` - Gaunt 因子参数结构 (会被修改) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// SUBROUTINE GFREE0(ID) +/// INCLUDE 'BASICS.FOR' +/// INCLUDE 'MODELQ.FOR' +/// ... +/// T=TEMP(ID) +/// GF0(ID)=(A0+B0*THET) +/// ... +/// END +/// ``` +pub fn gfree0(id: usize, temp: &[f64], gffpar: &mut crate::state::GffPar) { + let t = temp[id]; + let thet0_over_t = THET0 / t; + + // 计算 θ = 1 / max(θ₀/T, θ_min) + let thet = 1.0 / thet0_over_t.max(THMIN); + + // 计算 Gaunt 因子分量 + gffpar.gf0[id] = A0 + B0 * thet; + gffpar.gf1[id] = (A1 + B1 * thet) * thet + C1; + gffpar.gf2[id] = (A2 + B2 * thet) * thet + C2; + gffpar.gf3[id] = (A3 + B3 * thet) * thet + C3; + gffpar.gf4[id] = A4 + B4 * thet; + gffpar.gf5[id] = C0 + D0 * thet; + gffpar.gf6[id] = gffpar.gf0[id] + gffpar.gf5[id] / XMIN; + + // 辅助量用于导数 + let thet1 = 1.0 / THET0; + + if thet0_over_t >= THMIN { + // 正常情况:计算导数 + gffpar.gf0d[id] = B0 * thet1; + gffpar.gf1d[id] = (A1 + B1 * thet * 2.0) * thet1; + gffpar.gf2d[id] = (A2 + B2 * thet * 2.0) * thet1; + gffpar.gf3d[id] = (A3 + B3 * thet * 2.0) * thet1; + gffpar.gf4d[id] = B4 * thet1; + gffpar.gf5d[id] = D0 * thet1; + gffpar.gf6d[id] = gffpar.gf0d[id] + gffpar.gf5d[id] / XMIN; + } else { + // 饱和情况:导数为零 + gffpar.gf0d[id] = 0.0; + gffpar.gf1d[id] = 0.0; + gffpar.gf2d[id] = 0.0; + gffpar.gf3d[id] = 0.0; + gffpar.gf4d[id] = 0.0; + gffpar.gf5d[id] = 0.0; + gffpar.gf6d[id] = 0.0; + } +} + +// ============================================================================ +// GFREED - Gaunt 因子计算 +// ============================================================================ + +/// 计算氢自由-自由 Gaunt 因子及其导数。 +/// +/// # 参数 +/// +/// - `id` - 深度索引 (0-indexed) +/// - `fr` - 频率 +/// - `ch` - 电荷 +/// - `gffpar` - Gaunt 因子参数结构 +/// +/// # 返回 +/// +/// 元组 (GFR, GFRD):Gaunt 因子及其导数 +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// SUBROUTINE GFREED(ID,FR,CH,GFR,GFRD) +/// INCLUDE 'BASICS.FOR' +/// INCLUDE 'MODELQ.FOR' +/// ... +/// X=C14*CH/FR +/// IF(X.LT.UN) THEN +/// GFR=((GF4(ID)*X-GF3(ID))*X+GF2(ID))*X+GF1(ID) +/// ... +/// END IF +/// end +/// ``` +pub fn gfreed(id: usize, fr: f64, ch: f64, gffpar: &crate::state::GffPar) -> (f64, f64) { + let x = C14 * ch / fr; + let xmini = 1.0 / XMIN; + + let (gfr, gfrd) = if x < 1.0 { + // 低 X 区域:多项式拟合 + let gfr = ((gffpar.gf4[id] * x - gffpar.gf3[id]) * x + gffpar.gf2[id]) * x + gffpar.gf1[id]; + let gfrd = ((gffpar.gf4d[id] * x - gffpar.gf3d[id]) * x + gffpar.gf2d[id]) * x + gffpar.gf1d[id]; + (gfr, gfrd) + } else if x < xmini { + // 中间区域:线性插值 + let gfr = gffpar.gf0[id] + gffpar.gf5[id] * x; + let gfrd = gffpar.gf0d[id] + gffpar.gf5d[id] * x; + (gfr, gfrd) + } else { + // 高 X 区域:饱和值 + (gffpar.gf6[id], gffpar.gf6d[id]) + }; + + (gfr, gfrd) +} + +// ============================================================================ +// GFREE1 - Gaunt 因子 (仅值,无导数) +// ============================================================================ + +/// 计算氢自由-自由 Gaunt 因子 (仅值,无导数)。 +/// +/// 使用预先计算的系数进行插值。 +/// +/// # 参数 +/// +/// - `id` - 深度索引 (0-indexed) +/// - `x` - 无量纲频率参数 (C14 * CH / FR) +/// - `gffpar` - Gaunt 因子参数结构 +/// +/// # 返回 +/// +/// Gaunt 因子值 +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION GFREE1(ID,X) +/// IF(X.LT.UN) THEN +/// GFREE1=((GF4(ID)*X-GF3(ID))*X+GF2(ID))*X+GF1(ID) +/// ELSE IF(X.LT.XMINI) THEN +/// GFREE1=GF0(ID)+GF5(ID)*X +/// ELSE +/// GFREE1=GF6(ID) +/// END IF +/// END +/// ``` +pub fn gfree1(id: usize, x: f64, gffpar: &crate::state::GffPar) -> f64 { + let xmini = 1.0 / XMIN; + + if x < 1.0 { + // 低 X 区域:多项式拟合 + ((gffpar.gf4[id] * x - gffpar.gf3[id]) * x + gffpar.gf2[id]) * x + gffpar.gf1[id] + } else if x < xmini { + // 中间区域:线性插值 + gffpar.gf0[id] + gffpar.gf5[id] * x + } else { + // 高 X 区域:饱和值 + gffpar.gf6[id] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::state::GffPar; + + fn create_test_gffpar() -> GffPar { + let mut gffpar = GffPar::new(); + // 使用典型温度 10000K + let temp = vec![10000.0; crate::state::MDEPTH]; + // 初始化第一个深度点 + gfree0(0, &temp, &mut gffpar); + gffpar + } + + #[test] + fn test_gfree0_basic() { + let mut gffpar = GffPar::new(); + let temp = vec![10000.0; crate::state::MDEPTH]; + + gfree0(0, &temp, &mut gffpar); + + // 检查计算结果为正值 + assert!(gffpar.gf0[0] > 0.0); + assert!(gffpar.gf1[0] > 0.0); + assert!(gffpar.gf2[0] > 0.0); + assert!(gffpar.gf3[0] > 0.0); + assert!(gffpar.gf4[0] > 0.0); + assert!(gffpar.gf5[0] > 0.0); + assert!(gffpar.gf6[0] > 0.0); + } + + #[test] + fn test_gfree0_low_temperature() { + let mut gffpar = GffPar::new(); + // 低温测试:T = 100K + // THT = THET0/T = 5040.4/100 = 50.4 > THMIN = 0.04 + // 所以进入 IF 分支,计算非零导数 + let temp = vec![100.0; crate::state::MDEPTH]; + + gfree0(0, &temp, &mut gffpar); + + // 低温下导数应该非零 + assert!(gffpar.gf0d[0].abs() > 0.0); + assert!(gffpar.gf1d[0].abs() > 0.0); + assert!(gffpar.gf2d[0].abs() > 0.0); + } + + #[test] + fn test_gfree0_high_temperature() { + let mut gffpar = GffPar::new(); + // 高温测试:T = 200000K + // THT = THET0/T = 5040.4/200000 = 0.025 < THMIN = 0.04 + // 所以进入 ELSE 分支,导数为零 + let temp = vec![200000.0; crate::state::MDEPTH]; + + gfree0(0, &temp, &mut gffpar); + + // 高温下导数应该为零(饱和) + assert_eq!(gffpar.gf0d[0], 0.0); + assert_eq!(gffpar.gf1d[0], 0.0); + assert_eq!(gffpar.gf2d[0], 0.0); + } + + #[test] + fn test_gfreed_low_x() { + let gffpar = create_test_gffpar(); + // 使用高频率产生低 X 值 + let fr = 1e16; + let ch = 1.0; + + let (gfr, gfrd) = gfreed(0, fr, ch, &gffpar); + + // Gaunt 因子应该在合理范围内 + assert!(gfr > 0.0); + } + + #[test] + fn test_gfreed_mid_x() { + let gffpar = create_test_gffpar(); + // 使用中等频率产生中间 X 值 + let fr = 1e15; + let ch = 1.0; + + let (gfr, gfrd) = gfreed(0, fr, ch, &gffpar); + + assert!(gfr > 0.0); + } + + #[test] + fn test_gfreed_high_x() { + let gffpar = create_test_gffpar(); + // 使用低频率产生高 X 值 + let fr = 1e13; + let ch = 1.0; + + let (gfr, gfrd) = gfreed(0, fr, ch, &gffpar); + + // 高 X 应该使用 GF6 饱和值 + assert!((gfr - gffpar.gf6[0]).abs() < 1e-10); + } + + #[test] + fn test_gfree_consistency() { + // 测试 gfree0 和 gfreed 的一致性 + let mut gffpar = GffPar::new(); + let temp = vec![10000.0; crate::state::MDEPTH]; + + gfree0(0, &temp, &mut gffpar); + + // 在边界条件下测试连续性 + let ch = 1.0; + + // X ≈ 1 边界 + let fr1 = C14 * ch * 0.999; + let fr2 = C14 * ch * 1.001; + let (gfr1, _) = gfreed(0, fr1, ch, &gffpar); + let (gfr2, _) = gfreed(0, fr2, ch, &gffpar); + // 在边界附近应该连续 + assert!((gfr1 - gfr2).abs() < 1.0); + } + + #[test] + fn test_gfree1_basic() { + let gffpar = create_test_gffpar(); + + // 测试低 X 区域 + let x_low = 0.5; + let result_low = gfree1(0, x_low, &gffpar); + assert!(result_low > 0.0); + + // 测试中间区域 + let x_mid = 2.0; + let result_mid = gfree1(0, x_mid, &gffpar); + assert!(result_mid > 0.0); + + // 测试高 X 区域 + let x_high = 10.0; + let result_high = gfree1(0, x_high, &gffpar); + assert!(result_high > 0.0); + + // 高 X 应该等于 GF6 饱和值 + assert!((result_high - gffpar.gf6[0]).abs() < 1e-10); + } + + #[test] + fn test_gfree1_vs_gfreed() { + // gfree1 和 gfreed 的 GFR 部分应该一致 + let gffpar = create_test_gffpar(); + + for x in [0.5, 1.0, 2.0, 5.0, 10.0].iter() { + let fr = C14 / x; // X = C14 * 1 / FR + let (gfr, _) = gfreed(0, fr, 1.0, &gffpar); + let gfr1 = gfree1(0, *x, &gffpar); + assert!((gfr - gfr1).abs() < 1e-10, "Mismatch at x={}", x); + } + } +} diff --git a/src/math/irc.rs b/src/math/irc.rs new file mode 100644 index 0000000..e6384a8 --- /dev/null +++ b/src/math/irc.rs @@ -0,0 +1,117 @@ +//! 氢原子碰撞电离速率。 +//! +//! 重构自 TLUSTY `irc.f` +//! +//! 基于 Johnson (1972)。 + +use crate::math::{expinx, szirc}; + +/// 氢原子碰撞电离激发速率。 +/// +/// 计算从状态 N 由于电子碰撞导致的氢原子电离激发速率。 +/// +/// # 参数 +/// +/// * `n` - 主量子数 +/// * `t` - 温度 (K) +/// * `ic` - 电荷 (1 = H) +/// * `rno` - 连续谱起始能级 +/// +/// # 返回值 +/// +/// 激发速率 SE (cm³/s)。 +/// +/// # 备注 +/// +/// 基于 Johnson (1972)。 +/// Tim Kallman 的 XSTAR 程序的修改版本。 +pub fn irc(n: i32, t: f64, ic: i32, rno: f64) -> f64 { + // 非 H 原子调用 szirc + if ic != 1 { + return szirc(n as usize, t, ic, rno); + } + + let nf = n as f64; + let xo = 1.0 - nf * nf / rno / rno; + let yn = xo * 157803.0 / (t * nf * nf); + + let (an, bn, rn) = if n <= 1 { + let an = 1.9603 * nf + * (1.133 / 3.0 / xo.powi(3) - 0.4059 / 4.0 / xo.powi(4) + 0.07014 / 5.0 / xo.powi(5)); + let bn = 2.0 / 3.0 * nf * nf / xo * (3.0 + 2.0 / xo - 0.603 / (xo * xo)); + let rn = 0.45; + (an, bn, rn) + } else if n == 2 { + let an = 1.9603 * nf + * (1.0785 / 3.0 / xo.powi(3) - 0.2319 / 4.0 / xo.powi(4) + 0.02947 / 5.0 / xo.powi(5)); + let bn = (4.0 - 18.63 / nf + 36.24 / (nf * nf) - 28.09 / (nf * nf * nf)) / nf; + let bn = 2.0 / 3.0 * nf * nf / xo * (3.0 + 2.0 / xo + bn / (xo * xo)); + let rn = 0.653; + (an, bn, rn) + } else { + let g0 = (0.9935 + 0.2328 / nf - 0.1296 / (nf * nf)) / 3.0 / xo.powi(3); + let g1 = -(0.6282 - 0.5598 / nf + 0.5299 / (nf * nf)) / (nf * 4.0) / xo.powi(4); + let g2 = (0.3887 - 1.181 / nf + 1.470 / (nf * nf)) / (nf * nf * 5.0) / xo.powi(5); + let an = 1.9603 * nf * (g0 + g1 + g2); + let bn = (4.0 - 18.63 / nf + 36.24 / (nf * nf) - 28.09 / (nf * nf * nf)) / nf; + let bn = (3.0 + 2.0 / xo + bn / (xo * xo)) * 2.0 * nf * nf / 3.0 / xo; + let rn = 1.94 * nf.powf(-1.57); + (an, bn, rn) + }; + + let rn = rn * xo; + let zn = rn + yn; + + let ey = expinx(yn); + let ez = expinx(zn); + + let mut se = an * (ey / (yn * yn) - (-rn).exp() * ez / (zn * zn)); + + let ey = 1.0 + 1.0 / yn - ey * (2.0 / yn + 1.0); + let ez = (-rn).exp() * (1.0 + 1.0 / zn - ez * (2.0 / zn + 1.0)); + + se = se + (bn - an * (2.0 * nf * nf / xo).ln()) * (ey - ez); + se = se * t.sqrt() * yn * yn * nf * nf * 1.095e-10 / xo; + + se +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_irc_hydrogen_n1() { + // H I 从 n=1 电离,rno > n² = 1 + let result = irc(1, 10000.0, 1, 2.0); + assert!(result.is_finite()); + } + + #[test] + fn test_irc_hydrogen_n2() { + // H I 从 n=2 电离,rno > n² = 4 + let result = irc(2, 10000.0, 1, 5.0); + assert!(result.is_finite()); + } + + #[test] + fn test_irc_hydrogen_n3() { + // H I 从 n=3 电离,rno > n² = 9 + let result = irc(3, 10000.0, 1, 10.0); + assert!(result.is_finite()); + } + + #[test] + fn test_irc_hydrogen_high_temp() { + // 高温 + let result = irc(1, 50000.0, 1, 2.0); + assert!(result.is_finite()); + } + + #[test] + fn test_irc_non_hydrogen() { + // 非 H 原子 (调用 szirc) + let result = irc(1, 10000.0, 2, 2.0); + assert!(result.is_finite()); + } +} diff --git a/src/math/mod.rs b/src/math/mod.rs index 04c5029..ea2dd12 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -1,73 +1,117 @@ //! 数学工具函数,重构自 TLUSTY Fortran。 +mod angset; mod betah; mod bkhsgo; +mod butler; mod carbon; mod ceh12; +mod cion; +mod ckoest; +mod collhe; +mod cross; +mod dielrc; mod erfcx; mod expo; mod expint; mod ffcros; mod gauleg; +mod getwrd; mod gami; +mod gamsp; +mod gfree; mod gaunt; mod gntk; mod grcor; mod hephot; mod hidalg; mod indexx; +mod irc; mod interpolate; mod laguer; mod locate; mod minv3; mod quartc; +mod pffe; +mod pfni; +mod pfspec; mod quit; mod raph; mod reiman; +mod sbfch; +mod sbfhe1; mod sbfhmi; +mod sbfhmi_old; +mod sbfoh; mod sghe12; mod sffhmi; +mod spsigk; mod stark0; mod szirc; +mod tiopf; mod tridag; mod ubeta; +mod verner; mod voigt; mod voigte; mod xk2dop; +mod wn; mod ylintp; +pub use angset::angset; pub use betah::betah; pub use bkhsgo::bkhsgo; +pub use butler::butler; pub use carbon::carbon; pub use ceh12::ceh12; +pub use cion::cion; +pub use ckoest::ckoest; +pub use collhe::collhe; +pub use cross::{cross, crossd}; +pub use dielrc::dielrc; pub use erfcx::{erfcin, erfcx}; pub use expo::expo; pub use expint::{eint, expinx}; pub use ffcros::ffcros; pub use gauleg::gauleg; +pub use getwrd::getwrd; pub use gami::gami; +pub use gamsp::gamsp; +pub use gfree::{gfree0, gfreed}; pub use gaunt::gaunt; pub use gntk::gntk; pub use grcor::grcor; pub use hephot::hephot; pub use hidalg::hidalg; pub use indexx::indexx; +pub use irc::irc; pub use interpolate::{lagran, yint}; pub use laguer::laguer; pub use locate::locate; pub use minv3::minv3; pub use quartc::quartc; +pub use pffe::pffe; +pub use pfni::pfni; +pub use pfspec::pfspec; pub use quit::{quit, quit_error}; pub use raph::raph; pub use reiman::reiman; +pub use sbfch::sbfch; +pub use sbfhe1::sbfhe1; pub use sbfhmi::sbfhmi; +pub use sbfhmi_old::sbfhmi_old; +pub use sbfoh::sbfoh; pub use sghe12::sghe12; pub use sffhmi::sffhmi; +pub use spsigk::spsigk; pub use stark0::stark0; pub use szirc::szirc; +pub use tiopf::tiopf; pub use tridag::tridag; pub use ubeta::ubeta; +pub use verner::verner; pub use voigt::voigt; pub use voigte::voigte; +pub use wn::wn; pub use xk2dop::xk2dop; pub use ylintp::ylintp; diff --git a/src/math/pffe.rs b/src/math/pffe.rs new file mode 100644 index 0000000..5d389e6 --- /dev/null +++ b/src/math/pffe.rs @@ -0,0 +1,193 @@ +//! Fe IV - Fe IX 的配分函数。 +//! +//! 重构自 TLUSTY `pffe.f` +//! 参考: Fischel and Sparks, 1971, NASA SP-3066 +//! +//! 在温度和电子密度网格上进行二维插值计算配分函数。 + +use crate::data::{PFFE_NCA as NCA, PFFE_PN as PN, PFFE_P4A as P4A, PFFE_P4B as P4B, PFFE_P5A as P5A, PFFE_P5B as P5B, PFFE_P6A as P6A, PFFE_P6B as P6B, PFFE_P7A as P7A, PFFE_P7B as P7B, PFFE_P8A as P8A, PFFE_P8B as P8B, PFFE_P9A as P9A, PFFE_P9B as P9B, PFFE_TT as TT}; + +// 常量 +const XEN: f64 = 2.302585093; // ln(10) +const XMIL: f64 = 0.001; +const XMILEN: f64 = XMIL * XEN; +const XBTZ: f64 = 1.38054e-16; // 玻尔兹曼常数 + +/// Fe IV - Fe IX 的配分函数。 +/// +/// 在温度和电子密度网格上进行二维插值。 +/// +/// # 参数 +/// +/// * `ion` - 电离态 (4 = Fe IV, 5 = Fe V, ..., 9 = Fe IX) +/// * `t` - 温度 (K) +/// * `ane` - 电子密度 (cm^-3) +/// +/// # 返回值 +/// +/// * `pf` - 配分函数 +/// * `dut` - d(PF)/dT 导数 +/// * `dun` - d(PF)/d(ANE) 导数 +pub fn pffe(ion: i32, t: f64, ane: f64) -> (f64, f64, f64) { + // Fortran 1-indexed: nca(ion) → Rust 0-indexed: NCA[ion - 1] + // ion: 4=FeIV, 5=FeV, ..., 9=FeIX + let na = NCA[ion as usize - 1] as usize; + let _nb = 50 - na; + let pne = (ane * XBTZ * t).log10(); + let t0 = XMIL * t; + + // 查找电子密度索引 + let (j1, j2) = find_pn_indices(pne); + + // 查找温度索引 + let (i1, i2) = find_tt_indices(t0); + + // 根据温度区间选择插值方式 + let (px1, px2, py1, py2) = if i2 < na { + // 在纯 a 区域 + get_a_values(ion, i1, i2) + } else if i1 == na - 1 { + // 在 a/b 边界 + get_boundary_values(ion, i1, i2, j1, j2, na) + } else { + // 在纯 b 区域 + get_b_values(ion, i1, i2, j1, j2, na) + }; + + // 插值计算 + let dlgunx = px2 - px1; + let px = px1 + (pne - PN[j1]) * dlgunx; + let dlguny = py2 - py1; + let py = py1 + (pne - PN[j1]) * dlguny; + + let delt = TT[i2] - TT[i1]; + let (pf_log, dlgut, dlgun) = if delt != 0.0 { + let dlgut = (py - px) / delt; + let pf_log = px + (t0 - TT[i1]) * dlgut; + let dlgun = dlgunx + (t0 - TT[i1]) / delt * (dlguny - dlgunx); + (pf_log, dlgut, dlgun) + } else { + (px, 0.0, dlgunx) + }; + + let pf = (XEN * pf_log).exp(); + let dut = XMILEN * pf * dlgut; + let dun = (dlgun * pf - t * dut) / ane; + + (pf, dut, dun) +} + +/// 查找电子密度索引 +fn find_pn_indices(pne: f64) -> (usize, usize) { + if pne < PN[0] { + return (0, 0); + } + if pne > PN[9] { + return (9, 9); + } + for j in 0..9 { + if pne >= PN[j] && pne < PN[j + 1] { + return (j, j + 1); + } + } + (0, 1) +} + +/// 查找温度索引 +fn find_tt_indices(t0: f64) -> (usize, usize) { + for i in 0..49 { + if t0 >= TT[i] && t0 < TT[i + 1] { + return (i, i + 1); + } + } + if t0 > TT[49] { + (49, 49) + } else { + (0, 1) + } +} + +/// 从 a 数组获取值 (低密度区) +fn get_a_values(ion: i32, i1: usize, i2: usize) -> (f64, f64, f64, f64) { + match ion { + 4 => (P4A[i1], P4A[i1], P4A[i2], P4A[i2]), + 5 => (P5A[i1], P5A[i1], P5A[i2], P5A[i2]), + 6 => (P6A[i1], P6A[i1], P6A[i2], P6A[i2]), + 7 => (P7A[i1], P7A[i1], P7A[i2], P7A[i2]), + 8 => (P8A[i1], P8A[i1], P8A[i2], P8A[i2]), + 9 => (P9A[i1], P9A[i1], P9A[i2], P9A[i2]), + _ => (0.0, 0.0, 0.0, 0.0), + } +} + +/// 从边界区域获取值 +fn get_boundary_values( + ion: i32, + i1: usize, + i2: usize, + j1: usize, + j2: usize, + na: usize, +) -> (f64, f64, f64, f64) { + let i_idx = i2 - na; + match ion { + 4 => (P4A[i1], P4A[i1], P4B[j1][i_idx], P4B[j2][i_idx]), + 5 => (P5A[i1], P5A[i1], P5B[j1][i_idx], P5B[j2][i_idx]), + 6 => (P6A[i1], P6A[i1], P6B[j1][i_idx], P6B[j2][i_idx]), + 7 => (P7A[i1], P7A[i1], P7B[j1][i_idx], P7B[j2][i_idx]), + 8 => (P8A[i1], P8A[i1], P8B[j1][i_idx], P8B[j2][i_idx]), + 9 => (P9A[i1], P9A[i1], P9B[j1][i_idx], P9B[j2][i_idx]), + _ => (0.0, 0.0, 0.0, 0.0), + } +} + +/// 从 b 数组获取值 (高密度区) +fn get_b_values( + ion: i32, + i1: usize, + i2: usize, + j1: usize, + j2: usize, + na: usize, +) -> (f64, f64, f64, f64) { + let i1_idx = i1 - na; + let i2_idx = i2 - na; + match ion { + 4 => (P4B[j1][i1_idx], P4B[j2][i1_idx], P4B[j1][i2_idx], P4B[j2][i2_idx]), + 5 => (P5B[j1][i1_idx], P5B[j2][i1_idx], P5B[j1][i2_idx], P5B[j2][i2_idx]), + 6 => (P6B[j1][i1_idx], P6B[j2][i1_idx], P6B[j1][i2_idx], P6B[j2][i2_idx]), + 7 => (P7B[j1][i1_idx], P7B[j2][i1_idx], P7B[j1][i2_idx], P7B[j2][i2_idx]), + 8 => (P8B[j1][i1_idx], P8B[j2][i1_idx], P8B[j1][i2_idx], P8B[j2][i2_idx]), + 9 => (P9B[j1][i1_idx], P9B[j2][i1_idx], P9B[j1][i2_idx], P9B[j2][i2_idx]), + _ => (0.0, 0.0, 0.0, 0.0), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pffe_fe4() { + let (pf, dut, dun) = pffe(4, 20000.0, 1e12); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert!(dun.is_finite()); + } + + #[test] + fn test_pffe_fe5() { + let (pf, dut, dun) = pffe(5, 25000.0, 1e13); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert!(dun.is_finite()); + } + + #[test] + fn test_pffe_fe9() { + let (pf, dut, dun) = pffe(9, 50000.0, 1e14); + assert!(pf >= 0.0); + assert!(dut.is_finite()); + assert!(dun.is_finite()); + } +} diff --git a/src/math/pfni.rs b/src/math/pfni.rs new file mode 100644 index 0000000..328e3fe --- /dev/null +++ b/src/math/pfni.rs @@ -0,0 +1,126 @@ +//! Ni IV - Ni IX 的配分函数。 +//! +//! 重构自 TLUSTY `pfni.f` +//! 参考: Kurucz (1992),超过 12,000 个能级 +//! +//! 配分函数只依赖于温度(没有密度依赖)。 + +use crate::data::{ + PFNI_G0, PFNI_P4A, PFNI_P4B, PFNI_P5A, PFNI_P5B, PFNI_P6A, PFNI_P6B, PFNI_P7A, PFNI_P7B, + PFNI_P8A, PFNI_P8B, PFNI_P9A, PFNI_P9B, PFNI_XEN, PFNI_XMIL, +}; + +/// Ni IV - Ni IX 的配分函数。 +/// +/// 在温度网格上进行插值。 +/// +/// # 参数 +/// +/// * `ion` - 电离态 (4 = Ni IV, 5 = Ni V, ..., 9 = Ni IX) +/// * `t` - 温度 (K) +/// +/// # 返回值 +/// +/// * `pf` - 配分函数 +/// * `dut` - d(PF)/dT 导数 +/// * `dun` - d(PF)/d(ANE) 导数 (总是 0,因为没有密度依赖) +pub fn pfni(ion: i32, t: f64) -> (f64, f64, f64) { + // 温度低于 12000 K 时,使用基态统计权重 + if t < 12000.0 { + // Fortran 1-indexed: g0(ion-3) -> Rust: G0[ion-4] + let pf = PFNI_G0[ion as usize - 4]; + return (pf, 0.0, 0.0); + } + + // 计算温度索引 + let it = (t / 1000.0) as i32; + let it = if it >= 350 { 349 } else { it }; + + let t1 = 1000.0 * it as f64; + + // 根据离子和温度选择数组 + let (xu1, xu2) = if t <= 200000.0 { + // 使用 "a" 数组 (11K - 200K, 索引 11-200) + let idx1 = (it - 11) as usize; + let idx2 = (it - 10) as usize; + + match ion { + 4 => (PFNI_P4A[idx1], PFNI_P4A[idx2]), + 5 => (PFNI_P5A[idx1], PFNI_P5A[idx2]), + 6 => (PFNI_P6A[idx1], PFNI_P6A[idx2]), + 7 => (PFNI_P7A[idx1], PFNI_P7A[idx2]), + 8 => (PFNI_P8A[idx1], PFNI_P8A[idx2]), + 9 => (PFNI_P9A[idx1], PFNI_P9A[idx2]), + _ => return (1.0, 0.0, 0.0), + } + } else { + // 使用 "b" 数组 (181K - 350K, 索引 181-350) + let idx1 = (it - 181) as usize; + let idx2 = (it - 180) as usize; + + match ion { + 4 => (PFNI_P4B[idx1], PFNI_P4B[idx2]), + 5 => (PFNI_P5B[idx1], PFNI_P5B[idx2]), + 6 => (PFNI_P6B[idx1], PFNI_P6B[idx2]), + 7 => (PFNI_P7B[idx1], PFNI_P7B[idx2]), + 8 => (PFNI_P8B[idx1], PFNI_P8B[idx2]), + 9 => (PFNI_P9B[idx1], PFNI_P9B[idx2]), + _ => return (1.0, 0.0, 0.0), + } + }; + + // 插值计算 + let dxt = PFNI_XMIL * (xu2 - xu1); + let xu = xu1 + (t - t1) * dxt; + let pf = (PFNI_XEN * xu).exp(); + let dut = PFNI_XEN * pf * dxt; + + (pf, dut, 0.0) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pfni_ni4() { + let (pf, dut, dun) = pfni(4, 20000.0); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert_eq!(dun, 0.0); + } + + #[test] + fn test_pfni_ni5() { + let (pf, dut, dun) = pfni(5, 50000.0); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert_eq!(dun, 0.0); + } + + #[test] + fn test_pfni_ni9() { + let (pf, dut, dun) = pfni(9, 100000.0); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert_eq!(dun, 0.0); + } + + #[test] + fn test_pfni_low_temp() { + // 低温使用基态统计权重 + let (pf, dut, dun) = pfni(4, 10000.0); + assert_eq!(pf, PFNI_G0[0]); // Ni IV 的 g0 + assert_eq!(dut, 0.0); + assert_eq!(dun, 0.0); + } + + #[test] + fn test_pfni_high_temp() { + // 高温使用 "b" 数组 + let (pf, dut, dun) = pfni(6, 250000.0); + assert!(pf > 0.0); + assert!(dut.is_finite()); + assert_eq!(dun, 0.0); + } +} diff --git a/src/math/pfspec.rs b/src/math/pfspec.rs new file mode 100644 index 0000000..b08bb91 --- /dev/null +++ b/src/math/pfspec.rs @@ -0,0 +1,152 @@ +//! 特殊元素的配分函数。 +//! +//! 重构自 TLUSTY `pfspec.f` +//! +//! 为特定原子(Ne 和 S)的特定电离态返回固定的配分函数值。 +//! 这是一个用户自定义过程,用于非标准配分函数计算。 + +/// 特殊元素的配分函数。 +/// +/// 为特定原子和电离态返回预设的配分函数值。 +/// 目前只支持 Ne (Z=10) 和 S (Z=16)。 +/// +/// # 参数 +/// +/// * `iat` - 原子序数 (Z) +/// * `izi` - 电离电荷 (+1 表示中性,+2 表示一次电离,依此类推) +/// * `_t` - 温度 (K),此函数中未使用 +/// * `_ane` - 电子密度 (cm^-3),此函数中未使用 +/// +/// # 返回值 +/// +/// * `u` - 配分函数 +/// * `dut` - dU/dT 导数 (此函数中始终为 0) +/// * `dun` - dU/d(ANE) 导数 (此函数中始终为 0) +/// +/// # 备注 +/// +/// 这是一个占位函数,为特定情况提供固定值。 +/// 支持的原子和电离态: +/// +/// | 原子 | Z | 电离态 | U | +/// |------|---|--------|---| +/// | Ne | 10 | Ne V | 9 | +/// | Ne | 10 | Ne VI | 6 | +/// | Ne | 10 | Ne VII | 12 | +/// | Ne | 10 | Ne VIII | 8 | +/// | Ne | 10 | Ne IX | 1 | +/// | S | 16 | S V | 1 | +/// | S | 16 | S VI | 2 | +/// | S | 16 | S VII | 1 | +/// | S | 16 | S VIII | 6 | +/// | S | 16 | S IX | 9 | +pub fn pfspec(iat: i32, izi: i32, _t: f64, _ane: f64) -> (f64, f64, f64) { + // 默认值 + let mut u = 0.0; + let dut = 0.0; + let dun = 0.0; + + // Ne (Z=10) 的配分函数 + if iat == 10 { + match izi { + 5 => u = 9.0, + 6 => u = 6.0, + 7 => u = 12.0, + 8 => u = 8.0, + 9 => u = 1.0, + _ => {} + } + return (u, dut, dun); + } + + // S (Z=16) 的配分函数 + if iat == 16 { + match izi { + 5 => u = 1.0, + 6 => u = 2.0, + 7 => u = 1.0, + 8 => u = 6.0, + 9 => u = 9.0, + _ => {} + } + return (u, dut, dun); + } + + (u, dut, dun) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pfspec_neon() { + // Ne V + let (u, dut, dun) = pfspec(10, 5, 10000.0, 1e12); + assert!((u - 9.0).abs() < 1e-15); + assert!((dut - 0.0).abs() < 1e-15); + assert!((dun - 0.0).abs() < 1e-15); + + // Ne VI + let (u, _, _) = pfspec(10, 6, 10000.0, 1e12); + assert!((u - 6.0).abs() < 1e-15); + + // Ne VII + let (u, _, _) = pfspec(10, 7, 10000.0, 1e12); + assert!((u - 12.0).abs() < 1e-15); + + // Ne VIII + let (u, _, _) = pfspec(10, 8, 10000.0, 1e12); + assert!((u - 8.0).abs() < 1e-15); + + // Ne IX + let (u, _, _) = pfspec(10, 9, 10000.0, 1e12); + assert!((u - 1.0).abs() < 1e-15); + } + + #[test] + fn test_pfspec_sulfur() { + // S V + let (u, dut, dun) = pfspec(16, 5, 10000.0, 1e12); + assert!((u - 1.0).abs() < 1e-15); + assert!((dut - 0.0).abs() < 1e-15); + assert!((dun - 0.0).abs() < 1e-15); + + // S VI + let (u, _, _) = pfspec(16, 6, 10000.0, 1e12); + assert!((u - 2.0).abs() < 1e-15); + + // S VII + let (u, _, _) = pfspec(16, 7, 10000.0, 1e12); + assert!((u - 1.0).abs() < 1e-15); + + // S VIII + let (u, _, _) = pfspec(16, 8, 10000.0, 1e12); + assert!((u - 6.0).abs() < 1e-15); + + // S IX + let (u, _, _) = pfspec(16, 9, 10000.0, 1e12); + assert!((u - 9.0).abs() < 1e-15); + } + + #[test] + fn test_pfspec_unsupported() { + // 不支持的原子 + let (u, _, _) = pfspec(1, 1, 10000.0, 1e12); // H + assert!((u - 0.0).abs() < 1e-15); + + // 支持的原子但不支持的电离态 + let (u, _, _) = pfspec(10, 1, 10000.0, 1e12); // Ne I + assert!((u - 0.0).abs() < 1e-15); + } + + #[test] + fn test_pfspec_temperature_independence() { + // 结果应该与温度无关 + let (u1, _, _) = pfspec(10, 5, 5000.0, 1e12); + let (u2, _, _) = pfspec(10, 5, 10000.0, 1e12); + let (u3, _, _) = pfspec(10, 5, 50000.0, 1e12); + assert!((u1 - u2).abs() < 1e-15); + assert!((u2 - u3).abs() < 1e-15); + } +} diff --git a/src/math/sbfch.rs b/src/math/sbfch.rs new file mode 100644 index 0000000..0ae826f --- /dev/null +++ b/src/math/sbfch.rs @@ -0,0 +1,215 @@ +//! CH 束缚-自由截面 × 配分函数。 +//! +//! 重构自 TLUSTY `sbfch.f` +//! 参考: Kurucz ATLAS9 +//! +//! 计算CH分子的光电离截面与配分函数的乘积。 + +use crate::data::{ + SBFCH_C1, SBFCH_C10, SBFCH_C11, SBFCH_C2, SBFCH_C3, SBFCH_C4, SBFCH_C5, SBFCH_C6, SBFCH_C7, + SBFCH_C8, SBFCH_C9, SBFCH_PARTCH as PARTCH, +}; + +// 常量 +const FIHU: f64 = 500.0; +const FIHUI: f64 = 1.0 / FIHU; +const TWHU: f64 = 200.0; +const TWHUI: f64 = 1.0 / TWHU; +const TENL: f64 = 2.30258509299405; // ln(10) +const CAS: f64 = 2.99792458e10; // 光速 (cm/s) + +/// CH 束缚-自由截面 × 配分函数。 +/// +/// # 参数 +/// +/// * `fr` - 频率 (Hz) +/// * `t` - 温度 (K) +/// +/// # 返回值 +/// +/// 截面 × 配分函数 (cm²) +pub fn sbfch(fr: f64, t: f64) -> f64 { + // 静态变量保存上一次的频率和计算结果 + // 在 Rust 中使用 static + Cell 或直接重新计算 + // 这里简化处理,每次都重新计算 + + // 频率转换为波数和电子伏特 + let waveno = fr / CAS; + let evolt = waveno / 8065.479; + + let n = (evolt * 10.0) as i32; + let en = (n as f64) * 0.1; + + // 边界检查 + if n < 20 || n >= 105 { + return 0.0; + } + + // 温度边界检查 + if t >= 9000.0 { + return 0.0; + } + + // 插值计算截面 (在能量方向) + let crosscht = compute_crosscht(n, evolt, en); + + // 插值计算配分函数 + let part = compute_partition(t); + + // 插值计算截面 (在温度方向) + compute_opacity(t, &crosscht, part) +} + +/// 计算截面在能量方向的插值 +/// +/// # 参数 +/// * `n` - Fortran 1-indexed 能量索引 (20-104) +/// * `evolt` - 电子伏特 +/// * `en` - 离散化的能量 +fn compute_crosscht(n: i32, evolt: f64, en: f64) -> [f64; 15] { + let mut crosscht = [0.0; 15]; + + // Fortran 1-indexed: CROSSCH(it, n), it=1-15, n=20-104 + // 在 Rust 中直接使用 Fortran 索引计算 + for it in 1..=15_i32 { + let val1 = get_crossch(it, n); + let val2 = get_crossch(it, n + 1); + crosscht[(it - 1) as usize] = val1 + (val2 - val1) * (evolt - en) * 10.0; + } + + crosscht +} + +/// 从 CROSSCH 数组获取值 +/// +/// Fortran EQUIVALENCE 映射 (列优先存储): +/// - C1: CROSSCH(1:15, 1:10) -> 150 元素 +/// - C2: CROSSCH(1:15, 11:20) -> 150 元素 +/// - ... +/// - C11: CROSSCH(1:15, 101:105) -> 75 元素 +/// +/// # 参数 +/// * `it` - Fortran 1-indexed 温度索引 (1-15) +/// * `n` - Fortran 1-indexed 能量索引 (20-104) +fn get_crossch(it: i32, n: i32) -> f64 { + // 确定属于哪个 C 数组 (1-11) + let c_index = (n - 1) / 10 + 1; // 1-11 + // 在该 C 数组内的局部 n 值 (0-9) + let local_n = (n - 1) % 10; // 0-9 + + // Fortran 列优先存储: 索引 = local_n * 15 + it + let idx = (local_n * 15 + it - 1) as usize; // 转为 0-indexed + + match c_index { + 1 => SBFCH_C1[idx], + 2 => SBFCH_C2[idx], + 3 => SBFCH_C3[idx], + 4 => SBFCH_C4[idx], + 5 => SBFCH_C5[idx], + 6 => SBFCH_C6[idx], + 7 => SBFCH_C7[idx], + 8 => SBFCH_C8[idx], + 9 => SBFCH_C9[idx], + 10 => SBFCH_C10[idx], + 11 => { + if idx < 75 { + SBFCH_C11[idx] + } else { + 0.0 + } + } + _ => 0.0, + } +} + +/// 计算配分函数插值 +fn compute_partition(t: f64) -> f64 { + // Fortran: IT=int((T-1000.)*twhui+1.) + // twhui = 1/200, 所以 IT = (T-1000)/200 + 1 + let mut it = ((t - 1000.0) * TWHUI + 1.0) as i32; + if it < 1 { + it = 1; + } + if it > 40 { + it = 40; + } + + let tn = (it as f64) * TWHU + 800.0; + + // Fortran 1-indexed: PARTCH(IT) -> Rust 0-indexed: PARTCH[it-1] + let it_usize = it as usize; + if it_usize >= 41 { + return PARTCH[40]; + } + + PARTCH[it_usize - 1] + (PARTCH[it_usize] - PARTCH[it_usize - 1]) * (t - tn) * TWHUI +} + +/// 计算最终的截面 × 配分函数 +fn compute_opacity(t: f64, crosscht: &[f64; 15], part: f64) -> f64 { + // Fortran: IT=int((T-2000.)*fihui+1.) + // fihui = 1/500, 所以 IT = (T-2000)/500 + 1 + let mut it = ((t - 2000.0) * FIHUI + 1.0) as i32; + if it < 1 { + it = 1; + } + if it > 14 { + it = 14; + } + + let tn = (it as f64) * FIHU + 1500.0; + let it_usize = it as usize; + + // 插值 + let log_cross = crosscht[it_usize - 1] + + (crosscht[it_usize] - crosscht[it_usize - 1]) * (t - tn) * FIHUI; + + (log_cross * TENL).exp() * part +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sbfch_boundary_low_energy() { + // 能量太低 (< 2 eV) + // 2 eV = 2 * 8065.479 cm^-1 = 16130.958 cm^-1 + // FR = 16130.958 * CAS = 4.834e14 Hz + let result = sbfch(1e14, 5000.0); // ~0.012 eV + assert_eq!(result, 0.0); + } + + #[test] + fn test_sbfch_boundary_high_energy() { + // 能量太高 (>= 10.5 eV) + // 10.5 eV = 10.5 * 8065.479 cm^-1 = 84687.5 cm^-1 + // FR = 84687.5 * CAS = 2.54e15 Hz + let result = sbfch(3e15, 5000.0); // ~24.8 eV + assert_eq!(result, 0.0); + } + + #[test] + fn test_sbfch_boundary_high_temp() { + // 温度太高 (>= 9000 K) + let result = sbfch(1e15, 10000.0); // ~8.3 eV, 10000 K + assert_eq!(result, 0.0); + } + + #[test] + fn test_sbfch_valid() { + // 有效范围内的计算 + // 5 eV -> FR ≈ 1.2e15 Hz + let result = sbfch(1.2e15, 5000.0); // ~5 eV, 5000 K + assert!(result > 0.0, "Expected positive result, got {}", result); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfch_mid_range() { + // 中间范围: 6 eV, 4000 K + let result = sbfch(1.45e15, 4000.0); + assert!(result >= 0.0, "Expected non-negative result, got {}", result); + assert!(result.is_finite()); + } +} diff --git a/src/math/sbfhe1.rs b/src/math/sbfhe1.rs new file mode 100644 index 0000000..8af88a7 --- /dev/null +++ b/src/math/sbfhe1.rs @@ -0,0 +1,213 @@ +//! He I 束缚-自由光电离截面。 +//! +//! 重构自 TLUSTY `sbfhe1.f`。 +//! +//! 计算中性氦 n = 1, 2, 3, 4 态的光电离截面。 +//! 使用 Opacity Project 截面的适当平均 (由 HEPHOT 计算) 或 Koester 拟合。 + +use super::{ckoest, hephot}; + +/// 计算 He I 光电离截面。 +/// +/// 对于非平均 (l,s) 态或某些平均态计算截面。 +/// +/// # 参数 +/// +/// - `ii` - 下能级索引 (显式能级编号) +/// - `ib` - 光电离开关 IBF +/// - = 10: 从平均能级跃迁 +/// - = 11 或 21: 从非平均单态跃迁 +/// - = 13 或 23: 从非平均三态跃迁 +/// - `fr` - 频率 (Hz) +/// - `nquanti` - 能级 ii 的主量子数 n +/// - `gi` - 能级 ii 的统计权重 g +/// - `gg` - 用于 Koester 拟合的统计权重 +/// +/// # 返回 +/// +/// 光电离截面 (cm²) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION SBFHE1(II,IB,FR,GG) +/// NI=NQUANT(II) +/// IGI=INT(G(II)+0.01) +/// IS=IB-10 +/// IF(IB.GT.20) IS=IB-20 +/// ... +/// END +/// ``` +pub fn sbfhe1(ib: i32, nquanti: i32, gi: f64, fr: f64, gg: f64) -> f64 { + let ni = nquanti; + let igi = (gi + 0.01) as i32; + let is = if ib > 20 { ib - 20 } else { ib - 10 }; + + // ---------------------------------------------------------------- + // IB=11 或 13 - 从非平均 (l,s) 能级光电离 + // ---------------------------------------------------------------- + if is == 1 || is == 3 { + let il = (igi / is - 1) / 2; + if ib < 20 { + return hephot(is, il, ni, fr); + } else { + return ckoest(is, il, ni, fr, gg); + } + } + + // ---------------------------------------------------------------- + // IS=0 - 从平均能级光电离 + // ---------------------------------------------------------------- + if is == 0 { + if ni == 2 { + // n=2 平均能级 + return sbfhe1_n2(igi, fr); + } else if ni == 3 { + // n=3 平均能级 + return sbfhe1_n3(igi, fr); + } else if ni == 4 { + // n=4 平均能级 + return sbfhe1_n4(igi, fr); + } + } + + // 不一致的输入 + panic!( + "SBFHE1: inconsistent input - quantum number={}, statistical weight={}, S={}", + ni, igi, is + ); +} + +/// n=2 平均能级光电离截面 +fn sbfhe1_n2(igi: i32, fr: f64) -> f64 { + if igi == 4 { + // a) 平均单态 + (hephot(1, 0, 2, fr) + 3.0 * hephot(1, 1, 2, fr)) / 9.0 + } else if igi == 12 { + // b) 平均三态 + (hephot(3, 0, 2, fr) + 3.0 * hephot(3, 1, 2, fr)) / 9.0 + } else if igi == 16 { + // c) 单态和三态的平均 + (hephot(1, 0, 2, fr) + + 3.0 * (hephot(1, 1, 2, fr) + hephot(3, 0, 2, fr)) + + 9.0 * hephot(3, 1, 2, fr)) + / 16.0 + } else { + panic!("SBFHE1: inconsistent n=2 level, igi={}", igi); + } +} + +/// n=3 平均能级光电离截面 +fn sbfhe1_n3(igi: i32, fr: f64) -> f64 { + if igi == 9 { + // a) 平均单态 + (hephot(1, 0, 3, fr) + 3.0 * hephot(1, 1, 3, fr) + 5.0 * hephot(1, 2, 3, fr)) / 9.0 + } else if igi == 27 { + // b) 平均三态 + (hephot(3, 0, 3, fr) + 3.0 * hephot(3, 1, 3, fr) + 5.0 * hephot(3, 2, 3, fr)) / 9.0 + } else if igi == 36 { + // c) 单态和三态的平均 + (hephot(1, 0, 3, fr) + + 3.0 * hephot(1, 1, 3, fr) + + 5.0 * hephot(1, 2, 3, fr) + + 3.0 * hephot(3, 0, 3, fr) + + 9.0 * hephot(3, 1, 3, fr) + + 15.0 * hephot(3, 2, 3, fr)) + / 36.0 + } else { + panic!("SBFHE1: inconsistent n=3 level, igi={}", igi); + } +} + +/// n=4 平均能级光电离截面 +fn sbfhe1_n4(igi: i32, fr: f64) -> f64 { + if igi == 16 { + // a) 平均单态 + (hephot(1, 0, 4, fr) + + 3.0 * hephot(1, 1, 4, fr) + + 5.0 * hephot(1, 2, 4, fr) + + 7.0 * hephot(1, 3, 4, fr)) + / 16.0 + } else if igi == 48 { + // b) 平均三态 + (hephot(3, 0, 4, fr) + + 3.0 * hephot(3, 1, 4, fr) + + 5.0 * hephot(3, 2, 4, fr) + + 7.0 * hephot(3, 3, 4, fr)) + / 16.0 + } else if igi == 64 { + // c) 单态和三态的平均 + (hephot(1, 0, 4, fr) + + 3.0 * hephot(1, 1, 4, fr) + + 5.0 * hephot(1, 2, 4, fr) + + 7.0 * hephot(1, 3, 4, fr) + + 3.0 * hephot(3, 0, 4, fr) + + 9.0 * hephot(3, 1, 4, fr) + + 15.0 * hephot(3, 2, 4, fr) + + 21.0 * hephot(3, 3, 4, fr)) + / 64.0 + } else { + panic!("SBFHE1: inconsistent n=4 level, igi={}", igi); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sbfhe1_singlet() { + // IB=11: 非平均单态 + let fr = 1e16; // 高于电离阈值 + let result = sbfhe1(11, 2, 1.0, fr, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_triplet() { + // IB=13: 非平均三态 + let fr = 1e16; + let result = sbfhe1(13, 2, 3.0, fr, 3.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_averaged_n2_singlet() { + // IB=10, n=2, igi=4: 平均单态 + let fr = 1e15; + let result = sbfhe1(10, 2, 4.0, fr, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_averaged_n2_triplet() { + // IB=10, n=2, igi=12: 平均三态 + let fr = 1e15; + let result = sbfhe1(10, 2, 12.0, fr, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_averaged_n3() { + // IB=10, n=3 + let fr = 1e15; + let result = sbfhe1(10, 3, 9.0, fr, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_averaged_n4() { + // IB=10, n=4 + let fr = 1e15; + let result = sbfhe1(10, 4, 16.0, fr, 1.0); + assert!(result > 0.0); + } + + #[test] + fn test_sbfhe1_koester() { + // IB=21 或 23: 使用 Koester 拟合 + let fr = 1e16; + let result = sbfhe1(21, 2, 1.0, fr, 1.0); + assert!(result > 0.0); + } +} diff --git a/src/math/sbfhmi_old.rs b/src/math/sbfhmi_old.rs new file mode 100644 index 0000000..3dea14c --- /dev/null +++ b/src/math/sbfhmi_old.rs @@ -0,0 +1,109 @@ +//! H⁻ 束缚-自由截面 (旧版本)。 +//! +//! 重构自 TLUSTY `sbfhmi_old.f` +//! +//! 负氢离子的束缚-自由光致电离截面。 + +/// H⁻ 束缚-自由截面 (旧版本)。 +/// +/// 计算负氢离子的束缚-自由光致电离截面。 +/// +/// # 参数 +/// +/// * `fr` - 频率 (Hz) +/// +/// # 返回值 +/// +/// 截面 (cm²),如果频率低于阈值则返回 0。 +/// +/// # 备注 +/// +/// 阈值频率 FR0 = 1.8259×10¹⁴ Hz (对应 H⁻ 的束缚能)。 +/// 使用两个不同的多项式拟合: +/// - 低于 2.111×10¹⁴ Hz: 使用 X = c × (1/FR0 - 1/FR) 的多项式 +/// - 高于 2.111×10¹⁴ Hz: 使用 X = c/FR 的多项式 +pub fn sbfhmi_old(fr: f64) -> f64 { + const FR0: f64 = 1.8259e14; + const C: f64 = 2.997925e15; // 光速 (Å/s) + + // 低于阈值 + if fr < FR0 { + return 0.0; + } + + if fr < 2.111e14 { + // 低于 2.111×10¹⁴ Hz 的多项式 + let x = C * (1.0 / FR0 - 1.0 / fr); + let sbfhmi = (2.69818e-1 + x * (2.2019e-1 + x * (-4.11288e-2 + x * 2.73236e-3))) + * x + * 1e-17; + sbfhmi + } else { + // 高于 2.111×10¹⁴ Hz 的多项式 + let x = C / fr; + let sbfhmi = (6.80133e-3 + + x * (1.78708e-1 + x * (1.6479e-1 + x * (-2.04842e-2 + x * 5.95244e-4)))) + * 1e-17; + sbfhmi + } +} + +#[cfg(test)] +mod tests { + use super::*; + use approx::assert_relative_eq; + + #[test] + fn test_sbfhmi_old_below_threshold() { + // 低于阈值 + let result = sbfhmi_old(1e14); + assert_relative_eq!(result, 0.0, epsilon = 1e-30); + } + + #[test] + fn test_sbfhmi_old_at_threshold() { + // 在阈值处 (x=0,结果为 0) + let result = sbfhmi_old(1.8259e14); + assert_relative_eq!(result, 0.0, epsilon = 1e-30); + } + + #[test] + fn test_sbfhmi_old_low_frequency() { + // 低频区 (1.8259e14 < fr < 2.111e14) + let result = sbfhmi_old(2.0e14); + assert!(result > 0.0); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfhmi_old_transition() { + // 在过渡点 (2.111e14) + let result = sbfhmi_old(2.111e14); + assert!(result > 0.0); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfhmi_old_high_frequency() { + // 高频区 (fr > 2.111e14) + let result = sbfhmi_old(5e14); + assert!(result > 0.0); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfhmi_old_visible() { + // 可见光范围 + let result = sbfhmi_old(5.45e14); // 550 nm + assert!(result > 0.0); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfhmi_old_uv() { + // 紫外范围 + let result = sbfhmi_old(1e15); + assert!(result > 0.0); + assert!(result.is_finite()); + } +} diff --git a/src/math/sbfoh.rs b/src/math/sbfoh.rs new file mode 100644 index 0000000..e14b4bc --- /dev/null +++ b/src/math/sbfoh.rs @@ -0,0 +1,185 @@ +//! OH 束缚-自由截面 × 配分函数。 +//! +//! 重构自 TLUSTY `sbfoh.f` +//! 参考: Kurucz ATLAS9 + +use crate::data::{ + SBFOH_C1, SBFOH_C10, SBFOH_C11, SBFOH_C12, SBFOH_C13, SBFOH_C2, SBFOH_C3, SBFOH_C4, + SBFOH_C5, SBFOH_C6, SBFOH_C7, SBFOH_C8, SBFOH_C9, SBFOH_PARTOH as PARTOH, +}; + +// 常量 +const FIHU: f64 = 500.0; +const FIHUI: f64 = 1.0 / FIHU; +const TWHU: f64 = 200.0; +const TWHUI: f64 = 1.0 / TWHU; +const TENL: f64 = 2.30258509299405; // ln(10) +const CAS: f64 = 2.99792458e10; // 光速 (cm/s) + +/// OH 束缚-自由截面 × 配分函数。 +/// +/// # 参数 +/// +/// * `fr` - 频率 (Hz) +/// * `t` - 温度 (K) +/// +/// # 返回值 +/// +/// 截面 × 配分函数 (cm²) +pub fn sbfoh(fr: f64, t: f64) -> f64 { + // 频率转换为波数和电子伏特 + let waveno = fr / CAS; + let evolt = waveno / 8065.479; + + // Fortran: N=int(EVOLT*10.-20.) + // EN = N*0.1 + 2.0 + // N 范围: 1-129 (对应 evolt 2.1-14.9 eV) + let n = (evolt * 10.0 - 20.0) as i32; + let en = (n as f64) * 0.1 + 2.0; + + // 边界检查 + if n <= 0 || n >= 130 { + return 0.0; + } + + // 温度边界检查 + if t >= 9000.0 { + return 0.0; + } + + // 插值计算截面 (在能量方向) + let crossoht = compute_crossoht(n, evolt, en); + + // 插值计算配分函数 + let part = compute_partition(t); + + // 插值计算截面 (在温度方向) + compute_opacity(t, &crossoht, part) +} + +/// 计算截面在能量方向的插值 +fn compute_crossoht(n: i32, evolt: f64, en: f64) -> [f64; 15] { + let mut crossoht = [0.0; 15]; + + // Fortran 1-indexed: CROSSOH(it, n), it=1-15, n=1-130 + for it in 1..=15_i32 { + let val1 = get_crossoh(it, n); + let val2 = get_crossoh(it, n + 1); + crossoht[(it - 1) as usize] = val1 + (val2 - val1) * (evolt - en) * 10.0; + } + + crossoht +} + +/// 从 CROSSOH 数组获取值 +/// +/// Fortran EQUIVALENCE 映射 (列优先存储): +/// - C1: CROSSOH(1:15, 1:10) -> 150 元素 +/// - C2: CROSSOH(1:15, 11:20) -> 150 元素 +/// - ... +/// - C13: CROSSOH(1:15, 121:130) -> 150 元素 +fn get_crossoh(it: i32, n: i32) -> f64 { + // 确定属于哪个 C 数组 (1-13) + let c_index = (n - 1) / 10 + 1; + // 在该 C 数组内的局部 n 值 (0-9) + let local_n = (n - 1) % 10; + + // Fortran 列优先存储: 索引 = local_n * 15 + it + let idx = (local_n * 15 + it - 1) as usize; + + match c_index { + 1 => SBFOH_C1[idx], + 2 => SBFOH_C2[idx], + 3 => SBFOH_C3[idx], + 4 => SBFOH_C4[idx], + 5 => SBFOH_C5[idx], + 6 => SBFOH_C6[idx], + 7 => SBFOH_C7[idx], + 8 => SBFOH_C8[idx], + 9 => SBFOH_C9[idx], + 10 => SBFOH_C10[idx], + 11 => SBFOH_C11[idx], + 12 => SBFOH_C12[idx], + 13 => SBFOH_C13[idx], + _ => 0.0, + } +} + +/// 计算配分函数插值 +fn compute_partition(t: f64) -> f64 { + let mut it = ((t - 1000.0) * TWHUI + 1.0) as i32; + if it < 1 { + it = 1; + } + if it > 40 { + it = 40; + } + + let tn = (it as f64) * TWHU + 800.0; + let it_usize = it as usize; + + PARTOH[it_usize - 1] + (PARTOH[it_usize] - PARTOH[it_usize - 1]) * (t - tn) * TWHUI +} + +/// 计算最终的截面 × 配分函数 +fn compute_opacity(t: f64, crossoht: &[f64; 15], part: f64) -> f64 { + let mut it = ((t - 2000.0) * FIHUI + 1.0) as i32; + if it < 1 { + it = 1; + } + if it > 14 { + it = 14; + } + + let tn = (it as f64) * FIHU + 1500.0; + let it_usize = it as usize; + + let log_cross = crossoht[it_usize - 1] + + (crossoht[it_usize] - crossoht[it_usize - 1]) * (t - tn) * FIHUI; + + (log_cross * TENL).exp() * part +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sbfoh_boundary_low_energy() { + // 能量太低 (<= 2 eV) + let result = sbfoh(4e14, 5000.0); // ~3.3 eV 但 n 可能 <= 0 + // n = (3.3*10 - 20) = 13, 应该是有效的 + assert!(result >= 0.0); + } + + #[test] + fn test_sbfoh_boundary_high_energy() { + // 能量太高 (>= 15 eV) + let result = sbfoh(4e15, 5000.0); // ~33 eV + assert_eq!(result, 0.0); + } + + #[test] + fn test_sbfoh_boundary_high_temp() { + // 温度太高 (>= 9000 K) + let result = sbfoh(1e15, 10000.0); + assert_eq!(result, 0.0); + } + + #[test] + fn test_sbfoh_valid() { + // 有效范围: 5 eV, 5000 K + // 5 eV -> n = 50 - 20 = 30 + let result = sbfoh(1.2e15, 5000.0); + assert!(result > 0.0, "Expected positive result, got {}", result); + assert!(result.is_finite()); + } + + #[test] + fn test_sbfoh_mid_range() { + // 中间范围: 8 eV, 4000 K + let result = sbfoh(1.9e15, 4000.0); + assert!(result >= 0.0); + assert!(result.is_finite()); + } +} diff --git a/src/math/spsigk.rs b/src/math/spsigk.rs new file mode 100644 index 0000000..e3a020c --- /dev/null +++ b/src/math/spsigk.rs @@ -0,0 +1,114 @@ +//! 特殊光电离截面评估。 +//! +//! 重构自 TLUSTY `spsigk.f` +//! +//! 非标准光电离截面评估,用户自定义过程。 + +use crate::math::{carbon, hidalg, reiman, sghe12}; + +/// 特殊光电离截面。 +/// +/// 根据能级索引 IB 选择适当的光电离截面计算方法。 +/// +/// # 参数 +/// +/// * `ib` - 能级索引 (负值表示特殊处理) +/// * `fr` - 频率 (Hz) +/// +/// # 返回值 +/// +/// 光电离截面 (cm²)。 +/// +/// # 备注 +/// +/// 基本上是用户自定义过程,这里提供一些示例: +/// - IB = -201: He I 基态的特殊公式 +/// - IB = -202: He I 平均能级 +/// - IB = -602, -603: C I 基态组态能级 2p² ¹D 和 ¹S +/// - IB = -101 到 -137: Hidalgo (1968) 数据 +/// - IB = -301 到 -337: Reilman & Manson (1979) 数据 +pub fn spsigk(ib: i32, fr: f64) -> f64 { + // He I 基态的特殊公式 + if ib == -201 { + return 7.3e-18 * (1.373 - 2.311e-16 * fr).exp(); + } + + // He I 平均能级 + if ib == -202 { + return sghe12(fr); + } + + // C I 基态组态能级 2p² ¹D 和 ¹S + if ib == -602 || ib == -603 { + return carbon(ib, fr); + } + + // Hidalgo (Ap.J. 153, 981, 1968) 光电离数据 + if ib >= -137 && ib <= -101 { + return hidalg(ib, fr); + } + + // Reilman & Manson (Ap.J. Suppl. 40, 815, 1979) 光电离数据 + if ib >= -337 && ib <= -301 { + return reiman(ib, fr); + } + + // 默认返回 0 + 0.0 +} + +#[cfg(test)] +mod tests { + use super::*; + use approx::assert_relative_eq; + + #[test] + fn test_spsigk_he_ground() { + // He I 基态 + let result = spsigk(-201, 1e16); + assert!(result.is_finite()); + assert!(result > 0.0); + } + + #[test] + fn test_spsigk_he_n2() { + // He I + let result = spsigk(-202, 1e16); + assert!(result.is_finite()); + } + + #[test] + fn test_spsigk_carbon_d() { + // C I 2p² ¹D + let result = spsigk(-602, 1e16); + assert!(result.is_finite()); + } + + #[test] + fn test_spsigk_carbon_s() { + // C I 2p² ¹S + let result = spsigk(-603, 1e16); + assert!(result.is_finite()); + } + + #[test] + fn test_spsigk_hidalgo() { + // Hidalgo 数据 + let result = spsigk(-101, 1e16); + assert!(result.is_finite()); + } + + #[test] + fn test_spsigk_reiman() { + // Reilman & Manson 数据 + let result = spsigk(-301, 1e16); + assert!(result.is_finite()); + } + + #[test] + fn test_spsigk_unknown() { + // 未知索引返回 0 + let result = spsigk(-999, 1e16); + assert_relative_eq!(result, 0.0, epsilon = 1e-30); + } +} diff --git a/src/math/tiopf.rs b/src/math/tiopf.rs new file mode 100644 index 0000000..c3367ee --- /dev/null +++ b/src/math/tiopf.rs @@ -0,0 +1,204 @@ +//! TiO 配分函数。 +//! +//! 重构自 TLUSTY `tiopf.f` +//! +//! 数据来自 Kurucz 网站。 + +use std::sync::OnceLock; + +/// TiO 配分函数数据 (800个点,10K-8000K)。 +static PF0: OnceLock<[f64; 800]> = OnceLock::new(); + +fn get_pf0() -> &'static [f64; 800] { + PF0.get_or_init(|| { + [ + 29.107, 55.425, 82.417, 111.190, 142.564, 176.916, 214.340, 254.774, 298.065, 344.021, + 392.431, 443.089, 495.795, 550.365, 606.632, 664.449, 723.686, 784.230, 845.981, + 908.862, 972.800, 1037.739, 1103.636, 1170.451, 1238.155, 1306.723, 1376.144, + 1446.403, 1517.492, 1589.409, 1662.152, 1735.724, 1810.122, 1885.352, 1961.428, + 2038.351, 2116.119, 2194.758, 2274.260, 2354.633, 2435.907, 2518.063, 2601.125, + 2685.096, 2769.992, 2855.809, 2942.560, 3030.257, 3118.897, 3208.496, 3299.067, + 3390.598, 3483.106, 3576.598, 3671.095, 3766.569, 3863.048, 3960.522, 4059.035, + 4158.545, 4259.074, 4360.642, 4463.259, 4566.905, 4671.582, 4777.321, 4884.105, + 4991.937, 5100.852, 5210.813, 5321.838, 5433.972, 5547.154, 5661.417, 5776.789, + 5893.211, 6010.774, 6129.422, 6249.173, 6370.026, 6491.973, 6615.042, 6739.240, + 6864.542, 6990.959, 7118.533, 7247.214, 7377.053, 7508.012, 7640.121, 7773.370, + 7907.764, 8043.309, 8180.032, 8317.835, 8456.861, 8597.055, 8738.396, 8880.926, + 9024.672, 9169.570, 9315.610, 9462.927, 9611.339, 9760.963, 9911.798, 10063.900, + 10217.148, 10371.572, 10527.253, 10684.109, 10842.173, 11001.469, 11161.970, + 11323.751, 11486.758, 11650.978, 11816.415, 11983.159, 12151.134, 12320.243, + 12490.668, 12662.333, 12835.234, 13009.470, 13184.926, 13361.601, 13539.660, + 13718.891, 13899.456, 14081.252, 14264.326, 14448.643, 14634.341, 14821.225, + 15009.476, 15199.021, 15389.829, 15581.955, 15775.377, 15970.188, 16166.239, + 16363.513, 16562.006, 16761.930, 16963.301, 17165.906, 17369.881, 17575.236, + 17781.814, 17989.816, 18198.996, 18409.707, 18621.680, 18835.068, 19049.715, + 19265.768, 19483.375, 19702.006, 19922.209, 20143.668, 20366.555, 20590.742, + 20816.402, 21043.338, 21271.672, 21501.369, 21732.563, 21965.119, 22199.068, + 22434.432, 22671.266, 22909.307, 23148.898, 23389.893, 23632.322, 23875.969, + 24121.160, 24367.707, 24615.848, 24865.471, 25116.320, 25368.604, 25622.342, + 25877.512, 26134.055, 26392.404, 26651.764, 26912.826, 27175.250, 27439.197, + 27704.539, 27971.287, 28239.572, 28509.373, 28780.707, 29053.516, 29327.602, + 29603.338, 29880.539, 30159.105, 30439.322, 30721.055, 31004.254, 31288.818, + 31575.061, 31862.693, 32151.781, 32442.586, 32734.619, 33027.777, 33323.023, + 33619.535, 33917.707, 34217.711, 34518.996, 34821.676, 35126.195, 35432.141, + 35739.602, 36048.926, 36359.488, 36672.023, 36985.633, 37300.863, 37617.965, + 37936.469, 38256.309, 38578.074, 38901.668, 39226.461, 39552.969, 39880.852, + 40210.785, 40541.852, 40874.691, 41209.359, 41545.535, 41883.602, 42222.715, + 42563.895, 42906.508, 43250.656, 43596.902, 43944.355, 44293.695, 44644.504, + 44997.621, 45351.590, 45707.242, 46065.008, 46424.367, 46785.605, 47148.023, + 47512.496, 47878.418, 48246.426, 48615.895, 48987.336, 49360.082, 49734.758, + 50111.004, 50489.383, 50868.996, 51250.250, 51633.691, 52018.945, 52405.715, + 52794.090, 53184.340, 53576.375, 53970.605, 54366.176, 54763.148, 55162.430, + 55563.215, 55966.391, 56371.000, 56777.176, 57185.570, 57596.074, 58007.617, + 58421.418, 58837.172, 59254.539, 59673.418, 60094.066, 60517.410, 60941.844, + 61368.660, 61797.395, 62227.590, 62659.789, 63094.238, 63529.695, 63967.488, + 64407.887, 64849.496, 65292.867, 65735.922, 66182.000, 66631.266, 67082.055, + 67534.391, 67988.992, 68446.117, 68904.789, 69365.180, 69827.914, 70292.781, + 70759.352, 71228.500, 71699.375, 72171.672, 72647.086, 73123.984, 73603.023, + 74083.516, 74566.359, 75050.555, 75537.758, 76027.258, 76518.125, 77012.008, + 77507.063, 78003.813, 78503.977, 79006.125, 79509.320, 80015.375, 80522.461, + 81031.938, 81544.164, 82058.313, 82574.352, 83093.914, 83614.367, 84136.820, + 84662.211, 85188.867, 85719.375, 86249.977, 86783.781, 87319.219, 87857.180, + 88396.797, 88939.805, 89484.266, 90032.023, 90580.930, 91132.563, 91686.148, + 92242.742, 92799.406, 93360.016, 93923.453, 94488.313, 95055.211, 95625.297, + 96197.477, 96771.531, 97348.156, 97926.922, 98507.453, 99091.563, 99677.938, + 100267.234, 100856.438, 101449.828, 102045.750, 102643.094, 103244.117, 103846.969, + 104450.313, 105057.641, 105667.188, 106279.516, 106894.937, 107512.789, 108133.117, + 108754.758, 109377.687, 110005.039, 110634.602, 111266.141, 111902.133, 112537.984, + 113178.891, 113819.766, 114464.312, 115110.969, 115760.687, 116412.469, 117068.055, + 117724.547, 118384.383, 119047.469, 119712.469, 120380.187, 121051.336, 121724.102, + 122399.250, 123076.266, 123756.977, 124441.195, 125126.406, 125816.453, 126506.766, + 127202.367, 127899.086, 128598.266, 129299.969, 130004.969, 130712.016, 131409.266, + 132117.719, 132828.969, 133544.016, 134262.750, 134986.344, 135712.891, 136439.937, + 137170.969, 137905.562, 138641.578, 139380.266, 140122.937, 140868.641, 141615.484, + 142366.703, 143123.078, 143880.000, 144638.484, 145401.594, 146168.125, 146935.359, + 147707.484, 148482.641, 149256.578, 150037.281, 150821.953, 151606.750, 152396.094, + 153188.766, 153983.391, 154782.141, 155582.203, 156387.234, 157192.719, 158003.156, + 158815.125, 159632.437, 160450.766, 161274.750, 162098.172, 162926.000, 163756.609, + 164593.141, 165430.859, 166270.937, 167114.750, 167960.797, 168811.562, 169663.906, + 170517.203, 171376.531, 172239.469, 173105.891, 173975.250, 174847.203, 175721.453, + 176597.250, 177480.984, 178366.094, 179253.828, 180145.734, 181038.000, 181936.031, + 182837.969, 183739.922, 184645.937, 185558.281, 186470.844, 187387.422, 188307.234, + 189232.281, 190156.000, 191088.234, 192022.062, 192957.250, 193899.328, 194842.984, + 195788.391, 196736.156, 197687.828, 198645.719, 199603.422, 200569.234, 201536.437, + 202508.641, 203481.000, 204459.016, 205438.750, 206424.312, 207409.953, 208398.734, + 209393.234, 210391.047, 211390.984, 212395.516, 213401.547, 214420.141, 215431.812, + 216453.453, 217476.734, 218501.266, 219530.219, 220560.719, 221597.891, 222637.875, + 223677.750, 224725.500, 225777.406, 226829.297, 227893.125, 228954.547, 230020.969, + 231086.453, 232157.469, 233233.047, 234315.406, 235395.625, 236480.953, 237572.125, + 238666.484, 239765.125, 240863.281, 241969.750, 243079.250, 244191.719, 245304.812, + 246427.937, 247548.234, 248673.562, 249804.984, 250942.781, 252078.953, 253222.812, + 254369.641, 255519.359, 256671.406, 257827.906, 258988.859, 260154.734, 261322.281, + 262458.781, 263606.437, 264770.625, 265947.750, 267125.156, 268314.125, 269507.687, + 270702.344, 271905.156, 273110.156, 274318.937, 275531.687, 276751.344, 277970.781, + 279198.531, 280425.750, 281663.250, 282897.469, 284138.906, 285383.594, 286637.031, + 287891.156, 289147.625, 290413.312, 291678.719, 292946.031, 294225.875, 295501.344, + 296782.656, 298070.094, 299363.875, 300652.250, 301953.750, 303260.062, 304563.781, + 305874.375, 307191.437, 308517.031, 309835.750, 311159.375, 312490.937, 313827.469, + 315166.781, 316511.031, 317860.406, 319214.969, 320565.875, 321929.344, 323296.906, + 324660.219, 326035.687, 327413.844, 328794.406, 330173.156, 331566.156, 332953.469, + 334356.187, 335757.625, 337165.562, 338566.094, 339984.750, 341402.937, 342828.125, + 344257.562, 345686.750, 347123.125, 348564.250, 350008.906, 351453.219, 352908.062, + 354361.469, 355828.000, 357292.500, 358765.719, 360233.687, 361713.562, 363200.187, + 364685.656, 366174.500, 367673.594, 369174.906, 370678.969, 372191.125, 373708.937, + 375225.281, 376743.719, 378270.406, 379804.500, 381334.250, 382879.125, 384420.812, + 385969.531, 387519.812, 389078.937, 390639.781, 392213.875, 393782.437, 395359.156, + 396943.625, 398527.625, 400110.937, 401711.750, 403310.344, 404908.937, 406513.875, + 408125.781, 409741.906, 411356.875, 412979.500, 414613.125, 416245.500, 417889.094, + 419530.000, 421179.906, 422831.531, 424484.344, 426153.187, 427816.406, 429489.094, + 431161.312, 432840.656, 434517.000, 436215.281, 437896.000, 439602.594, 441300.625, + 443016.156, 444722.906, 446445.437, 448164.812, 449885.937, 451615.094, 453351.594, + 455090.125, 456833.281, 458582.719, 460335.344, 462094.844, 463857.094, 465629.906, + 467402.781, 469178.406, 470963.750, 472745.906, 474539.594, 476333.312, 478131.125, + 479934.000, 481740.750, 483557.844, 485376.625, 487202.937, 489033.562, 490868.031, + 492709.281, 494547.375, 496401.094, 498249.594, 500110.250, 501966.594, 503836.062, + 505704.437, 507580.687, 509469.187, 511349.781, 513239.000, 515137.187, 517038.812, + 518942.906, 520858.156, 522767.094, 524610.625, 526433.812, 528331.062, 530253.437, + 532185.500, 534127.875, 536073.937, 538028.312, 539983.375, 541954.687, 543916.312, + 545902.500, 547874.812, 549857.125, 551850.937, 553839.937, 555836.625, 557838.500, + 559849.937, 561859.375, 563880.625, 565889.875, 567916.000, 569953.625, 571990.375, + 574034.937, 576085.062, 578127.375, 580188.937, 582251.000, 584328.812, 586385.562, + 588464.062, 590551.875, 592644.625, 594722.250, 596829.937, 598931.375, 601029.687, + 603142.812, 605262.812, 607384.625, 609513.125, 611644.000, 613775.875, 615930.375, + 618073.750, 620218.437, 622381.937, 624524.312, 626697.500, 628869.000, 631040.937, + 633223.562, 635409.187, 637597.562, 639800.187, 642002.125, 644212.562, 646416.250, + 648633.562, 650864.187, 653083.687, 655315.312, 657549.687, 659795.500, 662032.250, + 664292.875, 666542.312, 668806.250, 671071.312, 673340.937, 675626.938, 677898.750, + ] + }) +} + +/// TiO 配分函数。 +/// +/// # 参数 +/// +/// * `t` - 温度 (K) +/// +/// # 返回值 +/// +/// 配分函数值。 +/// +/// # 备注 +/// +/// 数据来自 Kurucz 网站,温度范围 10K-8000K。 +/// Fortran 原代码: it=int(t/10.), pf=pf0(it) +/// Fortran 1-indexed: t=10 → it=1 → pf0(1) +/// Rust 0-indexed: t=10 → it=0 → pf0[0] +pub fn tiopf(t: f64) -> f64 { + let pf0 = get_pf0(); + + // 计算索引: Fortran int(t/10.) 是 1-indexed + // Rust 需要 -1 转换为 0-indexed + let mut it = (t / 10.0) as i32 - 1; + + // 限制索引范围 + if it < 0 { + it = 0; + } + if it >= 800 { + it = 799; + } + + pf0[it as usize] +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tiopf_low_temp() { + // 低温边界 (T=10K → index 1 in Fortran, index 0 in Rust) + let result = tiopf(10.0); + assert!((result - 29.107).abs() < 1e-6); + } + + #[test] + fn test_tiopf_mid_temp() { + // 中间温度 (T=5000K → index 500 in Fortran, index 499 in Rust) + let result = tiopf(5000.0); + assert!(result > 0.0); + assert!(result.is_finite()); + } + + #[test] + fn test_tiopf_high_temp() { + // 高温边界 (T=8000K → index 800, clamped to 799) + let result = tiopf(8000.0); + assert!((result - 677898.750).abs() < 1e-6); + } + + #[test] + fn test_tiopf_above_max() { + // 超过最大温度 + let result = tiopf(10000.0); + assert!((result - 677898.750).abs() < 1e-6); + } + + #[test] + fn test_tiopf_exact_step() { + // 精确步长 (T=100K → index 10 in Fortran, index 9 in Rust) + let result = tiopf(100.0); + assert!((result - 344.021).abs() < 1e-6); + } +} diff --git a/src/math/verner.rs b/src/math/verner.rs new file mode 100644 index 0000000..c31be96 --- /dev/null +++ b/src/math/verner.rs @@ -0,0 +1,298 @@ +//! Verner 光电离截面计算。 +//! +//! 重构自 TLUSTY `verner.f`, `vern16.f`, `vern18.f`, `vern20.f`, `vern26.f`。 +//! +//! 基态原子和离子的光电离截面解析拟合。 +//! 参考:Verner D.A. et al. 1996, ApJ 465; Verner & Yakovlev 1995, A&AS 109, 125 + +use crate::data::{ + VERN16_E0, VERN16_E95, VERN16_EMX, VERN16_P95, VERN16_PV, VERN16_S0, VERN16_S95, + VERN16_Y0, VERN16_Y1, VERN16_Y95, VERN16_YA, VERN16_YW, VERN16_YW95, VERN18_E0, VERN18_E95, + VERN18_EMX, VERN18_P95, VERN18_PV, VERN18_S0, VERN18_S95, VERN18_Y0, VERN18_Y1, VERN18_Y95, + VERN18_YA, VERN18_YW, VERN18_YW95, VERN20_E0, VERN20_E95, VERN20_EMX, VERN20_P95, + VERN20_PV, VERN20_S0, VERN20_S95, VERN20_Y0, VERN20_Y1, VERN20_Y95, VERN20_YA, VERN20_YW, + VERN20_YW95, VERN26_E0, VERN26_E95, VERN26_EMX, VERN26_P95, VERN26_PV, VERN26_S0, + VERN26_S95, VERN26_Y0, VERN26_Y1, VERN26_Y95, VERN26_YA, VERN26_YW, VERN26_YW95, + VERNER_E0, VERNER_E95, VERNER_EMX, VERNER_IV0, VERNER_P95, VERNER_PV, VERNER_S0, + VERNER_S95, VERNER_Y0, VERNER_Y1, VERNER_Y95, VERNER_YA, VERNER_YW, VERNER_YW95, +}; +use crate::state::H; + +// ============================================================================ +// 常量 +// ============================================================================ + +/// h / 1.6022e-12 (erg/eV) +const HHEV: f64 = H / 1.6022e-12; +const T18: f64 = 1e-18; + +// ============================================================================ +// Verner 截面计算 +// ============================================================================ + +/// 计算基态原子和离子的光电离截面。 +/// +/// 使用 Verner et al. (1996) 的解析拟合公式。 +/// 支持 H 到 Si, S, Ar, Ca 和 Fe 的基态。 +/// +/// # 参数 +/// +/// - `fr` - 频率 (Hz) +/// - `itr` - 跃迁索引 (0-indexed) +/// - `atomic` - 原子数据 +/// +/// # 返回 +/// +/// 光电离截面 (cm²) +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// FUNCTION VERNER(FR,ITR) +/// INCLUDE 'BASICS.FOR' +/// INCLUDE 'ATOMIC.FOR' +/// ... +/// II=ILOW(ITR) +/// N1=NFIRST(IEL(II)) +/// ... +/// END +/// ``` +pub fn verner(fr: f64, itr: usize, atomic: &crate::state::AtomicData) -> f64 { + let e = HHEV * fr; + + // 获取跃迁的下能级索引 (Fortran 1-indexed → Rust 0-indexed) + let ii = (atomic.trapar.ilow[itr] - 1) as usize; + + // 检查是否为基态 + let ion_idx = (atomic.levpar.iel[ii] - 1) as usize; + let n1 = atomic.ionpar.nfirst[ion_idx]; + if atomic.trapar.ilow[itr] != n1 { + panic!( + "Verner fits only for ground states: ilow={}, nfirst={}", + atomic.trapar.ilow[itr], n1 + ); + } + + // 获取原子序号和电荷 + let atm_idx = (atomic.levpar.iatm[ii] - 1) as usize; + let iat = atomic.atopar.numat[atm_idx]; + let izz = atomic.ionpar.iz[ion_idx]; + + // 检查原子序号范围 + if iat > 14 { + // 对于更重的元素,调用专门的函数 + return verner_heavy(e, izz, iat); + } + + // 计算索引 + let iver = (VERNER_IV0[(iat - 1) as usize] as usize) + (izz as usize); + + // 根据能量选择表达式 + if e < VERNER_EMX[iver] { + // 1996 表达式 + let xx = e / VERNER_E0[iver] - VERNER_Y0[iver]; + let yy = (xx * xx + VERNER_Y1[iver] * VERNER_Y1[iver]).sqrt(); + let aa = (xx - 1.0) * (xx - 1.0) + VERNER_YW[iver] * VERNER_YW[iver]; + let bb = yy.powf(0.5 * VERNER_PV[iver] - 5.5); + let cc = (1.0 + (yy / VERNER_YA[iver]).sqrt()).powf(VERNER_PV[iver]); + let fy = aa * bb / cc; + VERNER_S0[iver] * T18 * fy + } else { + // 1995 高能表达式 (内壳层电子电离) + let yy = e / VERNER_E95[iver]; + let xl = if (iat - izz) >= 10 { 1.0 } else { 0.0 }; + let q = 0.5 * VERNER_P95[iver] - 5.5 - xl; + let aa = (yy - 1.0) * (yy - 1.0) + VERNER_YW95[iver] * VERNER_YW95[iver]; + let bb = yy.powf(q); + let cc = (1.0 + (yy / VERNER_Y95[iver]).sqrt()).powf(VERNER_P95[iver]); + let fy = aa * bb / cc; + VERNER_S95[iver] * T18 * fy + } +} + +/// 重元素 Verner 截面计算。 +fn verner_heavy(e: f64, izz: i32, iat: i32) -> f64 { + match iat { + 26 => vern26(e, izz), + 16 => vern16(e, izz), + 18 => vern18(e, izz), + 20 => vern20(e, izz), + _ => panic!("VERNER - No data for this element: iat={}, izz={}", iat, izz), + } +} + +// ============================================================================ +// 重元素截面函数 +// ============================================================================ + +/// S (Z=16) Verner 截面。 +/// +/// 计算 S I - S XVI 所有硫离子的基态光电离截面。 +/// +/// # 参数 +/// +/// - `e` - 光子能量 (eV) +/// - `izz` - 电荷 (1-16, 对应 S I 到 S XVI) +fn vern16(e: f64, izz: i32) -> f64 { + let iver = (izz - 1) as usize; + + if e < VERN16_EMX[iver] { + // 1996 表达式 + let xx = e / VERN16_E0[iver] - VERN16_Y0[iver]; + let yy = (xx * xx + VERN16_Y1[iver] * VERN16_Y1[iver]).sqrt(); + let aa = (xx - 1.0) * (xx - 1.0) + VERN16_YW[iver] * VERN16_YW[iver]; + let bb = yy.powf(0.5 * VERN16_PV[iver] - 5.5); + let cc = (1.0 + (yy / VERN16_YA[iver]).sqrt()).powf(VERN16_PV[iver]); + let fy = aa * bb / cc; + VERN16_S0[iver] * T18 * fy + } else { + // 1995 高能表达式 (内壳层电子电离) + let yy = e / VERN16_E95[iver]; + let xl = if izz <= 6 { 1.0 } else { 0.0 }; + let q = 0.5 * VERN16_P95[iver] - 5.5 - xl; + let aa = (yy - 1.0) * (yy - 1.0) + VERN16_YW95[iver] * VERN16_YW95[iver]; + let bb = yy.powf(q); + let cc = (1.0 + (yy / VERN16_Y95[iver]).sqrt()).powf(VERN16_P95[iver]); + let fy = aa * bb / cc; + VERN16_S95[iver] * T18 * fy + } +} + +/// Ar (Z=18) Verner 截面。 +/// +/// 计算 Ar I - Ar XVIII 所有氩离子的基态光电离截面。 +fn vern18(e: f64, izz: i32) -> f64 { + let iver = (izz - 1) as usize; + + if e < VERN18_EMX[iver] { + let xx = e / VERN18_E0[iver] - VERN18_Y0[iver]; + let yy = (xx * xx + VERN18_Y1[iver] * VERN18_Y1[iver]).sqrt(); + let aa = (xx - 1.0) * (xx - 1.0) + VERN18_YW[iver] * VERN18_YW[iver]; + let bb = yy.powf(0.5 * VERN18_PV[iver] - 5.5); + let cc = (1.0 + (yy / VERN18_YA[iver]).sqrt()).powf(VERN18_PV[iver]); + let fy = aa * bb / cc; + VERN18_S0[iver] * T18 * fy + } else { + let yy = e / VERN18_E95[iver]; + let xl = if izz <= 8 { 1.0 } else { 0.0 }; + let q = 0.5 * VERN18_P95[iver] - 5.5 - xl; + let aa = (yy - 1.0) * (yy - 1.0) + VERN18_YW95[iver] * VERN18_YW95[iver]; + let bb = yy.powf(q); + let cc = (1.0 + (yy / VERN18_Y95[iver]).sqrt()).powf(VERN18_P95[iver]); + let fy = aa * bb / cc; + VERN18_S95[iver] * T18 * fy + } +} + +/// Ca (Z=20) Verner 截面。 +/// +/// 计算 Ca I - Ca XX 所有钙离子的基态光电离截面。 +fn vern20(e: f64, izz: i32) -> f64 { + let iver = (izz - 1) as usize; + + if e < VERN20_EMX[iver] { + let xx = e / VERN20_E0[iver] - VERN20_Y0[iver]; + let yy = (xx * xx + VERN20_Y1[iver] * VERN20_Y1[iver]).sqrt(); + let aa = (xx - 1.0) * (xx - 1.0) + VERN20_YW[iver] * VERN20_YW[iver]; + let bb = yy.powf(0.5 * VERN20_PV[iver] - 5.5); + let cc = (1.0 + (yy / VERN20_YA[iver]).sqrt()).powf(VERN20_PV[iver]); + let fy = aa * bb / cc; + VERN20_S0[iver] * T18 * fy + } else { + let yy = e / VERN20_E95[iver]; + let xl = if izz <= 10 { 1.0 } else { 0.0 }; + let q = 0.5 * VERN20_P95[iver] - 5.5 - xl; + let aa = (yy - 1.0) * (yy - 1.0) + VERN20_YW95[iver] * VERN20_YW95[iver]; + let bb = yy.powf(q); + let cc = (1.0 + (yy / VERN20_Y95[iver]).sqrt()).powf(VERN20_P95[iver]); + let fy = aa * bb / cc; + VERN20_S95[iver] * T18 * fy + } +} + +/// Fe (Z=26) Verner 截面。 +/// +/// 计算 Fe I - Fe XXVI 所有铁离子的基态光电离截面。 +fn vern26(e: f64, izz: i32) -> f64 { + let iver = (izz - 1) as usize; + + if e < VERN26_EMX[iver] { + // 1996 表达式 + let xx = e / VERN26_E0[iver] - VERN26_Y0[iver]; + let yy = (xx * xx + VERN26_Y1[iver] * VERN26_Y1[iver]).sqrt(); + let aa = (xx - 1.0) * (xx - 1.0) + VERN26_YW[iver] * VERN26_YW[iver]; + let bb = yy.powf(0.5 * VERN26_PV[iver] - 5.5); + let cc = (1.0 + (yy / VERN26_YA[iver]).sqrt()).powf(VERN26_PV[iver]); + let fy = aa * bb / cc; + VERN26_S0[iver] * T18 * fy + } else { + // 1995 高能表达式 (内壳层电子电离) + let yy = e / VERN26_E95[iver]; + let xl = if izz <= 16 { 1.0 } else { 0.0 }; + let q = 0.5 * VERN26_P95[iver] - 5.5 - xl; + let aa = (yy - 1.0) * (yy - 1.0) + VERN26_YW95[iver] * VERN26_YW95[iver]; + let bb = yy.powf(q); + let cc = (1.0 + (yy / VERN26_Y95[iver]).sqrt()).powf(VERN26_P95[iver]); + let fy = aa * bb / cc; + VERN26_S95[iver] * T18 * fy + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // 创建测试用的原子数据 + fn create_test_atomic_data() -> crate::state::AtomicData { + let mut atomic = crate::state::AtomicData::default(); + + // 设置 H I 的数据 (最简单的情况) + // 假设能级 1 是 H I 基态 + atomic.levpar.iel[0] = 1; // 离子索引 1 + atomic.levpar.iatm[0] = 1; // 原子索引 1 + + // H I 离子参数 + atomic.ionpar.nfirst[0] = 1; // 第一个能级索引 + atomic.ionpar.iz[0] = 1; // 电荷 Z=1 + + // H 原子参数 + atomic.atopar.numat[0] = 1; // 原子序数 Z=1 + + // 跃迁参数 - 跃迁 0 从能级 1 开始 + atomic.trapar.ilow[0] = 1; + + atomic + } + + #[test] + fn test_verner_hydrogen() { + let atomic = create_test_atomic_data(); + + // 测试 H I 基态光电离 + // 频率对应 13.6 eV (电离阈值) + let fr_threshold = 13.6 / HHEV; + let result = verner(fr_threshold, 0, &atomic); + + // 在阈值处应该有非零截面 + assert!(result > 0.0); + } + + #[test] + fn test_verner_high_frequency() { + let atomic = create_test_atomic_data(); + + // 高频测试 + let fr = 100.0 / HHEV; // 100 eV + let result = verner(fr, 0, &atomic); + + assert!(result >= 0.0); + } + + #[test] + fn test_verner_data_loaded() { + // 验证数据已加载 + assert!(VERNER_S0.len() > 0); + assert!(VERNER_E0.len() > 0); + assert!(VERNER_IV0.len() == 14); + } +} diff --git a/src/math/wn.rs b/src/math/wn.rs new file mode 100644 index 0000000..10c4261 --- /dev/null +++ b/src/math/wn.rs @@ -0,0 +1,138 @@ +//! 占据概率计算。 +//! +//! 重构自 TLUSTY `wn.f`。 +//! +//! 使用 Hummer & Mihalas (1988) 的方法计算氢离子占据概率。 + +// ============================================================================ +// 常量参数 +// ============================================================================ + +const P1: f64 = 0.1402; +const P2: f64 = 0.1285; +const P3: f64 = 1.0; +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; + +// ============================================================================ +// 主函数 +// ============================================================================ + +/// 计算氢离子的占据概率。 +/// +/// 使用 Hummer & Mihalas (1988) Ap.J. 331, 794 的公式 (4.26) 和 (4.39)。 +/// 近似计算 Q(β)。 +/// +/// # 参数 +/// +/// - `xn` - 对应于量子数 n 的实数 +/// - `a` - 相关参数 +/// - `ane` - 电子密度 +/// - `z` - 离子电荷 +/// - `bergfc` - β 引力因子 (来自 INPPAR COMMON) +/// +/// # 返回 +/// +/// 占据概率 w_n +/// +/// # Fortran 原始代码 +/// +/// ```fortran +/// function wn(xn,a,ane,z) +/// INCLUDE 'BASICS.FOR' +/// ... +/// cb=cb0*bergfc +/// ... +/// end +/// ``` +pub fn wn(xn: f64, a: f64, ane: f64, z: f64, bergfc: f64) -> f64 { + // 计算 cb = cb0 * bergfc + let cb = CB0 * bergfc; + + // 计算 k(n) + let xkn = if xn <= TKN { + 1.0 + } else { + let xn1 = 1.0 / (xn + 1.0); + CKN * xn * xn1 * xn1 + }; + + // 计算 beta + // beta = cb * z^3 * k(n) / n^4 * ane^(2/3) + let beta = cb * z.powi(3) * xkn / xn.powi(4) * ane.powf(F23); + + // 近似表达式计算 Q(beta) + let x = (1.0 + P3 * a).powf(P4); + let c1 = P1 * (x + P5 * (z - 1.0) * a.powi(3)); + let c2 = P2 * x; + let f = (c1 * beta.powi(3)) / (1.0 + c2 * beta * beta.sqrt()); + + // w_n = f / (1 + f) + f / (1.0 + f) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_wn_basic() { + // 基本测试:xn=3, z=1, ane=1e14, a=0 + let result = wn(3.0, 0.0, 1e14, 1.0, 1.0); + assert!(result > 0.0 && result < 1.0, "wn should be between 0 and 1"); + } + + #[test] + fn test_wn_low_quantum_number() { + // 低量子数 (xn <= TKN) + let result = wn(2.0, 0.1, 1e14, 1.0, 1.0); + assert!(result > 0.0 && result < 1.0); + } + + #[test] + fn test_wn_high_quantum_number() { + // 高量子数 (xn > TKN) + let result = wn(10.0, 0.1, 1e14, 1.0, 1.0); + assert!(result > 0.0 && result < 1.0); + } + + #[test] + fn test_wn_different_charge() { + // 不同电荷 + let result = wn(5.0, 0.1, 1e14, 2.0, 1.0); + assert!(result > 0.0 && result < 1.0); + } + + #[test] + fn test_wn_different_bergfc() { + // 不同 bergfc 值 + let result1 = wn(5.0, 0.1, 1e14, 1.0, 1.0); + let result2 = wn(5.0, 0.1, 1e14, 1.0, 2.0); + // bergfc 越大,cb 越大,beta 越大,wn 应该越大 + assert!(result2 > result1); + } + + #[test] + fn test_wn_electron_density_effect() { + // 电子密度影响 + let result1 = wn(5.0, 0.1, 1e12, 1.0, 1.0); + let result2 = wn(5.0, 0.1, 1e16, 1.0, 1.0); + // 电子密度越高,wn 应该越小 + assert!(result2 < result1); + } + + #[test] + fn test_wn_correlation_parameter() { + // 相关参数影响 + let result1 = wn(5.0, 0.0, 1e14, 1.0, 1.0); + let result2 = wn(5.0, 1.0, 1e14, 1.0, 1.0); + // a > 0 时结果应该不同 + assert!((result1 - result2).abs() > 1e-10); + } +} diff --git a/src/state/alipar.rs b/src/state/alipar.rs new file mode 100644 index 0000000..e296c90 --- /dev/null +++ b/src/state/alipar.rs @@ -0,0 +1,250 @@ +//! ALI (加速 Lambda 迭代) 相关数组。 +//! +//! 重构自 TLUSTY `ALIPAR.FOR` + +use super::constants::*; + +// ============================================================================ +// FIXALP - 固定 ALI 参数 +// ============================================================================ + +/// ALI 固定参数和数组。 +/// 对应 COMMON /FIXALP/ +/// +/// 包含大量辐射转移计算中间变量: +/// - ABSO, EMIS, SCAT: 吸收/发射/散射系数 +/// - REIT, REIN, REIM, REIP: 辐射等效项 +/// - AREIT, AREIN, AREIM, AREIP: A 相关 +/// - HEIT, HEIN, HEIM, HEIP: He 相关 +#[derive(Debug, Clone)] +pub struct FixAlp { + // 频率相关 (MFREQ) + /// 吸收系数 + pub abso: Vec, + /// 发射系数 + pub emis: Vec, + /// 散射系数 + pub scat: Vec, + + // 深度相关 (MDEPTH) + /// 辐射等效 - T 导数 + pub reit: Vec, + /// 辐射等效 - N 导数 + pub rein: Vec, + /// 辐射等效 - M 导数 + pub reim: Vec, + + // 能级导数 (MLVEXP × MDEPTH) + pub reip: Vec>, + + // A 矩阵相关 + pub areit: Vec, + pub arein: Vec, + pub areim: Vec, + pub areip: Vec>, + + // C 矩阵相关 + pub creit: Vec, + pub crein: Vec, + pub creim: Vec, + pub creip: Vec>, + + // 辐射等效 X + pub reix: Vec, + pub creix: Vec, + + // Red 相关 - T + pub redx: Vec, + pub redt: Vec, + pub redn: Vec, + pub redm: Vec, + pub redp: Vec>, + + // Red 相关 - M + pub redxm: Vec, + pub redtm: Vec, + pub rednm: Vec, + pub redmm: Vec, + pub redpm: Vec>, + + // Red 相关 - P + pub redtp: Vec, + pub rednp: Vec, + pub redxp: Vec, + pub redmp: Vec, + pub redpp: Vec>, + + // He 相关 - T + pub heit: Vec, + pub hein: Vec, + pub heim: Vec, + pub heip: Vec>, + + // He 相关 - M + pub heitm: Vec, + pub heinm: Vec, + pub heimm: Vec, + pub heipm: Vec>, + + // He 相关 - P + pub heitp: Vec, + pub heinp: Vec, + pub heimp: Vec, + pub heipp: Vec>, + + // Ehe/Ere 相关 + pub ehet: Vec, + pub ehen: Vec, + pub eret: Vec, + pub eren: Vec, + pub ehep: Vec>, + pub erep: Vec>, + + // AP 相关 + pub apt: Vec>, + pub apn: Vec>, + pub aapt: Vec>, + pub aapn: Vec>, + pub capt: Vec>, + pub capn: Vec>, + + // APP 矩阵 (MLVEXP × MLVEXP × MDEPTH) + pub app: Vec>>, + pub aapp: Vec>>, + pub capp: Vec>>, + + // 控制参数 + pub qtlas: f64, + pub ifali: i32, + pub ifpopr: i32, + pub irprec: i32, + pub ifprec: i32, + pub itold1: i32, + pub itold2: i32, + pub itlas: i32, +} + +impl Default for FixAlp { + fn default() -> Self { + Self { + abso: vec![0.0; MFREQ], + emis: vec![0.0; MFREQ], + scat: vec![0.0; MFREQ], + + reit: vec![0.0; MDEPTH], + rein: vec![0.0; MDEPTH], + reim: vec![0.0; MDEPTH], + reip: vec![vec![0.0; MDEPTH]; MLVEXP], + + areit: vec![0.0; MDEPTH], + arein: vec![0.0; MDEPTH], + areim: vec![0.0; MDEPTH], + areip: vec![vec![0.0; MDEPTH]; MLVEXP], + + creit: vec![0.0; MDEPTH], + crein: vec![0.0; MDEPTH], + creim: vec![0.0; MDEPTH], + creip: vec![vec![0.0; MDEPTH]; MLVEXP], + + reix: vec![0.0; MDEPTH], + creix: vec![0.0; MDEPTH], + + redx: vec![0.0; MDEPTH], + redt: vec![0.0; MDEPTH], + redn: vec![0.0; MDEPTH], + redm: vec![0.0; MDEPTH], + redp: vec![vec![0.0; MDEPTH]; MLVEXP], + + redxm: vec![0.0; MDEPTH], + redtm: vec![0.0; MDEPTH], + rednm: vec![0.0; MDEPTH], + redmm: vec![0.0; MDEPTH], + redpm: vec![vec![0.0; MDEPTH]; MLVEXP], + + redtp: vec![0.0; MDEPTH], + rednp: vec![0.0; MDEPTH], + redxp: vec![0.0; MDEPTH], + redmp: vec![0.0; MDEPTH], + redpp: vec![vec![0.0; MDEPTH]; MLVEXP], + + heit: vec![0.0; MDEPTH], + hein: vec![0.0; MDEPTH], + heim: vec![0.0; MDEPTH], + heip: vec![vec![0.0; MDEPTH]; MLVEXP], + + heitm: vec![0.0; MDEPTH], + heinm: vec![0.0; MDEPTH], + heimm: vec![0.0; MDEPTH], + heipm: vec![vec![0.0; MDEPTH]; MLVEXP], + + heitp: vec![0.0; MDEPTH], + heinp: vec![0.0; MDEPTH], + heimp: vec![0.0; MDEPTH], + heipp: vec![vec![0.0; MDEPTH]; MLVEXP], + + ehet: vec![0.0; MDEPTH], + ehen: vec![0.0; MDEPTH], + eret: vec![0.0; MDEPTH], + eren: vec![0.0; MDEPTH], + ehep: vec![vec![0.0; MDEPTH]; MLVEX3], + erep: vec![vec![0.0; MDEPTH]; MLVEX3], + + apt: vec![vec![0.0; MDEPTH]; MLVEXP], + apn: vec![vec![0.0; MDEPTH]; MLVEXP], + aapt: vec![vec![0.0; MDEPTH]; MLVEX3], + aapn: vec![vec![0.0; MDEPTH]; MLVEX3], + capt: vec![vec![0.0; MDEPTH]; MLVEX3], + capn: vec![vec![0.0; MDEPTH]; MLVEX3], + + app: vec![vec![vec![0.0; MDEPTH]; MLVEXP]; MLVEXP], + aapp: vec![vec![vec![0.0; MDEPTH]; MLVEX3]; MLVEX3], + capp: vec![vec![vec![0.0; MDEPTH]; MLVEX3]; MLVEX3], + + qtlas: 0.0, + ifali: 0, + ifpopr: 0, + irprec: 0, + ifprec: 0, + itold1: 0, + itold2: 0, + itlas: 0, + } + } +} + +impl FixAlp { + /// 估算内存使用 (MB) + pub fn memory_usage_mb(&self) -> f64 { + // 主要数组大小估算 + let freq_size = 3 * MFREQ * std::mem::size_of::(); + let depth_1d = 22 * MDEPTH * std::mem::size_of::(); + let depth_2d_lvexp = 17 * MLVEXP * MDEPTH * std::mem::size_of::(); + let depth_2d_lvex3 = 10 * MLVEX3 * MDEPTH * std::mem::size_of::(); + let depth_3d_lvexp = 3 * MLVEXP * MLVEXP * MDEPTH * std::mem::size_of::(); + let depth_3d_lvex3 = 3 * MLVEX3 * MLVEX3 * MDEPTH * std::mem::size_of::(); + + (freq_size + depth_1d + depth_2d_lvexp + depth_2d_lvex3 + depth_3d_lvexp + depth_3d_lvex3) as f64 + / (1024.0 * 1024.0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_fixalp_creation() { + let fixalp = FixAlp::default(); + assert_eq!(fixalp.abso.len(), MFREQ); + assert_eq!(fixalp.reit.len(), MDEPTH); + assert_eq!(fixalp.reip.len(), MLVEXP); + } + + #[test] + fn test_fixalp_memory() { + let fixalp = FixAlp::default(); + let mem = fixalp.memory_usage_mb(); + println!("FixAlp memory usage: {:.2} MB", mem); + assert!(mem > 0.0); + } +} diff --git a/src/state/arrays.rs b/src/state/arrays.rs new file mode 100644 index 0000000..369aade --- /dev/null +++ b/src/state/arrays.rs @@ -0,0 +1,329 @@ +//! 大型计算数组。 +//! +//! 重构自 TLUSTY `ARRAY1.FOR` 中的 COMMON 块。 +//! 包含辐射转移方程求解所需的大型矩阵和向量。 + +use super::constants::*; + +// ============================================================================ +// 主矩阵数组 (无标签 COMMON) +// ============================================================================ + +/// 主计算数组。 +/// 对应 ARRAY1.FOR 中的无标签 COMMON 块 +#[derive(Debug, Clone)] +pub struct MainArrays { + // 矩阵 (MTOT × MTOT) + /// A 矩阵 + pub a: Vec>, + /// B 矩阵 + pub b: Vec>, + /// C 矩阵 + pub c: Vec>, + /// E 矩阵 + pub e: Vec>, + + // 向量 (MTOT) + /// 左向量 + pub vecl: Vec, + /// Y1 向量 + pub y1: Vec, + /// Y2 向量 + pub y2: Vec, + + // Ψ 相关向量 (MTOT) + /// Ψ 在前深度 + pub psi0: Vec, + /// Ψ 在当前深度 + pub psim: Vec, + /// Ψ 在后深度 + pub psip: Vec, + + // 辐射相关向量 (MTOT) + pub rad0: Vec, + pub radm: Vec, + pub radp: Vec, + + // 频率相关数组 (MFREX) + /// FK 在前深度 + pub fkm: Vec, + /// FK 在当前深度 + pub fk0: Vec, + /// FK 在后深度 + pub fkp: Vec, + + // 吸收系数 (MFREX) + pub absom: Vec, + pub abso0: Vec, + pub absop: Vec, + + // 发射系数 (MFREX) + pub emism: Vec, + pub emis0: Vec, + pub emisp: Vec, + + // 散射系数 (MFREX) + pub scatm: Vec, + pub scat0: Vec, + pub scatp: Vec, + + // 温度导数 (MFREX) + pub dabtm: Vec, + pub dabt0: Vec, + pub dabtp: Vec, + pub demtm: Vec, + pub demt0: Vec, + pub demtp: Vec, + + // 密度导数 (MFREX) + pub dabnm: Vec, + pub dabn0: Vec, + pub dabnp: Vec, + pub demnm: Vec, + pub demn0: Vec, + pub demnp: Vec, + + // 质量导数 (MFREX) + pub dabmm: Vec, + pub dabm0: Vec, + pub dabmp: Vec, + pub demmm: Vec, + pub demm0: Vec, + pub demmp: Vec, + + // 深度权重 (MFREX) + pub wdepm: Vec, + pub wdep0: Vec, + pub wdepp: Vec, + + // 能级相关 (MLEVEL) + /// 束缚-自由源函数 (前) + pub sbfm: Vec, + /// 束缚-自由源函数 (当前) + pub sbf0: Vec, + /// 束缚-自由源函数 (后) + pub sbfp: Vec, + + /// 氦激发速率 + pub hex: Vec, + /// 复合激发速率 + pub rex: Vec, + pub rexa: Vec, + + /// 束缚-自由导数 + pub dsbfm: Vec, + pub dsbf0: Vec, + pub dsbfp: Vec, + + /// 电荷求和 + pub sumdch: Vec, + + // 二维导数数组 (MLEVEL × MFREX) + pub drchm: Vec>, + pub dretm: Vec>, + pub drch0: Vec>, + pub dret0: Vec>, + pub drchp: Vec>, + pub dretp: Vec>, +} + +impl Default for MainArrays { + fn default() -> Self { + Self { + a: vec![vec![0.0; MTOT]; MTOT], + b: vec![vec![0.0; MTOT]; MTOT], + c: vec![vec![0.0; MTOT]; MTOT], + e: vec![vec![0.0; MTOT]; MTOT], + vecl: vec![0.0; MTOT], + y1: vec![0.0; MTOT], + y2: vec![0.0; MTOT], + psi0: vec![0.0; MTOT], + psim: vec![0.0; MTOT], + psip: vec![0.0; MTOT], + rad0: vec![0.0; MTOT], + radm: vec![0.0; MTOT], + radp: vec![0.0; MTOT], + fkm: vec![0.0; MFREX], + fk0: vec![0.0; MFREX], + fkp: vec![0.0; MFREX], + absom: vec![0.0; MFREX], + abso0: vec![0.0; MFREX], + absop: vec![0.0; MFREX], + emism: vec![0.0; MFREX], + emis0: vec![0.0; MFREX], + emisp: vec![0.0; MFREX], + scatm: vec![0.0; MFREX], + scat0: vec![0.0; MFREX], + scatp: vec![0.0; MFREX], + dabtm: vec![0.0; MFREX], + dabt0: vec![0.0; MFREX], + dabtp: vec![0.0; MFREX], + demtm: vec![0.0; MFREX], + demt0: vec![0.0; MFREX], + demtp: vec![0.0; MFREX], + dabnm: vec![0.0; MFREX], + dabn0: vec![0.0; MFREX], + dabnp: vec![0.0; MFREX], + demnm: vec![0.0; MFREX], + demn0: vec![0.0; MFREX], + demnp: vec![0.0; MFREX], + dabmm: vec![0.0; MFREX], + dabm0: vec![0.0; MFREX], + dabmp: vec![0.0; MFREX], + demmm: vec![0.0; MFREX], + demm0: vec![0.0; MFREX], + demmp: vec![0.0; MFREX], + wdepm: vec![0.0; MFREX], + wdep0: vec![0.0; MFREX], + wdepp: vec![0.0; MFREX], + sbfm: vec![0.0; MLEVEL], + sbf0: vec![0.0; MLEVEL], + sbfp: vec![0.0; MLEVEL], + hex: vec![0.0; MLEVEL], + rex: vec![0.0; MLEVEL], + rexa: vec![0.0; MLEVEL], + dsbfm: vec![0.0; MLEVEL], + dsbf0: vec![0.0; MLEVEL], + dsbfp: vec![0.0; MLEVEL], + sumdch: vec![0.0; MLEVEL], + drchm: vec![vec![0.0; MFREX]; MLEVEL], + dretm: vec![vec![0.0; MFREX]; MLEVEL], + drch0: vec![vec![0.0; MFREX]; MLEVEL], + dret0: vec![vec![0.0; MFREX]; MLEVEL], + drchp: vec![vec![0.0; MFREX]; MLEVEL], + dretp: vec![vec![0.0; MFREX]; MLEVEL], + } + } +} + +// ============================================================================ +// EXPRAD - 扩展辐射数组 +// ============================================================================ + +/// 扩展辐射数组。 +/// 对应 COMMON /EXPRAD/ +#[derive(Debug, Clone)] +pub struct ExpRad { + /// 吸收系数扩展 (频率 × 深度) + pub absoex: Vec>, + /// 发射系数扩展 + pub emisex: Vec>, + /// 散射系数扩展 + pub scatex: Vec>, + + // 导数扩展 + pub dabtex: Vec>, + pub demtex: Vec>, + pub dabcex: Vec>, + pub demnex: Vec>, + pub dabmex: Vec>, + pub demmex: Vec>, + + // 能级导数扩展 (线性化能级 × 频率 × 深度) + pub drchex: Vec>>, + pub dretex: Vec>>, +} + +impl Default for ExpRad { + fn default() -> Self { + Self { + absoex: vec![vec![0.0; MDEPTH]; MFREX], + emisex: vec![vec![0.0; MDEPTH]; MFREX], + scatex: vec![vec![0.0; MDEPTH]; MFREX], + dabtex: vec![vec![0.0; MDEPTH]; MFREX], + demtex: vec![vec![0.0; MDEPTH]; MFREX], + dabcex: vec![vec![0.0; MDEPTH]; MFREX], + demnex: vec![vec![0.0; MDEPTH]; MFREX], + dabmex: vec![vec![0.0; MDEPTH]; MFREX], + demmex: vec![vec![0.0; MDEPTH]; MFREX], + drchex: vec![vec![vec![0.0; MDEPTH]; MFREX]; MLVEXP], + dretex: vec![vec![vec![0.0; MDEPTH]; MFREX]; MLVEXP], + } + } +} + +// ============================================================================ +// BPOCOM - 束缚-占据矩阵 +// ============================================================================ + +/// 束缚-占据矩阵。 +/// 对应 COMMON /BPOCOM/ +#[derive(Debug, Clone, Default)] +pub struct BpoCom { + /// 电子散射矩阵 + pub esemat: Vec>, + /// 束缚-电子散射 + pub bese: Vec, + /// 衰减 + pub att: Vec, + /// Ann 矩阵对角 + pub ann: Vec, +} + +impl BpoCom { + pub fn new() -> Self { + Self { + esemat: vec![vec![0.0; MLEVEL]; MLEVEL], + bese: vec![0.0; MLEVEL], + att: vec![0.0; MLEVEL], + ann: vec![0.0; MLEVEL], + } + } +} + +// ============================================================================ +// 综合数组结构 +// ============================================================================ + +/// TLUSTY 计算数组。 +#[derive(Debug, Clone, Default)] +pub struct ComputeArrays { + pub main: MainArrays, + pub exprad: ExpRad, + pub bpocom: BpoCom, +} + +impl ComputeArrays { + pub fn new() -> Self { + Self { + bpocom: BpoCom::new(), + ..Default::default() + } + } + + /// 估算内存使用量 (MB) + pub fn memory_usage_mb(&self) -> f64 { + let main_size = std::mem::size_of::(); + let exprad_size = std::mem::size_of::(); + let bpocom_size = std::mem::size_of::(); + (main_size + exprad_size + bpocom_size) as f64 / (1024.0 * 1024.0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_main_arrays_creation() { + let arrays = MainArrays::default(); + assert_eq!(arrays.a.len(), MTOT); + assert_eq!(arrays.a[0].len(), MTOT); + assert_eq!(arrays.vecl.len(), MTOT); + } + + #[test] + fn test_exprad_creation() { + let exprad = ExpRad::default(); + assert_eq!(exprad.absoex.len(), MFREX); + assert_eq!(exprad.absoex[0].len(), MDEPTH); + } + + #[test] + fn test_compute_arrays() { + let arrays = ComputeArrays::new(); + let mem = arrays.memory_usage_mb(); + println!("ComputeArrays memory usage: {:.2} MB", mem); + assert!(mem > 0.0); + } +} diff --git a/src/state/atomic.rs b/src/state/atomic.rs new file mode 100644 index 0000000..464d485 --- /dev/null +++ b/src/state/atomic.rs @@ -0,0 +1,422 @@ +//! 原子、离子、能级数据。 +//! +//! 重构自 TLUSTY `ATOMIC.FOR` 中的 COMMON 块。 + +use super::constants::*; + +// ============================================================================ +// ATOPAR - 原子参数 +// ============================================================================ + +/// 原子参数。 +/// 对应 COMMON /ATOPAR/ +#[derive(Debug, Clone)] +pub struct AtoPar { + /// 原子质量 + pub amass: Vec, + /// 丰度 (原子/深度点) + pub abund: Vec>, + /// 原子序数 + pub numat: Vec, + /// 原子起始能级索引 + pub n0a: Vec, + /// 原子终止能级索引 + pub nka: Vec, + /// 参考原子 + pub nref: Vec, + /// 原子提取标志 + pub iatex: Vec, + /// 参考丰度 (深度点) + pub nrefs: Vec>, + /// 采用的原子 + pub iadop: Vec, + /// 固定丰度标志 + pub iifix: Vec, + /// 参考原子索引 + pub iatref: i32, + /// 参考模型 + pub modref: i32, +} + +impl Default for AtoPar { + fn default() -> Self { + Self { + amass: vec![0.0; MATOM], + abund: vec![vec![0.0; MDEPTH]; MATOM], + numat: vec![0; MATOM], + n0a: vec![0; MATOM], + nka: vec![0; MATOM], + nref: vec![0; MATOM], + iatex: vec![0; MATOM], + nrefs: vec![vec![0; MDEPTH]; MATOM], + iadop: vec![0; MATOM], + iifix: vec![0; MATOM], + iatref: 0, + modref: 0, + } + } +} + +// ============================================================================ +// IONPAR - 离子参数 +// ============================================================================ + +/// 离子参数。 +/// 对应 COMMON /IONPAR/ +#[derive(Debug, Clone)] +pub struct IonPar { + /// 电离势 (Ry) + pub ff: Vec, + /// 电荷² + pub charg2: Vec, + /// 离子起始能级索引 + pub nfirst: Vec, + /// 离子终止能级索引 + pub nlast: Vec, + /// 下一个能级索引 + pub nnext: Vec, + /// 原子序数 Z + pub iz: Vec, + /// 上能级求和索引 + pub iupsum: Vec, + /// 碰撞耦合索引 + pub icup: Vec, + /// LTE 标志 + pub ilte: Vec, + /// LTE 离子标志 + pub iltion: Vec, +} + +impl Default for IonPar { + fn default() -> Self { + Self { + ff: vec![0.0; MION], + charg2: vec![0.0; MION], + nfirst: vec![0; MION], + nlast: vec![0; MION], + nnext: vec![0; MION], + iz: vec![0; MION], + iupsum: vec![0; MION], + icup: vec![0; MION], + ilte: vec![0; MION], + iltion: vec![0; MION], + } + } +} + +// ============================================================================ +// LEVPAR - 能级参数 +// ============================================================================ + +/// 能级参数。 +/// 对应 COMMON /LEVPAR/ +#[derive(Debug, Clone)] +pub struct LevPar { + /// 电离能 (cm⁻¹) + pub enion: Vec, + /// 统计权重 g + pub g: Vec, + /// 主量子数 + pub nquant: Vec, + /// 所属原子索引 + pub iatm: Vec, + /// 所属离子索引 + pub iel: Vec, + /// 能级类型 + pub ilk: Vec, + /// 线性化标志 + pub ilin: Vec, + /// LTE 能级标志 + pub iltlev: Vec, + /// 能级索引 + pub indlev: Vec, + /// 模型能级 + pub imodl: Vec, + /// 显式能级标志 + pub iiexp: Vec, + /// Fortran 能级标志 + pub iifor: Vec, + /// 零占据概率标志 + pub ipzert: Vec, + /// 零 g 标志 + pub igzert: Vec, + /// 零 g 能级索引 + pub indlgz: Vec, + /// 非零能级标志 + pub iinonz: Vec, + /// 显式能级数 + pub nlvexp: i32, + /// Fortran 能级数 + pub nlvfor: i32, + /// 零能级数 + pub nlvexz: i32, + /// 束缚-自由 X 标志 + pub lbpfx: i32, +} + +impl Default for LevPar { + fn default() -> Self { + Self { + enion: vec![0.0; MLEVEL], + g: vec![0.0; MLEVEL], + nquant: vec![0; MLEVEL], + iatm: vec![0; MLEVEL], + iel: vec![0; MLEVEL], + ilk: vec![0; MLEVEL], + ilin: vec![0; MLEVEL], + iltlev: vec![0; MLEVEL], + indlev: vec![0; MLEVEL], + imodl: vec![0; MLEVEL], + iiexp: vec![0; MLEVEL], + iifor: vec![0; MLEVEL], + ipzert: vec![0; MLEVEL], + igzert: vec![0; MLEVEL], + indlgz: vec![0; MLEVEL], + iinonz: vec![0; MLEVEL], + nlvexp: 0, nlvfor: 0, nlvexz: 0, lbpfx: 0, + } + } +} + +// ============================================================================ +// TRAPAR - 跃迁参数 +// ============================================================================ + +/// 跃迁参数。 +/// 对应 COMMON /TRAPAR/ +#[derive(Debug, Clone)] +pub struct TraPar { + /// 跃迁频率 (Hz) + pub fr0: Vec, + /// 振子强度 + pub osc0: Vec, + /// 线宽参数 + pub cpar: Vec, + /// 最大频率 + pub frqmx: Vec, + /// 跃迁频率 (cm⁻¹) + pub fr0pc: Vec, + /// 碰撞 Ω 矩阵 + pub omecol: Vec>, + + // 梯度参数 + pub xgrad: f64, + pub strl1: f64, + pub strl2: f64, + pub strlx: f64, + + // 索引数组 + /// 下能级索引 + pub ilow: Vec, + /// 上能级索引 + pub iup: Vec, + /// 指数索引 + pub indexp: Vec, + /// 频率索引 + pub kfr0: Vec, + pub kfr1: Vec, + /// Luck 跃迁标志 + pub iluctr: Vec, + /// 频率计数 + pub ifc0: Vec, + pub ifc1: Vec, + pub ifr0: Vec, + pub ifr1: Vec, + /// 跃迁矩阵 + pub itra: Vec>, + /// 轮廓类型 + pub iprof: Vec, + /// 碰撞标志 + pub icol: Vec, + /// 积分模式 + pub intmod: Vec, + /// 连续跃迁标志 + pub itrcon: Vec, + /// 双电子标志 + pub idiel: Vec, + /// 跃迁 J-T 因子 + pub ijtf: Vec, + /// 复合线标志 + pub lcomp: Vec, + /// 谱线索引 + pub line: Vec, +} + +impl Default for TraPar { + fn default() -> Self { + Self { + fr0: vec![0.0; MTRANS], + osc0: vec![0.0; MTRANS], + cpar: vec![0.0; MTRANS], + frqmx: vec![0.0; MTRANS], + fr0pc: vec![0.0; MTRANS], + omecol: vec![vec![0.0; MLEVEL]; MLEVEL], + xgrad: 0.0, strl1: 0.0, strl2: 0.0, strlx: 0.0, + ilow: vec![0; MTRANS], + iup: vec![0; MTRANS], + indexp: vec![0; MTRANS], + kfr0: vec![0; MTRANS], + kfr1: vec![0; MTRANS], + iluctr: vec![0; MTRANS], + ifc0: vec![0; MTRANS], + ifc1: vec![0; MTRANS], + ifr0: vec![0; MTRANS], + ifr1: vec![0; MTRANS], + itra: vec![vec![0; MLEVEL]; MLEVEL], + iprof: vec![0; MTRANS], + icol: vec![0; MTRANS], + intmod: vec![0; MTRANS], + itrcon: vec![0; MTRANS], + idiel: vec![0; MTRANS], + ijtf: vec![0; MTRANS], + lcomp: vec![0; MTRANS], + line: vec![0; MTRANS], + } + } +} + +// ============================================================================ +// PHOSET - 光电离设置 +// ============================================================================ + +/// 光电离设置。 +/// 对应 COMMON /PHOSET/ +#[derive(Debug, Clone, Default)] +pub struct PhoSet { + /// 截面参数 S₀ + pub s0cs: Vec, + /// 截面参数 α + pub alfcs: Vec, + /// 截面参数 β + pub betcs: Vec, + /// 截面参数 γ + pub gamcs: Vec, + /// 束缚-自由索引 + pub ibf: Vec, +} + +impl PhoSet { + pub fn new() -> Self { + Self { + s0cs: vec![0.0; MLEVEL], + alfcs: vec![0.0; MLEVEL], + betcs: vec![0.0; MLEVEL], + gamcs: vec![0.0; MLEVEL], + ibf: vec![0; MLEVEL], + } + } +} + +// ============================================================================ +// VOIPAR - Voigt 参数 +// ============================================================================ + +/// Voigt 轮廓参数。 +/// 对应 COMMON /VOIPAR/ +#[derive(Debug, Clone, Default)] +pub struct VoiPar { + /// 辐射宽度 γ + pub gamar: Vec, + /// Stark 展宽参数 1 + pub stark1: Vec, + /// Stark 展宽参数 2 + pub stark2: Vec, + /// Stark 展宽参数 3 + pub stark3: Vec, + /// van der Waals 宽度 + pub vdwh: Vec, +} + +impl VoiPar { + pub fn new() -> Self { + Self { + gamar: vec![0.0; MVOIGT], + stark1: vec![0.0; MVOIGT], + stark2: vec![0.0; MVOIGT], + stark3: vec![0.0; MVOIGT], + vdwh: vec![0.0; MVOIGT], + } + } +} + +// ============================================================================ +// HECRAT - 氦碰撞速率 +// ============================================================================ + +/// 氦碰撞速率系数。 +/// 对应 COMMON /HECRAT/ +#[derive(Debug, Clone, Default)] +pub struct HeCrat { + /// 氦碰撞速率矩阵 (19×19) + pub colhe1: [[f64; 19]; 19], +} + +// ============================================================================ +// 综合原子数据结构 +// ============================================================================ + +/// TLUSTY 原子数据。 +/// 包含所有原子、离子、能级、跃迁信息。 +#[derive(Debug, Clone, Default)] +pub struct AtomicData { + pub atopar: AtoPar, + pub ionpar: IonPar, + pub levpar: LevPar, + pub trapar: TraPar, + pub phoset: PhoSet, + pub voipar: VoiPar, + pub hecrat: HeCrat, +} + +impl AtomicData { + pub fn new() -> Self { + Self { + phoset: PhoSet::new(), + voipar: VoiPar::new(), + ..Default::default() + } + } + + /// 获取指定能级的原子序数 Z + pub fn get_z(&self, level: usize) -> i32 { + if level < MLEVEL { + let ion_idx = self.levpar.iel[level] as usize; + if ion_idx < MION { + return self.ionpar.iz[ion_idx]; + } + } + 0 + } + + /// 获取指定能级的电离电荷 + pub fn get_charge(&self, level: usize) -> f64 { + if level < MLEVEL { + let ion_idx = self.levpar.iel[level] as usize; + if ion_idx < MION { + return self.ionpar.charg2[ion_idx].sqrt(); + } + } + 0.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_atomic_data_creation() { + let data = AtomicData::new(); + assert_eq!(data.atopar.amass.len(), MATOM); + assert_eq!(data.ionpar.ff.len(), MION); + assert_eq!(data.levpar.g.len(), MLEVEL); + } + + #[test] + fn test_get_z() { + let mut data = AtomicData::new(); + data.levpar.iel[0] = 1; + data.ionpar.iz[1] = 2; // He + assert_eq!(data.get_z(0), 2); + } +} diff --git a/src/state/config.rs b/src/state/config.rs new file mode 100644 index 0000000..67cded3 --- /dev/null +++ b/src/state/config.rs @@ -0,0 +1,428 @@ +//! 运行时配置参数。 +//! +//! 重构自 TLUSTY `BASICS.FOR` 中的控制 COMMON 块。 + +use super::constants::*; + +// ============================================================================ +// BASNUM - 基本数值计数器 +// ============================================================================ + +/// 基本数值计数器。 +/// 对应 COMMON /BASNUM/ +#[derive(Debug, Clone)] +pub struct BasNum { + /// 显式原子数 + pub natom: i32, + /// 显式离子数 + pub nion: i32, + /// 显式能级数 + pub nlevel: i32, + /// 跃迁数 + pub ntrans: i32, + /// 深度点数 + pub nd: i32, + /// 频率点数 + pub nfreq: i32, + /// 连续谱频率数 + pub nfreqc: i32, + /// 线性化频率数 + pub nfreqe: i32, + + // 各种选项标志 + pub ioptab: i32, + pub idisk: i32, + pub izscal: i32, + pub idmfix: i32, + pub iheso6: i32, + pub ifmol: i32, + pub ifentr: i32, + pub nfreql: i32, + pub nlev0: i32, + pub icolhn: i32, + pub ioscor: i32, + pub ilgder: i32, + pub ifryb: i32, + pub ifrset: i32, + pub nfread: i32, + pub nelsc: i32, + pub ntranc: i32, + pub iover: i32, + pub jali: i32, + pub ibc: i32, + pub iubc: i32, + pub intens: i32, + pub irder: i32, + pub ilmcor: i32, + pub ifdiel: i32, + pub ifalih: i32, + pub iftene: i32, + pub itndre: i32, + pub ilpsct: i32, + pub ilasct: i32, + pub irte: i32, + pub idlte: i32, + pub ibfint: i32, + pub intrpl: i32, + pub ichang: i32, + pub natoms: i32, + pub ipslte: i32, + pub ispodf: i32, + pub itlucy: i32, + pub nretc: i32, + pub ifrayl: i32, + pub ifprad: i32, +} + +impl Default for BasNum { + fn default() -> Self { + Self { + natom: 0, nion: 0, nlevel: 0, ntrans: 0, + nd: 0, nfreq: 0, nfreqc: 0, nfreqe: 0, + ioptab: 0, idisk: 0, izscal: 0, idmfix: 0, + iheso6: 0, ifmol: 0, ifentr: 0, nfreql: 0, + nlev0: 0, icolhn: 0, ioscor: 0, ilgder: 0, + ifryb: 0, ifrset: 0, nfread: 0, nelsc: 0, + ntranc: 0, iover: 0, jali: 0, ibc: 0, + iubc: 0, intens: 0, irder: 0, ilmcor: 0, + ifdiel: 0, ifalih: 0, iftene: 0, itndre: 0, + ilpsct: 0, ilasct: 0, irte: 0, idlte: 0, + ibfint: 0, intrpl: 0, ichang: 0, natoms: 0, + ipslte: 0, ispodf: 0, itlucy: 0, nretc: 0, + ifrayl: 0, ifprad: 0, + } + } +} + +// ============================================================================ +// INPPAR - 输入参数 +// ============================================================================ + +/// 输入参数。 +/// 对应 COMMON /INPPAR/ +#[derive(Debug, Clone)] +pub struct InpPar { + /// 有效温度 (K) + pub teff: f64, + /// 表面重力 (cm/s²) + pub grav: f64, + + /// 总 He 丰度 (质量分数) + pub ytot: Vec, + /// 平均分子量 + pub wmm: Vec, + /// He 质量分数 + pub wmy: Vec, + /// 分子温度极限 + pub tmolim: f64, + + // 恒星风参数 + pub xmstar: f64, + pub xmdot: f64, + pub rstar: f64, + pub alpha0: f64, + pub reynum: f64, + + // 引力相关 + pub qgrav: f64, + pub edisc: f64, + pub dzeta: f64, + pub reldst: f64, + + // 粘性参数 + pub visc: f64, + pub zeta0: f64, + pub zeta1: f64, + pub dmvisc: f64, + pub fractv: f64, + + // 自转参数 + pub omeg32: f64, + pub wbarm: f64, + pub wbar: f64, + pub alphav: f64, + pub pgas0: f64, + + // 控制参数 + pub bergfc: f64, // β 引力因子 (wn.f 使用) + pub cutlym: f64, + pub cutbal: f64, + + // 选项标志 + pub isplin: i32, + pub irsplt: i32, + pub ivisc: i32, + pub ibche: i32, + pub lte: bool, + pub ltgrey: bool, + pub lchc: bool, + pub lresc: bool, +} + +impl InpPar { + pub fn new() -> Self { + Self { + teff: 10000.0, + grav: 4.44, // log g = 4.44 (太阳) + ytot: vec![0.0; MDEPTH], + wmm: vec![0.0; MDEPTH], + wmy: vec![0.0; MDEPTH], + tmolim: 0.0, + xmstar: 0.0, xmdot: 0.0, rstar: 0.0, alpha0: 0.0, reynum: 0.0, + qgrav: 0.0, edisc: 0.0, dzeta: 0.0, reldst: 0.0, + visc: 0.0, zeta0: 0.0, zeta1: 0.0, dmvisc: 0.0, fractv: 0.0, + omeg32: 0.0, wbarm: 0.0, wbar: 0.0, alphav: 0.0, pgas0: 0.0, + bergfc: 1.0, // 默认值 + cutlym: 0.0, cutbal: 0.0, + isplin: 0, irsplt: 0, ivisc: 0, ibche: 0, + lte: false, ltgrey: false, lchc: false, lresc: false, + } + } +} + +impl Default for InpPar { + fn default() -> Self { + Self::new() + } +} + +// ============================================================================ +// MATKEY - 材料键 +// ============================================================================ + +/// 材料键。 +/// 对应 COMMON /MATKEY/ +#[derive(Debug, Clone, Default)] +pub struct MatKey { + pub nn: i32, + pub nn0: i32, + pub inhe: i32, + pub inre: i32, + pub inpc: i32, + pub inse: i32, + pub inzd: i32, + pub inmp: i32, + pub ndre: i32, + pub insel: i32, +} + +// ============================================================================ +// RUNKEY - 运行控制 +// ============================================================================ + +/// 运行控制键。 +/// 对应 COMMON /RUNKEY/ +#[derive(Debug, Clone, Default)] +pub struct RunKey { + pub chmax: f64, + pub iter: i32, + pub niter: i32, + pub nitzer: i32, + pub init: i32, + pub lac2: i32, + pub lfin: i32, +} + +// ============================================================================ +// CONKEY - 收敛控制 +// ============================================================================ + +/// 收敛控制键。 +/// 对应 COMMON /CONKEY/ +#[derive(Debug, Clone, Default)] +pub struct ConKey { + pub hmix0: f64, + pub crflim: f64, + pub nconit: i32, + pub iconv: i32, + pub indl: i32, + pub ipress: i32, + pub itemp: i32, + pub icbeg: i32, + pub itmcor: i32, + pub iconre: i32, + pub ideepc: i32, + pub ndcgap: i32, + pub idconz: i32, +} + +// ============================================================================ +// OPCPAR - 额外不透明度控制 +// ============================================================================ + +/// 额外不透明度控制。 +/// 对应 COMMON /OPCPAR/ +#[derive(Debug, Clone, Default)] +pub struct OpcPar { + pub iophmi: i32, // H⁻ + pub ioph2p: i32, // H₂⁺ + pub iophem: i32, // He⁻ + pub iopch: i32, // CH + pub iopoh: i32, // OH + pub ioph2m: i32, // H₂⁻ + pub ioh2h2: i32, // H₂-H₂ CIA + pub ioh2he: i32, // H₂-He CIA + pub ioh2h: i32, // H₂-H CIA + pub iohhe: i32, // H-He CIA + pub iophli: i32, // H⁻ 自由-自由 + pub irsct: i32, // 汤姆逊散射 + pub irsche: i32, // He 散射 + pub irsch2: i32, // H₂ 散射 + pub keepop: i32, + pub iopold: i32, +} + +// ============================================================================ +// PRINTS - 打印控制 +// ============================================================================ + +/// 打印控制。 +/// 对应 COMMON /PRINTS/ +#[derive(Debug, Clone, Default)] +pub struct Prints { + pub iprint: i32, + pub ipring: i32, + pub iprind: i32, + pub iprinp: i32, + pub icoolp: i32, + pub ichckp: i32, + pub ipopac: i32, + pub iprini: i32, +} + +// ============================================================================ +// ANGLES - 角度设置 +// ============================================================================ + +/// 角度设置。 +/// 对应 COMMON /ANGLES/ +#[derive(Debug, Clone)] +pub struct Angles { + /// 角度余弦值 + pub amu: Vec, + /// 角度权重 + pub wtmu: Vec, + /// 角度函数 + pub fmu: Vec, + /// 角度点数 + pub nmu: i32, +} + +impl Default for Angles { + fn default() -> Self { + Self { + amu: vec![0.0; MMU], + wtmu: vec![0.0; MMU], + fmu: vec![0.0; MMU], + nmu: 0, + } + } +} + +// ============================================================================ +// COMPTN - Compton 散射角度参数 +// ============================================================================ + +/// Compton 散射角度参数。 +/// 对应 COMMON /COMPTN/ 和 /ANGNUM/ +#[derive(Debug, Clone)] +pub struct Comptn { + /// 角度余弦值 + pub amuc: Vec, + /// 角度权重 + pub wtmuc: Vec, + /// amuc * wtmuc + pub amuc1: Vec, + /// amuc² * wtmuc + pub amuc2: Vec, + /// amuc³ * wtmuc + pub amuc3: Vec, + /// 角度相关量 + pub amuj: Vec, + pub amuk: Vec, + pub amuh: Vec, + pub amun: Vec, + /// Compton 散射 α 系数 + pub calph: Vec>, + /// Compton 散射 β 系数 + pub cbeta: Vec>, + /// Compton 散射 γ 系数 + pub cgamm: Vec>, + /// 辐射零点 + pub radzer: f64, + /// Compton 频率 + pub frlcom: f64, + /// Compton 截面 + pub sigec: Vec, + /// 原始频率索引 + pub ijorig: Vec, + /// Compton 角度点数 + pub nmuc: i32, +} + +impl Default for Comptn { + fn default() -> Self { + Self { + amuc: vec![0.0; MMUC], + wtmuc: vec![0.0; MMUC], + amuc1: vec![0.0; MMUC], + amuc2: vec![0.0; MMUC], + amuc3: vec![0.0; MMUC], + amuj: vec![0.0; MMUC], + amuk: vec![0.0; MMUC], + amuh: vec![0.0; MMUC], + amun: vec![0.0; MMUC], + calph: vec![vec![0.0; MMUC]; MMUC], + cbeta: vec![vec![0.0; MMUC]; MMUC], + cgamm: vec![vec![0.0; MMUC]; MMUC], + radzer: 0.0, + frlcom: 0.0, + sigec: vec![0.0; MFREQ], + ijorig: vec![0; MFREQ], + nmuc: 0, + } + } +} + +// ============================================================================ +// 综合配置结构 +// ============================================================================ + +/// TLUSTY 综合配置。 +/// 包含所有控制参数。 +#[derive(Debug, Clone, Default)] +pub struct TlustyConfig { + pub basnum: BasNum, + pub inppar: InpPar, + pub matkey: MatKey, + pub runkey: RunKey, + pub conkey: ConKey, + pub opcpar: OpcPar, + pub prints: Prints, + pub angles: Angles, + pub comptn: Comptn, +} + +impl TlustyConfig { + pub fn new() -> Self { + Self::default() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_config_creation() { + let config = TlustyConfig::new(); + assert_eq!(config.basnum.natom, 0); + assert_eq!(config.inppar.teff, 10000.0); + } + + #[test] + fn test_inppar_arrays() { + let inppar = InpPar::new(); + assert_eq!(inppar.ytot.len(), MDEPTH); + } +} diff --git a/src/state/constants.rs b/src/state/constants.rs new file mode 100644 index 0000000..3ab7a85 --- /dev/null +++ b/src/state/constants.rs @@ -0,0 +1,164 @@ +//! 物理常数和维度参数。 +//! +//! 重构自 TLUSTY `BASICS.FOR` 中的 PARAMETER 定义。 + +// ============================================================================ +// 维度参数 (数组大小) +// ============================================================================ + +/// 最大原子数 +pub const MATOM: usize = 99; +/// 最大离子数 +pub const MION: usize = 170; +/// 最大能级数 +pub const MLEVEL: usize = 1134; +/// 最大线性化能级数 +pub const MLVEXP: usize = 233; +/// 最大跃迁数 +pub const MTRANS: usize = 21000; +/// 最大深度点数 +pub const MDEPTH: usize = 100; +/// 最大频率点数 +pub const MFREQ: usize = 135000; +/// 工作频率数组大小 +pub const MFREQP: usize = 220000; +/// 连续谱频率点数 +pub const MFREQC: usize = 125000; +/// 线性化频率数 +pub const MFREX: usize = 54; +/// 每条谱线频率数 +pub const MFREQL: usize = 25798; +/// 最大线性化参数数 +pub const MTOT: usize = 280; +/// 最大角度点数 +pub const MMU: usize = 6; +/// Compton 散射最大角度点数 +pub const MMUC: usize = 2; +/// 光电离截面拟合点数 +pub const MFIT: usize = 357; +/// 重叠跃迁数 +pub const MITJ: usize = 380; +/// 伪连续能级数 +pub const MMCDW: usize = 26; +/// 合并能级数 +pub const MMER: usize = 12; +/// Voigt 轮廓谱线数 +pub const MVOIGT: usize = 8080; +/// 占据概率离子最大电荷 +pub const MZZ: usize = 10; +/// 最高氢能级 +pub const NLMX: usize = 80; +/// 对角预处理能级数 +pub const MLEVE3: usize = 1; +/// 对角/三对角操作能级数 +pub const MLVEX3: usize = 1; +/// 对角/三对角操作跃迁数 +pub const MTRAN3: usize = 1; +/// 光电离截面数 +pub const MCROSS: usize = MLEVEL + 5; +/// 束缚-自由跃迁数 +pub const MBF: usize = MLEVEL; + +// ============================================================================ +// 物理常数 (CGS 单位) +// ============================================================================ + +/// 普朗克常数 h (erg·s) +pub const H: f64 = 6.6256e-27; +/// 玻尔兹曼常数 k (erg/K) +pub const BOLK: f64 = 1.38054e-16; +/// h/k (s·K) +pub const HK: f64 = 4.79928144e-11; +/// 光速 c (Å/s) +pub const CAS: f64 = 2.997925e18; +/// 氢电离能 (erg) +pub const EH: f64 = 2.17853041e-11; +/// 2*h/c³ +pub const BN: f64 = 1.4743e-2; +/// 汤姆逊散射截面 (cm²) +pub const SIGE: f64 = 6.6516e-25; +/// 斯特藩-玻尔兹曼常数/4π +pub const SIG4P: f64 = 4.5114062e-6; +/// 4π/h +pub const PI4H: f64 = 1.8966e27; +/// 4π/c +pub const PCK: f64 = 4.19168946e-10; +/// 氢原子质量 (g) +pub const HMASS: f64 = 1.67333e-24; + +// ============================================================================ +// 数学常数 +// ============================================================================ + +/// 单位 1 +pub const UN: f64 = 1.0; +/// 二分之一 +pub const HALF: f64 = 0.5; +/// 二 +pub const TWO: f64 = 2.0; +/// π +pub const PI: f64 = std::f64::consts::PI; +/// 2π +pub const TWOPI: f64 = 2.0 * std::f64::consts::PI; +/// 4π +pub const FOURPI: f64 = 4.0 * std::f64::consts::PI; +/// ln(10) +pub const LN10: f64 = std::f64::consts::LN_10; + +// ============================================================================ +// 辅助函数 +// ============================================================================ + +/// 安全指数函数,避免溢出。 +/// 重构自 TLUSTY `expo.f` +#[inline] +pub fn expo(x: f64) -> f64 { + const MAX_EXP: f64 = 700.0; + if x > MAX_EXP { + (MAX_EXP).exp() + } else if x < -MAX_EXP { + 0.0 + } else { + x.exp() + } +} + +/// 安全对数函数,避免 log(0)。 +#[inline] +pub fn safe_log(x: f64) -> f64 { + if x <= 0.0 { + f64::NEG_INFINITY + } else { + x.ln() + } +} + +/// 安全对数10函数。 +#[inline] +pub fn safe_log10(x: f64) -> f64 { + if x <= 0.0 { + f64::NEG_INFINITY + } else { + x.log10() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_expo() { + assert!((expo(0.0) - 1.0).abs() < 1e-15); + assert!((expo(1.0) - std::f64::consts::E).abs() < 1e-15); + assert_eq!(expo(-1000.0), 0.0); + assert!(expo(1000.0).is_finite()); + } + + #[test] + fn test_constants() { + assert!(H > 0.0); + assert!(BOLK > 0.0); + assert!(CAS > 0.0); + } +} diff --git a/src/state/iterat.rs b/src/state/iterat.rs new file mode 100644 index 0000000..61285aa --- /dev/null +++ b/src/state/iterat.rs @@ -0,0 +1,246 @@ +//! 迭代控制参数。 +//! +//! 重构自 TLUSTY `ITERAT.FOR` + +use super::constants::*; + +// ============================================================================ +// 迭代参数维度 +// ============================================================================ + +/// 最大迭代次数 +pub const MITER: usize = 200; +/// 最大 Lambda 点数 +pub const MLAMBD: usize = 100; + +// ============================================================================ +// LAMBDA - Lambda 迭代参数 +// ============================================================================ + +/// Lambda 迭代控制。 +/// 对应 COMMON /LAMBDA/ +#[derive(Debug, Clone, Default)] +pub struct Lambda { + /// Lambda 点数 + pub nlambd: i32, + /// 固定频率标志 + pub iffix: Vec, + /// 显式净跃迁 + pub netexp: Vec, + /// 固定净跃迁 + pub netfix: Vec, + /// 显式能级跃迁 + pub ietexp: Vec>, + /// 固定能级跃迁 + pub ietfix: Vec>, + /// Lambda 索引 + pub nitlam: Vec, + /// 能级修正标志 + pub ielcor: i32, +} + +impl Lambda { + pub fn new() -> Self { + Self { + nlambd: 0, + iffix: vec![0; MITER], + netexp: vec![0; MITER], + netfix: vec![0; MITER], + ietexp: vec![vec![0; MLAMBD]; MITER], + ietfix: vec![vec![0; MLAMBD]; MITER], + nitlam: vec![0; MITER + 1], + ielcor: 0, + } + } +} + +// ============================================================================ +// CHNMAT - 材料变化控制 +// ============================================================================ + +/// 材料变化控制。 +/// 对应 COMMON /CHNMAT/ +#[derive(Debug, Clone, Default)] +pub struct ChnMat { + /// He 变化索引 + pub inhe0: Vec, + /// 辐射变化索引 + pub inre0: Vec, + /// PC 变化索引 + pub inpc0: Vec, + /// 深度变化索引 + pub indl0: Vec, + /// SE 变化索引 + pub inse0: Vec, + /// MP 变化索引 + pub inmp0: Vec, + /// NN 变化 + pub nn00: Vec, + /// 深度修正 + pub ndre0: Vec, + /// 材料变化标志 + pub lchmat: i32, + /// 辐射存储 + pub lirost: i32, +} + +impl ChnMat { + pub fn new() -> Self { + Self { + inhe0: vec![0; MITER], + inre0: vec![0; MITER], + inpc0: vec![0; MITER], + indl0: vec![0; MITER], + inse0: vec![0; MITER], + inmp0: vec![0; MITER], + nn00: vec![0; MITER], + ndre0: vec![0; MITER], + lchmat: 0, + lirost: 0, + } + } +} + +// ============================================================================ +// ACCEL - 加速参数 +// ============================================================================ + +/// 加速收敛参数。 +/// 对应 COMMON /ACCEL/ +#[derive(Debug, Clone, Default)] +pub struct Accel { + /// 过松弛因子 + pub orelax: f64, + /// 迭代计数 + pub itek: i32, + /// 加速标志 + pub iacc: i32, + /// 初始加速 + pub iacc0: i32, + /// 加速方向 + pub iacd: i32, + /// Kantorovich 向量 + pub kant: Vec, + /// 奇异点计数 + pub ksng: i32, + /// 奇异点位置 + pub lsng: Vec, + /// Aitken 步 + pub laso: i32, + /// 重启动标志 + pub lres2: i32, +} + +impl Accel { + pub fn new() -> Self { + Self { + orelax: 1.0, + itek: 0, + iacc: 0, + iacc0: 0, + iacd: 0, + kant: vec![0; MITER], + ksng: 0, + lsng: vec![0; MTOT], + laso: 0, + lres2: 0, + } + } +} + +// ============================================================================ +// ACCLP - 加速 Lambda 参数 +// ============================================================================ + +/// 加速 Lambda 迭代参数。 +/// 对应 COMMON /ACCLP/ +#[derive(Debug, Clone, Default)] +pub struct Acclp { + pub ilam: i32, + pub iacpp: i32, + pub iacc0p: i32, + pub iacdp: i32, + pub lac2p: i32, +} + +// ============================================================================ +// ACCLT - 温度加速 +// ============================================================================ + +/// 温度加速参数。 +/// 对应 COMMON /ACCLT/ +#[derive(Debug, Clone, Default)] +pub struct Acclt { + pub iaclt: i32, + pub iacldt: i32, +} + +// ============================================================================ +// CHNAD - 变化附加 +// ============================================================================ + +/// 变化附加参数。 +/// 对应 COMMON /CHNAD/ +#[derive(Debug, Clone, Default)] +pub struct ChnAd { + /// 最大变化 + pub chmaxt: f64, + /// Lambda 计数 + pub nlamt: i32, + /// 导数标志 + pubilder: i32, + /// BPOP 标志 + pub ibpope: i32, +} + +// ============================================================================ +// 综合迭代控制 +// ============================================================================ + +/// TLUSTY 迭代控制。 +#[derive(Debug, Clone, Default)] +pub struct IterControl { + pub lambda: Lambda, + pub chnmat: ChnMat, + pub accel: Accel, + pub acclp: Acclp, + pub acclt: Acclt, + pub chnad: ChnAd, +} + +impl IterControl { + pub fn new() -> Self { + Self { + lambda: Lambda::new(), + chnmat: ChnMat::new(), + accel: Accel::new(), + ..Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_lambda_creation() { + let lambda = Lambda::new(); + assert_eq!(lambda.iffix.len(), MITER); + assert_eq!(lambda.ietexp.len(), MITER); + assert_eq!(lambda.nitlam.len(), MITER + 1); + } + + #[test] + fn test_accel_creation() { + let accel = Accel::new(); + assert_eq!(accel.kant.len(), MITER); + assert_eq!(accel.lsng.len(), MTOT); + } + + #[test] + fn test_iter_control() { + let ctrl = IterControl::new(); + assert_eq!(ctrl.lambda.nlambd, 0); + } +} diff --git a/src/state/mod.rs b/src/state/mod.rs new file mode 100644 index 0000000..4537268 --- /dev/null +++ b/src/state/mod.rs @@ -0,0 +1,32 @@ +//! TLUSTY 状态管理模块。 +//! +//! 将 Fortran COMMON 块转换为 Rust struct。 +//! +//! # 模块结构 +//! +//! - `constants`: 物理和数学常数 (compile-time) +//! - `config`: 运行时配置参数 +//! - `atomic`: 原子/离子/能级数据 +//! - `model`: 大气模型状态 +//! - `arrays`: 大型计算数组 +//! - `iterat`: 迭代控制参数 +//! - `alipar`: ALI (加速 Lambda 迭代) 数组 +//! - `odfpar`: ODF (不透明度分布函数) 数据 + +pub mod constants; +pub mod config; +pub mod atomic; +pub mod model; +pub mod arrays; +pub mod iterat; +pub mod alipar; +pub mod odfpar; + +pub use constants::*; +pub use config::*; +pub use atomic::*; +pub use model::*; +pub use arrays::*; +pub use iterat::*; +pub use alipar::*; +pub use odfpar::*; diff --git a/src/state/model.rs b/src/state/model.rs new file mode 100644 index 0000000..7fa44b4 --- /dev/null +++ b/src/state/model.rs @@ -0,0 +1,524 @@ +//! 大气模型状态。 +//! +//! 重构自 TLUSTY `MODELQ.FOR` 中的 COMMON 块。 +//! 包含温度、密度、电子密度、占据数等物理状态。 + +use super::constants::*; + +// ============================================================================ +// MODPAR - 模型参数 +// ============================================================================ + +/// 模型基本参数。 +/// 对应 COMMON /MODPAR/ +#[derive(Debug, Clone)] +pub struct ModPar { + /// 深度 (柱质量密度, g/cm²) + pub dm: Vec, + /// 温度 (K) + pub temp: Vec, + /// 电子密度 (cm⁻³) + pub elec: Vec, + /// 总粒子密度 (cm⁻³) + pub dens: Vec, + /// 总粒子数 + pub totn: Vec, + + /// 总原子密度 + pub anto: Vec, + /// 金属原子密度 + pub anma: Vec, + /// 中性氢密度 + pub anh1: Vec, + /// 深度变量 + pub zd: Vec, + + // 辅助温度量 + /// h/kT + pub hkt1: Vec, + /// 1/T + pub tk1: Vec, + /// h/(kT)² + pub hkt21: Vec, + /// sqrt(T) + pub sqt1: Vec, + + // 迭代中间量 + pub temp1: Vec, + pub elec1: Vec, + pub dens1: Vec, + pub densi: Vec, + pub densim: Vec, + + // 散射相关 + /// 电子散射不透明度 + pub elscat: Vec, + /// 线性化辐射参数 + pub alab: Vec, + + // 深度差分 + pub deldm: Vec, + pub dedm1: f64, + pub deldmz: Vec, + + // 速度场 + pub thetav: Vec, + pub viscd: Vec, + pub dalpmx: f64, + pub xhyd: f64, + + // 全局量 + pub dmtot: f64, + pub rrdil: f64, + pub tempbd: f64, + pub alptav: f64, + pub alpgav: f64, + pub nalp: i32, + pub ibeta: i32, +} + +impl Default for ModPar { + fn default() -> Self { + Self { + dm: vec![0.0; MDEPTH], + temp: vec![0.0; MDEPTH], + elec: vec![0.0; MDEPTH], + dens: vec![0.0; MDEPTH], + totn: vec![0.0; MDEPTH], + anto: vec![0.0; MDEPTH], + anma: vec![0.0; MDEPTH], + anh1: vec![0.0; MDEPTH], + zd: vec![0.0; MDEPTH], + hkt1: vec![0.0; MDEPTH], + tk1: vec![0.0; MDEPTH], + hkt21: vec![0.0; MDEPTH], + sqt1: vec![0.0; MDEPTH], + temp1: vec![0.0; MDEPTH], + elec1: vec![0.0; MDEPTH], + dens1: vec![0.0; MDEPTH], + densi: vec![0.0; MDEPTH], + densim: vec![0.0; MDEPTH], + elscat: vec![0.0; MDEPTH], + alab: vec![0.0; MDEPTH], + deldm: vec![0.0; MDEPTH], + dedm1: 0.0, + deldmz: vec![0.0; MDEPTH], + thetav: vec![0.0; MDEPTH], + viscd: vec![0.0; MDEPTH], + dalpmx: 0.0, + xhyd: 0.0, + dmtot: 0.0, + rrdil: 0.0, + tempbd: 0.0, + alptav: 0.0, + alpgav: 0.0, + nalp: 0, + ibeta: 0, + } + } +} + +// ============================================================================ +// LEVPOP - 能级占据数 +// ============================================================================ + +/// 能级占据数。 +/// 对应 COMMON /LEVPOP/ +#[derive(Debug, Clone)] +pub struct LevPop { + /// 占据数 (能级 × 深度) + pub popul: Vec>, + /// Boltzmann 因子 + pub bfac: Vec>, + /// 逆占据数 + pub popinv: Vec>, + + /// 当前深度占据数 + pub popgrp: Vec, + pub pop: Vec, + /// 束缚-自由源函数 + pub sbf: Vec, + pub dsbf: Vec, + /// 离子配分函数 + pub usum: Vec, +} + +impl Default for LevPop { + fn default() -> Self { + Self { + popul: vec![vec![0.0; MDEPTH]; MLEVEL], + bfac: vec![vec![0.0; MDEPTH]; MLEVEL], + popinv: vec![vec![0.0; MDEPTH]; MLEVEL], + popgrp: vec![0.0; MLEVEL], + pop: vec![0.0; MLEVEL], + sbf: vec![0.0; MLEVEL], + dsbf: vec![0.0; MLEVEL], + usum: vec![0.0; MION], + } + } +} + +// ============================================================================ +// GFFPAR - 自由-自由 Gaunt 因子 +// ============================================================================ + +/// 自由-自由 Gaunt 因子参数。 +/// 对应 COMMON /GFFPAR/ +#[derive(Debug, Clone, Default)] +pub struct GffPar { + /// Gaunt 因子 (深度) + pub gf0: Vec, + pub gf1: Vec, + pub gf2: Vec, + pub gf3: Vec, + pub gf4: Vec, + pub gf5: Vec, + pub gf6: Vec, + + /// Gaunt 因子导数 + pub gf0d: Vec, + pub gf1d: Vec, + pub gf2d: Vec, + pub gf3d: Vec, + pub gf4d: Vec, + pub gf5d: Vec, + pub gf6d: Vec, + + /// 温度步长 + pub deltt: Vec, +} + +impl GffPar { + pub fn new() -> Self { + Self { + gf0: vec![0.0; MDEPTH], + gf1: vec![0.0; MDEPTH], + gf2: vec![0.0; MDEPTH], + gf3: vec![0.0; MDEPTH], + gf4: vec![0.0; MDEPTH], + gf5: vec![0.0; MDEPTH], + gf6: vec![0.0; MDEPTH], + gf0d: vec![0.0; MDEPTH], + gf1d: vec![0.0; MDEPTH], + gf2d: vec![0.0; MDEPTH], + gf3d: vec![0.0; MDEPTH], + gf4d: vec![0.0; MDEPTH], + gf5d: vec![0.0; MDEPTH], + gf6d: vec![0.0; MDEPTH], + deltt: vec![0.0; MDEPTH], + } + } +} + +// ============================================================================ +// TOTRAD - 总辐射场 +// ============================================================================ + +/// 总辐射场。 +/// 对应 COMMON /TOTRAD/ +#[derive(Debug, Clone)] +pub struct TotRad { + /// 辐射强度 (频率 × 深度) + pub rad: Vec>, + /// 频率相关深度 + pub fhd: Vec, + /// 吸收系数 × 辐射 + pub fak: Vec>, + pub radk: Vec>, + + /// 外辐射 + pub extrad: Vec, + /// 外辐射强度 (频率 × 角度) + pub extint: Vec>, + /// 氦外辐射 + pub hextrd: Vec, + + // 全局量 + pub trad: f64, + pub wdil: f64, + pub extot: f64, + pub tstar: f64, +} + +impl Default for TotRad { + fn default() -> Self { + Self { + rad: vec![vec![0.0; MDEPTH]; MFREQ], + fhd: vec![0.0; MFREQ], + fak: vec![vec![0.0; MDEPTH]; MFREQ], + radk: vec![vec![0.0; MDEPTH]; MFREQ], + extrad: vec![0.0; MFREQ], + extint: vec![vec![0.0; MMU]; MFREQ], + hextrd: vec![0.0; MFREQ], + trad: 0.0, + wdil: 0.0, + extot: 0.0, + tstar: 0.0, + } + } +} + +// ============================================================================ +// CURRAD - 当前深度辐射 +// ============================================================================ + +/// 当前深度辐射。 +/// 对应 COMMON /CURRAD/ +#[derive(Debug, Clone, Default)] +pub struct CurRad { + pub rad1: Vec, + pub ali1: Vec, + pub fak1: Vec, + pub radcm: Vec>, + pub radl: Vec>, + pub absali: Vec>, + pub alih1: Vec, +} + +impl CurRad { + pub fn new() -> Self { + Self { + rad1: vec![0.0; MDEPTH], + ali1: vec![0.0; MDEPTH], + fak1: vec![0.0; MDEPTH], + radcm: vec![vec![0.0; MDEPTH]; MFREQ], + radl: vec![vec![0.0; MDEPTH]; MFREQL], + absali: vec![vec![0.0; MDEPTH]; MFREQL], + alih1: vec![0.0; MDEPTH], + } + } +} + +// ============================================================================ +// FRQALL - 频率相关数组 +// ============================================================================ + +/// 频率相关数组。 +/// 对应 COMMON /FRQALL/ +#[derive(Debug, Clone)] +pub struct FrqAll { + /// 频率网格 (Hz) + pub freq: Vec, + /// 频率权重 + pub w: Vec, + /// 谱线轮廓 + pub prof: Vec, + /// 谱线权重 + pub wch: Vec, + + // 索引数组 + pub jik: Vec, + pub ijx: Vec, + pub ijbf: Vec, + pub ifs0: i32, + pub kij: Vec, + pub lskip: Vec>, +} + +impl Default for FrqAll { + fn default() -> Self { + Self { + freq: vec![0.0; MFREQ], + w: vec![0.0; MFREQ], + prof: vec![0.0; MFREQP], + wch: vec![0.0; MFREQ], + jik: vec![0; MFREQ], + ijx: vec![0; MFREQ], + ijbf: vec![0; MFREQ], + ifs0: 0, + kij: vec![0; MFREQ], + lskip: vec![vec![0; MFREQ]; MDEPTH], + } + } +} + +// ============================================================================ +// TOTPRF - 总谱线轮廓 +// ============================================================================ + +/// 谱线轮廓数组。 +/// 对应 COMMON /TOTPRF/ +#[derive(Debug, Clone, Default)] +pub struct TotPrf { + /// 谱线轮廓 (深度 × 频率) + pub prflin: Vec>, +} + +impl TotPrf { + pub fn new() -> Self { + Self { + prflin: vec![vec![0.0; MFREQP]; MDEPTH], + } + } +} + +// ============================================================================ +// PHOEXP - 光电离截面展开 +// ============================================================================ + +/// 光电离截面展开参数。 +/// 对应 COMMON /PHOEXP/ +#[derive(Debug, Clone, Default)] +pub struct PhoExp { + /// 频率插值系数 + pub aijbf: Vec, + /// 束缚-自由截面 (MCROSS × MFREQC) + pub bfcs: Vec>, + /// 频率索引 + pub ifreqb: Vec, +} + +impl PhoExp { + pub fn new() -> Self { + Self { + aijbf: vec![0.0; MFREQ], + bfcs: vec![vec![0.0; MFREQC]; MCROSS], + ifreqb: vec![0; MFREQC], + } + } +} + +// ============================================================================ +// OBFPAR - 束缚-自由跃迁参数 +// ============================================================================ + +/// 束缚-自由跃迁参数。 +/// 对应 COMMON /OBFPAR/ +#[derive(Debug, Clone, Default)] +pub struct ObfPar { + /// 束缚-自由跃迁对应的跃迁索引 + pub itrbf: Vec, +} + +impl ObfPar { + pub fn new() -> Self { + Self { + itrbf: vec![0; MBF], + } + } +} + +// ============================================================================ +// LEVADD - 能级附加数组 +// ============================================================================ + +/// 能级附加数组。 +/// 对应 COMMON /LEVADD/ +#[derive(Debug, Clone, Default)] +pub struct LevAdd { + /// 离子配分函数和 (离子 × 深度) + pub usums: Vec>, + /// 配分函数温度导数 + pub dusmt: Vec>, + /// 配分函数密度导数 + pub dusmn: Vec>, + /// 双电子复合截面 (离子 × 深度) + pub diesig: Vec>, +} + +impl LevAdd { + pub fn new() -> Self { + Self { + usums: vec![vec![0.0; MDEPTH]; MION], + dusmt: vec![vec![0.0; MDEPTH]; MION], + dusmn: vec![vec![0.0; MDEPTH]; MION], + diesig: vec![vec![0.0; MDEPTH]; MION], + } + } +} + +// ============================================================================ +// 综合模型状态 +// ============================================================================ + +/// TLUSTY 大气模型状态。 +#[derive(Debug, Clone, Default)] +pub struct ModelState { + pub modpar: ModPar, + pub levpop: LevPop, + pub gffpar: GffPar, + pub totrad: TotRad, + pub currad: CurRad, + pub frqall: FrqAll, + pub totprf: TotPrf, + pub phoexp: PhoExp, + pub obfpar: ObfPar, + pub levadd: LevAdd, +} + +impl ModelState { + pub fn new() -> Self { + Self { + gffpar: GffPar::new(), + currad: CurRad::new(), + totprf: TotPrf::new(), + phoexp: PhoExp::new(), + obfpar: ObfPar::new(), + levadd: LevAdd::new(), + ..Default::default() + } + } + + /// 获取指定深度的温度 + pub fn temperature(&self, depth: usize) -> f64 { + if depth < MDEPTH { + self.modpar.temp[depth] + } else { + 0.0 + } + } + + /// 获取指定深度的电子密度 + pub fn electron_density(&self, depth: usize) -> f64 { + if depth < MDEPTH { + self.modpar.elec[depth] + } else { + 0.0 + } + } + + /// 获取指定深度的总粒子密度 + pub fn total_density(&self, depth: usize) -> f64 { + if depth < MDEPTH { + self.modpar.dens[depth] + } else { + 0.0 + } + } + + /// 获取指定能级在指定深度的占据数 + pub fn population(&self, level: usize, depth: usize) -> f64 { + if level < MLEVEL && depth < MDEPTH { + self.levpop.popul[level][depth] + } else { + 0.0 + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_model_state_creation() { + let state = ModelState::new(); + assert_eq!(state.modpar.temp.len(), MDEPTH); + assert_eq!(state.levpop.popul.len(), MLEVEL); + } + + #[test] + fn test_temperature_accessor() { + let mut state = ModelState::new(); + state.modpar.temp[0] = 10000.0; + assert!((state.temperature(0) - 10000.0).abs() < 1e-10); + assert_eq!(state.temperature(MDEPTH), 0.0); // 越界 + } + + #[test] + fn test_population_accessor() { + let mut state = ModelState::new(); + state.levpop.popul[0][0] = 1e10; + assert!((state.population(0, 0) - 1e10).abs() < 1e-5); + } +} diff --git a/src/state/odfpar.rs b/src/state/odfpar.rs new file mode 100644 index 0000000..db398fa --- /dev/null +++ b/src/state/odfpar.rs @@ -0,0 +1,466 @@ +//! ODF (不透明度分布函数) 相关参数。 +//! +//! 重构自 TLUSTY `ODFPAR.FOR` + +use super::constants::*; + +// ============================================================================ +// ODF 维度参数 +// ============================================================================ + +/// ODF 频率点数 +pub const MFODF: usize = 180; +/// ODF 热点数 +pub const MHOD: usize = 3; +/// ODF 频率范围 +pub const MFRO: usize = MFREQL; +/// ODF 深度维度 +pub const MDODF: usize = 3; +/// Kurucz 能级数 +pub const MKULEV: usize = 7000; +/// 谱线数 +pub const MLINE: usize = 1140000; +/// Fe 系数数 +pub const MCFE: usize = 7824000; + +// ============================================================================ +// ODFION - ODF 离子控制 +// ============================================================================ + +/// ODF 离子控制。 +/// 对应 COMMON /ODFION/ +#[derive(Debug, Clone, Default)] +pub struct OdfIon { + /// ODF 起始索引 1 + pub inodf1: Vec, + /// ODF 起始索引 2 + pub inodf2: Vec, + /// 束缚-自由截面索引 + pub inbfcs: Vec, + /// Kurucz 观测标志 + pub ikobs: Vec, +} + +impl OdfIon { + pub fn new() -> Self { + Self { + inodf1: vec![0; MION], + inodf2: vec![0; MION], + inbfcs: vec![0; MION], + ikobs: vec![0; MION], + } + } +} + +// ============================================================================ +// ODFCTR - ODF 控制 +// ============================================================================ + +/// ODF 控制参数。 +/// 对应 COMMON /ODFCTR/ +#[derive(Debug, Clone, Default)] +pub struct OdfCtr { + /// ODF 频率 + pub frodf: Vec, + /// ODF 频率计数 + pub nfrodf: Vec, + /// 能级 ODF 索引 + pub indodf: Vec, + /// 跃迁 ODF 索引 + pub jndodf: Vec, +} + +impl OdfCtr { + pub fn new() -> Self { + Self { + frodf: vec![0.0; MLEVEL], + nfrodf: vec![0; MHOD], + indodf: vec![0; MLEVEL], + jndodf: vec![0; MTRANS], + } + } +} + +// ============================================================================ +// ODFFRQ - ODF 频率数据 +// ============================================================================ + +/// ODF 频率数据。 +/// 对应 COMMON /ODFFRQ/ +#[derive(Debug, Clone, Default)] +pub struct OdfFrq { + /// ODF 频率 (起点) + pub fros: Vec>, + /// 波数 + pub wnus: Vec>, + /// XDO + pub xdo: Vec>, + /// KDO + pub kdo: Vec>, +} + +impl OdfFrq { + pub fn new() -> Self { + Self { + fros: vec![vec![0.0; MHOD]; MFRO], + wnus: vec![vec![0.0; MHOD]; MFRO], + xdo: vec![vec![0.0; 3]; MHOD], + kdo: vec![vec![0; 4]; MHOD], + } + } +} + +// ============================================================================ +// ODFMOD - ODF 模型数据 +// ============================================================================ + +/// ODF 模型数据。 +/// 对应 COMMON /ODFMOD/ +#[derive(Debug, Clone, Default)] +pub struct OdfMod { + pub i1odf: Vec, + pub i2odf: Vec, + pub nqlodf: Vec, +} + +impl OdfMod { + pub fn new() -> Self { + Self { + i1odf: vec![0; MLEVEL], + i2odf: vec![0; MLEVEL], + nqlodf: vec![0; MLEVEL], + } + } +} + +// ============================================================================ +// ODFSTK - ODF Stark 数据 +// ============================================================================ + +/// ODF Stark 展宽数据。 +/// 对应 COMMON /ODFSTK/ +#[derive(Debug, Clone, Default)] +pub struct OdfStk { + /// XKIJ + pub xkij: Vec>, + /// 波长 + pub wl0: Vec>, + /// FIJ + pub fij: Vec>, +} + +impl OdfStk { + pub fn new(nlmx: usize) -> Self { + Self { + xkij: vec![vec![0.0; nlmx]; MHOD], + wl0: vec![vec![0.0; nlmx]; MHOD], + fij: vec![vec![0.0; nlmx]; MHOD], + } + } +} + +// ============================================================================ +// SPLCOM - 样条/Fe 线数据 +// ============================================================================ + +/// Fe 线样条数据。 +/// 对应 COMMON /SPLCOM/ +/// +/// 注意:SIGFE 是非常大的数组 (3 × 7,824,000 = 23,472,000 个 f32) +#[derive(Debug, Clone)] +pub struct SplCom { + /// Fe 截面 (f32 节省内存) + pub sigfe: Vec>>, + /// 频率起点 1 + pub frs1: f64, + /// 频率终点 2 + pub frs2: f64, + /// 频率间隔 + pub dxnu: f64, + /// J 积分 + pub xjid: Vec, + /// J ID + pub jidi: Vec, + /// J ID 半径 + pub jidr: Vec, + /// J ID 起始 + pub jids: i32, + /// J ID 数量 + pub jidn: i32, + /// 频率起始索引 + pub nfrs1: i32, + /// 频率表总数 + pub nftt: i32, +} + +impl Default for SplCom { + fn default() -> Self { + Self { + // 使用较小的测试大小,实际运行时需要调整 + sigfe: vec![vec![vec![0.0; 100]; MDODF]; 100], + frs1: 0.0, + frs2: 0.0, + dxnu: 0.0, + xjid: vec![0.0; MDEPTH], + jidi: vec![0; MDEPTH], + jidr: vec![0; MDODF], + jids: 0, + jidn: 0, + nfrs1: 0, + nftt: 0, + } + } +} + +impl SplCom { + /// 创建完整大小的数组 (需要大量内存) + pub fn new_full() -> Self { + Self { + sigfe: vec![vec![vec![0.0; MCFE]; MDODF]; 1], + frs1: 0.0, + frs2: 0.0, + dxnu: 0.0, + xjid: vec![0.0; MDEPTH], + jidi: vec![0; MDEPTH], + jidr: vec![0; MDODF], + jids: 0, + jidn: 0, + nfrs1: 0, + nftt: 0, + } + } + + /// 估算完整内存使用 (MB) + pub fn full_memory_mb() -> f64 { + // SIGFE: MDODF × MCFE × sizeof(f32) + (MDODF * MCFE * std::mem::size_of::()) as f64 / (1024.0 * 1024.0) + } +} + +// ============================================================================ +// OPALIM - 不透明度限制 +// ============================================================================ + +/// 不透明度限制参数。 +/// 对应 COMMON /OPALIM/ +#[derive(Debug, Clone, Default)] +pub struct OpaLim { + pub m1file: Vec>, + pub m2file: Vec>, + pub imerg: i32, +} + +impl OpaLim { + pub fn new(nlmx: usize) -> Self { + Self { + m1file: vec![vec![0; MHOD]; nlmx], + m2file: vec![vec![0; MHOD]; nlmx], + imerg: 0, + } + } +} + +// ============================================================================ +// OPLIMT - 不透明度限制 T +// ============================================================================ + +/// 不透明度限制温度相关。 +/// 对应 COMMON /OPLIMT/ +#[derive(Debug, Clone, Default)] +pub struct OpLimT { + pub allim1: f64, + pub ablim1: f64, + pub ablim2: f64, + pub ablim3: f64, +} + +// ============================================================================ +// LEVCOM - 能级 ODF 数据 +// ============================================================================ + +/// 能级 ODF 综合数据。 +/// 对应 COMMON /LEVCOM/ +#[derive(Debug, Clone)] +pub struct LevCom { + /// EMKU + pub emku: Vec>, + /// YMKU + pub ymku: Vec>, + /// XEV + pub xev: Vec>, + /// XOD + pub xod: Vec>, + /// EU + pub eu: Vec, + /// JEN + pub jen: Vec, + + // Kurucz 能级数据 + /// EEV + pub eev: Vec, + /// AEV + pub aev: Vec, + /// SEV + pub sev: Vec, + /// WEV + pub wev: Vec, + /// EOD + pub eod: Vec, + /// AOD + pub aod: Vec, + /// SOD + pub sod: Vec, + /// WOD + pub wod: Vec, + /// KSEV + pub ksev: Vec, + /// KSOD + pub ksod: Vec, + /// NEVKU + pub nevku: Vec, + /// NODKU + pub nodku: Vec, + + // 计数器 + pub nlevku: i32, + pub nlinku: i32, + pub keve: i32, + pub kodd: i32, +} + +impl Default for LevCom { + fn default() -> Self { + // 使用较小的测试大小 + Self { + emku: vec![vec![0.0; 2]; MLEVEL], + ymku: vec![vec![0.0; 2]; MLEVEL], + xev: vec![vec![0.0; MION]; MLEVEL], + xod: vec![vec![0.0; MION]; MLEVEL], + eu: vec![0.0; 2 * MLEVEL], + jen: vec![0; 2 * MLEVEL], + + // Kurucz 数据使用较小的默认大小 + eev: vec![0.0; 1000], + aev: vec![0.0; 1000], + sev: vec![0.0; 1000], + wev: vec![0.0; 1000], + eod: vec![0.0; 1000], + aod: vec![0.0; 1000], + sod: vec![0.0; 1000], + wod: vec![0.0; 1000], + ksev: vec![0; 1000], + ksod: vec![0; 1000], + nevku: vec![0; MION], + nodku: vec![0; MION], + + nlevku: 0, + nlinku: 0, + keve: 0, + kodd: 0, + } + } +} + +impl LevCom { + /// 创建完整大小的数组 + pub fn new_full() -> Self { + Self { + emku: vec![vec![0.0; 2]; MLEVEL], + ymku: vec![vec![0.0; 2]; MLEVEL], + xev: vec![vec![0.0; MION]; MLEVEL], + xod: vec![vec![0.0; MION]; MLEVEL], + eu: vec![0.0; 2 * MLEVEL], + jen: vec![0; 2 * MLEVEL], + + eev: vec![0.0; MKULEV], + aev: vec![0.0; MKULEV], + sev: vec![0.0; MKULEV], + wev: vec![0.0; MKULEV], + eod: vec![0.0; MKULEV], + aod: vec![0.0; MKULEV], + sod: vec![0.0; MKULEV], + wod: vec![0.0; MKULEV], + ksev: vec![0; MKULEV], + ksod: vec![0; MKULEV], + nevku: vec![0; MION], + nodku: vec![0; MION], + + nlevku: 0, + nlinku: 0, + keve: 0, + kodd: 0, + } + } + + /// 估算完整内存使用 (MB) + pub fn full_memory_mb() -> f64 { + let main_size = (4 * MLEVEL * MION + 4 * MLEVEL + 2 * 2 * MLEVEL) * std::mem::size_of::(); + let kurucz_size = 8 * MKULEV * std::mem::size_of::(); + (main_size + kurucz_size) as f64 / (1024.0 * 1024.0) + } +} + +// ============================================================================ +// 综合 ODF 数据结构 +// ============================================================================ + +/// TLUSTY ODF 综合数据。 +#[derive(Debug, Clone, Default)] +pub struct OdfData { + pub odfion: OdfIon, + pub odfctr: OdfCtr, + pub odffrq: OdfFrq, + pub odfmod: OdfMod, + pub splcom: SplCom, + pub opalim: OpaLim, + pub oplimt: OpLimT, + pub levcom: LevCom, +} + +impl OdfData { + pub fn new() -> Self { + Self { + odfion: OdfIon::new(), + odfctr: OdfCtr::new(), + odffrq: OdfFrq::new(), + odfmod: OdfMod::new(), + ..Default::default() + } + } + + /// 估算完整内存使用 (MB) + pub fn full_memory_mb() -> f64 { + SplCom::full_memory_mb() + LevCom::full_memory_mb() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_odfion_creation() { + let odfion = OdfIon::new(); + assert_eq!(odfion.inodf1.len(), MION); + } + + #[test] + fn test_odfctr_creation() { + let odfctr = OdfCtr::new(); + assert_eq!(odfctr.frodf.len(), MLEVEL); + assert_eq!(odfctr.nfrodf.len(), MHOD); + } + + #[test] + fn test_memory_estimates() { + println!("SplCom full memory: {:.2} MB", SplCom::full_memory_mb()); + println!("LevCom full memory: {:.2} MB", LevCom::full_memory_mb()); + println!("Total ODF memory: {:.2} MB", OdfData::full_memory_mb()); + } + + #[test] + fn test_odf_data_creation() { + let odf = OdfData::new(); + assert_eq!(odf.odfion.inodf1.len(), MION); + } +} diff --git a/tlusty/extracted/sbfch.f b/tlusty/extracted/sbfch.f index e31c551..7c59064 100644 --- a/tlusty/extracted/sbfch.f +++ b/tlusty/extracted/sbfch.f @@ -202,7 +202,7 @@ C 9-19.184,-19.175,-19.170,-19.168,-19.169,-19.171,-19.174,-19.177, A -19.977,-19.756,-19.606,-19.501,-19.425,-19.370,-19.330, A-19.300,-19.278,-19.262,-19.250,-19.241,-19.235,-19.230,-19.227/ - DATAC10/-20.445,-20.158,-19.958,-19.815,-19.711,-19.633,-19.574, + DATA C10/-20.445,-20.158,-19.958,-19.815,-19.711,-19.633,-19.574, 1-19.528,-19.493,-19.465,-19.442,-19.425,-19.410,-19.398,-19.389, 2 -20.980,-20.625,-20.391,-20.229,-20.110,-20.020,-19.949, 2-19.892,-19.846,-19.807,-19.775,-19.748,-19.724,-19.704,-19.687, @@ -222,7 +222,7 @@ C 9-21.147,-21.099,-21.061,-21.031,-21.006,-20.985,-20.968,-20.954, A -22.969,-22.561,-22.288,-22.092,-21.945,-21.832,-21.743, A-21.672,-21.616,-21.570,-21.533,-21.503,-21.477,-21.457,-21.439/ - DATAC11/-24.001,-23.527,-23.199,-22.957,-22.772,-22.629,-22.516, + DATA C11/-24.001,-23.527,-23.199,-22.957,-22.772,-22.629,-22.516, 1-22.427,-22.355,-22.297,-22.250,-22.212,-22.180,-22.153,-22.131, 2 -24.233,-23.774,-23.477,-23.273,-23.128,-23.022,-22.943, 2-22.883,-22.837,-22.802,-22.774,-22.752,-22.735,-22.721,-22.710, diff --git a/tlusty/extracted/sbfoh.f b/tlusty/extracted/sbfoh.f index 10e3ec0..a986464 100644 --- a/tlusty/extracted/sbfoh.f +++ b/tlusty/extracted/sbfoh.f @@ -202,7 +202,7 @@ C 9-17.488,-17.493,-17.499,-17.504,-17.509,-17.514,-17.519,-17.524, A -17.396,-17.403,-17.412,-17.420,-17.429,-17.437,-17.444, A-17.451,-17.458,-17.464,-17.470,-17.476,-17.481,-17.487,-17.492/ - DATAC10/-17.344,-17.355,-17.366,-17.377,-17.387,-17.396,-17.405, + DATA C10/-17.344,-17.355,-17.366,-17.377,-17.387,-17.396,-17.405, 1-17.413,-17.420,-17.427,-17.434,-17.440,-17.446,-17.452,-17.458, 2 -17.295,-17.307,-17.321,-17.333,-17.345,-17.355,-17.365, 2-17.373,-17.382,-17.389,-17.397,-17.404,-17.410,-17.417,-17.423, @@ -222,7 +222,7 @@ C 9-17.260,-17.270,-17.280,-17.289,-17.298,-17.307,-17.316,-17.325, A -17.193,-17.211,-17.227,-17.241,-17.254,-17.266,-17.277, A-17.288,-17.298,-17.308,-17.317,-17.327,-17.336,-17.345,-17.353/ - DATAC11/-17.239,-17.256,-17.271,-17.284,-17.297,-17.309,-17.320, + DATA C11/-17.239,-17.256,-17.271,-17.284,-17.297,-17.309,-17.320, 1-17.330,-17.340,-17.350,-17.359,-17.369,-17.378,-17.387,-17.395, 2 -17.299,-17.315,-17.329,-17.342,-17.354,-17.365,-17.376, 2-17.386,-17.396,-17.405,-17.415,-17.424,-17.433,-17.442,-17.451, @@ -242,7 +242,7 @@ C 9-18.235,-18.243,-18.252,-18.260,-18.268,-18.277,-18.285,-18.293, A -18.381,-18.393,-18.403,-18.413,-18.422,-18.430,-18.438, A-18.447,-18.455,-18.463,-18.471,-18.479,-18.487,-18.495,-18.503/ - DATAC12/-18.625,-18.638,-18.650,-18.660,-18.669,-18.678,-18.687, + DATA C12/-18.625,-18.638,-18.650,-18.660,-18.669,-18.678,-18.687, 1-18.695,-18.703,-18.711,-18.719,-18.726,-18.734,-18.742,-18.750, 2 -18.912,-18.929,-18.943,-18.955,-18.966,-18.975,-18.984, 2-18.993,-19.001,-19.008,-19.016,-19.023,-19.031,-19.038,-19.045, @@ -262,7 +262,7 @@ C 9-21.569,-21.585,-21.600,-21.614,-21.627,-21.640,-21.652,-21.663, A -21.516,-21.549,-21.580,-21.609,-21.635,-21.658,-21.678, A-21.696,-21.713,-21.728,-21.742,-21.755,-21.767,-21.779,-21.790/ - DATAC13/-21.651,-21.681,-21.711,-21.738,-21.763,-21.785,-21.804, + DATA C13/-21.651,-21.681,-21.711,-21.738,-21.763,-21.785,-21.804, 1-21.821,-21.837,-21.851,-21.864,-21.876,-21.887,-21.898,-21.908, 2 -21.810,-21.831,-21.853,-21.874,-21.893,-21.910,-21.925, 2-21.938,-21.950,-21.961,-21.971,-21.980,-21.989,-21.998,-22.006,