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