1   /* Copyright 2022-2025 Romain Serra
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.analytical;
18  
19  import org.hipparchus.geometry.euclidean.threed.Rotation;
20  import org.hipparchus.ode.events.Action;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.Test;
23  import org.junit.jupiter.params.ParameterizedTest;
24  import org.junit.jupiter.params.provider.EnumSource;
25  import org.orekit.attitudes.FrameAlignedProvider;
26  import org.orekit.frames.FramesFactory;
27  import org.orekit.orbits.CartesianOrbit;
28  import org.orekit.orbits.KeplerianOrbit;
29  import org.orekit.orbits.Orbit;
30  import org.orekit.orbits.PositionAngleType;
31  import org.orekit.propagation.AdditionalDataProvider;
32  import org.orekit.propagation.SpacecraftState;
33  import org.orekit.propagation.events.DateDetector;
34  import org.orekit.propagation.events.EventDetectionSettings;
35  import org.orekit.propagation.events.EventDetector;
36  import org.orekit.propagation.events.handlers.ContinueOnEvent;
37  import org.orekit.propagation.events.handlers.EventHandler;
38  import org.orekit.propagation.events.handlers.StopOnEvent;
39  import org.orekit.time.AbsoluteDate;
40  import org.orekit.utils.Constants;
41  
42  import java.util.stream.Stream;
43  
44  
45  class AbstractAnalyticalPropagatorTest {
46  
47      @Test
48      void testRemoveAdditionalDataProvider() {
49          // GIVEN
50          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
51          final Orbit orbit = getOrbit(date);
52          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
53          final String name = "a";
54          final AdditionalDataProvider<Boolean> dataProvider = new AdditionalDataProvider<Boolean>() {
55              @Override
56              public String getName() {
57                  return name;
58              }
59  
60              @Override
61              public Boolean getAdditionalData(SpacecraftState state) {
62                  return Boolean.TRUE;
63              }
64          };
65          // WHEN & THEN
66          propagator.addAdditionalDataProvider(dataProvider);
67          Assertions.assertFalse(propagator.getAdditionalDataProviders().isEmpty());
68          propagator.removeAdditionalDataProvider(dataProvider.getName());
69          Assertions.assertTrue(propagator.getAdditionalDataProviders().isEmpty());
70      }
71  
72      @Test
73      void testInternalEventDetector() {
74          // GIVEN
75          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
76          final Orbit orbit = getOrbit(date);
77          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
78          final AbsoluteDate interruptingDate = date.shiftedBy(1);
79          propagator.setAttitudeProvider(new InterruptingAttitudeProvider(interruptingDate));
80          // WHEN
81          final SpacecraftState state = propagator.propagate(date.shiftedBy(10.));
82          // THEN
83          Assertions.assertEquals(state.getDate(), interruptingDate);
84      }
85  
86      @ParameterizedTest
87      @EnumSource(value = Action.class, names = {"RESET_STATE", "RESET_DERIVATIVES"})
88      void testReset(final Action action) {
89          // GIVEN
90          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
91          final Orbit orbit = getOrbit(date);
92          final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
93          final EventHandler handler = (s, detector, increasing) -> action;
94          final TestDetector detector = new TestDetector(date.shiftedBy(0.5), handler);
95          propagator.addEventDetector(detector);
96          // WHEN
97          propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
98          // THEN
99          Assertions.assertTrue(detector.resetted);
100     }
101 
102     private static class TestDetector extends DateDetector {
103         boolean resetted = false;
104 
105         TestDetector(final AbsoluteDate date, final EventHandler handler) {
106             super(EventDetectionSettings.getDefaultEventDetectionSettings(), handler, 1., date);
107         }
108 
109         @Override
110         public void reset(SpacecraftState state, AbsoluteDate target) {
111             resetted = true;
112         }
113     }
114 
115     @Test
116     void testFinish() {
117         // GIVEN
118         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
119         final Orbit orbit = getOrbit(date);
120         final TestAnalyticalPropagator propagator = new TestAnalyticalPropagator(orbit);
121         final TestHandler handler = new TestHandler();
122         propagator.addEventDetector(new DateDetector().withHandler(handler));
123         // WHEN
124         propagator.propagate(propagator.getInitialState().getDate().shiftedBy(1.));
125         // THEN
126         Assertions.assertTrue(handler.isFinished);
127     }
128 
129     private static Orbit getOrbit(final AbsoluteDate date) {
130         return new KeplerianOrbit(8000000.0, 0.01, 0.87, 2.44, 0.21, -1.05,
131                 PositionAngleType.MEAN, FramesFactory.getEME2000(), date, Constants.EIGEN5C_EARTH_MU);
132     }
133 
134     private static class TestHandler extends ContinueOnEvent {
135         boolean isFinished = false;
136 
137         @Override
138         public void finish(SpacecraftState finalState, EventDetector detector) {
139             isFinished = true;
140         }
141     }
142 
143     private static class TestAnalyticalPropagator extends AbstractAnalyticalPropagator {
144 
145         private final Orbit orbit;
146 
147         protected TestAnalyticalPropagator(Orbit orbit) {
148             super(new FrameAlignedProvider(FramesFactory.getGCRF()));
149             this.orbit = orbit;
150             resetInitialState(new SpacecraftState(orbit));
151         }
152 
153         @Override
154         protected double getMass(AbsoluteDate date) {
155             return 1;
156         }
157 
158         @Override
159         protected void resetIntermediateState(SpacecraftState state, boolean forward) {
160 
161         }
162 
163         @Override
164         public Orbit propagateOrbit(AbsoluteDate date) {
165             return new CartesianOrbit(orbit.getPVCoordinates(), orbit.getFrame(), date, orbit.getMu());
166         }
167     }
168 
169     private static class InterruptingAttitudeProvider extends FrameAlignedProvider {
170 
171         private final AbsoluteDate interruptingDate;
172 
173         public InterruptingAttitudeProvider(final AbsoluteDate interruptingDate) {
174             super(Rotation.IDENTITY);
175             this.interruptingDate = interruptingDate;
176         }
177 
178         @Override
179         public Stream<EventDetector> getEventDetectors() {
180             final DateDetector detector = new DateDetector(interruptingDate).withHandler(new StopOnEvent());
181             return Stream.of(detector);
182         }
183     }
184 }