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  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Rotation;
23  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.time.AbsoluteDate;
26  import org.orekit.time.FieldAbsoluteDate;
27  import org.orekit.time.TimeScalarFunction;
28  import org.orekit.time.TimeScale;
29  import org.orekit.time.TimeScales;
30  import org.orekit.utils.Constants;
31  import org.orekit.utils.IERSConventions;
32  
33  /** Greenwich True Of Date Frame, also known as True of Date Rotating frame (TDR)
34   * or Greenwich Rotating Coordinate frame (GCR).
35   * <p> This frame handles the sidereal time according to IAU-82 model.</p>
36   * <p> Its parent frame is the {@link TODProvider}.</p>
37   * <p> The pole motion is not applied here.</p>
38   * @author Pascal Parraud
39   * @author Thierry Ceolin
40   */
41  public class GTODProvider implements EOPBasedTransformProvider {
42  
43      /** Angular velocity of the Earth, in rad/s. */
44      private static final double AVE = 7.292115146706979e-5;
45  
46      /** Conventions. */
47      private final IERSConventions conventions;
48  
49      /** EOP history. */
50      private final EOPHistory eopHistory;
51  
52      /** GAST function. */
53      private final TimeScalarFunction gastFunction;
54  
55      /** Simple constructor.
56       * @param conventions IERS conventions to use
57       * @param eopHistory EOP history (may be null)
58       * @param timeScales  set of time scales to use.
59       * @since 10.1
60       */
61      protected GTODProvider(final IERSConventions conventions,
62                             final EOPHistory eopHistory,
63                             final TimeScales timeScales) {
64          final TimeScale ut1 = eopHistory == null ?
65                  timeScales.getUTC() : // UT1 wihthout EOP is UTC
66                  timeScales.getUT1(eopHistory.getConventions(), eopHistory.isSimpleEop());
67          this.conventions   = conventions;
68          this.eopHistory    = eopHistory;
69          this.gastFunction  = conventions.getGASTFunction(ut1, eopHistory, timeScales);
70      }
71  
72      /**
73       * Private constructor.
74       *
75       * @param conventions  IERS conventions to use
76       * @param eopHistory   EOP history (may be null)
77       * @param gastFunction GAST function
78       */
79      private GTODProvider(final IERSConventions conventions,
80                           final EOPHistory eopHistory,
81                           final TimeScalarFunction gastFunction) {
82          this.conventions = conventions;
83          this.eopHistory = eopHistory;
84          this.gastFunction = gastFunction;
85      }
86  
87      /** {@inheritDoc} */
88      @Override
89      public EOPHistory getEOPHistory() {
90          return eopHistory;
91      }
92  
93      /** {@inheritDoc} */
94      @Override
95      public GTODProvider getNonInterpolatingProvider() {
96          return new GTODProvider(conventions, eopHistory.getEOPHistoryWithoutCachedTidalCorrection(),
97                  gastFunction);
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public Transform getTransform(final AbsoluteDate date) {
103         return new Transform(date, getRotation(date), getRotationRate(date));
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
109         return KinematicTransform.of(date, getRotation(date), getRotationRate(date));
110     }
111 
112     /** {@inheritDoc} */
113     @Override
114     public StaticTransform getStaticTransform(final AbsoluteDate date) {
115         return StaticTransform.of(date, getRotation(date));
116     }
117 
118     /** Form rotation to parent TOD.
119      * @param date transform date
120      * @return rotation to parent at date
121      * @since 12.1
122      */
123     private Rotation getRotation(final AbsoluteDate date) {
124         // compute Greenwich apparent sidereal time, in radians
125         final double gast = gastFunction.value(date);
126 
127         // set up the transform from parent TOD
128         return new Rotation(Vector3D.PLUS_K, gast, RotationConvention.FRAME_TRANSFORM);
129     }
130 
131     /** Form rotation rate w.r.t. parent TOD.
132      * @param date transform date
133      * @return rotation rate at date
134      * @since 12.1
135      */
136     private Vector3D getRotationRate(final AbsoluteDate date) {
137         // compute true angular rotation of Earth, in rad/s
138         final double lod = (eopHistory == null) ? 0.0 : eopHistory.getLOD(date);
139         final double omp = AVE * (1 - lod / Constants.JULIAN_DAY);
140         return new Vector3D(omp, Vector3D.PLUS_K);
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
146         return new FieldTransform<>(date, getRotation(date), getRotationRate(date));
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
152         return FieldKinematicTransform.of(date, getRotation(date), getRotationRate(date));
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
158         return FieldStaticTransform.of(date, getRotation(date));
159     }
160 
161     /** Form rotation to parent TOD.
162      * @param <T> type of the elements
163      * @param date transform date
164      * @return rotation to parent at date
165      * @since 12.1
166      */
167     private <T extends CalculusFieldElement<T>> FieldRotation<T> getRotation(final FieldAbsoluteDate<T> date) {
168         // compute Greenwich apparent sidereal time, in radians
169         final T gast = gastFunction.value(date);
170 
171         // set up the transform from parent TOD
172         return new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), gast, RotationConvention.FRAME_TRANSFORM);
173     }
174 
175     /** Form rotation rate w.r.t. parent TOD.
176      * @param <T> type of the elements
177      * @param date transform date
178      * @return rotation rate at date
179      * @since 12.1
180      */
181     private <T extends CalculusFieldElement<T>> FieldVector3D<T> getRotationRate(final FieldAbsoluteDate<T> date) {
182         // compute true angular rotation of Earth, in rad/s
183         final T lod = (eopHistory == null) ? date.getField().getZero() : eopHistory.getLOD(date);
184         final T omp = lod.multiply(-1.0 / Constants.JULIAN_DAY).add(1).multiply(AVE);
185         return new FieldVector3D<>(date.getField().getZero(),
186                 date.getField().getZero(),
187                 date.getField().getZero().add(omp));
188     }
189 
190 }