1   /* Copyright 2022-2025 Romain Serra
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.orbits;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.analysis.differentiation.Gradient;
21  import org.hipparchus.analysis.differentiation.GradientField;
22  import org.hipparchus.complex.Complex;
23  import org.hipparchus.complex.ComplexField;
24  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.hipparchus.util.Binary64;
27  import org.hipparchus.util.MathUtils;
28  import org.junit.jupiter.api.Assertions;
29  import org.junit.jupiter.api.Test;
30  import org.orekit.frames.Frame;
31  import org.orekit.frames.FramesFactory;
32  import org.orekit.time.FieldAbsoluteDate;
33  import org.orekit.utils.Constants;
34  import org.orekit.utils.FieldPVCoordinates;
35  import org.orekit.utils.PVCoordinates;
36  import org.orekit.utils.TimeStampedFieldPVCoordinates;
37  
38  
39  class FieldOrbitTest {
40  
41      @Test
42      void testGetPosition() {
43          // GIVEN
44          final TestFieldOrbit testFieldOrbit = new TestFieldOrbit(1.);
45          final FieldAbsoluteDate<Complex> date = testFieldOrbit.getDate().shiftedBy(0.);
46          final Frame frame = testFieldOrbit.getFrame();
47          // WHEN
48          final FieldVector3D<Complex> actualPosition = testFieldOrbit.getPosition(date, frame);
49          // THEN
50          final FieldVector3D<Complex> expectedPosition = testFieldOrbit.getPVCoordinates(date, frame).getPosition();
51          Assertions.assertEquals(expectedPosition, actualPosition);
52      }
53  
54      @Test
55      void testHasNonKeplerianAccelerationDerivative() {
56          // GIVEN
57          final GradientField field = GradientField.getField(0);
58          final Gradient mu = field.getZero().newInstance(Constants.EGM96_EARTH_MU);
59          final FieldPVCoordinates<Gradient> fieldPVCoordinates = createFieldTPVWithKeplerianAcceleration(mu);
60          // WHEN
61          final boolean actualResult = FieldOrbit.hasNonKeplerianAcceleration(fieldPVCoordinates, mu);
62          // THEN
63          Assertions.assertFalse(actualResult);
64      }
65  
66      @Test
67      void testIssue1344() {
68          // GIVEN
69          final Binary64 mu = Binary64.ZERO.newInstance(Constants.EGM96_EARTH_MU);
70          final FieldPVCoordinates<Binary64> fieldPVCoordinates = createFieldTPVWithKeplerianAcceleration(mu);
71          // WHEN
72          final boolean actualResult = FieldOrbit.hasNonKeplerianAcceleration(fieldPVCoordinates, mu);
73          // THEN
74          Assertions.assertFalse(actualResult);
75      }
76  
77      private static <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> createFieldTPVWithKeplerianAcceleration(final T mu) {
78          final Vector3D position = new Vector3D(1e6, 0, 0);
79          final Vector3D keplerianAcceleration = new Vector3D(-mu.getReal() / position.getNormSq() / position.getNorm(),
80                  position);
81          return new FieldPVCoordinates<>(mu.getField(), new PVCoordinates(position, Vector3D.ZERO, keplerianAcceleration));
82      }
83  
84      @Test
85      void testKeplerianMeanMotionAndPeriod() {
86          // GIVEN
87          final double aIn = 1.;
88          final TestFieldOrbit testOrbit = new TestFieldOrbit(aIn);
89          // WHEN
90          final Complex meanMotion = testOrbit.getKeplerianMeanMotion();
91          final Complex period = testOrbit.getKeplerianPeriod();
92          final double actualValue = period.multiply(meanMotion).getReal();
93          // THEN
94          final double expectedValue = MathUtils.TWO_PI;
95          Assertions.assertEquals(expectedValue, actualValue, 1e-10);
96      }
97  
98      @Test
99      void testIsElliptical() {
100         templateTestIsElliptical(1.);
101     }
102 
103     @Test
104     void testIsNotElliptical() {
105         templateTestIsElliptical(-1.);
106     }
107 
108     private void templateTestIsElliptical(final double aIn) {
109         // GIVEN
110         final TestFieldOrbit testOrbit = new TestFieldOrbit(aIn);
111         // WHEN
112         final boolean actualValue = testOrbit.isElliptical();
113         // THEN
114         final boolean expectedValue = aIn > 0.;
115         Assertions.assertEquals(expectedValue, actualValue);
116     }
117 
118     private static class TestFieldOrbit extends FieldOrbit<Complex> {
119 
120         final Complex a;
121 
122         protected TestFieldOrbit(final double aIn)
123                 throws IllegalArgumentException {
124             super(FramesFactory.getGCRF(), FieldAbsoluteDate.getArbitraryEpoch(ComplexField.getInstance()), Complex.ONE);
125             a = new Complex(aIn, 0.);
126         }
127 
128         @Override
129         public OrbitType getType() {
130             return null;
131         }
132 
133         @Override
134         public Orbit toOrbit() {
135             return null;
136         }
137 
138         @Override
139         public Complex getA() {
140             return this.a;
141         }
142 
143         @Override
144         public Complex getADot() {
145             return null;
146         }
147 
148         @Override
149         public Complex getEquinoctialEx() {
150             return null;
151         }
152 
153         @Override
154         public Complex getEquinoctialExDot() {
155             return null;
156         }
157 
158         @Override
159         public Complex getEquinoctialEy() {
160             return null;
161         }
162 
163         @Override
164         public Complex getEquinoctialEyDot() {
165             return null;
166         }
167 
168         @Override
169         public Complex getHx() {
170             return null;
171         }
172 
173         @Override
174         public Complex getHxDot() {
175             return null;
176         }
177 
178         @Override
179         public Complex getHy() {
180             return null;
181         }
182 
183         @Override
184         public Complex getHyDot() {
185             return null;
186         }
187 
188         @Override
189         public Complex getLE() {
190             return null;
191         }
192 
193         @Override
194         public Complex getLEDot() {
195             return null;
196         }
197 
198         @Override
199         public Complex getLv() {
200             return null;
201         }
202 
203         @Override
204         public Complex getLvDot() {
205             return null;
206         }
207 
208         @Override
209         public Complex getLM() {
210             return null;
211         }
212 
213         @Override
214         public Complex getLMDot() {
215             return null;
216         }
217 
218         @Override
219         public Complex getE() {
220             return null;
221         }
222 
223         @Override
224         public Complex getEDot() {
225             return null;
226         }
227 
228         @Override
229         public Complex getI() {
230             return null;
231         }
232 
233         @Override
234         public Complex getIDot() {
235             return null;
236         }
237 
238         @Override
239         public boolean hasNonKeplerianAcceleration() {
240             return false;
241         }
242 
243         @Override
244         protected FieldVector3D<Complex> initPosition() {
245             return new FieldVector3D<>(getField(), new Vector3D(a.getReal(), 0., 0.));
246         }
247 
248         @Override
249         protected TimeStampedFieldPVCoordinates<Complex> initPVCoordinates() {
250             final FieldPVCoordinates<Complex> fieldPVCoordinates = new FieldPVCoordinates<>(initPosition(),
251                     FieldVector3D.getZero(getField()));
252             return new TimeStampedFieldPVCoordinates<>(getDate(), fieldPVCoordinates);
253         }
254 
255         @Override
256         public FieldOrbit<Complex> inFrame(Frame inertialFrame) {
257             return null;
258         }
259 
260         @Override
261         public FieldOrbit<Complex> shiftedBy(Complex dt) {
262             return shiftedBy(dt.getReal());
263         }
264 
265         @Override
266         public FieldOrbit<Complex> shiftedBy(double dt) {
267             return new TestFieldOrbit(a.getReal());
268         }
269 
270         @Override
271         protected Complex[][] computeJacobianMeanWrtCartesian() {
272             return null;
273         }
274 
275         @Override
276         protected Complex[][] computeJacobianEccentricWrtCartesian() {
277             return null;
278         }
279 
280         @Override
281         protected Complex[][] computeJacobianTrueWrtCartesian() {
282             return null;
283         }
284 
285         @Override
286         public void addKeplerContribution(PositionAngleType type, Complex gm, Complex[] pDot) {
287 
288         }
289 
290     }
291     
292 }