HansenTesseralLinear.java

  1. /* Copyright 2002-2018 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. import org.hipparchus.analysis.differentiation.DSFactory;
  19. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  20. import org.hipparchus.analysis.polynomials.PolynomialFunction;
  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;

  23. /**
  24.  * Hansen coefficients K(t,n,s) for t!=0 and n < 0.
  25.  * <p>
  26.  * Implements Collins 4-236 or Danielson 2.7.3-(9) for Hansen Coefficients and
  27.  * Collins 4-240 for derivatives. The recursions are transformed into
  28.  * composition of linear transformations to obtain the associated polynomials
  29.  * for coefficients and their derivatives - see Petre's paper
  30.  *
  31.  * @author Petre Bazavan
  32.  * @author Lucian Barbulescu
  33.  */
  34. public class HansenTesseralLinear {

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

  37.     /**
  38.      * The first vector of polynomials associated to Hansen coefficients and
  39.      * derivatives.
  40.      */
  41.     private PolynomialFunction[][] mpvec;

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

  44.     /** The Hansen coefficients used as roots. */
  45.     private double[][] hansenRoot;

  46.     /** The derivatives of the Hansen coefficients used as roots. */
  47.     private double[][] hansenDerivRoot;

  48.     /** The minimum value for the order. */
  49.     private int Nmin;

  50.     /** The index of the initial condition, Petre's paper. */
  51.     private int N0;

  52.     /** The s coefficient. */
  53.     private int s;

  54.     /** The j coefficient. */
  55.     private int j;

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

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

  63.     /** The objects used to calculate initial data by means of Newcomb operators. */
  64.     private HansenCoefficientsBySeries[] hansenInit;

  65.     /**
  66.      * Constructor.
  67.      *
  68.      * @param nMax the maximum (absolute) value of n parameter
  69.      * @param s s parameter
  70.      * @param j j parameter
  71.      * @param n0 the minimum (absolute) value of n
  72.      * @param maxHansen maximum power of e2 in Hansen expansion
  73.      */
  74.     public HansenTesseralLinear(final int nMax, final int s, final int j, final int n0, final int maxHansen) {
  75.         //Initialize the fields
  76.         this.offset = nMax + 1;
  77.         this.Nmin = -nMax - 1;
  78.         this.N0 = -n0 - 4;
  79.         this.s = s;
  80.         this.j = j;

  81.         //Ensure that only the needed terms are computed
  82.         final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
  83.         this.hansenInit = new HansenCoefficientsBySeries[maxRoots];
  84.         for (int i = 0; i < maxRoots; i++) {
  85.             this.hansenInit[i] = new HansenCoefficientsBySeries(N0 - i + 3, s, j, maxHansen);
  86.         }

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

  95.             // Prepare the database of the associated polynomials
  96.             generatePolynomials();
  97.         }

  98.     }

  99.     /**
  100.      * Compute polynomial coefficient a.
  101.      *
  102.      *  <p>
  103.      *  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>
  104.      *  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²
  105.      *  </p>
  106.      *
  107.      *  <p>
  108.      *  See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
  109.      *  </p>
  110.      *
  111.      * @param mnm1 -n-1
  112.      * @return the polynomial
  113.      */
  114.     private PolynomialFunction a(final int mnm1) {
  115.         // Collins 4-236, Danielson 2.7.3-(9)
  116.         final double r1 = (mnm1 + 2.) * (2. * mnm1 + 5.);
  117.         final double r2 = (2. + mnm1 + s) * (2. + mnm1 - s);
  118.         return new PolynomialFunction(new double[] {
  119.             0.0, 0.0, r1 / r2
  120.         });
  121.     }

  122.     /**
  123.      * Compute polynomial coefficient b.
  124.      *
  125.      *  <p>
  126.      *  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>
  127.      *  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²
  128.      *  </p>
  129.      *
  130.      *  <p>
  131.      *  See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
  132.      *  </p>
  133.      *
  134.      * @param mnm1 -n-1
  135.      * @return the polynomial
  136.      */
  137.     private PolynomialFunction b(final int mnm1) {
  138.         // Collins 4-236, Danielson 2.7.3-(9)
  139.         final double r2 = (2. + mnm1 + s) * (2. + mnm1 - s);
  140.         final double d1 = (mnm1 + 3.) * 2. * j * s / (r2 * (mnm1 + 4.));
  141.         final double d2 = (mnm1 + 3.) * (mnm1 + 2.) / r2;
  142.         return new PolynomialFunction(new double[] {
  143.             0.0, -d1, -d2
  144.         });
  145.     }

  146.     /**
  147.      * Compute polynomial coefficient c.
  148.      *
  149.      *  <p>
  150.      *  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>
  151.      *  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²
  152.      *  </p>
  153.      *
  154.      *  <p>
  155.      *  See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
  156.      *  </p>
  157.      *
  158.      * @param mnm1 -n-1
  159.      * @return the polynomial
  160.      */
  161.     private PolynomialFunction c(final int mnm1) {
  162.         // Collins 4-236, Danielson 2.7.3-(9)
  163.         final double r1 = j * j * (mnm1 + 2.);
  164.         final double r2 = (mnm1 + 4.) * (2. + mnm1 + s) * (2. + mnm1 - s);

  165.         return new PolynomialFunction(new double[] {
  166.             0.0, 0.0, r1 / r2
  167.         });
  168.     }

  169.     /**
  170.      * Compute polynomial coefficient d.
  171.      *
  172.      *  <p>
  173.      *  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²
  174.      *  </p>
  175.      *
  176.      *  <p>
  177.      *  See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
  178.      *  </p>
  179.      *
  180.      * @param mnm1 -n-1
  181.      * @return the polynomial
  182.      */
  183.     private PolynomialFunction d(final int mnm1) {
  184.         // Collins 4-236, Danielson 2.7.3-(9)
  185.         return new PolynomialFunction(new double[] {
  186.             0.0, 0.0, 1.0
  187.         });
  188.     }

  189.     /**
  190.      * Compute polynomial coefficient f.
  191.      *
  192.      *  <p>
  193.      *  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²
  194.      *  </p>
  195.      *
  196.      *  <p>
  197.      *  See Danielson 2.7.3-(9) and Collins 4-236 and 4-240
  198.      *  </p>
  199.      *
  200.      * @param n index
  201.      * @return the polynomial
  202.      */
  203.     private PolynomialFunction f(final int n) {
  204.         // Collins 4-236, Danielson 2.7.3-(9)
  205.         final double r1 = (n + 3.0) * j * s;
  206.         final double r2 = (n + 4.0) * (2.0 + n + s) * (2.0 + n - s);
  207.         return new PolynomialFunction(new double[] {
  208.             0.0, 0.0, 0.0, r1 / r2
  209.         });
  210.     }

  211.     /**
  212.      * Generate the polynomials needed in the linear transformation.
  213.      *
  214.      * <p>
  215.      * See Petre's paper
  216.      * </p>
  217.      */
  218.     private void generatePolynomials() {


  219.         // Initialization of the matrices for linear transformations
  220.         // The final configuration of these matrices are obtained by composition
  221.         // of linear transformations

  222.         // The matrix of polynomials associated to Hansen coefficients, Petre's
  223.         // paper
  224.         PolynomialFunctionMatrix A = HansenUtilities.buildIdentityMatrix4();

  225.         // The matrix of polynomials associated to derivatives, Petre's paper
  226.         final PolynomialFunctionMatrix B = HansenUtilities.buildZeroMatrix4();
  227.         PolynomialFunctionMatrix D = HansenUtilities.buildZeroMatrix4();
  228.         final PolynomialFunctionMatrix a = HansenUtilities.buildZeroMatrix4();

  229.         // The matrix of the current linear transformation
  230.         a.setMatrixLine(0, new PolynomialFunction[] {
  231.             HansenUtilities.ZERO, HansenUtilities.ONE, HansenUtilities.ZERO, HansenUtilities.ZERO
  232.         });
  233.         a.setMatrixLine(1, new PolynomialFunction[] {
  234.             HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ONE, HansenUtilities.ZERO
  235.         });
  236.         a.setMatrixLine(2, new PolynomialFunction[] {
  237.             HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ZERO, HansenUtilities.ONE
  238.         });
  239.         // The generation process
  240.         int index;
  241.         int sliceCounter = 0;
  242.         for (int i = N0 - 1; i > Nmin - 1; i--) {
  243.             index = i + this.offset;
  244.             // The matrix of the current linear transformation is updated
  245.             // Petre's paper
  246.             a.setMatrixLine(3, new PolynomialFunction[] {
  247.                     c(i), HansenUtilities.ZERO, b(i), a(i)
  248.             });

  249.             // composition of the linear transformations to calculate
  250.             // the polynomials associated to Hansen coefficients
  251.             // Petre's paper
  252.             A = A.multiply(a);
  253.             // store the polynomials for Hansen coefficients
  254.             mpvec[index] = A.getMatrixLine(3);
  255.             // composition of the linear transformations to calculate
  256.             // the polynomials associated to derivatives
  257.             // Petre's paper
  258.             D = D.multiply(a);

  259.             //Update the B matrix
  260.             B.setMatrixLine(3, new PolynomialFunction[] {
  261.                 HansenUtilities.ZERO, f(i),
  262.                 HansenUtilities.ZERO, d(i)
  263.             });
  264.             D = D.add(A.multiply(B));

  265.             // store the polynomials for Hansen coefficients from the
  266.             // expressions of derivatives
  267.             mpvecDeriv[index] = D.getMatrixLine(3);

  268.             if (++sliceCounter % SLICE == 0) {
  269.                 // Re-Initialisation of matrix for linear transformmations
  270.                 // The final configuration of these matrix are obtained by composition
  271.                 // of linear transformations
  272.                 A = HansenUtilities.buildIdentityMatrix4();
  273.                 D = HansenUtilities.buildZeroMatrix4();
  274.             }
  275.         }
  276.     }

  277.     /**
  278.      * Compute the values for the first four coefficients and their derivatives by means of series.
  279.      *
  280.      * @param e2 e²
  281.      * @param chi &Chi;
  282.      * @param chi2 &Chi;²
  283.      */
  284.     public void computeInitValues(final double e2, final double chi, final double chi2) {
  285.         // compute the values for n, n+1, n+2 and n+3 by series
  286.         // See Danielson 2.7.3-(10)
  287.         //Ensure that only the needed terms are computed
  288.         final int maxRoots = FastMath.min(4, N0 - Nmin + 4);
  289.         for (int i = 0; i < maxRoots; i++) {
  290.             final DerivativeStructure hansenKernel = hansenInit[i].getValue(e2, chi, chi2);
  291.             this.hansenRoot[0][i] = hansenKernel.getValue();
  292.             this.hansenDerivRoot[0][i] = hansenKernel.getPartialDerivative(1);
  293.         }

  294.         for (int i = 1; i < numSlices; i++) {
  295.             for (int k = 0; k < 4; k++) {
  296.                 final PolynomialFunction[] mv = mpvec[N0 - (i * SLICE) - k + 3 + offset];
  297.                 final PolynomialFunction[] sv = mpvecDeriv[N0 - (i * SLICE) - k + 3 + offset];

  298.                 hansenDerivRoot[i][k] = mv[3].value(chi) * hansenDerivRoot[i - 1][3] +
  299.                                         mv[2].value(chi) * hansenDerivRoot[i - 1][2] +
  300.                                         mv[1].value(chi) * hansenDerivRoot[i - 1][1] +
  301.                                         mv[0].value(chi) * hansenDerivRoot[i - 1][0] +
  302.                                         sv[3].value(chi) * hansenRoot[i - 1][3] +
  303.                                         sv[2].value(chi) * hansenRoot[i - 1][2] +
  304.                                         sv[1].value(chi) * hansenRoot[i - 1][1] +
  305.                                         sv[0].value(chi) * hansenRoot[i - 1][0];

  306.                 hansenRoot[i][k] =  mv[3].value(chi) * hansenRoot[i - 1][3] +
  307.                                     mv[2].value(chi) * hansenRoot[i - 1][2] +
  308.                                     mv[1].value(chi) * hansenRoot[i - 1][1] +
  309.                                     mv[0].value(chi) * hansenRoot[i - 1][0];
  310.             }
  311.         }
  312.     }

  313.     /**
  314.      * Compute the value of the Hansen coefficient K<sub>j</sub><sup>-n-1, s</sup>.
  315.      *
  316.      * @param mnm1 -n-1
  317.      * @param chi χ
  318.      * @return the coefficient K<sub>j</sub><sup>-n-1, s</sup>
  319.      */
  320.     public double getValue(final int mnm1, final double chi) {
  321.         //Compute n
  322.         final int n = -mnm1 - 1;

  323.         //Compute the potential slice
  324.         int sliceNo = (n + N0 + 4) / SLICE;
  325.         if (sliceNo < numSlices) {
  326.             //Compute the index within the slice
  327.             final int indexInSlice = (n + N0 + 4) % SLICE;

  328.             //Check if a root must be returned
  329.             if (indexInSlice <= 3) {
  330.                 return hansenRoot[sliceNo][indexInSlice];
  331.             }
  332.         } else {
  333.             //the value was a potential root for a slice, but that slice was not required
  334.             //Decrease the slice number
  335.             sliceNo--;
  336.         }

  337.         // Computes the coefficient by linear transformation
  338.         // Danielson 2.7.3-(9) or Collins 4-236 and Petre's paper
  339.         final PolynomialFunction[] v = mpvec[mnm1 + offset];
  340.         return v[3].value(chi) * hansenRoot[sliceNo][3] +
  341.                v[2].value(chi) * hansenRoot[sliceNo][2] +
  342.                v[1].value(chi) * hansenRoot[sliceNo][1] +
  343.                v[0].value(chi) * hansenRoot[sliceNo][0];

  344.     }

  345.     /**
  346.      * Compute the value of the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de².
  347.      *
  348.      * @param mnm1 -n-1
  349.      * @param chi χ
  350.      * @return the derivative dK<sub>j</sub><sup>-n-1, s</sup> / de²
  351.      */
  352.     public double getDerivative(final int mnm1, final double chi) {

  353.         //Compute n
  354.         final int n = -mnm1 - 1;

  355.         //Compute the potential slice
  356.         int sliceNo = (n + N0 + 4) / SLICE;
  357.         if (sliceNo < numSlices) {
  358.             //Compute the index within the slice
  359.             final int indexInSlice = (n + N0 + 4) % SLICE;

  360.             //Check if a root must be returned
  361.             if (indexInSlice <= 3) {
  362.                 return hansenDerivRoot[sliceNo][indexInSlice];
  363.             }
  364.         } else {
  365.             //the value was a potential root for a slice, but that slice was not required
  366.             //Decrease the slice number
  367.             sliceNo--;
  368.         }

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

  373.         return v[3].value(chi)  * hansenDerivRoot[sliceNo][3] +
  374.                v[2].value(chi)  * hansenDerivRoot[sliceNo][2] +
  375.                v[1].value(chi)  * hansenDerivRoot[sliceNo][1] +
  376.                v[0].value(chi)  * hansenDerivRoot[sliceNo][0] +
  377.                vv[3].value(chi) * hansenRoot[sliceNo][3] +
  378.                vv[2].value(chi) * hansenRoot[sliceNo][2] +
  379.                vv[1].value(chi) * hansenRoot[sliceNo][1] +
  380.                vv[0].value(chi) * hansenRoot[sliceNo][0];

  381.     }

  382.     /**
  383.      * Compute a Hansen coefficient with series.
  384.      * <p>
  385.      * This class implements the computation of the Hansen kernels
  386.      * through a power series in e² and that is using
  387.      * modified Newcomb operators. The reference formulae can be found
  388.      * in Danielson 2.7.3-10 and 3.3-5
  389.      * </p>
  390.      */
  391.     private static class HansenCoefficientsBySeries {

  392.         /** -n-1 coefficient. */
  393.         private final int mnm1;

  394.         /** s coefficient. */
  395.         private final int s;

  396.         /** j coefficient. */
  397.         private final int j;

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

  400.         /** Polynomial representing the serie. */
  401.         private PolynomialFunction polynomial;

  402.         /** Factory for the DerivativeStructure instances. */
  403.         private final DSFactory factory;

  404.         /**
  405.          * Class constructor.
  406.          *
  407.          * @param mnm1 -n-1 value
  408.          * @param s s value
  409.          * @param j j value
  410.          * @param maxHansen max power of e² in series expansion
  411.          */
  412.         HansenCoefficientsBySeries(final int mnm1, final int s,
  413.                                           final int j, final int maxHansen) {
  414.             this.mnm1 = mnm1;
  415.             this.s = s;
  416.             this.j = j;
  417.             this.maxNewcomb = maxHansen;
  418.             this.polynomial = generatePolynomial();
  419.             this.factory = new DSFactory(1, 1);
  420.         }

  421.         /** Computes the value of Hansen kernel and its derivative at e².
  422.          * <p>
  423.          * The formulae applied are described in Danielson 2.7.3-10 and
  424.          * 3.3-5
  425.          * </p>
  426.          * @param e2 e²
  427.          * @param chi &Chi;
  428.          * @param chi2 &Chi;²
  429.          * @return the value of the Hansen coefficient and its derivative for e²
  430.          */
  431.         public DerivativeStructure getValue(final double e2, final double chi, final double chi2) {

  432.             //Estimation of the serie expansion at e2
  433.             final DerivativeStructure serie = polynomial.value(factory.variable(0, e2));

  434.             final double value      =  FastMath.pow(chi2, -mnm1 - 1) * serie.getValue() / chi;
  435.             final double coef       = -(mnm1 + 1.5);
  436.             final double derivative = coef * chi2 * value +
  437.                                       FastMath.pow(chi2, -mnm1 - 1) * serie.getPartialDerivative(1) / chi;
  438.             return factory.build(value, derivative);
  439.         }

  440.         /** Generate the serie expansion in e².
  441.          * <p>
  442.          * Generate the series expansion in e² used in the formulation
  443.          * of the Hansen kernel (see Danielson 2.7.3-10):
  444.          * &Sigma; Y<sup>ns</sup><sub>α+a,α+b</sub>
  445.          * *e<sup>2α</sup>
  446.          * </p>
  447.          * @return polynomial representing the power serie expansion
  448.          */
  449.         private PolynomialFunction generatePolynomial() {
  450.             // Initialization
  451.             final int aHT = FastMath.max(j - s, 0);
  452.             final int bHT = FastMath.max(s - j, 0);

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

  454.             //Loop for getting the Newcomb operators
  455.             for (int alphaHT = 0; alphaHT <= maxNewcomb; alphaHT++) {
  456.                 coefficients[alphaHT] =
  457.                         NewcombOperators.getValue(alphaHT + aHT, alphaHT + bHT, mnm1, s);
  458.             }

  459.             //Creation of the polynomial
  460.             return new PolynomialFunction(coefficients);
  461.         }
  462.     }

  463. }