1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.analytical;
18
19 import java.io.Serializable;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.stream.Collectors;
23
24 import org.hipparchus.exception.LocalizedCoreFormats;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.util.FastMath;
27 import org.orekit.attitudes.Attitude;
28 import org.orekit.attitudes.AttitudeProvider;
29 import org.orekit.attitudes.InertialProvider;
30 import org.orekit.errors.OrekitException;
31 import org.orekit.errors.OrekitMessages;
32 import org.orekit.frames.Frame;
33 import org.orekit.orbits.Orbit;
34 import org.orekit.propagation.BoundedPropagator;
35 import org.orekit.propagation.SpacecraftState;
36 import org.orekit.time.AbsoluteDate;
37 import org.orekit.utils.ImmutableTimeStampedCache;
38 import org.orekit.utils.PVCoordinatesProvider;
39 import org.orekit.utils.TimeStampedPVCoordinates;
40
41
42
43
44
45
46
47
48
49 public class Ephemeris extends AbstractAnalyticalPropagator implements BoundedPropagator {
50
51
52
53
54 public static final double DEFAULT_EXTRAPOLATION_THRESHOLD_SEC = 1e-3;
55
56
57 private final AbsoluteDate minDate;
58
59
60 private final AbsoluteDate maxDate;
61
62
63 private final double extrapolationThreshold;
64
65
66 private final Frame frame;
67
68
69 private final String[] additional;
70
71
72 private LocalPVProvider pvProvider;
73
74
75 private final transient ImmutableTimeStampedCache<SpacecraftState> cache;
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
92 throws MathIllegalArgumentException {
93 this(states, interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints,
108 final double extrapolationThreshold)
109 throws MathIllegalArgumentException {
110 this(states, interpolationPoints, extrapolationThreshold,
111
112 states.isEmpty() ? null : InertialProvider.of(states.get(0).getFrame()));
113 }
114
115
116
117
118
119
120
121
122
123
124
125 public Ephemeris(final List<SpacecraftState> states,
126 final int interpolationPoints,
127 final double extrapolationThreshold,
128 final AttitudeProvider attitudeProvider)
129 throws MathIllegalArgumentException {
130
131 super(attitudeProvider);
132
133 if (states.size() < interpolationPoints) {
134 throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
135 states.size(), interpolationPoints);
136 }
137
138 final SpacecraftState s0 = states.get(0);
139 minDate = s0.getDate();
140 maxDate = states.get(states.size() - 1).getDate();
141 frame = s0.getFrame();
142
143 final Set<String> names0 = s0.getAdditionalStates().keySet();
144 additional = names0.toArray(new String[names0.size()]);
145
146
147 for (final SpacecraftState state : states) {
148 s0.ensureCompatibleAdditionalStates(state);
149 }
150
151 pvProvider = new LocalPVProvider(states, interpolationPoints, extrapolationThreshold);
152
153
154 setAttitudeProvider(null);
155
156
157 cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);
158
159 this.extrapolationThreshold = extrapolationThreshold;
160 }
161
162
163
164
165 public AbsoluteDate getMinDate() {
166 return minDate;
167 }
168
169
170
171
172 public AbsoluteDate getMaxDate() {
173 return maxDate;
174 }
175
176
177
178
179
180 public double getExtrapolationThreshold() {
181 return extrapolationThreshold;
182 }
183
184 @Override
185 public Frame getFrame() {
186 return frame;
187 }
188
189 @Override
190
191 public SpacecraftState basicPropagate(final AbsoluteDate date) {
192 final SpacecraftState evaluatedState;
193
194 final AbsoluteDate central;
195 if (date.compareTo(minDate) < 0 && FastMath.abs(date.durationFrom(minDate)) <= extrapolationThreshold) {
196
197 central = minDate;
198 } else if (date.compareTo(maxDate) > 0 && FastMath.abs(date.durationFrom(maxDate)) <= extrapolationThreshold) {
199
200 central = maxDate;
201 } else {
202 central = date;
203 }
204 final List<SpacecraftState> neighbors = cache.getNeighbors(central).collect(Collectors.toList());
205 evaluatedState = neighbors.get(0).interpolate(date, neighbors);
206
207 final AttitudeProvider attitudeProvider = getAttitudeProvider();
208
209 if (attitudeProvider == null) {
210 return evaluatedState;
211 } else {
212 pvProvider.setCurrentState(evaluatedState);
213 final Attitude calculatedAttitude = attitudeProvider.getAttitude(pvProvider, date,
214 evaluatedState.getFrame());
215
216
217 if (evaluatedState.isOrbitDefined()) {
218 return new SpacecraftState(evaluatedState.getOrbit(), calculatedAttitude,
219 evaluatedState.getMass(), evaluatedState.getAdditionalStates());
220 } else {
221 return new SpacecraftState(evaluatedState.getAbsPVA(), calculatedAttitude,
222 evaluatedState.getMass(), evaluatedState.getAdditionalStates());
223 }
224
225 }
226 }
227
228
229 protected Orbit propagateOrbit(final AbsoluteDate date) {
230 return basicPropagate(date).getOrbit();
231 }
232
233
234 protected double getMass(final AbsoluteDate date) {
235 return basicPropagate(date).getMass();
236 }
237
238
239 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f) {
240 return propagate(date).getPVCoordinates(f);
241 }
242
243
244
245
246
247
248
249 public void resetInitialState(final SpacecraftState state) {
250 throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
251 }
252
253
254 protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
255 throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
256 }
257
258
259 public SpacecraftState getInitialState() {
260 return basicPropagate(getMinDate());
261 }
262
263
264 @Override
265 public boolean isAdditionalStateManaged(final String name) {
266
267
268 if (super.isAdditionalStateManaged(name)) {
269 return true;
270 }
271
272
273 for (final String a : additional) {
274 if (a.equals(name)) {
275 return true;
276 }
277 }
278
279 return false;
280
281 }
282
283
284 @Override
285 public String[] getManagedAdditionalStates() {
286 final String[] upperManaged = super.getManagedAdditionalStates();
287 final String[] managed = new String[upperManaged.length + additional.length];
288 System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
289 System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
290 return managed;
291 }
292
293
294 private static class LocalPVProvider implements PVCoordinatesProvider, Serializable {
295
296
297 private static final long serialVersionUID = 20160115L;
298
299
300 private SpacecraftState currentState;
301
302
303 private List<SpacecraftState> states;
304
305
306 private int interpolationPoints;
307
308
309 private double extrapolationThreshold;
310
311
312
313
314
315
316 LocalPVProvider(final List<SpacecraftState> states, final int interpolationPoints,
317 final double extrapolationThreshold) {
318
319 this.states = states;
320 this.interpolationPoints = interpolationPoints;
321 this.extrapolationThreshold = extrapolationThreshold;
322 }
323
324
325
326
327 public SpacecraftState getCurrentState() {
328 return currentState;
329 }
330
331
332
333
334 public void setCurrentState(final SpacecraftState state) {
335 this.currentState = state;
336 }
337
338
339 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame f) {
340 final double dt = getCurrentState().getDate().durationFrom(date);
341 final double closeEnoughTimeInSec = 1e-9;
342
343 if (FastMath.abs(dt) > closeEnoughTimeInSec) {
344
345
346 final Ephemeris ephemeris = new Ephemeris(states, interpolationPoints, extrapolationThreshold, null);
347 return ephemeris.getPVCoordinates(date, f);
348 }
349
350 return currentState.getPVCoordinates(f);
351
352 }
353
354 }
355
356 }