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.hipparchus.util.MathUtils;
28  import org.orekit.annotation.DefaultDataContext;
29  import org.orekit.data.DataContext;
30  import org.orekit.errors.OrekitException;
31  import org.orekit.errors.OrekitInternalError;
32  import org.orekit.time.AbsoluteDate;
33  import org.orekit.time.FieldAbsoluteDate;
34  import org.orekit.time.TimeScalarFunction;
35  import org.orekit.time.TimeScale;
36  import org.orekit.utils.Constants;
37  
38  /** Terrestrial Intermediate Reference Frame.
39   * <p> The pole motion is not considered : Pseudo Earth Fixed Frame. It handles
40   * the earth rotation angle, its parent frame is the {@link CIRFProvider}</p>
41   */
42  class TIRFProvider implements EOPBasedTransformProvider {
43  
44      /** Serializable UID. */
45      private static final long serialVersionUID = 20130919L;
46  
47      /** Angular velocity of the Earth, in rad/s. */
48      private static final double AVE = 7.292115146706979e-5;
49  
50      /** EOP history. */
51      private final EOPHistory eopHistory;
52  
53      /** UT1 time scale. */
54      private final transient TimeScale ut1;
55  
56      /** ERA function. */
57      private final transient TimeScalarFunction era;
58  
59      /** Simple constructor.
60       * @param eopHistory EOP history
61       * @param ut1 the UT1 time scale.
62       */
63      protected TIRFProvider(final EOPHistory eopHistory, final TimeScale ut1) {
64  
65          this.ut1        = ut1;
66          this.eopHistory = eopHistory;
67          this.era        = eopHistory.getConventions().getEarthOrientationAngleFunction(
68                  ut1,
69                  eopHistory.getTimeScales().getTAI());
70  
71      }
72  
73      /** {@inheritDoc} */
74      @Override
75      public EOPHistory getEOPHistory() {
76          return eopHistory;
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public TIRFProvider getNonInterpolatingProvider() {
82          return new TIRFProvider(eopHistory.getEOPHistoryWithoutCachedTidalCorrection(), ut1);
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public Transform getTransform(final AbsoluteDate date) {
88          return new Transform(date, getRotation(date), getRotationRate(date));
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public KinematicTransform getKinematicTransform(final AbsoluteDate date) {
94          return KinematicTransform.of(date, getRotation(date), getRotationRate(date));
95      }
96  
97      /** {@inheritDoc} */
98      @Override
99      public StaticTransform getStaticTransform(final AbsoluteDate date) {
100         return StaticTransform.of(date, getRotation(date));
101     }
102 
103     /** Form rotation to parent CIRF.
104      * @param date transform date
105      * @return rotation to parent at date
106      * @since 12.1
107      */
108     private Rotation getRotation(final AbsoluteDate date) {
109         // compute proper rotation
110         final double correctedERA = era.value(date);
111         // set up the transform from parent CIRF
112         return new Rotation(Vector3D.PLUS_K, correctedERA, RotationConvention.FRAME_TRANSFORM);
113     }
114 
115     /** Form rotation rate w.r.t. parent CIRF.
116      * @param date transform date
117      * @return rotation rate at date
118      * @since 12.1
119      */
120     private Vector3D getRotationRate(final AbsoluteDate date) {
121         // compute true angular rotation of Earth, in rad/s
122         final double lod = (eopHistory == null) ? 0.0 : eopHistory.getLOD(date);
123         final double omp = AVE * (1 - lod / Constants.JULIAN_DAY);
124         return new Vector3D(omp, Vector3D.PLUS_K);
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
130         return new FieldTransform<>(date, getRotation(date), getRotationRate(date));
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
136         return FieldKinematicTransform.of(date, getRotation(date), getRotationRate(date));
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
142         return FieldStaticTransform.of(date, getRotation(date));
143     }
144 
145     /** Form rotation to parent CIRF.
146      * @param <T> type of the elements
147      * @param date transform date
148      * @return rotation to parent at date
149      * @since 12.1
150      */
151     private <T extends CalculusFieldElement<T>> FieldRotation<T> getRotation(final FieldAbsoluteDate<T> date) {
152         // compute proper rotation
153         final T correctedERA = era.value(date);
154 
155         // set up the transform from parent CIRF
156         return new FieldRotation<>(
157                 FieldVector3D.getPlusK(date.getField()),
158                 correctedERA,
159                 RotationConvention.FRAME_TRANSFORM);
160     }
161 
162     /** Form rotation rate w.r.t. parent CIRF.
163      * @param <T> type of the elements
164      * @param date transform date
165      * @return rotation rate at date
166      * @since 12.1
167      */
168     private <T extends CalculusFieldElement<T>> FieldVector3D<T> getRotationRate(final FieldAbsoluteDate<T> date) {
169         // compute true angular rotation of Earth, in rad/s
170         final T lod = (eopHistory == null) ? date.getField().getZero() : eopHistory.getLOD(date);
171         final T omp = lod.divide(Constants.JULIAN_DAY).subtract(1).multiply(-AVE);
172         return new FieldVector3D<>(omp, Vector3D.PLUS_K);
173     }
174 
175     /** Get the Earth Rotation Angle at the current date.
176      * @param  date the date
177      * @return Earth Rotation Angle at the current date in radians
178      */
179     public double getEarthRotationAngle(final AbsoluteDate date) {
180         return MathUtils.normalizeAngle(era.value(date), 0);
181     }
182 
183     /** Replace the instance with a data transfer object for serialization.
184      * <p>
185      * This intermediate class serializes only the frame key.
186      * </p>
187      * @return data transfer object that will be serialized
188      */
189     @DefaultDataContext
190     private Object writeReplace() {
191         return new DataTransferObject(eopHistory);
192     }
193 
194     /** Internal class used only for serialization. */
195     @DefaultDataContext
196     private static class DataTransferObject implements Serializable {
197 
198         /** Serializable UID. */
199         private static final long serialVersionUID = 20131209L;
200 
201         /** EOP history. */
202         private final EOPHistory eopHistory;
203 
204         /** Simple constructor.
205          * @param eopHistory EOP history
206          */
207         DataTransferObject(final EOPHistory eopHistory) {
208             this.eopHistory = eopHistory;
209         }
210 
211         /** Replace the deserialized data transfer object with a {@link TIRFProvider}.
212          * @return replacement {@link TIRFProvider}
213          */
214         private Object readResolve() {
215             try {
216                 // retrieve a managed frame
217                 return new TIRFProvider(eopHistory,
218                         DataContext.getDefault().getTimeScales().getUT1(eopHistory));
219             } catch (OrekitException oe) {
220                 throw new OrekitInternalError(oe);
221             }
222         }
223 
224     }
225 
226 }