1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.ccsds.ndm.odm.oem;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.SequenceInputStream;
23  import java.net.URISyntaxException;
24  import java.nio.charset.Charset;
25  import java.nio.charset.StandardCharsets;
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.function.Function;
29  
30  import org.hamcrest.MatcherAssert;
31  import org.hamcrest.Matchers;
32  import org.hipparchus.geometry.euclidean.threed.Rotation;
33  import org.hipparchus.geometry.euclidean.threed.Vector3D;
34  import org.hipparchus.linear.Array2DRowRealMatrix;
35  import org.hipparchus.util.Pair;
36  import org.junit.jupiter.api.Assertions;
37  import org.junit.jupiter.api.BeforeEach;
38  import org.junit.jupiter.api.Test;
39  import org.orekit.OrekitMatchers;
40  import org.orekit.Utils;
41  import org.orekit.bodies.CelestialBody;
42  import org.orekit.bodies.CelestialBodyFactory;
43  import org.orekit.data.DataContext;
44  import org.orekit.data.DataSource;
45  import org.orekit.errors.OrekitException;
46  import org.orekit.errors.OrekitMessages;
47  import org.orekit.files.ccsds.definitions.BodyFacade;
48  import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
49  import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
50  import org.orekit.files.ccsds.definitions.FrameFacade;
51  import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
52  import org.orekit.files.ccsds.definitions.OrekitCcsdsFrameMapper;
53  import org.orekit.files.ccsds.ndm.ParserBuilder;
54  import org.orekit.files.ccsds.ndm.odm.CartesianCovariance;
55  import org.orekit.frames.FactoryManagedFrame;
56  import org.orekit.frames.Frame;
57  import org.orekit.frames.FramesFactory;
58  import org.orekit.frames.ITRFVersion;
59  import org.orekit.frames.LOFType;
60  import org.orekit.frames.Transform;
61  import org.orekit.orbits.CartesianOrbit;
62  import org.orekit.propagation.BoundedPropagator;
63  import org.orekit.time.AbsoluteDate;
64  import org.orekit.time.TimeScale;
65  import org.orekit.time.TimeScalesFactory;
66  import org.orekit.utils.CartesianDerivativesFilter;
67  import org.orekit.utils.IERSConventions;
68  import org.orekit.utils.PVCoordinates;
69  import org.orekit.utils.TimeStampedPVCoordinates;
70  
71  
72  public class OemParserTest {
73  
74      @BeforeEach
75      public void setUp()
76          throws Exception {
77          Utils.setDataRoot("regular-data");
78      }
79  
80      @Test
81      public void testIssue788() {
82  
83          // Read the file
84          final String ex = "/ccsds/odm/oem/test.oem";
85          final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
86          final OemParser parser  = new ParserBuilder().buildOemParser();
87          final Oem file = parser.parseMessage(source);
88  
89          // Verify
90          Assertions.assertEquals(file.getDataContext().getCelestialBodies().getEarth().getGM(), file.getSegments().get(0).getMu(), Double.MIN_VALUE);
91          Assertions.assertEquals(3.986004328969392E14, file.getSegments().get(0).getMu(), Double.MIN_VALUE);
92  
93      }
94  
95      @Test
96      public void testParseOEM1() throws IOException {
97          //
98          final String ex = "/ccsds/odm/oem/OEMExample1.txt";
99          final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
100         final OemParser parser  = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOemParser();
101         final Oem file = parser.parseMessage(source);
102         Assertions.assertEquals("public, test-data", file.getHeader().getClassification());
103         Assertions.assertEquals(3, file.getSegments().size());
104         Assertions.assertEquals("UTC", file.getSegments().get(0).getMetadata().getTimeSystem().name());
105         Assertions.assertEquals("MARS GLOBAL SURVEYOR", file.getSegments().get(0).getMetadata().getObjectName());
106         Assertions.assertEquals("1996-062A", file.getSegments().get(0).getMetadata().getObjectID());
107         Assertions.assertEquals("MARS BARYCENTER", file.getSegments().get(0).getMetadata().getCenter().getName());
108         Assertions.assertEquals(1996, file.getSegments().get(0).getMetadata().getLaunchYear());
109         Assertions.assertEquals(62, file.getSegments().get(0).getMetadata().getLaunchNumber());
110         Assertions.assertEquals("A", file.getSegments().get(0).getMetadata().getLaunchPiece());
111         Assertions.assertNull(file.getSegments().get(0).getMetadata().getCenter().getBody());
112         Assertions.assertNull(file.getSegments().get(0).getMetadata().getCenter().getBody());
113         Assertions.assertEquals(new AbsoluteDate(1996, 12, 18, 12, 00, 0.331, TimeScalesFactory.getUTC()),
114                             file.getSegments().get(0).getMetadata().getStartTime());
115         Assertions.assertEquals(new AbsoluteDate(1996, 12, 28, 21, 28, 0.331, TimeScalesFactory.getUTC()),
116                             file.getSegments().get(0).getMetadata().getStopTime());
117         Assertions.assertEquals(new AbsoluteDate(1996, 12, 18, 12, 10, 0.331, TimeScalesFactory.getUTC()),
118                             file.getSegments().get(0).getMetadata().getUseableStartTime());
119         Assertions.assertEquals(new AbsoluteDate(1996, 12, 28, 21, 23, 0.331, TimeScalesFactory.getUTC()),
120                             file.getSegments().get(0).getMetadata().getUseableStopTime());
121         Assertions.assertEquals(InterpolationMethod.HERMITE, file.getSegments().get(0).getMetadata().getInterpolationMethod());
122         Assertions.assertEquals(7, file.getSegments().get(0).getMetadata().getInterpolationDegree());
123         ArrayList<String> ephemeridesDataLinesComment = new ArrayList<String>();
124         ephemeridesDataLinesComment.add("This file was produced by M.R. Somebody, MSOO NAV/JPL, 1996NOV 04. It is");
125         ephemeridesDataLinesComment.add("to be used for DSN scheduling purposes only.");
126         Assertions.assertEquals(ephemeridesDataLinesComment, file.getSegments().get(0).getData().getComments());
127         CartesianOrbit orbit = new CartesianOrbit(new PVCoordinates
128                                                   (new Vector3D(2789.619 * 1000, -280.045 * 1000, -1746.755 * 1000),
129                                                    new Vector3D(4.73372 * 1000, -2.49586 * 1000, -1.04195 * 1000)),
130                                                    FramesFactory.getEME2000(),
131                                                    new AbsoluteDate("1996-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
132                                                    CelestialBodyFactory.getEarth().getGM());
133         Assertions.assertArrayEquals(orbit.getPosition().toArray(),
134                                      file.getSegments().get(0).getData().getEphemeridesDataLines().get(0).getPosition().toArray(), 1e-10);
135         Assertions.assertArrayEquals(orbit.getVelocity().toArray(), file.getSegments().get(0).getData().getEphemeridesDataLines().get(0).getVelocity().toArray(), 1e-10);
136         Assertions.assertEquals(Vector3D.ZERO, file.getSegments().get(1).getData().getEphemeridesDataLines().get(1).getAcceleration());
137         final Array2DRowRealMatrix covMatrix = new Array2DRowRealMatrix(6, 6);
138         final double[] column1 = {
139              3.3313494e-04,  4.6189273e-04, -3.0700078e-04, -3.3493650e-07, -2.2118325e-07, -3.0413460e-07
140         };
141         final double[] column2 = {
142              4.6189273e-04,  6.7824216e-04, -4.2212341e-04, -4.6860842e-07, -2.8641868e-07, -4.9894969e-07
143         };
144         final double[] column3 = {
145             -3.0700078e-04, -4.2212341e-04, 3.2319319e-04,  2.4849495e-07, 1.7980986e-07,  3.5403109e-07
146         };
147         final double[] column4 = {
148             -3.3493650e-07, -4.6860842e-07, 2.4849495e-07,  4.29602280e-10, 2.6088992e-10,  1.86926319e-10
149         };
150         final double[] column5 = {
151             -2.2118325e-07, -2.8641868e-07, 1.7980986e-07,  2.6088992e-10, 1.7675147e-10,  1.0088625e-10
152         };
153         final double[] column6 = {
154             -3.0413460e-07, -4.9894969e-07, 3.5403109e-07,  1.8692631e-10, 1.0088625e-10,  6.2244443e-10
155         };
156         covMatrix.setColumn(0, column1);
157         covMatrix.setColumn(1, column2);
158         covMatrix.setColumn(2, column3);
159         covMatrix.setColumn(3, column4);
160         covMatrix.setColumn(4, column5);
161         covMatrix.setColumn(5, column6);
162         for (int i = 0; i < 6; i++) {
163             for (int j = 0; j < 6; j++) {
164                 Assertions.assertEquals(covMatrix.getEntry(i, j) * 1.0e6,
165                                     file.getSegments().get(2).getData().getCovarianceMatrices().get(0).getCovarianceMatrix().getEntry(i, j),
166                                     1e-10);
167             }
168         }
169         Assertions.assertEquals(new AbsoluteDate("1996-12-28T21:29:07.267", TimeScalesFactory.getUTC()),
170                             file.getSegments().get(2).getCovarianceMatrices().get(0).getEpoch());
171         Assertions.assertEquals(LOFType.QSW_INERTIAL,
172                             file.getSegments().get(2).getCovarianceMatrices().get(0).getReferenceFrame().asOrbitRelativeFrame().getLofType());
173         Assertions.assertNull(file.getSegments().get(2).getCovarianceMatrices().get(0).getReferenceFrame().asFrame());
174         Assertions.assertNull(file.getSegments().get(2).getCovarianceMatrices().get(0).getReferenceFrame().asCelestialBodyFrame());
175         Assertions.assertNull(file.getSegments().get(2).getCovarianceMatrices().get(0).getReferenceFrame().asSpacecraftBodyFrame());
176         Assertions.assertNull(file.getSegments().get(2).getCovarianceMatrices().get(1).getReferenceFrame().asOrbitRelativeFrame());
177         Assertions.assertEquals(FramesFactory.getEME2000(),
178                             file.getSegments().get(2).getCovarianceMatrices().get(1).getReferenceFrame().asFrame());
179     }
180 
181     @Test
182     public void testParseOEM2() throws URISyntaxException {
183 
184         final String ex = "/ccsds/odm/oem/OEMExample2.txt";
185         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
186         final AbsoluteDate missionReferenceDate = new AbsoluteDate("1996-12-17T00:00:00.000", TimeScalesFactory.getUTC());
187         OemParser parser = new ParserBuilder().
188                            withConventions(IERSConventions.IERS_2010).
189                            withSimpleEOP(true).
190                            withDataContext(DataContext.getDefault()).
191                            withMissionReferenceDate(missionReferenceDate).
192                            withMu(CelestialBodyFactory.getMars().getGM()).
193                            withDefaultInterpolationDegree(1).
194                            buildOemParser();
195 
196         final Oem file = parser.parseMessage(source);
197         final List<String> headerComment = new ArrayList<String>();
198         headerComment.add("comment");
199         Assertions.assertEquals(headerComment, file.getHeader().getComments());
200         final List<String> metadataComment = new ArrayList<String>();
201         metadataComment.add("comment 1");
202         metadataComment.add("comment 2");
203         Assertions.assertEquals(metadataComment, file.getSegments().get(0).getMetadata().getComments());
204         Assertions.assertEquals("TOD/2010 simple EOP",
205                             file.getSegments().get(0).getMetadata().getReferenceFrame().asFrame().getName());
206         Assertions.assertEquals("TOD",
207                             file.getSegments().get(0).getMetadata().getReferenceFrame().getName());
208         Assertions.assertEquals("EME2000", file.getSegments().get(1).getMetadata().getReferenceFrame().getName());
209         List<OemSegment> blocks = file.getSegments();
210         Assertions.assertEquals(2, blocks.size());
211         Assertions.assertEquals(129600.331,
212                             blocks.get(0).getMetadata().getFrameEpoch().durationFrom(missionReferenceDate),
213                             1.0e-15);
214         Assertions.assertEquals(129600.331,
215                             blocks.get(0).getMetadata().getStartTime().durationFrom(missionReferenceDate),
216                             1.0e-15);
217         Assertions.assertEquals(941347.267,
218                             blocks.get(1).getMetadata().getStartTime().durationFrom(missionReferenceDate),
219                             1.0e-15);
220 
221     }
222 
223     @Test
224     public void testParseOEM3KVN() throws IOException {
225 
226         final String ex = "/ccsds/odm/oem/OEMExample3.txt";
227         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
228         final OemParser parser  = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOemParser();
229         final Oem file = parser.parse(source); // using the generic API here
230         Assertions.assertEquals("Copy of OEMExample.txt with changes so that interpolation will work.",
231                             file.getHeader().getComments().get(0));
232         Assertions.assertEquals(new AbsoluteDate("1996-11-04T17:22:31", TimeScalesFactory.getUTC()),
233                             file.getHeader().getCreationDate());
234         Assertions.assertEquals("NASA/JPL", file.getHeader().getOriginator());
235         Assertions.assertEquals("OEM 201113719185", file.getHeader().getMessageId());
236         Assertions.assertEquals("UTC", file.getSegments().get(0).getMetadata().getTimeSystem().name());
237         Assertions.assertEquals("MARS GLOBAL SURVEYOR", file.getSegments().get(0).getMetadata().getObjectName());
238         Assertions.assertEquals("1996-062A", file.getSegments().get(0).getMetadata().getObjectID());
239 
240         Assertions.assertEquals(1, file.getSatellites().size());
241         Assertions.assertTrue(file.getSatellites().containsKey("1996-062A"));
242         Assertions.assertFalse(file.getSatellites().containsKey("MARS GLOBAL SURVEYOR"));
243         Assertions.assertEquals(1, file.getSatellites().size());
244         Assertions.assertEquals("1996-062A", file.getSatellites().values().iterator().next().getId());
245         Assertions.assertEquals(
246                 new AbsoluteDate("1996-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
247                 file.getSegments().get(0).getMetadata().getStartTime());
248 
249         final OemSatelliteEphemeris satellite = file.getSatellites().get("1996-062A");
250         Assertions.assertEquals("1996-062A", satellite.getId());
251         final OemSegment segment = (OemSegment) satellite.getSegments().get(0);
252         Assertions.assertEquals(CelestialBodyFactory.getMars().getGM(), segment.getMu(), 1.0);
253         Assertions.assertEquals("EME2000", segment.getMetadata().getReferenceFrame().getName());
254         Assertions.assertEquals(segment.getMetadata().getCenter().getName(), "MARS BARYCENTER");
255         Assertions.assertNull(segment.getMetadata().getCenter().getBody());
256         // Frame not creatable since it's center can't be created.
257         try {
258             segment.getFrame();
259             Assertions.fail("Expected Exception");
260         } catch (OrekitException e){
261             Assertions.assertEquals(e.getSpecifier(), OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY);
262         }
263         Assertions.assertEquals("UTC", segment.getMetadata().getTimeSystem().name());
264         Assertions.assertEquals(InterpolationMethod.HERMITE, segment.getMetadata().getInterpolationMethod());
265         Assertions.assertEquals(2, segment.getMetadata().getInterpolationDegree());
266         Assertions.assertEquals(3, segment.getInterpolationSamples());
267         Assertions.assertEquals(segment.getAvailableDerivatives(), CartesianDerivativesFilter.USE_PV);
268 
269         List<OemSegment> segments = file.getSegments();
270         Assertions.assertEquals(3, segments.size());
271         Assertions.assertEquals(3, segments.get(2).getData().getCoordinates().size());
272         final TimeStampedPVCoordinates pv20 = segments.get(2).getData().getCoordinates().get(0);
273         Assertions.assertEquals(
274                             new AbsoluteDate("1996-12-28T21:29:07.267", TimeScalesFactory.getUTC()),
275                             pv20.getDate());
276         Assertions.assertEquals(-2432166.0,   pv20.getPosition().getX(), 1.0e-10);
277         Assertions.assertEquals(  -63042.0,   pv20.getPosition().getY(), 1.0e-10);
278         Assertions.assertEquals( 1742754.0,   pv20.getPosition().getZ(), 1.0e-10);
279         Assertions.assertEquals(    7337.02,  pv20.getVelocity().getX(), 1.0e-10);
280         Assertions.assertEquals(   -3495.867, pv20.getVelocity().getY(), 1.0e-10);
281         Assertions.assertEquals(   -1041.945, pv20.getVelocity().getZ(), 1.0e-10);
282         final TimeStampedPVCoordinates pv21 = segments.get(2).getData().getCoordinates().get(1);
283         Assertions.assertEquals(new AbsoluteDate("1996-12-28T21:59:02.267", TimeScalesFactory.getUTC()),
284                             pv21.getDate());
285         Assertions.assertEquals(-2445234.0,   pv21.getPosition().getX(), 1.0e-10);
286         Assertions.assertEquals( -878141.0,   pv21.getPosition().getY(), 1.0e-10);
287         Assertions.assertEquals( 1873073.0,   pv21.getPosition().getZ(), 1.0e-10);
288         Assertions.assertEquals(    1860.43,  pv21.getVelocity().getX(), 1.0e-10);
289         Assertions.assertEquals(   -3421.256, pv21.getVelocity().getY(), 1.0e-10);
290         Assertions.assertEquals(    -996.366, pv21.getVelocity().getZ(), 1.0e-10);
291         final TimeStampedPVCoordinates pv22 = segments.get(2).getData().getCoordinates().get(2);
292         Assertions.assertEquals(new AbsoluteDate("1996-12-28T22:00:02.267", TimeScalesFactory.getUTC()),
293                             pv22.getDate());
294         Assertions.assertEquals(-2458079.0,   pv22.getPosition().getX(), 1.0e-10);
295         Assertions.assertEquals( -683858.0,   pv22.getPosition().getY(), 1.0e-10);
296         Assertions.assertEquals( 2007684.0,   pv22.getPosition().getZ(), 1.0e-10);
297         Assertions.assertEquals(    6367.86,  pv22.getVelocity().getX(), 1.0e-10);
298         Assertions.assertEquals(   -3339.563, pv22.getVelocity().getY(), 1.0e-10);
299         Assertions.assertEquals(    -946.654, pv22.getVelocity().getZ(), 1.0e-10);
300 
301         Assertions.assertEquals(2, segments.get(2).getCovarianceMatrices().size());
302         final CartesianCovariance c20 = segments.get(2).getCovarianceMatrices().get(0);
303         Assertions.assertEquals(new AbsoluteDate("1996-12-28T21:29:07.267", TimeScalesFactory.getUTC()),
304                             c20.getEpoch());
305         Assertions.assertEquals(OrbitRelativeFrame.RTN, c20.getReferenceFrame().asOrbitRelativeFrame());
306         Assertions.assertEquals( 333.13494,       c20.getCovarianceMatrix().getEntry(0, 0), 1.0e-5);
307         Assertions.assertEquals( 461.89273,       c20.getCovarianceMatrix().getEntry(1, 0), 1.0e-5);
308         Assertions.assertEquals( 678.24216,       c20.getCovarianceMatrix().getEntry(1, 1), 1.0e-5);
309         Assertions.assertEquals(-307.00078,       c20.getCovarianceMatrix().getEntry(2, 0), 1.0e-5);
310         Assertions.assertEquals(-422.12341,       c20.getCovarianceMatrix().getEntry(2, 1), 1.0e-5);
311         Assertions.assertEquals( 323.19319,       c20.getCovarianceMatrix().getEntry(2, 2), 1.0e-5);
312         Assertions.assertEquals(  -0.33493650,    c20.getCovarianceMatrix().getEntry(3, 0), 1.0e-8);
313         Assertions.assertEquals(  -0.46860842,    c20.getCovarianceMatrix().getEntry(3, 1), 1.0e-8);
314         Assertions.assertEquals(   0.24849495,    c20.getCovarianceMatrix().getEntry(3, 2), 1.0e-8);
315         Assertions.assertEquals(   0.00042960228, c20.getCovarianceMatrix().getEntry(3, 3), 1.0e-11);
316         Assertions.assertEquals(  -0.22118325,    c20.getCovarianceMatrix().getEntry(4, 0), 1.0e-8);
317         Assertions.assertEquals(  -0.28641868,    c20.getCovarianceMatrix().getEntry(4, 1), 1.0e-8);
318         Assertions.assertEquals(   0.17980986,    c20.getCovarianceMatrix().getEntry(4, 2), 1.0e-8);
319         Assertions.assertEquals(   0.00026088992, c20.getCovarianceMatrix().getEntry(4, 3), 1.0e-11);
320         Assertions.assertEquals(   0.00017675147, c20.getCovarianceMatrix().getEntry(4, 4), 1.0e-11);
321         Assertions.assertEquals(  -0.30413460,    c20.getCovarianceMatrix().getEntry(5, 0), 1.0e-8);
322         Assertions.assertEquals(  -0.49894969,    c20.getCovarianceMatrix().getEntry(5, 1), 1.0e-8);
323         Assertions.assertEquals(   0.35403109,    c20.getCovarianceMatrix().getEntry(5, 2), 1.0e-8);
324         Assertions.assertEquals(   0.00018692631, c20.getCovarianceMatrix().getEntry(5, 3), 1.0e-11);
325         Assertions.assertEquals(   0.00010088625, c20.getCovarianceMatrix().getEntry(5, 4), 1.0e-11);
326         Assertions.assertEquals(   0.00062244443, c20.getCovarianceMatrix().getEntry(5, 5), 1.0e-11);
327         for (int i = 0; i < c20.getCovarianceMatrix().getRowDimension(); ++i) {
328             for (int j = i + 1; j < c20.getCovarianceMatrix().getColumnDimension(); ++j) {
329                 Assertions.assertEquals(c20.getCovarianceMatrix().getEntry(j, i),
330                                     c20.getCovarianceMatrix().getEntry(i, j),
331                                     1.0e-10);
332             }
333         }
334 
335         final CartesianCovariance c21 = segments.get(2).getCovarianceMatrices().get(1);
336         Assertions.assertEquals(new AbsoluteDate("1996-12-29T21:00:00", TimeScalesFactory.getUTC()),
337                             c21.getEpoch());
338         Assertions.assertEquals(CelestialBodyFrame.EME2000, c21.getReferenceFrame().asCelestialBodyFrame());
339         Assertions.assertEquals( 344.24505,       c21.getCovarianceMatrix().getEntry(0, 0), 1.0e-5);
340         Assertions.assertEquals( 450.78162,       c21.getCovarianceMatrix().getEntry(1, 0), 1.0e-5);
341         Assertions.assertEquals( 689.35327,       c21.getCovarianceMatrix().getEntry(1, 1), 1.0e-5);
342         for (int i = 0; i < c21.getCovarianceMatrix().getRowDimension(); ++i) {
343             for (int j = i + 1; j < c21.getCovarianceMatrix().getColumnDimension(); ++j) {
344                 Assertions.assertEquals(c21.getCovarianceMatrix().getEntry(j, i),
345                                     c21.getCovarianceMatrix().getEntry(i, j),
346                                     1.0e-10);
347             }
348         }
349 
350     }
351 
352     @Test
353     public void testParseOEM3XML() throws IOException {
354 
355         final String ex = "/ccsds/odm/oem/OEMExample3.xml";
356         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
357         final OemParser parser  = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOemParser();
358         final Oem file = parser.parseMessage(source);
359         Assertions.assertEquals("OEM 201113719185", file.getHeader().getMessageId());
360         Assertions.assertEquals("UTC", file.getSegments().get(0).getMetadata().getTimeSystem().name());
361         Assertions.assertEquals("MARS GLOBAL SURVEYOR", file.getSegments().get(0).getMetadata().getObjectName());
362         Assertions.assertEquals("2000-028A", file.getSegments().get(0).getMetadata().getObjectID());
363 
364         Assertions.assertEquals(1, file.getSatellites().size());
365         Assertions.assertTrue(file.getSatellites().containsKey("2000-028A"));
366         Assertions.assertFalse(file.getSatellites().containsKey("MARS GLOBAL SURVEYOR"));
367         Assertions.assertEquals(1, file.getSatellites().size());
368         Assertions.assertEquals("2000-028A", file.getSatellites().values().iterator().next().getId());
369         Assertions.assertEquals(
370                 new AbsoluteDate("1996-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
371                 file.getSegments().get(0).getMetadata().getStartTime());
372 
373         final OemSatelliteEphemeris satellite = file.getSatellites().get("2000-028A");
374         Assertions.assertEquals("2000-028A", satellite.getId());
375         final OemSegment segment = (OemSegment) satellite.getSegments().get(0);
376         Assertions.assertEquals(CelestialBodyFactory.getMars().getGM(), segment.getMu(), 1.0);
377         Assertions.assertEquals("J2000", segment.getMetadata().getReferenceFrame().getName());
378         Assertions.assertEquals(segment.getMetadata().getCenter().getName(), "MARS BARYCENTER");
379         Assertions.assertNull(segment.getMetadata().getCenter().getBody());
380         // Frame not creatable since it's center can't be created.
381         try {
382             segment.getFrame();
383             Assertions.fail("Expected Exception");
384         } catch (OrekitException e){
385             Assertions.assertEquals(e.getSpecifier(), OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY);
386         }
387         Assertions.assertEquals("UTC", segment.getMetadata().getTimeSystem().name());
388         Assertions.assertEquals(InterpolationMethod.HERMITE, segment.getMetadata().getInterpolationMethod());
389         Assertions.assertEquals(7, segment.getMetadata().getInterpolationDegree());
390         Assertions.assertEquals(segment.getAvailableDerivatives(), CartesianDerivativesFilter.USE_PVA);
391 
392         List<OemSegment> segments = file.getSegments();
393         Assertions.assertEquals(1, segments.size());
394         Assertions.assertEquals("Produced by M.R. Sombedody, MSOO NAV/JPL, 1996 OCT 11. It is", segments.get(0).getData().getComments().get(0));
395         Assertions.assertEquals("to be used for DSN scheduling purposes only.", segments.get(0).getData().getComments().get(1));
396         Assertions.assertEquals(4, segments.get(0).getData().getCoordinates().size());
397         final TimeStampedPVCoordinates pv00 = segments.get(0).getData().getCoordinates().get(0);
398         Assertions.assertEquals(new AbsoluteDate("1996-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
399                             pv00.getDate());
400         Assertions.assertEquals( 2789600.0, pv00.getPosition().getX(),     1.0e-10);
401         Assertions.assertEquals( -280000.0, pv00.getPosition().getY(),     1.0e-10);
402         Assertions.assertEquals(-1746800.0, pv00.getPosition().getZ(),     1.0e-10);
403         Assertions.assertEquals(    4730.0, pv00.getVelocity().getX(),     1.0e-10);
404         Assertions.assertEquals(   -2500.0, pv00.getVelocity().getY(),     1.0e-10);
405         Assertions.assertEquals(   -1040.0, pv00.getVelocity().getZ(),     1.0e-10);
406         Assertions.assertEquals(       8.0, pv00.getAcceleration().getX(), 1.0e-10);
407         Assertions.assertEquals(       1.0, pv00.getAcceleration().getY(), 1.0e-10);
408         Assertions.assertEquals(    -159.0, pv00.getAcceleration().getZ(), 1.0e-10);
409         final TimeStampedPVCoordinates pv01 = segments.get(0).getData().getCoordinates().get(1);
410         Assertions.assertEquals(new AbsoluteDate("1996-12-18T12:01:00.331", TimeScalesFactory.getUTC()),
411                             pv01.getDate());
412         Assertions.assertEquals( 2783400.0, pv01.getPosition().getX(),     1.0e-10);
413         Assertions.assertEquals( -308100.0, pv01.getPosition().getY(),     1.0e-10);
414         Assertions.assertEquals(-1877100.0, pv01.getPosition().getZ(),     1.0e-10);
415         Assertions.assertEquals(    5190.0, pv01.getVelocity().getX(),     1.0e-10);
416         Assertions.assertEquals(   -2420.0, pv01.getVelocity().getY(),     1.0e-10);
417         Assertions.assertEquals(   -2000.0, pv01.getVelocity().getZ(),     1.0e-10);
418         Assertions.assertEquals(       8.0, pv01.getAcceleration().getX(), 1.0e-10);
419         Assertions.assertEquals(       1.0, pv01.getAcceleration().getY(), 1.0e-10);
420         Assertions.assertEquals(       1.0, pv01.getAcceleration().getZ(), 1.0e-10);
421         final TimeStampedPVCoordinates pv02 = segments.get(0).getData().getCoordinates().get(2);
422         Assertions.assertEquals(new AbsoluteDate("1996-12-18T12:02:00.331", TimeScalesFactory.getUTC()),
423                             pv02.getDate());
424         Assertions.assertEquals( 2776000.0, pv02.getPosition().getX(),     1.0e-10);
425         Assertions.assertEquals( -336900.0, pv02.getPosition().getY(),     1.0e-10);
426         Assertions.assertEquals(-2008700.0, pv02.getPosition().getZ(),     1.0e-10);
427         Assertions.assertEquals(    5640.0, pv02.getVelocity().getX(),     1.0e-10);
428         Assertions.assertEquals(   -2340.0, pv02.getVelocity().getY(),     1.0e-10);
429         Assertions.assertEquals(   -1950.0, pv02.getVelocity().getZ(),     1.0e-10);
430         Assertions.assertEquals(       8.0, pv02.getAcceleration().getX(), 1.0e-10);
431         Assertions.assertEquals(       1.0, pv02.getAcceleration().getY(), 1.0e-10);
432         Assertions.assertEquals(     159.0, pv02.getAcceleration().getZ(), 1.0e-10);
433         final TimeStampedPVCoordinates pv03 = segments.get(0).getData().getCoordinates().get(3);
434         Assertions.assertEquals(new AbsoluteDate("1996-12-28T21:28:00.331", TimeScalesFactory.getUTC()),
435                             pv03.getDate());
436         Assertions.assertEquals(-3881000.0, pv03.getPosition().getX(),     1.0e-10);
437         Assertions.assertEquals(  564000.0, pv03.getPosition().getY(),     1.0e-10);
438         Assertions.assertEquals( -682800.0, pv03.getPosition().getZ(),     1.0e-10);
439         Assertions.assertEquals(   -3290.0, pv03.getVelocity().getX(),     1.0e-10);
440         Assertions.assertEquals(   -3670.0, pv03.getVelocity().getY(),     1.0e-10);
441         Assertions.assertEquals(    1640.0, pv03.getVelocity().getZ(),     1.0e-10);
442         Assertions.assertEquals(      -3.0, pv03.getAcceleration().getX(), 1.0e-10);
443         Assertions.assertEquals(       0.0, pv03.getAcceleration().getY(), 1.0e-10);
444         Assertions.assertEquals(       0.0, pv03.getAcceleration().getZ(), 1.0e-10);
445 
446         Assertions.assertEquals(1, segments.get(0).getCovarianceMatrices().size());
447         final CartesianCovariance c20 = segments.get(0).getCovarianceMatrices().get(0);
448         Assertions.assertEquals(new AbsoluteDate("1996-12-28T22:28:00.331", TimeScalesFactory.getUTC()),
449                             c20.getEpoch());
450         Assertions.assertEquals(CelestialBodyFrame.ITRF1997, c20.getReferenceFrame().asCelestialBodyFrame());
451         Assertions.assertEquals( 316000.0, c20.getCovarianceMatrix().getEntry(0, 0), 1.0e-10);
452         Assertions.assertEquals( 722000.0, c20.getCovarianceMatrix().getEntry(1, 0), 1.0e-10);
453         Assertions.assertEquals( 518000.0, c20.getCovarianceMatrix().getEntry(1, 1), 1.0e-10);
454         Assertions.assertEquals( 202000.0, c20.getCovarianceMatrix().getEntry(2, 0), 1.0e-10);
455         Assertions.assertEquals( 715000.0, c20.getCovarianceMatrix().getEntry(2, 1), 1.0e-10);
456         Assertions.assertEquals(   2000.0, c20.getCovarianceMatrix().getEntry(2, 2), 1.0e-10);
457         Assertions.assertEquals( 912000.0, c20.getCovarianceMatrix().getEntry(3, 0), 1.0e-10);
458         Assertions.assertEquals( 306000.0, c20.getCovarianceMatrix().getEntry(3, 1), 1.0e-10);
459         Assertions.assertEquals( 276000.0, c20.getCovarianceMatrix().getEntry(3, 2), 1.0e-10);
460         Assertions.assertEquals( 797000.0, c20.getCovarianceMatrix().getEntry(3, 3), 1.0e-10);
461         Assertions.assertEquals( 562000.0, c20.getCovarianceMatrix().getEntry(4, 0), 1.0e-10);
462         Assertions.assertEquals( 899000.0, c20.getCovarianceMatrix().getEntry(4, 1), 1.0e-10);
463         Assertions.assertEquals(  22000.0, c20.getCovarianceMatrix().getEntry(4, 2), 1.0e-10);
464         Assertions.assertEquals(  79000.0, c20.getCovarianceMatrix().getEntry(4, 3), 1.0e-10);
465         Assertions.assertEquals( 415000.0, c20.getCovarianceMatrix().getEntry(4, 4), 1.0e-10);
466         Assertions.assertEquals( 245000.0, c20.getCovarianceMatrix().getEntry(5, 0), 1.0e-10);
467         Assertions.assertEquals( 965000.0, c20.getCovarianceMatrix().getEntry(5, 1), 1.0e-10);
468         Assertions.assertEquals( 950000.0, c20.getCovarianceMatrix().getEntry(5, 2), 1.0e-10);
469         Assertions.assertEquals( 435000.0, c20.getCovarianceMatrix().getEntry(5, 3), 1.0e-10);
470         Assertions.assertEquals( 621000.0, c20.getCovarianceMatrix().getEntry(5, 4), 1.0e-10);
471         Assertions.assertEquals( 991000.0, c20.getCovarianceMatrix().getEntry(5, 5), 1.0e-10);
472         for (int i = 0; i < c20.getCovarianceMatrix().getRowDimension(); ++i) {
473             for (int j = i + 1; j < c20.getCovarianceMatrix().getColumnDimension(); ++j) {
474                 Assertions.assertEquals(c20.getCovarianceMatrix().getEntry(j, i),
475                                     c20.getCovarianceMatrix().getEntry(i, j),
476                                     1.0e-10);
477             }
478         }
479 
480     }
481 
482     @Test
483     public void testParseOemMissingOptionalData() throws IOException {
484 
485         final String ex = "/ccsds/odm/oem/OEMExample6.txt";
486         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
487         final OemParser parser  = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM()).buildOemParser();
488         final Oem file = parser.parseMessage(source);
489         Assertions.assertEquals("UTC", file.getSegments().get(0).getMetadata().getTimeSystem().name());
490         Assertions.assertEquals("MARS GLOBAL SURVEYOR", file.getSegments().get(0).getMetadata().getObjectName());
491         Assertions.assertEquals("1996-062A", file.getSegments().get(0).getMetadata().getObjectID());
492 
493         Assertions.assertEquals(1, file.getSatellites().size());
494         Assertions.assertTrue(file.getSatellites().containsKey("1996-062A"));
495         Assertions.assertFalse(file.getSatellites().containsKey("MARS GLOBAL SURVEYOR"));
496         Assertions.assertEquals(1, file.getSatellites().size());
497         Assertions.assertEquals("1996-062A", file.getSatellites().values().iterator().next().getId());
498         Assertions.assertEquals(
499                 new AbsoluteDate("2002-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
500                 file.getSegments().get(0).getMetadata().getStartTime());
501 
502         OemSatelliteEphemeris satellite = file.getSatellites().get("1996-062A");
503         Assertions.assertEquals("1996-062A", satellite.getId());
504         OemSegment segment = satellite.getSegments().get(0);
505         Assertions.assertEquals(CelestialBodyFactory.getMars().getGM(), segment.getMu(), 1.0);
506         FactoryManagedFrame eme2000 = FramesFactory.getEME2000();
507         Frame actualFrame = segment.getFrame();
508         AbsoluteDate actualStart = satellite.getStart();
509         Transform actualTransform = eme2000.getTransformTo(actualFrame, actualStart);
510         CelestialBody mars = CelestialBodyFactory.getMars();
511         TimeStampedPVCoordinates marsPV = mars.getPVCoordinates(actualStart, eme2000);
512         TimeStampedPVCoordinates marsPV_in_marscentered_frame = mars.getPVCoordinates(actualStart, actualFrame);
513         MatcherAssert.assertThat(marsPV_in_marscentered_frame,
514                                  OrekitMatchers.pvCloseTo(PVCoordinates.ZERO, 1e-3));
515         Assertions.assertEquals(actualTransform.getTranslation(), marsPV.getPosition().negate());
516         Assertions.assertEquals(actualTransform.getVelocity(), marsPV.getVelocity().negate());
517         Assertions.assertEquals(actualTransform.getAcceleration(), marsPV.getAcceleration().negate());
518         Assertions.assertEquals(
519                 Rotation.distance(actualTransform.getRotation(), Rotation.IDENTITY),
520                 0.0, 0.0);
521         Assertions.assertEquals(actualTransform.getRotationRate(), Vector3D.ZERO);
522         Assertions.assertEquals(actualTransform.getRotationAcceleration(), Vector3D.ZERO);
523         Assertions.assertEquals("Mars/EME2000", actualFrame.getName());
524         Assertions.assertEquals(CelestialBodyFrame.EME2000, segment.getMetadata().getReferenceFrame().asCelestialBodyFrame());
525         Assertions.assertEquals("UTC", segment.getMetadata().getTimeSystem().name());
526         Assertions.assertEquals(segment.getAvailableDerivatives(),
527                 CartesianDerivativesFilter.USE_PV);
528         Assertions.assertEquals(satellite.getSegments().get(0).getMetadata().getStartTime(), actualStart);
529         Assertions.assertEquals(satellite.getSegments().get(2).getMetadata().getStopTime(), satellite.getStop());
530 
531         final BoundedPropagator propagator = satellite.getPropagator();
532         Assertions.assertEquals(propagator.getMinDate(), satellite.getStart());
533         Assertions.assertEquals(propagator.getMinDate(), satellite.getSegments().get(0).getStart());
534         Assertions.assertEquals(propagator.getMaxDate(), satellite.getStop());
535         Assertions.assertEquals(propagator.getMaxDate(), satellite.getSegments().get(2).getStop());
536 
537         final List<TimeStampedPVCoordinates> dataLines = new ArrayList<>();
538         for (OemSegment block : file.getSegments()) {
539             for (TimeStampedPVCoordinates dataLine : block.getData().getEphemeridesDataLines()) {
540                 if (dataLine.getDate().compareTo(satellite.getStart()) >= 0) {
541                     dataLines.add(dataLine);
542                 }
543             }
544         }
545 
546         final int ulps = 12;
547         for (TimeStampedPVCoordinates coord : dataLines) {
548             MatcherAssert.assertThat(propagator.getPVCoordinates(coord.getDate(), actualFrame),
549                                      OrekitMatchers.pvCloseTo(coord, ulps));
550             MatcherAssert.assertThat(propagator.propagate(coord.getDate()).getPVCoordinates(),
551                                      OrekitMatchers.pvCloseTo(coord, ulps));
552         }
553 
554     }
555 
556     @Test
557     public void testWrongODMType() {
558         try {
559             final String ex = "/ccsds/odm/oem/OEMExample1.txt";
560             final DataSource source =  new DataSource(ex, () -> getClass().getResourceAsStream(ex));
561             new ParserBuilder().
562             withMu(CelestialBodyFactory.getMars().getGM()).
563             buildOemParser().
564             parseMessage(source);
565         } catch (OrekitException oe) {
566             Assertions.assertEquals(OrekitMessages.UNSUPPORTED_FILE_FORMAT, oe.getSpecifier());
567             Assertions.assertEquals("OPMExample1.txt", oe.getParts()[0]);
568         }
569     }
570 
571     @Test
572     public void testEphemerisNumberFormatErrorType() {
573         final String ex = "/ccsds/odm/oem/OEM-ephemeris-number-format-error.txt";
574         try {
575             final DataSource source =  new DataSource(ex, () -> getClass().getResourceAsStream(ex));
576             new ParserBuilder().
577             withMu(CelestialBodyFactory.getMars().getGM()).
578             buildOemParser().
579             parseMessage(source);
580         } catch (OrekitException oe) {
581             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
582             Assertions.assertEquals(44, oe.getParts()[0]);
583             Assertions.assertEquals(ex, oe.getParts()[1]);
584             Assertions.assertEquals("1996-12-28T21:59:02.267 -2445.234 -878.141 this-is-not-a-number 1.86043 -3.421256 -0.996366", oe.getParts()[2]);
585         }
586     }
587 
588     @Test
589     public void testCovarianceNumberFormatErrorType() {
590         final String ex = "/ccsds/odm/oem/OEM-covariance-number-format-error.txt";
591         try {
592             final DataSource source =  new DataSource(ex, () -> getClass().getResourceAsStream(ex));
593             new ParserBuilder().
594             withMu(CelestialBodyFactory.getMars().getGM()).
595             buildOemParser().
596             parseMessage(source);
597         } catch (OrekitException oe) {
598             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
599             Assertions.assertEquals(52, oe.getParts()[0]);
600             Assertions.assertEquals(ex, oe.getParts()[1]);
601             Assertions.assertEquals("4.6189273e-04 this-is-not-a-number", oe.getParts()[2]);
602         }
603     }
604 
605     @Test
606     public void testNonExistentFile() throws URISyntaxException {
607         final String realName = getClass().getResource("/ccsds/odm/oem/OEMExample1.txt").toURI().getPath();
608         final String wrongName = realName + "xxxxx";
609         final DataSource source =  new DataSource(wrongName, () -> getClass().getResourceAsStream(wrongName));
610         try {
611             new ParserBuilder().
612             withMu(CelestialBodyFactory.getMars().getGM()).
613             buildOemParser().
614             parseMessage(source);
615             Assertions.fail("an exception should have been thrown");
616         } catch (OrekitException oe) {
617             Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier());
618             Assertions.assertEquals(wrongName, oe.getParts()[0]);
619         }
620     }
621 
622     @Test
623     public void testInconsistentTimeSystems() {
624         try {
625             final String ex = "/ccsds/odm/oem/OEM-inconsistent-time-systems.txt";
626             final DataSource source =  new DataSource(ex, () -> getClass().getResourceAsStream(ex));
627             new ParserBuilder().
628             withMu(CelestialBodyFactory.getMars().getGM()).
629             buildOemParser().
630             parseMessage(source);
631         } catch (OrekitException oe) {
632             Assertions.assertEquals(OrekitMessages.CCSDS_INCONSISTENT_TIME_SYSTEMS, oe.getSpecifier());
633             Assertions.assertEquals("UTC", oe.getParts()[0]);
634             Assertions.assertEquals("TCG", oe.getParts()[1]);
635         }
636     }
637 
638     @Test
639     public void testLowerCaseValue() {
640         //setup
641         String file = "/ccsds/odm/oem/oemLowerCaseValue.oem";
642         final DataSource source =  new DataSource(file, () -> getClass().getResourceAsStream(file));
643 
644         //action
645         final Oem actual = new ParserBuilder().
646                                withMu(CelestialBodyFactory.getMars().getGM()).
647                                buildOemParser().
648                                parseMessage(source);
649 
650         //verify
651         Assertions.assertEquals(
652                 CelestialBodyFactory.getEarth(),
653                 actual.getSegments().get(0).getMetadata().getCenter().getBody());
654     }
655 
656     @Test
657     public void testWrongKeyword()
658         throws URISyntaxException {
659         // simple test for OMM file, contains p/v entries and other mandatory
660         // data.
661         final String name = "/ccsds/odm/oem/OEM-wrong-keyword.txt";
662         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
663         try {
664             new ParserBuilder().
665             withMu(CelestialBodyFactory.getMars().getGM()).
666             buildOemParser().
667             parseMessage(source);
668             Assertions.fail("an exception should have been thrown");
669         } catch (OrekitException oe) {
670             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
671             Assertions.assertEquals(19, ((Integer) oe.getParts()[0]).intValue());
672             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("WRONG_KEYWORD"));
673         }
674     }
675 
676     @Test
677     public void testKeywordWithinEphemeris()
678         throws URISyntaxException {
679         // simple test for OMM file, contains p/v entries and other mandatory
680         // data.
681         final String name = "/ccsds/odm/oem/OEM-keyword-within-ephemeris.txt";
682         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
683         try {
684             new ParserBuilder().
685             withMu(CelestialBodyFactory.getMars().getGM()).
686             buildOemParser().
687             parseMessage(source);
688             Assertions.fail("an exception should have been thrown");
689         } catch (OrekitException oe) {
690             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
691             Assertions.assertEquals(24, ((Integer) oe.getParts()[0]).intValue());
692             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("USER_DEFINED_TEST_KEY"));
693         }
694     }
695 
696     @Test
697     public void testKeywordWithinCovariance()
698         throws URISyntaxException {
699         // simple test for OMM file, contains p/v entries and other mandatory
700         // data.
701         final String name = "/ccsds/odm/oem/OEM-keyword-within-covariance.txt";
702         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
703         try {
704             new ParserBuilder().
705             withMu(CelestialBodyFactory.getMars().getGM()).
706             buildOemParser().
707             parseMessage(source);
708             Assertions.fail("an exception should have been thrown");
709         } catch (OrekitException oe) {
710             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
711             Assertions.assertEquals(91, ((Integer) oe.getParts()[0]).intValue());
712             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("USER_DEFINED_TEST_KEY"));
713         }
714     }
715 
716     @Test
717     public void testTooLargeCovarianceDimension()
718         throws URISyntaxException {
719         final String name = "/ccsds/odm/oem/OEM-too-large-covariance-dimension.txt";
720         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
721         try {
722             new ParserBuilder().
723             withMu(CelestialBodyFactory.getMars().getGM()).
724             buildOemParser().
725             parseMessage(source);
726             Assertions.fail("an exception should have been thrown");
727         } catch (OrekitException oe) {
728             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
729             Assertions.assertEquals(91, ((Integer) oe.getParts()[0]).intValue());
730             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("1.0e-12"));
731         }
732     }
733 
734     @Test
735     public void testTooSmallCovarianceDimension()
736         throws URISyntaxException {
737         final String name = "/ccsds/odm/oem/OEM-too-small-covariance-dimension.txt";
738         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
739         try {
740             new ParserBuilder().
741             withMu(CelestialBodyFactory.getMars().getGM()).
742             buildOemParser().
743             parseMessage(source);
744             Assertions.fail("an exception should have been thrown");
745         } catch (OrekitException oe) {
746             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_ELEMENT_IN_FILE, oe.getSpecifier());
747             Assertions.assertEquals("EPOCH", oe.getParts()[0]);
748             Assertions.assertEquals(89, ((Integer) oe.getParts()[1]).intValue());
749             Assertions.assertTrue(((String) oe.getParts()[2]).endsWith("OEM-too-small-covariance-dimension.txt"));
750         }
751     }
752 
753     @Test
754     public void testTooManyCovarianceColumns()
755         throws URISyntaxException {
756         final String name = "/ccsds/odm/oem/OEM-too-many-covariance-columns.txt";
757         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
758         try {
759             new ParserBuilder().
760             withMu(CelestialBodyFactory.getMars().getGM()).
761             buildOemParser().
762             parseMessage(source);
763             Assertions.fail("an exception should have been thrown");
764         } catch (OrekitException oe) {
765             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
766             Assertions.assertEquals(51, ((Integer) oe.getParts()[0]).intValue());
767             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("3.3313494e-04"));
768         }
769     }
770 
771     @Test
772     public void testTooFewCovarianceColumns()
773         throws URISyntaxException {
774         final String name = "/ccsds/odm/oem/OEM-too-few-covariance-columns.txt";
775         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
776         try {
777             new ParserBuilder().
778             withMu(CelestialBodyFactory.getMars().getGM()).
779             buildOemParser().
780             parseMessage(source);
781             Assertions.fail("an exception should have been thrown");
782         } catch (OrekitException oe) {
783             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
784             Assertions.assertEquals(55, ((Integer) oe.getParts()[0]).intValue());
785             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("-2.2118325e-07"));
786         }
787     }
788 
789     /**
790      * Check if the parser enters the correct interpolation degree
791      * (the parsed one or the default if there is none)
792      */
793     @Test
794     public void testDefaultInterpolationDegree()
795         throws URISyntaxException {
796 
797         final String name = "/ccsds/odm/oem/OEMExample8.txt";
798 
799         final ParserBuilder builder = new ParserBuilder().withMu(CelestialBodyFactory.getMars().getGM());
800 
801         final DataSource source1 =  new DataSource(name, () -> getClass().getResourceAsStream(name));
802         final Oem file1 = builder.buildOemParser().parseMessage(source1);
803         Assertions.assertEquals(1, file1.getSegments().get(0).getMetadata().getInterpolationDegree());
804         Assertions.assertEquals(7, file1.getSegments().get(1).getMetadata().getInterpolationDegree());
805 
806         final DataSource source2 =  new DataSource(name, () -> getClass().getResourceAsStream(name));
807         final Oem file2 = builder.withDefaultInterpolationDegree(5).buildOemParser().parseMessage(source2);
808         Assertions.assertEquals(5, file2.getSegments().get(0).getMetadata().getInterpolationDegree());
809         Assertions.assertEquals(7, file2.getSegments().get(1).getMetadata().getInterpolationDegree());
810     }
811 
812     /**
813      * Check the parser can parse several ITRF frames. Test case for #361.
814      */
815     @Test
816     public void testITRFFrames() {
817         // setup
818         Charset utf8 = StandardCharsets.UTF_8;
819         IERSConventions conventions = IERSConventions.IERS_2010;
820         boolean simpleEop = true;
821         OemParser parser  = new ParserBuilder().
822                             withMu(CelestialBodyFactory.getMars().getGM()).
823                             buildOemParser();
824 
825         // frames to check
826         List<Pair<String, Frame>> frames = new ArrayList<>();
827         frames.add(new Pair<>("ITRF-93",  FramesFactory.getITRF(ITRFVersion.ITRF_1993, conventions, simpleEop)));
828         frames.add(new Pair<>("ITRF-97",  FramesFactory.getITRF(ITRFVersion.ITRF_1997, conventions, simpleEop)));
829         frames.add(new Pair<>("ITRF2000", FramesFactory.getITRF(ITRFVersion.ITRF_2000, conventions, simpleEop)));
830         frames.add(new Pair<>("ITRF2005", FramesFactory.getITRF(ITRFVersion.ITRF_2005, conventions, simpleEop)));
831         frames.add(new Pair<>("ITRF2008", FramesFactory.getITRF(ITRFVersion.ITRF_2008, conventions, simpleEop)));
832         frames.add(new Pair<>("ITRF2014", FramesFactory.getITRF(ITRFVersion.ITRF_2014, conventions, simpleEop)));
833 
834         for (Pair<String, Frame> frame : frames) {
835             final String frameName = frame.getFirst();
836 
837             InputStream pre    = OemParserTest.class.getResourceAsStream("/ccsds/odm/oem/OEMExample7.txt.pre");
838             InputStream middle = new ByteArrayInputStream(("REF_FRAME = " + frameName).getBytes(utf8));
839             InputStream post   = OemParserTest.class.getResourceAsStream("/ccsds/odm/oem/OEMExample7.txt.post");
840             DataSource   source = new DataSource("<patched>", () -> new SequenceInputStream(pre, new SequenceInputStream(middle, post)));
841 
842             // action
843             Oem actual = parser.parseMessage(source);
844 
845             // verify
846             OemSegment segment = actual.getSegments().get(0);
847             switch (frameName) {
848                 case "ITRF-93" :
849                     Assertions.assertEquals("ITRF1993", segment.getMetadata().getReferenceFrame().getName());
850                     break;
851                 case "ITRF-97" :
852                     Assertions.assertEquals("ITRF1997", segment.getMetadata().getReferenceFrame().getName());
853                     break;
854                 default :
855                     Assertions.assertEquals(frameName, segment.getMetadata().getReferenceFrame().getName());
856                     break;
857             }
858             // check expected frame
859             Frame actualFrame = segment.getFrame();
860             Frame expectedFrame = frame.getSecond();
861             Assertions.assertEquals(expectedFrame, actualFrame);
862             Assertions.assertEquals(expectedFrame.getTransformProvider(),
863                                 actualFrame.getTransformProvider());
864         }
865     }
866 
867     @Test
868     public void testEmptyComments() {
869         final String name = "/ccsds/odm/oem/ISS.resampled.truncated.txt";
870         final ParserBuilder builder = new ParserBuilder();
871         final DataSource source =  new DataSource(name, () -> getClass().getResourceAsStream(name));
872         final Oem iss = builder.buildOemParser().parseMessage(source);
873         Assertions.assertEquals("1998-067-A", iss.getSegments().get(0).getMetadata().getObjectID());
874         Assertions.assertEquals(23, iss.getSegments().get(0).getData().getComments().size());
875         Assertions.assertEquals("", iss.getSegments().get(0).getData().getComments().get(13));
876         Assertions.assertEquals("", iss.getSegments().get(0).getData().getComments().get(20));
877         Assertions.assertEquals(25, iss.getSegments().get(0).getData().getCoordinates().size());
878     }
879 
880 
881     /** Unit tests for parsing an OEM with a custom frame mapper. */
882     @Test
883     public void testFrameMapper() {
884         // setup
885         TimeScale utc = TimeScalesFactory.getUTC();
886         Frame tod = FramesFactory.getTOD(false);
887         Frame myTod = new Frame(tod, Transform.IDENTITY, "MyTOD");
888         AbsoluteDate expectedEpoch = new AbsoluteDate("2019-09-09", utc);
889         CcsdsFrameMapper mapper = new CcsdsFrameMapper() {
890             @Override
891             public Frame buildCcsdsFrame(FrameFacade orientation, AbsoluteDate epoch) {
892                 if ("TOD".equals(orientation.getName()) && null == epoch) {
893                     return myTod;
894                 }
895                 throw new IllegalArgumentException("" + orientation + " " + epoch);
896             }
897 
898             @Override
899             public Frame buildCcsdsFrame(BodyFacade center,
900                                          FrameFacade orientation,
901                                          AbsoluteDate frameEpoch) {
902                 if ("EARTH".equals(center.getName()) &&
903                         "TOD".equals(orientation.getName()) &&
904                         expectedEpoch.equals(frameEpoch)) {
905                     return myTod;
906                 }
907                 throw new IllegalArgumentException(
908                         center + " " + orientation + " " + frameEpoch);
909             }
910         };
911         OemParser parser = new ParserBuilder()
912                 .withFrameMapper(mapper)
913                 .buildOemParser();
914         String name = "/ccsds/odm/oem/test_cov.oem";
915         DataSource source =
916                 new DataSource(name, () -> getClass().getResourceAsStream(name));
917 
918         // action
919         Oem oem = parser.parse(source);
920 
921         // verify
922         List<OemSegment> segments = oem.getSegments();
923         for (OemSegment segment : segments) {
924             MatcherAssert.assertThat(segment.getFrame(), Matchers.sameInstance(myTod));
925             // myTod is not "pseudo-inertial", so use closest ancestor
926             MatcherAssert.assertThat(segment.getInertialFrame(),
927                     Matchers.sameInstance(tod));
928             List<CartesianCovariance> covariances = segment.getCovarianceMatrices();
929             for (CartesianCovariance covariance : covariances) {
930                 MatcherAssert.assertThat(
931                         covariance.getFrame(),
932                         Matchers.sameInstance(myTod));
933             }
934             MatcherAssert.assertThat(covariances.size(), Matchers.is(1));
935         }
936         MatcherAssert.assertThat(segments.size(), Matchers.is(1));
937     }
938 
939     /** Test deprecated constructor. Can be removed in 14.0. */
940     @Test
941     @Deprecated
942     public void testDeprecatedConstructor() {
943         // action
944         OemParser actual = new OemParser(
945                 null, true, null, null, 0, 0, null, new Function[0]);
946 
947         // verify
948         MatcherAssert.assertThat(actual.getFrameMapper(),
949                 Matchers.is(new OrekitCcsdsFrameMapper()));
950     }
951 
952 }