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  
18  package org.orekit.files.ccsds.ndm.odm.omm;
19  
20  import org.orekit.files.ccsds.section.CommentsContainer;
21  
22  /** Container for TLE data.
23   * <p>
24   * Beware that the Orekit getters and setters all rely on SI units. The parsers
25   * and writers take care of converting these SI units into CCSDS mandatory units.
26   * The {@link org.orekit.utils.units.Unit Unit} class provides useful
27   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
28   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
29   * already use CCSDS units instead of the API SI units. The general-purpose
30   * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
31   * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
32   * (with an 's') also provide some predefined units. These predefined units and the
33   * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
34   * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
35   * what the parsers and writers use for the conversions.
36   * </p>
37   * @author sports
38   * @since 6.1
39   */
40  public class OmmTle extends CommentsContainer {
41  
42      /** Constant for EPHEMERIS_TYPE SGP.
43       * @since 12.0
44       */
45      public static final int EPHEMERIS_TYPE_SGP = 0;
46  
47      /** Constant for EPHEMERIS_TYPE SGP4.
48       * @since 12.0
49       */
50      public static final int EPHEMERIS_TYPE_SGP4 = 2;
51  
52      /** Constant for EPHEMERIS_TYPE PPT3.
53       * @since 12.0
54       */
55      public static final int EPHEMERIS_TYPE_PPT3 = 3;
56  
57      /** Constant for EPHEMERIS_TYPE SGP4-XP.
58       * @since 12.0
59       */
60      public static final int EPHEMERIS_TYPE_SGP4_XP = 4;
61  
62      /** Constant for EPHEMERIS_TYPE Special Perturbations.
63       * @since 12.0
64       */
65      public static final int EPHEMERIS_TYPE_SPECIAL_PERTURBATIONS = 6;
66  
67      /** Ephemeris Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the coding for
68       * the EPHEMERIS_TYPE keyword: 0 = SGP, 2 = SGP4, 3 = PPT3, 4 = SGP4-XP, 6 = Special Perturbations. Default value = 0.
69       */
70      private int ephemerisType;
71  
72      /** Classification Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the
73       *  following coding for the CLASSIFICATION_TYPE keyword: U = unclassified, S = secret. Default value = U.
74       */
75      private char classificationType;
76  
77      /** NORAD Catalog Number ("Satellite Number"), an integer of up to nine digits. */
78      private int noradID;
79  
80      /** Element set number for this satellite, only required if MEAN_ELEMENT_THEORY = SGP/SGP4.
81       * Normally incremented sequentially, but may be out of sync if it is generated from a backup source.
82       * Used to distinguish different TLEs, and therefore only meaningful if TLE based data is being exchanged. */
83      private int elementSetNo;
84  
85      /** Revolution Number, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
86      private int revAtEpoch;
87  
88      /** SGP/SGP4 drag-like coefficient (in units 1/[Earth radii]), only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
89      private double bStar;
90  
91      /** SGP4-XP drag-like coefficient (in m²/kg), only required if MEAN_ELEMENT_THEORY = SGP4-XP.
92       * @since 12.0
93       */
94      private double bTerm;
95  
96      /** First Time Derivative of the Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
97      private double meanMotionDot;
98  
99      /** Second Time Derivative of Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
100     private double meanMotionDotDot;
101 
102     /** SGP4-XP solar radiation pressure-like coefficient Aγ/m (in m²/kg), only required if MEAN_ELEMENT_THEORY = SGP4-XP.
103      * @since 12.0
104      */
105     private double agOm;
106 
107     /** Create an empty data set.
108      */
109     public OmmTle() {
110         ephemerisType      = EPHEMERIS_TYPE_SGP;
111         classificationType = 'U';
112         noradID            = -1;
113         elementSetNo       = -1;
114         revAtEpoch         = -1;
115         bStar              =  Double.NaN;
116         bTerm              =  Double.NaN;
117         meanMotionDot      =  Double.NaN;
118         meanMotionDotDot   =  Double.NaN;
119         agOm               =  Double.NaN;
120     }
121 
122     /** {@inheritDoc} */
123     @Override
124     public void validate(final double version) {
125         super.validate(version);
126 
127         checkNotNegative(noradID,      OmmTleKey.NORAD_CAT_ID.name());
128         checkNotNegative(elementSetNo, OmmTleKey.ELEMENT_SET_NO.name());
129         checkNotNegative(revAtEpoch,   OmmTleKey.REV_AT_EPOCH.name());
130 
131         if (ephemerisType == EPHEMERIS_TYPE_SGP4) {
132             checkNotNaN(bStar, OmmTleKey.BSTAR.name());
133         } else if (ephemerisType == EPHEMERIS_TYPE_SGP4_XP) {
134             checkNotNaN(bTerm, OmmTleKey.BTERM.name());
135         }
136 
137         if (ephemerisType == EPHEMERIS_TYPE_SGP  || ephemerisType == EPHEMERIS_TYPE_PPT3) {
138             checkNotNaN(meanMotionDot, OmmTleKey.MEAN_MOTION_DOT.name());
139         }
140 
141         if (ephemerisType == EPHEMERIS_TYPE_SGP  || ephemerisType == EPHEMERIS_TYPE_PPT3) {
142             checkNotNaN(meanMotionDotDot, OmmTleKey.MEAN_MOTION_DDOT.name());
143         } else if (ephemerisType == EPHEMERIS_TYPE_SGP4_XP) {
144             checkNotNaN(agOm, OmmTleKey.AGOM.name());
145         }
146 
147     }
148 
149     /** Get the ephemeris type.
150      * @return the ephemerisType
151      */
152     public int getEphemerisType() {
153         return ephemerisType;
154     }
155 
156     /** Set the ephemeris type.
157      * @param ephemerisType the ephemeris type to be set
158      */
159     public void setEphemerisType(final int ephemerisType) {
160         refuseFurtherComments();
161         this.ephemerisType = ephemerisType;
162     }
163 
164     /** Get the classification type.
165      * @return the classificationType
166      */
167     public char getClassificationType() {
168         return classificationType;
169     }
170 
171     /** Set the classification type.
172      * @param classificationType the classification type to be set
173      */
174     public void setClassificationType(final char classificationType) {
175         refuseFurtherComments();
176         this.classificationType = classificationType;
177     }
178 
179     /** Get the NORAD Catalog Number ("Satellite Number").
180      * @return the NORAD Catalog Number
181      */
182     public int getNoradID() {
183         return noradID;
184     }
185 
186     /** Set the NORAD Catalog Number ("Satellite Number").
187      * @param noradID the element set number to be set
188      */
189     public void setNoradID(final int noradID) {
190         refuseFurtherComments();
191         this.noradID = noradID;
192     }
193 
194     /** Get the element set number for this satellite.
195      * @return the element set number for this satellite
196      */
197     public int getElementSetNumber() {
198         return elementSetNo;
199     }
200 
201     /** Set the element set number for this satellite.
202      * @param elementSetNo the element set number to be set
203      */
204     public void setElementSetNo(final int elementSetNo) {
205         refuseFurtherComments();
206         this.elementSetNo = elementSetNo;
207     }
208 
209     /** Get the revolution rumber.
210      * @return the revolution rumber
211      */
212     public int getRevAtEpoch() {
213         return revAtEpoch;
214     }
215 
216     /** Set the revolution rumber.
217      * @param revAtEpoch the Revolution Number to be set
218      */
219     public void setRevAtEpoch(final int revAtEpoch) {
220         refuseFurtherComments();
221         this.revAtEpoch = revAtEpoch;
222     }
223 
224     /** Get the SGP/SGP4 drag-like coefficient.
225      * @return the SGP/SGP4 drag-like coefficient
226      */
227     public double getBStar() {
228         return bStar;
229     }
230 
231     /** Set the SGP/SGP4 drag-like coefficient.
232      * @param bstar the SGP/SGP4 drag-like coefficient to be set
233      */
234     public void setBStar(final double bstar) {
235         refuseFurtherComments();
236         this.bStar = bstar;
237     }
238 
239     /** Get the SGP4-XP drag-like coefficient.
240      * @return the SGP4-XP drag-like coefficient
241      * @since 12.0
242      */
243     public double getBTerm() {
244         return bTerm;
245     }
246 
247     /** Set the SGP4-XP drag-like coefficient.
248      * @param bterm the SGP4-XP drag-like coefficient to be set
249      * @since 12.0
250      */
251     public void setBTerm(final double bterm) {
252         refuseFurtherComments();
253         this.bTerm = bterm;
254     }
255 
256     /** Get the first time derivative of the mean motion.
257      * @return the first time derivative of the mean motion
258      */
259     public double getMeanMotionDot() {
260         return meanMotionDot;
261     }
262 
263     /** Set the first time derivative of the mean motion.
264      * @param meanMotionDot the first time derivative of the mean motion to be set
265      */
266     public void setMeanMotionDot(final double meanMotionDot) {
267         refuseFurtherComments();
268         this.meanMotionDot = meanMotionDot;
269     }
270 
271     /** Get the second time derivative of the mean motion.
272      * @return the second time derivative of the mean motion
273      */
274     public double getMeanMotionDotDot() {
275         return meanMotionDotDot;
276     }
277 
278     /** Set the second time derivative of the mean motion.
279      * @param meanMotionDotDot the second time derivative of the mean motion to be set
280      */
281     public void setMeanMotionDotDot(final double meanMotionDotDot) {
282         refuseFurtherComments();
283         this.meanMotionDotDot = meanMotionDotDot;
284     }
285 
286     /** Get the SGP4-XP solar radiation pressure-like coefficient Aγ/m.
287      * @return the SGP4-XP solar radiation pressure-like coefficient Aγ/m
288      * @since 12.0
289      */
290     public double getAGoM() {
291         return agOm;
292     }
293 
294     /** Set the SGP4-XP solar radiation pressure-like coefficient Aγ/m.
295      * @param agom the SGP4-XP solar radiation pressure-like coefficient Aγ/m to be set
296      * @since 12.0
297      */
298     public void setAGoM(final double agom) {
299         refuseFurtherComments();
300         this.agOm = agom;
301     }
302 
303 }