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