Ephemeris.java

  1. /* Copyright 2002-2016 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.Set;

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

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

  46.     /** Serializable UID. */
  47.     private static final long serialVersionUID = 20151022L;

  48.      /** First date in range. */
  49.     private final AbsoluteDate minDate;

  50.     /** Last date in range. */
  51.     private final AbsoluteDate maxDate;

  52.     /** Reference frame. */
  53.     private final Frame frame;

  54.     /** Names of the additional states. */
  55.     private final String[] additional;

  56.     /** Local PV Provider used for computing attitude. **/
  57.     private LocalPVProvider pvProvider;

  58.     /** Thread-safe cache. */
  59.     private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

  60.     /** Constructor with tabulated states.
  61.      * @param states tabulates states
  62.      * @param interpolationPoints number of points to use in interpolation
  63.      * @exception OrekitException if some states have incompatible additional states
  64.      * @exception MathIllegalArgumentException if the number of states is smaller than
  65.      * the number of points to use in interpolation
  66.      */
  67.     public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
  68.         throws OrekitException, MathIllegalArgumentException {

  69.         super(DEFAULT_LAW);

  70.         if (states.size() < interpolationPoints) {
  71.             throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
  72.                                                    states.size(), interpolationPoints);
  73.         }

  74.         final SpacecraftState s0 = states.get(0);
  75.         minDate = s0.getDate();
  76.         maxDate = states.get(states.size() - 1).getDate();
  77.         frame = s0.getFrame();

  78.         final Set<String> names0 = s0.getAdditionalStates().keySet();
  79.         additional = names0.toArray(new String[names0.size()]);

  80.         // check all states handle the same additional states
  81.         for (final SpacecraftState state : states) {
  82.             s0.ensureCompatibleAdditionalStates(state);
  83.         }

  84.         pvProvider = new LocalPVProvider();

  85.         //User needs to explicitly set attitude provider if they want to use one
  86.         this.setAttitudeProvider(null);

  87.         // set up cache
  88.         cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);
  89.     }

  90.     /** Get the first date of the range.
  91.      * @return the first date of the range
  92.      */
  93.     public AbsoluteDate getMinDate() {
  94.         return minDate;
  95.     }

  96.     /** Get the last date of the range.
  97.      * @return the last date of the range
  98.      */
  99.     public AbsoluteDate getMaxDate() {
  100.         return maxDate;
  101.     }

  102.     @Override
  103.     public Frame getFrame() {
  104.         return this.frame;
  105.     }

  106.     @Override
  107.     /** {@inheritDoc} */
  108.     public SpacecraftState basicPropagate(final AbsoluteDate date) throws OrekitException {
  109.         final List<SpacecraftState> neighbors = cache.getNeighbors(date);
  110.         final SpacecraftState interpolatedState = neighbors.get(0).interpolate(date, neighbors);

  111.         final AttitudeProvider attitudeProvider = this.getAttitudeProvider();

  112.         if (attitudeProvider == null) {
  113.             return interpolatedState;
  114.         }
  115.         else {
  116.             pvProvider.setCurrentState(interpolatedState);
  117.             final Attitude calculatedAttitude = attitudeProvider.getAttitude(pvProvider, date, interpolatedState.getFrame());
  118.             return new SpacecraftState(interpolatedState.getOrbit(), calculatedAttitude, interpolatedState.getMass());
  119.         }
  120.     }

  121.     /** {@inheritDoc} */
  122.     protected Orbit propagateOrbit(final AbsoluteDate date) throws OrekitException {
  123.         return basicPropagate(date).getOrbit();
  124.     }

  125.     /** {@inheritDoc} */
  126.     protected double getMass(final AbsoluteDate date) throws OrekitException {
  127.         return basicPropagate(date).getMass();
  128.     }

  129.     /** {@inheritDoc} */
  130.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f)
  131.         throws OrekitException {
  132.         return propagate(date).getPVCoordinates(f);
  133.     }

  134.     /** Try (and fail) to reset the initial state.
  135.      * <p>
  136.      * This method always throws an exception, as ephemerides cannot be reset.
  137.      * </p>
  138.      * @param state new initial state to consider
  139.      * @exception OrekitException always thrown as ephemerides cannot be reset
  140.      */
  141.     public void resetInitialState(final SpacecraftState state)
  142.         throws OrekitException {
  143.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  144.     }

  145.     /** {@inheritDoc} */
  146.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward)
  147.         throws OrekitException {
  148.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  149.     }

  150.     /** {@inheritDoc} */
  151.     public SpacecraftState getInitialState() throws OrekitException {
  152.         return basicPropagate(getMinDate());
  153.     }

  154.     /** {@inheritDoc} */
  155.     @Override
  156.     public boolean isAdditionalStateManaged(final String name) {

  157.         // the additional state may be managed by a specific provider in the base class
  158.         if (super.isAdditionalStateManaged(name)) {
  159.             return true;
  160.         }

  161.         // the additional state may be managed in the states sample
  162.         for (final String a : additional) {
  163.             if (a.equals(name)) {
  164.                 return true;
  165.             }
  166.         }

  167.         return false;

  168.     }

  169.     /** {@inheritDoc} */
  170.     @Override
  171.     public String[] getManagedAdditionalStates() {
  172.         final String[] upperManaged = super.getManagedAdditionalStates();
  173.         final String[] managed = new String[upperManaged.length + additional.length];
  174.         System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
  175.         System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
  176.         return managed;
  177.     }

  178.     /** Replace the instance with a data transfer object for serialization.
  179.      * <p>
  180.      * This intermediate class serializes only the data needed for generation,
  181.      * but does <em>not</em> serializes the cache itself (in fact the cache is
  182.      * not serializable).
  183.      * </p>
  184.      * @return data transfer object that will be serialized
  185.      */
  186.     private Object writeReplace() {
  187.         return new DataTransferObject(cache.getAll(), cache.getNeighborsSize());
  188.     }

  189.     /** Internal class used only for serialization. */
  190.     private static class DataTransferObject implements Serializable {

  191.         /** Serializable UID. */
  192.         private static final long serialVersionUID = -8479036196711159270L;

  193.         /** Tabulates states. */
  194.         private final List<SpacecraftState> states;

  195.         /** Number of points to use in interpolation. */
  196.         private final int interpolationPoints;

  197.         /** Simple constructor.
  198.          * @param states tabulates states
  199.          * @param interpolationPoints number of points to use in interpolation
  200.          */
  201.         private DataTransferObject(final List<SpacecraftState> states, final int interpolationPoints) {
  202.             this.states              = states;
  203.             this.interpolationPoints = interpolationPoints;
  204.         }

  205.         /** Replace the deserialized data transfer object with a {@link Ephemeris}.
  206.          * @return replacement {@link Ephemeris}
  207.          */
  208.         private Object readResolve() {
  209.             try {
  210.                 // build a new provider, with an empty cache
  211.                 return new Ephemeris(states, interpolationPoints);
  212.             } catch (OrekitException oe) {
  213.                 // this should never happen
  214.                 throw new OrekitInternalError(oe);
  215.             }
  216.         }

  217.     }

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

  220.         /** Serializable UID. */
  221.         private static final long serialVersionUID = 20160115L;

  222.         /** Current state. */
  223.         private SpacecraftState currentState;

  224.         /** Get the current state.
  225.          * @return current state
  226.          */
  227.         public SpacecraftState getCurrentState() {
  228.             return currentState;
  229.         }

  230.         /** Set the current state.
  231.          * @param state state to set
  232.          */
  233.         public void setCurrentState(final SpacecraftState state) {
  234.             this.currentState = state;
  235.         }

  236.         /** {@inheritDoc} */
  237.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f)
  238.             throws OrekitException {
  239.             final double dt = this.getCurrentState().getDate().durationFrom(date);
  240.             final double closeEnoughTimeInSec = 1e-9;

  241.             if (FastMath.abs(dt) > closeEnoughTimeInSec) {
  242.                 throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  243.                                           FastMath.abs(dt), 0.0, closeEnoughTimeInSec);
  244.             }

  245.             return this.getCurrentState().getPVCoordinates(f);

  246.         }

  247.     }


  248. }