1   /* Copyright 2002-2022 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.getNonInterpolatingEOPHistory(),
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     /** Replace the instance with a data transfer object for serialization.
163      * <p>
164      * This intermediate class serializes only the frame key.
165      * </p>
166      * @return data transfer object that will be serialized
167      */
168     @DefaultDataContext
169     private Object writeReplace() {
170         return new DataTransferObject(conventions, eopHistory);
171     }
172 
173     /** Internal class used only for serialization. */
174     @DefaultDataContext
175     private static class DataTransferObject implements Serializable {
176 
177         /** Serializable UID. */
178         private static final long serialVersionUID = 20131209L;
179 
180         /** Conventions. */
181         private final IERSConventions conventions;
182 
183         /** EOP history. */
184         private final EOPHistory eopHistory;
185 
186         /** Simple constructor.
187          * @param conventions IERS conventions to apply
188          * @param eopHistory EOP history
189          */
190         DataTransferObject(final IERSConventions conventions, final EOPHistory eopHistory) {
191             this.conventions = conventions;
192             this.eopHistory  = eopHistory;
193         }
194 
195         /** Replace the deserialized data transfer object with a {@link GTODProvider}.
196          * @return replacement {@link GTODProvider}
197          */
198         private Object readResolve() {
199             try {
200                 // retrieve a managed frame
201                 return new GTODProvider(conventions, eopHistory,
202                         DataContext.getDefault().getTimeScales());
203             } catch (OrekitException oe) {
204                 throw new OrekitInternalError(oe);
205             }
206         }
207 
208     }
209 
210 }