1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.odm.ocm;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.regex.Pattern;
24
25 import org.orekit.data.DataContext;
26 import org.orekit.data.DataSource;
27 import org.orekit.errors.OrekitException;
28 import org.orekit.errors.OrekitIllegalArgumentException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.files.ccsds.ndm.odm.OdmParser;
31 import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
32 import org.orekit.files.ccsds.ndm.odm.OdmMetadataKey;
33 import org.orekit.files.ccsds.ndm.odm.UserDefined;
34 import org.orekit.files.ccsds.section.Header;
35 import org.orekit.files.ccsds.section.HeaderProcessingState;
36 import org.orekit.files.ccsds.section.KvnStructureProcessingState;
37 import org.orekit.files.ccsds.section.MetadataKey;
38 import org.orekit.files.ccsds.section.Segment;
39 import org.orekit.files.ccsds.section.XmlStructureProcessingState;
40 import org.orekit.files.ccsds.utils.ContextBinding;
41 import org.orekit.files.ccsds.utils.FileFormat;
42 import org.orekit.files.ccsds.utils.lexical.ParseToken;
43 import org.orekit.files.ccsds.utils.lexical.TokenType;
44 import org.orekit.files.ccsds.utils.lexical.UserDefinedXmlTokenBuilder;
45 import org.orekit.files.ccsds.utils.lexical.XmlTokenBuilder;
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 public class OcmParser extends OdmParser<Ocm, OcmParser> implements EphemerisFileParser<Ocm> {
66
67
68 private static final Pattern SPLIT_AT_BLANKS = Pattern.compile("\\s+");
69
70
71 private Header header;
72
73
74 private OcmMetadata metadata;
75
76
77 private ContextBinding context;
78
79
80 private List<TrajectoryStateHistory> trajectoryBlocks;
81
82
83 private TrajectoryStateHistoryMetadata currentTrajectoryStateHistoryMetadata;
84
85
86 private List<TrajectoryState> currentTrajectoryStateHistory;
87
88
89 private PhysicalProperties physicBlock;
90
91
92 private List<CovarianceHistory> covarianceBlocks;
93
94
95 private CovarianceHistoryMetadata currentCovarianceHistoryMetadata;
96
97
98 private List<Covariance> currentCovarianceHistory;
99
100
101 private List<ManeuverHistory> maneuverBlocks;
102
103
104 private ManeuverHistoryMetadata currentManeuverHistoryMetadata;
105
106
107 private List<Maneuver> currentManeuverHistory;
108
109
110 private Perturbations perturbationsBlock;
111
112
113 private OrbitDetermination orbitDeterminationBlock;
114
115
116 private UserDefined userDefinedBlock;
117
118
119 private ProcessingState structureProcessor;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 public OcmParser(final IERSConventions conventions, final boolean simpleEOP, final DataContext dataContext,
135 final double mu, final ParsedUnitsBehavior parsedUnitsBehavior) {
136 super(Ocm.ROOT, Ocm.FORMAT_VERSION_KEY, conventions, simpleEOP, dataContext, null, mu, parsedUnitsBehavior);
137 }
138
139
140 @Override
141 public Map<String, XmlTokenBuilder> getSpecialXmlElementsBuilders() {
142
143 final Map<String, XmlTokenBuilder> builders = super.getSpecialXmlElementsBuilders();
144
145
146 builders.put(UserDefined.USER_DEFINED_XML_TAG, new UserDefinedXmlTokenBuilder());
147
148 return builders;
149
150 }
151
152
153 @Override
154 public Ocm parse(final DataSource source) {
155 return parseMessage(source);
156 }
157
158
159 @Override
160 public Header getHeader() {
161 return header;
162 }
163
164
165 @Override
166 public void reset(final FileFormat fileFormat) {
167 header = new Header(3.0);
168 metadata = null;
169 context = null;
170 trajectoryBlocks = null;
171 physicBlock = null;
172 covarianceBlocks = null;
173 maneuverBlocks = null;
174 perturbationsBlock = null;
175 orbitDeterminationBlock = null;
176 userDefinedBlock = null;
177 if (fileFormat == FileFormat.XML) {
178 structureProcessor = new XmlStructureProcessingState(Ocm.ROOT, this);
179 reset(fileFormat, structureProcessor);
180 } else {
181 structureProcessor = new KvnStructureProcessingState(this);
182 reset(fileFormat, new HeaderProcessingState(this));
183 }
184 }
185
186
187 @Override
188 public boolean prepareHeader() {
189 anticipateNext(new HeaderProcessingState(this));
190 return true;
191 }
192
193
194 @Override
195 public boolean inHeader() {
196 anticipateNext(structureProcessor);
197 return true;
198 }
199
200
201 @Override
202 public boolean finalizeHeader() {
203 header.validate(header.getFormatVersion());
204 return true;
205 }
206
207
208 @Override
209 public boolean prepareMetadata() {
210 if (metadata != null) {
211 return false;
212 }
213 metadata = new OcmMetadata(getDataContext());
214 context = new ContextBinding(this::getConventions, this::isSimpleEOP, this::getDataContext,
215 this::getParsedUnitsBehavior, metadata::getEpochT0, metadata::getTimeSystem,
216 metadata::getSclkOffsetAtEpoch, metadata::getSclkSecPerSISec);
217 anticipateNext(this::processMetadataToken);
218 return true;
219 }
220
221
222 @Override
223 public boolean inMetadata() {
224 anticipateNext(structureProcessor);
225 return true;
226 }
227
228
229 @Override
230 public boolean finalizeMetadata() {
231 metadata.validate(header.getFormatVersion());
232 anticipateNext(this::processDataSubStructureToken);
233 return true;
234 }
235
236
237 @Override
238 public boolean prepareData() {
239 anticipateNext(this::processDataSubStructureToken);
240 return true;
241 }
242
243
244 @Override
245 public boolean inData() {
246 return true;
247 }
248
249
250 @Override
251 public boolean finalizeData() {
252
253 final List<TrajectoryStateHistory> old = trajectoryBlocks;
254 if (old != null) {
255 trajectoryBlocks = new ArrayList<>(old.size());
256 for (final TrajectoryStateHistory osh : old) {
257 trajectoryBlocks.add(new TrajectoryStateHistory(osh.getMetadata(), osh.getTrajectoryStates(), getSelectedMu()));
258 }
259 }
260 return true;
261 }
262
263
264
265
266
267
268 boolean manageTrajectoryStateSection(final boolean starting) {
269 if (starting) {
270 if (trajectoryBlocks == null) {
271
272 trajectoryBlocks = new ArrayList<>();
273 }
274 currentTrajectoryStateHistoryMetadata = new TrajectoryStateHistoryMetadata(metadata.getEpochT0(),
275 getDataContext());
276 currentTrajectoryStateHistory = new ArrayList<>();
277 anticipateNext(this::processTrajectoryStateToken);
278 } else {
279 anticipateNext(structureProcessor);
280 if (currentTrajectoryStateHistoryMetadata.getCenter().getBody() != null) {
281 setMuCreated(currentTrajectoryStateHistoryMetadata.getCenter().getBody().getGM());
282 }
283
284
285 trajectoryBlocks.add(new TrajectoryStateHistory(currentTrajectoryStateHistoryMetadata,
286 currentTrajectoryStateHistory,
287 Double.NaN));
288 }
289 return true;
290 }
291
292
293
294
295
296
297 boolean managePhysicalPropertiesSection(final boolean starting) {
298 if (starting) {
299 if (physicBlock == null) {
300
301 physicBlock = new PhysicalProperties(metadata.getEpochT0());
302 }
303 anticipateNext(this::processPhysicalPropertyToken);
304 } else {
305 anticipateNext(structureProcessor);
306 }
307 return true;
308 }
309
310
311
312
313
314
315 boolean manageCovarianceHistorySection(final boolean starting) {
316 if (starting) {
317 if (covarianceBlocks == null) {
318
319 covarianceBlocks = new ArrayList<>();
320 }
321 currentCovarianceHistoryMetadata = new CovarianceHistoryMetadata(metadata.getEpochT0());
322 currentCovarianceHistory = new ArrayList<>();
323 anticipateNext(this::processCovarianceToken);
324 } else {
325 anticipateNext(structureProcessor);
326 covarianceBlocks.add(new CovarianceHistory(currentCovarianceHistoryMetadata,
327 currentCovarianceHistory));
328 currentCovarianceHistoryMetadata = null;
329 currentCovarianceHistory = null;
330 }
331 return true;
332 }
333
334
335
336
337
338
339 boolean manageManeuversSection(final boolean starting) {
340 if (starting) {
341 if (maneuverBlocks == null) {
342
343 maneuverBlocks = new ArrayList<>();
344 }
345 currentManeuverHistoryMetadata = new ManeuverHistoryMetadata(metadata.getEpochT0());
346 currentManeuverHistory = new ArrayList<>();
347 anticipateNext(this::processManeuverToken);
348 } else {
349 anticipateNext(structureProcessor);
350 maneuverBlocks.add(new ManeuverHistory(currentManeuverHistoryMetadata,
351 currentManeuverHistory));
352 currentManeuverHistoryMetadata = null;
353 currentManeuverHistory = null;
354 }
355 return true;
356 }
357
358
359
360
361
362
363 boolean managePerturbationParametersSection(final boolean starting) {
364 if (starting) {
365 if (perturbationsBlock == null) {
366
367 perturbationsBlock = new Perturbations(context.getDataContext().getCelestialBodies());
368 }
369 anticipateNext(this::processPerturbationToken);
370 } else {
371 anticipateNext(structureProcessor);
372 }
373 return true;
374 }
375
376
377
378
379
380
381 boolean manageOrbitDeterminationSection(final boolean starting) {
382 if (starting) {
383 if (orbitDeterminationBlock == null) {
384
385 orbitDeterminationBlock = new OrbitDetermination();
386 }
387 anticipateNext(this::processOrbitDeterminationToken);
388 } else {
389 anticipateNext(structureProcessor);
390 }
391 return true;
392 }
393
394
395
396
397
398
399 boolean manageUserDefinedParametersSection(final boolean starting) {
400 if (starting) {
401 if (userDefinedBlock == null) {
402
403 userDefinedBlock = new UserDefined();
404 }
405 anticipateNext(this::processUserDefinedToken);
406 } else {
407 anticipateNext(structureProcessor);
408 }
409 return true;
410 }
411
412
413 @Override
414 public Ocm build() {
415
416
417 finalizeData();
418 if (userDefinedBlock != null && userDefinedBlock.getParameters().isEmpty()) {
419 userDefinedBlock = null;
420 }
421 if (perturbationsBlock != null) {
422
423 setMuParsed(perturbationsBlock.getGm());
424 }
425 final OcmData data = new OcmData(trajectoryBlocks, physicBlock, covarianceBlocks,
426 maneuverBlocks, perturbationsBlock,
427 orbitDeterminationBlock, userDefinedBlock);
428 data.validate(header.getFormatVersion());
429 return new Ocm(header, Collections.singletonList(new Segment<>(metadata, data)),
430 getConventions(), getDataContext(), getSelectedMu());
431 }
432
433
434
435
436
437 private boolean processMetadataToken(final ParseToken token) {
438 inMetadata();
439 try {
440 return token.getName() != null &&
441 MetadataKey.valueOf(token.getName()).process(token, context, metadata);
442 } catch (IllegalArgumentException iaeM) {
443 try {
444 return OdmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
445 } catch (IllegalArgumentException iaeD) {
446 try {
447 return OcmMetadataKey.valueOf(token.getName()).process(token, context, metadata);
448 } catch (IllegalArgumentException iaeC) {
449
450 return false;
451 }
452 }
453 }
454 }
455
456
457
458
459
460 private boolean processDataSubStructureToken(final ParseToken token) {
461 try {
462 return token.getName() != null &&
463 OcmDataSubStructureKey.valueOf(token.getName()).process(token, this);
464 } catch (IllegalArgumentException iae) {
465
466 return false;
467 }
468 }
469
470
471
472
473
474 private boolean processTrajectoryStateToken(final ParseToken token) {
475 if (token.getName() != null && !token.getName().equals(Ocm.TRAJ_LINE)) {
476
477 try {
478 return TrajectoryStateHistoryMetadataKey.valueOf(token.getName()).
479 process(token, context, currentTrajectoryStateHistoryMetadata);
480 } catch (IllegalArgumentException iae) {
481
482 return false;
483 }
484 } else {
485
486 if (currentTrajectoryStateHistory.isEmpty()) {
487
488 currentTrajectoryStateHistoryMetadata.validate(header.getFormatVersion());
489 anticipateNext(this::processDataSubStructureToken);
490 }
491 if (token.getType() == TokenType.START || token.getType() == TokenType.STOP) {
492 return true;
493 }
494 try {
495 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
496
497 final List<Unit> units = currentTrajectoryStateHistoryMetadata.getTrajType().getUnits();
498 if (fields.length != units.size() + 1) {
499 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
500 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
501 }
502 final AbsoluteDate epoch = context.getTimeSystem().getConverter(context).parse(fields[0]);
503 return currentTrajectoryStateHistory.add(new TrajectoryState(currentTrajectoryStateHistoryMetadata.getTrajType(),
504 epoch, fields, 1, units));
505 } catch (NumberFormatException | OrekitIllegalArgumentException e) {
506 throw new OrekitException(e, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
507 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
508 }
509 }
510 }
511
512
513
514
515
516 private boolean processPhysicalPropertyToken(final ParseToken token) {
517 if (physicBlock == null) {
518 physicBlock = new PhysicalProperties(metadata.getEpochT0());
519 }
520 anticipateNext(this::processDataSubStructureToken);
521 try {
522 return token.getName() != null &&
523 PhysicalPropertiesKey.valueOf(token.getName()).process(token, context, physicBlock);
524 } catch (IllegalArgumentException iae) {
525
526 return false;
527 }
528 }
529
530
531
532
533
534 private boolean processCovarianceToken(final ParseToken token) {
535 if (token.getName() != null && !token.getName().equals(Ocm.COV_LINE)) {
536
537 try {
538 return CovarianceHistoryMetadataKey.valueOf(token.getName()).
539 process(token, context, currentCovarianceHistoryMetadata);
540 } catch (IllegalArgumentException iae) {
541
542 return false;
543 }
544 } else {
545
546 if (currentCovarianceHistory.isEmpty()) {
547
548 currentCovarianceHistoryMetadata.validate(header.getFormatVersion());
549 anticipateNext(this::processDataSubStructureToken);
550 }
551 if (token.getType() == TokenType.START || token.getType() == TokenType.STOP) {
552 return true;
553 }
554 try {
555 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
556 final int n = currentCovarianceHistoryMetadata.getCovUnits().size();
557 if (fields.length - 1 != currentCovarianceHistoryMetadata.getCovOrdering().nbElements(n)) {
558 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
559 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
560 }
561 currentCovarianceHistory.add(new Covariance(currentCovarianceHistoryMetadata.getCovType(),
562 currentCovarianceHistoryMetadata.getCovOrdering(),
563 context.getTimeSystem().getConverter(context).parse(fields[0]),
564 fields, 1));
565 return true;
566 } catch (NumberFormatException nfe) {
567 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
568 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
569 }
570 }
571 }
572
573
574
575
576
577 private boolean processManeuverToken(final ParseToken token) {
578 if (token.getName() != null && !token.getName().equals(Ocm.MAN_LINE)) {
579
580 try {
581 return ManeuverHistoryMetadataKey.valueOf(token.getName()).
582 process(token, context, currentManeuverHistoryMetadata);
583 } catch (IllegalArgumentException iae) {
584
585 return false;
586 }
587 } else {
588
589 if (currentManeuverHistory.isEmpty()) {
590
591 currentManeuverHistoryMetadata.validate(header.getFormatVersion());
592 anticipateNext(this::processDataSubStructureToken);
593 }
594 if (token.getType() == TokenType.START || token.getType() == TokenType.STOP) {
595 return true;
596 }
597 try {
598 final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
599 final List<ManeuverFieldType> types = currentManeuverHistoryMetadata.getManComposition();
600 if (fields.length != types.size()) {
601 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
602 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
603 }
604 final Maneuver maneuver = new Maneuver();
605 for (int i = 0; i < fields.length; ++i) {
606 types.get(i).process(fields[i], context, maneuver, token.getLineNumber(), token.getFileName());
607 }
608 currentManeuverHistory.add(maneuver);
609 return true;
610 } catch (NumberFormatException nfe) {
611 throw new OrekitException(nfe, OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
612 token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
613 }
614 }
615 }
616
617
618
619
620
621 private boolean processPerturbationToken(final ParseToken token) {
622 anticipateNext(this::processDataSubStructureToken);
623 try {
624 return token.getName() != null &&
625 PerturbationsKey.valueOf(token.getName()).process(token, context, perturbationsBlock);
626 } catch (IllegalArgumentException iae) {
627
628 return false;
629 }
630 }
631
632
633
634
635
636 private boolean processOrbitDeterminationToken(final ParseToken token) {
637 if (orbitDeterminationBlock == null) {
638 orbitDeterminationBlock = new OrbitDetermination();
639 }
640 anticipateNext(this::processDataSubStructureToken);
641 try {
642 return token.getName() != null &&
643 OrbitDeterminationKey.valueOf(token.getName()).process(token, context, orbitDeterminationBlock);
644 } catch (IllegalArgumentException iae) {
645
646 return false;
647 }
648 }
649
650
651
652
653
654 private boolean processUserDefinedToken(final ParseToken token) {
655 if (userDefinedBlock == null) {
656 userDefinedBlock = new UserDefined();
657 }
658 anticipateNext(this::processDataSubStructureToken);
659 if ("COMMENT".equals(token.getName())) {
660 return token.getType() == TokenType.ENTRY ? userDefinedBlock.addComment(token.getContentAsNormalizedString()) : true;
661 } else if (token.getName().startsWith(UserDefined.USER_DEFINED_PREFIX)) {
662 if (token.getType() == TokenType.ENTRY) {
663 userDefinedBlock.addEntry(token.getName().substring(UserDefined.USER_DEFINED_PREFIX.length()),
664 token.getContentAsNormalizedString());
665 }
666 return true;
667 } else {
668
669 return false;
670 }
671 }
672
673 }