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.SortedMap;
  19. import java.util.TreeMap;
  20. import java.util.concurrent.ConcurrentSkipListMap;

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

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

  34.     /** Internal storage of the polynomial values. Reused for further computation. */
  35.     private static SortedMap<NSKey, Double> VNS = new ConcurrentSkipListMap<NSKey, Double>();

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

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

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

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

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

  68.         // first element
  69.         Qns[0][0] = 1;

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

  83.         return Qns;
  84.     }

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

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

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

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

  120.         return Qns;
  121.     }

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

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

  148.         return GsHs;
  149.     }

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

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

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

  180.         return GsHs;
  181.     }

  182.     /** Compute the V<sub>n,s</sub> coefficients from 2.8.2-(1)(2).
  183.      * @param order Order of the computation. Computation will be done from 0 to order -1
  184.      * @return Map of the V<sub>n, s</sub> coefficients
  185.      * @deprecated as of 11.3.3, replaced by {@link #computeVnsCoefficients(int)}
  186.      */
  187.     @Deprecated
  188.     public static TreeMap<NSKey, Double> computeVns(final int order) {
  189.         return new TreeMap<>(computeVnsCoefficients(order));
  190.     }

  191.     /** Compute the V<sub>n,s</sub> coefficients from 2.8.2-(1)(2).
  192.      * @param order Order of the computation. Computation will be done from 0 to order -1
  193.      * @return Map of the V<sub>n, s</sub> coefficients
  194.      * @since 11.3.3
  195.      */
  196.     // TODO rename to computeVns in 12.0?
  197.     public static SortedMap<NSKey, Double> computeVnsCoefficients(final int order) {

  198.         if (order > LAST_VNS_ORDER) {
  199.             // Compute coefficient
  200.             // Need previous computation as recurrence relation is done at s + 1 and n + 2
  201.             final int min = (LAST_VNS_ORDER - 2 < 0) ? 0 : (LAST_VNS_ORDER - 2);
  202.             for (int n = min; n < order; n++) {
  203.                 for (int s = 0; s < n + 1; s++) {
  204.                     if ((n - s) % 2 != 0) {
  205.                         VNS.put(new NSKey(n, s), 0.);
  206.                     } else {
  207.                         // s = n
  208.                         if (n == s && (s + 1) < order) {
  209.                             VNS.put(new NSKey(s + 1, s + 1), VNS.get(new NSKey(s, s)) / (2 * s + 2.));
  210.                         }
  211.                         // otherwise
  212.                         if ((n + 2) < order) {
  213.                             VNS.put(new NSKey(n + 2, s), VNS.get(new NSKey(n, s)) * (-n + s - 1.) / (n + s + 2.));
  214.                         }
  215.                     }
  216.                 }
  217.             }
  218.             LAST_VNS_ORDER = order;
  219.         }
  220.         return new ConcurrentSkipListMap<>(VNS);
  221.     }

  222.     /** Get the V<sub>n,s</sub><sup>m</sup> coefficient from V<sub>n,s</sub>.
  223.      *  <br>See § 2.8.2 in Danielson paper.
  224.      * @param m m
  225.      * @param n n
  226.      * @param s s
  227.      * @return The V<sub>n, s</sub> <sup>m</sup> coefficient
  228.      */
  229.     public static double getVmns(final int m, final int n, final int s) {
  230.         if (m > n) {
  231.             throw new OrekitException(OrekitMessages.DSST_VMNS_COEFFICIENT_ERROR_MS, m, n);
  232.         }
  233.         final double fns = CombinatoricsUtils.factorialDouble(n + FastMath.abs(s));
  234.         final double fnm = CombinatoricsUtils.factorialDouble(n  - m);

  235.         double result = 0;
  236.         // If (n - s) is odd, the Vmsn coefficient is null
  237.         if ((n - s) % 2 == 0) {
  238.             // Update the Vns coefficient
  239.             if ((n + 1) > LAST_VNS_ORDER) {
  240.                 computeVnsCoefficients(n + 1);
  241.             }
  242.             if (s >= 0) {
  243.                 result = fns  * VNS.get(new NSKey(n, s)) / fnm;
  244.             } else {
  245.                 // If s < 0 : Vmn-s = (-1)^(-s) Vmns
  246.                 final int mops = (s % 2 == 0) ? 1 : -1;
  247.                 result = mops * fns * VNS.get(new NSKey(n, -s)) / fnm;
  248.             }
  249.         }
  250.         return result;
  251.     }

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

  254.         /** n value. */
  255.         private final int n;

  256.         /** s value. */
  257.         private final int s;

  258.         /** Simple constructor.
  259.          * @param n n
  260.          * @param s s
  261.          */
  262.         public NSKey(final int n, final int s) {
  263.             this.n = n;
  264.             this.s = s;
  265.         }

  266.         /** Get n.
  267.          * @return n
  268.          */
  269.         public int getN() {
  270.             return n;
  271.         }

  272.         /** Get s.
  273.          * @return s
  274.          */
  275.         public int getS() {
  276.             return s;
  277.         }

  278.         /** {@inheritDoc} */
  279.         public int compareTo(final NSKey key) {
  280.             int result = 1;
  281.             if (n == key.n) {
  282.                 if (s < key.s) {
  283.                     result = -1;
  284.                 } else if (s == key.s) {
  285.                     result = 0;
  286.                 }
  287.             } else if (n < key.n) {
  288.                 result = -1;
  289.             }
  290.             return result;
  291.         }

  292.         /** {@inheritDoc} */
  293.         public boolean equals(final Object key) {

  294.             if (key == this) {
  295.                 // first fast check
  296.                 return true;
  297.             }

  298.             if (key instanceof NSKey) {
  299.                 return n == ((NSKey) key).n && s == ((NSKey) key).s;
  300.             }

  301.             return false;

  302.         }

  303.         /** {@inheritDoc} */
  304.         public int hashCode() {
  305.             return 0x998493a6 ^ (n << 8) ^ s;
  306.         }

  307.     }

  308. }