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.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<OdmHeader, 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 protected 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 true, false);
307 }
308
309
310 generator.writeEntry(MetadataKey.TIME_SYSTEM.name(), metadata.getTimeSystem(), true);
311 generator.writeEntry(OemMetadataKey.START_TIME.name(), getTimeConverter(), metadata.getStartTime(), false, true);
312 if (metadata.getUseableStartTime() != null) {
313 generator.writeEntry(OemMetadataKey.USEABLE_START_TIME.name(), getTimeConverter(), metadata.getUseableStartTime(), false, false);
314 }
315 if (metadata.getUseableStopTime() != null) {
316 generator.writeEntry(OemMetadataKey.USEABLE_STOP_TIME.name(), getTimeConverter(), metadata.getUseableStopTime(), false, false);
317 }
318 generator.writeEntry(OemMetadataKey.STOP_TIME.name(), getTimeConverter(), metadata.getStopTime(), false, true);
319
320
321 generator.writeEntry(OemMetadataKey.INTERPOLATION.name(), metadata.getInterpolationMethod(), false);
322
323 if (metadata.getInterpolationDegree() >= 0) {
324 generator.writeEntry(OemMetadataKey.INTERPOLATION_DEGREE.name(),
325 Integer.toString(metadata.getInterpolationDegree()),
326 null, false);
327 }
328
329
330 generator.exitSection();
331
332
333 generator.newLine();
334
335 }
336
337
338
339
340
341
342
343
344
345 void writeOrbitEphemerisLine(final Generator generator, final OemMetadata metadata,
346 final TimeStampedPVCoordinates coordinates,
347 final boolean useAcceleration)
348 throws IOException {
349
350 if (generator.getFormat() == FileFormat.KVN) {
351
352
353 generator.writeRawData(generator.dateToString(getTimeConverter(), coordinates.getDate()));
354
355
356 generator.writeRawData(' ');
357 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getX()))));
358 generator.writeRawData(' ');
359 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getY()))));
360 generator.writeRawData(' ');
361 generator.writeRawData(String.format(AccurateFormatter.format(Unit.KILOMETRE.fromSI(coordinates.getPosition().getZ()))));
362
363
364 generator.writeRawData(' ');
365 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getX()))));
366 generator.writeRawData(' ');
367 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getY()))));
368 generator.writeRawData(' ');
369 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S.fromSI(coordinates.getVelocity().getZ()))));
370
371
372 if (useAcceleration) {
373 generator.writeRawData(' ');
374 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getX()))));
375 generator.writeRawData(' ');
376 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getY()))));
377 generator.writeRawData(' ');
378 generator.writeRawData(String.format(AccurateFormatter.format(Units.KM_PER_S2.fromSI(coordinates.getAcceleration().getZ()))));
379 }
380
381
382 generator.newLine();
383 } else {
384 generator.enterSection(OemDataSubStructureKey.stateVector.name());
385
386
387 generator.writeEntry(StateVectorKey.EPOCH.name(), getTimeConverter(), coordinates.getDate(), false, true);
388
389
390 generator.writeEntry(StateVectorKey.X.name(), coordinates.getPosition().getX(), Unit.KILOMETRE, true);
391 generator.writeEntry(StateVectorKey.Y.name(), coordinates.getPosition().getY(), Unit.KILOMETRE, true);
392 generator.writeEntry(StateVectorKey.Z.name(), coordinates.getPosition().getZ(), Unit.KILOMETRE, true);
393
394
395 generator.writeEntry(StateVectorKey.X_DOT.name(), coordinates.getVelocity().getX(), Units.KM_PER_S, true);
396 generator.writeEntry(StateVectorKey.Y_DOT.name(), coordinates.getVelocity().getY(), Units.KM_PER_S, true);
397 generator.writeEntry(StateVectorKey.Z_DOT.name(), coordinates.getVelocity().getZ(), Units.KM_PER_S, true);
398
399
400 if (useAcceleration) {
401 generator.writeEntry(StateVectorKey.X_DDOT.name(), coordinates.getAcceleration().getX(), Units.KM_PER_S2, true);
402 generator.writeEntry(StateVectorKey.Y_DDOT.name(), coordinates.getAcceleration().getY(), Units.KM_PER_S2, true);
403 generator.writeEntry(StateVectorKey.Z_DDOT.name(), coordinates.getAcceleration().getZ(), Units.KM_PER_S2, true);
404 }
405
406 generator.exitSection();
407
408 }
409 }
410
411
412
413
414
415
416
417
418 void writeCovariances(final Generator generator, final OemMetadata metadata,
419 final List<CartesianCovariance> covariances)
420 throws IOException {
421 if (covariances != null && !covariances.isEmpty()) {
422
423
424 if (generator.getFormat() == FileFormat.KVN) {
425 generator.enterSection(OemDataSubStructureKey.COVARIANCE.name());
426 }
427
428 for (final CartesianCovariance covariance : covariances) {
429 writeCovariance(generator, metadata, covariance);
430 }
431
432
433 if (generator.getFormat() == FileFormat.KVN) {
434 generator.exitSection();
435 }
436
437 }
438 }
439
440
441
442
443
444
445
446
447 private void writeCovariance(final Generator generator, final OemMetadata metadata,
448 final CartesianCovariance covariance)
449 throws IOException {
450
451
452 if (generator.getFormat() == FileFormat.XML) {
453 generator.enterSection(OemDataSubStructureKey.covarianceMatrix.name());
454 }
455
456
457 generator.writeEntry(CartesianCovarianceKey.EPOCH.name(), getTimeConverter(), covariance.getEpoch(), false, true);
458
459
460 if (covariance.getReferenceFrame() != metadata.getReferenceFrame()) {
461 generator.writeEntry(CartesianCovarianceKey.COV_REF_FRAME.name(), covariance.getReferenceFrame().getName(), null, false);
462 }
463
464
465 final RealMatrix m = covariance.getCovarianceMatrix();
466 if (generator.getFormat() == FileFormat.KVN) {
467 for (int i = 0; i < m.getRowDimension(); ++i) {
468
469
470 for (int j = 0; j <= i; ++j) {
471 if (j > 0) {
472 generator.writeRawData(' ');
473 }
474 generator.writeRawData(AccurateFormatter.format(Units.KM2.fromSI(m.getEntry(i, j))));
475 }
476
477
478 generator.newLine();
479
480 }
481 } else {
482 generator.writeEntry(CartesianCovarianceKey.CX_X.name(), m.getEntry(0, 0), Units.KM2, true);
483 generator.writeEntry(CartesianCovarianceKey.CY_X.name(), m.getEntry(1, 0), Units.KM2, true);
484 generator.writeEntry(CartesianCovarianceKey.CY_Y.name(), m.getEntry(1, 1), Units.KM2, true);
485 generator.writeEntry(CartesianCovarianceKey.CZ_X.name(), m.getEntry(2, 0), Units.KM2, true);
486 generator.writeEntry(CartesianCovarianceKey.CZ_Y.name(), m.getEntry(2, 1), Units.KM2, true);
487 generator.writeEntry(CartesianCovarianceKey.CZ_Z.name(), m.getEntry(2, 2), Units.KM2, true);
488 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X.name(), m.getEntry(3, 0), Units.KM2_PER_S, true);
489 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Y.name(), m.getEntry(3, 1), Units.KM2_PER_S, true);
490 generator.writeEntry(CartesianCovarianceKey.CX_DOT_Z.name(), m.getEntry(3, 2), Units.KM2_PER_S, true);
491 generator.writeEntry(CartesianCovarianceKey.CX_DOT_X_DOT.name(), m.getEntry(3, 3), Units.KM2_PER_S2, true);
492 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X.name(), m.getEntry(4, 0), Units.KM2_PER_S, true);
493 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y.name(), m.getEntry(4, 1), Units.KM2_PER_S, true);
494 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Z.name(), m.getEntry(4, 2), Units.KM2_PER_S, true);
495 generator.writeEntry(CartesianCovarianceKey.CY_DOT_X_DOT.name(), m.getEntry(4, 3), Units.KM2_PER_S2, true);
496 generator.writeEntry(CartesianCovarianceKey.CY_DOT_Y_DOT.name(), m.getEntry(4, 4), Units.KM2_PER_S2, true);
497 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X.name(), m.getEntry(5, 0), Units.KM2_PER_S, true);
498 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y.name(), m.getEntry(5, 1), Units.KM2_PER_S, true);
499 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z.name(), m.getEntry(5, 2), Units.KM2_PER_S, true);
500 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_X_DOT.name(), m.getEntry(5, 3), Units.KM2_PER_S2, true);
501 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Y_DOT.name(), m.getEntry(5, 4), Units.KM2_PER_S2, true);
502 generator.writeEntry(CartesianCovarianceKey.CZ_DOT_Z_DOT.name(), m.getEntry(5, 5), Units.KM2_PER_S2, true);
503 }
504
505
506 if (generator.getFormat() == FileFormat.XML) {
507 generator.exitSection();
508 }
509
510 }
511
512
513
514
515
516 void startData(final Generator generator) throws IOException {
517 if (generator.getFormat() == FileFormat.XML) {
518 generator.enterSection(XmlStructureKey.data.name());
519 }
520 }
521
522
523
524
525
526 void endData(final Generator generator) throws IOException {
527 if (generator.getFormat() == FileFormat.XML) {
528 generator.exitSection();
529 }
530 }
531
532 }