EventSlopeFilter.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.hipparchus.ode.events.Action;
  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 EventFilter from the
  26.  * Hipparchus 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 implicitly
  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 orbit propagation, 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.  * EventHandler#eventOccurred(SpacecraftState, EventDetector, boolean)
  52.  * eventOccurred} method in order to ignore uninteresting events. The
  53.  * wrapped regular {@link EventDetector event detector} will then see only
  54.  * the interesting events, i.e. either only {@code increasing} events or
  55.  * only {@code decreasing} events. The number of calls to the {@link
  56.  * EventDetector#g(SpacecraftState) g function} will also be reduced.</p>
  57.  * @see EventEnablingPredicateFilter
  58.  * @param <T> type of the detector
  59.  */

  60. public class EventSlopeFilter<T extends EventDetector> implements EventDetector {

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

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

  65.     /** Filter to use. */
  66.     private final FilterType filterType;

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

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

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

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

  75.     /** Event detection settings. */
  76.     private final EventDetectionSettings detectionSettings;

  77.     /** Specialized event handler. */
  78.     private final LocalHandler<T> handler;

  79.     /** Wrap an {@link EventDetector event detector}.
  80.      * @param rawDetector event detector to wrap
  81.      * @param filter filter to use
  82.      */
  83.     public EventSlopeFilter(final T rawDetector, final FilterType filter) {
  84.         this(rawDetector.getDetectionSettings(), rawDetector, filter);
  85.     }

  86.     /** Constructor with full parameters.
  87.      * @param detectionSettings event detection settings
  88.      * @param rawDetector event detector to wrap
  89.      * @param filterType filter to use
  90.      * @since 13.0
  91.      */
  92.     public EventSlopeFilter(final EventDetectionSettings detectionSettings,
  93.                             final T rawDetector, final FilterType filterType) {
  94.         this.detectionSettings = detectionSettings;
  95.         this.handler = new LocalHandler<>();
  96.         this.rawDetector  = rawDetector;
  97.         this.filterType = filterType;
  98.         this.transformers = new Transformer[HISTORY_SIZE];
  99.         this.updates      = new AbsoluteDate[HISTORY_SIZE];
  100.     }

  101.     /** {@inheritDoc} */
  102.     @Override
  103.     public EventHandler getHandler() {
  104.         return handler;
  105.     }


  106.     @Override
  107.     public EventDetectionSettings getDetectionSettings() {
  108.         return detectionSettings;
  109.     }

  110.     /**
  111.      * Builds a new instance from the input detection settings.
  112.      * @param settings event detection settings to be used
  113.      * @return a new detector
  114.      */
  115.     public EventSlopeFilter<T> withDetectionSettings(final EventDetectionSettings settings) {
  116.         return new EventSlopeFilter<>(settings, rawDetector, filterType);
  117.     }

  118.     /**
  119.      * Get the wrapped raw detector.
  120.      * @return the wrapped raw detector
  121.      * @since 11.1
  122.      */
  123.     public T getDetector() {
  124.         return rawDetector;
  125.     }

  126.     /** Get filter type.
  127.      * @return filter type
  128.      * @deprecated since 13.0 (use getFilterType)
  129.      */
  130.     @Deprecated
  131.     public FilterType getFilter() {
  132.         return getFilterType();
  133.     }

  134.     /** Get filter type.
  135.      * @return filter type
  136.      * @since 13.0
  137.      */
  138.     public FilterType getFilterType() {
  139.         return filterType;
  140.     }

  141.     /**  {@inheritDoc} */
  142.     @Override
  143.     public void init(final SpacecraftState s0, final AbsoluteDate t) {
  144.         EventDetector.super.init(s0, t);

  145.         // delegate to raw detector
  146.         rawDetector.init(s0, t);

  147.         // initialize events triggering logic
  148.         forward  = AbstractDetector.checkIfForward(s0, t);
  149.         extremeT = forward ? AbsoluteDate.PAST_INFINITY : AbsoluteDate.FUTURE_INFINITY;
  150.         Arrays.fill(transformers, Transformer.UNINITIALIZED);
  151.         Arrays.fill(updates, extremeT);

  152.     }

  153.     /**  {@inheritDoc} */
  154.     @Override
  155.     public void reset(final SpacecraftState state, final AbsoluteDate target) {
  156.         EventDetector.super.reset(state, target);
  157.         rawDetector.reset(state, target);
  158.     }

  159.     /**  {@inheritDoc} */
  160.     @Override
  161.     public void finish(final SpacecraftState state) {
  162.         EventDetector.super.finish(state);
  163.         rawDetector.finish(state);
  164.     }

  165.     /**  {@inheritDoc} */
  166.     @Override
  167.     public double g(final SpacecraftState s) {

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

  169.         // search which transformer should be applied to g
  170.         if (isForward()) {
  171.             final int last = transformers.length - 1;
  172.             if (extremeT.compareTo(s.getDate()) < 0) {
  173.                 // we are at the forward end of the history

  174.                 // check if a new rough root has been crossed
  175.                 final Transformer previous = transformers[last];
  176.                 final Transformer next     = filterType.selectTransformer(previous, rawG, forward);
  177.                 if (next != previous) {
  178.                     // there is a root somewhere between extremeT and t.
  179.                     // the new transformer is valid for t (this is how we have just computed
  180.                     // it above), but it is in fact valid on both sides of the root, so
  181.                     // it was already valid before t and even up to previous time. We store
  182.                     // the switch at extremeT for safety, to ensure the previous transformer
  183.                     // is not applied too close of the root
  184.                     System.arraycopy(updates,      1, updates,      0, last);
  185.                     System.arraycopy(transformers, 1, transformers, 0, last);
  186.                     updates[last]      = extremeT;
  187.                     transformers[last] = next;
  188.                 }

  189.                 extremeT = s.getDate();

  190.                 // apply the transform
  191.                 return next.transformed(rawG);

  192.             } else {
  193.                 // we are in the middle of the history

  194.                 // select the transformer
  195.                 for (int i = last; i > 0; --i) {
  196.                     if (updates[i].compareTo(s.getDate()) <= 0) {
  197.                         // apply the transform
  198.                         return transformers[i].transformed(rawG);
  199.                     }
  200.                 }

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

  202.             }
  203.         } else {
  204.             if (s.getDate().compareTo(extremeT) < 0) {
  205.                 // we are at the backward end of the history

  206.                 // check if a new rough root has been crossed
  207.                 final Transformer previous = transformers[0];
  208.                 final Transformer next     = filterType.selectTransformer(previous, rawG, forward);
  209.                 if (next != previous) {
  210.                     // there is a root somewhere between extremeT and t.
  211.                     // the new transformer is valid for t (this is how we have just computed
  212.                     // it above), but it is in fact valid on both sides of the root, so
  213.                     // it was already valid before t and even up to previous time. We store
  214.                     // the switch at extremeT for safety, to ensure the previous transformer
  215.                     // is not applied too close of the root
  216.                     System.arraycopy(updates,      0, updates,      1, updates.length - 1);
  217.                     System.arraycopy(transformers, 0, transformers, 1, transformers.length - 1);
  218.                     updates[0]      = extremeT;
  219.                     transformers[0] = next;
  220.                 }

  221.                 extremeT = s.getDate();

  222.                 // apply the transform
  223.                 return next.transformed(rawG);

  224.             } else {
  225.                 // we are in the middle of the history

  226.                 // select the transformer
  227.                 for (int i = 0; i < updates.length - 1; ++i) {
  228.                     if (s.getDate().compareTo(updates[i]) <= 0) {
  229.                         // apply the transform
  230.                         return transformers[i].transformed(rawG);
  231.                     }
  232.                 }

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

  234.             }
  235.         }

  236.     }

  237.     /** Check if the current propagation is forward or backward.
  238.      * @return true if the current propagation is forward
  239.      */
  240.     public boolean isForward() {
  241.         return forward;
  242.     }

  243.     /** Local handler. */
  244.     private static class LocalHandler<T extends EventDetector> implements EventHandler {

  245.         /** {@inheritDoc} */
  246.         public Action eventOccurred(final SpacecraftState s, final EventDetector detector, final boolean increasing) {
  247.             @SuppressWarnings("unchecked")
  248.             final EventSlopeFilter<T> esf = (EventSlopeFilter<T>) detector;
  249.             return esf.rawDetector.getHandler().eventOccurred(s, esf.rawDetector, esf.filterType.getTriggeredIncreasing());
  250.         }

  251.         /** {@inheritDoc} */
  252.         @Override
  253.         public SpacecraftState resetState(final EventDetector detector, final SpacecraftState oldState) {
  254.             @SuppressWarnings("unchecked")
  255.             final EventSlopeFilter<T> esf = (EventSlopeFilter<T>) detector;
  256.             return esf.rawDetector.getHandler().resetState(esf.rawDetector, oldState);
  257.         }

  258.     }

  259. }