1   /* Copyright 2002-2026 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  
19  import org.hipparchus.CalculusFieldElement;
20  import org.orekit.errors.OrekitException;
21  import org.orekit.errors.OrekitMessages;
22  import org.orekit.propagation.FieldSpacecraftState;
23  import org.orekit.propagation.events.functions.EventFunction;
24  import org.orekit.propagation.events.handlers.EventHandler;
25  import org.orekit.propagation.events.handlers.FieldEventHandler;
26  import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
27  import org.orekit.time.FieldAbsoluteDate;
28  
29  /** Common parts shared by several events finders.
30   * It should only be implemented by detectors able to accept any handler.
31   * @param <D> type of the detector
32   * @param <T> type of the field element
33   * @see org.orekit.propagation.Propagator#addEventDetector(EventDetector)
34   * @author Luc Maisonobe
35   */
36  public abstract class FieldAbstractDetector<D extends FieldAbstractDetector<D, T>, T extends CalculusFieldElement<T>>
37      implements FieldEventDetector<T> {
38  
39      /** Default maximum checking interval (s). */
40      public static final double DEFAULT_MAX_CHECK = FieldEventDetectionSettings.DEFAULT_MAX_CHECK;
41  
42      /** Default convergence threshold (s). */
43      public static final double DEFAULT_THRESHOLD = FieldEventDetectionSettings.DEFAULT_THRESHOLD;
44  
45      /** Default maximum number of iterations in the event time search. */
46      public static final int DEFAULT_MAX_ITER = FieldEventDetectionSettings.DEFAULT_MAX_ITER;
47  
48      /** Detection settings. */
49      private final FieldEventDetectionSettings<T> eventDetectionSettings;
50  
51      /** Default handler for event overrides. */
52      private final FieldEventHandler<T> handler;
53  
54      /** Propagation direction. */
55      private boolean forward = true;
56  
57      /** Event function. */
58      private final EventFunction defaultEventFunction;
59  
60      /** Build a new instance with an event function.
61       * @param eventFunction event function
62       * @param detectionSettings event detection settings
63       * @param handler event handler to call at event occurrences
64       * @since 14.0
65       */
66      protected FieldAbstractDetector(final EventFunction eventFunction,
67                                      final FieldEventDetectionSettings<T> detectionSettings,
68                                      final FieldEventHandler<T> handler) {
69          checkStrictlyPositive(detectionSettings.getThreshold().getReal());
70          this.eventDetectionSettings = detectionSettings;
71          this.handler   = handler;
72          this.defaultEventFunction = eventFunction;
73      }
74  
75      /** Build a new instance.
76       * @param detectionSettings event detection settings
77       * @param handler event handler to call at event occurrences
78       * @since 12.2
79       */
80      protected FieldAbstractDetector(final FieldEventDetectionSettings<T> detectionSettings,
81                                      final FieldEventHandler<T> handler) {
82          checkStrictlyPositive(detectionSettings.getThreshold().getReal());
83          this.eventDetectionSettings = detectionSettings;
84          this.handler   = handler;
85          this.defaultEventFunction = EventFunction.of(detectionSettings.getThreshold().getField(), this::g);
86      }
87  
88      /**
89       * Check if propagation is forward or not.
90       * @param <W> field type
91       * @param state initial state
92       * @param targetDate target propagation date
93       * @return forward flag
94       * @since 13.0
95       */
96      public static <W extends CalculusFieldElement<W>> boolean checkIfForward(final FieldSpacecraftState<W> state,
97                                                                               final FieldAbsoluteDate<W> targetDate) {
98          return targetDate.durationFrom(state.getDate()).getReal() >= 0.0;
99      }
100 
101     /** Check value is strictly positive.
102      * @param value value to check
103      * @exception OrekitException if value is not strictly positive
104      * @since 11.2
105      */
106     private void checkStrictlyPositive(final double value) throws OrekitException {
107         if (value <= 0.0) {
108             throw new OrekitException(OrekitMessages.NOT_STRICTLY_POSITIVE, value);
109         }
110     }
111 
112     @Override
113     public EventFunction getEventFunction() {
114         return defaultEventFunction;
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
120         FieldEventDetector.super.init(s0, t);
121         forward = checkIfForward(s0, t);
122     }
123 
124     /** {@inheritDoc} */
125     @Override
126     public FieldEventDetectionSettings<T> getDetectionSettings() {
127         return eventDetectionSettings;
128     }
129 
130     /**
131      * Set up the maximum checking interval.
132      * <p>
133      * This will override a maximum checking interval if it has been configured previously.
134      * </p>
135      * @param newMaxCheck maximum checking interval (s)
136      * @return a new detector with updated configuration (the instance is not changed)
137      * @since 12.0
138      */
139     public D withMaxCheck(final double newMaxCheck) {
140         return withMaxCheck(FieldAdaptableInterval.of(newMaxCheck));
141     }
142 
143     /**
144      * Set up the maximum checking interval.
145      * <p>
146      * This will override a maximum checking interval if it has been configured previously.
147      * </p>
148      * @param newMaxCheck maximum checking interval (s)
149      * @return a new detector with updated configuration (the instance is not changed)
150      * @since 12.0
151      */
152     public D withMaxCheck(final FieldAdaptableInterval<T> newMaxCheck) {
153         return withDetectionSettings(new FieldEventDetectionSettings<>(newMaxCheck, getThreshold(), getMaxIterationCount()));
154     }
155 
156     /**
157      * Set up the maximum number of iterations in the event time search.
158      * <p>
159      * This will override a number of iterations if it has been configured previously.
160      * </p>
161      * @param newMaxIter maximum number of iterations in the event time search
162      * @return a new detector with updated configuration (the instance is not changed)
163      * @since 6.1
164      */
165     public D withMaxIter(final int newMaxIter) {
166         return withDetectionSettings(new FieldEventDetectionSettings<>(getMaxCheckInterval(), getThreshold(), newMaxIter));
167     }
168 
169     /**
170      * Set up the convergence threshold.
171      * <p>
172      * This will override a convergence threshold if it has been configured previously.
173      * </p>
174      * @param newThreshold convergence threshold (s)
175      * @return a new detector with updated configuration (the instance is not changed)
176      * @since 6.1
177      */
178     public D withThreshold(final T newThreshold) {
179         return withDetectionSettings(new FieldEventDetectionSettings<>(getMaxCheckInterval(), newThreshold, getMaxIterationCount()));
180     }
181 
182     /**
183      * Set up the event detection settings.
184      * <p>
185      * This will override settings previously configured.
186      * </p>
187      * @param newSettings new event detection settings
188      * @return a new detector with updated configuration (the instance is not changed)
189      * @since 12.2
190      */
191     public D withDetectionSettings(final FieldEventDetectionSettings<T> newSettings) {
192         return create(newSettings, getHandler());
193     }
194 
195     /**
196      * Set up the event handler to call at event occurrences.
197      * <p>
198      * This will override a handler if it has been configured previously.
199      * </p>
200      * @param newHandler event handler to call at event occurrences
201      * @return a new detector with updated configuration (the instance is not changed)
202      * @since 6.1
203      */
204     public D withHandler(final FieldEventHandler<T> newHandler) {
205         return create(getDetectionSettings(), newHandler);
206     }
207 
208     /** {@inheritDoc} */
209     public FieldEventHandler<T> getHandler() {
210         return handler;
211     }
212 
213     /** Build a new instance.
214      * @param detectionSettings detection settings
215      * @param newHandler event handler to call at event occurrences
216      * @return a new instance of the appropriate sub-type
217      * @since 12.2
218      */
219     protected abstract D create(FieldEventDetectionSettings<T> detectionSettings, FieldEventHandler<T> newHandler);
220 
221     /** Check if the current propagation is forward or backward.
222      * @return true if the current propagation is forward
223      * @since 7.2
224      */
225     public boolean isForward() {
226         return forward;
227     }
228 
229     /**
230      * Build non-Field instance.
231      * @param eventHandler event handler
232      * @return event detector
233      * @since 14.0
234      */
235     public EventDetector toEventDetector(final EventHandler eventHandler) {
236         return EventDetector.of(getEventFunction(), eventHandler, getDetectionSettings().toEventDetectionSettings());
237     }
238 }