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.propagation.semianalytical.dsst.utilities;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.hipparchus.CalculusFieldElement;
25 import org.hipparchus.analysis.differentiation.FieldGradient;
26 import org.hipparchus.analysis.differentiation.Gradient;
27 import org.hipparchus.analysis.polynomials.JacobiKey;
28 import org.hipparchus.analysis.polynomials.PolynomialFunction;
29 import org.hipparchus.analysis.polynomials.PolynomialsUtils;
30 import org.orekit.propagation.semianalytical.dsst.forces.DSSTThirdBody;
31
32 /** Provider of the Jacobi polynomials P<sub>l</sub><sup>v,w</sup>.
33 * <p>
34 * This class is used for {@link
35 * org.orekit.propagation.semianalytical.dsst.forces.DSSTTesseral
36 * tesseral contribution} computation and {@link DSSTThirdBody}.
37 * </p>
38 *
39 * @author Nicolas Bernard
40 * @since 6.1
41 */
42 public class JacobiPolynomials {
43
44 /** Storage map. */
45 private static final Map<JacobiKey, List<PolynomialFunction>> MAP = new HashMap<>();
46
47 /** Private constructor as class is a utility. */
48 private JacobiPolynomials() {
49 }
50
51 /** Returns the value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup> evaluated at γ.
52 * <p>This method is guaranteed to be thread-safe
53 * <p>It was added to improve performances of DSST propagation with tesseral gravity field or third-body perturbations.
54 * <p>See issue <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1098">1098</a>.
55 * <p>It appeared the "Gradient" version was degrading performances. This last was however kept for validation purposes.
56 * @param l degree of the polynomial
57 * @param v v value
58 * @param w w value
59 * @param x x value
60 * @return value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup>(γ)
61 * @since 11.3.3
62 */
63 public static double[] getValueAndDerivative(final int l, final int v, final int w, final double x) {
64 // compute value and derivative
65 return getValueAndDerivative(computePolynomial(l, v, w), x);
66 }
67
68 /** Get value and 1st-order of a mono-variate polynomial.
69 *
70 * <p> This method was added to improve performances of DSST propagation with tesseral gravity field or third-body perturbations.
71 * <p> See issue <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1098">1098</a>.
72 * @param polynomial polynomial to evaluate
73 * @param x value to evaluate on
74 * @return value and 1s-order derivative as a double array
75 * @since 11.3.3
76 */
77 private static double[] getValueAndDerivative(final PolynomialFunction polynomial, final double x) {
78
79 // Polynomial coefficients
80 final double[] coefficients = polynomial.getCoefficients();
81
82 // Degree of the polynomial
83 final int degree = polynomial.degree();
84
85 // Initialize value and 1st-order derivative
86 double value = coefficients[degree];
87 double derivative = value * degree;
88 for (int j = degree - 1; j >= 1; j--) {
89
90 // Increment both value and derivative
91 final double coef = coefficients[j];
92 value = value * x + coef;
93 derivative = derivative * x + coef * j;
94 }
95 // If degree > 0, perform last operation
96 if (degree > 0) {
97 value = value * x + coefficients[0];
98 }
99
100 // Return value and 1st-order derivative as double array
101 return new double[] {value, derivative};
102 }
103
104 /** Returns the value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup> evaluated at γ.
105 *
106 * <p>This method is guaranteed to be thread-safe
107 * <p>It's not used in the code anymore, see {@link #getValueAndDerivative(int, int, int, double)}, but was kept for validation purpose.
108 * @param l degree of the polynomial
109 * @param v v value
110 * @param w w value
111 * @param gamma γ value
112 * @return value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup>(γ)
113 * @since 10.2
114 */
115 public static Gradient getValue(final int l, final int v, final int w, final Gradient gamma) {
116 // compute value and derivative
117 return computePolynomial(l, v, w).value(gamma);
118 }
119
120 /** Returns the value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup> evaluated at γ.
121 * <p>
122 * This method is guaranteed to be thread-safe
123 * </p>
124 * @param <T> the type of the field elements
125 * @param l degree of the polynomial
126 * @param v v value
127 * @param w w value
128 * @param gamma γ value
129 * @return value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup>(γ)
130 * @since 10.2
131 */
132 public static <T extends CalculusFieldElement<T>> FieldGradient<T> getValue(final int l, final int v, final int w,
133 final FieldGradient<T> gamma) {
134 // compute value and derivative
135 return computePolynomial(l, v, w).value(gamma);
136
137 }
138
139 /** Initializes the polynomial to evalutate.
140 * @param l degree of the polynomial
141 * @param v v value
142 * @param w w value
143 * @return the polynomial to evaluate
144 */
145 private static PolynomialFunction computePolynomial(final int l, final int v, final int w) {
146 final List<PolynomialFunction> polyList;
147 synchronized (MAP) {
148
149 final JacobiKey key = new JacobiKey(v, w);
150
151 // Check the existence of the corresponding key in the map.
152 if (!MAP.containsKey(key)) {
153 MAP.put(key, new ArrayList<>());
154 }
155
156 polyList = MAP.get(key);
157
158 }
159
160 final PolynomialFunction polynomial;
161 synchronized (polyList) {
162 // If the l-th degree polynomial has not been computed yet, the polynomials
163 // up to this degree are computed.
164 for (int degree = polyList.size(); degree <= l; degree++) {
165 polyList.add(degree, PolynomialsUtils.createJacobiPolynomial(degree, v, w));
166 }
167 polynomial = polyList.get(l);
168 }
169
170 return polynomial;
171 }
172 }