deep_time/sidereal/mod.rs
1#[cfg(feature = "sidereal-earth")]
2pub mod earth_eo_ee;
3
4use crate::Real;
5use core::f64::consts::TAU;
6
7#[cfg(feature = "sidereal-earth")]
8use earth_eo_ee::*;
9
10/// Represents the rotational state of a celestial body and provides
11/// methods to compute the orientation of its prime meridian at any
12/// given time.
13///
14/// The rotation angle of the prime meridian is the basis for
15/// calculating local sidereal time. Local sidereal time is required
16/// to compute the hour angle of a celestial object (HA = LST − RA),
17/// to determine when an object will cross the local meridian,
18/// to convert between horizon coordinates (altitude/azimuth) and
19/// equatorial coordinates, and to calculate accurate pointing
20/// directions for telescopes and spacecraft antennas.
21///
22/// The struct implements the modern CIO-based rotation model and
23/// works for any rotating body (Earth, Mars, the Moon, etc.) by
24/// supplying the appropriate rotation rate and reference values.
25///
26/// ## Fields
27///
28/// * `rate_rad_per_sec` — Mean sidereal rotation rate in radians per SI second.
29/// * `ref_epoch` — Reference epoch (MJD) at which `ref_angle_rad` is defined.
30/// * `ref_angle_rad` — Rotation angle of the prime meridian at `ref_epoch`.
31/// * `longitude_rad` — Observer longitude on the body (radians, east positive).
32/// `0.0` corresponds to the body's prime meridian.
33/// * `correction_rad` — General-purpose additive correction in radians.
34///
35/// ## Examples
36///
37/// Basic usage with Earth constants:
38///
39/// ```rust
40/// use deep_time::Sidereal;
41///
42/// let mut earth = Sidereal::EARTH;
43/// earth.longitude_rad = 0.0; // Greenwich
44///
45/// let mjd = 60000.0;
46/// let era = earth.rotation_angle(mjd);
47///
48/// // Local Mean Sidereal Time using the mean Equation of the Origins
49/// let eo_mean = earth.earth_eo_mean(mjd + 32.184 / 86400.0);
50/// let lmst = earth.local_sidereal_time_mean(mjd, eo_mean);
51/// ```
52///
53/// Realistic usage with DUT1 correction (UT1 time scale):
54///
55/// ```rust
56/// use deep_time::{Dt, Sidereal};
57/// use deep_time::eop::{EopData, EopFormat, Separator};
58///
59/// let eop = EopData::from_text_file(
60/// "finals.all.iau2000.txt",
61/// EopFormat::Finals2000A,
62/// Separator::Whitespace,
63/// ).unwrap();
64///
65/// let mjd_utc = 56879.0;
66/// let dut1 = Dt::mjd_to_eop_offset_f(mjd_utc, &eop).unwrap();
67/// let mjd_ut1 = mjd_utc + dut1 / 86400.0;
68///
69/// let earth = Sidereal::EARTH;
70///
71/// let era = earth.rotation_angle(mjd_ut1);
72///
73/// // Greenwich Mean Sidereal Time
74/// let eo_mean = earth.earth_eo_mean(mjd_ut1 + 32.184 / 86400.0);
75/// let gmst = earth.sidereal_angle_mean(mjd_ut1, eo_mean);
76///
77/// // Local Mean Sidereal Time
78/// let lmst = earth.local_sidereal_time_mean(mjd_ut1, eo_mean);
79/// ```
80#[derive(Debug, Clone, Copy)]
81pub struct Sidereal {
82 /// Mean sidereal rotation rate in **radians per SI second**.
83 pub rate_rad_per_sec: Real,
84 /// Reference epoch.
85 pub ref_epoch: Real,
86 /// Rotation angle of the prime meridian (radians) at `ref_epoch`.
87 pub ref_angle_rad: Real,
88 /// Longitude of the observer on the body (radians, east positive).
89 /// `0.0` = body's prime meridian.
90 pub longitude_rad: Real,
91 /// General scalar correction in radians.
92 pub correction_rad: Real,
93}
94
95impl Sidereal {
96 /// Pre-configured `Sidereal` for Earth using IAU 2000/2006 conventions.
97 ///
98 /// This uses:
99 /// - The conventional mean sidereal rotation rate of Earth.
100 /// - J2000.0 as the reference epoch (`ref_epoch = 51544.5`).
101 /// - The Earth Rotation Angle (ERA) at J2000.0 as `ref_angle_rad`.
102 ///
103 /// You can still customize fields after construction (e.g. `longitude_rad`
104 /// or `correction_rad`).
105 pub const EARTH: Self = Self {
106 rate_rad_per_sec: (1.00273781191135448 * core::f64::consts::TAU) / 86400.0,
107 ref_epoch: 51544.5,
108 ref_angle_rad: 0.7790572732640 * core::f64::consts::TAU,
109 longitude_rad: 0.0,
110 correction_rad: 0.0,
111 };
112
113 /// Pre-configured `Sidereal` for Mars.
114 ///
115 /// Uses a simplified mean sidereal rotation rate and J2000.0 as the
116 /// reference epoch. `ref_angle_rad` is set to zero (no specific
117 /// reference angle is defined).
118 ///
119 /// You can customize fields (especially `longitude_rad`) after construction.
120 pub const MARS: Self = Self {
121 rate_rad_per_sec: core::f64::consts::TAU / 88642.663,
122 ref_epoch: 51544.5,
123 ref_angle_rad: 0.0,
124 longitude_rad: 0.0,
125 correction_rad: 0.0,
126 };
127
128 /// Pre-configured `Sidereal` for the Moon.
129 ///
130 /// Uses a simplified mean sidereal rotation rate and J2000.0 as the
131 /// reference epoch. `ref_angle_rad` is set to zero (no specific
132 /// reference angle is defined).
133 ///
134 /// You can customize fields (especially `longitude_rad`) after construction.
135 pub const MOON: Self = Self {
136 rate_rad_per_sec: core::f64::consts::TAU / 2_360_591.424,
137 ref_epoch: 51544.5,
138 ref_angle_rad: 0.0,
139 longitude_rad: 0.0,
140 correction_rad: 0.0,
141 };
142
143 // Normalize to [0, 2π)
144 #[inline]
145 const fn normalize_angle(angle: Real) -> Real {
146 ((angle % TAU) + TAU) % TAU
147 }
148
149 /// Returns the instantaneous rotation angle of the body's prime meridian
150 /// (in radians) at the given instant, normalized to `[0, 2π)`.
151 ///
152 /// For Earth this is the pure Earth Rotation Angle (ERA) in the
153 /// Celestial Intermediate Origin (CIO) frame. It does **not** include
154 /// observer longitude or the Equation of the Origins.
155 ///
156 /// Matches Astropy's `Time.earth_rotation_angle(longitude=None)`
157 /// (or with `longitude=0`).
158 ///
159 /// ## Example
160 ///
161 /// ```rust
162 /// use deep_time::Sidereal;
163 ///
164 /// let era = Sidereal::EARTH.rotation_angle(57753.5);
165 /// ```
166 pub const fn rotation_angle(&self, mjd: Real) -> Real {
167 // elapsed time in seconds between ref_epoch (MJD) and the given mjd
168 let elapsed_days = mjd - self.ref_epoch;
169 let elapsed_sec = elapsed_days * 86400.0;
170
171 let angle = self.ref_angle_rad + self.rate_rad_per_sec * elapsed_sec + self.correction_rad;
172
173 Self::normalize_angle(angle)
174 }
175
176 /// Returns the rotation angle of the prime meridian at the observer's
177 /// longitude, normalized to `[0, 2π)`.
178 ///
179 /// This is equivalent to `rotation_angle(mjd) + self.longitude_rad`.
180 /// It gives the angle between the Celestial Intermediate Origin (CIO)
181 /// and the observer’s local meridian.
182 ///
183 /// This value is commonly used when computing the local hour angle
184 /// of a celestial object:
185 ///
186 /// ```text
187 /// HA = local_rotation_angle(mjd) - RA
188 /// ```
189 ///
190 /// ## Example
191 ///
192 /// ```rust
193 /// use deep_time::Sidereal;
194 ///
195 /// let mut earth = Sidereal::EARTH;
196 /// earth.longitude_rad = 0.0; // Greenwich
197 ///
198 /// let mjd = 60000.0;
199 /// let local_era = earth.local_rotation_angle(mjd);
200 /// ```
201 #[inline]
202 pub const fn local_rotation_angle(&self, mjd: Real) -> Real {
203 Self::normalize_angle(self.rotation_angle(mjd) + self.longitude_rad)
204 }
205
206 /// Returns the sidereal angle of the body's prime meridian in radians,
207 /// normalized to `[0, 2π)`.
208 ///
209 /// This computes Greenwich Mean Sidereal Time (GMST) when an appropriate
210 /// Equation of the Origins value is supplied.
211 ///
212 /// ## Parameters
213 ///
214 /// - `eo_rad`: The Equation of the Origins value to subtract from the
215 /// Earth Rotation Angle (ERA).
216 /// - Pass `0.0` to get the pure CIO-based rotation angle (ERA).
217 /// - Pass the **mean** Equation of the Origins (e.g. from
218 /// [`earth_eo_mean`](Self::earth_eo_mean)) to obtain GMST.
219 ///
220 /// ## Details
221 ///
222 /// - When `eo_rad = 0.0`, the result is the modern Earth Rotation Angle (ERA)
223 /// relative to the Celestial Intermediate Origin (CIO).
224 ///
225 /// - When `eo_rad` is the mean Equation of the Origins (i.e. the value that
226 /// satisfies `GMST = ERA − eo_rad`), the result is Greenwich Mean Sidereal
227 /// Time (GMST) referred to the mean equinox. This is the traditional
228 /// equinox-based mean sidereal time.
229 ///
230 /// ## Example
231 ///
232 /// ```rust
233 /// use deep_time::Sidereal;
234 ///
235 /// let earth = Sidereal::EARTH;
236 /// let mjd = 60000.0;
237 ///
238 /// // Pure CIO-based rotation angle (Earth Rotation Angle)
239 /// let era = earth.sidereal_angle_mean(mjd, 0.0);
240 ///
241 /// // Traditional mean sidereal time using the mean Equation of the Origins
242 /// // convert to the mjd to tt if necessary
243 /// let eo_mean = earth.earth_eo_mean(mjd + 32.184 / 86400.0);
244 /// let gmst = earth.sidereal_angle_mean(mjd, eo_mean);
245 /// ```
246 #[inline]
247 pub const fn sidereal_angle_mean(&self, mjd: Real, eo_rad: Real) -> Real {
248 let angle = self.rotation_angle(mjd) - eo_rad;
249 Self::normalize_angle(angle)
250 }
251
252 /// Returns the local sidereal angle at the observer's longitude in radians,
253 /// normalized to `[0, 2π)`.
254 ///
255 /// This computes **Local Mean Sidereal Time (LMST)** when an appropriate
256 /// Equation of the Origins value is supplied.
257 ///
258 /// ## Parameters
259 ///
260 /// - `eo_rad`: The Equation of the Origins value to subtract from the
261 /// Earth Rotation Angle (ERA).
262 /// - Pass `0.0` to get the pure local Earth Rotation Angle (CIO-based).
263 /// - Pass the **mean** Equation of the Origins (e.g. from
264 /// [`earth_eo_mean`](Self::earth_eo_mean)) to obtain Local Mean
265 /// Sidereal Time (LMST).
266 ///
267 /// ## Details
268 ///
269 /// - When `eo_rad = 0.0`, the result is the local Earth Rotation Angle
270 /// relative to the Celestial Intermediate Origin (CIO) at the observer’s
271 /// longitude.
272 ///
273 /// - When `eo_rad` is the mean Equation of the Origins, the result is
274 /// **Local Mean Sidereal Time (LMST)** referred to the mean equinox.
275 ///
276 /// This value is commonly used when calculating the local hour angle of a
277 /// celestial object:
278 ///
279 /// ```text
280 /// HA = local_sidereal_angle_mean(mjd, eo) − RA
281 /// ```
282 ///
283 /// ## Example
284 ///
285 /// ```rust
286 /// use deep_time::Sidereal;
287 ///
288 /// let mut earth = Sidereal::EARTH;
289 /// earth.longitude_rad = 0.0; // Greenwich
290 ///
291 /// let mjd = 60000.0;
292 ///
293 /// // Pure local Earth Rotation Angle (CIO-based)
294 /// let local_era = earth.local_sidereal_angle_mean(mjd, 0.0);
295 ///
296 /// // Local Mean Sidereal Time using the mean Equation of the Origins
297 /// let eo_mean = earth.earth_eo_mean(mjd + 32.184 / 86400.0);
298 /// let lmst = earth.local_sidereal_angle_mean(mjd, eo_mean);
299 /// ```
300 #[inline]
301 pub const fn local_sidereal_angle_mean(&self, mjd: Real, eo_rad: Real) -> Real {
302 let angle = self.rotation_angle(mjd) + self.longitude_rad - eo_rad;
303 Self::normalize_angle(angle)
304 }
305
306 /// Returns sidereal time at the body's prime meridian as seconds since
307 /// sidereal midnight, wrapped to the range `[0, 86400)`.
308 ///
309 /// This is the time equivalent of [`sidereal_angle_mean`].
310 ///
311 /// ## Parameters
312 ///
313 /// - `eo_rad`: The Equation of the Origins value to use.
314 /// - Pass `0.0` to get the time equivalent of the pure Earth Rotation Angle (ERA).
315 /// - Pass the **mean** Equation of the Origins (e.g. from
316 /// [`earth_eo_mean`](Self::earth_eo_mean)) to obtain Greenwich Mean
317 /// Sidereal Time (GMST).
318 ///
319 /// ## Details
320 ///
321 /// - When `eo_rad = 0.0`, the result is the time equivalent of the modern
322 /// Earth Rotation Angle (ERA).
323 ///
324 /// - When `eo_rad` is the mean Equation of the Origins, the result is
325 /// **Greenwich Mean Sidereal Time (GMST)** referred to the mean equinox.
326 ///
327 /// As of Astropy 7.x, this is consistent with
328 /// `Time.sidereal_time("mean").to_value("sec")` (when no longitude is
329 /// specified) when using matching UT1 time and the mean Equation of the Origins.
330 ///
331 /// ## Example
332 ///
333 /// ```rust
334 /// use deep_time::Sidereal;
335 ///
336 /// let earth = Sidereal::EARTH;
337 /// let mjd = 60000.0;
338 ///
339 /// // Time equivalent of pure Earth Rotation Angle
340 /// let era_seconds = earth.sidereal_time_mean(mjd, 0.0);
341 ///
342 /// // Greenwich Mean Sidereal Time in seconds
343 /// let eo_mean = earth.earth_eo_mean(mjd + 32.184 / 86400.0);
344 /// let gmst_seconds = earth.sidereal_time_mean(mjd, eo_mean);
345 /// ```
346 pub const fn sidereal_time_mean(&self, mjd: Real, eo_rad: Real) -> Real {
347 let angle = self.sidereal_angle_mean(mjd, eo_rad);
348 let fraction = ((angle / TAU) % 1.0 + 1.0) % 1.0;
349 fraction * 86400.0
350 }
351
352 /// Returns local sidereal time at the observer's longitude as seconds since
353 /// sidereal midnight, wrapped to the range `[0, 86400)`.
354 ///
355 /// This is the time equivalent of [`local_sidereal_angle_mean`].
356 ///
357 /// ## Parameters
358 ///
359 /// - `eo_rad`: The Equation of the Origins value to use.
360 /// - Pass `0.0` to get the time equivalent of the local Earth Rotation Angle (CIO-based).
361 /// - Pass the **mean** Equation of the Origins (e.g. from
362 /// [`earth_eo_mean`](Self::earth_eo_mean)) to obtain **Local Mean Sidereal Time (LMST)**.
363 ///
364 /// ## Details
365 ///
366 /// - When `eo_rad = 0.0`, the result is the time equivalent of the local
367 /// Earth Rotation Angle relative to the Celestial Intermediate Origin (CIO)
368 /// at the observer’s longitude.
369 ///
370 /// - When `eo_rad` is the mean Equation of the Origins, the result is
371 /// **Local Mean Sidereal Time (LMST)** referred to the mean equinox.
372 ///
373 /// As of Astropy 7.x, this is consistent with
374 /// `Time.sidereal_time("mean", longitude=...).to_value("sec")` when using
375 /// matching UT1 time and the mean Equation of the Origins.
376 ///
377 /// ## Example
378 ///
379 /// ```rust
380 /// use deep_time::Sidereal;
381 ///
382 /// let mut earth = Sidereal::EARTH;
383 /// earth.longitude_rad = 0.0; // Greenwich
384 ///
385 /// let mjd = 60000.0;
386 ///
387 /// // Time equivalent of local Earth Rotation Angle
388 /// let local_era_seconds = earth.local_sidereal_time_mean(mjd, 0.0);
389 ///
390 /// // Local Mean Sidereal Time in seconds
391 /// let eo_mean = earth.earth_eo_mean(mjd + 32.184 / 86400.0);
392 /// let lmst_seconds = earth.local_sidereal_time_mean(mjd, eo_mean);
393 /// ```
394 pub const fn local_sidereal_time_mean(&self, mjd: Real, eo_rad: Real) -> Real {
395 let angle = self.local_sidereal_angle_mean(mjd, eo_rad);
396 let fraction = ((angle / TAU) % 1.0 + 1.0) % 1.0;
397 fraction * 86400.0
398 }
399
400 /// Returns the apparent sidereal angle of the body's prime meridian
401 /// in radians, normalized to `[0, 2π)`.
402 ///
403 /// This computes **Greenwich Apparent Sidereal Time (GAST)** when the
404 /// apparent Equation of the Origins is supplied.
405 ///
406 /// ## Parameters
407 ///
408 /// - `eo_rad`: The **apparent** Equation of the Origins
409 /// (e.g. from [`earth_eo_apparent`](Self::earth_eo_apparent)).
410 /// When supplied, the result is Greenwich Apparent Sidereal Time (GAST)
411 /// referred to the true equinox.
412 ///
413 /// ## Details
414 ///
415 /// This function implements the direct relationship:
416 ///
417 /// ```text
418 /// GAST = ERA − EO_apparent
419 /// ```
420 ///
421 /// As of Astropy 7.x, this is consistent with
422 /// `Time.sidereal_time("apparent").rad` (when no longitude is specified)
423 /// when using matching UT1 time and the apparent Equation of the Origins.
424 ///
425 /// ## Example
426 ///
427 /// ```rust
428 /// use deep_time::Sidereal;
429 ///
430 /// let earth = Sidereal::EARTH;
431 /// let mjd = 60000.0;
432 ///
433 /// // Greenwich Apparent Sidereal Time
434 /// let eo_app = earth.earth_eo_apparent(mjd + 32.184 / 86400.0);
435 /// let gast = earth.sidereal_angle_apparent(mjd, eo_app);
436 /// ```
437 pub const fn sidereal_angle_apparent(&self, mjd: Real, eo_rad: Real) -> Real {
438 let angle = self.rotation_angle(mjd) - eo_rad;
439 Self::normalize_angle(angle)
440 }
441
442 /// Returns the local apparent sidereal angle at the observer's longitude
443 /// in radians, normalized to `[0, 2π)`.
444 ///
445 /// This computes **Local Apparent Sidereal Time (LAST)** when the
446 /// apparent Equation of the Origins is supplied.
447 ///
448 /// ## Parameters
449 ///
450 /// - `eo_rad`: The **apparent** Equation of the Origins
451 /// (e.g. from [`earth_eo_apparent`](Self::earth_eo_apparent)).
452 /// When supplied, the result is Local Apparent Sidereal Time (LAST)
453 /// at the observer’s longitude, referred to the true equinox.
454 ///
455 /// ## Details
456 ///
457 /// This function implements the direct relationship:
458 ///
459 /// ```text
460 /// LAST = ERA + longitude − EO_apparent
461 /// ```
462 ///
463 /// As of Astropy 7.x, this is consistent with
464 /// `Time.sidereal_time("apparent", longitude=...).rad` when using
465 /// matching UT1 time and the apparent Equation of the Origins.
466 ///
467 /// ## Example
468 ///
469 /// ```rust
470 /// use deep_time::Sidereal;
471 ///
472 /// let mut earth = Sidereal::EARTH;
473 /// earth.longitude_rad = 0.0; // Greenwich
474 ///
475 /// let mjd = 60000.0;
476 ///
477 /// // Local Apparent Sidereal Time
478 /// let eo_app = earth.earth_eo_apparent(mjd + 32.184 / 86400.0);
479 /// let last = earth.local_sidereal_angle_apparent(mjd, eo_app);
480 /// ```
481 pub const fn local_sidereal_angle_apparent(&self, mjd: Real, eo_rad: Real) -> Real {
482 let angle = self.rotation_angle(mjd) + self.longitude_rad - eo_rad;
483 Self::normalize_angle(angle)
484 }
485
486 /// Returns apparent sidereal time at the body's prime meridian as seconds
487 /// since sidereal midnight, wrapped to the range `[0, 86400)`.
488 ///
489 /// This is the time equivalent of [`sidereal_angle_apparent`].
490 ///
491 /// When the **apparent** Equation of the Origins is supplied, this function
492 /// returns **Greenwich Apparent Sidereal Time (GAST)**.
493 ///
494 /// ## Parameters
495 ///
496 /// - `eo_rad`: The **apparent** Equation of the Origins
497 /// (e.g. from [`earth_eo_apparent`](Self::earth_eo_apparent)).
498 /// When supplied, the result is Greenwich Apparent Sidereal Time (GAST)
499 /// in seconds since sidereal midnight.
500 ///
501 /// ## Details
502 ///
503 /// This function computes:
504 ///
505 /// ```text
506 /// GAST (seconds) = (ERA − EO_apparent) in fractional days × 86400
507 /// ```
508 ///
509 /// As of Astropy 7.x, this is consistent with
510 /// `Time.sidereal_time("apparent").to_value("sec")` (Greenwich) when using
511 /// matching UT1 time and the apparent Equation of the Origins.
512 ///
513 /// ## Example
514 ///
515 /// ```rust
516 /// use deep_time::Sidereal;
517 ///
518 /// let earth = Sidereal::EARTH;
519 /// let mjd = 60000.0;
520 ///
521 /// // Greenwich Apparent Sidereal Time in seconds
522 /// let eo_app = earth.earth_eo_apparent(mjd + 32.184 / 86400.0);
523 /// let gast_seconds = earth.sidereal_time_apparent(mjd, eo_app);
524 /// ```
525 pub const fn sidereal_time_apparent(&self, mjd: Real, eo_rad: Real) -> Real {
526 let angle = self.sidereal_angle_apparent(mjd, eo_rad);
527 let fraction = ((angle / TAU) % 1.0 + 1.0) % 1.0;
528 fraction * 86400.0
529 }
530
531 /// Returns local apparent sidereal time at the observer's longitude as
532 /// seconds since sidereal midnight, wrapped to the range `[0, 86400)`.
533 ///
534 /// This is the time equivalent of [`local_sidereal_angle_apparent`].
535 ///
536 /// When the **apparent** Equation of the Origins is supplied, this function
537 /// returns **Local Apparent Sidereal Time (LAST)**.
538 ///
539 /// ## Parameters
540 ///
541 /// - `eo_rad`: The **apparent** Equation of the Origins
542 /// (e.g. from [`earth_eo_apparent`](Self::earth_eo_apparent)).
543 /// When supplied, the result is Local Apparent Sidereal Time (LAST)
544 /// at the observer’s longitude, in seconds since sidereal midnight.
545 ///
546 /// ## Details
547 ///
548 /// This function computes:
549 ///
550 /// ```text
551 /// LAST (seconds) = (ERA + longitude − EO_apparent) in fractional days × 86400
552 /// ```
553 ///
554 /// As of Astropy 7.x, this is consistent with
555 /// `Time.sidereal_time("apparent", longitude=...).to_value("sec")` when using
556 /// matching UT1 time and the apparent Equation of the Origins.
557 ///
558 /// ## Example
559 ///
560 /// ```rust
561 /// use deep_time::Sidereal;
562 ///
563 /// let mut earth = Sidereal::EARTH;
564 /// earth.longitude_rad = 0.0; // Greenwich
565 ///
566 /// let mjd = 60000.0;
567 ///
568 /// // Local Apparent Sidereal Time in seconds
569 /// let eo_app = earth.earth_eo_apparent(mjd + 32.184 / 86400.0);
570 /// let last_seconds = earth.local_sidereal_time_apparent(mjd, eo_app);
571 /// ```
572 pub const fn local_sidereal_time_apparent(&self, mjd: Real, eo_rad: Real) -> Real {
573 let angle = self.local_sidereal_angle_apparent(mjd, eo_rad);
574 let fraction = ((angle / TAU) % 1.0 + 1.0) % 1.0;
575 fraction * 86400.0
576 }
577
578 /// Returns the apparent Equation of the Origins (radians) at the given MJD.
579 ///
580 /// This returns the value computed by ERFA’s `eo06a`. It is the modern
581 /// CIO-based quantity used to derive **Greenwich Apparent Sidereal Time (GAST)**
582 /// from the Earth Rotation Angle (ERA).
583 ///
584 /// When you subtract this value from the ERA, you get GAST:
585 ///
586 /// ```text
587 /// GAST = ERA − earth_eo_apparent(...)
588 /// ```
589 ///
590 /// This method is equivalent to calling `erfa.eo06a(tt.jd1, tt.jd2)` in Astropy.
591 ///
592 /// You should pass the value returned by this function to the apparent
593 /// sidereal time functions (`sidereal_angle_apparent`, `local_sidereal_angle_apparent`,
594 /// `sidereal_time_apparent`, and `local_sidereal_time_apparent`).
595 ///
596 /// # Example
597 ///
598 /// ```rust
599 /// use deep_time::Sidereal;
600 ///
601 /// let earth = Sidereal::EARTH;
602 /// let mjd_tt = 60000.0 + 32.184 / 86400.0;
603 ///
604 /// let eo_app = earth.earth_eo_apparent(mjd_tt);
605 /// let gast = earth.sidereal_angle_apparent(mjd_tt, eo_app);
606 /// ```
607 #[cfg(feature = "sidereal-earth")]
608 #[inline]
609 pub const fn earth_eo_apparent(&self, tt_mjd: Real) -> Real {
610 // Convert MJD → two-part Julian Date
611 let date1 = 2400000.5 + tt_mjd;
612 earth_eo(date1, 0.0)
613 }
614
615 /// Returns the mean Equation of the Origins (radians) at the given MJD.
616 ///
617 /// This returns the value that should be subtracted from the Earth Rotation
618 /// Angle (ERA) to obtain **Greenwich Mean Sidereal Time (GMST)**:
619 ///
620 /// ```text
621 /// GMST = ERA − earth_eo_mean(...)
622 /// ```
623 ///
624 /// Internally, this is computed as:
625 ///
626 /// ```text
627 /// earth_eo_mean = earth_eo_apparent() + earth_ee()
628 /// ```
629 ///
630 /// This is equivalent to computing `era - gmst` in Astropy:
631 ///
632 /// ```python
633 /// era = ut1.earth_rotation_angle(...).rad
634 /// gmst = ut1.sidereal_time("mean", ...).rad
635 /// eo_mean = era - gmst
636 /// ```
637 ///
638 /// You should pass the value returned by this function to the mean
639 /// sidereal time functions (`sidereal_angle_mean`, `local_sidereal_angle_mean`,
640 /// `sidereal_time_mean`, and `local_sidereal_time_mean`).
641 ///
642 /// # Example
643 ///
644 /// ```rust
645 /// use deep_time::Sidereal;
646 ///
647 /// let earth = Sidereal::EARTH;
648 /// let mjd_tt = 60000.0 + 32.184 / 86400.0;
649 ///
650 /// let eo_mean = earth.earth_eo_mean(mjd_tt);
651 /// let gmst = earth.sidereal_angle_mean(mjd_tt, eo_mean);
652 /// ```
653 #[cfg(feature = "sidereal-earth")]
654 #[inline]
655 pub const fn earth_eo_mean(&self, tt_mjd: Real) -> Real {
656 // Convert MJD → two-part Julian Date
657 let date1 = 2400000.5 + tt_mjd;
658 earth_eo(date1, 0.0) + earth_ee(date1, 0.0)
659 }
660
661 /// Returns the Equation of the Equinoxes (radians) at the given MJD.
662 ///
663 /// This returns the value computed by ERFA’s `ee06a`. The Equation of the
664 /// Equinoxes represents the nutation contribution to sidereal time and is
665 /// defined as:
666 ///
667 /// ```text
668 /// EE = GAST − GMST
669 /// ```
670 ///
671 /// It is equivalent to computing `gast - gmst` in Astropy:
672 ///
673 /// ```python
674 /// gast = ut1.sidereal_time("apparent", ...).rad
675 /// gmst = ut1.sidereal_time("mean", ...).rad
676 /// ee = gast - gmst
677 /// ```
678 ///
679 /// This value is used internally when converting between mean and apparent
680 /// sidereal time (for example, when the mean functions are given the apparent
681 /// EO + EE).
682 ///
683 /// # Example
684 ///
685 /// ```rust
686 /// use deep_time::Sidereal;
687 ///
688 /// let earth = Sidereal::EARTH;
689 /// let mjd_tt = 60000.0 + 32.184 / 86400.0;
690 ///
691 /// let ee = earth.earth_ee(mjd_tt);
692 /// ```
693 #[cfg(feature = "sidereal-earth")]
694 #[inline]
695 pub const fn earth_ee(&self, tt_mjd: Real) -> Real {
696 // Convert MJD → two-part Julian Date
697 let date1 = 2400000.5 + tt_mjd;
698 earth_ee(date1, 0.0)
699 }
700}