IntegratedEphemeris.java

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

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

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

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

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

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

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

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

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

  87.     /** Names of additional equations.
  88.      * @since 11.2
  89.      */
  90.     private final String[] equations;

  91.     /** Dimensions of additional equations.
  92.      * @since 11.2
  93.      */
  94.     private final int[] dimensions;

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

  115.         super(mapper.getAttitudeProvider());

  116.         this.startDate = startDate;
  117.         this.minDate   = minDate;
  118.         this.maxDate   = maxDate;
  119.         this.mapper    = mapper;
  120.         this.type      = type;
  121.         this.model     = model;
  122.         this.unmanaged = unmanaged;

  123.         // set up the pre-integrated providers
  124.         for (final AdditionalStateProvider provider : providers) {
  125.             addAdditionalStateProvider(provider);
  126.         }

  127.         this.equations  = equations.clone();
  128.         this.dimensions = dimensions.clone();

  129.         // set up initial state
  130.         super.resetInitialState(getInitialState());

  131.     }

  132.     /** Interpolate the model at some date.
  133.      * @param date desired interpolation date
  134.      * @return state interpolated at date
  135.      */
  136.     private ODEStateAndDerivative getInterpolatedState(final AbsoluteDate date) {

  137.         // compare using double precision instead of AbsoluteDate.compareTo(...)
  138.         // because time is expressed as a double when searching for events
  139.         if (date.compareTo(minDate.shiftedBy(-EXTRAPOLATION_TOLERANCE)) < 0) {
  140.             // date is outside of supported range
  141.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_BEFORE,
  142.                     date, minDate, maxDate, minDate.durationFrom(date));
  143.         }
  144.         if (date.compareTo(maxDate.shiftedBy(EXTRAPOLATION_TOLERANCE)) > 0) {
  145.             // date is outside of supported range
  146.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_AFTER,
  147.                     date, minDate, maxDate, date.durationFrom(maxDate));
  148.         }

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

  150.     }

  151.     /** {@inheritDoc} */
  152.     @Override
  153.     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
  154.         final ODEStateAndDerivative os = getInterpolatedState(date);
  155.         SpacecraftState state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
  156.                                                        os.getPrimaryState(), os.getPrimaryDerivative(),
  157.                                                        type);
  158.         for (DoubleArrayDictionary.Entry initial : unmanaged.getData()) {
  159.             state = state.addAdditionalState(initial.getKey(), initial.getValue());
  160.         }
  161.         return state;
  162.     }

  163.     /** {@inheritDoc} */
  164.     protected Orbit propagateOrbit(final AbsoluteDate date) {
  165.         return basicPropagate(date).getOrbit();
  166.     }

  167.     /** {@inheritDoc} */
  168.     protected double getMass(final AbsoluteDate date) {
  169.         return basicPropagate(date).getMass();
  170.     }

  171.     /** Get the first date of the range.
  172.      * @return the first date of the range
  173.      */
  174.     public AbsoluteDate getMinDate() {
  175.         return minDate;
  176.     }

  177.     /** Get the last date of the range.
  178.      * @return the last date of the range
  179.      */
  180.     public AbsoluteDate getMaxDate() {
  181.         return maxDate;
  182.     }

  183.     @Override
  184.     public Frame getFrame() {
  185.         return this.mapper.getFrame();
  186.     }

  187.     /** {@inheritDoc} */
  188.     public void resetInitialState(final SpacecraftState state) {
  189.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  190.     }

  191.     /** {@inheritDoc} */
  192.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  193.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  194.     }

  195.     /** {@inheritDoc} */
  196.     @Override
  197.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  198.         super.setAttitudeProvider(attitudeProvider);
  199.         if (mapper != null) {
  200.             // At the construction, the mapper is not set yet
  201.             // However, if the attitude provider is changed afterwards, it must be changed in the mapper too
  202.             mapper.setAttitudeProvider(attitudeProvider);
  203.         }
  204.     }

  205.     /** {@inheritDoc} */
  206.     public SpacecraftState getInitialState() {
  207.         return updateAdditionalStates(basicPropagate(getMinDate()));
  208.     }

  209.     /** {@inheritDoc} */
  210.     @Override
  211.     protected SpacecraftState updateAdditionalStates(final SpacecraftState original) {

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

  213.         if (equations.length > 0) {
  214.             final ODEStateAndDerivative osd                = getInterpolatedState(updated.getDate());
  215.             final double[]              combinedState      = osd.getSecondaryState(1);
  216.             final double[]              combinedDerivative = osd.getSecondaryDerivative(1);
  217.             int index = 0;
  218.             for (int i = 0; i < equations.length; ++i) {
  219.                 final double[] state      = Arrays.copyOfRange(combinedState,      index, index + dimensions[i]);
  220.                 final double[] derivative = Arrays.copyOfRange(combinedDerivative, index, index + dimensions[i]);
  221.                 updated = updated.
  222.                           addAdditionalState(equations[i], state).
  223.                           addAdditionalStateDerivative(equations[i], derivative);
  224.                 index += dimensions[i];
  225.             }
  226.         }

  227.         return updated;

  228.     }

  229. }