1   /* Copyright 2002-2024 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 java.io.Serializable;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Rotation;
25  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
26  import org.hipparchus.geometry.euclidean.threed.Vector3D;
27  import org.orekit.annotation.DefaultDataContext;
28  import org.orekit.data.DataContext;
29  import org.orekit.errors.OrekitException;
30  import org.orekit.errors.OrekitInternalError;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.time.FieldAbsoluteDate;
33  import org.orekit.time.TimeScalarFunction;
34  import org.orekit.time.TimeScale;
35  import org.orekit.time.TimeScales;
36  import org.orekit.utils.Constants;
37  import org.orekit.utils.IERSConventions;
38  
39  /** Greenwich True Of Date Frame, also known as True of Date Rotating frame (TDR)
40   * or Greenwich Rotating Coordinate frame (GCR).
41   * <p> This frame handles the sidereal time according to IAU-82 model.</p>
42   * <p> Its parent frame is the {@link TODProvider}.</p>
43   * <p> The pole motion is not applied here.</p>
44   * @author Pascal Parraud
45   * @author Thierry Ceolin
46   */
47  public class GTODProvider implements EOPBasedTransformProvider {
48  
49      /** Serializable UID. */
50      private static final long serialVersionUID = 20141228L;
51  
52      /** Angular velocity of the Earth, in rad/s. */
53      private static final double AVE = 7.292115146706979e-5;
54  
55      /** Conventions. */
56      private final IERSConventions conventions;
57  
58      /** EOP history. */
59      private final EOPHistory eopHistory;
60  
61      /** GAST function. */
62      private final transient TimeScalarFunction gastFunction;
63  
64      /** Simple constructor.
65       * @param conventions IERS conventions to use
66       * @param eopHistory EOP history (may be null)
67       * @param timeScales  set of time scales to use.
68       * @since 10.1
69       */
70      protected GTODProvider(final IERSConventions conventions,
71                             final EOPHistory eopHistory,
72                             final TimeScales timeScales) {
73          final TimeScale ut1 = eopHistory == null ?
74                  timeScales.getUTC() : // UT1 wihthout EOP is UTC
75                  timeScales.getUT1(eopHistory.getConventions(), eopHistory.isSimpleEop());
76          this.conventions   = conventions;
77          this.eopHistory    = eopHistory;
78          this.gastFunction  = conventions.getGASTFunction(ut1, eopHistory, timeScales);
79      }
80  
81      /**
82       * Private constructor.
83       *
84       * @param conventions  IERS conventions to use
85       * @param eopHistory   EOP history (may be null)
86       * @param gastFunction GAST function
87       */
88      private GTODProvider(final IERSConventions conventions,
89                           final EOPHistory eopHistory,
90                           final TimeScalarFunction gastFunction) {
91          this.conventions = conventions;
92          this.eopHistory = eopHistory;
93          this.gastFunction = gastFunction;
94      }
95  
96      /** {@inheritDoc} */
97      @Override
98      public EOPHistory getEOPHistory() {
99          return eopHistory;
100     }
101 
102     /** {@inheritDoc} */
103     @Override
104     public GTODProvider getNonInterpolatingProvider() {
105         return new GTODProvider(conventions, eopHistory.getEOPHistoryWithoutCachedTidalCorrection(),
106                 gastFunction);
107     }
108 
109     /** {@inheritDoc} */
110     @Override
111     public Transform getTransform(final AbsoluteDate date) {
112         return new Transform(date, getRotation(date), getRotationRate(date));
113     }
114 
115     /** {@inheritDoc} */
116     @Override
117     public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
118         return KinematicTransform.of(date, getRotation(date), getRotationRate(date));
119     }
120 
121     /** {@inheritDoc} */
122     @Override
123     public StaticTransform getStaticTransform(final AbsoluteDate date) {
124         return StaticTransform.of(date, getRotation(date));
125     }
126 
127     /** Form rotation to parent TOD.
128      * @param date transform date
129      * @return rotation to parent at date
130      * @since 12.1
131      */
132     private Rotation getRotation(final AbsoluteDate date) {
133         // compute Greenwich apparent sidereal time, in radians
134         final double gast = gastFunction.value(date);
135 
136         // set up the transform from parent TOD
137         return new Rotation(Vector3D.PLUS_K, gast, RotationConvention.FRAME_TRANSFORM);
138     }
139 
140     /** Form rotation rate w.r.t. parent TOD.
141      * @param date transform date
142      * @return rotation rate at date
143      * @since 12.1
144      */
145     private Vector3D getRotationRate(final AbsoluteDate date) {
146         // compute true angular rotation of Earth, in rad/s
147         final double lod = (eopHistory == null) ? 0.0 : eopHistory.getLOD(date);
148         final double omp = AVE * (1 - lod / Constants.JULIAN_DAY);
149         return new Vector3D(omp, Vector3D.PLUS_K);
150     }
151 
152     /** {@inheritDoc} */
153     @Override
154     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
155         return new FieldTransform<>(date, getRotation(date), getRotationRate(date));
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
161         return FieldKinematicTransform.of(date, getRotation(date), getRotationRate(date));
162     }
163 
164     /** {@inheritDoc} */
165     @Override
166     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
167         return FieldStaticTransform.of(date, getRotation(date));
168     }
169 
170     /** Form rotation to parent TOD.
171      * @param <T> type of the elements
172      * @param date transform date
173      * @return rotation to parent at date
174      * @since 12.1
175      */
176     private <T extends CalculusFieldElement<T>> FieldRotation<T> getRotation(final FieldAbsoluteDate<T> date) {
177         // compute Greenwich apparent sidereal time, in radians
178         final T gast = gastFunction.value(date);
179 
180         // set up the transform from parent TOD
181         return new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), gast, RotationConvention.FRAME_TRANSFORM);
182     }
183 
184     /** Form rotation rate w.r.t. parent TOD.
185      * @param <T> type of the elements
186      * @param date transform date
187      * @return rotation rate at date
188      * @since 12.1
189      */
190     private <T extends CalculusFieldElement<T>> FieldVector3D<T> getRotationRate(final FieldAbsoluteDate<T> date) {
191         // compute true angular rotation of Earth, in rad/s
192         final T lod = (eopHistory == null) ? date.getField().getZero() : eopHistory.getLOD(date);
193         final T omp = lod.multiply(-1.0 / Constants.JULIAN_DAY).add(1).multiply(AVE);
194         return new FieldVector3D<>(date.getField().getZero(),
195                 date.getField().getZero(),
196                 date.getField().getZero().add(omp));
197     }
198 
199     /** Replace the instance with a data transfer object for serialization.
200      * <p>
201      * This intermediate class serializes only the frame key.
202      * </p>
203      * @return data transfer object that will be serialized
204      */
205     @DefaultDataContext
206     private Object writeReplace() {
207         return new DataTransferObject(conventions, eopHistory);
208     }
209 
210     /** Internal class used only for serialization. */
211     @DefaultDataContext
212     private static class DataTransferObject implements Serializable {
213 
214         /** Serializable UID. */
215         private static final long serialVersionUID = 20131209L;
216 
217         /** Conventions. */
218         private final IERSConventions conventions;
219 
220         /** EOP history. */
221         private final EOPHistory eopHistory;
222 
223         /** Simple constructor.
224          * @param conventions IERS conventions to apply
225          * @param eopHistory EOP history
226          */
227         DataTransferObject(final IERSConventions conventions, final EOPHistory eopHistory) {
228             this.conventions = conventions;
229             this.eopHistory  = eopHistory;
230         }
231 
232         /** Replace the deserialized data transfer object with a {@link GTODProvider}.
233          * @return replacement {@link GTODProvider}
234          */
235         private Object readResolve() {
236             try {
237                 // retrieve a managed frame
238                 return new GTODProvider(conventions, eopHistory,
239                         DataContext.getDefault().getTimeScales());
240             } catch (OrekitException oe) {
241                 throw new OrekitInternalError(oe);
242             }
243         }
244 
245     }
246 
247 }