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.io.Serializable;
20 import java.util.Collection;
21 import java.util.List;
22
23 import org.apache.commons.math3.analysis.interpolation.HermiteInterpolator;
24 import org.orekit.errors.OrekitException;
25 import org.orekit.errors.OrekitMessages;
26 import org.orekit.errors.TimeStampedCacheException;
27 import org.orekit.time.AbsoluteDate;
28 import org.orekit.time.TimeFunction;
29 import org.orekit.time.TimeStamped;
30 import org.orekit.utils.IERSConventions;
31 import org.orekit.utils.ImmutableTimeStampedCache;
32
33
34
35
36 public class EOPHistory implements Serializable {
37
38
39 private static final long serialVersionUID = 20131010L;
40
41
42 private static final int INTERPOLATION_POINTS = 4;
43
44
45
46
47
48
49 private final boolean hasData;
50
51
52 private final transient ImmutableTimeStampedCache<EOPEntry> cache;
53
54
55 private final IERSConventions conventions;
56
57
58 private final transient TimeFunction<double[]> tidalCorrection;
59
60
61
62
63
64
65
66 protected EOPHistory(final IERSConventions conventions,
67 final Collection<EOPEntry> data,
68 final boolean simpleEOP)
69 throws OrekitException {
70 this.conventions = conventions;
71 tidalCorrection = simpleEOP ? null : conventions.getEOPTidalCorrection();
72 if (data.size() >= INTERPOLATION_POINTS) {
73
74 cache = new ImmutableTimeStampedCache<EOPEntry>(INTERPOLATION_POINTS, data);
75 hasData = true;
76 } else {
77
78 cache = ImmutableTimeStampedCache.emptyCache();
79 hasData = false;
80 }
81 }
82
83
84
85
86 public IERSConventions getConventions() {
87 return conventions;
88 }
89
90
91
92
93 public AbsoluteDate getStartDate() {
94 return this.cache.getEarliest().getDate();
95 }
96
97
98
99
100 public AbsoluteDate getEndDate() {
101 return this.cache.getLatest().getDate();
102 }
103
104
105
106
107
108
109 public double getUT1MinusUTC(final AbsoluteDate date) {
110
111 if (!this.hasDataFor(date)) {
112
113 return (tidalCorrection == null) ? 0.0 : tidalCorrection.value(date)[2];
114 }
115
116 try {
117 final List<EOPEntry> neighbors = getNeighbors(date);
118 final HermiteInterpolator interpolator = new HermiteInterpolator();
119 final double firstDUT = neighbors.get(0).getUT1MinusUTC();
120 boolean beforeLeap = true;
121 for (final EOPEntry neighbor : neighbors) {
122 final double dut;
123 if (neighbor.getUT1MinusUTC() - firstDUT > 0.9) {
124
125 dut = neighbor.getUT1MinusUTC() - 1.0;
126 if (neighbor.getDate().compareTo(date) <= 0) {
127 beforeLeap = false;
128 }
129 } else {
130 dut = neighbor.getUT1MinusUTC();
131 }
132 interpolator.addSamplePoint(neighbor.getDate().durationFrom(date),
133 new double[] {
134 dut
135 });
136 }
137 double interpolated = interpolator.value(0)[0];
138 if (tidalCorrection != null) {
139 interpolated += tidalCorrection.value(date)[2];
140 }
141 return beforeLeap ? interpolated : interpolated + 1.0;
142 } catch (TimeStampedCacheException tce) {
143
144 throw OrekitException.createInternalError(tce);
145 }
146 }
147
148
149
150
151
152
153
154
155
156
157
158 protected List<EOPEntry> getNeighbors(final AbsoluteDate central) throws TimeStampedCacheException {
159 return cache.getNeighbors(central);
160 }
161
162
163
164
165
166
167 public double getLOD(final AbsoluteDate date) {
168
169 if (!this.hasDataFor(date)) {
170
171 return (tidalCorrection == null) ? 0.0 : tidalCorrection.value(date)[3];
172 }
173
174 try {
175 final HermiteInterpolator interpolator = new HermiteInterpolator();
176 for (final EOPEntry entry : getNeighbors(date)) {
177 interpolator.addSamplePoint(entry.getDate().durationFrom(date),
178 new double[] {
179 entry.getLOD()
180 });
181 }
182 double interpolated = interpolator.value(0)[0];
183 if (tidalCorrection != null) {
184 interpolated += tidalCorrection.value(date)[3];
185 }
186 return interpolated;
187 } catch (TimeStampedCacheException tce) {
188
189 throw OrekitException.createInternalError(tce);
190 }
191 }
192
193
194
195
196
197
198
199 public PoleCorrection getPoleCorrection(final AbsoluteDate date) {
200
201 if (!this.hasDataFor(date)) {
202
203 if (tidalCorrection == null) {
204 return PoleCorrection.NULL_CORRECTION;
205 } else {
206 final double[] correction = tidalCorrection.value(date);
207 return new PoleCorrection(correction[0], correction[1]);
208 }
209 }
210
211 try {
212 final HermiteInterpolator interpolator = new HermiteInterpolator();
213 for (final EOPEntry entry : getNeighbors(date)) {
214 interpolator.addSamplePoint(entry.getDate().durationFrom(date),
215 new double[] {
216 entry.getX(), entry.getY()
217 });
218 }
219 final double[] interpolated = interpolator.value(0);
220 if (tidalCorrection != null) {
221 final double[] correction = tidalCorrection.value(date);
222 interpolated[0] += correction[0];
223 interpolated[1] += correction[1];
224 }
225 return new PoleCorrection(interpolated[0], interpolated[1]);
226 } catch (TimeStampedCacheException tce) {
227
228 throw OrekitException.createInternalError(tce);
229 }
230 }
231
232
233
234
235
236
237
238 public double[] getEquinoxNutationCorrection(final AbsoluteDate date) {
239
240 if (!this.hasDataFor(date)) {
241
242 return new double[2];
243 }
244
245 try {
246 final HermiteInterpolator interpolator = new HermiteInterpolator();
247 for (final EOPEntry entry : getNeighbors(date)) {
248 interpolator.addSamplePoint(entry.getDate().durationFrom(date),
249 new double[] {
250 entry.getDdPsi(), entry.getDdEps()
251 });
252 }
253 return interpolator.value(0);
254 } catch (TimeStampedCacheException tce) {
255
256 throw OrekitException.createInternalError(tce);
257 }
258 }
259
260
261
262
263
264
265
266 public double[] getNonRotatinOriginNutationCorrection(final AbsoluteDate date) {
267
268 if (!this.hasDataFor(date)) {
269
270 return new double[2];
271 }
272
273 try {
274 final HermiteInterpolator interpolator = new HermiteInterpolator();
275 for (final EOPEntry entry : getNeighbors(date)) {
276 interpolator.addSamplePoint(entry.getDate().durationFrom(date),
277 new double[] {
278 entry.getDx(), entry.getDy()
279 });
280 }
281 return interpolator.value(0);
282 } catch (TimeStampedCacheException tce) {
283
284 throw OrekitException.createInternalError(tce);
285 }
286 }
287
288
289
290
291
292 public void checkEOPContinuity(final double maxGap) throws OrekitException {
293 TimeStamped preceding = null;
294 for (final TimeStamped current : this.cache.getAll()) {
295
296
297 if ((preceding != null) && ((current.getDate().durationFrom(preceding.getDate())) > maxGap)) {
298 throw new OrekitException(OrekitMessages.MISSING_EARTH_ORIENTATION_PARAMETERS_BETWEEN_DATES,
299 preceding.getDate(), current.getDate());
300 }
301
302
303 preceding = current;
304
305 }
306 }
307
308
309
310
311
312
313
314
315
316 protected boolean hasDataFor(final AbsoluteDate date) {
317
318
319
320
321 return this.hasData && this.getStartDate().compareTo(date) <= 0 &&
322 date.compareTo(this.getEndDate()) <= 0;
323 }
324
325
326
327
328 List<EOPEntry> getEntries() {
329 return cache.getAll();
330 }
331
332
333
334
335
336
337
338 private Object writeReplace() {
339 return new DataTransferObject(conventions, getEntries(), tidalCorrection == null);
340 }
341
342
343 private static class DataTransferObject implements Serializable {
344
345
346 private static final long serialVersionUID = 20131010L;
347
348
349 private final IERSConventions conventions;
350
351
352 private final List<EOPEntry> entries;
353
354
355 private final boolean simpleEOP;
356
357
358
359
360
361
362 public DataTransferObject(final IERSConventions conventions,
363 final List<EOPEntry> entries,
364 final boolean simpleEOP) {
365 this.conventions = conventions;
366 this.entries = entries;
367 this.simpleEOP = simpleEOP;
368 }
369
370
371
372
373 private Object readResolve() {
374 try {
375
376 return new EOPHistory(conventions, entries, simpleEOP);
377 } catch (OrekitException oe) {
378 throw OrekitException.createInternalError(oe);
379 }
380 }
381
382 }
383
384 }