FieldCircularLatitudeArgumentUtility.java

  1. /* Copyright 2022-2025 Romain Serra
  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.orbits;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.util.FastMath;
  20. import org.hipparchus.util.FieldSinCos;
  21. import org.orekit.errors.OrekitException;
  22. import org.orekit.errors.OrekitInternalError;
  23. import org.orekit.errors.OrekitMessages;

  24. /**
  25.  * Utility methods for converting between different latitude arguments used by {@link FieldCircularOrbit}.
  26.  * @author Romain Serra
  27.  * @see FieldCircularOrbit
  28.  * @since 12.1
  29.  */
  30. public class FieldCircularLatitudeArgumentUtility {

  31.     /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */
  32.     private static final double TOLERANCE_CONVERGENCE = 1.0e-11;

  33.     /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */
  34.     private static final int MAXIMUM_ITERATION = 50;

  35.     /** Private constructor for utility class. */
  36.     private FieldCircularLatitudeArgumentUtility() {
  37.         // nothing here (utils class)
  38.     }

  39.     /**
  40.      * Computes the true latitude argument from the eccentric latitude argument.
  41.      *
  42.      * @param <T>    Type of the field elements
  43.      * @param ex     e cos(ω), first component of circular eccentricity vector
  44.      * @param ey     e sin(ω), second component of circular eccentricity vector
  45.      * @param alphaE = E + ω eccentric latitude argument (rad)
  46.      * @return the true latitude argument.
  47.      */
  48.     public static <T extends CalculusFieldElement<T>> T eccentricToTrue(final T ex, final T ey, final T alphaE) {
  49.         final T epsilon               = eccentricAndTrueEpsilon(ex, ey);
  50.         final FieldSinCos<T> scAlphaE = FastMath.sinCos(alphaE);
  51.         final T cosAlphaE             = scAlphaE.cos();
  52.         final T sinAlphaE             = scAlphaE.sin();
  53.         final T num                   = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE));
  54.         final T den                   = epsilon.add(1).subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE));
  55.         return alphaE.add(eccentricAndTrueAtan(num, den));
  56.     }

  57.     /**
  58.      * Computes the eccentric latitude argument from the true latitude argument.
  59.      *
  60.      * @param <T>    Type of the field elements
  61.      * @param ex     e cos(ω), first component of circular eccentricity vector
  62.      * @param ey     e sin(ω), second component of circular eccentricity vector
  63.      * @param alphaV = v + ω true latitude argument (rad)
  64.      * @return the eccentric latitude argument.
  65.      */
  66.     public static <T extends CalculusFieldElement<T>> T trueToEccentric(final T ex, final T ey, final T alphaV) {
  67.         final T epsilon               = eccentricAndTrueEpsilon(ex, ey);
  68.         final FieldSinCos<T> scAlphaV = FastMath.sinCos(alphaV);
  69.         final T cosAlphaV             = scAlphaV.cos();
  70.         final T sinAlphaV             = scAlphaV.sin();
  71.         final T num                   = ey.multiply(cosAlphaV).subtract(ex.multiply(sinAlphaV));
  72.         final T den                   = epsilon.add(1).add(ex.multiply(cosAlphaV).add(ey.multiply(sinAlphaV)));
  73.         return alphaV.add(eccentricAndTrueAtan(num, den));
  74.     }

  75.     /**
  76.      * Computes an intermediate quantity for conversions between true and eccentric.
  77.      *
  78.      * @param <T>    Type of the field elements
  79.      * @param ex e cos(ω), first component of circular eccentricity vector
  80.      * @param ey e sin(ω), second component of circular eccentricity vector
  81.      * @return intermediate variable referred to as epsilon.
  82.      */
  83.     private static <T extends CalculusFieldElement<T>> T eccentricAndTrueEpsilon(final T ex, final T ey) {
  84.         return (ex.square().negate().subtract(ey.square()).add(1.)).sqrt();
  85.     }

  86.     /**
  87.      * Computes another intermediate quantity for conversions between true and eccentric.
  88.      *
  89.      * @param <T>    Type of the field elements
  90.      * @param num numerator for angular conversion
  91.      * @param den denominator for angular conversion
  92.      * @return arc-tangent of ratio of inputs times two.
  93.      */
  94.     private static <T extends CalculusFieldElement<T>> T eccentricAndTrueAtan(final T num, final T den) {
  95.         return (num.divide(den)).atan().multiply(2);
  96.     }

  97.     /**
  98.      * Computes the eccentric latitude argument from the mean latitude argument.
  99.      *
  100.      * @param <T>    Type of the field elements
  101.      * @param ex     e cos(ω), first component of circular eccentricity vector
  102.      * @param ey     e sin(ω), second component of circular eccentricity vector
  103.      * @param alphaM = M + ω  mean latitude argument (rad)
  104.      * @return the eccentric latitude argument.
  105.      */
  106.     public static <T extends CalculusFieldElement<T>> T meanToEccentric(final T ex, final T ey, final T alphaM) {
  107.         // Generalization of Kepler equation to circular parameters
  108.         // with alphaE = PA + E and
  109.         //      alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)

  110.         T alphaE                = alphaM;
  111.         T shift;
  112.         T alphaEMalphaM         = alphaM.getField().getZero();
  113.         boolean hasConverged;
  114.         int    iter     = 0;
  115.         do {
  116.             final FieldSinCos<T> scAlphaE = FastMath.sinCos(alphaE);
  117.             final T f2 = ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos()));
  118.             final T f1 = ex.negate().multiply(scAlphaE.cos()).subtract(ey.multiply(scAlphaE.sin())).add(1);
  119.             final T f0 = alphaEMalphaM.subtract(f2);

  120.             final T f12 = f1.multiply(2);
  121.             shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2)));

  122.             alphaEMalphaM  = alphaEMalphaM.subtract(shift);
  123.             alphaE         = alphaM.add(alphaEMalphaM);

  124.             hasConverged = FastMath.abs(shift.getReal()) <= TOLERANCE_CONVERGENCE;
  125.         } while (++iter < MAXIMUM_ITERATION && !hasConverged);

  126.         if (!hasConverged) {
  127.             throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT, iter);
  128.         }
  129.         return alphaE;

  130.     }

  131.     /**
  132.      * Computes the mean latitude argument from the eccentric latitude argument.
  133.      *
  134.      * @param <T>    Type of the field elements
  135.      * @param ex     e cos(ω), first component of circular eccentricity vector
  136.      * @param ey     e sin(ω), second component of circular eccentricity vector
  137.      * @param alphaE = E + ω  eccentric latitude argument (rad)
  138.      * @return the mean latitude argument.
  139.      */
  140.     public static <T extends CalculusFieldElement<T>> T eccentricToMean(final T ex, final T ey, final T alphaE) {
  141.         final FieldSinCos<T> scAlphaE = FastMath.sinCos(alphaE);
  142.         return alphaE.subtract(ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos())));
  143.     }

  144.     /**
  145.      * Computes the mean latitude argument from the eccentric latitude argument.
  146.      *
  147.      * @param <T>    Type of the field elements
  148.      * @param ex     e cos(ω), first component of circular eccentricity vector
  149.      * @param ey     e sin(ω), second component of circular eccentricity vector
  150.      * @param alphaV = V + ω  true latitude argument (rad)
  151.      * @return the mean latitude argument.
  152.      */
  153.     public static <T extends CalculusFieldElement<T>> T trueToMean(final T ex, final T ey, final T alphaV) {
  154.         final T alphaE = trueToEccentric(ex, ey, alphaV);
  155.         return eccentricToMean(ex, ey, alphaE);
  156.     }

  157.     /**
  158.      * Computes the true latitude argument from the eccentric latitude argument.
  159.      *
  160.      * @param <T>    Type of the field elements
  161.      * @param ex     e cos(ω), first component of circular eccentricity vector
  162.      * @param ey     e sin(ω), second component of circular eccentricity vector
  163.      * @param alphaM = M + ω  mean latitude argument (rad)
  164.      * @return the true latitude argument.
  165.      */
  166.     public static <T extends CalculusFieldElement<T>> T meanToTrue(final T ex, final T ey, final T alphaM) {
  167.         final T alphaE = meanToEccentric(ex, ey, alphaM);
  168.         return eccentricToTrue(ex, ey, alphaE);
  169.     }

  170.     /**
  171.      * Convert argument of latitude.
  172.      * @param oldType old position angle type
  173.      * @param alpha old value for argument of latitude
  174.      * @param ex ex
  175.      * @param ey ey
  176.      * @param newType new position angle type
  177.      * @param <T> field type
  178.      * @return convert argument of latitude
  179.      * @since 12.2
  180.      */
  181.     public static <T extends CalculusFieldElement<T>> T convertAlpha(final PositionAngleType oldType, final T alpha,
  182.                                                                      final T ex, final T ey,
  183.                                                                      final PositionAngleType newType) {
  184.         if (oldType == newType) {
  185.             return alpha;

  186.         } else {
  187.             switch (newType) {

  188.                 case ECCENTRIC:
  189.                     if (oldType == PositionAngleType.MEAN) {
  190.                         return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alpha);
  191.                     } else {
  192.                         return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alpha);
  193.                     }

  194.                 case MEAN:
  195.                     if (oldType == PositionAngleType.TRUE) {
  196.                         return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, alpha);
  197.                     } else {
  198.                         return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alpha);
  199.                     }

  200.                 case TRUE:
  201.                     if (oldType == PositionAngleType.MEAN) {
  202.                         return FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha);
  203.                     } else {
  204.                         return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha);
  205.                     }

  206.                 default:
  207.                     throw new OrekitInternalError(null);
  208.             }
  209.         }
  210.     }
  211. }