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.integration;
18  
19  import org.hipparchus.ode.ODEIntegrator;
20  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.Test;
23  import org.mockito.Mockito;
24  import org.orekit.TestUtils;
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.frames.Frame;
27  import org.orekit.frames.FramesFactory;
28  import org.orekit.orbits.EquinoctialOrbit;
29  import org.orekit.orbits.Orbit;
30  import org.orekit.orbits.OrbitType;
31  import org.orekit.orbits.PositionAngleType;
32  import org.orekit.propagation.BoundedPropagator;
33  import org.orekit.propagation.EphemerisGenerator;
34  import org.orekit.propagation.PropagationType;
35  import org.orekit.propagation.SpacecraftState;
36  import org.orekit.propagation.events.DateDetector;
37  import org.orekit.propagation.events.handlers.EventHandler;
38  import org.orekit.propagation.events.handlers.ResetDerivativesOnEvent;
39  import org.orekit.propagation.numerical.NumericalPropagator;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.utils.Constants;
42  
43  class AbstractIntegratedPropagatorTest {
44  
45      @Test
46      void testIntegrateWithResetDerivativesAndEvents() {
47          // GIVEN
48          final Orbit initialOrbit = TestUtils.getDefaultOrbit(AbsoluteDate.ARBITRARY_EPOCH);
49          final NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(100));
50          propagator.setInitialState(new SpacecraftState(initialOrbit));
51          final TestDetector detector = new TestDetector(initialOrbit.getDate().shiftedBy(10.));
52          propagator.addEventDetector(detector);
53          // WHEN
54          propagator.propagate(initialOrbit.getDate().shiftedBy(100));
55          // THEN
56          Assertions.assertTrue(detector.resetted);
57      }
58  
59      private static class TestDetector extends DateDetector {
60          boolean resetted = false;
61  
62          TestDetector(final AbsoluteDate date) {
63              super(date);
64          }
65  
66          @Override
67          public void reset(SpacecraftState state, AbsoluteDate target) {
68              super.reset(state, target);
69              resetted = true;
70          }
71  
72          @Override
73          public EventHandler getHandler() {
74              return new ResetDerivativesOnEvent();
75          }
76      }
77  
78      @Test
79      void testGetResetAtEndTrue() {
80          testGetResetAtEnd(true);
81      }
82  
83      @Test
84      void testGetResetAtEndFalse() {
85          testGetResetAtEnd(false);
86      }
87  
88      private void testGetResetAtEnd(final boolean expectedResetAtEnd) {
89          // GIVEN
90          final TestAbstractIntegratedPropagator testAbstractIntegratedPropagator = new TestAbstractIntegratedPropagator();
91          // WHEN
92          testAbstractIntegratedPropagator.setResetAtEnd(expectedResetAtEnd);
93          // THEN
94          final boolean actualResetAtEnd = testAbstractIntegratedPropagator.getResetAtEnd();
95          Assertions.assertEquals(expectedResetAtEnd, actualResetAtEnd);
96      }
97      
98      /**
99       * Test issue 1254: Wrong behavior of method "propagate(tStart, tEnd)" when used with "setResetAtEnd(false)".
100      * <p>
101      * Bug discovery and test are a courtesy of Christophe Le Bris.
102      */
103     @Test
104     void testIssue1254() {
105         // GIVEN
106         // GEO orbit
107         final Orbit startOrbit = new EquinoctialOrbit(42165765.0, 0.0, 0.0, 0.0, 0.0, 0.0, PositionAngleType.TRUE,
108                                                       FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH,
109                                                       Constants.IERS2010_EARTH_MU);
110 
111         // Init numerical propagator
112         final NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(300.));
113         propagator.setInitialState(new SpacecraftState(startOrbit));
114         propagator.setResetAtEnd(false);
115 
116         // Produce ephemeris
117         final EphemerisGenerator generator = propagator.getEphemerisGenerator();
118         final AbsoluteDate       minDate   = startOrbit.getDate().shiftedBy(-3600.0);
119         final AbsoluteDate       maxDate   = startOrbit.getDate().shiftedBy(+3600.0);
120         propagator.propagate(minDate, maxDate);
121 
122         // WHEN
123         final BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
124 
125         // THEN
126         Assertions.assertEquals(0., ephemeris.getMinDate().durationFrom(minDate), 0.);
127         Assertions.assertEquals(0., ephemeris.getMaxDate().durationFrom(maxDate), 0.);
128     }
129     
130     /** Test issue 1461.
131      * <p>Test for the new generic method AbstractIntegratedPropagator.reset(SpacecraftState, PropagationType)
132      */
133     @Test
134     void testIssue1461() {
135         // GIVEN
136         // GEO orbit
137         final Orbit startOrbit = new EquinoctialOrbit(42165765.0, 0.0, 0.0, 0.0, 0.0, 0.0, PositionAngleType.TRUE,
138                                                       FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH,
139                                                       Constants.IERS2010_EARTH_MU);
140 
141         // Init numerical propagator
142         final SpacecraftState state = new SpacecraftState(startOrbit);
143         final NumericalPropagator propagator = new NumericalPropagator(new ClassicalRungeKuttaIntegrator(300.));
144         propagator.setInitialState(state);
145 
146         // WHEN
147         propagator.resetInitialState(state, PropagationType.OSCULATING);
148         final SpacecraftState oscState = propagator.getInitialState();
149         
150         propagator.resetInitialState(state, PropagationType.MEAN);
151         final SpacecraftState meanState = propagator.getInitialState();
152 
153         // THEN
154         
155         // Check that all three states are identical
156         final double dpOsc = oscState.getPosition().distance(state.getPosition());
157         final double dvOsc = oscState.getPVCoordinates().getVelocity().distance(state.getPVCoordinates().getVelocity());
158         
159         final double dpMean = meanState.getPosition().distance(state.getPosition());
160         final double dvMean = meanState.getPVCoordinates().getVelocity().distance(state.getPVCoordinates().getVelocity());
161         
162         Assertions.assertEquals(0., dpOsc, 0.);
163         Assertions.assertEquals(0., dvOsc, 0.);
164         Assertions.assertEquals(0., dpMean, 0.);
165         Assertions.assertEquals(0., dvMean, 0.);
166     }
167 
168     private static class TestAbstractIntegratedPropagator extends AbstractIntegratedPropagator {
169 
170         protected TestAbstractIntegratedPropagator() {
171             super(Mockito.mock(ODEIntegrator.class), PropagationType.OSCULATING);
172         }
173 
174         @Override
175         protected StateMapper createMapper(AbsoluteDate referenceDate, double mu, OrbitType orbitType, PositionAngleType positionAngleType, AttitudeProvider attitudeProvider, Frame frame) {
176             return null;
177         }
178 
179         @Override
180         protected MainStateEquations getMainStateEquations(ODEIntegrator integ) {
181             return null;
182         }
183     }
184 
185 }