1   /* Copyright 2002-2024 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.adm.aem;
18  
19  import java.io.IOException;
20  import java.net.URISyntaxException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
25  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
26  import org.hipparchus.geometry.euclidean.threed.Rotation;
27  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
28  import org.hipparchus.geometry.euclidean.threed.RotationOrder;
29  import org.hipparchus.geometry.euclidean.threed.Vector3D;
30  import org.hipparchus.util.Binary64;
31  import org.hipparchus.util.Binary64Field;
32  import org.hipparchus.util.FastMath;
33  import org.hipparchus.util.MathUtils;
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.attitudes.Attitude;
39  import org.orekit.attitudes.BoundedAttitudeProvider;
40  import org.orekit.attitudes.FieldAttitude;
41  import org.orekit.bodies.CelestialBodyFactory;
42  import org.orekit.data.DataContext;
43  import org.orekit.data.DataSource;
44  import org.orekit.errors.OrekitException;
45  import org.orekit.errors.OrekitMessages;
46  import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
47  import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
48  import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
49  import org.orekit.files.ccsds.definitions.TimeSystem;
50  import org.orekit.files.ccsds.ndm.ParserBuilder;
51  import org.orekit.files.ccsds.ndm.adm.AttitudeType;
52  import org.orekit.files.ccsds.section.Segment;
53  import org.orekit.frames.FramesFactory;
54  import org.orekit.frames.ITRFVersion;
55  import org.orekit.orbits.CircularOrbit;
56  import org.orekit.orbits.FieldCircularOrbit;
57  import org.orekit.orbits.PositionAngleType;
58  import org.orekit.time.AbsoluteDate;
59  import org.orekit.time.FieldAbsoluteDate;
60  import org.orekit.time.TimeScale;
61  import org.orekit.time.TimeScalesFactory;
62  import org.orekit.utils.AngularDerivativesFilter;
63  import org.orekit.utils.Constants;
64  import org.orekit.utils.IERSConventions;
65  import org.orekit.utils.TimeStampedAngularCoordinates;
66  
67  public class AEMParserTest {
68  
69      @BeforeEach
70      public void setUp()
71          throws Exception {
72          Utils.setDataRoot("regular-data");
73      }
74  
75      @Test
76      public void testParseAEM01() throws IOException {
77          final String ex = "/ccsds/adm/aem/AEMExample01.txt";
78          final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
79          final Aem file = new ParserBuilder().buildAemParser().parseMessage(source);
80          final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
81          final Segment<AemMetadata, AemData> segment1 = file.getSegments().get(1);
82          final AbsoluteDate start = new AbsoluteDate("1996-11-28T22:08:02.5555", TimeScalesFactory.getUTC());
83          Assertions.assertEquals(0.0, start.durationFrom(file.getSatellites().get("1996-062A").getStart()), Double.MIN_VALUE);
84          final AbsoluteDate end = new AbsoluteDate("1996-12-28T21:23:00.5555", TimeScalesFactory.getUTC());
85          Assertions.assertEquals(0.0, end.durationFrom(file.getSatellites().get("1996-062A").getStop()), Double.MIN_VALUE);
86          Assertions.assertEquals("1996-062A", file.getSatellites().get("1996-062A").getId());
87          Assertions.assertEquals(1.0, file.getHeader().getFormatVersion(), Double.MIN_VALUE);
88          Assertions.assertEquals(new AbsoluteDate(2002, 11, 4, 17, 22, 31.0, TimeScalesFactory.getUTC()),
89                              file.getHeader().getCreationDate());
90          Assertions.assertEquals("NASA/JPL", file.getHeader().getOriginator());
91          Assertions.assertEquals("UTC",     segment0.getMetadata().getTimeSystem().name());
92          Assertions.assertEquals("MARS GLOBAL SURVEYOR", segment0.getMetadata().getObjectName());
93          Assertions.assertEquals("1996-062A",            segment0.getMetadata().getObjectID());
94          Assertions.assertEquals("MARS BARYCENTER",      segment0.getMetadata().getCenter().getName());
95          Assertions.assertEquals(1996,                   segment0.getMetadata().getLaunchYear());
96          Assertions.assertEquals(62,                     segment0.getMetadata().getLaunchNumber());
97          Assertions.assertEquals("A",                    segment0.getMetadata().getLaunchPiece());
98          Assertions.assertFalse(segment0.getMetadata().getHasCreatableBody());
99          Assertions.assertNull(segment0.getMetadata().getCenter().getBody());
100         Assertions.assertEquals(new AbsoluteDate(1996, 11, 28, 21, 29, 7.2555, TimeScalesFactory.getUTC()),
101                             segment0.getMetadata().getStartTime());
102         Assertions.assertEquals(new AbsoluteDate(1996, 11, 30, 1, 28, 2.5555, TimeScalesFactory.getUTC()),
103                             segment0.getMetadata().getStopTime());
104         Assertions.assertEquals(new AbsoluteDate(1996, 11, 28, 22, 8, 2.5555, TimeScalesFactory.getUTC()),
105                             segment0.getMetadata().getUseableStartTime());
106         Assertions.assertEquals(new AbsoluteDate(1996, 11, 30, 1, 18, 2.5555, TimeScalesFactory.getUTC()),
107                             segment0.getMetadata().getUseableStopTime());
108         Assertions.assertEquals("HERMITE", segment0.getMetadata().getInterpolationMethod());
109         Assertions.assertEquals(7,         segment0.getMetadata().getInterpolationDegree());
110         Assertions.assertFalse(segment0.getMetadata().isFirst());
111         Assertions.assertEquals("EME2000",       segment0.getMetadata().getEndpoints().getFrameA().getName());
112         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY,
113                             segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
114         Assertions.assertEquals("1",
115                             segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
116         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
117         Assertions.assertEquals(AttitudeType.QUATERNION, segment1.getMetadata().getAttitudeType());
118         Assertions.assertEquals(AngularDerivativesFilter.USE_R, segment0.getMetadata().getAttitudeType().getAngularDerivativesFilter());
119         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 11, 28, 21, 29, 7.2555, TimeScalesFactory.getUTC()),
120                                                                    new Rotation(0.68427, 0.56748, 0.03146, 0.45689, false),
121                                                                    Vector3D.ZERO,
122                                                                    Vector3D.ZERO),
123                                  segment0.getData().getAngularCoordinates().get(0), 1.0e-5);
124         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 11, 28, 22, 8, 3.5555, TimeScalesFactory.getUTC()),
125                                                                    new Rotation(0.74533, 0.42319, -0.45697, 0.23784, false),
126                                                                    Vector3D.ZERO,
127                                                                    Vector3D.ZERO),
128                                  segment0.getData().getAngularCoordinates().get(1), 1.0e-5);
129         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 11, 28, 22, 8, 4.5555, TimeScalesFactory.getUTC()),
130                                                                    new Rotation(0.45652, -0.84532, 0.26974, -0.06532, false),
131                                                                    Vector3D.ZERO,
132                                                                    Vector3D.ZERO),
133                                  segment0.getData().getAngularCoordinates().get(2), 1.0e-5);
134         ArrayList<String> ephemeridesDataLinesComment = new ArrayList<String>();
135         ephemeridesDataLinesComment.add("This file was produced by M.R. Somebody, MSOO NAV/JPL, 2002 OCT 04.");
136         ephemeridesDataLinesComment.add("It is to be used for attitude reconstruction only. The relative accuracy of these");
137         ephemeridesDataLinesComment.add("attitudes is 0.1 degrees per axis.");
138         Assertions.assertEquals(ephemeridesDataLinesComment, segment0.getMetadata().getComments());
139 
140         Assertions.assertEquals("UTC",                      segment1.getMetadata().getTimeSystem().name());
141         Assertions.assertEquals("MARS GLOBAL SURVEYOR",     segment1.getMetadata().getObjectName());
142         Assertions.assertEquals("1996-062A",                segment1.getMetadata().getObjectID());
143         Assertions.assertEquals("MARS BARYCENTER",          segment1.getMetadata().getCenter().getName());
144         Assertions.assertEquals(1996,                       segment1.getMetadata().getLaunchYear());
145         Assertions.assertEquals(62,                         segment1.getMetadata().getLaunchNumber());
146         Assertions.assertEquals("A",                        segment1.getMetadata().getLaunchPiece());
147         Assertions.assertFalse(segment1.getMetadata().getHasCreatableBody());
148         Assertions.assertNull(segment1.getMetadata().getCenter().getBody());
149         Assertions.assertEquals(new AbsoluteDate(1996, 12, 18, 12, 5, 0.5555, TimeScalesFactory.getUTC()),
150                             segment1.getMetadata().getStartTime());
151         Assertions.assertEquals(new AbsoluteDate(1996, 12, 28, 21, 28, 0.5555, TimeScalesFactory.getUTC()),
152                             segment1.getMetadata().getStopTime());
153         Assertions.assertEquals(new AbsoluteDate(1996, 12, 18, 12, 10, 0.5555, TimeScalesFactory.getUTC()),
154                             segment1.getMetadata().getUseableStartTime());
155         Assertions.assertEquals(new AbsoluteDate(1996, 12, 28, 21, 23, 0.5555, TimeScalesFactory.getUTC()),
156                             segment1.getMetadata().getUseableStopTime());
157         Assertions.assertFalse(segment1.getMetadata().isFirst());
158         Assertions.assertEquals("EME2000",       segment0.getMetadata().getEndpoints().getFrameA().getName());
159         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY,
160                             segment0.getMetadata().getEndpoints().getSpacecraftBodyFrame().asSpacecraftBodyFrame().getBaseEquipment());
161         Assertions.assertEquals("1",
162                             segment0.getMetadata().getEndpoints().getSpacecraftBodyFrame().asSpacecraftBodyFrame().getLabel());
163         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
164         Assertions.assertEquals(AttitudeType.QUATERNION, segment1.getMetadata().getAttitudeType());
165         Assertions.assertEquals(AngularDerivativesFilter.USE_R, segment0.getMetadata().getAttitudeType().getAngularDerivativesFilter());
166         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 12, 18, 12, 5, 0.5555, TimeScalesFactory.getUTC()),
167                                                                    new Rotation(0.72501, -0.64585, 0.018542, -0.23854, false),
168                                                                    Vector3D.ZERO,
169                                                                    Vector3D.ZERO),
170                                  segment1.getData().getAngularCoordinates().get(0), 1.0e-5);
171         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 12, 18, 12, 10, 5.5555, TimeScalesFactory.getUTC()),
172                                                                    new Rotation(-0.16767, 0.87451, -0.43475, 0.13458, false),
173                                                                    Vector3D.ZERO,
174                                                                    Vector3D.ZERO),
175                                  segment1.getData().getAngularCoordinates().get(1), 1.0e-5);
176         verifyAngularCoordinates(new TimeStampedAngularCoordinates(new AbsoluteDate(1996, 12, 18, 12, 10, 10.5555, TimeScalesFactory.getUTC()),
177                                                                    new Rotation(-0.71418, 0.03125, -0.65874, 0.23458, false),
178                                                                    Vector3D.ZERO,
179                                                                    Vector3D.ZERO),
180                                  segment1.getData().getAngularCoordinates().get(2), 1.0e-5);
181         ArrayList<String> ephemeridesDataLinesComment2 = new ArrayList<String>();
182         ephemeridesDataLinesComment2.add("This block begins after trajectory correction maneuver TCM-3.");
183         Assertions.assertEquals(ephemeridesDataLinesComment2, segment1.getMetadata().getComments());
184     }
185 
186     @Test
187     public void testParseAEM02() throws URISyntaxException {
188         final String name = "/ccsds/adm/aem/AEMExample02.txt";
189         final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
190         AemParser parser = new ParserBuilder().
191                            withMissionReferenceDate(new AbsoluteDate("1996-12-17T00:00:00.000",
192                                                                      TimeScalesFactory.getUTC())).
193                            buildAemParser();
194 
195         final Aem file = parser.parse(source); // using generic API here
196         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
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("This file was produced by M.R. Somebody, MSOO NAV/JPL, 2002 OCT 04.");
202         metadataComment.add("It is to be used for attitude reconstruction only. The relative accuracy of these");
203         metadataComment.add("attitudes is 0.1 degrees per axis.");
204         Assertions.assertEquals(metadataComment, segment0.getMetadata().getComments());
205         Assertions.assertEquals("EME2000",       segment0.getMetadata().getEndpoints().getFrameA().getName());
206         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY,
207                             segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
208         Assertions.assertEquals("1",
209                             segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
210         List<AemSegment> blocks = file.getSegments();
211         Assertions.assertEquals(1, blocks.size());
212         Assertions.assertEquals(IERSConventions.IERS_2010, parser.getConventions());
213         Assertions.assertTrue(parser.isSimpleEOP());
214         Assertions.assertEquals(0.0, parser.getMissionReferenceDate().durationFrom(new AbsoluteDate(1996, 12, 17, 0, 0, 0.0, TimeScalesFactory.getUTC())), 1.0e-5);
215         Assertions.assertEquals(DataContext.getDefault(), parser.getDataContext());
216         Assertions.assertEquals((new AbsoluteDate("1996-12-17T00:00:00.000",
217                                               TimeScalesFactory.getUTC())),
218                             parser.getMissionReferenceDate());
219     }
220 
221     @Test
222     public void testParseKvnAEM03() throws URISyntaxException {
223         final String ex = "/ccsds/adm/aem/AEMExample03.txt";
224         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
225         validateAEM03(new ParserBuilder().buildAemParser().parseMessage(source));
226     }
227 
228     @Test
229     public void testParseXmlAEM03() throws URISyntaxException {
230         final String ex = "/ccsds/adm/aem/AEMExample03.xml";
231         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
232         final AemParser parser  = new ParserBuilder().buildAemParser();
233         validateAEM03(parser.parse(source));
234     }
235 
236     private void validateAEM03(final Aem file) {
237 
238         final TimeScale utc = TimeScalesFactory.getUTC();
239         Assertions.assertEquals(1.0, file.getHeader().getFormatVersion(), 1.0e-15);
240         Assertions.assertEquals(0,
241                             file.getHeader().getCreationDate().durationFrom(new AbsoluteDate("2008-071T17:09:49", utc)),
242                             1.0e-12);
243         Assertions.assertEquals("GSFC FDF", file.getHeader().getOriginator());
244         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
245         Assertions.assertEquals("ST5-224", segment0.getMetadata().getObjectName());
246         Assertions.assertEquals("2006224", segment0.getMetadata().getObjectID());
247         Assertions.assertEquals("J2000",   segment0.getMetadata().getEndpoints().getFrameA().getName());
248         Assertions.assertEquals("SC_BODY_1", segment0.getMetadata().getEndpoints().getFrameB().getName());
249         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
250         Assertions.assertEquals(TimeSystem.UTC, segment0.getMetadata().getTimeSystem());
251         Assertions.assertEquals(0,
252                             segment0.getMetadata().getStartTime().durationFrom(new AbsoluteDate("2006-090T05:00:00.071", utc)),
253                             1.0e-12);
254         Assertions.assertEquals(0,
255                             segment0.getMetadata().getUseableStartTime().durationFrom(new AbsoluteDate("2006-090T05:00:00.071", utc)),
256                             1.0e-12);
257         Assertions.assertEquals(0,
258                             segment0.getMetadata().getUseableStopTime().durationFrom(new AbsoluteDate("2006-090T05:00:00.946", utc)),
259                             1.0e-12);
260         Assertions.assertEquals(0,
261                             segment0.getMetadata().getStopTime().durationFrom(new AbsoluteDate("2006-090T05:00:00.946", utc)),
262                             1.0e-12);
263         Assertions.assertEquals(AttitudeType.SPIN, segment0.getMetadata().getAttitudeType());
264         Assertions.assertEquals(1, segment0.getData().getComments().size());
265         Assertions.assertEquals("Spin KF ground solution, SPINKF rates", segment0.getData().getComments().get(0));
266         Assertions.assertEquals(8, segment0.getData().getAngularCoordinates().size());
267         TimeStampedAngularCoordinates prev = null;
268         for (TimeStampedAngularCoordinates tac : segment0.getData().getAngularCoordinates()) {
269             if (prev != null) {
270                 double dt = tac.getDate().durationFrom(prev.getDate());
271                 double dR = Rotation.distance(tac.getRotation(), prev.getRotation());
272                 double meanRate = 0.5 * (prev.getRotationRate().getNorm() + tac.getRotationRate().getNorm());
273                 Assertions.assertEquals(dR, dt * meanRate, 1.3e-3);
274             }
275             prev = tac;
276         }
277 
278     }
279 
280     @Test
281     public void testParseAEM04() throws URISyntaxException {
282         final TimeScale utc = TimeScalesFactory.getUTC();
283         final String ex = "/ccsds/adm/aem/AEMExample04.txt";
284         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
285         final AemParser parser  = new ParserBuilder().buildAemParser();
286         final Aem file = parser.parseMessage(source);
287         Assertions.assertEquals(1.0, file.getHeader().getFormatVersion(), 1.0e-15);
288         Assertions.assertEquals(0,
289                             file.getHeader().getCreationDate().durationFrom(new AbsoluteDate("2021-04-13T08:41:42", utc)),
290                             1.0e-12);
291         Assertions.assertEquals("CS GROUP", file.getHeader().getOriginator());
292         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
293         Assertions.assertEquals("COPIHUE",   segment0.getMetadata().getObjectName());
294         Assertions.assertEquals("2100-017F", segment0.getMetadata().getObjectID());
295         Assertions.assertEquals(2100,        segment0.getMetadata().getLaunchYear());
296         Assertions.assertEquals(17,          segment0.getMetadata().getLaunchNumber());
297         Assertions.assertEquals("F",         segment0.getMetadata().getLaunchPiece());
298         Assertions.assertEquals("EME2000",   segment0.getMetadata().getEndpoints().getFrameA().getName());
299         Assertions.assertEquals("SC_BODY_1", segment0.getMetadata().getEndpoints().getFrameB().getName());
300         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
301         Assertions.assertEquals(TimeSystem.UTC, segment0.getMetadata().getTimeSystem());
302         Assertions.assertEquals(0,
303                             segment0.getMetadata().getStartTime().durationFrom(new AbsoluteDate("2021-12-31T00:00:00.000", utc)),
304                             1.0e-12);
305         Assertions.assertEquals(0,
306                             segment0.getMetadata().getUseableStartTime().durationFrom(new AbsoluteDate("2021-12-31T00:00:00.500", utc)),
307                             1.0e-12);
308         Assertions.assertEquals(0,
309                             segment0.getMetadata().getUseableStopTime().durationFrom(new AbsoluteDate("2021-12-31T00:00:05.500", utc)),
310                             1.0e-12);
311         Assertions.assertEquals(0,
312                             segment0.getMetadata().getStopTime().durationFrom(new AbsoluteDate("2021-12-31T00:00:06.000", utc)),
313                             1.0e-12);
314         Assertions.assertEquals(AttitudeType.QUATERNION_DERIVATIVE, segment0.getMetadata().getAttitudeType());
315         Assertions.assertEquals("HERMITE", segment0.getMetadata().getInterpolationMethod());
316         Assertions.assertEquals(3, segment0.getMetadata().getInterpolationDegree());
317         Assertions.assertEquals(1, segment0.getData().getComments().size());
318         Assertions.assertEquals(13, segment0.getData().getAngularCoordinates().size());
319         TimeStampedAngularCoordinates prev = null;
320         for (TimeStampedAngularCoordinates tac : segment0.getData().getAngularCoordinates()) {
321             if (prev != null) {
322                 double dt = tac.getDate().durationFrom(prev.getDate());
323                 double dR = Rotation.distance(tac.getRotation(), prev.getRotation());
324                 double meanRate = 0.5 * (prev.getRotationRate().getNorm() + tac.getRotationRate().getNorm());
325                 Assertions.assertEquals(dR, dt * meanRate, 1.5e-6);
326             }
327             prev = tac;
328         }
329 
330     }
331 
332     @Test
333     public void testParseAEM05() throws URISyntaxException {
334         final String ex = "/ccsds/adm/aem/AEMExample05.txt";
335         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
336         final AemParser parser  = new ParserBuilder().buildAemParser();
337         final Aem file = parser.parseMessage(source);
338         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
339         final List<String> headerComment = new ArrayList<String>();
340         headerComment.add("comment");
341         Assertions.assertEquals(headerComment, file.getHeader().getComments());
342         final List<String> metadataComment = new ArrayList<String>();
343         metadataComment.add("This file was produced by M.R. Somebody, MSOO NAV/JPL, 2002 OCT 04.");
344         metadataComment.add("It is to be used for attitude reconstruction only. The relative accuracy of these");
345         metadataComment.add("attitudes is 0.1 degrees per axis.");
346         Assertions.assertEquals(metadataComment,        segment0.getMetadata().getComments());
347         Assertions.assertEquals("UTC",                  segment0.getMetadata().getTimeSystem().name());
348         Assertions.assertEquals("MARS GLOBAL SURVEYOR", segment0.getMetadata().getObjectName());
349         Assertions.assertEquals("1996-062A",            segment0.getMetadata().getObjectID());
350         Assertions.assertEquals("MARS BARYCENTER",      segment0.getMetadata().getCenter().getName());
351         Assertions.assertEquals(1996,                   segment0.getMetadata().getLaunchYear());
352         Assertions.assertEquals(62,                     segment0.getMetadata().getLaunchNumber());
353         Assertions.assertEquals("A",                    segment0.getMetadata().getLaunchPiece());
354         Assertions.assertEquals(RotationOrder.ZXY,      segment0.getMetadata().getEulerRotSeq());
355         Assertions.assertTrue(segment0.getMetadata().rateFrameIsA());
356         Assertions.assertFalse(segment0.getMetadata().getHasCreatableBody());
357         Assertions.assertNull(segment0.getMetadata().getCenter().getBody());
358 
359         // Reference values
360         final AbsoluteDate refDate = new AbsoluteDate(1996, 11, 28, 21, 29, 7.2555, TimeScalesFactory.getUTC());
361 
362         // Computed angular coordinates
363         final TimeStampedAngularCoordinates ac = segment0.getData().getAngularCoordinates().get(0);
364         final FieldRotation<UnivariateDerivative1> r = ac.toUnivariateDerivative1Rotation();
365         final UnivariateDerivative1[] angles = r.getAngles(segment0.getMetadata().getEulerRotSeq(),
366                                                            RotationConvention.FRAME_TRANSFORM);
367         Assertions.assertEquals(0.0,     refDate.durationFrom(ac.getDate()),                 1.0e-5);
368         Assertions.assertEquals(0.0,     ac.getRotationAcceleration().getNorm(),             1.0e-5);
369         Assertions.assertEquals(-26.78,  FastMath.toDegrees(angles[0].getValue()),           1.0e-2);
370         Assertions.assertEquals(46.26,   FastMath.toDegrees(angles[1].getValue()),           1.0e-2);
371         Assertions.assertEquals(144.10,  FastMath.toDegrees(angles[2].getValue()),           1.0e-2);
372         Assertions.assertEquals(0.10450, FastMath.toDegrees(angles[0].getFirstDerivative()), 1.0e-5);
373         Assertions.assertEquals(0.03214, FastMath.toDegrees(angles[1].getFirstDerivative()), 1.0e-5);
374         Assertions.assertEquals(0.02156, FastMath.toDegrees(angles[2].getFirstDerivative()), 1.0e-5);
375     }
376 
377     @Test
378     public void testParseAEM06a() throws URISyntaxException {
379         final String ex = "/ccsds/adm/aem/AEMExample06a.txt";
380         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
381         final AemParser parser  = new ParserBuilder().buildAemParser();
382 
383         final Aem file = parser.parseMessage(source);
384         final TimeStampedAngularCoordinates ac = file.getSegments().get(0).getAngularCoordinates().get(7);
385         final Vector3D lastSpin = ac.getRotation().applyInverseTo(Vector3D.PLUS_K);
386         Assertions.assertEquals(268.45119, FastMath.toDegrees(MathUtils.normalizeAngle(lastSpin.getAlpha(), FastMath.PI)), 1.0e-5);
387         Assertions.assertEquals(68.317275, FastMath.toDegrees(lastSpin.getDelta()), 1.0e-5);
388     }
389 
390     @Test
391     public void testParseAEM06b() throws URISyntaxException {
392         final String ex = "/ccsds/adm/aem/AEMExample06b.txt";
393         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
394         final AemParser parser  = new ParserBuilder().buildAemParser();
395 
396         final Aem file = parser.parseMessage(source);
397         final TimeStampedAngularCoordinates ac = file.getSegments().get(0).getAngularCoordinates().get(7);
398         final Vector3D lastSpin = ac.getRotation().applyInverseTo(Vector3D.PLUS_K);
399         Assertions.assertEquals(268.45119, FastMath.toDegrees(MathUtils.normalizeAngle(lastSpin.getAlpha(), FastMath.PI)), 1.0e-5);
400         Assertions.assertEquals(68.317275, FastMath.toDegrees(lastSpin.getDelta()), 1.0e-5);
401     }
402 
403     @Test
404     public void testParseAEM07() throws URISyntaxException {
405         final String ex = "/ccsds/adm/aem/AEMExample07.txt";
406         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
407         final AemParser parser  = new ParserBuilder().buildAemParser();
408         final Aem file = parser.parseMessage(source);
409         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
410         final List<String> headerComment = new ArrayList<String>();
411         headerComment.add("comment");
412         Assertions.assertEquals(headerComment, file.getHeader().getComments());
413         final List<String> metadataComment = new ArrayList<String>();
414         metadataComment.add("This file was produced by M.R. Somebody, MSOO NAV/JPL, 2002 OCT 04.");
415         metadataComment.add("It is to be used for attitude reconstruction only. The relative accuracy of these");
416         metadataComment.add("attitudes is 0.1 degrees per axis.");
417         Assertions.assertEquals(metadataComment,        segment0.getMetadata().getComments());
418         Assertions.assertEquals(TimeSystem.UTC,         segment0.getMetadata().getTimeSystem());
419         Assertions.assertEquals("MARS GLOBAL SURVEYOR", segment0.getMetadata().getObjectName());
420         Assertions.assertEquals("1996-062A",            segment0.getMetadata().getObjectID());
421         Assertions.assertEquals("MARS BARYCENTER",      segment0.getMetadata().getCenter().getName());
422         Assertions.assertEquals(1996,                   segment0.getMetadata().getLaunchYear());
423         Assertions.assertEquals(62,                     segment0.getMetadata().getLaunchNumber());
424         Assertions.assertEquals("A",                    segment0.getMetadata().getLaunchPiece());
425         Assertions.assertFalse(segment0.getMetadata().getHasCreatableBody());
426         Assertions.assertNull(segment0.getMetadata().getCenter().getBody());
427         Assertions.assertEquals(CelestialBodyFrame.EME2000, segment0.getMetadata().getEndpoints().getFrameA().asCelestialBodyFrame());
428         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY, segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
429         Assertions.assertEquals("1", segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
430         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
431         Assertions.assertEquals(new AbsoluteDate("2002-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
432                             segment0.getMetadata().getStartTime());
433         Assertions.assertEquals(new AbsoluteDate("2002-12-18T12:00:00.331", TimeScalesFactory.getUTC()),
434                             segment0.getMetadata().getUseableStartTime());
435         Assertions.assertEquals(new AbsoluteDate("2002-12-18T12:02:00.331", TimeScalesFactory.getUTC()),
436                             segment0.getMetadata().getUseableStopTime());
437         Assertions.assertEquals(new AbsoluteDate("2002-12-18T12:02:00.331", TimeScalesFactory.getUTC()),
438                             segment0.getMetadata().getStopTime());
439         Assertions.assertEquals(AttitudeType.QUATERNION, segment0.getMetadata().getAttitudeType());
440         Assertions.assertFalse(segment0.getMetadata().isFirst());
441         Assertions.assertEquals("HERMITE", segment0.getMetadata().getInterpolationMethod());
442         Assertions.assertEquals(7, segment0.getMetadata().getInterpolationDegree());
443 
444         final AbsoluteDate refDate = new AbsoluteDate("2002-12-18T12:00:00.331", TimeScalesFactory.getUTC());
445 
446         Assertions.assertEquals(3, segment0.getData().getAngularCoordinates().size());
447         final TimeStampedAngularCoordinates ac0 = segment0.getData().getAngularCoordinates().get(0);
448         Assertions.assertEquals(0.0, ac0.getDate().durationFrom(refDate), 1.0e-5);
449         Assertions.assertEquals(0.0,
450                             Rotation.distance(new Rotation(0.68427, 0.56748, 0.03146, 0.45689, true),
451                                               ac0.getRotation()),
452                             1.0e-10);
453         final TimeStampedAngularCoordinates ac1 = segment0.getData().getAngularCoordinates().get(1);
454         Assertions.assertEquals(60.0, ac1.getDate().durationFrom(refDate), 1.0e-5);
455         Assertions.assertEquals(0.0,
456                             Rotation.distance(new Rotation(0.74533, 0.42319, -0.45697, 0.23784, true),
457                                               ac1.getRotation()),
458                             1.0e-10);
459         final TimeStampedAngularCoordinates ac2 = segment0.getData().getAngularCoordinates().get(2);
460         Assertions.assertEquals(120.0, ac2.getDate().durationFrom(refDate), 1.0e-5);
461         Assertions.assertEquals(0.0,
462                             Rotation.distance(new Rotation(0.45652, -0.84532, 0.26974, -0.06532, true),
463                                               ac2.getRotation()),
464                             1.0e-10);
465 
466     }
467 
468     @Test
469     public void testParseAEM11() throws URISyntaxException {
470         final String ex = "/ccsds/adm/aem/AEMExample11.xml";
471         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
472         final AemParser parser  = new ParserBuilder().buildAemParser();
473         final Aem file = parser.parseMessage(source);
474         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
475         final List<String> headerComment = new ArrayList<String>();
476         headerComment.add("This example shows an AEM with a rotation");
477         Assertions.assertEquals(headerComment, file.getHeader().getComments());
478         final List<String> metadataComment = new ArrayList<String>();
479         metadataComment.add("The relative accuracy of these");
480         metadataComment.add("attitudes is 0.1 degrees per axis.");
481         Assertions.assertEquals(metadataComment, segment0.getMetadata().getComments());
482         Assertions.assertEquals(TimeSystem.UTC,  segment0.getMetadata().getTimeSystem());
483         Assertions.assertEquals("FICTITIOUS",    segment0.getMetadata().getObjectName());
484         Assertions.assertEquals("2020-224A",     segment0.getMetadata().getObjectID());
485         Assertions.assertEquals("EARTH",         segment0.getMetadata().getCenter().getName());
486         Assertions.assertEquals(CelestialBodyFrame.J2000, segment0.getMetadata().getEndpoints().getFrameA().asCelestialBodyFrame());
487         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY, segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
488         Assertions.assertEquals("1", segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
489         Assertions.assertTrue(segment0.getMetadata().getEndpoints().isA2b());
490         Assertions.assertEquals(new AbsoluteDate("2020-090T05:00:00.071", TimeScalesFactory.getUTC()),
491                             segment0.getMetadata().getStartTime());
492         Assertions.assertEquals(new AbsoluteDate("2020-090T05:00:00.946", TimeScalesFactory.getUTC()),
493                             segment0.getMetadata().getStopTime());
494         Assertions.assertEquals(AttitudeType.EULER_ANGLE_DERIVATIVE, segment0.getMetadata().getAttitudeType());
495 
496         final AbsoluteDate refDate = new AbsoluteDate("2020-090T05:00:00.071", TimeScalesFactory.getUTC());
497 
498         Assertions.assertEquals(2, segment0.getData().getAngularCoordinates().size());
499         final TimeStampedAngularCoordinates ac0 = segment0.getData().getAngularCoordinates().get(0);
500         Assertions.assertEquals(0.0, ac0.getDate().durationFrom(refDate), 1.0e-5);
501         Assertions.assertEquals(0.0,
502                             Rotation.distance(new Rotation(RotationOrder.XYZ, RotationConvention.FRAME_TRANSFORM,
503                                                            FastMath.toRadians(45),
504                                                            FastMath.toRadians(0.9),
505                                                            FastMath.toRadians(15)),
506                                               ac0.getRotation()),
507                             1.0e-10);
508         final TimeStampedAngularCoordinates ac1 = segment0.getData().getAngularCoordinates().get(1);
509         Assertions.assertEquals(0.875, ac1.getDate().durationFrom(refDate), 1.0e-5);
510         Assertions.assertEquals(0.0,
511                             Rotation.distance(new Rotation(RotationOrder.XYZ, RotationConvention.FRAME_TRANSFORM,
512                                                            FastMath.toRadians(50),
513                                                            FastMath.toRadians(1.9),
514                                                            FastMath.toRadians(1.5)),
515                                               ac1.getRotation()),
516                             1.0e-10);
517 
518     }
519 
520     @Test
521     public void testParseAEM13() throws URISyntaxException {
522         final TimeScale tai = TimeScalesFactory.getTAI();
523         final String ex = "/ccsds/adm/aem/AEMExample13.xml";
524         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
525         final AemParser parser  = new ParserBuilder().buildAemParser();
526         final Aem file = parser.parseMessage(source);
527         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
528         Assertions.assertEquals(TimeSystem.TAI,          segment0.getMetadata().getTimeSystem());
529         Assertions.assertEquals("OREKIT SAT",            segment0.getMetadata().getObjectName());
530         Assertions.assertEquals("2020-012A",             segment0.getMetadata().getObjectID());
531         Assertions.assertEquals(OrbitRelativeFrame.LVLH, segment0.getMetadata().getEndpoints().getFrameA().asOrbitRelativeFrame());
532         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.IMU_FRAME, segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
533         Assertions.assertEquals("1", segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
534         Assertions.assertFalse(segment0.getMetadata().getEndpoints().isA2b());
535         Assertions.assertEquals(new AbsoluteDate("2021-04-15T13:31:20.000", tai), segment0.getMetadata().getStartTime());
536         Assertions.assertEquals(new AbsoluteDate("2021-04-15T13:31:23.000", tai), segment0.getMetadata().getStopTime());
537         Assertions.assertEquals(AttitudeType.QUATERNION_DERIVATIVE, segment0.getMetadata().getAttitudeType());
538         Assertions.assertTrue(segment0.getMetadata().isFirst());
539 
540         final AbsoluteDate refDate = new AbsoluteDate("2021-04-15T13:31:20.000", tai);
541 
542         Assertions.assertEquals(7, segment0.getData().getAngularCoordinates().size());
543         final TimeStampedAngularCoordinates ac0 = segment0.getData().getAngularCoordinates().get(0);
544         Assertions.assertEquals(0.0, ac0.getDate().durationFrom(refDate), 1.0e-5);
545         Assertions.assertEquals(0.0,
546                             Rotation.distance(new Rotation(-0.488615, -0.402157,  0.581628,  0.511111, true),
547                                               ac0.getRotation()),
548                             1.0e-10);
549         final TimeStampedAngularCoordinates ac1 = segment0.getData().getAngularCoordinates().get(1);
550         Assertions.assertEquals(0.5, ac1.getDate().durationFrom(refDate), 1.0e-5);
551         Assertions.assertEquals(0.0,
552                             Rotation.distance(new Rotation(-0.488765, -0.402027,  0.581486,  0.511231, true),
553                                               ac1.getRotation()),
554                             1.0e-10);
555         final TimeStampedAngularCoordinates ac2 = segment0.getData().getAngularCoordinates().get(2);
556         Assertions.assertEquals(1.0, ac2.getDate().durationFrom(refDate), 1.0e-5);
557         Assertions.assertEquals(0.0,
558                             Rotation.distance(new Rotation(-0.488916, -0.401898,  0.581344,  0.511350, true),
559                                               ac2.getRotation()),
560                             1.0e-10);
561 
562         final CircularOrbit o = new CircularOrbit(6992992, -5e-04, 1.2e-03,
563                                                   FastMath.toRadians(97.83), FastMath.toRadians(80.95),
564                                                   FastMath.toRadians(179.86), PositionAngleType.MEAN,
565                                                   FramesFactory.getEME2000(),
566                                                   new AbsoluteDate("2021-04-15T13:31:22.000", tai),
567                                                   Constants.EIGEN5C_EARTH_MU);
568         final FieldCircularOrbit<Binary64> fo =
569                         new FieldCircularOrbit<>(new Binary64(o.getA()),
570                                                  new Binary64(o.getCircularEx()), new Binary64(o.getCircularEy()),
571                                                  new Binary64(o.getI()), new Binary64(o.getRightAscensionOfAscendingNode()),
572                                                  new Binary64(o.getAlphaM()), PositionAngleType.MEAN,
573                                                  o.getFrame(), new FieldAbsoluteDate<>(Binary64Field.getInstance(), o.getDate()),
574                                                  new Binary64(o.getMu()));
575         final AemSatelliteEphemeris ephemeris = file.getSatellites().get("2020-012A");
576         final BoundedAttitudeProvider provider = ephemeris.getAttitudeProvider();
577         Attitude                  a = provider.getAttitude(o, o.getDate(), o.getFrame());
578         FieldAttitude<Binary64> fa = provider.getAttitude(fo, fo.getDate(), fo.getFrame());
579         Assertions.assertEquals(a.getRotation().getQ0(), fa.getRotation().getQ0().getReal(), 0.00001);
580         Assertions.assertEquals(a.getRotation().getQ1(), fa.getRotation().getQ1().getReal(), 0.00001);
581         Assertions.assertEquals(a.getRotation().getQ2(), fa.getRotation().getQ2().getReal(), 0.00001);
582         Assertions.assertEquals(a.getRotation().getQ3(), fa.getRotation().getQ3().getReal(), 0.00001);
583 
584     }
585 
586     @Test
587     public void testParseAEM14() throws URISyntaxException {
588         final TimeScale tai = TimeScalesFactory.getTAI();
589         final String ex = "/ccsds/adm/aem/AEMExample14.txt";
590         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
591         final AemParser parser  = new ParserBuilder().buildAemParser();
592         final Aem file = parser.parseMessage(source);
593 
594         final Segment<AemMetadata, AemData> segment0 = file.getSegments().get(0);
595         Assertions.assertEquals(TimeSystem.TAI,          segment0.getMetadata().getTimeSystem());
596         Assertions.assertEquals("MMS",                   segment0.getMetadata().getObjectName());
597         Assertions.assertEquals("2015-011A",             segment0.getMetadata().getObjectID());
598         Assertions.assertEquals("EME2000",               segment0.getMetadata().getEndpoints().getFrameA().getName());
599         Assertions.assertEquals(SpacecraftBodyFrame.BaseEquipment.SC_BODY, segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getBaseEquipment());
600         Assertions.assertEquals("1", segment0.getMetadata().getEndpoints().getFrameB().asSpacecraftBodyFrame().getLabel());
601         Assertions.assertEquals(new AbsoluteDate("2023-01-01T00:00:00.000", tai), segment0.getMetadata().getStartTime());
602         Assertions.assertEquals(new AbsoluteDate("2023-01-01T00:04:30.000", tai), segment0.getMetadata().getStopTime());
603         Assertions.assertEquals(AttitudeType.EULER_ANGLE_DERIVATIVE, segment0.getMetadata().getAttitudeType());
604         Assertions.assertEquals(RotationOrder.ZXZ, segment0.getMetadata().getEulerRotSeq());
605         Assertions.assertEquals(10, segment0.getData().getAngularCoordinates().size());
606 
607         Assertions.assertEquals(AttitudeType.SPIN_NUTATION_MOMENTUM,
608                                 file.getSegments().get(1).getMetadata().getAttitudeType());
609         Assertions.assertEquals(AttitudeType.QUATERNION,
610                                 file.getSegments().get(2).getMetadata().getAttitudeType());
611         Assertions.assertEquals(AttitudeType.QUATERNION_ANGVEL,
612                                 file.getSegments().get(3).getMetadata().getAttitudeType());
613         Assertions.assertEquals(AttitudeType.EULER_ANGLE_ANGVEL,
614                                 file.getSegments().get(4).getMetadata().getAttitudeType());
615 
616     }
617 
618     @Test
619     public void testWrongNDMType() {
620         final String name = "/ccsds/odm/opm/OPMExample1.txt";
621         try {
622             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
623             new ParserBuilder().buildAemParser().parseMessage(source);
624             Assertions.fail("an exception should have been thrown");
625         } catch (OrekitException oe) {
626             Assertions.assertEquals(OrekitMessages.UNSUPPORTED_FILE_FORMAT, oe.getSpecifier());
627             Assertions.assertEquals(name, oe.getParts()[0]);
628         }
629     }
630 
631     @Test
632     public void testNonExistentFile() throws URISyntaxException {
633         final String realName = getClass().getResource("/ccsds/adm/aem/AEMExample01.txt").toURI().getPath();
634         final String wrongName = realName + "xxxxx";
635         final DataSource source =  new DataSource(wrongName, () -> getClass().getResourceAsStream(wrongName));
636         try {
637             new ParserBuilder().buildAemParser().parseMessage(source);
638             Assertions.fail("an exception should have been thrown");
639         } catch (OrekitException oe) {
640             Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier());
641             Assertions.assertEquals(wrongName, oe.getParts()[0]);
642         }
643     }
644 
645     @Test
646     public void testMissingAttitudeType() {
647         try {
648             final String name = "/ccsds/adm/aem/AEM-missing-attitude-type.txt";
649             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
650             new ParserBuilder().buildAemParser().parseMessage(source);
651             Assertions.fail("an exception should have been thrown");
652         } catch (OrekitException oe) {
653             Assertions.assertEquals(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, oe.getSpecifier());
654             Assertions.assertEquals(AemMetadataKey.ATTITUDE_TYPE.name(), oe.getParts()[0]);
655         }
656     }
657 
658     @Test
659     public void testInconsistentDirection() {
660         try {
661             final String name = "/ccsds/adm/aem/AEM-inconsistent-direction.txt";
662             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
663             new ParserBuilder().buildAemParser().parseMessage(source);
664             Assertions.fail("an exception should have been thrown");
665         } catch (OrekitException oe) {
666             Assertions.assertEquals(OrekitMessages.CCSDS_KEYWORD_NOT_ALLOWED_IN_VERSION, oe.getSpecifier());
667             Assertions.assertEquals(AemMetadataKey.ATTITUDE_DIR, oe.getParts()[0]);
668             Assertions.assertEquals(2.0, ((Double) oe.getParts()[1]).doubleValue(), 1.0e-15);
669         }
670     }
671 
672     @Test
673     public void testInconsistentQuaternionType() {
674         try {
675             final String name = "/ccsds/adm/aem/AEM-inconsistent-quaternion-type.txt";
676             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
677             new ParserBuilder().buildAemParser().parseMessage(source);
678             Assertions.fail("an exception should have been thrown");
679         } catch (OrekitException oe) {
680             Assertions.assertEquals(OrekitMessages.CCSDS_KEYWORD_NOT_ALLOWED_IN_VERSION, oe.getSpecifier());
681             Assertions.assertEquals(AemMetadataKey.QUATERNION_TYPE, oe.getParts()[0]);
682             Assertions.assertEquals(2.0, ((Double) oe.getParts()[1]).doubleValue(), 1.0e-15);
683         }
684     }
685 
686     @Test
687     public void testLowerCaseValue() {
688         //setup
689         String file = "/ccsds/adm/aem/aemLowerCaseValue.aem";
690         final DataSource source = new DataSource(file, () -> getClass().getResourceAsStream(file));
691 
692         //action
693         Aem actual = new ParserBuilder().buildAemParser().parseMessage(source);
694 
695         //verify
696         Assertions.assertEquals(
697                 CelestialBodyFactory.getEarth(),
698                 actual.getSegments().get(0).getMetadata().getCenter().getBody());
699     }
700 
701     @Test
702     public void testWrongFile() {
703         final String name = "/ccsds/odm/opm/OPMExample1.txt";
704         try {
705             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
706             new ParserBuilder().buildAemParser().parseMessage(source);
707             Assertions.fail("an exception should have been thrown");
708         } catch (OrekitException oe) {
709             Assertions.assertEquals(OrekitMessages.UNSUPPORTED_FILE_FORMAT, oe.getSpecifier());
710             Assertions.assertEquals(name, oe.getParts()[0]);
711         }
712     }
713 
714     @Test
715     public void testWrongKeyword()
716         throws URISyntaxException {
717         // simple test for AEM file, contains a wrong keyword in the metadata.
718         final String name = "/ccsds/adm/aem/AEM-wrong-keyword.txt";
719         final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
720         try {
721             new ParserBuilder().buildAemParser().parseMessage(source);
722             Assertions.fail("an exception should have been thrown");
723         } catch (OrekitException oe) {
724             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
725             Assertions.assertEquals(24, ((Integer) oe.getParts()[0]).intValue());
726             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("WRONG_KEYWORD"));
727         }
728     }
729 
730     @Test
731     public void testEphemerisNumberFormatErrorType() {
732         final String name = "/ccsds/adm/aem/AEM-ephemeris-number-format-error.txt";
733         try {
734             final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
735             new ParserBuilder().buildAemParser().parseMessage(source);
736             Assertions.fail("an exception should have been thrown");
737         } catch (OrekitException oe) {
738             Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier());
739             Assertions.assertEquals(28, oe.getParts()[0]);
740             Assertions.assertEquals(name, oe.getParts()[1]);
741             Assertions.assertEquals("1996-11-28T22:08:03.5555 0.42319   this-is-not-a-number  0.23784   0.74533", oe.getParts()[2]);
742         }
743     }
744 
745     @Test
746     public void testKeywordWithinEphemeris()
747         throws URISyntaxException {
748         // simple test for AEM file, contains p/v entries and other mandatory data.
749         final String name = "/ccsds/adm/aem/AEM-keyword-within-ephemeris.txt";
750         final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
751         try {
752             new ParserBuilder().buildAemParser().parseMessage(source);
753             Assertions.fail("an exception should have been thrown");
754         } catch (OrekitException oe) {
755             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
756             Assertions.assertEquals(29, ((Integer) oe.getParts()[0]).intValue());
757             Assertions.assertTrue(((String) oe.getParts()[2]).startsWith("USER_DEFINED_TEST_KEY"));
758         }
759     }
760 
761     @Test
762     public void testWrongRotationSequence() throws URISyntaxException {
763         // simple test for AEM file, contains a wrong keyword in the metadata.
764         final String name = "/ccsds/adm/aem/AEM-inconsistent-rotation-sequence.txt";
765         final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
766         try {
767             new ParserBuilder().buildAemParser().parseMessage(source);
768             Assertions.fail("an exception should have been thrown");
769         } catch (OrekitException oe) {
770             Assertions.assertEquals(OrekitMessages.CCSDS_INVALID_ROTATION_SEQUENCE, oe.getSpecifier());
771             Assertions.assertEquals("7051995", oe.getParts()[0]);
772             Assertions.assertEquals(22, ((Integer) oe.getParts()[1]).intValue());
773             Assertions.assertEquals(name, oe.getParts()[2]);
774         }
775     }
776 
777     @Test
778     public void testSpuriousMetaDataSection() throws URISyntaxException {
779         final String name = "/ccsds/adm/aem/spurious-metadata.txt";
780         final DataSource source = new DataSource(name, () -> getClass().getResourceAsStream(name));
781         try {
782             new ParserBuilder().buildAemParser().parseMessage(source);
783             Assertions.fail("an exception should have been thrown");
784         } catch (OrekitException oe) {
785             Assertions.assertEquals(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD, oe.getSpecifier());
786             Assertions.assertEquals(26, ((Integer) oe.getParts()[0]).intValue());
787             Assertions.assertEquals("META", oe.getParts()[2]);
788         }
789     }
790 
791     @Test
792     public void testMissingConvention() throws URISyntaxException {
793         final String ex = "/ccsds/adm/aem/AEMExample01.txt";
794         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
795         final Aem file = new ParserBuilder().buildAemParser().parseMessage(source);
796         try {
797             file.getConventions();
798         } catch (OrekitException oe) {
799             Assertions.assertEquals(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS, oe.getSpecifier());
800         }
801     }
802 
803     private void verifyAngularCoordinates(final TimeStampedAngularCoordinates expected,
804                                           final TimeStampedAngularCoordinates actual,
805                                           final double threshold) {
806         // Verify date
807         Assertions.assertEquals(0.0, expected.getDate().durationFrom(actual.getDate()), threshold);
808 
809         // Verify Angular elements
810         Assertions.assertEquals(expected.getRotation().getQ0(), actual.getRotation().getQ0(), threshold);
811         Assertions.assertEquals(expected.getRotation().getQ1(), actual.getRotation().getQ1(), threshold);
812         Assertions.assertEquals(expected.getRotation().getQ2(), actual.getRotation().getQ2(), threshold);
813         Assertions.assertEquals(expected.getRotation().getQ3(), actual.getRotation().getQ3(), threshold);
814 
815         Assertions.assertEquals(0.0, expected.getRotationRate().distance(actual.getRotationRate()), threshold);
816     }
817 
818     /**
819      * Check if the parser enters the correct interpolation degree
820      * (the parsed one or the default if there is none)
821      */
822     @Test
823     public void testDefaultInterpolationDegree()
824         throws URISyntaxException {
825 
826         final String name = "/ccsds/adm/aem/AEMExample01.txt";
827         ParserBuilder builder = new ParserBuilder();
828 
829         final DataSource source1 = new DataSource(name, () -> getClass().getResourceAsStream(name));
830         final Aem file = builder.buildAemParser().parseMessage(source1);
831         Assertions.assertEquals(7, file.getSegments().get(0).getMetadata().getInterpolationDegree());
832         Assertions.assertEquals(1, file.getSegments().get(1).getMetadata().getInterpolationDegree());
833 
834         final DataSource source2 = new DataSource(name, () -> getClass().getResourceAsStream(name));
835         final Aem file2 = builder.withDefaultInterpolationDegree(5).buildAemParser().parseMessage(source2);
836         Assertions.assertEquals(7, file2.getSegments().get(0).getMetadata().getInterpolationDegree());
837         Assertions.assertEquals(5, file2.getSegments().get(1).getMetadata().getInterpolationDegree());
838     }
839 
840     @Test
841     public void testIssue739() {
842         final String ex = "/ccsds/adm/aem/AEMExample08.txt";
843         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
844         final Aem file = new ParserBuilder().buildAemParser().parseMessage(source);
845         final AemSegment segment0 = file.getSegments().get(0);
846         Assertions.assertEquals(CelestialBodyFrame.GTOD, segment0.getMetadata().getEndpoints().getFrameB().asCelestialBodyFrame());
847 
848         final BoundedAttitudeProvider provider = segment0.getAttitudeProvider();
849         Attitude attitude = provider.getAttitude(null, new AbsoluteDate("1996-11-28T22:08:03.555", TimeScalesFactory.getUTC()), null);
850         Rotation rotation = attitude.getRotation();
851         Assertions.assertEquals(0.42319,  rotation.getQ1(), 0.0001);
852         Assertions.assertEquals(-0.45697, rotation.getQ2(), 0.0001);
853         Assertions.assertEquals(0.23784,  rotation.getQ3(), 0.0001);
854         Assertions.assertEquals(0.74533,  rotation.getQ0(), 0.0001);
855         Assertions.assertEquals(0.0, provider.getMinDate().durationFrom(segment0.getMetadata().getStart()), 0.0001);
856         Assertions.assertEquals(0.0, provider.getMaxDate().durationFrom(segment0.getMetadata().getStop()), 0.0001);
857 
858     }
859 
860     @Test
861     public void testIssue739_2() {
862         final String ex = "/ccsds/adm/aem/AEMExample09.txt";
863         final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
864         final Aem file = new ParserBuilder().buildAemParser().parseMessage(source);
865         final AemSegment segment0 = file.getSegments().get(0);
866         Assertions.assertEquals(FramesFactory.getITRF(ITRFVersion.ITRF_1993, IERSConventions.IERS_2010, true),
867                             segment0.getMetadata().getEndpoints().getFrameA().asFrame());
868 
869         final BoundedAttitudeProvider provider = segment0.getAttitudeProvider();
870         Attitude attitude = provider.getAttitude(null, new AbsoluteDate("1996-11-28T22:08:03.555", TimeScalesFactory.getUTC()), null);
871         Rotation rotation = attitude.getRotation();
872         Assertions.assertEquals(0.42319,  rotation.getQ1(), 0.0001);
873         Assertions.assertEquals(-0.45697, rotation.getQ2(), 0.0001);
874         Assertions.assertEquals(0.23784,  rotation.getQ3(), 0.0001);
875         Assertions.assertEquals(0.74533,  rotation.getQ0(), 0.0001);
876         Assertions.assertEquals(0.0, provider.getMinDate().durationFrom(segment0.getMetadata().getStart()), 0.0001);
877         Assertions.assertEquals(0.0, provider.getMaxDate().durationFrom(segment0.getMetadata().getStop()), 0.0001);
878 
879     }
880 
881 }