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.hamcrest.MatcherAssert;
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.Field;
22  import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
23  import org.hipparchus.analysis.differentiation.UnivariateDerivative1Field;
24  import org.hipparchus.complex.Complex;
25  import org.hipparchus.complex.ComplexField;
26  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
27  import org.hipparchus.geometry.euclidean.threed.Rotation;
28  import org.hipparchus.geometry.euclidean.threed.Vector3D;
29  import org.hipparchus.util.Binary64Field;
30  import org.hipparchus.util.FastMath;
31  import org.junit.jupiter.api.Assertions;
32  import org.junit.jupiter.api.BeforeEach;
33  import org.junit.jupiter.api.Test;
34  import org.orekit.OrekitMatchers;
35  import org.orekit.Utils;
36  import org.orekit.bodies.GeodeticPoint;
37  import org.orekit.bodies.OneAxisEllipsoid;
38  import org.orekit.time.AbsoluteDate;
39  import org.orekit.time.FieldAbsoluteDate;
40  import org.orekit.time.TimeScalesFactory;
41  import org.orekit.utils.Constants;
42  import org.orekit.utils.IERSConventions;
43  import org.orekit.utils.PVCoordinates;
44  
45  import java.util.Random;
46  
47  class FrameTest {
48  
49      @Test
50      void testSameFrameRoot() {
51          Random random = new Random(0x29448c7d58b95565L);
52          Frame  frame  = FramesFactory.getEME2000();
53          checkNoTransform(frame.getTransformTo(frame, new AbsoluteDate()), random);
54          Assertions.assertTrue(frame.getDepth() > 0);
55          Assertions.assertEquals(frame.getParent().getDepth() + 1, frame.getDepth());
56      }
57  
58      @Test
59      void testSameFrameNoRoot() {
60          Random random = new Random(0xc6e88d0f53e29116L);
61          Transform t   = randomTransform(random);
62          Frame frame   = new Frame(FramesFactory.getEME2000(), t, null, true);
63          checkNoTransform(frame.getTransformTo(frame, new AbsoluteDate()), random);
64      }
65  
66      @Test
67      void testSimilarFrames() {
68          Random random = new Random(0x1b868f67a83666e5L);
69          Transform t   = randomTransform(random);
70          Frame frame1  = new Frame(FramesFactory.getEME2000(), t, null, true);
71          Frame frame2  = new Frame(FramesFactory.getEME2000(), t, null, false);
72          checkNoTransform(frame1.getTransformTo(frame2, new AbsoluteDate()), random);
73      }
74  
75      @Test
76      void testFromParent() {
77          Random random = new Random(0xb92fba1183fe11b8L);
78          Transform fromEME2000  = randomTransform(random);
79          Frame frame = new Frame(FramesFactory.getEME2000(), fromEME2000, null);
80          Transform toEME2000 = frame.getTransformTo(FramesFactory.getEME2000(), new AbsoluteDate());
81          checkNoTransform(new Transform(fromEME2000.getDate(), fromEME2000, toEME2000), random);
82      }
83  
84      @Test
85      void testDecomposedTransform() {
86          Random random = new Random(0xb7d1a155e726da57L);
87          Transform t1  = randomTransform(random);
88          Transform t2  = randomTransform(random);
89          Transform t3  = randomTransform(random);
90          Frame frame1 =
91              new Frame(FramesFactory.getEME2000(),
92                        new Transform(t1.getDate(), new Transform(t1.getDate(), t1, t2), t3),
93                        null);
94          Frame frame2 =
95              new Frame(new Frame(new Frame(FramesFactory.getEME2000(), t1, null), t2, null), t3, null);
96          checkNoTransform(frame1.getTransformTo(frame2, new AbsoluteDate()), random);
97      }
98  
99      @Test
100     void testFindCommon() {
101 
102         Random random = new Random(0xb7d1a155e726da57L);
103         Transform t1  = randomTransform(random);
104         Transform t2  = randomTransform(random);
105         Transform t3  = randomTransform(random);
106 
107         Frame R1 = new Frame(FramesFactory.getEME2000(), t1, "R1");
108         Frame R2 = new Frame(R1, t2, "R2");
109         Frame R3 = new Frame(R2, t3, "R3");
110         Assertions.assertTrue(R1.getDepth() > 0);
111         Assertions.assertEquals(R1.getDepth() + 1, R2.getDepth());
112         Assertions.assertEquals(R2.getDepth() + 1, R3.getDepth());
113 
114         Transform T = R1.getTransformTo(R3, new AbsoluteDate());
115 
116         Transform S = new Transform(t2.getDate(), t2, t3);
117 
118         checkNoTransform(new Transform(T.getDate(), T, S.getInverse()) , random);
119 
120     }
121 
122     @Test
123     void testDepthAndAncestor() {
124         Random random = new Random(0x01f8d3b944123044L);
125         Frame root = Frame.getRoot();
126 
127         Frame f1 = new Frame(root, randomTransform(random), "f1");
128         Frame f2 = new Frame(f1,   randomTransform(random), "f2");
129         Frame f3 = new Frame(f1,   randomTransform(random), "f3");
130         Frame f4 = new Frame(f2,   randomTransform(random), "f4");
131         Frame f5 = new Frame(f3,   randomTransform(random), "f5");
132         Frame f6 = new Frame(f5,   randomTransform(random), "f6");
133 
134         Assertions.assertEquals(0, root.getDepth());
135         Assertions.assertEquals(1, f1.getDepth());
136         Assertions.assertEquals(2, f2.getDepth());
137         Assertions.assertEquals(2, f3.getDepth());
138         Assertions.assertEquals(3, f4.getDepth());
139         Assertions.assertEquals(3, f5.getDepth());
140         Assertions.assertEquals(4, f6.getDepth());
141 
142         Assertions.assertSame(root, f1.getAncestor(1));
143         Assertions.assertSame(root, f6.getAncestor(4));
144         Assertions.assertSame(f1, f6.getAncestor(3));
145         Assertions.assertSame(f3, f6.getAncestor(2));
146         Assertions.assertSame(f5, f6.getAncestor(1));
147         Assertions.assertSame(f6, f6.getAncestor(0));
148 
149         try {
150             f6.getAncestor(5);
151             Assertions.fail("an exception should have been triggered");
152         } catch (IllegalArgumentException iae) {
153             // expected behavior
154         } catch (Exception e) {
155             Assertions.fail("wrong exception caught: " + e.getClass().getName());
156         }
157 
158     }
159 
160     @Test
161     void testIsChildOf() {
162         Random random = new Random(0xb7d1a155e726da78L);
163         Frame eme2000 = FramesFactory.getEME2000();
164 
165         Frame f1 = new Frame(eme2000, randomTransform(random), "f1");
166         Frame f2 = new Frame(f1     , randomTransform(random), "f2");
167         Frame f4 = new Frame(f2     , randomTransform(random), "f4");
168         Frame f5 = new Frame(f4     , randomTransform(random), "f5");
169         Frame f6 = new Frame(eme2000, randomTransform(random), "f6");
170         Frame f7 = new Frame(f6     , randomTransform(random), "f7");
171         Frame f8 = new Frame(f6     , randomTransform(random), "f8");
172         Frame f9 = new Frame(f7     , randomTransform(random), "f9");
173 
174         // check if the root frame can be an ancestor of another frame
175         Assertions.assertFalse(eme2000.isChildOf(f5));
176 
177         // check if a frame which belongs to the same branch than the 2nd frame is a branch of it
178         Assertions.assertTrue(f5.isChildOf(f1));
179 
180         // check if a random frame is the child of the root frame
181         Assertions.assertTrue(f9.isChildOf(eme2000));
182 
183         // check that a frame is not its own child
184         Assertions.assertFalse(f4.isChildOf(f4));
185 
186         // check if a frame which belongs to a different branch than the 2nd frame can be a child for it
187         Assertions.assertFalse(f9.isChildOf(f5));
188 
189         // check if the root frame is not a child of itself
190         Assertions.assertFalse(eme2000.isChildOf(eme2000));
191 
192         Assertions.assertFalse(f9.isChildOf(f8));
193 
194     }
195 
196     @Test
197     void testH0m9() {
198         AbsoluteDate h0         = new AbsoluteDate("2010-07-01T10:42:09", TimeScalesFactory.getUTC());
199         Frame itrf              = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
200         Frame rotatingPadFrame  = new TopocentricFrame(new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
201                                                                             Constants.WGS84_EARTH_FLATTENING,
202                                                                             itrf),
203                                                        new GeodeticPoint(FastMath.toRadians(5.0),
204                                                                                               FastMath.toRadians(-100.0),
205                                                                                               0.0),
206                                                        "launch pad");
207 
208         // create a new inertially oriented frame that is aligned with ITRF at h0 - 9 seconds
209         AbsoluteDate h0M9       = h0.shiftedBy(-9.0);
210         Frame eme2000           = FramesFactory.getEME2000();
211         Frame frozenLaunchFrame = rotatingPadFrame.getFrozenFrame(eme2000, h0M9, "launch frame");
212 
213         // check velocity module is unchanged
214         Vector3D pEme2000 = new Vector3D(-29536113.0, 30329259.0, -100125.0);
215         Vector3D vEme2000 = new Vector3D(-2194.0, -2141.0, -8.0);
216         PVCoordinates pvEme2000 = new PVCoordinates(pEme2000, vEme2000);
217         PVCoordinates pvH0m9 = eme2000.getTransformTo(frozenLaunchFrame, h0M9).transformPVCoordinates(pvEme2000);
218         Assertions.assertEquals(vEme2000.getNorm(), pvH0m9.getVelocity().getNorm(), 1.0e-6);
219         Vector3D pH0m9 = eme2000.getStaticTransformTo(frozenLaunchFrame, h0M9)
220                 .transformPosition(pvEme2000.getPosition());
221         MatcherAssert.assertThat(pH0m9,
222                 OrekitMatchers.vectorCloseTo(pvH0m9.getPosition(), 1e-15));
223 
224         // this frame is fixed with respect to EME2000 but rotates with respect to the non-frozen one
225         // the following loop should have a fixed angle a1 and an evolving angle a2
226         double minA1 = Double.POSITIVE_INFINITY;
227         double maxA1 = Double.NEGATIVE_INFINITY;
228         double minA2 = Double.POSITIVE_INFINITY;
229         double maxA2 = Double.NEGATIVE_INFINITY;
230         double dt;
231         for (dt = 0; dt < 86164; dt += 300.0) {
232             AbsoluteDate date = h0M9.shiftedBy(dt);
233             double a1 = frozenLaunchFrame.getTransformTo(eme2000,          date).getRotation().getAngle();
234             double a2 = frozenLaunchFrame.getTransformTo(rotatingPadFrame, date).getRotation().getAngle();
235             minA1 = FastMath.min(minA1, a1);
236             maxA1 = FastMath.max(maxA1, a1);
237             minA2 = FastMath.min(minA2, a2);
238             maxA2 = FastMath.max(maxA2, a2);
239         }
240         Assertions.assertEquals(0, maxA1 - minA1, 1.0e-12);
241         Assertions.assertEquals(FastMath.PI, maxA2 - minA2, 0.01);
242 
243     }
244 
245     private Transform randomTransform(Random random) {
246         Transform transform = Transform.IDENTITY;
247         for (int i = random.nextInt(10); i > 0; --i) {
248             if (random.nextBoolean()) {
249                 Vector3D u = new Vector3D(random.nextDouble() * 1000.0,
250                                           random.nextDouble() * 1000.0,
251                                           random.nextDouble() * 1000.0);
252                 transform = new Transform(transform.getDate(), transform, new Transform(transform.getDate(), u));
253             } else {
254                 double q0 = random.nextDouble() * 2 - 1;
255                 double q1 = random.nextDouble() * 2 - 1;
256                 double q2 = random.nextDouble() * 2 - 1;
257                 double q3 = random.nextDouble() * 2 - 1;
258                 double q  = FastMath.sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
259                 Rotation r = new Rotation(q0 / q, q1 / q, q2 / q, q3 / q, false);
260                 transform = new Transform(transform.getDate(), transform, new Transform(transform.getDate(), r));
261             }
262         }
263         return transform;
264     }
265 
266     private void checkNoTransform(Transform transform, Random random) {
267         for (int i = 0; i < 100; ++i) {
268             Vector3D a = new Vector3D(random.nextDouble(),
269                                       random.nextDouble(),
270                                       random.nextDouble());
271             Vector3D b = transform.transformVector(a);
272             Assertions.assertEquals(0, a.subtract(b).getNorm(), 1.0e-10);
273             Vector3D c = transform.transformPosition(a);
274             Assertions.assertEquals(0, a.subtract(c).getNorm(), 1.0e-10);
275         }
276     }
277 
278     @Test
279     void testGetKinematicTransformTo() {
280         // GIVEN
281         final Frame oldFrame = FramesFactory.getEME2000();
282         final Frame newFrame = FramesFactory.getGCRF();
283         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
284         // WHEN
285         final KinematicTransform kinematicTransform = oldFrame.getKinematicTransformTo(newFrame, date);
286         // THEN
287         final Transform transform = oldFrame.getTransformTo(newFrame, date);
288         Assertions.assertEquals(date, kinematicTransform.getDate());
289         Assertions.assertEquals(transform.getCartesian().getPosition(), kinematicTransform.getTranslation());
290         Assertions.assertEquals(transform.getCartesian().getVelocity(), kinematicTransform.getVelocity());
291         Assertions.assertEquals(0., Rotation.distance(transform.getRotation(), kinematicTransform.getRotation()));
292         Assertions.assertEquals(transform.getRotationRate(), kinematicTransform.getRotationRate());
293     }
294 
295     @Test
296     void testGetStaticTransformIdentity() {
297         // GIVEN
298         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
299         final Frame frame = FramesFactory.getGCRF();
300         // WHEN
301         final StaticTransform staticTransform = frame.getStaticTransformTo(frame, date);
302         // THEN
303         Assertions.assertEquals(staticTransform, staticTransform.getStaticInverse());
304     }
305 
306     @Test
307     void testGetStaticTransformIdentityField() {
308         // GIVEN
309         final FieldAbsoluteDate<Complex> fieldDate = FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance());
310         final Frame frame = FramesFactory.getGCRF();
311         // WHEN
312         final FieldStaticTransform<Complex> staticTransform = frame.getStaticTransformTo(frame, fieldDate);
313         // THEN
314         Assertions.assertEquals(staticTransform.getClass(), staticTransform.getStaticInverse().getClass());
315     }
316 
317     @Test
318     void testFieldGetKinematicTransformToWithConstantDate() {
319         templateTestFieldGetKinematicTransformTo(getComplexDate());
320     }
321 
322     @Test
323     void testFieldGetKinematicTransformToWithNonConstantDate() {
324         templateTestFieldGetKinematicTransformTo(getComplexDate().shiftedBy(Complex.I));
325     }
326 
327     private void templateTestFieldGetKinematicTransformTo(final FieldAbsoluteDate<Complex> fieldDate) {
328         // GIVEN
329         final Frame oldFrame = FramesFactory.getEME2000();
330         final Frame newFrame = FramesFactory.getGCRF();
331         // WHEN
332         final FieldKinematicTransform<Complex> fieldKinematicTransform = oldFrame.getKinematicTransformTo(newFrame,
333                 fieldDate);
334         // THEN
335         final KinematicTransform kinematicTransform = oldFrame.getKinematicTransformTo(newFrame,
336                 fieldDate.toAbsoluteDate());
337         Assertions.assertEquals(kinematicTransform.getDate(), fieldKinematicTransform.getDate());
338         Assertions.assertEquals(kinematicTransform.getTranslation(), fieldKinematicTransform.getTranslation().toVector3D());
339         Assertions.assertEquals(kinematicTransform.getVelocity(), fieldKinematicTransform.getVelocity().toVector3D());
340         Assertions.assertEquals(0., Rotation.distance(kinematicTransform.getRotation(),
341                 fieldKinematicTransform.getRotation().toRotation()));
342         Assertions.assertEquals(kinematicTransform.getRotationRate(),
343                 fieldKinematicTransform.getRotationRate().toVector3D());
344     }
345 
346     private FieldAbsoluteDate<Complex> getComplexDate() {
347         return FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance());
348     }
349 
350     @Test
351     void testGetTransformTo() {
352         // GIVEN
353         final Frame oldFrame = FramesFactory.getEME2000();
354         final Frame newFrame = FramesFactory.getGTOD(true);
355         final UnivariateDerivative1Field field = UnivariateDerivative1Field.getInstance();
356         final FieldAbsoluteDate<UnivariateDerivative1> fieldDate = FieldAbsoluteDate.getArbitraryEpoch(field);
357         final FieldAbsoluteDate<UnivariateDerivative1> shiftedDate = fieldDate.shiftedBy(new UnivariateDerivative1(0., 1));
358         // WHEN
359         final FieldTransform<UnivariateDerivative1> fieldTransform = oldFrame.getTransformTo(newFrame, shiftedDate);
360         // THEN
361         Assertions.assertEquals(shiftedDate, fieldTransform.getFieldDate());
362         final FieldTransform<UnivariateDerivative1> referenceTransform = oldFrame.getTransformTo(newFrame, fieldDate);
363         Assertions.assertEquals(fieldTransform.getDate(), referenceTransform.getDate());
364         Assertions.assertEquals(fieldTransform.getTranslation().toVector3D(),
365                 referenceTransform.getTranslation().toVector3D());
366         compareFieldVectorWithMargin(fieldTransform.getRotationRate(), referenceTransform.getRotationRate());
367         compareFieldVectorWithMargin(fieldTransform.getRotationAcceleration(), referenceTransform.getRotationAcceleration());
368         Assertions.assertEquals(0., Rotation.distance(fieldTransform.getRotation().toRotation(),
369                 referenceTransform.getRotation().toRotation()));
370     }
371 
372     @Test
373     public void testNoPeering() {
374 
375         Frame eme2000 = FramesFactory.getEME2000();
376         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
377         Assertions.assertNull(eme2000.getPeer());
378         Assertions.assertNull(itrf.getPeer());
379 
380         // with caching disabled, tB should be a new recomputed instance, similar to tA
381         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
382         final Transform tA = eme2000.getTransformTo(itrf, t0);
383         final Transform tB = eme2000.getTransformTo(itrf, t0);
384         final Transform backAndForth = new Transform(t0, tA, tB.getInverse());
385         Assertions.assertNotSame(tA, tB);
386         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
387         Assertions.assertEquals(0.0, backAndForth.getCartesian().getPosition().getNorm(), 1.0e-20);
388 
389     }
390 
391     @Test
392     public void testNoPeeringKinematic() {
393 
394         Frame eme2000 = FramesFactory.getEME2000();
395         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
396         Assertions.assertNull(eme2000.getPeer());
397         Assertions.assertNull(itrf.getPeer());
398 
399         // with caching disabled, tB should be a new recomputed instance, similar to tA
400         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
401         final KinematicTransform tA = eme2000.getKinematicTransformTo(itrf, t0);
402         final KinematicTransform tB = eme2000.getKinematicTransformTo(itrf, t0);
403         final KinematicTransform backAndForth = KinematicTransform.compose(t0, tA, tB.getInverse());
404         Assertions.assertNotSame(tA, tB);
405         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
406         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm(), 1.0e-20);
407 
408     }
409 
410     @Test
411     public void testNoPeeringStatic() {
412 
413         Frame eme2000 = FramesFactory.getEME2000();
414         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
415         Assertions.assertNull(eme2000.getPeer());
416         Assertions.assertNull(itrf.getPeer());
417 
418         // with caching disabled, tB should be a new recomputed instance, similar to tA
419         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
420         final StaticTransform tA = eme2000.getStaticTransformTo(itrf, t0);
421         final StaticTransform tB = eme2000.getStaticTransformTo(itrf, t0);
422         final StaticTransform backAndForth = StaticTransform.compose(t0, tA, tB.getInverse());
423         Assertions.assertNotSame(tA, tB);
424         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
425         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm(), 1.0e-20);
426 
427     }
428 
429     @Test
430     public void testNoPeeringField() {
431         doTestNoPeeringField(Binary64Field.getInstance());
432     }
433 
434     private <T extends CalculusFieldElement<T>> void doTestNoPeeringField(final Field<T> field) {
435 
436         Frame eme2000 = FramesFactory.getEME2000();
437         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
438         Assertions.assertNull(eme2000.getPeer());
439         Assertions.assertNull(itrf.getPeer());
440 
441         // with caching disabled, tB should be a new recomputed instance, similar to tA
442         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
443         final FieldTransform<T> tA = eme2000.getTransformTo(itrf, t0);
444         final FieldTransform<T> tB = eme2000.getTransformTo(itrf, t0);
445         final FieldTransform<T> backAndForth = new FieldTransform<>(t0, tA, tB.getInverse());
446         Assertions.assertNotSame(tA, tB);
447         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
448         Assertions.assertEquals(0.0, backAndForth.getCartesian().getPosition().getNorm().getReal(), 1.0e-20);
449 
450     }
451 
452     @Test
453     public void testNoPeeringFieldKinematic() {
454         doTestNoPeeringFieldKinematic(Binary64Field.getInstance());
455     }
456 
457     private <T extends CalculusFieldElement<T>> void doTestNoPeeringFieldKinematic(final Field<T> field) {
458 
459         Frame eme2000 = FramesFactory.getEME2000();
460         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
461         Assertions.assertNull(eme2000.getPeer());
462         Assertions.assertNull(itrf.getPeer());
463 
464         // with caching disabled, tB should be a new recomputed instance, similar to tA
465         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
466         final FieldKinematicTransform<T> tA = eme2000.getKinematicTransformTo(itrf, t0);
467         final FieldKinematicTransform<T> tB = eme2000.getKinematicTransformTo(itrf, t0);
468         final FieldKinematicTransform<T> backAndForth = FieldKinematicTransform.compose(t0, tA, tB.getInverse());
469         Assertions.assertNotSame(tA, tB);
470         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
471         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
472 
473     }
474 
475     @Test
476     public void testNoPeeringFieldStatic() {
477         doTestNoPeeringFieldStatic(Binary64Field.getInstance());
478     }
479 
480     private <T extends CalculusFieldElement<T>> void doTestNoPeeringFieldStatic(final Field<T> field) {
481 
482         Frame eme2000 = FramesFactory.getEME2000();
483         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
484         Assertions.assertNull(eme2000.getPeer());
485         Assertions.assertNull(itrf.getPeer());
486 
487         // with caching disabled, tB should be a new recomputed instance, similar to tA
488         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
489         final FieldStaticTransform<T> tA = eme2000.getStaticTransformTo(itrf, t0);
490         final FieldStaticTransform<T> tB = eme2000.getStaticTransformTo(itrf, t0);
491         final FieldStaticTransform<T> backAndForth = FieldStaticTransform.compose(t0, tA, tB.getInverse());
492         Assertions.assertNotSame(tA, tB);
493         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
494         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
495 
496     }
497 
498     @Test
499     public void testPeering() {
500 
501         Frame eme2000 = FramesFactory.getEME2000();
502         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
503         Assertions.assertNull(eme2000.getPeer());
504         Assertions.assertNull(itrf.getPeer());
505 
506         final int cachesize = 20;
507         eme2000.setPeerCaching(itrf, cachesize);
508         Assertions.assertSame(itrf,    eme2000.getPeer());
509         Assertions.assertNull(itrf.getPeer());
510 
511         // with caching activated, tB should be a reference to the same transform as tA
512         // without being recomputed
513         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
514         final Transform tA = eme2000.getTransformTo(itrf, t0);
515         final Transform tB = eme2000.getTransformTo(itrf, t0);
516         final Transform backAndForth = new Transform(t0, tA, tB.getInverse());
517         Assertions.assertSame(tA, tB);
518         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
519         Assertions.assertEquals(0.0, backAndForth.getCartesian().getPosition().getNorm(), 1.0e-20);
520 
521         // non-peered frames should still be recomputed
522         Frame gcrf = FramesFactory.getGCRF();
523         Assertions.assertNotSame(eme2000.getTransformTo(gcrf, t0),
524                                  eme2000.getTransformTo(gcrf, t0));
525 
526         final Transform[] direct  = new Transform[cachesize];
527         for ( int i = 0; i < cachesize; i++ ) {
528             direct[i]  = eme2000.getTransformTo(itrf, t0.shiftedBy(i));
529         }
530 
531         // with caching activated, we should not recompute any transform, just retrieve existing ones
532         for (int i = 0; i < 10000; ++i) {
533             Assertions.assertSame(direct[i % cachesize], eme2000.getTransformTo(itrf, t0.shiftedBy(i % cachesize)));
534         }
535 
536         // check we can clear the cache
537         eme2000.setPeerCaching(null, cachesize);
538         Assertions.assertNull(eme2000.getPeer());
539         Assertions.assertNotNull(eme2000.getTransformTo(itrf, t0));
540 
541     }
542 
543     @Test
544     public void testPeeringKinematic() {
545 
546         Frame eme2000 = FramesFactory.getEME2000();
547         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
548         Assertions.assertNull(eme2000.getPeer());
549         Assertions.assertNull(itrf.getPeer());
550 
551         final int cachesize = 20;
552         eme2000.setPeerCaching(itrf, cachesize);
553         Assertions.assertSame(itrf,    eme2000.getPeer());
554         Assertions.assertNull(itrf.getPeer());
555 
556         // with caching activated, tB should be a reference to the same transform as tA
557         // without being recomputed
558         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
559         final KinematicTransform tA = eme2000.getKinematicTransformTo(itrf, t0);
560         final KinematicTransform tB = eme2000.getKinematicTransformTo(itrf, t0);
561         final KinematicTransform backAndForth = KinematicTransform.compose(t0, tA, tB.getInverse());
562         Assertions.assertSame(tA, tB);
563         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
564         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm(), 1.0e-20);
565 
566         // non-peered frames should still be recomputed
567         Frame gcrf = FramesFactory.getGCRF();
568         Assertions.assertNotSame(eme2000.getKinematicTransformTo(gcrf, t0),
569                                  eme2000.getKinematicTransformTo(gcrf, t0));
570 
571         final KinematicTransform[] direct  = new KinematicTransform[cachesize];
572         for ( int i = 0; i < cachesize; i++ ) {
573             direct[i]  = eme2000.getKinematicTransformTo(itrf, t0.shiftedBy(i));
574         }
575 
576         // with caching activated, we should not recompute any transform, just retrieve existing ones
577         for (int i = 0; i < 10000; ++i) {
578             Assertions.assertSame(direct[i % cachesize], eme2000.getKinematicTransformTo(itrf, t0.shiftedBy(i % cachesize)));
579         }
580 
581     }
582 
583     @Test
584     public void testPeeringStatic() {
585 
586         Frame eme2000 = FramesFactory.getEME2000();
587         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
588         Assertions.assertNull(eme2000.getPeer());
589         Assertions.assertNull(itrf.getPeer());
590 
591         final int cachesize = 20;
592         eme2000.setPeerCaching(itrf, cachesize);
593         Assertions.assertSame(itrf,    eme2000.getPeer());
594         Assertions.assertNull(itrf.getPeer());
595 
596         // with caching activated, tB should be a reference to the same transform as tA
597         // without being recomputed
598         final AbsoluteDate t0 = new AbsoluteDate(2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
599         final StaticTransform tA = eme2000.getStaticTransformTo(itrf, t0);
600         final StaticTransform tB = eme2000.getStaticTransformTo(itrf, t0);
601         final StaticTransform backAndForth = StaticTransform.compose(t0, tA, tB.getInverse());
602         Assertions.assertSame(tA, tB);
603         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle(), 1.0e-20);
604         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm(), 1.0e-20);
605 
606         // non-peered frames should still be recomputed
607         Frame gcrf = FramesFactory.getGCRF();
608         Assertions.assertNotSame(eme2000.getStaticTransformTo(gcrf, t0),
609                                  eme2000.getStaticTransformTo(gcrf, t0));
610 
611         final StaticTransform[] direct  = new StaticTransform[cachesize];
612         for ( int i = 0; i < cachesize; i++ ) {
613             direct[i]  = eme2000.getStaticTransformTo(itrf, t0.shiftedBy(i));
614         }
615 
616         // with caching activated, we should not recompute any transform, just retrieve existing ones
617         for (int i = 0; i < 10000; ++i) {
618             Assertions.assertSame(direct[i % cachesize], eme2000.getStaticTransformTo(itrf, t0.shiftedBy(i % cachesize)));
619         }
620 
621     }
622 
623     @Test
624     public void testPeeringField() {
625         doTestPeeringField(Binary64Field.getInstance());
626     }
627 
628     @SuppressWarnings("unchecked")
629     private <T extends CalculusFieldElement<T>> void doTestPeeringField(final Field<T> field) {
630 
631         Frame eme2000 = FramesFactory.getEME2000();
632         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
633         Assertions.assertNull(eme2000.getPeer());
634         Assertions.assertNull(itrf.getPeer());
635 
636         // with caching activated, tB should be a reference to the same transform as tA
637         // without being recomputed
638         final int cachesize = 20;
639         eme2000.setPeerCaching(itrf, cachesize);
640         Assertions.assertSame(itrf,    eme2000.getPeer());
641         Assertions.assertNull(itrf.getPeer());
642 
643         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
644         final FieldTransform<T> tA = eme2000.getTransformTo(itrf, t0);
645         final FieldTransform<T> tB = eme2000.getTransformTo(itrf, t0);
646         final FieldTransform<T> backAndForth = new FieldTransform<>(t0, tA, tB.getInverse());
647         Assertions.assertSame(tA, tB);
648         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
649         Assertions.assertEquals(0.0, backAndForth.getCartesian().getPosition().getNorm().getReal(), 1.0e-20);
650 
651         // non-peered frames should still be recomputed
652         Frame gcrf = FramesFactory.getGCRF();
653         Assertions.assertNotSame(eme2000.getTransformTo(gcrf, t0),
654                                  eme2000.getTransformTo(gcrf, t0));
655 
656         final FieldTransform<T>[] direct  = new FieldTransform[cachesize];
657         for ( int i = 0; i < cachesize; i++ ) {
658             direct[i]  = eme2000.getTransformTo(itrf, t0.shiftedBy(i));
659         }
660 
661         // with caching activated, we should not recompute any transform, just retrieve existing ones
662         for (int i = 0; i < 10000; ++i) {
663             Assertions.assertSame(direct[i % cachesize], eme2000.getTransformTo(itrf, t0.shiftedBy(i % cachesize)));
664         }
665 
666     }
667 
668     @Test
669     public void testPeeringFieldKinematic() {
670         doTestPeeringFieldKinematic(Binary64Field.getInstance());
671     }
672 
673     @SuppressWarnings("unchecked")
674     private <T extends CalculusFieldElement<T>> void doTestPeeringFieldKinematic(final Field<T> field) {
675 
676         Frame eme2000 = FramesFactory.getEME2000();
677         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
678         Assertions.assertNull(eme2000.getPeer());
679         Assertions.assertNull(itrf.getPeer());
680 
681         // with caching activated, tB should be a reference to the same transform as tA
682         // without being recomputed
683         final int cachesize = 20;
684         eme2000.setPeerCaching(itrf, cachesize);
685         Assertions.assertSame(itrf,    eme2000.getPeer());
686         Assertions.assertNull(itrf.getPeer());
687 
688         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
689         final FieldKinematicTransform<T> tA = eme2000.getKinematicTransformTo(itrf, t0);
690         final FieldKinematicTransform<T> tB = eme2000.getKinematicTransformTo(itrf, t0);
691         final FieldKinematicTransform<T> backAndForth = FieldKinematicTransform.compose(t0, tA, tB.getInverse());
692         Assertions.assertSame(tA, tB);
693         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
694         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
695 
696         // non-peered frames should still be recomputed
697         Frame gcrf = FramesFactory.getGCRF();
698         Assertions.assertNotSame(eme2000.getKinematicTransformTo(gcrf, t0),
699                                  eme2000.getKinematicTransformTo(gcrf, t0));
700 
701         final FieldKinematicTransform<T>[] direct  = new FieldKinematicTransform[cachesize];
702         for ( int i = 0; i < cachesize; i++ ) {
703             direct[i]  = eme2000.getKinematicTransformTo(itrf, t0.shiftedBy(i));
704         }
705 
706         // with caching activated, we should not recompute any transform, just retrieve existing ones
707         for (int i = 0; i < 10000; ++i) {
708             Assertions.assertSame(direct[i % cachesize], eme2000.getKinematicTransformTo(itrf, t0.shiftedBy(i % cachesize)));
709         }
710 
711     }
712 
713     @Test
714     public void testPeeringFieldStatic() {
715         doTestPeeringFieldStatic(Binary64Field.getInstance());
716     }
717 
718     @SuppressWarnings("unchecked")
719     private <T extends CalculusFieldElement<T>> void doTestPeeringFieldStatic(final Field<T> field) {
720 
721         Frame eme2000 = FramesFactory.getEME2000();
722         Frame itrf    = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
723         Assertions.assertNull(eme2000.getPeer());
724         Assertions.assertNull(itrf.getPeer());
725 
726         // with caching activated, tB should be a reference to the same transform as tA
727         // without being recomputed
728         final int cachesize = 20;
729         eme2000.setPeerCaching(itrf, cachesize);
730         Assertions.assertSame(itrf,    eme2000.getPeer());
731         Assertions.assertNull(itrf.getPeer());
732 
733         final FieldAbsoluteDate<T> t0 = new FieldAbsoluteDate<>(field, 2004, 5, 7, 17, 42, 37.5, TimeScalesFactory.getUTC());
734         final FieldStaticTransform<T> tA = eme2000.getStaticTransformTo(itrf, t0);
735         final FieldStaticTransform<T> tB = eme2000.getStaticTransformTo(itrf, t0);
736         final FieldStaticTransform<T> backAndForth = FieldStaticTransform.compose(t0, tA, tB.getInverse());
737         Assertions.assertSame(tA, tB);
738         Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
739         Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
740 
741         // non-peered frames should still be recomputed
742         Frame gcrf = FramesFactory.getGCRF();
743         Assertions.assertNotSame(eme2000.getStaticTransformTo(gcrf, t0),
744                                  eme2000.getStaticTransformTo(gcrf, t0));
745 
746         final FieldStaticTransform<T>[] direct  = new FieldStaticTransform[cachesize];
747         for ( int i = 0; i < cachesize; i++ ) {
748             direct[i]  = eme2000.getStaticTransformTo(itrf, t0.shiftedBy(i));
749         }
750 
751         // with caching activated, we should not recompute any transform, just retrieve existing ones
752         for (int i = 0; i < 10000; ++i) {
753             Assertions.assertSame(direct[i % cachesize], eme2000.getStaticTransformTo(itrf, t0.shiftedBy(i % cachesize)));
754         }
755 
756     }
757 
758     private static <T extends CalculusFieldElement<T>> void compareFieldVectorWithMargin(final FieldVector3D<T> expectedVector,
759                                                                                          final FieldVector3D<T> actualVector) {
760         Assertions.assertEquals(0., actualVector.toVector3D().subtract(expectedVector.toVector3D()).getNorm(),
761                 1e-12);
762     }
763 
764     @BeforeEach
765     public void setUp() {
766         Utils.setDataRoot("compressed-data");
767     }
768 
769 }