1pub mod almanac;
17pub mod angles;
18pub mod anomaly;
19pub mod apparent;
20pub mod atmosphere;
21pub mod bodies;
22pub mod cdm;
23pub mod conjunction;
24pub mod constants;
25pub mod covariance;
26pub mod coverage;
27pub mod data;
28pub mod doppler;
29pub mod elements;
30pub mod equinoctial;
31pub mod error;
32pub mod events;
33pub mod forces;
34pub mod frames;
35pub mod integrators;
36pub mod iod;
37pub mod lambert;
38pub mod math;
39pub mod ndm;
40pub mod observation;
41pub mod oem;
42pub mod omm;
43pub mod opm;
44pub mod passes;
45pub mod propagator;
46pub mod relative;
47pub mod rf;
48pub mod sgp4;
49pub mod space_weather;
50pub mod spk;
51pub mod state;
52pub mod tca;
53pub mod time;
54pub mod tle;
55pub mod tolerances;
56pub mod xml;
57
58pub use spk::{
59 DafByteOrder, DafFileRecord, DafSpk, Spk, SpkError, SpkSegmentDescriptor, SpkState,
60 SpkStateVector,
61};
62
63#[cfg(all(feature = "sgp4-debug-oracle", sgp4_oracle_built))]
64#[doc(hidden)]
65pub mod sgp4_cpp_oracle {
66 use std::os::raw::{c_char, c_double, c_int};
72
73 pub const CPP_DUMP_DOUBLE_COUNT: usize = 112;
74 pub const CPP_DUMP_INT_COUNT: usize = 5;
75
76 extern "C" {
77 pub fn cpp_sgp4init_dump(
78 satnum: *const c_char,
79 opsmode: c_char,
80 epoch_sgp4: c_double,
81 bstar: c_double,
82 ndot: c_double,
83 nddot: c_double,
84 ecco: c_double,
85 argpo: c_double,
86 inclo: c_double,
87 mo: c_double,
88 no_kozai: c_double,
89 nodeo: c_double,
90 epochyr: c_int,
91 epochdays: c_double,
92 jdsatepoch: c_double,
93 jdsatepoch_frac: c_double,
94 double_out: *mut c_double,
95 int_out: *mut c_int,
96 ) -> c_int;
97
98 pub fn cpp_sgp4_step(
99 satnum: *const c_char,
100 opsmode: c_char,
101 epoch_sgp4: c_double,
102 bstar: c_double,
103 ndot: c_double,
104 nddot: c_double,
105 ecco: c_double,
106 argpo: c_double,
107 inclo: c_double,
108 mo: c_double,
109 no_kozai: c_double,
110 nodeo: c_double,
111 epochyr: c_int,
112 epochdays: c_double,
113 jdsatepoch: c_double,
114 jdsatepoch_frac: c_double,
115 tsince: c_double,
116 r_out: *mut c_double,
117 v_out: *mut c_double,
118 ) -> c_int;
119 }
120
121 #[doc(hidden)]
125 pub fn force_link_oracle() -> usize {
126 let init_dump = cpp_sgp4init_dump as *const ();
127 let step = cpp_sgp4_step as *const ();
128
129 init_dump as usize ^ step as usize
130 }
131}
132
133#[cfg(all(feature = "sgp4-debug-oracle", sgp4_oracle_built))]
134pub use sgp4_cpp_oracle::cpp_sgp4_step;
135
136pub use anomaly::{
137 eccentric_to_mean, eccentric_to_true, mean_to_eccentric, mean_to_true, propagate_kepler,
138 solve_kepler, true_to_eccentric, true_to_mean, AnomalyError, KeplerSolution,
139};
140pub use elements::{coe2rv, rv2coe, ClassicalElements, ElementsError, OrbitType};
141pub use equinoctial::{
142 coe2eq, coe2mee, eq2coe, eq2mee, eq2rv, mee2coe, mee2eq, mee2rv, rv2eq, rv2mee,
143 EquinoctialElements, EquinoctialError, ModifiedEquinoctialElements, RetrogradeFactor,
144};
145pub use error::PropagationError;
146pub use state::CartesianState;
147pub use time::Time;
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use crate::astro::forces::TwoBodyGravity;
153 use crate::astro::integrators::{Integrator, DP54};
154 use crate::astro::propagator::{api::IntegratorOptions, OrbitalDynamics, PropagationContext};
155 use nalgebra::Vector3;
156
157 #[test]
158 fn test_two_body_dp54_precision() {
159 let r_mag: f64 = 7000.0;
160 let mu: f64 = 398600.4418;
161 let v_mag: f64 = (mu / r_mag).sqrt();
162 let initial_state = CartesianState {
163 epoch_tdb_seconds: 0.0,
164 position_km: Vector3::new(r_mag, 0.0, 0.0),
165 velocity_km_s: Vector3::new(0.0, v_mag, 0.0),
166 };
167
168 let force = TwoBodyGravity::default();
169 let dynamics = OrbitalDynamics {
170 force_model: &force,
171 };
172 let integrator = DP54;
173 let ctx = PropagationContext::default();
174 let opts = IntegratorOptions {
175 abs_tol: 1e-12,
176 rel_tol: 1e-12,
177 initial_step: 1.0,
178 min_step: 1e-15,
179 ..IntegratorOptions::default()
180 };
181
182 let period = 2.0 * std::f64::consts::PI * (r_mag.powi(3) / mu).sqrt();
183 let result = integrator
184 .propagate(initial_state, period, &dynamics, &ctx, &opts)
185 .unwrap();
186
187 let final_pos = result.final_state.position_km;
188 let final_vel = result.final_state.velocity_km_s;
189
190 assert!(
192 (final_pos.x - r_mag).abs() < 1e-7,
193 "Position X error too large: {}",
194 (final_pos.x - r_mag).abs()
195 );
196 assert!(
197 final_pos.y.abs() < 1e-7,
198 "Position Y error too large: {}",
199 final_pos.y.abs()
200 );
201
202 let initial_energy = v_mag.powi(2) / 2.0 - mu / r_mag;
204 let final_v_mag = final_vel.norm();
205 let final_r_mag = final_pos.norm();
206 let final_energy = final_v_mag.powi(2) / 2.0 - mu / final_r_mag;
207 assert!(
208 (final_energy - initial_energy).abs() < 1e-10,
209 "Energy conservation failure: {}",
210 (final_energy - initial_energy).abs()
211 );
212 }
213}