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.frames;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.util.Binary64Field;
24  import org.hipparchus.util.FastMath;
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.CR3BPFactory;
30  import org.orekit.bodies.CR3BPSystem;
31  import org.orekit.bodies.CelestialBody;
32  import org.orekit.bodies.CelestialBodyFactory;
33  import org.orekit.time.AbsoluteDate;
34  import org.orekit.time.FieldAbsoluteDate;
35  import org.orekit.time.TimeScale;
36  import org.orekit.time.TimeScalesFactory;
37  import org.orekit.utils.Constants;
38  import org.orekit.utils.FieldPVCoordinates;
39  
40  /**Unit tests for {@link CR3BPRotatingTransformProvider}.
41   * @author Vincent Mouraux
42   */
43  public class CR3BPRotatingTransformProviderTest {
44  
45      @Test
46      public void testTransformationOrientationForEarthMoon() {
47  
48          // Load Bodies
49          final CelestialBody moon = CelestialBodyFactory.getMoon();
50  
51          // Set frames
52          final Frame eme2000 = FramesFactory.getEME2000();
53          final CR3BPSystem syst = CR3BPFactory.getEarthMoonCR3BP();
54          final Frame baryFrame = syst.getRotatingFrame();
55  
56          // Time settings
57          final AbsoluteDate date = new AbsoluteDate(2000, 01, 01, 0, 0, 00.000,
58                                                     TimeScalesFactory.getUTC());
59  
60          // Compute Moon position in EME2000
61          Vector3D posMoon = moon.getPosition(date, eme2000);
62  
63          // Compute barycenter position in EME2000
64          // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
65          // because the test should avoid doing wrong interpretation of the meaning and
66          // particularly on the sign of the translation)
67          Vector3D posBary   = baryFrame.getStaticTransformTo(eme2000,date).transformPosition(Vector3D.ZERO);
68  
69          // check barycenter and Moon are aligned as seen from Earth
70          Assertions.assertEquals(0.0, Vector3D.angle(posMoon, posBary), 1.0e-10);
71      }
72  
73      @Test
74      public void testFieldTransformationOrientationForEarthMoon() {
75          doTestFieldTransformationOrientationForEarthMoon(Binary64Field.getInstance());
76      }
77  
78      private <T extends CalculusFieldElement<T>> void doTestFieldTransformationOrientationForEarthMoon(final Field<T> field) {
79  
80          // Load Bodies
81          final CelestialBody moon = CelestialBodyFactory.getMoon();
82  
83          // Set frames
84          final Frame eme2000 = FramesFactory.getEME2000();
85          final CR3BPSystem syst = CR3BPFactory.getEarthMoonCR3BP();
86          final Frame baryFrame = syst.getRotatingFrame();
87  
88          // Time settings
89          final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2000, 01, 01, 0, 0, 00.000,
90                                                                    TimeScalesFactory.getUTC());
91  
92          // Compute Moon position in EME2000
93          FieldPVCoordinates<T> pvMoon = moon.getPVCoordinates(date, eme2000);
94          FieldVector3D<T> posMoon = pvMoon.getPosition();
95  
96          // Compute barycenter position in EME2000
97          // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
98          // because the test should avoid doing wrong interpretation of the meaning and
99          // particularly on the sign of the translation)
100         FieldVector3D<T> posBary   = baryFrame.getTransformTo(eme2000,date).transformPosition(Vector3D.ZERO);
101 
102         // check barycenter and Moon are aligned as seen from Earth
103         Assertions.assertEquals(0.0, FieldVector3D.angle(posMoon, posBary).getReal(), 1.0e-10);
104     }
105 
106 
107     @Test
108     public void testSunEarth() {
109 
110         // Load Bodies
111         final CelestialBody sun = CelestialBodyFactory.getSun();
112         final CelestialBody earth = CelestialBodyFactory.getEarth();
113 
114         // Time settings
115         final TimeScale timeScale = TimeScalesFactory.getUTC();
116         final AbsoluteDate date = new AbsoluteDate(2000, 01, 01, 0, 0, 00.000,
117                                                    timeScale);
118 
119         // Set frames
120         final Frame sunFrame = sun.getInertiallyOrientedFrame();
121         final CR3BPSystem syst = CR3BPFactory.getSunEarthCR3BP(date, timeScale);
122         final Frame baryFrame = syst.getRotatingFrame();
123 
124         // Compute Earth position in Sun centered frame
125         Vector3D posEarth = earth.getPosition(date, sunFrame);
126 
127         // Compute barycenter position in Sun centered frame
128         // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
129         // because the test should avoid doing wrong interpretation of the meaning and
130         // particularly on the sign of the translation)
131         Vector3D posBary   = baryFrame.getStaticTransformTo(sunFrame,date).transformPosition(Vector3D.ZERO);
132 
133         // check L1 and Earth are aligned as seen from Sun
134         Assertions.assertEquals(0.0, Vector3D.angle(posEarth, posBary), 3.0e-5);
135     }
136 
137     @Test
138     public void testFieldSunEarth() {
139         doTestFieldSunEarth(Binary64Field.getInstance());
140     }
141 
142     private <T extends CalculusFieldElement<T>> void doTestFieldSunEarth(final Field<T> field) {
143 
144         // Load Bodies
145         final CelestialBody sun = CelestialBodyFactory.getSun();
146         final CelestialBody earth = CelestialBodyFactory.getEarth();
147 
148         // Time settings
149         final TimeScale timeScale = TimeScalesFactory.getUTC();
150         final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2000, 01, 01, 0, 0, 00.000,
151                                                                   timeScale);
152 
153         // Set frames
154         final Frame sunFrame = sun.getInertiallyOrientedFrame();
155         final CR3BPSystem syst = CR3BPFactory.getSunEarthCR3BP(date.toAbsoluteDate(), timeScale);
156         final Frame baryFrame = syst.getRotatingFrame();
157 
158         // Compute Earth position in Sun centered frame
159         FieldPVCoordinates<T> pvEarth = earth.getPVCoordinates(date, sunFrame);
160         FieldVector3D<T> posEarth = pvEarth.getPosition();
161 
162         // Compute barycenter position in Sun centered frame
163         // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
164         // because the test should avoid doing wrong interpretation of the meaning and
165         // particularly on the sign of the translation)
166         FieldVector3D<T> posBary   = baryFrame.getStaticTransformTo(sunFrame,date).transformPosition(FieldVector3D.getZero(field));
167 
168         // check L2 and Earth are aligned as seen from Sun
169         Assertions.assertEquals(0.0, FieldVector3D.angle(posEarth, posBary).getReal(), 3.0e-5);
170     }
171 
172     @Test
173     public void testSunJupiter() {
174 
175         // Load Bodies
176         final CelestialBody sun = CelestialBodyFactory.getSun();
177         final CelestialBody jupiter = CelestialBodyFactory.getJupiter();
178 
179         // Time settings
180         final TimeScale timeScale = TimeScalesFactory.getUTC();
181         final AbsoluteDate date = new AbsoluteDate(2000, 01, 01, 0, 0, 00.000,
182                                                    timeScale);
183 
184         // Set frames
185         final Frame sunFrame = sun.getInertiallyOrientedFrame();
186         final CR3BPSystem syst = CR3BPFactory.getSunJupiterCR3BP(date, timeScale);
187         final Frame baryFrame = syst.getRotatingFrame();
188 
189         // Compute Jupiter position in Sun centered frame
190         Vector3D posJupiter = jupiter.getPosition(date, sunFrame);
191 
192         // Compute barycenter position in Sun centered frame
193         // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
194         // because the test should avoid doing wrong interpretation of the meaning and
195         // particularly on the sign of the translation)
196         Vector3D posBary   = baryFrame.getStaticTransformTo(sunFrame,date).transformPosition(Vector3D.ZERO);
197 
198         // check barycenter and Jupiter are aligned as seen from Sun
199         Assertions.assertEquals(0.0, Vector3D.angle(posJupiter, posBary), 1.0e-10);
200     }
201 
202     @Test
203     public void testFieldSunJupiter() {
204         doTestFieldSunJupiter(Binary64Field.getInstance());
205     }
206 
207     private <T extends CalculusFieldElement<T>> void doTestFieldSunJupiter(final Field<T> field) {
208 
209         // Load Bodies
210         final CelestialBody sun = CelestialBodyFactory.getSun();
211         final CelestialBody jupiter = CelestialBodyFactory.getJupiter();
212 
213         // Time settings
214         final TimeScale timeScale = TimeScalesFactory.getUTC();
215         final FieldAbsoluteDate<T> date = new FieldAbsoluteDate<>(field, 2000, 01, 01, 0, 0, 00.000,
216                                                                   timeScale);
217 
218         // Set frames
219         final Frame sunFrame = sun.getInertiallyOrientedFrame();
220         final CR3BPSystem syst = CR3BPFactory.getSunJupiterCR3BP(date.toAbsoluteDate(), timeScale);
221         final Frame baryFrame = syst.getRotatingFrame();
222 
223         // Compute Jupiter position in Sun centered frame
224         FieldPVCoordinates<T> pvJupiter = jupiter.getPVCoordinates(date, sunFrame);
225         FieldVector3D<T> posJupiter = pvJupiter.getPosition();
226 
227         // Compute barycenter position in Sun centered frame
228         // (it is important to use transformPosition(Vector3D.ZERO) and *not* getTranslation()
229         // because the test should avoid doing wrong interpretation of the meaning and
230         // particularly on the sign of the translation)
231         FieldVector3D<T> posBary   = baryFrame.getStaticTransformTo(sunFrame,date).transformPosition(Vector3D.ZERO);
232 
233         // check barycenter and Jupiter are aligned as seen from Sun
234         Assertions.assertEquals(0.0, FieldVector3D.angle(posJupiter, posBary).getReal(), 1.0e-10);
235     }
236 
237     @Test
238     public void testBaryOrientation() {
239 
240         final TimeScale timeScale = TimeScalesFactory.getUTC();
241         final AbsoluteDate date0 = new AbsoluteDate(2000, 01, 1, 11, 58, 20.000,
242                                                     timeScale);
243         final CelestialBody sun     = CelestialBodyFactory.getSun();
244         final CelestialBody earth   = CelestialBodyFactory.getEarth();
245         final CR3BPSystem syst = CR3BPFactory.getSunEarthCR3BP(date0, timeScale);
246         final Frame baryFrame = syst.getRotatingFrame();
247         for (double dt = -Constants.JULIAN_DAY; dt <= Constants.JULIAN_DAY; dt += 3600.0) {
248             final AbsoluteDate date              = date0.shiftedBy(dt);
249             final Vector3D     sunPositionInBary   = sun.getPosition(date, baryFrame);
250             final Vector3D     earthPositionInBary = earth.getPosition(date, baryFrame);
251             Assertions.assertEquals(0.0, Vector3D.angle(sunPositionInBary,   Vector3D.MINUS_I), 1.0e-10);
252             Assertions.assertEquals(FastMath.PI, Vector3D.angle(earthPositionInBary, Vector3D.MINUS_I), 1.0e-4);
253         }
254     }
255 
256     @Test
257     public void testFieldBaryOrientation() {
258         doTestFieldBaryOrientation(Binary64Field.getInstance());
259     }
260 
261     private <T extends CalculusFieldElement<T>> void doTestFieldBaryOrientation(final Field<T> field) {
262 
263         final TimeScale timeScale = TimeScalesFactory.getUTC();
264         final FieldAbsoluteDate<T> date0 = new FieldAbsoluteDate<>(field, 2000, 01, 1, 11, 58, 20.000,
265                                                                    timeScale);
266         final CelestialBody sun     = CelestialBodyFactory.getSun();
267         final CelestialBody earth   = CelestialBodyFactory.getEarth();
268         final CR3BPSystem syst = CR3BPFactory.getSunEarthCR3BP(date0.toAbsoluteDate(), timeScale);
269         final Frame baryFrame = syst.getRotatingFrame();
270         for (double dt = -Constants.JULIAN_DAY; dt <= Constants.JULIAN_DAY; dt += 3600.0) {
271             final FieldAbsoluteDate<T> date              = date0.shiftedBy(dt);
272             final FieldVector3D<T>     sunPositionInBary   = sun.getPosition(date, baryFrame);
273             final FieldVector3D<T>     earthPositionInBary = earth.getPosition(date, baryFrame);
274             Assertions.assertEquals(0.0, FieldVector3D.angle(sunPositionInBary,   Vector3D.MINUS_I).getReal(), 1.0e-10);
275             Assertions.assertEquals(FastMath.PI, FieldVector3D.angle(earthPositionInBary, Vector3D.MINUS_I).getReal(), 1.0e-4);
276         }
277     }
278 
279     @BeforeEach
280     public void setUp() {
281         Utils.setDataRoot("regular-data");
282     }
283 
284 }