IntegratedEphemeris.java

  1. /* Copyright 2002-2022 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.propagation.integration;

  18. import java.util.List;
  19. import java.util.Map;

  20. import org.hipparchus.ode.DenseOutputModel;
  21. import org.hipparchus.ode.ODEStateAndDerivative;
  22. import org.orekit.attitudes.AttitudeProvider;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.errors.OrekitMessages;
  25. import org.orekit.frames.Frame;
  26. import org.orekit.orbits.Orbit;
  27. import org.orekit.propagation.AdditionalStateProvider;
  28. import org.orekit.propagation.BoundedPropagator;
  29. import org.orekit.propagation.PropagationType;
  30. import org.orekit.propagation.SpacecraftState;
  31. import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.utils.DoubleArrayDictionary;
  34. import org.orekit.utils.TimeStampedPVCoordinates;

  35. /** This class stores sequentially generated orbital parameters for
  36.  * later retrieval.
  37.  *
  38.  * <p>
  39.  * Instances of this class are built automatically when the {@link
  40.  * org.orekit.propagation.Propagator#getEphemerisGenerator()
  41.  * getEphemerisGenerator} method has been called. They are created when propagation is over.
  42.  * Random access to any intermediate state of the orbit throughout the propagation range is
  43.  * possible afterwards through this object.
  44.  * </p>
  45.  * <p>
  46.  * A typical use case is for numerically integrated orbits, which can be used by
  47.  * algorithms that need to wander around according to their own algorithm without
  48.  * cumbersome tight links with the integrator.
  49.  * </p>
  50.  * <p>
  51.  * As this class implements the {@link org.orekit.propagation.Propagator Propagator}
  52.  * interface, it can itself be used in batch mode to build another instance of the
  53.  * same type. This is however not recommended since it would be a waste of resources.
  54.  * </p>
  55.  * <p>
  56.  * Note that this class stores all intermediate states along with interpolation
  57.  * models, so it may be memory intensive.
  58.  * </p>
  59.  *
  60.  * @see org.orekit.propagation.numerical.NumericalPropagator
  61.  * @author Mathieu Rom&eacute;ro
  62.  * @author Luc Maisonobe
  63.  * @author V&eacute;ronique Pommier-Maurussane
  64.  */
  65. public class IntegratedEphemeris
  66.     extends AbstractAnalyticalPropagator implements BoundedPropagator {

  67.     /** Event detection requires evaluating the state slightly before / past an event. */
  68.     private static final double EXTRAPOLATION_TOLERANCE = 1.0;

  69.     /** Mapper between raw double components and spacecraft state. */
  70.     private final StateMapper mapper;

  71.     /** Type of orbit to output (mean or osculating).
  72.      * <p>
  73.      * This is used only in the case of semianalitical propagators where there is a clear separation between
  74.      * mean and short periodic elements. It is ignored by the Numerical propagator.
  75.      * </p>
  76.      */
  77.     private PropagationType type;

  78.     /** Start date of the integration (can be min or max). */
  79.     private final AbsoluteDate startDate;

  80.     /** First date of the range. */
  81.     private final AbsoluteDate minDate;

  82.     /** Last date of the range. */
  83.     private final AbsoluteDate maxDate;

  84.     /** Underlying raw mathematical model. */
  85.     private DenseOutputModel model;

  86.     /** Unmanaged additional states that must be simply copied. */
  87.     private final DoubleArrayDictionary unmanaged;

  88.     /** Creates a new instance of IntegratedEphemeris.
  89.      * @param startDate Start date of the integration (can be minDate or maxDate)
  90.      * @param minDate first date of the range
  91.      * @param maxDate last date of the range
  92.      * @param mapper mapper between raw double components and spacecraft state
  93.      * @param type type of orbit to output (mean or osculating)
  94.      * @param model underlying raw mathematical model
  95.      * @param unmanaged unmanaged additional states that must be simply copied
  96.      * @param providers providers for pre-integrated states
  97.      * @param equations names of additional equations
  98.      * @deprecated as of 11.1, replaced by {@link #IntegratedEphemeris(AbsoluteDate,
  99.      * AbsoluteDate, AbsoluteDate, StateMapper, PropagationType, DenseOutputModel,
  100.      * DoubleArrayDictionary, List, String[])}
  101.      */
  102.     @Deprecated
  103.     public IntegratedEphemeris(final AbsoluteDate startDate,
  104.                                final AbsoluteDate minDate, final AbsoluteDate maxDate,
  105.                                final StateMapper mapper, final PropagationType type,
  106.                                final DenseOutputModel model,
  107.                                final Map<String, double[]> unmanaged,
  108.                                final List<AdditionalStateProvider> providers,
  109.                                final String[] equations) {
  110.         this(startDate, minDate, maxDate, mapper, type, model,
  111.              new DoubleArrayDictionary(unmanaged), providers, equations);
  112.     }

  113.     /** Creates a new instance of IntegratedEphemeris.
  114.      * @param startDate Start date of the integration (can be minDate or maxDate)
  115.      * @param minDate first date of the range
  116.      * @param maxDate last date of the range
  117.      * @param mapper mapper between raw double components and spacecraft state
  118.      * @param type type of orbit to output (mean or osculating)
  119.      * @param model underlying raw mathematical model
  120.      * @param unmanaged unmanaged additional states that must be simply copied
  121.      * @param providers providers for pre-integrated states
  122.      * @param equations names of additional equations
  123.      * @since 11.1
  124.      */
  125.     public IntegratedEphemeris(final AbsoluteDate startDate,
  126.                                final AbsoluteDate minDate, final AbsoluteDate maxDate,
  127.                                final StateMapper mapper, final PropagationType type,
  128.                                final DenseOutputModel model,
  129.                                final DoubleArrayDictionary unmanaged,
  130.                                final List<AdditionalStateProvider> providers,
  131.                                final String[] equations) {

  132.         super(mapper.getAttitudeProvider());

  133.         this.startDate = startDate;
  134.         this.minDate   = minDate;
  135.         this.maxDate   = maxDate;
  136.         this.mapper    = mapper;
  137.         this.type      = type;
  138.         this.model     = model;
  139.         this.unmanaged = unmanaged;

  140.         // set up the pre-integrated providers
  141.         for (final AdditionalStateProvider provider : providers) {
  142.             addAdditionalStateProvider(provider);
  143.         }

  144.         // set up providers to map the final elements of the model array to additional states
  145.         for (int i = 0; i < equations.length; ++i) {
  146.             addAdditionalStateProvider(new LocalGenerator(equations[i], i));
  147.         }

  148.     }

  149.     /** Interpolate the model at some date.
  150.      * @param date desired interpolation date
  151.      * @return state interpolated at date
  152.      */
  153.     private ODEStateAndDerivative getInterpolatedState(final AbsoluteDate date) {

  154.         // compare using double precision instead of AbsoluteDate.compareTo(...)
  155.         // because time is expressed as a double when searching for events
  156.         if (date.compareTo(minDate.shiftedBy(-EXTRAPOLATION_TOLERANCE)) < 0) {
  157.             // date is outside of supported range
  158.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_BEFORE,
  159.                     date, minDate, maxDate, minDate.durationFrom(date));
  160.         }
  161.         if (date.compareTo(maxDate.shiftedBy(EXTRAPOLATION_TOLERANCE)) > 0) {
  162.             // date is outside of supported range
  163.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_AFTER,
  164.                     date, minDate, maxDate, date.durationFrom(maxDate));
  165.         }

  166.         return model.getInterpolatedState(date.durationFrom(startDate));

  167.     }

  168.     /** {@inheritDoc} */
  169.     @Override
  170.     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
  171.         final ODEStateAndDerivative os = getInterpolatedState(date);
  172.         SpacecraftState state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
  173.                                                        os.getPrimaryState(), os.getPrimaryDerivative(),
  174.                                                        type);
  175.         for (DoubleArrayDictionary.Entry initial : unmanaged.getData()) {
  176.             state = state.addAdditionalState(initial.getKey(), initial.getValue());
  177.         }
  178.         return state;
  179.     }

  180.     /** {@inheritDoc} */
  181.     protected Orbit propagateOrbit(final AbsoluteDate date) {
  182.         return basicPropagate(date).getOrbit();
  183.     }

  184.     /** {@inheritDoc} */
  185.     protected double getMass(final AbsoluteDate date) {
  186.         return basicPropagate(date).getMass();
  187.     }

  188.     /** {@inheritDoc} */
  189.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  190.         return propagate(date).getPVCoordinates(frame);
  191.     }

  192.     /** Get the first date of the range.
  193.      * @return the first date of the range
  194.      */
  195.     public AbsoluteDate getMinDate() {
  196.         return minDate;
  197.     }

  198.     /** Get the last date of the range.
  199.      * @return the last date of the range
  200.      */
  201.     public AbsoluteDate getMaxDate() {
  202.         return maxDate;
  203.     }

  204.     @Override
  205.     public Frame getFrame() {
  206.         return this.mapper.getFrame();
  207.     }

  208.     /** {@inheritDoc} */
  209.     public void resetInitialState(final SpacecraftState state) {
  210.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  211.     }

  212.     /** {@inheritDoc} */
  213.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  214.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  215.     }

  216.     /** {@inheritDoc} */
  217.     @Override
  218.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  219.         super.setAttitudeProvider(attitudeProvider);
  220.         if (mapper != null) {
  221.             // At the construction, the mapper is not set yet
  222.             // However, if the attitude provider is changed afterwards, it must be changed in the mapper too
  223.             mapper.setAttitudeProvider(attitudeProvider);
  224.         }
  225.     }

  226.     /** {@inheritDoc} */
  227.     public SpacecraftState getInitialState() {
  228.         return updateAdditionalStates(basicPropagate(getMinDate()));
  229.     }

  230.     /** Local generator for additional state data. */
  231.     private class LocalGenerator implements AdditionalStateProvider {

  232.         /** Name of the additional state. */
  233.         private final String name;

  234.         /** Index of the additional state. */
  235.         private final int index;

  236.         /** Simple constructor.
  237.          * @param name name of the additional state
  238.          * @param index index of the additional state
  239.          */
  240.         LocalGenerator(final String name, final int index) {
  241.             this.name  = name;
  242.             this.index = index;
  243.         }

  244.         /** {@inheritDoc} */
  245.         public String getName() {
  246.             return name;
  247.         }

  248.         /** {@inheritDoc} */
  249.         public double[] getAdditionalState(final SpacecraftState state) {

  250.             // extract the part of the interpolated array corresponding to the additional state
  251.             return getInterpolatedState(state.getDate()).getSecondaryState(index + 1);

  252.         }

  253.     }

  254. }