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.hansen;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.analysis.polynomials.PolynomialFunction;
22  import org.hipparchus.util.FastMath;
23  import org.hipparchus.util.MathArrays;
24  
25  /**
26   * Hansen coefficients K(t,n,s) for t=0 and n > 0.
27   * <p>
28   * Implements Collins 4-254 or Danielson 2.7.3-(7) for Hansen Coefficients and
29   * Danielson 3.2-(3) for derivatives. The recursions are transformed into
30   * composition of linear transformations to obtain the associated polynomials
31   * for coefficients and their derivatives - see Petre's paper
32   *
33   * @author Petre Bazavan
34   * @author Lucian Barbulescu
35   * @author Bryan Cazabonne
36   * @param <T> type of the field elements
37   */
38  public class FieldHansenThirdBodyLinear <T extends CalculusFieldElement<T>> {
39  
40      /** The number of coefficients that will be computed with a set of roots. */
41      private  static final int SLICE = 10;
42  
43      /**
44       * The first vector of polynomials associated to Hansen coefficients and
45       * derivatives.
46       */
47      private final PolynomialFunction[][] mpvec;
48  
49      /** The second vector of polynomials associated only to derivatives. */
50      private final PolynomialFunction[][] mpvecDeriv;
51  
52      /** The Hansen coefficients used as roots. */
53      private final T[][] hansenRoot;
54  
55      /** The derivatives of the Hansen coefficients used as roots. */
56      private final T[][] hansenDerivRoot;
57  
58      /** The number of slices needed to compute the coefficients. */
59      private final int numSlices;
60  
61      /** The s index. */
62      private final int s;
63  
64      /** (-1)<sup>s</sup> * (2*s + 1)!! / (s+1)!  */
65      private double twosp1dfosp1f;
66  
67      /** (-1)<sup>s</sup> * (2*s + 1)!! / (s+2)!  */
68      private final double twosp1dfosp2f;
69  
70      /** (-1)<sup>s</sup> * 2 * (2*s + 1)!! / (s+2)!  */
71      private final double two2sp1dfosp2f;
72  
73      /** (2*s + 3). */
74      private final double twosp3;
75  
76      /**
77       * Constructor.
78       *
79       * @param nMax the maximum value of n
80       * @param s the value of s
81       * @param field field used by default
82       */
83      public FieldHansenThirdBodyLinear(final int nMax, final int s, final Field<T> field) {
84          // initialise fields
85          this.s = s;
86  
87          //Compute the fields that will be used to determine the initial values for the coefficients
88          this.twosp1dfosp1f = (s % 2 == 0) ? 1.0 : -1.0;
89          for (int i = s; i >= 1; i--) {
90              this.twosp1dfosp1f *= (2.0 * i + 1.0) / (i + 1.0);
91          }
92  
93          this.twosp1dfosp2f = this.twosp1dfosp1f / (s + 2.);
94          this.twosp3 = 2 * s + 3;
95          this.two2sp1dfosp2f = 2 * this.twosp1dfosp2f;
96  
97          // initialization of structures for stored data
98          mpvec = new PolynomialFunction[nMax + 1][];
99          mpvecDeriv = new PolynomialFunction[nMax + 1][];
100 
101         this.numSlices  = FastMath.max(1, (nMax - s + SLICE - 2) / SLICE);
102 
103         hansenRoot      = MathArrays.buildArray(field, numSlices, 2);
104         hansenDerivRoot = MathArrays.buildArray(field, numSlices, 2);
105 
106         // Prepare the database of the associated polynomials
107         HansenUtilities.generateThirdBodyPolynomials(s, nMax, SLICE, s,
108                                                      mpvec, mpvecDeriv);
109 
110     }
111 
112     /**
113      * Compute the initial values (see Collins, 4-255, 4-256 and 4.259)
114      * <p>
115      * K₀<sup>s, s</sup> = (-1)<sup>s</sup> * ( (2*s+1)!! / (s+1)! )
116      * </p>
117      * <p>
118      * K₀<sup>s+1, s</sup> = (-1)<sup>s</sup> * ( (2*s+1)!! / (s+2)!
119      * ) * (2*s+3 - χ<sup>-2</sup>)
120      * </p>
121      * <p>
122      * dK₀<sup>s+1, s</sup> / dχ = = (-1)<sup>s</sup> * 2 * (
123      * (2*s+1)!! / (s+2)! ) * χ<sup>-3</sup>
124      * </p>
125      * @param chitm1 sqrt(1 - e²)
126      * @param chitm2 sqrt(1 - e²)²
127      * @param chitm3 sqrt(1 - e²)³
128      */
129     public void computeInitValues(final T chitm1, final T chitm2, final T chitm3) {
130         final Field<T> field = chitm2.getField();
131         final T zero = field.getZero();
132         this.hansenRoot[0][0] = zero.newInstance(twosp1dfosp1f);
133         this.hansenRoot[0][1] = (chitm2.negate().add(this.twosp3)).multiply(this.twosp1dfosp2f);
134         this.hansenDerivRoot[0][0] = zero;
135         this.hansenDerivRoot[0][1] = chitm3.multiply(two2sp1dfosp2f);
136 
137         for (int i = 1; i < numSlices; i++) {
138             for (int j = 0; j < 2; j++) {
139                 // Get the required polynomials
140                 final PolynomialFunction[] mv = mpvec[s + (i * SLICE) + j];
141                 final PolynomialFunction[] sv = mpvecDeriv[s + (i * SLICE) + j];
142 
143                 //Compute the root derivatives
144                 hansenDerivRoot[i][j] = mv[1].value(chitm1).multiply(hansenDerivRoot[i - 1][1]).
145                                     add(mv[0].value(chitm1).multiply(hansenDerivRoot[i - 1][0])).
146                                     add(sv[1].value(chitm1).multiply(hansenRoot[i - 1][1])).
147                                     add(sv[0].value(chitm1).multiply(hansenRoot[i - 1][0]));
148 
149                 //Compute the root Hansen coefficients
150                 hansenRoot[i][j] =  mv[1].value(chitm1).multiply(hansenRoot[i - 1][1]).
151                                 add(mv[0].value(chitm1).multiply(hansenRoot[i - 1][0]));
152             }
153         }
154     }
155 
156     /**
157      * Compute the value of the Hansen coefficient K₀<sup>n, s</sup>.
158      *
159      * @param n n value
160      * @param chitm1 χ<sup>-1</sup>
161      * @return the coefficient K₀<sup>n, s</sup>
162      */
163     public T getValue(final int n, final T chitm1) {
164         //Compute the potential slice
165         int sliceNo = (n - s) / SLICE;
166         if (sliceNo < numSlices) {
167             //Compute the index within the slice
168             final int indexInSlice = (n - s) % SLICE;
169 
170             //Check if a root must be returned
171             if (indexInSlice <= 1) {
172                 return hansenRoot[sliceNo][indexInSlice];
173             }
174         } else {
175             //the value was a potential root for a slice, but that slice was not required
176             //Decrease the slice number
177             sliceNo--;
178         }
179 
180         // Danielson 2.7.3-(6c)/Collins 4-242 and Petre's paper
181         final PolynomialFunction[] v = mpvec[n];
182         T ret = v[1].value(chitm1).multiply(hansenRoot[sliceNo][1]);
183         if (hansenRoot[sliceNo][0].getReal() != 0) {
184             ret = ret.add(v[0].value(chitm1).multiply(hansenRoot[sliceNo][0]));
185         }
186 
187         return ret;
188 
189     }
190 
191     /**
192      * Compute the value of the Hansen coefficient dK₀<sup>n, s</sup> / d&Chi;.
193      *
194      * @param n n value
195      * @param chitm1 χ<sup>-1</sup>
196      * @return the coefficient dK₀<sup>n, s</sup> / d&Chi;
197      */
198     public T getDerivative(final int n, final T chitm1) {
199         //Compute the potential slice
200         int sliceNo = (n - s) / SLICE;
201         if (sliceNo < numSlices) {
202             //Compute the index within the slice
203             final int indexInSlice = (n - s) % SLICE;
204 
205             //Check if a root must be returned
206             if (indexInSlice <= 1) {
207                 return hansenDerivRoot[sliceNo][indexInSlice];
208             }
209         } else {
210             //the value was a potential root for a slice, but that slice was not required
211             //Decrease the slice number
212             sliceNo--;
213         }
214 
215         final PolynomialFunction[] v = mpvec[n];
216         T ret = v[1].value(chitm1).multiply(hansenDerivRoot[sliceNo][1]);
217         if (hansenDerivRoot[sliceNo][0].getReal() != 0) {
218             ret = ret.add(v[0].value(chitm1).multiply(hansenDerivRoot[sliceNo][0]));
219         }
220 
221         // Danielson 2.7.3-(7c)/Collins 4-254 and Petre's paper
222         final PolynomialFunction[] v1 = mpvecDeriv[n];
223         ret = ret.add(v1[1].value(chitm1).multiply(hansenRoot[sliceNo][1]));
224         if (hansenRoot[sliceNo][0].getReal() != 0) {
225             ret = ret.add(v1[0].value(chitm1).multiply(hansenRoot[sliceNo][0]));
226         }
227         return ret;
228 
229     }
230 
231 }