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