SpectraRust/src/synspec/math/pfni.rs
fmq e2c1a4580a feat: F2R 重构全部完成 + 自动化脚本改进
Phase 1 翻译 (完成):
- TLUSTY 350 函数 100% 翻译
- SYNSPEC 168 函数 100% 翻译
- ~495 Rust 模块

Phase 2 集成 (完成):
- TLUSTY RESOLV 7 个 TODO 全部清除
- TLUSTY Runner IJALI 频率选择实现
- OPFRAC ioniz.dat 解析完整实现
- SYNSPEC Runner 编排流程连接完成
- SYNSPEC RESOLV OPAC→RTE→OUTPRI 调用链完整

Phase 3 验证 (完成, 修复 8 处 bug):
- INITIA: compute_hydrogen_level_bounds 索引混合修复
- INILIN: GAMR0/GS0/GW0 展宽公式修复, 经典 VdW 公式修复
- INIBL0: CNM 常数 2.997925e18→e17 修复
- OPAC: Lyman IJ=2 修正缺失修复
- RTE: minv3 矩阵求逆符号错误修复

自动化脚本改进:
- specf2r.sh: 添加 429 限流退避、完成检测、同步等待
- SKILL.md: 三阶段工作流 + 状态文件系统
- references/: Phase 1/2/3 独立参考文档

新增:
- src/bin/synspec.rs: SYNSPEC 可执行文件入口
- .f2r_phase/.f2r_tasks/.f2r_complete: 状态管理文件

编译: 0 错误 | Clippy: 0 错误 | 测试: voigt 28 + eldens 5 通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 14:54:53 +08:00

425 lines
20 KiB
Rust

