1 /* Copyright 2002-2024 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 java.util.Arrays;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.util.FastMath;
23 import org.hipparchus.util.FieldSinCos;
24 import org.hipparchus.util.MathArrays;
25 import org.hipparchus.util.SinCos;
26 import org.orekit.errors.OrekitInternalError;
27 import org.orekit.utils.Constants;
28
29 /** Base class for nutation series terms.
30 * @author Luc Maisonobe
31 * @see PoissonSeries
32 */
33 abstract class SeriesTerm {
34
35 /** Coefficients for the sine part. */
36 private double[][] sinCoeff;
37
38 /** Coefficients for the cosine part. */
39 private double[][] cosCoeff;
40
41 /** Simple constructor for the base class.
42 */
43 protected SeriesTerm() {
44 this.sinCoeff = new double[0][0];
45 this.cosCoeff = new double[0][0];
46 }
47
48 /** Get the degree of the function component.
49 * @param index index of the function component (must be less than dimension)
50 * @return degree of the function component
51 */
52 public int getDegree(final int index) {
53 return sinCoeff[index].length - 1;
54 }
55
56 /** Add a pair of values to existing term coefficients.
57 * <p>
58 * Despite it would seem logical to simply set coefficients
59 * rather than add to them, this does not work for some IERS
60 * files. As an example in table 5.3a in IERS conventions 2003,
61 * the coefficients for luni-solar term for 2F+Ω with period
62 * 13.633 days appears twice with different coefficients, as
63 * well as term for 2(F+D+Ω)+l with period 5.643 days, term for
64 * 2(F+D+Ω)-l with period 9.557 days, term for 2(Ω-l') with
65 * period -173.318 days, term for 2D-l with period 31.812 days ...
66 * 35 different duplicated terms have been identified in the
67 * tables 5.3a and 5.3b in IERS conventions 2003.
68 * The coefficients read in lines duplicating a term must be
69 * added together.
70 * </p>
71 * @param index index of the components (will automatically
72 * increase dimension if needed)
73 * @param degree degree of the coefficients, may be negative if
74 * the term does not contribute to component (will automatically
75 * increase {@link #getDegree() degree} of the component if needed)
76 * @param sinID coefficient for the sine part, at index and degree
77 * @param cosID coefficient for the cosine part, at index and degree
78 */
79 public void add(final int index, final int degree,
80 final double sinID, final double cosID) {
81 sinCoeff = extendArray(index, degree, sinCoeff);
82 cosCoeff = extendArray(index, degree, cosCoeff);
83 if (degree >= 0) {
84 sinCoeff[index][degree] += sinID;
85 cosCoeff[index][degree] += cosID;
86 }
87 }
88
89 /** Get a coefficient for the sine part.
90 * @param index index of the function component (must be less than dimension)
91 * @param degree degree of the coefficients
92 * (must be less than {@link #getDegree() degree} for the component)
93 * @return coefficient for the sine part, at index and degree
94 */
95 public double getSinCoeff(final int index, final int degree) {
96 return sinCoeff[index][degree];
97 }
98
99 /** Get a coefficient for the cosine part.
100 * @param index index of the function component (must be less than dimension)
101 * @param degree degree of the coefficients
102 * (must be less than {@link #getDegree() degree} for the component)
103 * @return coefficient for the cosine part, at index and degree
104 */
105 public double getCosCoeff(final int index, final int degree) {
106 return cosCoeff[index][degree];
107 }
108
109 /** Evaluate the value of the series term.
110 * @param elements bodies elements for nutation
111 * @return value of the series term
112 */
113 public double[] value(final BodiesElements elements) {
114
115 // preliminary computation
116 final double tc = elements.getTC();
117 final double a = argument(elements);
118 final SinCos sc = FastMath.sinCos(a);
119
120 // compute each function
121 final double[] values = new double[sinCoeff.length];
122 for (int i = 0; i < values.length; ++i) {
123 double s = 0;
124 double c = 0;
125 for (int j = sinCoeff[i].length - 1; j >= 0; --j) {
126 s = s * tc + sinCoeff[i][j];
127 c = c * tc + cosCoeff[i][j];
128 }
129 values[i] = s * sc.sin() + c * sc.cos();
130 }
131
132 return values;
133
134 }
135
136 /** Evaluate the time derivative of the series term.
137 * @param elements bodies elements for nutation
138 * @return time derivative of the series term
139 */
140 public double[] derivative(final BodiesElements elements) {
141
142 // preliminary computation
143 final double tc = elements.getTC();
144 final double a = argument(elements);
145 final double aDot = argumentDerivative(elements);
146 final SinCos sc = FastMath.sinCos(a);
147
148 // compute each function
149 final double[] derivatives = new double[sinCoeff.length];
150 for (int i = 0; i < derivatives.length; ++i) {
151 double s = 0;
152 double c = 0;
153 double sDot = 0;
154 double cDot = 0;
155 if (sinCoeff[i].length > 0) {
156 for (int j = sinCoeff[i].length - 1; j > 0; --j) {
157 s = s * tc + sinCoeff[i][j];
158 c = c * tc + cosCoeff[i][j];
159 sDot = sDot * tc + j * sinCoeff[i][j];
160 cDot = cDot * tc + j * cosCoeff[i][j];
161 }
162 s = s * tc + sinCoeff[i][0];
163 c = c * tc + cosCoeff[i][0];
164 sDot /= Constants.JULIAN_CENTURY;
165 cDot /= Constants.JULIAN_CENTURY;
166 }
167 derivatives[i] = (sDot - c * aDot) * sc.sin() + (cDot + s * aDot) * sc.cos();
168 }
169
170 return derivatives;
171
172 }
173
174 /** Compute the argument for the current date.
175 * @param elements luni-solar and planetary elements for the current date
176 * @return current value of the argument
177 */
178 protected abstract double argument(BodiesElements elements);
179
180 /** Compute the time derivative of the argument for the current date.
181 * @param elements luni-solar and planetary elements for the current date
182 * @return current time derivative of the argument
183 */
184 protected abstract double argumentDerivative(BodiesElements elements);
185
186 /** Evaluate the value of the series term.
187 * @param elements bodies elements for nutation
188 * @param <T> the type of the field elements
189 * @return value of the series term
190 */
191 public <T extends CalculusFieldElement<T>> T[] value(final FieldBodiesElements<T> elements) {
192
193 // preliminary computation
194 final T tc = elements.getTC();
195 final T a = argument(elements);
196 final FieldSinCos<T> sc = FastMath.sinCos(a);
197
198 // compute each function
199 final T[] values = MathArrays.buildArray(tc.getField(), sinCoeff.length);
200 for (int i = 0; i < values.length; ++i) {
201 T s = tc.getField().getZero();
202 T c = tc.getField().getZero();
203 for (int j = sinCoeff[i].length - 1; j >= 0; --j) {
204 s = s.multiply(tc).add(sinCoeff[i][j]);
205 c = c.multiply(tc).add(cosCoeff[i][j]);
206 }
207 values[i] = s.multiply(sc.sin()).add(c.multiply(sc.cos()));
208 }
209
210 return values;
211
212 }
213
214 /** Evaluate the time derivative of the series term.
215 * @param elements bodies elements for nutation
216 * @param <T> the type of the field elements
217 * @return time derivative of the series term
218 */
219 public <T extends CalculusFieldElement<T>> T[] derivative(final FieldBodiesElements<T> elements) {
220
221 // preliminary computation
222 final T tc = elements.getTC();
223 final T a = argument(elements);
224 final T aDot = argumentDerivative(elements);
225 final FieldSinCos<T> sc = FastMath.sinCos(a);
226
227 // compute each function
228 final T[] derivatives = MathArrays.buildArray(tc.getField(), sinCoeff.length);
229 for (int i = 0; i < derivatives.length; ++i) {
230 T s = tc.getField().getZero();
231 T c = tc.getField().getZero();
232 T sDot = tc.getField().getZero();
233 T cDot = tc.getField().getZero();
234 if (sinCoeff[i].length > 0) {
235 for (int j = sinCoeff[i].length - 1; j > 0; --j) {
236 s = s.multiply(tc).add(sinCoeff[i][j]);
237 c = c.multiply(tc).add(cosCoeff[i][j]);
238 sDot = sDot.multiply(tc).add(j * sinCoeff[i][j]);
239 cDot = cDot.multiply(tc).add(j * cosCoeff[i][j]);
240 }
241 s = s.multiply(tc).add(sinCoeff[i][0]);
242 c = c.multiply(tc).add(cosCoeff[i][0]);
243 sDot = sDot.divide(Constants.JULIAN_CENTURY);
244 cDot = cDot.divide(Constants.JULIAN_CENTURY);
245 }
246 derivatives[i] = sDot.subtract(c.multiply(aDot)).multiply(sc.sin()).
247 add(cDot.add(s.multiply(aDot)).multiply(sc.cos()));
248 }
249
250 return derivatives;
251
252 }
253
254 /** Compute the argument for the current date.
255 * @param elements luni-solar and planetary elements for the current date
256 * @param <T> the type of the field elements
257 * @return current value of the argument
258 */
259 protected abstract <T extends CalculusFieldElement<T>> T argument(FieldBodiesElements<T> elements);
260
261 /** Compute the time derivative of the argument for the current date.
262 * @param elements luni-solar and planetary elements for the current date
263 * @param <T> the type of the field elements
264 * @return current time derivative of the argument
265 */
266 protected abstract <T extends CalculusFieldElement<T>> T argumentDerivative(FieldBodiesElements<T> elements);
267
268 /** Factory method for building the appropriate object.
269 * <p>The method checks the null coefficients and build an instance
270 * of an appropriate type to avoid too many unnecessary multiplications
271 * by zero coefficients.</p>
272 * @param cGamma coefficient for γ = GMST + π tide parameter
273 * @param cL coefficient for mean anomaly of the Moon
274 * @param cLPrime coefficient for mean anomaly of the Sun
275 * @param cF coefficient for L - Ω where L is the mean longitude of the Moon
276 * @param cD coefficient for mean elongation of the Moon from the Sun
277 * @param cOmega coefficient for mean longitude of the ascending node of the Moon
278 * @param cMe coefficient for mean Mercury longitude
279 * @param cVe coefficient for mean Venus longitude
280 * @param cE coefficient for mean Earth longitude
281 * @param cMa coefficient for mean Mars longitude
282 * @param cJu coefficient for mean Jupiter longitude
283 * @param cSa coefficient for mean Saturn longitude
284 * @param cUr coefficient for mean Uranus longitude
285 * @param cNe coefficient for mean Neptune longitude
286 * @param cPa coefficient for general accumulated precession in longitude
287 * @return a nutation serie term instance well suited for the set of coefficients
288 */
289 public static SeriesTerm buildTerm(final int cGamma,
290 final int cL, final int cLPrime, final int cF,
291 final int cD, final int cOmega,
292 final int cMe, final int cVe, final int cE,
293 final int cMa, final int cJu, final int cSa,
294 final int cUr, final int cNe, final int cPa) {
295 if (cGamma == 0 && cL == 0 && cLPrime == 0 && cF == 0 && cD == 0 && cOmega == 0) {
296 return new PlanetaryTerm(cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa);
297 } else if (cGamma == 0 &&
298 cMe == 0 && cVe == 0 && cE == 0 && cMa == 0 && cJu == 0 &&
299 cSa == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
300 return new LuniSolarTerm(cL, cLPrime, cF, cD, cOmega);
301 } else if (cGamma != 0 &&
302 cMe == 0 && cVe == 0 && cE == 0 && cMa == 0 && cJu == 0 &&
303 cSa == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
304 return new TideTerm(cGamma, cL, cLPrime, cF, cD, cOmega);
305 } else if (cGamma == 0 && cLPrime == 0 && cUr == 0 && cNe == 0 && cPa == 0) {
306 return new NoFarPlanetsTerm(cL, cF, cD, cOmega,
307 cMe, cVe, cE, cMa, cJu, cSa);
308 } else if (cGamma == 0) {
309 return new GeneralTerm(cL, cLPrime, cF, cD, cOmega,
310 cMe, cVe, cE, cMa, cJu, cSa, cUr, cNe, cPa);
311 } else {
312 throw new OrekitInternalError(null);
313 }
314
315 }
316
317 /** Extend an array to hold at least index and degree.
318 * @param index index of the function
319 * @param degree degree of the coefficients
320 * @param array to extend
321 * @return extended array
322 */
323 private static double[][] extendArray(final int index, final int degree,
324 final double[][] array) {
325
326 // extend the number of rows if needed
327 final double[][] extended;
328 if (array.length > index) {
329 extended = array;
330 } else {
331 final int rows = index + 1;
332 extended = new double[rows][];
333 System.arraycopy(array, 0, extended, 0, array.length);
334 Arrays.fill(extended, array.length, index + 1, new double[0]);
335 }
336
337 // extend the number of elements in the row if needed
338 extended[index] = extendArray(degree, extended[index]);
339
340 return extended;
341
342 }
343
344 /** Extend an array to hold at least degree.
345 * @param degree degree of the coefficients
346 * @param array to extend
347 * @return extended array
348 */
349 private static double[] extendArray(final int degree, final double[] array) {
350 // extend the number of elements if needed
351 if (array.length > degree) {
352 return array;
353 } else {
354 final double[] extended = new double[degree + 1];
355 System.arraycopy(array, 0, extended, 0, array.length);
356 return extended;
357 }
358 }
359
360 }