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.hipparchus.Field;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.ode.events.Action;
23  import org.hipparchus.ode.nonstiff.AdaptiveStepsizeFieldIntegrator;
24  import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
25  import org.hipparchus.util.Binary64Field;
26  import org.junit.jupiter.api.AfterEach;
27  import org.junit.jupiter.api.Assertions;
28  import org.junit.jupiter.api.BeforeEach;
29  import org.junit.jupiter.api.Test;
30  import org.orekit.Utils;
31  import org.orekit.bodies.CelestialBodyFactory;
32  import org.orekit.bodies.OneAxisEllipsoid;
33  import org.orekit.frames.FramesFactory;
34  import org.orekit.orbits.FieldEquinoctialOrbit;
35  import org.orekit.orbits.FieldOrbit;
36  import org.orekit.orbits.OrbitType;
37  import org.orekit.propagation.FieldSpacecraftState;
38  import org.orekit.propagation.events.handlers.FieldEventHandler;
39  import org.orekit.propagation.numerical.FieldNumericalPropagator;
40  import org.orekit.time.FieldAbsoluteDate;
41  import org.orekit.time.TimeScalesFactory;
42  import org.orekit.utils.FieldPVCoordinates;
43  
44  import java.util.List;
45  
46  public class FieldEventsLoggerTest {
47  
48      private double               mu;
49  //    private FieldAbsoluteDate<T>         iniDate;
50  //    private FieldSpacecraftState<T>      initialState;
51      private int                  count;
52  //    private FieldEventDetector<T>        umbraDetector;
53  //    private FieldEventDetector<T>        penumbraDetector;
54  
55  
56      @BeforeEach
57      public void setUp() {
58              Utils.setDataRoot("regular-data");
59              mu  = 3.9860047e14;
60      }
61  
62      @Test
63      public void testLogUmbra() {
64          doTestLogUmbra(Binary64Field.getInstance());
65      }
66      @Test
67      public void testLogPenumbra() {
68          doTestLogPenumbra(Binary64Field.getInstance());
69      }
70      @Test
71      public void testLogAll() {
72          doTestLogAll(Binary64Field.getInstance());
73      }
74      @Test
75      public void testImmutableList() {
76          doTestImmutableList(Binary64Field.getInstance());
77      }
78      @Test
79      public void testClearLog() {
80          doTestClearLog(Binary64Field.getInstance());
81      }
82  
83      private <T extends CalculusFieldElement<T>> void doTestLogUmbra(Field<T> field) {
84  
85          T zero = field.getZero();
86  
87  
88          final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add(3492467.560), zero.add(-25767.25680));
89          final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685) , zero.add(942.7809215), zero.add(7435.922231));
90          FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
91          final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position,  velocity),
92                                                                  FramesFactory.getEME2000(), iniDate, zero.add(mu));
93          FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(orbit);
94          double[] absTolerance = {
95              0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
96          };
97          double[] relTolerance = {
98              1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
99          };
100         AdaptiveStepsizeFieldIntegrator<T> integrator =
101             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
102         integrator.setInitialStepSize(60);
103         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
104         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
105         propagator.setInitialState(initialState);
106         count = 0;
107         FieldEclipseDetector<T> umbraDetector = buildDetector(field, true);
108         FieldEclipseDetector<T> penumbraDetector = buildDetector(field, false);
109 
110 
111 
112         FieldEventsLogger<T> logger = new FieldEventsLogger<>();
113         FieldEventDetector<T> monitored = logger.monitorDetector(umbraDetector.withMaxIter(200));
114         Assertions.assertEquals(100, umbraDetector.getMaxIterationCount());
115         Assertions.assertEquals(200, monitored.getMaxIterationCount());
116 
117         propagator.addEventDetector(monitored);
118         propagator.addEventDetector(penumbraDetector);
119         count = 0;
120         propagator.propagate(iniDate.shiftedBy(16215)).getDate();
121         Assertions.assertEquals(11, count);
122         checkCounts(logger, 3, 3, 0, 0);
123     }
124 
125     private <T extends CalculusFieldElement<T>> void doTestLogPenumbra(final Field<T> field) {
126 
127 
128         T zero = field.getZero();
129 
130 
131         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add(3492467.560), zero.add(-25767.25680));
132         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685) , zero.add(942.7809215), zero.add(7435.922231));
133         FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
134         final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position,  velocity),
135                                                                 FramesFactory.getEME2000(), iniDate, zero.add(mu));
136         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(orbit);
137         double[] absTolerance = {
138             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
139         };
140         double[] relTolerance = {
141             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
142         };
143         AdaptiveStepsizeFieldIntegrator<T> integrator =
144             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
145         integrator.setInitialStepSize(60);
146         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
147         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
148         propagator.setInitialState(initialState);
149         count = 0;
150         FieldEventDetector<T> umbraDetector = buildDetector(field, true);
151         FieldEventDetector<T> penumbraDetector = buildDetector(field, false);
152 
153         FieldEventsLogger<T> logger = new FieldEventsLogger<>();
154         propagator.addEventDetector(umbraDetector);
155         propagator.addEventDetector(logger.monitorDetector(penumbraDetector));
156         count = 0;
157         propagator.propagate(iniDate.shiftedBy(16215)).getDate();
158         Assertions.assertEquals(11, count);
159         checkCounts(logger, 0, 0, 2, 3);
160     }
161 
162     private <T extends CalculusFieldElement<T>> void doTestLogAll(final Field<T> field) {
163 
164         T zero = field.getZero();
165 
166 
167         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add(3492467.560), zero.add(-25767.25680));
168         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685) , zero.add(942.7809215), zero.add(7435.922231));
169         FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
170         final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position,  velocity),
171                                                                 FramesFactory.getEME2000(), iniDate, zero.add(mu));
172         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(orbit);
173         double[] absTolerance = {
174             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
175         };
176         double[] relTolerance = {
177             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
178         };
179         AdaptiveStepsizeFieldIntegrator<T> integrator =
180             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
181         integrator.setInitialStepSize(60);
182         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
183         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
184         propagator.setInitialState(initialState);
185         count = 0;
186         FieldEventDetector<T> umbraDetector = buildDetector(field, true);
187         FieldEventDetector<T> penumbraDetector = buildDetector(field, false);
188 
189 
190 
191 
192 
193 
194 
195 
196         FieldEventsLogger<T> logger = new FieldEventsLogger<>();
197         propagator.addEventDetector(logger.monitorDetector(umbraDetector));
198         propagator.addEventDetector(logger.monitorDetector(penumbraDetector));
199         count = 0;
200         propagator.propagate(iniDate.shiftedBy(16215));
201         Assertions.assertEquals(11, count);
202         checkCounts(logger, 3, 3, 2, 3);
203     }
204 
205     private <T extends CalculusFieldElement<T>> void doTestImmutableList(final Field<T> field) {
206 
207 
208         T zero = field.getZero();
209 
210 
211         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add(3492467.560), zero.add(-25767.25680));
212         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685) , zero.add(942.7809215), zero.add(7435.922231));
213         FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
214         final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position,  velocity),
215                                                                 FramesFactory.getEME2000(), iniDate, zero.add(mu));
216         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(orbit);
217         double[] absTolerance = {
218             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
219         };
220         double[] relTolerance = {
221             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
222         };
223         AdaptiveStepsizeFieldIntegrator<T> integrator =
224             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
225         integrator.setInitialStepSize(60);
226         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
227         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
228         propagator.setInitialState(initialState);
229         count = 0;
230         FieldEventDetector<T> umbraDetector = buildDetector(field, true);
231         FieldEventDetector<T> penumbraDetector = buildDetector(field, false);
232 
233         FieldEventsLogger<T> logger = new FieldEventsLogger<>();
234         propagator.addEventDetector(logger.monitorDetector(umbraDetector));
235         propagator.addEventDetector(logger.monitorDetector(penumbraDetector));
236         count = 0;
237         propagator.propagate(iniDate.shiftedBy(16215));
238         List<FieldEventsLogger.FieldLoggedEvent<T>> firstList = logger.getLoggedEvents();
239         Assertions.assertEquals(11, firstList.size());
240         propagator.propagate(iniDate.shiftedBy(30000));
241         List<FieldEventsLogger.FieldLoggedEvent<T>> secondList = logger.getLoggedEvents();
242         Assertions.assertEquals(11, firstList.size());
243         Assertions.assertEquals(20, secondList.size());
244         for (int i = 0; i < firstList.size(); ++i) {
245 
246             FieldEventsLogger.FieldLoggedEvent<T> e1 = firstList.get(i);
247             FieldEventsLogger.FieldLoggedEvent<T> e2 = secondList.get(i);
248             FieldPVCoordinates<T> pv1 = e1.getState().getPVCoordinates();
249             FieldPVCoordinates<T> pv2 = e2.getState().getPVCoordinates();
250 
251             Assertions.assertTrue(e1.getEventDetector() == e2.getEventDetector());
252             Assertions.assertEquals(0, pv1.getPosition().subtract(pv2.getPosition()).getNorm().getReal(), 1.0e-10);
253             Assertions.assertEquals(0, pv1.getVelocity().subtract(pv2.getVelocity()).getNorm().getReal(), 1.0e-10);
254             Assertions.assertEquals(e1.isIncreasing(), e2.isIncreasing());
255 
256         }
257     }
258 
259     private <T extends CalculusFieldElement<T>> void doTestClearLog(final Field<T> field) {
260 
261 
262 
263 
264         T zero = field.getZero();
265 
266 
267         final FieldVector3D<T> position  = new FieldVector3D<>(zero.add(-6142438.668), zero.add(3492467.560), zero.add(-25767.25680));
268         final FieldVector3D<T> velocity  = new FieldVector3D<>(zero.add(505.8479685) , zero.add(942.7809215), zero.add(7435.922231));
269         FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
270         final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position,  velocity),
271                                                                 FramesFactory.getEME2000(), iniDate, zero.add(mu));
272         FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(orbit);
273         double[] absTolerance = {
274             0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
275         };
276         double[] relTolerance = {
277             1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
278         };
279         AdaptiveStepsizeFieldIntegrator<T> integrator =
280             new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
281         integrator.setInitialStepSize(60);
282         FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
283         propagator.setOrbitType(OrbitType.EQUINOCTIAL);
284         propagator.setInitialState(initialState);
285         count = 0;
286         FieldEventDetector<T> umbraDetector = buildDetector(field, true);
287         FieldEventDetector<T> penumbraDetector = buildDetector(field, false);
288 
289 
290 
291         FieldEventsLogger<T> logger = new FieldEventsLogger<>();
292         propagator.addEventDetector(logger.monitorDetector(umbraDetector));
293         propagator.addEventDetector(logger.monitorDetector(penumbraDetector));
294         count = 0;
295         propagator.propagate(iniDate.shiftedBy(16215));
296         List<FieldEventsLogger.FieldLoggedEvent<T>> firstList = logger.getLoggedEvents();
297         Assertions.assertEquals(11, firstList.size());
298         logger.clearLoggedEvents();
299         propagator.propagate(iniDate.shiftedBy(30000));
300         List<FieldEventsLogger.FieldLoggedEvent<T>> secondList = logger.getLoggedEvents();
301         Assertions.assertEquals(11, firstList.size());
302         Assertions.assertEquals( 9, secondList.size());
303     }
304 
305     private <T extends CalculusFieldElement<T>> void checkCounts(FieldEventsLogger<T> logger,
306                              int expectedUmbraIncreasingCount, int expectedUmbraDecreasingCount,
307                              int expectedPenumbraIncreasingCount, int expectedPenumbraDecreasingCount) {
308         int umbraIncreasingCount = 0;
309         int umbraDecreasingCount = 0;
310         int penumbraIncreasingCount = 0;
311         int penumbraDecreasingCount = 0;
312         for (FieldEventsLogger.FieldLoggedEvent<T> event : logger.getLoggedEvents()) {
313             final FieldEclipseDetector<T> eclipseDetector = (FieldEclipseDetector<T>) (event.getEventDetector());
314             if (eclipseDetector.getTotalEclipse()) {
315                 if (event.isIncreasing()) {
316                     ++umbraIncreasingCount;
317                 } else {
318                     ++umbraDecreasingCount;
319                 }
320             }
321             else {
322                 if (event.isIncreasing()) {
323                     ++penumbraIncreasingCount;
324                 } else {
325                     ++penumbraDecreasingCount;
326                 }
327             }
328         }
329         Assertions.assertEquals(expectedUmbraIncreasingCount,    umbraIncreasingCount);
330         Assertions.assertEquals(expectedUmbraDecreasingCount,    umbraDecreasingCount);
331         Assertions.assertEquals(expectedPenumbraIncreasingCount, penumbraIncreasingCount);
332         Assertions.assertEquals(expectedPenumbraDecreasingCount, penumbraDecreasingCount);
333     }
334 
335     private <T extends CalculusFieldElement<T>> FieldEclipseDetector<T> buildDetector(Field<T> field, final boolean totalEclipse) {
336 
337         FieldEclipseDetector<T> detector =
338                 new FieldEclipseDetector<>(field, CelestialBodyFactory.getSun(), 696000000,
339                                            new OneAxisEllipsoid(6400000, 0.0, FramesFactory.getGCRF())).
340                 withMaxCheck(60.0).
341                 withThreshold(field.getZero().newInstance(1.0e-3));
342 
343         if (totalEclipse) {
344             detector = detector.withUmbra();
345         } else {
346             detector = detector.withPenumbra();
347         }
348 
349         detector = detector.withHandler(new FieldEventHandler<T>() {
350             public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> detector, boolean increasing) {
351                 ++count;
352                 return Action.CONTINUE;
353             }
354         } );
355 
356         return detector;
357 
358     }
359 
360     @AfterEach
361     public void tearDown() {
362         count = 0;
363     }
364 
365 }
366