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.Arrays;
  19. import java.util.List;
  20. import java.util.Map;

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

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

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

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

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

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

  82.     /** First date of the range. */
  83.     private final AbsoluteDate minDate;

  84.     /** Last date of the range. */
  85.     private final AbsoluteDate maxDate;

  86.     /** Underlying raw mathematical model. */
  87.     private DenseOutputModel model;

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

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

  115.     /** Creates a new instance of IntegratedEphemeris.
  116.      * @param startDate Start date of the integration (can be minDate or maxDate)
  117.      * @param minDate first date of the range
  118.      * @param maxDate last date of the range
  119.      * @param mapper mapper between raw double components and spacecraft state
  120.      * @param type type of orbit to output (mean or osculating)
  121.      * @param model underlying raw mathematical model
  122.      * @param unmanaged unmanaged additional states that must be simply copied
  123.      * @param providers providers for pre-integrated states
  124.      * @param equations names of additional equations
  125.      * @since 11.1
  126.      * @deprecated as of 11.1.2, replaced by {@link #IntegratedEphemeris(AbsoluteDate,
  127.      * AbsoluteDate, AbsoluteDate, StateMapper, PropagationType, DenseOutputModel,
  128.      * DoubleArrayDictionary, List, String[], int[])}
  129.      */
  130.     @Deprecated
  131.     public IntegratedEphemeris(final AbsoluteDate startDate,
  132.                                final AbsoluteDate minDate, final AbsoluteDate maxDate,
  133.                                final StateMapper mapper, final PropagationType type,
  134.                                final DenseOutputModel model,
  135.                                final DoubleArrayDictionary unmanaged,
  136.                                final List<AdditionalStateProvider> providers,
  137.                                final String[] equations) {
  138.         this(startDate, minDate, maxDate, mapper, type, model,
  139.              unmanaged, providers, equations,
  140.              remainingDimensions(model, unmanaged, providers, equations));
  141.     }

  142.     /** Creates a new instance of IntegratedEphemeris.
  143.      * @param startDate Start date of the integration (can be minDate or maxDate)
  144.      * @param minDate first date of the range
  145.      * @param maxDate last date of the range
  146.      * @param mapper mapper between raw double components and spacecraft state
  147.      * @param type type of orbit to output (mean or osculating)
  148.      * @param model underlying raw mathematical model
  149.      * @param unmanaged unmanaged additional states that must be simply copied
  150.      * @param providers providers for pre-integrated states
  151.      * @param equations names of additional equations
  152.      * @param dimensions dimensions of additional equations
  153.      * @since 11.1.2
  154.      */
  155.     public IntegratedEphemeris(final AbsoluteDate startDate,
  156.                                final AbsoluteDate minDate, final AbsoluteDate maxDate,
  157.                                final StateMapper mapper, final PropagationType type,
  158.                                final DenseOutputModel model,
  159.                                final DoubleArrayDictionary unmanaged,
  160.                                final List<AdditionalStateProvider> providers,
  161.                                final String[] equations, final int[] dimensions) {

  162.         super(mapper.getAttitudeProvider());

  163.         this.startDate = startDate;
  164.         this.minDate   = minDate;
  165.         this.maxDate   = maxDate;
  166.         this.mapper    = mapper;
  167.         this.type      = type;
  168.         this.model     = model;
  169.         this.unmanaged = unmanaged;

  170.         // set up the pre-integrated providers
  171.         for (final AdditionalStateProvider provider : providers) {
  172.             addAdditionalStateProvider(provider);
  173.         }

  174.         // set up providers to map the final elements of the model array to additional states
  175.         for (int i = 0; i < equations.length; ++i) {
  176.             addAdditionalStateProvider(new LocalGenerator(equations[i], i, dimensions[i]));
  177.         }

  178.     }

  179.     /** Compute remaining dimensions for additional equations.
  180.      * @param model underlying raw mathematical model
  181.      * @param unmanaged unmanaged additional states that must be simply copied
  182.      * @param providers providers for pre-integrated states
  183.      * @param equations names of additional equations
  184.      * @return dimensions of additional equations
  185.      * @deprecated as of 11.1.2 this method is temporary and should be removed
  186.      * when the calling constructors are removed
  187.      * @since 11.1.2
  188.      */
  189.     @Deprecated
  190.     private static int[] remainingDimensions(final DenseOutputModel model,
  191.                                              final DoubleArrayDictionary unmanaged,
  192.                                              final List<AdditionalStateProvider> providers,
  193.                                              final String[] equations) {
  194.         final ODEStateAndDerivative osd = model.getInterpolatedState(model.getInitialTime());
  195.         if (equations.length != osd.getNumberOfSecondaryStates()) {
  196.             throw new OrekitInternalError(null);
  197.         }
  198.         final int[] dimensions = new int[equations.length];
  199.         for (int i = 0; i < dimensions.length; ++i) {
  200.             dimensions[i] = osd.getSecondaryStateDimension(i + 1);
  201.         }
  202.         return dimensions;
  203.     }

  204.     /** Interpolate the model at some date.
  205.      * @param date desired interpolation date
  206.      * @return state interpolated at date
  207.      */
  208.     private ODEStateAndDerivative getInterpolatedState(final AbsoluteDate date) {

  209.         // compare using double precision instead of AbsoluteDate.compareTo(...)
  210.         // because time is expressed as a double when searching for events
  211.         if (date.compareTo(minDate.shiftedBy(-EXTRAPOLATION_TOLERANCE)) < 0) {
  212.             // date is outside of supported range
  213.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_BEFORE,
  214.                     date, minDate, maxDate, minDate.durationFrom(date));
  215.         }
  216.         if (date.compareTo(maxDate.shiftedBy(EXTRAPOLATION_TOLERANCE)) > 0) {
  217.             // date is outside of supported range
  218.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_AFTER,
  219.                     date, minDate, maxDate, date.durationFrom(maxDate));
  220.         }

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

  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
  226.         final ODEStateAndDerivative os = getInterpolatedState(date);
  227.         SpacecraftState state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
  228.                                                        os.getPrimaryState(), os.getPrimaryDerivative(),
  229.                                                        type);
  230.         for (DoubleArrayDictionary.Entry initial : unmanaged.getData()) {
  231.             state = state.addAdditionalState(initial.getKey(), initial.getValue());
  232.         }
  233.         return state;
  234.     }

  235.     /** {@inheritDoc} */
  236.     protected Orbit propagateOrbit(final AbsoluteDate date) {
  237.         return basicPropagate(date).getOrbit();
  238.     }

  239.     /** {@inheritDoc} */
  240.     protected double getMass(final AbsoluteDate date) {
  241.         return basicPropagate(date).getMass();
  242.     }

  243.     /** {@inheritDoc} */
  244.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  245.         return propagate(date).getPVCoordinates(frame);
  246.     }

  247.     /** Get the first date of the range.
  248.      * @return the first date of the range
  249.      */
  250.     public AbsoluteDate getMinDate() {
  251.         return minDate;
  252.     }

  253.     /** Get the last date of the range.
  254.      * @return the last date of the range
  255.      */
  256.     public AbsoluteDate getMaxDate() {
  257.         return maxDate;
  258.     }

  259.     @Override
  260.     public Frame getFrame() {
  261.         return this.mapper.getFrame();
  262.     }

  263.     /** {@inheritDoc} */
  264.     public void resetInitialState(final SpacecraftState state) {
  265.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  266.     }

  267.     /** {@inheritDoc} */
  268.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  269.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  270.     }

  271.     /** {@inheritDoc} */
  272.     @Override
  273.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  274.         super.setAttitudeProvider(attitudeProvider);
  275.         if (mapper != null) {
  276.             // At the construction, the mapper is not set yet
  277.             // However, if the attitude provider is changed afterwards, it must be changed in the mapper too
  278.             mapper.setAttitudeProvider(attitudeProvider);
  279.         }
  280.     }

  281.     /** {@inheritDoc} */
  282.     public SpacecraftState getInitialState() {
  283.         return updateAdditionalStates(basicPropagate(getMinDate()));
  284.     }

  285.     /** Local generator for additional state data. */
  286.     private class LocalGenerator implements AdditionalStateProvider {

  287.         /** Name of the additional state. */
  288.         private final String name;

  289.         /** Index of the additional state. */
  290.         private final int index;

  291.         /** Dimension of the additional state. */
  292.         private final int dimension;

  293.         /** Simple constructor.
  294.          * @param name name of the additional state
  295.          * @param index index of the additional state
  296.          * @param dimension dimension of the additional state
  297.          */
  298.         LocalGenerator(final String name, final int index, final int dimension) {
  299.             this.name      = name;
  300.             this.index     = index;
  301.             this.dimension = dimension;
  302.         }

  303.         /** {@inheritDoc} */
  304.         public String getName() {
  305.             return name;
  306.         }

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

  309.             // extract the part of the interpolated array corresponding to the additional state
  310.             final double[] combined = getInterpolatedState(state.getDate()).getSecondaryState(1);
  311.             return Arrays.copyOfRange(combined, index, index + dimension);

  312.         }

  313.     }

  314. }