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.     /** Names of additional equations.
  91.      * @since 11.2
  92.      */
  93.     private final String[] equations;

  94.     /** Dimensions of additional equations.
  95.      * @since 11.2
  96.      */
  97.     private final int[] dimensions;

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

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

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

  170.         super(mapper.getAttitudeProvider());

  171.         this.startDate = startDate;
  172.         this.minDate   = minDate;
  173.         this.maxDate   = maxDate;
  174.         this.mapper    = mapper;
  175.         this.type      = type;
  176.         this.model     = model;
  177.         this.unmanaged = unmanaged;

  178.         // set up the pre-integrated providers
  179.         for (final AdditionalStateProvider provider : providers) {
  180.             addAdditionalStateProvider(provider);
  181.         }

  182.         this.equations  = equations.clone();
  183.         this.dimensions = dimensions.clone();

  184.     }

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

  210.     /** Interpolate the model at some date.
  211.      * @param date desired interpolation date
  212.      * @return state interpolated at date
  213.      */
  214.     private ODEStateAndDerivative getInterpolatedState(final AbsoluteDate date) {

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

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

  228.     }

  229.     /** {@inheritDoc} */
  230.     @Override
  231.     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
  232.         final ODEStateAndDerivative os = getInterpolatedState(date);
  233.         SpacecraftState state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
  234.                                                        os.getPrimaryState(), os.getPrimaryDerivative(),
  235.                                                        type);
  236.         for (DoubleArrayDictionary.Entry initial : unmanaged.getData()) {
  237.             state = state.addAdditionalState(initial.getKey(), initial.getValue());
  238.         }
  239.         return state;
  240.     }

  241.     /** {@inheritDoc} */
  242.     protected Orbit propagateOrbit(final AbsoluteDate date) {
  243.         return basicPropagate(date).getOrbit();
  244.     }

  245.     /** {@inheritDoc} */
  246.     protected double getMass(final AbsoluteDate date) {
  247.         return basicPropagate(date).getMass();
  248.     }

  249.     /** {@inheritDoc} */
  250.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  251.         return propagate(date).getPVCoordinates(frame);
  252.     }

  253.     /** Get the first date of the range.
  254.      * @return the first date of the range
  255.      */
  256.     public AbsoluteDate getMinDate() {
  257.         return minDate;
  258.     }

  259.     /** Get the last date of the range.
  260.      * @return the last date of the range
  261.      */
  262.     public AbsoluteDate getMaxDate() {
  263.         return maxDate;
  264.     }

  265.     @Override
  266.     public Frame getFrame() {
  267.         return this.mapper.getFrame();
  268.     }

  269.     /** {@inheritDoc} */
  270.     public void resetInitialState(final SpacecraftState state) {
  271.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  272.     }

  273.     /** {@inheritDoc} */
  274.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  275.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  276.     }

  277.     /** {@inheritDoc} */
  278.     @Override
  279.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  280.         super.setAttitudeProvider(attitudeProvider);
  281.         if (mapper != null) {
  282.             // At the construction, the mapper is not set yet
  283.             // However, if the attitude provider is changed afterwards, it must be changed in the mapper too
  284.             mapper.setAttitudeProvider(attitudeProvider);
  285.         }
  286.     }

  287.     /** {@inheritDoc} */
  288.     public SpacecraftState getInitialState() {
  289.         return updateAdditionalStates(basicPropagate(getMinDate()));
  290.     }

  291.     /** {@inheritDoc} */
  292.     @Override
  293.     protected SpacecraftState updateAdditionalStates(final SpacecraftState original) {

  294.         SpacecraftState updated = super.updateAdditionalStates(original);

  295.         if (equations.length > 0) {
  296.             final ODEStateAndDerivative osd                = getInterpolatedState(updated.getDate());
  297.             final double[]              combinedState      = osd.getSecondaryState(1);
  298.             final double[]              combinedDerivative = osd.getSecondaryDerivative(1);
  299.             int index = 0;
  300.             for (int i = 0; i < equations.length; ++i) {
  301.                 final double[] state      = Arrays.copyOfRange(combinedState,      index, index + dimensions[i]);
  302.                 final double[] derivative = Arrays.copyOfRange(combinedDerivative, index, index + dimensions[i]);
  303.                 updated = updated.
  304.                           addAdditionalState(equations[i], state).
  305.                           addAdditionalStateDerivative(equations[i], derivative);
  306.                 index += dimensions[i];
  307.             }
  308.         }

  309.         return updated;

  310.     }

  311. }