1 /* Copyright 2016 Applied Defense Solutions (ADS)
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 * ADS 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.files.general;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import org.orekit.annotation.DefaultDataContext;
26 import org.orekit.bodies.CelestialBody;
27 import org.orekit.data.DataContext;
28 import org.orekit.errors.OrekitIllegalArgumentException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.frames.Frame;
31 import org.orekit.propagation.SpacecraftState;
32 import org.orekit.time.AbsoluteDate;
33 import org.orekit.time.TimeScale;
34 import org.orekit.utils.CartesianDerivativesFilter;
35 import org.orekit.utils.TimeStampedPVCoordinates;
36
37 /**
38 * A class for encapsulating Orekit propagators within an {@link EphemerisFile}
39 * complaint object that makes for easy serialization to external ephemeris
40 * formats like OEM.
41 *
42 * @author Hank Grabowski
43 * @since 9.0
44 *
45 */
46 public class OrekitEphemerisFile
47 implements EphemerisFile<TimeStampedPVCoordinates, OrekitEphemerisFile.OrekitEphemerisSegment> {
48
49 /** Hashmap of satellite ephemeris. **/
50 private final Map<String, OrekitSatelliteEphemeris> satellites;
51
52 /**
53 * Standard default constructor.
54 */
55 public OrekitEphemerisFile() {
56 this.satellites = new ConcurrentHashMap<>();
57 }
58
59 /** {@inheritDoc} */
60 @Override
61 public Map<String, OrekitSatelliteEphemeris> getSatellites() {
62 return Collections.unmodifiableMap(satellites);
63 }
64
65 /**
66 * Adds a new satellite to this object.
67 *
68 * @param id
69 * ID to use for this satellite
70 * @return the new satellite object
71 */
72 public OrekitSatelliteEphemeris addSatellite(final String id) {
73 final OrekitSatelliteEphemeris newSat = new OrekitSatelliteEphemeris(id);
74 this.satellites.put(id, newSat);
75 return newSat;
76 }
77
78 /**
79 * Inner class of {@link OrekitEphemerisFile} that defines the
80 * {@link OrekitSatelliteEphemeris} corresponding object for this ephemeris type.
81 */
82 public static class OrekitSatelliteEphemeris
83 implements EphemerisFile.SatelliteEphemeris<TimeStampedPVCoordinates, OrekitEphemerisSegment> {
84
85 /**
86 * Defines the default interpolation sample size if it is not specified
87 * on a segment.
88 **/
89 public static final int DEFAULT_INTERPOLATION_SIZE = 2;
90
91 /** ID of the space object encapsulated here. **/
92 private final String id;
93
94 /** Earliest date of this file. **/
95 private AbsoluteDate startDate;
96
97 /** Latest date of this file. **/
98 private AbsoluteDate stopDate;
99
100 /** List of segments in the file. **/
101 private final List<OrekitEphemerisSegment> segments;
102
103 /**
104 * Standard constructor for building the satellite Ephemeris object.
105 *
106 * @param id
107 * the ID of the space object for this data
108 */
109 public OrekitSatelliteEphemeris(final String id) {
110 this.id = id;
111 this.segments = new ArrayList<>();
112 }
113
114 /** {@inheritDoc} */
115 @Override
116 public String getId() {
117 return id;
118 }
119
120 /** {@inheritDoc} */
121 @Override
122 public double getMu() {
123 if (this.segments.size() == 0) {
124 return 0;
125 } else {
126 return this.segments.get(0).getMu();
127 }
128 }
129
130 /** {@inheritDoc} */
131 @Override
132 public List<OrekitEphemerisSegment> getSegments() {
133 return Collections.unmodifiableList(this.segments);
134 }
135
136 /** {@inheritDoc} */
137 @Override
138 public AbsoluteDate getStart() {
139 return this.startDate;
140 }
141
142 /** {@inheritDoc} */
143 @Override
144 public AbsoluteDate getStop() {
145 return this.stopDate;
146 }
147
148 /**
149 * Injects pre-computed satellite states into this ephemeris file
150 * object, returning the generated {@link OrekitEphemerisSegment} that
151 * has been stored internally. Defaults the celestial body to earth and
152 * the interpolation size to the default.
153 *
154 * <p>This method uses the {@link DataContext#getDefault() default data context}.
155 *
156 * @param states
157 * a list of {@link SpacecraftState} that will comprise this
158 * new unit.
159 * @return the generated {@link OrekitEphemerisSegment}
160 * @see #addNewSegment(List, CelestialBody, int, TimeScale)
161 */
162 @DefaultDataContext
163 public OrekitEphemerisSegment addNewSegment(final List<SpacecraftState> states) {
164 return this.addNewSegment(states, DEFAULT_INTERPOLATION_SIZE);
165 }
166
167 /**
168 * Injects pre-computed satellite states into this ephemeris file
169 * object, returning the generated {@link OrekitEphemerisSegment} that
170 * has been stored internally. Defaults the Celestial Body to be Earths
171 *
172 * <p>This method uses the {@link DataContext#getDefault() default data context}.
173 *
174 * @param states
175 * a list of {@link SpacecraftState} that will comprise this
176 * new unit.
177 * @param interpolationSampleSize
178 * the number of interpolation samples that should be used
179 * when processed by another system
180 * @return the generated {@link OrekitEphemerisSegment}
181 * @see #addNewSegment(List, CelestialBody, int, TimeScale)
182 */
183 @DefaultDataContext
184 public OrekitEphemerisSegment addNewSegment(final List<SpacecraftState> states,
185 final int interpolationSampleSize) {
186 return this.addNewSegment(
187 states,
188 DataContext.getDefault().getCelestialBodies().getEarth(),
189 interpolationSampleSize);
190 }
191
192 /**
193 * Injects pre-computed satellite states into this ephemeris file
194 * object, returning the generated {@link OrekitEphemerisSegment} that
195 * has been stored internally.
196 *
197 * <p>This method uses the {@link DataContext#getDefault() default data context}.
198 *
199 * @param states
200 * a list of {@link SpacecraftState} that will comprise this
201 * new unit.
202 * @param body
203 * the celestial body the state's frames are with respect to
204 * @param interpolationSampleSize
205 * the number of interpolation samples that should be used
206 * when processed by another system
207 * @return the generated {@link OrekitEphemerisSegment}
208 * @see #addNewSegment(List, CelestialBody, int, TimeScale)
209 */
210 @DefaultDataContext
211 public OrekitEphemerisSegment addNewSegment(final List<SpacecraftState> states, final CelestialBody body,
212 final int interpolationSampleSize) {
213 return addNewSegment(states, body, interpolationSampleSize,
214 DataContext.getDefault().getTimeScales().getUTC());
215 }
216
217 /**
218 * Injects pre-computed satellite states into this ephemeris file
219 * object, returning the generated {@link OrekitEphemerisSegment} that
220 * has been stored internally.
221 *
222 * @param states
223 * a list of {@link SpacecraftState} that will comprise this
224 * new unit.
225 * @param body
226 * the celestial body from which the frames are defined
227 * @param interpolationSampleSize
228 * the number of interpolation samples that should be used
229 * when processed by another system
230 * @param timeScale
231 * the time scale used in the new segment.
232 * @return the generated {@link OrekitEphemerisSegment}
233 * @since 10.1
234 */
235 public OrekitEphemerisSegment addNewSegment(final List<SpacecraftState> states,
236 final CelestialBody body,
237 final int interpolationSampleSize,
238 final TimeScale timeScale) {
239 final int minimumSampleSize = 2;
240 if (states == null || states.size() == 0) {
241 throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "states");
242 }
243
244 if (interpolationSampleSize < minimumSampleSize) {
245 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA,
246 interpolationSampleSize);
247 }
248
249 final AbsoluteDate start = states.get(0).getDate();
250 final AbsoluteDate stop = states.get(states.size() - 1).getDate();
251
252 if (this.startDate == null || start.compareTo(this.startDate) < 0) {
253 this.startDate = start;
254 }
255
256 if (this.stopDate == null || stop.compareTo(this.stopDate) > 0) {
257 this.stopDate = stop;
258 }
259
260 final List<TimeStampedPVCoordinates> coordinates = new ArrayList<>();
261 for (SpacecraftState state : states) {
262 coordinates.add(state.getPVCoordinates());
263 }
264
265 final Frame frame = states.get(0).getFrame();
266
267 final OrekitEphemerisSegment newSeg =
268 new OrekitEphemerisSegment(coordinates, frame, body.getGM(), interpolationSampleSize);
269 this.segments.add(newSeg);
270
271 return newSeg;
272 }
273 }
274
275 /** Ephemeris segment. */
276 public static class OrekitEphemerisSegment
277 implements EphemerisFile.EphemerisSegment<TimeStampedPVCoordinates> {
278
279 /** Coordinates for this ephemeris segment. **/
280 private final List<TimeStampedPVCoordinates> coordinates;
281
282 /** The reference frame for this ephemeris segment. **/
283 private final Frame frame;
284
285 /** Standard gravitational parameter for the satellite. **/
286 private final double mu;
287
288 /** The number of interpolation samples. */
289 private final int interpolationSamples;
290
291 /**
292 * constructor for OrekitEphemerisSegment.
293 *
294 * @param coordinates
295 * coordinates making up the ephemeris for this segment
296 * @param frame
297 * the frame the coordinates are in
298 * @param mu
299 * the gravitational constant used in force model evaluations
300 * @param interpolationSamples
301 * the number of samples to use during interpolation
302 */
303 public OrekitEphemerisSegment(final List<TimeStampedPVCoordinates> coordinates, final Frame frame,
304 final double mu, final int interpolationSamples) {
305 this.coordinates = coordinates;
306 this.frame = frame;
307 this.mu = mu;
308 this.interpolationSamples = interpolationSamples;
309 }
310
311 /** {@inheritDoc} */
312 @Override
313 public double getMu() {
314 return mu;
315 }
316
317 /** {@inheritDoc} */
318 @Override
319 public Frame getFrame() {
320 return frame;
321 }
322
323 /** {@inheritDoc} */
324 @Override
325 public Frame getInertialFrame() {
326 return frame;
327 }
328
329 /** {@inheritDoc} */
330 @Override
331 public int getInterpolationSamples() {
332 return interpolationSamples;
333 }
334
335 /** {@inheritDoc} */
336 @Override
337 public CartesianDerivativesFilter getAvailableDerivatives() {
338 return CartesianDerivativesFilter.USE_PV;
339 }
340
341 /** {@inheritDoc} */
342 @Override
343 public List<TimeStampedPVCoordinates> getCoordinates() {
344 return Collections.unmodifiableList(coordinates);
345 }
346
347 /** {@inheritDoc} */
348 @Override
349 public AbsoluteDate getStart() {
350 return coordinates.get(0).getDate();
351 }
352
353 /** {@inheritDoc} */
354 @Override
355 public AbsoluteDate getStop() {
356 return coordinates.get(coordinates.size() - 1).getDate();
357 }
358
359 }
360 }