EventFilter.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.util.Arrays;

  19. import org.orekit.errors.OrekitException;
  20. import org.orekit.propagation.SpacecraftState;
  21. import org.orekit.propagation.events.handlers.EventHandler;
  22. import org.orekit.time.AbsoluteDate;

  23. /** Wrapper used to detect only increasing or decreasing events.
  24.  *
  25.  * <p>This class is heavily based on the class with the same name from the
  26.  * Apache Commons Math library. The changes performed consist in replacing
  27.  * raw types (double and double arrays) with space dynamics types
  28.  * ({@link AbsoluteDate}, {@link SpacecraftState}).</p>
  29.  *
  30.  * <p>General {@link EventDetector events} are defined implicitely
  31.  * by a {@link EventDetector#g(SpacecraftState) g function} crossing
  32.  * zero. This function needs to be continuous in the event neighborhood,
  33.  * and its sign must remain consistent between events. This implies that
  34.  * during an ODE integration, events triggered are alternately events
  35.  * for which the function increases from negative to positive values,
  36.  * and events for which the function decreases from positive to
  37.  * negative values.
  38.  * </p>
  39.  *
  40.  * <p>Sometimes, users are only interested in one type of event (say
  41.  * increasing events for example) and not in the other type. In these
  42.  * cases, looking precisely for all events location and triggering
  43.  * events that will later be ignored is a waste of computing time.</p>
  44.  *
  45.  * <p>Users can wrap a regular {@link EventDetector event detector} in
  46.  * an instance of this class and provide this wrapping instance to
  47.  * a {@link org.orekit.propagation.Propagator}
  48.  * in order to avoid wasting time looking for uninteresting events.
  49.  * The wrapper will intercept the calls to the {@link
  50.  * EventDetector#g(SpacecraftState) g function} and to the {@link
  51.  * EventDetector#eventOccurred(SpacecraftState, boolean)
  52.  * eventOccurred} method in order to ignore uninteresting events. The
  53.  * wrapped regular {@link EventDetector event detector} will the see only
  54.  * the interesting events, i.e. either only {@code increasing} events or
  55.  * {@code decreasing} events. the number of calls to the {@link
  56.  * EventDetector#g(SpacecraftState) g function} will also be reduced.</p>
  57.  *
  58.  */

  59. public class EventFilter<T extends EventDetector> extends AbstractReconfigurableDetector<EventFilter<T>> {

  60.     /** Serializable UID. */
  61.     private static final long serialVersionUID = 20130409L;

  62.     /** Number of past transformers updates stored. */
  63.     private static final int HISTORY_SIZE = 100;

  64.     /** Wrapped event detector. */
  65.     private final T rawDetector;

  66.     /** Filter to use. */
  67.     private final FilterType filter;

  68.     /** Transformers of the g function. */
  69.     private final Transformer[] transformers;

  70.     /** Update time of the transformers. */
  71.     private final AbsoluteDate[] updates;

  72.     /** Indicator for forward integration. */
  73.     private boolean forward;

  74.     /** Extreme time encountered so far. */
  75.     private AbsoluteDate extremeT;

  76.     /** Wrap an {@link EventDetector event detector}.
  77.      * @param rawDetector event detector to wrap
  78.      * @param filter filter to use
  79.      */
  80.     public EventFilter(final T rawDetector, final FilterType filter) {
  81.         this(rawDetector.getMaxCheckInterval(), rawDetector.getThreshold(),
  82.              rawDetector.getMaxIterationCount(), new LocalHandler<T>(),
  83.              rawDetector, filter);
  84.     }

  85.     /** Private constructor with full parameters.
  86.      * <p>
  87.      * This constructor is private as users are expected to use the builder
  88.      * API with the various {@code withXxx()} methods to set up the instance
  89.      * in a readable manner without using a huge amount of parameters.
  90.      * </p>
  91.      * @param maxCheck maximum checking interval (s)
  92.      * @param threshold convergence threshold (s)
  93.      * @param maxIter maximum number of iterations in the event time search
  94.      * @param handler event handler to call at event occurrences
  95.      * @param rawDetector event detector to wrap
  96.      * @param filter filter to use
  97.      * @since 6.1
  98.      */
  99.     private EventFilter(final double maxCheck, final double threshold,
  100.                         final int maxIter, final EventHandler<EventFilter<T>> handler,
  101.                         final T rawDetector, final FilterType filter) {
  102.         super(maxCheck, threshold, maxIter, handler);
  103.         this.rawDetector  = rawDetector;
  104.         this.filter       = filter;
  105.         this.transformers = new Transformer[HISTORY_SIZE];
  106.         this.updates      = new AbsoluteDate[HISTORY_SIZE];
  107.     }

  108.     /** {@inheritDoc} */
  109.     @Override
  110.     protected EventFilter<T> create(final double newMaxCheck, final double newThreshold,
  111.                                  final int newMaxIter, final EventHandler<EventFilter<T>> newHandler) {
  112.         return new EventFilter<T>(newMaxCheck, newThreshold, newMaxIter, newHandler, rawDetector, filter);
  113.     }

  114.     /**  {@inheritDoc} */
  115.     public void init(final SpacecraftState s0, final AbsoluteDate t) {

  116.         // delegate to raw detector
  117.         rawDetector.init(s0, t);

  118.         // initialize events triggering logic
  119.         forward  = t.compareTo(s0.getDate()) >= 0;
  120.         extremeT = forward ? AbsoluteDate.PAST_INFINITY : AbsoluteDate.FUTURE_INFINITY;
  121.         Arrays.fill(transformers, Transformer.UNINITIALIZED);
  122.         Arrays.fill(updates, extremeT);

  123.     }

  124.     /**  {@inheritDoc} */
  125.     public double g(final SpacecraftState s) throws OrekitException {

  126.         final double rawG = rawDetector.g(s);

  127.         // search which transformer should be applied to g
  128.         if (forward) {
  129.             final int last = transformers.length - 1;
  130.             if (extremeT.compareTo(s.getDate()) < 0) {
  131.                 // we are at the forward end of the history

  132.                 // check if a new rough root has been crossed
  133.                 final Transformer previous = transformers[last];
  134.                 final Transformer next     = filter.selectTransformer(previous, rawG, forward);
  135.                 if (next != previous) {
  136.                     // there is a root somewhere between extremeT end t
  137.                     // the new transformer, which is valid on both sides of the root,
  138.                     // so it is valid for t (this is how we have just computed it above),
  139.                     // but it was already valid before, so we store the switch at extremeT
  140.                     // for safety, to ensure the previous transformer is not applied too
  141.                     // close of the root
  142.                     System.arraycopy(updates,      1, updates,      0, last);
  143.                     System.arraycopy(transformers, 1, transformers, 0, last);
  144.                     updates[last]      = extremeT;
  145.                     transformers[last] = next;
  146.                 }

  147.                 extremeT = s.getDate();

  148.                 // apply the transform
  149.                 return next.transformed(rawG);

  150.             } else {
  151.                 // we are in the middle of the history

  152.                 // select the transformer
  153.                 for (int i = last; i > 0; --i) {
  154.                     if (updates[i].compareTo(s.getDate()) <= 0) {
  155.                         // apply the transform
  156.                         return transformers[i].transformed(rawG);
  157.                     }
  158.                 }

  159.                 return transformers[0].transformed(rawG);

  160.             }
  161.         } else {
  162.             if (s.getDate().compareTo(extremeT) < 0) {
  163.                 // we are at the backward end of the history

  164.                 // check if a new rough root has been crossed
  165.                 final Transformer previous = transformers[0];
  166.                 final Transformer next     = filter.selectTransformer(previous, rawG, forward);
  167.                 if (next != previous) {
  168.                     // there is a root somewhere between extremeT end t
  169.                     // the new transformer, which is valid on both sides of the root,
  170.                     // so it is valid for t (this is how we have just computed it above),
  171.                     // but it was already valid before, so we store the switch at extremeT
  172.                     // for safety, to ensure the previous transformer is not applied too
  173.                     // close of the root
  174.                     System.arraycopy(updates,      0, updates,      1, updates.length - 1);
  175.                     System.arraycopy(transformers, 0, transformers, 1, transformers.length - 1);
  176.                     updates[0]      = extremeT;
  177.                     transformers[0] = next;
  178.                 }

  179.                 extremeT = s.getDate();

  180.                 // apply the transform
  181.                 return next.transformed(rawG);

  182.             } else {
  183.                 // we are in the middle of the history

  184.                 // select the transformer
  185.                 for (int i = 0; i < updates.length - 1; ++i) {
  186.                     if (s.getDate().compareTo(updates[i]) <= 0) {
  187.                         // apply the transform
  188.                         return transformers[i].transformed(rawG);
  189.                     }
  190.                 }

  191.                 return transformers[updates.length - 1].transformed(rawG);

  192.             }
  193.         }

  194.     }

  195.     /** Local handler. */
  196.     private static class LocalHandler<T extends EventDetector> implements EventHandler<EventFilter<T>> {

  197.         /** {@inheritDoc} */
  198.         public Action eventOccurred(final SpacecraftState s, final EventFilter<T> ef, final boolean increasing)
  199.             throws OrekitException {
  200.             if (ef.rawDetector instanceof AbstractReconfigurableDetector) {
  201.                 @SuppressWarnings("unchecked")
  202.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) ef.rawDetector).getHandler();
  203.                 return handler.eventOccurred(s, ef.rawDetector, ef.filter.getTriggeredIncreasing());
  204.             } else {
  205.                 @SuppressWarnings("deprecation")
  206.                 final EventDetector.Action a = ef.rawDetector.eventOccurred(s, ef.filter.getTriggeredIncreasing());
  207.                 return AbstractReconfigurableDetector.convert(a);
  208.             }
  209.         }

  210.         /** {@inheritDoc} */
  211.         @Override
  212.         public SpacecraftState resetState(final EventFilter<T> ef, final SpacecraftState oldState)
  213.             throws OrekitException {
  214.             if (ef.rawDetector instanceof AbstractReconfigurableDetector) {
  215.                 @SuppressWarnings("unchecked")
  216.                 final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) ef.rawDetector).getHandler();
  217.                 return handler.resetState(ef.rawDetector, oldState);
  218.             } else {
  219.                 @SuppressWarnings("deprecation")
  220.                 final SpacecraftState newState = ef.rawDetector.resetState(oldState);
  221.                 return newState;
  222.             }
  223.         }

  224.     }

  225. }