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.propagation.conversion.osc2mean;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.orekit.annotation.DefaultDataContext;
22  import org.orekit.data.DataContext;
23  import org.orekit.frames.Frame;
24  import org.orekit.orbits.FieldKeplerianOrbit;
25  import org.orekit.orbits.FieldOrbit;
26  import org.orekit.orbits.KeplerianOrbit;
27  import org.orekit.orbits.Orbit;
28  import org.orekit.orbits.OrbitType;
29  import org.orekit.propagation.analytical.tle.FieldTLE;
30  import org.orekit.propagation.analytical.tle.FieldTLEPropagator;
31  import org.orekit.propagation.analytical.tle.TLE;
32  import org.orekit.propagation.analytical.tle.TLEConstants;
33  import org.orekit.propagation.analytical.tle.TLEPropagator;
34  import org.orekit.propagation.analytical.tle.generation.TleGenerationUtil;
35  import org.orekit.time.FieldAbsoluteDate;
36  import org.orekit.time.TimeScale;
37  
38  /**
39   * TLE, i.e. SGP4/SDP4, theory for osculating to mean orbit conversion.
40   *
41   * @author Pascal Parraud
42   * @since 13.0
43   */
44  public class TLETheory implements MeanTheory {
45  
46      /** First line of arbitrary TLE. Should not impact conversion. */
47      public static final String TMP_L1 = "1 00000U 00000A   00001.00000000  .00000000  00000+0  00000+0 0    02";
48      /** Second line of arbitrary TLE. Should not impact conversion. */
49      public static final String TMP_L2 = "2 00000   0.0000   0.0000 0000000   0.0000   0.0000  0.00000000    02";
50  
51      /** Theory used for converting from osculating to mean orbit. */
52      public static final String THEORY = "TLE";
53  
54      /** Template TLE. */
55      private final TLE tmpTle;
56  
57      /** UTC scale. */
58      private final TimeScale utc;
59  
60      /** TEME frame. */
61      private final Frame teme;
62  
63      /**
64       * Constructor with default data context and default TLE template.
65       */
66      @DefaultDataContext
67      public TLETheory() {
68          this(DataContext.getDefault());
69      }
70  
71      /**
72       * Constructor with default data context.
73       * @param template template TLE
74       */
75      @DefaultDataContext
76      public TLETheory(final TLE template) {
77          this(template, DataContext.getDefault());
78      }
79  
80      /**
81       * Constructor with default data context.
82       * @param <T> type of the elements
83       * @param template template TLE
84       */
85      @DefaultDataContext
86      public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template) {
87          this(template, DataContext.getDefault());
88      }
89  
90      /**
91       * Constructor with default TLE template.
92       * @param dataContext data context
93       */
94      public TLETheory(final DataContext dataContext) {
95          this(dataContext.getTimeScales().getUTC(), dataContext.getFrames().getTEME());
96      }
97  
98      /**
99       * Constructor.
100      * @param utc      UTC scale
101      * @param teme     TEME frame scale
102      */
103     public TLETheory(final TimeScale utc, final Frame teme) {
104         this(new TLE(TMP_L1, TMP_L2, utc), utc, teme);
105     }
106 
107     /**
108      * Constructor.
109      * @param template template TLE
110      * @param dataContext data context
111      */
112     public TLETheory(final TLE template, final DataContext dataContext) {
113         this(template, dataContext.getTimeScales().getUTC(), dataContext.getFrames().getTEME());
114     }
115 
116     /**
117      * Constructor.
118      * @param template template TLE
119      * @param utc      UTC scale
120      * @param teme     TEME frame scale
121      */
122     public TLETheory(final TLE template, final TimeScale utc, final Frame teme) {
123         this.tmpTle = template;
124         this.utc    = utc;
125         this.teme   = teme;
126     }
127 
128     /**
129      * Constructor.
130      * @param <T> type of the elements
131      * @param template template TLE
132      * @param dataContext data context
133      */
134     public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template, final DataContext dataContext) {
135         this(template, dataContext.getTimeScales().getUTC(), dataContext.getFrames().getTEME());
136     }
137 
138     /**
139      * Constructor.
140      * @param <T> type of the elements
141      * @param template template TLE
142      * @param utc      UTC scale
143      * @param teme     TEME frame scale
144      */
145     public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template, final TimeScale utc, final Frame teme) {
146         this.tmpTle = template.toTLE();
147         this.utc    = utc;
148         this.teme   = teme;
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public String getTheoryName() {
154         return THEORY;
155     }
156 
157     /** {@inheritDoc} */
158     @Override
159     public double getReferenceRadius() {
160         return 1000 * TLEConstants.EARTH_RADIUS;
161     };
162 
163     /** Pre-treatment of the osculating orbit to be converted.
164      * <p>The osculating orbit is transformed to TEME frame.</p>
165      */
166     @Override
167     public Orbit preprocessing(final Orbit osculating) {
168         return new KeplerianOrbit(osculating.getPVCoordinates(teme), teme, TLEPropagator.getMU());
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public Orbit meanToOsculating(final Orbit mean) {
174         // Build TLE from mean and template
175         final KeplerianOrbit meanKepl = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(mean);
176         final TLE meanTle = TleGenerationUtil.newTLE(meanKepl, tmpTle, tmpTle.getBStar(mean.getDate()), utc);
177         final TLEPropagator propagator = TLEPropagator.selectExtrapolator(meanTle, teme);
178         return propagator.getInitialState().getOrbit();
179     }
180 
181     /** Post-treatment of the converted mean orbit.
182      * <p>The mean orbit returned is a Keplerian orbit in TEME frame.</p>
183      */
184     @Override
185     public Orbit postprocessing(final Orbit osculating, final Orbit mean) {
186         return OrbitType.KEPLERIAN.convertType(mean);
187     }
188 
189     /** Pre-treatment of the osculating orbit to be converted.
190      * <p>The osculating orbit is transformed to TEME frame.</p>
191      */
192     @Override
193     public <T extends CalculusFieldElement<T>> FieldOrbit<T> preprocessing(final FieldOrbit<T> osculating) {
194         final T mu = osculating.getDate().getField().getZero().newInstance(TLEConstants.MU);
195         return new FieldKeplerianOrbit<T>(osculating.getPVCoordinates(teme), teme, mu);
196     }
197 
198     /** {@inheritDoc} */
199     @Override
200     public <T extends CalculusFieldElement<T>> FieldOrbit<T> meanToOsculating(final FieldOrbit<T> mean) {
201         final FieldAbsoluteDate<T> date = mean.getDate();
202         final Field<T> field = date.getField();
203         final FieldTLE<T> fieldTmpTle = new FieldTLE<T>(field, tmpTle.getLine1(), tmpTle.getLine2(), utc);
204         final T bStar = field.getZero().newInstance(fieldTmpTle.getBStar());
205         // Build TLE from mean and template
206         final FieldKeplerianOrbit<T> meanKepl = (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(mean);
207         final FieldTLE<T> meanTle = TleGenerationUtil.newTLE(meanKepl, fieldTmpTle, bStar, utc);
208         final FieldTLEPropagator<T> propagator = FieldTLEPropagator.selectExtrapolator(meanTle, teme, meanTle.getParameters(field));
209         return propagator.getInitialState().getOrbit();
210     }
211 
212     /** Post-treatment of the converted mean orbit.
213      * <p>The mean orbit returned is a Keplerian orbit in TEME frame.</p>
214      */
215     @Override
216     public <T extends CalculusFieldElement<T>> FieldOrbit<T> postprocessing(final FieldOrbit<T> osculating,
217                                                                             final FieldOrbit<T> mean) {
218         return OrbitType.KEPLERIAN.convertType(mean);
219     }
220 
221 }