EventState.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF 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.events;

  18. import java.io.Serializable;

  19. import org.apache.commons.math3.analysis.UnivariateFunction;
  20. import org.apache.commons.math3.analysis.solvers.AllowedSolution;
  21. import org.apache.commons.math3.analysis.solvers.BracketingNthOrderBrentSolver;
  22. import org.apache.commons.math3.exception.NoBracketingException;
  23. import org.apache.commons.math3.exception.TooManyEvaluationsException;
  24. import org.apache.commons.math3.util.FastMath;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.propagation.SpacecraftState;
  27. import org.orekit.propagation.events.handlers.EventHandler;
  28. import org.orekit.propagation.sampling.OrekitStepInterpolator;
  29. import org.orekit.time.AbsoluteDate;

  30. /** This class handles the state for one {@link EventDetector
  31.  * event detector} during integration steps.
  32.  *
  33.  * <p>This class is heavily based on the class with the same name from the
  34.  * Apache Commons Math library. The changes performed consist in replacing
  35.  * raw types (double and double arrays) with space dynamics types
  36.  * ({@link AbsoluteDate}, {@link SpacecraftState}).</p>
  37.  * <p>Each time the propagator proposes a step, the event detector
  38.  * should be checked. This class handles the state of one detector
  39.  * during one propagation step, with references to the state at the
  40.  * end of the preceding step. This information is used to determine if
  41.  * the detector should trigger an event or not during the proposed
  42.  * step (and hence the step should be reduced to ensure the event
  43.  * occurs at a bound rather than inside the step).</p>
  44.  * @author Luc Maisonobe
  45.  * @param <T> class type for the generic version
  46.  */
  47. public class EventState<T extends EventDetector> implements Serializable {

  48.     /** Serializable version identifier. */
  49.     private static final long serialVersionUID = 4489391420715269318L;

  50.     /** Event detector. */
  51.     private T detector;

  52.     /** Time of the previous call to g. */
  53.     private AbsoluteDate lastT;

  54.     /** Value from the previous call to g. */
  55.     private double lastG;

  56.     /** Time at the beginning of the step. */
  57.     private AbsoluteDate t0;

  58.     /** Value of the event detector at the beginning of the step. */
  59.     private double g0;

  60.     /** Simulated sign of g0 (we cheat when crossing events). */
  61.     private boolean g0Positive;

  62.     /** Indicator of event expected during the step. */
  63.     private boolean pendingEvent;

  64.     /** Occurrence time of the pending event. */
  65.     private AbsoluteDate pendingEventTime;

  66.     /** Occurrence time of the previous event. */
  67.     private AbsoluteDate previousEventTime;

  68.     /** Integration direction. */
  69.     private boolean forward;

  70.     /** Variation direction around pending event.
  71.      *  (this is considered with respect to the integration direction)
  72.      */
  73.     private boolean increasing;

  74.     /** Next action indicator. */
  75.     private EventHandler.Action nextAction;

  76.     /** Simple constructor.
  77.      * @param detector monitored event detector
  78.      */
  79.     public EventState(final T detector) {
  80.         this.detector     = detector;

  81.         // some dummy values ...
  82.         t0                = null;
  83.         g0                = Double.NaN;
  84.         g0Positive        = true;
  85.         pendingEvent      = false;
  86.         pendingEventTime  = null;
  87.         previousEventTime = null;
  88.         increasing        = true;
  89.         nextAction        = EventHandler.Action.CONTINUE;

  90.     }

  91.     /** Get the underlying event detector.
  92.      * @return underlying event detector
  93.      */
  94.     public T getEventDetector() {
  95.         return detector;
  96.     }

  97.     /** Initialize event handler at the start of a propagation.
  98.      * <p>
  99.      * This method is called once at the start of the propagation. It
  100.      * may be used by the event handler to initialize some internal data
  101.      * if needed.
  102.      * </p>
  103.      * @param s0 initial state
  104.      * @param t target time for the integration
  105.      */
  106.     public void init(final SpacecraftState s0, final AbsoluteDate t) {
  107.         detector.init(s0, t);
  108.         lastT = AbsoluteDate.PAST_INFINITY;
  109.         lastG = Double.NaN;
  110.     }

  111.     /** Compute the value of the switching function.
  112.      * This function must be continuous (at least in its roots neighborhood),
  113.      * as the integrator will need to find its roots to locate the events.
  114.      * @param s the current state information: date, kinematics, attitude
  115.      * @return value of the switching function
  116.      * @exception OrekitException if some specific error occurs
  117.      */
  118.     private double g(final SpacecraftState s) throws OrekitException {
  119.         if (!s.getDate().equals(lastT)) {
  120.             lastT = s.getDate();
  121.             lastG = detector.g(s);
  122.         }
  123.         return lastG;
  124.     }

  125.     /** Reinitialize the beginning of the step.
  126.      * @param state0 state value at the beginning of the step
  127.      * @param isForward if true, step will be forward
  128.      * @exception OrekitException if the event detector
  129.      * value cannot be evaluated at the beginning of the step
  130.      */
  131.     public void reinitializeBegin(final SpacecraftState state0, final boolean isForward)
  132.         throws OrekitException {
  133.         this.t0 = state0.getDate();
  134.         g0 = g(state0);
  135.         if (g0 == 0) {
  136.             // extremely rare case: there is a zero EXACTLY at interval start
  137.             // we will use the sign slightly after step beginning to force ignoring this zero
  138.             g0 = g(state0.shiftedBy((isForward ? 0.5 : -0.5) * detector.getThreshold()));
  139.         }
  140.         g0Positive = g0 >= 0;
  141.     }

  142.     /** Evaluate the impact of the proposed step on the event detector.
  143.      * @param interpolator step interpolator for the proposed step
  144.      * @return true if the event detector triggers an event before
  145.      * the end of the proposed step (this implies the step should be
  146.      * rejected)
  147.      * @exception OrekitException if the switching function
  148.      * cannot be evaluated
  149.      * @exception TooManyEvaluationsException if an event cannot be located
  150.      * @exception NoBracketingException if bracketing cannot be performed
  151.      */
  152.     public boolean evaluateStep(final OrekitStepInterpolator interpolator)
  153.         throws OrekitException, TooManyEvaluationsException, NoBracketingException {

  154.         try {

  155.             final double convergence    = detector.getThreshold();
  156.             final int maxIterationcount = detector.getMaxIterationCount();
  157.             if (forward ^ interpolator.isForward()) {
  158.                 forward = !forward;
  159.                 pendingEvent      = false;
  160.                 pendingEventTime  = null;
  161.                 previousEventTime = null;
  162.             }
  163.             final AbsoluteDate t1 = interpolator.getCurrentDate();
  164.             final double dt = t1.durationFrom(t0);
  165.             if (FastMath.abs(dt) < convergence) {
  166.                 // we cannot do anything on such a small step, don't trigger any events
  167.                 return false;
  168.             }
  169.             final int    n = FastMath.max(1, (int) FastMath.ceil(FastMath.abs(dt) / detector.getMaxCheckInterval()));
  170.             final double h = dt / n;

  171.             final UnivariateFunction f = new UnivariateFunction() {
  172.                 public double value(final double t) throws LocalWrapperException {
  173.                     try {
  174.                         interpolator.setInterpolatedDate(t0.shiftedBy(t));
  175.                         return g(interpolator.getInterpolatedState());
  176.                     } catch (OrekitException oe) {
  177.                         throw new LocalWrapperException(oe);
  178.                     }
  179.                 }
  180.             };

  181.             final BracketingNthOrderBrentSolver solver =
  182.                     new BracketingNthOrderBrentSolver(convergence, 5);

  183.             AbsoluteDate ta = t0;
  184.             double ga = g0;
  185.             for (int i = 0; i < n; ++i) {

  186.                 // evaluate detector value at the end of the substep
  187.                 final AbsoluteDate tb = t0.shiftedBy((i + 1) * h);
  188.                 interpolator.setInterpolatedDate(tb);
  189.                 final double gb = g(interpolator.getInterpolatedState());

  190.                 // check events occurrence
  191.                 if (g0Positive ^ (gb >= 0)) {
  192.                     // there is a sign change: an event is expected during this step

  193.                     // variation direction, with respect to the integration direction
  194.                     increasing = gb >= ga;

  195.                     // find the event time making sure we select a solution just at or past the exact root
  196.                     final double dtA = ta.durationFrom(t0);
  197.                     final double dtB = tb.durationFrom(t0);
  198.                     final double dtRoot = forward ?
  199.                                           solver.solve(maxIterationcount, f, dtA, dtB, AllowedSolution.RIGHT_SIDE) :
  200.                                           solver.solve(maxIterationcount, f, dtB, dtA, AllowedSolution.LEFT_SIDE);
  201.                     final AbsoluteDate root = t0.shiftedBy(dtRoot);

  202.                     if ((previousEventTime != null) &&
  203.                         (FastMath.abs(root.durationFrom(ta)) <= convergence) &&
  204.                         (FastMath.abs(root.durationFrom(previousEventTime)) <= convergence)) {
  205.                         // we have either found nothing or found (again ?) a past event,
  206.                         // retry the substep excluding this value
  207.                         ta = forward ? ta.shiftedBy(convergence) : ta.shiftedBy(-convergence);
  208.                         ga = f.value(ta.durationFrom(t0));
  209.                         --i;
  210.                     } else if ((previousEventTime == null) ||
  211.                                (FastMath.abs(previousEventTime.durationFrom(root)) > convergence)) {
  212.                         pendingEventTime = root;
  213.                         pendingEvent = true;
  214.                         return true;
  215.                     } else {
  216.                         // no sign change: there is no event for now
  217.                         ta = tb;
  218.                         ga = gb;
  219.                     }

  220.                 } else {
  221.                     // no sign change: there is no event for now
  222.                     ta = tb;
  223.                     ga = gb;
  224.                 }

  225.             }

  226.             // no event during the whole step
  227.             pendingEvent     = false;
  228.             pendingEventTime = null;
  229.             return false;

  230.         } catch (LocalWrapperException lwe) {
  231.             throw lwe.getWrappedException();
  232.         }

  233.     }

  234.     /** Get the occurrence time of the event triggered in the current
  235.      * step.
  236.      * @return occurrence time of the event triggered in the current
  237.      * step.
  238.      */
  239.     public AbsoluteDate getEventTime() {
  240.         return pendingEventTime;
  241.     }

  242.     /** Acknowledge the fact the step has been accepted by the propagator.
  243.      * @param state value of the state vector at the end of the step
  244.      * @exception OrekitException if the value of the switching
  245.      * function cannot be evaluated
  246.      */
  247.     public void stepAccepted(final SpacecraftState state)
  248.         throws OrekitException {

  249.         t0 = state.getDate();
  250.         g0 = g(state);

  251.         if (pendingEvent) {
  252.             // force the sign to its value "just after the event"
  253.             previousEventTime = state.getDate();
  254.             g0Positive        = increasing;
  255.             if (detector instanceof AbstractReconfigurableDetector) {
  256.                 @SuppressWarnings("unchecked")
  257.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) detector).getHandler();
  258.                 nextAction = handler.eventOccurred(state, detector, !(increasing ^ forward));
  259.             } else {
  260.                 @SuppressWarnings("deprecation")
  261.                 final EventHandler.Action a =
  262.                     AbstractReconfigurableDetector.convert(detector.eventOccurred(state, !(increasing ^ forward)));
  263.                 nextAction = a;
  264.             }
  265.         } else {
  266.             g0Positive = g0 >= 0;
  267.             nextAction = EventHandler.Action.CONTINUE;
  268.         }
  269.     }

  270.     /** Check if the propagation should be stopped at the end of the
  271.      * current step.
  272.      * @return true if the propagation should be stopped
  273.      */
  274.     public boolean stop() {
  275.         return nextAction == EventHandler.Action.STOP;
  276.     }

  277.     /** Let the event detector reset the state if it wants.
  278.      * @param oldState value of the state vector at the beginning of the next step
  279.      * @return new state (null if no reset is needed)
  280.      * @exception OrekitException if the state cannot be reset by the event
  281.      * detector
  282.      */
  283.     public SpacecraftState reset(final SpacecraftState oldState)
  284.         throws OrekitException {

  285.         if (!pendingEvent) {
  286.             return null;
  287.         }

  288.         final SpacecraftState newState;
  289.         if (nextAction != EventHandler.Action.RESET_STATE) {
  290.             newState = null;
  291.         } else {
  292.             if (detector instanceof AbstractReconfigurableDetector) {
  293.                 @SuppressWarnings("unchecked")
  294.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) detector).getHandler();
  295.                 newState = handler.resetState(detector, oldState);
  296.             } else {
  297.                 @SuppressWarnings("deprecation")
  298.                 final SpacecraftState s = detector.resetState(oldState);
  299.                 newState = s;
  300.             }
  301.         }

  302.         pendingEvent      = false;
  303.         pendingEventTime  = null;

  304.         return newState;

  305.     }

  306.     /** Local runtime exception wrapping OrekitException. */
  307.     private static class LocalWrapperException extends RuntimeException {

  308.         /** Serializable UID. */
  309.         private static final long serialVersionUID = 2734331164409224983L;

  310.         /** Wrapped exception. */
  311.         private final OrekitException wrappedException;

  312.         /** Simple constructor.
  313.          * @param wrapped wrapped exception
  314.          */
  315.         public LocalWrapperException(final OrekitException wrapped) {
  316.             this.wrappedException = wrapped;
  317.         }

  318.         /** Get the wrapped exception.
  319.          * @return wrapped exception
  320.          */
  321.         public OrekitException getWrappedException() {
  322.             return wrappedException;
  323.         }

  324.     }

  325. }