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.time.Instant;
21 import java.time.LocalDateTime;
22 import java.time.ZoneId;
23
24 import org.hipparchus.CalculusFieldElement;
25 import org.hipparchus.Field;
26 import org.hipparchus.complex.Complex;
27 import org.hipparchus.complex.ComplexField;
28 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
29 import org.hipparchus.ode.events.Action;
30 import org.hipparchus.ode.nonstiff.AdaptiveStepsizeFieldIntegrator;
31 import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
32 import org.hipparchus.util.Binary64;
33 import org.hipparchus.util.Binary64Field;
34 import org.hipparchus.util.MathArrays;
35 import org.junit.jupiter.api.Assertions;
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.Test;
38 import org.mockito.Mockito;
39 import org.orekit.Utils;
40 import org.orekit.frames.FramesFactory;
41 import org.orekit.orbits.FieldEquinoctialOrbit;
42 import org.orekit.orbits.FieldOrbit;
43 import org.orekit.orbits.OrbitType;
44 import org.orekit.propagation.FieldPropagator;
45 import org.orekit.propagation.FieldSpacecraftState;
46 import org.orekit.propagation.analytical.tle.FieldTLE;
47 import org.orekit.propagation.analytical.tle.FieldTLEPropagator;
48 import org.orekit.propagation.events.handlers.FieldContinueOnEvent;
49 import org.orekit.propagation.events.handlers.FieldEventHandler;
50 import org.orekit.propagation.events.handlers.FieldStopOnEvent;
51 import org.orekit.propagation.integration.FieldAdditionalDerivativesProvider;
52 import org.orekit.propagation.integration.FieldCombinedDerivatives;
53 import org.orekit.propagation.numerical.FieldNumericalPropagator;
54 import org.orekit.propagation.sampling.FieldOrekitStepInterpolator;
55 import org.orekit.time.AbsoluteDate;
56 import org.orekit.time.FieldAbsoluteDate;
57 import org.orekit.time.FieldTimeStamped;
58 import org.orekit.time.TimeScalesFactory;
59 import org.orekit.utils.FieldPVCoordinates;
60
61 public class FieldDateDetectorTest {
62
63 private int evtno = 0;
64 private double minGap;
65 private double threshold;
66 private double dt;
67 private double mu;
68 private AbsoluteDate nodeDate;
69
70 @Test
71 void testSimpleTimer() {
72 doTestSimpleTimer(Binary64Field.getInstance());
73 }
74
75 @Test
76 void testEmbeddedTimer() {
77 doTestEmbeddedTimer(Binary64Field.getInstance());
78 }
79
80 @Test
81 void testAutoEmbeddedTimer() {
82 doTestAutoEmbeddedTimer(Binary64Field.getInstance());
83 }
84
85 @Test
86 void testExceptionTimer() {
87 Assertions.assertThrows(IllegalArgumentException.class, () -> {
88 doTestExceptionTimer(Binary64Field.getInstance());
89 });
90 }
91
92 @Test
93 void testGenericHandler() {
94 doTestGenericHandler(Binary64Field.getInstance());
95 }
96
97 @Test
98 @SuppressWarnings("unchecked")
99 void testGetDefaultDetectionSettings() {
100
101 final FieldDateDetector<Complex> fieldDateDetector = new FieldDateDetector<>(FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance()));
102
103 final FieldEventDetectionSettings<Complex> fieldEventDetectionSettings = fieldDateDetector.getDetectionSettings();
104
105 Assertions.assertEquals(DateDetector.DEFAULT_THRESHOLD, fieldEventDetectionSettings.getThreshold().getReal());
106 Assertions.assertEquals(DateDetector.DEFAULT_MAX_ITER, fieldEventDetectionSettings.getMaxIterationCount());
107 Assertions.assertEquals(DateDetector.DEFAULT_MAX_CHECK, fieldEventDetectionSettings.getMaxCheckInterval()
108 .currentInterval(Mockito.mock(FieldSpacecraftState.class), true));
109 }
110
111 @Test
112 void testConstructor() {
113
114 final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
115 final Binary64Field field = Binary64Field.getInstance();
116 final FieldAbsoluteDate<Binary64> fieldDate = new FieldAbsoluteDate<>(field, date);
117
118 final FieldDateDetector<Binary64> fieldDateDetector = new FieldDateDetector<>(fieldDate);
119
120 Assertions.assertEquals(fieldDate, fieldDateDetector.getDate());
121 final EventDetectionSettings expectedSettings = new DateDetector().getDetectionSettings();
122 Assertions.assertEquals(expectedSettings.getThreshold(), fieldDateDetector.getThreshold().getReal());
123 Assertions.assertEquals(expectedSettings.getMaxIterationCount(), fieldDateDetector.getMaxIterationCount());
124 }
125
126 @Test
127 void testDependsOnlyOnTime() {
128
129 final FieldDateDetector<Binary64> detector = new FieldDateDetector<>(FieldAbsoluteDate.getArbitraryEpoch(Binary64Field.getInstance()));
130
131 final boolean value = detector.dependsOnTimeOnly();
132
133 Assertions.assertTrue(value);
134 }
135
136 @Test
137 void testIssue935() {
138 doTestIssue935(Binary64Field.getInstance());
139 }
140
141 private <T extends CalculusFieldElement<T>> void doTestSimpleTimer(final Field<T> field) {
142 T zero = field.getZero();
143 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
144 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
145 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
146 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
147 FramesFactory.getEME2000(), iniDate, zero.add(mu));
148 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
149 double[] absTolerance = {
150 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
151 };
152 double[] relTolerance = {
153 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
154 };
155 AdaptiveStepsizeFieldIntegrator<T> integrator =
156 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
157 integrator.setInitialStepSize(60);
158 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
159 propagator.addAdditionalDerivativesProvider(new FieldAdditionalDerivativesProvider<T>() {
160 public String getName() { return "dummy"; }
161 public int getDimension() { return 1; }
162 public FieldCombinedDerivatives<T> combinedDerivatives(FieldSpacecraftState<T> s) {
163 return new FieldCombinedDerivatives<>(MathArrays.buildArray(field, 1), null);
164 }
165 });
166 propagator.getMultiplexer().add(interpolator -> {
167 FieldSpacecraftState<T> prev = interpolator.getPreviousState();
168 FieldSpacecraftState<T> curr = interpolator.getCurrentState();
169 T dt = curr.getDate().durationFrom(prev.getDate());
170 FieldOrekitStepInterpolator<T> restricted =
171 interpolator.restrictStep(prev.shiftedBy(dt.multiply(+0.25)),
172 curr.shiftedBy(dt.multiply(-0.25)));
173 FieldSpacecraftState<T> restrictedPrev = restricted.getPreviousState();
174 FieldSpacecraftState<T> restrictedCurr = restricted.getCurrentState();
175 T restrictedDt = restrictedCurr.getDate().durationFrom(restrictedPrev.getDate());
176 Assertions.assertEquals(dt.multiply(0.5).getReal(), restrictedDt.getReal(), 1.0e-10);
177 });
178 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
179 propagator.setInitialState(initialState.addAdditionalData("dummy", MathArrays.buildArray(field, 1)));
180
181 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(2.0*dt))).
182 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
183 Assertions.assertEquals(2 * dt, dateDetector.getDate().durationFrom(iniDate).getReal(), 1.0e-10);
184 propagator.addEventDetector(dateDetector);
185 final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
186
187 Assertions.assertEquals(2.0*dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
188 }
189
190
191 private <T extends CalculusFieldElement<T>> void doTestEmbeddedTimer(Field<T> field) {
192 T zero = field.getZero();
193 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
194 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
195 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
196 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
197 FramesFactory.getEME2000(), iniDate, zero.add(mu));
198 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
199 double[] absTolerance = {
200 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
201 };
202 double[] relTolerance = {
203 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
204 };
205 AdaptiveStepsizeFieldIntegrator<T> integrator =
206 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
207 integrator.setInitialStepSize(60);
208 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
209 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
210 propagator.setInitialState(initialState);
211 @SuppressWarnings("unchecked")
212 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 0)).
213 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
214 Assertions.assertNull(dateDetector.getDate());
215 FieldEventDetector<T> nodeDetector = new FieldNodeDetector<>(iniOrbit, iniOrbit.getFrame()).
216 withHandler(new FieldContinueOnEvent<T>() {
217 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> nd, boolean increasing) {
218 if (increasing) {
219 nodeDate = s.getDate().toAbsoluteDate();
220 dateDetector.addEventDate(s.getDate().shiftedBy(dt));
221 }
222 return Action.CONTINUE;
223 }
224 });
225
226 propagator.addEventDetector(nodeDetector);
227 propagator.addEventDetector(dateDetector);
228 final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
229
230 Assertions.assertEquals(dt, finalState.getDate().durationFrom(nodeDate).getReal(), threshold);
231 }
232
233
234 private <T extends CalculusFieldElement<T>> void doTestAutoEmbeddedTimer(Field<T> field) {
235 T zero = field.getZero();
236 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
237 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
238 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
239 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
240 FramesFactory.getEME2000(), iniDate, zero.add(mu));
241 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
242 double[] absTolerance = {
243 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
244 };
245 double[] relTolerance = {
246 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
247 };
248 AdaptiveStepsizeFieldIntegrator<T> integrator =
249 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
250 integrator.setInitialStepSize(60);
251 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
252 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
253 propagator.setInitialState(initialState);
254
255 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(-dt))).
256 withMinGap(minGap).
257 withThreshold(field.getZero().newInstance(threshold)).
258 withHandler(new FieldContinueOnEvent<T >() {
259 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> dd, boolean increasing) {
260 FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(-dt);
261 ((FieldDateDetector<T>) dd).addEventDate(nextDate);
262 ++evtno;
263 return Action.CONTINUE;
264 }
265 });
266 propagator.addEventDetector(dateDetector);
267 propagator.propagate(iniDate.shiftedBy(-100.*dt));
268
269 Assertions.assertEquals(100, evtno);
270 }
271
272 private <T extends CalculusFieldElement<T>> void doTestExceptionTimer(Field<T> field) {
273 T zero = field.getZero();
274 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
275 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
276 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
277 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
278 FramesFactory.getEME2000(), iniDate, zero.add(mu));
279 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
280 double[] absTolerance = {
281 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
282 };
283 double[] relTolerance = {
284 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
285 };
286 AdaptiveStepsizeFieldIntegrator<T> integrator =
287 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
288 integrator.setInitialStepSize(60);
289 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
290 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
291 propagator.setInitialState(initialState);
292
293 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(dt))).
294 withMinGap(minGap).
295 withThreshold(field.getZero().newInstance(threshold)).
296 withHandler(new FieldContinueOnEvent<T>() {
297 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> dd, boolean increasing)
298 {
299 double step = (evtno % 2 == 0) ? 2.*minGap : minGap/2.;
300 FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(step);
301 ((FieldDateDetector<T>) dd).addEventDate(nextDate);
302 ++evtno;
303 return Action.CONTINUE;
304 }
305 });
306 propagator.addEventDetector(dateDetector);
307 propagator.propagate(iniDate.shiftedBy(100.*dt));
308 }
309
310
311
312
313
314 private <T extends CalculusFieldElement<T>> void doTestGenericHandler(Field<T> field) {
315 T zero = field.getZero();
316 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
317 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
318 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
319 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
320 FramesFactory.getEME2000(), iniDate, zero.add(mu));
321 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
322 double[] absTolerance = {
323 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
324 };
325 double[] relTolerance = {
326 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
327 };
328 AdaptiveStepsizeFieldIntegrator<T> integrator =
329 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
330 integrator.setInitialStepSize(60);
331 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
332 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
333 propagator.setInitialState(initialState);
334
335
336 final FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(dt))).
337 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
338
339 FieldEventHandler<T> handler = new FieldEventHandler<T>() {
340 @Override
341 public Action eventOccurred(FieldSpacecraftState<T> s,
342 FieldEventDetector<T> detector,
343 boolean increasing) {
344 return Action.STOP;
345 }
346
347 @Override
348 public FieldSpacecraftState<T> resetState(FieldEventDetector<T> detector,
349 FieldSpacecraftState<T> oldState) {
350 throw new RuntimeException("Should not be called");
351 }
352 };
353
354
355 final FieldDateDetector<T> dateDetector2;
356
357 dateDetector2 = dateDetector.withHandler(handler);
358
359 propagator.addEventDetector(dateDetector2);
360 FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100 * dt));
361
362
363 Assertions.assertEquals(dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
364 }
365
366 private <T extends CalculusFieldElement<T>> void doTestIssue935(Field<T> field) {
367
368
369 long start = 1570802400000L;
370 long end = 1570838399000L;
371
372
373 FieldTLE<T> tle = new FieldTLE<>(field,
374 "1 43197U 18015F 19284.07336221 .00000533 00000-0 24811-4 0 9998",
375 "2 43197 97.4059 50.1428 0017543 265.5429 181.0400 15.24136761 93779");
376 FieldPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(tle, tle.getParameters(field));
377
378
379 int maxCheck = (int) ((end - start) / 2000);
380 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, getAbsoluteDateFromTimestamp(field, start)).
381 withMinGap(maxCheck).
382 withThreshold(field.getZero().newInstance(1.0e-6)).
383 withHandler(new FieldStopOnEvent<>());
384 dateDetector.addEventDate(getAbsoluteDateFromTimestamp(field, end));
385
386
387 propagator.addEventDetector(dateDetector);
388
389
390 final FieldAbsoluteDate<T> startDate = getAbsoluteDateFromTimestamp(field, start);
391 final FieldAbsoluteDate<T> endDate = getAbsoluteDateFromTimestamp(field, end);
392 FieldSpacecraftState<T> lastState = propagator.propagate(startDate, endDate.shiftedBy(1));
393 Assertions.assertEquals(0.0, lastState.getDate().durationFrom(endDate).getReal(), 1.0e-15);
394
395 }
396
397 public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getAbsoluteDateFromTimestamp(final Field<T> field,
398 final long timestamp) {
399 LocalDateTime utcDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp),
400 ZoneId.of("UTC"));
401 int year = utcDate.getYear();
402 int month = utcDate.getMonthValue();
403 int day = utcDate.getDayOfMonth();
404 int hour = utcDate.getHour();
405 int minute = utcDate.getMinute();
406 double second = utcDate.getSecond();
407 double millis = utcDate.getNano() / 1e9;
408 return new FieldAbsoluteDate<>(field, year, month, day, hour, minute, second, TimeScalesFactory.getUTC()).shiftedBy(millis);
409 }
410
411 private <T extends CalculusFieldElement<T>> FieldTimeStamped<T>[] toArray(final FieldAbsoluteDate<T> date) {
412 @SuppressWarnings("unchecked")
413 final FieldTimeStamped<T>[] array = (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 1);
414 array[0] = date;
415 return array;
416 }
417
418 @BeforeEach
419 public void setUp() {
420 Utils.setDataRoot("regular-data");
421 mu = 3.9860047e14;
422 dt = 60.;
423 minGap = 10.;
424 threshold = 10.e-7;
425 evtno = 0;
426 }
427
428 }