1   /* Copyright 2002-2024 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.analytical;
18  
19  import org.hamcrest.MatcherAssert;
20  import org.hipparchus.analysis.polynomials.SmoothStepFactory;
21  import org.hipparchus.geometry.euclidean.threed.Rotation;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.linear.BlockRealMatrix;
24  import org.hipparchus.linear.MatrixUtils;
25  import org.hipparchus.linear.RealMatrix;
26  import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
27  import org.hipparchus.util.FastMath;
28  import org.junit.jupiter.api.Assertions;
29  import org.junit.jupiter.api.DisplayName;
30  import org.junit.jupiter.api.Test;
31  import org.junit.jupiter.api.Timeout;
32  import org.mockito.Mockito;
33  import org.orekit.OrekitMatchers;
34  import org.orekit.TestUtils;
35  import org.orekit.Utils;
36  import org.orekit.attitudes.AttitudeInterpolator;
37  import org.orekit.attitudes.AttitudeProvider;
38  import org.orekit.attitudes.AttitudesSequence;
39  import org.orekit.attitudes.CelestialBodyPointed;
40  import org.orekit.attitudes.LofOffset;
41  import org.orekit.bodies.CelestialBodyFactory;
42  import org.orekit.bodies.GeodeticPoint;
43  import org.orekit.bodies.OneAxisEllipsoid;
44  import org.orekit.errors.OrekitException;
45  import org.orekit.errors.OrekitIllegalArgumentException;
46  import org.orekit.errors.OrekitIllegalStateException;
47  import org.orekit.errors.OrekitMessages;
48  import org.orekit.errors.TimeStampedCacheException;
49  import org.orekit.frames.Frame;
50  import org.orekit.frames.FramesFactory;
51  import org.orekit.frames.LOFType;
52  import org.orekit.frames.TopocentricFrame;
53  import org.orekit.models.earth.EarthStandardAtmosphereRefraction;
54  import org.orekit.models.earth.ReferenceEllipsoid;
55  import org.orekit.orbits.KeplerianOrbit;
56  import org.orekit.orbits.Orbit;
57  import org.orekit.orbits.OrbitBlender;
58  import org.orekit.orbits.OrbitHermiteInterpolator;
59  import org.orekit.orbits.OrbitType;
60  import org.orekit.orbits.PositionAngleType;
61  import org.orekit.propagation.AdditionalStateProvider;
62  import org.orekit.propagation.Propagator;
63  import org.orekit.propagation.SpacecraftState;
64  import org.orekit.propagation.SpacecraftStateInterpolator;
65  import org.orekit.propagation.StateCovariance;
66  import org.orekit.propagation.StateCovarianceBlender;
67  import org.orekit.propagation.StateCovarianceKeplerianHermiteInterpolator;
68  import org.orekit.propagation.StateCovarianceTest;
69  import org.orekit.propagation.events.DateDetector;
70  import org.orekit.propagation.events.ElevationDetector;
71  import org.orekit.propagation.events.handlers.ContinueOnEvent;
72  import org.orekit.propagation.events.handlers.RecordAndContinue;
73  import org.orekit.propagation.numerical.NumericalPropagator;
74  import org.orekit.time.AbsoluteDate;
75  import org.orekit.time.DateComponents;
76  import org.orekit.time.TimeComponents;
77  import org.orekit.time.TimeInterpolator;
78  import org.orekit.time.TimeScalesFactory;
79  import org.orekit.time.TimeStampedDoubleHermiteInterpolator;
80  import org.orekit.time.TimeStampedPair;
81  import org.orekit.utils.AbsolutePVCoordinates;
82  import org.orekit.utils.AbsolutePVCoordinatesTest;
83  import org.orekit.utils.AngularDerivativesFilter;
84  import org.orekit.utils.CartesianDerivativesFilter;
85  import org.orekit.utils.Constants;
86  import org.orekit.utils.IERSConventions;
87  import org.orekit.utils.PVCoordinates;
88  import org.orekit.utils.TimeStampedPVCoordinates;
89  
90  import java.lang.reflect.InvocationTargetException;
91  import java.lang.reflect.Method;
92  import java.util.ArrayList;
93  import java.util.Arrays;
94  import java.util.List;
95  import java.util.Optional;
96  import java.util.concurrent.TimeUnit;
97  import java.util.stream.Stream;
98  
99  public class EphemerisTest {
100 
101     private AbsoluteDate initDate;
102     private AbsoluteDate finalDate;
103     private Frame        inertialFrame;
104     private Propagator   propagator;
105     private Orbit        initialState;
106 
107     @Test
108     @DisplayName("test default Ephemeris constructor")
109     void testDefaultEphemerisConstructor() {
110         // Given
111         // Create spacecraft state sample
112         final Orbit           defaultOrbit = TestUtils.getDefaultOrbit(new AbsoluteDate());
113         final SpacecraftState firstState   = new SpacecraftState(defaultOrbit);
114         final SpacecraftState secondState  = firstState.shiftedBy(1);
115 
116         final List<SpacecraftState> states = new ArrayList<>();
117         states.add(firstState);
118         states.add(secondState);
119 
120         final Ephemeris defaultEphemeris = new Ephemeris(states, states.size());
121 
122         // When
123         final SpacecraftStateInterpolator defaultStateInterpolator =
124                 (SpacecraftStateInterpolator) defaultEphemeris.getStateInterpolator();
125 
126         // Then
127         final Frame                       inertialFrame              = defaultOrbit.getFrame();
128         final SpacecraftStateInterpolator referenceStateInterpolator = new SpacecraftStateInterpolator(inertialFrame);
129 
130         Assertions.assertEquals(referenceStateInterpolator.getExtrapolationThreshold(),
131                                 defaultStateInterpolator.getExtrapolationThreshold());
132         Assertions.assertEquals(referenceStateInterpolator.getOutputFrame(),
133                                 defaultStateInterpolator.getOutputFrame());
134         Assertions.assertEquals(referenceStateInterpolator.getAttitudeInterpolator().isPresent(),
135                                 defaultStateInterpolator.getAttitudeInterpolator().isPresent());
136         Assertions.assertEquals(referenceStateInterpolator.getAdditionalStateInterpolator().isPresent(),
137                                 defaultStateInterpolator.getAdditionalStateInterpolator().isPresent());
138 
139         Assertions.assertInstanceOf(OrbitHermiteInterpolator.class,
140                                     defaultStateInterpolator.getOrbitInterpolator().get());
141         Assertions.assertInstanceOf(TimeStampedDoubleHermiteInterpolator.class,
142                                     defaultStateInterpolator.getMassInterpolator().get());
143         Assertions.assertInstanceOf(AttitudeInterpolator.class,
144                                     defaultStateInterpolator.getAttitudeInterpolator().get());
145         Assertions.assertInstanceOf(TimeStampedDoubleHermiteInterpolator.class,
146                                     defaultStateInterpolator.getAdditionalStateInterpolator().get());
147 
148         Assertions.assertFalse(defaultEphemeris.getCovarianceInterpolator().isPresent());
149 
150     }
151 
152     @Test
153     @DisplayName("test error thrown when using an empty list to create an Ephemeris")
154     void testErrorThrownWhenUsingEmptyStateList() {
155         // Given
156         final SpacecraftState firstState  = Mockito.mock(SpacecraftState.class);
157         final SpacecraftState secondState = Mockito.mock(SpacecraftState.class);
158 
159         Mockito.when(firstState.isOrbitDefined()).thenReturn(true);
160         Mockito.when(secondState.isOrbitDefined()).thenReturn(true);
161 
162         final List<SpacecraftState> states = new ArrayList<>();
163 
164         // Create interpolator
165         final Frame inertialFrameMock = Mockito.mock(Frame.class);
166         Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true);
167 
168         final int nbInterpolationPoints = 3;
169         final TimeInterpolator<SpacecraftState> stateInterpolator =
170                 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrameMock, inertialFrameMock);
171 
172         // When & Then
173         OrekitIllegalArgumentException thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class,
174                                                                         () -> new Ephemeris(states, stateInterpolator));
175 
176         Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, thrown.getSpecifier());
177         Assertions.assertEquals(0, ((Integer) thrown.getParts()[0]).intValue());
178 
179     }
180 
181     @Test
182     @DisplayName("test error thrown when using inconsistent states sample and state interpolator")
183     void testErrorThrownWhenUsingInconsistentStatesSampleAndStateInterpolator() {
184         // Given
185         final SpacecraftState firstState  = Mockito.mock(SpacecraftState.class);
186         final SpacecraftState secondState = Mockito.mock(SpacecraftState.class);
187 
188         Mockito.when(firstState.isOrbitDefined()).thenReturn(true);
189         Mockito.when(secondState.isOrbitDefined()).thenReturn(true);
190 
191         final List<SpacecraftState> states = new ArrayList<>();
192         states.add(firstState);
193         states.add(secondState);
194 
195         // Create interpolator
196         final Frame inertialFrameMock = Mockito.mock(Frame.class);
197         Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true);
198 
199         final int nbInterpolationPoints = 3;
200         final TimeInterpolator<SpacecraftState> stateInterpolator =
201                 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrameMock, inertialFrameMock);
202 
203         // When & Then
204         OrekitIllegalArgumentException thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class,
205                                                                         () -> new Ephemeris(states, stateInterpolator));
206 
207         Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, thrown.getSpecifier());
208         Assertions.assertEquals(2, ((Integer) thrown.getParts()[0]).intValue());
209 
210     }
211 
212     @Test
213     @DisplayName("test error thrown when using inconsistent states and covariances")
214     void testErrorThrownWhenUsingInconsistentStatesAndCovariances() {
215         // Given
216 
217         // Create spacecraft state sample
218         final SpacecraftState firstState  = Mockito.mock(SpacecraftState.class);
219         final SpacecraftState secondState = Mockito.mock(SpacecraftState.class);
220 
221         Mockito.when(firstState.isOrbitDefined()).thenReturn(true);
222         Mockito.when(secondState.isOrbitDefined()).thenReturn(true);
223 
224         final List<SpacecraftState> states = new ArrayList<>();
225         states.add(firstState);
226         states.add(secondState);
227 
228         // Create covariance state sample
229         final StateCovariance firstCovariance  = Mockito.mock(StateCovariance.class);
230         final StateCovariance secondCovariance = Mockito.mock(StateCovariance.class);
231 
232         final List<StateCovariance> covariances = new ArrayList<>();
233         covariances.add(firstCovariance);
234         covariances.add(secondCovariance);
235 
236         // Simulate inconsistency between state and covariance
237         final AbsoluteDate referenceDate = new AbsoluteDate();
238         Mockito.when(firstState.getDate()).thenReturn(referenceDate);
239         Mockito.when(firstCovariance.getDate()).thenReturn(referenceDate.shiftedBy(1));
240 
241         // Create state interpolator
242         final Frame inertialFrameMock = Mockito.mock(Frame.class);
243         Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true);
244 
245         final TimeInterpolator<SpacecraftState> stateInterpolator = new SpacecraftStateInterpolator(inertialFrameMock);
246 
247         // Create covariance interpolator
248         @SuppressWarnings("unchecked")
249         final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator =
250                 Mockito.mock(TimeInterpolator.class);
251 
252         // When & Then
253         Exception thrown = Assertions.assertThrows(OrekitIllegalStateException.class,
254                                                    () -> new Ephemeris(states, stateInterpolator,
255                                                                        covariances, covarianceInterpolator));
256 
257         Assertions.assertEquals(
258                 "state date 2000-01-01T11:58:55.816Z does not match its covariance date 2000-01-01T11:58:56.816Z",
259                 thrown.getMessage());
260     }
261 
262     @Test
263     @DisplayName("test error thrown when using different states and covariances sample size ")
264     void testErrorThrownWhenUsingDifferentStatesAndCovariancesSampleSize() {
265         // Given
266 
267         // Create spacecraft state sample
268         final SpacecraftState firstState  = Mockito.mock(SpacecraftState.class);
269         final SpacecraftState secondState = Mockito.mock(SpacecraftState.class);
270 
271         Mockito.when(firstState.isOrbitDefined()).thenReturn(true);
272         Mockito.when(secondState.isOrbitDefined()).thenReturn(true);
273 
274         final List<SpacecraftState> states = new ArrayList<>();
275         states.add(firstState);
276         states.add(secondState);
277 
278         // Create covariance state sample
279         final StateCovariance firstCovariance = Mockito.mock(StateCovariance.class);
280 
281         final List<StateCovariance> covariances = new ArrayList<>();
282         covariances.add(firstCovariance);
283 
284         // Create state interpolator
285         final Frame inertialFrameMock = Mockito.mock(Frame.class);
286         Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true);
287 
288         final TimeInterpolator<SpacecraftState> stateInterpolator = new SpacecraftStateInterpolator(inertialFrameMock);
289 
290         // Create covariance interpolator
291         @SuppressWarnings("unchecked")
292         final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator =
293                 Mockito.mock(TimeInterpolator.class);
294 
295         // When & Then
296         Exception thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class,
297                                                    () -> new Ephemeris(states, stateInterpolator,
298                                                                        covariances, covarianceInterpolator));
299 
300         Assertions.assertEquals(
301                 "inconsistent dimensions: 2 != 1", thrown.getMessage());
302     }
303 
304     @Test
305     @DisplayName("test error thrown when trying to reset intermediate state ")
306     void testErrorThrownWhenTryingToResetIntermediateState() {
307         // Given
308         // Create spacecraft state sample
309         final Orbit           defaultOrbit = TestUtils.getDefaultOrbit(new AbsoluteDate());
310         final SpacecraftState firstState   = new SpacecraftState(defaultOrbit);
311         final SpacecraftState secondState  = firstState.shiftedBy(1);
312 
313         final List<SpacecraftState> states = new ArrayList<>();
314         states.add(firstState);
315         states.add(secondState);
316 
317         // Create state interpolator
318         final Frame inertialFrame = FramesFactory.getEME2000();
319 
320         final TimeInterpolator<SpacecraftState> stateInterpolator = new SpacecraftStateInterpolator(inertialFrame);
321 
322         final Ephemeris ephemeris = new Ephemeris(states, stateInterpolator);
323 
324         // When & Then
325         Exception thrown =
326                 Assertions.assertThrows(OrekitException.class, () -> ephemeris.resetIntermediateState(firstState, true));
327 
328         Assertions.assertEquals("reset state not allowed", thrown.getMessage());
329     }
330 
331     @Test
332     @DisplayName("test that an empty optional is returned when getting covariance from a state only ephemeris")
333     void testEmptyCovarianceGetter() {
334         // GIVEN
335         final AbsoluteDate initialDate  = new AbsoluteDate();
336         final Orbit        initialOrbit = TestUtils.getDefaultOrbit(initialDate);
337 
338         // Setup propagator
339         final Orbit                 finalOrbit = initialOrbit.shiftedBy(1);
340         final List<SpacecraftState> states     = new ArrayList<>();
341         states.add(new SpacecraftState(initialOrbit));
342         states.add(new SpacecraftState(finalOrbit));
343 
344         final Ephemeris ephemeris = new Ephemeris(states, 2);
345 
346         // When
347         final Optional<StateCovariance> optionalCovariance = ephemeris.getCovariance(Mockito.mock(AbsoluteDate.class));
348 
349         // Then
350         Assertions.assertFalse(optionalCovariance.isPresent());
351 
352     }
353 
354     @Test
355     @SuppressWarnings("unchecked")
356     @DisplayName("test that the expected spacecraft state is returned when no attitude provider is given at construction")
357     void testExpectedStateReturnedWhenNoAttitudeProvider() {
358         // GIVEN
359         final AbsoluteDate initialDate  = new AbsoluteDate();
360         final Orbit        initialOrbit = TestUtils.getDefaultOrbit(initialDate);
361 
362         // Setup behaviour
363         final AbsoluteDate    propDate          = initialDate.shiftedBy(0.5);
364         final SpacecraftState mockExpectedState = Mockito.mock(SpacecraftState.class);
365 
366         // Setup propagator
367         final Orbit                 finalOrbit = initialOrbit.shiftedBy(1);
368         final List<SpacecraftState> states     = new ArrayList<>();
369 
370         final SpacecraftState initialState = new SpacecraftState(initialOrbit);
371         final SpacecraftState finalState   = new SpacecraftState(finalOrbit);
372 
373         states.add(initialState);
374         states.add(finalState);
375 
376         // Setup mock interpolator
377         final TimeInterpolator<SpacecraftState> mockInterpolator = Mockito.mock(TimeInterpolator.class);
378 
379         Mockito.when(mockInterpolator.getNbInterpolationPoints()).thenReturn(2);
380         Mockito.when(mockInterpolator.getExtrapolationThreshold()).thenReturn(0.001);
381 
382         Mockito.when(mockInterpolator.interpolate(Mockito.eq(initialDate), Mockito.any(Stream.class)))
383                .thenReturn(initialState);
384         Mockito.when(mockInterpolator.interpolate(Mockito.eq(propDate), Mockito.any(Stream.class)))
385                .thenReturn(mockExpectedState);
386 
387         final Ephemeris ephemeris = new Ephemeris(states, mockInterpolator, null);
388 
389         // When
390         final SpacecraftState propState = ephemeris.basicPropagate(propDate);
391 
392         // Then
393         Assertions.assertEquals(mockExpectedState, propState);
394 
395     }
396 
397     @Test
398     public void testAttitudeOverride() throws IllegalArgumentException, OrekitException {
399         setUp();
400 
401         final double positionTolerance = 1e-6;
402         final double velocityTolerance = 1e-5;
403         final double attitudeTolerance = 1e-6;
404 
405         int    numberOfIntervals = 1440;
406         double deltaT            = finalDate.durationFrom(initDate) / ((double) numberOfIntervals);
407 
408         propagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
409 
410         List<SpacecraftState> states = new ArrayList<>(numberOfIntervals + 1);
411         for (int j = 0; j <= numberOfIntervals; j++) {
412             states.add(propagator.propagate(initDate.shiftedBy((j * deltaT))));
413         }
414 
415         // Create interpolator
416         final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
417 
418         // Create ephemeris with attitude override
419         Ephemeris ephemPropagator = new Ephemeris(states, interpolator, new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
420         Assertions.assertEquals(0, ephemPropagator.getManagedAdditionalStates().length);
421 
422         //First test that we got position, velocity and attitude nailed
423         int numberEphemTestIntervals = 2880;
424         deltaT = finalDate.durationFrom(initDate) / ((double) numberEphemTestIntervals);
425         doTestInterpolation(numberEphemTestIntervals, deltaT, ephemPropagator,
426                             positionTolerance, velocityTolerance, attitudeTolerance,
427                             "LVLH_CCSDS");
428 
429         //Now force an override on the attitude and check it against a Keplerian propagator
430         //setup identically to the first but with a different attitude
431         //If override isn't working this will fail.
432         propagator = new KeplerianPropagator(propagator.getInitialState().getOrbit());
433         propagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.QSW));
434 
435         ephemPropagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.QSW));
436         doTestInterpolation(numberEphemTestIntervals, deltaT, ephemPropagator,
437                             positionTolerance, velocityTolerance, attitudeTolerance,
438                             "QSW");
439     }
440 
441     private void doTestInterpolation(final int numberEphemTestIntervals, final double deltaT,
442                                      final Ephemeris ephemPropagator,
443                                      final double positionTolerance,
444                                      final double velocityTolerance,
445                                      final double attitudeTolerance,
446                                      final String errorMessage) {
447         for (int j = 0; j <= numberEphemTestIntervals; j++) {
448             AbsoluteDate    currentDate   = initDate.shiftedBy(j * deltaT);
449             SpacecraftState ephemState    = ephemPropagator.propagate(currentDate);
450             SpacecraftState keplerState   = propagator.propagate(currentDate);
451             double          positionDelta = calculatePositionDelta(ephemState, keplerState);
452             double          velocityDelta = calculateVelocityDelta(ephemState, keplerState);
453             double          attitudeDelta = calculateAttitudeDelta(ephemState, keplerState);
454             Assertions.assertEquals(0.0, positionDelta, positionTolerance, errorMessage + " Unmatched Position at: " + currentDate);
455             Assertions.assertEquals(0.0, velocityDelta, velocityTolerance, errorMessage + " Unmatched Velocity at: " + currentDate);
456             Assertions.assertEquals(0.0, attitudeDelta, attitudeTolerance, errorMessage + " Unmatched Attitude at: " + currentDate);
457         }
458     }
459 
460     @Test
461     public void testAttitudeSequenceTransition() {
462         setUp();
463 
464         // Initialize the orbit
465         final AbsoluteDate initialDate = new AbsoluteDate(2003, 01, 01, 0, 0, 00.000, TimeScalesFactory.getUTC());
466         final Vector3D     position    = new Vector3D(-39098981.4866597, -15784239.3610601, 78908.2289853595);
467         final Vector3D     velocity    = new Vector3D(1151.00321021175, -2851.14864755189, -2.02133248357321);
468         final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
469                                                       FramesFactory.getGCRF(), initialDate,
470                                                       Constants.WGS84_EARTH_MU);
471         final SpacecraftState initialState = new SpacecraftState(initialOrbit);
472 
473         // Define attitude laws
474         AttitudeProvider before =
475                 new CelestialBodyPointed(FramesFactory.getICRF(), CelestialBodyFactory.getSun(), Vector3D.PLUS_K,
476                                          Vector3D.PLUS_I, Vector3D.PLUS_K);
477         AttitudeProvider after =
478                 new CelestialBodyPointed(FramesFactory.getICRF(), CelestialBodyFactory.getEarth(), Vector3D.PLUS_K,
479                                          Vector3D.PLUS_I, Vector3D.PLUS_K);
480 
481         // Define attitude sequence
482         AbsoluteDate switchDate     = initialDate.shiftedBy(86400.0);
483         double       transitionTime = 600;
484         DateDetector switchDetector = new DateDetector(switchDate).withHandler(new ContinueOnEvent());
485 
486         AttitudesSequence attitudeSequence = new AttitudesSequence();
487         attitudeSequence.resetActiveProvider(before);
488         attitudeSequence.addSwitchingCondition(before, after, switchDetector, true, false, transitionTime,
489                                                AngularDerivativesFilter.USE_RR, null);
490 
491         NumericalPropagator propagator = new NumericalPropagator(new DormandPrince853Integrator(0.1, 500, 1e-9, 1e-9));
492         propagator.setInitialState(initialState);
493 
494         // Propagate and build ephemeris
495         final List<SpacecraftState> propagatedStates = new ArrayList<>();
496 
497         propagator.setStepHandler(60, propagatedStates::add);
498         propagator.propagate(initialDate.shiftedBy(2 * 86400.0));
499 
500         // Create interpolator
501         final int nbInterpolationPoints = 8;
502         final TimeInterpolator<SpacecraftState> interpolator =
503                 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrame, inertialFrame);
504 
505         final Ephemeris ephemeris = new Ephemeris(propagatedStates, interpolator);
506 
507         // Add attitude switch event to ephemeris
508         ephemeris.setAttitudeProvider(attitudeSequence);
509         attitudeSequence.registerSwitchEvents(ephemeris);
510 
511         // Propagate with a step during the transition
512         AbsoluteDate    endDate     = initialDate.shiftedBy(2 * 86400.0);
513         SpacecraftState stateBefore = ephemeris.getInitialState();
514         ephemeris.propagate(switchDate.shiftedBy(transitionTime / 2));
515         SpacecraftState stateAfter = ephemeris.propagate(endDate);
516 
517         // Check that the attitudes are correct
518         Assertions.assertEquals(
519                 before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation()
520                       .getQ0(),
521                 stateBefore.getAttitude().getRotation().getQ0(),
522                 1.0E-16);
523         Assertions.assertEquals(
524                 before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation()
525                       .getQ1(),
526                 stateBefore.getAttitude().getRotation().getQ1(),
527                 1.0E-16);
528         Assertions.assertEquals(
529                 before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation()
530                       .getQ2(),
531                 stateBefore.getAttitude().getRotation().getQ2(),
532                 1.0E-16);
533         Assertions.assertEquals(
534                 before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation()
535                       .getQ3(),
536                 stateBefore.getAttitude().getRotation().getQ3(),
537                 1.0E-16);
538 
539         Assertions.assertEquals(
540                 after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ0(),
541                 stateAfter.getAttitude().getRotation().getQ0(),
542                 1.0E-16);
543         Assertions.assertEquals(
544                 after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ1(),
545                 stateAfter.getAttitude().getRotation().getQ1(),
546                 1.0E-16);
547         Assertions.assertEquals(
548                 after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ2(),
549                 stateAfter.getAttitude().getRotation().getQ2(),
550                 1.0E-16);
551         Assertions.assertEquals(
552                 after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ3(),
553                 stateAfter.getAttitude().getRotation().getQ3(),
554                 1.0E-16);
555     }
556 
557     @Test
558     public void testNonResettableState() {
559         setUp();
560         try {
561             propagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
562 
563             List<SpacecraftState> states = new ArrayList<>();
564             for (double dt = 0; dt >= -1200; dt -= 60.0) {
565                 states.add(propagator.propagate(initDate.shiftedBy(dt)));
566             }
567 
568             // Create interpolator
569             final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
570 
571             new Ephemeris(states, interpolator).resetInitialState(propagator.getInitialState());
572             Assertions.fail("an exception should have been thrown");
573         }
574         catch (OrekitException oe) {
575             Assertions.assertEquals(OrekitMessages.NON_RESETABLE_STATE, oe.getSpecifier());
576         }
577     }
578 
579     @Test
580     public void testAdditionalStates() {
581         setUp();
582 
583         final String name1 = "dt0";
584         final String name2 = "dt1";
585         propagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
586 
587         List<SpacecraftState> states = new ArrayList<>();
588         for (double dt = 0; dt >= -1200; dt -= 60.0) {
589             final SpacecraftState original = propagator.propagate(initDate.shiftedBy(dt));
590             final SpacecraftState expanded = original.addAdditionalState(name2, original.getDate().durationFrom(finalDate));
591             states.add(expanded);
592         }
593 
594         // Create interpolator
595         final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
596 
597         final Propagator ephem = new Ephemeris(states, interpolator);
598         ephem.addAdditionalStateProvider(new AdditionalStateProvider() {
599             public String getName() {
600                 return name1;
601             }
602 
603             public double[] getAdditionalState(SpacecraftState state) {
604                 return new double[] { state.getDate().durationFrom(initDate) };
605             }
606         });
607 
608         final String[] additional = ephem.getManagedAdditionalStates();
609         Arrays.sort(additional);
610         Assertions.assertEquals(2, additional.length);
611         Assertions.assertEquals(name1, ephem.getManagedAdditionalStates()[0]);
612         Assertions.assertEquals(name2, ephem.getManagedAdditionalStates()[1]);
613         Assertions.assertTrue(ephem.isAdditionalStateManaged(name1));
614         Assertions.assertTrue(ephem.isAdditionalStateManaged(name2));
615         Assertions.assertFalse(ephem.isAdditionalStateManaged("not managed"));
616 
617         SpacecraftState s = ephem.propagate(initDate.shiftedBy(-270.0));
618         Assertions.assertEquals(-270.0, s.getAdditionalState(name1)[0], 1.0e-15);
619         Assertions.assertEquals(-86670.0, s.getAdditionalState(name2)[0], 1.0e-15);
620 
621     }
622 
623     @Test
624     public void testProtectedMethods()
625             throws SecurityException, NoSuchMethodException,
626             InvocationTargetException, IllegalAccessException {
627         setUp();
628 
629         propagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
630 
631         List<SpacecraftState> states = new ArrayList<>();
632         for (double dt = 0; dt >= -1200; dt -= 60.0) {
633             final SpacecraftState original = propagator.propagate(initDate.shiftedBy(dt));
634             final SpacecraftState modified = new SpacecraftState(original.getOrbit(),
635                                                                  original.getAttitude(),
636                                                                  original.getMass() - 0.0625 * dt);
637             states.add(modified);
638         }
639 
640         // Create interpolator
641         final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
642 
643         final Propagator ephem          = new Ephemeris(states, interpolator);
644         Method           propagateOrbit = Ephemeris.class.getDeclaredMethod("propagateOrbit", AbsoluteDate.class);
645         propagateOrbit.setAccessible(true);
646         Method getMass = Ephemeris.class.getDeclaredMethod("getMass", AbsoluteDate.class);
647         getMass.setAccessible(true);
648 
649         SpacecraftState s = ephem.propagate(initDate.shiftedBy(-270.0));
650         Orbit           o = (Orbit) propagateOrbit.invoke(ephem, s.getDate());
651         double          m = (Double) getMass.invoke(ephem, s.getDate());
652         Assertions.assertEquals(0.0,
653                                 Vector3D.distance(s.getPosition(),
654                                                   o.getPosition()),
655                                 1.0e-15);
656         Assertions.assertEquals(s.getMass(), m, 1.0e-15);
657 
658     }
659 
660     @Test
661     public void testGetCovariance() {
662 
663         // Given
664         setUp();
665 
666         double                dt          = finalDate.durationFrom(initDate);
667         double                timeStep    = dt / 20.0;
668         List<SpacecraftState> states      = new ArrayList<>();
669         List<StateCovariance> covariances = new ArrayList<>();
670 
671         final StateCovariance initialCovariance = getDefaultCovariance(initDate, inertialFrame);
672 
673         for (double t = 0; t <= dt; t += timeStep) {
674             final AbsoluteDate    currentDate       = initDate.shiftedBy(t);
675             final SpacecraftState currentState      = propagator.propagate(currentDate);
676             final StateCovariance currentCovariance = initialCovariance.shiftedBy(initialState, t);
677             states.add(currentState);
678             covariances.add(currentCovariance);
679         }
680 
681         // Create state interpolator
682         final int nbInterpolationPoints = 5;
683         final TimeInterpolator<SpacecraftState> stateInterpolator =
684                 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrame, inertialFrame);
685 
686         // Create covariance interpolators
687         final SmoothStepFactory.SmoothStepFunction blendingFunction = SmoothStepFactory.getQuadratic();
688 
689         final OrbitBlender orbitBlender =
690                 new OrbitBlender(blendingFunction, new KeplerianPropagator(initialState), inertialFrame);
691 
692         final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceBlender =
693                 new StateCovarianceBlender(blendingFunction, orbitBlender, inertialFrame, OrbitType.CARTESIAN,
694                                            PositionAngleType.MEAN);
695 
696         final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceHermite =
697                 new StateCovarianceKeplerianHermiteInterpolator(2, orbitBlender, CartesianDerivativesFilter.USE_PVA,
698                                                                 inertialFrame, OrbitType.CARTESIAN, PositionAngleType.MEAN);
699 
700         Ephemeris ephemerisUsingBlender = new Ephemeris(states, stateInterpolator, covariances, covarianceBlender);
701         Ephemeris ephemerisUsingHermite = new Ephemeris(states, stateInterpolator, covariances, covarianceHermite);
702 
703         // When
704         final AbsoluteDate initialDateShiftedByHalfTimeStep = initDate.shiftedBy(timeStep * 0.5);
705         final AbsoluteDate initialDateShiftedByTimeStep     = initDate.shiftedBy(timeStep);
706 
707         final StateCovariance blendedCovarianceAtT0 = ephemerisUsingBlender.getCovariance(initDate).get();
708         final StateCovariance blendedCovarianceBetweenT0AndT1 =
709                 ephemerisUsingBlender.getCovariance(initialDateShiftedByHalfTimeStep).get();
710         final StateCovariance blendedCovarianceAtT1 =
711                 ephemerisUsingBlender.getCovariance(initialDateShiftedByTimeStep).get();
712 
713         final StateCovariance hermiteCovarianceAtT0 = ephemerisUsingHermite.getCovariance(initDate).get();
714         final StateCovariance hermiteCovarianceBetweenT0AndT1 =
715                 ephemerisUsingHermite.getCovariance(initialDateShiftedByHalfTimeStep).get();
716         final StateCovariance hermiteCovarianceAtT1 =
717                 ephemerisUsingHermite.getCovariance(initialDateShiftedByTimeStep).get();
718 
719         // Then
720         final RealMatrix initialMatrix = initialCovariance.getMatrix();
721         final RealMatrix initialMatrixShiftedByHalfTimeStep =
722                 initialCovariance.shiftedBy(initialState, timeStep * 0.5).getMatrix();
723         final RealMatrix initialMatrixShiftedByTimeStep =
724                 initialCovariance.shiftedBy(initialState, timeStep).getMatrix();
725         final RealMatrix zeroMatrix =
726                 MatrixUtils.createRealMatrix(StateCovariance.STATE_DIMENSION, StateCovariance.STATE_DIMENSION);
727 
728         StateCovarianceTest.compareCovariance(zeroMatrix,
729                                               blendedCovarianceAtT0.getMatrix().subtract(initialMatrix),
730                                               1e-11);
731         StateCovarianceTest.compareCovariance(zeroMatrix,
732                                               blendedCovarianceBetweenT0AndT1.getMatrix()
733                                                                              .subtract(initialMatrixShiftedByHalfTimeStep),
734                                               1e-9);
735         StateCovarianceTest.compareCovariance(zeroMatrix, blendedCovarianceAtT1.getMatrix()
736                                                                                .subtract(initialMatrixShiftedByTimeStep),
737                                               1e-9);
738 
739         StateCovarianceTest.compareCovariance(zeroMatrix,
740                                               hermiteCovarianceAtT0.getMatrix().subtract(initialMatrix),
741                                               1e-11);
742         StateCovarianceTest.compareCovariance(zeroMatrix,
743                                               hermiteCovarianceBetweenT0AndT1.getMatrix()
744                                                                              .subtract(initialMatrixShiftedByHalfTimeStep),
745                                               1e-9);
746         StateCovarianceTest.compareCovariance(zeroMatrix, hermiteCovarianceAtT1.getMatrix()
747                                                                                .subtract(initialMatrixShiftedByTimeStep),
748                                               1e-8);
749 
750     }
751 
752     private StateCovariance getDefaultCovariance(final AbsoluteDate date, final Frame frame) {
753 
754         final RealMatrix covarianceMatrix = new BlockRealMatrix(new double[][] { { 1, 0, 0, 0, 0, 0 },
755                                                                                  { 0, 1, 0, 0, 0, 0 },
756                                                                                  { 0, 0, 1, 0, 0, 0 },
757                                                                                  { 0, 0, 0, 1e-3, 0, 0 },
758                                                                                  { 0, 0, 0, 0, 1e-3, 0 },
759                                                                                  { 0, 0, 0, 0, 0, 1e-3 }, });
760 
761         return new StateCovariance(covarianceMatrix, date, frame, OrbitType.CARTESIAN, PositionAngleType.MEAN);
762     }
763 
764     @Test
765     public void testExtrapolation() {
766         setUp();
767 
768         double                dt       = finalDate.durationFrom(initDate);
769         double                timeStep = dt / 20.0;
770         List<SpacecraftState> states   = new ArrayList<>();
771 
772         for (double t = 0; t <= dt; t += timeStep) {
773             states.add(propagator.propagate(initDate.shiftedBy(t)));
774         }
775 
776         // Create interpolator
777         final int nbInterpolationPoints = 5;
778         final TimeInterpolator<SpacecraftState> interpolator =
779                 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrame, inertialFrame);
780 
781         Ephemeris ephemeris = new Ephemeris(states, interpolator);
782         Assertions.assertEquals(finalDate, ephemeris.getMaxDate());
783 
784         double tolerance = interpolator.getExtrapolationThreshold();
785 
786         final TimeStampedPVCoordinates interpolatedPV =
787                 ephemeris.getPVCoordinates(initDate.shiftedBy(timeStep), inertialFrame);
788 
789         final TimeStampedPVCoordinates propagatedPV = states.get(1).getPVCoordinates();
790 
791         // Assert getPVCoordinates method
792         AbsolutePVCoordinatesTest.assertPV(propagatedPV, interpolatedPV, 1e-8);
793 
794         // Assert getFrame method
795         Assertions.assertEquals(inertialFrame, ephemeris.getFrame());
796 
797         ephemeris.propagate(ephemeris.getMinDate());
798         ephemeris.propagate(ephemeris.getMaxDate());
799         ephemeris.propagate(ephemeris.getMinDate().shiftedBy(-tolerance / 2.0));
800         ephemeris.propagate(ephemeris.getMaxDate().shiftedBy(tolerance / 2.0));
801 
802         try {
803             ephemeris.propagate(ephemeris.getMinDate().shiftedBy(-2.0 * tolerance));
804             Assertions.fail("an exception should have been thrown");
805         }
806         catch (TimeStampedCacheException e) {
807             //supposed to fail since out of bounds
808         }
809 
810         try {
811             ephemeris.propagate(ephemeris.getMaxDate().shiftedBy(2.0 * tolerance));
812             Assertions.fail("an exception should have been thrown");
813         }
814         catch (TimeStampedCacheException e) {
815             //supposed to fail since out of bounds
816         }
817     }
818 
819     @Test
820     public void testIssue662() {
821         setUp();
822 
823         // Input parameters
824         int    numberOfIntervals = 1440;
825         double deltaT            = finalDate.durationFrom(initDate) / ((double) numberOfIntervals);
826 
827         // Build the list of spacecraft states
828         String                additionalName  = "testValue";
829         double                additionalValue = 1.0;
830         List<SpacecraftState> states          = new ArrayList<>(numberOfIntervals + 1);
831         for (int j = 0; j <= numberOfIntervals; j++) {
832             states.add(propagator.propagate(initDate.shiftedBy((j * deltaT)))
833                                  .addAdditionalState(additionalName, additionalValue));
834         }
835 
836         // Build the ephemeris propagator
837         // Create interpolator
838         final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
839 
840         Ephemeris ephemPropagator = new Ephemeris(states, interpolator);
841 
842         // State before adding an attitude provider
843         SpacecraftState stateBefore = ephemPropagator.propagate(ephemPropagator.getMaxDate().shiftedBy(-60.0));
844         Assertions.assertEquals(1, stateBefore.getAdditionalState(additionalName).length);
845         Assertions.assertEquals(additionalValue, stateBefore.getAdditionalState(additionalName)[0], Double.MIN_VALUE);
846 
847         // Set an attitude provider
848         ephemPropagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
849 
850         // State after adding an attitude provider
851         SpacecraftState stateAfter = ephemPropagator.propagate(ephemPropagator.getMaxDate().shiftedBy(-60.0));
852         Assertions.assertEquals(1, stateAfter.getAdditionalState(additionalName).length);
853         Assertions.assertEquals(additionalValue, stateAfter.getAdditionalState(additionalName)[0], Double.MIN_VALUE);
854 
855     }
856 
857     @Test
858     public void testIssue680() {
859         setUp();
860 
861         // Initial PV coordinates
862         AbsolutePVCoordinates initPV = new AbsolutePVCoordinates(inertialFrame,
863                                                                  new TimeStampedPVCoordinates(initDate,
864                                                                                               new PVCoordinates(new Vector3D(
865                                                                                                       -29536113.0,
866                                                                                                       30329259.0, -100125.0),
867                                                                                                                 new Vector3D(
868                                                                                                                         -2194.0,
869                                                                                                                         -2141.0,
870                                                                                                                         -8.0))));
871         // Input parameters
872         int    numberOfIntervals = 1440;
873         double deltaT            = finalDate.durationFrom(initDate) / ((double) numberOfIntervals);
874 
875         // Build the list of spacecraft states
876         List<SpacecraftState> states = new ArrayList<>(numberOfIntervals + 1);
877         for (int j = 0; j <= numberOfIntervals; j++) {
878             states.add(new SpacecraftState(initPV).shiftedBy(j * deltaT));
879         }
880 
881         // Build the ephemeris propagator
882         // Create interpolator
883         final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
884 
885         Ephemeris ephemPropagator = new Ephemeris(states, interpolator);
886 
887         // Get initial state without attitude provider
888         SpacecraftState withoutAttitudeProvider = ephemPropagator.getInitialState();
889         Assertions.assertEquals(0.0,
890                                 Vector3D.distance(withoutAttitudeProvider.getAbsPVA().getPosition(), initPV.getPosition()),
891                                 1.0e-10);
892         Assertions.assertEquals(0.0,
893                                 Vector3D.distance(withoutAttitudeProvider.getAbsPVA().getVelocity(), initPV.getVelocity()),
894                                 1.0e-10);
895 
896         // Set an attitude provider
897         ephemPropagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
898 
899         // Get initial state with attitude provider
900         SpacecraftState withAttitudeProvider = ephemPropagator.getInitialState();
901         Assertions.assertEquals(0.0, Vector3D.distance(withAttitudeProvider.getAbsPVA().getPosition(), initPV.getPosition()),
902                                 1.0e-10);
903         Assertions.assertEquals(0.0, Vector3D.distance(withAttitudeProvider.getAbsPVA().getVelocity(), initPV.getVelocity()),
904                                 1.0e-10);
905 
906     }
907 
908     /** Error with specific propagators & additional state provider throwing a NullPointerException when propagating */
909     @Test
910     public void testIssue949() {
911         // GIVEN
912         final AbsoluteDate initialDate  = new AbsoluteDate();
913         final Orbit        initialOrbit = TestUtils.getDefaultOrbit(initialDate);
914 
915         // Setup propagator
916         final Orbit                 finalOrbit = initialOrbit.shiftedBy(1);
917         final List<SpacecraftState> states     = new ArrayList<>();
918         states.add(new SpacecraftState(initialOrbit));
919         states.add(new SpacecraftState(finalOrbit));
920 
921         final Ephemeris ephemeris = new Ephemeris(states, 2);
922 
923         // Setup additional state provider which use the initial state in its init method
924         final AdditionalStateProvider additionalStateProvider = TestUtils.getAdditionalProviderWithInit();
925         ephemeris.addAdditionalStateProvider(additionalStateProvider);
926 
927         // WHEN & THEN
928         Assertions.assertDoesNotThrow(() -> ephemeris.propagate(ephemeris.getMaxDate()), "No error should have been thrown");
929 
930     }
931 
932     @Test
933     @Timeout(value = 5000, unit = TimeUnit.SECONDS)
934     void testIssue1277() {
935         // GIVEN
936         // Create orbit
937         double       mu    = Constants.IERS2010_EARTH_MU;
938         AbsoluteDate date  = new AbsoluteDate();
939         Frame        frame = FramesFactory.getEME2000();
940         Orbit orbit = new KeplerianOrbit(6378000 + 500000, 0.01, FastMath.toRadians(15), 0, 0, 0,
941                                          PositionAngleType.MEAN, frame,date, mu);
942         // Create propagator
943         Propagator propagator = new KeplerianPropagator(orbit);
944 
945         // Add step handler for saving states
946         List<SpacecraftState> states = new ArrayList<>();
947         propagator.getMultiplexer().add(10, states::add);
948 
949         // Run propagation over one week
950         propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY * 7));
951 
952         // Create event detector
953         GeodeticPoint    station = new GeodeticPoint(0, 0, 0);
954         Frame            itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
955         OneAxisEllipsoid wgs84   = ReferenceEllipsoid.getWgs84(itrf);
956         TopocentricFrame topo    = new TopocentricFrame(wgs84, station, "station");
957 
958         RecordAndContinue handler = new RecordAndContinue();
959         ElevationDetector detector = new ElevationDetector(topo).withConstantElevation(FastMath.toRadians(5))
960                                                                 .withRefraction(new EarthStandardAtmosphereRefraction())
961                                                                 .withMaxCheck(60).withHandler(handler);
962 
963         // Create ephemeris from states
964         Ephemeris ephemeris = new Ephemeris(states, 4);
965 
966         // Add detector
967         ephemeris.addEventDetector(detector);
968 
969         // WHEN & THEN
970         ephemeris.propagate(ephemeris.getMinDate(), ephemeris.getMaxDate());
971     }
972 
973     /* Ephemeris propagate fails for interpolation point value of 1 */
974     @Test
975     void testMinInterpolationPoints() {
976         // GIVEN
977         final AbsoluteDate initialDate  = new AbsoluteDate();
978         final Orbit        initialOrbit = TestUtils.getDefaultOrbit(initialDate);
979 
980         // Setup propagator
981         final Orbit                 finalOrbit = initialOrbit.shiftedBy(1);
982         final List<SpacecraftState> states     = new ArrayList<>();
983         states.add(new SpacecraftState(initialOrbit));
984         states.add(new SpacecraftState(finalOrbit));
985 
986         final Ephemeris ephemeris = new Ephemeris(states, 1);
987 
988         // WHEN
989         final AbsoluteDate t = ephemeris.getMaxDate();
990         final SpacecraftState actual = ephemeris.propagate(t);
991 
992         // THEN
993         MatcherAssert.assertThat(actual.getDate(),
994                 OrekitMatchers.durationFrom(t, OrekitMatchers.closeTo(0, 0)));
995         MatcherAssert.assertThat(actual.getPVCoordinates(),
996                 OrekitMatchers.pvCloseTo(finalOrbit.getPVCoordinates(), 0.0));
997     }
998 
999     public void setUp() throws IllegalArgumentException, OrekitException {
1000         Utils.setDataRoot("regular-data");
1001 
1002         initDate = new AbsoluteDate(new DateComponents(2004, 01, 01),
1003                                     TimeComponents.H00,
1004                                     TimeScalesFactory.getUTC());
1005 
1006         finalDate = new AbsoluteDate(new DateComponents(2004, 01, 02),
1007                                      TimeComponents.H00,
1008                                      TimeScalesFactory.getUTC());
1009 
1010         double a     = 7187990.1979844316;
1011         double e     = 0.5e-4;
1012         double i     = 1.7105407051081795;
1013         double omega = 1.9674147913622104;
1014         double OMEGA = FastMath.toRadians(261);
1015         double lv    = 0;
1016         double mu    = 3.9860047e14;
1017         inertialFrame = FramesFactory.getEME2000();
1018 
1019         initialState = new KeplerianOrbit(a, e, i, omega, OMEGA, lv, PositionAngleType.TRUE,
1020                                           inertialFrame, initDate, mu);
1021         propagator   = new KeplerianPropagator(initialState);
1022 
1023     }
1024 
1025     private double calculatePositionDelta(SpacecraftState state1, SpacecraftState state2) {
1026         return Vector3D.distance(state1.getPosition(), state2.getPosition());
1027     }
1028 
1029     private double calculateVelocityDelta(SpacecraftState state1, SpacecraftState state2) {
1030         return Vector3D.distance(state1.getPVCoordinates().getVelocity(), state2.getPVCoordinates().getVelocity());
1031     }
1032 
1033     private double calculateAttitudeDelta(SpacecraftState state1, SpacecraftState state2) {
1034         return Rotation.distance(state1.getAttitude().getRotation(), state2.getAttitude().getRotation());
1035     }
1036 
1037 }