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.propagation.events.intervals.FieldAdaptableInterval;
  31. import org.orekit.time.FieldAbsoluteDate;

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

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

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

  67.     /**
  68.      * Private constructor with all the parameters.
  69.      *
  70.      * @param detectors    the operands.
  71.      * @param operator     reduction operator to apply to value of the g function of the
  72.      *                     operands.
  73.      * @param detectionSettings event detection settings.
  74.      * @param newHandler   event handler.
  75.      * @since 13.0
  76.      */
  77.     protected FieldBooleanDetector(final List<FieldEventDetector<T>> detectors,
  78.                                    final Operator operator,
  79.                                    final FieldEventDetectionSettings<T> detectionSettings,
  80.                                    final FieldEventHandler<T> newHandler) {
  81.         super(detectionSettings, newHandler);
  82.         this.detectors = detectors;
  83.         this.operator = operator;
  84.     }

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

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

  130.         return new FieldBooleanDetector<>(new ArrayList<>(detectors), // copy for immutability
  131.                                           Operator.AND,
  132.                                           new FieldEventDetectionSettings<>(FieldAdaptableInterval.of(Double.POSITIVE_INFINITY, detectors.stream()
  133.                                                   .map(FieldEventDetector::getMaxCheckInterval).toArray(FieldAdaptableInterval[]::new)),
  134.                                           detectors.stream().map(FieldEventDetector::getThreshold).min(new FieldComparator<>()).get(),
  135.                                           detectors.stream().map(FieldEventDetector::getMaxIterationCount).min(Integer::compareTo).get()),
  136.                                           new FieldContinueOnEvent<>());
  137.     }

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

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

  183.         return new FieldBooleanDetector<>(new ArrayList<>(detectors), // copy for immutability
  184.                                           Operator.OR,
  185.                                           new FieldEventDetectionSettings<>(FieldAdaptableInterval.of(Double.POSITIVE_INFINITY, detectors.stream()
  186.                                                   .map(FieldEventDetector::getMaxCheckInterval).toArray(FieldAdaptableInterval[]::new)),
  187.                                           detectors.stream().map(FieldEventDetector::getThreshold).min(new FieldComparator<>()).get(),
  188.                                           detectors.stream().map(FieldEventDetector::getMaxIterationCount).min(Integer::compareTo).get()),
  189.                                           new FieldContinueOnEvent<>());
  190.     }

  191.     /**
  192.      * Create a new event detector that negates the g function of another detector.
  193.      *
  194.      * <p> This detector will be initialized with the same {@link
  195.      * FieldEventDetector#getMaxCheckInterval()}, {@link FieldEventDetector#getThreshold()}, and
  196.      * {@link FieldEventDetector#getMaxIterationCount()} as {@code detector}. The event handler
  197.      * of the underlying detector is not used, instead the default handler is {@link
  198.      * FieldContinueOnEvent}.
  199.      *
  200.      * @param <T> type of the field elements
  201.      * @param detector to negate.
  202.      * @return an new event detector whose g function is the same magnitude but opposite
  203.      * sign of {@code detector}.
  204.      * @see #andCombine(Collection)
  205.      * @see #orCombine(Collection)
  206.      * @see FieldBooleanDetector
  207.      */
  208.     public static <T extends CalculusFieldElement<T>> FieldNegateDetector<T> notCombine(final FieldEventDetector<T> detector) {
  209.         return new FieldNegateDetector<>(detector);
  210.     }

  211.     @Override
  212.     public T g(final FieldSpacecraftState<T> s) {
  213.         // can't use stream/lambda here because g(s) throws a checked exception
  214.         // so write out and combine the map and reduce loops
  215.         T ret = s.getDate().getField().getZero().newInstance(Double.NaN); // return value
  216.         boolean first = true;
  217.         for (final FieldEventDetector<T> detector : detectors) {
  218.             if (first) {
  219.                 ret = detector.g(s);
  220.                 first = false;
  221.             } else {
  222.                 ret = operator.combine(ret, detector.g(s));
  223.             }
  224.         }
  225.         // return the result of applying the operator to all operands
  226.         return ret;
  227.     }

  228.     @Override
  229.     protected FieldBooleanDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
  230.                                              final FieldEventHandler<T> newHandler) {
  231.         return new FieldBooleanDetector<>(detectors, operator, detectionSettings, newHandler);
  232.     }

  233.     @Override
  234.     public void init(final FieldSpacecraftState<T> s0,
  235.                      final FieldAbsoluteDate<T> t) {
  236.         super.init(s0, t);
  237.         for (final FieldEventDetector<T> detector : detectors) {
  238.             detector.init(s0, t);
  239.         }
  240.     }

  241.     @Override
  242.     public void reset(final FieldSpacecraftState<T> state, final FieldAbsoluteDate<T> target) {
  243.         super.reset(state, target);
  244.         for (final FieldEventDetector<T> detector : detectors) {
  245.             detector.reset(state, target);
  246.         }
  247.     }

  248.     @Override
  249.     public void finish(final FieldSpacecraftState<T> state) {
  250.         super.finish(state);
  251.         for (final FieldEventDetector<T> detector : detectors) {
  252.             detector.finish(state);
  253.         }
  254.     }

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

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

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

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

  271.         },

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

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

  279.         };

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

  287.     }

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

  296. }