extern crate bacon_sci;
extern crate crossbeam;
extern crate csv;
extern crate rayon;
use crate::errors::NyxError;
use crate::io::formatter::StateFormatter;
use crate::{Orbit, SpacecraftState};
use std::fs::File;
use std::str::FromStr;
pub mod ui;
pub mod trajectory;
mod events;
pub use events::{Event, EventEvaluator};
pub type ScTraj = trajectory::Traj<SpacecraftState>;
pub type Ephemeris = trajectory::Traj<Orbit>;
pub trait MdHdlr<StateType: Copy>: Send + Sync {
fn handle(&mut self, state: &StateType);
}
pub struct OrbitStateOutput {
csv_out: csv::Writer<File>,
fmtr: StateFormatter,
}
impl OrbitStateOutput {
pub fn new(fmtr: StateFormatter) -> Result<Self, NyxError> {
match csv::Writer::from_path(fmtr.filename.clone()) {
Ok(mut wtr) => {
wtr.serialize(&fmtr.headers)
.expect("could not write headers");
info!("Saving output to {}", fmtr.filename);
Ok(Self { csv_out: wtr, fmtr })
}
Err(e) => Err(NyxError::ExportError(e.to_string())),
}
}
}
impl MdHdlr<SpacecraftState> for OrbitStateOutput {
fn handle(&mut self, state: &SpacecraftState) {
self.csv_out
.serialize(self.fmtr.fmt(&state.orbit))
.expect("could not format state");
}
}
impl MdHdlr<Orbit> for OrbitStateOutput {
fn handle(&mut self, state: &Orbit) {
self.csv_out
.serialize(self.fmtr.fmt(&state))
.expect("could not format state");
}
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum StateParameter {
AoL,
AoP,
Apoapsis,
ApoapsisRadius,
Declination,
Epoch,
EccentricAnomaly,
Eccentricity,
Energy,
FuelMass,
GeodeticHeight,
GeodeticLatitude,
GeodeticLongitude,
Hmag,
HX,
HY,
HZ,
Inclination,
MeanAnomaly,
Periapsis,
PeriapsisRadius,
Period,
RightAscension,
RAAN,
Rmag,
SemiParameter,
SMA,
SemiMinorAxis,
TrueAnomaly,
TrueLongitude,
Vmag,
X,
Y,
Z,
VX,
VY,
VZ,
Custom { mapping: usize },
}
impl StateParameter {
pub fn default_event_precision(self) -> f64 {
match self {
Self::Eccentricity => 1e-5,
Self::AoL
| Self::AoP
| Self::Declination
| Self::GeodeticLatitude
| Self::GeodeticLongitude
| Self::Inclination
| Self::RightAscension
| Self::RAAN
| Self::TrueLongitude => 1e-1,
Self::Apoapsis
| Self::Periapsis
| Self::MeanAnomaly
| Self::EccentricAnomaly
| Self::TrueAnomaly => 1e-3,
Self::ApoapsisRadius
| Self::GeodeticHeight
| Self::Hmag
| Self::HX
| Self::HY
| Self::HZ
| Self::PeriapsisRadius
| Self::Rmag
| Self::SemiParameter
| Self::SMA
| Self::SemiMinorAxis
| Self::X
| Self::Y
| Self::Z => 1e-3,
Self::VX | Self::VY | Self::VZ | Self::Vmag => 1e-3,
Self::Energy => 1e-3,
Self::FuelMass => 1e-3,
Self::Period => 1e-1,
_ => unimplemented!(),
}
}
}
impl FromStr for StateParameter {
type Err = NyxError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let keyword = s.trim().to_lowercase();
match keyword.as_str() {
"apoapsis" => Ok(Self::Apoapsis),
"periapsis" => Ok(Self::Periapsis),
"aol" => Ok(Self::AoL),
"aop" => Ok(Self::AoP),
"declin" => Ok(Self::Declination),
"apoapsis_radius" => Ok(Self::ApoapsisRadius),
"ea" => Ok(Self::EccentricAnomaly),
"ecc" => Ok(Self::Eccentricity),
"energy" => Ok(Self::Energy),
"fuel_mass" => Ok(Self::FuelMass),
"geodetic_height" => Ok(Self::GeodeticHeight),
"geodetic_latitude" => Ok(Self::GeodeticLatitude),
"geodetic_longitude" => Ok(Self::GeodeticLongitude),
"hmag" => Ok(Self::Hmag),
"hx" => Ok(Self::HX),
"hy" => Ok(Self::HY),
"hz" => Ok(Self::HZ),
"inc" => Ok(Self::Inclination),
"ma" => Ok(Self::MeanAnomaly),
"periapsis_radius" => Ok(Self::PeriapsisRadius),
"period" => Ok(Self::Period),
"right_asc" => Ok(Self::RightAscension),
"raan" => Ok(Self::RAAN),
"rmag" => Ok(Self::Rmag),
"semi_parameter" => Ok(Self::SemiParameter),
"semi_minor" => Ok(Self::SemiMinorAxis),
"sma" => Ok(Self::SMA),
"ta" => Ok(Self::TrueAnomaly),
"tlong" => Ok(Self::TrueLongitude),
"vmag" => Ok(Self::Vmag),
"x" => Ok(Self::X),
"y" => Ok(Self::Y),
"z" => Ok(Self::Z),
"vx" => Ok(Self::VX),
"vy" => Ok(Self::VY),
"vz" => Ok(Self::VZ),
_ => Err(NyxError::LoadingError(format!(
"Unknown state parameter: {}",
s
))),
}
}
}