1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.utils;
18
19 import org.hamcrest.CoreMatchers;
20 import org.hamcrest.MatcherAssert;
21 import org.hipparchus.random.RandomGenerator;
22 import org.hipparchus.random.Well1024a;
23 import org.junit.jupiter.api.Assertions;
24 import org.junit.jupiter.api.BeforeEach;
25 import org.junit.jupiter.api.DisplayName;
26 import org.junit.jupiter.api.Test;
27 import org.orekit.Utils;
28 import org.orekit.bodies.GeodeticPoint;
29 import org.orekit.errors.OrekitIllegalArgumentException;
30 import org.orekit.errors.TimeStampedCacheException;
31 import org.orekit.frames.Frame;
32 import org.orekit.frames.FramesFactory;
33 import org.orekit.frames.TopocentricFrame;
34 import org.orekit.models.earth.ReferenceEllipsoid;
35 import org.orekit.propagation.analytical.tle.TLE;
36 import org.orekit.propagation.analytical.tle.TLEPropagator;
37 import org.orekit.propagation.events.ElevationDetector;
38 import org.orekit.time.AbsoluteDate;
39 import org.orekit.time.TimeScale;
40 import org.orekit.time.TimeScalesFactory;
41
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.concurrent.ExecutorService;
46 import java.util.concurrent.Executors;
47 import java.util.concurrent.TimeUnit;
48 import java.util.concurrent.atomic.AtomicReference;
49 import java.util.stream.Collectors;
50
51
52 public class GenericTimeStampedCacheTest {
53
54 @Test
55 public void testSingleCall() throws TimeStampedCacheException {
56 GenericTimeStampedCache<AbsoluteDate> cache = createCache(10, 3600.0, 13);
57 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
58 list.add(AbsoluteDate.GALILEO_EPOCH);
59 Assertions.assertEquals(1, checkDatesSingleThread(list, cache));
60 Assertions.assertEquals(1, cache.getGetNeighborsCalls());
61 Assertions.assertEquals(4, cache.getGenerateCalls());
62 Assertions.assertEquals(0, cache.getSlotsEvictions());
63 Assertions.assertEquals(10, cache.getMaxSlots());
64 Assertions.assertEquals(Constants.JULIAN_DAY, cache.getNewSlotQuantumGap(), 1.0e-10);
65 Assertions.assertEquals(Constants.JULIAN_YEAR, cache.getMaxSpan(), 1.0e-10);
66 }
67
68 @Test
69 public void testPastInfinityRange() throws TimeStampedCacheException {
70 GenericTimeStampedCache<AbsoluteDate> cache =
71 new GenericTimeStampedCache<AbsoluteDate>(2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
72 new Generator(AbsoluteDate.PAST_INFINITY,
73 AbsoluteDate.J2000_EPOCH,
74 10.0));
75 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
76 list.add(AbsoluteDate.GALILEO_EPOCH);
77 list.add(AbsoluteDate.MODIFIED_JULIAN_EPOCH);
78 list.add(AbsoluteDate.JULIAN_EPOCH);
79 Assertions.assertEquals(3, checkDatesSingleThread(list, cache));
80 Assertions.assertEquals(3, cache.getGetNeighborsCalls());
81 try {
82 cache.getNeighbors(AbsoluteDate.J2000_EPOCH.shiftedBy(100.0));
83 Assertions.fail("expected TimeStampedCacheException");
84 } catch (TimeStampedCacheException tce) {
85
86 } catch (Exception e) {
87 Assertions.fail("wrong exception caught");
88 }
89 }
90
91 @Test
92 public void testFutureInfinityRange() throws TimeStampedCacheException {
93 GenericTimeStampedCache<AbsoluteDate> cache =
94 new GenericTimeStampedCache<AbsoluteDate>(2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
95 new Generator(AbsoluteDate.MODIFIED_JULIAN_EPOCH,
96 AbsoluteDate.FUTURE_INFINITY, 10.0));
97 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
98 list.add(AbsoluteDate.J2000_EPOCH);
99 list.add(AbsoluteDate.GALILEO_EPOCH);
100 Assertions.assertEquals(2, checkDatesSingleThread(list, cache));
101 Assertions.assertEquals(2, cache.getGetNeighborsCalls());
102 try {
103 cache.getNeighbors(AbsoluteDate.JULIAN_EPOCH);
104 Assertions.fail("expected TimeStampedCacheException");
105 } catch (TimeStampedCacheException tce) {
106
107 } catch (Exception e) {
108 Assertions.fail("wrong exception caught");
109 }
110 }
111
112 @Test
113 public void testInfinityRange() throws TimeStampedCacheException {
114 GenericTimeStampedCache<AbsoluteDate> cache =
115 new GenericTimeStampedCache<AbsoluteDate>(2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
116 new Generator(AbsoluteDate.PAST_INFINITY,
117 AbsoluteDate.FUTURE_INFINITY,
118 10.0));
119 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
120 list.add(AbsoluteDate.J2000_EPOCH.shiftedBy(+4.6e12));
121 list.add(AbsoluteDate.J2000_EPOCH.shiftedBy(-4.6e12));
122 list.add(AbsoluteDate.JULIAN_EPOCH);
123 list.add(AbsoluteDate.J2000_EPOCH);
124 list.add(AbsoluteDate.GALILEO_EPOCH);
125 Assertions.assertEquals(5, checkDatesSingleThread(list, cache));
126 Assertions.assertEquals(5, cache.getGetNeighborsCalls());
127 }
128
129 @Test
130 public void testRegularCalls() throws TimeStampedCacheException {
131 GenericTimeStampedCache<AbsoluteDate> cache = createCache(2, 3600, 13);
132 Assertions.assertEquals(2000, testMultipleSingleThread(cache, new SequentialMode(), 2));
133 Assertions.assertEquals(2000, cache.getGetNeighborsCalls());
134 Assertions.assertEquals(56, cache.getGenerateCalls());
135 Assertions.assertEquals(0, cache.getSlotsEvictions());
136 }
137
138 @Test
139 public void testAlternateCallsGoodConfiguration() throws TimeStampedCacheException {
140 GenericTimeStampedCache<AbsoluteDate> cache = createCache(2, 3600, 13);
141 Assertions.assertEquals(2000, testMultipleSingleThread(cache, new AlternateMode(), 2));
142 Assertions.assertEquals(2000, cache.getGetNeighborsCalls());
143 Assertions.assertEquals(56, cache.getGenerateCalls());
144 Assertions.assertEquals(0, cache.getSlotsEvictions());
145 }
146
147 @Test
148 public void testAlternateCallsBadConfiguration() throws TimeStampedCacheException {
149 GenericTimeStampedCache<AbsoluteDate> cache = createCache(1, 3600, 13);
150 Assertions.assertEquals(2000, testMultipleSingleThread(cache, new AlternateMode(), 2));
151 Assertions.assertEquals(2000, cache.getGetNeighborsCalls());
152 Assertions.assertEquals(8000, cache.getGenerateCalls());
153 Assertions.assertEquals(1999, cache.getSlotsEvictions());
154 }
155
156 @Test
157 public void testRandomCallsGoodConfiguration() throws TimeStampedCacheException {
158 GenericTimeStampedCache<AbsoluteDate> cache = createCache(30, 3600, 13);
159 Assertions.assertEquals(5000, testMultipleSingleThread(cache, new RandomMode(64394632125212l), 5));
160 Assertions.assertEquals(5000, cache.getGetNeighborsCalls());
161 Assertions.assertTrue(cache.getGenerateCalls() < 250);
162 Assertions.assertEquals(0, cache.getSlotsEvictions());
163 }
164
165 @Test
166 public void testRandomCallsBadConfiguration() throws TimeStampedCacheException {
167 GenericTimeStampedCache<AbsoluteDate> cache = createCache(3, 3600, 13);
168 Assertions.assertEquals(5000, testMultipleSingleThread(cache, new RandomMode(64394632125212l), 5));
169 Assertions.assertEquals(5000, cache.getGetNeighborsCalls());
170 Assertions.assertTrue(cache.getGenerateCalls() > 400);
171 Assertions.assertTrue(cache.getSlotsEvictions() > 300);
172 }
173
174 @Test
175 public void testMultithreadedGoodConfiguration() throws TimeStampedCacheException {
176 GenericTimeStampedCache<AbsoluteDate> cache = createCache(50, 3600, 13);
177 int n = testMultipleMultiThread(cache, new AlternateMode(), 50, 30);
178 Assertions.assertEquals(n, cache.getGetNeighborsCalls());
179 Assertions.assertTrue(cache.getGenerateCalls() < n / 20,
180 "this test may fail randomly due to multi-threading non-determinism" +
181 " (n = " + n + ", calls = " + cache.getGenerateCalls() +
182 ", ratio = " + (n / cache.getGenerateCalls()) + ")");
183 Assertions.assertTrue(cache.getSlotsEvictions() < n / 1000,
184 "this test may fail randomly due to multi-threading non-determinism" +
185 " (n = " + n + ", evictions = " + cache.getSlotsEvictions() +
186 (cache.getSlotsEvictions() == 0 ? "" : (", ratio = " + (n / cache.getSlotsEvictions()))) + ")");
187 }
188
189 @Test
190 public void testMultithreadedBadConfiguration() throws TimeStampedCacheException {
191 GenericTimeStampedCache<AbsoluteDate> cache = createCache(3, 3600, 13);
192 int n = testMultipleMultiThread(cache, new AlternateMode(), 50, 100);
193 Assertions.assertEquals(n, cache.getGetNeighborsCalls());
194 Assertions.assertTrue(cache.getGenerateCalls() > n / 15,
195 "this test may fail randomly due to multi-threading non-determinism" +
196 " (n = " + n + ", calls = " + cache.getGenerateCalls() +
197 ", ratio = " + (n / cache.getGenerateCalls()) + ")");
198 Assertions.assertTrue(cache.getSlotsEvictions() > n / 60,
199 "this test may fail randomly due to multi-threading non-determinism" +
200 " (n = " + n + ", evictions = " + cache.getSlotsEvictions() +
201 ", ratio = " + (n / cache.getSlotsEvictions()) + ")");
202 }
203
204 @Test
205 public void testSmallShift() throws TimeStampedCacheException {
206 double hour = 3600;
207 GenericTimeStampedCache<AbsoluteDate> cache = createCache(10, hour, 13);
208 Assertions.assertEquals(0, cache.getSlots());
209 Assertions.assertEquals(0, cache.getEntries());
210 final AbsoluteDate start = AbsoluteDate.GALILEO_EPOCH;
211 cache.getNeighbors(start);
212 Assertions.assertEquals(1, cache.getGetNeighborsCalls());
213 Assertions.assertEquals(1, cache.getSlots());
214 Assertions.assertEquals(18, cache.getEntries());
215 Assertions.assertEquals(4, cache.getGenerateCalls());
216 Assertions.assertEquals(-11 * hour, cache.getEarliest().durationFrom(start), 1.0e-10);
217 Assertions.assertEquals( +6 * hour, cache.getLatest().durationFrom(start), 1.0e-10);
218 cache.getNeighbors(start.shiftedBy(-3 * 3600));
219 Assertions.assertEquals(2, cache.getGetNeighborsCalls());
220 Assertions.assertEquals(1, cache.getSlots());
221 Assertions.assertEquals(18, cache.getEntries());
222 Assertions.assertEquals(4, cache.getGenerateCalls());
223 Assertions.assertEquals(-11 * hour, cache.getEarliest().durationFrom(start), 1.0e-10);
224 Assertions.assertEquals( +6 * hour, cache.getLatest().durationFrom(start), 1.0e-10);
225 cache.getNeighbors(start.shiftedBy(7 * 3600));
226 Assertions.assertEquals(3, cache.getGetNeighborsCalls());
227 Assertions.assertEquals(1, cache.getSlots());
228 Assertions.assertEquals(25, cache.getEntries());
229 Assertions.assertEquals(5, cache.getGenerateCalls());
230 Assertions.assertEquals(-11 * hour, cache.getEarliest().durationFrom(start), 1.0e-10);
231 Assertions.assertEquals(+13 * hour, cache.getLatest().durationFrom(start), 1.0e-10);
232 }
233
234 @Test
235 public void testNotEnoughSlots() {
236 Assertions.assertThrows(IllegalArgumentException.class, () -> {
237 createCache(0, 3600.0, 13);
238 });
239 }
240
241 @Test
242 public void testNotEnoughNeighbors() {
243 Assertions.assertThrows(IllegalArgumentException.class, () -> {
244 createCache(10, 3600.0, 1);
245 });
246 }
247
248 @Test
249 public void testNoEarliestEntry() {
250 Assertions.assertThrows(IllegalStateException.class, () -> {
251 createCache(10, 3600.0, 3).getEarliest();
252 });
253 }
254
255 @Test
256 public void testNoLatestEntry() {
257 Assertions.assertThrows(IllegalStateException.class, () -> {
258 createCache(10, 3600.0, 3).getLatest();
259 });
260 }
261
262 @Test
263 public void testNoGeneratedData() throws TimeStampedCacheException {
264 Assertions.assertThrows(TimeStampedCacheException.class, () -> {
265 TimeStampedGenerator<AbsoluteDate> nullGenerator =
266 new TimeStampedGenerator<AbsoluteDate>() {
267 public List<AbsoluteDate> generate(AbsoluteDate existingDate,
268 AbsoluteDate date) {
269 return new ArrayList<AbsoluteDate>();
270 }
271 };
272 new GenericTimeStampedCache<AbsoluteDate>(2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
273 nullGenerator).getNeighbors(AbsoluteDate.J2000_EPOCH);
274 });
275 }
276
277 @Test
278 public void testNoDataBefore() throws TimeStampedCacheException {
279 TimeStampedGenerator<AbsoluteDate> nullGenerator =
280 new TimeStampedGenerator<AbsoluteDate>() {
281 public List<AbsoluteDate> generate(AbsoluteDate existingDate,
282 AbsoluteDate date) {
283 return Collections.singletonList(AbsoluteDate.J2000_EPOCH);
284 }
285 };
286 AbsoluteDate central = AbsoluteDate.J2000_EPOCH.shiftedBy(-10);
287 GenericTimeStampedCache<AbsoluteDate> cache = new GenericTimeStampedCache<>(
288 2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY, nullGenerator);
289 try {
290 cache.getNeighbors(central);
291 Assertions.fail("Expected Exception");
292 } catch (TimeStampedCacheException e) {
293 MatcherAssert.assertThat(e.getMessage(),
294 CoreMatchers.containsString(central.toString()));
295 }
296 }
297
298 @Test
299 public void testNoDataAfter() throws TimeStampedCacheException {
300 TimeStampedGenerator<AbsoluteDate> nullGenerator =
301 new TimeStampedGenerator<AbsoluteDate>() {
302 public List<AbsoluteDate> generate(AbsoluteDate existingDate,
303 AbsoluteDate date) {
304 return Collections.singletonList(AbsoluteDate.J2000_EPOCH);
305 }
306 };
307 AbsoluteDate central = AbsoluteDate.J2000_EPOCH.shiftedBy(+10);
308 GenericTimeStampedCache<AbsoluteDate> cache = new GenericTimeStampedCache<>(
309 2, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY, nullGenerator);
310 try {
311 cache.getNeighbors(central);
312 Assertions.fail("Expected Exception");
313 } catch (TimeStampedCacheException e) {
314 MatcherAssert.assertThat(e.getMessage(),
315 CoreMatchers.containsString(central.toString()));
316 }
317 }
318
319 @Test
320 public void testUnsortedEntries() throws TimeStampedCacheException {
321 Assertions.assertThrows(TimeStampedCacheException.class, () -> {
322 TimeStampedGenerator<AbsoluteDate> reversedGenerator =
323 new TimeStampedGenerator<AbsoluteDate>() {
324
325 public List<AbsoluteDate> generate(AbsoluteDate existingDate, AbsoluteDate date) {
326 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
327 list.add(date);
328 list.add(date.shiftedBy(-10.0));
329 return list;
330 }
331 };
332
333 new GenericTimeStampedCache<AbsoluteDate>(3, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
334 reversedGenerator).getNeighbors(AbsoluteDate.J2000_EPOCH);
335 });
336 }
337
338 @Test
339 public void testDuplicatingGenerator() throws TimeStampedCacheException {
340
341 final double step = 3600.0;
342
343 TimeStampedGenerator<AbsoluteDate> duplicatingGenerator =
344 new TimeStampedGenerator<AbsoluteDate>() {
345
346
347 public List<AbsoluteDate> generate(AbsoluteDate existingDate, AbsoluteDate date) {
348 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
349 if (existingDate == null) {
350 list.add(date);
351 } else {
352 if (date.compareTo(existingDate) > 0) {
353 AbsoluteDate t = existingDate.shiftedBy(-10 * step);
354 do {
355 t = t.shiftedBy(step);
356 list.add(list.size(), t);
357 } while (t.compareTo(date) <= 0);
358 } else {
359 AbsoluteDate t = existingDate.shiftedBy(10 * step);
360 do {
361 t = t.shiftedBy(-step);
362 list.add(0, t);
363 } while (t.compareTo(date) >= 0);
364 }
365 }
366 return list;
367 }
368
369 };
370
371 final GenericTimeStampedCache<AbsoluteDate> cache =
372 new GenericTimeStampedCache<AbsoluteDate>(5, 10, Constants.JULIAN_YEAR, Constants.JULIAN_DAY,
373 duplicatingGenerator);
374
375 final AbsoluteDate start = AbsoluteDate.GALILEO_EPOCH;
376 final List<AbsoluteDate> firstSet = cache.getNeighbors(start).collect(Collectors.toList());
377 Assertions.assertEquals(5, firstSet.size());
378 Assertions.assertEquals(4, cache.getGenerateCalls());
379 Assertions.assertEquals(8, cache.getEntries());
380 for (int i = 1; i < firstSet.size(); ++i) {
381 Assertions.assertEquals(step, firstSet.get(i).durationFrom(firstSet.get(i - 1)), 1.0e-10);
382 }
383
384 final List<AbsoluteDate> secondSet = cache.getNeighbors(cache.getLatest().shiftedBy(10 * step)).collect(Collectors.toList());
385 Assertions.assertEquals(5, secondSet.size());
386 Assertions.assertEquals(7, cache.getGenerateCalls());
387 Assertions.assertEquals(20, cache.getEntries());
388 for (int i = 1; i < secondSet.size(); ++i) {
389 Assertions.assertEquals(step, firstSet.get(i).durationFrom(firstSet.get(i - 1)), 1.0e-10);
390 }
391
392 }
393
394 @Test
395 @DisplayName("Test that the cache of the detector does not get corrupted when a propagation to infinity has been run")
396 void testIssue1108() {
397
398 final TLE aTle = new TLE("1 27424U 02022A 23173.43403823 .00001056 00000+0 23935-3 0 9994",
399 "2 27424 98.2874 117.8299 0001810 103.6635 5.7337 14.58117998124128");
400
401 final Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
402 final GeodeticPoint site = new GeodeticPoint(0.0, 0.0, 0.0);
403 final TopocentricFrame siteFrame = new TopocentricFrame(ReferenceEllipsoid.getIers2010(itrf), site, "site");
404 final ElevationDetector siteVisDetector =
405 new ElevationDetector(60, 0.001, siteFrame).withConstantElevation(5.0);
406
407
408 final TLEPropagator tlePropagator = TLEPropagator.selectExtrapolator(aTle);
409 tlePropagator.addEventDetector(siteVisDetector);
410
411 try {
412
413
414 tlePropagator.propagate(AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY);
415 } catch (OrekitIllegalArgumentException e) {
416
417 TimeScale utc = TimeScalesFactory.getUTC();
418 final AbsoluteDate ephemerisStartDate = new AbsoluteDate(23, 6, 15, 0, 0, 0, utc);
419 final AbsoluteDate ephemerisEndDate = new AbsoluteDate(23, 6, 15, 0, 0, 1, utc);
420
421
422 Assertions.assertDoesNotThrow(() -> tlePropagator.propagate(ephemerisStartDate, ephemerisEndDate));
423 }
424 }
425
426 private int testMultipleSingleThread(GenericTimeStampedCache<AbsoluteDate> cache, Mode mode, int slots)
427 throws TimeStampedCacheException {
428 double step = ((Generator) cache.getGenerator()).getStep();
429 AbsoluteDate[] base = new AbsoluteDate[slots];
430 base[0] = AbsoluteDate.GALILEO_EPOCH;
431 for (int i = 1; i < base.length; ++i) {
432 base[i] = base[i - 1].shiftedBy(10 * Constants.JULIAN_DAY);
433 }
434 return checkDatesSingleThread(mode.generateDates(base, 25 * step, 0.025 * step), cache);
435 }
436
437 private int testMultipleMultiThread(GenericTimeStampedCache<AbsoluteDate> cache, Mode mode,
438 int slots, int threadPoolSize)
439 throws TimeStampedCacheException {
440 double step = ((Generator) cache.getGenerator()).getStep();
441 AbsoluteDate[] base = new AbsoluteDate[slots];
442 base[0] = AbsoluteDate.GALILEO_EPOCH;
443 for (int i = 1; i < base.length; ++i) {
444 base[i] = base[i - 1].shiftedBy(10 * Constants.JULIAN_DAY);
445 }
446 return checkDatesMultiThread(mode.generateDates(base, 25 * step, 0.025 * step), cache, threadPoolSize);
447 }
448
449 private GenericTimeStampedCache<AbsoluteDate> createCache(int maxSlots, double step, int neighborsSize) {
450 Generator generator =
451 new Generator(AbsoluteDate.J2000_EPOCH.shiftedBy(-Constants.JULIAN_CENTURY),
452 AbsoluteDate.J2000_EPOCH.shiftedBy(+Constants.JULIAN_CENTURY),
453 step);
454 return new GenericTimeStampedCache<AbsoluteDate>(neighborsSize, maxSlots, Constants.JULIAN_YEAR,
455 Constants.JULIAN_DAY, generator);
456 }
457
458 private int checkDatesSingleThread(final List<AbsoluteDate> centralDates,
459 final GenericTimeStampedCache<AbsoluteDate> cache)
460 throws TimeStampedCacheException {
461
462 final int n = cache.getMaxNeighborsSize();
463 final double step = ((Generator) cache.getGenerator()).getStep();
464
465 for (final AbsoluteDate central : centralDates) {
466 final List<AbsoluteDate> neighbors = cache.getNeighbors(central).collect(Collectors.toList());
467 Assertions.assertEquals(n, neighbors.size());
468 for (final AbsoluteDate date : neighbors) {
469 Assertions.assertTrue(date.durationFrom(central) >= -(n + 1) * step);
470 Assertions.assertTrue(date.durationFrom(central) <= n * step);
471 }
472 }
473
474 return centralDates.size();
475
476 }
477
478 private int checkDatesMultiThread(final List<AbsoluteDate> centralDates,
479 final GenericTimeStampedCache<AbsoluteDate> cache,
480 final int threadPoolSize)
481 throws TimeStampedCacheException {
482
483 final int n = cache.getMaxNeighborsSize();
484 final double step = ((Generator) cache.getGenerator()).getStep();
485 final AtomicReference<AbsoluteDate[]> failedDates = new AtomicReference<AbsoluteDate[]>();
486 final AtomicReference<TimeStampedCacheException> caught = new AtomicReference<TimeStampedCacheException>();
487 ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
488
489 for (final AbsoluteDate central : centralDates) {
490 executorService.execute(new Runnable() {
491 public void run() {
492 try {
493 final List<AbsoluteDate> neighbors = cache.getNeighbors(central).collect(Collectors.toList());
494 Assertions.assertEquals(n, neighbors.size());
495 for (final AbsoluteDate date : neighbors) {
496 if (date.durationFrom(central) < -(n + 1) * step ||
497 date.durationFrom(central) > n * step) {
498 AbsoluteDate[] dates = new AbsoluteDate[n + 1];
499 dates[0] = central;
500 System.arraycopy(neighbors, 0, dates, 1, n);
501 failedDates.set(dates);
502 }
503 }
504 } catch (TimeStampedCacheException tce) {
505 caught.set(tce);
506 }
507 }
508 });
509 }
510
511 try {
512 executorService.shutdown();
513 Assertions.assertTrue(executorService.awaitTermination(10, TimeUnit.MINUTES),
514 "Not enough time for all threads to complete, try increasing the timeout");
515 } catch (InterruptedException ie) {
516 Assertions.fail(ie.getLocalizedMessage());
517 }
518
519 if (caught.get() != null) {
520 throw caught.get();
521 }
522
523 if (failedDates.get() != null) {
524 AbsoluteDate[] dates = failedDates.get();
525 StringBuilder builder = new StringBuilder();
526 String eol = System.getProperty("line.separator");
527 builder.append("central = ").append(dates[0]).append(eol);
528 builder.append("step = ").append(step).append(eol);
529 builder.append("neighbors =").append(eol);
530 for (int i = 1; i < dates.length; ++i) {
531 builder.append(" ").append(dates[i]).append(eol);
532 }
533 Assertions.fail(builder.toString());
534 }
535
536 return centralDates.size();
537
538 }
539
540 private static class Generator implements TimeStampedGenerator<AbsoluteDate> {
541
542 private final AbsoluteDate earliest;
543 private final AbsoluteDate latest;
544 private final double step;
545
546 public Generator(final AbsoluteDate earliest, final AbsoluteDate latest, final double step) {
547 this.earliest = earliest;
548 this.latest = latest;
549 this.step = step;
550 }
551
552 public double getStep() {
553 return step;
554 }
555
556 public List<AbsoluteDate> generate(AbsoluteDate existingDate, AbsoluteDate date) {
557 List<AbsoluteDate> dates = new ArrayList<AbsoluteDate>();
558 if (existingDate == null) {
559 dates.add(date);
560 } else if (date.compareTo(existingDate) >= 0) {
561 AbsoluteDate previous = existingDate;
562 while (date.compareTo(previous) > 0) {
563 previous = previous.shiftedBy(step);
564 if (previous.compareTo(earliest) >= 0 && previous.compareTo(latest) <= 0) {
565 dates.add(dates.size(), previous);
566 }
567 }
568 } else {
569 AbsoluteDate previous = existingDate;
570 while (date.compareTo(previous) < 0) {
571 previous = previous.shiftedBy(-step);
572 if (previous.compareTo(earliest) >= 0 && previous.compareTo(latest) <= 0) {
573 dates.add(0, previous);
574 }
575 }
576 }
577 return dates;
578 }
579
580 }
581
582 private interface Mode {
583 List<AbsoluteDate> generateDates(AbsoluteDate[] base, double duration, double step);
584 }
585
586 private class SequentialMode implements Mode {
587
588 public List<AbsoluteDate> generateDates(AbsoluteDate[] base, double duration, double step) {
589 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
590 for (final AbsoluteDate initial : base) {
591 for (double dt = 0; dt < duration; dt += step) {
592 list.add(initial.shiftedBy(dt));
593 }
594 }
595 return list;
596 }
597
598 }
599
600 private class AlternateMode implements Mode {
601
602 public List<AbsoluteDate> generateDates(AbsoluteDate[] base, double duration, double step) {
603 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
604 for (double dt = 0; dt < duration; dt += step) {
605 for (final AbsoluteDate initial : base) {
606 list.add(initial.shiftedBy(dt));
607 }
608 }
609 return list;
610 }
611
612 }
613
614 private class RandomMode implements Mode {
615
616 private RandomGenerator random;
617
618 public RandomMode(long seed) {
619 random = new Well1024a(seed);
620 }
621
622 public List<AbsoluteDate> generateDates(AbsoluteDate[] base, double duration, double step) {
623 List<AbsoluteDate> list = new ArrayList<AbsoluteDate>();
624 for (int i = 0; i < base.length * duration / step; ++i) {
625 int j = random.nextInt(base.length);
626 double dt = random.nextDouble() * duration;
627 list.add(base[j].shiftedBy(dt));
628 }
629 return list;
630 }
631
632 }
633
634 @BeforeEach
635 public void setUp() {
636 Utils.setDataRoot("regular-data");
637 }
638 }