// Check that the small body has the right degrees of freedom in the frame of
// the big body.
TEST_F(BodyCentredNonRotatingDynamicFrameTest, SmallBodyInBigFrame) {
  int const kSteps = 100;
  Bivector<double, ICRFJ2000Equator> const axis({0, 0, 1});

  RelativeDegreesOfFreedom<ICRFJ2000Equator> const initial_big_to_small =
      small_initial_state_ - big_initial_state_;
  ContinuousTrajectory<ICRFJ2000Equator>::Hint hint;
  for (Instant t = t0_; t < t0_ + 1 * period_; t += period_ / kSteps) {
    DegreesOfFreedom<ICRFJ2000Equator> const small_in_inertial_frame_at_t =
        solar_system_.trajectory(*ephemeris_, kSmall).
            EvaluateDegreesOfFreedom(t, &hint);

    auto const rotation_in_big_frame_at_t =
        Rotation<ICRFJ2000Equator, Big>(-2 * π * (t - t0_) * Radian / period_,
                                        axis);
    DegreesOfFreedom<Big> const small_in_big_frame_at_t(
        rotation_in_big_frame_at_t(initial_big_to_small.displacement()) +
            Big::origin,
        rotation_in_big_frame_at_t(initial_big_to_small.velocity()));

    auto const to_big_frame_at_t = big_frame_->ToThisFrameAtTime(t);
    EXPECT_THAT(AbsoluteError(
                    to_big_frame_at_t(small_in_inertial_frame_at_t).position(),
                    small_in_big_frame_at_t.position()),
                Lt(0.3 * Milli(Metre)));
    EXPECT_THAT(AbsoluteError(
                    to_big_frame_at_t(small_in_inertial_frame_at_t).velocity(),
                    small_in_big_frame_at_t.velocity()),
                Lt(4 * Milli(Metre) / Second));
  }
}
Ejemplo n.º 2
0
DegreesOfFreedom<ToFrame> RigidMotion<FromFrame, ToFrame>::operator()(
    DegreesOfFreedom<FromFrame> const& degrees_of_freedom) const {
  return {rigid_transformation_(degrees_of_freedom.position()),
          orthogonal_map()(
              degrees_of_freedom.velocity() - velocity_of_to_frame_origin_ -
              angular_velocity_of_to_frame_ *
                  (degrees_of_freedom.position() -
                   rigid_transformation_.Inverse()(ToFrame::origin)) /
                  Radian)};
}
RigidMotion<InertialFrame, ThisFrame>
BodyCentredNonRotatingDynamicFrame<InertialFrame, ThisFrame>::ToThisFrameAtTime(
    Instant const& t) const {
    DegreesOfFreedom<InertialFrame> const centre_degrees_of_freedom =
        centre_trajectory_->EvaluateDegreesOfFreedom(t, &hint_);
    RigidTransformation<InertialFrame, ThisFrame> const
    rigid_transformation(centre_degrees_of_freedom.position(),
                         ThisFrame::origin,
                         Identity<InertialFrame, ThisFrame>().Forget());
    return RigidMotion<InertialFrame, ThisFrame>(
               rigid_transformation,
               AngularVelocity<InertialFrame>(),
               centre_degrees_of_freedom.velocity());
}
Ejemplo n.º 4
0
QP principia__IteratorGetQP(Iterator const* const iterator) {
  journal::Method<journal::IteratorGetQP> 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<QP>(
      [](DiscreteTrajectory<World>::Iterator const& iterator) -> QP {
        DegreesOfFreedom<World> const degrees_of_freedom =
            iterator.degrees_of_freedom();
        return {
            ToXYZ(
                (degrees_of_freedom.position() - World::origin).coordinates() /
                Metre),
            ToXYZ(degrees_of_freedom.velocity().coordinates() /
                  (Metre / Second))};
      }));
}
Ejemplo n.º 5
0
RigidMotion<InertialFrame, ThisFrame>
BodySurfaceDynamicFrame<InertialFrame, ThisFrame>::ToThisFrameAtTime(
    Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const centre_degrees_of_freedom =
      centre_trajectory_->EvaluateDegreesOfFreedom(t, &hint_);

  Rotation<InertialFrame, ThisFrame> rotation =
      centre_->template ToSurfaceFrame<ThisFrame>(t);
  AngularVelocity<InertialFrame> angular_velocity = centre_->angular_velocity();
  RigidTransformation<InertialFrame, ThisFrame> const
      rigid_transformation(centre_degrees_of_freedom.position(),
                           ThisFrame::origin,
                           rotation.Forget());
  return RigidMotion<InertialFrame, ThisFrame>(
             rigid_transformation,
             angular_velocity,
             centre_degrees_of_freedom.velocity());
}
Ejemplo n.º 6
0
void ContinuousTrajectory<Frame>::Append(
    Instant const& time,
    DegreesOfFreedom<Frame> const& degrees_of_freedom) {
  // Consistency checks.
  if (first_time_) {
    Instant const t0;
    CHECK_GE(1,
             ULPDistance((last_points_.back().first + step_ - t0) /
                             SIUnit<Time>(),
                         (time - t0) / SIUnit<Time>()))
        << "Append at times that are not equally spaced";
  } else {
    first_time_ = time;
  }

  if (last_points_.size() == divisions) {
    // These vectors are static to avoid deallocation/reallocation each time we
    // go through this code path.
    static std::vector<Displacement<Frame>> q(divisions + 1);
    static std::vector<Velocity<Frame>> v(divisions + 1);
    q.clear();
    v.clear();

    for (auto const& pair : last_points_) {
      DegreesOfFreedom<Frame> const& degrees_of_freedom = pair.second;
      q.push_back(degrees_of_freedom.position() - Frame::origin);
      v.push_back(degrees_of_freedom.velocity());
    }
    q.push_back(degrees_of_freedom.position() - Frame::origin);
    v.push_back(degrees_of_freedom.velocity());

    ComputeBestNewhallApproximation(
        time, q, v, &ЧебышёвSeries<Displacement<Frame>>::NewhallApproximation);

    // Wipe-out the points that have just been incorporated in a series.
    last_points_.clear();
  }

  // Note that we only insert the new point in the map *after* computing the
  // approximation, because clearing the map is much more efficient than erasing
  // every element but one.
  last_points_.emplace_back(time, degrees_of_freedom);
}
Ejemplo n.º 7
0
Rotation<Frenet<ThisFrame>, ThisFrame>
DynamicFrame<InertialFrame, ThisFrame>::FrenetFrame(
    Instant const& t,
    DegreesOfFreedom<ThisFrame> const& degrees_of_freedom) const {
  Velocity<ThisFrame> const& velocity = degrees_of_freedom.velocity();
  Vector<Acceleration, ThisFrame> const acceleration =
      GeometricAcceleration(t, degrees_of_freedom);
  Vector<Acceleration, ThisFrame> normal_acceleration = acceleration;
  velocity.template Orthogonalize<Acceleration>(&normal_acceleration);
  Vector<double, ThisFrame> tangent = Normalize(velocity);
  Vector<double, ThisFrame> normal = Normalize(normal_acceleration);
  Bivector<double, ThisFrame> binormal = Wedge(tangent, normal);
  // Maps |tangent| to {1, 0, 0}, |normal| to {0, 1, 0}, and |binormal| to
  // {0, 0, 1}.
  return Rotation<Frenet<ThisFrame>, ThisFrame>(
      R3x3Matrix(tangent.coordinates(),
                 normal.coordinates(),
                 binormal.coordinates()).Transpose());
}
std::string DebugString(DegreesOfFreedom<Frame> const& degrees_of_freedom) {
  return "{" + DebugString(degrees_of_freedom.position()) + ", " +
         DebugString(degrees_of_freedom.velocity()) + "}";
}
Ejemplo n.º 9
0
  // Interpreting the elements as Jacobi coordinates in the Jool system.
  std::vector<DegreesOfFreedom<KSP>> JacobiInitialStates() {
    // Jool-centric coordinates: a nonrotating inertial frame in which Jool is
    // centred and immobile, for building the Jool system in Jacobi coordinates.
    // We only use this frame at |game_epoch_|.
    using JoolCentric = Frame<serialization::Frame::TestTag,
                              serialization::Frame::TEST1,
                              /*is_inertial=*/false>;
    // These coordinate systems have the same axes.
    auto const id = OrthogonalMap<KSP, JoolCentric>::Identity();

        std::map<not_null<MassiveBody const*>, KeplerOrbit<KSP>> orbits;

    orbits.emplace(jool_, KeplerOrbit<KSP>(*sun_,
                                           *jool_,
                                           elements_[jool_],
                                           game_epoch_));

    // The barycentre of the bodies of the Jool system considered so far.
    BarycentreCalculator<DegreesOfFreedom<JoolCentric>, GravitationalParameter>
        inner_system_barycentre;
    // TODO(egg): BarycentreCalculator should just have a method that returns
    // the weight of the whole thing, so we're not accumulating it twice.
    GravitationalParameter inner_system_parameter =
        jool_->gravitational_parameter();
    std::map<not_null<MassiveBody const*>, DegreesOfFreedom<JoolCentric>>
        jool_centric_initial_state;

    // Jool.
    DegreesOfFreedom<JoolCentric> const jool_dof = {JoolCentric::origin,
                                                    Velocity<JoolCentric>()};
    inner_system_barycentre.Add(jool_dof, jool_->gravitational_parameter());
    // The elements of each moon are interpreted as the osculating elements of
    // an orbit around a point mass at the barycentre of Jool and the
    // previously-added moons, so that the state vectors are Jacobi coordinates
    // for the system.
    for (auto const moon : joolian_moons_) {
      jool_centric_initial_state.emplace(
          moon,
          inner_system_barycentre.Get() +
              id(KeplerOrbit<KSP>(MassiveBody(inner_system_parameter),
                                  *moon,
                                  elements_[moon],
                                  game_epoch_).StateVectors(game_epoch_)));
      inner_system_parameter += moon->gravitational_parameter();
      inner_system_barycentre.Add(jool_centric_initial_state.at(moon),
                                  moon->gravitational_parameter());
    }

    // |inner_system_barycentre| is now the barycentre of the whole Jool system.
    // We want that to be placed where dictated by Jool's orbit.
    DegreesOfFreedom<KSP> const jool_barycentre_initial_state =
        origin_ + orbits.at(jool_).StateVectors(game_epoch_);
    // TODO(egg): this is very messy, a constructor from a pair of
    // |DegreesOfFreedom|s like the constructor for |RigidTransformation| from a
    // pair of |Position|s would be nice...
    RigidMotion<JoolCentric, KSP> const to_heliocentric(
        RigidTransformation<JoolCentric, KSP>(
            inner_system_barycentre.Get().position(),
            jool_barycentre_initial_state.position(),
            id.Inverse()),
        AngularVelocity<JoolCentric>(),
        /*velocity_of_to_frame_origin=*/
            inner_system_barycentre.Get().velocity() -
            id(jool_barycentre_initial_state.velocity()));

    // The Sun and Jool.
    std::vector<DegreesOfFreedom<KSP>> initial_states = {
        origin_, to_heliocentric(jool_dof)};
    for (auto const moon : joolian_moons_) {
      initial_states.emplace_back(
          to_heliocentric(jool_centric_initial_state.at(moon)));
    }
    return initial_states;
  }
