FieldHansenTesseralLinear.java

  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. import java.lang.reflect.Array;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.Field;
  21. import org.hipparchus.analysis.differentiation.FieldGradient;
  22. import org.hipparchus.analysis.polynomials.PolynomialFunction;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.MathArrays;
  25. import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;

  26. /**
  27.  * Hansen coefficients K(t,n,s) for t!=0 and n < 0.
  28.  * <p>
  29.  * Implements Collins 4-236 or Danielson 2.7.3-(9) for Hansen Coefficients and
  30.  * Collins 4-240 for derivatives. The recursions are transformed into
  31.  * composition of linear transformations to obtain the associated polynomials
  32.  * for coefficients and their derivatives - see Petre's paper
  33.  *
  34.  * @author Petre Bazavan
  35.  * @author Lucian Barbulescu
  36.  * @author Bryan Cazabonne
  37.  * @param <T> type of the field elements
  38.  */
  39. public class FieldHansenTesseralLinear <T extends CalculusFieldElement<T>> {

  40.     /** The number of coefficients that will be computed with a set of roots. */
  41.     private static final int SLICE = 10;

  42.     /**
  43.      * The first vector of polynomials associated to Hansen coefficients and
  44.      * derivatives.
  45.      */
  46.     private PolynomialFunction[][] mpvec;

  47.     /** The second vector of polynomials associated only to derivatives. */
  48.     private PolynomialFunction[][] mpvecDeriv;

  49.     /** The Hansen coefficients used as roots. */
  50.     private final T[][] hansenRoot;

  51.     /** The derivatives of the Hansen coefficients used as roots. */
  52.     private final T[][] hansenDerivRoot;

  53.     /** The minimum value for the order. */
  54.     private final int Nmin;

  55.     /** The index of the initial condition, Petre's paper. */
  56.     private final int N0;

  57.     /** The number of slices needed to compute the coefficients. */
  58.     private final int numSlices;

  59.     /**
  60.      * The offset used to identify the polynomial that corresponds to a negative.
  61.      * value of n in the internal array that starts at 0
  62.      */
  63.     private final int offset;

  64.     /** The objects used to calculate initial data by means of Newcomb operators. */
  65.     private final FieldHansenCoefficientsBySeries<T>[] hansenInit;

  66.     /**
  67.      * Constructor.
  68.      *
  69.      * @param nMax the maximum (absolute) value of n parameter
  70.      * @param s s parameter
  71.      * @param j j parameter
  72.      * @param n0 the minimum (absolute) value of n
  73.      * @param maxHansen maximum power of the eccentricity to use in Hansen coefficient Kernel expansion.
  74.      * @param field field used by default
  75.      */
  76.     @SuppressWarnings("unchecked")
  77.     public FieldHansenTesseralLinear(final int nMax, final int s, final int j, final int n0,
  78.                                      final int maxHansen, final Field<T> field) {
  79.         //Initialize the fields
  80.         this.offset = nMax + 1;
  81.         this.Nmin = -nMax - 1;
  82.         this.N0 = -n0 - 4;

  83.         final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
  84.         //Ensure that only the needed terms are computed
  85.         this.hansenInit = (FieldHansenCoefficientsBySeries<T>[]) Array.newInstance(FieldHansenCoefficientsBySeries.class, maxRoots);
  86.         for (int i = 0; i < maxRoots; i++) {
  87.             this.hansenInit[i] = new FieldHansenCoefficientsBySeries<>(N0 - i + 3, s, j, maxHansen, field);
  88.         }

  89.         // The first 4 values are computed with series. No linear combination is needed.
  90.         final int size = N0 - Nmin;
  91.         this.numSlices = (int) FastMath.max(FastMath.ceil(((double) size) / SLICE), 1);
  92.         hansenRoot = MathArrays.buildArray(field, numSlices, 4);
  93.         hansenDerivRoot = MathArrays.buildArray(field, numSlices, 4);
  94.         if (size > 0) {
  95.             mpvec = new PolynomialFunction[size][];
  96.             mpvecDeriv = new PolynomialFunction[size][];

  97.             // Prepare the database of the associated polynomials
  98.             HansenUtilities.generateTesseralPolynomials(N0, Nmin, offset, SLICE, j, s,
  99.                                                         mpvec, mpvecDeriv);
  100.         }

  101.     }

  102.     /**
  103.      * Compute the values for the first four coefficients and their derivatives by means of series.
  104.      *
  105.      * @param e2 e²
  106.      * @param chi &Chi;
  107.      * @param chi2 &Chi;²
  108.      */
  109.     public void computeInitValues(final T e2, final T chi, final T chi2) {
  110.         // compute the values for n, n+1, n+2 and n+3 by series
  111.         // See Danielson 2.7.3-(10)
  112.         //Ensure that only the needed terms are computed
  113.         final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
  114.         for (int i = 0; i < maxRoots; i++) {
  115.             final FieldGradient<T> hansenKernel = hansenInit[i].getValueGradient(e2, chi, chi2);
  116.             this.hansenRoot[0][i] = hansenKernel.getValue();
  117.             this.hansenDerivRoot[0][i] = hansenKernel.getPartialDerivative(0);
  118.         }

  119.         for (int i = 1; i < numSlices; i++) {
  120.             for (int k = 0; k < 4; k++) {
  121.                 final PolynomialFunction[] mv = mpvec[N0 - (i * SLICE) - k + 3 + offset];
  122.                 final PolynomialFunction[] sv = mpvecDeriv[N0 - (i * SLICE) - k + 3 + offset];

  123.                 hansenDerivRoot[i][k] = mv[3].value(chi).multiply(hansenDerivRoot[i - 1][3]).
  124.                                         add(mv[2].value(chi).multiply(hansenDerivRoot[i - 1][2])).
  125.                                         add(mv[1].value(chi).multiply(hansenDerivRoot[i - 1][1])).
  126.                                         add(mv[0].value(chi).multiply(hansenDerivRoot[i - 1][0])).
  127.                                         add(sv[3].value(chi).multiply(hansenRoot[i - 1][3])).
  128.                                         add(sv[2].value(chi).multiply(hansenRoot[i - 1][2])).
  129.                                         add(sv[1].value(chi).multiply(hansenRoot[i - 1][1])).
  130.                                         add(sv[0].value(chi).multiply(hansenRoot[i - 1][0]));

  131.                 hansenRoot[i][k] =  mv[3].value(chi).multiply(hansenRoot[i - 1][3]).
  132.                                     add(mv[2].value(chi).multiply(hansenRoot[i - 1][2])).
  133.                                     add(mv[1].value(chi).multiply(hansenRoot[i - 1][1])).
  134.                                     add(mv[0].value(chi).multiply(hansenRoot[i - 1][0]));
  135.             }
  136.         }
  137.     }

  138.     /**
  139.      * Compute the value of the Hansen coefficient K<sub>j</sub><sup>-n-1, s</sup>.
  140.      *
  141.      * @param mnm1 -n-1
  142.      * @param chi χ
  143.      * @return the coefficient K<sub>j</sub><sup>-n-1, s</sup>
  144.      */
  145.     public T getValue(final int mnm1, final T chi) {
  146.         //Compute n
  147.         final int n = -mnm1 - 1;

  148.         //Compute the potential slice
  149.         int sliceNo = (n + N0 + 4) / SLICE;
  150.         if (sliceNo < numSlices) {
  151.             //Compute the index within the slice
  152.             final int indexInSlice = (n + N0 + 4) % SLICE;

  153.             //Check if a root must be returned
  154.             if (indexInSlice <= 3) {
  155.                 return hansenRoot[sliceNo][indexInSlice];
  156.             }
  157.         } else {
  158.             //the value was a potential root for a slice, but that slice was not required
  159.             //Decrease the slice number
  160.             sliceNo--;
  161.         }

  162.         // Computes the coefficient by linear transformation
  163.         // Danielson 2.7.3-(9) or Collins 4-236 and Petre's paper
  164.         final PolynomialFunction[] v = mpvec[mnm1 + offset];
  165.         return v[3].value(chi).multiply(hansenRoot[sliceNo][3]).
  166.                add(v[2].value(chi).multiply(hansenRoot[sliceNo][2])).
  167.                add(v[1].value(chi).multiply(hansenRoot[sliceNo][1])).
  168.                add(v[0].value(chi).multiply(hansenRoot[sliceNo][0]));

  169.     }

  170.     /**
  171.      * Compute the value of the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de².
  172.      *
  173.      * @param mnm1 -n-1
  174.      * @param chi χ
  175.      * @return the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de²
  176.      */
  177.     public T getDerivative(final int mnm1, final T chi) {

  178.         //Compute n
  179.         final int n = -mnm1 - 1;

  180.         //Compute the potential slice
  181.         int sliceNo = (n + N0 + 4) / SLICE;
  182.         if (sliceNo < numSlices) {
  183.             //Compute the index within the slice
  184.             final int indexInSlice = (n + N0 + 4) % SLICE;

  185.             //Check if a root must be returned
  186.             if (indexInSlice <= 3) {
  187.                 return hansenDerivRoot[sliceNo][indexInSlice];
  188.             }
  189.         } else {
  190.             //the value was a potential root for a slice, but that slice was not required
  191.             //Decrease the slice number
  192.             sliceNo--;
  193.         }

  194.         // Computes the coefficient by linear transformation
  195.         // Danielson 2.7.3-(9) or Collins 4-236 and Petre's paper
  196.         final PolynomialFunction[] v = mpvec[mnm1 + this.offset];
  197.         final PolynomialFunction[] vv = mpvecDeriv[mnm1 + this.offset];

  198.         return v[3].value(chi).multiply(hansenDerivRoot[sliceNo][3]).
  199.                add(v[2].value(chi).multiply(hansenDerivRoot[sliceNo][2])).
  200.                add(v[1].value(chi).multiply(hansenDerivRoot[sliceNo][1])).
  201.                add(v[0].value(chi).multiply(hansenDerivRoot[sliceNo][0])).
  202.                add(vv[3].value(chi).multiply(hansenRoot[sliceNo][3])).
  203.                add(vv[2].value(chi).multiply(hansenRoot[sliceNo][2])).
  204.                add( vv[1].value(chi).multiply(hansenRoot[sliceNo][1])).
  205.                add(vv[0].value(chi).multiply(hansenRoot[sliceNo][0]));

  206.     }

  207.     /**
  208.      * Compute a Hansen coefficient with series.
  209.      * <p>
  210.      * This class implements the computation of the Hansen kernels
  211.      * through a power series in e² and that is using
  212.      * modified Newcomb operators. The reference formulae can be found
  213.      * in Danielson 2.7.3-10 and 3.3-5
  214.      * </p>
  215.      */
  216.     private static class FieldHansenCoefficientsBySeries <T extends CalculusFieldElement<T>> {

  217.         /** -n-1 coefficient. */
  218.         private final int mnm1;

  219.         /** s coefficient. */
  220.         private final int s;

  221.         /** j coefficient. */
  222.         private final int j;

  223.         /** Max power in e² for the Newcomb's series expansion. */
  224.         private final int maxNewcomb;

  225.         /** Polynomial representing the serie. */
  226.         private final PolynomialFunction polynomial;

  227.         /**
  228.          * Class constructor.
  229.          *
  230.          * @param mnm1 -n-1 value
  231.          * @param s s value
  232.          * @param j j value
  233.          * @param maxHansen max power of e² in series expansion
  234.          * @param field field for the function parameters and value
  235.          */
  236.         FieldHansenCoefficientsBySeries(final int mnm1, final int s,
  237.                                           final int j, final int maxHansen, final Field<T> field) {
  238.             this.mnm1 = mnm1;
  239.             this.s = s;
  240.             this.j = j;
  241.             this.maxNewcomb = maxHansen;
  242.             this.polynomial = generatePolynomial();
  243.         }

  244.         /** Computes the value of Hansen kernel and its derivative at e².
  245.          * <p>
  246.          * The formulae applied are described in Danielson 2.7.3-10 and
  247.          * 3.3-5
  248.          * </p>
  249.          * @param e2 e²
  250.          * @param chi &Chi;
  251.          * @param chi2 &Chi;²
  252.          * @return the value of the Hansen coefficient and its derivative for e²
  253.          */
  254.         private FieldGradient<T> getValueGradient(final T e2, final T chi, final T chi2) {

  255.             final T zero = e2.getField().getZero();
  256.             //Estimation of the serie expansion at e2
  257.             final FieldGradient<T> serie = polynomial.value(FieldGradient.variable(1, 0, e2));

  258.             final T value      =  FastMath.pow(chi2, -mnm1 - 1).multiply(serie.getValue()).divide(chi);
  259.             final T coef       = zero.subtract(mnm1 + 1.5);
  260.             final T derivative = coef.multiply(chi2).multiply(value).
  261.                             add(FastMath.pow(chi2, -mnm1 - 1).multiply(serie.getPartialDerivative(0)).divide(chi));
  262.             return new FieldGradient<>(value, derivative);
  263.         }

  264.         /** Generate the serie expansion in e².
  265.          * <p>
  266.          * Generate the series expansion in e² used in the formulation
  267.          * of the Hansen kernel (see Danielson 2.7.3-10):
  268.          * &Sigma; Y<sup>ns</sup><sub>α+a,α+b</sub>
  269.          * *e<sup>2α</sup>
  270.          * </p>
  271.          * @return polynomial representing the power serie expansion
  272.          */
  273.         private PolynomialFunction generatePolynomial() {
  274.             // Initialization
  275.             final int aHT = FastMath.max(j - s, 0);
  276.             final int bHT = FastMath.max(s - j, 0);

  277.             final double[] coefficients = new double[maxNewcomb + 1];

  278.             //Loop for getting the Newcomb operators
  279.             for (int alphaHT = 0; alphaHT <= maxNewcomb; alphaHT++) {
  280.                 coefficients[alphaHT] =
  281.                         NewcombOperators.getValue(alphaHT + aHT, alphaHT + bHT, mnm1, s);
  282.             }

  283.             //Creation of the polynomial
  284.             return new PolynomialFunction(coefficients);
  285.         }
  286.     }

  287. }