deep_time/sidereal/earth.rs
1//! Earth equinox sidereal time (IAU 2000/2006).
2//!
3//! [`Sidereal`](../struct.Sidereal.html) is a prime-meridian clock. On Earth that clock is the Earth
4//! Rotation Angle (ERA, CIO origin). This module adds the IAU equinox readout
5//! of that clock as methods on [`Sidereal`](../struct.Sidereal.html):
6//!
7//! ```text
8//! GAST = ERA − eo06a(TT) // true equinox
9//! GMST = ERA − eo06a(TT) − ee06a(TT) // mean equinox
10//! LAST = GAST + λ // east longitude, radians
11//! LMST = GMST + λ
12//! ```
13//!
14//! ERA / GMST / GAST take **UT1** MJD. The Equation of the Origins (`eo`) and
15//! Equation of the Equinoxes (`ee`) take **TT** MJD. These quantities are
16//! Earth-only; they are not a generic mode of [`Sidereal`](../struct.Sidereal.html).
17//!
18//! With matching UT1 and TT, results agree with Astropy mean/apparent sidereal
19//! time and ERFA `eo06a` / `ee06a` (see tests).
20
21use super::earth_eo_ee::{earth_ee, earth_eo};
22use super::{Sidereal, wrap_angle};
23use crate::Real;
24
25/// Earth equinox sidereal time.
26///
27/// Greenwich forms (`era`, `gmst`, `gast`, `eo`, `ee`) always use the IAU ERA
28/// ([`Sidereal::EARTH`](../struct.Sidereal.html#associatedconstant.EARTH)), not this instance's `rate` or `correction_rad`.
29/// Local forms (`lmst`, `last`) add this instance's [`Sidereal::longitude_rad`](../struct.Sidereal.html#structfield.longitude_rad)
30/// (east positive).
31impl Sidereal {
32 /// Earth Rotation Angle at **UT1** MJD, radians in `[0, 2π)`.
33 ///
34 /// Same as [`Sidereal::EARTH`](../struct.Sidereal.html#associatedconstant.EARTH).[`Sidereal::rotation_angle`](../struct.Sidereal.html#method.rotation_angle).
35 #[inline]
36 pub const fn era(ut1_mjd: Real) -> Real {
37 Self::EARTH.rotation_angle(ut1_mjd)
38 }
39
40 /// Equation of the Origins at **TT** MJD (`eo06a`): `EO = ERA − GAST`.
41 #[inline]
42 pub const fn eo(tt_mjd: Real) -> Real {
43 earth_eo(2_400_000.5, tt_mjd)
44 }
45
46 /// Equation of the Equinoxes at **TT** MJD (`ee06a`): `EE = GAST − GMST`.
47 #[inline]
48 pub const fn ee(tt_mjd: Real) -> Real {
49 earth_ee(2_400_000.5, tt_mjd)
50 }
51
52 /// Greenwich Mean Sidereal Time (radians): `ERA(UT1) − eo(TT) − ee(TT)`.
53 ///
54 /// ## Examples
55 ///
56 /// ```rust
57 /// # #[cfg(all(feature = "eop", feature = "std", feature = "sidereal-earth"))] {
58 /// use deep_time::eop::{EopData, EopFormat, Separator};
59 /// use deep_time::{Dt, Scale, Sidereal};
60 ///
61 /// let eop = EopData::from_text_file(
62 /// "tests/assets/EOP_20u24_C04_one_file_1962-now.txt",
63 /// EopFormat::C04,
64 /// Separator::Whitespace,
65 /// ).unwrap();
66 /// let utc = Dt::from_mjd_f(56879.0, Scale::UTC);
67 /// let ut1 = utc.to_ut1(&eop).unwrap().to_mjd_f_raw();
68 /// let tt = utc.to(Scale::TT).to_mjd_f_raw();
69 ///
70 /// let gmst = Sidereal::gmst(ut1, tt);
71 /// let _ = gmst;
72 /// # }
73 /// ```
74 #[inline]
75 pub const fn gmst(ut1_mjd: Real, tt_mjd: Real) -> Real {
76 wrap_angle(Self::era(ut1_mjd) - Self::eo(tt_mjd) - Self::ee(tt_mjd))
77 }
78
79 /// Greenwich Apparent Sidereal Time (radians): `ERA(UT1) − eo(TT)`.
80 #[inline]
81 pub const fn gast(ut1_mjd: Real, tt_mjd: Real) -> Real {
82 wrap_angle(Self::era(ut1_mjd) - Self::eo(tt_mjd))
83 }
84
85 /// Local Mean Sidereal Time (radians): `GMST + longitude_rad`.
86 ///
87 /// Always uses IAU Earth ERA
88 /// ([`Sidereal::gmst`](../struct.Sidereal.html#method.gmst)). Only
89 /// [`Sidereal::longitude_rad`](../struct.Sidereal.html#structfield.longitude_rad) (east positive) is taken from this instance.
90 ///
91 /// ```text
92 /// HA = lmst(ut1, tt) − RA // mean-equinox RA
93 /// ```
94 #[inline]
95 pub const fn lmst(&self, ut1_mjd: Real, tt_mjd: Real) -> Real {
96 wrap_angle(Self::gmst(ut1_mjd, tt_mjd) + self.longitude_rad)
97 }
98
99 /// Local Apparent Sidereal Time (radians): `GAST + longitude_rad`.
100 ///
101 /// Always uses IAU Earth ERA
102 /// ([`Sidereal::gast`](../struct.Sidereal.html#method.gast)). Only
103 /// [`Sidereal::longitude_rad`](../struct.Sidereal.html#structfield.longitude_rad) (east positive) is taken from this instance.
104 ///
105 /// ```text
106 /// HA = last(ut1, tt) − RA // true-equinox RA
107 /// ```
108 #[inline]
109 pub const fn last(&self, ut1_mjd: Real, tt_mjd: Real) -> Real {
110 wrap_angle(Self::gast(ut1_mjd, tt_mjd) + self.longitude_rad)
111 }
112}