AbstractAnalyticalPropagator.java

  1. /* Copyright 2002-2020 CS GROUP
  2.  * Licensed to CS GROUP (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.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Collections;
  21. import java.util.Comparator;
  22. import java.util.List;
  23. import java.util.PriorityQueue;
  24. import java.util.Queue;

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

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

  57.     /** Provider for attitude computation. */
  58.     private PVCoordinatesProvider pvProvider;

  59.     /** Start date of last propagation. */
  60.     private AbsoluteDate lastPropagationStart;

  61.     /** End date of last propagation. */
  62.     private AbsoluteDate lastPropagationEnd;

  63.     /** Initialization indicator of events states. */
  64.     private boolean statesInitialized;

  65.     /** Indicator for last step. */
  66.     private boolean isLastStep;

  67.     /** Event steps. */
  68.     private final Collection<EventState<?>> eventsStates;

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

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

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

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

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

  100.     /** {@inheritDoc} */
  101.     public SpacecraftState propagate(final AbsoluteDate start, final AbsoluteDate target) {
  102.         try {

  103.             initializePropagation();

  104.             lastPropagationStart = start;

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

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

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

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

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

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


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

  144.                 // Update the potential changes in the spacecraft state due to the events
  145.                 // especially the potential attitude transition
  146.                 state = updateAdditionalStates(basicPropagate(state.getDate()));

  147.             } while (!isLastStep);

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

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

  156.     /** Accept a step, triggering events and step handlers.
  157.      * @param interpolator interpolator for the current step
  158.      * @param target final propagation time
  159.      * @param epsilon threshold for end date detection
  160.      * @return state at the end of the step
  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 MathRuntimeException {

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


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

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

  177.             statesInitialized = true;

  178.         }

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

  188.         boolean doneWithStep = false;
  189.         resetEvents:
  190.         do {

  191.             // Evaluate all event detectors for events
  192.             occurringEvents.clear();
  193.             for (final EventState<?> state : eventsStates) {
  194.                 if (state.evaluateStep(interpolator)) {
  195.                     // the event occurs during the current step
  196.                     occurringEvents.add(state);
  197.                 }
  198.             }

  199.             do {

  200.                 eventLoop:
  201.                 while (!occurringEvents.isEmpty()) {

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

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

  206.                     // restrict the interpolator to the first part of the step, up to the event
  207.                     restricted = restricted.restrictStep(previous, eventState);

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

  222.                     final EventOccurrence occurrence = currentEvent.doEvent(eventState);
  223.                     final Action action = occurrence.getAction();
  224.                     isLastStep = action == Action.STOP;

  225.                     if (isLastStep) {
  226.                         // ensure the event is after the root if it is returned STOP
  227.                         // this lets the user integrate to a STOP event and then restart
  228.                         // integration from the same time.
  229.                         eventState = interpolator.getInterpolatedState(occurrence.getStopDate());
  230.                         restricted = restricted.restrictStep(previous, eventState);
  231.                     }

  232.                     // handle the first part of the step, up to the event
  233.                     if (getStepHandler() != null) {
  234.                         getStepHandler().handleStep(restricted, isLastStep);
  235.                     }

  236.                     if (isLastStep) {
  237.                         // the event asked to stop integration
  238.                         return eventState;
  239.                     }

  240.                     if (action == Action.RESET_DERIVATIVES || action == Action.RESET_STATE) {
  241.                         // some event handler has triggered changes that
  242.                         // invalidate the derivatives, we need to recompute them
  243.                         final SpacecraftState resetState = occurrence.getNewState();
  244.                         if (resetState != null) {
  245.                             resetIntermediateState(resetState, interpolator.isForward());
  246.                             return resetState;
  247.                         }
  248.                     }
  249.                     // at this point action == Action.CONTINUE or Action.RESET_EVENTS

  250.                     // prepare handling of the remaining part of the step
  251.                     previous = eventState;
  252.                     restricted = new BasicStepInterpolator(restricted.isForward(), eventState, current);

  253.                     if (action == Action.RESET_EVENTS) {
  254.                         continue resetEvents;
  255.                     }

  256.                     // at this point action == Action.CONTINUE
  257.                     // check if the same event occurs again in the remaining part of the step
  258.                     if (currentEvent.evaluateStep(restricted)) {
  259.                         // the event occurs during the current step
  260.                         occurringEvents.add(currentEvent);
  261.                     }

  262.                 }

  263.                 // last part of the step, after the last event. Advance all detectors to
  264.                 // the end of the step. Should only detect a new event here if an event
  265.                 // modified the g function of another detector. Detecting such events here
  266.                 // is unreliable and RESET_EVENTS should be used instead. Might as well
  267.                 // re-check here because we have to loop through all the detectors anyway
  268.                 // and the alternative is to throw an exception.
  269.                 for (final EventState<?> state : eventsStates) {
  270.                     if (state.tryAdvance(current, interpolator)) {
  271.                         occurringEvents.add(state);
  272.                     }
  273.                 }

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

  275.             doneWithStep = true;
  276.         } while (!doneWithStep);

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

  278.         // handle the remaining part of the step, after all events if any
  279.         if (getStepHandler() != null) {
  280.             getStepHandler().handleStep(interpolator, isLastStep);
  281.         }

  282.         return current;

  283.     }

  284.     /** Get the mass.
  285.      * @param date target date for the orbit
  286.      * @return mass mass
  287.      */
  288.     protected abstract double getMass(AbsoluteDate date);

  289.     /** Get PV coordinates provider.
  290.      * @return PV coordinates provider
  291.      */
  292.     public PVCoordinatesProvider getPvProvider() {
  293.         return pvProvider;
  294.     }

  295.     /** Reset an intermediate state.
  296.      * @param state new intermediate state to consider
  297.      * @param forward if true, the intermediate state is valid for
  298.      * propagations after itself
  299.      */
  300.     protected abstract void resetIntermediateState(SpacecraftState state, boolean forward);

  301.     /** Extrapolate an orbit up to a specific target date.
  302.      * @param date target date for the orbit
  303.      * @return extrapolated parameters
  304.      */
  305.     protected abstract Orbit propagateOrbit(AbsoluteDate date);

  306.     /** Propagate an orbit without any fancy features.
  307.      * <p>This method is similar in spirit to the {@link #propagate} method,
  308.      * except that it does <strong>not</strong> call any handler during
  309.      * propagation, nor any discrete events, not additional states. It always
  310.      * stop exactly at the specified date.</p>
  311.      * @param date target date for propagation
  312.      * @return state at specified date
  313.      */
  314.     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
  315.         try {

  316.             // evaluate orbit
  317.             final Orbit orbit = propagateOrbit(date);

  318.             // evaluate attitude
  319.             final Attitude attitude =
  320.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

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

  323.         } catch (OrekitException oe) {
  324.             throw new OrekitException(oe);
  325.         }
  326.     }

  327.     /** Internal PVCoordinatesProvider for attitude computation. */
  328.     private class LocalPVProvider implements PVCoordinatesProvider {

  329.         /** {@inheritDoc} */
  330.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  331.             return propagateOrbit(date).getPVCoordinates(frame);
  332.         }

  333.     }

  334.     /** {@link BoundedPropagator} view of the instance. */
  335.     private class BoundedPropagatorView extends AbstractAnalyticalPropagator implements BoundedPropagator {

  336.         /** Min date. */
  337.         private final AbsoluteDate minDate;

  338.         /** Max date. */
  339.         private final AbsoluteDate maxDate;

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

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

  363.         }

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

  368.         /** {@inheritDoc} */
  369.         public AbsoluteDate getMaxDate() {
  370.             return maxDate;
  371.         }

  372.         /** {@inheritDoc} */
  373.         protected Orbit propagateOrbit(final AbsoluteDate target) {
  374.             return AbstractAnalyticalPropagator.this.propagateOrbit(target);
  375.         }

  376.         /** {@inheritDoc} */
  377.         public double getMass(final AbsoluteDate date) {
  378.             return AbstractAnalyticalPropagator.this.getMass(date);
  379.         }

  380.         /** {@inheritDoc} */
  381.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  382.             return propagate(date).getPVCoordinates(frame);
  383.         }

  384.         /** {@inheritDoc} */
  385.         public void resetInitialState(final SpacecraftState state) {
  386.             AbstractAnalyticalPropagator.this.resetInitialState(state);
  387.         }

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

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

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

  400.     }

  401.     /** Internal class for local propagation. */
  402.     private class BasicStepInterpolator implements OrekitStepInterpolator {

  403.         /** Previous state. */
  404.         private final SpacecraftState previousState;

  405.         /** Current state. */
  406.         private final SpacecraftState currentState;

  407.         /** Forward propagation indicator. */
  408.         private final boolean forward;

  409.         /** Simple constructor.
  410.          * @param isForward integration direction indicator
  411.          * @param previousState start of the step
  412.          * @param currentState end of the step
  413.          */
  414.         BasicStepInterpolator(final boolean isForward,
  415.                               final SpacecraftState previousState,
  416.                               final SpacecraftState currentState) {
  417.             this.forward         = isForward;
  418.             this.previousState   = previousState;
  419.             this.currentState    = currentState;
  420.         }

  421.         /** {@inheritDoc} */
  422.         @Override
  423.         public SpacecraftState getPreviousState() {
  424.             return previousState;
  425.         }

  426.         /** {@inheritDoc} */
  427.         @Override
  428.         public boolean isPreviousStateInterpolated() {
  429.             // no difference in analytical propagators
  430.             return false;
  431.         }

  432.         /** {@inheritDoc} */
  433.         @Override
  434.         public SpacecraftState getCurrentState() {
  435.             return currentState;
  436.         }

  437.         /** {@inheritDoc} */
  438.         @Override
  439.         public boolean isCurrentStateInterpolated() {
  440.             // no difference in analytical propagators
  441.             return false;
  442.         }

  443.         /** {@inheritDoc} */
  444.         @Override
  445.         public SpacecraftState getInterpolatedState(final AbsoluteDate date) {

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

  448.             // add the additional states
  449.             return updateAdditionalStates(basicState);

  450.         }

  451.         /** {@inheritDoc} */
  452.         @Override
  453.         public boolean isForward() {
  454.             return forward;
  455.         }

  456.         /** {@inheritDoc} */
  457.         @Override
  458.         public BasicStepInterpolator restrictStep(final SpacecraftState newPreviousState,
  459.                                                   final SpacecraftState newCurrentState) {
  460.             return new BasicStepInterpolator(forward, newPreviousState, newCurrentState);
  461.         }

  462.     }

  463. }