//! PFNI - Partition functions for Ni IV to Ni IX
//!
//! Interpolation within a grid calculated from all levels predicted by
//! Kurucz (1992), i.e. over 12,000 levels per ion.
//! The partition functions depend only on T (no level dissolution with density).
//!
//! TL 27-DEC-1994, 23-JAN-1995
/// Evaluates partition function for Ni IV to Ni IX.
///
/// # Arguments
/// * `ion` - Ionization stage (4-9, where 4=Ni IV, 9=Ni IX)
/// * `t` - Temperature in K
///
/// # Returns
/// * `(pf, dut, dun)` - Partition function, dPF/dT, dPF/dANE (=0 in this version)
pub fn pfni(ion: usize, t: f64) -> (f64, f64, f64) {
let xen = std::f64::consts::LN_10;
let xmil = 0.001_f64;
// Ground state statistical weights for Ni IV to Ni IX
let g0 = [28.0, 25.0, 6.0, 25.0, 28.0, 21.0];
// Partition function data arrays (log10 values)
// p*a = temperature range 12000-200000 K (190 points, 1000 K steps)
// p*b = temperature range 200000-350000 K (170 points, 1000 K steps)
let p4a: [f64; 190] = [
1.447,1.464,1.482,1.501,1.518,1.535,1.551,1.567,1.582,1.596,
1.610,1.623,1.636,1.648,1.659,1.671,1.681,1.692,1.702,1.711,
1.721,1.730,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.850,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.000,2.012,2.025,2.037,2.050,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.260,2.276,
2.293,2.310,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.640,2.657,2.674,2.690,2.707,2.723,2.740,2.756,2.772,2.788,
2.804,2.819,2.835,2.850,2.866,2.881,2.896,2.911,2.925,2.940,
2.954,2.969,2.983,2.997,3.010,3.024,3.038,3.051,3.064,3.077,
3.090,3.103,3.116,3.128,std::f64::consts::PI,3.153,3.165,3.177,3.189,3.201,
3.213,3.224,3.235,3.247,3.258,3.269,3.280,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.430,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.550,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,
];
let 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.740,3.747,3.753,3.759,3.765,3.771,3.777,3.782,
3.788,3.794,3.800,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.950,3.954,3.959,3.963,3.967,3.972,3.976,3.980,
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.040,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.090,4.093,
4.097,4.100,4.103,4.107,4.110,4.113,4.116,4.120,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.180,4.182,4.185,
4.188,4.191,4.193,4.196,4.199,4.202,4.204,4.207,4.210,4.212,
4.215,4.217,4.220,4.223,4.225,4.228,4.230,4.233,4.235,4.238,
4.240,4.243,4.245,4.247,4.250,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.280,4.282,4.284,
];
let 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.940,1.946,1.953,1.960,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.040,2.046,
2.052,2.058,2.065,2.071,2.077,2.084,2.090,2.097,2.103,2.110,
2.117,2.124,2.131,2.138,2.145,2.152,2.160,2.167,2.175,2.183,
2.191,2.199,2.207,2.216,2.224,2.233,2.241,2.250,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.430,2.441,2.452,2.463,2.474,
2.485,2.497,2.508,2.519,2.530,2.542,2.553,2.564,2.576,2.587,
2.599,2.610,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.790,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.120,3.129,3.138,3.147,3.156,3.164,3.173,3.182,3.190,3.198,
3.207,3.215,3.223,3.232,3.240,3.248,3.256,3.264,3.272,3.279,
];
let p5b: [f64; 170] = [
3.120,3.129,3.138,3.147,3.156,3.164,3.173,3.182,3.190,3.198,
3.207,3.215,3.223,3.232,3.240,3.248,3.256,3.264,3.272,3.279,
3.287,3.295,3.303,3.310,3.318,3.325,3.333,3.340,3.347,3.355,
3.362,3.369,3.376,3.383,3.390,3.397,3.404,3.411,3.417,3.424,
3.431,3.438,3.444,3.451,3.457,3.464,3.470,3.476,3.483,3.489,
3.495,3.501,3.507,3.514,3.520,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.600,3.605,
3.610,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.720,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.790,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.850,3.854,3.858,3.862,3.865,3.869,3.873,
3.876,3.880,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.970,3.974,
3.977,3.980,3.983,3.986,3.989,3.992,3.995,3.998,4.001,4.004,
];
let 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.440,1.459,1.478,1.497,
1.515,1.532,1.548,1.564,1.580,1.594,1.609,1.623,1.636,1.649,
1.662,1.674,1.686,1.698,1.709,1.720,1.730,1.740,1.750,1.760,
1.769,1.779,1.788,1.796,1.805,1.813,1.821,1.829,1.837,1.845,
1.852,1.860,1.867,1.874,1.881,1.888,1.894,1.901,1.907,1.914,
1.920,1.926,1.932,1.938,1.944,1.950,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.080,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.190,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.330,2.338,2.346,2.354,2.362,
2.370,2.379,2.387,2.395,2.404,2.412,2.420,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.560,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.710,
std::f64::consts::E,2.727,2.736,2.744,2.753,2.761,2.770,2.779,2.787,2.796,
];
let p6b: [f64; 170] = [
2.631,2.639,2.648,2.657,2.666,2.675,2.683,2.692,2.701,2.710,
std::f64::consts::E,2.727,2.736,2.744,2.753,2.761,2.770,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.020,3.027,3.035,
3.042,3.049,3.057,3.064,3.071,3.078,3.086,3.093,3.100,3.107,
3.114,3.121,3.128,3.135,std::f64::consts::PI,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.240,
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.330,3.336,3.342,3.348,3.353,3.359,
3.364,3.370,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.440,3.445,3.450,3.455,3.460,3.465,
3.470,3.475,3.480,3.485,3.490,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.560,
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,
];
let p7a: [f64; 190] = [
1.398,1.398,1.398,1.398,1.406,1.425,1.443,1.461,1.480,1.498,
1.516,1.534,1.551,1.568,1.585,1.601,1.616,1.631,1.646,1.660,
1.674,1.687,1.700,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.840,1.848,1.855,1.863,
1.870,1.877,1.883,1.890,1.896,1.902,1.908,1.914,1.920,1.925,
1.931,1.936,1.941,1.946,1.951,1.956,1.960,1.965,1.969,1.974,
1.978,1.982,1.986,1.990,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.050,2.053,2.056,2.059,2.061,2.064,2.067,2.069,2.072,
2.075,2.077,2.080,2.082,2.085,2.088,2.090,2.093,2.095,2.098,
2.100,2.103,2.105,2.107,2.110,2.112,2.115,2.117,2.120,2.122,
2.125,2.127,2.130,2.132,2.135,2.137,2.140,2.142,2.145,2.148,
2.150,2.153,2.155,2.158,2.161,2.163,2.166,2.169,2.172,2.175,
2.178,2.180,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.250,2.254,2.258,2.261,2.265,2.269,2.273,2.277,
2.282,2.286,2.290,2.294,2.299,2.303,2.307,2.312,2.316,2.321,
2.325,2.330,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.410,2.415,2.420,
];
let p7b: [f64; 170] = [
2.325,2.330,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.410,2.415,2.420,
2.426,2.431,2.437,2.442,2.448,2.453,2.459,2.464,2.470,2.476,
2.481,2.487,2.493,2.498,2.504,2.510,2.516,2.521,2.527,2.533,
2.539,2.545,2.551,2.556,2.562,2.568,2.574,2.580,2.586,2.592,
2.598,2.604,2.610,2.616,2.622,2.628,2.634,2.640,2.646,2.652,
2.658,2.664,2.670,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.770,
2.776,2.782,2.788,2.794,2.799,2.805,2.811,2.817,2.823,2.828,
2.834,2.840,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.940,
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.030,3.035,3.040,3.045,
3.050,3.055,3.060,3.065,3.070,3.075,3.080,3.085,3.090,3.095,
3.099,3.104,3.109,3.114,3.119,3.123,3.128,3.133,3.138,std::f64::consts::PI,
3.147,3.152,3.156,3.161,3.165,3.170,3.175,3.179,3.184,3.188,
3.193,3.197,3.202,3.206,3.210,3.215,3.219,3.224,3.228,3.232,
];
let 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.580,1.591,1.602,1.612,1.622,
1.631,1.640,1.649,1.658,1.666,1.674,1.682,1.689,1.696,1.703,
1.710,1.716,1.722,1.728,1.734,1.740,1.745,1.751,1.756,1.761,
1.766,1.770,1.775,1.779,1.784,1.788,1.792,1.796,1.800,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.850,1.853,1.855,1.858,1.860,1.863,
1.865,1.867,1.870,1.872,1.874,1.876,1.878,1.880,1.882,1.884,
1.886,1.888,1.890,1.892,1.894,1.896,1.898,1.900,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.950,1.951,1.953,1.955,
1.957,1.959,1.960,1.962,1.964,1.966,1.968,1.970,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.000,2.002,2.004,2.006,2.009,2.011,2.013,2.015,
2.018,2.020,2.023,2.025,2.027,2.030,2.032,2.035,2.037,2.040,
2.043,2.045,2.048,2.051,2.053,2.056,2.059,2.062,2.064,2.067,
2.070,2.073,2.076,2.079,2.082,2.085,2.088,2.091,2.094,2.097,
2.100,2.103,2.107,2.110,2.113,2.116,2.120,2.123,2.126,2.130,
];
let p8b: [f64; 170] = [
2.070,2.073,2.076,2.079,2.082,2.085,2.088,2.091,2.094,2.097,
2.100,2.103,2.107,2.110,2.113,2.116,2.120,2.123,2.126,2.130,
2.133,2.137,2.140,2.143,2.147,2.151,2.154,2.158,2.161,2.165,
2.168,2.172,2.176,2.180,2.183,2.187,2.191,2.195,2.198,2.202,
2.206,2.210,2.214,2.218,2.222,2.226,2.230,2.233,2.237,2.241,
2.245,2.250,2.254,2.258,2.262,2.266,2.270,2.274,2.278,2.282,
2.286,2.291,2.295,2.299,2.303,2.307,2.312,2.316,2.320,2.324,
2.329,2.333,2.337,2.341,2.346,2.350,2.354,2.359,2.363,2.367,
2.371,2.376,2.380,2.384,2.389,2.393,2.397,2.402,2.406,2.410,
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.480,2.484,2.488,2.493,2.497,
2.501,2.506,2.510,2.514,2.519,2.523,2.527,2.531,2.536,2.540,
2.544,2.548,2.553,2.557,2.561,2.565,2.570,2.574,2.578,2.582,
2.586,2.591,2.595,2.599,2.603,2.607,2.611,2.616,2.620,2.624,
2.628,2.632,2.636,2.640,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.700,2.704,
2.708,2.712,2.716,2.720,2.724,2.728,2.732,2.736,2.739,2.743,
];
let 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.380,1.386,1.392,1.398,
1.404,1.409,1.415,1.420,1.425,1.429,1.434,1.438,1.442,1.446,
1.450,1.454,1.457,1.461,1.464,1.467,1.470,1.473,1.476,1.479,
1.482,1.485,1.487,1.490,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.520,1.522,
1.524,1.525,1.527,1.528,1.530,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.560,1.561,
1.562,1.563,1.565,1.566,1.567,1.568,1.569,1.570,1.571,1.573,
1.574,1.575,1.576,1.577,1.579,1.580,1.581,1.582,1.584,1.585,
1.586,1.588,1.589,1.590,1.592,1.593,1.594,1.596,1.597,1.599,
1.600,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.630,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.670,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.740,1.743,1.746,1.749,
];
let 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.740,1.743,1.746,1.749,
1.751,1.754,1.757,1.760,1.763,1.765,1.768,1.771,1.774,1.777,
1.780,1.783,1.786,1.789,1.792,1.795,1.798,1.801,1.804,1.807,
1.810,1.813,1.816,1.819,1.822,1.825,1.828,1.831,1.834,1.837,
1.840,1.843,1.847,1.850,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.910,1.913,1.917,1.920,1.923,1.926,1.930,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.040,2.044,2.047,2.050,2.053,2.057,2.060,2.063,
2.066,2.070,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.140,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.190,
2.193,2.196,2.199,2.202,2.205,2.208,2.212,2.215,2.218,2.221,
];
// For T < 12000 K, return ground state statistical weight
if t < 12000.0 {
return (g0[ion - 4], 0.0, 0.0);
}
// Determine temperature grid indices
let it = (t / 1000.0) as usize;
let it = if it >= 350 { 349 } else { it };
let t1 = 1000.0 * it as f64;
let _t2 = t1 + 1000.0;
// Select appropriate data arrays based on ionization stage
let (xu1, xu2) = match ion {
4 => {
if t <= 200000.0 {
(p4a[it - 10], p4a[it - 9])
} else {
(p4b[it - 180], p4b[it - 179])
}
}
5 => {
if t <= 200000.0 {
(p5a[it - 10], p5a[it - 9])
} else {
(p5b[it - 180], p5b[it - 179])
}
}
6 => {
if t <= 200000.0 {
(p6a[it - 10], p6a[it - 9])
} else {
(p6b[it - 180], p6b[it - 179])
}
}
7 => {
if t <= 200000.0 {
(p7a[it - 10], p7a[it - 9])
} else {
(p7b[it - 180], p7b[it - 179])
}
}
8 => {
if t <= 200000.0 {
(p8a[it - 10], p8a[it - 9])
} else {
(p8b[it - 180], p8b[it - 179])
}
}
9 => {
if t <= 200000.0 {
(p9a[it - 10], p9a[it - 9])
} else {
(p9b[it - 180], p9b[it - 179])
}
}
_ => return (0.0, 0.0, 0.0),
};
// Linear interpolation
let dxt = xmil * (xu2 - xu1);
let xu = xu1 + (t - t1) * dxt;
let pf = (xen * xu).exp();
let dut = xen * pf * dxt;
let dun = 0.0;
(pf, dut, dun)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pfni_low_temperature() {
// For T < 12000 K, should return ground state statistical weight
let (pf, dut, dun) = pfni(4, 10000.0);
assert_eq!(pf, 28.0); // g0[0] for Ni IV
assert_eq!(dut, 0.0);
assert_eq!(dun, 0.0);
}
#[test]
fn test_pfni_ni_iv() {
// Test Ni IV at a temperature within the table range
let (pf, dut, dun) = pfni(4, 20000.0);
assert!(pf > 0.0);
assert!(pf.is_finite());
assert!(dut.is_finite());
assert_eq!(dun, 0.0);
}
#[test]
fn test_pfni_ni_ix() {
// Test Ni IX at a temperature within the table range
let (pf, dut, dun) = pfni(9, 50000.0);
assert!(pf > 0.0);
assert!(pf.is_finite());
assert!(dut.is_finite());
assert_eq!(dun, 0.0);
}
#[test]
fn test_pfni_high_temperature() {
// Test at high temperature (above 200000 K, using p*b tables)
let (pf, dut, dun) = pfni(4, 250000.0);
assert!(pf > 0.0);
assert!(pf.is_finite());
assert!(dut.is_finite());
assert_eq!(dun, 0.0);
}
#[test]
fn test_pfni_monotonicity() {
// Partition functions should generally increase with temperature
let (pf1, _, _) = pfni(4, 15000.0);
let (pf2, _, _) = pfni(4, 30000.0);
let (pf3, _, _) = pfni(4, 100000.0);
assert!(pf2 > pf1);
assert!(pf3 > pf2);
}
#[test]
fn test_pfni_all_ions() {
// Test all ionization stages
for ion in 4..=9 {
let (pf, dut, dun) = pfni(ion, 50000.0);
assert!(pf > 0.0, "PF should be positive for Ni {}", ion_to_roman(ion));
assert!(pf.is_finite(), "PF should be finite for Ni {}", ion_to_roman(ion));
assert!(dut.is_finite(), "dUT should be finite for Ni {}", ion_to_roman(ion));
assert_eq!(dun, 0.0);
}
}
fn ion_to_roman(ion: usize) -> &'static str {
match ion {
4 => "IV",
5 => "V",
6 => "VI",
7 => "VII",
8 => "VIII",
9 => "IX",
_ => "?",
}
}
}