1   /* Copyright 2022-2024 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  
19  import org.hipparchus.util.FastMath;
20  import org.hipparchus.util.SinCos;
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitMessages;
23  
24  /**
25   * Utility methods for converting between different longitude arguments used by {@link EquinoctialOrbit}.
26   * @author Romain Serra
27   * @see EquinoctialOrbit
28   * @since 12.1
29   */
30  public class EquinoctialLongitudeArgumentUtility {
31  
32      /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */
33      private static final double TOLERANCE_CONVERGENCE = 1.0e-12;
34  
35      /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */
36      private static final int MAXIMUM_ITERATION = 50;
37  
38      /** Private constructor for utility class. */
39      private EquinoctialLongitudeArgumentUtility() {
40          // nothing here (utils class)
41      }
42  
43      /**
44       * Computes the true longitude argument from the eccentric longitude argument.
45       *
46       * @param ex e cos(ω), first component of eccentricity vector
47       * @param ey e sin(ω), second component of eccentricity vector
48       * @param lE = E + ω + Ω eccentric longitude argument (rad)
49       * @return the true longitude argument.
50       */
51      public static double eccentricToTrue(final double ex, final double ey, final double lE) {
52          final double epsilon = eccentricAndTrueEpsilon(ex, ey);
53          final SinCos scLE    = FastMath.sinCos(lE);
54          final double num     = ex * scLE.sin() - ey * scLE.cos();
55          final double den     = epsilon + 1 - ex * scLE.cos() - ey * scLE.sin();
56          return lE + eccentricAndTrueAtan(num, den);
57      }
58  
59      /**
60       * Computes the eccentric longitude argument from the true longitude argument.
61       *
62       * @param ex e cos(ω), first component of eccentricity vector
63       * @param ey e sin(ω), second component of eccentricity vector
64       * @param lV = V + ω + Ω true longitude argument (rad)
65       * @return the eccentric longitude argument.
66       */
67      public static double trueToEccentric(final double ex, final double ey, final double lV) {
68          final double epsilon = eccentricAndTrueEpsilon(ex, ey);
69          final SinCos scLv    = FastMath.sinCos(lV);
70          final double num     = ey * scLv.cos() - ex * scLv.sin();
71          final double den     = epsilon + 1 + ex * scLv.cos() + ey * scLv.sin();
72          return lV + eccentricAndTrueAtan(num, den);
73      }
74  
75      /**
76       * Computes an intermediate quantity for conversions between true and eccentric.
77       *
78       * @param ex e cos(ω), first component of eccentricity vector
79       * @param ey e sin(ω), second component of eccentricity vector
80       * @return intermediate variable referred to as epsilon.
81       */
82      private static double eccentricAndTrueEpsilon(final double ex, final double ey) {
83          return FastMath.sqrt(1 - ex * ex - ey * ey);
84      }
85  
86      /**
87       * Computes another intermediate quantity for conversions between true and eccentric.
88       *
89       * @param num numerator for angular conversion
90       * @param den denominator for angular conversion
91       * @return arc-tangent of ratio of inputs times two.
92       */
93      private static double eccentricAndTrueAtan(final double num, final double den) {
94          return 2. * FastMath.atan(num / den);
95      }
96  
97      /**
98       * Computes the eccentric longitude argument from the mean longitude argument.
99       *
100      * @param ex e cos(ω), first component of eccentricity vector
101      * @param ey e sin(ω), second component of eccentricity vector
102      * @param lM = M + ω + Ω  mean longitude argument (rad)
103      * @return the eccentric longitude argument.
104      */
105     public static double meanToEccentric(final double ex, final double ey, final double lM) {
106         // Generalization of Kepler equation to equinoctial parameters
107         // with lE = PA + RAAN + E and
108         //      lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE)
109         double lE = lM;
110         double shift;
111         double lEmlM = 0.0;
112         boolean hasConverged;
113         int iter = 0;
114         do {
115             final SinCos scLE  = FastMath.sinCos(lE);
116             final double f2 = ex * scLE.sin() - ey * scLE.cos();
117             final double f1 = 1.0 - ex * scLE.cos() - ey * scLE.sin();
118             final double f0 = lEmlM - f2;
119 
120             final double f12 = 2.0 * f1;
121             shift = f0 * f12 / (f1 * f12 - f0 * f2);
122 
123             lEmlM -= shift;
124             lE     = lM + lEmlM;
125 
126             hasConverged = FastMath.abs(shift) <= TOLERANCE_CONVERGENCE;
127         } while (++iter < MAXIMUM_ITERATION && !hasConverged);
128 
129         if (!hasConverged) {
130             throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT, iter);
131         }
132         return lE;
133 
134     }
135 
136     /**
137      * Computes the mean longitude argument from the eccentric longitude argument.
138      *
139      * @param ex e cos(ω), first component of eccentricity vector
140      * @param ey e sin(ω), second component of eccentricity vector
141      * @param lE = E + ω + Ω  mean longitude argument (rad)
142      * @return the mean longitude argument.
143      */
144     public static double eccentricToMean(final double ex, final double ey, final double lE) {
145         final SinCos scLE = FastMath.sinCos(lE);
146         return lE - ex * scLE.sin() + ey * scLE.cos();
147     }
148 
149     /**
150      * Computes the mean longitude argument from the eccentric longitude argument.
151      *
152      * @param ex e cos(ω), first component of eccentricity vector
153      * @param ey e sin(ω), second component of eccentricity vector
154      * @param lV = V + ω + Ω  true longitude argument (rad)
155      * @return the mean longitude argument.
156      */
157     public static double trueToMean(final double ex, final double ey, final double lV) {
158         final double alphaE = trueToEccentric(ex, ey, lV);
159         return eccentricToMean(ex, ey, alphaE);
160     }
161 
162     /**
163      * Computes the true longitude argument from the eccentric longitude argument.
164      *
165      * @param ex e cos(ω), first component of eccentricity vector
166      * @param ey e sin(ω), second component of eccentricity vector
167      * @param lM = M + ω + Ω  mean longitude argument (rad)
168      * @return the true longitude argument.
169      */
170     public static double meanToTrue(final double ex, final double ey, final double lM) {
171         final double alphaE = meanToEccentric(ex, ey, lM);
172         return eccentricToTrue(ex, ey, alphaE);
173     }
174 
175 }