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.integration;
18  
19  import java.util.Collections;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.hipparchus.CalculusFieldElement;
24  import org.hipparchus.ode.FieldDenseOutputModel;
25  import org.hipparchus.ode.FieldODEStateAndDerivative;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.frames.Frame;
29  import org.orekit.orbits.FieldOrbit;
30  import org.orekit.propagation.FieldAdditionalStateProvider;
31  import org.orekit.propagation.FieldBoundedPropagator;
32  import org.orekit.propagation.FieldSpacecraftState;
33  import org.orekit.propagation.PropagationType;
34  import org.orekit.propagation.analytical.FieldAbstractAnalyticalPropagator;
35  import org.orekit.time.FieldAbsoluteDate;
36  import org.orekit.utils.ParameterDriver;
37  import org.orekit.utils.TimeStampedFieldPVCoordinates;
38  
39  /** This class stores sequentially generated orbital parameters for
40   * later retrieval.
41   *
42   * <p>
43   * Instances of this class are built automatically when the {@link
44   * org.orekit.propagation.FieldPropagator#getEphemerisGenerator()
45   * getEphemerisGenerator} method has been called. They are created when propagation is over.
46   * Random access to any intermediate state of the orbit throughout the propagation range is
47   * possible afterwards through this object.
48   * </p>
49   * <p>
50   * A typical use case is for numerically integrated orbits, which can be used by
51   * algorithms that need to wander around according to their own algorithm without
52   * cumbersome tight links with the integrator.
53   * </p>
54   * <p>
55   * As this class implements the {@link org.orekit.propagation.Propagator Propagator}
56   * interface, it can itself be used in batch mode to build another instance of the
57   * same type. This is however not recommended since it would be a waste of resources.
58   * </p>
59   * <p>
60   * Note that this class stores all intermediate states along with interpolation
61   * models, so it may be memory intensive.
62   * </p>
63   *
64   * @see org.orekit.propagation.numerical.NumericalPropagator
65   * @author Mathieu Rom&eacute;ro
66   * @author Luc Maisonobe
67   * @author V&eacute;ronique Pommier-Maurussane
68   */
69  public class FieldIntegratedEphemeris <T extends CalculusFieldElement<T>>
70      extends FieldAbstractAnalyticalPropagator<T> implements FieldBoundedPropagator<T> {
71  
72      /** Event detection requires evaluating the state slightly before / past an event. */
73      private static final double EXTRAPOLATION_TOLERANCE = 1.0;
74  
75      /** Mapper between raw double components and spacecraft state. */
76      private final FieldStateMapper<T> mapper;
77  
78      /** Type of orbit to output (mean or osculating).
79       * <p>
80       * This is used only in the case of semianalitical propagators where there is a clear separation between
81       * mean and short periodic elements. It is ignored by the Numerical propagator.
82       * </p>
83       */
84      private PropagationType type;
85  
86      /** Start date of the integration (can be min or max). */
87      private final FieldAbsoluteDate<T> startDate;
88  
89      /** First date of the range. */
90      private final FieldAbsoluteDate<T> minDate;
91  
92      /** Last date of the range. */
93      private final FieldAbsoluteDate<T> maxDate;
94  
95      /** Underlying raw mathematical model. */
96      private FieldDenseOutputModel<T> model;
97  
98      /** Unmanaged additional states that must be simply copied. */
99      private final Map<String, T[]> unmanaged;
100 
101     /** Creates a new instance of IntegratedEphemeris.
102      * @param startDate Start date of the integration (can be minDate or maxDate)
103      * @param minDate first date of the range
104      * @param maxDate last date of the range
105      * @param mapper mapper between raw double components and spacecraft state
106      * @param type type of orbit to output (mean or osculating)
107      * @param model underlying raw mathematical model
108      * @param unmanaged unmanaged additional states that must be simply copied
109      * @param providers providers for pre-integrated states
110      * @param equations names of additional equations
111      */
112     public FieldIntegratedEphemeris(final FieldAbsoluteDate<T> startDate,
113                                final FieldAbsoluteDate<T> minDate, final FieldAbsoluteDate<T> maxDate,
114                                final FieldStateMapper<T> mapper, final PropagationType type,
115                                final FieldDenseOutputModel<T> model,
116                                final Map<String, T[]> unmanaged,
117                                final List<FieldAdditionalStateProvider<T>> providers,
118                                final String[] equations) {
119 
120         super(startDate.getField(), mapper.getAttitudeProvider());
121 
122         this.startDate = startDate;
123         this.minDate   = minDate;
124         this.maxDate   = maxDate;
125         this.mapper    = mapper;
126         this.type      = type;
127         this.model     = model;
128         this.unmanaged = unmanaged;
129         // set up the pre-integrated providers
130         for (final FieldAdditionalStateProvider<T> provider : providers) {
131             addAdditionalStateProvider(provider);
132         }
133 
134         // set up providers to map the final elements of the model array to additional states
135         for (int i = 0; i < equations.length; ++i) {
136             addAdditionalStateProvider(new LocalProvider(equations[i], i));
137         }
138 
139     }
140 
141     /** Interpolate the model at some date.
142      * @param date desired interpolation date
143      * @return state interpolated at date
144           * of supported range
145      */
146     private FieldODEStateAndDerivative<T> getInterpolatedState(final FieldAbsoluteDate<T> date) {
147 
148         // compare using double precision instead of FieldAbsoluteDate<T>.compareTo(...)
149         // because time is expressed as a double when searching for events
150         if (date.compareTo(minDate.shiftedBy(-EXTRAPOLATION_TOLERANCE)) < 0) {
151             // date is outside of supported range
152             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_BEFORE,
153                     date, minDate, maxDate, minDate.durationFrom(date).getReal());
154         }
155         if (date.compareTo(maxDate.shiftedBy(EXTRAPOLATION_TOLERANCE)) > 0) {
156             // date is outside of supported range
157             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_AFTER,
158                     date, minDate, maxDate, date.durationFrom(maxDate).getReal());
159         }
160 
161         return model.getInterpolatedState(date.durationFrom(startDate));
162 
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     protected FieldSpacecraftState<T> basicPropagate(final FieldAbsoluteDate<T> date) {
168         final FieldODEStateAndDerivative<T> os = getInterpolatedState(date);
169         FieldSpacecraftState<T> state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
170                                                                os.getPrimaryState(), os.getPrimaryDerivative(),
171                                                                type);
172         for (Map.Entry<String, T[]> initial : unmanaged.entrySet()) {
173             state = state.addAdditionalState(initial.getKey(), initial.getValue());
174         }
175         return state;
176     }
177 
178     /** {@inheritDoc} */
179     @Override
180     protected FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
181         return basicPropagate(date).getOrbit();
182     }
183 
184     /** {@inheritDoc} */
185     @Override
186     protected T getMass(final FieldAbsoluteDate<T> date) {
187         return basicPropagate(date).getMass();
188     }
189 
190     /** {@inheritDoc} */
191     @Override
192     public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> date, final Frame frame) {
193         return propagate(date).getPVCoordinates(frame);
194     }
195 
196     /** Get the first date of the range.
197      * @return the first date of the range
198      */
199     @Override
200     public FieldAbsoluteDate<T> getMinDate() {
201         return minDate;
202     }
203 
204     /** Get the last date of the range.
205      * @return the last date of the range
206      */
207     @Override
208     public FieldAbsoluteDate<T> getMaxDate() {
209         return maxDate;
210     }
211 
212     @Override
213     public Frame getFrame() {
214         return this.mapper.getFrame();
215     }
216 
217     /** {@inheritDoc} */
218     @Override
219     public void resetInitialState(final FieldSpacecraftState<T> state) {
220         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
221     }
222 
223     /** {@inheritDoc} */
224     @Override
225     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
226         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
227     }
228 
229     /** {@inheritDoc} */
230     @Override
231     public FieldSpacecraftState<T> getInitialState() {
232         return updateAdditionalStates(basicPropagate(getMinDate()));
233     }
234 
235     /** Local provider for additional state data. */
236     private class LocalProvider implements FieldAdditionalStateProvider<T> {
237 
238         /** Name of the additional state. */
239         private final String name;
240 
241         /** Index of the additional state. */
242         private final int index;
243 
244         /** Simple constructor.
245          * @param name name of the additional state
246          * @param index index of the additional state
247          */
248         LocalProvider(final String name, final int index) {
249             this.name  = name;
250             this.index = index;
251         }
252 
253         /** {@inheritDoc} */
254         @Override
255         public String getName() {
256             return name;
257         }
258 
259         /** {@inheritDoc} */
260         @Override
261         public T[] getAdditionalState(final FieldSpacecraftState<T> state) {
262 
263             // extract the part of the interpolated array corresponding to the additional state
264             return getInterpolatedState(state.getDate()).getSecondaryState(index + 1);
265 
266         }
267 
268     }
269 
270     /** {@inheritDoc} */
271     @Override
272     protected List<ParameterDriver> getParametersDrivers() {
273         // Integrated Ephemeris propagation model does not have parameter drivers.
274         return Collections.emptyList();
275     }
276 
277 }