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