#![cfg(feature = "grib")]
use winds_engine::grib::profile_from_grib2;
fn golden() -> Vec<u8> {
std::fs::read(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/data/gfs_20261026_00z_mpx.grib2"
))
.unwrap()
}
#[test]
fn golden_gfs_subset_decodes_to_a_profile() {
let profile = profile_from_grib2(&golden(), 44.883, -93.233, 0.0).unwrap();
let levels = profile.levels();
assert_eq!(levels.len(), 3);
assert!(levels[0].altitude_m < levels[2].altitude_m);
for level in levels {
println!(
"PIN alt={:.4} speed={:.4} dir={:.4}",
level.altitude_m, level.speed_mps, level.direction_from_deg
);
}
let expected = [
(1583.5270, 2.7566, 60.9195),
(3169.2878, 15.0535, 247.1875),
(5812.0977, 21.2301, 258.2658),
];
for (level, &(alt, speed, dir)) in levels.iter().zip(&expected) {
assert!(
(level.altitude_m - alt).abs() / alt < 0.001,
"alt {} vs {alt}",
level.altitude_m
);
assert!(
(level.speed_mps - speed).abs() / speed.max(1.0) < 0.001,
"speed {} vs {speed}",
level.speed_mps
);
assert!(
(level.direction_from_deg - dir).abs() < 0.001,
"dir {} vs {dir}",
level.direction_from_deg
);
}
for level in levels {
assert!(level.speed_mps >= 0.0 && level.speed_mps < 100.0);
assert!(level.direction_from_deg >= 0.0 && level.direction_from_deg < 360.0);
}
}
#[test]
fn direction_rotates_with_launch_azimuth() {
let north = profile_from_grib2(&golden(), 44.883, -93.233, 0.0).unwrap();
let east = profile_from_grib2(&golden(), 44.883, -93.233, 90.0).unwrap();
for (n, e) in north.levels().iter().zip(east.levels()) {
let rotated = (n.direction_from_deg - 90.0).rem_euclid(360.0);
assert!(
(rotated - e.direction_from_deg).abs() < 1e-9,
"{rotated} vs {}",
e.direction_from_deg
);
assert_eq!(n.speed_mps, e.speed_mps);
}
}
#[test]
fn validates_its_inputs() {
let data = golden();
assert!(profile_from_grib2(&data, 91.0, 0.0, 0.0).is_err());
assert!(profile_from_grib2(&data, 45.0, f64::NAN, 0.0).is_err());
assert!(profile_from_grib2(b"not grib", 45.0, 0.0, 0.0).is_err());
}