1#![doc = include_str!("./README.md")]
2extern crate log;
3extern crate nyx_space as nyx;
4extern crate pretty_env_logger as pel;
5
6use anise::{
7 almanac::metaload::MetaFile,
8 constants::{
9 celestial_objects::{MOON, SUN},
10 frames::{EARTH_J2000, IAU_EARTH_FRAME, MOON_J2000},
11 },
12};
13use hifitime::{Epoch, Unit};
14use nyx::{
15 cosmic::{eclipse::EclipseLocator, Mass, MetaAlmanac, Orbit, SRPData},
16 dynamics::{Harmonics, OrbitalDynamics, SolarPressure, SpacecraftDynamics},
17 io::{gravity::HarmonicsMem, ExportCfg},
18 propagators::Propagator,
19 Spacecraft, State,
20};
21use polars::{df, prelude::ParquetWriter};
22
23use std::fs::File;
24use std::{error::Error, sync::Arc};
25
26fn main() -> Result<(), Box<dyn Error>> {
27 pel::init();
28 let almanac = Arc::new(MetaAlmanac::latest().map_err(Box::new)?);
38 let epoch = Epoch::from_gregorian_utc_hms(2024, 2, 29, 12, 13, 14);
40
41 let earth_j2000 = almanac.frame_from_uid(EARTH_J2000)?;
47
48 let orbit = Orbit::try_keplerian(42164.0, 1e-5, 0., 163.0, 75.0, 0.0, epoch, earth_j2000)?;
51 println!("{orbit:x}");
53
54 let state_bf = almanac.transform_to(orbit, IAU_EARTH_FRAME, None)?;
55 let (orig_lat_deg, orig_long_deg, orig_alt_km) = state_bf.latlongalt()?;
56
57 let sc = Spacecraft::builder()
63 .orbit(orbit)
64 .mass(Mass::from_dry_mass(9.60))
65 .srp(SRPData {
66 area_m2: 10e-4,
67 coeff_reflectivity: 1.1,
68 })
69 .build();
70 println!("{sc:x}");
71
72 let mut orbital_dyn = OrbitalDynamics::point_masses(vec![MOON, SUN]);
77
78 let mut jgm3_meta = MetaFile {
81 uri: "http://public-data.nyxspace.com/nyx/models/JGM3.cof.gz".to_string(),
82 crc32: Some(0xF446F027), };
84 jgm3_meta.process(true)?;
86
87 let harmonics_21x21 = Harmonics::from_stor(
91 almanac.frame_from_uid(IAU_EARTH_FRAME)?,
92 HarmonicsMem::from_cof(&jgm3_meta.uri, 21, 21, true).unwrap(),
93 );
94
95 orbital_dyn.accel_models.push(harmonics_21x21);
97
98 let srp_dyn = SolarPressure::new(vec![EARTH_J2000, MOON_J2000], almanac.clone())?;
101
102 let dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn);
105
106 println!("{dynamics}");
107
108 let (future_sc, trajectory) = Propagator::default(dynamics)
112 .with(sc, almanac.clone())
113 .until_epoch_with_traj(epoch + Unit::Century * 0.03)?;
114
115 println!("=== High fidelity propagation ===");
116 println!(
117 "SMA changed by {:.3} km",
118 orbit.sma_km()? - future_sc.orbit.sma_km()?
119 );
120 println!(
121 "ECC changed by {:.6}",
122 orbit.ecc()? - future_sc.orbit.ecc()?
123 );
124 println!(
125 "INC changed by {:.3e} deg",
126 orbit.inc_deg()? - future_sc.orbit.inc_deg()?
127 );
128 println!(
129 "RAAN changed by {:.3} deg",
130 orbit.raan_deg()? - future_sc.orbit.raan_deg()?
131 );
132 println!(
133 "AOP changed by {:.3} deg",
134 orbit.aop_deg()? - future_sc.orbit.aop_deg()?
135 );
136 println!(
137 "TA changed by {:.3} deg",
138 orbit.ta_deg()? - future_sc.orbit.ta_deg()?
139 );
140
141 println!("{trajectory}");
143
144 println!("Spacecraft params after 3 years without active control:\n{future_sc:x}");
145
146 let analysis_step = Unit::Minute * 5;
151
152 trajectory.to_parquet(
153 "./03_geo_hf_prop.parquet",
154 Some(vec![
155 &EclipseLocator::cislunar(almanac.clone()).to_penumbra_event()
156 ]),
157 ExportCfg::builder().step(analysis_step).build(),
158 almanac.clone(),
159 )?;
160
161 let mut offset_s = vec![];
165 let mut epoch_str = vec![];
166 let mut longitude_deg = vec![];
167 let mut latitude_deg = vec![];
168 let mut altitude_km = vec![];
169
170 for state in trajectory.every(analysis_step) {
171 let this_epoch = state.epoch();
175
176 offset_s.push((this_epoch - orbit.epoch).to_seconds());
177 epoch_str.push(this_epoch.to_isoformat());
178
179 let state_bf = almanac.transform_to(state.orbit, IAU_EARTH_FRAME, None)?;
180 let (lat_deg, long_deg, alt_km) = state_bf.latlongalt()?;
181 longitude_deg.push(long_deg);
182 latitude_deg.push(lat_deg);
183 altitude_km.push(alt_km);
184 }
185
186 println!(
187 "Longitude changed by {:.3} deg -- Box is 0.1 deg E-W",
188 orig_long_deg - longitude_deg.last().unwrap()
189 );
190
191 println!(
192 "Latitude changed by {:.3} deg -- Box is 0.05 deg N-S",
193 orig_lat_deg - latitude_deg.last().unwrap()
194 );
195
196 println!(
197 "Altitude changed by {:.3} km -- Box is 30 km",
198 orig_alt_km - altitude_km.last().unwrap()
199 );
200
201 let mut sk_df = df!(
203 "Offset (s)" => offset_s.clone(),
204 "Epoch (UTC)" => epoch_str.clone(),
205 "Longitude E-W (deg)" => longitude_deg,
206 "Latitude N-S (deg)" => latitude_deg,
207 "Altitude (km)" => altitude_km,
208
209 )?;
210
211 let file = File::create("./03_geo_lla.parquet").expect("Could not create file");
213
214 ParquetWriter::new(file).finish(&mut sk_df)?;
216
217 Ok(())
218}