1 /* Copyright 2002-2015 CS Systèmes d'Information
2 * Licensed to CS Systèmes d'Information (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.apache.commons.math3.analysis.differentiation.DerivativeStructure;
20 import org.apache.commons.math3.analysis.polynomials.PolynomialFunction;
21 import org.apache.commons.math3.util.FastMath;
22 import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;
23
24 /**
25 * Hansen coefficients K(t,n,s) for t!=0 and n < 0.
26 * <p>
27 * Implements Collins 4-236 or Danielson 2.7.3-(9) for Hansen Coefficients and
28 * Collins 4-240 for derivatives. The recursions are transformed into
29 * composition of linear transformations to obtain the associated polynomials
30 * for coefficients and their derivatives - see Petre's paper
31 *
32 * @author Petre Bazavan
33 * @author Lucian Barbulescu
34 */
35 public class HansenTesseralLinear {
36
37 /** The number of coefficients that will be computed with a set of roots. */
38 private static final int SLICE = 10;
39
40 /**
41 * The first vector of polynomials associated to Hansen coefficients and
42 * derivatives.
43 */
44 private PolynomialFunction[][] mpvec;
45
46 /** The second vector of polynomials associated only to derivatives. */
47 private PolynomialFunction[][] mpvecDeriv;
48
49 /** The Hansen coefficients used as roots. */
50 private double[][] hansenRoot;
51
52 /** The derivatives of the Hansen coefficients used as roots. */
53 private double[][] hansenDerivRoot;
54
55 /** The minimum value for the order. */
56 private int Nmin;
57
58 /** The index of the initial condition, Petre's paper. */
59 private int N0;
60
61 /** The s coefficient. */
62 private int s;
63
64 /** The j coefficient. */
65 private int j;
66
67 /** The number of slices needed to compute the coefficients. */
68 private int numSlices;
69
70 /**
71 * The offset used to identify the polynomial that corresponds to a negative.
72 * value of n in the internal array that starts at 0
73 */
74 private int offset;
75
76 /** The objects used to calculate initial data by means of Newcomb operators. */
77 private HansenCoefficientsBySeries[] hansenInit;
78
79 /**
80 * Constructor.
81 *
82 * @param nMax the maximum (absolute) value of n parameter
83 * @param s s parameter
84 * @param j j parameter
85 * @param n0 the minimum (absolute) value of n
86 * @param maxHansen maximum power of e2 in Hansen expansion
87 */
88 public HansenTesseralLinear(final int nMax, final int s, final int j, final int n0, final int maxHansen) {
89 //Initialize the fields
90 this.offset = nMax + 1;
91 this.Nmin = -nMax - 1;
92 this.N0 = -n0 - 4;
93 this.s = s;
94 this.j = j;
95
96 //Ensure that only the needed terms are computed
97 final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
98 this.hansenInit = new HansenCoefficientsBySeries[maxRoots];
99 for (int i = 0; i < maxRoots; i++) {
100 this.hansenInit[i] = new HansenCoefficientsBySeries(N0 - i + 3, s, j, maxHansen);
101 }
102
103 // The first 4 values are computed with series. No linear combination is needed.
104 final int size = N0 - Nmin;
105 this.numSlices = (int) FastMath.max(FastMath.ceil(((double) size) / SLICE), 1);
106 hansenRoot = new double[numSlices][4];
107 hansenDerivRoot = new double[numSlices][4];
108 if (size > 0) {
109 mpvec = new PolynomialFunction[size][];
110 mpvecDeriv = new PolynomialFunction[size][];
111
112 // Prepare the database of the associated polynomials
113 generatePolynomials();
114 }
115 }
116
117 /**
118 * Compute polynomial coefficient a.
119 *
120 * <p>
121 * It is used to generate the coefficient for K<sub>j</sub><sup>-n, s</sup> when computing K<sub>j</sub><sup>-n-1, s</sup>
122 * and the coefficient for dK<sub>j</sub><sup>-n, s</sup> / de² when computing dK<sub>j</sub><sup>-n-1, s</sup> / de²
123 * </p>
124 *
125 * <p>
126 * See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
127 * </p>
128 *
129 * @param mnm1 -n-1
130 * @return the polynomial
131 */
132 private PolynomialFunction a(final int mnm1) {
133 // Collins 4-236, Danielson 2.7.3-(9)
134 final double r1 = (mnm1 + 2.) * (2. * mnm1 + 5.);
135 final double r2 = (2. + mnm1 + s) * (2. + mnm1 - s);
136 return new PolynomialFunction(new double[] {
137 0.0, 0.0, r1 / r2
138 });
139 }
140
141 /**
142 * Compute polynomial coefficient b.
143 *
144 * <p>
145 * It is used to generate the coefficient for K<sub>j</sub><sup>-n+1, s</sup> when computing K<sub>j</sub><sup>-n-1, s</sup>
146 * and the coefficient for dK<sub>j</sub><sup>-n+1, s</sup> / de² when computing dK<sub>j</sub><sup>-n-1, s</sup> / de²
147 * </p>
148 *
149 * <p>
150 * See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
151 * </p>
152 *
153 * @param mnm1 -n-1
154 * @return the polynomial
155 */
156 private PolynomialFunction b(final int mnm1) {
157 // Collins 4-236, Danielson 2.7.3-(9)
158 final double r2 = (2. + mnm1 + s) * (2. + mnm1 - s);
159 final double d1 = (mnm1 + 3.) * 2. * j * s / (r2 * (mnm1 + 4.));
160 final double d2 = (mnm1 + 3.) * (mnm1 + 2.) / r2;
161 return new PolynomialFunction(new double[] {
162 0.0, -d1, -d2
163 });
164 }
165
166 /**
167 * Compute polynomial coefficient c.
168 *
169 * <p>
170 * It is used to generate the coefficient for K<sub>j</sub><sup>-n+3, s</sup> when computing K<sub>j</sub><sup>-n-1, s</sup>
171 * and the coefficient for dK<sub>j</sub><sup>-n+3, s</sup> / de² when computing dK<sub>j</sub><sup>-n-1, s</sup> / de²
172 * </p>
173 *
174 * <p>
175 * See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
176 * </p>
177 *
178 * @param mnm1 -n-1
179 * @return the polynomial
180 */
181 private PolynomialFunction c(final int mnm1) {
182 // Collins 4-236, Danielson 2.7.3-(9)
183 final double r1 = j * j * (mnm1 + 2.);
184 final double r2 = (mnm1 + 4.) * (2. + mnm1 + s) * (2. + mnm1 - s);
185
186 return new PolynomialFunction(new double[] {
187 0.0, 0.0, r1 / r2
188 });
189 }
190
191 /**
192 * Compute polynomial coefficient d.
193 *
194 * <p>
195 * It is used to generate the coefficient for K<sub>j</sub><sup>-n-1, s</sup> / dχ when computing dK<sub>j</sub><sup>-n-1, s</sup> / de²
196 * </p>
197 *
198 * <p>
199 * See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
200 * </p>
201 *
202 * @param mnm1 -n-1
203 * @return the polynomial
204 */
205 private PolynomialFunction d(final int mnm1) {
206 // Collins 4-236, Danielson 2.7.3-(9)
207 return new PolynomialFunction(new double[] {
208 0.0, 0.0, 1.0
209 });
210 }
211
212 /**
213 * Compute polynomial coefficient f.
214 *
215 * <p>
216 * It is used to generate the coefficient for K<sub>j</sub><sup>-n+1, s</sup> / dχ when computing dK<sub>j</sub><sup>-n-1, s</sup> / de²
217 * </p>
218 *
219 * <p>
220 * See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
221 * </p>
222 *
223 * @param n index
224 * @return the polynomial
225 */
226 private PolynomialFunction f(final int n) {
227 // Collins 4-236, Danielson 2.7.3-(9)
228 final double r1 = (n + 3.0) * j * s;
229 final double r2 = (n + 4.0) * (2.0 + n + s) * (2.0 + n - s);
230 return new PolynomialFunction(new double[] {
231 0.0, 0.0, 0.0, r1 / r2
232 });
233 }
234
235 /**
236 * Generate the polynomials needed in the linear transformation.
237 *
238 * <p>
239 * See Petre's paper
240 * </p>
241 */
242 private void generatePolynomials() {
243
244
245 // Initialization of the matrices for linear transformations
246 // The final configuration of these matrices are obtained by composition
247 // of linear transformations
248
249 // The matrix of polynomials associated to Hansen coefficients, Petre's
250 // paper
251 PolynomialFunctionMatrix A = HansenUtilities.buildIdentityMatrix4();
252
253 // The matrix of polynomials associated to derivatives, Petre's paper
254 final PolynomialFunctionMatrix B = HansenUtilities.buildZeroMatrix4();
255 PolynomialFunctionMatrix D = HansenUtilities.buildZeroMatrix4();
256 final PolynomialFunctionMatrix a = HansenUtilities.buildZeroMatrix4();
257
258 // The matrix of the current linear transformation
259 a.setMatrixLine(0, new PolynomialFunction[] {
260 HansenUtilities.ZERO, HansenUtilities.ONE, HansenUtilities.ZERO, HansenUtilities.ZERO
261 });
262 a.setMatrixLine(1, new PolynomialFunction[] {
263 HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ONE, HansenUtilities.ZERO
264 });
265 a.setMatrixLine(2, new PolynomialFunction[] {
266 HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ONE
267 });
268 // The generation process
269 int index;
270 int sliceCounter = 0;
271 for (int i = N0 - 1; i > Nmin - 1; i--) {
272 index = i + this.offset;
273 // The matrix of the current linear transformation is updated
274 // Petre's paper
275 a.setMatrixLine(3, new PolynomialFunction[] {
276 c(i), HansenUtilities.ZERO, b(i), a(i)
277 });
278
279 // composition of the linear transformations to calculate
280 // the polynomials associated to Hansen coefficients
281 // Petre's paper
282 A = A.multiply(a);
283 // store the polynomials for Hansen coefficients
284 mpvec[index] = A.getMatrixLine(3);
285 // composition of the linear transformations to calculate
286 // the polynomials associated to derivatives
287 // Petre's paper
288 D = D.multiply(a);
289
290 //Update the B matrix
291 B.setMatrixLine(3, new PolynomialFunction[] {
292 HansenUtilities.ZERO, f(i),
293 HansenUtilities.ZERO, d(i)
294 });
295 D = D.add(A.multiply(B));
296
297 // store the polynomials for Hansen coefficients from the
298 // expressions of derivatives
299 mpvecDeriv[index] = D.getMatrixLine(3);
300
301 if (++sliceCounter % SLICE == 0) {
302 // Re-Initialisation of matrix for linear transformmations
303 // The final configuration of these matrix are obtained by composition
304 // of linear transformations
305 A = HansenUtilities.buildIdentityMatrix4();
306 D = HansenUtilities.buildZeroMatrix4();
307 }
308 }
309 }
310
311 /**
312 * Compute the values for the first four coefficients and their derivatives by means of series.
313 *
314 * @param e2 e²
315 * @param chi Χ
316 * @param chi2 Χ²
317 */
318 public void computeInitValues(final double e2, final double chi, final double chi2) {
319 // compute the values for n, n+1, n+2 and n+3 by series
320 // See Danielson 2.7.3-(10)
321 //Ensure that only the needed terms are computed
322 final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
323 for (int i = 0; i < maxRoots; i++) {
324 final DerivativeStructure hansenKernel = hansenInit[i].getValue(e2, chi, chi2);
325 this.hansenRoot[0][i] = hansenKernel.getValue();
326 this.hansenDerivRoot[0][i] = hansenKernel.getPartialDerivative(1);
327 }
328
329 for (int i = 1; i < numSlices; i++) {
330 for (int k = 0; k < 4; k++) {
331 final PolynomialFunction[] mv = mpvec[N0 - (i * SLICE) - k + 3 + offset];
332 final PolynomialFunction[] sv = mpvecDeriv[N0 - (i * SLICE) - k + 3 + offset];
333
334 hansenDerivRoot[i][k] = mv[3].value(chi) * hansenDerivRoot[i - 1][3] +
335 mv[2].value(chi) * hansenDerivRoot[i - 1][2] +
336 mv[1].value(chi) * hansenDerivRoot[i - 1][1] +
337 mv[0].value(chi) * hansenDerivRoot[i - 1][0] +
338 sv[3].value(chi) * hansenRoot[i - 1][3] +
339 sv[2].value(chi) * hansenRoot[i - 1][2] +
340 sv[1].value(chi) * hansenRoot[i - 1][1] +
341 sv[0].value(chi) * hansenRoot[i - 1][0];
342
343 hansenRoot[i][k] = mv[3].value(chi) * hansenRoot[i - 1][3] +
344 mv[2].value(chi) * hansenRoot[i - 1][2] +
345 mv[1].value(chi) * hansenRoot[i - 1][1] +
346 mv[0].value(chi) * hansenRoot[i - 1][0];
347 }
348 }
349 }
350
351 /**
352 * Compute the value of the Hansen coefficient K<sub>j</sub><sup>-n-1, s</sup>.
353 *
354 * @param mnm1 -n-1
355 * @param chi χ
356 * @return the coefficient K<sub>j</sub><sup>-n-1, s</sup>
357 */
358 public double getValue(final int mnm1, final double chi) {
359 //Compute n
360 final int n = -mnm1 - 1;
361
362 //Compute the potential slice
363 int sliceNo = (n + N0 + 4) / SLICE;
364 if (sliceNo < numSlices) {
365 //Compute the index within the slice
366 final int indexInSlice = (n + N0 + 4) % SLICE;
367
368 //Check if a root must be returned
369 if (indexInSlice <= 3) {
370 return hansenRoot[sliceNo][indexInSlice];
371 }
372 } else {
373 //the value was a potential root for a slice, but that slice was not required
374 //Decrease the slice number
375 sliceNo--;
376 }
377
378 // Computes the coefficient by linear transformation
379 // Danielson 2.7.3-(9) or Collins 4-236 and Petre's paper
380 final PolynomialFunction[] v = mpvec[mnm1 + offset];
381 return v[3].value(chi) * hansenRoot[sliceNo][3] +
382 v[2].value(chi) * hansenRoot[sliceNo][2] +
383 v[1].value(chi) * hansenRoot[sliceNo][1] +
384 v[0].value(chi) * hansenRoot[sliceNo][0];
385
386 }
387
388 /**
389 * Compute the value of the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de².
390 *
391 * @param mnm1 -n-1
392 * @param chi χ
393 * @return the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de²
394 */
395 public double getDerivative(final int mnm1, final double chi) {
396
397 //Compute n
398 final int n = -mnm1 - 1;
399
400 //Compute the potential slice
401 int sliceNo = (n + N0 + 4) / SLICE;
402 if (sliceNo < numSlices) {
403 //Compute the index within the slice
404 final int indexInSlice = (n + N0 + 4) % SLICE;
405
406 //Check if a root must be returned
407 if (indexInSlice <= 3) {
408 return hansenDerivRoot[sliceNo][indexInSlice];
409 }
410 } else {
411 //the value was a potential root for a slice, but that slice was not required
412 //Decrease the slice number
413 sliceNo--;
414 }
415
416 // Computes the coefficient by linear transformation
417 // Danielson 2.7.3-(9) or Collins 4-236 and Petre's paper
418 final PolynomialFunction[] v = mpvec[mnm1 + this.offset];
419 final PolynomialFunction[] vv = mpvecDeriv[mnm1 + this.offset];
420
421 return v[3].value(chi) * hansenDerivRoot[sliceNo][3] +
422 v[2].value(chi) * hansenDerivRoot[sliceNo][2] +
423 v[1].value(chi) * hansenDerivRoot[sliceNo][1] +
424 v[0].value(chi) * hansenDerivRoot[sliceNo][0] +
425 vv[3].value(chi) * hansenRoot[sliceNo][3] +
426 vv[2].value(chi) * hansenRoot[sliceNo][2] +
427 vv[1].value(chi) * hansenRoot[sliceNo][1] +
428 vv[0].value(chi) * hansenRoot[sliceNo][0];
429
430 }
431
432 /**
433 * Compute a Hansen coefficient with series.
434 * <p>
435 * This class implements the computation of the Hansen kernels
436 * through a power series in e² and that is using
437 * modified Newcomb operators. The reference formulae can be found
438 * in Danielson 2.7.3-10 and 3.3-5
439 * </p>
440 */
441 private static class HansenCoefficientsBySeries {
442
443 /** -n-1 coefficient. */
444 private final int mnm1;
445
446 /** s coefficient. */
447 private final int s;
448
449 /** j coefficient. */
450 private final int j;
451
452 /** Max power in e² for the Newcomb's series expansion. */
453 private final int maxNewcomb;
454
455 /** Polynomial representing the serie. */
456 private PolynomialFunction polynomial;
457
458 /**
459 * Class constructor.
460 *
461 * @param mnm1 -n-1 value
462 * @param s s value
463 * @param j j value
464 * @param maxHansen max power of e² in series expansion
465 */
466 public HansenCoefficientsBySeries(final int mnm1, final int s,
467 final int j, final int maxHansen) {
468 this.mnm1 = mnm1;
469 this.s = s;
470 this.j = j;
471 this.maxNewcomb = maxHansen;
472 this.polynomial = generatePolynomial();
473 }
474
475 /** Computes the value of Hansen kernel and its derivative at e².
476 * <p>
477 * The formulae applied are described in Danielson 2.7.3-10 and
478 * 3.3-5
479 * </p>
480 * @param e2 e²
481 * @param chi Χ
482 * @param chi2 Χ²
483 * @return the value of the Hansen coefficient and its derivative for e²
484 */
485 public DerivativeStructure getValue(final double e2, final double chi, final double chi2) {
486
487 //Estimation of the serie expansion at e2
488 final DerivativeStructure serie = polynomial.value(
489 new DerivativeStructure(1, 1, 0, e2));
490
491 final double value = FastMath.pow(chi2, -mnm1 - 1) * serie.getValue() / chi;
492 final double coef = -(mnm1 + 1.5);
493 final double derivative = coef * chi2 * value +
494 FastMath.pow(chi2, -mnm1 - 1) * serie.getPartialDerivative(1) / chi;
495 return new DerivativeStructure(1, 1, value, derivative);
496 }
497
498 /** Generate the serie expansion in e².
499 * <p>
500 * Generate the series expansion in e² used in the formulation
501 * of the Hansen kernel (see Danielson 2.7.3-10):
502 * Σ Y<sup>ns</sup><sub>α+a,α+b</sub>
503 * *e<sup>2α</sup>
504 * </p>
505 * @return polynomial representing the power serie expansion
506 */
507 private PolynomialFunction generatePolynomial() {
508 // Initialization
509 final int aHT = FastMath.max(j - s, 0);
510 final int bHT = FastMath.max(s - j, 0);
511
512 final double[] coefficients = new double[maxNewcomb + 1];
513
514 //Loop for getting the Newcomb operators
515 for (int alphaHT = 0; alphaHT <= maxNewcomb; alphaHT++) {
516 coefficients[alphaHT] =
517 NewcombOperators.getValue(alphaHT + aHT, alphaHT + bHT, mnm1, s);
518 }
519
520 //Creation of the polynomial
521 return new PolynomialFunction(coefficients);
522 }
523 }
524
525 }