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.frames;
18  
19  
20  import org.hipparchus.geometry.euclidean.threed.Rotation;
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.util.FastMath;
23  import org.hipparchus.util.MathUtils;
24  import org.junit.Assert;
25  import org.junit.Before;
26  import org.junit.Test;
27  import org.orekit.Utils;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.DateComponents;
30  import org.orekit.time.TTScale;
31  import org.orekit.time.TimeComponents;
32  import org.orekit.time.TimeScale;
33  import org.orekit.time.TimeScalesFactory;
34  import org.orekit.time.UT1Scale;
35  import org.orekit.utils.Constants;
36  import org.orekit.utils.IERSConventions;
37  import org.orekit.utils.PVCoordinates;
38  
39  public class ITRFProviderTest {
40  
41      @Test
42      public void testTidalEffects() {
43  
44          final Frame itrfWith    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
45          final Frame itrfWithout = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
46          final AbsoluteDate date0 = new AbsoluteDate(2007, 10, 20, TimeScalesFactory.getUTC());
47  
48          double minCorrection = Double.POSITIVE_INFINITY;
49          double maxCorrection = Double.NEGATIVE_INFINITY;
50          for (double dt = 0; dt < 3 * Constants.JULIAN_DAY; dt += 60) {
51              final AbsoluteDate date = date0.shiftedBy(dt);
52              final Transform t = itrfWith.getTransformTo(itrfWithout, date);
53              Assert.assertEquals(0, t.getTranslation().getNorm(), 1.0e-15);
54              final double milliarcSeconds = FastMath.toDegrees(t.getRotation().getAngle()) * 3600000.0;
55              minCorrection = FastMath.min(minCorrection, milliarcSeconds);
56              maxCorrection = FastMath.max(maxCorrection, milliarcSeconds);
57          }
58  
59          Assert.assertEquals(0.064, minCorrection, 0.001);
60          Assert.assertEquals(0.613, maxCorrection, 0.001);
61  
62      }
63  
64      @Test
65      public void testAASReferenceLEO() {
66  
67          // this reference test has been extracted from the following paper:
68          // Implementation Issues Surrounding the New IAU Reference Systems for Astrodynamics
69          // David A. Vallado, John H. Seago, P. Kenneth Seidelmann
70          // http://www.centerforspace.com/downloads/files/pubs/AAS-06-134.pdf
71          // Reference position & velocity from : "Fundamentals of Astrodynamics and Applications", Third edition, David A. Vallado
72          Utils.setLoaders(IERSConventions.IERS_2010,
73                           Utils.buildEOPList(IERSConventions.IERS_2010, ITRFVersion.ITRF_2008, new double[][] {
74                               { 53098, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
75                               { 53099, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
76                               { 53100, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
77                               { 53101, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
78                               { 53102, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
79                               { 53103, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
80                               { 53104, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 },
81                               { 53105, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 }
82                           }));
83          AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 04, 06),
84                                             new TimeComponents(07, 51, 28.386009),
85                                             TimeScalesFactory.getUTC());
86  
87          // Positions LEO
88          Frame itrfA = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
89          PVCoordinates pvITRF =
90              new PVCoordinates(new Vector3D(-1033479.3830, 7901295.2754, 6380356.5958),
91                                new Vector3D(-3225.636520, -2872.451450, 5531.924446));
92  
93          // Reference coordinates
94          PVCoordinates pvGcrfIau2000A =
95              new PVCoordinates(new Vector3D(5102508.9579, 6123011.4038, 6378136.9252),
96                                new Vector3D(-4743.220156, 790.536497, 5533.755728));
97          checkPV(pvGcrfIau2000A,
98                  itrfA.getTransformTo(FramesFactory.getGCRF(), t0).transformPVCoordinates(pvITRF),
99                  0.0192, 2.15e-5);
100 
101         PVCoordinates pvEME2000EqA =
102             new PVCoordinates(new Vector3D(5102509.0383, 6123011.9758, 6378136.3118),
103                               new Vector3D(-4743.219766, 790.536344, 5533.756084));
104         checkPV(pvEME2000EqA,
105                 itrfA.getTransformTo(FramesFactory.getEME2000(), t0).transformPVCoordinates(pvITRF),
106                 0.0191, 2.13e-5);
107 
108     }
109 
110     @Test
111     public void testAASReferenceGEO() {
112 
113         // this reference test has been extracted from the following paper:
114         // Implementation Issues Surrounding the New IAU Reference Systems for Astrodynamics
115         // David A. Vallado, John H. Seago, P. Kenneth Seidelmann
116         // http://www.centerforspace.com/downloads/files/pubs/AAS-06-134.pdf
117         Utils.setLoaders(IERSConventions.IERS_2010,
118                          Utils.buildEOPList(IERSConventions.IERS_2010, ITRFVersion.ITRF_2008, new double[][] {
119                              { 53153, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
120                              { 53154, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
121                              { 53155, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
122                              { 53156, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
123                              { 53157, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
124                              { 53158, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
125                              { 53159, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 },
126                              { 53160, -0.4709050,  0.0000000, -0.083853,  0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 }
127                          }));
128 
129         AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 06, 01),
130                                            TimeComponents.H00,
131                                            TimeScalesFactory.getUTC());
132 
133         //  Positions GEO
134         Frame itrfA = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
135         PVCoordinates pvITRF =
136             new PVCoordinates(new Vector3D(24796919.2915, -34115870.9234, 10226.0621),
137                               new Vector3D(-0.979178, -1.476538, -0.928776));
138 
139         PVCoordinates pvGCRFiau2000A =
140             new PVCoordinates(new Vector3D(-40588150.3617, -11462167.0397, 27143.1974),
141                               new Vector3D(834.787458, -2958.305691, -1.172993));
142         checkPV(pvGCRFiau2000A,
143                 itrfA.getTransformTo(FramesFactory.getGCRF(), t0).transformPVCoordinates(pvITRF),
144                 0.0806, 1.03e-4);
145 
146         PVCoordinates pvEME2000EqA =
147             new PVCoordinates(new Vector3D(-40588149.5482, -11462169.9118, 27146.8462),
148                               new Vector3D(834.787667, -2958.305632, -1.172963));
149         checkPV(pvEME2000EqA,
150                 itrfA.getTransformTo(FramesFactory.getEME2000(), t0).transformPVCoordinates(pvITRF),
151                 0.0806, 1.04e-4);
152 
153     }
154 
155     @Test
156     public void testAASReferenceGEODX0DY0() {
157 
158         // this reference test has been extracted from the following paper:
159         // Implementation Issues Surrounding the New IAU Reference Systems for Astrodynamics
160         // David A. Vallado, John H. Seago, P. Kenneth Seidelmann
161         // http://www.centerforspace.com/downloads/files/pubs/AAS-06-134.pdf
162         Utils.setLoaders(IERSConventions.IERS_2010,
163                          Utils.buildEOPList(IERSConventions.IERS_2010, ITRFVersion.ITRF_2008, new double[][] {
164                              { 53153, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
165                              { 53154, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
166                              { 53155, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
167                              { 53156, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
168                              { 53157, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
169                              { 53158, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
170                              { 53159, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 },
171                              { 53160, -0.4709050,  0.0000000, -0.083853,  0.467217, 0.0, 0.0, 0.0, 0.0 }
172                          }));
173 
174         AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 06, 01),
175                                            TimeComponents.H00,
176                                            TimeScalesFactory.getUTC());
177 
178         //  Positions GEO
179         Frame itrfA = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
180         PVCoordinates pvITRF =
181             new PVCoordinates(new Vector3D(24796919.2915, -34115870.9234, 10226.0621),
182                               new Vector3D(-0.979178, -1.476538, -0.928776));
183 
184         PVCoordinates pvGCRFdx0dy0 =
185             new PVCoordinates(new Vector3D(-40588150.3643, -11462167.0302, 27143.1979),
186                               new Vector3D(834.787457, -2958.305691, -1.172993));
187         checkPV(pvGCRFdx0dy0,
188                 itrfA.getTransformTo(FramesFactory.getGCRF(), t0).transformPVCoordinates(pvITRF),
189                 0.0505, 1.06e-4);
190 
191         PVCoordinates pvEME2000EqA =
192             new PVCoordinates(new Vector3D(-40588149.5482, -11462169.9118, 27146.8462),
193                               new Vector3D(834.787667, -2958.305632, -1.172963));
194         checkPV(pvEME2000EqA,
195                 itrfA.getTransformTo(FramesFactory.getEME2000(), t0).transformPVCoordinates(pvITRF),
196                 0.0603, 1.07e-4);
197 
198     }
199 
200     @Test
201     public void testSofaCookbook() {
202 
203         // SOFA cookbook test case:
204         //     date       2007 April 05, 12h00m00s.0 UTC
205         //     xp         +0′′.0349282
206         //     yp         +0′′.4833163
207         //     UT1 − UTC  -0s.072073685
208         //     dψ 1980    -0′′.0550655
209         //     dε 1980    -0′′.0063580
210         //     dX 2000    +0′′.0001725
211         //     dY 2000    -0′′.0002650
212         //     dX 2006    +0′′.0001750
213         //     dY 2006    -0′′.0002259
214 
215         Utils.setLoaders(IERSConventions.IERS_2010,
216                          Utils.buildEOPList(IERSConventions.IERS_2010, ITRFVersion.ITRF_2008, new double[][] {
217                              { 54192, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
218                              { 54193, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
219                              { 54194, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
220                              { 54195, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
221                              { 54196, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
222                              { 54197, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
223                              { 54198, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 },
224                              { 54199, -0.072073685,  1.4020, 0.0349282, 0.4833163, -Double.NaN, Double.NaN, 0.0001750, -0.0002259 }
225                          }));
226 
227         EOPHistory eopHistory = FramesFactory.getEOPHistory(IERSConventions.IERS_2010, true);
228 
229         TimeScale utc = TimeScalesFactory.getUTC();
230         TTScale tt    = TimeScalesFactory.getTT();
231         UT1Scale ut1  = TimeScalesFactory.getUT1(eopHistory);
232         Frame gcrf    = FramesFactory.getGCRF();
233         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
234         Frame gtod    = itrf.getParent();
235         Frame tod     = gtod.getParent();
236 
237         // time scales checks
238         AbsoluteDate date = new AbsoluteDate(new DateComponents(2007, 4, 5), TimeComponents.H12, utc);
239         Assert.assertEquals(0.50075444444444,
240                             date.getComponents(tt).getTime().getSecondsInUTCDay() / Constants.JULIAN_DAY,
241                             5.0e-15);
242         Assert.assertEquals(0.499999165813831,
243                             date.getComponents(ut1).getTime().getSecondsInUTCDay() / Constants.JULIAN_DAY,
244                             1.0e-15);
245 
246         // sidereal time check
247         double era = IERSConventions.IERS_2010.getEarthOrientationAngleFunction(ut1).value(date);
248         Assert.assertEquals(13.318492966097 * 3600 * 1.0e6,
249                             radToMicroAS(MathUtils.normalizeAngle(era, 0)),
250                             0.0022);
251 
252         // nutation/precession/bias matrix check
253         Rotation refNPB = new Rotation(new double[][] {
254             { +0.999999746339445, -0.000000005138721, -0.000712264730182 },
255             { -0.000000026475329, +0.999999999014975, -0.000044385242666 },
256             { +0.000712264729708, +0.000044385250265, +0.999999745354420 }
257         }, 1.0e-13);
258         Rotation npb = gcrf.getTransformTo(tod, date).getRotation();
259         Assert.assertEquals(0.0, radToMicroAS(Rotation.distance(refNPB, npb)), 0.31);
260 
261         // celestial to terrestrial frames matrix, without polar motion
262         Rotation refWithoutPolarMotion = new Rotation(new double[][] {
263             { +0.973104317573104, +0.230363826247808, -0.000703332818915 },
264             { -0.230363798804281, +0.973104570735550, +0.000120888549767 },
265             { +0.000712264729708, +0.000044385250265, +0.999999745354420 }
266         }, 1.0e-13);
267         Rotation withoutPM = gcrf.getTransformTo(gtod, date).getRotation();
268         Assert.assertEquals(0.0, radToMicroAS(Rotation.distance(refWithoutPolarMotion, withoutPM)), 0.31);
269 
270         // celestial to terrestrial frames matrix, with polar motion
271         Rotation refWithPolarMotion = new Rotation(new double[][] {
272             { +0.973104317697512, +0.230363826239227, -0.000703163482268 },
273             { -0.230363800456136, +0.973104570632777, +0.000118545366806 },
274             { +0.000711560162777, +0.000046626403835, +0.999999745754024 }
275         }, 1.0e-13);
276         Rotation withPM = gcrf.getTransformTo(itrf, date).getRotation();
277         Assert.assertEquals(0.0, radToMicroAS(Rotation.distance(refWithPolarMotion, withPM)), 0.31);
278 
279     }
280 
281     @Before
282     public void setUp() {
283         Utils.setDataRoot("compressed-data");
284     }
285 
286     private void checkPV(PVCoordinates reference, PVCoordinates result,
287                          double expectedPositionError, double expectedVelocityError) {
288 
289         Vector3D dP = result.getPosition().subtract(reference.getPosition());
290         Vector3D dV = result.getVelocity().subtract(reference.getVelocity());
291         Assert.assertEquals(expectedPositionError, dP.getNorm(), 0.01 * expectedPositionError);
292         Assert.assertEquals(expectedVelocityError, dV.getNorm(), 0.01 * expectedVelocityError);
293     }
294 
295     double radToMicroAS(double deltaRad) {
296         return deltaRad * 1.0e6 / Constants.ARC_SECONDS_TO_RADIANS;
297     }
298 
299 }