Skip to main content

celestial_core/nutation/
fundamental_args.rs

1//! Fundamental arguments for nutation and precession models.
2//!
3//! Fundamental arguments are periodic angular quantities derived from the orbital
4//! mechanics of the Earth-Moon-Sun system and planetary motions. They form the
5//! basis for computing nutation, precession, and other Earth orientation effects.
6//!
7//! This module provides two trait-based interfaces:
8//!
9//! - [`IERS2010FundamentalArgs`]: Arguments from IERS Conventions (2010), including
10//!   planetary longitudes, lunar arguments, and the general precession.
11//!
12//! - [`MHB2000FundamentalArgs`]: Additional arguments from the Mathews-Herring-Buffett
13//!   2000 nutation model (MHB2000), used in IAU 2000A nutation.
14//!
15//! All methods are implemented on `f64` representing time in Julian centuries (TDB)
16//! from J2000.0. Results are in radians, normalized to [0, 2π) where applicable.
17//!
18//! # References
19//!
20//! - IERS Conventions (2010), Chapter 5
21//! - Mathews, Herring, & Buffett 2002, J. Geophys. Res. 107(B4)
22
23use crate::constants::{ARCSEC_TO_RAD, CIRCULAR_ARCSECONDS, TWOPI};
24use crate::math::fmod;
25
26/// Fundamental arguments from IERS Conventions (2010).
27///
28/// These arguments are functions of TDB Julian centuries from J2000.0.
29/// They include mean planetary longitudes and lunar orbital elements
30/// required for computing nutation and precession.
31///
32/// # Usage
33///
34/// ```
35/// use celestial_core::nutation::IERS2010FundamentalArgs;
36///
37/// let t: f64 = 0.1; // Julian centuries from J2000.0
38/// let l = t.moon_mean_anomaly();
39/// let f = t.mean_argument_of_latitude();
40/// ```
41pub trait IERS2010FundamentalArgs {
42    /// Mean longitude of Mercury (radians).
43    fn mercury_lng(&self) -> f64;
44
45    /// Mean longitude of Venus (radians).
46    fn venus_lng(&self) -> f64;
47
48    /// Mean longitude of Earth (radians).
49    fn earth_lng(&self) -> f64;
50
51    /// Mean longitude of Mars (radians).
52    fn mars_lng(&self) -> f64;
53
54    /// Mean longitude of Jupiter (radians).
55    fn jupiter_lng(&self) -> f64;
56
57    /// Mean longitude of Saturn (radians).
58    fn saturn_lng(&self) -> f64;
59
60    /// Mean longitude of Uranus (radians).
61    fn uranus_lng(&self) -> f64;
62
63    /// General accumulated precession in longitude (radians).
64    ///
65    /// This is the precession of the ecliptic along the equator, not normalized
66    /// to [0, 2π).
67    fn precession(&self) -> f64;
68
69    /// Mean anomaly of the Moon (radians), denoted l.
70    ///
71    /// Computed using a 4th-order polynomial in arcseconds, then converted
72    /// to radians and normalized.
73    fn moon_mean_anomaly(&self) -> f64;
74
75    /// Mean argument of latitude of the Moon (radians), denoted F.
76    ///
77    /// The angular distance from the ascending node to the Moon, measured
78    /// along the lunar orbit.
79    fn mean_argument_of_latitude(&self) -> f64;
80
81    /// Mean longitude of the Moon's ascending node (radians), denoted Ω.
82    ///
83    /// The point where the Moon's orbit crosses the ecliptic from south to
84    /// north.
85    fn moon_ascending_node_longitude(&self) -> f64;
86}
87
88impl IERS2010FundamentalArgs for f64 {
89    #[inline]
90    fn mercury_lng(&self) -> f64 {
91        fmod(4.402608842 + 2608.7903141574 * self, TWOPI)
92    }
93
94    #[inline]
95    fn venus_lng(&self) -> f64 {
96        fmod(3.176146697 + 1021.3285546211 * self, TWOPI)
97    }
98
99    #[inline]
100    fn earth_lng(&self) -> f64 {
101        fmod(1.753470314 + 628.3075849991 * self, TWOPI)
102    }
103
104    #[inline]
105    fn mars_lng(&self) -> f64 {
106        fmod(6.203480913 + 334.0612426700 * self, TWOPI)
107    }
108
109    #[inline]
110    fn jupiter_lng(&self) -> f64 {
111        fmod(0.599546497 + 52.9690962641 * self, TWOPI)
112    }
113
114    #[inline]
115    fn saturn_lng(&self) -> f64 {
116        fmod(0.874016757 + 21.3299104960 * self, TWOPI)
117    }
118
119    #[inline]
120    fn uranus_lng(&self) -> f64 {
121        fmod(5.481293872 + 7.4781598567 * self, TWOPI)
122    }
123
124    #[inline]
125    fn precession(&self) -> f64 {
126        0.024381750 * self + 0.00000538691 * self * self
127    }
128
129    #[inline]
130    fn moon_mean_anomaly(&self) -> f64 {
131        let l = 485868.249036
132            + self * (1717915923.2178 + self * (31.8792 + self * (0.051635 - self * 0.00024470)));
133        fmod(l, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD
134    }
135
136    #[inline]
137    fn mean_argument_of_latitude(&self) -> f64 {
138        let f = 335779.526232
139            + self * (1739527262.8478 + self * (-12.7512 + self * (-0.001037 + self * 0.00000417)));
140        fmod(f, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD
141    }
142
143    #[inline]
144    fn moon_ascending_node_longitude(&self) -> f64 {
145        let om = 450160.398036
146            + self * (-6962890.5431 + self * (7.4722 + self * (0.007702 - self * 0.00005939)));
147        fmod(om, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD
148    }
149}
150
151/// Additional fundamental arguments from the MHB2000 nutation model.
152///
153/// These arguments supplement [`IERS2010FundamentalArgs`] with expressions
154/// specific to the Mathews-Herring-Buffett 2000 nutation series. The `_mhb`
155/// suffix distinguishes these from IERS 2010 versions where expressions differ.
156///
157/// # Usage
158///
159/// ```
160/// use celestial_core::nutation::MHB2000FundamentalArgs;
161///
162/// let t: f64 = 0.1; // Julian centuries from J2000.0
163/// let lp = t.sun_mean_anomaly_mhb();
164/// let d = t.mean_elongation_mhb();
165/// ```
166pub trait MHB2000FundamentalArgs {
167    /// Mean anomaly of the Sun (radians), denoted l'.
168    ///
169    /// Uses the MHB2000 polynomial coefficients.
170    fn sun_mean_anomaly_mhb(&self) -> f64;
171
172    /// Mean elongation of the Moon from the Sun (radians), denoted D.
173    ///
174    /// The angular separation between the Moon and Sun as seen from Earth.
175    fn mean_elongation_mhb(&self) -> f64;
176
177    /// Mean longitude of Neptune (radians).
178    fn neptune_longitude_mhb(&self) -> f64;
179}
180
181impl MHB2000FundamentalArgs for f64 {
182    #[inline]
183    fn sun_mean_anomaly_mhb(&self) -> f64 {
184        let lp = 1287104.79305
185            + self * (129596581.0481 + self * (-0.5532 + self * (0.000136 - self * 0.00001149)));
186        fmod(lp, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD
187    }
188
189    #[inline]
190    fn mean_elongation_mhb(&self) -> f64 {
191        let d = 1072260.70369
192            + self * (1602961601.2090 + self * (-6.3706 + self * (0.006593 - self * 0.00003169)));
193        fmod(d, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD
194    }
195
196    #[inline]
197    fn neptune_longitude_mhb(&self) -> f64 {
198        fmod(5.321159000 + 3.8127774000 * self, TWOPI)
199    }
200}