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