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
30 import org.orekit.data.DataProvidersManager;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.time.AbsoluteDate;
34 import org.orekit.time.DateComponents;
35 import org.orekit.time.TimeScale;
36 import org.orekit.utils.IERSConventions;
37 import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
38 import org.orekit.utils.units.Unit;
39
40
41
42
43
44
45
46
47 class EopCsvFilesLoader extends AbstractEopLoader implements EopHistoryLoader {
48
49
50 private static final String SEPARATOR = ";";
51
52
53 private static final String MJD = "MJD";
54
55
56 private static final String YEAR = "Year";
57
58
59 private static final String MONTH = "Month";
60
61
62 private static final String DAY = "Day";
63
64
65 private static final String X_POLE = "x_pole";
66
67
68 private static final String Y_POLE = "y_pole";
69
70
71 private static final String X_RATE = "x_rate";
72
73
74 private static final String Y_RATE = "y_rate";
75
76
77 private static final String UT1_UTC = "UT1-UTC";
78
79
80 private static final String LOD = "LOD";
81
82
83 private static final String DPSI = "dPsi";
84
85
86 private static final String DEPSILON = "dEpsilon";
87
88
89 private static final String DX = "dX";
90
91
92 private static final String DY = "dY";
93
94
95 private static final Unit AS = Unit.parse("as");
96
97
98 private static final Unit AS_D = Unit.parse("as/day");
99
100
101 private static final Unit S = Unit.parse("s");
102
103
104
105
106
107
108 EopCsvFilesLoader(final String supportedNames,
109 final DataProvidersManager manager,
110 final Supplier<TimeScale> utcSupplier) {
111 super(supportedNames, manager, utcSupplier);
112 }
113
114
115 public void fillHistory(final IERSConventions.NutationCorrectionConverter converter,
116 final SortedSet<EOPEntry> history) {
117 final Parser parser = new Parser(converter, getUtc());
118 final EopParserLoader loader = new EopParserLoader(parser);
119 this.feed(loader);
120 history.addAll(loader.getEop());
121 }
122
123
124 class Parser extends AbstractEopParser {
125
126
127 private final ItrfVersionProvider itrfVersionProvider;
128
129
130 private int mjdColumn;
131
132
133 private int yearColumn;
134
135
136 private int monthColumn;
137
138
139 private int dayColumn;
140
141
142 private int xPoleColumn;
143
144
145 private int yPoleColumn;
146
147
148 private int xRatePoleColumn;
149
150
151 private int yRatePoleColumn;
152
153
154 private int ut1Column;
155
156
157 private int lodColumn;
158
159
160 private int dxColumn;
161
162
163 private int dyColumn;
164
165
166 private int dPsiColumn;
167
168
169 private int dEpsilonColumn;
170
171
172 private ITRFVersionLoader.ITRFVersionConfiguration configuration;
173
174
175
176
177
178 Parser(final NutationCorrectionConverter converter,
179 final TimeScale utc) {
180 super(converter, null, utc);
181 this.itrfVersionProvider = new ITRFVersionLoader(ITRFVersionLoader.SUPPORTED_NAMES,
182 getDataProvidersManager());
183 }
184
185
186 public Collection<EOPEntry> parse(final InputStream input, final String name)
187 throws IOException, OrekitException {
188
189 final List<EOPEntry> history = new ArrayList<>();
190
191
192 try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
193
194 int lineNumber = 0;
195 configuration = null;
196
197
198 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
199 ++lineNumber;
200
201 final boolean parsed;
202 if (lineNumber == 1) {
203 parsed = parseHeaderLine(line);
204 } else {
205 history.add(parseDataLine(line, name));
206 parsed = true;
207 }
208
209 if (!parsed) {
210 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
211 lineNumber, name, line);
212 }
213 }
214
215
216 if (lineNumber < 2) {
217 throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, name);
218 }
219 }
220
221 return history;
222 }
223
224
225
226
227
228 private boolean parseHeaderLine(final String headerLine) {
229
230
231 mjdColumn = -1;
232 yearColumn = -1;
233 monthColumn = -1;
234 dayColumn = -1;
235 xPoleColumn = -1;
236 yPoleColumn = -1;
237 xRatePoleColumn = -1;
238 yRatePoleColumn = -1;
239 ut1Column = -1;
240 lodColumn = -1;
241 dxColumn = -1;
242 dyColumn = -1;
243 dPsiColumn = -1;
244 dEpsilonColumn = -1;
245
246
247 final String[] fields = headerLine.split(SEPARATOR);
248
249
250 for (int column = 0; column < fields.length; ++column) {
251 switch (fields[column]) {
252 case MJD :
253 mjdColumn = column;
254 break;
255 case YEAR :
256 yearColumn = column;
257 break;
258 case MONTH :
259 monthColumn = column;
260 break;
261 case DAY :
262 dayColumn = column;
263 break;
264 case X_POLE :
265 xPoleColumn = column;
266 break;
267 case Y_POLE :
268 yPoleColumn = column;
269 break;
270 case X_RATE :
271 xRatePoleColumn = column;
272 break;
273 case Y_RATE :
274 yRatePoleColumn = column;
275 break;
276 case UT1_UTC :
277 ut1Column = column;
278 break;
279 case LOD :
280 lodColumn = column;
281 break;
282 case DX :
283 dxColumn = column;
284 break;
285 case DY :
286 dyColumn = column;
287 break;
288 case DPSI :
289 dPsiColumn = column;
290 break;
291 case DEPSILON :
292 dEpsilonColumn = column;
293 break;
294 default :
295
296 }
297 }
298
299
300 return mjdColumn >= 0 && yearColumn >= 0 && monthColumn >= 0 && dayColumn >= 0 &&
301 xPoleColumn >= 0 && yPoleColumn >= 0 && ut1Column >= 0 && lodColumn >= 0 &&
302 (dxColumn >= 0 && dyColumn >= 0 || dPsiColumn >= 0 && dEpsilonColumn >= 0);
303
304 }
305
306
307
308
309
310
311 private EOPEntry parseDataLine(final String line, final String name) {
312
313 final String[] fields = line.split(SEPARATOR);
314
315
316 final DateComponents dc = new DateComponents(Integer.parseInt(fields[yearColumn]),
317 Integer.parseInt(fields[monthColumn]),
318 Integer.parseInt(fields[dayColumn]));
319 final int mjd = Integer.parseInt(fields[mjdColumn]);
320 if (dc.getMJD() != mjd) {
321 throw new OrekitException(OrekitMessages.INCONSISTENT_DATES_IN_IERS_FILE,
322 name, dc.getYear(), dc.getMonth(), dc.getDay(), mjd);
323 }
324 final AbsoluteDate date = new AbsoluteDate(dc, getUtc());
325
326 if (configuration == null || !configuration.isValid(mjd)) {
327
328 configuration = itrfVersionProvider.getConfiguration(name, mjd);
329 }
330
331 final double x = parseField(fields, xPoleColumn, AS);
332 final double y = parseField(fields, yPoleColumn, AS);
333 final double xRate = parseField(fields, xRatePoleColumn, AS_D);
334 final double yRate = parseField(fields, yRatePoleColumn, AS_D);
335 final double dtu1 = parseField(fields, ut1Column, S);
336 final double lod = parseField(fields, lodColumn, S);
337
338 if (dxColumn >= 0) {
339
340 final double dx = parseField(fields, dxColumn, AS);
341 final double dy = parseField(fields, dyColumn, AS);
342 final double[] equinox = getConverter().toEquinox(date, dx, dy);
343 return new EOPEntry(dc.getMJD(), dtu1, lod, x, y, xRate, yRate,
344 equinox[0], equinox[1], dx, dy,
345 configuration.getVersion(), date);
346 } else {
347
348 final double ddPsi = parseField(fields, dPsiColumn, AS);
349 final double dddEpsilon = parseField(fields, dEpsilonColumn, AS);
350 final double[] nro = getConverter().toNonRotating(date, ddPsi, dddEpsilon);
351 return new EOPEntry(dc.getMJD(), dtu1, lod, x, y, xRate, yRate,
352 ddPsi, dddEpsilon, nro[0], nro[1],
353 configuration.getVersion(), date);
354 }
355
356
357 }
358
359
360
361
362
363
364
365 private double parseField(final String[] fields, final int index, final Unit unit) {
366 return (index < 0 || index >= fields.length || fields[index].isEmpty()) ?
367 Double.NaN :
368 unit.toSI(Double.parseDouble(fields[index]));
369 }
370
371 }
372
373 }