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  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.hipparchus.CalculusFieldElement;
24  import org.hipparchus.ode.events.Action;
25  import org.orekit.propagation.FieldSpacecraftState;
26  import org.orekit.propagation.events.handlers.FieldEventHandler;
27  import org.orekit.time.FieldAbsoluteDate;
28  
29  /** This class logs events detectors events during propagation.
30   *
31   * <p>As {@link FieldEventDetector events detectors} are triggered during
32   * orbit propagation, an event specific {@link
33   * FieldEventHandler#eventOccurred(FieldSpacecraftState, FieldEventDetector, boolean) eventOccurred}
34   * method is called. This class can be used to add a global logging
35   * feature registering all events with their corresponding states in
36   * a chronological sequence (or reverse-chronological if propagation
37   * occurs backward).
38   * <p>This class works by wrapping user-provided {@link FieldEventDetector
39   * events detectors} before they are registered to the propagator. The
40   * wrapper monitor the calls to {@link
41   * FieldEventHandler#eventOccurred(FieldSpacecraftState, FieldEventDetector, boolean) eventOccurred}
42   * and store the corresponding events as {@link FieldLoggedEvent} instances.
43   * After propagation is complete, the user can retrieve all the events
44   * that have occurred at once by calling method {@link #getLoggedEvents()}.</p>
45   *
46   * @author Luc Maisonobe
47   * @param <T> type of the field elements
48   */
49  public class FieldEventsLogger<T extends CalculusFieldElement<T>> {
50  
51      /** List of occurred events. */
52      private final List<FieldLoggedEvent<T>> log;
53  
54      /** Simple constructor.
55       * <p>
56       * Build an empty logger for events detectors.
57       * </p>
58       */
59      public FieldEventsLogger() {
60          log = new ArrayList<>();
61      }
62  
63      /** Monitor an event detector.
64       * <p>
65       * In order to monitor an event detector, it must be wrapped thanks to
66       * this method as follows:
67       * </p>
68       * <pre>
69       * Propagator propagator = new XyzPropagator(...);
70       * EventsLogger logger = new EventsLogger();
71       * FieldEventDetector&lt;T&gt; detector = new UvwDetector(...);
72       * propagator.addEventDetector(logger.monitorDetector(detector));
73       * </pre>
74       * <p>
75       * Note that the event detector returned by the {@link
76       * FieldLoggedEvent#getEventDetector() getEventDetector} method in
77       * {@link FieldLoggedEvent FieldLoggedEvent} instances returned by {@link
78       * #getLoggedEvents()} are the {@code monitoredDetector} instances
79       * themselves, not the wrapping detector returned by this method.
80       * </p>
81       * @param monitoredDetector event detector to monitor
82       * @return the wrapping detector to add to the propagator
83       */
84      public FieldEventDetector<T> monitorDetector(final FieldEventDetector<T> monitoredDetector) {
85          return new FieldLoggingWrapper(monitoredDetector);
86      }
87  
88      /** Clear the logged events.
89       */
90      public void clearLoggedEvents() {
91          log.clear();
92      }
93  
94      /** Get an immutable copy of the logged events.
95       * <p>
96       * The copy is independent of the logger. It is preserved
97       * event if the {@link #clearLoggedEvents() clearLoggedEvents} method
98       * is called and the logger reused in another propagation.
99       * </p>
100      * @return an immutable copy of the logged events
101      */
102     public List<FieldLoggedEvent<T>> getLoggedEvents() {
103         return new ArrayList<>(log);
104     }
105 
106     /** Class for logged events entries.
107      * @param <T> type of the field elements
108      */
109     public static class FieldLoggedEvent <T extends CalculusFieldElement<T>> {
110 
111         /** Event detector triggered. */
112         private final FieldEventDetector<T> detector;
113 
114         /** Triggering state. */
115         private final FieldSpacecraftState<T> state;
116 
117         /** Increasing/decreasing status. */
118         private final boolean increasing;
119 
120         /** Reset state if any, otherwise event state. */
121         private final FieldSpacecraftState<T> resetState;
122 
123         /** Constructor.
124          * @param detectorN detector for event that was triggered
125          * @param stateN state at event trigger date
126          * @param resetStateN reset state if any, otherwise same as event state
127          * @param increasingN indicator if the event switching function was increasing
128          * or decreasing at event occurrence date
129          * @since 13.1
130          */
131         private FieldLoggedEvent(final FieldEventDetector<T> detectorN, final FieldSpacecraftState<T> stateN,
132                                  final FieldSpacecraftState<T> resetStateN, final boolean increasingN) {
133             detector = detectorN;
134             state      = stateN;
135             resetState = resetStateN;
136             increasing = increasingN;
137         }
138 
139         /** Get the event detector triggered.
140          * @return event detector triggered
141          */
142         public FieldEventDetector<T> getEventDetector() {
143             return detector;
144         }
145 
146         /** Get the triggering state.
147          * @return triggering state
148          * @see FieldEventHandler#eventOccurred(FieldSpacecraftState, FieldEventDetector, boolean)
149          */
150         public FieldSpacecraftState<T> getState() {
151             return state;
152         }
153 
154         /**
155          * Get the reset state.
156          * @return reset state
157          * @since 13.1
158          */
159         public FieldSpacecraftState<T> getResetState() {
160             return resetState;
161         }
162 
163         /** Get the Increasing/decreasing status of the event.
164          * @return increasing/decreasing status of the event
165          * @see FieldEventHandler#eventOccurred(FieldSpacecraftState, FieldEventDetector, boolean)
166          */
167         public boolean isIncreasing() {
168             return increasing;
169         }
170 
171     }
172 
173     /** Internal wrapper for events detectors. */
174     private class FieldLoggingWrapper implements FieldDetectorModifier<T> {
175 
176         /** Wrapped detector. */
177         private final FieldEventDetector<T> wrappedDetector;
178 
179         /** Simple constructor.
180          * @param detector events detector to wrap
181          */
182         FieldLoggingWrapper(final FieldEventDetector<T> detector) {
183             this.wrappedDetector = detector;
184         }
185 
186         @Override
187         public FieldEventDetector<T> getDetector() {
188             return wrappedDetector;
189         }
190 
191         /** Log an event.
192          * @param state state at event trigger date
193          * @param resetState reset state if any, otherwise same as event state
194          * @param increasing indicator if the event switching function was increasing
195          */
196         void logEvent(final FieldSpacecraftState<T> state, final FieldSpacecraftState<T> resetState,
197                       final boolean increasing) {
198             log.add(new FieldLoggedEvent<>(getDetector(), state, resetState, increasing));
199         }
200 
201         /** {@inheritDoc} */
202         @Override
203         public FieldEventHandler<T> getHandler() {
204 
205             final FieldEventHandler<T> handler = getDetector().getHandler();
206 
207             return new FieldEventHandler<T>() {
208 
209                 private FieldSpacecraftState<T> lastTriggeringState = null;
210                 private FieldSpacecraftState<T> lastResetState = null;
211 
212                 @Override
213                 public void init(final FieldSpacecraftState<T> initialState, final FieldAbsoluteDate<T> target,
214                                  final FieldEventDetector<T> detector) {
215                     FieldEventHandler.super.init(initialState, target, detector);
216                     lastResetState = null;
217                     lastTriggeringState = null;
218                 }
219 
220                 /** {@inheritDoc} */
221                 @Override
222                 public Action eventOccurred(final FieldSpacecraftState<T> s,
223                                             final FieldEventDetector<T> d,
224                                             final boolean increasing) {
225                     final Action action = handler.eventOccurred(s, getDetector(), increasing);
226                     if (action == Action.RESET_STATE) {
227                         lastResetState = resetState(getDetector(), s);
228                     } else {
229                         lastResetState = s;
230                     }
231                     lastTriggeringState = s;
232                     logEvent(s, lastResetState, increasing);
233                     return action;
234                 }
235 
236                 /** {@inheritDoc} */
237                 @Override
238                 public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> d,
239                                                           final FieldSpacecraftState<T> oldState) {
240                     if (lastTriggeringState != oldState) {
241                         lastTriggeringState = oldState;
242                         lastResetState = handler.resetState(getDetector(), oldState);
243                     }
244                     return lastResetState;
245                 }
246 
247             };
248         }
249 
250     }
251 
252 }