AbstractAnalyticalPropagator.java

  1. /* Copyright 2002-2013 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.Iterator;
  23. import java.util.List;

  24. import org.apache.commons.math3.exception.NoBracketingException;
  25. import org.apache.commons.math3.exception.TooManyEvaluationsException;
  26. import org.apache.commons.math3.util.FastMath;
  27. import org.orekit.attitudes.Attitude;
  28. import org.orekit.attitudes.AttitudeProvider;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.PropagationException;
  31. import org.orekit.frames.Frame;
  32. import org.orekit.orbits.Orbit;
  33. import org.orekit.propagation.AbstractPropagator;
  34. import org.orekit.propagation.BoundedPropagator;
  35. import org.orekit.propagation.SpacecraftState;
  36. import org.orekit.propagation.events.EventDetector;
  37. import org.orekit.propagation.events.EventState;
  38. import org.orekit.propagation.sampling.OrekitStepInterpolator;
  39. import org.orekit.time.AbsoluteDate;
  40. import org.orekit.utils.PVCoordinates;
  41. import org.orekit.utils.PVCoordinatesProvider;

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

  54.     /** Internal steps interpolator. */
  55.     private final BasicStepInterpolator interpolator;

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

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

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

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

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

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

  68.     /** Build a new instance.
  69.      * @param attitudeProvider provider for attitude computation
  70.      */
  71.     protected AbstractAnalyticalPropagator(final AttitudeProvider attitudeProvider) {
  72.         setAttitudeProvider(attitudeProvider);
  73.         interpolator             = new BasicStepInterpolator();
  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.         throws PropagationException {
  103.         try {

  104.             lastPropagationStart = start;

  105.             final double dt      = target.durationFrom(start);
  106.             final double epsilon = FastMath.ulp(dt);
  107.             interpolator.storeDate(start);
  108.             SpacecraftState state = interpolator.getInterpolatedState();

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

  120.             // initialize event detectors
  121.             for (final EventState<?> 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.                 interpolator.shift();
  134.                 final AbsoluteDate t = interpolator.getCurrentDate().shiftedBy(stepSize);
  135.                 if ((dt == 0) || ((dt > 0) ^ (t.compareTo(target) <= 0))) {
  136.                     // current step exceeds target
  137.                     interpolator.storeDate(target);
  138.                 } else {
  139.                     // current step is within range
  140.                     interpolator.storeDate(t);
  141.                 }

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

  144.             } while (!isLastStep);

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

  149.         } catch (PropagationException pe) {
  150.             throw pe;
  151.         } catch (OrekitException oe) {
  152.             throw PropagationException.unwrap(oe);
  153.         } catch (TooManyEvaluationsException tmee) {
  154.             throw PropagationException.unwrap(tmee);
  155.         } catch (NoBracketingException nbe) {
  156.             throw PropagationException.unwrap(nbe);
  157.         }
  158.     }

  159.     /** Accept a step, triggering events and step handlers.
  160.      * @param target final propagation time
  161.      * @param epsilon threshold for end date detection
  162.      * @return state at the end of the step
  163.      * @exception OrekitException if the switching function cannot be evaluated
  164.      * @exception TooManyEvaluationsException if an event cannot be located
  165.      * @exception NoBracketingException if bracketing cannot be performed
  166.      */
  167.     protected SpacecraftState acceptStep(final AbsoluteDate target, final double epsilon)
  168.         throws OrekitException, TooManyEvaluationsException, NoBracketingException {

  169.         AbsoluteDate previousT = interpolator.getGlobalPreviousDate();
  170.         AbsoluteDate currentT  = interpolator.getGlobalCurrentDate();

  171.         // initialize the events states if needed
  172.         if (!statesInitialized) {

  173.             if (!eventsStates.isEmpty()) {
  174.                 // initialize the events states
  175.                 final AbsoluteDate t0 = interpolator.getPreviousDate();
  176.                 interpolator.setInterpolatedDate(t0);
  177.                 final SpacecraftState y = interpolator.getInterpolatedState();
  178.                 for (final EventState<?> state : eventsStates) {
  179.                     state.reinitializeBegin(y, interpolator.isForward());
  180.                 }
  181.             }

  182.             statesInitialized = true;

  183.         }

  184.         // search for next events that may occur during the step
  185.         final List<EventState<?>> occurringEvents = new ArrayList<EventState<?>>();
  186.         for (final EventState<?> state : eventsStates) {
  187.             if (state.evaluateStep(interpolator)) {
  188.                 // the event occurs during the current step
  189.                 occurringEvents.add(state);
  190.             }
  191.         }

  192.         // chronological or reverse chronological sorter, according to propagation direction
  193.         final int orderingSign = interpolator.isForward() ? +1 : -1;
  194.         final Comparator<EventState<?>> sorter = new Comparator<EventState<?>>() {

  195.             /** {@inheritDoc} */
  196.             public int compare(final EventState<?> es0, final EventState<?> es1) {
  197.                 return orderingSign * es0.getEventTime().compareTo(es1.getEventTime());
  198.             }

  199.         };

  200.         while (!occurringEvents.isEmpty()) {

  201.             // handle the chronologically first event
  202.             Collections.sort(occurringEvents, sorter);
  203.             final Iterator<EventState<?>> iterator = occurringEvents.iterator();
  204.             final EventState<?> currentEvent = iterator.next();
  205.             iterator.remove();

  206.             // restrict the interpolator to the first part of the step, up to the event
  207.             final AbsoluteDate eventT = currentEvent.getEventTime();
  208.             interpolator.setSoftPreviousDate(previousT);
  209.             interpolator.setSoftCurrentDate(eventT);

  210.             // trigger the event
  211.             interpolator.setInterpolatedDate(eventT);
  212.             final SpacecraftState eventY = interpolator.getInterpolatedState();
  213.             currentEvent.stepAccepted(eventY);
  214.             isLastStep = currentEvent.stop();

  215.             // handle the first part of the step, up to the event
  216.             if (getStepHandler() != null) {
  217.                 getStepHandler().handleStep(interpolator, isLastStep);
  218.             }

  219.             if (isLastStep) {
  220.                 // the event asked to stop integration
  221.                 return eventY;
  222.             }

  223.             final SpacecraftState resetState = currentEvent.reset(eventY);
  224.             if (resetState != null) {
  225.                 resetInitialState(resetState);
  226.                 return resetState;
  227.             }

  228.             // prepare handling of the remaining part of the step
  229.             previousT = eventT;
  230.             interpolator.setSoftPreviousDate(eventT);
  231.             interpolator.setSoftCurrentDate(currentT);

  232.             // check if the same event occurs again in the remaining part of the step
  233.             if (currentEvent.evaluateStep(interpolator)) {
  234.                 // the event occurs during the current step
  235.                 occurringEvents.add(currentEvent);
  236.             }

  237.         }

  238.         final double remaining = target.durationFrom(currentT);
  239.         if (interpolator.isForward()) {
  240.             isLastStep = remaining <  epsilon;
  241.         } else {
  242.             isLastStep = remaining > -epsilon;
  243.         }
  244.         if (isLastStep) {
  245.             currentT = target;
  246.         }

  247.         interpolator.setInterpolatedDate(currentT);
  248.         final SpacecraftState currentY = interpolator.getInterpolatedState();
  249.         for (final EventState<?> state : eventsStates) {
  250.             state.stepAccepted(currentY);
  251.             isLastStep = isLastStep || state.stop();
  252.         }

  253.         // handle the remaining part of the step, after all events if any
  254.         if (getStepHandler() != null) {
  255.             getStepHandler().handleStep(interpolator, isLastStep);
  256.         }

  257.         return currentY;

  258.     }

  259.     /** Get the mass.
  260.      * @param date target date for the orbit
  261.      * @return mass mass
  262.      * @exception PropagationException if some parameters are out of bounds
  263.      */
  264.     protected abstract double getMass(final AbsoluteDate date)
  265.         throws PropagationException;

  266.     /** Get PV coordinates provider.
  267.      * @return PV coordinates provider
  268.      */
  269.     public PVCoordinatesProvider getPvProvider() {
  270.         return pvProvider;
  271.     }

  272.     /** Extrapolate an orbit up to a specific target date.
  273.      * @param date target date for the orbit
  274.      * @return extrapolated parameters
  275.      * @exception PropagationException if some parameters are out of bounds
  276.      */
  277.     protected abstract Orbit propagateOrbit(final AbsoluteDate date)
  278.         throws PropagationException;

  279.     /** Propagate an orbit without any fancy features.
  280.      * <p>This method is similar in spirit to the {@link #propagate} method,
  281.      * except that it does <strong>not</strong> call any handler during
  282.      * propagation, nor any discrete events, not additional states. It always
  283.      * stop exactly at the specified date.</p>
  284.      * @param date target date for propagation
  285.      * @return state at specified date
  286.      * @exception PropagationException if propagation cannot reach specified date
  287.      */
  288.     protected SpacecraftState basicPropagate(final AbsoluteDate date) throws PropagationException {
  289.         try {

  290.             // evaluate orbit
  291.             final Orbit orbit = propagateOrbit(date);

  292.             // evaluate attitude
  293.             final Attitude attitude =
  294.                 getAttitudeProvider().getAttitude(pvProvider, date, orbit.getFrame());

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

  297.         } catch (OrekitException oe) {
  298.             throw new PropagationException(oe);
  299.         }
  300.     }

  301.     /** Internal PVCoordinatesProvider for attitude computation. */
  302.     private class LocalPVProvider implements PVCoordinatesProvider {

  303.         /** {@inheritDoc} */
  304.         public PVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
  305.             throws OrekitException {
  306.             return propagateOrbit(date).getPVCoordinates(frame);
  307.         }

  308.     }

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

  311.         /** Min date. */
  312.         private final AbsoluteDate minDate;

  313.         /** Max date. */
  314.         private final AbsoluteDate maxDate;

  315.         /** Simple constructor.
  316.          * @param startDate start date of the propagation
  317.          * @param endDate end date of the propagation
  318.          */
  319.         public BoundedPropagatorView(final AbsoluteDate startDate, final AbsoluteDate endDate) {
  320.             super(AbstractAnalyticalPropagator.this.getAttitudeProvider());
  321.             if (startDate.compareTo(endDate) <= 0) {
  322.                 minDate = startDate;
  323.                 maxDate = endDate;
  324.             } else {
  325.                 minDate = endDate;
  326.                 maxDate = startDate;
  327.             }
  328.         }

  329.         /** {@inheritDoc} */
  330.         public AbsoluteDate getMinDate() {
  331.             return minDate;
  332.         }

  333.         /** {@inheritDoc} */
  334.         public AbsoluteDate getMaxDate() {
  335.             return maxDate;
  336.         }

  337.         /** {@inheritDoc} */
  338.         protected Orbit propagateOrbit(final AbsoluteDate target)
  339.             throws PropagationException {
  340.             return AbstractAnalyticalPropagator.this.propagateOrbit(target);
  341.         }

  342.         /** {@inheritDoc} */
  343.         public double getMass(final AbsoluteDate date) throws PropagationException {
  344.             return AbstractAnalyticalPropagator.this.getMass(date);
  345.         }

  346.         /** {@inheritDoc} */
  347.         public PVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame)
  348.             throws OrekitException {
  349.             return propagate(date).getPVCoordinates(frame);
  350.         }

  351.         /** {@inheritDoc} */
  352.         public void resetInitialState(final SpacecraftState state) throws PropagationException {
  353.             AbstractAnalyticalPropagator.this.resetInitialState(state);
  354.         }

  355.         /** {@inheritDoc} */
  356.         public SpacecraftState getInitialState() throws PropagationException {
  357.             return AbstractAnalyticalPropagator.this.getInitialState();
  358.         }

  359.     }

  360.     /** Internal class for local propagation. */
  361.     private class BasicStepInterpolator implements OrekitStepInterpolator {

  362.         /** Global previous date. */
  363.         private AbsoluteDate globalPreviousDate;

  364.         /** Global current date. */
  365.         private AbsoluteDate globalCurrentDate;

  366.         /** Soft previous date. */
  367.         private AbsoluteDate softPreviousDate;

  368.         /** Soft current date. */
  369.         private AbsoluteDate softCurrentDate;

  370.         /** Interpolated state. */
  371.         private SpacecraftState interpolatedState;

  372.         /** Forward propagation indicator. */
  373.         private boolean forward;

  374.         /** Build a new instance from a basic propagator.
  375.          */
  376.         public BasicStepInterpolator() {
  377.             globalPreviousDate = AbsoluteDate.PAST_INFINITY;
  378.             globalCurrentDate  = AbsoluteDate.PAST_INFINITY;
  379.             softPreviousDate   = AbsoluteDate.PAST_INFINITY;
  380.             softCurrentDate    = AbsoluteDate.PAST_INFINITY;
  381.         }

  382.         /** Restrict step range to a limited part of the global step.
  383.          * <p>
  384.          * This method can be used to restrict a step and make it appear
  385.          * as if the original step was smaller. Calling this method
  386.          * <em>only</em> changes the value returned by {@link #getPreviousDate()},
  387.          * it does not change any other property
  388.          * </p>
  389.          * @param softPreviousDate start of the restricted step
  390.          */
  391.         public void setSoftPreviousDate(final AbsoluteDate softPreviousDate) {
  392.             this.softPreviousDate = softPreviousDate;
  393.         }

  394.         /** Restrict step range to a limited part of the global step.
  395.          * <p>
  396.          * This method can be used to restrict a step and make it appear
  397.          * as if the original step was smaller. Calling this method
  398.          * <em>only</em> changes the value returned by {@link #getCurrentDate()},
  399.          * it does not change any other property
  400.          * </p>
  401.          * @param softCurrentDate end of the restricted step
  402.          */
  403.         public void setSoftCurrentDate(final AbsoluteDate softCurrentDate) {
  404.             this.softCurrentDate  = softCurrentDate;
  405.         }

  406.         /**
  407.          * Get the previous global grid point time.
  408.          * @return previous global grid point time
  409.          */
  410.         public AbsoluteDate getGlobalPreviousDate() {
  411.             return globalPreviousDate;
  412.         }

  413.         /**
  414.          * Get the current global grid point time.
  415.          * @return current global grid point time
  416.          */
  417.         public AbsoluteDate getGlobalCurrentDate() {
  418.             return globalCurrentDate;
  419.         }

  420.         /** {@inheritDoc} */
  421.         public AbsoluteDate getCurrentDate() {
  422.             return softCurrentDate;
  423.         }

  424.         /** {@inheritDoc} */
  425.         public AbsoluteDate getInterpolatedDate() {
  426.             return interpolatedState.getDate();
  427.         }

  428.         /** {@inheritDoc} */
  429.         public SpacecraftState getInterpolatedState() throws OrekitException {
  430.             return interpolatedState;
  431.         }

  432.         /** {@inheritDoc} */
  433.         public AbsoluteDate getPreviousDate() {
  434.             return softPreviousDate;
  435.         }

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

  440.         /** {@inheritDoc} */
  441.         public void setInterpolatedDate(final AbsoluteDate date) throws PropagationException {

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

  444.             // add the additional states
  445.             interpolatedState = updateAdditionalStates(basicState);

  446.         }

  447.         /** Shift one step forward.
  448.          * Copy the current date into the previous date, hence preparing the
  449.          * interpolator for future calls to {@link #storeDate storeDate}
  450.          */
  451.         public void shift() {
  452.             globalPreviousDate = globalCurrentDate;
  453.             softPreviousDate   = globalPreviousDate;
  454.             softCurrentDate    = globalCurrentDate;
  455.         }

  456.         /** Store the current step date.
  457.          * @param date current date
  458.          * @exception PropagationException if the state cannot be propagated at specified date
  459.          */
  460.         public void storeDate(final AbsoluteDate date)
  461.             throws PropagationException {
  462.             globalCurrentDate = date;
  463.             softCurrentDate   = globalCurrentDate;
  464.             forward           = globalCurrentDate.compareTo(globalPreviousDate) >= 0;
  465.             setInterpolatedDate(globalCurrentDate);
  466.         }

  467.     }

  468. }