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.OdmHeader;
34 import org.orekit.files.ccsds.ndm.odm.OdmMetadataKey;
35 import org.orekit.files.ccsds.ndm.odm.StateVectorKey;
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.CartesianDerivativesFilter;
46 import org.orekit.utils.IERSConventions;
47 import org.orekit.utils.TimeStampedPVCoordinates;
48 import org.orekit.utils.units.Unit;
49
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 public class OemWriter extends AbstractMessageWriter<OdmHeader, OemSegment, Oem> {
192
193
194 public static final double CCSDS_OEM_VERS = 3.0;
195
196
197 public static final String DEFAULT_FILE_NAME = "<OEM output>";
198
199
200 public static final int KVN_PADDING_WIDTH = 20;
201
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 public OemWriter(final IERSConventions conventions, final DataContext dataContext,
228 final AbsoluteDate missionReferenceDate) {
229 super(Oem.ROOT, Oem.FORMAT_VERSION_KEY, CCSDS_OEM_VERS,
230 new ContextBinding(
231 () -> conventions, () -> true, () -> dataContext,
232 () -> ParsedUnitsBehavior.STRICT_COMPLIANCE,
233 () -> missionReferenceDate, () -> TimeSystem.UTC, () -> 0.0, () -> 1.0));
234 }
235
236
237 @Override
238 protected void writeSegmentContent(final Generator generator, final double formatVersion,
239 final OemSegment segment)
240 throws IOException {
241
242 final OemMetadata metadata = segment.getMetadata();
243 writeMetadata(generator, metadata);
244
245 startData(generator);
246
247
248 generator.writeComments(segment.getData().getComments());
249
250
251 final CartesianDerivativesFilter filter = segment.getAvailableDerivatives();
252 if (filter == CartesianDerivativesFilter.USE_P) {
253 throw new OrekitException(OrekitMessages.MISSING_VELOCITY);
254 }
255 final boolean useAcceleration = filter.equals(CartesianDerivativesFilter.USE_PVA);
256 for (final TimeStampedPVCoordinates coordinates : segment.getCoordinates()) {
257 writeOrbitEphemerisLine(generator, metadata, coordinates, useAcceleration);
258 }
259
260
261 writeCovariances(generator, segment.getMetadata(), segment.getData().getCovarianceMatrices());
262
263 endData(generator);
264
265 }
266
267
268
269
270
271
272 void writeMetadata(final Generator generator, final OemMetadata metadata)
273 throws IOException {
274
275
276 generator.newLine();
277
278 final ContextBinding oldContext = getContext();
279 setContext(new ContextBinding(oldContext::getConventions,
280 oldContext::isSimpleEOP,
281 oldContext::getDataContext,
282 oldContext::getParsedUnitsBehavior,
283 oldContext::getReferenceDate,
284 metadata::getTimeSystem,
285 oldContext::getClockCount,
286 oldContext::getClockRate));
287
288
289 generator.enterSection(generator.getFormat() == FileFormat.KVN ?
290 KvnStructureKey.META.name() :
291 XmlStructureKey.metadata.name());
292
293 generator.writeComments(metadata.getComments());
294
295
296 generator.writeEntry(OdmMetadataKey.OBJECT_NAME.name(), metadata.getObjectName(), null, true);
297 generator.writeEntry(CommonMetadataKey.OBJECT_ID.name(), metadata.getObjectID(), null, true);
298 generator.writeEntry(CommonMetadataKey.CENTER_NAME.name(), metadata.getCenter().getName(), null, false);
299
300
301 generator.writeEntry(CommonMetadataKey.REF_FRAME.name(), metadata.getReferenceFrame().getName(), null, true);
302 if (metadata.getFrameEpoch() != null) {
303 generator.writeEntry(CommonMetadataKey.REF_FRAME_EPOCH.name(),
304 getTimeConverter(), metadata.getFrameEpoch(),
305 true, false);
306 }
307
308
309 generator.writeEntry(MetadataKey.TIME_SYSTEM.name(), metadata.getTimeSystem(), true);
310 generator.writeEntry(OemMetadataKey.START_TIME.name(), getTimeConverter(), metadata.getStartTime(), false, true);
311 if (metadata.getUseableStartTime() != null) {
312 generator.writeEntry(OemMetadataKey.USEABLE_START_TIME.name(), getTimeConverter(), metadata.getUseableStartTime(), false, false);
313 }
314 if (metadata.getUseableStopTime() != null) {
315 generator.writeEntry(OemMetadataKey.USEABLE_STOP_TIME.name(), getTimeConverter(), metadata.getUseableStopTime(), false, false);
316 }
317 generator.writeEntry(OemMetadataKey.STOP_TIME.name(), getTimeConverter(), metadata.getStopTime(), false, true);
318
319
320 generator.writeEntry(OemMetadataKey.INTERPOLATION.name(), metadata.getInterpolationMethod(), false);
321
322 if (metadata.getInterpolationDegree() >= 0) {
323 generator.writeEntry(OemMetadataKey.INTERPOLATION_DEGREE.name(),
324 Integer.toString(metadata.getInterpolationDegree()),
325 null, false);
326 }
327
328
329 generator.exitSection();
330
331
332 generator.newLine();
333
334 }
335
336
337
338
339
340
341
342
343
344 void writeOrbitEphemerisLine(final Generator generator, final OemMetadata metadata,
345 final TimeStampedPVCoordinates coordinates,
346 final boolean useAcceleration)
347 throws IOException {
348
349 if (generator.getFormat() == FileFormat.KVN) {
350
351
352 generator.writeRawData(generator.dateToString(getTimeConverter(), coordinates.getDate()));
353
354
355 generator.writeRawData(' ');
356 generator.writeRawData(String.format(generator.doubleToString(Unit.KILOMETRE.fromSI(coordinates.getPosition().getX()))));
357 generator.writeRawData(' ');
358 generator.writeRawData(String.format(generator.doubleToString(Unit.KILOMETRE.fromSI(coordinates.getPosition().getY()))));
359 generator.writeRawData(' ');
360 generator.writeRawData(String.format(generator.doubleToString(Unit.KILOMETRE.fromSI(coordinates.getPosition().getZ()))));
361
362
363 generator.writeRawData(' ');
364 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S.fromSI(coordinates.getVelocity().getX()))));
365 generator.writeRawData(' ');
366 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S.fromSI(coordinates.getVelocity().getY()))));
367 generator.writeRawData(' ');
368 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S.fromSI(coordinates.getVelocity().getZ()))));
369
370
371 if (useAcceleration) {
372 generator.writeRawData(' ');
373 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getX()))));
374 generator.writeRawData(' ');
375 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getY()))));
376 generator.writeRawData(' ');
377 generator.writeRawData(String.format(generator.doubleToString(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getZ()))));
378 }
379
380
381 generator.newLine();
382 } else {
383 generator.enterSection(OemDataSubStructureKey.stateVector.name());
384
385
386 generator.writeEntry(StateVectorKey.EPOCH.name(), getTimeConverter(), coordinates.getDate(), false, true);
387
388
389 generator.writeEntry(StateVectorKey.X.name(), coordinates.getPosition().getX(), Unit.KILOMETRE, true);
390 generator.writeEntry(StateVectorKey.Y.name(), coordinates.getPosition().getY(), Unit.KILOMETRE, true);
391 generator.writeEntry(StateVectorKey.Z.name(), coordinates.getPosition().getZ(), Unit.KILOMETRE, true);
392
393
394 generator.writeEntry(StateVectorKey.X_DOT.name(), coordinates.getVelocity().getX(), Units.KM_PER_S, true);
395 generator.writeEntry(StateVectorKey.Y_DOT.name(), coordinates.getVelocity().getY(), Units.KM_PER_S, true);
396 generator.writeEntry(StateVectorKey.Z_DOT.name(), coordinates.getVelocity().getZ(), Units.KM_PER_S, true);
397
398
399 if (useAcceleration) {
400 generator.writeEntry(StateVectorKey.X_DDOT.name(), coordinates.getAcceleration().getX(), Units.KM_PER_S2, true);
401 generator.writeEntry(StateVectorKey.Y_DDOT.name(), coordinates.getAcceleration().getY(), Units.KM_PER_S2, true);
402 generator.writeEntry(StateVectorKey.Z_DDOT.name(), coordinates.getAcceleration().getZ(), Units.KM_PER_S2, true);
403 }
404
405 generator.exitSection();
406
407 }
408 }
409
410
411
412
413
414
415
416
417 void writeCovariances(final Generator generator, final OemMetadata metadata,
418 final List<CartesianCovariance> covariances)
419 throws IOException {
420 if (covariances != null && !covariances.isEmpty()) {
421
422
423 if (generator.getFormat() == FileFormat.KVN) {
424 generator.enterSection(OemDataSubStructureKey.COVARIANCE.name());
425 }
426
427 for (final CartesianCovariance covariance : covariances) {
428 writeCovariance(generator, metadata, covariance);
429 }
430
431
432 if (generator.getFormat() == FileFormat.KVN) {
433 generator.exitSection();
434 }
435
436 }
437 }
438
439
440
441
442
443
444
445
446 private void writeCovariance(final Generator generator, final OemMetadata metadata,
447 final CartesianCovariance covariance)
448 throws IOException {
449
450
451 if (generator.getFormat() == FileFormat.XML) {
452 generator.enterSection(OemDataSubStructureKey.covarianceMatrix.name());
453 }
454
455
456 generator.writeEntry(CartesianCovarianceKey.EPOCH.name(), getTimeConverter(), covariance.getEpoch(), false, true);
457
458
459 if (covariance.getReferenceFrame() != metadata.getReferenceFrame()) {
460 generator.writeEntry(CartesianCovarianceKey.COV_REF_FRAME.name(), covariance.getReferenceFrame().getName(), null, false);
461 }
462
463
464 final RealMatrix m = covariance.getCovarianceMatrix();
465 if (generator.getFormat() == FileFormat.KVN) {
466 for (int i = 0; i < m.getRowDimension(); ++i) {
467
468
469 for (int j = 0; j <= i; ++j) {
470 if (j > 0) {
471 generator.writeRawData(' ');
472 }
473 generator.writeRawData(generator.doubleToString(Units.KM2.fromSI(m.getEntry(i, j))));
474 }
475
476
477 generator.newLine();
478
479 }
480 } else {
481 generator.writeEntry(CartesianCovarianceKey.CX_X.name(), m.getEntry(0, 0), Units.KM2, true);
482 generator.writeEntry(CartesianCovarianceKey.CY_X.name(), m.getEntry(1, 0), Units.KM2, true);
483 generator.writeEntry(CartesianCovarianceKey.CY_Y.name(), m.getEntry(1, 1), Units.KM2, true);
484 generator.writeEntry(CartesianCovarianceKey.CZ_X.name(), m.getEntry(2, 0), Units.KM2, true);
485 generator.writeEntry(CartesianCovarianceKey.CZ_Y.name(), m.getEntry(2, 1), Units.KM2, true);
486 generator.writeEntry(CartesianCovarianceKey.CZ_Z.name(), m.getEntry(2, 2), Units.KM2, true);
487 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X.name(), m.getEntry(3, 0), Units.KM2_PER_S, true);
488 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Y.name(), m.getEntry(3, 1), Units.KM2_PER_S, true);
489 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Z.name(), m.getEntry(3, 2), Units.KM2_PER_S, true);
490 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X_DOT.name(), m.getEntry(3, 3), Units.KM2_PER_S2, true);
491 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X.name(), m.getEntry(4, 0), Units.KM2_PER_S, true);
492 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y.name(), m.getEntry(4, 1), Units.KM2_PER_S, true);
493 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Z.name(), m.getEntry(4, 2), Units.KM2_PER_S, true);
494 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X_DOT.name(), m.getEntry(4, 3), Units.KM2_PER_S2, true);
495 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y_DOT.name(), m.getEntry(4, 4), Units.KM2_PER_S2, true);
496 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X.name(), m.getEntry(5, 0), Units.KM2_PER_S, true);
497 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y.name(), m.getEntry(5, 1), Units.KM2_PER_S, true);
498 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z.name(), m.getEntry(5, 2), Units.KM2_PER_S, true);
499 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X_DOT.name(), m.getEntry(5, 3), Units.KM2_PER_S2, true);
500 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y_DOT.name(), m.getEntry(5, 4), Units.KM2_PER_S2, true);
501 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z_DOT.name(), m.getEntry(5, 5), Units.KM2_PER_S2, true);
502 }
503
504
505 if (generator.getFormat() == FileFormat.XML) {
506 generator.exitSection();
507 }
508
509 }
510
511
512
513
514
515 void startData(final Generator generator) throws IOException {
516 if (generator.getFormat() == FileFormat.XML) {
517 generator.enterSection(XmlStructureKey.data.name());
518 }
519 }
520
521
522
523
524
525 void endData(final Generator generator) throws IOException {
526 if (generator.getFormat() == FileFormat.XML) {
527 generator.exitSection();
528 }
529 }
530
531 }