1   /* Copyright 2002-2021 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.analytical.tle;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.analysis.differentiation.Gradient;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.attitudes.FieldAttitude;
27  import org.orekit.frames.Frame;
28  import org.orekit.orbits.FieldCartesianOrbit;
29  import org.orekit.orbits.FieldOrbit;
30  import org.orekit.propagation.FieldSpacecraftState;
31  import org.orekit.propagation.SpacecraftState;
32  import org.orekit.propagation.integration.AbstractGradientConverter;
33  import org.orekit.time.TimeScale;
34  import org.orekit.utils.FieldAngularCoordinates;
35  import org.orekit.utils.FieldPVCoordinates;
36  import org.orekit.utils.ParameterDriver;
37  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
38  import org.orekit.utils.TimeStampedFieldPVCoordinates;
39  
40  /** Converter for TLE propagator.
41   * @author Luc Maisonobe
42   * @author Bryan Cazabonne
43   * @author Thomas Paulet
44   * @since 11.0
45   */
46  class TLEGradientConverter extends AbstractGradientConverter {
47  
48      /** Fixed dimension of the state. */
49      public static final int FREE_STATE_PARAMETERS = 6;
50  
51      /** Current TLE. */
52      private final TLE tle;
53  
54      /** UTC time scale. */
55      private final TimeScale utc;
56  
57      /** TEME frame. */
58      private final Frame teme;
59  
60      /** Attitude provider. */
61      private final AttitudeProvider provider;
62  
63      /** States with various number of additional propagation parameters. */
64      private final List<FieldSpacecraftState<Gradient>> gStates;
65  
66      /** Simple constructor.
67       * @param propagator TLE propagator used to access initial orbit
68       */
69      TLEGradientConverter(final TLEPropagator propagator) {
70  
71          super(FREE_STATE_PARAMETERS);
72  
73          // TLE and related parameters
74          this.tle  = propagator.getTLE();
75          this.teme = propagator.getFrame();
76          this.utc  = tle.getUtc();
77  
78          // Attitude provider
79          this.provider = propagator.getAttitudeProvider();
80  
81          // Spacecraft state
82          final SpacecraftState state = propagator.getInitialState();
83  
84          // Position always has derivatives
85          final Vector3D pos = state.getPVCoordinates().getPosition();
86          final FieldVector3D<Gradient> posG = new FieldVector3D<>(Gradient.variable(FREE_STATE_PARAMETERS, 0, pos.getX()),
87                                                                   Gradient.variable(FREE_STATE_PARAMETERS, 1, pos.getY()),
88                                                                   Gradient.variable(FREE_STATE_PARAMETERS, 2, pos.getZ()));
89  
90          // Velocity may have derivatives or not
91          final Vector3D vel = state.getPVCoordinates().getVelocity();
92          final FieldVector3D<Gradient> velG = new FieldVector3D<>(Gradient.variable(FREE_STATE_PARAMETERS, 3, vel.getX()),
93                                                                   Gradient.variable(FREE_STATE_PARAMETERS, 4, vel.getY()),
94                                                                   Gradient.variable(FREE_STATE_PARAMETERS, 5, vel.getZ()));
95  
96          // Acceleration never has derivatives
97          final Vector3D acc = state.getPVCoordinates().getAcceleration();
98          final FieldVector3D<Gradient> accG = new FieldVector3D<>(Gradient.constant(FREE_STATE_PARAMETERS, acc.getX()),
99                                                                   Gradient.constant(FREE_STATE_PARAMETERS, acc.getY()),
100                                                                  Gradient.constant(FREE_STATE_PARAMETERS, acc.getZ()));
101 
102         // Mass never has derivatives
103         final Gradient gM = Gradient.constant(FREE_STATE_PARAMETERS, state.getMass());
104 
105         final Gradient gMu = Gradient.constant(FREE_STATE_PARAMETERS, TLEPropagator.getMU());
106 
107         final FieldOrbit<Gradient> gOrbit =
108                         new FieldCartesianOrbit<>(new TimeStampedFieldPVCoordinates<>(state.getDate(), posG, velG, accG),
109                                                   state.getFrame(), gMu);
110 
111         // Attitude
112         final FieldAttitude<Gradient> gAttitude = provider.getAttitude(gOrbit, gOrbit.getDate(), gOrbit.getFrame());
113 
114         // Initialize the list with the state having 0 force model parameters
115         gStates = new ArrayList<>();
116         gStates.add(new FieldSpacecraftState<>(gOrbit, gAttitude, gM));
117 
118     }
119 
120     /** Get the state with the number of parameters consistent with TLE model.
121      * @return state with the number of parameters consistent with TLE model
122      */
123     public FieldSpacecraftState<Gradient> getState() {
124 
125         // Count the required number of parameters
126         int nbParams = 0;
127         for (final ParameterDriver driver : tle.getParametersDrivers()) {
128             if (driver.isSelected()) {
129                 ++nbParams;
130             }
131         }
132 
133         // Fill in intermediate slots
134         while (gStates.size() < nbParams + 1) {
135             gStates.add(null);
136         }
137 
138         if (gStates.get(nbParams) == null) {
139             // It is the first time we need this number of parameters
140             // We need to create the state
141             final int freeParameters = FREE_STATE_PARAMETERS + nbParams;
142             final FieldSpacecraftState<Gradient> s0 = gStates.get(0);
143 
144             // Orbit
145             final FieldPVCoordinates<Gradient> pv0 = s0.getPVCoordinates();
146             final FieldOrbit<Gradient> gOrbit =
147                             new FieldCartesianOrbit<>(new TimeStampedFieldPVCoordinates<>(s0.getDate().toAbsoluteDate(),
148                                                                                           extend(pv0.getPosition(),     freeParameters),
149                                                                                           extend(pv0.getVelocity(),     freeParameters),
150                                                                                           extend(pv0.getAcceleration(), freeParameters)),
151                                                       s0.getFrame(),
152                                                       extend(s0.getMu(), freeParameters));
153 
154             // Attitude
155             final FieldAngularCoordinates<Gradient> ac0 = s0.getAttitude().getOrientation();
156             final FieldAttitude<Gradient> gAttitude =
157                             new FieldAttitude<>(s0.getAttitude().getReferenceFrame(),
158                                                 new TimeStampedFieldAngularCoordinates<>(gOrbit.getDate(),
159                                                                                          extend(ac0.getRotation(), freeParameters),
160                                                                                          extend(ac0.getRotationRate(), freeParameters),
161                                                                                          extend(ac0.getRotationAcceleration(), freeParameters)));
162 
163             // Mass
164             final Gradient gM = extend(s0.getMass(), freeParameters);
165 
166             gStates.set(nbParams, new FieldSpacecraftState<>(gOrbit, gAttitude, gM));
167         }
168 
169         return gStates.get(nbParams);
170 
171     }
172 
173     /** Get the model parameters.
174      * @param state state as returned by {@link #getState(TLE)}
175      * @return TLE model parameters
176      */
177     public Gradient[] getParameters(final FieldSpacecraftState<Gradient> state) {
178         final int freeParameters = state.getMass().getFreeParameters();
179         final List<ParameterDriver> drivers = tle.getParametersDrivers();
180         final Gradient[] parameters = new Gradient[drivers.size()];
181         int index = FREE_STATE_PARAMETERS;
182         int i = 0;
183         for (ParameterDriver driver : drivers) {
184             parameters[i++] = driver.isSelected() ?
185                               Gradient.variable(freeParameters, index++, driver.getValue()) :
186                               Gradient.constant(freeParameters, driver.getValue());
187         }
188         return parameters;
189     }
190 
191     /** Get the converted TLE propagator.
192      * @param state state as returned by {@link #getState(TLE)}
193      * @param parameters model parameters as returned by {@link #getParameters(FieldSpacecraftState, TLE)}
194      * @return the converted propagator
195      */
196     public FieldTLEPropagator<Gradient> getPropagator(final FieldSpacecraftState<Gradient> state,
197                                                       final Gradient[] parameters) {
198 
199         // Zero
200         final Gradient zero = state.getA().getField().getZero();
201 
202         // Template TLE
203         final int satelliteNumber         = tle.getSatelliteNumber();
204         final char classification         = tle.getClassification();
205         final int launchYear              = tle.getLaunchYear();
206         final int launchNumber            = tle.getLaunchNumber();
207         final String launchPiece          = tle.getLaunchPiece();
208         final int ephemerisType           = tle.getEphemerisType();
209         final int elementNumber           = tle.getElementNumber();
210         final int revolutionNumberAtEpoch = tle.getRevolutionNumberAtEpoch();
211         final double bStar                = tle.getBStar();
212 
213         // Initialize the new TLE
214         final FieldTLE<Gradient> templateTLE = new FieldTLE<>(satelliteNumber, classification,
215                         launchYear, launchNumber, launchPiece, ephemerisType, elementNumber, state.getDate(),
216                         zero, zero, zero, zero, zero, zero, zero, zero,
217                         revolutionNumberAtEpoch, bStar, utc);
218 
219         // TLE
220         final FieldTLE<Gradient> gTLE = FieldTLE.stateToTLE(state, templateTLE, utc, teme);
221 
222         // Return the "Field" propagator
223         return FieldTLEPropagator.selectExtrapolator(gTLE, provider, state.getMass(), teme, parameters);
224 
225     }
226 
227 }