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.exception.MathRuntimeException;
20  import org.hipparchus.geometry.euclidean.threed.Vector3D;
21  import org.hipparchus.ode.LocalizedODEFormats;
22  import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
23  import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
24  import org.hipparchus.util.FastMath;
25  import org.junit.jupiter.api.AfterEach;
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.BeforeEach;
28  import org.junit.jupiter.api.Test;
29  import org.orekit.Utils;
30  import org.orekit.bodies.CelestialBody;
31  import org.orekit.bodies.CelestialBodyFactory;
32  import org.orekit.bodies.OneAxisEllipsoid;
33  import org.orekit.errors.OrekitException;
34  import org.orekit.errors.OrekitMessages;
35  import org.orekit.frames.FramesFactory;
36  import org.orekit.orbits.CartesianOrbit;
37  import org.orekit.orbits.EquinoctialOrbit;
38  import org.orekit.orbits.KeplerianOrbit;
39  import org.orekit.orbits.Orbit;
40  import org.orekit.orbits.OrbitType;
41  import org.orekit.orbits.PositionAngleType;
42  import org.orekit.propagation.SpacecraftState;
43  import org.orekit.propagation.events.EventsLogger.LoggedEvent;
44  import org.orekit.propagation.events.handlers.ContinueOnEvent;
45  import org.orekit.propagation.events.handlers.StopOnDecreasing;
46  import org.orekit.propagation.numerical.NumericalPropagator;
47  import org.orekit.time.AbsoluteDate;
48  import org.orekit.time.TimeScalesFactory;
49  import org.orekit.utils.Constants;
50  import org.orekit.utils.IERSConventions;
51  import org.orekit.utils.PVCoordinates;
52  import org.orekit.utils.TimeStampedPVCoordinates;
53  
54  import java.util.List;
55  
56  class EclipseDetectorTest {
57  
58      private double               mu;
59      private AbsoluteDate         iniDate;
60      private SpacecraftState      initialState;
61      private NumericalPropagator  propagator;
62  
63      private CelestialBody        sun;
64      private OneAxisEllipsoid     earth;
65      private double               sunRadius;
66  
67      @Test
68      void testPolar() {
69          final KeplerianOrbit original = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(initialState.getOrbit());
70          final KeplerianOrbit polar    = new KeplerianOrbit(original.getA(), original.getE(),
71                                                             0.5 * FastMath.PI, original.getPerigeeArgument(),
72                                                             original.getRightAscensionOfAscendingNode(),
73                                                             original.getTrueAnomaly(), PositionAngleType.TRUE,
74                                                             original.getFrame(), original.getDate(),
75                                                             original.getMu());
76          propagator.resetInitialState(new SpacecraftState(polar));
77          EventsLogger logger = new EventsLogger();
78          OneAxisEllipsoid sphericalEarth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
79                                                                 0.0,
80                                                                 FramesFactory.getITRF(IERSConventions.IERS_2010,
81                                                                                       true));
82          EclipseDetector withoutFlattening = new EclipseDetector(sun, sunRadius, sphericalEarth).
83                                              withMaxCheck(60.0).
84                                              withThreshold(1.0e-3).
85                                              withHandler(new ContinueOnEvent()).
86                                              withUmbra();
87          OneAxisEllipsoid obateEarth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
88                                                             Constants.WGS84_EARTH_FLATTENING,
89                                                             FramesFactory.getITRF(IERSConventions.IERS_2010,
90                                                                                   true));
91          EclipseDetector withFlattening    = new EclipseDetector(sun, sunRadius, obateEarth).
92                                              withMaxCheck(60.0).
93                                              withThreshold(1.0e-3).
94                                              withHandler(new ContinueOnEvent()).
95                                              withUmbra();
96          propagator.addEventDetector(logger.monitorDetector(withoutFlattening));
97          propagator.addEventDetector(logger.monitorDetector(withFlattening));
98          double duration = 15000.0;
99          final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(duration));
100         Assertions.assertEquals(duration, finalState.getDate().durationFrom(iniDate), 1.0e-3);
101         final List<LoggedEvent> events = logger.getLoggedEvents();
102         Assertions.assertEquals(10, events.size());
103         Assertions.assertTrue(events.get(0).getEventDetector() == withoutFlattening);
104         Assertions.assertFalse(events.get(0).isIncreasing());
105         Assertions.assertEquals( 2274.702, events.get(0).getState().getDate().durationFrom(iniDate), 1.0e-3);
106         Assertions.assertTrue(events.get(1).getEventDetector() == withFlattening);
107         Assertions.assertFalse(events.get(1).isIncreasing());
108         Assertions.assertEquals( 2280.427, events.get(1).getState().getDate().durationFrom(iniDate), 1.0e-3);
109         Assertions.assertTrue(events.get(2).getEventDetector() == withFlattening);
110         Assertions.assertTrue(events.get(2).isIncreasing());
111         Assertions.assertEquals( 4310.741, events.get(2).getState().getDate().durationFrom(iniDate), 1.0e-3);
112         Assertions.assertTrue(events.get(3).getEventDetector() == withoutFlattening);
113         Assertions.assertTrue(events.get(3).isIncreasing());
114         Assertions.assertEquals( 4317.155, events.get(3).getState().getDate().durationFrom(iniDate), 1.6e-3);
115         Assertions.assertTrue(events.get(4).getEventDetector() == withoutFlattening);
116         Assertions.assertFalse(events.get(4).isIncreasing());
117         Assertions.assertEquals( 8189.250, events.get(4).getState().getDate().durationFrom(iniDate), 1.0e-3);
118         Assertions.assertTrue(events.get(5).getEventDetector() == withFlattening);
119         Assertions.assertFalse(events.get(5).isIncreasing());
120         Assertions.assertEquals( 8194.978, events.get(5).getState().getDate().durationFrom(iniDate), 1.0e-3);
121         Assertions.assertTrue(events.get(6).getEventDetector() == withFlattening);
122         Assertions.assertTrue(events.get(6).isIncreasing());
123         Assertions.assertEquals(10225.704, events.get(6).getState().getDate().durationFrom(iniDate), 1.0e-3);
124         Assertions.assertTrue(events.get(7).getEventDetector() == withoutFlattening);
125         Assertions.assertTrue(events.get(7).isIncreasing());
126         Assertions.assertEquals(10232.115, events.get(7).getState().getDate().durationFrom(iniDate), 1.0e-3);
127         Assertions.assertTrue(events.get(8).getEventDetector() == withoutFlattening);
128         Assertions.assertFalse(events.get(8).isIncreasing());
129         Assertions.assertEquals(14103.800, events.get(8).getState().getDate().durationFrom(iniDate), 1.0e-3);
130         Assertions.assertTrue(events.get(9).getEventDetector() == withFlattening);
131         Assertions.assertFalse(events.get(9).isIncreasing());
132         Assertions.assertEquals(14109.530, events.get(9).getState().getDate().durationFrom(iniDate), 1.0e-3);
133 
134     }
135 
136     @Test
137     void testEclipse() {
138         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth).
139                             withMaxCheck(60.0).
140                             withThreshold(1.0e-3).
141                             withHandler(new StopOnDecreasing()).
142                             withUmbra();
143         Assertions.assertEquals(60.0, e.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
144         Assertions.assertEquals(1.0e-3, e.getThreshold(), 1.0e-15);
145         Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, e.getMaxIterationCount());
146         Assertions.assertEquals(0.0, e.getMargin(), 1.0e-15);
147         Assertions.assertTrue(e.getTotalEclipse());
148         propagator.addEventDetector(e);
149         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(6000));
150         Assertions.assertEquals(2303.1835, finalState.getDate().durationFrom(iniDate), 1.0e-3);
151     }
152 
153     @Test
154     void testPenumbra() {
155         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth).
156                             withMaxCheck(60.0).
157                             withThreshold(1.0e-3).
158                             withPenumbra();
159         Assertions.assertFalse(e.getTotalEclipse());
160         propagator.addEventDetector(e);
161         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(6000));
162         Assertions.assertEquals(4388.155852, finalState.getDate().durationFrom(iniDate), 2.0e-6);
163     }
164 
165     @Test
166     void testWithMethods() {
167         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth).
168                              withHandler(new StopOnDecreasing()).
169                              withMaxCheck(120.0).
170                              withThreshold(1.0e-4).
171                              withMaxIter(12).
172                              withMargin(0.001);
173         Assertions.assertEquals(120.0, e.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
174         Assertions.assertEquals(1.0e-4, e.getThreshold(), 1.0e-15);
175         Assertions.assertEquals(12, e.getMaxIterationCount());
176         propagator.addEventDetector(e);
177         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(6000));
178         Assertions.assertEquals(2304.188978, finalState.getDate().durationFrom(iniDate), 1.0e-4);
179 
180     }
181 
182     @Test
183     void testInsideOcculting() {
184         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth);
185         SpacecraftState s = new SpacecraftState(new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH,
186                                                                                                 new Vector3D(1e6, 2e6, 3e6),
187                                                                                                 new Vector3D(1000, 0, 0)),
188                                                                    FramesFactory.getGCRF(),
189                                                                    mu));
190         try {
191             e.g(s);
192             Assertions.fail("an exception should have been thrown");
193         } catch (OrekitException oe) {
194             Assertions.assertEquals(OrekitMessages.POINT_INSIDE_ELLIPSOID, oe.getSpecifier());
195         }
196     }
197 
198     @Test
199     void testInsideOcculted() {
200         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth);
201         Vector3D p = sun.getPosition(AbsoluteDate.J2000_EPOCH, FramesFactory.getGCRF());
202         SpacecraftState s = new SpacecraftState(new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH,
203                                                                                                 p.add(Vector3D.PLUS_I),
204                                                                                                 Vector3D.PLUS_K),
205                                                                    FramesFactory.getGCRF(),
206                                                                    mu));
207         Assertions.assertEquals(FastMath.PI, e.g(s), 1.0e-15);
208     }
209 
210     @Test
211     void testTooSmallMaxIterationCount() {
212         int n = 5;
213         EclipseDetector e = new EclipseDetector(sun, sunRadius, earth).
214                              withHandler(new StopOnDecreasing()).
215                              withMaxCheck(120.0).
216                              withThreshold(1.0e-4).
217                              withMaxIter(n);
218        propagator.addEventDetector(e);
219         try {
220             propagator.propagate(iniDate.shiftedBy(6000));
221             Assertions.fail("an exception should have been thrown");
222         } catch (OrekitException oe) {
223             Assertions.assertEquals(LocalizedODEFormats.FIND_ROOT,
224                                     ((MathRuntimeException) oe.getCause()).getSpecifier());
225         }
226     }
227 
228     @BeforeEach
229     public void setUp() {
230         try {
231             Utils.setDataRoot("regular-data");
232             mu  = 3.9860047e14;
233             final Vector3D position  = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
234             final Vector3D velocity  = new Vector3D(505.8479685, 942.7809215, 7435.922231);
235             iniDate = new AbsoluteDate(1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
236             final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position,  velocity),
237                                                      FramesFactory.getGCRF(), iniDate, mu);
238             initialState = new SpacecraftState(orbit);
239             double[] absTolerance = {
240                 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
241             };
242             double[] relTolerance = {
243                 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
244             };
245             AdaptiveStepsizeIntegrator integrator =
246                 new DormandPrince853Integrator(0.001, 1000, absTolerance, relTolerance);
247             integrator.setInitialStepSize(60);
248             propagator = new NumericalPropagator(integrator);
249             propagator.setInitialState(initialState);
250             sun = CelestialBodyFactory.getSun();
251             earth = new OneAxisEllipsoid(6400000., 0.0, FramesFactory.getITRF(IERSConventions.IERS_2010, true));
252             sunRadius = 696000000.;
253         } catch (OrekitException oe) {
254             Assertions.fail(oe.getLocalizedMessage());
255         }
256     }
257 
258     @AfterEach
259     public void tearDown() {
260         iniDate = null;
261         initialState = null;
262         propagator = null;
263     }
264 
265 }
266