EventDetectorsProvider.java

  1. /* Copyright 2002-2025 CS GROUP
  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.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import java.util.SortedSet;
  22. import java.util.TreeSet;
  23. import java.util.stream.Collectors;
  24. import java.util.stream.Stream;

  25. import org.hipparchus.CalculusFieldElement;
  26. import org.hipparchus.Field;
  27. import org.orekit.forces.ForceModel;
  28. import org.orekit.propagation.events.handlers.FieldResetDerivativesOnEvent;
  29. import org.orekit.propagation.events.handlers.ResetDerivativesOnEvent;
  30. import org.orekit.propagation.events.intervals.AdaptableInterval;
  31. import org.orekit.propagation.events.intervals.DateDetectionAdaptableIntervalFactory;
  32. import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
  33. import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
  34. import org.orekit.time.AbsoluteDate;
  35. import org.orekit.time.ChronologicalComparator;
  36. import org.orekit.time.FieldAbsoluteDate;
  37. import org.orekit.time.FieldTimeStamped;
  38. import org.orekit.time.TimeStamped;
  39. import org.orekit.utils.ParameterDriver;

  40. /** Interface for building event detectors for force models and maneuver parameters.
  41.  *
  42.  * <p>
  43.  * Objects implementing this interface are mainly {@link ForceModel} and {@link DSSTForceModel}.
  44.  *
  45.  * @author Luc Maisonobe
  46.  * @author Melina Vanel
  47.  * @author Maxime Journot
  48.  * @since 12.0
  49.  */
  50. public interface EventDetectorsProvider {

  51.     /** Accuracy of switching events dates (s). */
  52.     double DATATION_ACCURACY = DateDetector.DEFAULT_THRESHOLD;

  53.     /** Get the discrete events related to the model.
  54.      *
  55.      * <p><b>This method is not intended to be called several time, only once by a propagator</b>,
  56.      * as it has the side effect of rebuilding the events detectors when called
  57.      *
  58.      * @return stream of event detectors
  59.      */
  60.     Stream<EventDetector> getEventDetectors();

  61.     /** Get the discrete events related to the model.
  62.      *
  63.      * <p><b>This method is not intended to be called several time, only once by a propagator</b>,
  64.      * as it has the side effect of rebuilding the events detectors when called
  65.      *
  66.      * @param field field to which the state belongs
  67.      * @param <T> extends CalculusFieldElement&lt;T&gt;
  68.      * @return stream of event detectors
  69.      */
  70.     <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field);

  71.     /** Get the discrete events related to the model from a list of {@link ParameterDriver}
  72.      *
  73.      * <p>Date detectors are used to cleanly stop the propagator and reset
  74.      * the state derivatives at transition dates (if any) of the parameter drivers.
  75.      *
  76.      * <p><b>This method is not intended to be called several times, only once by a propagator</b>,
  77.      * as it has the side effect of rebuilding the events detectors when called.
  78.      *
  79.      * @param parameterDrivers list of parameter drivers
  80.      * @return stream of event detectors
  81.      */
  82.     default Stream<EventDetector> getEventDetectors(List<ParameterDriver> parameterDrivers) {
  83.         // If force model does not have parameter Driver, an empty stream is given as results
  84.         final ArrayList<TimeStamped> transitionDates = new ArrayList<>();
  85.         for (final ParameterDriver driver : parameterDrivers) {
  86.             // Get the transitions' dates from the TimeSpanMap
  87.             transitionDates.addAll(Arrays.asList(driver.getTransitionDates()));
  88.         }
  89.         // Either force model does not have any parameter driver or only contains parameter driver with only 1 span
  90.         if (transitionDates.isEmpty()) {
  91.             return Stream.empty();

  92.         } else {
  93.             // Create the date detector containing all transition dates and return it
  94.             final DateDetector detector = getDateDetector(transitionDates.toArray(new TimeStamped[0]));
  95.             return Stream.of(detector);
  96.         }
  97.     }

  98.     /** Get the discrete events related to the model from a list of {@link ParameterDriver}
  99.      *
  100.      * <p>Date detectors are used to cleanly stop the propagator and reset
  101.      * the state derivatives at transition dates (if any) of the parameter drivers.
  102.      *
  103.      * <p><b>This method is not intended to be called several times, only once by a propagator</b>,
  104.      * as it has the side effect of rebuilding the events detectors when called.
  105.      *
  106.      * @param parameterDrivers list of parameter drivers
  107.      * @param field field to which the state belongs
  108.      * @param <T> extends CalculusFieldElement&lt;T&gt;
  109.      * @return stream of event detectors
  110.      */
  111.     default <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(Field<T> field,
  112.                                                                                                      List<ParameterDriver> parameterDrivers) {
  113.         // If force model does not have parameter Driver, an empty stream is given as results
  114.         final ArrayList<AbsoluteDate> transitionDates = new ArrayList<>();
  115.         for (ParameterDriver driver : parameterDrivers) {
  116.             // Get the transitions' dates from the TimeSpanMap
  117.             transitionDates.addAll(Arrays.asList(driver.getTransitionDates()));
  118.         }
  119.         // Either force model does not have any parameter driver or only contains parameter driver with only 1 span
  120.         if (transitionDates.isEmpty()) {
  121.             return Stream.empty();

  122.         } else {
  123.             // Initialize the date detector
  124.             final FieldDateDetector<T> datesDetector = getFieldDateDetector(field,
  125.                     transitionDates.toArray(new AbsoluteDate[0]));
  126.             // Return the detectors
  127.             return Stream.of(datesDetector);
  128.         }
  129.     }

  130.     /**
  131.      * Method building dates' detector.
  132.      * @param timeStampeds dates to detect
  133.      * @return dates detector
  134.      * @since 13.0
  135.      */
  136.     default DateDetector getDateDetector(final TimeStamped... timeStampeds) {
  137.         final AdaptableInterval maxCheck = DateDetectionAdaptableIntervalFactory.getDatesDetectionInterval(
  138.                 timeStampeds);
  139.         final double minGap = DateDetectionAdaptableIntervalFactory.getMinGap(timeStampeds) / 2;
  140.         final DateDetector dateDetector = new DateDetector().withMaxCheck(maxCheck).withMinGap(minGap).
  141.                 withThreshold(DATATION_ACCURACY).withHandler(new ResetDerivativesOnEvent());
  142.         final SortedSet<AbsoluteDate> sortedDates = new TreeSet<>(new ChronologicalComparator());
  143.         sortedDates.addAll(Arrays.stream(timeStampeds).map(TimeStamped::getDate).collect(Collectors.toList()));
  144.         for (final AbsoluteDate date : sortedDates) {
  145.             dateDetector.addEventDate(date);
  146.         }
  147.         return dateDetector;
  148.     }

  149.     /**
  150.      * Method building dates' detector.
  151.      * @param field field
  152.      * @param timeStampeds dates to detect
  153.      * @param <T> field type
  154.      * @return dates detector
  155.      * @since 13.0
  156.      */
  157.     default <T extends CalculusFieldElement<T>> FieldDateDetector<T> getFieldDateDetector(final Field<T> field,
  158.                                                                                           final TimeStamped... timeStampeds) {
  159.         @SuppressWarnings("unchecked")
  160.         final FieldAdaptableInterval<T> maxCheck = DateDetectionAdaptableIntervalFactory.getDatesDetectionFieldInterval(
  161.                 Arrays.stream(timeStampeds).map(timeStamped -> new FieldAbsoluteDate<>(field, timeStamped.getDate()))
  162.                         .toArray(FieldTimeStamped[]::new));
  163.         final double minGap = DateDetectionAdaptableIntervalFactory.getMinGap(timeStampeds) / 2;
  164.         final FieldDateDetector<T> fieldDateDetector = new FieldDateDetector<>(field).
  165.                 withHandler(new FieldResetDerivativesOnEvent<>()).withMaxCheck(maxCheck).withMinGap(minGap).
  166.                 withThreshold(field.getZero().newInstance(DATATION_ACCURACY));
  167.         final SortedSet<AbsoluteDate> sortedDates = new TreeSet<>(new ChronologicalComparator());
  168.         sortedDates.addAll(Arrays.stream(timeStampeds).map(TimeStamped::getDate).collect(Collectors.toList()));
  169.         for (final AbsoluteDate date : sortedDates) {
  170.             fieldDateDetector.addEventDate(new FieldAbsoluteDate<>(field, date));
  171.         }
  172.         return fieldDateDetector;
  173.     }
  174. }