1   /* Copyright 2002-2023 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 
113         // compute Greenwich apparent sidereal time, in radians
114         final double gast = gastFunction.value(date);
115 
116         // compute true angular rotation of Earth, in rad/s
117         final double lod = (eopHistory == null) ? 0.0 : eopHistory.getLOD(date);
118         final double omp = AVE * (1 - lod / Constants.JULIAN_DAY);
119         final Vector3D rotationRate = new Vector3D(omp, Vector3D.PLUS_K);
120 
121         // set up the transform from parent TOD
122         return new Transform(date, new Rotation(Vector3D.PLUS_K, gast, RotationConvention.FRAME_TRANSFORM), rotationRate);
123 
124     }
125 
126     /** {@inheritDoc} */
127     @Override
128     public StaticTransform getStaticTransform(final AbsoluteDate date) {
129 
130         // compute Greenwich apparent sidereal time, in radians
131         final double gast = gastFunction.value(date);
132 
133         // set up the transform from parent TOD
134         return StaticTransform.of(
135                 date,
136                 new Rotation(Vector3D.PLUS_K, gast, RotationConvention.FRAME_TRANSFORM));
137 
138     }
139 
140     /** {@inheritDoc} */
141     @Override
142     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
143 
144         // compute Greenwich apparent sidereal time, in radians
145         final T gast = gastFunction.value(date);
146 
147         // compute true angular rotation of Earth, in rad/s
148         final T lod = (eopHistory == null) ? date.getField().getZero() : eopHistory.getLOD(date);
149         final T omp = lod.multiply(-1.0 / Constants.JULIAN_DAY).add(1).multiply(AVE);
150         final FieldVector3D<T> rotationRate = new FieldVector3D<>(date.getField().getZero(),
151                                                                   date.getField().getZero(),
152                                                                   date.getField().getZero().add(omp));
153 
154         // set up the transform from parent TOD
155         return new FieldTransform<>(date,
156                                     new FieldRotation<>(FieldVector3D.getPlusK(date.getField()),
157                                                         gast, RotationConvention.FRAME_TRANSFORM),
158                                     rotationRate);
159 
160     }
161 
162     /** {@inheritDoc} */
163     @Override
164     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
165 
166         // compute Greenwich apparent sidereal time, in radians
167         final T gast = gastFunction.value(date);
168 
169         // set up the transform from parent TOD
170         return FieldStaticTransform.of(
171                 date,
172                 new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), gast, RotationConvention.FRAME_TRANSFORM));
173 
174     }
175 
176     /** Replace the instance with a data transfer object for serialization.
177      * <p>
178      * This intermediate class serializes only the frame key.
179      * </p>
180      * @return data transfer object that will be serialized
181      */
182     @DefaultDataContext
183     private Object writeReplace() {
184         return new DataTransferObject(conventions, eopHistory);
185     }
186 
187     /** Internal class used only for serialization. */
188     @DefaultDataContext
189     private static class DataTransferObject implements Serializable {
190 
191         /** Serializable UID. */
192         private static final long serialVersionUID = 20131209L;
193 
194         /** Conventions. */
195         private final IERSConventions conventions;
196 
197         /** EOP history. */
198         private final EOPHistory eopHistory;
199 
200         /** Simple constructor.
201          * @param conventions IERS conventions to apply
202          * @param eopHistory EOP history
203          */
204         DataTransferObject(final IERSConventions conventions, final EOPHistory eopHistory) {
205             this.conventions = conventions;
206             this.eopHistory  = eopHistory;
207         }
208 
209         /** Replace the deserialized data transfer object with a {@link GTODProvider}.
210          * @return replacement {@link GTODProvider}
211          */
212         private Object readResolve() {
213             try {
214                 // retrieve a managed frame
215                 return new GTODProvider(conventions, eopHistory,
216                         DataContext.getDefault().getTimeScales());
217             } catch (OrekitException oe) {
218                 throw new OrekitInternalError(oe);
219             }
220         }
221 
222     }
223 
224 }