TEST_F(BodyTest, RotatingSerializationSuccess) { EXPECT_FALSE(rotating_body_.is_massless()); EXPECT_FALSE(rotating_body_.is_oblate()); serialization::Body message; RotatingBody<World> const* cast_rotating_body; rotating_body_.WriteToMessage(&message); EXPECT_TRUE(message.has_massive_body()); EXPECT_FALSE(message.has_massless_body()); EXPECT_TRUE(message.massive_body().HasExtension( serialization::RotatingBody::rotating_body)); EXPECT_EQ(17, message.massive_body().gravitational_parameter().magnitude()); serialization::RotatingBody const rotating_body_extension = message.massive_body().GetExtension( serialization::RotatingBody::rotating_body); EXPECT_EQ(3, rotating_body_extension.reference_angle().magnitude()); EXPECT_EQ(4, rotating_body_extension.reference_instant().scalar().magnitude()); EXPECT_EQ(angular_velocity_, AngularVelocity<World>::ReadFromMessage( rotating_body_extension.angular_velocity())); // Dispatching from |MassiveBody|. not_null<std::unique_ptr<MassiveBody const>> const massive_body = MassiveBody::ReadFromMessage(message); EXPECT_EQ(rotating_body_.gravitational_parameter(), massive_body->gravitational_parameter()); cast_rotating_body = dynamic_cast<RotatingBody<World> const*>(&*massive_body); EXPECT_THAT(cast_rotating_body, NotNull()); EXPECT_EQ(rotating_body_.gravitational_parameter(), cast_rotating_body->gravitational_parameter()); EXPECT_EQ(rotating_body_.angular_velocity(), cast_rotating_body->angular_velocity()); EXPECT_EQ(rotating_body_.AngleAt(Instant()), cast_rotating_body->AngleAt(Instant())); // Dispatching from |Body|. not_null<std::unique_ptr<Body const>> const body = Body::ReadFromMessage(message); cast_rotating_body = dynamic_cast<RotatingBody<World> const*>(&*body); EXPECT_THAT(cast_rotating_body, NotNull()); EXPECT_EQ(rotating_body_.gravitational_parameter(), cast_rotating_body->gravitational_parameter()); EXPECT_EQ(rotating_body_.angular_velocity(), cast_rotating_body->angular_velocity()); EXPECT_EQ(rotating_body_.AngleAt(Instant()), cast_rotating_body->AngleAt(Instant())); }
void TestRotatingBody() { using F = Frame<Tag, tag, true>; AngularVelocity<F> const angular_velocity = AngularVelocity<F>({-1 * Radian / Second, 2 * Radian / Second, 5 * Radian / Second}); auto const rotating_body = RotatingBody<F>(17 * SIUnit<GravitationalParameter>(), typename RotatingBody<F>::Parameters( 3 * Radian, Instant() + 4 * Second, angular_velocity)); serialization::Body message; RotatingBody<F> const* cast_rotating_body; rotating_body.WriteToMessage(&message); EXPECT_TRUE(message.has_massive_body()); EXPECT_FALSE(message.has_massless_body()); EXPECT_TRUE(message.massive_body().HasExtension( serialization::RotatingBody::rotating_body)); not_null<std::unique_ptr<MassiveBody const>> const massive_body = MassiveBody::ReadFromMessage(message); EXPECT_EQ(rotating_body.gravitational_parameter(), massive_body->gravitational_parameter()); cast_rotating_body = dynamic_cast<RotatingBody<F> const*>(&*massive_body); EXPECT_THAT(cast_rotating_body, NotNull()); }
TEST_F(ManœuvreTest, TargetΔv) { Instant const t0 = Instant(); Vector<double, World> e_y({0, 1, 0}); Manœuvre<World> manœuvre(1 * Newton /*thrust*/, 2 * Kilogram /*initial_mass*/, 1 * Newton * Second / Kilogram /*specific_impulse*/, e_y /*direction*/); EXPECT_EQ(1 * Newton, manœuvre.thrust()); EXPECT_EQ(2 * Kilogram, manœuvre.initial_mass()); EXPECT_EQ(1 * Metre / Second, manœuvre.specific_impulse()); EXPECT_EQ(e_y, manœuvre.direction()); EXPECT_EQ(1 * Kilogram / Second, manœuvre.mass_flow()); manœuvre.set_Δv(1 * Metre / Second); EXPECT_EQ(1 * Metre / Second, manœuvre.Δv()); EXPECT_EQ((2 - 2 / e) * Second, manœuvre.duration()); EXPECT_EQ((2 - 2 / Sqrt(e)) * Second, manœuvre.time_to_half_Δv()); EXPECT_EQ((2 / e) * Kilogram, manœuvre.final_mass()); manœuvre.set_time_of_half_Δv(t0); EXPECT_EQ(t0 - (2 - 2 / Sqrt(e)) * Second, manœuvre.initial_time()); EXPECT_EQ(t0 + (2 / Sqrt(e) - 2 / e) * Second, manœuvre.final_time()); EXPECT_EQ(t0, manœuvre.time_of_half_Δv()); EXPECT_EQ( 0 * Metre / Pow<2>(Second), manœuvre.acceleration()(manœuvre.initial_time() - 1 * Second).Norm()); EXPECT_EQ(0.5 * Metre / Pow<2>(Second), manœuvre.acceleration()(manœuvre.initial_time()).Norm()); EXPECT_EQ(Sqrt(e) / 2 * Metre / Pow<2>(Second), manœuvre.acceleration()(manœuvre.time_of_half_Δv()).Norm()); EXPECT_EQ((e / 2) * Metre / Pow<2>(Second), manœuvre.acceleration()(manœuvre.final_time()).Norm()); EXPECT_EQ(0 * Metre / Pow<2>(Second), manœuvre.acceleration()(manœuvre.final_time() + 1 * Second).Norm()); }
std::unique_ptr<MassiveBody> SolarSystem<Frame>::MakeMassiveBody( serialization::GravityModel::Body const& body) { CHECK(body.has_gravitational_parameter()); CHECK_EQ(body.has_j2(), body.has_reference_radius()); CHECK_EQ(body.has_axis_declination(), body.has_axis_right_ascension()); MassiveBody::Parameters massive_body_parameters( ParseQuantity<GravitationalParameter>( body.gravitational_parameter())); if (body.has_axis_declination()) { // TODO(phl): Parse the additional parameters. typename RotatingBody<Frame>::Parameters rotating_body_parameters( 0 * Radian, Instant(), Bivector<double, Frame>( RadiusLatitudeLongitude( 1.0, ParseQuantity<Angle>(body.axis_declination()), ParseQuantity<Angle>(body.axis_right_ascension())). ToCartesian()) * Radian / Second); if (body.has_j2()) { typename OblateBody<Frame>::Parameters oblate_body_parameters( ParseQuantity<double>(body.j2()), ParseQuantity<Length>(body.reference_radius())); return std::make_unique<OblateBody<Frame>>(massive_body_parameters, rotating_body_parameters, oblate_body_parameters); } else { return std::make_unique<RotatingBody<Frame>>(massive_body_parameters, rotating_body_parameters); } } else { return std::make_unique<MassiveBody>(massive_body_parameters); } }
double principia__IteratorGetTime(Iterator const* const iterator) { journal::Method<journal::IteratorGetTime> m({iterator}); CHECK_NOTNULL(iterator); auto const typed_iterator = check_not_null( dynamic_cast<TypedIterator<DiscreteTrajectory<World>> const*>(iterator)); return m.Return(typed_iterator->Get<double>( [](DiscreteTrajectory<World>::Iterator const& iterator) -> double { return (iterator.time() - Instant()) / Second; })); }
Plugin* NewPlugin(double const initial_time, int const sun_index, double const sun_gravitational_parameter, double const planetarium_rotation_in_degrees) { LOG(INFO) << "Constructing Principia plugin"; std::unique_ptr<Plugin> result = std::make_unique<Plugin>( Instant(initial_time * Second), sun_index, sun_gravitational_parameter * SIUnit<GravitationalParameter>(), planetarium_rotation_in_degrees * Degree); LOG(INFO) << "Plugin constructed"; return result.release(); }
void Ephemeris<Frame>::AppendMassiveBodiesState( typename NewtonianMotionEquation::SystemState const& state) { last_state_ = state; int index = 0; for (auto& trajectory : trajectories_) { trajectory->Append( state.time.value, DegreesOfFreedom<Frame>(state.positions[index].value, state.velocities[index].value)); ++index; } // Record an intermediate state if we haven't done so for too long. CHECK(!trajectories_.empty()); Instant const t_last_intermediate_state = checkpoints_.empty() ? Instant() - std::numeric_limits<double>::infinity() * Second : checkpoints_.back().system_state.time.value; if (t_max() - t_last_intermediate_state > max_time_between_checkpoints) { checkpoints_.push_back(GetCheckpoint()); } }
void AdvanceTime(Plugin* const plugin, double const t, double const planetarium_rotation) { CHECK_NOTNULL(plugin)->AdvanceTime(Instant(t * Second), planetarium_rotation * Degree); }
MockPlugin::MockPlugin() : Plugin(Instant(), Angle()) {}
TEST_F(SolarSystemTest, RealSolarSystem) { solar_system_.Initialize( SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt", SOLUTION_DIR / "astronomy" / "initial_state_jd_2433282_500000000.proto.txt"); EXPECT_EQ(Instant() - 50 * 365.25 * Day, solar_system_.epoch()); EXPECT_THAT(solar_system_.names(), ElementsAreArray({"Ariel", "Callisto", "Ceres", "Charon", "Deimos", "Dione", "Earth", "Enceladus", "Eris", "Europa", "Ganymede", "Iapetus", "Io", "Jupiter", "Mars", "Mercury", "Mimas", "Miranda", "Moon", "Neptune", "Oberon", "Phobos", "Pluto", "Rhea", "Saturn", "Sun", "Tethys", "Titan", "Titania", "Triton", "Umbriel", "Uranus", "Venus", "Vesta"})); EXPECT_EQ(1, solar_system_.index("Callisto")); EXPECT_EQ(32, solar_system_.index("Venus")); auto const ephemeris = solar_system_.MakeEphemeris( /*fitting_tolerance=*/1 * Metre, Ephemeris<ICRFJ2000Equator>::FixedStepParameters( integrators::McLachlanAtela1992Order4Optimal< Position<ICRFJ2000Equator>>(), /*step=*/1 * Second)); auto const earth = solar_system_.massive_body(*ephemeris, "Earth"); EXPECT_LT(RelativeError(5.97258 * Yotta(Kilogram), earth->mass()), 6E-9); auto const& earth_trajectory = solar_system_.trajectory(*ephemeris, "Earth"); EXPECT_TRUE(earth_trajectory.empty()); auto const& sun_initial_state = solar_system_.initial_state_message("Sun"); EXPECT_EQ("+1.309126697236264E+05 km", sun_initial_state.x()); EXPECT_EQ("-7.799754996220354E-03 km/s", sun_initial_state.vx()); auto const& sun_gravity_model = solar_system_.gravity_model_message("Sun"); EXPECT_EQ("286.13 deg", sun_gravity_model.axis_right_ascension()); EXPECT_EQ("63.87 deg", sun_gravity_model.axis_declination()); }