// The best serialization revenge. TEST_F(BodyTest, MassiveSerializationSuccess) { EXPECT_FALSE(massive_body_.is_massless()); EXPECT_FALSE(massive_body_.is_oblate()); serialization::Body message; MassiveBody const* cast_massive_body; massive_body_.WriteToMessage(&message); EXPECT_TRUE(message.has_massive_body()); EXPECT_FALSE(message.has_massless_body()); EXPECT_EQ(42, message.massive_body().gravitational_parameter().magnitude()); // Direct deserialization. MassiveBody const massive_body = *MassiveBody::ReadFromMessage(message); EXPECT_EQ(massive_body_.gravitational_parameter(), massive_body.gravitational_parameter()); // Dispatching from |Body|. not_null<std::unique_ptr<Body>> body = Body::ReadFromMessage(message); cast_massive_body = dynamic_cast<MassiveBody*>(&*body); EXPECT_THAT(cast_massive_body, NotNull()); EXPECT_EQ(massive_body_.gravitational_parameter(), cast_massive_body->gravitational_parameter()); }
KeplerOrbit<Frame>::KeplerOrbit( MassiveBody const& primary, Body const& secondary, KeplerianElements<Frame> const& elements_at_epoch, Instant const& epoch) : gravitational_parameter_( primary.gravitational_parameter() + (secondary.is_massless() ? GravitationalParameter{} : dynamic_cast<MassiveBody const&>(secondary). gravitational_parameter())), elements_at_epoch_(elements_at_epoch), epoch_(epoch) { CHECK(static_cast<bool>(elements_at_epoch_.semimajor_axis) ^ static_cast<bool>(elements_at_epoch_.mean_motion)); GravitationalParameter const μ = gravitational_parameter_; if (elements_at_epoch_.semimajor_axis) { Length const& a = *elements_at_epoch_.semimajor_axis; elements_at_epoch_.mean_motion = Sqrt(μ / Pow<3>(a)) * Radian; } else {
void Ephemeris<Frame>:: ComputeGravitationalAccelerationByMassiveBodyOnMasslessBodies( Instant const& t, MassiveBody const& body1, size_t const b1, std::vector<Position<Frame>> const& positions, not_null<std::vector<Vector<Acceleration, Frame>>*> const accelerations, not_null<typename ContinuousTrajectory<Frame>::Hint*> const hint1) const { GravitationalParameter const& μ1 = body1.gravitational_parameter(); Position<Frame> const position1 = trajectories_[b1]->EvaluatePosition(t, hint1); for (size_t b2 = 0; b2 < positions.size(); ++b2) { Displacement<Frame> const Δq = position1 - positions[b2]; Square<Length> const Δq_squared = InnerProduct(Δq, Δq); // NOTE(phl): Don't try to compute one_over_Δq_squared here, it makes the // non-oblate path slower. Exponentiation<Length, -3> const one_over_Δq_cubed = Sqrt(Δq_squared) / (Δq_squared * Δq_squared); auto const μ1_over_Δq_cubed = μ1 * one_over_Δq_cubed; (*accelerations)[b2] += Δq * μ1_over_Δq_cubed; if (body1_is_oblate) { Exponentiation<Length, -2> const one_over_Δq_squared = 1 / Δq_squared; Vector<Quotient<Acceleration, GravitationalParameter>, Frame> const order_2_zonal_effect1 = Order2ZonalEffect<Frame>( static_cast<OblateBody<Frame> const &>(body1), Δq, one_over_Δq_squared, one_over_Δq_cubed); (*accelerations)[b2] += μ1 * order_2_zonal_effect1; } } }
void Ephemeris<Frame>:: ComputeGravitationalAccelerationByMassiveBodyOnMassiveBodies( MassiveBody const& body1, size_t const b1, std::vector<not_null<MassiveBodyConstPtr>> const& bodies2, size_t const b2_begin, size_t const b2_end, std::vector<Position<Frame>> const& positions, not_null<std::vector<Vector<Acceleration, Frame>>*> const accelerations) { Position<Frame> const& position_of_b1 = positions[b1]; Vector<Acceleration, Frame>& acceleration_on_b1 = (*accelerations)[b1]; GravitationalParameter const& μ1 = body1.gravitational_parameter(); for (std::size_t b2 = b2_begin; b2 < b2_end; ++b2) { Vector<Acceleration, Frame>& acceleration_on_b2 = (*accelerations)[b2]; MassiveBody const& body2 = *bodies2[b2]; GravitationalParameter const& μ2 = body2.gravitational_parameter(); Displacement<Frame> const Δq = position_of_b1 - positions[b2]; Square<Length> const Δq_squared = InnerProduct(Δq, Δq); // NOTE(phl): Don't try to compute one_over_Δq_squared here, it makes the // non-oblate path slower. Exponentiation<Length, -3> const one_over_Δq_cubed = Sqrt(Δq_squared) / (Δq_squared * Δq_squared); auto const μ1_over_Δq_cubed = μ1 * one_over_Δq_cubed; acceleration_on_b2 += Δq * μ1_over_Δq_cubed; // Lex. III. Actioni contrariam semper & æqualem esse reactionem: // sive corporum duorum actiones in se mutuo semper esse æquales & // in partes contrarias dirigi. auto const μ2_over_Δq_cubed = μ2 * one_over_Δq_cubed; acceleration_on_b1 -= Δq * μ2_over_Δq_cubed; if (body1_is_oblate || body2_is_oblate) { Exponentiation<Length, -2> const one_over_Δq_squared = 1 / Δq_squared; if (body1_is_oblate) { Vector<Quotient<Acceleration, GravitationalParameter>, Frame> const order_2_zonal_effect1 = Order2ZonalEffect<Frame>( static_cast<OblateBody<Frame> const&>(body1), Δq, one_over_Δq_squared, one_over_Δq_cubed); acceleration_on_b1 -= μ2 * order_2_zonal_effect1; acceleration_on_b2 += μ1 * order_2_zonal_effect1; } if (body2_is_oblate) { Vector<Quotient<Acceleration, GravitationalParameter>, Frame> const order_2_zonal_effect2 = Order2ZonalEffect<Frame>( static_cast<OblateBody<Frame> const&>(body2), Δq, one_over_Δq_squared, one_over_Δq_cubed); acceleration_on_b1 -= μ2 * order_2_zonal_effect2; acceleration_on_b2 += μ1 * order_2_zonal_effect2; } } } }