KeplerianPropagator.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.NotSerializableException;
  19. import java.io.Serializable;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import java.util.SortedSet;

  23. import org.orekit.attitudes.AttitudeProvider;
  24. import org.orekit.errors.OrekitException;
  25. import org.orekit.errors.OrekitInternalError;
  26. import org.orekit.errors.PropagationException;
  27. import org.orekit.orbits.Orbit;
  28. import org.orekit.orbits.OrbitType;
  29. import org.orekit.orbits.PositionAngle;
  30. import org.orekit.propagation.AdditionalStateProvider;
  31. import org.orekit.propagation.SpacecraftState;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.utils.TimeSpanMap;

  34. /** Simple keplerian orbit propagator.
  35.  * @see Orbit
  36.  * @author Guylaine Prat
  37.  */
  38. public class KeplerianPropagator extends AbstractAnalyticalPropagator implements Serializable {

  39.     /** Serializable UID. */
  40.     private static final long serialVersionUID = 20151117L;

  41.     /** Initial state. */
  42.     private SpacecraftState initialState;

  43.     /** All states. */
  44.     private transient TimeSpanMap<SpacecraftState> states;

  45.     /** Build a propagator from orbit only.
  46.      * <p>The central attraction coefficient μ is set to the same value used
  47.      * for the initial orbit definition. Mass and attitude provider are set to
  48.      * unspecified non-null arbitrary values.</p>
  49.      * @param initialOrbit initial orbit
  50.      * @exception PropagationException if initial attitude cannot be computed
  51.      */
  52.     public KeplerianPropagator(final Orbit initialOrbit)
  53.         throws PropagationException {
  54.         this(initialOrbit, DEFAULT_LAW, initialOrbit.getMu(), DEFAULT_MASS);
  55.     }

  56.     /** Build a propagator from orbit and central attraction coefficient μ.
  57.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  58.      * @param initialOrbit initial orbit
  59.      * @param mu central attraction coefficient (m³/s²)
  60.      * @exception PropagationException if initial attitude cannot be computed
  61.      */
  62.     public KeplerianPropagator(final Orbit initialOrbit, final double mu)
  63.         throws PropagationException {
  64.         this(initialOrbit, DEFAULT_LAW, mu, DEFAULT_MASS);
  65.     }

  66.     /** Build a propagator from orbit and attitude provider.
  67.      * <p>The central attraction coefficient μ is set to the same value
  68.      * used for the initial orbit definition. Mass is set to an unspecified
  69.      * non-null arbitrary value.</p>
  70.      * @param initialOrbit initial orbit
  71.      * @param attitudeProv  attitude provider
  72.      * @exception PropagationException if initial attitude cannot be computed
  73.      */
  74.     public KeplerianPropagator(final Orbit initialOrbit,
  75.                                final AttitudeProvider attitudeProv)
  76.         throws PropagationException {
  77.         this(initialOrbit, attitudeProv, initialOrbit.getMu(), DEFAULT_MASS);
  78.     }

  79.     /** Build a propagator from orbit, attitude provider and central attraction
  80.      * coefficient μ.
  81.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  82.      * @param initialOrbit initial orbit
  83.      * @param attitudeProv attitude provider
  84.      * @param mu central attraction coefficient (m³/s²)
  85.      * @exception PropagationException if initial attitude cannot be computed
  86.      */
  87.     public KeplerianPropagator(final Orbit initialOrbit,
  88.                                final AttitudeProvider attitudeProv,
  89.                                final double mu)
  90.         throws PropagationException {
  91.         this(initialOrbit, attitudeProv, mu, DEFAULT_MASS);
  92.     }

  93.     /** Build propagator from orbit, attitude provider, central attraction
  94.      * coefficient μ and mass.
  95.      * @param initialOrbit initial orbit
  96.      * @param attitudeProv attitude provider
  97.      * @param mu central attraction coefficient (m³/s²)
  98.      * @param mass spacecraft mass (kg)
  99.      * @exception PropagationException if initial attitude cannot be computed
  100.      */
  101.     public KeplerianPropagator(final Orbit initialOrbit, final AttitudeProvider attitudeProv,
  102.                                final double mu, final double mass)
  103.         throws PropagationException {

  104.         super(attitudeProv);

  105.         try {

  106.             // ensure the orbit use the specified mu
  107.             final OrbitType type = initialOrbit.getType();
  108.             final double[] stateVector = new double[6];
  109.             type.mapOrbitToArray(initialOrbit, PositionAngle.TRUE, stateVector);
  110.             final Orbit orbit = type.mapArrayToOrbit(stateVector, PositionAngle.TRUE,
  111.                                                      initialOrbit.getDate(), mu, initialOrbit.getFrame());

  112.             resetInitialState(new SpacecraftState(orbit,
  113.                                                    getAttitudeProvider().getAttitude(orbit,
  114.                                                                                      orbit.getDate(),
  115.                                                                                      orbit.getFrame()),
  116.                                                    mass));

  117.         } catch (OrekitException oe) {
  118.             throw new PropagationException(oe);
  119.         }
  120.     }

  121.     /** {@inheritDoc} */
  122.     public void resetInitialState(final SpacecraftState state)
  123.         throws PropagationException {
  124.         super.resetInitialState(state);
  125.         initialState   = state;
  126.         states         = new TimeSpanMap<SpacecraftState>(initialState);
  127.     }

  128.     /** {@inheritDoc} */
  129.     protected void resetIntermediateState(final SpacecraftState state, final boolean forward)
  130.         throws PropagationException {
  131.         super.resetIntermediateState(state, forward);
  132.         if (forward) {
  133.             states.addValidAfter(state, state.getDate());
  134.         } else {
  135.             states.addValidBefore(state, state.getDate());
  136.         }
  137.     }

  138.     /** {@inheritDoc} */
  139.     protected Orbit propagateOrbit(final AbsoluteDate date)
  140.         throws PropagationException {

  141.         // propagate orbit
  142.         Orbit orbit = states.get(date).getOrbit();
  143.         do {
  144.             // we use a loop here to compensate for very small date shifts error
  145.             // that occur with long propagation time
  146.             orbit = orbit.shiftedBy(date.durationFrom(orbit.getDate()));
  147.         } while(!date.equals(orbit.getDate()));

  148.         return orbit;

  149.     }

  150.     /** {@inheritDoc}*/
  151.     protected double getMass(final AbsoluteDate date) {
  152.         return states.get(date).getMass();
  153.     }

  154.     /** Replace the instance with a data transfer object for serialization.
  155.      * @return data transfer object that will be serialized
  156.      * @exception NotSerializableException if an additional state provider is not serializable
  157.      */
  158.     private Object writeReplace() throws NotSerializableException {
  159.         try {

  160.             // managed states providers
  161.             final List<AdditionalStateProvider> serializableProviders = new ArrayList<AdditionalStateProvider>();
  162.             for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
  163.                 if (provider instanceof Serializable) {
  164.                     serializableProviders.add(provider);
  165.                 } else {
  166.                     throw new NotSerializableException(provider.getClass().getName());
  167.                 }
  168.             }

  169.             // states transitions
  170.             final AbsoluteDate[]    transitionDates;
  171.             final SpacecraftState[] allStates;
  172.             final SortedSet<TimeSpanMap.Transition<SpacecraftState>> transitions = states.getTransitions();
  173.             if (transitions.size() == 1  && transitions.first().getBefore() == transitions.first().getAfter()) {
  174.                 // the single entry is a dummy one, without a real transition
  175.                 // we ignore it completely
  176.                 transitionDates = null;
  177.                 allStates       = null;
  178.             } else {
  179.                 transitionDates = new AbsoluteDate[transitions.size()];
  180.                 allStates       = new SpacecraftState[transitions.size() + 1];
  181.                 int i = 0;
  182.                 for (final TimeSpanMap.Transition<SpacecraftState> transition : transitions) {
  183.                     if (i == 0) {
  184.                         // state before the first transition
  185.                         allStates[i] = transition.getBefore();
  186.                     }
  187.                     transitionDates[i] = transition.getDate();
  188.                     allStates[++i]     = transition.getAfter();
  189.                 }
  190.             }

  191.             return new DataTransferObject(getInitialState().getOrbit(), getAttitudeProvider(),
  192.                                           getInitialState().getMu(), getInitialState().getMass(),
  193.                                           transitionDates, allStates,
  194.                                           serializableProviders.toArray(new AdditionalStateProvider[serializableProviders.size()]));
  195.         } catch (OrekitException orekitException) {
  196.             // this should never happen
  197.             throw new OrekitInternalError(null);
  198.         }

  199.     }

  200.     /** Internal class used only for serialization. */
  201.     private static class DataTransferObject implements Serializable {

  202.         /** Serializable UID. */
  203.         private static final long serialVersionUID = 20151202L;

  204.         /** Initial orbit. */
  205.         private final Orbit orbit;

  206.         /** Attitude provider. */
  207.         private final AttitudeProvider attitudeProvider;

  208.         /** Central attraction coefficient (m³/s²). */
  209.         private final double mu;

  210.         /** Spacecraft mass (kg). */
  211.         private final double mass;

  212.         /** Transition dates (may be null). */
  213.         private final AbsoluteDate[] transitionDates;

  214.         /** States before and after transitions (may be null). */
  215.         private final SpacecraftState[] allStates;

  216.         /** Providers for additional states. */
  217.         private final AdditionalStateProvider[] providers;

  218.         /** Simple constructor.
  219.          * @param orbit initial orbit
  220.          * @param attitudeProvider attitude provider
  221.          * @param mu central attraction coefficient (m³/s²)
  222.          * @param mass initial spacecraft mass (kg)
  223.          * @param transitionDates transition dates (may be null)
  224.          * @param allStates states before and after transitions (may be null)
  225.          * @param providers providers for additional states
  226.          */
  227.         DataTransferObject(final Orbit orbit,
  228.                            final AttitudeProvider attitudeProvider,
  229.                            final double mu, final double mass,
  230.                            final AbsoluteDate[] transitionDates,
  231.                            final SpacecraftState[] allStates,
  232.                            final AdditionalStateProvider[] providers) {
  233.             this.orbit            = orbit;
  234.             this.attitudeProvider = attitudeProvider;
  235.             this.mu               = mu;
  236.             this.mass             = mass;
  237.             this.transitionDates  = transitionDates;
  238.             this.allStates        = allStates;
  239.             this.providers        = providers;
  240.         }

  241.         /** Replace the deserialized data transfer object with a {@link KeplerianPropagator}.
  242.          * @return replacement {@link KeplerianPropagator}
  243.          */
  244.         private Object readResolve() {
  245.             try {

  246.                 final KeplerianPropagator propagator =
  247.                                 new KeplerianPropagator(orbit, attitudeProvider, mu, mass);
  248.                 for (final AdditionalStateProvider provider : providers) {
  249.                     propagator.addAdditionalStateProvider(provider);
  250.                 }

  251.                 if (transitionDates != null) {
  252.                     // override the state transitions
  253.                     propagator.states = new TimeSpanMap<SpacecraftState>(allStates[0]);
  254.                     for (int i = 0; i < transitionDates.length; ++i) {
  255.                         propagator.states.addValidAfter(allStates[i + 1], transitionDates[i]);
  256.                     }
  257.                 }

  258.                 return propagator;

  259.             } catch (OrekitException oe) {
  260.                 throw new OrekitInternalError(oe);
  261.             }
  262.         }

  263.     }

  264. }