Ephemeris.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.analytical;

  18. import java.io.Serializable;
  19. import java.util.List;
  20. import java.util.stream.Collectors;

  21. import org.hipparchus.exception.LocalizedCoreFormats;
  22. import org.hipparchus.exception.MathIllegalArgumentException;
  23. import org.hipparchus.linear.RealMatrix;
  24. import org.hipparchus.util.FastMath;
  25. import org.orekit.attitudes.Attitude;
  26. import org.orekit.attitudes.AttitudeProvider;
  27. import org.orekit.attitudes.InertialProvider;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.orbits.Orbit;
  32. import org.orekit.propagation.AbstractMatricesHarvester;
  33. import org.orekit.propagation.BoundedPropagator;
  34. import org.orekit.propagation.SpacecraftState;
  35. import org.orekit.time.AbsoluteDate;
  36. import org.orekit.utils.DoubleArrayDictionary;
  37. import org.orekit.utils.ImmutableTimeStampedCache;
  38. import org.orekit.utils.PVCoordinatesProvider;
  39. import org.orekit.utils.TimeStampedPVCoordinates;

  40. /** This class is designed to accept and handle tabulated orbital entries.
  41.  * Tabulated entries are classified and then extrapolated in way to obtain
  42.  * continuous output, with accuracy and computation methods configured by the user.
  43.  *
  44.  * @author Fabien Maussion
  45.  * @author Véronique Pommier-Maurussane
  46.  * @author Luc Maisonobe
  47.  */
  48. public class Ephemeris extends AbstractAnalyticalPropagator implements BoundedPropagator {

  49.     /** Default extrapolation time threshold: 1ms.
  50.      * @since 9.0
  51.      **/
  52.     public static final double DEFAULT_EXTRAPOLATION_THRESHOLD_SEC = 1e-3;

  53.      /** First date in range. */
  54.     private final AbsoluteDate minDate;

  55.     /** Last date in range. */
  56.     private final AbsoluteDate maxDate;

  57.     /** The extrapolation threshold beyond which the propagation will fail. **/
  58.     private final double extrapolationThreshold;

  59.     /** Reference frame. */
  60.     private final Frame frame;

  61.     /** Names of the additional states. */
  62.     private final String[] additional;

  63.     /** Local PV Provider used for computing attitude. **/
  64.     private LocalPVProvider pvProvider;

  65.     /** Thread-safe cache. */
  66.     private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

  67.     /** Constructor with tabulated states.
  68.      * <p>
  69.      * This constructor allows extrapolating outside of the states time span
  70.      * by up to the 1ms {@link #DEFAULT_EXTRAPOLATION_THRESHOLD_SEC default
  71.      * extrapolation threshold}.
  72.      * </p>
  73.      *
  74.      * @param states tabulates states
  75.      * @param interpolationPoints number of points to use in interpolation
  76.           * @exception MathIllegalArgumentException if the number of states is smaller than
  77.      * the number of points to use in interpolation
  78.      * @see #Ephemeris(List, int, double)
  79.      * @see #Ephemeris(List, int, double, AttitudeProvider)
  80.      */
  81.     public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
  82.         throws MathIllegalArgumentException {
  83.         this(states, interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC);
  84.     }

  85.     /** Constructor with tabulated states.
  86.      *
  87.      * @param states tabulates states
  88.      * @param interpolationPoints number of points to use in interpolation
  89.      * @param extrapolationThreshold the largest time difference in seconds between
  90.      * the start or stop boundary of the ephemeris bounds to be doing extrapolation
  91.      * @exception MathIllegalArgumentException if the number of states is smaller than
  92.      * the number of points to use in interpolation
  93.      * @since 9.0
  94.      * @see #Ephemeris(List, int, double, AttitudeProvider)
  95.      */
  96.     public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints,
  97.                      final double extrapolationThreshold)
  98.         throws MathIllegalArgumentException {
  99.         this(states, interpolationPoints, extrapolationThreshold,
  100.                 // if states is empty an exception will be thrown in the other constructor
  101.                 states.isEmpty() ? null : InertialProvider.of(states.get(0).getFrame()));
  102.     }

  103.     /** Constructor with tabulated states.
  104.      * @param states tabulates states
  105.      * @param interpolationPoints number of points to use in interpolation
  106.      * @param extrapolationThreshold the largest time difference in seconds between
  107.      * the start or stop boundary of the ephemeris bounds to be doing extrapolation
  108.      * @param attitudeProvider attitude law to use.
  109.      * @exception MathIllegalArgumentException if the number of states is smaller than
  110.      * the number of points to use in interpolation
  111.      * @since 10.1
  112.      */
  113.     public Ephemeris(final List<SpacecraftState> states,
  114.                      final int interpolationPoints,
  115.                      final double extrapolationThreshold,
  116.                      final AttitudeProvider attitudeProvider)
  117.         throws MathIllegalArgumentException {

  118.         super(attitudeProvider);

  119.         if (states.size() < interpolationPoints) {
  120.             throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
  121.                                                    states.size(), interpolationPoints);
  122.         }

  123.         final SpacecraftState s0 = states.get(0);
  124.         minDate = s0.getDate();
  125.         maxDate = states.get(states.size() - 1).getDate();
  126.         frame = s0.getFrame();

  127.         final List<DoubleArrayDictionary.Entry> as = s0.getAdditionalStatesValues().getData();
  128.         additional = new String[as.size()];
  129.         for (int i = 0; i < additional.length; ++i) {
  130.             additional[i] = as.get(i).getKey();
  131.         }

  132.         // check all states handle the same additional states
  133.         for (final SpacecraftState state : states) {
  134.             s0.ensureCompatibleAdditionalStates(state);
  135.         }

  136.         pvProvider = new LocalPVProvider(states, interpolationPoints, extrapolationThreshold);

  137.         // user needs to explicitly set attitude provider if they want to use one
  138.         setAttitudeProvider(null);

  139.         // set up cache
  140.         cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);

  141.         this.extrapolationThreshold = extrapolationThreshold;
  142.     }

  143.     /** Get the first date of the range.
  144.      * @return the first date of the range
  145.      */
  146.     public AbsoluteDate getMinDate() {
  147.         return minDate;
  148.     }

  149.     /** Get the last date of the range.
  150.      * @return the last date of the range
  151.      */
  152.     public AbsoluteDate getMaxDate() {
  153.         return maxDate;
  154.     }

  155.     /** Get the maximum timespan outside of the stored ephemeris that is allowed
  156.      * for extrapolation.
  157.      * @return the extrapolation threshold in seconds
  158.      */
  159.     public double getExtrapolationThreshold() {
  160.         return extrapolationThreshold;
  161.     }

  162.     @Override
  163.     public Frame getFrame() {
  164.         return frame;
  165.     }

  166.     @Override
  167.     /** {@inheritDoc} */
  168.     public SpacecraftState basicPropagate(final AbsoluteDate date) {
  169.         final SpacecraftState evaluatedState;

  170.         final AbsoluteDate central;
  171.         if (date.compareTo(minDate) < 0 && FastMath.abs(date.durationFrom(minDate)) <= extrapolationThreshold) {
  172.             // avoid TimeStampedCacheException as we are still within the tolerance before minDate
  173.             central = minDate;
  174.         } else if (date.compareTo(maxDate) > 0 && FastMath.abs(date.durationFrom(maxDate)) <= extrapolationThreshold) {
  175.             // avoid TimeStampedCacheException as we are still within the tolerance after maxDate
  176.             central = maxDate;
  177.         } else {
  178.             central = date;
  179.         }
  180.         final List<SpacecraftState> neighbors = cache.getNeighbors(central).collect(Collectors.toList());
  181.         evaluatedState = neighbors.get(0).interpolate(date, neighbors);

  182.         final AttitudeProvider attitudeProvider = getAttitudeProvider();

  183.         if (attitudeProvider == null) {
  184.             return evaluatedState;
  185.         } else {
  186.             pvProvider.setCurrentState(evaluatedState);
  187.             final Attitude calculatedAttitude = attitudeProvider.getAttitude(pvProvider, date,
  188.                                                                              evaluatedState.getFrame());

  189.             // Verify if orbit is defined
  190.             if (evaluatedState.isOrbitDefined()) {
  191.                 return new SpacecraftState(evaluatedState.getOrbit(), calculatedAttitude, evaluatedState.getMass(),
  192.                                            evaluatedState.getAdditionalStatesValues(), evaluatedState.getAdditionalStatesDerivatives());
  193.             } else {
  194.                 return new SpacecraftState(evaluatedState.getAbsPVA(), calculatedAttitude, evaluatedState.getMass(),
  195.                                            evaluatedState.getAdditionalStatesValues(), evaluatedState.getAdditionalStatesDerivatives());
  196.             }

  197.         }
  198.     }

  199.     /** {@inheritDoc} */
  200.     protected Orbit propagateOrbit(final AbsoluteDate date) {
  201.         return basicPropagate(date).getOrbit();
  202.     }

  203.     /** {@inheritDoc} */
  204.     protected double getMass(final AbsoluteDate date) {
  205.         return basicPropagate(date).getMass();
  206.     }

  207.     /** {@inheritDoc} */
  208.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f) {
  209.         return propagate(date).getPVCoordinates(f);
  210.     }

  211.     /** Try (and fail) to reset the initial state.
  212.      * <p>
  213.      * This method always throws an exception, as ephemerides cannot be reset.
  214.      * </p>
  215.      * @param state new initial state to consider
  216.      */
  217.     public void resetInitialState(final SpacecraftState state) {
  218.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  219.     }

  220.     /** {@inheritDoc} */
  221.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  222.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  223.     }

  224.     /** {@inheritDoc} */
  225.     public SpacecraftState getInitialState() {
  226.         return basicPropagate(getMinDate());
  227.     }

  228.     /** {@inheritDoc} */
  229.     @Override
  230.     public boolean isAdditionalStateManaged(final String name) {

  231.         // the additional state may be managed by a specific provider in the base class
  232.         if (super.isAdditionalStateManaged(name)) {
  233.             return true;
  234.         }

  235.         // the additional state may be managed in the states sample
  236.         for (final String a : additional) {
  237.             if (a.equals(name)) {
  238.                 return true;
  239.             }
  240.         }

  241.         return false;

  242.     }

  243.     /** {@inheritDoc} */
  244.     @Override
  245.     public String[] getManagedAdditionalStates() {
  246.         final String[] upperManaged = super.getManagedAdditionalStates();
  247.         final String[] managed = new String[upperManaged.length + additional.length];
  248.         System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
  249.         System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
  250.         return managed;
  251.     }

  252.     /** {@inheritDoc} */
  253.     @Override
  254.     protected AbstractMatricesHarvester createHarvester(final String stmName, final RealMatrix initialStm,
  255.                                                         final DoubleArrayDictionary initialJacobianColumns) {
  256.         // In order to not throw an Orekit exception during ephemeris based orbit determination
  257.         // The default behavior of the method is overrided to return a null parameter
  258.         return null;
  259.     }

  260.     /** Internal PVCoordinatesProvider for attitude computation. */
  261.     private static class LocalPVProvider implements PVCoordinatesProvider, Serializable {

  262.         /** Serializable UID. */
  263.         private static final long serialVersionUID = 20160115L;

  264.         /** Current state. */
  265.         private SpacecraftState currentState;

  266.         /** List of spacecraft states. */
  267.         private List<SpacecraftState> states;

  268.         /** Interpolation points number. */
  269.         private int interpolationPoints;

  270.         /** Extrapolation threshold. */
  271.         private double extrapolationThreshold;

  272.         /** Constructor.
  273.          * @param states list of spacecraft states
  274.          * @param interpolationPoints interpolation points number
  275.          * @param extrapolationThreshold extrapolation threshold value
  276.          */
  277.         LocalPVProvider(final List<SpacecraftState> states, final int interpolationPoints,
  278.                      final double extrapolationThreshold) {

  279.             this.states = states;
  280.             this.interpolationPoints = interpolationPoints;
  281.             this.extrapolationThreshold = extrapolationThreshold;
  282.         }

  283.         /** Get the current state.
  284.          * @return current state
  285.          */
  286.         public SpacecraftState getCurrentState() {
  287.             return currentState;
  288.         }

  289.         /** Set the current state.
  290.          * @param state state to set
  291.          */
  292.         public void setCurrentState(final SpacecraftState state) {
  293.             this.currentState = state;
  294.         }

  295.         /** {@inheritDoc} */
  296.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f) {
  297.             final double dt = getCurrentState().getDate().durationFrom(date);
  298.             final double closeEnoughTimeInSec = 1e-9;

  299.             if (FastMath.abs(dt) > closeEnoughTimeInSec) {

  300.                 // used in case of attitude transition, the attitude computed is not at the current date.
  301.                 final Ephemeris ephemeris = new Ephemeris(states, interpolationPoints, extrapolationThreshold, null);
  302.                 return ephemeris.getPVCoordinates(date, f);
  303.             }

  304.             return currentState.getPVCoordinates(f);

  305.         }

  306.     }

  307. }