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.apache.commons.math3.exception.MathIllegalArgumentException;
  22. import org.apache.commons.math3.exception.OutOfRangeException;
  23. import org.apache.commons.math3.exception.util.LocalizedFormats;
  24. import org.apache.commons.math3.util.FastMath;
  25. import org.orekit.attitudes.Attitude;
  26. import org.orekit.attitudes.AttitudeProvider;
  27. import org.orekit.errors.OrekitException;
  28. import org.orekit.errors.OrekitInternalError;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.errors.PropagationException;
  31. import org.orekit.frames.Frame;
  32. import org.orekit.orbits.Orbit;
  33. import org.orekit.propagation.BoundedPropagator;
  34. import org.orekit.propagation.SpacecraftState;
  35. import org.orekit.time.AbsoluteDate;
  36. import org.orekit.utils.ImmutableTimeStampedCache;
  37. import org.orekit.utils.TimeStampedPVCoordinates;
  38. import org.orekit.utils.PVCoordinatesProvider;

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

  48.     /** Serializable UID. */
  49.     private static final long serialVersionUID = 20151022L;

  50.      /** First date in range. */
  51.     private final AbsoluteDate minDate;

  52.     /** Last date in range. */
  53.     private final AbsoluteDate maxDate;

  54.     /** Reference frame. */
  55.     private final Frame frame;

  56.     /** Names of the additional states. */
  57.     private final String[] additional;

  58.     /** Local PV Provider used for computing attitude. **/
  59.     private LocalPVProvider pvProvider;

  60.     /** Thread-safe cache. */
  61.     private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

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

  71.         super(DEFAULT_LAW);

  72.         if (states.size() < interpolationPoints) {
  73.             throw new MathIllegalArgumentException(LocalizedFormats.INSUFFICIENT_DIMENSION,
  74.                                                    states.size(), interpolationPoints);
  75.         }

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

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

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

  86.         pvProvider = new LocalPVProvider();

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

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

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

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

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

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

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

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

  123.         } catch (OrekitException tce) {
  124.             throw new PropagationException(tce);
  125.         }
  126.     }

  127.     /** {@inheritDoc} */
  128.     protected Orbit propagateOrbit(final AbsoluteDate date) throws PropagationException {
  129.         return basicPropagate(date).getOrbit();
  130.     }

  131.     /** {@inheritDoc} */
  132.     protected double getMass(final AbsoluteDate date) throws PropagationException {
  133.         return basicPropagate(date).getMass();
  134.     }

  135.     /** {@inheritDoc} */
  136.     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f)
  137.         throws OrekitException {
  138.         return propagate(date).getPVCoordinates(f);
  139.     }

  140.     /** Try (and fail) to reset the initial state.
  141.      * <p>
  142.      * This method always throws an exception, as ephemerides cannot be reset.
  143.      * </p>
  144.      * @param state new initial state to consider
  145.      * @exception PropagationException always thrown as ephemerides cannot be reset
  146.      */
  147.     public void resetInitialState(final SpacecraftState state)
  148.         throws PropagationException {
  149.         throw new PropagationException(OrekitMessages.NON_RESETABLE_STATE);
  150.     }

  151.     /** {@inheritDoc} */
  152.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward)
  153.         throws PropagationException {
  154.         throw new PropagationException(OrekitMessages.NON_RESETABLE_STATE);
  155.     }

  156.     /** {@inheritDoc} */
  157.     public SpacecraftState getInitialState() throws PropagationException {
  158.         return basicPropagate(getMinDate());
  159.     }

  160.     /** {@inheritDoc} */
  161.     @Override
  162.     public boolean isAdditionalStateManaged(final String name) {

  163.         // the additional state may be managed by a specific provider in the base class
  164.         if (super.isAdditionalStateManaged(name)) {
  165.             return true;
  166.         }

  167.         // the additional state may be managed in the states sample
  168.         for (final String a : additional) {
  169.             if (a.equals(name)) {
  170.                 return true;
  171.             }
  172.         }

  173.         return false;

  174.     }

  175.     /** {@inheritDoc} */
  176.     @Override
  177.     public String[] getManagedAdditionalStates() {
  178.         final String[] upperManaged = super.getManagedAdditionalStates();
  179.         final String[] managed = new String[upperManaged.length + additional.length];
  180.         System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
  181.         System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
  182.         return managed;
  183.     }

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

  195.     /** Internal class used only for serialization. */
  196.     private static class DataTransferObject implements Serializable {

  197.         /** Serializable UID. */
  198.         private static final long serialVersionUID = -8479036196711159270L;

  199.         /** Tabulates states. */
  200.         private final List<SpacecraftState> states;

  201.         /** Number of points to use in interpolation. */
  202.         private final int interpolationPoints;

  203.         /** Simple constructor.
  204.          * @param states tabulates states
  205.          * @param interpolationPoints number of points to use in interpolation
  206.          */
  207.         private DataTransferObject(final List<SpacecraftState> states, final int interpolationPoints) {
  208.             this.states              = states;
  209.             this.interpolationPoints = interpolationPoints;
  210.         }

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

  223.     }

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

  226.         /** Serializable UID. */
  227.         private static final long serialVersionUID = 20160115L;

  228.         /** Current state. */
  229.         private SpacecraftState currentState;

  230.         /** Get the current state.
  231.          * @return current state
  232.          */
  233.         public SpacecraftState getCurrentState() {
  234.             return currentState;
  235.         }

  236.         /** Set the current state.
  237.          * @param state state to set
  238.          */
  239.         public void setCurrentState(final SpacecraftState state) {
  240.             this.currentState = state;
  241.         }

  242.         /** {@inheritDoc} */
  243.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f)
  244.             throws OrekitException {
  245.             final double dt = this.getCurrentState().getDate().durationFrom(date);
  246.             final double closeEnoughTimeInSec = 1e-9;

  247.             if (FastMath.abs(dt) > closeEnoughTimeInSec) {
  248.                 throw new OrekitException(new OutOfRangeException(new Double(FastMath.abs(dt)), 0.0, closeEnoughTimeInSec));
  249.             }

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

  251.         }

  252.     }


  253. }