Ephemeris.java

  1. /* Copyright 2002-2013 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.util.LocalizedFormats;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.errors.OrekitMessages;
  25. import org.orekit.errors.PropagationException;
  26. import org.orekit.frames.Frame;
  27. import org.orekit.orbits.Orbit;
  28. import org.orekit.propagation.BoundedPropagator;
  29. import org.orekit.propagation.SpacecraftState;
  30. import org.orekit.time.AbsoluteDate;
  31. import org.orekit.utils.ImmutableTimeStampedCache;
  32. import org.orekit.utils.PVCoordinates;

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

  42.     /** First date in range. */
  43.     private final AbsoluteDate minDate;

  44.     /** Last date in range. */
  45.     private final AbsoluteDate maxDate;

  46.     /** Reference frame. */
  47.     private final Frame frame;

  48.     /** Names of the additional states. */
  49.     private final String[] additional;

  50.     /** Thread-safe cache. */
  51.     private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

  52.     /** Constructor with tabulated states.
  53.      * @param states tabulates states
  54.      * @param interpolationPoints number of points to use in interpolation
  55.      * @exception OrekitException if some states have incompatible additional states
  56.      * @exception MathIllegalArgumentException if the number of states is smaller than
  57.      * the number of points to use in interpolation
  58.      */
  59.     public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
  60.         throws OrekitException, MathIllegalArgumentException {

  61.         super(DEFAULT_LAW);

  62.         if (states.size() < interpolationPoints) {
  63.             throw new MathIllegalArgumentException(LocalizedFormats.INSUFFICIENT_DIMENSION,
  64.                                                    states.size(), interpolationPoints);
  65.         }

  66.         final SpacecraftState s0 = states.get(0);
  67.         minDate = s0.getDate();
  68.         maxDate = states.get(states.size() - 1).getDate();
  69.         frame = s0.getFrame();

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

  72.         // check all states handle the same additional states
  73.         for (final SpacecraftState state : states) {
  74.             s0.ensureCompatibleAdditionalStates(state);
  75.         }

  76.         // set up cache
  77.         cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);
  78.     }

  79.     /** Get the first date of the range.
  80.      * @return the first date of the range
  81.      */
  82.     public AbsoluteDate getMinDate() {
  83.         return minDate;
  84.     }

  85.     /** Get the last date of the range.
  86.      * @return the last date of the range
  87.      */
  88.     public AbsoluteDate getMaxDate() {
  89.         return maxDate;
  90.     }

  91.     @Override
  92.     public Frame getFrame() {
  93.         return this.frame;
  94.     }

  95.     @Override
  96.     /** {@inheritDoc} */
  97.     public SpacecraftState basicPropagate(final AbsoluteDate date) throws PropagationException {
  98.         try {
  99.             final List<SpacecraftState> neighbors = cache.getNeighbors(date);
  100.             return neighbors.get(0).interpolate(date, neighbors);
  101.         } catch (OrekitException tce) {
  102.             throw new PropagationException(tce);
  103.         }
  104.     }

  105.     /** {@inheritDoc} */
  106.     protected Orbit propagateOrbit(final AbsoluteDate date) throws PropagationException {
  107.         return basicPropagate(date).getOrbit();
  108.     }

  109.     /** {@inheritDoc} */
  110.     protected double getMass(final AbsoluteDate date) throws PropagationException {
  111.         return basicPropagate(date).getMass();
  112.     }

  113.     /** {@inheritDoc} */
  114.     public PVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f)
  115.         throws OrekitException {
  116.         return propagate(date).getPVCoordinates(f);
  117.     }

  118.     /** Try (and fail) to reset the initial state.
  119.      * <p>
  120.      * This method always throws an exception, as ephemerides cannot be reset.
  121.      * </p>
  122.      * @param state new initial state to consider
  123.      * @exception PropagationException always thrown as ephemerides cannot be reset
  124.      */
  125.     public void resetInitialState(final SpacecraftState state)
  126.         throws PropagationException {
  127.         throw new PropagationException(OrekitMessages.NON_RESETABLE_STATE);
  128.     }

  129.     /** {@inheritDoc} */
  130.     public SpacecraftState getInitialState() throws PropagationException {
  131.         return basicPropagate(getMinDate());
  132.     }

  133.     /** {@inheritDoc} */
  134.     @Override
  135.     public boolean isAdditionalStateManaged(final String name) {

  136.         // the additional state may be managed by a specific provider in the base class
  137.         if (super.isAdditionalStateManaged(name)) {
  138.             return true;
  139.         }

  140.         // the additional state may be managed in the states sample
  141.         for (final String a : additional) {
  142.             if (a.equals(name)) {
  143.                 return true;
  144.             }
  145.         }

  146.         return false;

  147.     }

  148.     /** {@inheritDoc} */
  149.     @Override
  150.     public String[] getManagedAdditionalStates() {
  151.         final String[] upperManaged = super.getManagedAdditionalStates();
  152.         final String[] managed = new String[upperManaged.length + additional.length];
  153.         System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
  154.         System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
  155.         return managed;
  156.     }

  157.     /** Replace the instance with a data transfer object for serialization.
  158.      * <p>
  159.      * This intermediate class serializes only the data needed for generation,
  160.      * but does <em>not</em> serializes the cache itself (in fact the cache is
  161.      * not serializable).
  162.      * </p>
  163.      * @return data transfer object that will be serialized
  164.      */
  165.     private Object writeReplace() {
  166.         return new DataTransferObject(cache.getAll(), cache.getNeighborsSize());
  167.     }

  168.     /** Internal class used only for serialization. */
  169.     private static class DataTransferObject implements Serializable {

  170.         /** Serializable UID. */
  171.         private static final long serialVersionUID = -8479036196711159270L;

  172.         /** Tabulates states. */
  173.         private final List<SpacecraftState> states;

  174.         /** Number of points to use in interpolation. */
  175.         private final int interpolationPoints;

  176.         /** Simple constructor.
  177.          * @param states tabulates states
  178.          * @param interpolationPoints number of points to use in interpolation
  179.          */
  180.         private DataTransferObject(final List<SpacecraftState> states, final int interpolationPoints) {
  181.             this.states              = states;
  182.             this.interpolationPoints = interpolationPoints;
  183.         }

  184.         /** Replace the deserialized data transfer object with a {@link Ephemeris}.
  185.          * @return replacement {@link Ephemeris}
  186.          */
  187.         private Object readResolve() {
  188.             try {
  189.                 // build a new provider, with an empty cache
  190.                 return new Ephemeris(states, interpolationPoints);
  191.             } catch (OrekitException oe) {
  192.                 // this should never happen
  193.                 throw OrekitException.createInternalError(oe);
  194.             }
  195.         }

  196.     }

  197. }