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 public void testSimpleTimer() {
72 doTestSimpleTimer(Binary64Field.getInstance());
73 }
74
75 @Test
76 public void testEmbeddedTimer() {
77 doTestEmbeddedTimer(Binary64Field.getInstance());
78 }
79
80 @Test
81 public void testAutoEmbeddedTimer() {
82 doTestAutoEmbeddedTimer(Binary64Field.getInstance());
83 }
84
85 @Test
86 public void testExceptionTimer() {
87 Assertions.assertThrows(IllegalArgumentException.class, () -> {
88 doTestExceptionTimer(Binary64Field.getInstance());
89 });
90 }
91
92 @Test
93 public 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 public void testIssue935() {
128 doTestIssue935(Binary64Field.getInstance());
129 }
130
131 private <T extends CalculusFieldElement<T>> void doTestSimpleTimer(final Field<T> field) {
132 T zero = field.getZero();
133 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
134 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
135 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
136 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
137 FramesFactory.getEME2000(), iniDate, zero.add(mu));
138 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
139 double[] absTolerance = {
140 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
141 };
142 double[] relTolerance = {
143 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
144 };
145 AdaptiveStepsizeFieldIntegrator<T> integrator =
146 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
147 integrator.setInitialStepSize(60);
148 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
149 propagator.addAdditionalDerivativesProvider(new FieldAdditionalDerivativesProvider<T>() {
150 public String getName() { return "dummy"; }
151 public int getDimension() { return 1; }
152 public FieldCombinedDerivatives<T> combinedDerivatives(FieldSpacecraftState<T> s) {
153 return new FieldCombinedDerivatives<>(MathArrays.buildArray(field, 1), null);
154 }
155 });
156 propagator.getMultiplexer().add(interpolator -> {
157 FieldSpacecraftState<T> prev = interpolator.getPreviousState();
158 FieldSpacecraftState<T> curr = interpolator.getCurrentState();
159 T dt = curr.getDate().durationFrom(prev.getDate());
160 FieldOrekitStepInterpolator<T> restricted =
161 interpolator.restrictStep(prev.shiftedBy(dt.multiply(+0.25)),
162 curr.shiftedBy(dt.multiply(-0.25)));
163 FieldSpacecraftState<T> restrictedPrev = restricted.getPreviousState();
164 FieldSpacecraftState<T> restrictedCurr = restricted.getCurrentState();
165 T restrictedDt = restrictedCurr.getDate().durationFrom(restrictedPrev.getDate());
166 Assertions.assertEquals(dt.multiply(0.5).getReal(), restrictedDt.getReal(), 1.0e-10);
167 });
168 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
169 propagator.setInitialState(initialState.addAdditionalData("dummy", MathArrays.buildArray(field, 1)));
170
171 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(2.0*dt))).
172 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
173 Assertions.assertEquals(2 * dt, dateDetector.getDate().durationFrom(iniDate).getReal(), 1.0e-10);
174 propagator.addEventDetector(dateDetector);
175 final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
176
177 Assertions.assertEquals(2.0*dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
178 }
179
180
181 private <T extends CalculusFieldElement<T>> void doTestEmbeddedTimer(Field<T> field) {
182 T zero = field.getZero();
183 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
184 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
185 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
186 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
187 FramesFactory.getEME2000(), iniDate, zero.add(mu));
188 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
189 double[] absTolerance = {
190 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
191 };
192 double[] relTolerance = {
193 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
194 };
195 AdaptiveStepsizeFieldIntegrator<T> integrator =
196 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
197 integrator.setInitialStepSize(60);
198 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
199 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
200 propagator.setInitialState(initialState);
201 @SuppressWarnings("unchecked")
202 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 0)).
203 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
204 Assertions.assertNull(dateDetector.getDate());
205 FieldEventDetector<T> nodeDetector = new FieldNodeDetector<>(iniOrbit, iniOrbit.getFrame()).
206 withHandler(new FieldContinueOnEvent<T>() {
207 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> nd, boolean increasing) {
208 if (increasing) {
209 nodeDate = s.getDate().toAbsoluteDate();
210 dateDetector.addEventDate(s.getDate().shiftedBy(dt));
211 }
212 return Action.CONTINUE;
213 }
214 });
215
216 propagator.addEventDetector(nodeDetector);
217 propagator.addEventDetector(dateDetector);
218 final FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100.*dt));
219
220 Assertions.assertEquals(dt, finalState.getDate().durationFrom(nodeDate).getReal(), threshold);
221 }
222
223
224 private <T extends CalculusFieldElement<T>> void doTestAutoEmbeddedTimer(Field<T> field) {
225 T zero = field.getZero();
226 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
227 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
228 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
229 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
230 FramesFactory.getEME2000(), iniDate, zero.add(mu));
231 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
232 double[] absTolerance = {
233 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
234 };
235 double[] relTolerance = {
236 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
237 };
238 AdaptiveStepsizeFieldIntegrator<T> integrator =
239 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
240 integrator.setInitialStepSize(60);
241 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
242 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
243 propagator.setInitialState(initialState);
244
245 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(-dt))).
246 withMinGap(minGap).
247 withThreshold(field.getZero().newInstance(threshold)).
248 withHandler(new FieldContinueOnEvent<T >() {
249 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> dd, boolean increasing) {
250 FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(-dt);
251 ((FieldDateDetector<T>) dd).addEventDate(nextDate);
252 ++evtno;
253 return Action.CONTINUE;
254 }
255 });
256 propagator.addEventDetector(dateDetector);
257 propagator.propagate(iniDate.shiftedBy(-100.*dt));
258
259 Assertions.assertEquals(100, evtno);
260 }
261
262 private <T extends CalculusFieldElement<T>> void doTestExceptionTimer(Field<T> field) {
263 T zero = field.getZero();
264 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
265 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
266 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
267 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
268 FramesFactory.getEME2000(), iniDate, zero.add(mu));
269 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
270 double[] absTolerance = {
271 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
272 };
273 double[] relTolerance = {
274 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
275 };
276 AdaptiveStepsizeFieldIntegrator<T> integrator =
277 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
278 integrator.setInitialStepSize(60);
279 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
280 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
281 propagator.setInitialState(initialState);
282
283 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(dt))).
284 withMinGap(minGap).
285 withThreshold(field.getZero().newInstance(threshold)).
286 withHandler(new FieldContinueOnEvent<T>() {
287 public Action eventOccurred(FieldSpacecraftState<T> s, FieldEventDetector<T> dd, boolean increasing)
288 {
289 double step = (evtno % 2 == 0) ? 2.*minGap : minGap/2.;
290 FieldAbsoluteDate<T> nextDate = s.getDate().shiftedBy(step);
291 ((FieldDateDetector<T>) dd).addEventDate(nextDate);
292 ++evtno;
293 return Action.CONTINUE;
294 }
295 });
296 propagator.addEventDetector(dateDetector);
297 propagator.propagate(iniDate.shiftedBy(100.*dt));
298 }
299
300
301
302
303
304 private <T extends CalculusFieldElement<T>> void doTestGenericHandler(Field<T> field) {
305 T zero = field.getZero();
306 final FieldVector3D<T> position = new FieldVector3D<>(zero.add(-6142438.668), zero.add( 3492467.560), zero.add( -25767.25680));
307 final FieldVector3D<T> velocity = new FieldVector3D<>(zero.add(505.8479685), zero.add(942.7809215), zero.add(7435.922231));
308 FieldAbsoluteDate<T> iniDate = new FieldAbsoluteDate<>(field, 1969, 7, 28, 4, 0, 0.0, TimeScalesFactory.getTT());
309 FieldOrbit<T> iniOrbit = new FieldEquinoctialOrbit<>(new FieldPVCoordinates<>(position, velocity),
310 FramesFactory.getEME2000(), iniDate, zero.add(mu));
311 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(iniOrbit);
312 double[] absTolerance = {
313 0.001, 1.0e-9, 1.0e-9, 1.0e-6, 1.0e-6, 1.0e-6, 0.001
314 };
315 double[] relTolerance = {
316 1.0e-7, 1.0e-4, 1.0e-4, 1.0e-7, 1.0e-7, 1.0e-7, 1.0e-7
317 };
318 AdaptiveStepsizeFieldIntegrator<T> integrator =
319 new DormandPrince853FieldIntegrator<>(field, 0.001, 1000, absTolerance, relTolerance);
320 integrator.setInitialStepSize(60);
321 FieldNumericalPropagator<T> propagator = new FieldNumericalPropagator<>(field, integrator);
322 propagator.setOrbitType(OrbitType.EQUINOCTIAL);
323 propagator.setInitialState(initialState);
324
325
326 final FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, toArray(iniDate.shiftedBy(dt))).
327 withMinGap(minGap).withThreshold(field.getZero().newInstance(threshold));
328
329 FieldEventHandler<T> handler = new FieldEventHandler<T>() {
330 @Override
331 public Action eventOccurred(FieldSpacecraftState<T> s,
332 FieldEventDetector<T> detector,
333 boolean increasing) {
334 return Action.STOP;
335 }
336
337 @Override
338 public FieldSpacecraftState<T> resetState(FieldEventDetector<T> detector,
339 FieldSpacecraftState<T> oldState) {
340 throw new RuntimeException("Should not be called");
341 }
342 };
343
344
345 final FieldDateDetector<T> dateDetector2;
346
347 dateDetector2 = dateDetector.withHandler(handler);
348
349 propagator.addEventDetector(dateDetector2);
350 FieldSpacecraftState<T> finalState = propagator.propagate(iniDate.shiftedBy(100 * dt));
351
352
353 Assertions.assertEquals(dt, finalState.getDate().durationFrom(iniDate).getReal(), threshold);
354 }
355
356 private <T extends CalculusFieldElement<T>> void doTestIssue935(Field<T> field) {
357
358
359 long start = 1570802400000L;
360 long end = 1570838399000L;
361
362
363 FieldTLE<T> tle = new FieldTLE<>(field,
364 "1 43197U 18015F 19284.07336221 .00000533 00000-0 24811-4 0 9998",
365 "2 43197 97.4059 50.1428 0017543 265.5429 181.0400 15.24136761 93779");
366 FieldPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(tle, tle.getParameters(field));
367
368
369 int maxCheck = (int) ((end - start) / 2000);
370 FieldDateDetector<T> dateDetector = new FieldDateDetector<>(field, getAbsoluteDateFromTimestamp(field, start)).
371 withMinGap(maxCheck).
372 withThreshold(field.getZero().newInstance(1.0e-6)).
373 withHandler(new FieldStopOnEvent<>());
374 dateDetector.addEventDate(getAbsoluteDateFromTimestamp(field, end));
375
376
377 propagator.addEventDetector(dateDetector);
378
379
380 final FieldAbsoluteDate<T> startDate = getAbsoluteDateFromTimestamp(field, start);
381 final FieldAbsoluteDate<T> endDate = getAbsoluteDateFromTimestamp(field, end);
382 FieldSpacecraftState<T> lastState = propagator.propagate(startDate, endDate.shiftedBy(1));
383 Assertions.assertEquals(0.0, lastState.getDate().durationFrom(endDate).getReal(), 1.0e-15);
384
385 }
386
387 public static <T extends CalculusFieldElement<T>> FieldAbsoluteDate<T> getAbsoluteDateFromTimestamp(final Field<T> field,
388 final long timestamp) {
389 LocalDateTime utcDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp),
390 ZoneId.of("UTC"));
391 int year = utcDate.getYear();
392 int month = utcDate.getMonthValue();
393 int day = utcDate.getDayOfMonth();
394 int hour = utcDate.getHour();
395 int minute = utcDate.getMinute();
396 double second = utcDate.getSecond();
397 double millis = utcDate.getNano() / 1e9;
398 return new FieldAbsoluteDate<>(field, year, month, day, hour, minute, second, TimeScalesFactory.getUTC()).shiftedBy(millis);
399 }
400
401 private <T extends CalculusFieldElement<T>> FieldTimeStamped<T>[] toArray(final FieldAbsoluteDate<T> date) {
402 @SuppressWarnings("unchecked")
403 final FieldTimeStamped<T>[] array = (FieldTimeStamped<T>[]) Array.newInstance(FieldTimeStamped.class, 1);
404 array[0] = date;
405 return array;
406 }
407
408 @BeforeEach
409 public void setUp() {
410 Utils.setDataRoot("regular-data");
411 mu = 3.9860047e14;
412 dt = 60.;
413 minGap = 10.;
414 threshold = 10.e-7;
415 evtno = 0;
416 }
417
418 }