FieldEventSlopeFilter.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.lang.reflect.Array;
  19. import java.util.Arrays;

  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.ode.events.Action;
  22. import org.orekit.propagation.FieldSpacecraftState;
  23. import org.orekit.propagation.events.handlers.FieldEventHandler;
  24. import org.orekit.time.FieldAbsoluteDate;

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

  63. public class FieldEventSlopeFilter<D extends FieldEventDetector<T>, T extends CalculusFieldElement<T>>
  64.     implements FieldEventDetector<T> {

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

  67.     /** Wrapped event detector. */
  68.     private final D rawDetector;

  69.     /** Filter to use. */
  70.     private final FilterType filterType;

  71.     /** Transformers of the g function. */
  72.     private final Transformer[] transformers;

  73.     /** Update time of the transformers. */
  74.     private final FieldAbsoluteDate<T>[] updates;

  75.     /** Event detection settings. */
  76.     private final FieldEventDetectionSettings<T> detectionSettings;

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

  79.     /** Indicator for forward integration. */
  80.     private boolean forward;

  81.     /** Extreme time encountered so far. */
  82.     private FieldAbsoluteDate<T> extremeT;

  83.     /** Wrap an {@link EventDetector event detector}.
  84.      * @param rawDetector event detector to wrap
  85.      * @param filterType filter to use
  86.      */
  87.     public FieldEventSlopeFilter(final D rawDetector, final FilterType filterType) {
  88.         this(rawDetector.getDetectionSettings(), rawDetector, filterType);
  89.     }

  90.     /** Constructor with full parameters.
  91.      * @param detectionSettings event detection settings
  92.      * @param rawDetector event detector to wrap
  93.      * @param filterType filter to use
  94.      * since 13.0
  95.      */
  96.     @SuppressWarnings("unchecked")
  97.     public FieldEventSlopeFilter(final FieldEventDetectionSettings<T> detectionSettings,
  98.                                  final D rawDetector, final FilterType filterType) {
  99.         this.detectionSettings = detectionSettings;
  100.         this.handler = new LocalHandler<>();
  101.         this.rawDetector  = rawDetector;
  102.         this.filterType = filterType;
  103.         this.transformers = new Transformer[HISTORY_SIZE];
  104.         this.updates      = (FieldAbsoluteDate<T>[]) Array.newInstance(FieldAbsoluteDate.class, HISTORY_SIZE);
  105.     }

  106.     /**
  107.      * Builds a new instance from the input detection settings.
  108.      * @param settings event detection settings to be used
  109.      * @return a new detector
  110.      */
  111.     public FieldEventSlopeFilter<D, T> withDetectionSettings(final FieldEventDetectionSettings<T> settings) {
  112.         return new FieldEventSlopeFilter<>(settings, rawDetector, filterType);
  113.     }

  114.     /** Get filter type.
  115.      * @return filter type
  116.      * @since 13.0
  117.      */
  118.     public FilterType getFilterType() {
  119.         return filterType;
  120.     }

  121.     @Override
  122.     public FieldEventHandler<T> getHandler() {
  123.         return handler;
  124.     }

  125.     @Override
  126.     public FieldEventDetectionSettings<T> getDetectionSettings() {
  127.         return detectionSettings;
  128.     }

  129.     /**
  130.      * Get the wrapped raw detector.
  131.      * @return the wrapped raw detector
  132.      */
  133.     public D getDetector() {
  134.         return rawDetector;
  135.     }

  136.     /**  {@inheritDoc} */
  137.     @Override
  138.     public void init(final FieldSpacecraftState<T> s0,
  139.                      final FieldAbsoluteDate<T> t) {
  140.         FieldEventDetector.super.init(s0, t);

  141.         // delegate to raw detector
  142.         rawDetector.init(s0, t);

  143.         // initialize events triggering logic
  144.         forward  = FieldAbstractDetector.checkIfForward(s0, t);
  145.         extremeT = forward ?
  146.                    FieldAbsoluteDate.getPastInfinity(t.getField()) :
  147.                    FieldAbsoluteDate.getFutureInfinity(t.getField());
  148.         Arrays.fill(transformers, Transformer.UNINITIALIZED);
  149.         Arrays.fill(updates, extremeT);

  150.     }

  151.     /**  {@inheritDoc} */
  152.     @Override
  153.     public void reset(final FieldSpacecraftState<T> state, final FieldAbsoluteDate<T> target) {
  154.         FieldEventDetector.super.reset(state, target);
  155.         rawDetector.reset(state, target);
  156.     }

  157.     /**  {@inheritDoc} */
  158.     @Override
  159.     public void finish(final FieldSpacecraftState<T> state) {
  160.         FieldEventDetector.super.finish(state);
  161.         rawDetector.finish(state);
  162.     }

  163.     /**  {@inheritDoc} */
  164.     @Override
  165.     public T g(final FieldSpacecraftState<T> s) {

  166.         final T rawG = rawDetector.g(s);

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

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

  187.                 extremeT = s.getDate();

  188.                 // apply the transform
  189.                 return next.transformed(rawG);

  190.             } else {
  191.                 // we are in the middle of the history

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

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

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

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

  219.                 extremeT = s.getDate();

  220.                 // apply the transform
  221.                 return next.transformed(rawG);

  222.             } else {
  223.                 // we are in the middle of the history

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

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

  232.             }
  233.         }

  234.     }

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

  241.     /** Local handler. */
  242.     private static class LocalHandler<D extends FieldEventDetector<T>, T extends CalculusFieldElement<T>> implements FieldEventHandler<T> {

  243.         /** {@inheritDoc} */
  244.         public Action eventOccurred(final FieldSpacecraftState<T> s, final FieldEventDetector<T> detector, final boolean increasing) {
  245.             final FieldEventSlopeFilter<D, T> esf = (FieldEventSlopeFilter<D, T>) detector;
  246.             return esf.rawDetector.getHandler().eventOccurred(s, esf.rawDetector, esf.filterType.getTriggeredIncreasing());
  247.         }

  248.         /** {@inheritDoc} */
  249.         @Override
  250.         public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> detector, final FieldSpacecraftState<T> oldState) {
  251.             final FieldEventSlopeFilter<D, T> esf = (FieldEventSlopeFilter<D, T>) detector;
  252.             return esf.rawDetector.getHandler().resetState(esf.rawDetector, oldState);
  253.         }

  254.     }

  255. }