IntegratedEphemeris.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.integration;

  18. import java.io.NotSerializableException;
  19. import java.io.Serializable;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;

  25. import org.apache.commons.math3.ode.ContinuousOutputModel;
  26. import org.orekit.errors.OrekitException;
  27. import org.orekit.errors.OrekitExceptionWrapper;
  28. import org.orekit.errors.OrekitMessages;
  29. import org.orekit.errors.PropagationException;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.orbits.Orbit;
  32. import org.orekit.propagation.AdditionalStateProvider;
  33. import org.orekit.propagation.BoundedPropagator;
  34. import org.orekit.propagation.SpacecraftState;
  35. import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
  36. import org.orekit.time.AbsoluteDate;
  37. import org.orekit.utils.PVCoordinates;

  38. /** This class stores sequentially generated orbital parameters for
  39.  * later retrieval.
  40.  *
  41.  * <p>
  42.  * Instances of this class are built and then must be fed with the results
  43.  * provided by {@link org.orekit.propagation.Propagator Propagator} objects
  44.  * configured in {@link org.orekit.propagation.Propagator#setEphemerisMode()
  45.  * ephemeris generation mode}. Once propagation is o, random access to any
  46.  * intermediate state of the orbit throughout the propagation range is possible.
  47.  * </p>
  48.  * <p>
  49.  * A typical use case is for numerically integrated orbits, which can be used by
  50.  * algorithms that need to wander around according to their own algorithm without
  51.  * cumbersome tight links with the integrator.
  52.  * </p>
  53.  * <p>
  54.  * Another use case is persistence, as this class is one of the few propagators
  55.  * to be serializable.
  56.  * </p>
  57.  * <p>
  58.  * As this class implements the {@link org.orekit.propagation.Propagator Propagator}
  59.  * interface, it can itself be used in batch mode to build another instance of the
  60.  * same type. This is however not recommended since it would be a waste of resources.
  61.  * </p>
  62.  * <p>
  63.  * Note that this class stores all intermediate states along with interpolation
  64.  * models, so it may be memory intensive.
  65.  * </p>
  66.  *
  67.  * @see org.orekit.propagation.numerical.NumericalPropagator
  68.  * @author Mathieu Rom&eacute;ro
  69.  * @author Luc Maisonobe
  70.  * @author V&eacute;ronique Pommier-Maurussane
  71.  */
  72. public class IntegratedEphemeris
  73.     extends AbstractAnalyticalPropagator implements BoundedPropagator, Serializable  {

  74.     /** Serializable UID. */
  75.     private static final long serialVersionUID = 20130613L;

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

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

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

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

  84.     /** Underlying raw mathematical model. */
  85.     private ContinuousOutputModel model;

  86.     /** Unmanaged additional states that must be simply copied. */
  87.     private final Map<String, double[]> unmanaged;

  88.     /** Creates a new instance of IntegratedEphemeris.
  89.      * @param startDate Start date of the integration (can be minDate or maxDate)
  90.      * @param minDate first date of the range
  91.      * @param maxDate last date of the range
  92.      * @param mapper mapper between raw double components and spacecraft state
  93.      * @param model underlying raw mathematical model
  94.      * @param unmanaged unmanaged additional states that must be simply copied
  95.      * @param providers providers for pre-integrated states
  96.      * @param equations names of additional equations
  97.      * @exception OrekitException if several providers have the same name
  98.      */
  99.     public IntegratedEphemeris(final AbsoluteDate startDate,
  100.                                final AbsoluteDate minDate, final AbsoluteDate maxDate,
  101.                                final StateMapper mapper, final ContinuousOutputModel model,
  102.                                final Map<String, double[]> unmanaged,
  103.                                final List<AdditionalStateProvider> providers,
  104.                                final String[] equations)
  105.         throws OrekitException {

  106.         super(mapper.getAttitudeProvider());

  107.         this.startDate = startDate;
  108.         this.minDate   = minDate;
  109.         this.maxDate   = maxDate;
  110.         this.mapper    = mapper;
  111.         this.model     = model;
  112.         this.unmanaged = unmanaged;

  113.         // set up the pre-integrated providers
  114.         for (final AdditionalStateProvider provider : providers) {
  115.             addAdditionalStateProvider(provider);
  116.         }

  117.         // set up providers to map the final elements of the model array to additional states
  118.         for (int i = 0; i < equations.length; ++i) {
  119.             addAdditionalStateProvider(new LocalProvider(equations[i], i));
  120.         }

  121.     }

  122.     /** Set up the model at some interpolation date.
  123.      * @param date desired interpolation date
  124.      * @exception PropagationException if specified date is outside
  125.      * of supported range
  126.      */
  127.     private void setInterpolationDate(final AbsoluteDate date)
  128.         throws PropagationException {

  129.         if (date.equals(startDate.shiftedBy(model.getInterpolatedTime()))) {
  130.             // the current model date is already the desired one
  131.             return;
  132.         }

  133.         if ((date.compareTo(minDate) < 0) || (date.compareTo(maxDate) > 0)) {
  134.             // date is outside of supported range
  135.             throw new PropagationException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE,
  136.                                            date, minDate, maxDate);
  137.         }

  138.         // reset interpolation model to the desired date
  139.         model.setInterpolatedTime(date.durationFrom(startDate));

  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     protected SpacecraftState basicPropagate(final AbsoluteDate date)
  144.         throws PropagationException {
  145.         try {
  146.             setInterpolationDate(date);
  147.             SpacecraftState state = mapper.mapArrayToState(model.getInterpolatedTime(),
  148.                                                            model.getInterpolatedState());
  149.             for (Map.Entry<String, double[]> initial : unmanaged.entrySet()) {
  150.                 state = state.addAdditionalState(initial.getKey(), initial.getValue());
  151.             }
  152.             return state;
  153.         } catch (OrekitExceptionWrapper oew) {
  154.             if (oew.getException() instanceof PropagationException) {
  155.                 throw (PropagationException) oew.getException();
  156.             } else {
  157.                 throw new PropagationException(oew.getException());
  158.             }
  159.         } catch (OrekitException oe) {
  160.             if (oe instanceof PropagationException) {
  161.                 throw (PropagationException) oe;
  162.             } else {
  163.                 throw new PropagationException(oe);
  164.             }
  165.         }
  166.     }

  167.     /** {@inheritDoc} */
  168.     protected Orbit propagateOrbit(final AbsoluteDate date)
  169.         throws PropagationException {
  170.         return basicPropagate(date).getOrbit();
  171.     }

  172.     /** {@inheritDoc} */
  173.     protected double getMass(final AbsoluteDate date) throws PropagationException {
  174.         return basicPropagate(date).getMass();
  175.     }

  176.     /** {@inheritDoc} */
  177.     public PVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
  178.         throws OrekitException {
  179.         return propagate(date).getPVCoordinates(frame);
  180.     }

  181.     /** Get the first date of the range.
  182.      * @return the first date of the range
  183.      */
  184.     public AbsoluteDate getMinDate() {
  185.         return minDate;
  186.     }

  187.     /** Get the last date of the range.
  188.      * @return the last date of the range
  189.      */
  190.     public AbsoluteDate getMaxDate() {
  191.         return maxDate;
  192.     }

  193.     @Override
  194.     public Frame getFrame() {
  195.         return this.mapper.getFrame();
  196.     }

  197.     /** {@inheritDoc} */
  198.     public void resetInitialState(final SpacecraftState state)
  199.         throws PropagationException {
  200.         throw new PropagationException(OrekitMessages.NON_RESETABLE_STATE);
  201.     }

  202.     /** {@inheritDoc} */
  203.     public SpacecraftState getInitialState() throws PropagationException {
  204.         return updateAdditionalStates(basicPropagate(getMinDate()));
  205.     }

  206.     /** Replace the instance with a data transfer object for serialization.
  207.      * @return data transfer object that will be serialized
  208.      * @exception NotSerializableException if the state mapper cannot be serialized (typically for DSST propagator)
  209.      */
  210.     private Object writeReplace() throws NotSerializableException {

  211.         // unmanaged additional states
  212.         final String[]   unmanagedNames  = new String[unmanaged.size()];
  213.         final double[][] unmanagedValues = new double[unmanaged.size()][];
  214.         int i = 0;
  215.         for (Map.Entry<String, double[]> entry : unmanaged.entrySet()) {
  216.             unmanagedNames[i]  = entry.getKey();
  217.             unmanagedValues[i] = entry.getValue();
  218.             ++i;
  219.         }

  220.         // managed states providers
  221.         final List<AdditionalStateProvider> serializableProviders = new ArrayList<AdditionalStateProvider>();
  222.         final List<String> equationNames = new ArrayList<String>();
  223.         for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
  224.             if (provider instanceof LocalProvider) {
  225.                 equationNames.add(((LocalProvider) provider).getName());
  226.             } else if (provider instanceof Serializable) {
  227.                 serializableProviders.add(provider);
  228.             }
  229.         }

  230.         return new DataTransferObject(startDate, minDate, maxDate, mapper, model,
  231.                                       unmanagedNames, unmanagedValues,
  232.                                       serializableProviders.toArray(new AdditionalStateProvider[serializableProviders.size()]),
  233.                                       equationNames.toArray(new String[equationNames.size()]));

  234.     }

  235.     /** Local provider for additional state data. */
  236.     private class LocalProvider implements AdditionalStateProvider {

  237.         /** Name of the additional state. */
  238.         private final String name;

  239.         /** Index of the additional state. */
  240.         private final int index;

  241.         /** Simple constructor.
  242.          * @param name name of the additional state
  243.          * @param index index of the additional state
  244.          */
  245.         public LocalProvider(final String name, final int index) {
  246.             this.name  = name;
  247.             this.index = index;
  248.         }

  249.         /** {@inheritDoc} */
  250.         public String getName() {
  251.             return name;
  252.         }

  253.         /** {@inheritDoc} */
  254.         public double[] getAdditionalState(final SpacecraftState state)
  255.             throws PropagationException {

  256.             // set the model date
  257.             setInterpolationDate(state.getDate());

  258.             // extract the part of the interpolated array corresponding to the additional state
  259.             return model.getInterpolatedSecondaryState(index);

  260.         }

  261.     }

  262.     /** Internal class used only for serialization. */
  263.     private static class DataTransferObject implements Serializable {

  264.         /** Serializable UID. */
  265.         private static final long serialVersionUID = 20130621L;

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

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

  270.         /** First date of the range. */
  271.         private final AbsoluteDate minDate;

  272.         /** Last date of the range. */
  273.         private final AbsoluteDate maxDate;

  274.         /** Underlying raw mathematical model. */
  275.         private final ContinuousOutputModel model;

  276.         /** Names of unmanaged additional states that must be simply copied. */
  277.         private final String[] unmanagedNames;

  278.         /** Values of unmanaged additional states that must be simply copied. */
  279.         private final double[][] unmanagedValues;

  280.         /** Names of additional equations. */
  281.         private final String[] equations;

  282.         /** Providers for pre-integrated states. */
  283.         private final AdditionalStateProvider[] providers;

  284.         /** Simple constructor.
  285.          * @param startDate Start date of the integration (can be minDate or maxDate)
  286.          * @param minDate first date of the range
  287.          * @param maxDate last date of the range
  288.          * @param mapper mapper between raw double components and spacecraft state
  289.          * @param model underlying raw mathematical model
  290.          * @param unmanagedNames names of unmanaged additional states that must be simply copied
  291.          * @param unmanagedValues values of unmanaged additional states that must be simply copied
  292.          * @param providers providers for pre-integrated states
  293.          * @param equations names of additional equations
  294.          */
  295.         public DataTransferObject(final AbsoluteDate startDate,
  296.                                   final AbsoluteDate minDate, final AbsoluteDate maxDate,
  297.                                   final StateMapper mapper, final ContinuousOutputModel model,
  298.                                   final String[] unmanagedNames, final double[][] unmanagedValues,
  299.                                   final AdditionalStateProvider[] providers,
  300.                                   final String[] equations) {
  301.             this.startDate       = startDate;
  302.             this.minDate         = minDate;
  303.             this.maxDate         = maxDate;
  304.             this.mapper          = mapper;
  305.             this.model           = model;
  306.             this.unmanagedNames  = unmanagedNames;
  307.             this.unmanagedValues = unmanagedValues;
  308.             this.providers       = providers;
  309.             this.equations       = equations;
  310.         }

  311.         /** Replace the deserialized data transfer object with a {@link IntegratedEphemeris}.
  312.          * @return replacement {@link IntegratedEphemeris}
  313.          */
  314.         private Object readResolve() {
  315.             try {
  316.                 final Map<String, double[]> unmanaged = new HashMap<String, double[]>(unmanagedNames.length);
  317.                 for (int i = 0; i < unmanagedNames.length; ++i) {
  318.                     unmanaged.put(unmanagedNames[i], unmanagedValues[i]);
  319.                 }
  320.                 return new IntegratedEphemeris(startDate, minDate, maxDate, mapper, model,
  321.                                                unmanaged, Arrays.asList(providers), equations);
  322.             } catch (OrekitException oe) {
  323.                 throw OrekitException.createInternalError(oe);
  324.             }
  325.         }

  326.     }

  327. }