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

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

  59. public abstract class FieldAbstractAnalyticalPropagator<T extends RealFieldElement<T>> extends FieldAbstractPropagator<T> {

  60.     /** Provider for attitude computation. */
  61.     private FieldPVCoordinatesProvider<T> pvProvider;

  62.     /** Start date of last propagation. */
  63.     private FieldAbsoluteDate<T> lastPropagationStart;

  64.     /** End date of last propagation. */
  65.     private FieldAbsoluteDate<T> lastPropagationEnd;

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

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

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

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

  85.     /** {@inheritDoc} */
  86.     public FieldBoundedPropagator<T> getGeneratedEphemeris() {
  87.         return new FieldBoundedPropagatorView(lastPropagationStart, lastPropagationEnd);
  88.     }

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

  97.     /** {@inheritDoc} */
  98.     public void clearEventsDetectors() {
  99.         eventsStates.clear();
  100.     }
  101.     /** {@inheritDoc} */
  102.     public FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> start, final FieldAbsoluteDate<T> target)
  103.         throws OrekitException {
  104.         try {
  105.             lastPropagationStart = start;

  106.             final T dt       = target.durationFrom(start);

  107.             final double epsilon  = FastMath.ulp(dt.getReal());

  108.             FieldSpacecraftState<T> state = updateAdditionalStates(basicPropagate(start));

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

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

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

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

  132.                 // go ahead one step size
  133.                 final FieldSpacecraftState<T> previous = state;
  134.                 FieldAbsoluteDate<T> t = previous.getDate().shiftedBy(stepSize);
  135.                 if ((dt.getReal() == 0) || ((dt.getReal() > 0) ^ (t.compareTo(target) <= 0))) {
  136.                     // current step exceeds target
  137.                     t = target;
  138.                 }
  139.                 final FieldSpacecraftState<T> current = updateAdditionalStates(basicPropagate(t));
  140.                 final FieldBasicStepInterpolator interpolator = new FieldBasicStepInterpolator(dt.getReal() >= 0, previous, current);



  141.                 // accept the step, trigger events and step handlers
  142.                 state = acceptStep(interpolator, target, epsilon);
  143.             } while (!isLastStep);
  144.             // return the last computed state
  145.             lastPropagationEnd = state.getDate();
  146.             setStartDate(state.getDate());
  147.             return state;

  148.         } catch (OrekitException pe) {
  149.             throw pe;
  150.         } catch (MathRuntimeException mrte) {
  151.             throw OrekitException.unwrap(mrte);
  152.         }
  153.     }

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

  165.         FieldSpacecraftState<T>       previous = interpolator.getPreviousState();
  166.         final FieldSpacecraftState<T> current  = interpolator.getCurrentState();
  167.         // initialize the events states if needed
  168.         if (!statesInitialized) {

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

  175.             statesInitialized = true;

  176.         }
  177.         // search for next events that may occur during the step
  178.         final int orderingSign = interpolator.isForward() ? +1 : -1;
  179.         final Queue<FieldEventState<?, T>> occurringEvents = new PriorityQueue<>(new Comparator<FieldEventState<?, T>>() {
  180.             /** {@inheritDoc} */
  181.             @Override
  182.             public int compare(final FieldEventState<?, T> es0, final FieldEventState<?, T> es1) {
  183.                 return orderingSign * es0.getEventDate().compareTo(es1.getEventDate());
  184.             }
  185.         });
  186.         for (final FieldEventState<?, T> state : eventsStates) {
  187.             if (state.evaluateStep(interpolator)) {
  188.                 // the event occurs during the current step
  189.                 occurringEvents.add(state);
  190.             }
  191.         }



  192.         FieldBasicStepInterpolator restricted = interpolator;

  193.         do {
  194.             eventLoop:
  195.             while (!occurringEvents.isEmpty()) {
  196.                 // handle the chronologically first event
  197.                 final FieldEventState<?, T> currentEvent = occurringEvents.poll();

  198.                 // get state at event time
  199.                 FieldSpacecraftState<T> eventState = restricted.getInterpolatedState(currentEvent.getEventDate());
  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.                         occurringEvents.add(currentEvent);
  205.                         occurringEvents.remove(state); // remove if already has pending event
  206.                         occurringEvents.add(state);
  207.                         continue eventLoop;
  208.                     }
  209.                 }
  210.                 // all event detectors agree we can advance to the current event time
  211.                 final EventOccurrence<T> occurrence = currentEvent.doEvent(eventState);
  212.                 final Action action = occurrence.getAction();
  213.                 isLastStep = action == Action.STOP;
  214.                 if (isLastStep) {
  215.                     // ensure the event is after the root if it is returned STOP
  216.                     // this lets the user integrate to a STOP event and then restart
  217.                     // integration from the same time.
  218.                     eventState = interpolator.getInterpolatedState(occurrence.getStopDate());
  219.                     restricted = new FieldBasicStepInterpolator(restricted.isForward(), previous, eventState);
  220.                 }
  221.                 // handle the first part of the step, up to the event
  222.                 if (getStepHandler() != null) {
  223.                     getStepHandler().handleStep(restricted, isLastStep);
  224.                 }

  225.                 if (isLastStep) {
  226.                     // the event asked to stop integration
  227.                     return eventState;
  228.                 }

  229.                 if (action == Action.RESET_DERIVATIVES || action == Action.RESET_STATE) {
  230.                     // some event handler has triggered changes that
  231.                     // invalidate the derivatives, we need to recompute them
  232.                     final FieldSpacecraftState<T> resetState = occurrence.getNewState();
  233.                     if (resetState != null) {
  234.                         resetIntermediateState( resetState, interpolator.isForward());
  235.                         return resetState;
  236.                     }
  237.                 }
  238.                 // at this point we know action == Action.CONTINUE

  239.                 // prepare handling of the remaining part of the step
  240.                 previous = eventState;
  241.                 restricted         = new FieldBasicStepInterpolator(restricted.isForward(), eventState, current);

  242.                 // check if the same event occurs again in the remaining part of the step
  243.                 if (currentEvent.evaluateStep(restricted)) {
  244.                     // the event occurs during the current step
  245.                     occurringEvents.add(currentEvent);
  246.                 }

  247.             }

  248.             // last part of the step, after the last event
  249.             // may be a new event here if the last event modified the g function of
  250.             // another event detector.
  251.             for (final FieldEventState<?, T> state : eventsStates) {
  252.                 if (state.tryAdvance(current, interpolator)) {
  253.                     occurringEvents.add(state);
  254.                 }
  255.             }

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

  257.         final T remaining = target.durationFrom(current.getDate());
  258.         if (interpolator.isForward()) {
  259.             isLastStep = remaining.getReal() <  epsilon;
  260.         } else {
  261.             isLastStep = remaining.getReal() > -epsilon;
  262.         }

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

  268.     }

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

  276.     /** Get PV coordinates provider.
  277.      * @return PV coordinates provider
  278.      */
  279.     public FieldPVCoordinatesProvider<T> getPvProvider() {
  280.         return pvProvider;
  281.     }

  282.     /** {@inheritDoc} */
  283.     public <D extends FieldEventDetector<T>> void addEventDetector(final D detector) {
  284.         eventsStates.add(new FieldEventState<D, T>(detector));
  285.     }

  286.     /** Reset an intermediate state.
  287.      * @param state new intermediate state to consider
  288.      * @param forward if true, the intermediate state is valid for
  289.      * propagations after itself
  290.      * @exception OrekitException if initial state cannot be reset
  291.      */
  292.     protected abstract void resetIntermediateState(FieldSpacecraftState<T> state, boolean forward)
  293.         throws OrekitException;

  294.     /** Extrapolate an orbit up to a specific target date.
  295.      * @param date target date for the orbit
  296.      * @return extrapolated parameters
  297.      * @exception OrekitException if some parameters are out of bounds
  298.      */
  299.     protected abstract FieldOrbit<T> propagateOrbit(FieldAbsoluteDate<T> date)
  300.         throws OrekitException;

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

  312.             // evaluate orbit
  313.             final FieldOrbit<T> orbit = propagateOrbit(date);

  314.             // evaluate attitude
  315.             final FieldAttitude<T> attitude =
  316.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

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

  319.         } catch (OrekitException oe) {
  320.             throw new OrekitException(oe);
  321.         }
  322.     }

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

  325.         /** {@inheritDoc} */
  326.         public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame)
  327.             throws OrekitException {
  328.             return propagateOrbit(date).getPVCoordinates(frame);
  329.         }

  330.     }

  331.     /** {@link BoundedPropagator} view of the instance. */
  332.     private class FieldBoundedPropagatorView extends FieldAbstractAnalyticalPropagator<T>
  333.         implements FieldBoundedPropagator<T> {

  334.         /** Min date. */
  335.         private final FieldAbsoluteDate<T> minDate;

  336.         /** Max date. */
  337.         private final FieldAbsoluteDate<T> maxDate;

  338.         /** Simple constructor.
  339.          * @param startDate start date of the propagation
  340.          * @param endDate end date of the propagation
  341.          */
  342.         FieldBoundedPropagatorView(final FieldAbsoluteDate<T> startDate, final FieldAbsoluteDate<T> endDate) {
  343.             super(startDate.durationFrom(endDate).getField(), FieldAbstractAnalyticalPropagator.this.getAttitudeProvider());
  344.             if (startDate.compareTo(endDate) <= 0) {
  345.                 minDate = startDate;
  346.                 maxDate = endDate;
  347.             } else {
  348.                 minDate = endDate;
  349.                 maxDate = startDate;
  350.             }

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

  361.         }

  362.         /** {@inheritDoc} */
  363.         public FieldAbsoluteDate<T> getMinDate() {
  364.             return minDate;
  365.         }

  366.         /** {@inheritDoc} */
  367.         public FieldAbsoluteDate<T> getMaxDate() {
  368.             return maxDate;
  369.         }

  370.         /** {@inheritDoc} */
  371.         protected FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> target)
  372.             throws OrekitException {
  373.             return FieldAbstractAnalyticalPropagator.this.propagateOrbit(target);
  374.         }

  375.         /** {@inheritDoc} */
  376.         public T getMass(final FieldAbsoluteDate<T> date) throws OrekitException {
  377.             return FieldAbstractAnalyticalPropagator.this.getMass(date);
  378.         }

  379.         /** {@inheritDoc} */
  380.         public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame)
  381.             throws OrekitException {
  382.             return propagate(date).getPVCoordinates(frame);
  383.         }

  384.         /** {@inheritDoc} */
  385.         public void resetInitialState(final FieldSpacecraftState<T> state) throws OrekitException {
  386.             FieldAbstractAnalyticalPropagator.this.resetInitialState(state);
  387.         }

  388.         /** {@inheritDoc} */
  389.         protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward)
  390.             throws OrekitException {
  391.             FieldAbstractAnalyticalPropagator.this.resetIntermediateState(state, forward);
  392.         }

  393.         /** {@inheritDoc} */
  394.         public FieldSpacecraftState<T> getInitialState() throws OrekitException {
  395.             return FieldAbstractAnalyticalPropagator.this.getInitialState();
  396.         }

  397.         /** {@inheritDoc} */
  398.         public Frame getFrame() {
  399.             return FieldAbstractAnalyticalPropagator.this.getFrame();
  400.         }
  401.     }


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

  404.         /** Previous state. */
  405.         private final FieldSpacecraftState<T> previousState;

  406.         /** Current state. */
  407.         private final FieldSpacecraftState<T> currentState;

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

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

  422.         /** {@inheritDoc} */
  423.         public FieldSpacecraftState<T> getPreviousState() {
  424.             return previousState;
  425.         }

  426.         /** {@inheritDoc} */
  427.         public FieldSpacecraftState<T> getCurrentState() {
  428.             return currentState;
  429.         }

  430.         /** {@inheritDoc} */
  431.         public FieldSpacecraftState<T> getInterpolatedState(final FieldAbsoluteDate<T> date)
  432.             throws OrekitException {

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

  435.             // add the additional states
  436.             return updateAdditionalStates(basicState);

  437.         }

  438.         /** {@inheritDoc} */
  439.         public boolean isForward() {
  440.             return forward;
  441.         }

  442.     }

  443. }