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.sampling;
18  
19  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
20  import org.hipparchus.util.FastMath;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.Test;
24  import org.orekit.Utils;
25  import org.orekit.bodies.CelestialBodyFactory;
26  import org.orekit.frames.FactoryManagedFrame;
27  import org.orekit.frames.Frame;
28  import org.orekit.frames.FramesFactory;
29  import org.orekit.orbits.KeplerianOrbit;
30  import org.orekit.orbits.OrbitType;
31  import org.orekit.orbits.PositionAngleType;
32  import org.orekit.propagation.Propagator;
33  import org.orekit.propagation.SpacecraftState;
34  import org.orekit.propagation.analytical.KeplerianPropagator;
35  import org.orekit.propagation.events.DateDetector;
36  import org.orekit.propagation.events.handlers.ContinueOnEvent;
37  import org.orekit.propagation.numerical.NumericalPropagator;
38  import org.orekit.time.AbsoluteDate;
39  import org.orekit.time.TimeScalesFactory;
40  import org.orekit.utils.Constants;
41  
42  import java.util.ArrayDeque;
43  import java.util.Arrays;
44  import java.util.Queue;
45  import java.util.concurrent.Callable;
46  import java.util.concurrent.ExecutionException;
47  import java.util.concurrent.ExecutorService;
48  import java.util.concurrent.Executors;
49  import java.util.concurrent.Future;
50  import java.util.concurrent.TimeUnit;
51  import java.util.concurrent.TimeoutException;
52  
53  public class OrekitStepHandlerTest {
54  
55      @Test
56      public void testForwardBackwardStep()
57          throws InterruptedException, ExecutionException, TimeoutException {
58          final AbsoluteDate initialDate = new AbsoluteDate(2014, 01, 01, 00, 00,
59                                                            00.000,
60                                                            TimeScalesFactory
61                                                                .getUTC());
62          final double mu = CelestialBodyFactory.getEarth().getGM();
63          FactoryManagedFrame inertialFrame = FramesFactory.getEME2000();
64  
65          final double propagationTime = 7200.0;// seconds
66          final double fixedStepSize = 3600; // seconds
67  
68          final double semimajorAxis = 8000e3; // meters
69          final double eccentricity = 0.001; // unitless
70          final double inclination = FastMath.toRadians(15.0);
71          final double argPerigee = FastMath.toRadians(10.0);
72          final double raan = FastMath.toRadians(45.0);
73          final double trueAnomaly = FastMath.toRadians(10.0);
74  
75          KeplerianOrbit initialOrbit = new KeplerianOrbit(semimajorAxis,
76                                                           eccentricity,
77                                                           inclination,
78                                                           argPerigee, raan,
79                                                           trueAnomaly,
80                                                           PositionAngleType.TRUE,
81                                                           inertialFrame,
82                                                           initialDate, mu);
83  
84          final Propagator kepler = new KeplerianPropagator(initialOrbit);
85  
86          kepler.setStepHandler(fixedStepSize, currentState -> {});
87  
88          kepler.propagate(initialDate.shiftedBy(propagationTime));
89  
90          final double stepSizeInSeconds = 120;
91          ExecutorService service = Executors.newSingleThreadExecutor();
92          for (double elapsedTime = 0; elapsedTime <= propagationTime; elapsedTime += stepSizeInSeconds) {
93              final double dt = elapsedTime;
94              Future<SpacecraftState> stateFuture = service
95                  .submit(new Callable<SpacecraftState>() {
96  
97                      public SpacecraftState call()
98                          {
99                          return kepler.propagate(initialDate.shiftedBy(dt));
100                     }
101                 });
102 
103             SpacecraftState finalState = stateFuture.get(5, TimeUnit.SECONDS);
104             Assertions.assertNotNull(finalState);
105         }
106     }
107 
108     /**
109      * Check {@link OrekitStepInterpolator#isPreviousStateInterpolated()} and {@link
110      * OrekitStepInterpolator#isCurrentStateInterpolated()}.
111      */
112     @Test
113     public void testIsInterpolated() {
114         // setup
115         NumericalPropagator propagator =
116                 new NumericalPropagator(new ClassicalRungeKuttaIntegrator(60));
117         AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
118         Frame eci = FramesFactory.getGCRF();
119         SpacecraftState ic = new SpacecraftState(new KeplerianOrbit(
120                 6378137 + 500e3, 1e-3, 0, 0, 0, 0,
121                 PositionAngleType.TRUE, eci, date, Constants.EIGEN5C_EARTH_MU));
122         propagator.setInitialState(ic);
123         propagator.setOrbitType(OrbitType.CARTESIAN);
124         // detector triggers half way through second step
125         DateDetector detector =
126                 new DateDetector(date.shiftedBy(90)).withHandler(new ContinueOnEvent());
127         propagator.addEventDetector(detector);
128 
129         // action and verify
130         Queue<Boolean> expected =
131                 new ArrayDeque<>(Arrays.asList(false, false, false, true, true, false));
132         propagator.setStepHandler(interpolator -> {
133             Assertions.assertEquals(expected.poll(), interpolator.isPreviousStateInterpolated());
134             Assertions.assertEquals(expected.poll(), interpolator.isCurrentStateInterpolated());
135             Assertions.assertNotNull(interpolator.getPosition(date, eci));
136         });
137         final AbsoluteDate end = date.shiftedBy(120);
138         Assertions.assertEquals(end, propagator.propagate(end).getDate());
139     }
140 
141     @BeforeEach
142     public void setUp() {
143         Utils.setDataRoot("regular-data");
144     }
145 
146 }