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.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.ode.events.Action;
21  import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
22  import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
23  import org.junit.jupiter.api.AfterEach;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.junit.jupiter.params.ParameterizedTest;
28  import org.junit.jupiter.params.provider.ValueSource;
29  import org.mockito.Mockito;
30  import org.orekit.Utils;
31  import org.orekit.errors.OrekitException;
32  import org.orekit.frames.FramesFactory;
33  import org.orekit.orbits.EquinoctialOrbit;
34  import org.orekit.orbits.Orbit;
35  import org.orekit.propagation.SpacecraftState;
36  import org.orekit.propagation.events.handlers.EventHandler;
37  import org.orekit.propagation.events.handlers.StopOnEvent;
38  import org.orekit.propagation.numerical.NumericalPropagator;
39  import org.orekit.time.AbsoluteDate;
40  import org.orekit.time.TimeScalesFactory;
41  import org.orekit.utils.PVCoordinates;
42  
43  import java.util.concurrent.atomic.AtomicInteger;
44  
45  class DetectorModifierTest {
46  
47      private double maxCheck;
48      private double threshold;
49      private double dt;
50      private Orbit iniOrbit;
51      private AbsoluteDate iniDate;
52      private NumericalPropagator propagator;
53  
54      @Test
55      void testGetDetectionSettings() {
56          // GIVEN
57          final EventDetector detector = Mockito.mock(EventDetector.class);
58          final EventDetectionSettings detectionSettings = Mockito.mock(EventDetectionSettings.class);
59          Mockito.when(detector.getDetectionSettings()).thenReturn(detectionSettings);
60          final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
61          // WHEN
62          final EventDetectionSettings actualSettings = detectorModifier.getDetectionSettings();
63          // THEN
64          Assertions.assertEquals(detectionSettings, actualSettings);
65      }
66  
67      @ParameterizedTest
68      @ValueSource(booleans = {true, false})
69      void testDependsOnTimeOnly(final boolean value) {
70          // GIVEN
71          final EventDetector detector = Mockito.mock(EventDetector.class);
72          Mockito.when(detector.dependsOnTimeOnly()).thenReturn(value);
73          final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
74          // WHEN
75          final boolean actual = detectorModifier.dependsOnTimeOnly();
76          // THEN
77          Assertions.assertEquals(value, actual);
78      }
79  
80      @Test
81      void testInit() {
82          // GIVEN
83          final EventDetector detector = Mockito.mock(EventDetector.class);
84          Mockito.when(detector.getHandler()).thenReturn(new StopOnEvent());
85          final SpacecraftState mockedState = Mockito.mock(SpacecraftState.class);
86          final AbsoluteDate mockedDate = Mockito.mock(AbsoluteDate.class);
87          final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
88          // WHEN
89          detectorModifier.init(mockedState, mockedDate);
90          // THEN
91          Mockito.verify(detector).init(mockedState, mockedDate);
92      }
93  
94      @Test
95      void testReset() {
96          // GIVEN
97          final EventDetector detector = Mockito.mock(EventDetector.class);
98          final SpacecraftState mockedState = Mockito.mock(SpacecraftState.class);
99          final AbsoluteDate mockedDate = Mockito.mock(AbsoluteDate.class);
100         final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
101         // WHEN
102         detectorModifier.reset(mockedState, mockedDate);
103         // THEN
104         Mockito.verify(detector).reset(mockedState, mockedDate);
105     }
106 
107     @Test
108     void testG() {
109         // GIVEN
110         final EventDetector detector = Mockito.mock(EventDetector.class);
111         final SpacecraftState mockedState = Mockito.mock(SpacecraftState.class);
112         final double expectedG = 10.;
113         Mockito.when(detector.g(mockedState)).thenReturn(expectedG);
114         final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
115         // WHEN
116         final double actualG = detectorModifier.g(mockedState);
117         // THEN
118         Assertions.assertEquals(expectedG, actualG);
119     }
120 
121     @Test
122     void testFinish() {
123         // GIVEN
124         final EventDetector detector = Mockito.mock(EventDetector.class);
125         Mockito.when(detector.getHandler()).thenReturn(new StopOnEvent());
126         final SpacecraftState mockedState = Mockito.mock(SpacecraftState.class);
127         final DetectorModifier detectorModifier = new TestDetectorModifier(detector);
128         // WHEN
129         detectorModifier.finish(mockedState);
130         // THEN
131         Mockito.verify(detector).finish(mockedState);
132     }
133 
134     @Test
135     void testSimpleTimer() {
136         DateDetector dateDetector = new DateDetector(iniDate.shiftedBy(2.0*dt)).
137                                     withMaxCheck(maxCheck).
138                                     withThreshold(threshold);
139         DetectorModifier adapter = new TestDetectorModifier(dateDetector);
140         Assertions.assertSame(dateDetector, adapter.getDetector());
141         Assertions.assertEquals(2 * dt, dateDetector.getDate().durationFrom(iniDate), 1.0e-10);
142         propagator.addEventDetector(adapter);
143         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
144 
145         Assertions.assertEquals(2.0*dt, finalState.getDate().durationFrom(iniDate), threshold);
146     }
147 
148     @Test
149     void testOverrideHandler() {
150         AtomicInteger count = new AtomicInteger(0);
151         DateDetector dateDetector = new DateDetector(iniDate.shiftedBy(2.0*dt)).
152                                     withMaxCheck(maxCheck).
153                                     withThreshold(threshold);
154         DetectorModifier adapter = new TestDetectorModifier(dateDetector) {
155             /** {@inheritDoc} */
156             @Override
157             public EventHandler getHandler() {
158                 return new EventHandler() {
159                     /** {@inheritDoc} */
160                     @Override
161                     public Action eventOccurred(final SpacecraftState s, final EventDetector detector, final boolean increasing) {
162                         count.incrementAndGet();
163                         return Action.RESET_STATE;
164                     }
165                 };
166             }
167         };
168         Assertions.assertSame(dateDetector, adapter.getDetector());
169         Assertions.assertEquals(2 * dt, dateDetector.getDate().durationFrom(iniDate), 1.0e-10);
170         propagator.addEventDetector(adapter);
171         Assertions.assertEquals(0, count.get());
172         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
173         Assertions.assertEquals(1, count.get());
174 
175         Assertions.assertEquals(100.0*dt, finalState.getDate().durationFrom(iniDate), threshold);
176     }
177 
178     @Deprecated
179     @Test
180     void testAdapterDetector() {
181         // GIVEN
182         final DateDetector detector = new DateDetector();
183         // WHEN
184         final AdapterDetector adapterDetector = new AdapterDetector(detector);
185         // THEN
186         final TestDetectorModifier detectorModifier = new TestDetectorModifier(detector);
187         Assertions.assertEquals(detectorModifier.getDetector(), adapterDetector.getDetector());
188     }
189     
190     private static class TestDetectorModifier implements DetectorModifier {
191 
192         private final EventDetector detector;
193 
194         TestDetectorModifier(final EventDetector detector) {
195             this.detector = detector;
196         }
197 
198         @Override
199         public EventDetector getDetector() {
200             return detector;
201         }
202     }
203 
204     @BeforeEach
205     public void setUp() {
206         try {
207             Utils.setDataRoot("regular-data");
208             final double mu = 3.9860047e14;
209             final Vector3D position  = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
210             final Vector3D velocity  = new Vector3D(505.8479685, 942.7809215, 7435.922231);
211             iniDate  = new AbsoluteDate(1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
212             iniOrbit = new EquinoctialOrbit(new PVCoordinates(position, velocity),
213                                             FramesFactory.getEME2000(), iniDate, mu);
214             SpacecraftState initialState = new SpacecraftState(iniOrbit);
215             double[] absTolerance = {
216                 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
217             };
218             double[] relTolerance = {
219                 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
220             };
221             AdaptiveStepsizeIntegrator integrator =
222                 new DormandPrince853Integrator(0.001, 1000, absTolerance, relTolerance);
223             integrator.setInitialStepSize(60);
224             propagator = new NumericalPropagator(integrator);
225             propagator.setInitialState(initialState);
226             dt = 60.;
227             maxCheck  = 10.;
228             threshold = 10.e-10;
229         } catch (OrekitException oe) {
230             Assertions.fail(oe.getLocalizedMessage());
231         }
232     }
233 
234     @AfterEach
235     public void tearDown() {
236         iniDate = null;
237         propagator = null;
238     }
239 
240 }