FieldAbstractAnalyticalPropagator.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.CalculusFieldElement;
  26. import org.hipparchus.Field;
  27. import org.hipparchus.exception.MathRuntimeException;
  28. import org.hipparchus.ode.events.Action;
  29. import org.hipparchus.util.MathArrays;
  30. import org.orekit.attitudes.AttitudeProvider;
  31. import org.orekit.attitudes.FieldAttitude;
  32. import org.orekit.errors.OrekitException;
  33. import org.orekit.errors.OrekitInternalError;
  34. import org.orekit.frames.Frame;
  35. import org.orekit.orbits.FieldOrbit;
  36. import org.orekit.propagation.BoundedPropagator;
  37. import org.orekit.propagation.FieldAbstractPropagator;
  38. import org.orekit.propagation.FieldAdditionalStateProvider;
  39. import org.orekit.propagation.FieldBoundedPropagator;
  40. import org.orekit.propagation.FieldEphemerisGenerator;
  41. import org.orekit.propagation.FieldSpacecraftState;
  42. import org.orekit.propagation.events.FieldEventDetector;
  43. import org.orekit.propagation.events.FieldEventState;
  44. import org.orekit.propagation.events.FieldEventState.EventOccurrence;
  45. import org.orekit.propagation.sampling.FieldOrekitStepInterpolator;
  46. import org.orekit.time.FieldAbsoluteDate;
  47. import org.orekit.utils.FieldPVCoordinatesProvider;
  48. import org.orekit.utils.ParameterDriver;
  49. import org.orekit.utils.TimeStampedFieldPVCoordinates;

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

  61. public abstract class FieldAbstractAnalyticalPropagator<T extends CalculusFieldElement<T>> extends FieldAbstractPropagator<T> {

  62.     /** Provider for attitude computation. */
  63.     private FieldPVCoordinatesProvider<T> pvProvider;

  64.     /** Start date of last propagation. */
  65.     private FieldAbsoluteDate<T> lastPropagationStart;

  66.     /** End date of last propagation. */
  67.     private FieldAbsoluteDate<T> lastPropagationEnd;

  68.     /** Initialization indicator of events states. */
  69.     private boolean statesInitialized;

  70.     /** Indicator for last step. */
  71.     private boolean isLastStep;

  72.     /** Event steps. */
  73.     private final Collection<FieldEventState<?, T>> eventsStates;

  74.     /** Build a new instance.
  75.      * @param attitudeProvider provider for attitude computation
  76.      * @param field field used as default
  77.      */
  78.     protected FieldAbstractAnalyticalPropagator(final Field<T> field, final AttitudeProvider attitudeProvider) {
  79.         super(field);
  80.         setAttitudeProvider(attitudeProvider);
  81.         pvProvider           = new FieldLocalPVProvider();
  82.         lastPropagationStart = FieldAbsoluteDate.getPastInfinity(field);
  83.         lastPropagationEnd   = FieldAbsoluteDate.getFutureInfinity(field);
  84.         statesInitialized    = false;
  85.         eventsStates         = new ArrayList<>();
  86.     }

  87.     /** {@inheritDoc} */
  88.     @Override
  89.     public FieldEphemerisGenerator<T> getEphemerisGenerator() {
  90.         return () -> new FieldBoundedPropagatorView(lastPropagationStart, lastPropagationEnd);
  91.     }

  92.     /** {@inheritDoc} */
  93.     public <D extends FieldEventDetector<T>> void addEventDetector(final D detector) {
  94.         eventsStates.add(new FieldEventState<>(detector));
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public Collection<FieldEventDetector<T>> getEventsDetectors() {
  99.         final List<FieldEventDetector<T>> list = new ArrayList<>();
  100.         for (final FieldEventState<?, T> state : eventsStates) {
  101.             list.add(state.getEventDetector());
  102.         }
  103.         return Collections.unmodifiableCollection(list);
  104.     }

  105.     /** {@inheritDoc} */
  106.     @Override
  107.     public void clearEventsDetectors() {
  108.         eventsStates.clear();
  109.     }
  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> start, final FieldAbsoluteDate<T> target) {
  113.         try {

  114.             initializePropagation();

  115.             lastPropagationStart = start;

  116.             // Initialize additional states
  117.             initializeAdditionalStates(target);

  118.             final boolean           isForward = target.compareTo(start) >= 0;
  119.             FieldSpacecraftState<T> state   = updateAdditionalStates(basicPropagate(start));

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

  124.             // initialize step handlers
  125.             getMultiplexer().init(state, target);

  126.             // iterate over the propagation range, need loop due to reset events
  127.             statesInitialized = false;
  128.             isLastStep = false;
  129.             do {

  130.                 // attempt to advance to the target date
  131.                 final FieldSpacecraftState<T> previous = state;
  132.                 final FieldSpacecraftState<T> current = updateAdditionalStates(basicPropagate(target));
  133.                 final FieldBasicStepInterpolator interpolator =
  134.                         new FieldBasicStepInterpolator(isForward, previous, current);

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

  137.                 // Update the potential changes in the spacecraft state due to the events
  138.                 // especially the potential attitude transition
  139.                 state = updateAdditionalStates(basicPropagate(state.getDate()));

  140.             } while (!isLastStep);

  141.             // return the last computed state
  142.             lastPropagationEnd = state.getDate();
  143.             setStartDate(state.getDate());
  144.             return state;

  145.         } catch (MathRuntimeException mrte) {
  146.             throw OrekitException.unwrap(mrte);
  147.         }
  148.     }

  149.     /** Accept a step, triggering events and step handlers.
  150.      * @param interpolator interpolator for the current step
  151.      * @param target final propagation time
  152.      * @return state at the end of the step
  153.      * @exception MathRuntimeException if an event cannot be located
  154.      */
  155.     protected FieldSpacecraftState<T> acceptStep(final FieldBasicStepInterpolator interpolator,
  156.                                                  final FieldAbsoluteDate<T> target)
  157.         throws MathRuntimeException {

  158.         FieldSpacecraftState<T>       previous   = interpolator.getPreviousState();
  159.         final FieldSpacecraftState<T> current    = interpolator.getCurrentState();
  160.         FieldBasicStepInterpolator    restricted = interpolator;

  161.         // initialize the events states if needed
  162.         if (!statesInitialized) {

  163.             if (!eventsStates.isEmpty()) {
  164.                 // initialize the events states
  165.                 for (final FieldEventState<?, T> state : eventsStates) {
  166.                     state.reinitializeBegin(interpolator);
  167.                 }
  168.             }

  169.             statesInitialized = true;

  170.         }

  171.         // search for next events that may occur during the step
  172.         final int orderingSign = interpolator.isForward() ? +1 : -1;
  173.         final Queue<FieldEventState<?, T>> occurringEvents = new PriorityQueue<>(new Comparator<FieldEventState<?, T>>() {
  174.             /** {@inheritDoc} */
  175.             @Override
  176.             public int compare(final FieldEventState<?, T> es0, final FieldEventState<?, T> es1) {
  177.                 return orderingSign * es0.getEventDate().compareTo(es1.getEventDate());
  178.             }
  179.         });

  180.         boolean doneWithStep = false;
  181.         resetEvents:
  182.         do {

  183.             // Evaluate all event detectors for events
  184.             occurringEvents.clear();
  185.             for (final FieldEventState<?, T> state : eventsStates) {
  186.                 if (state.evaluateStep(interpolator)) {
  187.                     // the event occurs during the current step
  188.                     occurringEvents.add(state);
  189.                 }
  190.             }


  191.             do {

  192.                 eventLoop:
  193.                 while (!occurringEvents.isEmpty()) {

  194.                     // handle the chronologically first event
  195.                     final FieldEventState<?, T> currentEvent = occurringEvents.poll();

  196.                     // get state at event time
  197.                     FieldSpacecraftState<T> eventState = restricted.getInterpolatedState(currentEvent.getEventDate());

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

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

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

  216.                     // acknowledge event occurrence
  217.                     final EventOccurrence<T> occurrence = currentEvent.doEvent(eventState);
  218.                     final Action action = occurrence.getAction();
  219.                     isLastStep = action == Action.STOP;
  220.                     if (isLastStep) {

  221.                         // ensure the event is after the root if it is returned STOP
  222.                         // this lets the user integrate to a STOP event and then restart
  223.                         // integration from the same time.
  224.                         final FieldSpacecraftState<T> savedState = eventState;
  225.                         eventState = interpolator.getInterpolatedState(occurrence.getStopDate());
  226.                         restricted = restricted.restrictStep(savedState, eventState);

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

  230.                     }

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

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

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

  246.                     if (action == Action.RESET_EVENTS) {
  247.                         continue resetEvents;
  248.                     }

  249.                     // at this pint action == Action.CONTINUE
  250.                     // check if the same event occurs again in the remaining part of the step
  251.                     if (currentEvent.evaluateStep(restricted)) {
  252.                         // the event occurs during the current step
  253.                         occurringEvents.add(currentEvent);
  254.                     }

  255.                 }

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

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

  268.             doneWithStep = true;
  269.         } while (!doneWithStep);

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

  271.         // handle the remaining part of the step, after all events if any
  272.         getMultiplexer().handleStep(restricted);
  273.         if (isLastStep) {
  274.             getMultiplexer().finish(restricted.getCurrentState());
  275.         }

  276.         return current;

  277.     }

  278.     /** Get the mass.
  279.      * @param date target date for the orbit
  280.      * @return mass mass
  281.      */
  282.     protected abstract T getMass(FieldAbsoluteDate<T> date);

  283.     /** Get PV coordinates provider.
  284.      * @return PV coordinates provider
  285.      */
  286.     public FieldPVCoordinatesProvider<T> getPvProvider() {
  287.         return pvProvider;
  288.     }

  289.     /** Reset an intermediate state.
  290.      * @param state new intermediate state to consider
  291.      * @param forward if true, the intermediate state is valid for
  292.      * propagations after itself
  293.      */
  294.     protected abstract void resetIntermediateState(FieldSpacecraftState<T> state, boolean forward);

  295.     /** Extrapolate an orbit up to a specific target date.
  296.      * @param date target date for the orbit
  297.      * @param parameters model parameters
  298.      * @return extrapolated parameters
  299.      */
  300.     protected abstract FieldOrbit<T> propagateOrbit(FieldAbsoluteDate<T> date, T[] parameters);

  301.     /** Get the parameters driver for propagation model.
  302.      * @return drivers for propagation model
  303.      */
  304.     protected abstract List<ParameterDriver> getParametersDrivers();

  305.     /** Get model parameters.
  306.      * @param field field to which the elements belong
  307.      * @return model parameters
  308.      */
  309.     public T[] getParameters(final Field<T> field) {
  310.         final List<ParameterDriver> drivers = getParametersDrivers();
  311.         final T[] parameters = MathArrays.buildArray(field, drivers.size());
  312.         for (int i = 0; i < drivers.size(); ++i) {
  313.             parameters[i] = field.getZero().add(drivers.get(i).getValue());
  314.         }
  315.         return parameters;
  316.     }

  317.     /** Propagate an orbit without any fancy features.
  318.      * <p>This method is similar in spirit to the {@link #propagate} method,
  319.      * except that it does <strong>not</strong> call any handler during
  320.      * propagation, nor any discrete events, not additional states. It always
  321.      * stop exactly at the specified date.</p>
  322.      * @param date target date for propagation
  323.      * @return state at specified date
  324.      */
  325.     protected FieldSpacecraftState<T> basicPropagate(final FieldAbsoluteDate<T> date) {
  326.         try {

  327.             // evaluate orbit
  328.             final FieldOrbit<T> orbit = propagateOrbit(date, getParameters(date.getField()));

  329.             // evaluate attitude
  330.             final FieldAttitude<T> attitude =
  331.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

  332.             // build raw state
  333.             return new FieldSpacecraftState<>(orbit, attitude, getMass(date));

  334.         } catch (OrekitException oe) {
  335.             throw new OrekitException(oe);
  336.         }
  337.     }

  338.     /** Internal FieldPVCoordinatesProvider<T> for attitude computation. */
  339.     private class FieldLocalPVProvider implements FieldPVCoordinatesProvider<T> {

  340.         /** {@inheritDoc} */
  341.         @Override
  342.         public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame) {
  343.             return propagateOrbit(date, getParameters(date.getField())).getPVCoordinates(frame);
  344.         }

  345.     }

  346.     /** {@link BoundedPropagator} view of the instance. */
  347.     private class FieldBoundedPropagatorView extends FieldAbstractAnalyticalPropagator<T>
  348.         implements FieldBoundedPropagator<T> {

  349.         /** Min date. */
  350.         private final FieldAbsoluteDate<T> minDate;

  351.         /** Max date. */
  352.         private final FieldAbsoluteDate<T> maxDate;

  353.         /** Simple constructor.
  354.          * @param startDate start date of the propagation
  355.          * @param endDate end date of the propagation
  356.          */
  357.         FieldBoundedPropagatorView(final FieldAbsoluteDate<T> startDate, final FieldAbsoluteDate<T> endDate) {
  358.             super(startDate.durationFrom(endDate).getField(), FieldAbstractAnalyticalPropagator.this.getAttitudeProvider());
  359.             super.resetInitialState(FieldAbstractAnalyticalPropagator.this.getInitialState());
  360.             if (startDate.compareTo(endDate) <= 0) {
  361.                 minDate = startDate;
  362.                 maxDate = endDate;
  363.             } else {
  364.                 minDate = endDate;
  365.                 maxDate = startDate;
  366.             }

  367.             try {
  368.                 // copy the same additional state providers as the original propagator
  369.                 for (FieldAdditionalStateProvider<T> provider : FieldAbstractAnalyticalPropagator.this.getAdditionalStateProviders()) {
  370.                     addAdditionalStateProvider(provider);
  371.                 }
  372.             } catch (OrekitException oe) {
  373.                 // as the providers are already compatible with each other,
  374.                 // this should never happen
  375.                 throw new OrekitInternalError(null);
  376.             }

  377.         }

  378.         /** {@inheritDoc} */
  379.         @Override
  380.         public FieldAbsoluteDate<T> getMinDate() {
  381.             return minDate;
  382.         }

  383.         /** {@inheritDoc} */
  384.         @Override
  385.         public FieldAbsoluteDate<T> getMaxDate() {
  386.             return maxDate;
  387.         }

  388.         /** {@inheritDoc} */
  389.         @Override
  390.         protected FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> target, final T[] parameters) {
  391.             return FieldAbstractAnalyticalPropagator.this.propagateOrbit(target, parameters);
  392.         }

  393.         /** {@inheritDoc} */
  394.         @Override
  395.         public T getMass(final FieldAbsoluteDate<T> date) {
  396.             return FieldAbstractAnalyticalPropagator.this.getMass(date);
  397.         }

  398.         /** {@inheritDoc} */
  399.         @Override
  400.         public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame) {
  401.             return propagate(date).getPVCoordinates(frame);
  402.         }

  403.         /** {@inheritDoc} */
  404.         @Override
  405.         public void resetInitialState(final FieldSpacecraftState<T> state) {
  406.             super.resetInitialState(state);
  407.             FieldAbstractAnalyticalPropagator.this.resetInitialState(state);
  408.         }

  409.         /** {@inheritDoc} */
  410.         @Override
  411.         protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  412.             FieldAbstractAnalyticalPropagator.this.resetIntermediateState(state, forward);
  413.         }

  414.         /** {@inheritDoc} */
  415.         @Override
  416.         public FieldSpacecraftState<T> getInitialState() {
  417.             return FieldAbstractAnalyticalPropagator.this.getInitialState();
  418.         }

  419.         /** {@inheritDoc} */
  420.         @Override
  421.         public Frame getFrame() {
  422.             return FieldAbstractAnalyticalPropagator.this.getFrame();
  423.         }

  424.         @Override
  425.         protected List<ParameterDriver> getParametersDrivers() {
  426.             return FieldAbstractAnalyticalPropagator.this.getParametersDrivers();
  427.         }
  428.     }


  429.     /** Internal class for local propagation. */
  430.     private class FieldBasicStepInterpolator implements FieldOrekitStepInterpolator<T> {

  431.         /** Previous state. */
  432.         private final FieldSpacecraftState<T> previousState;

  433.         /** Current state. */
  434.         private final FieldSpacecraftState<T> currentState;

  435.         /** Forward propagation indicator. */
  436.         private final boolean forward;

  437.         /** Simple constructor.
  438.          * @param isForward integration direction indicator
  439.          * @param previousState start of the step
  440.          * @param currentState end of the step
  441.          */
  442.         FieldBasicStepInterpolator(final boolean isForward,
  443.                                    final FieldSpacecraftState<T> previousState,
  444.                                    final FieldSpacecraftState<T> currentState) {
  445.             this.forward             = isForward;
  446.             this.previousState   = previousState;
  447.             this.currentState    = currentState;
  448.         }

  449.         /** {@inheritDoc} */
  450.         @Override
  451.         public FieldSpacecraftState<T> getPreviousState() {
  452.             return previousState;
  453.         }

  454.         /** {@inheritDoc} */
  455.         @Override
  456.         public FieldSpacecraftState<T> getCurrentState() {
  457.             return currentState;
  458.         }

  459.         /** {@inheritDoc} */
  460.         @Override
  461.         public FieldSpacecraftState<T> getInterpolatedState(final FieldAbsoluteDate<T> date) {

  462.             // compute the basic spacecraft state
  463.             final FieldSpacecraftState<T> basicState = basicPropagate(date);

  464.             // add the additional states
  465.             return updateAdditionalStates(basicState);

  466.         }

  467.         /** {@inheritDoc} */
  468.         @Override
  469.         public boolean isForward() {
  470.             return forward;
  471.         }

  472.         /** {@inheritDoc} */
  473.         @Override
  474.         public FieldBasicStepInterpolator restrictStep(final FieldSpacecraftState<T> newPreviousState,
  475.                                                        final FieldSpacecraftState<T> newCurrentState) {
  476.             return new FieldBasicStepInterpolator(forward, newPreviousState, newCurrentState);
  477.         }

  478.     }

  479. }