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.BufferedReader;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.function.Supplier;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27
28 import org.orekit.data.DataProvidersManager;
29 import org.orekit.data.DataSource;
30 import org.orekit.errors.OrekitException;
31 import org.orekit.errors.OrekitMessages;
32 import org.orekit.time.AbsoluteDate;
33 import org.orekit.time.DateComponents;
34 import org.orekit.time.TimeScale;
35 import org.orekit.utils.IERSConventions;
36 import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
37 import org.orekit.utils.units.UnitsConverter;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 class RapidDataAndPredictionColumnsLoader extends AbstractEopLoader
64 implements EopHistoryLoader {
65
66
67 private static final String INTEGER2_FIELD = "((?:\\p{Blank}|\\p{Digit})\\p{Digit})";
68
69
70 private static final String MJD_FIELD = "\\p{Blank}+(\\p{Digit}+)\\.00*";
71
72
73 private static final String SEPARATOR = "\\p{Blank}*([IP])";
74
75
76 private static final String REAL_FIELD = "\\p{Blank}*(-?\\p{Digit}*\\.\\p{Digit}*)";
77
78
79 private static final int DATE_START = 0;
80
81
82 private static final int DATE_END = 15;
83
84
85 private static final Pattern DATE_PATTERN = Pattern.compile(INTEGER2_FIELD + INTEGER2_FIELD + INTEGER2_FIELD + MJD_FIELD);
86
87
88 private static final int POLE_START_A = 16;
89
90
91 private static final int POLE_END_A = 55;
92
93
94 private static final Pattern POLE_PATTERN_A = Pattern.compile(SEPARATOR + REAL_FIELD + REAL_FIELD + REAL_FIELD + REAL_FIELD);
95
96
97 private static final int POLE_START_B = 134;
98
99
100 private static final int POLE_END_B = 154;
101
102
103 private static final Pattern POLE_PATTERN_B = Pattern.compile(REAL_FIELD + REAL_FIELD);
104
105
106 private static final int UT1_UTC_START_A = 57;
107
108
109 private static final int UT1_UTC_END_A = 78;
110
111
112 private static final Pattern UT1_UTC_PATTERN_A = Pattern.compile(SEPARATOR + REAL_FIELD + REAL_FIELD);
113
114
115 private static final int UT1_UTC_START_B = 154;
116
117
118 private static final int UT1_UTC_END_B = 165;
119
120
121 private static final Pattern UT1_UTC_PATTERN_B = Pattern.compile(REAL_FIELD);
122
123
124 private static final int LOD_START_A = 79;
125
126
127 private static final int LOD_END_A = 93;
128
129
130 private static final Pattern LOD_PATTERN_A = Pattern.compile(REAL_FIELD + REAL_FIELD);
131
132
133
134
135 private static final int NUTATION_START_A = 95;
136
137
138 private static final int NUTATION_END_A = 134;
139
140
141 private static final Pattern NUTATION_PATTERN_A = Pattern.compile(SEPARATOR + REAL_FIELD + REAL_FIELD + REAL_FIELD + REAL_FIELD);
142
143
144 private static final int NUTATION_START_B = 165;
145
146
147 private static final int NUTATION_END_B = 185;
148
149
150 private static final Pattern NUTATION_PATTERN_B = Pattern.compile(REAL_FIELD + REAL_FIELD);
151
152
153 private final boolean isNonRotatingOrigin;
154
155
156
157
158
159
160
161
162
163
164 RapidDataAndPredictionColumnsLoader(final boolean isNonRotatingOrigin,
165 final String supportedNames,
166 final DataProvidersManager manager,
167 final Supplier<TimeScale> utcSupplier) {
168 super(supportedNames, manager, utcSupplier);
169 this.isNonRotatingOrigin = isNonRotatingOrigin;
170 }
171
172
173 public void fillHistory(final IERSConventions.NutationCorrectionConverter converter,
174 final Collection<EOPEntry> history) {
175 final ItrfVersionProvider itrfVersionProvider = new ITRFVersionLoader(
176 ITRFVersionLoader.SUPPORTED_NAMES,
177 getDataProvidersManager());
178 final Parser parser =
179 new Parser(converter, itrfVersionProvider, getUtc(), isNonRotatingOrigin);
180 final EopParserLoader loader = new EopParserLoader(parser);
181 this.feed(loader);
182 history.addAll(loader.getEop());
183 }
184
185
186 static class Parser extends AbstractEopParser {
187
188
189 private final boolean isNonRotatingOrigin;
190
191
192
193
194
195
196
197 Parser(final NutationCorrectionConverter converter,
198 final ItrfVersionProvider itrfVersionProvider,
199 final TimeScale utc,
200 final boolean isNonRotatingOrigin) {
201 super(converter, itrfVersionProvider, utc);
202 this.isNonRotatingOrigin = isNonRotatingOrigin;
203 }
204
205
206 @Override
207 public Collection<EOPEntry> parse(final DataSource source)
208 throws IOException {
209
210 final List<EOPEntry> history = new ArrayList<>();
211 ITRFVersionLoader.ITRFVersionConfiguration configuration = null;
212
213
214 int lineNumber = 0;
215
216
217 try (BufferedReader reader = new BufferedReader(source.getOpener().openReaderOnce())) {
218
219 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
220
221 lineNumber++;
222
223
224 final String datePart = getPart(line, DATE_START, DATE_END);
225 final String polePartA = getPart(line, POLE_START_A, POLE_END_A);
226 final String ut1utcPartA = getPart(line, UT1_UTC_START_A, UT1_UTC_END_A);
227 final String lodPartA = getPart(line, LOD_START_A, LOD_END_A);
228 final String nutationPartA = getPart(line, NUTATION_START_A, NUTATION_END_A);
229 final String polePartB = getPart(line, POLE_START_B, POLE_END_B);
230 final String ut1utcPartB = getPart(line, UT1_UTC_START_B, UT1_UTC_END_B);
231 final String nutationPartB = getPart(line, NUTATION_START_B, NUTATION_END_B);
232
233
234 final Matcher dateMatcher = DATE_PATTERN.matcher(datePart);
235 final int mjd;
236 if (dateMatcher.matches()) {
237 final int yy = Integer.parseInt(dateMatcher.group(1).trim());
238 final int mm = Integer.parseInt(dateMatcher.group(2).trim());
239 final int dd = Integer.parseInt(dateMatcher.group(3).trim());
240 mjd = Integer.parseInt(dateMatcher.group(4).trim());
241 final DateComponents reconstructedDate = new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjd);
242 if ((reconstructedDate.getYear() % 100) != yy ||
243 reconstructedDate.getMonth() != mm ||
244 reconstructedDate.getDay() != dd) {
245 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
246 lineNumber, source.getName(), line);
247 }
248 } else {
249 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
250 lineNumber, source.getName(), line);
251 }
252
253
254 EopDataType eopDataType = EopDataType.UNKNOWN;
255
256
257 final double x;
258 final double y;
259 if (polePartB.trim().isEmpty()) {
260
261 if (polePartA.trim().isEmpty()) {
262
263 x = 0;
264 y = 0;
265 } else {
266 final Matcher poleAMatcher = POLE_PATTERN_A.matcher(polePartA);
267 if (poleAMatcher.matches()) {
268 x = UnitsConverter.ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(poleAMatcher.group(2)));
269 y = UnitsConverter.ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(poleAMatcher.group(4)));
270 eopDataType = getEopDataType(poleAMatcher);
271 } else {
272 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
273 lineNumber, source.getName(), line);
274 }
275 }
276 } else {
277 final Matcher poleBMatcher = POLE_PATTERN_B.matcher(polePartB);
278 if (poleBMatcher.matches()) {
279 x = UnitsConverter.ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(poleBMatcher.group(1)));
280 y = UnitsConverter.ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(poleBMatcher.group(2)));
281 eopDataType = EopDataType.FINAL;
282 } else {
283 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
284 lineNumber, source.getName(), line);
285 }
286 }
287
288
289 final double dtu1;
290 if (ut1utcPartB.trim().isEmpty()) {
291
292 if (ut1utcPartA.trim().isEmpty()) {
293
294 dtu1 = 0;
295 } else {
296 final Matcher ut1utcAMatcher = UT1_UTC_PATTERN_A.matcher(ut1utcPartA);
297 if (ut1utcAMatcher.matches()) {
298 dtu1 = Double.parseDouble(ut1utcAMatcher.group(2));
299 eopDataType = updateEopDataTypeIfUnknown(eopDataType, () -> getEopDataType(ut1utcAMatcher));
300 } else {
301 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
302 lineNumber, source.getName(), line);
303 }
304 }
305 } else {
306 final Matcher ut1utcBMatcher = UT1_UTC_PATTERN_B.matcher(ut1utcPartB);
307 if (ut1utcBMatcher.matches()) {
308 dtu1 = Double.parseDouble(ut1utcBMatcher.group(1));
309 eopDataType = updateEopDataTypeIfUnknown(eopDataType, () -> EopDataType.FINAL);
310 } else {
311 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
312 lineNumber, source.getName(), line);
313 }
314 }
315
316
317 final double lod;
318 if (lodPartA.trim().isEmpty()) {
319
320 lod = Double.NaN;
321 } else {
322 final Matcher lodAMatcher = LOD_PATTERN_A.matcher(lodPartA);
323 if (lodAMatcher.matches()) {
324 lod = UnitsConverter.MILLI_SECONDS_TO_SECONDS.convert(Double.parseDouble(lodAMatcher.group(1)));
325 } else {
326 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
327 lineNumber, source.getName(), line);
328 }
329 }
330
331
332 final double[] nro;
333 final double[] equinox;
334 final AbsoluteDate mjdDate =
335 new AbsoluteDate(new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjd),
336 getUtc());
337 if (nutationPartB.trim().isEmpty()) {
338
339 if (nutationPartA.trim().isEmpty()) {
340
341 nro = new double[2];
342 equinox = new double[2];
343 } else {
344 final Matcher nutationAMatcher = NUTATION_PATTERN_A.matcher(nutationPartA);
345 if (nutationAMatcher.matches()) {
346 if (isNonRotatingOrigin) {
347 nro = new double[] {
348 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationAMatcher.group(2))),
349 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationAMatcher.group(4)))
350 };
351 equinox = getConverter().toEquinox(mjdDate, nro[0], nro[1]);
352 } else {
353 equinox = new double[] {
354 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationAMatcher.group(2))),
355 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationAMatcher.group(4)))
356 };
357 nro = getConverter().toNonRotating(mjdDate, equinox[0], equinox[1]);
358 }
359 eopDataType = updateEopDataTypeIfUnknown(eopDataType, () -> getEopDataType(nutationAMatcher));
360 } else {
361 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
362 lineNumber, source.getName(), line);
363 }
364 }
365 } else {
366 final Matcher nutationBMatcher = NUTATION_PATTERN_B.matcher(nutationPartB);
367 if (nutationBMatcher.matches()) {
368 if (isNonRotatingOrigin) {
369 nro = new double[] {
370 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationBMatcher.group(1))),
371 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationBMatcher.group(2)))
372 };
373 equinox = getConverter().toEquinox(mjdDate, nro[0], nro[1]);
374 } else {
375 equinox = new double[] {
376 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationBMatcher.group(1))),
377 UnitsConverter.MILLI_ARC_SECONDS_TO_RADIANS.convert(Double.parseDouble(nutationBMatcher.group(2)))
378 };
379 nro = getConverter().toNonRotating(mjdDate, equinox[0], equinox[1]);
380 }
381 eopDataType = updateEopDataTypeIfUnknown(eopDataType, () -> EopDataType.FINAL);
382 } else {
383 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
384 lineNumber, source.getName(), line);
385 }
386 }
387
388 if (configuration == null || !configuration.isValid(mjd)) {
389
390 configuration = getItrfVersionProvider().getConfiguration(source.getName(), mjd);
391 }
392 history.add(new EOPEntry(mjd, dtu1, lod, x, y, Double.NaN, Double.NaN,
393 equinox[0], equinox[1], nro[0], nro[1],
394 configuration.getVersion(), mjdDate, eopDataType));
395
396 }
397
398 }
399
400 return history;
401 }
402
403
404
405
406
407
408 private EopDataType getEopDataType(final Matcher matcher) {
409 if (matcher.group(1).equals("P")) {
410 return EopDataType.PREDICTED;
411 } else {
412 return EopDataType.RAPID;
413 }
414 }
415
416
417
418
419
420
421 private EopDataType updateEopDataTypeIfUnknown(final EopDataType data, final Supplier<EopDataType> supplier) {
422 return data == EopDataType.UNKNOWN ? supplier.get() : data;
423 }
424 }
425
426
427
428
429
430
431
432
433 private static String getPart(final String line, final int start, final int end) {
434 return (line.length() >= end) ? line.substring(start, end) : "";
435 }
436
437 }