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