Ejemplo n.º 10
0
void Ephemeris<Frame>::ComputeApsides(
    not_null<MassiveBody const*> const body,
    typename DiscreteTrajectory<Frame>::Iterator const begin,
    typename DiscreteTrajectory<Frame>::Iterator const end,
    DiscreteTrajectory<Frame>& apoapsides,
    DiscreteTrajectory<Frame>& periapsides) {
  not_null<ContinuousTrajectory<Frame> const*> const body_trajectory =
      trajectory(body);
  typename ContinuousTrajectory<Frame>::Hint hint;

  std::experimental::optional<Instant> previous_time;
  std::experimental::optional<DegreesOfFreedom<Frame>>
      previous_degrees_of_freedom;
  std::experimental::optional<Square<Length>> previous_squared_distance;
  std::experimental::optional<Variation<Square<Length>>>
      previous_squared_distance_derivative;

  for (auto it = begin; it != end; ++it) {
    Instant const time = it.time();
    DegreesOfFreedom<Frame> const degrees_of_freedom = it.degrees_of_freedom();
    DegreesOfFreedom<Frame> const body_degrees_of_freedom =
        body_trajectory->EvaluateDegreesOfFreedom(time, &hint);
    RelativeDegreesOfFreedom<Frame> const relative =
        degrees_of_freedom - body_degrees_of_freedom;
    Square<Length> const squared_distance =
        InnerProduct(relative.displacement(), relative.displacement());
    // This is the derivative of |squared_distance|.
    Variation<Square<Length>> const squared_distance_derivative =
        2.0 * InnerProduct(relative.displacement(), relative.velocity());

    if (previous_squared_distance_derivative &&
        Sign(squared_distance_derivative) !=
            Sign(*previous_squared_distance_derivative)) {
      CHECK(previous_time &&
            previous_degrees_of_freedom &&
            previous_squared_distance);

      // The derivative of |squared_distance| changed sign.  Construct a Hermite
      // approximation of |squared_distance| and find its extrema.
      Hermite3<Instant, Square<Length>> const
          squared_distance_approximation(
              {*previous_time, time},
              {*previous_squared_distance, squared_distance},
              {*previous_squared_distance_derivative,
               squared_distance_derivative});
      std::set<Instant> const extrema =
          squared_distance_approximation.FindExtrema();

      // Now look at the extrema and check that exactly one is in the required
      // time interval.  This is normally the case, but it can fail due to
      // ill-conditioning.
      Instant apsis_time;
      int valid_extrema = 0;
      for (auto const& extremum : extrema) {
        if (extremum >= *previous_time && extremum <= time) {
          apsis_time = extremum;
          ++valid_extrema;
        }
      }
      if (valid_extrema != 1) {
        // Something went wrong when finding the extrema of
        // |squared_distance_approximation|. Use a linear interpolation of
        // |squared_distance_derivative| instead.
        apsis_time = Barycentre<Instant, Variation<Square<Length>>>(
            {time, *previous_time},
            {*previous_squared_distance_derivative,
             -squared_distance_derivative});
      }

      // Now that we know the time of the apsis, construct a Hermite
      // approximation of the position of the body, and use it to derive its
      // degrees of freedom.  Note that an extremum of
      // |squared_distance_approximation| is in general not an extremum for
      // |position_approximation|: the distance computed using the latter is a
      // 6th-degree polynomial.  However, approximating this polynomial using a
      // 3rd-degree polynomial would yield |squared_distance_approximation|, so
      // we shouldn't be far from the truth.
      Hermite3<Instant, Position<Frame>> position_approximation(
          {*previous_time, time},
          {previous_degrees_of_freedom->position(),
           degrees_of_freedom.position()},
          {previous_degrees_of_freedom->velocity(),
           degrees_of_freedom.velocity()});
      DegreesOfFreedom<Frame> const apsis_degrees_of_freedom(
          position_approximation.Evaluate(apsis_time),
          position_approximation.EvaluateDerivative(apsis_time));
      if (Sign(squared_distance_derivative).Negative()) {
        apoapsides.Append(apsis_time, apsis_degrees_of_freedom);
      } else {
        periapsides.Append(apsis_time, apsis_degrees_of_freedom);
      }
    }

    previous_time = time;
    previous_degrees_of_freedom = degrees_of_freedom;
    previous_squared_distance = squared_distance;
    previous_squared_distance_derivative = squared_distance_derivative;
  }
}