1 /* Copyright 2002-2025 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.files.ilrs;
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.hipparchus.geometry.euclidean.threed.Vector3D;
26 import org.orekit.attitudes.AttitudeProvider;
27 import org.orekit.files.general.EphemerisFile;
28 import org.orekit.frames.Frame;
29 import org.orekit.propagation.BoundedPropagator;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.time.TimeScale;
32 import org.orekit.utils.CartesianDerivativesFilter;
33 import org.orekit.utils.TimeStampedPVCoordinates;
34
35 /**
36 * This class stores all the information of the Consolidated laser ranging Prediction File (CPF) parsed
37 * by CPFParser. It contains the header and a list of ephemeris entry.
38 * @author Bryan Cazabonne
39 * @since 10.3
40 */
41 public class CPF implements EphemerisFile<CPF.CPFCoordinate, CPF.CPFEphemeris> {
42
43 /** Default satellite ID, used if header is null when initializing the ephemeris. */
44 public static final String DEFAULT_ID = "9999999";
45
46 /** Gravitational coefficient. */
47 private double mu;
48
49 /** The interpolation sample. */
50 private int interpolationSample;
51
52 /** Time scale of dates in the ephemeris file. */
53 private TimeScale timeScale;
54
55 /** Indicates if data contains velocity or not. */
56 private CartesianDerivativesFilter filter;
57
58 /** CPF file header. */
59 private final CPFHeader header;
60
61 /** Map containing satellite information. */
62 private final Map<String, CPFEphemeris> ephemeris;
63
64 /** List of comments contained in the file. */
65 private final List<String> comments;
66
67 /**
68 * Constructor.
69 */
70 public CPF() {
71 this.mu = Double.NaN;
72 this.ephemeris = new ConcurrentHashMap<>();
73 this.header = new CPFHeader();
74 this.comments = new ArrayList<>();
75 }
76
77 /** {@inheritDoc}
78 * First key corresponds to String value of {@link CPFHeader#getIlrsSatelliteId()}
79 */
80 @Override
81 public Map<String, CPFEphemeris> getSatellites() {
82 // Return the map
83 return Collections.unmodifiableMap(ephemeris);
84 }
85
86 /**
87 * Get the CPF file header.
88 * @return the CPF file header
89 */
90 public CPFHeader getHeader() {
91 return header;
92 }
93
94 /**
95 * Get the time scale used in CPF file.
96 * @return the time scale used to parse epochs in CPF file.
97 */
98 public TimeScale getTimeScale() {
99 return timeScale;
100 }
101
102 /**
103 * Get the comments contained in the file.
104 * @return the comments contained in the file
105 */
106 public List<String> getComments() {
107 return comments;
108 }
109
110 /**
111 * Adds a set of P/V coordinates to the satellite.
112 * @param id satellite ILRS identifier
113 * @param coord set of coordinates
114 * @since 11.0.1
115 */
116 public void addSatelliteCoordinates(final String id, final List<CPFCoordinate> coord) {
117 final CPFEphemeris e;
118 synchronized (this) {
119 e = ephemeris.computeIfAbsent(id, CPFEphemeris::new);
120 }
121 e.coordinates.addAll(coord);
122 }
123
124 /**
125 * Add a new P/V coordinates to the satellite.
126 * @param id satellite ILRS identifier
127 * @param coord the P/V coordinate of the satellite
128 * @since 11.0.1
129 */
130 public void addSatelliteCoordinate(final String id, final CPFCoordinate coord) {
131 final CPFEphemeris e;
132 synchronized (this) {
133 e = ephemeris.computeIfAbsent(id, CPFEphemeris::new);
134 }
135 e.coordinates.add(coord);
136 }
137
138 /**
139 * Add the velocity to the last CPF coordinate entry.
140 * @param id satellite ILRS identifier
141 * @param velocity the velocity vector of the satellite
142 * @since 11.2
143 */
144 public void addSatelliteVelocityToCPFCoordinate(final String id, final Vector3D velocity) {
145 // Get the last coordinate entry, which contains the position vector
146 final CPFCoordinate lastCoordinate = ephemeris.get(id).coordinates.get(ephemeris.get(id).coordinates.size() - 1);
147
148 // Create a new CPFCoordinate object with both position and velocity information
149 final CPFCoordinate CPFCoordUpdated = new CPFCoordinate(lastCoordinate.getDate(),
150 lastCoordinate.getPosition(),
151 velocity,
152 lastCoordinate.getLeap());
153
154 // Patch the last record
155 ephemeris.get(id).coordinates.set(ephemeris.get(id).coordinates.size() - 1, CPFCoordUpdated);
156 }
157
158 /**
159 * Set the interpolation sample.
160 * @param interpolationSample interpolation sample
161 */
162 public void setInterpolationSample(final int interpolationSample) {
163 this.interpolationSample = interpolationSample;
164 }
165
166 /**
167 * Set the gravitational coefficient.
168 * @param mu the coefficient to be set
169 */
170 public void setMu(final double mu) {
171 this.mu = mu;
172 }
173
174 /**
175 * Set the time scale.
176 * @param timeScale use to parse dates in this file.
177 */
178 public void setTimeScale(final TimeScale timeScale) {
179 this.timeScale = timeScale;
180 }
181
182 /**
183 * Set the derivatives filter.
184 * @param filter that indicates which derivatives of position are available.
185 */
186 public void setFilter(final CartesianDerivativesFilter filter) {
187 this.filter = filter;
188 }
189
190 /** An ephemeris entry for a single satellite contains in a CPF file. */
191 public class CPFEphemeris
192 implements EphemerisFile.SatelliteEphemeris<CPFCoordinate, CPFEphemeris>,
193 EphemerisFile.EphemerisSegment<CPFCoordinate> {
194
195 /** Satellite ID. */
196 private final String id;
197
198 /** Ephemeris Data. */
199 private final List<CPFCoordinate> coordinates;
200
201 /**
202 * Constructor.
203 * @param id satellite ID
204 */
205 public CPFEphemeris(final String id) {
206 this.id = id;
207 this.coordinates = new ArrayList<>();
208 }
209
210
211 /** {@inheritDoc} */
212 @Override
213 public Frame getFrame() {
214 return header.getRefFrame();
215 }
216
217 /** {@inheritDoc} */
218 @Override
219 public int getInterpolationSamples() {
220 return interpolationSample;
221 }
222
223 /** {@inheritDoc} */
224 @Override
225 public CartesianDerivativesFilter getAvailableDerivatives() {
226 return filter;
227 }
228
229 /** {@inheritDoc} */
230 @Override
231 public List<CPFCoordinate> getCoordinates() {
232 return Collections.unmodifiableList(this.coordinates);
233 }
234
235 /** {@inheritDoc} */
236 @Override
237 public String getId() {
238 return id == null ? DEFAULT_ID : id;
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public double getMu() {
244 return mu;
245 }
246
247 /** Returns a list containing only {@code this}. */
248 @Override
249 public List<CPFEphemeris> getSegments() {
250 return Collections.singletonList(this);
251 }
252
253 /** {@inheritDoc} */
254 @Override
255 public AbsoluteDate getStart() {
256 return coordinates.get(0).getDate();
257 }
258
259 /** {@inheritDoc} */
260 @Override
261 public AbsoluteDate getStop() {
262 return coordinates.get(coordinates.size() - 1).getDate();
263 }
264
265 /** {@inheritDoc} */
266 @Override
267 public BoundedPropagator getPropagator() {
268 return EphemerisSegment.super.getPropagator();
269 }
270
271 /** {@inheritDoc} */
272 @Override
273 public BoundedPropagator getPropagator(final AttitudeProvider attitudeProvider) {
274 return EphemerisSegment.super.getPropagator(attitudeProvider);
275 }
276
277 /** Get the list of Ephemerides data lines.
278 * @return a reference to the internal list of Ephemerides data lines
279 */
280 public List<CPFCoordinate> getEphemeridesDataLines() {
281 return this.coordinates;
282 }
283
284 }
285
286 /** A single record of position and possibility velocity in an SP3 file. */
287 public static class CPFCoordinate extends TimeStampedPVCoordinates {
288
289 /** Leap second flag. */
290 private final int leap;
291
292 /**
293 * Constructor with null velocity vector.
294 * @param date date of coordinates validity
295 * @param position position vector
296 * @param leap leap second flag (= 0 or the value of the new leap second)
297 */
298 public CPFCoordinate(final AbsoluteDate date,
299 final Vector3D position,
300 final int leap) {
301 this(date, position, Vector3D.ZERO, leap);
302 }
303
304 /**
305 * Constructor.
306 * @param date date of coordinates validity
307 * @param position position vector
308 * @param velocity velocity vector
309 * @param leap leap second flag (= 0 or the value of the new leap second)
310 */
311 public CPFCoordinate(final AbsoluteDate date,
312 final Vector3D position,
313 final Vector3D velocity,
314 final int leap) {
315 super(date, position, velocity);
316 this.leap = leap;
317 }
318
319 /**
320 * Get the leap second flag (= 0 or the value of the new leap second).
321 * @return the leap second flag
322 */
323 public int getLeap() {
324 return leap;
325 }
326
327 }
328
329 }