1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.frames;
18
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.Optional;
23 import java.util.function.BiFunction;
24 import java.util.function.Consumer;
25 import java.util.function.Function;
26 import java.util.stream.Stream;
27
28 import org.hipparchus.CalculusFieldElement;
29 import org.hipparchus.analysis.interpolation.FieldHermiteInterpolator;
30 import org.hipparchus.analysis.interpolation.HermiteInterpolator;
31 import org.hipparchus.util.FastMath;
32 import org.hipparchus.util.MathArrays;
33 import org.orekit.annotation.DefaultDataContext;
34 import org.orekit.data.DataContext;
35 import org.orekit.errors.OrekitException;
36 import org.orekit.errors.OrekitInternalError;
37 import org.orekit.errors.OrekitMessages;
38 import org.orekit.errors.TimeStampedCacheException;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.FieldAbsoluteDate;
41 import org.orekit.time.TimeScales;
42 import org.orekit.time.TimeStamped;
43 import org.orekit.time.TimeVectorFunction;
44 import org.orekit.utils.Constants;
45 import org.orekit.utils.GenericTimeStampedCache;
46 import org.orekit.utils.IERSConventions;
47 import org.orekit.utils.ImmutableTimeStampedCache;
48 import org.orekit.utils.OrekitConfiguration;
49 import org.orekit.utils.TimeStampedCache;
50 import org.orekit.utils.TimeStampedGenerator;
51
52
53
54
55
56 public class EOPHistory {
57
58
59
60
61 public static final int DEFAULT_INTERPOLATION_DEGREE = 3;
62
63
64
65
66 private final int interpolationDegree;
67
68
69
70
71
72
73 private final boolean hasData;
74
75
76 private final transient ImmutableTimeStampedCache<EOPEntry> cache;
77
78
79 private final IERSConventions conventions;
80
81
82 private final transient TimeVectorFunction tidalCorrection;
83
84
85 private final transient TimeScales timeScales;
86
87
88
89
90
91
92
93
94
95
96
97 @DefaultDataContext
98 protected EOPHistory(final IERSConventions conventions,
99 final int interpolationDegree,
100 final Collection<? extends EOPEntry> data,
101 final boolean simpleEOP) {
102 this(conventions, interpolationDegree, data, simpleEOP, DataContext.getDefault().getTimeScales());
103 }
104
105
106
107
108
109
110
111
112
113 public EOPHistory(final IERSConventions conventions,
114 final int interpolationDegree,
115 final Collection<? extends EOPEntry> data,
116 final boolean simpleEOP,
117 final TimeScales timeScales) {
118 this(conventions, interpolationDegree, data,
119 simpleEOP ? null : new CachedCorrection(conventions.getEOPTidalCorrection(timeScales)),
120 timeScales);
121 }
122
123
124
125
126
127
128
129
130
131 private EOPHistory(final IERSConventions conventions,
132 final int interpolationDegree,
133 final Collection<? extends EOPEntry> data,
134 final TimeVectorFunction tidalCorrection,
135 final TimeScales timeScales) {
136
137
138 final int k = (interpolationDegree + 1) / 4;
139 if (interpolationDegree != 4 * k - 1) {
140 throw new OrekitException(OrekitMessages.WRONG_EOP_INTERPOLATION_DEGREE, interpolationDegree);
141 }
142
143 this.conventions = conventions;
144 this.interpolationDegree = interpolationDegree;
145 this.tidalCorrection = tidalCorrection;
146 this.timeScales = timeScales;
147 if (data.size() >= 1) {
148
149 if (missSomeDerivatives(data)) {
150
151 final ImmutableTimeStampedCache<EOPEntry> rawCache =
152 new ImmutableTimeStampedCache<>(FastMath.min(interpolationDegree + 1, data.size()), data);
153 final List<EOPEntry>fixedData = new ArrayList<>();
154 for (final EOPEntry entry : rawCache.getAll()) {
155 fixedData.add(fixDerivatives(entry, rawCache));
156 }
157 cache = new ImmutableTimeStampedCache<>(FastMath.min(interpolationDegree + 1, fixedData.size()), fixedData);
158 } else {
159 cache = new ImmutableTimeStampedCache<>(FastMath.min(interpolationDegree + 1, data.size()), data);
160 }
161 hasData = true;
162 } else {
163
164 cache = ImmutableTimeStampedCache.emptyCache();
165 hasData = false;
166 }
167 }
168
169
170
171
172
173
174 public boolean isSimpleEop() {
175 return tidalCorrection == null;
176 }
177
178
179
180
181
182 public int getInterpolationDegree() {
183 return interpolationDegree;
184 }
185
186
187
188
189
190
191
192 public TimeScales getTimeScales() {
193 return timeScales;
194 }
195
196
197
198
199
200 public EOPHistory getEOPHistoryWithoutCachedTidalCorrection() {
201 return new EOPHistory(conventions, interpolationDegree, getEntries(),
202 conventions.getEOPTidalCorrection(timeScales),
203 timeScales);
204 }
205
206
207
208
209
210 public boolean cachesTidalCorrection() {
211 return tidalCorrection instanceof CachedCorrection;
212 }
213
214
215
216
217 public IERSConventions getConventions() {
218 return conventions;
219 }
220
221
222
223
224 public AbsoluteDate getStartDate() {
225 return this.cache.getEarliest().getDate();
226 }
227
228
229
230
231 public AbsoluteDate getEndDate() {
232 return this.cache.getLatest().getDate();
233 }
234
235
236
237
238
239
240 public double getUT1MinusUTC(final AbsoluteDate date) {
241
242
243 if (!this.hasDataFor(date)) {
244
245 return (tidalCorrection == null) ? 0.0 : tidalCorrection.value(date)[2];
246 }
247
248
249 try {
250 final DUT1Interpolator interpolator = new DUT1Interpolator(date);
251 getNeighbors(date, interpolationDegree + 1).forEach(interpolator);
252 double interpolated = interpolator.getInterpolated();
253 if (tidalCorrection != null) {
254 interpolated += tidalCorrection.value(date)[2];
255 }
256 return interpolated;
257 } catch (TimeStampedCacheException tce) {
258
259 throw new OrekitInternalError(tce);
260 }
261
262 }
263
264
265
266
267
268
269
270
271 public <T extends CalculusFieldElement<T>> T getUT1MinusUTC(final FieldAbsoluteDate<T> date) {
272
273
274 final AbsoluteDate absDate = date.toAbsoluteDate();
275 if (!this.hasDataFor(absDate)) {
276
277 return (tidalCorrection == null) ? date.getField().getZero() : tidalCorrection.value(date)[2];
278 }
279
280
281 try {
282 final FieldDUT1Interpolator<T> interpolator = new FieldDUT1Interpolator<>(date, absDate);
283 getNeighbors(absDate, interpolationDegree + 1).forEach(interpolator);
284 T interpolated = interpolator.getInterpolated();
285 if (tidalCorrection != null) {
286 interpolated = interpolated.add(tidalCorrection.value(date)[2]);
287 }
288 return interpolated;
289 } catch (TimeStampedCacheException tce) {
290
291 throw new OrekitInternalError(tce);
292 }
293
294 }
295
296
297 private static class DUT1Interpolator implements Consumer<EOPEntry> {
298
299
300 private double firstDUT;
301
302
303 private boolean beforeLeap;
304
305
306 private final HermiteInterpolator interpolator;
307
308
309 private AbsoluteDate date;
310
311
312
313
314 DUT1Interpolator(final AbsoluteDate date) {
315 this.firstDUT = Double.NaN;
316 this.beforeLeap = true;
317 this.interpolator = new HermiteInterpolator();
318 this.date = date;
319 }
320
321
322 @Override
323 public void accept(final EOPEntry neighbor) {
324 if (Double.isNaN(firstDUT)) {
325 firstDUT = neighbor.getUT1MinusUTC();
326 }
327 final double dut;
328 if (neighbor.getUT1MinusUTC() - firstDUT > 0.9) {
329
330 dut = neighbor.getUT1MinusUTC() - 1.0;
331
332
333
334
335 if (neighbor.getDate().shiftedBy(-1).compareTo(date) <= 0) {
336 beforeLeap = false;
337 }
338 } else {
339 dut = neighbor.getUT1MinusUTC();
340 }
341 interpolator.addSamplePoint(neighbor.getDate().durationFrom(date),
342 new double[] {
343 dut
344 });
345 }
346
347
348
349
350 public double getInterpolated() {
351 final double interpolated = interpolator.value(0)[0];
352 return beforeLeap ? interpolated : interpolated + 1.0;
353 }
354
355 }
356
357
358 private static class FieldDUT1Interpolator<T extends CalculusFieldElement<T>> implements Consumer<EOPEntry> {
359
360
361 private double firstDUT;
362
363
364 private boolean beforeLeap;
365
366
367 private final FieldHermiteInterpolator<T> interpolator;
368
369
370 private FieldAbsoluteDate<T> date;
371
372
373 private AbsoluteDate absDate;
374
375
376
377
378
379 FieldDUT1Interpolator(final FieldAbsoluteDate<T> date, final AbsoluteDate absDate) {
380 this.firstDUT = Double.NaN;
381 this.beforeLeap = true;
382 this.interpolator = new FieldHermiteInterpolator<>();
383 this.date = date;
384 this.absDate = absDate;
385 }
386
387
388 @Override
389 public void accept(final EOPEntry neighbor) {
390 if (Double.isNaN(firstDUT)) {
391 firstDUT = neighbor.getUT1MinusUTC();
392 }
393 final double dut;
394 if (neighbor.getUT1MinusUTC() - firstDUT > 0.9) {
395
396 dut = neighbor.getUT1MinusUTC() - 1.0;
397 if (neighbor.getDate().compareTo(absDate) <= 0) {
398 beforeLeap = false;
399 }
400 } else {
401 dut = neighbor.getUT1MinusUTC();
402 }
403 final T[] array = MathArrays.buildArray(date.getField(), 1);
404 array[0] = date.getField().getZero().newInstance(dut);
405 interpolator.addSamplePoint(date.durationFrom(neighbor.getDate()).negate(),
406 array);
407 }
408
409
410
411
412 public T getInterpolated() {
413 final T interpolated = interpolator.value(date.getField().getZero())[0];
414 return beforeLeap ? interpolated : interpolated.add(1.0);
415 }
416
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430 protected Stream<EOPEntry> getNeighbors(final AbsoluteDate central, final int n) {
431 return cache.getNeighbors(central, n);
432 }
433
434
435
436
437
438
439 public double getLOD(final AbsoluteDate date) {
440
441
442 if (!this.hasDataFor(date)) {
443
444 return (tidalCorrection == null) ? 0.0 : tidalCorrection.value(date)[3];
445 }
446
447
448 double interpolated = interpolate(date, EOPEntry::getLOD);
449 if (tidalCorrection != null) {
450 interpolated += tidalCorrection.value(date)[3];
451 }
452 return interpolated;
453
454 }
455
456
457
458
459
460
461
462
463 public <T extends CalculusFieldElement<T>> T getLOD(final FieldAbsoluteDate<T> date) {
464
465 final AbsoluteDate aDate = date.toAbsoluteDate();
466
467
468 if (!this.hasDataFor(aDate)) {
469
470 return (tidalCorrection == null) ? date.getField().getZero() : tidalCorrection.value(date)[3];
471 }
472
473
474 T interpolated = interpolate(date, aDate, EOPEntry::getLOD);
475 if (tidalCorrection != null) {
476 interpolated = interpolated.add(tidalCorrection.value(date)[3]);
477 }
478
479 return interpolated;
480
481 }
482
483
484
485
486
487
488
489 public PoleCorrection getPoleCorrection(final AbsoluteDate date) {
490
491
492 if (!this.hasDataFor(date)) {
493
494 if (tidalCorrection == null) {
495 return PoleCorrection.NULL_CORRECTION;
496 } else {
497 final double[] correction = tidalCorrection.value(date);
498 return new PoleCorrection(correction[0], correction[1]);
499 }
500 }
501
502
503 final double[] interpolated = interpolate(date,
504 EOPEntry::getX, EOPEntry::getY,
505 EOPEntry::getXRate, EOPEntry::getYRate);
506 if (tidalCorrection != null) {
507 final double[] correction = tidalCorrection.value(date);
508 interpolated[0] += correction[0];
509 interpolated[1] += correction[1];
510 }
511 return new PoleCorrection(interpolated[0], interpolated[1]);
512
513 }
514
515
516
517
518
519
520
521
522 public <T extends CalculusFieldElement<T>> FieldPoleCorrection<T> getPoleCorrection(final FieldAbsoluteDate<T> date) {
523
524 final AbsoluteDate aDate = date.toAbsoluteDate();
525
526
527 if (!this.hasDataFor(aDate)) {
528
529 if (tidalCorrection == null) {
530 return new FieldPoleCorrection<>(date.getField().getZero(), date.getField().getZero());
531 } else {
532 final T[] correction = tidalCorrection.value(date);
533 return new FieldPoleCorrection<>(correction[0], correction[1]);
534 }
535 }
536
537
538 final T[] interpolated = interpolate(date, aDate, EOPEntry::getX, EOPEntry::getY);
539 if (tidalCorrection != null) {
540 final T[] correction = tidalCorrection.value(date);
541 interpolated[0] = interpolated[0].add(correction[0]);
542 interpolated[1] = interpolated[1].add(correction[1]);
543 }
544 return new FieldPoleCorrection<>(interpolated[0], interpolated[1]);
545
546 }
547
548
549
550
551
552
553
554 public double[] getEquinoxNutationCorrection(final AbsoluteDate date) {
555
556
557 if (!this.hasDataFor(date)) {
558
559 return new double[2];
560 }
561
562
563 return interpolate(date, EOPEntry::getDdPsi, EOPEntry::getDdEps);
564
565 }
566
567
568
569
570
571
572
573
574 public <T extends CalculusFieldElement<T>> T[] getEquinoxNutationCorrection(final FieldAbsoluteDate<T> date) {
575
576 final AbsoluteDate aDate = date.toAbsoluteDate();
577
578
579 if (!this.hasDataFor(aDate)) {
580
581 return MathArrays.buildArray(date.getField(), 2);
582 }
583
584
585 return interpolate(date, aDate, EOPEntry::getDdPsi, EOPEntry::getDdEps);
586
587 }
588
589
590
591
592
593
594
595 public double[] getNonRotatinOriginNutationCorrection(final AbsoluteDate date) {
596
597
598 if (!this.hasDataFor(date)) {
599
600 return new double[2];
601 }
602
603
604 return interpolate(date, EOPEntry::getDx, EOPEntry::getDy);
605
606 }
607
608
609
610
611
612
613
614
615 public <T extends CalculusFieldElement<T>> T[] getNonRotatinOriginNutationCorrection(final FieldAbsoluteDate<T> date) {
616
617 final AbsoluteDate aDate = date.toAbsoluteDate();
618
619
620 if (!this.hasDataFor(aDate)) {
621
622 return MathArrays.buildArray(date.getField(), 2);
623 }
624
625
626 return interpolate(date, aDate, EOPEntry::getDx, EOPEntry::getDy);
627
628 }
629
630
631
632
633
634
635 public ITRFVersion getITRFVersion(final AbsoluteDate date) {
636
637
638 if (!this.hasDataFor(date)) {
639
640 return ITRFVersion.ITRF_2014;
641 }
642
643 try {
644
645 final Optional<EOPEntry> first = getNeighbors(date, 1).findFirst();
646 return first.isPresent() ? first.get().getITRFType() : ITRFVersion.ITRF_2014;
647
648 } catch (TimeStampedCacheException tce) {
649
650 throw new OrekitInternalError(tce);
651 }
652
653 }
654
655
656
657
658 public void checkEOPContinuity(final double maxGap) {
659 TimeStamped preceding = null;
660 for (final TimeStamped current : this.cache.getAll()) {
661
662
663 if (preceding != null && (current.getDate().durationFrom(preceding.getDate())) > maxGap) {
664 throw new OrekitException(OrekitMessages.MISSING_EARTH_ORIENTATION_PARAMETERS_BETWEEN_DATES_GAP,
665 preceding.getDate(), current.getDate(),
666 current.getDate().durationFrom(preceding.getDate()));
667 }
668
669
670 preceding = current;
671
672 }
673 }
674
675
676
677
678
679
680
681
682
683 protected boolean hasDataFor(final AbsoluteDate date) {
684
685
686
687
688 return this.hasData && this.getStartDate().compareTo(date) <= 0 &&
689 date.compareTo(this.getEndDate()) <= 0;
690 }
691
692
693
694
695 public List<EOPEntry> getEntries() {
696 return cache.getAll();
697 }
698
699
700
701
702
703
704
705
706
707 private double interpolate(final AbsoluteDate date, final Function<EOPEntry, Double> selector) {
708 try {
709 final HermiteInterpolator interpolator = new HermiteInterpolator();
710 getNeighbors(date, interpolationDegree + 1).
711 forEach(entry -> interpolator.addSamplePoint(entry.getDate().durationFrom(date),
712 new double[] {
713 selector.apply(entry)
714 }));
715 return interpolator.value(0)[0];
716 } catch (TimeStampedCacheException tce) {
717
718 throw new OrekitInternalError(tce);
719 }
720 }
721
722
723
724
725
726
727
728
729
730
731
732 private <T extends CalculusFieldElement<T>> T interpolate(final FieldAbsoluteDate<T> date,
733 final AbsoluteDate aDate,
734 final Function<EOPEntry, Double> selector) {
735 try {
736 final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<>();
737 final T[] y = MathArrays.buildArray(date.getField(), 1);
738 final T zero = date.getField().getZero();
739 final FieldAbsoluteDate<T> central = new FieldAbsoluteDate<>(aDate, zero);
740
741
742 getNeighbors(aDate, interpolationDegree + 1).
743 forEach(entry -> {
744 y[0] = zero.newInstance(selector.apply(entry));
745 interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y);
746 });
747 return interpolator.value(date.durationFrom(central))[0];
748 } catch (TimeStampedCacheException tce) {
749
750 throw new OrekitInternalError(tce);
751 }
752 }
753
754
755
756
757
758
759
760
761
762
763 private double[] interpolate(final AbsoluteDate date,
764 final Function<EOPEntry, Double> selector1,
765 final Function<EOPEntry, Double> selector2) {
766 try {
767 final HermiteInterpolator interpolator = new HermiteInterpolator();
768 getNeighbors(date, interpolationDegree + 1).
769 forEach(entry -> interpolator.addSamplePoint(entry.getDate().durationFrom(date),
770 new double[] {
771 selector1.apply(entry),
772 selector2.apply(entry)
773 }));
774 return interpolator.value(0);
775 } catch (TimeStampedCacheException tce) {
776
777 throw new OrekitInternalError(tce);
778 }
779 }
780
781
782
783
784
785
786
787
788
789
790
791
792
793 private double[] interpolate(final AbsoluteDate date,
794 final Function<EOPEntry, Double> selector1,
795 final Function<EOPEntry, Double> selector2,
796 final Function<EOPEntry, Double> selector1Rate,
797 final Function<EOPEntry, Double> selector2Rate) {
798 try {
799 final HermiteInterpolator interpolator = new HermiteInterpolator();
800 getNeighbors(date, (interpolationDegree + 1) / 2).
801 forEach(entry -> interpolator.addSamplePoint(entry.getDate().durationFrom(date),
802 new double[] {
803 selector1.apply(entry),
804 selector2.apply(entry)
805 },
806 new double[] {
807 selector1Rate.apply(entry),
808 selector2Rate.apply(entry)
809 }));
810 return interpolator.value(0);
811 } catch (TimeStampedCacheException tce) {
812
813 throw new OrekitInternalError(tce);
814 }
815 }
816
817
818
819
820
821
822
823
824
825
826
827
828 private <T extends CalculusFieldElement<T>> T[] interpolate(final FieldAbsoluteDate<T> date,
829 final AbsoluteDate aDate,
830 final Function<EOPEntry, Double> selector1,
831 final Function<EOPEntry, Double> selector2) {
832 try {
833 final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<>();
834 final T[] y = MathArrays.buildArray(date.getField(), 2);
835 final T zero = date.getField().getZero();
836 final FieldAbsoluteDate<T> central = new FieldAbsoluteDate<>(aDate, zero);
837
838
839 getNeighbors(aDate, interpolationDegree + 1).
840 forEach(entry -> {
841 y[0] = zero.newInstance(selector1.apply(entry));
842 y[1] = zero.newInstance(selector2.apply(entry));
843 interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y);
844 });
845 return interpolator.value(date.durationFrom(central));
846 } catch (TimeStampedCacheException tce) {
847
848 throw new OrekitInternalError(tce);
849 }
850 }
851
852
853
854
855
856
857 private boolean missSomeDerivatives(final Collection<? extends EOPEntry> raw) {
858 for (final EOPEntry entry : raw) {
859 if (Double.isNaN(entry.getLOD() + entry.getXRate() + entry.getYRate())) {
860 return true;
861 }
862 }
863 return false;
864 }
865
866
867
868
869
870
871
872 private EOPEntry fixDerivatives(final EOPEntry entry, final ImmutableTimeStampedCache<EOPEntry> rawCache) {
873
874
875 final BiFunction<EOPEntry, Function<EOPEntry, Double>, Double> differentiator =
876 (e, selector) -> {
877 final HermiteInterpolator interpolator = new HermiteInterpolator();
878 rawCache.getNeighbors(e.getDate()).
879 forEach(f -> interpolator.addSamplePoint(f.getDate().durationFrom(e.getDate()),
880 new double[] {
881 selector.apply(f)
882 }));
883 return interpolator.derivatives(0.0, 1)[1][0];
884 };
885
886 if (Double.isNaN(entry.getLOD() + entry.getXRate() + entry.getYRate())) {
887 final double lod = Double.isNaN(entry.getLOD()) ?
888 -differentiator.apply(entry, EOPEntry::getUT1MinusUTC) :
889 entry.getLOD();
890 final double xRate = Double.isNaN(entry.getXRate()) ?
891 differentiator.apply(entry, EOPEntry::getX) :
892 entry.getXRate();
893 final double yRate = Double.isNaN(entry.getYRate()) ?
894 differentiator.apply(entry, EOPEntry::getY) :
895 entry.getYRate();
896 return new EOPEntry(entry.getMjd(),
897 entry.getUT1MinusUTC(), lod,
898 entry.getX(), entry.getY(), xRate, yRate,
899 entry.getDdPsi(), entry.getDdEps(),
900 entry.getDx(), entry.getDy(),
901 entry.getITRFType(), entry.getDate());
902 } else {
903
904 return entry;
905 }
906 }
907
908
909 private static class TidalCorrectionEntry implements TimeStamped {
910
911
912 private final AbsoluteDate date;
913
914
915 private final double[] correction;
916
917
918
919
920
921 TidalCorrectionEntry(final AbsoluteDate date, final double[] correction) {
922 this.date = date;
923 this.correction = correction;
924 }
925
926
927 @Override
928 public AbsoluteDate getDate() {
929 return date;
930 }
931
932 }
933
934
935 private static class CachedCorrection
936 implements TimeVectorFunction, TimeStampedGenerator<TidalCorrectionEntry> {
937
938
939 private final TimeVectorFunction tidalCorrection;
940
941
942 private final double step;
943
944
945 private final TimeStampedCache<TidalCorrectionEntry> cache;
946
947
948
949
950 CachedCorrection(final TimeVectorFunction tidalCorrection) {
951 this.step = 60 * 60;
952 this.tidalCorrection = tidalCorrection;
953 this.cache =
954 new GenericTimeStampedCache<>(8,
955 OrekitConfiguration.getCacheSlotsNumber(),
956 Constants.JULIAN_DAY * 30,
957 Constants.JULIAN_DAY,
958 this);
959 }
960
961
962 @Override
963 public double[] value(final AbsoluteDate date) {
964 try {
965
966 final HermiteInterpolator interpolator = new HermiteInterpolator();
967 cache.getNeighbors(date).forEach(entry -> interpolator.addSamplePoint(entry.date.durationFrom(date), entry.correction));
968
969
970 return interpolator.value(0.0);
971 } catch (TimeStampedCacheException tsce) {
972
973 throw new OrekitInternalError(tsce);
974 }
975 }
976
977
978 @Override
979 public <T extends CalculusFieldElement<T>> T[] value(final FieldAbsoluteDate<T> date) {
980 try {
981
982 final AbsoluteDate aDate = date.toAbsoluteDate();
983
984 final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<>();
985 final T[] y = MathArrays.buildArray(date.getField(), 4);
986 final T zero = date.getField().getZero();
987 final FieldAbsoluteDate<T> central = new FieldAbsoluteDate<>(aDate, zero);
988
989
990 cache.getNeighbors(aDate).forEach(entry -> {
991 for (int i = 0; i < y.length; ++i) {
992 y[i] = zero.newInstance(entry.correction[i]);
993 }
994 interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y);
995 });
996
997
998 return interpolator.value(date.durationFrom(central));
999
1000 } catch (TimeStampedCacheException tsce) {
1001
1002 throw new OrekitInternalError(tsce);
1003 }
1004 }
1005
1006
1007 @Override
1008 public List<TidalCorrectionEntry> generate(final AbsoluteDate existingDate, final AbsoluteDate date) {
1009
1010 final List<TidalCorrectionEntry> generated = new ArrayList<>();
1011
1012 if (existingDate == null) {
1013
1014
1015 for (int i = -cache.getMaxNeighborsSize() / 2; generated.size() < cache.getMaxNeighborsSize(); ++i) {
1016 final AbsoluteDate t = date.shiftedBy(i * step);
1017 generated.add(new TidalCorrectionEntry(t, tidalCorrection.value(t)));
1018 }
1019
1020 } else {
1021
1022
1023
1024
1025 AbsoluteDate t = existingDate;
1026 if (date.compareTo(t) > 0) {
1027
1028 do {
1029 t = t.shiftedBy(step);
1030 generated.add(new TidalCorrectionEntry(t, tidalCorrection.value(t)));
1031 } while (t.compareTo(date) <= 0);
1032 } else {
1033
1034 do {
1035 t = t.shiftedBy(-step);
1036 generated.add(0, new TidalCorrectionEntry(t, tidalCorrection.value(t)));
1037 } while (t.compareTo(date) >= 0);
1038 }
1039 }
1040
1041
1042 return generated;
1043
1044 }
1045 }
1046
1047 }