1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS Systèmes d'Information (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;
18  
19  import java.lang.reflect.InvocationTargetException;
20  import java.util.List;
21  import java.util.Locale;
22  import java.util.Map;
23  import java.util.stream.Stream;
24  
25  import org.hipparchus.complex.Quaternion;
26  import org.hipparchus.geometry.euclidean.threed.Rotation;
27  import org.hipparchus.geometry.euclidean.threed.Vector3D;
28  import org.hipparchus.linear.RealMatrix;
29  import org.hipparchus.util.FastMath;
30  import org.hipparchus.util.Precision;
31  import org.junit.jupiter.api.Assertions;
32  import org.orekit.data.DataContext;
33  import org.orekit.errors.OrekitException;
34  import org.orekit.errors.OrekitMessages;
35  import org.orekit.files.ccsds.definitions.BodyFacade;
36  import org.orekit.files.ccsds.definitions.FrameFacade;
37  import org.orekit.files.ccsds.definitions.OdMethodFacade;
38  import org.orekit.files.ccsds.definitions.PocMethodFacade;
39  import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
40  import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints;
41  import org.orekit.files.ccsds.ndm.adm.acm.AcmSatelliteEphemeris;
42  import org.orekit.files.ccsds.ndm.adm.acm.AttitudeCovariance;
43  import org.orekit.files.ccsds.ndm.adm.acm.AttitudeCovarianceHistory;
44  import org.orekit.files.ccsds.ndm.adm.acm.AttitudeState;
45  import org.orekit.files.ccsds.ndm.adm.acm.AttitudeStateHistory;
46  import org.orekit.files.ccsds.ndm.adm.aem.AemSatelliteEphemeris;
47  import org.orekit.files.ccsds.ndm.adm.apm.ApmQuaternion;
48  import org.orekit.files.ccsds.ndm.cdm.CdmRelativeMetadata;
49  import org.orekit.files.ccsds.ndm.odm.ocm.OcmSatelliteEphemeris;
50  import org.orekit.files.ccsds.ndm.odm.ocm.OrbitCovariance;
51  import org.orekit.files.ccsds.ndm.odm.ocm.OrbitCovarianceHistory;
52  import org.orekit.files.ccsds.ndm.odm.ocm.OrbitManeuver;
53  import org.orekit.files.ccsds.ndm.odm.ocm.OrbitManeuverHistory;
54  import org.orekit.files.ccsds.ndm.odm.ocm.TrajectoryState;
55  import org.orekit.files.ccsds.ndm.odm.ocm.TrajectoryStateHistory;
56  import org.orekit.files.ccsds.ndm.odm.oem.OemSatelliteEphemeris;
57  import org.orekit.files.ccsds.ndm.tdm.Observation;
58  import org.orekit.files.ccsds.section.CommentsContainer;
59  import org.orekit.files.ccsds.section.Section;
60  import org.orekit.files.ccsds.section.Segment;
61  import org.orekit.frames.Frame;
62  import org.orekit.time.AbsoluteDate;
63  import org.orekit.utils.AngularCoordinates;
64  import org.orekit.utils.PVCoordinates;
65  import org.orekit.utils.units.Unit;
66  
67  public class NdmTestUtils {
68  
69      private static final int ULPS = 207;
70  
71      public static void checkEquals(final NdmConstituent<?, ?> original, final NdmConstituent<?, ?> rebuilt) {
72          checkContainer(original.getHeader(), rebuilt.getHeader());
73          Assertions.assertEquals(original.getSegments().size(), rebuilt.getSegments().size());
74          for (int i = 0; i < original.getSegments().size(); ++i) {
75              checkContainer(original.getSegments().get(i).getMetadata(), rebuilt.getSegments().get(i).getMetadata());
76              checkContainer(original.getSegments().get(i).getData(), rebuilt.getSegments().get(i).getData());
77          }
78      }
79  
80      public static boolean recurseCheck(final Object original, final Object rebuilt) {
81  
82          if (original == null) {
83              return rebuilt == null;
84          } else if (original instanceof String    ||
85                     original instanceof Boolean   ||
86                     original instanceof Character ||
87                     original instanceof Integer   ||
88                     original instanceof Enum) {
89              return original.equals(rebuilt);
90          } else if (original instanceof Double) {
91              checkDouble((Double) original, (Double) rebuilt);
92              return true;
93          } else if (original instanceof int[]) {
94              checkIntArray((int[]) original, (int[]) rebuilt);
95              return true;
96          } else if (original instanceof double[]) {
97              checkDoubleArray((double[]) original, (double[]) rebuilt);
98              return true;
99          } else if (original instanceof List) {
100             checkList((List<?>) original, (List<?>) rebuilt);
101             return true;
102         } else if (original instanceof Map) {
103             checkMap((Map<?, ?>) original, (Map<?, ?>) rebuilt);
104             return true;
105         } else if (original instanceof NdmConstituent            ||
106                    original instanceof Segment                   ||
107                    original instanceof Section                   ||
108                    original instanceof CommentsContainer         ||
109                    original instanceof ApmQuaternion             ||
110                    original instanceof AttitudeEndpoints         ||
111                    original instanceof OcmSatelliteEphemeris     ||
112                    original instanceof OemSatelliteEphemeris     ||
113                    original instanceof AemSatelliteEphemeris     ||
114                    original instanceof OrbitCovarianceHistory    ||
115                    original instanceof OrbitManeuverHistory      ||
116                    original instanceof TrajectoryState           ||
117                    original instanceof OrbitCovariance           ||
118                    original instanceof OrbitManeuver             ||
119                    original instanceof Observation               ||
120                    original instanceof SpacecraftBodyFrame       ||
121                    original instanceof PVCoordinates             ||
122                    original instanceof AngularCoordinates        ||
123                    original instanceof CdmRelativeMetadata       ||
124                    original instanceof AttitudeStateHistory      ||
125                    original instanceof AttitudeState             ||
126                    original instanceof AttitudeCovarianceHistory ||
127                    original instanceof AttitudeCovariance        ||
128                    original instanceof AcmSatelliteEphemeris) {
129             checkContainer(original, rebuilt);
130             return true;
131         } else if (original instanceof FrameFacade) {
132             checkFrameFacade((FrameFacade) original, (FrameFacade) rebuilt);
133             return true;
134         } else if (original instanceof BodyFacade) {
135             checkBodyFacade((BodyFacade) original, (BodyFacade) rebuilt);
136             return true;
137         } else if (original instanceof OdMethodFacade) {
138             checkOdMethodFacade((OdMethodFacade) original, (OdMethodFacade) rebuilt);
139             return true;
140         } else if (original instanceof PocMethodFacade) {
141             checkPocMethodFacade((PocMethodFacade) original, (PocMethodFacade) rebuilt);
142             return true;
143         } else if (original instanceof TrajectoryStateHistory) {
144             checkOrbitStateHistory((TrajectoryStateHistory) original, (TrajectoryStateHistory) rebuilt);
145             return true;
146         } else if (original instanceof DataContext) {
147             return true;
148         } else if (original instanceof Frame) {
149             checkFrame((Frame) original, (Frame) rebuilt);
150             return true;
151         } else if (original instanceof AbsoluteDate) {
152             checkDate((AbsoluteDate) original, (AbsoluteDate) rebuilt);
153             return true;
154         } else if (original instanceof Unit) {
155             checkUnit((Unit) original, (Unit) rebuilt);
156             return true;
157         } else if (original instanceof Vector3D) {
158             checkVector3D((Vector3D) original, (Vector3D) rebuilt);
159             return true;
160         } else if (original instanceof Quaternion) {
161             checkQuaternion((Quaternion) original, (Quaternion) rebuilt);
162             return true;
163         } else if (original instanceof RealMatrix) {
164             checkRealMatrix((RealMatrix) original, (RealMatrix) rebuilt);
165             return true;
166         } else if (original instanceof Rotation) {
167             checkRotation((Rotation) original, (Rotation) rebuilt);
168             return true;
169         } else {
170             return false;
171         }
172 
173     }
174 
175     public static void checkContainer(final Object original, final Object rebuilt) {
176         Assertions.assertEquals(original.getClass(), rebuilt.getClass());
177         final Class<?> cls = original.getClass();
178         Stream.of(cls.getMethods()).
179         filter(m -> m.getName().startsWith("get")              &&
180                     !m.getName().equals("getClass")            &&
181                     !m.getName().equals("getPropagator")       &&
182                     !m.getName().equals("getLaunchYear")       &&
183                     !m.getName().equals("getLaunchNumber")     &&
184                     !m.getName().equals("getLaunchPiece")      &&
185                     !m.getName().equals("getAttitudeProvider") &&
186                     m.getParameterCount() == 0).
187         forEach(getter -> {
188             try {
189                 Assertions.assertTrue(recurseCheck(getter.invoke(original), getter.invoke(rebuilt)));
190             } catch (InvocationTargetException e) {
191                 if (!((getter.getName().equals("getFrame") ||
192                        getter.getName().equals("getReferenceFrame") ||
193                        getter.getName().equals("getInertialFrame") ||
194                        getter.getName().equals("getAngularCoordinates")) &&
195                       e.getCause() instanceof OrekitException &&
196                       (((OrekitException) e.getCause()).getSpecifier() == OrekitMessages.NO_DATA_LOADED_FOR_CELESTIAL_BODY ||
197                        ((OrekitException) e.getCause()).getSpecifier() == OrekitMessages.CCSDS_INVALID_FRAME ||
198                        ((OrekitException) e.getCause()).getSpecifier() == OrekitMessages.CCSDS_UNSUPPORTED_ELEMENT_SET_TYPE))) {
199                     Assertions.fail(e.getCause().getLocalizedMessage());
200                 }
201             } catch (IllegalAccessException | IllegalArgumentException e) {
202                 Assertions.fail(e.getLocalizedMessage());
203             }
204         });
205     }
206 
207     public static void checkIntArray(final int[] original, final int[] rebuilt) {
208         Assertions.assertEquals(original.length, rebuilt.length);
209         for (int i = 0; i < original.length; ++i) {
210             Assertions.assertEquals(original[i], rebuilt[i]);
211         }
212     }
213 
214     public static void checkDoubleArray(final double[] original, final double[] rebuilt) {
215         Assertions.assertEquals(original.length, rebuilt.length);
216         for (int i = 0; i < original.length; ++i) {
217             Assertions.assertTrue(Precision.equalsIncludingNaN(original[i], rebuilt[i], 1));
218         }
219     }
220 
221     public static void checkList(final List<?> original, final List<?> rebuilt) {
222         Assertions.assertEquals(original.size(), rebuilt.size());
223         for (int i = 0; i < original.size(); ++i) {
224             Assertions.assertTrue(recurseCheck(original.get(i), rebuilt.get(i)));
225         }
226     }
227 
228     public static void checkMap(final Map<?, ?> original, final Map<?, ?> rebuilt) {
229         Assertions.assertEquals(original.size(), rebuilt.size());
230         for (final Map.Entry<?, ?> entry : original.entrySet()) {
231             Assertions.assertTrue(rebuilt.containsKey(entry.getKey()));
232             Assertions.assertTrue(recurseCheck(entry.getValue(), rebuilt.get(entry.getKey())));
233         }
234     }
235 
236     public static void checkFrameFacade(final FrameFacade original, final FrameFacade rebuilt) {
237         if (original.asFrame() == null) {
238             Assertions.assertNull(rebuilt.asFrame());
239         } else {
240             Assertions.assertEquals(original.asFrame().getName(),
241                                 rebuilt.asFrame().getName());
242         }
243         Assertions.assertEquals(original.asCelestialBodyFrame(),
244                             rebuilt.asCelestialBodyFrame());
245         if (original.asOrbitRelativeFrame() == null) {
246             Assertions.assertNull(rebuilt.asOrbitRelativeFrame());
247         } else {
248             Assertions.assertEquals(original.asOrbitRelativeFrame().getLofType(),
249                                 rebuilt.asOrbitRelativeFrame().getLofType());
250         }
251         if (original.asSpacecraftBodyFrame() == null) {
252             Assertions.assertNull(rebuilt.asSpacecraftBodyFrame());
253         } else {
254             Assertions.assertEquals(original.asSpacecraftBodyFrame().getBaseEquipment(),
255                                 rebuilt.asSpacecraftBodyFrame().getBaseEquipment());
256             Assertions.assertEquals(original.asSpacecraftBodyFrame().getLabel(),
257                                 rebuilt.asSpacecraftBodyFrame().getLabel());
258         }
259         Assertions.assertEquals(original.getName(), rebuilt.getName());
260     }
261 
262     public static void checkBodyFacade(final BodyFacade original, final BodyFacade rebuilt) {
263         if (original.getBody() == null) {
264             Assertions.assertNull(rebuilt.getBody());
265         } else {
266             Assertions.assertEquals(original.getBody().getName(),
267                                 rebuilt.getBody().getName());
268         }
269         Assertions.assertEquals(original.getName().toUpperCase(Locale.US), rebuilt.getName().toUpperCase(Locale.US));
270     }
271 
272     public static void checkOdMethodFacade(final OdMethodFacade original, final OdMethodFacade rebuilt) {
273         Assertions.assertEquals(original.getName(), rebuilt.getName());
274         Assertions.assertEquals(original.getType(), rebuilt.getType());
275         Assertions.assertEquals(original.getTool(), rebuilt.getTool());
276     }
277 
278     public static void checkPocMethodFacade(final PocMethodFacade original, final PocMethodFacade rebuilt) {
279         Assertions.assertEquals(original.getName(), rebuilt.getName());
280         Assertions.assertEquals(original.getType(), rebuilt.getType());
281     }
282 
283     public static void checkOrbitStateHistory(final TrajectoryStateHistory original, final TrajectoryStateHistory rebuilt) {
284         // we don't use checkContainer here because the history getters are redundant
285         // with embedded metadata and states, and because the getFrame() method
286         // that would be called automatically may throw an exception
287         // so we just jump down to metadata and states
288         Assertions.assertTrue(recurseCheck(original.getMetadata(), rebuilt.getMetadata()));
289         checkList(original.getTrajectoryStates(), rebuilt.getTrajectoryStates());
290     }
291 
292     public static void checkDate(final AbsoluteDate original, final AbsoluteDate rebuilt) {
293         Assertions.assertEquals(0.0, rebuilt.durationFrom(original), 4.0e-12);
294     }
295 
296     public static void checkUnit(final Unit original, final Unit rebuilt) {
297         Assertions.assertTrue(Precision.equals(original.getScale(), rebuilt.getScale(), 1));
298         Assertions.assertTrue(rebuilt.sameDimension(original));
299     }
300 
301     public static void checkFrame(final Frame original, final Frame rebuilt) {
302         Assertions.assertEquals(original.getName(), rebuilt.getName());
303     }
304 
305     public static void checkVector3D(final Vector3D original, final Vector3D rebuilt) {
306         double eps = ULPS * FastMath.ulp(FastMath.max(1.0, original.getNorm()));
307         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getX(), rebuilt.getX(), eps));
308         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getY(), rebuilt.getY(), eps));
309         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getZ(), rebuilt.getZ(), eps));
310     }
311 
312     public static void checkQuaternion(final Quaternion original, final Quaternion rebuilt) {
313         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getQ0(), rebuilt.getQ0(), ULPS));
314         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getQ1(), rebuilt.getQ1(), ULPS));
315         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getQ2(), rebuilt.getQ2(), ULPS));
316         Assertions.assertTrue(Precision.equalsIncludingNaN(original.getQ3(), rebuilt.getQ3(), ULPS));
317     }
318 
319     public static void checkRealMatrix(final RealMatrix original, final RealMatrix rebuilt) {
320         Assertions.assertEquals(original.getRowDimension(), rebuilt.getRowDimension());
321         Assertions.assertEquals(original.getColumnDimension(), rebuilt.getColumnDimension());
322         for (int i = 0; i < original.getRowDimension(); ++i) {
323             for (int j = 0; j < original.getColumnDimension(); ++j) {
324                 Assertions.assertTrue(Precision.equalsIncludingNaN(original.getEntry(i, j), rebuilt.getEntry(i, j), ULPS));
325             }
326         }
327     }
328 
329     public static void checkRotation(final Rotation original, final Rotation rebuilt) {
330         Assertions.assertEquals(0.0, Rotation.distance(original, rebuilt), 1.0e-12);
331     }
332 
333     public static void checkDouble(final Double original, final Double rebuilt) {
334         Assertions.assertTrue(Precision.equalsIncludingNaN(original.doubleValue(), rebuilt.doubleValue(), ULPS));
335     }
336 
337 
338 }