CoefficientsFactory.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;

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

  25. import java.util.SortedMap;
  26. import java.util.concurrent.ConcurrentSkipListMap;

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

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

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

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

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

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

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

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

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

  82.         return Qns;
  83.     }

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

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

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

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

  119.         return Qns;
  120.     }

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

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

  147.         return GsHs;
  148.     }

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

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

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

  179.         return GsHs;
  180.     }

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

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

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

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

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

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

  245.         /** s value. */
  246.         private final int s;

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

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

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

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

  281.         /** {@inheritDoc} */
  282.         public boolean equals(final Object key) {

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

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

  290.             return false;

  291.         }

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

  296.     }

  297. }