1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! # empyrean
//!
//! High-precision Solar System dynamics — trajectory propagation,
//! ephemeris generation, orbit determination, and event analysis
//! (close approaches, occultations, eclipses, sphere-of-influence
//! crossings) for real Solar System bodies.
//!
//! Safe Rust wrapper over `empyrean-sys`. Use this crate to propagate
//! orbits, generate ephemerides, and determine orbits from observations
//! without writing `unsafe` code.
//!
//! ## Standard workflow
//!
//! Pull an orbit from JPL SBDB, propagate it forward, generate
//! ephemerides at an observatory, and inspect detected events:
//!
//! ```no_run
//! use empyrean::{Context, EphemerisConfig, Frame, Origin, PropagationConfig};
//!
//! let ctx = Context::from_data_dir(None)?;
//!
//! // 1. Pull Apophis from SBDB (CometaryCoordinates with covariance).
//! let batch = empyrean::query_sbdb(&["99942"], None)?;
//!
//! // 2. Propagate 10 years past the SBDB epoch.
//! let cfg = PropagationConfig::default();
//! let t0 = batch.orbits[0].state.epoch.mjd_tdb()?;
//! let epochs = vec![empyrean::Epoch::from_mjd_tdb(t0 + 10.0 * 365.25)];
//! let result = ctx.propagate(&batch.orbits, &epochs, &cfg)?;
//! println!("{} states, {} events", result.states.len(), result.events.len());
//!
//! // 3. Predict on-sky positions at Mauna Kea (MPC code 568).
//! let observers = ctx.get_observers(&["568"], &epochs, Frame::ICRF, Origin::SSB)?;
//! let eph_cfg = EphemerisConfig::default();
//! let eph = ctx.generate_ephemeris(&batch.orbits, &observers, &eph_cfg)?;
//! # Ok::<(), empyrean::Error>(())
//! ```
//!
//! For close-approach analysis (impact probability, B-plane geometry),
//! see [`Context::compute_impact_probabilities`] and
//! [`Context::compute_b_planes`]. For OD from astrometric
//! observations, see [`Context::determine`] and the [`Session`] type
//! for interactive masking workflows.
//!
//! ## Coordinate transform
//!
//! ```no_run
//! use empyrean::{Context, CoordinateState, Frame, Origin, Representation};
//!
//! let ctx = Context::from_data_dir(None)?;
//! let input = CoordinateState::cometary(
//! empyrean::Epoch::from_mjd_tdb(60200.0),
//! [0.7461, 0.1914, 3.339, 204.446, 126.687, 60159.0],
//! Frame::EclipticJ2000,
//! Origin::SUN,
//! );
//! let cart =
//! ctx.transform_coordinates_single(&input, Representation::Cartesian, Frame::ICRF, Origin::SUN)?;
//! println!("x = {:.6} AU", cart.elements[0]);
//! # Ok::<(), empyrean::Error>(())
//! ```
//!
//! ## Quick reference
//!
//! | You want… | API |
//! |----------------------------------------|--------------------------------------------------|
//! | Propagate orbits to target epochs | [`Context::propagate`] |
//! | Predict observations at observatories | [`Context::generate_ephemeris`] |
//! | Fit an orbit to observations | [`Context::determine`] |
//! | Re-fit with a Bayesian prior | [`Context::refine`] |
//! | Residuals only — no fit | [`Context::evaluate`] |
//! | Stateful, mask-and-refit OD | [`Session`] |
//! | Impact probability | [`Context::compute_impact_probabilities`] |
//! | B-plane geometry | [`Context::compute_b_planes`] |
//! | Rank candidate follow-up observations | [`Context::evaluate_plan`] |
//! | Convert between coordinate types | [`Context::transform_coordinates`] (batch) / [`Context::transform_coordinates_single`] |
//! | Body / observer states | [`Context::get_states`] / [`Context::get_observers`] |
//! | Pull an orbit from JPL SBDB | [`query_sbdb`] |
//! | Pull predicted ephemeris from Horizons | [`query_horizons`] |
//! | Pull SSB state vectors from Horizons | [`query_horizons_vectors`] |
//! | Pull observations from MPC | [`query_observations`] |
//! | Pull radar astrometry from JPL | [`query_radar`] |
//! | Read ADES PSV observations | [`Context::read_ades`] |
//! | Default data directory | [`default_data_dir`] |
//!
//! ## Conventions
//!
//! - **Distances** in AU; **velocities** in AU/day; **angles** in
//! **degrees** at the API boundary (radians internally).
//! - **Epochs** are MJD on the **TDB** scale unless otherwise stated.
//! See [`time::Epoch`] for time-scale-aware values and
//! [`time::iso_to_mjd`] / [`time::mjd_to_iso`] for ISO 8601 interop.
//! - **Default integrator** is
//! [`IntegratorChoice::GR15`] (median Horizons error ≈ 35 m).
//! Switch to [`IntegratorChoice::DOP853`] via
//! [`AdvancedIntegratorConfig::integrator`] for ~1.4× speed at the
//! cost of ~10× position error.
//! - **Default frame** for propagation output is
//! [`Frame::EclipticJ2000`] (the integration frame); set
//! [`PropagationConfig::frame`] to [`Frame::ICRF`] for ICRF output.
// Public because [`propagate::MixtureComponent`] cannot be flattened to
// the crate root: [`MixtureComponent`] there is already the
// `split_gaussian` primitive (see the `pub use math::` line below), and
// renaming either one would break the API-parity rule against
// `empyrean_core::propagation::MixtureComponent`. Every other name in
// here is also re-exported at the root, so the module adds exactly the
// two mixture read-back types plus a second path to what the root
// already exposes.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// NAME COLLISION, resolved by module path. This root `MixtureComponent`
// is the `split_gaussian` primitive at t₀ (weight / mean / covariance,
// no basis tags). The AGM *read-back* component — the basis-tagged one
// named after `empyrean_core::propagation::MixtureComponent` — is
// [`propagate::MixtureComponent`] and is deliberately NOT re-exported
// here: flattening both names to the root would need one of them
// renamed away from the core name the parity rule pins.
pub use ;
pub use Observer;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use State;
pub use ;
pub use ;
pub use ;
// Compile the Rust examples in both READMEs as doctests under
// `cargo test --doc` so they cannot rot against the public API. The
// `cfg(doctest)` gate keeps these synthetic structs out of the public
// rustdoc — they exist only during doc-test compilation. `../README.md`
// is the crate (crates.io) README; `../../README.md` is the top-level
// workspace README.
;
;