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éro
66 * @author Luc Maisonobe
67 * @author Vé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 }