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 org.hipparchus.geometry.euclidean.threed.Vector3D;
20 import org.junit.jupiter.api.Assertions;
21 import org.junit.jupiter.api.BeforeEach;
22 import org.junit.jupiter.api.Test;
23 import org.orekit.Utils;
24 import org.orekit.bodies.CelestialBodyFactory;
25 import org.orekit.data.DataContext;
26 import org.orekit.data.DataSource;
27 import org.orekit.errors.OrekitIllegalArgumentException;
28 import org.orekit.errors.OrekitMessages;
29 import org.orekit.files.ccsds.definitions.BodyFacade;
30 import org.orekit.files.ccsds.definitions.FrameFacade;
31 import org.orekit.files.ccsds.definitions.TimeSystem;
32 import org.orekit.files.ccsds.ndm.ParserBuilder;
33 import org.orekit.files.ccsds.ndm.WriterBuilder;
34 import org.orekit.files.ccsds.ndm.odm.CartesianCovariance;
35 import org.orekit.files.ccsds.utils.FileFormat;
36 import org.orekit.files.ccsds.utils.generation.Generator;
37 import org.orekit.files.ccsds.utils.generation.KvnGenerator;
38 import org.orekit.files.ccsds.utils.generation.XmlGenerator;
39 import org.orekit.files.general.EphemerisFile;
40 import org.orekit.frames.Frame;
41 import org.orekit.frames.FramesFactory;
42 import org.orekit.time.AbsoluteDate;
43 import org.orekit.utils.Constants;
44 import org.orekit.utils.IERSConventions;
45 import org.orekit.utils.TimeStampedPVCoordinates;
46
47 import java.io.BufferedReader;
48 import java.io.BufferedWriter;
49 import java.io.ByteArrayInputStream;
50 import java.io.CharArrayWriter;
51 import java.io.IOException;
52 import java.io.InputStreamReader;
53 import java.nio.charset.StandardCharsets;
54 import java.util.ArrayList;
55 import java.util.Collections;
56 import java.util.HashMap;
57 import java.util.List;
58 import java.util.Map;
59
60 public class EphemerisOemWriterTest {
61
62
63 private static final double POSITION_PRECISION = 1;
64
65 private static final double VELOCITY_PRECISION = 1e-2;
66
67 @BeforeEach
68 public void setUp() throws Exception {
69 Utils.setDataRoot("regular-data");
70 }
71
72 @Test
73 public void testOEMWriter() {
74 Assertions.assertNotNull(new WriterBuilder().buildOemWriter());
75 }
76
77 @Test
78 public void testWriteOEM1Kvn() throws IOException {
79 final CharArrayWriter caw = new CharArrayWriter();
80 final Generator generator = new KvnGenerator(caw, 0, "", Constants.JULIAN_DAY, 60);
81 doTestWriteOEM1(caw, generator);
82 }
83
84 @Test
85 public void testWriteOEM1Xml() throws IOException {
86 final CharArrayWriter caw = new CharArrayWriter();
87 final Generator generator = new XmlGenerator(caw, 2, "", Constants.JULIAN_DAY, true, XmlGenerator.NDM_XML_V3_SCHEMA_LOCATION);
88 doTestWriteOEM1(caw, generator);
89 }
90
91 private void doTestWriteOEM1(final CharArrayWriter caw, Generator generator) throws IOException {
92 final String ex = "/ccsds/odm/oem/OEMExample1.txt";
93 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
94 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOemParser();
95 final Oem oem = parser.parseMessage(source);
96
97 OemWriter writer = new WriterBuilder().
98 withConventions(IERSConventions.IERS_2010).
99 withDataContext(DataContext.getDefault()).
100 buildOemWriter();
101 writer.writeMessage(generator, oem);
102 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
103
104 final Oem generatedOem = new ParserBuilder().
105 withConventions(IERSConventions.IERS_2010).
106 withSimpleEOP(true).
107 withDataContext(DataContext.getDefault()).
108 withMu(CelestialBodyFactory.getMars().getGM()).
109 withDefaultInterpolationDegree(1).
110 buildOemParser().
111 parseMessage(new DataSource("", () -> new ByteArrayInputStream(bytes)));
112 compareOems(oem, generatedOem);
113 }
114
115 @Test
116 public void testUnfoundSpaceId() throws IOException {
117 final String ex = "/ccsds/odm/oem/OEMExample1.txt";
118 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
119 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOemParser();
120 final Oem oem = parser.parseMessage(source);
121
122 EphemerisOemWriter writer = new EphemerisOemWriter(new WriterBuilder().buildOemWriter(),
123 oem.getHeader(), dummyMetadata(), FileFormat.KVN, "",
124 Constants.JULIAN_DAY, 0);
125 try {
126 writer.write(new CharArrayWriter(), oem);
127 Assertions.fail("an exception should have been thrown");
128 } catch (OrekitIllegalArgumentException oiae) {
129 Assertions.assertEquals(OrekitMessages.VALUE_NOT_FOUND, oiae.getSpecifier());
130 Assertions.assertEquals(dummyMetadata().getObjectID(), oiae.getParts()[0]);
131 }
132
133 }
134
135 @Test
136 public void testNullFile() throws IOException {
137 final String ex = "/ccsds/odm/oem/OEMExample1.txt";
138 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
139 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOemParser();
140 final Oem oem = parser.parseMessage(source);
141 EphemerisOemWriter writer = new EphemerisOemWriter(new WriterBuilder().buildOemWriter(),
142 oem.getHeader(),
143 oem.getSegments().get(0).getMetadata(),
144 FileFormat.KVN, "dummy",
145 Constants.JULIAN_DAY, 0);
146 try {
147 writer.write((BufferedWriter) null, oem);
148 Assertions.fail("an exception should have been thrown");
149 } catch (OrekitIllegalArgumentException oiae) {
150 Assertions.assertEquals(OrekitMessages.NULL_ARGUMENT, oiae.getSpecifier());
151 Assertions.assertEquals("writer", oiae.getParts()[0]);
152 }
153 }
154
155 @Test
156 public void testNullEphemeris() throws IOException {
157 EphemerisOemWriter writer = new EphemerisOemWriter(new WriterBuilder().buildOemWriter(),
158 null, dummyMetadata(), FileFormat.KVN, "nullEphemeris",
159 Constants.JULIAN_DAY, 60);
160 CharArrayWriter caw = new CharArrayWriter();
161 writer.write(caw, null);
162 Assertions.assertEquals(0, caw.size());
163 }
164
165 @Test
166 public void testUnisatelliteFileWithDefault() throws IOException {
167 final String ex = "/ccsds/odm/oem/OEMExample1.txt";
168 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
169 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOemParser();
170 final Oem oem = parser.parseMessage(source);
171
172 OemWriter writer = new WriterBuilder().buildOemWriter();
173 final CharArrayWriter caw = new CharArrayWriter();
174 writer.writeMessage(new KvnGenerator(caw, 0, "", Constants.JULIAN_DAY, 60), oem);
175 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
176
177 final Oem generatedOem = new ParserBuilder().
178 withMu(CelestialBodyFactory.getEarth().getGM()).
179 buildOemParser().
180 parseMessage(new DataSource("", () -> new ByteArrayInputStream(bytes)));
181 Assertions.assertEquals(oem.getSegments().get(0).getMetadata().getObjectID(),
182 generatedOem.getSegments().get(0).getMetadata().getObjectID());
183 }
184
185 @Test
186 public void testIssue723() throws IOException {
187 final String ex = "/ccsds/odm/oem/OEMExampleWithHeaderComment.txt";
188 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
189 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOemParser();
190 final Oem oem = parser.parseMessage(source);
191
192 EphemerisOemWriter writer = new EphemerisOemWriter(new WriterBuilder().buildOemWriter(),
193 oem.getHeader(),
194 oem.getSegments().get(0).getMetadata(),
195 FileFormat.KVN, "TestOEMIssue723.aem",
196 Constants.JULIAN_DAY, 0);
197 final CharArrayWriter caw = new CharArrayWriter();
198 writer.write(caw, oem);
199 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
200
201 final Oem generatedOem = new ParserBuilder().
202 withMu(CelestialBodyFactory.getEarth().getGM()).
203 buildOemParser().
204 parseMessage(new DataSource("", () -> new ByteArrayInputStream(bytes)));
205 Assertions.assertEquals(oem.getHeader().getComments().get(0), generatedOem.getHeader().getComments().get(0));
206 }
207
208
209
210
211
212
213 @Test
214 public void testWriteOemFormat() throws IOException {
215
216 String exampleFile = "/ccsds/odm/oem/OEMExample4.txt";
217 final DataSource source = new DataSource(exampleFile, () -> getClass().getResourceAsStream(exampleFile));
218 final OemParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOemParser();
219 Oem oem = parser.parseMessage(source);
220
221 OemWriter writer = new WriterBuilder().buildOemWriter();
222 final CharArrayWriter caw = new CharArrayWriter();
223 writer.writeMessage(new KvnGenerator(caw, 0, "", Constants.JULIAN_DAY, 60), oem);
224
225 String[] lines2 = caw.toString().split("\n");
226 Assertions.assertEquals("2002-12-18T12:00:00.331 2789.619 -280.045 -1746.755 4.73372 -2.49586 -1.0419499999999997", lines2[21]);
227 Assertions.assertEquals("2002-12-18T12:01:00.331 2783.419 -308.143 -1877.071 5.18604 -2.42124 -1.99608", lines2[22]);
228 Assertions.assertEquals("2002-12-18T12:02:00.331 2776.033 -336.859 -2008.682 5.63678 -2.33951 -1.94687", lines2[23]);
229
230 }
231
232 @Test
233 public void testMultisatelliteFile() throws IOException {
234
235 final DataContext context = DataContext.getDefault();
236 final String id1 = "1999-012A";
237 final String id2 = "1999-012B";
238 StandAloneEphemerisFile file = new StandAloneEphemerisFile();
239 file.generate(id1, id1 + "-name", context.getFrames().getEME2000(),
240 new TimeStampedPVCoordinates(AbsoluteDate.GALILEO_EPOCH,
241 new Vector3D(1.0e6, 2.0e6, 3.0e6),
242 new Vector3D(-300, -200, -100)),
243 900.0, 60.0);
244 file.generate(id2, id2 + "-name", context.getFrames().getEME2000(),
245 new TimeStampedPVCoordinates(AbsoluteDate.GALILEO_EPOCH,
246 new Vector3D(3.0e6, 2.0e6, -1.0e6),
247 new Vector3D(-17, -20, 150)),
248 600.0, 10.0);
249
250
251 OemMetadata metadata = dummyMetadata();
252 metadata.setObjectID(id2);
253 EphemerisOemWriter writer = new EphemerisOemWriter(new WriterBuilder().withDataContext(context).buildOemWriter(),
254 null, metadata, FileFormat.KVN, "",
255 Constants.JULIAN_DAY, -1);
256 final CharArrayWriter caw = new CharArrayWriter();
257 writer.write(caw, file);
258 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
259
260 int count = 0;
261 try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
262 InputStreamReader isr = new InputStreamReader(bais, StandardCharsets.UTF_8);
263 BufferedReader br = new BufferedReader(isr)) {
264 for (String line = br.readLine(); line != null; line = br.readLine()) {
265 ++count;
266 }
267 }
268 Assertions.assertEquals(80, count);
269
270 }
271
272 private static void compareOemEphemerisBlocks(OemSegment block1, OemSegment block2) {
273 compareOemEphemerisBlocksMetadata(block1.getMetadata(), block2.getMetadata());
274 Assertions.assertEquals(block1.getStart(), block2.getStart());
275 Assertions.assertEquals(block1.getStop(), block2.getStop());
276 Assertions.assertEquals(block1.getMetadata().getInterpolationDegree(), block2.getMetadata().getInterpolationDegree());
277 Assertions.assertEquals(block1.getMetadata().getInterpolationMethod(), block2.getMetadata().getInterpolationMethod());
278 Assertions.assertEquals(block1.getData().getEphemeridesDataLines().size(), block2.getData().getEphemeridesDataLines().size());
279 for (int i = 0; i < block1.getData().getEphemeridesDataLines().size(); i++) {
280 TimeStampedPVCoordinates c1 = block1.getData().getEphemeridesDataLines().get(i);
281 TimeStampedPVCoordinates c2 = block2.getData().getEphemeridesDataLines().get(i);
282 Assertions.assertEquals(c1.getDate(), c2.getDate());
283 Assertions.assertEquals( 0.0,
284 Vector3D.distance(c1.getPosition(), c2.getPosition()), POSITION_PRECISION,c1.getPosition() + " -> " + c2.getPosition());
285 Assertions.assertEquals( 0.0,
286 Vector3D.distance(c1.getVelocity(), c2.getVelocity()), VELOCITY_PRECISION,c1.getVelocity() + " -> " + c2.getVelocity());
287 }
288 Assertions.assertEquals(block1.getCovarianceMatrices().size(), block2.getCovarianceMatrices().size());
289 for (int j = 0; j < block1.getCovarianceMatrices().size(); j++) {
290 CartesianCovariance covMat1 = block1.getCovarianceMatrices().get(j);
291 CartesianCovariance covMat2 = block2.getCovarianceMatrices().get(j);
292 Assertions.assertEquals(covMat1.getEpoch(), covMat2.getEpoch());
293 Assertions.assertEquals(covMat1.getReferenceFrame().asFrame(), covMat2.getReferenceFrame().asFrame());
294 Assertions.assertEquals(covMat1.getReferenceFrame().asCelestialBodyFrame(), covMat2.getReferenceFrame().asCelestialBodyFrame());
295 Assertions.assertEquals(covMat1.getReferenceFrame().asOrbitRelativeFrame(), covMat2.getReferenceFrame().asOrbitRelativeFrame());
296 Assertions.assertEquals(covMat1.getReferenceFrame().asSpacecraftBodyFrame(), covMat2.getReferenceFrame().asSpacecraftBodyFrame());
297 Assertions.assertEquals(covMat1.getCovarianceMatrix(),covMat2.getCovarianceMatrix());
298 }
299 }
300
301 private static void compareOemEphemerisBlocksMetadata(OemMetadata meta1, OemMetadata meta2) {
302 Assertions.assertEquals(meta1.getObjectID(), meta2.getObjectID());
303 Assertions.assertEquals(meta1.getObjectName(), meta2.getObjectName());
304 Assertions.assertEquals(meta1.getCenter().getName(), meta2.getCenter().getName());
305 Assertions.assertEquals(meta1.getReferenceFrame().asFrame(), meta2.getReferenceFrame().asFrame());
306 Assertions.assertEquals(meta1.getReferenceFrame().asCelestialBodyFrame(), meta2.getReferenceFrame().asCelestialBodyFrame());
307 Assertions.assertEquals(meta1.getReferenceFrame().asOrbitRelativeFrame(), meta2.getReferenceFrame().asOrbitRelativeFrame());
308 Assertions.assertEquals(meta1.getReferenceFrame().asSpacecraftBodyFrame(), meta2.getReferenceFrame().asSpacecraftBodyFrame());
309 Assertions.assertEquals(meta1.getTimeSystem().name(), meta2.getTimeSystem().name());
310 }
311
312 static void compareOems(Oem file1, Oem file2) {
313 Assertions.assertEquals(file1.getHeader().getOriginator(), file2.getHeader().getOriginator());
314 Assertions.assertEquals(file1.getSegments().size(), file2.getSegments().size());
315 for (int i = 0; i < file1.getSegments().size(); i++) {
316 compareOemEphemerisBlocks(file1.getSegments().get(i), file2.getSegments().get(i));
317 }
318 }
319
320 private class StandAloneEphemerisFile
321 implements EphemerisFile<TimeStampedPVCoordinates, OemSegment> {
322 private final Map<String, OemSatelliteEphemeris> satEphem;
323
324
325
326 public StandAloneEphemerisFile() {
327 this.satEphem = new HashMap<String, OemSatelliteEphemeris>();
328 }
329
330 private void generate(final String objectID, final String objectName,
331 final Frame referenceFrame, final TimeStampedPVCoordinates pv0,
332 final double duration, final double step) {
333
334 OemMetadata metadata = dummyMetadata();
335 metadata.addComment("metadata for " + objectName);
336 metadata.setObjectID(objectID);
337 metadata.setObjectName(objectName);
338 metadata.setStartTime(pv0.getDate());
339 metadata.setStopTime(pv0.getDate().shiftedBy(duration));
340 metadata.setUseableStartTime(metadata.getStartTime().shiftedBy(step));
341 metadata.setUseableStartTime(metadata.getStopTime().shiftedBy(-step));
342
343 OemData data = new OemData();
344 data.addComment("generated data for " + objectName);
345 data.addComment("duration was set to " + duration + " s");
346 data.addComment("step was set to " + step + " s");
347 for (double dt = 0; dt < duration; dt += step) {
348 data.addData(pv0.shiftedBy(dt), false);
349 }
350
351 if (!satEphem.containsKey(objectID)) {
352 satEphem.put(objectID,
353 new OemSatelliteEphemeris(objectID, Constants.EIGEN5C_EARTH_MU, Collections.emptyList()));
354 }
355
356 List<OemSegment> segments =
357 new ArrayList<>(satEphem.get(objectID).getSegments());
358 segments.add(new OemSegment(metadata, data, Constants.EIGEN5C_EARTH_MU));
359 satEphem.put(objectID, new OemSatelliteEphemeris(objectID, Constants.EIGEN5C_EARTH_MU, segments));
360
361 }
362
363 @Override
364 public Map<String, OemSatelliteEphemeris> getSatellites() {
365 return satEphem;
366 }
367
368 }
369
370 private OemMetadata dummyMetadata() {
371 OemMetadata metadata = new OemMetadata(4);
372 metadata.addComment("dummy comment");
373 metadata.setTimeSystem(TimeSystem.TT);
374 metadata.setObjectID("9999-999ZZZ");
375 metadata.setObjectName("transgalactic");
376 metadata.setCenter(new BodyFacade("EARTH", CelestialBodyFactory.getCelestialBodies().getEarth()));
377 metadata.setReferenceFrame(FrameFacade.map(FramesFactory.getEME2000()));
378 metadata.setStartTime(AbsoluteDate.J2000_EPOCH.shiftedBy(80 * Constants.JULIAN_CENTURY));
379 metadata.setStopTime(metadata.getStartTime().shiftedBy(Constants.JULIAN_YEAR));
380 return metadata;
381 }
382
383 }