CoefficientsFactory.java

  1. /* Copyright 2002-2022 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. import java.util.TreeMap;

  19. import org.hipparchus.Field;
  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.util.CombinatoricsUtils;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.MathArrays;
  24. import org.orekit.errors.OrekitException;
  25. import org.orekit.errors.OrekitMessages;

  26. /**
  27.  * This class is designed to provide coefficient from the DSST theory.
  28.  *
  29.  * @author Romain Di Costanzo
  30.  */
  31. public class CoefficientsFactory {

  32.     /** Internal storage of the polynomial values. Reused for further computation. */
  33.     private static TreeMap<NSKey, Double> VNS = new TreeMap<NSKey, Double>();

  34.     /** Last computed order for V<sub>ns</sub> coefficients. */
  35.     private static int         LAST_VNS_ORDER = 2;

  36.     /** Static initialization for the V<sub>ns</sub> coefficient. */
  37.     static {
  38.         // Initialization
  39.         VNS.put(new NSKey(0, 0), 1.);
  40.         VNS.put(new NSKey(1, 0), 0.);
  41.         VNS.put(new NSKey(1, 1), 0.5);
  42.     }

  43.     /** Private constructor as the class is a utility class.
  44.      */
  45.     private CoefficientsFactory() {
  46.     }

  47.     /** Compute the Q<sub>n,s</sub> coefficients evaluated at γ from the recurrence formula 2.8.3-(2).
  48.      *  <p>
  49.      *  Q<sub>n,s</sub> coefficients are computed for n = 0 to nMax
  50.      *  and s = 0 to sMax + 1 in order to also get the derivative dQ<sub>n,s</sub>/dγ = Q(n, s + 1)
  51.      *  </p>
  52.      *  @param gamma γ angle
  53.      *  @param nMax n max value
  54.      *  @param sMax s max value
  55.      *  @return Q<sub>n,s</sub> coefficients array
  56.      */
  57.     public static double[][] computeQns(final double gamma, final int nMax, final int sMax) {

  58.         // Initialization
  59.         final int sDim = FastMath.min(sMax + 1, nMax) + 1;
  60.         final int rows = nMax + 1;
  61.         final double[][] Qns = new double[rows][];
  62.         for (int i = 0; i <= nMax; i++) {
  63.             final int snDim = FastMath.min(i + 1, sDim);
  64.             Qns[i] = new double[snDim];
  65.         }

  66.         // first element
  67.         Qns[0][0] = 1;

  68.         for (int n = 1; n <= nMax; n++) {
  69.             final int snDim = FastMath.min(n + 1, sDim);
  70.             for (int s = 0; s < snDim; s++) {
  71.                 if (n == s) {
  72.                     Qns[n][s] = (2. * s - 1.) * Qns[s - 1][s - 1];
  73.                 } else if (n == (s + 1)) {
  74.                     Qns[n][s] = (2. * s + 1.) * gamma * Qns[s][s];
  75.                 } else {
  76.                     Qns[n][s] = (2. * n - 1.) * gamma * Qns[n - 1][s] - (n + s - 1.) * Qns[n - 2][s];
  77.                     Qns[n][s] /= n - s;
  78.                 }
  79.             }
  80.         }

  81.         return Qns;
  82.     }

  83.     /** Compute the Q<sub>n,s</sub> coefficients evaluated at γ from the recurrence formula 2.8.3-(2).
  84.      *  <p>
  85.      *  Q<sub>n,s</sub> coefficients are computed for n = 0 to nMax
  86.      *  and s = 0 to sMax + 1 in order to also get the derivative dQ<sub>n,s</sub>/dγ = Q(n, s + 1)
  87.      *  </p>
  88.      *  @param gamma γ angle
  89.      *  @param nMax n max value
  90.      *  @param sMax s max value
  91.      *  @param <T> the type of the field elements
  92.      *  @return Q<sub>n,s</sub> coefficients array
  93.      */
  94.     public static <T extends CalculusFieldElement<T>> T[][] computeQns(final T gamma, final int nMax, final int sMax) {

  95.         // Initialization
  96.         final int sDim = FastMath.min(sMax + 1, nMax) + 1;
  97.         final int rows = nMax + 1;
  98.         final T[][] Qns = MathArrays.buildArray(gamma.getField(), rows, FastMath.min(nMax + 1, sDim) - 1);
  99.         for (int i = 0; i <= nMax; i++) {
  100.             final int snDim = FastMath.min(i + 1, sDim);
  101.             Qns[i] = MathArrays.buildArray(gamma.getField(), snDim);
  102.         }

  103.         // first element
  104.         Qns[0][0] = gamma.subtract(gamma).add(1.);

  105.         for (int n = 1; n <= nMax; n++) {
  106.             final int snDim = FastMath.min(n + 1, sDim);
  107.             for (int s = 0; s < snDim; s++) {
  108.                 if (n == s) {
  109.                     Qns[n][s] = Qns[s - 1][s - 1].multiply(2. * s - 1.);
  110.                 } else if (n == (s + 1)) {
  111.                     Qns[n][s] = Qns[s][s].multiply(gamma).multiply(2. * s + 1.);
  112.                 } else {
  113.                     Qns[n][s] = Qns[n - 1][s].multiply(gamma).multiply(2. * n - 1.).subtract(Qns[n - 2][s].multiply(n + s - 1.));
  114.                     Qns[n][s] = Qns[n][s].divide(n - s);
  115.                 }
  116.             }
  117.         }

  118.         return Qns;
  119.     }

  120.     /** Compute recursively G<sub>s</sub> and H<sub>s</sub> polynomials from equation 3.1-(5).
  121.      *  @param k x-component of the eccentricity vector
  122.      *  @param h y-component of the eccentricity vector
  123.      *  @param alpha 1st direction cosine
  124.      *  @param beta 2nd direction cosine
  125.      *  @param order development order
  126.      *  @return Array of G<sub>s</sub> and H<sub>s</sub> polynomials for s from 0 to order.<br>
  127.      *          The 1st column contains the G<sub>s</sub> values.
  128.      *          The 2nd column contains the H<sub>s</sub> values.
  129.      */
  130.     public static double[][] computeGsHs(final double k, final double h,
  131.                                          final double alpha, final double beta,
  132.                                          final int order) {
  133.         // Constant terms
  134.         final double hamkb = h * alpha - k * beta;
  135.         final double kaphb = k * alpha + h * beta;
  136.         // Initialization
  137.         final double[][] GsHs = new double[2][order + 1];
  138.         GsHs[0][0] = 1.;
  139.         GsHs[1][0] = 0.;

  140.         for (int s = 1; s <= order; s++) {
  141.             // Gs coefficient
  142.             GsHs[0][s] = kaphb * GsHs[0][s - 1] - hamkb * GsHs[1][s - 1];
  143.             // Hs coefficient
  144.             GsHs[1][s] = hamkb * GsHs[0][s - 1] + kaphb * GsHs[1][s - 1];
  145.         }

  146.         return GsHs;
  147.     }

  148.     /** Compute recursively G<sub>s</sub> and H<sub>s</sub> polynomials from equation 3.1-(5).
  149.      *  @param k x-component of the eccentricity vector
  150.      *  @param h y-component of the eccentricity vector
  151.      *  @param alpha 1st direction cosine
  152.      *  @param beta 2nd direction cosine
  153.      *  @param order development order
  154.      *  @param field field of elements
  155.      *  @param <T> the type of the field elements
  156.      *  @return Array of G<sub>s</sub> and H<sub>s</sub> polynomials for s from 0 to order.<br>
  157.      *          The 1st column contains the G<sub>s</sub> values.
  158.      *          The 2nd column contains the H<sub>s</sub> values.
  159.      */
  160.     public static <T extends CalculusFieldElement<T>> T[][] computeGsHs(final T k, final T h,
  161.                                          final T alpha, final T beta,
  162.                                          final int order, final Field<T> field) {
  163.         // Zero for initialization
  164.         final T zero = field.getZero();

  165.         // Constant terms
  166.         final T hamkb = h.multiply(alpha).subtract(k.multiply(beta));
  167.         final T kaphb = k.multiply(alpha).add(h.multiply(beta));
  168.         // Initialization
  169.         final T[][] GsHs = MathArrays.buildArray(field, 2, order + 1);
  170.         GsHs[0][0] = zero.add(1.);
  171.         GsHs[1][0] = zero;

  172.         for (int s = 1; s <= order; s++) {
  173.             // Gs coefficient
  174.             GsHs[0][s] = kaphb.multiply(GsHs[0][s - 1]).subtract(hamkb.multiply(GsHs[1][s - 1]));
  175.             // Hs coefficient
  176.             GsHs[1][s] = hamkb.multiply(GsHs[0][s - 1]).add(kaphb.multiply(GsHs[1][s - 1]));
  177.         }

  178.         return GsHs;
  179.     }

  180.     /** Compute the V<sub>n,s</sub> coefficients from 2.8.2-(1)(2).
  181.      * @param order Order of the computation. Computation will be done from 0 to order -1
  182.      * @return Map of the V<sub>n, s</sub> coefficients
  183.      */
  184.     public static TreeMap<NSKey, Double> computeVns(final int order) {

  185.         if (order > LAST_VNS_ORDER) {
  186.             // Compute coefficient
  187.             // Need previous computation as recurrence relation is done at s + 1 and n + 2
  188.             final int min = (LAST_VNS_ORDER - 2 < 0) ? 0 : (LAST_VNS_ORDER - 2);
  189.             for (int n = min; n < order; n++) {
  190.                 for (int s = 0; s < n + 1; s++) {
  191.                     if ((n - s) % 2 != 0) {
  192.                         VNS.put(new NSKey(n, s), 0.);
  193.                     } else {
  194.                         // s = n
  195.                         if (n == s && (s + 1) < order) {
  196.                             VNS.put(new NSKey(s + 1, s + 1), VNS.get(new NSKey(s, s)) / (2 * s + 2.));
  197.                         }
  198.                         // otherwise
  199.                         if ((n + 2) < order) {
  200.                             VNS.put(new NSKey(n + 2, s), VNS.get(new NSKey(n, s)) * (-n + s - 1.) / (n + s + 2.));
  201.                         }
  202.                     }
  203.                 }
  204.             }
  205.             LAST_VNS_ORDER = order;
  206.         }
  207.         return VNS;
  208.     }

  209.     /** Get the V<sub>n,s</sub><sup>m</sup> coefficient from V<sub>n,s</sub>.
  210.      *  <br>See § 2.8.2 in Danielson paper.
  211.      * @param m m
  212.      * @param n n
  213.      * @param s s
  214.      * @return The V<sub>n, s</sub> <sup>m</sup> coefficient
  215.      */
  216.     public static double getVmns(final int m, final int n, final int s) {
  217.         if (m > n) {
  218.             throw new OrekitException(OrekitMessages.DSST_VMNS_COEFFICIENT_ERROR_MS, m, n);
  219.         }
  220.         final double fns = CombinatoricsUtils.factorialDouble(n + FastMath.abs(s));
  221.         final double fnm = CombinatoricsUtils.factorialDouble(n  - m);

  222.         double result = 0;
  223.         // If (n - s) is odd, the Vmsn coefficient is null
  224.         if ((n - s) % 2 == 0) {
  225.             // Update the Vns coefficient
  226.             if ((n + 1) > LAST_VNS_ORDER) {
  227.                 computeVns(n + 1);
  228.             }
  229.             if (s >= 0) {
  230.                 result = fns  * VNS.get(new NSKey(n, s)) / fnm;
  231.             } else {
  232.                 // If s < 0 : Vmn-s = (-1)^(-s) Vmns
  233.                 final int mops = (s % 2 == 0) ? 1 : -1;
  234.                 result = mops * fns * VNS.get(new NSKey(n, -s)) / fnm;
  235.             }
  236.         }
  237.         return result;
  238.     }

  239.     /** Key formed by two integer values. */
  240.     public static class NSKey implements Comparable<NSKey> {

  241.         /** n value. */
  242.         private final int n;

  243.         /** s value. */
  244.         private final int s;

  245.         /** Simple constructor.
  246.          * @param n n
  247.          * @param s s
  248.          */
  249.         public NSKey(final int n, final int s) {
  250.             this.n = n;
  251.             this.s = s;
  252.         }

  253.         /** Get n.
  254.          * @return n
  255.          */
  256.         public int getN() {
  257.             return n;
  258.         }

  259.         /** Get s.
  260.          * @return s
  261.          */
  262.         public int getS() {
  263.             return s;
  264.         }

  265.         /** {@inheritDoc} */
  266.         public int compareTo(final NSKey key) {
  267.             int result = 1;
  268.             if (n == key.n) {
  269.                 if (s < key.s) {
  270.                     result = -1;
  271.                 } else if (s == key.s) {
  272.                     result = 0;
  273.                 }
  274.             } else if (n < key.n) {
  275.                 result = -1;
  276.             }
  277.             return result;
  278.         }

  279.         /** {@inheritDoc} */
  280.         public boolean equals(final Object key) {

  281.             if (key == this) {
  282.                 // first fast check
  283.                 return true;
  284.             }

  285.             if (key instanceof NSKey) {
  286.                 return n == ((NSKey) key).n && s == ((NSKey) key).s;
  287.             }

  288.             return false;

  289.         }

  290.         /** {@inheritDoc} */
  291.         public int hashCode() {
  292.             return 0x998493a6 ^ (n << 8) ^ s;
  293.         }

  294.     }

  295. }