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