1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.events;
18
19 import java.lang.reflect.Array;
20 import java.util.Locale;
21 import java.util.function.Function;
22
23 import org.hamcrest.CoreMatchers;
24 import org.hamcrest.MatcherAssert;
25 import org.hipparchus.CalculusFieldElement;
26 import org.hipparchus.Field;
27 import org.hipparchus.exception.LocalizedCoreFormats;
28 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
29 import org.hipparchus.ode.FieldODEIntegrator;
30 import org.hipparchus.ode.events.Action;
31 import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaFieldIntegrator;
32 import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
33 import org.hipparchus.util.Binary64;
34 import org.hipparchus.util.Binary64Field;
35 import org.hipparchus.util.FastMath;
36 import org.junit.jupiter.api.Assertions;
37 import org.junit.jupiter.api.BeforeEach;
38 import org.junit.jupiter.api.Test;
39 import org.mockito.Mockito;
40 import org.orekit.Utils;
41 import org.orekit.errors.OrekitException;
42 import org.orekit.frames.Frame;
43 import org.orekit.frames.FramesFactory;
44 import org.orekit.orbits.FieldCircularOrbit;
45 import org.orekit.orbits.FieldEquinoctialOrbit;
46 import org.orekit.orbits.FieldKeplerianOrbit;
47 import org.orekit.orbits.FieldOrbit;
48 import org.orekit.orbits.OrbitType;
49 import org.orekit.orbits.PositionAngleType;
50 import org.orekit.propagation.FieldPropagator;
51 import org.orekit.propagation.FieldSpacecraftState;
52 import org.orekit.propagation.ToleranceProvider;
53 import org.orekit.propagation.analytical.FieldKeplerianPropagator;
54 import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
55 import org.orekit.propagation.events.handlers.FieldEventHandler;
56 import org.orekit.propagation.events.handlers.FieldStopOnEvent;
57 import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
58 import org.orekit.propagation.numerical.FieldNumericalPropagator;
59 import org.orekit.propagation.sampling.FieldOrekitFixedStepHandler;
60 import org.orekit.time.AbsoluteDate;
61 import org.orekit.time.FieldAbsoluteDate;
62 import org.orekit.time.TimeScale;
63 import org.orekit.time.TimeScalesFactory;
64 import org.orekit.utils.Constants;
65 import org.orekit.utils.FieldPVCoordinates;
66 import org.orekit.utils.FieldPVCoordinatesProvider;
67
68 class FieldEventDetectorTest {
69
70 private double mu;
71
72 @Test
73 @SuppressWarnings("unchecked")
74 void testFinish() {
75
76 final FinishingHandler handler = new FinishingHandler();
77 final FieldEventDetector<?> detector = new DummyDetector(new FieldEventDetectionSettings<>(1.0, Binary64.ONE, 100), handler);
78
79 detector.finish(Mockito.mock(FieldSpacecraftState.class));
80
81 Assertions.assertTrue(handler.isFinished);
82 }
83
84 private static class FinishingHandler extends FieldContinueOnEvent<Binary64> {
85 boolean isFinished = false;
86
87 @Override
88 public void finish(FieldSpacecraftState<Binary64> finalState, FieldEventDetector<Binary64> detector) {
89 isFinished = true;
90 }
91 }
92
93 private static class DummyDetector implements FieldEventDetector<Binary64> {
94
95 private final FieldEventDetectionSettings<Binary64> detectionSettings;
96 private final FieldEventHandler<Binary64> handler;
97
98 public DummyDetector(final FieldEventDetectionSettings<Binary64> detectionSettings,
99 final FieldEventHandler<Binary64> handler) {
100 this.detectionSettings = detectionSettings;
101 this.handler = handler;
102 }
103
104 public Binary64 g(final FieldSpacecraftState<Binary64> s) {
105 return s.getDate().getField().getZero();
106 }
107
108 @Override
109 public FieldEventHandler<Binary64> getHandler() {
110 return handler;
111 }
112
113 @Override
114 public FieldEventDetectionSettings<Binary64> getDetectionSettings() {
115 return detectionSettings;
116 }
117
118 }
119
120 @Test
121 @SuppressWarnings("unchecked")
122 void testGetDetectionSettings() {
123
124 final FieldAdaptableInterval<Binary64> mockedInterval = Mockito.mock(FieldAdaptableInterval.class);
125 final FieldEventDetectionSettings<Binary64> settings = new FieldEventDetectionSettings<>(mockedInterval, Binary64.ONE, 10);
126 final FieldEventDetector<Binary64> detector = new DummyDetector(settings, null);
127
128 final FieldEventDetectionSettings<Binary64> actualSettings = detector.getDetectionSettings();
129
130 Assertions.assertEquals(mockedInterval, actualSettings.getMaxCheckInterval());
131 Assertions.assertEquals(settings.getMaxIterationCount(), actualSettings.getMaxIterationCount());
132 Assertions.assertEquals(settings.getThreshold(), actualSettings.getThreshold());
133 }
134
135 @Test
136 void testEventHandlerInit() {
137 doTestEventHandlerInit(Binary64Field.getInstance());
138 }
139
140 private <T extends CalculusFieldElement<T>> void doTestEventHandlerInit(Field<T> field) {
141
142 final T zero = field.getZero();
143 final TimeScale utc = TimeScalesFactory.getUTC();
144 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668),
145 zero.add(3492467.56),
146 zero.add(-25767.257));
147 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.848),
148 zero.add(942.781),
149 zero.add(7435.922));
150 final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc);
151 final FieldOrbit<T> orbit = new FieldCircularOrbit<>(new FieldPVCoordinates<>(position, velocity),
152 FramesFactory.getEME2000(), date, zero.add(mu));
153
154 final boolean[] eventOccurred = new boolean[1];
155 FieldEventHandler<T> handler = new FieldEventHandler<T>() {
156 private boolean initCalled;
157 @Override
158 public Action eventOccurred(FieldSpacecraftState<T> s,
159 FieldEventDetector<T> detector,
160 boolean increasing) {
161 if (!initCalled) {
162 throw new RuntimeException("init() not called before eventOccurred()");
163 }
164 eventOccurred[0] = true;
165 return Action.STOP;
166 }
167
168 @Override
169 public void init(final FieldSpacecraftState<T> initialState,
170 final FieldAbsoluteDate<T> target,
171 final FieldEventDetector<T> detector) {
172 initCalled = true;
173 }
174 };
175
176 FieldPropagator<T> propagator = new FieldKeplerianPropagator<>(orbit);
177 T stepSize = zero.add(60.0);
178 final FieldDateDetector<T> detector = new FieldDateDetector<>(field, date.shiftedBy(stepSize.multiply(5.25))).withHandler(handler);
179 propagator.addEventDetector(detector);
180 propagator.propagate(date.shiftedBy(stepSize.multiply(10)));
181 Assertions.assertTrue(eventOccurred[0]);
182
183 }
184
185 @Test
186 void testBasicScheduling() {
187 doTestBasicScheduling(Binary64Field.getInstance());
188 }
189
190 private <T extends CalculusFieldElement<T>> void doTestBasicScheduling(Field<T> field) {
191
192 final T zero = field.getZero();
193 final TimeScale utc = TimeScalesFactory.getUTC();
194 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668),
195 zero.add(3492467.56),
196 zero.add(-25767.257));
197 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.848),
198 zero.add(942.781),
199 zero.add(7435.922));
200 final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc);
201 final FieldOrbit<T> orbit = new FieldCircularOrbit<>(new FieldPVCoordinates<>(position, velocity),
202 FramesFactory.getEME2000(), date, zero.add(mu));
203
204 FieldPropagator<T> propagator = new FieldKeplerianPropagator<>(orbit);
205 T stepSize = zero.add(60.0);
206 OutOfOrderChecker<T> checker = new OutOfOrderChecker<>(stepSize);
207 FieldDateDetector<T> detector = new FieldDateDetector<>(field, date.shiftedBy(stepSize.multiply(5.25))).withHandler(checker);
208 propagator.addEventDetector(detector);
209 propagator.setStepHandler(stepSize, checker);
210 propagator.propagate(date.shiftedBy(stepSize.multiply(10)));
211 Assertions.assertTrue(checker.outOfOrderCallDetected());
212
213 }
214
215 private static class OutOfOrderChecker<T extends CalculusFieldElement<T>>
216 implements FieldEventHandler<T>, FieldOrekitFixedStepHandler<T> {
217
218 private FieldAbsoluteDate<T> triggerDate;
219 private boolean outOfOrderCallDetected;
220 private final T stepSize;
221
222 public OutOfOrderChecker(final T stepSize) {
223 triggerDate = null;
224 outOfOrderCallDetected = false;
225 this.stepSize = stepSize;
226 }
227
228 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> detector, boolean increasing) {
229 triggerDate = s.getDate();
230 return Action.CONTINUE;
231 }
232
233 public void handleStep(FieldSpacecraftState<T> currentState) {
234
235
236
237 if (triggerDate != null) {
238 double dt = currentState.getDate().durationFrom(triggerDate).getReal();
239 if (dt < 0) {
240 outOfOrderCallDetected = true;
241 Assertions.assertTrue(FastMath.abs(dt) < (2 * stepSize.getReal()));
242 }
243 }
244 }
245
246 public boolean outOfOrderCallDetected() {
247 return outOfOrderCallDetected;
248 }
249
250 }
251
252 @Test
253 void testIssue108Numerical() {
254 doTestIssue108Numerical(Binary64Field.getInstance());
255 }
256
257 private <T extends CalculusFieldElement<T>> void doTestIssue108Numerical(Field<T> field) {
258 final T zero = field.getZero();
259 final TimeScale utc = TimeScalesFactory.getUTC();
260 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668),
261 zero.add(3492467.56),
262 zero.add(-25767.257));
263 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.848),
264 zero.add(942.781),
265 zero.add(7435.922));
266 final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc);
267 final FieldOrbit<T> orbit = new FieldCircularOrbit<>(new FieldPVCoordinates<>(position, velocity),
268 FramesFactory.getEME2000(), date, zero.add(mu));
269 final T step = zero.add(60.0);
270 final int n = 100;
271 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, new ClassicalRungeKuttaFieldIntegrator<>(field, step));
272 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
273 propagator.resetInitialState(new FieldSpacecraftState<>(orbit));
274 GCallsCounter<T> counter = new GCallsCounter<>(FieldAdaptableInterval.of(100000.0), zero.add(1.0e-6), 20,
275 new FieldStopOnEvent<>());
276 propagator.addEventDetector(counter);
277 propagator.propagate(date.shiftedBy(step.multiply(n)));
278 Assertions.assertEquals(n + 1, counter.getCount());
279 }
280
281 @Test
282 void testIssue108Analytical() {
283 doTestIssue108Analytical(Binary64Field.getInstance());
284 }
285
286 private <T extends CalculusFieldElement<T>> void doTestIssue108Analytical(Field<T> field) {
287 final T zero = field.getZero();
288 final TimeScale utc = TimeScalesFactory.getUTC();
289 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668),
290 zero.add(3492467.56),
291 zero.add(-25767.257));
292 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.848),
293 zero.add(942.781),
294 zero.add(7435.922));
295 final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc);
296 final FieldOrbit<T> orbit = new FieldCircularOrbit<>(new FieldPVCoordinates<>(position, velocity),
297 FramesFactory.getEME2000(), date, zero.add(mu));
298 final T step = zero.add(60.0);
299 final int n = 100;
300 FieldKeplerianPropagator<T> propagator = new FieldKeplerianPropagator<>(orbit);
301 GCallsCounter<T> counter = new GCallsCounter<>(FieldAdaptableInterval.of(100000.0), zero.add(1.0e-6), 20,
302 new FieldStopOnEvent<>());
303 propagator.addEventDetector(counter);
304 propagator.setStepHandler(step, currentState -> {});
305 propagator.propagate(date.shiftedBy(step.multiply(n)));
306
307 Assertions.assertEquals(2, counter.getCount());
308 }
309
310 private static class GCallsCounter<T extends CalculusFieldElement<T>> extends FieldAbstractDetector<GCallsCounter<T>, T> {
311
312 private int count;
313
314 public GCallsCounter(final FieldAdaptableInterval<T> maxCheck, final T threshold,
315 final int maxIter, final FieldEventHandler<T> handler) {
316 super(new FieldEventDetectionSettings<>(maxCheck, threshold, maxIter), handler);
317 count = 0;
318 }
319
320 protected GCallsCounter<T> create(final FieldEventDetectionSettings<T> detectionSettings,
321 final FieldEventHandler<T> newHandler) {
322 return new GCallsCounter<>(detectionSettings.getMaxCheckInterval(), detectionSettings.getThreshold(),
323 detectionSettings.getMaxIterationCount(), newHandler);
324 }
325
326 public int getCount() {
327 return count;
328 }
329
330 public T g(FieldSpacecraftState<T> s) {
331 count++;
332 return s.getMass().getField().getZero().add(1.0);
333 }
334
335 }
336
337 @Test
338 void testNoisyGFunction() {
339 doTestNoisyGFunction(Binary64Field.getInstance());
340 }
341
342 private <T extends CalculusFieldElement<T>> void doTestNoisyGFunction(Field<T> field) {
343
344 final T zero = field.getZero();
345
346
347 Frame eme2000 = FramesFactory.getEME2000();
348 TimeScale utc = TimeScalesFactory.getUTC();
349 FieldAbsoluteDate<T> initialDate = new FieldAbsoluteDate<>(field, 2011, 5, 11, utc);
350 FieldAbsoluteDate<T> startDate = new FieldAbsoluteDate<>(field, 2032, 10, 17, utc);
351 @SuppressWarnings("unchecked")
352 FieldAbsoluteDate<T>[] interruptDates =
353 ( FieldAbsoluteDate<T>[]) Array.newInstance(FieldAbsoluteDate.class, 1);
354 interruptDates[0] = new FieldAbsoluteDate<>(field, 2032, 10, 18, utc);
355 FieldAbsoluteDate<T> targetDate = new FieldAbsoluteDate<>(field, 2211, 5, 11, utc);
356 FieldKeplerianPropagator<T> k1 =
357 new FieldKeplerianPropagator<>(new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(new FieldVector3D<>(zero.add(4008462.4706055815),
358 zero.add(-3155502.5373837613),
359 zero.add(-5044275.9880020910)),
360 new FieldVector3D<>(zero.add(-5012.9298276860990),
361 zero.add(1920.3567095973078),
362 zero.add(-5172.7403501801580))),
363 eme2000, initialDate, zero.add(Constants.WGS84_EARTH_MU)));
364 FieldKeplerianPropagator<T> k2 =
365 new FieldKeplerianPropagator<>(new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(new FieldVector3D<>(zero.add(4008912.4039522274),
366 zero.add(-3155453.3125615157),
367 zero.add(-5044297.6484738905)),
368 new FieldVector3D<>(zero.add(-5012.5883854112530),
369 zero.add(1920.6332221785074),
370 zero.add(-5172.2177085540500))),
371 eme2000, initialDate, zero.add(Constants.WGS84_EARTH_MU)));
372 k2.addEventDetector(new FieldCloseApproachDetector<>(FieldAdaptableInterval.of(2015.243454166727), zero.add(0.0001), 100,
373 new FieldContinueOnEvent<>(),
374 k1));
375 k2.addEventDetector(new FieldDateDetector<>(field, interruptDates).
376 withMaxCheck(FieldAdaptableInterval.of(Constants.JULIAN_DAY)).
377 withThreshold(field.getZero().newInstance(1.0e-6)));
378 FieldSpacecraftState<T> s = k2.propagate(startDate, targetDate);
379 Assertions.assertEquals(0.0, interruptDates[0].durationFrom(s.getDate()).getReal(), 1.1e-6);
380 }
381
382 private static class FieldCloseApproachDetector<T extends CalculusFieldElement<T>>
383 extends FieldAbstractDetector<FieldCloseApproachDetector<T>, T> {
384
385 private final FieldPVCoordinatesProvider<T> provider;
386
387 public FieldCloseApproachDetector(FieldAdaptableInterval<T> maxCheck, T threshold,
388 final int maxIter, final FieldEventHandler<T> handler,
389 FieldPVCoordinatesProvider<T> provider) {
390 super(new FieldEventDetectionSettings<>(maxCheck, threshold, maxIter), handler);
391 this.provider = provider;
392 }
393
394 public T g(final FieldSpacecraftState<T> s) {
395 FieldPVCoordinates<T> pv1 = provider.getPVCoordinates(s.getDate(), s.getFrame());
396 FieldPVCoordinates<T> pv2 = s.getPVCoordinates();
397 FieldVector3D<T> deltaP = pv1.getPosition().subtract(pv2.getPosition());
398 FieldVector3D<T> deltaV = pv1.getVelocity().subtract(pv2.getVelocity());
399 return FieldVector3D.dotProduct(deltaP.normalize(), deltaV);
400 }
401
402 protected FieldCloseApproachDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
403 final FieldEventHandler<T> newHandler) {
404 return new FieldCloseApproachDetector<>(detectionSettings.getMaxCheckInterval(), detectionSettings.getThreshold(),
405 detectionSettings.getMaxIterationCount(), newHandler, provider);
406 }
407
408 }
409
410 @Test
411 void testWrappedException() {
412 doTestWrappedException(Binary64Field.getInstance());
413 }
414
415 private <T extends CalculusFieldElement<T>> void doTestWrappedException(Field<T> field) {
416 final T zero = field.getZero();
417 final Throwable dummyCause = new RuntimeException();
418 try {
419
420 Frame eme2000 = FramesFactory.getEME2000();
421 TimeScale utc = TimeScalesFactory.getUTC();
422 final FieldAbsoluteDate<T> initialDate = new FieldAbsoluteDate<>(field, 2011, 5, 11, utc);
423 final FieldAbsoluteDate<T> exceptionDate = initialDate.shiftedBy(3600.0);
424 FieldKeplerianPropagator<T> k =
425 new FieldKeplerianPropagator<>(new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(new FieldVector3D<>(zero.add(4008462.4706055815),
426 zero.add(-3155502.5373837613),
427 zero.add(-5044275.9880020910)),
428 new FieldVector3D<>(zero.add(-5012.9298276860990),
429 zero.add(1920.3567095973078),
430 zero.add(-5172.7403501801580))),
431 eme2000, initialDate, zero.add(Constants.WGS84_EARTH_MU)));
432 k.addEventDetector(new FieldDateDetector<T>(field, initialDate.shiftedBy(Constants.JULIAN_DAY)) {
433 @Override
434 public T g(final FieldSpacecraftState<T> s) {
435 final T dt = s.getDate().durationFrom(exceptionDate);
436 if (dt.abs().getReal() < 1.0) {
437 throw new OrekitException(dummyCause, LocalizedCoreFormats.SIMPLE_MESSAGE, "dummy");
438 }
439 return dt;
440 }
441 });
442 k.propagate(initialDate.shiftedBy(Constants.JULIAN_YEAR));
443 Assertions.fail("an exception should have been thrown");
444 } catch (OrekitException oe) {
445 Assertions.assertSame(OrekitException.class, oe.getClass());
446 Assertions.assertSame(dummyCause, oe.getCause().getCause());
447 String expected = "failed to find root between 2011-05-11T00:00:00.000Z " +
448 "(g=-3.6E3) and 2012-05-10T06:00:00.000Z (g=3.1554E7)\n" +
449 "Last iteration at 2011-05-11T01:00:00.000Z (g=-3.6E3)";
450 MatcherAssert.assertThat(oe.getMessage(Locale.US),
451 CoreMatchers.containsString(expected));
452 }
453 }
454
455 @Test
456 void testDefaultMethods() {
457 doTestDefaultMethods(Binary64Field.getInstance());
458 }
459
460 private <T extends CalculusFieldElement<T>> void doTestDefaultMethods(final Field<T> field) {
461 FieldEventDetector<T> dummyDetector = new FieldEventDetector<T>() {
462
463 @Override
464 public FieldEventDetectionSettings<T> getDetectionSettings() {
465 return new FieldEventDetectionSettings<>(FieldAdaptableInterval.of(60), field.getZero().newInstance(1e-10), 100);
466 }
467
468 @Override
469 public T g(FieldSpacecraftState<T> s) {
470 return s.getDate().durationFrom(AbsoluteDate.J2000_EPOCH);
471 }
472
473 @Override
474 public FieldEventHandler<T> getHandler() {
475 return (state, detector, increasing) -> Action.RESET_STATE;
476 }
477 };
478
479
480 dummyDetector.init(null, null);
481
482
483 FieldSpacecraftState<T> s = new FieldSpacecraftState<>(new FieldKeplerianOrbit<>(field.getZero().add(7e6),
484 field.getZero().add(0.01),
485 field.getZero().add(0.3),
486 field.getZero().add(0),
487 field.getZero().add(0),
488 field.getZero().add(0), PositionAngleType.TRUE,
489 FramesFactory.getEME2000(),
490 FieldAbsoluteDate.getJ2000Epoch(field),
491 field.getZero().add(Constants.EIGEN5C_EARTH_MU)));
492 Assertions.assertSame(s, dummyDetector.getHandler().resetState(dummyDetector, s));
493
494 }
495
496 @Test
497 void testForwardAnalytical() {
498 doTestScheduling(Binary64Field.getInstance(), 0.0, 1.0, 21, this::buildAnalytical);
499 }
500
501 @Test
502 void testBackwardAnalytical() {
503 doTestScheduling(Binary64Field.getInstance(), 1.0, 0.0, 21, this::buildAnalytical);
504 }
505
506 @Test
507 void testForwardNumerical() {
508 doTestScheduling(Binary64Field.getInstance(), 0.0, 1.0, 23, this::buildNumerical);
509 }
510
511 @Test
512 void testBackwardNumerical() {
513 doTestScheduling(Binary64Field.getInstance(), 1.0, 0.0, 23, this::buildNumerical);
514 }
515
516 private <T extends CalculusFieldElement<T>> FieldPropagator<T> buildAnalytical(final FieldOrbit<T> orbit) {
517 return new FieldKeplerianPropagator<>(orbit);
518 }
519
520 private <T extends CalculusFieldElement<T>> FieldPropagator<T> buildNumerical(final FieldOrbit<T> orbit) {
521 Field<T> field = orbit.getDate().getField();
522 OrbitType type = OrbitType.CARTESIAN;
523 double[][] tol = ToleranceProvider.getDefaultToleranceProvider(0.0001).getTolerances(orbit, type);
524 FieldODEIntegrator<T> integrator = new DormandPrince853FieldIntegrator<>(field, 0.0001, 10.0, tol[0], tol[1]);
525 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
526 propagator.setOrbitType(type);
527 propagator.setInitialState(new FieldSpacecraftState<>(orbit));
528 return propagator;
529 }
530
531 private <T extends CalculusFieldElement<T>> void doTestScheduling(final Field<T> field,
532 final double start, final double stop, final int expectedCalls,
533 final Function<FieldOrbit<T>, FieldPropagator<T>> propagatorBuilder) {
534
535
536 Frame eme2000 = FramesFactory.getEME2000();
537 TimeScale utc = TimeScalesFactory.getUTC();
538 final FieldAbsoluteDate<T> initialDate = new FieldAbsoluteDate<>(field, 2011, 5, 11, utc);
539 final FieldOrbit<T> orbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(new FieldVector3D<>(field.getZero().newInstance(4008462.4706055815),
540 field.getZero().newInstance(-3155502.5373837613),
541 field.getZero().newInstance(-5044275.9880020910)),
542 new FieldVector3D<>(field.getZero().newInstance(-5012.9298276860990),
543 field.getZero().newInstance(1920.3567095973078),
544 field.getZero().newInstance(-5172.7403501801580))),
545 eme2000, initialDate, field.getZero().newInstance(Constants.WGS84_EARTH_MU));
546 FieldPropagator<T> propagator = propagatorBuilder.apply(orbit.shiftedBy(start));
547
548
549
550 final ScheduleChecker<T> checker = new ScheduleChecker<>(initialDate.shiftedBy(start),
551 initialDate.shiftedBy(stop));
552 propagator.setStepHandler(interpolator -> checker.callDate(interpolator.getCurrentState().getDate()));
553
554 for (int i = 0; i < 10; ++i) {
555 FieldDateDetector<T> detector = new FieldDateDetector<>(field, initialDate.shiftedBy(0.0625 * (i + 1))).
556 withHandler((state, d, increasing) -> {
557 checker.callDate(state.getDate());
558 return Action.CONTINUE;
559 });
560 propagator.addEventDetector(detector);
561 }
562
563 propagator.propagate(initialDate.shiftedBy(start), initialDate.shiftedBy(stop));
564
565 Assertions.assertEquals(expectedCalls, checker.calls);
566
567 }
568
569
570 private static class ScheduleChecker<T extends CalculusFieldElement<T>> {
571
572 private final FieldAbsoluteDate<T> start;
573 private final FieldAbsoluteDate<T> stop;
574 private FieldAbsoluteDate<T> last;
575 private int calls;
576
577 ScheduleChecker(final FieldAbsoluteDate<T> start, final FieldAbsoluteDate<T> stop) {
578 this.start = start;
579 this.stop = stop;
580 this.last = null;
581 this.calls = 0;
582 }
583
584 void callDate(final FieldAbsoluteDate<T> date) {
585 if (last != null) {
586
587 if (start.isBefore(stop)) {
588
589 Assertions.assertTrue(date.isAfterOrEqualTo(start));
590 Assertions.assertTrue(date.isBeforeOrEqualTo(stop));
591 Assertions.assertTrue(date.isAfterOrEqualTo(last));
592 } else {
593
594 Assertions.assertTrue(date.isBeforeOrEqualTo(start));
595 Assertions.assertTrue(date.isAfterOrEqualTo(stop));
596 Assertions.assertTrue(date.isBeforeOrEqualTo(last));
597 }
598 }
599 last = date;
600 ++calls;
601 }
602
603 }
604
605 @BeforeEach
606 public void setUp() {
607 Utils.setDataRoot("regular-data");
608 mu = Constants.EIGEN5C_EARTH_MU;
609 }
610
611 }
612