use crate::astro::era::earth_rotation_angle;
use crate::time::JulianDate;
use qtty::*;
use std::f64::consts::TAU;
pub use qtty::time::SIDEREAL_DAY;
const AS2RAD: f64 = std::f64::consts::PI / (180.0 * 3600.0);
#[inline]
pub fn gmst_iau2006(jd_ut1: JulianDate, jd_tt: JulianDate) -> Radians {
let era = earth_rotation_angle(jd_ut1);
let t = jd_tt.julian_centuries().value();
let poly_as = 0.014_506 + 4_612.156_534 * t + 1.391_581_7 * t.powi(2)
- 0.000_000_44 * t.powi(3)
- 0.000_029_956 * t.powi(4)
- 0.000_000_036_8 * t.powi(5);
let gmst = era.value() + poly_as * AS2RAD;
Radians::new(gmst.rem_euclid(TAU))
}
#[inline]
pub fn gast_iau2006(
jd_ut1: JulianDate,
jd_tt: JulianDate,
dpsi: Radians,
true_obliquity: Radians,
) -> Radians {
let gmst = gmst_iau2006(jd_ut1, jd_tt);
let ee = crate::astro::era::equation_of_the_equinoxes(dpsi, true_obliquity);
Radians::new((gmst.value() + ee.value()).rem_euclid(TAU))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gmst_iau2006_at_j2000() {
let jd = JulianDate::J2000;
let gmst = gmst_iau2006(jd, jd);
let gmst_deg = gmst.to::<Degree>();
assert!(
(gmst_deg.value() - 280.46_f64).abs() < 0.1,
"GMST at J2000 = {}°, expected ≈ 280.46°",
gmst_deg
);
}
#[test]
fn gmst_iau2006_range() {
for jd in [2_451_545.0, 2_460_000.5, 2_440_000.0] {
let jd = JulianDate::new(jd);
let gmst = gmst_iau2006(jd, jd);
assert!(gmst >= Radians::new(0.0), "GMST should be ≥ 0");
assert!(gmst < Radians::new(TAU), "GMST should be < 2π");
}
}
#[test]
fn gast_iau2006_close_to_gmst() {
let jd = JulianDate::new(2_460_000.5);
let nutation = crate::astro::nutation::nutation_iau2000b(jd);
let true_obliquity = nutation.true_obliquity();
let gast = gast_iau2006(jd, jd, nutation.dpsi, true_obliquity);
let gmst = gmst_iau2006(jd, jd);
let diff_as = (gast - gmst).value().abs() * 206_264.806;
assert!(
diff_as < 20.0,
"GAST–GMST = {:.3}″, max nutation effect should be < 20″",
diff_as
);
}
}