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;
18  
19  
20  import java.util.Collections;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.util.MathArrays;
26  import org.orekit.attitudes.AttitudeProvider;
27  import org.orekit.attitudes.FieldAttitude;
28  import org.orekit.attitudes.InertialProvider;
29  import org.orekit.orbits.FieldOrbit;
30  import org.orekit.orbits.Orbit;
31  import org.orekit.orbits.OrbitType;
32  import org.orekit.orbits.PositionAngle;
33  import org.orekit.propagation.FieldSpacecraftState;
34  import org.orekit.time.FieldAbsoluteDate;
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, Collections.emptyMap());
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
130      * @return fixed orbit
131      */
132     private FieldSpacecraftState<T> fixState(final FieldOrbit<T> orbit, final FieldAttitude<T> attitude, final T mass,
133                                              final T mu, final Map<String, T[]> additionalStates) {
134         final OrbitType type = orbit.getType();
135         final T[] stateVector = MathArrays.buildArray(mass.getField(), 6);
136         type.mapOrbitToArray(orbit, PositionAngle.TRUE, stateVector, null);
137         final FieldOrbit<T> fixedOrbit = type.mapArrayToOrbit(stateVector, null, PositionAngle.TRUE,
138                                                               orbit.getDate(), mu, orbit.getFrame());
139         FieldSpacecraftState<T> fixedState = new FieldSpacecraftState<>(fixedOrbit, attitude, mass);
140         for (final Map.Entry<String, T[]> entry : additionalStates.entrySet()) {
141             fixedState = fixedState.addAdditionalState(entry.getKey(), entry.getValue());
142         }
143         return fixedState;
144     }
145 
146     /** {@inheritDoc} */
147     public void resetInitialState(final FieldSpacecraftState<T> state) {
148 
149         // ensure the orbit use the specified mu and has no non-Keplerian derivatives
150         final FieldSpacecraftState<T> formerInitial = getInitialState();
151         final T mu = formerInitial == null ? state.getMu() : formerInitial.getMu();
152         final FieldSpacecraftState<T> fixedState = fixState(state.getOrbit(),
153                                                             state.getAttitude(),
154                                                             state.getMass(),
155                                                             mu,
156                                                             state.getAdditionalStates());
157 
158         states = new FieldTimeSpanMap<>(fixedState, state.getDate().getField());
159         super.resetInitialState(fixedState);
160 
161     }
162 
163     /** {@inheritDoc} */
164     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
165         if (forward) {
166             states.addValidAfter(state, state.getDate());
167         } else {
168             states.addValidBefore(state, state.getDate());
169         }
170         stateChanged(state);
171     }
172 
173     /** {@inheritDoc} */
174     protected FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
175         // propagate orbit
176         FieldOrbit<T> orbit = states.get(date).getOrbit();
177         do {
178             // we use a loop here to compensate for very small date shifts error
179             // that occur with long propagation time
180             orbit = orbit.shiftedBy(date.durationFrom(orbit.getDate()));
181         } while (!date.equals(orbit.getDate()));
182         return orbit;
183     }
184 
185     /** {@inheritDoc}*/
186     protected T getMass(final FieldAbsoluteDate<T> date) {
187         return states.get(date).getMass();
188     }
189 
190     /** {@inheritDoc} */
191     @Override
192     protected List<ParameterDriver> getParametersDrivers() {
193         // Keplerian propagation model does not have parameter drivers.
194         return Collections.emptyList();
195     }
196 
197 }