1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ccsds.ndm.odm.ocm;
18
19 import java.io.BufferedReader;
20 import java.io.BufferedWriter;
21 import java.io.ByteArrayInputStream;
22 import java.io.CharArrayWriter;
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.nio.charset.StandardCharsets;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.hipparchus.geometry.euclidean.threed.Vector3D;
33 import org.hipparchus.util.Precision;
34 import org.junit.jupiter.api.Assertions;
35 import org.junit.jupiter.api.BeforeEach;
36 import org.junit.jupiter.api.Test;
37 import org.orekit.Utils;
38 import org.orekit.bodies.CelestialBodyFactory;
39 import org.orekit.data.DataContext;
40 import org.orekit.data.DataSource;
41 import org.orekit.errors.OrekitIllegalArgumentException;
42 import org.orekit.errors.OrekitMessages;
43 import org.orekit.files.ccsds.definitions.BodyFacade;
44 import org.orekit.files.ccsds.definitions.CenterName;
45 import org.orekit.files.ccsds.definitions.FrameFacade;
46 import org.orekit.files.ccsds.definitions.TimeSystem;
47 import org.orekit.files.ccsds.ndm.ParserBuilder;
48 import org.orekit.files.ccsds.ndm.WriterBuilder;
49 import org.orekit.files.ccsds.ndm.odm.oem.InterpolationMethod;
50 import org.orekit.files.ccsds.utils.FileFormat;
51 import org.orekit.files.ccsds.utils.generation.Generator;
52 import org.orekit.files.ccsds.utils.generation.KvnGenerator;
53 import org.orekit.files.ccsds.utils.generation.XmlGenerator;
54 import org.orekit.files.general.EphemerisFile;
55 import org.orekit.frames.Frame;
56 import org.orekit.frames.FramesFactory;
57 import org.orekit.time.AbsoluteDate;
58 import org.orekit.time.TimeScalesFactory;
59 import org.orekit.utils.Constants;
60 import org.orekit.utils.IERSConventions;
61 import org.orekit.utils.TimeStampedPVCoordinates;
62
63 public class EphemerisOcmWriterTest {
64
65 @BeforeEach
66 public void setUp() throws Exception {
67 Utils.setDataRoot("regular-data");
68 }
69
70 @Test
71 public void testOCMWriter() {
72 Assertions.assertNotNull(new WriterBuilder().buildOcmWriter());
73 }
74
75 @Test
76 public void testWriteOCM3Kvn() throws IOException {
77 final CharArrayWriter caw = new CharArrayWriter();
78 final Generator generator = new KvnGenerator(caw, 0, "", Constants.JULIAN_DAY, 60);
79 doTestWriteOCM3(caw, generator);
80 }
81
82 @Test
83 public void testWriteOCM3Xml() throws IOException {
84 final CharArrayWriter caw = new CharArrayWriter();
85 final Generator generator = new XmlGenerator(caw, 2, "", Constants.JULIAN_DAY, true, XmlGenerator.NDM_XML_V3_SCHEMA_LOCATION);
86 doTestWriteOCM3(caw, generator);
87 }
88
89 private void doTestWriteOCM3(final CharArrayWriter caw, Generator generator) throws IOException {
90 final String ex = "/ccsds/odm/ocm/OCMExample3.txt";
91 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
92 final OcmParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOcmParser();
93 final Ocm ocm = parser.parseMessage(source);
94
95 OcmWriter writer = new WriterBuilder().
96 withConventions(IERSConventions.IERS_2010).
97 withDataContext(DataContext.getDefault()).
98 buildOcmWriter();
99 writer.writeMessage(generator, ocm);
100 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
101
102 final Ocm generatedOcm = new ParserBuilder().
103 withConventions(IERSConventions.IERS_2010).
104 withSimpleEOP(true).
105 withDataContext(DataContext.getDefault()).
106 withMu(Constants.EIGEN5C_EARTH_MU).
107 withDefaultInterpolationDegree(1).
108 buildOcmParser().
109 parseMessage(new DataSource("", () -> new ByteArrayInputStream(bytes)));
110 compareOcms(ocm, generatedOcm);
111 }
112
113 @Test
114 public void testUnfoundSpaceId() throws IOException {
115 final String ex = "/ccsds/odm/ocm/OCMExample1.txt";
116 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
117 final OcmParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOcmParser();
118 final Ocm ocm = parser.parseMessage(source);
119
120 EphemerisOcmWriter writer = new EphemerisOcmWriter(new WriterBuilder().buildOcmWriter(),
121 ocm.getHeader(), dummyMetadata(),
122 dummyTrajectoryMetadata(), FileFormat.KVN, "",
123 Constants.JULIAN_DAY, 0);
124 try {
125 writer.write(new CharArrayWriter(), ocm);
126 Assertions.fail("an exception should have been thrown");
127 } catch (OrekitIllegalArgumentException oiae) {
128 Assertions.assertEquals(OrekitMessages.VALUE_NOT_FOUND, oiae.getSpecifier());
129 Assertions.assertEquals(dummyMetadata().getInternationalDesignator(), oiae.getParts()[0]);
130 }
131
132 }
133
134 @Test
135 public void testNullFile() throws IOException {
136 final String ex = "/ccsds/odm/ocm/OCMExample1.txt";
137 final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
138 final OcmParser parser = new ParserBuilder().withMu(CelestialBodyFactory.getEarth().getGM()).buildOcmParser();
139 final Ocm ocm = parser.parseMessage(source);
140 EphemerisOcmWriter writer = new EphemerisOcmWriter(new WriterBuilder().buildOcmWriter(),
141 ocm.getHeader(),
142 ocm.getSegments().get(0).getMetadata(),
143 ocm.getSegments().get(0).getData().getTrajectoryBlocks().get(0).getMetadata(),
144 FileFormat.KVN, "dummy",
145 Constants.JULIAN_DAY, 0);
146 try {
147 writer.write((BufferedWriter) null, ocm);
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 EphemerisOcmWriter writer = new EphemerisOcmWriter(new WriterBuilder().buildOcmWriter(),
158 null, dummyMetadata(), dummyTrajectoryMetadata(),
159 FileFormat.KVN, "nullEphemeris",
160 Constants.JULIAN_DAY, 60);
161 CharArrayWriter caw = new CharArrayWriter();
162 writer.write(caw, null);
163 Assertions.assertEquals(0, caw.size());
164 }
165
166 @Test
167 public void testGenerateKVN() throws IOException {
168 doTestGenerate(FileFormat.KVN, 45);
169 }
170
171 @Test
172 public void testGenerateXML() throws IOException {
173 doTestGenerate(FileFormat.XML, 55);
174 }
175
176 private void doTestGenerate(FileFormat format, int expectedLines) throws IOException {
177
178 final DataContext context = DataContext.getDefault();
179 final String id = "1999-012A";
180 StandAloneEphemerisFile file = new StandAloneEphemerisFile();
181 file.generate(id, OrbitElementsType.CARTPV, context.getFrames().getEME2000(),
182 new TimeStampedPVCoordinates(AbsoluteDate.GALILEO_EPOCH,
183 new Vector3D(1.0e6, 2.0e6, 3.0e6),
184 new Vector3D(-300, -200, -100)),
185 900.0, 60.0);
186
187
188 OcmMetadata metadata = dummyMetadata();
189 metadata.setEpochT0(AbsoluteDate.GALILEO_EPOCH);
190 metadata.setInternationalDesignator(id);
191 EphemerisOcmWriter writer = new EphemerisOcmWriter(new WriterBuilder().withDataContext(context).buildOcmWriter(),
192 null, metadata, dummyTrajectoryMetadata(), format, "",
193 Constants.JULIAN_DAY, -1);
194 final CharArrayWriter caw = new CharArrayWriter();
195 writer.write(caw, file);
196 final byte[] bytes = caw.toString().getBytes(StandardCharsets.UTF_8);
197
198 int count = 0;
199 try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
200 InputStreamReader isr = new InputStreamReader(bais, StandardCharsets.UTF_8);
201 BufferedReader br = new BufferedReader(isr)) {
202 for (String line = br.readLine(); line != null; line = br.readLine()) {
203 ++count;
204 }
205 }
206 Assertions.assertEquals(expectedLines, count);
207
208 }
209
210 private static void compareOcmEphemerisBlocks(TrajectoryStateHistory block1, TrajectoryStateHistory block2) {
211 compareOcmEphemerisBlocksMetadata(block1.getMetadata(), block2.getMetadata());
212 Assertions.assertEquals(0.0, block1.getStart().durationFrom(block2.getStart()), 1.0e-12);
213 Assertions.assertEquals(0.0, block1.getStop().durationFrom(block2.getStop()), 1.0e-12);
214 Assertions.assertEquals(block1.getMetadata().getInterpolationDegree(), block2.getMetadata().getInterpolationDegree());
215 Assertions.assertEquals(block1.getMetadata().getInterpolationMethod(), block2.getMetadata().getInterpolationMethod());
216 Assertions.assertEquals(block1.getTrajectoryStates().size(), block2.getTrajectoryStates().size());
217 for (int i = 0; i < block1.getTrajectoryStates().size(); i++) {
218 TrajectoryState c1 = block1.getTrajectoryStates().get(i);
219 TrajectoryState c2 = block2.getTrajectoryStates().get(i);
220 Assertions.assertEquals(0.0, c1.getDate().durationFrom(c2.getDate()), 1.0e-12);
221 Assertions.assertEquals(c1.getType(), c2.getType());
222 Assertions.assertEquals(c1.getElements().length, c2.getElements().length);
223 for (int j = 0; j < c1.getElements().length; ++j) {
224 Assertions.assertTrue(Precision.equals(c1.getElements()[j], c2.getElements()[j], 2));
225 }
226 }
227 }
228
229 private static void compareOcmEphemerisBlocksMetadata(TrajectoryStateHistoryMetadata meta1, TrajectoryStateHistoryMetadata meta2) {
230 Assertions.assertEquals(meta1.getTrajID(), meta2.getTrajID());
231 Assertions.assertEquals(meta1.getTrajPrevID(), meta2.getTrajPrevID());
232 Assertions.assertEquals(meta1.getTrajNextID(), meta2.getTrajNextID());
233 Assertions.assertEquals(meta1.getTrajBasis(), meta2.getTrajBasis());
234 Assertions.assertEquals(meta1.getTrajBasisID(), meta2.getTrajBasisID());
235 Assertions.assertEquals(meta1.getInterpolationMethod(), meta2.getInterpolationMethod());
236 Assertions.assertEquals(meta1.getInterpolationDegree(), meta2.getInterpolationDegree());
237 Assertions.assertEquals(meta1.getPropagator(), meta2.getPropagator());
238 Assertions.assertEquals(meta1.getCenter().getName(), meta2.getCenter().getName());
239 Assertions.assertEquals(meta1.getTrajReferenceFrame().getName(), meta2.getTrajReferenceFrame().getName());
240 Assertions.assertEquals(meta1.getTrajFrameEpoch(), meta2.getTrajFrameEpoch());
241 Assertions.assertEquals(meta1.getUseableStartTime(), meta2.getUseableStartTime());
242 Assertions.assertEquals(meta1.getUseableStopTime(), meta2.getUseableStopTime());
243 Assertions.assertEquals(meta1.getOrbRevNum(), meta2.getOrbRevNum());
244 Assertions.assertEquals(meta1.getOrbRevNumBasis(), meta2.getOrbRevNumBasis());
245 Assertions.assertEquals(meta1.getOrbAveraging(), meta2.getOrbAveraging());
246 Assertions.assertEquals(meta1.getTrajType(), meta2.getTrajType());
247 Assertions.assertEquals(meta1.getTrajUnits().size(), meta2.getTrajUnits().size());
248 for (int i = 0; i < meta1.getTrajUnits().size(); ++i) {
249 Assertions.assertEquals(meta1.getTrajUnits().get(i), meta2.getTrajUnits().get(i));
250 }
251 }
252
253 static void compareOcms(Ocm file1, Ocm file2) {
254 Assertions.assertEquals(file1.getHeader().getOriginator(), file2.getHeader().getOriginator());
255 Assertions.assertEquals(file1.getSegments().get(0).getData().getTrajectoryBlocks().size(),
256 file2.getSegments().get(0).getData().getTrajectoryBlocks().size());
257 for (int i = 0; i < file1.getSegments().get(0).getData().getTrajectoryBlocks().size(); i++) {
258 compareOcmEphemerisBlocks(file1.getSegments().get(0).getData().getTrajectoryBlocks().get(i),
259 file2.getSegments().get(0).getData().getTrajectoryBlocks().get(i));
260 }
261 }
262
263 private class StandAloneEphemerisFile
264 implements EphemerisFile<TimeStampedPVCoordinates, TrajectoryStateHistory> {
265 private final Map<String, OcmSatelliteEphemeris> satEphem;
266
267
268
269 public StandAloneEphemerisFile() {
270 this.satEphem = new HashMap<>();
271 }
272
273 private void generate(final String internationalDesignator, final OrbitElementsType type,
274 final Frame referenceFrame, final TimeStampedPVCoordinates pv0,
275 final double duration, final double step) {
276
277 TrajectoryStateHistoryMetadata metadata = dummyTrajectoryMetadata();
278 metadata.addComment("generated for " + internationalDesignator);
279 metadata.setUseableStartTime(pv0.getDate());
280 metadata.setUseableStopTime(pv0.getDate().shiftedBy(duration));
281
282 List<TrajectoryState> states = new ArrayList<>();
283 for (double dt = 0; dt < duration; dt += step) {
284 TimeStampedPVCoordinates pv = pv0.shiftedBy(dt);
285 double[] elements = type.toRawElements(pv, referenceFrame, null, Constants.EIGEN5C_EARTH_MU);
286 states.add(new TrajectoryState(type, pv.getDate(), elements));
287 }
288
289 if (!satEphem.containsKey(internationalDesignator)) {
290 satEphem.put(internationalDesignator,
291 new OcmSatelliteEphemeris(internationalDesignator, Constants.EIGEN5C_EARTH_MU, Collections.emptyList()));
292 }
293
294 List<TrajectoryStateHistory> history = new ArrayList<>(satEphem.get(internationalDesignator).getSegments());
295 history.add(new TrajectoryStateHistory(metadata, states, null, Constants.EIGEN5C_EARTH_MU));
296 satEphem.put(internationalDesignator, new OcmSatelliteEphemeris(internationalDesignator, Constants.EIGEN5C_EARTH_MU, history));
297
298 }
299
300 @Override
301 public Map<String, OcmSatelliteEphemeris> getSatellites() {
302 return satEphem;
303 }
304
305 }
306
307 private OcmMetadata dummyMetadata() {
308 OcmMetadata metadata = new OcmMetadata(DataContext.getDefault());
309 metadata.addComment("dummy metadata comment");
310 metadata.setTimeSystem(TimeSystem.TT);
311 metadata.setInternationalDesignator("9999-999ZZZ");
312 metadata.setObjectName("transgalactic");
313 metadata.setEpochT0(AbsoluteDate.J2000_EPOCH.shiftedBy(80 * Constants.JULIAN_CENTURY));
314 metadata.setStartTime(metadata.getEpochT0());
315 metadata.setStopTime(metadata.getStartTime().shiftedBy(Constants.JULIAN_YEAR));
316 return metadata;
317 }
318
319 private TrajectoryStateHistoryMetadata dummyTrajectoryMetadata() {
320 final AbsoluteDate t0 = new AbsoluteDate(2003, 5, 7, 19, 43, 56.75, TimeScalesFactory.getUTC());
321 TrajectoryStateHistoryMetadata metadata = new TrajectoryStateHistoryMetadata(t0, DataContext.getDefault());
322 metadata.addComment("dummy trajectory comment");
323 metadata.setTrajID("traj 17");
324 metadata.setTrajBasis("PREDICTED");
325 metadata.setTrajBasisID("simulation 22");
326 metadata.setInterpolationMethod(InterpolationMethod.HERMITE);
327 metadata.setInterpolationDegree(4);
328 metadata.setPropagator("Orekit");
329 metadata.setCenter(BodyFacade.create(CenterName.EARTH));
330 metadata.setTrajReferenceFrame(FrameFacade.map(FramesFactory.getTOD(IERSConventions.IERS_2010, false)));
331 metadata.setTrajFrameEpoch(new AbsoluteDate(2003, 5, 7, TimeScalesFactory.getUTC()));
332 metadata.setUseableStartTime(t0);
333 metadata.setUseableStopTime(t0.shiftedBy(3600.0));
334 metadata.setOrbRevNum(12);
335 metadata.setOrbRevNumBasis(0);
336 metadata.setOrbAveraging("OSCULATING");
337 metadata.setTrajType(OrbitElementsType.KEPLERIAN);
338 metadata.setTrajUnits(metadata.getTrajType().getUnits());
339 return metadata;
340 }
341
342 }