255 lines
8.0 KiB
Rust
255 lines
8.0 KiB
Rust
//! 与 Fortran 参考实现对比的集成测试
|
|
//!
|
|
//! 这些测试确保 Rust 实现与原始 Fortran 代码输出一致。
|
|
|
|
use tlusty_rust::tlusty::math::{eint, erfcin, erfcx, expo, ffcros, gntk, lagran, raph, sghe12, tridag, yint, ylintp};
|
|
use approx::assert_relative_eq;
|
|
|
|
/// 测试 expo 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_expo_vs_fortran() {
|
|
// Fortran 参考值 (x, y) 对
|
|
let ref_values = [
|
|
(-80.0, 1.8048513878454153E-35),
|
|
(-60.0, 8.7565107626965200E-27),
|
|
(-40.0, 4.2483542552915889E-18),
|
|
(-20.0, 2.0611536224385579E-09),
|
|
(0.0, 1.0),
|
|
(20.0, 4.8516519540979028E+08),
|
|
(40.0, 2.3538526683702000E+17),
|
|
(60.0, 1.1420073898156842E+26),
|
|
(80.0, 5.5406223843935098E+34),
|
|
];
|
|
|
|
for (x, expected) in ref_values {
|
|
let result = expo(x);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 yint 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_yint_vs_fortran() {
|
|
let xl = [0.0, 1.0, 2.0];
|
|
let yl = [0.0, 1.0, 4.0]; // f(x) = x^2
|
|
|
|
// Fortran 参考值 (x0, y) 对
|
|
let ref_values = [
|
|
(-0.5, 2.5000000000000000E-01),
|
|
(0.0, 0.0),
|
|
(0.5, 2.5000000000000000E-01),
|
|
(1.0, 1.0),
|
|
(1.5, 2.2500000000000000E+00),
|
|
(2.0, 4.0),
|
|
(2.5, 6.2500000000000000E+00),
|
|
(3.0, 9.0),
|
|
];
|
|
|
|
for (x0, expected) in ref_values {
|
|
let result = yint(&xl, &yl, x0);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 lagran 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_lagran_vs_fortran() {
|
|
// Fortran 参考值 (x, y) 对
|
|
let ref_values = [
|
|
(-0.5, 2.5000000000000000E-01),
|
|
(0.0, 0.0),
|
|
(0.5, 2.5000000000000000E-01),
|
|
(1.0, 1.0),
|
|
(1.5, 2.2500000000000000E+00),
|
|
(2.0, 4.0),
|
|
(2.5, 6.2500000000000000E+00),
|
|
(3.0, 9.0),
|
|
];
|
|
|
|
for (x, expected) in ref_values {
|
|
let result = lagran(0.0, 1.0, 2.0, 0.0, 1.0, 4.0, x);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 eint 函数与 Fortran 对比
|
|
///
|
|
/// 注意: eint 使用 Abramowitz-Stegun 多项式近似,本身有约 1e-8 的误差
|
|
#[test]
|
|
fn test_eint_vs_fortran() {
|
|
// Fortran 参考值 (t, e1, e2, e3)
|
|
let ref_values = [
|
|
(0.5, 5.5977351132042752E-01, 3.2664390405241966E-01, 2.2160435384321181E-01),
|
|
(1.0, 2.1938394266180694E-01, 1.4849549850963539E-01, 1.0969197133090347E-01),
|
|
(1.5, 1.0001958508512092E-01, 7.3100782520748447E-02, 5.6739493183653573E-02),
|
|
(2.0, 4.8900511239767130E-02, 3.7534260757078441E-02, 3.0133380861227910E-02),
|
|
(2.5, 2.4914918849736040E-02, 1.9797701499558701E-02, 1.6295372437501024E-02),
|
|
(3.0, 1.3048381677757128E-02, 1.0641923334592560E-02, 8.9306491820431329E-03),
|
|
(3.5, 6.9701400793792615E-03, 5.8018931444910847E-03, 4.9453787082998531E-03),
|
|
(4.0, 3.7793524728216067E-03, 3.1982289974477520E-03, 2.7613614494715853E-03),
|
|
(4.5, 2.0734007690333418E-03, 1.7786930775922690E-03, 1.5524388445385473E-03),
|
|
(5.0, 1.1482955955412033E-03, 9.9646902137945012E-04, 8.7780094609410820E-04),
|
|
];
|
|
|
|
for (t, exp_e1, exp_e2, exp_e3) in ref_values {
|
|
let (e1, e2, e3) = eint(t);
|
|
// 多项式近似本身有约 1e-7 的误差
|
|
assert_relative_eq!(e1, exp_e1, epsilon = 1e-7);
|
|
assert_relative_eq!(e2, exp_e2, epsilon = 1e-7);
|
|
assert_relative_eq!(e3, exp_e3, epsilon = 1e-7);
|
|
}
|
|
}
|
|
|
|
/// 测试 tridag 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_tridag_vs_fortran() {
|
|
let a = [0.0, 1.0, 1.0];
|
|
let b = [2.0, 2.0, 2.0];
|
|
let c = [1.0, 1.0, 0.0];
|
|
let r = [5.0, 6.0, 5.0];
|
|
|
|
// Fortran 参考值
|
|
let expected = [1.9999999999999998E+00, 1.0000000000000004E+00, 1.9999999999999998E+00];
|
|
|
|
let u = tridag(&a, &b, &c, &r);
|
|
|
|
for i in 0..3 {
|
|
assert_relative_eq!(u[i], expected[i], epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 gntk 函数与 Fortran 对比
|
|
///
|
|
/// 注意: gntk 仅在特定频率范围内有效,低频时值异常大
|
|
#[test]
|
|
fn test_gntk_vs_fortran() {
|
|
// Fortran 参考值 (fr, g1, g2, g3, g4)
|
|
// 注意: 低频时值异常大,这是原 Fortran 代码的行为
|
|
let ref_values: [(f64, f64, f64, f64, f64); 5] = [
|
|
// (fr, g1, g2, g3, g4)
|
|
(1.0, -2.2684599999999999E+30, 4.0767699999999764E+28, 1.0353999999999900E+28, 1.0),
|
|
(1.5, -1.0082044444444443E+30, 1.8118977777777619E+28, 4.6017777777777113E+27, 1.0),
|
|
(2.0, -5.6711499999999998E+29, 1.0191924999999882E+28, 2.5884999999999503E+27, 1.0),
|
|
(2.5, -3.6295360000000007E+29, 6.5228319999999065E+27, 1.6566399999999606E+27, 1.0),
|
|
(3.0, -2.5205111111111108E+29, 4.5297444444443653E+27, 1.1504444444444115E+27, 1.0),
|
|
];
|
|
|
|
for (fr, exp_g1, exp_g2, exp_g3, exp_g4) in ref_values {
|
|
assert_relative_eq!(gntk(1, fr), exp_g1, epsilon = 1e-5);
|
|
assert_relative_eq!(gntk(2, fr), exp_g2, epsilon = 1e-5);
|
|
assert_relative_eq!(gntk(3, fr), exp_g3, epsilon = 1e-5);
|
|
assert_relative_eq!(gntk(4, fr), exp_g4, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 raph 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_raph_vs_fortran() {
|
|
// Fortran 参考值
|
|
let gam = 1.0;
|
|
let z1 = 0.5;
|
|
let z2 = 0.3;
|
|
let a1 = 1.0;
|
|
let a2 = 2.0;
|
|
let expected_dgam = 1.1134502923976604E+00;
|
|
|
|
let result = raph(gam, z1, z2, a1, a2);
|
|
assert_relative_eq!(result, expected_dgam, epsilon = 1e-10);
|
|
}
|
|
|
|
/// 测试 ffcros 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_ffcros_vs_fortran() {
|
|
// Fortran 参考值 - 都返回 0
|
|
assert_relative_eq!(ffcros(1, 1, 5000.0, 1e15), 0.0, epsilon = 1e-10);
|
|
assert_relative_eq!(ffcros(0, 1, 5000.0, 1e15), 0.0, epsilon = 1e-10);
|
|
assert_relative_eq!(ffcros(1, 0, 5000.0, 1e15), 0.0, epsilon = 1e-10);
|
|
}
|
|
|
|
/// 测试 erfcx 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_erfcx_vs_fortran() {
|
|
// Fortran 参考值 (x, erfc(x))
|
|
let ref_values = [
|
|
(0.0, 9.9999999900000003E-01),
|
|
(1.0, 1.5729931025241004E-01),
|
|
(2.0, 4.6778604187811181E-03),
|
|
(3.0, 2.2105148897756218E-05),
|
|
(4.0, 1.5460295789338392E-08),
|
|
(5.0, 1.5478170433336780E-12),
|
|
];
|
|
|
|
for (x, expected) in ref_values {
|
|
let result = erfcx(x);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 erfcin 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_erfcin_vs_fortran() {
|
|
// Fortran 参考值 (x, inverfc(x))
|
|
let ref_values = [
|
|
(0.1, 1.1630870584411228E+00),
|
|
(0.2, 9.0619407882011216E-01),
|
|
(0.3, 7.3286914940754166E-01),
|
|
(0.4, 5.9511595740386936E-01),
|
|
(0.5, 4.7693612816435027E-01),
|
|
(0.6, 3.7080712947986716E-01),
|
|
(0.7, 2.7246281969225733E-01),
|
|
(0.8, 1.7914355790849454E-01),
|
|
(0.9, 8.8855922153797298E-02),
|
|
];
|
|
|
|
for (x, expected) in ref_values {
|
|
let result = erfcin(x);
|
|
// 迭代方法精度约 1e-5
|
|
assert_relative_eq!(result, expected, epsilon = 1e-4);
|
|
}
|
|
}
|
|
|
|
/// 测试 sghe12 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_sghe12_vs_fortran() {
|
|
// Fortran 参考值 (fr, sghe12)
|
|
let ref_values = [
|
|
(1.0e15, 9.4707561349546987E-18),
|
|
(2.0e15, 1.5053055952018010E-18),
|
|
(3.0e15, 5.5703180206730121E-19),
|
|
(4.0e15, 2.8323006047161224E-19),
|
|
(5.0e15, 1.6942830613190454E-19),
|
|
];
|
|
|
|
for (fr, expected) in ref_values {
|
|
let result = sghe12(fr);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|
|
|
|
/// 测试 ylintp 函数与 Fortran 对比
|
|
#[test]
|
|
fn test_ylintp_vs_fortran() {
|
|
// f(x) = 2x + 1
|
|
let x = [0.0, 1.0, 2.0, 3.0];
|
|
let y = [1.0, 3.0, 5.0, 7.0];
|
|
|
|
// Fortran 参考值 (xint, y)
|
|
let ref_values = [
|
|
(-0.5, 0.0), // 外推
|
|
(0.0, 1.0),
|
|
(0.5, 2.0),
|
|
(1.0, 3.0),
|
|
(1.5, 4.0),
|
|
(2.0, 5.0),
|
|
(2.5, 6.0),
|
|
(3.0, 7.0),
|
|
(3.5, 8.0), // 外推
|
|
(4.0, 9.0), // 外推
|
|
];
|
|
|
|
for (xint, expected) in ref_values {
|
|
let result = ylintp(&x, &y, xint);
|
|
assert_relative_eq!(result, expected, epsilon = 1e-10);
|
|
}
|
|
}
|