1   /* Copyright 2002-2025 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 org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
21  import org.hipparchus.geometry.euclidean.threed.Rotation;
22  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
23  import org.hipparchus.geometry.euclidean.threed.RotationOrder;
24  import org.orekit.time.AbsoluteDate;
25  import org.orekit.time.FieldAbsoluteDate;
26  import org.orekit.time.TimeScalarFunction;
27  import org.orekit.time.TimeScales;
28  import org.orekit.time.TimeVectorFunction;
29  import org.orekit.utils.IERSConventions;
30  
31  /** Provider for True of Date (ToD) frame.
32   * <p>This frame handles nutation effects according to selected IERS conventions.</p>
33   * <p>Transform is computed with reference to the {@link MODProvider Mean of Date} frame.</p>
34   * @author Pascal Parraud
35   */
36  class TODProvider implements EOPBasedTransformProvider {
37  
38      /** Conventions. */
39      private final IERSConventions conventions;
40  
41      /** EOP history. */
42      private final EOPHistory eopHistory;
43  
44      /** Function computing the mean obliquity. */
45      private final TimeScalarFunction obliquityFunction;
46  
47      /** Function computing the nutation angles. */
48      private final TimeVectorFunction nutationFunction;
49  
50  
51      /**
52       * Simple constructor.
53       *  @param conventions IERS conventions to apply
54       * @param eopHistory  EOP history, or {@code null} if no correction should be
55       *                    applied.
56       * @param timeScales         TAI time scale.
57       */
58      TODProvider(final IERSConventions conventions,
59                  final EOPHistory eopHistory,
60                  final TimeScales timeScales) {
61          this.conventions       = conventions;
62          this.eopHistory        = eopHistory;
63          this.obliquityFunction = conventions.getMeanObliquityFunction(timeScales);
64          this.nutationFunction  =
65                  conventions.getNutationFunction(timeScales);
66      }
67  
68      /**
69       * Private constructor.
70       *
71       * @param conventions       IERS conventions to use.
72       * @param eopHistory        or {@code null} if no correction should be applied.
73       * @param obliquityFunction to use.
74       * @param nutationFunction  to use.
75       */
76      private TODProvider(final IERSConventions conventions,
77                          final EOPHistory eopHistory,
78                          final TimeScalarFunction obliquityFunction,
79                          final TimeVectorFunction nutationFunction) {
80          this.conventions = conventions;
81          this.eopHistory = eopHistory;
82          this.obliquityFunction = obliquityFunction;
83          this.nutationFunction = nutationFunction;
84      }
85  
86      /** {@inheritDoc} */
87      @Override
88      public EOPHistory getEOPHistory() {
89          return eopHistory;
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public TODProvider getNonInterpolatingProvider() {
95          return new TODProvider(conventions, eopHistory.getEOPHistoryWithoutCachedTidalCorrection(),
96                  obliquityFunction, nutationFunction);
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public Transform getTransform(final AbsoluteDate date) {
102 
103         // compute nutation angles
104         final double[] angles = nutationFunction.value(date);
105 
106         // compute the mean obliquity of the ecliptic
107         final double moe = obliquityFunction.value(date);
108 
109         double dpsi = angles[0];
110         double deps = angles[1];
111         if (eopHistory != null) {
112             // apply the corrections for the nutation parameters
113             final double[] correction = eopHistory.getEquinoxNutationCorrection(date);
114             dpsi += correction[0];
115             deps += correction[1];
116         }
117 
118         // compute the true obliquity of the ecliptic
119         final double toe = moe + deps;
120 
121         // complete nutation
122         final Rotation nutation = new Rotation(RotationOrder.XZX, RotationConvention.FRAME_TRANSFORM,
123                                                moe, -dpsi, -toe);
124 
125         // set up the transform from parent MOD
126         return new Transform(date, nutation);
127 
128     }
129 
130     /** Replace the instance with a data transfer object for serialization.
131     /** {@inheritDoc} */
132     @Override
133     public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
134 
135         // compute nutation angles
136         final T[] angles = nutationFunction.value(date);
137 
138         // compute the mean obliquity of the ecliptic
139         final T moe = obliquityFunction.value(date);
140 
141         T dpsi = angles[0];
142         T deps = angles[1];
143         if (eopHistory != null) {
144             // apply the corrections for the nutation parameters
145             final T[] correction = eopHistory.getEquinoxNutationCorrection(date);
146             dpsi = dpsi.add(correction[0]);
147             deps = deps.add(correction[1]);
148         }
149 
150         // compute the true obliquity of the ecliptic
151         final T toe = moe.add(deps);
152 
153         // complete nutation
154         final FieldRotation<T> nutation = new FieldRotation<>(RotationOrder.XZX, RotationConvention.FRAME_TRANSFORM,
155                                                               moe, dpsi.negate(), toe.negate());
156 
157         // set up the transform from parent MOD
158         return new FieldTransform<>(date, nutation);
159 
160     }
161 
162 }