EventEnablingPredicateFilter.java

  1. /* Copyright 2002-2016 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.events;

  18. import java.io.NotSerializableException;
  19. import java.io.Serializable;
  20. import java.util.Arrays;

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

  25. /** Wrapper used to detect events only when enabled by an external predicated function.
  26.  *
  27.  * <p>General {@link EventDetector events} are defined implicitly
  28.  * by a {@link EventDetector#g(SpacecraftState) g function} crossing
  29.  * zero. This implies that during an orbit propagation, events are
  30.  * triggered at all zero crossings.
  31.  * </p>
  32.  *
  33.  * <p>Sometimes, users would like to enable or disable events by themselves,
  34.  * for example to trigger them only for certain orbits, or to check elevation
  35.  * maximums only when elevation itself is positive (i.e. they want to
  36.  * discard elevation maximums below ground). In these cases, looking precisely
  37.  * for all events location and triggering events that will later be ignored
  38.  * is a waste of computing time.</p>
  39.  *
  40.  * <p>Users can wrap a regular {@link EventDetector event detector} in
  41.  * an instance of this class and provide this wrapping instance to
  42.  * a {@link org.orekit.propagation.Propagator}
  43.  * in order to avoid wasting time looking for uninteresting events.
  44.  * The wrapper will intercept the calls to the {@link
  45.  * EventDetector#g(SpacecraftState) g function} and to the {@link
  46.  * EventDetector#eventOccurred(SpacecraftState, boolean)
  47.  * eventOccurred} method in order to ignore uninteresting events. The
  48.  * wrapped regular {@link EventDetector event detector} will the see only
  49.  * the interesting events, i.e. either only events that occur when a
  50.  * user-provided event enabling predicate function is true, ignoring all events
  51.  * that occur when the event enabling predicate function is false. The number of
  52.  * calls to the {@link EventDetector#g(SpacecraftState) g function} will also be
  53.  * reduced.</p>
  54.  * @see EventSlopeFilter
  55.  * @since 7.1
  56.  */

  57. public class EventEnablingPredicateFilter<T extends EventDetector>
  58.     extends AbstractDetector<EventEnablingPredicateFilter<T>> {

  59.     /** Serializable UID. */
  60.     private static final long serialVersionUID = 20150910L;

  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.     /** Enabling predicate function. */
  66.     private final transient EnablingPredicate<T> enabler;

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

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

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

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

  75.     /** Detector function value at extremeT. */
  76.     private transient double extremeG;

  77.     /** Wrap an {@link EventDetector event detector}.
  78.      * @param rawDetector event detector to wrap
  79.      * @param enabler event enabling predicate function to use
  80.      */
  81.     public EventEnablingPredicateFilter(final T rawDetector, final EnablingPredicate<T> enabler) {
  82.         this(rawDetector.getMaxCheckInterval(), rawDetector.getThreshold(),
  83.              rawDetector.getMaxIterationCount(), new LocalHandler<T>(),
  84.              rawDetector, enabler);
  85.     }

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

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

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

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

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

  125.     }

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

  128.         final double  rawG      = rawDetector.g(s);
  129.         final boolean isEnabled = enabler.eventIsEnabled(s, rawDetector, rawG);
  130.         if (Double.isNaN(extremeG)) {
  131.             extremeG = rawG;
  132.         }

  133.         // search which transformer should be applied to g
  134.         if (forward) {
  135.             final int last = transformers.length - 1;
  136.             if (extremeT.compareTo(s.getDate()) < 0) {
  137.                 // we are at the forward end of the history

  138.                 // check if enabled status has changed
  139.                 final Transformer previous = transformers[last];
  140.                 final Transformer next     = selectTransformer(previous, extremeG, isEnabled);
  141.                 if (next != previous) {
  142.                     // there is a status change somewhere between extremeT and t.
  143.                     // the new transformer is valid for t (this is how we have just computed
  144.                     // it above), but it is in fact valid on both sides of the change, so
  145.                     // it was already valid before t and even up to previous time. We store
  146.                     // the switch at extremeT for safety, to ensure the previous transformer
  147.                     // is not applied too close of the root
  148.                     System.arraycopy(updates,      1, updates,      0, last);
  149.                     System.arraycopy(transformers, 1, transformers, 0, last);
  150.                     updates[last]      = extremeT;
  151.                     transformers[last] = next;
  152.                 }

  153.                 extremeT = s.getDate();
  154.                 extremeG = rawG;

  155.                 // apply the transform
  156.                 return next.transformed(rawG);

  157.             } else {
  158.                 // we are in the middle of the history

  159.                 // select the transformer
  160.                 for (int i = last; i > 0; --i) {
  161.                     if (updates[i].compareTo(s.getDate()) <= 0) {
  162.                         // apply the transform
  163.                         return transformers[i].transformed(rawG);
  164.                     }
  165.                 }

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

  167.             }
  168.         } else {
  169.             if (s.getDate().compareTo(extremeT) < 0) {
  170.                 // we are at the backward end of the history

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

  186.                 extremeT = s.getDate();
  187.                 extremeG = rawG;

  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 = 0; i < updates.length - 1; ++i) {
  194.                     if (s.getDate().compareTo(updates[i]) <= 0) {
  195.                         // apply the transform
  196.                         return transformers[i].transformed(rawG);
  197.                     }
  198.                 }

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

  200.             }
  201.         }

  202.     }

  203.     /** Get next function transformer in the specified direction.
  204.      * @param previous transformer active on the previous point with respect
  205.      * to integration direction (may be null if no previous point is known)
  206.      * @param previousG value of the g function at the previous point
  207.      * @param isEnabled if true the event should be enabled now
  208.      * @return next transformer transformer
  209.      */
  210.     private Transformer selectTransformer(final Transformer previous, final double previousG, final boolean isEnabled) {
  211.         if (isEnabled) {
  212.             // we need to select a transformer that can produce zero crossings,
  213.             // so it is either Transformer.PLUS or Transformer.MINUS
  214.             switch (previous) {
  215.                 case UNINITIALIZED :
  216.                     return Transformer.PLUS; // this initial choice is arbitrary, it could have been Transformer.MINUS
  217.                 case MIN :
  218.                     return previousG >= 0 ? Transformer.MINUS : Transformer.PLUS;
  219.                 case MAX :
  220.                     return previousG >= 0 ? Transformer.PLUS : Transformer.MINUS;
  221.                 default :
  222.                     return previous;
  223.             }
  224.         } else {
  225.             // we need to select a transformer that cannot produce any zero crossings,
  226.             // so it is either Transformer.MAX or Transformer.MIN
  227.             switch (previous) {
  228.                 case UNINITIALIZED :
  229.                     return Transformer.MAX; // this initial choice is arbitrary, it could have been Transformer.MIN
  230.                 case PLUS :
  231.                     return previousG >= 0 ? Transformer.MAX : Transformer.MIN;
  232.                 case MINUS :
  233.                     return previousG >= 0 ? Transformer.MIN : Transformer.MAX;
  234.                 default :
  235.                     return previous;
  236.             }
  237.         }
  238.     }

  239.     /** Replace the instance with a data transfer object for serialization.
  240.      * @return data transfer object that will be serialized
  241.      * @exception NotSerializableException if the {@link EnablingPredicate
  242.      * enabling predicate} is not serializable
  243.      */
  244.     private Object writeReplace() throws NotSerializableException {
  245.         if (enabler instanceof Serializable) {
  246.             return new DataTransferObject(rawDetector, (Serializable) enabler);
  247.         } else {
  248.             throw new NotSerializableException(enabler.getClass().getName());
  249.         }
  250.     }

  251.     /** Local handler. */
  252.     private static class LocalHandler<T extends EventDetector> implements EventHandler<EventEnablingPredicateFilter<T>> {

  253.         /** {@inheritDoc} */
  254.         public Action eventOccurred(final SpacecraftState s, final EventEnablingPredicateFilter<T> ef, final boolean increasing)
  255.             throws OrekitException {
  256.             final Transformer transformer = ef.forward ? ef.transformers[ef.transformers.length - 1] : ef.transformers[0];
  257.             return ef.rawDetector.eventOccurred(s, transformer == Transformer.PLUS ? increasing : !increasing);
  258.         }

  259.         /** {@inheritDoc} */
  260.         @Override
  261.         public SpacecraftState resetState(final EventEnablingPredicateFilter<T> ef, final SpacecraftState oldState)
  262.             throws OrekitException {
  263.             return ef.rawDetector.resetState(oldState);
  264.         }

  265.     }

  266.     /** Internal class used only for serialization. */
  267.     private static class DataTransferObject implements Serializable {

  268.         /** Serializable UID. */
  269.         private static final long serialVersionUID = 20160321L;

  270.         /** Wrapped event detector. */
  271.         private final EventDetector rawDetector;

  272.         /** Enabling predicate function. */
  273.         private final Serializable enabler;

  274.         /** Simple constructor.
  275.          * @param rawDetector wrapped event detector
  276.          * @param enabler enabling predicate function
  277.          */
  278.         DataTransferObject(final EventDetector rawDetector, final Serializable enabler) {
  279.             this.rawDetector = rawDetector;
  280.             this.enabler     = enabler;
  281.         }

  282.         /** Replace the deserialized data transfer object with a {@link EventEnablingPredicateFilter}.
  283.          * @return replacement {@link EventEnablingPredicateFilter}
  284.          */
  285.         @SuppressWarnings("unchecked")
  286.         private Object readResolve() {
  287.             return new EventEnablingPredicateFilter<EventDetector>(rawDetector,
  288.                             (EnablingPredicate<EventDetector>) enabler);
  289.         }

  290.     }

  291. }