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.frames;
18  
19  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
22  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23  import org.hipparchus.geometry.euclidean.threed.Rotation;
24  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.hipparchus.util.FastMath;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.time.FieldAbsoluteDate;
29  import org.orekit.time.TimeScalarFunction;
30  import org.orekit.time.TimeScales;
31  import org.orekit.time.TimeVectorFunction;
32  import org.orekit.utils.IERSConventions;
33  
34  /** True Equator Mean Equinox Frame.
35   * <p>This frame is used for the SGP4 model in TLE propagation. This frame has <em>no</em>
36   * official definition and there are some ambiguities about whether it should be used
37   * as "of date" or "of epoch". This frame should therefore be used <em>only</em> for
38   * TLE propagation and not for anything else, as recommended by the CCSDS Orbit Data Message
39   * blue book.</p>
40   * @author Luc Maisonobe
41   */
42  class TEMEProvider implements EOPBasedTransformProvider {
43  
44      /** Conventions. */
45      private final IERSConventions conventions;
46  
47      /** EOP history. */
48      private final EOPHistory eopHistory;
49  
50      /** Function computing the mean obliquity. */
51      private final TimeScalarFunction obliquityFunction;
52  
53      /** Function computing the nutation angles. */
54      private final TimeVectorFunction nutationFunction;
55  
56      /**
57       * Simple constructor.
58       *  @param conventions IERS conventions to apply
59       * @param eopHistory  EOP history or {@code null} if no corrections should be
60       *                    applied.
61       * @param timeScales  other time scales used in computing the transform.
62       */
63      TEMEProvider(final IERSConventions conventions,
64                   final EOPHistory eopHistory,
65                   final TimeScales timeScales) {
66          this.conventions       = conventions;
67          this.eopHistory        = eopHistory;
68          this.obliquityFunction = conventions.getMeanObliquityFunction(timeScales);
69          this.nutationFunction  = conventions.getNutationFunction(timeScales);
70      }
71  
72      /**
73       * Private constructor.
74       *
75       * @param conventions       IERS conventions to apply
76       * @param eopHistory        EOP history
77       * @param obliquityFunction to use.
78       * @param nutationFunction  to use.
79       */
80      private TEMEProvider(final IERSConventions conventions,
81                           final EOPHistory eopHistory,
82                           final TimeScalarFunction obliquityFunction,
83                           final TimeVectorFunction nutationFunction) {
84          this.conventions = conventions;
85          this.eopHistory = eopHistory;
86          this.obliquityFunction = obliquityFunction;
87          this.nutationFunction = nutationFunction;
88      }
89  
90      /** {@inheritDoc} */
91      @Override
92      public EOPHistory getEOPHistory() {
93          return eopHistory;
94      }
95  
96      /** {@inheritDoc} */
97      @Override
98      public TEMEProvider getNonInterpolatingProvider() {
99          return new TEMEProvider(conventions, eopHistory.getEOPHistoryWithoutCachedTidalCorrection(),
100                 obliquityFunction, nutationFunction);
101     }
102 
103     /** {@inheritDoc} */
104     @Override
105     public Transform getTransform(final AbsoluteDate date) {
106         final double eqe = getEquationOfEquinoxes(date);
107         return new Transform(date, new Rotation(Vector3D.PLUS_K, eqe, RotationConvention.FRAME_TRANSFORM));
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
113         final T eqe = getEquationOfEquinoxes(date);
114         return new FieldTransform<>(date, new FieldRotation<>(FieldVector3D.getPlusK(date.getField()),
115                                                               eqe,
116                                                               RotationConvention.FRAME_TRANSFORM));
117     }
118 
119     /** Get the Equation of the Equinoxes at the current date.
120      * @param  date the date
121      * @return equation of the equinoxes
122      */
123     private double getEquationOfEquinoxes(final AbsoluteDate date) {
124 
125         // compute nutation angles
126         final double[] angles = nutationFunction.value(date);
127 
128         // nutation in longitude
129         double dPsi = angles[0];
130 
131         if (eopHistory != null) {
132             // apply the corrections for the nutation parameters
133             final double[] correction = eopHistory.getEquinoxNutationCorrection(date);
134             dPsi += correction[0];
135         }
136 
137         // mean obliquity of ecliptic
138         final double moe = obliquityFunction.value(date);
139 
140         // original definition of equation of equinoxes
141         final double eqe = dPsi * FastMath.cos(moe);
142 
143         // apply correction if needed
144         return eqe + angles[2];
145 
146     }
147 
148     /** Get the Equation of the Equinoxes at the current date.
149      * @param  date the date
150      * @param <T> type of the field elements
151      * @return equation of the equinoxes
152      */
153     private <T extends CalculusFieldElement<T>> T getEquationOfEquinoxes(final FieldAbsoluteDate<T> date) {
154 
155         // compute nutation angles
156         final T[] angles = nutationFunction.value(date);
157 
158         // nutation in longitude
159         T dPsi = angles[0];
160 
161         if (eopHistory != null) {
162             // apply the corrections for the nutation parameters
163             final T[] correction = eopHistory.getEquinoxNutationCorrection(date);
164             dPsi = dPsi.add(correction[0]);
165         }
166 
167         // mean obliquity of ecliptic
168         final T moe = obliquityFunction.value(date);
169 
170         // original definition of equation of equinoxes
171         final T eqe = dPsi.multiply(moe.cos());
172 
173         // apply correction if needed
174         return eqe.add(angles[2]);
175 
176     }
177 
178 }