1   /* Copyright 2022-2026 Luc Maisonobe
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.propagation.analytical.gnss.data;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.util.FastMath;
22  import org.orekit.gnss.SatelliteSystem;
23  import org.orekit.time.FieldAbsoluteDate;
24  import org.orekit.time.FieldTimeStamped;
25  import org.orekit.time.GNSSDate;
26  import org.orekit.time.TimeScales;
27  
28  import java.util.function.Function;
29  
30  /** This class provides the minimal set of orbital elements needed by the {@link
31   * org.orekit.propagation.analytical.gnss.FieldGnssPropagator}.
32   * @param <T> type of the field elements
33   * @param <O> type of the orbital elements (non-field version)
34   * @since 13.0
35   * @author Luc Maisonobe
36  */
37  public abstract class FieldGnssOrbitalElements<T extends CalculusFieldElement<T>, O extends GNSSOrbitalElements<O>>
38      extends GNSSOrbitalElementsDriversProvider
39      implements FieldTimeStamped<T> {
40  
41      /** Earth's universal gravitational parameter. */
42      private final T mu;
43  
44      /** Reference epoch. */
45      private FieldAbsoluteDate<T> date;
46  
47      /** Semi-Major Axis (m). */
48      private T sma;
49  
50      /** Eccentricity. */
51      private T ecc;
52  
53      /** Inclination angle at reference time (rad). */
54      private T i0;
55  
56      /** Argument of perigee (rad). */
57      private T aop;
58  
59      /** Longitude of ascending node of orbit plane at weekly epoch (rad). */
60      private T om0;
61  
62      /** Mean anomaly at reference time (rad). */
63      private T anom;
64  
65      /** Simple constructor.
66       * @param mu              Earth's universal gravitational parameter
67       * @param angularVelocity mean angular velocity of the Earth for the GNSS model
68       * @param weeksInCycle    number of weeks in the GNSS cycle
69       * @param timeScales      known time scales
70       * @param system          satellite system to consider for interpreting week number
71       *                        (may be different from real system, for example in Rinex nav, weeks
72       *                        are always according to GPS)
73       */
74      protected FieldGnssOrbitalElements(final T mu, final double angularVelocity, final int weeksInCycle,
75                                         final TimeScales timeScales, final SatelliteSystem system) {
76  
77          super(angularVelocity, weeksInCycle, timeScales, system);
78  
79          // immutable field
80          this.mu   = mu;
81  
82          // Keplerian orbital elements
83          this.sma  = mu.newInstance(Double.NaN);
84          this.ecc  = mu.newInstance(Double.NaN);
85          this.i0   = mu.newInstance(Double.NaN);
86          this.aop  = mu.newInstance(Double.NaN);
87          this.om0  = mu.newInstance(Double.NaN);
88          this.anom = mu.newInstance(Double.NaN);
89  
90      }
91  
92      /** Constructor from non-field instance.
93       * @param field    field to which elements belong
94       * @param original regular non-field instance
95       */
96      protected FieldGnssOrbitalElements(final Field<T> field, final O original) {
97  
98          super(original.getAngularVelocity(), original.getWeeksInCycle(),
99                original.getTimeScales(), original.getSystem());
100         mu = field.getZero().newInstance(original.getMu());
101 
102         // non-Keplerian parameters
103         copyNonKeplerian(original);
104 
105         // Keplerian orbital elements
106         setGnssDate(new GNSSDate(original.getWeek(), original.getTime(), original.getSystem(), original.getTimeScales()));
107         setSma(field.getZero().newInstance(original.getSma()));
108         setE(field.getZero().newInstance(original.getE()));
109         setI0(field.getZero().newInstance(original.getI0()));
110         setPa(field.getZero().newInstance(original.getPa()));
111         setOmega0(field.getZero().newInstance(original.getOmega0()));
112         setM0(field.getZero().newInstance(original.getM0()));
113 
114         // copy selection settings
115         copySelectionSettings(original);
116 
117     }
118 
119     /** Constructor from different field instance.
120      * @param <V> type of the old field elements
121      * @param original regular non-field instance
122      * @param converter for field elements
123      */
124     protected <V extends CalculusFieldElement<V>> FieldGnssOrbitalElements(final Function<V, T> converter,
125                                                                            final FieldGnssOrbitalElements<V, O> original) {
126         super(original.getAngularVelocity(), original.getWeeksInCycle(),
127               original.getTimeScales(), original.getSystem());
128         mu = converter.apply(original.getMu());
129 
130         // non-Keplerian parameters
131         copyNonKeplerian(original);
132 
133         // Keplerian orbital elements
134         setGnssDate(new GNSSDate(original.getWeek(), original.getTime(), original.getSystem(), original.getTimeScales()));
135         setSma(converter.apply(original.getSma()));
136         setE(converter.apply(original.getE()));
137         setI0(converter.apply(original.getI0()));
138         setPa(converter.apply(original.getPa()));
139         setOmega0(converter.apply(original.getOmega0()));
140         setM0(converter.apply(original.getM0()));
141 
142         // copy selection settings
143         copySelectionSettings(original);
144 
145     }
146 
147     /** Create a non-field version of the instance.
148      * @return non-field version of the instance
149      */
150     public abstract O toNonField();
151 
152     /**
153      * Create another field version of the instance.
154      *
155      * @param <U>       type of the new field elements
156      * @param <G>       type of the orbital elements (field version)
157      * @param converter for field elements
158      * @return field version of the instance
159      */
160     public abstract <U extends CalculusFieldElement<U>, G extends FieldGnssOrbitalElements<U, O>>
161         G changeField(Function<T, U> converter);
162 
163     /** {@inheritDoc} */
164     protected void setGnssDate(final GNSSDate gnssDate) {
165         this.date = new FieldAbsoluteDate<>(mu.getField(), gnssDate.getDate());
166     }
167 
168     /** Get date.
169      * @return date
170      */
171     public FieldAbsoluteDate<T> getDate() {
172         return date;
173     }
174 
175     /** Get the Earth's universal gravitational parameter.
176      * @return the Earth's universal gravitational parameter
177      */
178     public T getMu() {
179         return mu;
180     }
181 
182     /** Get semi-major axis.
183      * @return semi-major axis (m)
184      */
185     public T getSma() {
186         return sma;
187     }
188 
189     /** Set semi-major axis.
190      * @param sma demi-major axis (m)
191      */
192     public void setSma(final T sma) {
193         this.sma = sma;
194     }
195 
196     /** Get the computed mean motion n₀.
197      * @return the computed mean motion n₀ (rad/s)
198      * @since 13.0
199      */
200     public T getMeanMotion0() {
201         final T invA = FastMath.abs(getSma()).reciprocal();
202         return FastMath.sqrt(getMu().multiply(invA)).multiply(invA);
203     }
204 
205     /** Get eccentricity.
206      * @return eccentricity
207      */
208     public T getE() {
209         return ecc;
210     }
211 
212     /** Set eccentricity.
213      * @param e eccentricity
214      */
215     public void setE(final T e) {
216         this.ecc = e;
217     }
218 
219     /** Get the inclination angle at reference time.
220      * @return inclination angle at reference time (rad)
221      */
222     public T getI0() {
223         return i0;
224     }
225 
226     /** Set inclination angle at reference time.
227      * @param i0 inclination angle at reference time (rad)
228      */
229     public void setI0(final T i0) {
230         this.i0 = i0;
231     }
232 
233     /** Get longitude of ascending node of orbit plane at weekly epoch.
234      * @return longitude of ascending node of orbit plane at weekly epoch (rad)
235      */
236     public T getOmega0() {
237         return om0;
238     }
239 
240     /** Set longitude of ascending node of orbit plane at weekly epoch.
241      * @param omega0 longitude of ascending node of orbit plane at weekly epoch (rad)
242      */
243     public void setOmega0(final T omega0) {
244         this.om0 = omega0;
245     }
246 
247     /** Get argument of perigee.
248      * @return argument of perigee (rad)
249      */
250     public T getPa() {
251         return aop;
252     }
253 
254     /** Set argument of perigee.
255      * @param pa argument of perigee (rad)
256      */
257     public void setPa(final T pa) {
258         this.aop = pa;
259     }
260 
261     /** Get mean anomaly at reference time.
262      * @return mean anomaly at reference time (rad)
263      */
264     public T getM0() {
265         return anom;
266     }
267 
268     /** Set mean anomaly at reference time.
269      * @param m0 mean anomaly at reference time (rad)
270      */
271     public void setM0(final T m0) {
272         this.anom = m0;
273     }
274 
275 }