1   /* Copyright 2002-2020 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.RealFieldElement;
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       *
66       * <p>This method uses the {@link DataContext#getDefault() default data context} if
67       * {@code eopHistory == null}.
68       *
69       * @param conventions IERS conventions to use
70       * @param eopHistory EOP history (may be null)
71       * @deprecated use {@link #GTODProvider(IERSConventions, EOPHistory, TimeScales)}
72       * instead.
73       */
74      @Deprecated
75      @DefaultDataContext
76      protected GTODProvider(final IERSConventions conventions,
77                             final EOPHistory eopHistory) {
78          this(conventions, eopHistory,
79                  eopHistory == null ?
80                          DataContext.getDefault().getTimeScales() :
81                          eopHistory.getTimeScales());
82      }
83  
84      /** Simple constructor.
85       * @param conventions IERS conventions to use
86       * @param eopHistory EOP history (may be null)
87       * @param timeScales  set of time scales to use.
88       * @since 10.1
89       */
90      protected GTODProvider(final IERSConventions conventions,
91                             final EOPHistory eopHistory,
92                             final TimeScales timeScales) {
93          final TimeScale ut1 = eopHistory == null ?
94                  timeScales.getUTC() : // UT1 wihthout EOP is UTC
95                  timeScales.getUT1(eopHistory.getConventions(), eopHistory.isSimpleEop());
96          this.conventions   = conventions;
97          this.eopHistory    = eopHistory;
98          this.gastFunction  = conventions.getGASTFunction(ut1, eopHistory, timeScales);
99      }
100 
101     /**
102      * Private constructor.
103      *
104      * @param conventions  IERS conventions to use
105      * @param eopHistory   EOP history (may be null)
106      * @param gastFunction GAST function
107      */
108     private GTODProvider(final IERSConventions conventions,
109                          final EOPHistory eopHistory,
110                          final TimeScalarFunction gastFunction) {
111         this.conventions = conventions;
112         this.eopHistory = eopHistory;
113         this.gastFunction = gastFunction;
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public EOPHistory getEOPHistory() {
119         return eopHistory;
120     }
121 
122     /** {@inheritDoc} */
123     @Override
124     public GTODProvider getNonInterpolatingProvider() {
125         return new GTODProvider(conventions, eopHistory.getNonInterpolatingEOPHistory(),
126                 gastFunction);
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public Transform getTransform(final AbsoluteDate date) {
132 
133         // compute Greenwich apparent sidereal time, in radians
134         final double gast = gastFunction.value(date);
135 
136         // compute true angular rotation of Earth, in rad/s
137         final double lod = (eopHistory == null) ? 0.0 : eopHistory.getLOD(date);
138         final double omp = AVE * (1 - lod / Constants.JULIAN_DAY);
139         final Vector3D rotationRate = new Vector3D(omp, Vector3D.PLUS_K);
140 
141         // set up the transform from parent TOD
142         return new Transform(date, new Rotation(Vector3D.PLUS_K, gast, RotationConvention.FRAME_TRANSFORM), rotationRate);
143 
144     }
145 
146     /** {@inheritDoc} */
147     @Override
148     public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
149 
150         // compute Greenwich apparent sidereal time, in radians
151         final T gast = gastFunction.value(date);
152 
153         // compute true angular rotation of Earth, in rad/s
154         final T lod = (eopHistory == null) ? date.getField().getZero() : eopHistory.getLOD(date);
155         final T omp = lod.multiply(-1.0 / Constants.JULIAN_DAY).add(1).multiply(AVE);
156         final FieldVector3D<T> rotationRate = new FieldVector3D<>(date.getField().getZero(),
157                                                                   date.getField().getZero(),
158                                                                   date.getField().getZero().add(omp));
159 
160         // set up the transform from parent TOD
161         return new FieldTransform<>(date,
162                                     new FieldRotation<>(FieldVector3D.getPlusK(date.getField()),
163                                                         gast, RotationConvention.FRAME_TRANSFORM),
164                                     rotationRate);
165 
166     }
167 
168     /** Replace the instance with a data transfer object for serialization.
169      * <p>
170      * This intermediate class serializes only the frame key.
171      * </p>
172      * @return data transfer object that will be serialized
173      */
174     @DefaultDataContext
175     private Object writeReplace() {
176         return new DataTransferObject(conventions, eopHistory);
177     }
178 
179     /** Internal class used only for serialization. */
180     @DefaultDataContext
181     private static class DataTransferObject implements Serializable {
182 
183         /** Serializable UID. */
184         private static final long serialVersionUID = 20131209L;
185 
186         /** Conventions. */
187         private final IERSConventions conventions;
188 
189         /** EOP history. */
190         private final EOPHistory eopHistory;
191 
192         /** Simple constructor.
193          * @param conventions IERS conventions to apply
194          * @param eopHistory EOP history
195          */
196         DataTransferObject(final IERSConventions conventions, final EOPHistory eopHistory) {
197             this.conventions = conventions;
198             this.eopHistory  = eopHistory;
199         }
200 
201         /** Replace the deserialized data transfer object with a {@link GTODProvider}.
202          * @return replacement {@link GTODProvider}
203          */
204         private Object readResolve() {
205             try {
206                 // retrieve a managed frame
207                 return new GTODProvider(conventions, eopHistory,
208                         DataContext.getDefault().getTimeScales());
209             } catch (OrekitException oe) {
210                 throw new OrekitInternalError(oe);
211             }
212         }
213 
214     }
215 
216 }