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.data;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.analysis.UnivariateFunction;
21  import org.hipparchus.analysis.differentiation.DSFactory;
22  import org.hipparchus.analysis.differentiation.DerivativeStructure;
23  import org.hipparchus.analysis.differentiation.FiniteDifferencesDifferentiator;
24  import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction;
25  import org.hipparchus.util.Binary64;
26  import org.hipparchus.util.Binary64Field;
27  import org.hipparchus.util.FastMath;
28  import org.hipparchus.util.MathUtils;
29  import org.junit.jupiter.api.Assertions;
30  import org.junit.jupiter.api.BeforeEach;
31  import org.junit.jupiter.api.Test;
32  import org.orekit.Utils;
33  import org.orekit.errors.OrekitException;
34  import org.orekit.errors.OrekitMessages;
35  import org.orekit.time.AbsoluteDate;
36  import org.orekit.time.FieldAbsoluteDate;
37  import org.orekit.time.TimeScale;
38  import org.orekit.time.TimeScalesFactory;
39  import org.orekit.utils.Constants;
40  import org.orekit.utils.IERSConventions;
41  
42  import java.io.BufferedReader;
43  import java.io.ByteArrayInputStream;
44  import java.io.IOException;
45  import java.io.InputStream;
46  import java.io.InputStreamReader;
47  import java.lang.reflect.InvocationTargetException;
48  import java.lang.reflect.Method;
49  import java.nio.charset.StandardCharsets;
50  import java.util.Arrays;
51  import java.util.function.Function;
52  
53  public class FundamentalNutationArgumentsTest {
54  
55      @Test
56      public void testNoStream() {
57          try {
58              new FundamentalNutationArguments(IERSConventions.IERS_2010, TimeScalesFactory.getTT(), null, "dummy");
59              Assertions.fail("an exception should have been thrown");
60          } catch (OrekitException oe) {
61              Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier());
62              Assertions.assertEquals("dummy", oe.getParts()[0]);
63          }
64      }
65  
66      @Test
67      public void testModifiedData() throws IOException {
68  
69          String directory = "/assets/org/orekit/IERS-conventions/";
70          InputStream is = getClass().getResourceAsStream(directory + "2010/nutation-arguments.txt");
71          BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
72          StringBuilder builder = new StringBuilder();
73          for (String line = reader.readLine(); line != null; line = reader.readLine()) {
74              builder.append(line);
75              builder.append('\n');
76          }
77          reader.close();
78          try {
79              // remove the line:
80              // F5 ≡ Ω = 125.04455501◦ − 6962890.5431″t + 7.4722″t² + 0.007702″t³ − 0.00005939″t⁴
81              String modified = builder.toString().replaceAll("F5[^\\n]+", "");
82              new FundamentalNutationArguments(IERSConventions.IERS_2010, null,
83                                               new ByteArrayInputStream(modified.getBytes()),
84                                               "modified-data");
85              Assertions.fail("an exception should have been thrown");
86          } catch (OrekitException oe) {
87              Assertions.assertEquals(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, oe.getSpecifier());
88          }
89      }
90  
91      @Test
92      public void testEnum() throws NoSuchMethodException, SecurityException,
93                                    IllegalAccessException, IllegalArgumentException,
94                                    InvocationTargetException {
95          Class<?> e = null;
96          for (final Class<?> c : FundamentalNutationArguments.class.getDeclaredClasses()) {
97              if (c.getName().endsWith("FundamentalName")) {
98                  e = c;
99              }
100         }
101         Method m = e.getDeclaredMethod("valueOf", String.class);
102         m.setAccessible(true);
103         for (String n : Arrays.asList("L", "L_PRIME", "F", "D", "OMEGA",
104                                       "L_ME", "L_VE", "L_E", "L_MA", "L_J", "L_SA", "L_U", "L_NE", "PA")) {
105             Assertions.assertEquals(n, m.invoke(null, n).toString());
106         }
107         try {
108             m.invoke(null, "inexistent");
109             Assertions.fail("an exception should have been thrown");
110         } catch (InvocationTargetException ite) {
111             Assertions.assertTrue(ite.getCause() instanceof IllegalArgumentException);
112         }
113     }
114 
115     @Test
116     public void testDotDouble() {
117         final IERSConventions conventions = IERSConventions.IERS_2010;
118         final TimeScale ut1 = TimeScalesFactory.getUT1(conventions, false);
119         final FundamentalNutationArguments fna = conventions.getNutationArguments(ut1);
120         final AbsoluteDate t0 = new AbsoluteDate(2002, 4, 7, 12, 34, 22.5, TimeScalesFactory.getUTC());
121         final UnivariateDifferentiableFunction gamma  = differentiate(fna, t0, b -> b.getGamma());
122         final UnivariateDifferentiableFunction l      = differentiate(fna, t0, b -> b.getL());
123         final UnivariateDifferentiableFunction lPrime = differentiate(fna, t0, b -> b.getLPrime());
124         final UnivariateDifferentiableFunction f      = differentiate(fna, t0, b -> b.getF());
125         final UnivariateDifferentiableFunction d      = differentiate(fna, t0, b -> b.getD());
126         final UnivariateDifferentiableFunction lMe    = differentiate(fna, t0, b -> b.getLMe());
127         final UnivariateDifferentiableFunction lVe    = differentiate(fna, t0, b -> b.getLVe());
128         final UnivariateDifferentiableFunction lE     = differentiate(fna, t0, b -> b.getLE());
129         final UnivariateDifferentiableFunction lMa    = differentiate(fna, t0, b -> b.getLMa());
130         final UnivariateDifferentiableFunction lJu    = differentiate(fna, t0, b -> b.getLJu());
131         final UnivariateDifferentiableFunction lSa    = differentiate(fna, t0, b -> b.getLSa());
132         final UnivariateDifferentiableFunction lUr    = differentiate(fna, t0, b -> b.getLUr());
133         final UnivariateDifferentiableFunction lNe    = differentiate(fna, t0, b -> b.getLNe());
134         final UnivariateDifferentiableFunction  pa    = differentiate(fna, t0, b -> b.getPa());
135         final DSFactory factory = new DSFactory(1, 1);
136         double maxErrorGamma  = 0;
137         double maxErrorL      = 0;
138         double maxErrorLPrime = 0;
139         double maxErrorF      = 0;
140         double maxErrorD      = 0;
141         double maxErrorLMe    = 0;
142         double maxErrorLVe    = 0;
143         double maxErrorLE     = 0;
144         double maxErrorLMa    = 0;
145         double maxErrorLJu    = 0;
146         double maxErrorLSa    = 0;
147         double maxErrorLUr    = 0;
148         double maxErrorLNe    = 0;
149         double maxErrorPa     = 0;
150         for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 60.0) {
151             BodiesElements be = fna.evaluateAll(t0.shiftedBy(dt));
152             DerivativeStructure dtDS = factory.variable(0, dt);
153             maxErrorGamma  = FastMath.max(maxErrorGamma,  FastMath.abs(gamma .value(dtDS).getPartialDerivative(1) - be.getGammaDot()));
154             maxErrorL      = FastMath.max(maxErrorL,      FastMath.abs(l     .value(dtDS).getPartialDerivative(1) - be.getLDot()));
155             maxErrorLPrime = FastMath.max(maxErrorLPrime, FastMath.abs(lPrime.value(dtDS).getPartialDerivative(1) - be.getLPrimeDot()));
156             maxErrorF      = FastMath.max(maxErrorF,      FastMath.abs(f     .value(dtDS).getPartialDerivative(1) - be.getFDot()));
157             maxErrorD      = FastMath.max(maxErrorD,      FastMath.abs(d     .value(dtDS).getPartialDerivative(1) - be.getDDot()));
158             maxErrorLMe    = FastMath.max(maxErrorLMe,    FastMath.abs(lMe   .value(dtDS).getPartialDerivative(1) - be.getLMeDot()));
159             maxErrorLVe    = FastMath.max(maxErrorLVe,    FastMath.abs(lVe   .value(dtDS).getPartialDerivative(1) - be.getLVeDot()));
160             maxErrorLE     = FastMath.max(maxErrorLE,     FastMath.abs(lE    .value(dtDS).getPartialDerivative(1) - be.getLEDot()));
161             maxErrorLMa    = FastMath.max(maxErrorLMa,    FastMath.abs(lMa   .value(dtDS).getPartialDerivative(1) - be.getLMaDot()));
162             maxErrorLJu    = FastMath.max(maxErrorLJu,    FastMath.abs(lJu   .value(dtDS).getPartialDerivative(1) - be.getLJuDot()));
163             maxErrorLSa    = FastMath.max(maxErrorLSa,    FastMath.abs(lSa   .value(dtDS).getPartialDerivative(1) - be.getLSaDot()));
164             maxErrorLUr    = FastMath.max(maxErrorLUr,    FastMath.abs(lUr   .value(dtDS).getPartialDerivative(1) - be.getLUrDot()));
165             maxErrorLNe    = FastMath.max(maxErrorLNe,    FastMath.abs(lNe   .value(dtDS).getPartialDerivative(1) - be.getLNeDot()));
166             maxErrorPa     = FastMath.max(maxErrorPa,     FastMath.abs(pa    .value(dtDS).getPartialDerivative(1) - be.getPaDot()));
167         }
168         Assertions.assertEquals(0, maxErrorGamma,  8.0e-13);
169         Assertions.assertEquals(0, maxErrorL,      1.0e-14);
170         Assertions.assertEquals(0, maxErrorLPrime, 6.0e-16);
171         Assertions.assertEquals(0, maxErrorF,      6.0e-15);
172         Assertions.assertEquals(0, maxErrorD,      6.0e-15);
173         Assertions.assertEquals(0, maxErrorLMe,    2.0e-15);
174         Assertions.assertEquals(0, maxErrorLVe,    5.0e-16);
175         Assertions.assertEquals(0, maxErrorLE,     3.0e-16);
176         Assertions.assertEquals(0, maxErrorLMa,    4.0e-16);
177         Assertions.assertEquals(0, maxErrorLJu,    3.0e-17);
178         Assertions.assertEquals(0, maxErrorLSa,    4.0e-17);
179         Assertions.assertEquals(0, maxErrorLUr,    1.0e-16);
180         Assertions.assertEquals(0, maxErrorLNe,    8.0e-17);
181         Assertions.assertEquals(0, maxErrorPa,     3.0e-20);
182     }
183 
184     private UnivariateDifferentiableFunction differentiate(final FundamentalNutationArguments fna, final AbsoluteDate t0,
185                                                            final Function<BodiesElements, Double> f) {
186         return new FiniteDifferencesDifferentiator(8, 10.0).differentiate(new UnivariateFunction() {
187             double angle = 0;
188             @Override
189             public double value(double t) {
190                 double raw = f.apply(fna.evaluateAll(t0.shiftedBy(t)));
191                 angle = MathUtils.normalizeAngle(raw, angle);
192                 return angle;
193             }
194         });
195     }
196 
197     @Test
198     public void testDotField() {
199         final IERSConventions conventions = IERSConventions.IERS_2010;
200         final TimeScale ut1 = TimeScalesFactory.getUT1(conventions, false);
201         final FundamentalNutationArguments fna = conventions.getNutationArguments(ut1);
202         final FieldAbsoluteDate<Binary64> t0 = new FieldAbsoluteDate<>(Binary64Field.getInstance(),
203                                                                         2002, 4, 7, 12, 34, 22.5, TimeScalesFactory.getUTC());
204         final UnivariateDifferentiableFunction gamma  = differentiate(fna, t0, b -> b.getGamma());
205         final UnivariateDifferentiableFunction l      = differentiate(fna, t0, b -> b.getL());
206         final UnivariateDifferentiableFunction lPrime = differentiate(fna, t0, b -> b.getLPrime());
207         final UnivariateDifferentiableFunction f      = differentiate(fna, t0, b -> b.getF());
208         final UnivariateDifferentiableFunction d      = differentiate(fna, t0, b -> b.getD());
209         final UnivariateDifferentiableFunction lMe    = differentiate(fna, t0, b -> b.getLMe());
210         final UnivariateDifferentiableFunction lVe    = differentiate(fna, t0, b -> b.getLVe());
211         final UnivariateDifferentiableFunction lE     = differentiate(fna, t0, b -> b.getLE());
212         final UnivariateDifferentiableFunction lMa    = differentiate(fna, t0, b -> b.getLMa());
213         final UnivariateDifferentiableFunction lJu    = differentiate(fna, t0, b -> b.getLJu());
214         final UnivariateDifferentiableFunction lSa    = differentiate(fna, t0, b -> b.getLSa());
215         final UnivariateDifferentiableFunction lUr    = differentiate(fna, t0, b -> b.getLUr());
216         final UnivariateDifferentiableFunction lNe    = differentiate(fna, t0, b -> b.getLNe());
217         final UnivariateDifferentiableFunction  pa    = differentiate(fna, t0, b -> b.getPa());
218         final DSFactory factory = new DSFactory(1, 1);
219         double maxErrorGamma  = 0;
220         double maxErrorL      = 0;
221         double maxErrorLPrime = 0;
222         double maxErrorF      = 0;
223         double maxErrorD      = 0;
224         double maxErrorLMe    = 0;
225         double maxErrorLVe    = 0;
226         double maxErrorLE     = 0;
227         double maxErrorLMa    = 0;
228         double maxErrorLJu    = 0;
229         double maxErrorLSa    = 0;
230         double maxErrorLUr    = 0;
231         double maxErrorLNe    = 0;
232         double maxErrorPa     = 0;
233         for (double dt = 0; dt < Constants.JULIAN_DAY; dt += 60.0) {
234             FieldBodiesElements<Binary64> be = fna.evaluateAll(t0.shiftedBy(dt));
235             DerivativeStructure dtDS = factory.variable(0, dt);
236             maxErrorGamma  = FastMath.max(maxErrorGamma,  FastMath.abs(gamma .value(dtDS).getPartialDerivative(1) - be.getGammaDot().getReal()));
237             maxErrorL      = FastMath.max(maxErrorL,      FastMath.abs(l     .value(dtDS).getPartialDerivative(1) - be.getLDot().getReal()));
238             maxErrorLPrime = FastMath.max(maxErrorLPrime, FastMath.abs(lPrime.value(dtDS).getPartialDerivative(1) - be.getLPrimeDot().getReal()));
239             maxErrorF      = FastMath.max(maxErrorF,      FastMath.abs(f     .value(dtDS).getPartialDerivative(1) - be.getFDot().getReal()));
240             maxErrorD      = FastMath.max(maxErrorD,      FastMath.abs(d     .value(dtDS).getPartialDerivative(1) - be.getDDot().getReal()));
241             maxErrorLMe    = FastMath.max(maxErrorLMe,    FastMath.abs(lMe   .value(dtDS).getPartialDerivative(1) - be.getLMeDot().getReal()));
242             maxErrorLVe    = FastMath.max(maxErrorLVe,    FastMath.abs(lVe   .value(dtDS).getPartialDerivative(1) - be.getLVeDot().getReal()));
243             maxErrorLE     = FastMath.max(maxErrorLE,     FastMath.abs(lE    .value(dtDS).getPartialDerivative(1) - be.getLEDot().getReal()));
244             maxErrorLMa    = FastMath.max(maxErrorLMa,    FastMath.abs(lMa   .value(dtDS).getPartialDerivative(1) - be.getLMaDot().getReal()));
245             maxErrorLJu    = FastMath.max(maxErrorLJu,    FastMath.abs(lJu   .value(dtDS).getPartialDerivative(1) - be.getLJuDot().getReal()));
246             maxErrorLSa    = FastMath.max(maxErrorLSa,    FastMath.abs(lSa   .value(dtDS).getPartialDerivative(1) - be.getLSaDot().getReal()));
247             maxErrorLUr    = FastMath.max(maxErrorLUr,    FastMath.abs(lUr   .value(dtDS).getPartialDerivative(1) - be.getLUrDot().getReal()));
248             maxErrorLNe    = FastMath.max(maxErrorLNe,    FastMath.abs(lNe   .value(dtDS).getPartialDerivative(1) - be.getLNeDot().getReal()));
249             maxErrorPa     = FastMath.max(maxErrorPa,     FastMath.abs(pa    .value(dtDS).getPartialDerivative(1) - be.getPaDot().getReal()));
250         }
251         Assertions.assertEquals(0, maxErrorGamma,  8.0e-13);
252         Assertions.assertEquals(0, maxErrorL,      1.0e-14);
253         Assertions.assertEquals(0, maxErrorLPrime, 6.0e-16);
254         Assertions.assertEquals(0, maxErrorF,      6.0e-15);
255         Assertions.assertEquals(0, maxErrorD,      6.0e-15);
256         Assertions.assertEquals(0, maxErrorLMe,    2.0e-15);
257         Assertions.assertEquals(0, maxErrorLVe,    5.0e-16);
258         Assertions.assertEquals(0, maxErrorLE,     3.0e-16);
259         Assertions.assertEquals(0, maxErrorLMa,    4.0e-16);
260         Assertions.assertEquals(0, maxErrorLJu,    3.0e-17);
261         Assertions.assertEquals(0, maxErrorLSa,    4.0e-17);
262         Assertions.assertEquals(0, maxErrorLUr,    1.0e-16);
263         Assertions.assertEquals(0, maxErrorLNe,    8.0e-17);
264         Assertions.assertEquals(0, maxErrorPa,     3.0e-20);
265     }
266 
267     private <T extends CalculusFieldElement<T>> UnivariateDifferentiableFunction differentiate(final FundamentalNutationArguments fna, final FieldAbsoluteDate<T> t0,
268                                                                                            final Function<FieldBodiesElements<T>, T> f) {
269         return new FiniteDifferencesDifferentiator(8, 10.0).differentiate(new UnivariateFunction() {
270             double angle = 0;
271             @Override
272             public double value(double t) {
273                 double raw = f.apply(fna.evaluateAll(t0.shiftedBy(t))).getReal();
274                 angle = MathUtils.normalizeAngle(raw, angle);
275                 return angle;
276             }
277         });
278     }
279 
280     @BeforeEach
281     public void setUp() {
282         Utils.setDataRoot("compressed-data");
283     }
284 
285 }