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