FieldBooleanDetector.java

  1. /* Contributed in the public domain.
  2.  * Licensed to CS GROUP (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.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.Comparator;
  23. import java.util.List;
  24. import java.util.NoSuchElementException;

  25. import org.hipparchus.CalculusFieldElement;
  26. import org.hipparchus.util.FastMath;
  27. import org.orekit.propagation.FieldSpacecraftState;
  28. import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
  29. import org.orekit.propagation.events.handlers.FieldEventHandler;
  30. import org.orekit.time.FieldAbsoluteDate;

  31. /**
  32.  * This class provides AND and OR operations for event detectors. This class treats
  33.  * positive values of the g function as true and negative values as false.
  34.  *
  35.  * <p> One example for an imaging satellite might be to only detect events when a
  36.  * satellite is overhead (elevation &gt; 0) AND when the ground point is sunlit (Sun
  37.  * elevation &gt; 0). Another slightly contrived example using the OR operator would be to
  38.  * detect access to a set of ground stations and only report events when the satellite
  39.  * enters or leaves the field of view of the set, but not hand-offs between the ground
  40.  * stations.
  41.  *
  42.  * <p> For the FieldBooleanDetector is important that the sign of the g function of the
  43.  * underlying event detector is not arbitrary, but has a semantic meaning, e.g. in or out,
  44.  * true or false. This class works well with event detectors that detect entry to or exit
  45.  * from a region, e.g. {@link FieldEclipseDetector}, {@link FieldElevationDetector}, {@link
  46.  * FieldLatitudeCrossingDetector}. Using this detector with detectors that are not based on
  47.  * entry to or exit from a region, e.g. {@link FieldDateDetector}, will likely lead to
  48.  * unexpected results. To apply conditions to this latter type of event detectors a
  49.  * {@link FieldEventEnablingPredicateFilter} is usually more appropriate.
  50.  *
  51.  * @param <T> type of the field elements
  52.  * @since 12.0
  53.  * @author Evan Ward
  54.  * @author luc Luc Maisonobe
  55.  * @see #andCombine(Collection)
  56.  * @see #orCombine(Collection)
  57.  * @see #notCombine(FieldEventDetector)
  58.  * @see EventEnablingPredicateFilter
  59.  * @see EventSlopeFilter
  60.  */
  61. public class FieldBooleanDetector<T extends CalculusFieldElement<T>> extends FieldAbstractDetector<FieldBooleanDetector<T>, T> {

  62.     /** Original detectors: the operands. */
  63.     private final List<FieldEventDetector<T>> detectors;

  64.     /** The composition function. Should be associative for predictable behavior. */
  65.     private final Operator operator;

  66.     /**
  67.      * Private constructor with all the parameters.
  68.      *
  69.      * @param detectors    the operands.
  70.      * @param operator     reduction operator to apply to value of the g function of the
  71.      *                     operands.
  72.      * @param newMaxCheck  max check interval.
  73.      * @param newThreshold convergence threshold in seconds.
  74.      * @param newMaxIter   max iterations.
  75.      * @param newHandler   event handler.
  76.      */
  77.     protected FieldBooleanDetector(final List<FieldEventDetector<T>> detectors,
  78.                                    final Operator operator,
  79.                                    final FieldAdaptableInterval<T> newMaxCheck,
  80.                                    final T newThreshold,
  81.                                    final int newMaxIter,
  82.                                    final FieldEventHandler<T> newHandler) {
  83.         super(new FieldEventDetectionSettings<>(newMaxCheck, newThreshold, newMaxIter), newHandler);
  84.         this.detectors = detectors;
  85.         this.operator = operator;
  86.     }

  87.     /**
  88.      * Create a new event detector that is the logical AND of the given event detectors.
  89.      *
  90.      * <p> The created event detector's g function is positive if and only if the g
  91.      * functions of all detectors in {@code detectors} are positive.
  92.      *
  93.      * <p> The starting interval, threshold, and iteration count are set to the most
  94.      * stringent (minimum) of all the {@code detectors}. The event handlers of the
  95.      * underlying {@code detectors} are not used, instead the default handler is {@link
  96.      * FieldContinueOnEvent}.
  97.      *
  98.      * @param <T> type of the field elements
  99.      * @param detectors the operands. Must contain at least one detector.
  100.      * @return a new event detector that is the logical AND of the operands.
  101.      * @throws NoSuchElementException if {@code detectors} is empty.
  102.      * @see FieldBooleanDetector
  103.      * @see #andCombine(Collection)
  104.      * @see #orCombine(FieldEventDetector...)
  105.      * @see #notCombine(FieldEventDetector)
  106.      */
  107.     @SafeVarargs
  108.     public static <T extends CalculusFieldElement<T>> FieldBooleanDetector<T> andCombine(final FieldEventDetector<T>... detectors) {
  109.         return andCombine(Arrays.asList(detectors));
  110.     }

  111.     /**
  112.      * Create a new event detector that is the logical AND of the given event detectors.
  113.      *
  114.      * <p> The created event detector's g function is positive if and only if the g
  115.      * functions of all detectors in {@code detectors} are positive.
  116.      *
  117.      * <p> The starting interval, threshold, and iteration count are set to the most
  118.      * stringent (minimum) of the {@code detectors}. The event handlers of the
  119.      * underlying {@code detectors} are not used, instead the default handler is {@link
  120.      * FieldContinueOnEvent}.
  121.      *
  122.      * @param <T> type of the field elements
  123.      * @param detectors the operands. Must contain at least one detector.
  124.      * @return a new event detector that is the logical AND of the operands.
  125.      * @throws NoSuchElementException if {@code detectors} is empty.
  126.      * @see FieldBooleanDetector
  127.      * @see #andCombine(FieldEventDetector...)
  128.      * @see #orCombine(Collection)
  129.      * @see #notCombine(FieldEventDetector)
  130.      */
  131.     public static <T extends CalculusFieldElement<T>> FieldBooleanDetector<T> andCombine(final Collection<? extends FieldEventDetector<T>> detectors) {

  132.         return new FieldBooleanDetector<>(new ArrayList<>(detectors), // copy for immutability
  133.                                           Operator.AND,
  134.                                           s -> {
  135.                                               double minInterval = Double.POSITIVE_INFINITY;
  136.                                               for (final FieldEventDetector<T> detector : detectors) {
  137.                                                   minInterval = FastMath.min(minInterval, detector.getMaxCheckInterval().currentInterval(s));
  138.                                               }
  139.                                               return minInterval;
  140.                                           },
  141.                                           detectors.stream().map(FieldEventDetector::getThreshold).min(new FieldComparator<>()).get(),
  142.                                           detectors.stream().map(FieldEventDetector::getMaxIterationCount).min(Integer::compareTo).get(),
  143.                                           new FieldContinueOnEvent<>());
  144.     }

  145.     /**
  146.      * Create a new event detector that is the logical OR of the given event detectors.
  147.      *
  148.      * <p> The created event detector's g function is positive if and only if at least
  149.      * one of g functions of the event detectors in {@code detectors} is positive.
  150.      *
  151.      * <p> The starting interval, threshold, and iteration count are set to the most
  152.      * stringent (minimum) of the {@code detectors}. The event handlers of the
  153.      * underlying EventDetectors are not used, instead the default handler is {@link
  154.      * FieldContinueOnEvent}.
  155.      *
  156.      * @param <T> type of the field elements
  157.      * @param detectors the operands. Must contain at least one detector.
  158.      * @return a new event detector that is the logical OR of the operands.
  159.      * @throws NoSuchElementException if {@code detectors} is empty.
  160.      * @see FieldBooleanDetector
  161.      * @see #orCombine(Collection)
  162.      * @see #andCombine(FieldEventDetector...)
  163.      * @see #notCombine(FieldEventDetector)
  164.      */
  165.     @SafeVarargs
  166.     public static <T extends CalculusFieldElement<T>> FieldBooleanDetector<T> orCombine(final FieldEventDetector<T>... detectors) {
  167.         return orCombine(Arrays.asList(detectors));
  168.     }

  169.     /**
  170.      * Create a new event detector that is the logical OR of the given event detectors.
  171.      *
  172.      * <p> The created event detector's g function is positive if and only if at least
  173.      * one of g functions of the event detectors in {@code detectors} is positive.
  174.      *
  175.      * <p> The starting interval, threshold, and iteration count are set to the most
  176.      * stringent (minimum) of the {@code detectors}. The event handlers of the
  177.      * underlying EventDetectors are not used, instead the default handler is {@link
  178.      * FieldContinueOnEvent}.
  179.      *
  180.      * @param <T> type of the field elements
  181.      * @param detectors the operands. Must contain at least one detector.
  182.      * @return a new event detector that is the logical OR of the operands.
  183.      * @throws NoSuchElementException if {@code detectors} is empty.
  184.      * @see FieldBooleanDetector
  185.      * @see #orCombine(FieldEventDetector...)
  186.      * @see #andCombine(Collection)
  187.      * @see #notCombine(FieldEventDetector)
  188.      */
  189.     public static <T extends CalculusFieldElement<T>> FieldBooleanDetector<T> orCombine(final Collection<? extends FieldEventDetector<T>> detectors) {

  190.         return new FieldBooleanDetector<>(new ArrayList<>(detectors), // copy for immutability
  191.                                           Operator.OR,
  192.                                           s -> {
  193.                                               double minInterval = Double.POSITIVE_INFINITY;
  194.                                               for (final FieldEventDetector<T> detector : detectors) {
  195.                                                   minInterval = FastMath.min(minInterval, detector.getMaxCheckInterval().currentInterval(s));
  196.                                               }
  197.                                               return minInterval;
  198.                                           },
  199.                                           detectors.stream().map(FieldEventDetector::getThreshold).min(new FieldComparator<>()).get(),
  200.                                           detectors.stream().map(FieldEventDetector::getMaxIterationCount).min(Integer::compareTo).get(),
  201.                                           new FieldContinueOnEvent<>());
  202.     }

  203.     /**
  204.      * Create a new event detector that negates the g function of another detector.
  205.      *
  206.      * <p> This detector will be initialized with the same {@link
  207.      * FieldEventDetector#getMaxCheckInterval()}, {@link FieldEventDetector#getThreshold()}, and
  208.      * {@link FieldEventDetector#getMaxIterationCount()} as {@code detector}. The event handler
  209.      * of the underlying detector is not used, instead the default handler is {@link
  210.      * FieldContinueOnEvent}.
  211.      *
  212.      * @param <T> type of the field elements
  213.      * @param detector to negate.
  214.      * @return an new event detector whose g function is the same magnitude but opposite
  215.      * sign of {@code detector}.
  216.      * @see #andCombine(Collection)
  217.      * @see #orCombine(Collection)
  218.      * @see FieldBooleanDetector
  219.      */
  220.     public static <T extends CalculusFieldElement<T>> FieldNegateDetector<T> notCombine(final FieldEventDetector<T> detector) {
  221.         return new FieldNegateDetector<>(detector);
  222.     }

  223.     @Override
  224.     public T g(final FieldSpacecraftState<T> s) {
  225.         // can't use stream/lambda here because g(s) throws a checked exception
  226.         // so write out and combine the map and reduce loops
  227.         T ret = s.getDate().getField().getZero().newInstance(Double.NaN); // return value
  228.         boolean first = true;
  229.         for (final FieldEventDetector<T> detector : detectors) {
  230.             if (first) {
  231.                 ret = detector.g(s);
  232.                 first = false;
  233.             } else {
  234.                 ret = operator.combine(ret, detector.g(s));
  235.             }
  236.         }
  237.         // return the result of applying the operator to all operands
  238.         return ret;
  239.     }

  240.     @Override
  241.     protected FieldBooleanDetector<T> create(final FieldAdaptableInterval<T> newMaxCheck,
  242.                                              final T newThreshold,
  243.                                              final int newMaxIter,
  244.                                              final FieldEventHandler<T> newHandler) {
  245.         return new FieldBooleanDetector<>(detectors, operator, newMaxCheck, newThreshold,
  246.                                           newMaxIter, newHandler);
  247.     }

  248.     @Override
  249.     public void init(final FieldSpacecraftState<T> s0,
  250.                      final FieldAbsoluteDate<T> t) {
  251.         super.init(s0, t);
  252.         for (final FieldEventDetector<T> detector : detectors) {
  253.             detector.init(s0, t);
  254.         }
  255.     }

  256.     /**
  257.      * Get the list of original detectors.
  258.      * @return the list of original detectors
  259.      */
  260.     public List<FieldEventDetector<T>> getDetectors() {
  261.         return new ArrayList<>(detectors);
  262.     }

  263.     /** Local class for operator. */
  264.     private enum Operator {

  265.         /** And operator. */
  266.         AND() {

  267.             @Override
  268.             /** {@inheritDoc} */
  269.             public <T extends CalculusFieldElement<T>> T combine(final T g1, final T g2) {
  270.                 return FastMath.min(g1, g2);
  271.             }

  272.         },

  273.         /** Or operator. */
  274.         OR() {

  275.             @Override
  276.             /** {@inheritDoc} */
  277.             public <T extends CalculusFieldElement<T>> T combine(final T g1, final T g2) {
  278.                 return FastMath.max(g1, g2);
  279.             }

  280.         };

  281.         /** Combine two g functions evaluations.
  282.          * @param <T> type of the field elements
  283.          * @param g1 first evaluation
  284.          * @param g2 second evaluation
  285.          * @return combined evaluation
  286.          */
  287.         public abstract <T extends CalculusFieldElement<T>> T combine(T g1, T g2);

  288.     }

  289.     /** Comparator for field elements.
  290.      * @param <T> type of the field elements
  291.      */
  292.     private static class FieldComparator<T extends CalculusFieldElement<T>> implements Comparator<T>, Serializable {
  293.         public int compare(final T t1, final T t2) {
  294.             return Double.compare(t1.getReal(), t2.getReal());
  295.         }
  296.     }

  297. }