AbstractAnalyticalPropagator.java

  1. /* Copyright 2002-2018 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.Collection;
  22. import java.util.Collections;
  23. import java.util.Comparator;
  24. import java.util.List;
  25. import java.util.PriorityQueue;
  26. import java.util.Queue;

  27. import org.hipparchus.exception.MathRuntimeException;
  28. import org.hipparchus.util.FastMath;
  29. import org.orekit.attitudes.Attitude;
  30. import org.orekit.attitudes.AttitudeProvider;
  31. import org.orekit.errors.OrekitException;
  32. import org.orekit.errors.OrekitInternalError;
  33. import org.orekit.frames.Frame;
  34. import org.orekit.orbits.Orbit;
  35. import org.orekit.propagation.AbstractPropagator;
  36. import org.orekit.propagation.AdditionalStateProvider;
  37. import org.orekit.propagation.BoundedPropagator;
  38. import org.orekit.propagation.SpacecraftState;
  39. import org.orekit.propagation.events.EventDetector;
  40. import org.orekit.propagation.events.EventState;
  41. import org.orekit.propagation.events.EventState.EventOccurrence;
  42. import org.orekit.propagation.events.handlers.EventHandler.Action;
  43. import org.orekit.propagation.sampling.OrekitStepInterpolator;
  44. import org.orekit.time.AbsoluteDate;
  45. import org.orekit.utils.PVCoordinatesProvider;
  46. import org.orekit.utils.TimeStampedPVCoordinates;

  47. /** Common handling of {@link org.orekit.propagation.Propagator} methods for analytical propagators.
  48.  * <p>
  49.  * This abstract class allows to provide easily the full set of {@link
  50.  * org.orekit.propagation.Propagator Propagator} methods, including all propagation
  51.  * modes support and discrete events support for any simple propagation method. Only
  52.  * two methods must be implemented by derived classes: {@link #propagateOrbit(AbsoluteDate)}
  53.  * and {@link #getMass(AbsoluteDate)}. The first method should perform straightforward
  54.  * propagation starting from some internally stored initial state up to the specified target date.
  55.  * </p>
  56.  * @author Luc Maisonobe
  57.  */
  58. public abstract class AbstractAnalyticalPropagator extends AbstractPropagator {

  59.     /** Provider for attitude computation. */
  60.     private PVCoordinatesProvider pvProvider;

  61.     /** Start date of last propagation. */
  62.     private AbsoluteDate lastPropagationStart;

  63.     /** End date of last propagation. */
  64.     private AbsoluteDate lastPropagationEnd;

  65.     /** Initialization indicator of events states. */
  66.     private boolean statesInitialized;

  67.     /** Indicator for last step. */
  68.     private boolean isLastStep;

  69.     /** Event steps. */
  70.     private final Collection<EventState<?>> eventsStates;

  71.     /** Build a new instance.
  72.      * @param attitudeProvider provider for attitude computation
  73.      */
  74.     protected AbstractAnalyticalPropagator(final AttitudeProvider attitudeProvider) {
  75.         setAttitudeProvider(attitudeProvider);
  76.         pvProvider               = new LocalPVProvider();
  77.         lastPropagationStart     = AbsoluteDate.PAST_INFINITY;
  78.         lastPropagationEnd       = AbsoluteDate.FUTURE_INFINITY;
  79.         statesInitialized        = false;
  80.         eventsStates             = new ArrayList<EventState<?>>();
  81.     }

  82.     /** {@inheritDoc} */
  83.     public BoundedPropagator getGeneratedEphemeris() {
  84.         return new BoundedPropagatorView(lastPropagationStart, lastPropagationEnd);
  85.     }

  86.     /** {@inheritDoc} */
  87.     public <T extends EventDetector> void addEventDetector(final T detector) {
  88.         eventsStates.add(new EventState<T>(detector));
  89.     }

  90.     /** {@inheritDoc} */
  91.     public Collection<EventDetector> getEventsDetectors() {
  92.         final List<EventDetector> list = new ArrayList<EventDetector>();
  93.         for (final EventState<?> state : eventsStates) {
  94.             list.add(state.getEventDetector());
  95.         }
  96.         return Collections.unmodifiableCollection(list);
  97.     }

  98.     /** {@inheritDoc} */
  99.     public void clearEventsDetectors() {
  100.         eventsStates.clear();
  101.     }

  102.     /** {@inheritDoc} */
  103.     public SpacecraftState propagate(final AbsoluteDate start, final AbsoluteDate target)
  104.         throws OrekitException {
  105.         try {

  106.             lastPropagationStart = start;

  107.             final double dt       = target.durationFrom(start);
  108.             final double epsilon  = FastMath.ulp(dt);
  109.             SpacecraftState state = updateAdditionalStates(basicPropagate(start));

  110.             // evaluate step size
  111.             final double stepSize;
  112.             if (getMode() == MASTER_MODE) {
  113.                 if (Double.isNaN(getFixedStepSize())) {
  114.                     stepSize = FastMath.copySign(state.getKeplerianPeriod() / 100, dt);
  115.                 } else {
  116.                     stepSize = FastMath.copySign(getFixedStepSize(), dt);
  117.                 }
  118.             } else {
  119.                 stepSize = dt;
  120.             }

  121.             // initialize event detectors
  122.             for (final EventState<?> es : eventsStates) {
  123.                 es.init(state, target);
  124.             }

  125.             // initialize step handler
  126.             if (getStepHandler() != null) {
  127.                 getStepHandler().init(state, target);
  128.             }

  129.             // iterate over the propagation range
  130.             statesInitialized = false;
  131.             isLastStep = false;
  132.             do {

  133.                 // go ahead one step size
  134.                 final SpacecraftState previous = state;
  135.                 AbsoluteDate t = previous.getDate().shiftedBy(stepSize);
  136.                 if ((dt == 0) || ((dt > 0) ^ (t.compareTo(target) <= 0)) ||
  137.                         (FastMath.abs(target.durationFrom(t)) <= epsilon)) {
  138.                     // current step exceeds target
  139.                     // or is target to within double precision
  140.                     t = target;
  141.                 }
  142.                 final SpacecraftState current = updateAdditionalStates(basicPropagate(t));
  143.                 final OrekitStepInterpolator interpolator = new BasicStepInterpolator(dt >= 0, previous, current);


  144.                 // accept the step, trigger events and step handlers
  145.                 state = acceptStep(interpolator, target, epsilon);

  146.             } while (!isLastStep);

  147.             // return the last computed state
  148.             lastPropagationEnd = state.getDate();
  149.             setStartDate(state.getDate());
  150.             return state;

  151.         } catch (MathRuntimeException mrte) {
  152.             throw OrekitException.unwrap(mrte);
  153.         }
  154.     }

  155.     /** Accept a step, triggering events and step handlers.
  156.      * @param interpolator interpolator for the current step
  157.      * @param target final propagation time
  158.      * @param epsilon threshold for end date detection
  159.      * @return state at the end of the step
  160.      * @exception OrekitException if the switching function cannot be evaluated
  161.      * @exception MathRuntimeException if an event cannot be located
  162.      */
  163.     protected SpacecraftState acceptStep(final OrekitStepInterpolator interpolator,
  164.                                          final AbsoluteDate target, final double epsilon)
  165.         throws OrekitException, MathRuntimeException {

  166.         SpacecraftState       previous = interpolator.getPreviousState();
  167.         final SpacecraftState current  = interpolator.getCurrentState();

  168.         // initialize the events states if needed
  169.         if (!statesInitialized) {

  170.             if (!eventsStates.isEmpty()) {
  171.                 // initialize the events states
  172.                 for (final EventState<?> state : eventsStates) {
  173.                     state.reinitializeBegin(interpolator);
  174.                 }
  175.             }

  176.             statesInitialized = true;

  177.         }

  178.         // search for next events that may occur during the step
  179.         final int orderingSign = interpolator.isForward() ? +1 : -1;
  180.         final Queue<EventState<?>> occurringEvents = new PriorityQueue<>(new Comparator<EventState<?>>() {
  181.             /** {@inheritDoc} */
  182.             @Override
  183.             public int compare(final EventState<?> es0, final EventState<?> es1) {
  184.                 return orderingSign * es0.getEventDate().compareTo(es1.getEventDate());
  185.             }
  186.         });

  187.         for (final EventState<?> state : eventsStates) {
  188.             if (state.evaluateStep(interpolator)) {
  189.                 // the event occurs during the current step
  190.                 occurringEvents.add(state);
  191.             }
  192.         }

  193.         OrekitStepInterpolator restricted = interpolator;

  194.         do {

  195.             eventLoop:
  196.             while (!occurringEvents.isEmpty()) {

  197.                 // handle the chronologically first event
  198.                 final EventState<?> currentEvent = occurringEvents.poll();

  199.                 // get state at event time
  200.                 SpacecraftState eventState = restricted.getInterpolatedState(currentEvent.getEventDate());

  201.                 // try to advance all event states to current time
  202.                 for (final EventState<?> state : eventsStates) {
  203.                     if (state != currentEvent && state.tryAdvance(eventState, interpolator)) {
  204.                         // we need to handle another event first
  205.                         // remove event we just updated to prevent heap corruption
  206.                         occurringEvents.remove(state);
  207.                         // add it back to update its position in the heap
  208.                         occurringEvents.add(state);
  209.                         // re-queue the event we were processing
  210.                         occurringEvents.add(currentEvent);
  211.                         continue eventLoop;
  212.                     }
  213.                 }
  214.                 // all event detectors agree we can advance to the current event time

  215.                 final EventOccurrence occurrence = currentEvent.doEvent(eventState);
  216.                 final Action action = occurrence.getAction();
  217.                 isLastStep = action == Action.STOP;

  218.                 if (isLastStep) {
  219.                     // ensure the event is after the root if it is returned STOP
  220.                     // this lets the user integrate to a STOP event and then restart
  221.                     // integration from the same time.
  222.                     eventState = interpolator.getInterpolatedState(occurrence.getStopDate());
  223.                     restricted = restricted.restrictStep(previous, eventState);
  224.                 }

  225.                 // handle the first part of the step, up to the event
  226.                 if (getStepHandler() != null) {
  227.                     getStepHandler().handleStep(restricted, isLastStep);
  228.                 }

  229.                 if (isLastStep) {
  230.                     // the event asked to stop integration
  231.                     return eventState;
  232.                 }

  233.                 if (action == Action.RESET_DERIVATIVES || action == Action.RESET_STATE) {
  234.                     // some event handler has triggered changes that
  235.                     // invalidate the derivatives, we need to recompute them
  236.                     final SpacecraftState resetState = occurrence.getNewState();
  237.                     if (resetState != null) {
  238.                         resetIntermediateState(resetState, interpolator.isForward());
  239.                         return resetState;
  240.                     }
  241.                 }
  242.                 // at this point we know action == Action.CONTINUE

  243.                 // prepare handling of the remaining part of the step
  244.                 previous = eventState;
  245.                 restricted         = new BasicStepInterpolator(restricted.isForward(), eventState, current);

  246.                 // check if the same event occurs again in the remaining part of the step
  247.                 if (currentEvent.evaluateStep(restricted)) {
  248.                     // the event occurs during the current step
  249.                     occurringEvents.add(currentEvent);
  250.                 }

  251.             }

  252.             // last part of the step, after the last event
  253.             // may be a new event here if the last event modified the g function of
  254.             // another event detector.
  255.             for (final EventState<?> state : eventsStates) {
  256.                 if (state.tryAdvance(current, interpolator)) {
  257.                     occurringEvents.add(state);
  258.                 }
  259.             }

  260.         } while (!occurringEvents.isEmpty());

  261.         isLastStep = target.equals(current.getDate());

  262.         // handle the remaining part of the step, after all events if any
  263.         if (getStepHandler() != null) {
  264.             getStepHandler().handleStep(interpolator, isLastStep);
  265.         }

  266.         return current;

  267.     }

  268.     /** Get the mass.
  269.      * @param date target date for the orbit
  270.      * @return mass mass
  271.      * @exception OrekitException if some parameters are out of bounds
  272.      */
  273.     protected abstract double getMass(AbsoluteDate date)
  274.         throws OrekitException;

  275.     /** Get PV coordinates provider.
  276.      * @return PV coordinates provider
  277.      */
  278.     public PVCoordinatesProvider getPvProvider() {
  279.         return pvProvider;
  280.     }

  281.     /** Reset an intermediate state.
  282.      * @param state new intermediate state to consider
  283.      * @param forward if true, the intermediate state is valid for
  284.      * propagations after itself
  285.      * @exception OrekitException if initial state cannot be reset
  286.      */
  287.     protected abstract void resetIntermediateState(SpacecraftState state, boolean forward)
  288.         throws OrekitException;

  289.     /** Extrapolate an orbit up to a specific target date.
  290.      * @param date target date for the orbit
  291.      * @return extrapolated parameters
  292.      * @exception OrekitException if some parameters are out of bounds
  293.      */
  294.     protected abstract Orbit propagateOrbit(AbsoluteDate date)
  295.         throws OrekitException;

  296.     /** Propagate an orbit without any fancy features.
  297.      * <p>This method is similar in spirit to the {@link #propagate} method,
  298.      * except that it does <strong>not</strong> call any handler during
  299.      * propagation, nor any discrete events, not additional states. It always
  300.      * stop exactly at the specified date.</p>
  301.      * @param date target date for propagation
  302.      * @return state at specified date
  303.      * @exception OrekitException if propagation cannot reach specified date
  304.      */
  305.     protected SpacecraftState basicPropagate(final AbsoluteDate date) throws OrekitException {
  306.         try {

  307.             // evaluate orbit
  308.             final Orbit orbit = propagateOrbit(date);

  309.             // evaluate attitude
  310.             final Attitude attitude =
  311.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

  312.             // build raw state
  313.             return new SpacecraftState(orbit, attitude, getMass(date));

  314.         } catch (OrekitException oe) {
  315.             throw new OrekitException(oe);
  316.         }
  317.     }

  318.     /** Internal PVCoordinatesProvider for attitude computation. */
  319.     private class LocalPVProvider implements PVCoordinatesProvider {

  320.         /** {@inheritDoc} */
  321.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
  322.             throws OrekitException {
  323.             return propagateOrbit(date).getPVCoordinates(frame);
  324.         }

  325.     }

  326.     /** {@link BoundedPropagator} view of the instance. */
  327.     private class BoundedPropagatorView
  328.         extends AbstractAnalyticalPropagator
  329.         implements BoundedPropagator, Serializable {

  330.         /** Serializable UID. */
  331.         private static final long serialVersionUID = 20151117L;

  332.         /** Min date. */
  333.         private final AbsoluteDate minDate;

  334.         /** Max date. */
  335.         private final AbsoluteDate maxDate;

  336.         /** Simple constructor.
  337.          * @param startDate start date of the propagation
  338.          * @param endDate end date of the propagation
  339.          */
  340.         BoundedPropagatorView(final AbsoluteDate startDate, final AbsoluteDate endDate) {
  341.             super(AbstractAnalyticalPropagator.this.getAttitudeProvider());
  342.             if (startDate.compareTo(endDate) <= 0) {
  343.                 minDate = startDate;
  344.                 maxDate = endDate;
  345.             } else {
  346.                 minDate = endDate;
  347.                 maxDate = startDate;
  348.             }

  349.             try {
  350.                 // copy the same additional state providers as the original propagator
  351.                 for (AdditionalStateProvider provider : AbstractAnalyticalPropagator.this.getAdditionalStateProviders()) {
  352.                     addAdditionalStateProvider(provider);
  353.                 }
  354.             } catch (OrekitException oe) {
  355.                 // as the providers are already compatible with each other,
  356.                 // this should never happen
  357.                 throw new OrekitInternalError(null);
  358.             }

  359.         }

  360.         /** {@inheritDoc} */
  361.         public AbsoluteDate getMinDate() {
  362.             return minDate;
  363.         }

  364.         /** {@inheritDoc} */
  365.         public AbsoluteDate getMaxDate() {
  366.             return maxDate;
  367.         }

  368.         /** {@inheritDoc} */
  369.         protected Orbit propagateOrbit(final AbsoluteDate target)
  370.             throws OrekitException {
  371.             return AbstractAnalyticalPropagator.this.propagateOrbit(target);
  372.         }

  373.         /** {@inheritDoc} */
  374.         public double getMass(final AbsoluteDate date) throws OrekitException {
  375.             return AbstractAnalyticalPropagator.this.getMass(date);
  376.         }

  377.         /** {@inheritDoc} */
  378.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
  379.             throws OrekitException {
  380.             return propagate(date).getPVCoordinates(frame);
  381.         }

  382.         /** {@inheritDoc} */
  383.         public void resetInitialState(final SpacecraftState state) throws OrekitException {
  384.             AbstractAnalyticalPropagator.this.resetInitialState(state);
  385.         }

  386.         /** {@inheritDoc} */
  387.         protected void resetIntermediateState(final SpacecraftState state, final boolean forward)
  388.             throws OrekitException {
  389.             AbstractAnalyticalPropagator.this.resetIntermediateState(state, forward);
  390.         }

  391.         /** {@inheritDoc} */
  392.         public SpacecraftState getInitialState() throws OrekitException {
  393.             return AbstractAnalyticalPropagator.this.getInitialState();
  394.         }

  395.         /** {@inheritDoc} */
  396.         public Frame getFrame() {
  397.             return AbstractAnalyticalPropagator.this.getFrame();
  398.         }

  399.         /** Replace the instance with a data transfer object for serialization.
  400.          * @return data transfer object that will be serialized
  401.          * @exception NotSerializableException if attitude provider or additional
  402.          * state provider is not serializable
  403.          */
  404.         private Object writeReplace() throws NotSerializableException {
  405.             return new DataTransferObject(minDate, maxDate, AbstractAnalyticalPropagator.this);
  406.         }

  407.     }

  408.     /** Internal class used only for serialization. */
  409.     private static class DataTransferObject implements Serializable {

  410.         /** Serializable UID. */
  411.         private static final long serialVersionUID = 20151117L;

  412.         /** Min date. */
  413.         private final AbsoluteDate minDate;

  414.         /** Max date. */
  415.         private final AbsoluteDate maxDate;

  416.         /** Underlying propagator. */
  417.         private final AbstractAnalyticalPropagator propagator;

  418.         /** Simple constructor.
  419.          * @param minDate min date
  420.          * @param maxDate max date
  421.          * @param propagator underlying propagator
  422.          */
  423.         DataTransferObject(final AbsoluteDate minDate, final AbsoluteDate maxDate,
  424.                            final AbstractAnalyticalPropagator propagator) {
  425.             this.minDate    = minDate;
  426.             this.maxDate    = maxDate;
  427.             this.propagator = propagator;
  428.         }

  429.         /** Replace the deserialized data transfer object with an {@link BoundedPropagatorView}.
  430.          * @return replacement {@link BoundedPropagatorView}
  431.          */
  432.         private Object readResolve() {
  433.             propagator.lastPropagationStart = minDate;
  434.             propagator.lastPropagationEnd   = maxDate;
  435.             return propagator.getGeneratedEphemeris();
  436.         }

  437.     }

  438.     /** Internal class for local propagation. */
  439.     private class BasicStepInterpolator implements OrekitStepInterpolator {

  440.         /** Previous state. */
  441.         private final SpacecraftState previousState;

  442.         /** Current state. */
  443.         private final SpacecraftState currentState;

  444.         /** Forward propagation indicator. */
  445.         private final boolean forward;

  446.         /** Simple constructor.
  447.          * @param isForward integration direction indicator
  448.          * @param previousState start of the step
  449.          * @param currentState end of the step
  450.          */
  451.         BasicStepInterpolator(final boolean isForward,
  452.                               final SpacecraftState previousState,
  453.                               final SpacecraftState currentState) {
  454.             this.forward         = isForward;
  455.             this.previousState   = previousState;
  456.             this.currentState    = currentState;
  457.         }

  458.         /** {@inheritDoc} */
  459.         @Override
  460.         public SpacecraftState getPreviousState() {
  461.             return previousState;
  462.         }

  463.         /** {@inheritDoc} */
  464.         @Override
  465.         public boolean isPreviousStateInterpolated() {
  466.             // no difference in analytical propagators
  467.             return false;
  468.         }

  469.         /** {@inheritDoc} */
  470.         @Override
  471.         public SpacecraftState getCurrentState() {
  472.             return currentState;
  473.         }

  474.         /** {@inheritDoc} */
  475.         @Override
  476.         public boolean isCurrentStateInterpolated() {
  477.             // no difference in analytical propagators
  478.             return false;
  479.         }

  480.         /** {@inheritDoc} */
  481.         @Override
  482.         public SpacecraftState getInterpolatedState(final AbsoluteDate date)
  483.             throws OrekitException {

  484.             // compute the basic spacecraft state
  485.             final SpacecraftState basicState = basicPropagate(date);

  486.             // add the additional states
  487.             return updateAdditionalStates(basicState);

  488.         }

  489.         /** {@inheritDoc} */
  490.         @Override
  491.         public boolean isForward() {
  492.             return forward;
  493.         }

  494.         /** {@inheritDoc} */
  495.         @Override
  496.         public BasicStepInterpolator restrictStep(final SpacecraftState newPreviousState,
  497.                                                   final SpacecraftState newCurrentState) {
  498.             return new BasicStepInterpolator(forward, newPreviousState, newCurrentState);
  499.         }

  500.     }

  501. }