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.io.IOException;
20 import java.util.Date;
21 import java.util.List;
22
23 import org.hipparchus.linear.RealMatrix;
24 import org.orekit.data.DataContext;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitMessages;
27 import org.orekit.files.ccsds.definitions.TimeSystem;
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.CommonMetadataKey;
33 import org.orekit.files.ccsds.ndm.odm.OdmMetadataKey;
34 import org.orekit.files.ccsds.ndm.odm.StateVectorKey;
35 import org.orekit.files.ccsds.section.Header;
36 import org.orekit.files.ccsds.section.HeaderKey;
37 import org.orekit.files.ccsds.section.KvnStructureKey;
38 import org.orekit.files.ccsds.section.MetadataKey;
39 import org.orekit.files.ccsds.section.XmlStructureKey;
40 import org.orekit.files.ccsds.utils.ContextBinding;
41 import org.orekit.files.ccsds.utils.FileFormat;
42 import org.orekit.files.ccsds.utils.generation.AbstractMessageWriter;
43 import org.orekit.files.ccsds.utils.generation.Generator;
44 import org.orekit.time.AbsoluteDate;
45 import org.orekit.utils.AccurateFormatter;
46 import org.orekit.utils.CartesianDerivativesFilter;
47 import org.orekit.utils.IERSConventions;
48 import org.orekit.utils.TimeStampedPVCoordinates;
49 import org.orekit.utils.units.Unit;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 public class OemWriter extends AbstractMessageWriter<Header, OemSegment, Oem> {
193
194
195 public static final double CCSDS_OEM_VERS = 3.0;
196
197
198 public static final String DEFAULT_FILE_NAME = "<OEM output>";
199
200
201 public static final int KVN_PADDING_WIDTH = 20;
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 public OemWriter(final IERSConventions conventions, final DataContext dataContext,
229 final AbsoluteDate missionReferenceDate) {
230 super(Oem.ROOT, Oem.FORMAT_VERSION_KEY, CCSDS_OEM_VERS,
231 new ContextBinding(
232 () -> conventions, () -> true, () -> dataContext,
233 () -> ParsedUnitsBehavior.STRICT_COMPLIANCE,
234 () -> missionReferenceDate, () -> TimeSystem.UTC, () -> 0.0, () -> 1.0));
235 }
236
237
238 @Override
239 public void writeSegmentContent(final Generator generator, final double formatVersion,
240 final OemSegment segment)
241 throws IOException {
242
243 final OemMetadata metadata = segment.getMetadata();
244 writeMetadata(generator, metadata);
245
246 startData(generator);
247
248
249 generator.writeComments(segment.getData().getComments());
250
251
252 final CartesianDerivativesFilter filter = segment.getAvailableDerivatives();
253 if (filter == CartesianDerivativesFilter.USE_P) {
254 throw new OrekitException(OrekitMessages.MISSING_VELOCITY);
255 }
256 final boolean useAcceleration = filter.equals(CartesianDerivativesFilter.USE_PVA);
257 for (final TimeStampedPVCoordinates coordinates : segment.getCoordinates()) {
258 writeOrbitEphemerisLine(generator, metadata, coordinates, useAcceleration);
259 }
260
261
262 writeCovariances(generator, segment.getMetadata(), segment.getData().getCovarianceMatrices());
263
264 endData(generator);
265
266 }
267
268
269
270
271
272
273 void writeMetadata(final Generator generator, final OemMetadata metadata)
274 throws IOException {
275
276
277 generator.newLine();
278
279 final ContextBinding oldContext = getContext();
280 setContext(new ContextBinding(oldContext::getConventions,
281 oldContext::isSimpleEOP,
282 oldContext::getDataContext,
283 oldContext::getParsedUnitsBehavior,
284 oldContext::getReferenceDate,
285 metadata::getTimeSystem,
286 oldContext::getClockCount,
287 oldContext::getClockRate));
288
289
290 generator.enterSection(generator.getFormat() == FileFormat.KVN ?
291 KvnStructureKey.META.name() :
292 XmlStructureKey.metadata.name());
293
294 generator.writeComments(metadata.getComments());
295
296
297 generator.writeEntry(OdmMetadataKey.OBJECT_NAME.name(), metadata.getObjectName(), null, true);
298 generator.writeEntry(CommonMetadataKey.OBJECT_ID.name(), metadata.getObjectID(), null, true);
299 generator.writeEntry(CommonMetadataKey.CENTER_NAME.name(), metadata.getCenter().getName(), null, false);
300
301
302 generator.writeEntry(CommonMetadataKey.REF_FRAME.name(), metadata.getReferenceFrame().getName(), null, true);
303 if (metadata.getFrameEpoch() != null) {
304 generator.writeEntry(CommonMetadataKey.REF_FRAME_EPOCH.name(),
305 getTimeConverter(), metadata.getFrameEpoch(),
306 false);
307 }
308
309
310 generator.writeEntry(MetadataKey.TIME_SYSTEM.name(), metadata.getTimeSystem(), true);
311 generator.writeEntry(OemMetadataKey.START_TIME.name(), getTimeConverter(), metadata.getStartTime(), true);
312 if (metadata.getUseableStartTime() != null) {
313 generator.writeEntry(OemMetadataKey.USEABLE_START_TIME.name(), getTimeConverter(), metadata.getUseableStartTime(), false);
314 }
315 if (metadata.getUseableStopTime() != null) {
316 generator.writeEntry(OemMetadataKey.USEABLE_STOP_TIME.name(), getTimeConverter(), metadata.getUseableStopTime(), false);
317 }
318 generator.writeEntry(OemMetadataKey.STOP_TIME.name(), getTimeConverter(), metadata.getStopTime(), true);
319
320
321 generator.writeEntry(OemMetadataKey.INTERPOLATION.name(), metadata.getInterpolationMethod(), false);
322 generator.writeEntry(OemMetadataKey.INTERPOLATION_DEGREE.name(),
323 Integer.toString(metadata.getInterpolationDegree()),
324 null, false);
325
326
327 generator.exitSection();
328
329
330 generator.newLine();
331
332 }
333
334
335
336
337
338
339
340
341
342 void writeOrbitEphemerisLine(final Generator generator, final OemMetadata metadata,
343 final TimeStampedPVCoordinates coordinates,
344 final boolean useAcceleration)
345 throws IOException {
346
347 if (generator.getFormat() == FileFormat.KVN) {
348
349
350 generator.writeRawData(generator.dateToString(getTimeConverter(), coordinates.getDate()));
351
352
353 generator.writeRawData(' ');
354 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getX()))));
355 generator.writeRawData(' ');
356 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getY()))));
357 generator.writeRawData(' ');
358 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getZ()))));
359
360
361 generator.writeRawData(' ');
362 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getX()))));
363 generator.writeRawData(' ');
364 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getY()))));
365 generator.writeRawData(' ');
366 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getZ()))));
367
368
369 if (useAcceleration) {
370 generator.writeRawData(' ');
371 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getX()))));
372 generator.writeRawData(' ');
373 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getY()))));
374 generator.writeRawData(' ');
375 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getZ()))));
376 }
377
378
379 generator.newLine();
380 } else {
381 generator.enterSection(OemDataSubStructureKey.stateVector.name());
382
383
384 generator.writeEntry(StateVectorKey.EPOCH.name(), getTimeConverter(), coordinates.getDate(), true);
385
386
387 generator.writeEntry(StateVectorKey.X.name(), coordinates.getPosition().getX(), Unit.KILOMETRE, true);
388 generator.writeEntry(StateVectorKey.Y.name(), coordinates.getPosition().getY(), Unit.KILOMETRE, true);
389 generator.writeEntry(StateVectorKey.Z.name(), coordinates.getPosition().getZ(), Unit.KILOMETRE, true);
390
391
392 generator.writeEntry(StateVectorKey.X_DOT.name(), coordinates.getVelocity().getX(), Units.KM_PER_S, true);
393 generator.writeEntry(StateVectorKey.Y_DOT.name(), coordinates.getVelocity().getY(), Units.KM_PER_S, true);
394 generator.writeEntry(StateVectorKey.Z_DOT.name(), coordinates.getVelocity().getZ(), Units.KM_PER_S, true);
395
396
397 if (useAcceleration) {
398 generator.writeEntry(StateVectorKey.X_DDOT.name(), coordinates.getAcceleration().getX(), Units.KM_PER_S2, true);
399 generator.writeEntry(StateVectorKey.Y_DDOT.name(), coordinates.getAcceleration().getY(), Units.KM_PER_S2, true);
400 generator.writeEntry(StateVectorKey.Z_DDOT.name(), coordinates.getAcceleration().getZ(), Units.KM_PER_S2, true);
401 }
402
403 generator.exitSection();
404
405 }
406 }
407
408
409
410
411
412
413
414
415 void writeCovariances(final Generator generator, final OemMetadata metadata,
416 final List<CartesianCovariance> covariances)
417 throws IOException {
418 if (covariances != null && !covariances.isEmpty()) {
419
420
421 if (generator.getFormat() == FileFormat.KVN) {
422 generator.enterSection(OemDataSubStructureKey.COVARIANCE.name());
423 }
424
425 for (final CartesianCovariance covariance : covariances) {
426 writeCovariance(generator, metadata, covariance);
427 }
428
429
430 if (generator.getFormat() == FileFormat.KVN) {
431 generator.exitSection();
432 }
433
434 }
435 }
436
437
438
439
440
441
442
443
444 private void writeCovariance(final Generator generator, final OemMetadata metadata,
445 final CartesianCovariance covariance)
446 throws IOException {
447
448
449 if (generator.getFormat() == FileFormat.XML) {
450 generator.enterSection(OemDataSubStructureKey.covarianceMatrix.name());
451 }
452
453
454 generator.writeEntry(CartesianCovarianceKey.EPOCH.name(), getTimeConverter(), covariance.getEpoch(), true);
455
456
457 if (covariance.getReferenceFrame() != metadata.getReferenceFrame()) {
458 generator.writeEntry(CartesianCovarianceKey.COV_REF_FRAME.name(), covariance.getReferenceFrame().getName(), null, false);
459 }
460
461
462 final RealMatrix m = covariance.getCovarianceMatrix();
463 if (generator.getFormat() == FileFormat.KVN) {
464 for (int i = 0; i < m.getRowDimension(); ++i) {
465
466
467 for (int j = 0; j <= i; ++j) {
468 if (j > 0) {
469 generator.writeRawData(' ');
470 }
471 generator.writeRawData(AccurateFormatter.format(Units.KM2.fromSI(m.getEntry(i, j))));
472 }
473
474
475 generator.newLine();
476
477 }
478 } else {
479 generator.writeEntry(CartesianCovarianceKey.CX_X.name(), m.getEntry(0, 0), Units.KM2, true);
480 generator.writeEntry(CartesianCovarianceKey.CY_X.name(), m.getEntry(1, 0), Units.KM2, true);
481 generator.writeEntry(CartesianCovarianceKey.CY_Y.name(), m.getEntry(1, 1), Units.KM2, true);
482 generator.writeEntry(CartesianCovarianceKey.CZ_X.name(), m.getEntry(2, 0), Units.KM2, true);
483 generator.writeEntry(CartesianCovarianceKey.CZ_Y.name(), m.getEntry(2, 1), Units.KM2, true);
484 generator.writeEntry(CartesianCovarianceKey.CZ_Z.name(), m.getEntry(2, 2), Units.KM2, true);
485 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X.name(), m.getEntry(3, 0), Units.KM2_PER_S, true);
486 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Y.name(), m.getEntry(3, 1), Units.KM2_PER_S, true);
487 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Z.name(), m.getEntry(3, 2), Units.KM2_PER_S, true);
488 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X_DOT.name(), m.getEntry(3, 3), Units.KM2_PER_S2, true);
489 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X.name(), m.getEntry(4, 0), Units.KM2_PER_S, true);
490 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y.name(), m.getEntry(4, 1), Units.KM2_PER_S, true);
491 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Z.name(), m.getEntry(4, 2), Units.KM2_PER_S, true);
492 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X_DOT.name(), m.getEntry(4, 3), Units.KM2_PER_S2, true);
493 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y_DOT.name(), m.getEntry(4, 4), Units.KM2_PER_S2, true);
494 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X.name(), m.getEntry(5, 0), Units.KM2_PER_S, true);
495 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y.name(), m.getEntry(5, 1), Units.KM2_PER_S, true);
496 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z.name(), m.getEntry(5, 2), Units.KM2_PER_S, true);
497 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X_DOT.name(), m.getEntry(5, 3), Units.KM2_PER_S2, true);
498 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y_DOT.name(), m.getEntry(5, 4), Units.KM2_PER_S2, true);
499 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z_DOT.name(), m.getEntry(5, 5), Units.KM2_PER_S2, true);
500 }
501
502
503 if (generator.getFormat() == FileFormat.XML) {
504 generator.exitSection();
505 }
506
507 }
508
509
510
511
512
513 void startData(final Generator generator) throws IOException {
514 if (generator.getFormat() == FileFormat.XML) {
515 generator.enterSection(XmlStructureKey.data.name());
516 }
517 }
518
519
520
521
522
523 void endData(final Generator generator) throws IOException {
524 if (generator.getFormat() == FileFormat.XML) {
525 generator.exitSection();
526 }
527 }
528
529 }