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.propagation.numerical;
18  
19  import java.lang.reflect.InvocationTargetException;
20  import java.lang.reflect.Method;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.Field;
24  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
27  import org.hipparchus.util.Decimal64Field;
28  import org.hipparchus.util.Precision;
29  import org.junit.Assert;
30  import org.junit.BeforeClass;
31  import org.junit.Test;
32  import org.orekit.Utils;
33  import org.orekit.frames.Frame;
34  import org.orekit.frames.FramesFactory;
35  import org.orekit.frames.ITRFVersion;
36  import org.orekit.propagation.SpacecraftState;
37  import org.orekit.propagation.analytical.gnss.data.GLONASSEphemeris;
38  import org.orekit.propagation.analytical.gnss.data.GLONASSNavigationMessage;
39  import org.orekit.propagation.analytical.gnss.data.GLONASSOrbitalElements;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.time.DateComponents;
42  import org.orekit.time.GLONASSDate;
43  import org.orekit.time.TimeComponents;
44  import org.orekit.time.TimeScalesFactory;
45  import org.orekit.utils.IERSConventions;
46  import org.orekit.utils.PVCoordinates;
47  
48  public class GLONASSNumericalPropagatorTest {
49  
50      private static GLONASSEphemeris ephemeris;
51  
52      @BeforeClass
53      public static void setUpBeforeClass() {
54          Utils.setDataRoot("regular-data");
55          // Reference values for validation are given into Glonass Interface Control Document v1.0 2016
56          ephemeris = new GLONASSEphemeris(5, 251, 11700,
57                                           7003008.789,
58                                           783.5417,
59                                           0.0,
60                                           -12206626.953,
61                                           2804.2530,
62                                           0.0,
63                                           21280765.625,
64                                           1352.5150,
65                                           0.0);
66      }
67  
68      @Test
69      public void testPerfectValues() {
70  
71          // 4th order Runge-Kutta
72          final ClassicalRungeKuttaIntegrator integrator = new ClassicalRungeKuttaIntegrator(10.);
73  
74          // Initialize the propagator
75          final GLONASSNumericalPropagator propagator = new GLONASSNumericalPropagatorBuilder(integrator, ephemeris, false).
76                          attitudeProvider(Utils.defaultLaw()).
77                          mass(1521.0).
78                          eci(FramesFactory.getEME2000()).
79                          build();
80  
81          // Target date
82          final AbsoluteDate target = new AbsoluteDate(new DateComponents(2012, 9, 7),
83                                                       new TimeComponents(12300),
84                                                       TimeScalesFactory.getGLONASS());
85  
86          // Initial verifications
87          final GLONASSOrbitalElements poe = propagator.getGLONASSOrbitalElements();
88          Assert.assertEquals(0.0, poe.getXDotDot(), Precision.SAFE_MIN);
89          Assert.assertEquals(0.0, poe.getYDotDot(), Precision.SAFE_MIN);
90          Assert.assertEquals(0.0, poe.getZDotDot(), Precision.SAFE_MIN);
91          Assert.assertEquals(5,   poe.getN4());
92          Assert.assertEquals(251, poe.getNa());
93  
94          // Propagation
95          final SpacecraftState finalState = propagator.propagate(target);
96          final PVCoordinates pvFinal = finalState.getPVCoordinates(FramesFactory.getPZ9011(IERSConventions.IERS_2010, true));
97  
98          // Expected outputs in PZ90.11 frame
99          final Vector3D expectedPosition = new Vector3D(7523174.819, -10506961.965, 21999239.413);
100         final Vector3D expectedVelocity = new Vector3D(950.126007, 2855.687825, 1040.679862);
101 
102         // Computed outputs
103         final Vector3D computedPosition = pvFinal.getPosition();
104         final Vector3D computedVelocity = pvFinal.getVelocity();
105 
106         Assert.assertEquals(0.0, computedPosition.distance(expectedPosition), 1.1e-3);
107         Assert.assertEquals(0.0, computedVelocity.distance(expectedVelocity), 3.3e-6);
108     }
109 
110     @Test
111     public void testFromITRF2008ToPZ90() {
112         // Reference for the test
113         // "PARAMETRY ZEMLI 1990" (PZ-90.11) Reference Document
114         //  MILITARY TOPOGRAPHIC DEPARTMENT OF THE GENERAL STAFF OF ARMED FORCES OF THE RUSSIAN FEDERATION, Moscow, 2014" 
115 
116         // Position in ITRF-2008
117         final Vector3D itrf2008P = new Vector3D(2845455.9753, 2160954.3073, 5265993.2656);
118 
119         // Ref position in PZ-90.11
120         final Vector3D refPZ90   = new Vector3D(2845455.9772, 2160954.3078, 5265993.2664);
121 
122         // Recomputed position in PZ-90.11
123         final Frame pz90 = FramesFactory.getPZ9011(IERSConventions.IERS_2010, true);
124         final Frame itrf2008 = FramesFactory.getITRF(ITRFVersion.ITRF_2008, IERSConventions.IERS_2010, true);
125         final Vector3D comPZ90 = itrf2008.getTransformTo(pz90, new AbsoluteDate(2010, 1, 1, 12, 0, 0, TimeScalesFactory.getTT())).transformPosition(itrf2008P);
126 
127         // Check
128         Assert.assertEquals(refPZ90.getX(), comPZ90.getX(), 1.0e-4);
129         Assert.assertEquals(refPZ90.getY(), comPZ90.getY(), 1.0e-4);
130         Assert.assertEquals(refPZ90.getZ(), comPZ90.getZ(), 1.0e-4);
131     }
132 
133     @Test
134     public void testFromITRF2008ToPZ90Field() {
135         doTestFromITRF2008ToPZ90Field(Decimal64Field.getInstance());
136     }
137 
138     private <T extends CalculusFieldElement<T>> void doTestFromITRF2008ToPZ90Field(final Field<T> field)  {
139         // Reference for the test
140         // "PARAMETRY ZEMLI 1990" (PZ-90.11) Reference Document
141         //  MILITARY TOPOGRAPHIC DEPARTMENT OF THE GENERAL STAFF OF ARMED FORCES OF THE RUSSIAN FEDERATION, Moscow, 2014" 
142 
143         // Position in ITRF-2008
144         final FieldVector3D<T> itrf2008P = new FieldVector3D<>(field,
145                         new Vector3D(2845455.9753, 2160954.3073, 5265993.2656));
146 
147         // Ref position in PZ-90.11
148         final FieldVector3D<T> refPZ90   = new FieldVector3D<>(field,
149                         new Vector3D(2845455.9772, 2160954.3078, 5265993.2664));
150 
151         // Recomputed position in PZ-90.11
152         final Frame pz90 = FramesFactory.getPZ9011(IERSConventions.IERS_2010, true);
153         final Frame itrf2008 = FramesFactory.getITRF(ITRFVersion.ITRF_2008, IERSConventions.IERS_2010, true);
154         final FieldVector3D<T> comPZ90 = itrf2008.getTransformTo(pz90, new AbsoluteDate(2010, 1, 1, 12, 0, 0, TimeScalesFactory.getTT())).transformPosition(itrf2008P);
155 
156         // Check
157         Assert.assertEquals(refPZ90.getX().getReal(), comPZ90.getX().getReal(), 1.0e-4);
158         Assert.assertEquals(refPZ90.getY().getReal(), comPZ90.getY().getReal(), 1.0e-4);
159         Assert.assertEquals(refPZ90.getZ().getReal(), comPZ90.getZ().getReal(), 1.0e-4);
160     }
161 
162     @Test
163     public void testPosition() {
164         // Frames
165         final Frame pz90 = FramesFactory.getPZ9011(IERSConventions.IERS_2010, true);
166         final Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
167         // Initial GLONASS orbital elements (Ref: IGS)
168         final GLONASSNavigationMessage ge = new GLONASSNavigationMessage();
169         ge.setDate(new GLONASSDate(1342, 4, 45900).getDate());
170         ge.setX(-1.0705924E7);
171         ge.setXDot(2052.252685546875);
172         ge.setXDotDot(0.0);
173         ge.setY(-1.5225037E7);
174         ge.setYDot(1229.055419921875);
175         ge.setYDotDot(-2.7939677238464355E-6);
176         ge.setZ(-1.7389698E7);
177         ge.setZDot(-2338.376953125);
178         ge.setZDotDot(1.862645149230957E-6);
179         // Date of the GLONASS orbital elements, 3 Septembre 2019 at 09:45:00 UTC
180         final AbsoluteDate target = ge.getDate().shiftedBy(-18.0);
181         // 4th order Runge-Kutta
182         final ClassicalRungeKuttaIntegrator integrator = new ClassicalRungeKuttaIntegrator(1.);
183         // Initialize the propagator
184         final GLONASSNumericalPropagator propagator = new GLONASSNumericalPropagatorBuilder(integrator, ge, true).build();
185         // Compute the PV coordinates at the date of the GLONASS orbital elements
186         final SpacecraftState finalState = propagator.propagate(target);
187         final PVCoordinates pvInPZ90 = finalState.getPVCoordinates(pz90);
188         final PVCoordinates pvInITRF = pz90.getTransformTo(itrf, target).transformPVCoordinates(pvInPZ90);
189         // Computed position
190         final Vector3D computedPos = pvInITRF.getPosition();
191         // Expected position (reference from IGS file igv20692_06.sp3)
192         final Vector3D expectedPos = new Vector3D(-10742801.600, -15247162.619, -17347541.633);
193         // Verify
194         Assert.assertEquals(0., Vector3D.distance(expectedPos, computedPos), 2.8);
195     }
196 
197     @Test
198     public void testIssue544() {
199         try {
200             Method eMeSinEM = GLONASSNumericalPropagator.class.getDeclaredMethod("eMeSinE",
201                                                                                  Double.TYPE, Double.TYPE);
202             eMeSinEM.setAccessible(true);
203             final double value = (double) eMeSinEM.invoke(null, Double.NaN, Double.NaN);
204             // Verify that an infinite loop did not occur
205             Assert.assertTrue(Double.isNaN(value));
206         } catch (NoSuchMethodException e) {
207             e.printStackTrace();
208         } catch (SecurityException e) {
209             e.printStackTrace();
210         } catch (IllegalAccessException e) {
211             e.printStackTrace();
212         } catch (IllegalArgumentException e) {
213             e.printStackTrace();
214         } catch (InvocationTargetException e) {
215             e.printStackTrace();
216         }
217     }
218 
219 }