1   /* Copyright 2002-2021 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.PolynomialFunction;
28  import org.hipparchus.analysis.polynomials.PolynomialsUtils;
29  
30  /** Provider of the Jacobi polynomials P<sub>l</sub><sup>v,w</sup>.
31   * <p>
32   * This class is used for {@link
33   * org.orekit.propagation.semianalytical.dsst.forces.DSSTTesseral
34   * tesseral contribution} computation.
35   * </p>
36   *
37   * @author Nicolas Bernard
38   * @since 6.1
39   */
40  public class JacobiPolynomials {
41  
42      /** Storage map. */
43      private static final Map<JacobiKey, List<PolynomialFunction>> MAP =
44              new HashMap<JacobiPolynomials.JacobiKey, List<PolynomialFunction>>();
45  
46      /** Private constructor as class is a utility. */
47      private JacobiPolynomials() {
48      }
49  
50      /** Returns the value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup> evaluated at γ.
51       * <p>
52       * This method is guaranteed to be thread-safe
53       * </p>
54       * @param l degree of the polynomial
55       * @param v v value
56       * @param w w value
57       * @param gamma γ value
58       * @return value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup>(γ)
59       * @since 10.2
60       */
61      public static Gradient getValue(final int l, final int v, final int w, final Gradient gamma) {
62  
63          final List<PolynomialFunction> polyList;
64          synchronized (MAP) {
65  
66              final JacobiKey key = new JacobiKey(v, w);
67  
68              // Check the existence of the corresponding key in the map.
69              if (!MAP.containsKey(key)) {
70                  MAP.put(key, new ArrayList<PolynomialFunction>());
71              }
72  
73              polyList = MAP.get(key);
74  
75          }
76  
77          final PolynomialFunction polynomial;
78          synchronized (polyList) {
79              // If the l-th degree polynomial has not been computed yet, the polynomials
80              // up to this degree are computed.
81              for (int degree = polyList.size(); degree <= l; degree++) {
82                  polyList.add(degree, PolynomialsUtils.createJacobiPolynomial(degree, v, w));
83              }
84              polynomial = polyList.get(l);
85          }
86  
87          // compute value and derivative
88          return polynomial.value(gamma);
89  
90      }
91  
92      /** Returns the value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup> evaluated at γ.
93       * <p>
94       * This method is guaranteed to be thread-safe
95       * </p>
96       * @param <T> the type of the field elements
97       * @param l degree of the polynomial
98       * @param v v value
99       * @param w w value
100      * @param gamma γ value
101      * @return value and derivatives of the Jacobi polynomial P<sub>l</sub><sup>v,w</sup>(γ)
102      * @since 10.2
103      */
104     public static <T extends CalculusFieldElement<T>> FieldGradient<T> getValue(final int l, final int v, final int w,
105                                                                             final FieldGradient<T> gamma) {
106 
107         final List<PolynomialFunction> polyList;
108         synchronized (MAP) {
109 
110             final JacobiKey key = new JacobiKey(v, w);
111 
112             // Check the existence of the corresponding key in the map.
113             if (!MAP.containsKey(key)) {
114                 MAP.put(key, new ArrayList<PolynomialFunction>());
115             }
116 
117             polyList = MAP.get(key);
118 
119         }
120 
121         final PolynomialFunction polynomial;
122         synchronized (polyList) {
123             // If the l-th degree polynomial has not been computed yet, the polynomials
124             // up to this degree are computed.
125             for (int degree = polyList.size(); degree <= l; degree++) {
126                 polyList.add(degree, PolynomialsUtils.createJacobiPolynomial(degree, v, w));
127             }
128             polynomial = polyList.get(l);
129         }
130 
131         // compute value and derivative
132         return polynomial.value(gamma);
133 
134     }
135 
136     /** Inner class for Jacobi polynomials keys.
137      * <p>
138      * Please note that this class is not original content but is a copy from the
139      * Hipparchus library. This library is published under the
140      * Apache License, version 2.0.
141      * </p>
142      *
143      * @see org.hipparchus.analysis.polynomials.PolynomialsUtils
144      */
145     private static class JacobiKey {
146 
147         /** First exponent. */
148         private final int v;
149 
150         /** Second exponent. */
151         private final int w;
152 
153         /** Simple constructor.
154          * @param v first exponent
155          * @param w second exponent
156          */
157         JacobiKey(final int v, final int w) {
158             this.v = v;
159             this.w = w;
160         }
161 
162         /** Get hash code.
163          * @return hash code
164          */
165         @Override
166         public int hashCode() {
167             return (v << 16) ^ w;
168         }
169 
170         /** Check if the instance represent the same key as another instance.
171          * @param key other key
172          * @return true if the instance and the other key refer to the same polynomial
173          */
174         @Override
175         public boolean equals(final Object key) {
176 
177             if (!(key instanceof JacobiKey)) {
178                 return false;
179             }
180 
181             final JacobiKey otherK = (JacobiKey) key;
182             return v == otherK.v && w == otherK.w;
183 
184         }
185     }
186 
187 }