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