1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.odm.oem;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.function.Function;
22 import java.util.regex.Pattern;
23
24 import org.orekit.data.DataContext;
25 import org.orekit.data.DataSource;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitMessages;
28 import org.orekit.files.ccsds.definitions.Units;
29 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
30 import org.orekit.files.ccsds.ndm.odm.CartesianCovariance;
31 import org.orekit.files.ccsds.ndm.odm.CartesianCovarianceKey;
32 import org.orekit.files.ccsds.ndm.odm.OdmCommonMetadata;
33 import org.orekit.files.ccsds.ndm.odm.CommonMetadataKey;
34 import org.orekit.files.ccsds.ndm.odm.OdmHeader;
35 import org.orekit.files.ccsds.ndm.odm.OdmMetadataKey;
36 import org.orekit.files.ccsds.ndm.odm.OdmParser;
37 import org.orekit.files.ccsds.ndm.odm.StateVector;
38 import org.orekit.files.ccsds.ndm.odm.StateVectorKey;
39 import org.orekit.files.ccsds.section.HeaderProcessingState;
40 import org.orekit.files.ccsds.section.KvnStructureProcessingState;
41 import org.orekit.files.ccsds.section.MetadataKey;
42 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
43 import org.orekit.files.ccsds.utils.ContextBinding;
44 import org.orekit.files.ccsds.utils.FileFormat;
45 import org.orekit.files.ccsds.utils.lexical.ParseToken;
46 import org.orekit.files.ccsds.utils.lexical.TokenType;
47 import org.orekit.files.ccsds.utils.parsing.ProcessingState;
48 import org.orekit.files.general.EphemerisFileParser;
49 import org.orekit.time.AbsoluteDate;
50 import org.orekit.utils.IERSConventions;
51 import org.orekit.utils.units.Unit;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class OemParser extends OdmParser<Oem, OemParser> implements EphemerisFileParser<Oem> {
68
69
70 private static final String COMMENT = "COMMENT";
71
72
73 private static final Pattern SPLIT_AT_BLANKS = Pattern.compile("\\s+");
74
75
76 private OdmHeader header;
77
78
79 private List<OemSegment> segments;
80
81
82 private OemMetadata metadata;
83
84
85 private ContextBinding context;
86
87
88 private OemData currentBlock;
89
90
91 private boolean inCovariance;
92
93
94 private CartesianCovariance currentCovariance;
95
96
97 private int currentRow;
98
99
100 private int defaultInterpolationDegree;
101
102
103 private ProcessingState structureProcessor;
104
105
106 private StateVector stateVectorBlock;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 public OemParser(final IERSConventions conventions, final boolean simpleEOP,
127 final DataContext dataContext,
128 final AbsoluteDate missionReferenceDate, final double mu,
129 final int defaultInterpolationDegree, final ParsedUnitsBehavior parsedUnitsBehavior,
130 final Function<ParseToken, List<ParseToken>>[] filters) {
131 super(Oem.ROOT, Oem.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext,
132 missionReferenceDate, mu, parsedUnitsBehavior, filters);
133 this.defaultInterpolationDegree = defaultInterpolationDegree;
134 }
135
136
137 @Override
138 public Oem parse(final DataSource source) {
139 return parseMessage(source);
140 }
141
142
143 @Override
144 public OdmHeader getHeader() {
145 return header;
146 }
147
148
149 @Override
150 public void reset(final FileFormat fileFormat) {
151 header = new OdmHeader();
152 segments = new ArrayList<>();
153 metadata = null;
154 context = null;
155 currentBlock = null;
156 inCovariance = false;
157 currentCovariance = null;
158 currentRow = -1;
159 if (fileFormat == FileFormat.XML) {
160 structureProcessor = new XmlStructureProcessingState(Oem.ROOT, this);
161 reset(fileFormat, structureProcessor);
162 } else {
163 structureProcessor = new KvnStructureProcessingState(this);
164 reset(fileFormat, new HeaderProcessingState(this));
165 }
166 }
167
168
169 @Override
170 public boolean prepareHeader() {
171 anticipateNext(new HeaderProcessingState(this));
172 return true;
173 }
174
175
176 @Override
177 public boolean inHeader() {
178 anticipateNext(structureProcessor);
179 return true;
180 }
181
182
183 @Override
184 public boolean finalizeHeader() {
185 header.validate(header.getFormatVersion());
186 return true;
187 }
188
189
190 @Override
191 public boolean prepareMetadata() {
192 if (currentBlock != null) {
193
194 finalizeData();
195 }
196 metadata = new OemMetadata(defaultInterpolationDegree);
197 context = new ContextBinding(this::getConventions, this::isSimpleEOP,
198 this::getDataContext, this::getParsedUnitsBehavior,
199 this::getMissionReferenceDate,
200 metadata::getTimeSystem, () -> 0.0, () -> 1.0);
201 anticipateNext(this::processMetadataToken);
202 return true;
203 }
204
205
206 @Override
207 public boolean inMetadata() {
208 anticipateNext(structureProcessor);
209 return true;
210 }
211
212
213 @Override
214 public boolean finalizeMetadata() {
215 metadata.finalizeMetadata(context);
216 metadata.validate(header.getFormatVersion());
217 if (metadata.getCenter().getBody() != null) {
218 setMuCreated(metadata.getCenter().getBody().getGM());
219 }
220 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processKvnDataToken);
221 return true;
222 }
223
224
225 @Override
226 public boolean prepareData() {
227 currentBlock = new OemData();
228 anticipateNext(getFileFormat() == FileFormat.XML ? this::processXmlSubStructureToken : this::processMetadataToken);
229 return true;
230 }
231
232
233 @Override
234 public boolean inData() {
235 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processKvnCovarianceToken);
236 return true;
237 }
238
239
240 @Override
241 public boolean finalizeData() {
242 if (metadata != null) {
243 currentBlock.validate(header.getFormatVersion());
244 segments.add(new OemSegment(metadata, currentBlock, getSelectedMu()));
245 }
246 metadata = null;
247 context = null;
248 currentBlock = null;
249 inCovariance = false;
250 currentCovariance = null;
251 currentRow = -1;
252 return true;
253 }
254
255
256 @Override
257 public Oem build() {
258
259
260 finalizeData();
261 final Oem file = new Oem(header, segments, getConventions(), getDataContext(), getSelectedMu());
262 file.checkTimeSystems();
263 return file;
264 }
265
266
267
268
269
270
271 boolean manageXmlStateVectorSection(final boolean starting) {
272 if (starting) {
273 stateVectorBlock = new StateVector();
274 anticipateNext(this::processXmlStateVectorToken);
275 } else {
276 currentBlock.addData(stateVectorBlock.toTimeStampedPVCoordinates(),
277 stateVectorBlock.hasAcceleration());
278 stateVectorBlock = null;
279 anticipateNext(structureProcessor);
280 }
281 return true;
282 }
283
284
285
286
287
288
289 boolean manageCovarianceSection(final boolean starting) {
290 if (starting) {
291
292 final OdmCommonMetadata savedMetadata = metadata;
293 currentCovariance = new CartesianCovariance(savedMetadata::getReferenceFrame);
294 anticipateNext(getFileFormat() == FileFormat.XML ?
295 this::processXmlCovarianceToken :
296 this::processKvnCovarianceToken);
297 } else {
298 currentBlock.addCovarianceMatrix(currentCovariance);
299 currentCovariance = null;
300 anticipateNext(structureProcessor);
301 }
302 return true;
303 }
304
305
306
307
308
309 private boolean processMetadataToken(final ParseToken token) {
310 inMetadata();
311 try {
312 return token.getName() != null &&
313 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
314 } catch (IllegalArgumentException iaeM) {
315 try {
316 return OdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
317 } catch (IllegalArgumentException iaeD) {
318 try {
319 return CommonMetadataKey.valueOf(token.getName()).process(token, context, metadata);
320 } catch (IllegalArgumentException iaeC) {
321 try {
322 return OemMetadataKey.valueOf(token.getName()).process(token, context, metadata);
323 } catch (IllegalArgumentException iaeE) {
324
325 return false;
326 }
327 }
328 }
329 }
330 }
331
332
333
334
335
336 private boolean processXmlSubStructureToken(final ParseToken token) {
337 if (COMMENT.equals(token.getName())) {
338 return token.getType() == TokenType.ENTRY ? currentBlock.addComment(token.getContentAsNormalizedString()) : true;
339 } else {
340 try {
341 return token.getName() != null &&
342 OemDataSubStructureKey.valueOf(token.getName()).process(token, this);
343 } catch (IllegalArgumentException iae) {
344
345 return false;
346 }
347 }
348 }
349
350
351
352
353
354 private boolean processKvnDataToken(final ParseToken token) {
355 if (currentBlock == null) {
356
357
358 prepareData();
359 }
360 inData();
361 if (COMMENT.equals(token.getName())) {
362 return token.getType() == TokenType.ENTRY ? currentBlock.addComment(token.getContentAsNormalizedString()) : true;
363 } else if (token.getType() == TokenType.RAW_LINE) {
364 try {
365 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
366 if (fields.length != 7 && fields.length != 10) {
367 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
368 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
369 }
370 stateVectorBlock = new StateVector();
371 stateVectorBlock.setEpoch(context.getTimeSystem().getConverter(context).parse(fields[0]));
372 stateVectorBlock.setP(0, Unit.KILOMETRE.toSI(Double.parseDouble(fields[1])));
373 stateVectorBlock.setP(1, Unit.KILOMETRE.toSI(Double.parseDouble(fields[2])));
374 stateVectorBlock.setP(2, Unit.KILOMETRE.toSI(Double.parseDouble(fields[3])));
375 stateVectorBlock.setV(0, Units.KM_PER_S.toSI(Double.parseDouble(fields[4])));
376 stateVectorBlock.setV(1, Units.KM_PER_S.toSI(Double.parseDouble(fields[5])));
377 stateVectorBlock.setV(2, Units.KM_PER_S.toSI(Double.parseDouble(fields[6])));
378 if (fields.length == 10) {
379 stateVectorBlock.setA(0, Units.KM_PER_S2.toSI(Double.parseDouble(fields[7])));
380 stateVectorBlock.setA(1, Units.KM_PER_S2.toSI(Double.parseDouble(fields[8])));
381 stateVectorBlock.setA(2, Units.KM_PER_S2.toSI(Double.parseDouble(fields[9])));
382 }
383 return currentBlock.addData(stateVectorBlock.toTimeStampedPVCoordinates(),
384 stateVectorBlock.hasAcceleration());
385 } catch (NumberFormatException nfe) {
386 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
387 token.getLineNumber(), token.getFileName(), token.getRawContent());
388 }
389 } else {
390
391 return false;
392 }
393 }
394
395
396
397
398
399 private boolean processXmlStateVectorToken(final ParseToken token) {
400 anticipateNext(this::processXmlSubStructureToken);
401 try {
402 return token.getName() != null &&
403 StateVectorKey.valueOf(token.getName()).process(token, context, stateVectorBlock);
404 } catch (IllegalArgumentException iae) {
405
406 return false;
407 }
408 }
409
410
411
412
413
414 private boolean processKvnCovarianceToken(final ParseToken token) {
415 anticipateNext(getFileFormat() == FileFormat.XML ? structureProcessor : this::processMetadataToken);
416 if (token.getName() != null) {
417 if (OemDataSubStructureKey.COVARIANCE.name().equals(token.getName()) ||
418 OemDataSubStructureKey.covarianceMatrix.name().equals(token.getName())) {
419
420 inCovariance = token.getType() == TokenType.START;
421 return true;
422 } else if (!inCovariance) {
423
424 return false;
425 } else {
426
427 if (currentRow > 0) {
428
429 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_ELEMENT_IN_FILE,
430 token.getName(), token.getLineNumber(), token.getFileName());
431 }
432
433 if (currentCovariance == null) {
434
435 final OdmCommonMetadata savedMetadata = metadata;
436 currentCovariance = new CartesianCovariance(savedMetadata::getReferenceFrame);
437 currentRow = 0;
438 }
439
440
441 try {
442 return CartesianCovarianceKey.valueOf(token.getName()).
443 process(token, context, currentCovariance);
444 } catch (IllegalArgumentException iae) {
445
446 return false;
447 }
448
449 }
450 } else {
451
452 try {
453 final String[] fields = SPLIT_AT_BLANKS.split(token.getContentAsNormalizedString().trim());
454 if (fields.length != currentRow + 1) {
455 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
456 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
457 }
458 for (int j = 0; j < fields.length; ++j) {
459 currentCovariance.setCovarianceMatrixEntry(currentRow, j, 1.0e6 * Double.parseDouble(fields[j]));
460 }
461 if (++currentRow == 6) {
462
463 currentBlock.addCovarianceMatrix(currentCovariance);
464 currentCovariance = null;
465 currentRow = -1;
466 }
467 return true;
468 } catch (NumberFormatException nfe) {
469 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
470 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
471 }
472 }
473 }
474
475
476
477
478
479 private boolean processXmlCovarianceToken(final ParseToken token) {
480 anticipateNext(this::processXmlSubStructureToken);
481 try {
482 return token.getName() != null &&
483 CartesianCovarianceKey.valueOf(token.getName()).process(token, context, currentCovariance);
484 } catch (IllegalArgumentException iae) {
485
486 return false;
487 }
488 }
489
490 }