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}