1   /* Copyright 2002-2026 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      /** TEME frame. */
58      private final Frame teme;
59  
60      /**
61       * Constructor with default data context and default TLE template.
62       */
63      @DefaultDataContext
64      public TLETheory() {
65          this(DataContext.getDefault());
66      }
67  
68      /**
69       * Constructor with default data context.
70       * @param template template TLE
71       */
72      @DefaultDataContext
73      public TLETheory(final TLE template) {
74          this(template, DataContext.getDefault());
75      }
76  
77      /**
78       * Constructor with default data context.
79       * @param <T> type of the elements
80       * @param template template TLE
81       */
82      @DefaultDataContext
83      public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template) {
84          this(template, DataContext.getDefault());
85      }
86  
87      /**
88       * Constructor with default TLE template.
89       * @param dataContext data context
90       */
91      public TLETheory(final DataContext dataContext) {
92          this(dataContext.getTimeScales().getUTC(), dataContext.getFrames().getTEME());
93      }
94  
95      /**
96       * Constructor.
97       * @param utc      UTC scale
98       * @param teme     TEME frame scale
99       */
100     public TLETheory(final TimeScale utc, final Frame teme) {
101         this(new TLE(TMP_L1, TMP_L2, utc), teme);
102     }
103 
104     /**
105      * Constructor.
106      * @param template template TLE
107      * @param dataContext data context
108      */
109     public TLETheory(final TLE template, final DataContext dataContext) {
110         this(template, dataContext.getFrames().getTEME());
111     }
112 
113     /**
114      * Constructor.
115      * @param template template TLE
116      * @param teme     TEME frame scale
117      */
118     public TLETheory(final TLE template, final Frame teme) {
119         this.tmpTle = template;
120         this.teme   = teme;
121     }
122 
123     /**
124      * Constructor.
125      * @param <T> type of the elements
126      * @param template template TLE
127      * @param dataContext data context
128      */
129     public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template, final DataContext dataContext) {
130         this(template, dataContext.getTimeScales().getUTC(), dataContext.getFrames().getTEME());
131     }
132 
133     /**
134      * Constructor.
135      * @param <T> type of the elements
136      * @param template template TLE
137      * @param utc      UTC scale
138      * @param teme     TEME frame scale
139      */
140     public <T extends CalculusFieldElement<T>> TLETheory(final FieldTLE<T> template, final TimeScale utc, final Frame teme) {
141         this.tmpTle = template.toTLE();
142         this.teme   = teme;
143     }
144 
145     /** {@inheritDoc} */
146     @Override
147     public String getTheoryName() {
148         return THEORY;
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public double getReferenceRadius() {
154         return 1000 * TLEConstants.EARTH_RADIUS;
155     }
156 
157     /** Pre-treatment of the osculating orbit to be converted.
158      * <p>The osculating orbit is transformed to TEME frame.</p>
159      */
160     @Override
161     public Orbit preprocessing(final Orbit osculating) {
162         return new KeplerianOrbit(osculating.getPVCoordinates(teme), teme, TLEPropagator.getMU());
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public Orbit meanToOsculating(final Orbit mean) {
168         // Build TLE from mean and template
169         final KeplerianOrbit meanKepl = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(mean);
170         final TLE meanTle = TleGenerationUtil.newTLE(meanKepl, tmpTle);
171         final TLEPropagator propagator = TLEPropagator.selectExtrapolator(meanTle, teme);
172         return propagator.getInitialState().getOrbit();
173     }
174 
175     /** Post-treatment of the converted mean orbit.
176      * <p>The mean orbit returned is a Keplerian orbit in TEME frame.</p>
177      */
178     @Override
179     public Orbit postprocessing(final Orbit osculating, final Orbit mean) {
180         return OrbitType.KEPLERIAN.convertType(mean);
181     }
182 
183     /** Pre-treatment of the osculating orbit to be converted.
184      * <p>The osculating orbit is transformed to TEME frame.</p>
185      */
186     @Override
187     public <T extends CalculusFieldElement<T>> FieldOrbit<T> preprocessing(final FieldOrbit<T> osculating) {
188         final T mu = osculating.getDate().getField().getZero().newInstance(TLEConstants.MU);
189         return new FieldKeplerianOrbit<>(osculating.getPVCoordinates(teme), teme, mu);
190     }
191 
192     /** {@inheritDoc} */
193     @Override
194     public <T extends CalculusFieldElement<T>> FieldOrbit<T> meanToOsculating(final FieldOrbit<T> mean) {
195         final FieldAbsoluteDate<T> date = mean.getDate();
196         final Field<T> field = date.getField();
197         final FieldTLE<T> fieldTmpTle = new FieldTLE<>(field, tmpTle.getLine1(), tmpTle.getLine2(), tmpTle.getUtc());
198         // Build TLE from mean and template
199         final FieldKeplerianOrbit<T> meanKepl = (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(mean);
200         final FieldTLE<T> meanTle = TleGenerationUtil.newTLE(meanKepl, fieldTmpTle);
201         final FieldTLEPropagator<T> propagator =
202             FieldTLEPropagator.selectExtrapolator(meanTle, teme);
203         return propagator.getInitialState().getOrbit();
204     }
205 
206     /** Post-treatment of the converted mean orbit.
207      * <p>The mean orbit returned is a Keplerian orbit in TEME frame.</p>
208      */
209     @Override
210     public <T extends CalculusFieldElement<T>> FieldOrbit<T> postprocessing(final FieldOrbit<T> osculating,
211                                                                             final FieldOrbit<T> mean) {
212         return OrbitType.KEPLERIAN.convertType(mean);
213     }
214 
215 }