1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.ccsds.definitions;
18  
19  import org.hamcrest.CoreMatchers;
20  import org.hamcrest.MatcherAssert;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.util.Binary64;
24  import org.hipparchus.util.Binary64Field;
25  import org.junit.jupiter.api.Assertions;
26  import org.junit.jupiter.api.BeforeEach;
27  import org.junit.jupiter.api.Test;
28  import org.orekit.Utils;
29  import org.orekit.bodies.CelestialBodyFactory;
30  import org.orekit.bodies.GeodeticPoint;
31  import org.orekit.bodies.OneAxisEllipsoid;
32  import org.orekit.data.DataContext;
33  import org.orekit.errors.OrekitException;
34  import org.orekit.errors.OrekitMessages;
35  import org.orekit.frames.Frame;
36  import org.orekit.frames.FramesFactory;
37  import org.orekit.frames.ITRFVersion;
38  import org.orekit.frames.TopocentricFrame;
39  import org.orekit.frames.Transform;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.time.FieldAbsoluteDate;
42  import org.orekit.utils.Constants;
43  import org.orekit.utils.IERSConventions;
44  
45  
46  public class CelestialBodyFrameTest {
47  
48      /** Latest ITRF body frame to which the ITRF enum should correspond. */
49      private final CelestialBodyFrame LATEST_ITRF_FRAME = CelestialBodyFrame.ITRF2020;
50  
51      /**
52       * Check mapping frames to CCSDS frames.
53       */
54      @Test
55      public void testMap() {
56          // action + verify
57          // check all non-LOF frames created by OEMParser
58          for (CelestialBodyFrame ccsdsFrame : CelestialBodyFrame.values()) {
59              Frame frame = ccsdsFrame.getFrame(IERSConventions.IERS_2010, true, DataContext.getDefault());
60              CelestialBodyFrame actual = CelestialBodyFrame.map(frame);
61              if (ccsdsFrame == CelestialBodyFrame.J2000) {
62                  // CCSDS allows both J2000 and EME2000 names
63                  // Orekit chose to use EME2000 when guessing name from frame instance
64                  MatcherAssert.assertThat(actual, CoreMatchers.is(CelestialBodyFrame.EME2000));
65              } else  if (ccsdsFrame == CelestialBodyFrame.TDR) {
66                  // CCSDS allows both GTOD (in ADM section A3) and
67                  // TDR (in ODM table 5-3 and section A2) names
68                  // Orekit chose to use GTOD when guessing name from frame instance
69                  MatcherAssert.assertThat(actual, CoreMatchers.is(CelestialBodyFrame.GTOD));
70              }
71              else if (ccsdsFrame == CelestialBodyFrame.ITRF) {
72                  Assertions.assertEquals(LATEST_ITRF_FRAME, actual);
73              }
74              else {
75                  MatcherAssert.assertThat(actual, CoreMatchers.is(ccsdsFrame));
76              }
77          }
78  
79          // check common Orekit frames from FramesFactory
80          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getGCRF()),
81                                   CoreMatchers.is(CelestialBodyFrame.GCRF));
82          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getEME2000()),
83                                   CoreMatchers.is(CelestialBodyFrame.EME2000));
84          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getITRFEquinox(IERSConventions.IERS_2010, true)),
85                                   CoreMatchers.is(CelestialBodyFrame.GRC));
86          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getICRF()),
87                                   CoreMatchers.is(CelestialBodyFrame.ICRF));
88          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getITRF(IERSConventions.IERS_2010, true)),
89                                   CoreMatchers.is(CelestialBodyFrame.ITRF2014));
90          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getGTOD(true)),
91                                   CoreMatchers.is(CelestialBodyFrame.GTOD));
92          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getTEME()),
93                                   CoreMatchers.is(CelestialBodyFrame.TEME));
94          MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getTOD(true)),
95                                   CoreMatchers.is(CelestialBodyFrame.TOD));
96  
97          // check that guessed name loses the IERS conventions and simpleEOP flag
98          for (ITRFVersion version : ITRFVersion.values()) {
99              final String name = version.getName().replaceAll("-", "");
100             for (final IERSConventions conventions : IERSConventions.values()) {
101                 MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getITRF(version, conventions, true)).name(),
102                                          CoreMatchers.is(name));
103                 MatcherAssert.assertThat(CelestialBodyFrame.map(FramesFactory.getITRF(version, conventions, false)).name(),
104                                          CoreMatchers.is(name));
105             }
106         }
107 
108         // check other names in Annex A
109         MatcherAssert.assertThat(
110                 CelestialBodyFrame.map(CelestialBodyFactory.getMars().getInertiallyOrientedFrame()),
111                 CoreMatchers.is(CelestialBodyFrame.MCI));
112         MatcherAssert.assertThat(CelestialBodyFrame.map(CelestialBodyFactory.getSolarSystemBarycenter().
113                                  getInertiallyOrientedFrame()),
114                                  CoreMatchers.is(CelestialBodyFrame.ICRF));
115         // check some special CCSDS frames
116         ModifiedFrame frame = new ModifiedFrame(FramesFactory.getEME2000(),
117                                                           CelestialBodyFrame.EME2000,
118                                                           CelestialBodyFactory.getMars(), "MARS");
119         MatcherAssert.assertThat(CelestialBodyFrame.map(frame), CoreMatchers.is(CelestialBodyFrame.EME2000));
120         Vector3D v = frame.getTransformProvider().getTransform(AbsoluteDate.J2000_EPOCH).getTranslation();
121         FieldVector3D<Binary64> v64 = frame.getTransformProvider().getTransform(FieldAbsoluteDate.getJ2000Epoch(Binary64Field.getInstance())).getTranslation();
122         Assertions.assertEquals(0.0, FieldVector3D.distance(v64, v).getReal(), 1.0e-10);
123 
124         // check unknown frame
125         try {
126             Frame topo = new TopocentricFrame(new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
127                                                                    Constants.WGS84_EARTH_FLATTENING,
128                                                                    FramesFactory.getITRF(IERSConventions.IERS_2010, true)),
129                                               new GeodeticPoint(1.2, 2.3, 45.6),
130                             "dummy");
131             CelestialBodyFrame.map(topo);
132             Assertions.fail("an exception should have been thrown");
133         } catch (OrekitException oe) {
134             Assertions.assertEquals(OrekitMessages.CCSDS_INVALID_FRAME, oe.getSpecifier());
135             Assertions.assertEquals("dummy", oe.getParts()[0]);
136         }
137 
138         // check a fake ICRF
139         Frame fakeICRF = new Frame(FramesFactory.getGCRF(), Transform.IDENTITY,
140                                    CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER + "/inertial");
141         MatcherAssert.assertThat(CelestialBodyFrame.map(fakeICRF), CoreMatchers.is(CelestialBodyFrame.ICRF));
142     }
143 
144     @Test
145     public void testNoConventions() {
146         for (final CelestialBodyFrame cbf : CelestialBodyFrame.values()) {
147             if (cbf == CelestialBodyFrame.EME2000 || cbf == CelestialBodyFrame.J2000 ||
148                 cbf == CelestialBodyFrame.GCRF    || cbf == CelestialBodyFrame.ICRF ||
149                 cbf == CelestialBodyFrame.MCI     || cbf == CelestialBodyFrame.TEME) {
150                 Assertions.assertNotNull(cbf.getFrame(null, false, DataContext.getDefault()));
151             } else {
152                 try {
153                     cbf.getFrame(null, false, DataContext.getDefault());
154                     Assertions.fail("an exception should have been thrown");
155                 } catch (OrekitException oe) {
156                     Assertions.assertEquals(OrekitMessages.CCSDS_UNKNOWN_CONVENTIONS, oe.getSpecifier());
157                 }
158             }
159         }
160     }
161 
162     @Test
163     public void testParse() {
164         Assertions.assertEquals(CelestialBodyFrame.EME2000, CelestialBodyFrame.parse("EME2000"));
165         Assertions.assertEquals(CelestialBodyFrame.ITRF2014, CelestialBodyFrame.parse("ITRF2014"));
166         Assertions.assertEquals(CelestialBodyFrame.ITRF1997, CelestialBodyFrame.parse("ITRF97"));
167         Assertions.assertEquals(CelestialBodyFrame.ITRF, CelestialBodyFrame.parse("ITRF"));
168         try {
169             Assertions.assertEquals(CelestialBodyFrame.EME2000, CelestialBodyFrame.parse("ITRF00"));
170             Assertions.fail("an exception should have been thrown");
171         } catch (IllegalArgumentException iae) {
172             Assertions.assertTrue(iae.getMessage().contains("ITRF00"));
173         }
174     }
175 
176     /**
177      * Check guessing names.
178      */
179     @Test
180     public void testGuessFrame() {
181 
182         Frame itrf89 = FramesFactory.getITRF(ITRFVersion.ITRF_1989, IERSConventions.IERS_1996, true);
183         Assertions.assertEquals("ITRF1989", CelestialBodyFrame.guessFrame(itrf89));
184 
185         Frame topo = new TopocentricFrame(new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
186                                                                Constants.WGS84_EARTH_FLATTENING,
187                                                                FramesFactory.getITRF(IERSConventions.IERS_2010, true)),
188                                           new GeodeticPoint(1.2, 2.3, 45.6),
189                         "dummy");
190         Assertions.assertEquals("dummy", CelestialBodyFrame.guessFrame(topo));
191     }
192 
193     @BeforeEach
194     public void setUp() {
195         Utils.setDataRoot("regular-data");
196     }
197 
198 }