AbstractAnalyticalPropagator.java

  1. /* Copyright 2002-2022 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.orekit.attitudes.Attitude;
  28. import org.orekit.attitudes.AttitudeProvider;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitInternalError;
  31. import org.orekit.frames.Frame;
  32. import org.orekit.orbits.Orbit;
  33. import org.orekit.propagation.AbstractPropagator;
  34. import org.orekit.propagation.AdditionalStateProvider;
  35. import org.orekit.propagation.BoundedPropagator;
  36. import org.orekit.propagation.EphemerisGenerator;
  37. import org.orekit.propagation.MatricesHarvester;
  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.sampling.OrekitStepInterpolator;
  43. import org.orekit.time.AbsoluteDate;
  44. import org.orekit.utils.PVCoordinatesProvider;
  45. import org.orekit.utils.TimeStampedPVCoordinates;

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

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

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

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

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

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

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

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

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public EphemerisGenerator getEphemerisGenerator() {
  84.         return () -> new BoundedPropagatorView(lastPropagationStart, lastPropagationEnd);
  85.     }

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

  90.     /** {@inheritDoc} */
  91.     public Collection<EventDetector> getEventsDetectors() {
  92.         final List<EventDetector> list = new ArrayList<>();
  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.         try {

  105.             initializePropagation();

  106.             lastPropagationStart = start;

  107.             // Initialize additional states
  108.             initializeAdditionalStates(target);

  109.             final boolean isForward = target.compareTo(start) >= 0;
  110.             SpacecraftState state   = updateAdditionalStates(basicPropagate(start));

  111.             // initialize event detectors
  112.             for (final EventState<?> es : eventsStates) {
  113.                 es.init(state, target);
  114.             }

  115.             // initialize step handlers
  116.             getMultiplexer().init(state, target);

  117.             // iterate over the propagation range, need loop due to reset events
  118.             statesInitialized = false;
  119.             isLastStep = false;
  120.             do {

  121.                 // attempt to advance to the target date
  122.                 final SpacecraftState previous = state;
  123.                 final SpacecraftState current = updateAdditionalStates(basicPropagate(target));
  124.                 final OrekitStepInterpolator interpolator =
  125.                         new BasicStepInterpolator(isForward, previous, current);

  126.                 // accept the step, trigger events and step handlers
  127.                 state = acceptStep(interpolator, target);

  128.                 // Update the potential changes in the spacecraft state due to the events
  129.                 // especially the potential attitude transition
  130.                 state = updateAdditionalStates(basicPropagate(state.getDate()));

  131.             } while (!isLastStep);

  132.             // return the last computed state
  133.             lastPropagationEnd = state.getDate();
  134.             setStartDate(state.getDate());
  135.             return state;

  136.         } catch (MathRuntimeException mrte) {
  137.             throw OrekitException.unwrap(mrte);
  138.         }
  139.     }

  140.     /** Accept a step, triggering events and step handlers.
  141.      * @param interpolator interpolator for the current step
  142.      * @param target final propagation time
  143.      * @return state at the end of the step
  144.      * @exception MathRuntimeException if an event cannot be located
  145.      */
  146.     protected SpacecraftState acceptStep(final OrekitStepInterpolator interpolator,
  147.                                          final AbsoluteDate target)
  148.         throws MathRuntimeException {

  149.         SpacecraftState        previous   = interpolator.getPreviousState();
  150.         final SpacecraftState  current    = interpolator.getCurrentState();
  151.         OrekitStepInterpolator restricted = interpolator;


  152.         // initialize the events states if needed
  153.         if (!statesInitialized) {

  154.             if (!eventsStates.isEmpty()) {
  155.                 // initialize the events states
  156.                 for (final EventState<?> state : eventsStates) {
  157.                     state.reinitializeBegin(interpolator);
  158.                 }
  159.             }

  160.             statesInitialized = true;

  161.         }

  162.         // search for next events that may occur during the step
  163.         final int orderingSign = interpolator.isForward() ? +1 : -1;
  164.         final Queue<EventState<?>> occurringEvents = new PriorityQueue<>(new Comparator<EventState<?>>() {
  165.             /** {@inheritDoc} */
  166.             @Override
  167.             public int compare(final EventState<?> es0, final EventState<?> es1) {
  168.                 return orderingSign * es0.getEventDate().compareTo(es1.getEventDate());
  169.             }
  170.         });

  171.         boolean doneWithStep = false;
  172.         resetEvents:
  173.         do {

  174.             // Evaluate all event detectors for events
  175.             occurringEvents.clear();
  176.             for (final EventState<?> state : eventsStates) {
  177.                 if (state.evaluateStep(interpolator)) {
  178.                     // the event occurs during the current step
  179.                     occurringEvents.add(state);
  180.                 }
  181.             }

  182.             do {

  183.                 eventLoop:
  184.                 while (!occurringEvents.isEmpty()) {

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

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

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

  191.                     // try to advance all event states to current time
  192.                     for (final EventState<?> state : eventsStates) {
  193.                         if (state != currentEvent && state.tryAdvance(eventState, interpolator)) {
  194.                             // we need to handle another event first
  195.                             // remove event we just updated to prevent heap corruption
  196.                             occurringEvents.remove(state);
  197.                             // add it back to update its position in the heap
  198.                             occurringEvents.add(state);
  199.                             // re-queue the event we were processing
  200.                             occurringEvents.add(currentEvent);
  201.                             continue eventLoop;
  202.                         }
  203.                     }
  204.                     // all event detectors agree we can advance to the current event time

  205.                     // handle the first part of the step, up to the event
  206.                     getMultiplexer().handleStep(restricted);

  207.                     // acknowledge event occurrence
  208.                     final EventOccurrence occurrence = currentEvent.doEvent(eventState);
  209.                     final Action action = occurrence.getAction();
  210.                     isLastStep = action == Action.STOP;

  211.                     if (isLastStep) {

  212.                         // ensure the event is after the root if it is returned STOP
  213.                         // this lets the user integrate to a STOP event and then restart
  214.                         // integration from the same time.
  215.                         final SpacecraftState savedState = eventState;
  216.                         eventState = interpolator.getInterpolatedState(occurrence.getStopDate());
  217.                         restricted = restricted.restrictStep(savedState, eventState);

  218.                         // handle the almost zero size last part of the final step, at event time
  219.                         getMultiplexer().handleStep(restricted);
  220.                         getMultiplexer().finish(restricted.getCurrentState());

  221.                     }

  222.                     if (isLastStep) {
  223.                         // the event asked to stop integration
  224.                         return eventState;
  225.                     }

  226.                     if (action == Action.RESET_DERIVATIVES || action == Action.RESET_STATE) {
  227.                         // some event handler has triggered changes that
  228.                         // invalidate the derivatives, we need to recompute them
  229.                         final SpacecraftState resetState = occurrence.getNewState();
  230.                         resetIntermediateState(resetState, interpolator.isForward());
  231.                         return resetState;
  232.                     }
  233.                     // at this point action == Action.CONTINUE or Action.RESET_EVENTS

  234.                     // prepare handling of the remaining part of the step
  235.                     previous = eventState;
  236.                     restricted = new BasicStepInterpolator(restricted.isForward(), eventState, current);

  237.                     if (action == Action.RESET_EVENTS) {
  238.                         continue resetEvents;
  239.                     }

  240.                     // at this point action == Action.CONTINUE
  241.                     // check if the same event occurs again in the remaining part of the step
  242.                     if (currentEvent.evaluateStep(restricted)) {
  243.                         // the event occurs during the current step
  244.                         occurringEvents.add(currentEvent);
  245.                     }

  246.                 }

  247.                 // last part of the step, after the last event. Advance all detectors to
  248.                 // the end of the step. Should only detect a new event here if an event
  249.                 // modified the g function of another detector. Detecting such events here
  250.                 // is unreliable and RESET_EVENTS should be used instead. Might as well
  251.                 // re-check here because we have to loop through all the detectors anyway
  252.                 // and the alternative is to throw an exception.
  253.                 for (final EventState<?> state : eventsStates) {
  254.                     if (state.tryAdvance(current, interpolator)) {
  255.                         occurringEvents.add(state);
  256.                     }
  257.                 }

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

  259.             doneWithStep = true;
  260.         } while (!doneWithStep);

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

  262.         // handle the remaining part of the step, after all events if any
  263.         getMultiplexer().handleStep(restricted);
  264.         if (isLastStep) {
  265.             getMultiplexer().finish(restricted.getCurrentState());
  266.         }

  267.         return current;

  268.     }

  269.     /** Get the mass.
  270.      * @param date target date for the orbit
  271.      * @return mass mass
  272.      */
  273.     protected abstract double getMass(AbsoluteDate date);

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

  280.     /** Reset an intermediate state.
  281.      * @param state new intermediate state to consider
  282.      * @param forward if true, the intermediate state is valid for
  283.      * propagations after itself
  284.      */
  285.     protected abstract void resetIntermediateState(SpacecraftState state, boolean forward);

  286.     /** Extrapolate an orbit up to a specific target date.
  287.      * @param date target date for the orbit
  288.      * @return extrapolated parameters
  289.      */
  290.     protected abstract Orbit propagateOrbit(AbsoluteDate date);

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

  301.             // evaluate orbit
  302.             final Orbit orbit = propagateOrbit(date);

  303.             // evaluate attitude
  304.             final Attitude attitude =
  305.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

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

  308.         } catch (OrekitException oe) {
  309.             throw new OrekitException(oe);
  310.         }
  311.     }

  312.     /**
  313.      * Get the names of the parameters in the matrix returned by {@link MatricesHarvester#getParametersJacobian}.
  314.      * @return names of the parameters (i.e. columns) of the Jacobian matrix
  315.      * @since 11.1
  316.      */
  317.     protected List<String> getJacobiansColumnsNames() {
  318.         return Collections.emptyList();
  319.     }

  320.     /** Internal PVCoordinatesProvider for attitude computation. */
  321.     private class LocalPVProvider implements PVCoordinatesProvider {

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

  326.     }

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

  329.         /** Min date. */
  330.         private final AbsoluteDate minDate;

  331.         /** Max date. */
  332.         private final AbsoluteDate maxDate;

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

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

  357.         }

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

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

  366.         /** {@inheritDoc} */
  367.         protected Orbit propagateOrbit(final AbsoluteDate target) {
  368.             return AbstractAnalyticalPropagator.this.propagateOrbit(target);
  369.         }

  370.         /** {@inheritDoc} */
  371.         public double getMass(final AbsoluteDate date) {
  372.             return AbstractAnalyticalPropagator.this.getMass(date);
  373.         }

  374.         /** {@inheritDoc} */
  375.         public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
  376.             return propagate(date).getPVCoordinates(frame);
  377.         }

  378.         /** {@inheritDoc} */
  379.         public void resetInitialState(final SpacecraftState state) {
  380.             super.resetInitialState(state);
  381.             AbstractAnalyticalPropagator.this.resetInitialState(state);
  382.         }

  383.         /** {@inheritDoc} */
  384.         protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
  385.             AbstractAnalyticalPropagator.this.resetIntermediateState(state, forward);
  386.         }

  387.         /** {@inheritDoc} */
  388.         public SpacecraftState getInitialState() {
  389.             return AbstractAnalyticalPropagator.this.getInitialState();
  390.         }

  391.         /** {@inheritDoc} */
  392.         public Frame getFrame() {
  393.             return AbstractAnalyticalPropagator.this.getFrame();
  394.         }

  395.     }

  396.     /** Internal class for local propagation. */
  397.     private class BasicStepInterpolator implements OrekitStepInterpolator {

  398.         /** Previous state. */
  399.         private final SpacecraftState previousState;

  400.         /** Current state. */
  401.         private final SpacecraftState currentState;

  402.         /** Forward propagation indicator. */
  403.         private final boolean forward;

  404.         /** Simple constructor.
  405.          * @param isForward integration direction indicator
  406.          * @param previousState start of the step
  407.          * @param currentState end of the step
  408.          */
  409.         BasicStepInterpolator(final boolean isForward,
  410.                               final SpacecraftState previousState,
  411.                               final SpacecraftState currentState) {
  412.             this.forward         = isForward;
  413.             this.previousState   = previousState;
  414.             this.currentState    = currentState;
  415.         }

  416.         /** {@inheritDoc} */
  417.         @Override
  418.         public SpacecraftState getPreviousState() {
  419.             return previousState;
  420.         }

  421.         /** {@inheritDoc} */
  422.         @Override
  423.         public boolean isPreviousStateInterpolated() {
  424.             // no difference in analytical propagators
  425.             return false;
  426.         }

  427.         /** {@inheritDoc} */
  428.         @Override
  429.         public SpacecraftState getCurrentState() {
  430.             return currentState;
  431.         }

  432.         /** {@inheritDoc} */
  433.         @Override
  434.         public boolean isCurrentStateInterpolated() {
  435.             // no difference in analytical propagators
  436.             return false;
  437.         }

  438.         /** {@inheritDoc} */
  439.         @Override
  440.         public SpacecraftState getInterpolatedState(final AbsoluteDate date) {

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

  443.             // add the additional states
  444.             return updateAdditionalStates(basicState);

  445.         }

  446.         /** {@inheritDoc} */
  447.         @Override
  448.         public boolean isForward() {
  449.             return forward;
  450.         }

  451.         /** {@inheritDoc} */
  452.         @Override
  453.         public BasicStepInterpolator restrictStep(final SpacecraftState newPreviousState,
  454.                                                   final SpacecraftState newCurrentState) {
  455.             return new BasicStepInterpolator(forward, newPreviousState, newCurrentState);
  456.         }

  457.     }

  458. }