1   /* Copyright 2002-2022 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;
18  
19  
20  import java.util.Collections;
21  import java.util.List;
22  
23  import org.hipparchus.CalculusFieldElement;
24  import org.hipparchus.util.MathArrays;
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.attitudes.FieldAttitude;
27  import org.orekit.attitudes.InertialProvider;
28  import org.orekit.orbits.FieldOrbit;
29  import org.orekit.orbits.Orbit;
30  import org.orekit.orbits.OrbitType;
31  import org.orekit.orbits.PositionAngle;
32  import org.orekit.propagation.FieldSpacecraftState;
33  import org.orekit.time.FieldAbsoluteDate;
34  import org.orekit.utils.FieldArrayDictionary;
35  import org.orekit.utils.FieldTimeSpanMap;
36  import org.orekit.utils.ParameterDriver;
37  
38  /** Simple Keplerian orbit propagator.
39   * @see FieldOrbit
40   * @author Guylaine Prat
41   */
42  public class FieldKeplerianPropagator<T extends CalculusFieldElement<T>> extends FieldAbstractAnalyticalPropagator<T> {
43  
44  
45      /** All states. */
46      private transient FieldTimeSpanMap<FieldSpacecraftState<T>, T> states;
47  
48      /** Build a propagator from orbit only.
49       * <p>The central attraction coefficient μ is set to the same value used
50       * for the initial orbit definition. Mass and attitude provider are set to
51       * unspecified non-null arbitrary values.</p>
52       *
53       * @param initialFieldOrbit initial orbit
54       * @see #FieldKeplerianPropagator(FieldOrbit, AttitudeProvider)
55       */
56      public FieldKeplerianPropagator(final FieldOrbit<T> initialFieldOrbit) {
57          this(initialFieldOrbit, InertialProvider.of(initialFieldOrbit.getFrame()),
58                  initialFieldOrbit.getMu(), initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS));
59      }
60  
61      /** Build a propagator from orbit and central attraction coefficient μ.
62       * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
63       *
64       * @param initialFieldOrbit initial orbit
65       * @param mu central attraction coefficient (m³/s²)
66       * @see #FieldKeplerianPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement)
67       */
68      public FieldKeplerianPropagator(final FieldOrbit<T> initialFieldOrbit, final T mu) {
69          this(initialFieldOrbit, InertialProvider.of(initialFieldOrbit.getFrame()),
70                  mu, initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS));
71      }
72  
73      /** Build a propagator from orbit and attitude provider.
74       * <p>The central attraction coefficient μ is set to the same value
75       * used for the initial orbit definition. Mass is set to an unspecified
76       * non-null arbitrary value.</p>
77       * @param initialFieldOrbit initial orbit
78       * @param attitudeProv  attitude provider
79       */
80      public FieldKeplerianPropagator(final FieldOrbit<T> initialFieldOrbit,
81                                      final AttitudeProvider attitudeProv) {
82          this(initialFieldOrbit, attitudeProv, initialFieldOrbit.getMu(), initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS));
83      }
84  
85      /** Build a propagator from orbit, attitude provider and central attraction
86       * coefficient μ.
87       * <p>Mass is set to an unspecified non-null arbitrary value.</p>
88       * @param initialFieldOrbit initial orbit
89       * @param attitudeProv attitude provider
90       * @param mu central attraction coefficient (m³/s²)
91       */
92      public FieldKeplerianPropagator(final FieldOrbit<T> initialFieldOrbit,
93                                      final AttitudeProvider attitudeProv,
94                                      final T mu) {
95          this(initialFieldOrbit, attitudeProv, mu, initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS));
96      }
97  
98      /** Build propagator from orbit, attitude provider, central attraction
99       * coefficient μ and mass.
100      * @param initialOrbit initial orbit
101      * @param attitudeProv attitude provider
102      * @param mu central attraction coefficient (m³/s²)
103      * @param mass spacecraft mass (kg)
104      */
105     public FieldKeplerianPropagator(final FieldOrbit<T> initialOrbit, final AttitudeProvider attitudeProv,
106                                     final T mu, final T mass) {
107 
108         super(initialOrbit.getA().getField(), attitudeProv);
109 
110         // ensure the orbit use the specified mu and has no non-Keplerian derivatives
111         final FieldSpacecraftState<T> initial = fixState(initialOrbit,
112                                                          getAttitudeProvider().getAttitude(initialOrbit,
113                                                                                            initialOrbit.getDate(),
114                                                                                            initialOrbit.getFrame()),
115                                                          mass, mu, null, null);
116         states = new FieldTimeSpanMap<>(initial, initialOrbit.getA().getField());
117         super.resetInitialState(initial);
118     }
119 
120     /** Fix state to use a specified mu and remove derivatives.
121      * <p>
122      * This ensures the propagation model (which is based on calling
123      * {@link Orbit#shiftedBy(double)}) is Keplerian only and uses a specified mu.
124      * </p>
125      * @param orbit orbit to fix
126      * @param attitude current attitude
127      * @param mass current mass
128      * @param mu gravity coefficient to use
129      * @param additionalStates additional states (may be null)
130      * @param additionalStatesderivatives additional states derivatives (may be null)
131      * @return fixed orbit
132      */
133     private FieldSpacecraftState<T> fixState(final FieldOrbit<T> orbit, final FieldAttitude<T> attitude, final T mass, final T mu,
134                                              final FieldArrayDictionary<T> additionalStates,
135                                              final FieldArrayDictionary<T> additionalStatesderivatives) {
136         final OrbitType type = orbit.getType();
137         final T[] stateVector = MathArrays.buildArray(mass.getField(), 6);
138         type.mapOrbitToArray(orbit, PositionAngle.TRUE, stateVector, null);
139         final FieldOrbit<T> fixedOrbit = type.mapArrayToOrbit(stateVector, null, PositionAngle.TRUE,
140                                                               orbit.getDate(), mu, orbit.getFrame());
141         FieldSpacecraftState<T> fixedState = new FieldSpacecraftState<>(fixedOrbit, attitude, mass);
142         if (additionalStates != null) {
143             for (final FieldArrayDictionary<T>.Entry entry : additionalStates.getData()) {
144                 fixedState = fixedState.addAdditionalState(entry.getKey(), entry.getValue());
145             }
146         }
147         if (additionalStatesderivatives != null) {
148             for (final FieldArrayDictionary<T>.Entry entry : additionalStatesderivatives.getData()) {
149                 fixedState = fixedState.addAdditionalStateDerivative(entry.getKey(), entry.getValue());
150             }
151         }
152         return fixedState;
153     }
154 
155     /** {@inheritDoc} */
156     public void resetInitialState(final FieldSpacecraftState<T> state) {
157 
158         // ensure the orbit use the specified mu and has no non-Keplerian derivatives
159         final FieldSpacecraftState<T> formerInitial = getInitialState();
160         final T mu = formerInitial == null ? state.getMu() : formerInitial.getMu();
161         final FieldSpacecraftState<T> fixedState = fixState(state.getOrbit(),
162                                                             state.getAttitude(),
163                                                             state.getMass(),
164                                                             mu,
165                                                             state.getAdditionalStatesValues(),
166                                                             state.getAdditionalStatesDerivatives());
167 
168         states = new FieldTimeSpanMap<>(fixedState, state.getDate().getField());
169         super.resetInitialState(fixedState);
170 
171     }
172 
173     /** {@inheritDoc} */
174     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
175         if (forward) {
176             states.addValidAfter(state, state.getDate());
177         } else {
178             states.addValidBefore(state, state.getDate());
179         }
180         stateChanged(state);
181     }
182 
183     /** {@inheritDoc} */
184     protected FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
185         // propagate orbit
186         FieldOrbit<T> orbit = states.get(date).getOrbit();
187         do {
188             // we use a loop here to compensate for very small date shifts error
189             // that occur with long propagation time
190             orbit = orbit.shiftedBy(date.durationFrom(orbit.getDate()));
191         } while (!date.equals(orbit.getDate()));
192         return orbit;
193     }
194 
195     /** {@inheritDoc}*/
196     protected T getMass(final FieldAbsoluteDate<T> date) {
197         return states.get(date).getMass();
198     }
199 
200     /** {@inheritDoc} */
201     @Override
202     protected List<ParameterDriver> getParametersDrivers() {
203         // Keplerian propagation model does not have parameter drivers.
204         return Collections.emptyList();
205     }
206 
207 }