use astrodyn::{
GravityControl, GravityControls, GravityGradient, GravityModel, GravitySource,
GravitySourceEntry, IntegratorType, Position, RootInertial, RotationModel, SimulationTime,
TranslationalStateTyped, VehicleConfig, Velocity, EARTH,
};
use astrodyn_runner::Simulation;
use glam::DVec3;
fn earth_central_source() -> GravitySourceEntry {
GravitySourceEntry {
source: GravitySource {
mu: EARTH.shape.mu,
model: GravityModel::PointMass,
},
position: Position::<RootInertial>::zero(),
velocity: Velocity::<RootInertial>::zero(),
t_inertial_pfix: Some(glam::DMat3::IDENTITY),
rotation_model: RotationModel::None,
delta_c20: 0.0,
tidal_config: None,
planet_omega: 0.0,
central: true,
marker_only: false,
}
}
fn leo_body_config(
integ_source: Option<astrodyn::FrameUid>,
gravity_source: astrodyn::FrameUid,
) -> VehicleConfig {
let altitude_m = 700_000.0;
let radius_m = EARTH.shape.r_eq() + altitude_m;
let speed_m_s = 7_504.567; let mut cfg = VehicleConfig {
trans: TranslationalStateTyped::<RootInertial> {
position: Position::<RootInertial>::from_raw_si(DVec3::new(radius_m, 0.0, 0.0)),
velocity: Velocity::<RootInertial>::from_raw_si(DVec3::new(0.0, speed_m_s, 0.0)),
},
integrator: IntegratorType::Rk4,
gravity_controls: GravityControls {
controls: vec![GravityControl::new_spherical(
gravity_source,
GravityGradient::Skip,
)],
},
..VehicleConfig::named("central-source-integ-frame-0")
};
cfg.integ_source = integ_source;
cfg.derived.orbital_elements_source = Some(cfg.gravity_controls.controls[0].source.clone());
cfg
}
#[test]
fn root_frame_is_named_root_and_central_source_has_distinct_inertial() {
let time = SimulationTime::at_j2000(astrodyn::default_leap_second_table());
let mut sim = Simulation::new(time, 1.0);
assert_eq!(
sim.frame_tree().get(sim.root_frame_id).name,
"root",
"root frame should be named \"root\" (neutral), not aliased to any planet"
);
let earth_idx = sim.add_source("Earth", earth_central_source());
let earth_inertial = sim.source_inertial_frame_id(earth_idx);
assert_ne!(
earth_inertial, sim.root_frame_id,
"post-#567 the central source's inertial frame must be a distinct child of root"
);
assert_eq!(
sim.frame_tree().get(earth_inertial).name,
"Earth.inertial",
"the central source's inertial frame node should carry the source-named label"
);
}
#[test]
fn integ_source_eq_central_with_orbital_elements_validates_clean() {
let time = SimulationTime::at_j2000(astrodyn::default_leap_second_table());
let mut sim = Simulation::new(time, 1.0);
let _earth_idx = sim.add_source("Earth", earth_central_source());
sim.add_body(leo_body_config(
Some(astrodyn::FrameUid::of::<
astrodyn::PlanetInertial<astrodyn::Earth>,
>()),
astrodyn::FrameUid::of::<astrodyn::PlanetInertial<astrodyn::Earth>>(),
));
sim.validate().unwrap_or_else(|errors| {
panic!(
"expected clean validation for a body integrating in the central source's \
inertial frame with orbital_elements; got errors: {errors:?}"
)
});
}
#[test]
fn integ_source_eq_none_with_orbital_elements_validates_clean() {
let time = SimulationTime::at_j2000(astrodyn::default_leap_second_table());
let mut sim = Simulation::new(time, 1.0);
let _earth_idx = sim.add_source("Earth", earth_central_source());
sim.add_body(leo_body_config(
None,
astrodyn::FrameUid::of::<astrodyn::PlanetInertial<astrodyn::Earth>>(),
));
sim.validate().unwrap_or_else(|errors| {
panic!(
"expected clean validation for a body integrating in root with \
orbital_elements; got errors: {errors:?}"
)
});
}
#[test]
fn frame_switch_target_central_with_derived_state_validates_clean() {
let time = SimulationTime::at_j2000(astrodyn::default_leap_second_table());
let mut sim = Simulation::new(time, 1.0);
let _earth_idx = sim.add_source("Earth", earth_central_source());
let mut cfg = leo_body_config(
None,
astrodyn::FrameUid::of::<astrodyn::PlanetInertial<astrodyn::Earth>>(),
);
cfg.frame_switches.push(astrodyn::FrameSwitchConfig {
target: astrodyn::FrameUid::of::<astrodyn::PlanetInertial<astrodyn::Earth>>(),
switch_sense: astrodyn::SwitchSense::OnDeparture,
switch_distance: 1.0e9,
active: true,
});
sim.add_body(cfg);
sim.validate().unwrap_or_else(|errors| {
panic!(
"expected clean validation for a frame switch to the central source; \
got errors: {errors:?}"
)
});
}