#![doc = include_str!("./README.md")]
extern crate log;
extern crate nyx_space as nyx;
extern crate pretty_env_logger as pel;
use anise::{
almanac::metaload::MetaFile,
constants::{
celestial_objects::{MOON, SUN},
frames::{EARTH_J2000, IAU_EARTH_FRAME},
},
};
use hifitime::{Epoch, TimeUnits, Unit};
use nyx::{
cosmic::{eclipse::EclipseLocator, GuidanceMode, MetaAlmanac, Orbit, SrpConfig},
dynamics::{
guidance::{Ruggiero, Thruster},
Harmonics, OrbitalDynamics, SolarPressure, SpacecraftDynamics,
},
io::{gravity::HarmonicsMem, ExportCfg},
mc::{MonteCarlo, MultivariateNormal, StateDispersion},
md::{prelude::Objective, StateParameter},
propagators::{ErrorControl, IntegratorOptions, Propagator},
Spacecraft, State,
};
use std::{error::Error, sync::Arc};
fn main() -> Result<(), Box<dyn Error>> {
pel::init();
let almanac = Arc::new(MetaAlmanac::latest().map_err(Box::new)?);
let epoch = Epoch::from_gregorian_utc_hms(2024, 2, 29, 12, 13, 14);
let earth_j2000 = almanac.frame_from_uid(EARTH_J2000)?;
let orbit = Orbit::try_keplerian(42164.0, 1e-5, 0., 163.0, 75.0, 0.0, epoch, earth_j2000)?;
println!("{orbit:x}");
let sc = Spacecraft::builder()
.orbit(orbit)
.dry_mass_kg(1000.0) .fuel_mass_kg(1000.0) .srp(SrpConfig::from_area(3.0 * 6.0)) .thruster(Thruster {
isp_s: 4435.0,
thrust_N: 0.472,
})
.mode(GuidanceMode::Thrust) .build();
let prop_time = 30.0 * Unit::Day;
let objectives = &[
Objective::within_tolerance(StateParameter::SMA, 42_164.0, 5.0), Objective::within_tolerance(StateParameter::Eccentricity, 0.001, 5e-5),
Objective::within_tolerance(StateParameter::Inclination, 0.05, 1e-2),
];
let ruggiero_ctrl = Ruggiero::from_max_eclipse(objectives, sc, 0.2)?;
println!("{ruggiero_ctrl}");
let mut orbital_dyn = OrbitalDynamics::point_masses(vec![MOON, SUN]);
let mut jgm3_meta = MetaFile {
uri: "http://public-data.nyxspace.com/nyx/models/JGM3.cof.gz".to_string(),
crc32: Some(0xF446F027), };
jgm3_meta.process(true)?;
let harmonics = Harmonics::from_stor(
almanac.frame_from_uid(IAU_EARTH_FRAME)?,
HarmonicsMem::from_cof(&jgm3_meta.uri, 8, 8, true)?,
);
orbital_dyn.accel_models.push(harmonics);
let srp_dyn = SolarPressure::default(EARTH_J2000, almanac.clone())?;
let sc_dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn)
.with_guidance_law(ruggiero_ctrl.clone());
println!("{sc_dynamics}");
let mc_rv = MultivariateNormal::new(
sc,
vec![StateDispersion::zero_mean(StateParameter::SMA, 3.0)],
)?;
let my_mc = MonteCarlo::new(
sc, mc_rv,
"03_geo_sk".to_string(), None, );
let setup = Propagator::rk89(
sc_dynamics.clone(),
IntegratorOptions::builder()
.min_step(10.0_f64.seconds())
.error_ctrl(ErrorControl::RSSCartesianStep)
.build(),
);
let num_runs = 25;
let rslts = my_mc.run_until_epoch(setup, almanac.clone(), sc.epoch() + prop_time, num_runs);
assert_eq!(rslts.runs.len(), num_runs);
rslts.to_parquet(
"03_geo_sk.parquet",
Some(vec![
&EclipseLocator::cislunar(almanac.clone()).to_penumbra_event()
]),
ExportCfg::default(),
almanac,
)?;
Ok(())
}