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