1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
111
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
123 final SpacecraftStateInterpolator defaultStateInterpolator =
124 (SpacecraftStateInterpolator) defaultEphemeris.getStateInterpolator();
125
126
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
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
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
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
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
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
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
216
217
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
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
237 final AbsoluteDate referenceDate = new AbsoluteDate();
238 Mockito.when(firstState.getDate()).thenReturn(referenceDate);
239 Mockito.when(firstCovariance.getDate()).thenReturn(referenceDate.shiftedBy(1));
240
241
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
248 @SuppressWarnings("unchecked")
249 final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator =
250 Mockito.mock(TimeInterpolator.class);
251
252
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
266
267
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
279 final StateCovariance firstCovariance = Mockito.mock(StateCovariance.class);
280
281 final List<StateCovariance> covariances = new ArrayList<>();
282 covariances.add(firstCovariance);
283
284
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
291 @SuppressWarnings("unchecked")
292 final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator =
293 Mockito.mock(TimeInterpolator.class);
294
295
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
308
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
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
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
335 final AbsoluteDate initialDate = new AbsoluteDate();
336 final Orbit initialOrbit = TestUtils.getDefaultOrbit(initialDate);
337
338
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
347 final Optional<StateCovariance> optionalCovariance = ephemeris.getCovariance(Mockito.mock(AbsoluteDate.class));
348
349
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
359 final AbsoluteDate initialDate = new AbsoluteDate();
360 final Orbit initialOrbit = TestUtils.getDefaultOrbit(initialDate);
361
362
363 final AbsoluteDate propDate = initialDate.shiftedBy(0.5);
364 final SpacecraftState mockExpectedState = Mockito.mock(SpacecraftState.class);
365
366
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
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
390 final SpacecraftState propState = ephemeris.basicPropagate(propDate);
391
392
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
416 final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
417
418
419 Ephemeris ephemPropagator = new Ephemeris(states, interpolator, new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
420 Assertions.assertEquals(0, ephemPropagator.getManagedAdditionalStates().length);
421
422
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
430
431
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
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
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
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
495 final List<SpacecraftState> propagatedStates = new ArrayList<>();
496
497 propagator.setStepHandler(60, propagatedStates::add);
498 propagator.propagate(initialDate.shiftedBy(2 * 86400.0));
499
500
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
508 ephemeris.setAttitudeProvider(attitudeSequence);
509 attitudeSequence.registerSwitchEvents(ephemeris);
510
511
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
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
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
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
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
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
682 final int nbInterpolationPoints = 5;
683 final TimeInterpolator<SpacecraftState> stateInterpolator =
684 new SpacecraftStateInterpolator(nbInterpolationPoints, inertialFrame, inertialFrame);
685
686
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
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
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
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
792 AbsolutePVCoordinatesTest.assertPV(propagatedPV, interpolatedPV, 1e-8);
793
794
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
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
816 }
817 }
818
819 @Test
820 public void testIssue662() {
821 setUp();
822
823
824 int numberOfIntervals = 1440;
825 double deltaT = finalDate.durationFrom(initDate) / ((double) numberOfIntervals);
826
827
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
837
838 final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
839
840 Ephemeris ephemPropagator = new Ephemeris(states, interpolator);
841
842
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
848 ephemPropagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
849
850
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
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
872 int numberOfIntervals = 1440;
873 double deltaT = finalDate.durationFrom(initDate) / ((double) numberOfIntervals);
874
875
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
882
883 final TimeInterpolator<SpacecraftState> interpolator = new SpacecraftStateInterpolator(inertialFrame);
884
885 Ephemeris ephemPropagator = new Ephemeris(states, interpolator);
886
887
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
897 ephemPropagator.setAttitudeProvider(new LofOffset(inertialFrame, LOFType.LVLH_CCSDS));
898
899
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
909 @Test
910 public void testIssue949() {
911
912 final AbsoluteDate initialDate = new AbsoluteDate();
913 final Orbit initialOrbit = TestUtils.getDefaultOrbit(initialDate);
914
915
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
924 final AdditionalStateProvider additionalStateProvider = TestUtils.getAdditionalProviderWithInit();
925 ephemeris.addAdditionalStateProvider(additionalStateProvider);
926
927
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
936
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
943 Propagator propagator = new KeplerianPropagator(orbit);
944
945
946 List<SpacecraftState> states = new ArrayList<>();
947 propagator.getMultiplexer().add(10, states::add);
948
949
950 propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY * 7));
951
952
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
964 Ephemeris ephemeris = new Ephemeris(states, 4);
965
966
967 ephemeris.addEventDetector(detector);
968
969
970 ephemeris.propagate(ephemeris.getMinDate(), ephemeris.getMaxDate());
971 }
972
973
974 @Test
975 void testMinInterpolationPoints() {
976
977 final AbsoluteDate initialDate = new AbsoluteDate();
978 final Orbit initialOrbit = TestUtils.getDefaultOrbit(initialDate);
979
980
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
989 final AbsoluteDate t = ephemeris.getMaxDate();
990 final SpacecraftState actual = ephemeris.propagate(t);
991
992
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 }