UpperBounds.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.util.FastMath;


  20. /** Utility class to compute upper bounds for truncation algorithms.
  21.  *
  22.  *  @author Pascal Parraud
  23.  */
  24. public class UpperBounds {

  25.     /** Private constructor as the class is a utility class. */
  26.     private UpperBounds() {
  27.     }

  28.     /** Get the upper bound value D<sub>n</sub><sup>l</sup>(&Chi;).
  29.     *
  30.     * @param xx value of &Chi;²
  31.     * @param xpl value of &Chi; * (&Chi;² / 2)<sup>l</sup>
  32.     * @param n index n (power of a/R)
  33.     * @param l index l (power of eccentricity)
  34.     * @return the upper bound D<sub>n</sub><sup>l</sup>(&Chi;)
  35.     */
  36.     public static double getDnl(final double xx, final double xpl, final int n, final int l) {
  37.         final int lp2 = l + 2;
  38.         if (n > lp2) {
  39.             final int ll = l * l;
  40.             double dM = xpl;
  41.             double dL = dM;
  42.             double dB = (l + 1) * xx * xpl;
  43.             for (int j = l + 3; j <= n; j++) {
  44.                 final int jm1 = j - 1;
  45.                 dL = dM;
  46.                 dM = dB;
  47.                 dB = jm1 * xx * ((2 * j - 3) * dM - (j - 2) * dL) / (jm1 * jm1 - ll);
  48.             }
  49.             return dB;
  50.         } else if (n == lp2) {
  51.             return  (l + 1) * xx * xpl;
  52.         } else {
  53.             return xpl;
  54.         }
  55.     }

  56.     /** Get the upper bound value D<sub>n</sub><sup>l</sup>(&Chi;).
  57.      *
  58.      * @param xx value of &Chi;²
  59.      * @param xpl value of &Chi; * (&Chi;² / 2)<sup>l</sup>
  60.      * @param n index n (power of a/R)
  61.      * @param l index l (power of eccentricity)
  62.      * @param <T> the type of the field elements
  63.      * @return the upper bound D<sub>n</sub><sup>l</sup>(&Chi;)
  64.      */
  65.     public static <T extends CalculusFieldElement<T>> T getDnl(final T xx, final T xpl, final int n, final int l) {
  66.         final int lp2 = l + 2;
  67.         if (n > lp2) {
  68.             final int ll = l * l;
  69.             T dM = xpl;
  70.             T dL = dM;
  71.             T dB = xx.multiply(xpl).multiply(l + 1);
  72.             for (int j = l + 3; j <= n; j++) {
  73.                 final int jm1 = j - 1;
  74.                 dL = dM;
  75.                 dM = dB;
  76.                 dB = xx.multiply(jm1).multiply(dM.multiply(2 * j - 3).subtract(dL.multiply(j - 2))).divide(jm1 * jm1 - ll);
  77.             }
  78.             return dB;
  79.         } else if (n == lp2) {
  80.             return  xx.multiply(xpl).multiply(l + 1);
  81.         } else {
  82.             return xpl;
  83.         }
  84.     }

  85.     /** Get the upper bound value R<sup>ε</sup><sub>n,m,l</sub>(γ).
  86.      *
  87.      * @param gamma value of γ
  88.      * @param n index n
  89.      * @param l index l
  90.      * @param m index m
  91.      * @param eps ε value (+1/-1)
  92.      * @param irf retrograde factor I (+1/-1)
  93.      * @return the upper bound R<sup>ε</sup><sub>n,m,l</sub>(γ)
  94.      */
  95.     public static double getRnml(final double gamma,
  96.                                  final int n, final int l, final int m,
  97.                                  final int eps, final int irf) {
  98.         // Initialization
  99.         final int mei = m * eps * irf;
  100.         final double sinisq = 1. - gamma * gamma;
  101.         // Set a lower bound for inclination
  102.         final double sininc = FastMath.max(0.03, FastMath.sqrt(sinisq));
  103.         final double onepig = 1. + gamma * irf;
  104.         final double sinincPowLmMEI = FastMath.pow(sininc, l - mei);
  105.         final double onepigPowLmMEI = FastMath.pow(onepig, mei);

  106.         // Bound for index 0
  107.         double rBound = sinincPowLmMEI * onepigPowLmMEI;

  108.         // If index > 0
  109.         if (n > l) {
  110.             final int lp1 = l + 1;

  111.             double dpnml  = lp1 * eps;
  112.             double pnml   = dpnml * gamma - m;

  113.             // If index > 1
  114.             if (n > l + 1) {
  115.                 final int ll  = l * l;
  116.                 final int ml  = m * l;
  117.                 final int mm  = m * m;

  118.                 double pn1ml  = 1.;
  119.                 double dpn1ml = 0.;
  120.                 double pn2ml  = 1.;
  121.                 double dpn2ml = 0.;
  122.                 for (int in = l + 2; in <= n; in++) {
  123.                     final int nm1   = in - 1;
  124.                     final int tnm1  = in + nm1;
  125.                     final int nnlnl = nm1 * (in * in - ll);
  126.                     final int nnmnm = in * (nm1 * nm1 - mm);
  127.                     final int c2nne = tnm1 * in * nm1 * eps;
  128.                     final int c2nml = tnm1 * ml;
  129.                     final double coef = c2nne * gamma - c2nml;

  130.                     pn2ml  = pn1ml;
  131.                     dpn2ml = dpn1ml;
  132.                     pn1ml  = pnml;
  133.                     dpn1ml = dpnml;
  134.                     pnml   = (coef * pn1ml  - nnmnm * pn2ml) / nnlnl;
  135.                     dpnml  = (coef * dpn1ml - nnmnm * dpn2ml + c2nne * pn1ml) / nnlnl;
  136.                 }
  137.             }
  138.             // Bound for index > 0
  139.             rBound *= FastMath.sqrt(pnml * pnml + dpnml * dpnml * sinisq / ((n - l) * (n + lp1)));
  140.         }

  141.         return rBound;
  142.     }

  143.     /** Get the upper bound value R<sup>ε</sup><sub>n,m,l</sub>(γ).
  144.     *
  145.     * @param gamma value of γ
  146.     * @param n index n
  147.     * @param l index l
  148.     * @param m index m
  149.     * @param eps ε value (+1/-1)
  150.     * @param irf retrograde factor I (+1/-1)
  151.     * @param <T> the type of the field elements
  152.     * @return the upper bound R<sup>ε</sup><sub>n,m,l</sub>(γ)
  153.     */
  154.     public static <T extends CalculusFieldElement<T>> T getRnml(final T gamma,
  155.                                 final int n, final int l, final int m,
  156.                                 final int eps, final int irf) {
  157.         final T zero = gamma.getField().getZero();
  158.         // Initialization
  159.         final int mei = m * eps * irf;
  160.         final T sinisq = gamma.square().negate().add(1.);
  161.         // Set a lower bound for inclination
  162.         final T sininc = FastMath.max(zero.newInstance(0.03), FastMath.sqrt(sinisq));
  163.         final T onepig = gamma.multiply(irf).add(1.);
  164.         final T sinincPowLmMEI = FastMath.pow(sininc, l - mei);
  165.         final T onepigPowLmMEI = FastMath.pow(onepig, mei);

  166.         // Bound for index 0
  167.         T rBound = sinincPowLmMEI.multiply(onepigPowLmMEI);

  168.         // If index > 0
  169.         if (n > l) {
  170.             final int lp1 = l + 1;

  171.             T dpnml  = zero.newInstance(lp1 * eps);
  172.             T pnml   = gamma.multiply(dpnml).subtract(m);

  173.             // If index > 1
  174.             if (n > l + 1) {
  175.                 final int ll  = l * l;
  176.                 final int ml  = m * l;
  177.                 final int mm  = m * m;

  178.                 T pn1ml  = zero.newInstance(1.);
  179.                 T dpn1ml = zero;
  180.                 T pn2ml  = zero.newInstance(1.);
  181.                 T dpn2ml = zero;
  182.                 for (int in = l + 2; in <= n; in++) {
  183.                     final int nm1   = in - 1;
  184.                     final int tnm1  = in + nm1;
  185.                     final int nnlnl = nm1 * (in * in - ll);
  186.                     final int nnmnm = in * (nm1 * nm1 - mm);
  187.                     final int c2nne = tnm1 * in * nm1 * eps;
  188.                     final int c2nml = tnm1 * ml;
  189.                     final T coef = gamma.multiply(c2nne).subtract(c2nml);

  190.                     pn2ml  = pn1ml;
  191.                     dpn2ml = dpn1ml;
  192.                     pn1ml  = pnml;
  193.                     dpn1ml = dpnml;
  194.                     pnml   = (coef.multiply(pn1ml).subtract(pn2ml.multiply(nnmnm))).divide(nnlnl);
  195.                     dpnml  = (coef.multiply(dpn1ml).subtract(dpn2ml.multiply(nnmnm)).add(pn1ml.multiply(c2nne))).divide(nnlnl);
  196.                 }
  197.             }
  198.             // Bound for index > 0
  199.             rBound = rBound.multiply(FastMath.sqrt(pnml.multiply(pnml).add(dpnml.multiply(dpnml).multiply(sinisq).divide((n - l) * (n + lp1)))));
  200.         }

  201.         return rBound;
  202.     }

  203. }