1   /* Copyright 2002-2024 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 CPFHeader header;
60  
61      /** Map containing satellite information. */
62      private Map<String, CPFEphemeris> ephemeris;
63  
64      /** List of comments contained in the file. */
65      private 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         ephemeris.computeIfAbsent(id, i -> new CPFEphemeris(i)).coordinates.addAll(coord);
118     }
119 
120     /**
121      * Add a new P/V coordinates to the satellite.
122      * @param id satellite ILRS identifier
123      * @param coord the P/V coordinate of the satellite
124      * @since 11.0.1
125      */
126     public void addSatelliteCoordinate(final String id, final CPFCoordinate coord) {
127         ephemeris.computeIfAbsent(id, i -> new CPFEphemeris(i)).coordinates.add(coord);
128     }
129 
130     /**
131      * Add the velocity to the last CPF coordinate entry.
132      * @param id satellite ILRS identifier
133      * @param velocity the velocity vector of the satellite
134      * @since 11.2
135      */
136     public void addSatelliteVelocityToCPFCoordinate(final String id, final Vector3D velocity) {
137         // Get the last coordinate entry, which contains the position vector
138         final CPFCoordinate lastCoordinate = ephemeris.get(id).coordinates.get(ephemeris.get(id).coordinates.size() - 1);
139 
140         // Create a new CPFCoordinate object with both position and velocity information
141         final CPFCoordinate CPFCoordUpdated = new CPFCoordinate(lastCoordinate.getDate(),
142                 lastCoordinate.getPosition(),
143                 velocity,
144                 lastCoordinate.getLeap());
145 
146         // Patch the last record
147         ephemeris.get(id).coordinates.set(ephemeris.get(id).coordinates.size() - 1, CPFCoordUpdated);
148     }
149 
150     /**
151      * Set the interpolation sample.
152      * @param interpolationSample interpolation sample
153      */
154     public void setInterpolationSample(final int interpolationSample) {
155         this.interpolationSample = interpolationSample;
156     }
157 
158     /**
159      * Set the gravitational coefficient.
160      * @param mu the coefficient to be set
161      */
162     public void setMu(final double mu) {
163         this.mu = mu;
164     }
165 
166     /**
167      * Set the time scale.
168      * @param timeScale use to parse dates in this file.
169      */
170     public void setTimeScale(final TimeScale timeScale) {
171         this.timeScale = timeScale;
172     }
173 
174     /**
175      * Set the derivatives filter.
176      * @param filter that indicates which derivatives of position are available.
177      */
178     public void setFilter(final CartesianDerivativesFilter filter) {
179         this.filter = filter;
180     }
181 
182     /** An ephemeris entry  for a single satellite contains in a CPF file. */
183     public class CPFEphemeris
184         implements EphemerisFile.SatelliteEphemeris<CPFCoordinate, CPFEphemeris>,
185                    EphemerisFile.EphemerisSegment<CPFCoordinate> {
186 
187         /** Satellite ID. */
188         private final String id;
189 
190         /** Ephemeris Data. */
191         private final List<CPFCoordinate> coordinates;
192 
193         /**
194          * Constructor.
195          * @param id satellite ID
196          */
197         public CPFEphemeris(final String id) {
198             this.id          = id;
199             this.coordinates = new ArrayList<>();
200         }
201 
202 
203         /** {@inheritDoc} */
204         @Override
205         public Frame getFrame() {
206             return header.getRefFrame();
207         }
208 
209         /** {@inheritDoc} */
210         @Override
211         public int getInterpolationSamples() {
212             return interpolationSample;
213         }
214 
215         /** {@inheritDoc} */
216         @Override
217         public CartesianDerivativesFilter getAvailableDerivatives() {
218             return filter;
219         }
220 
221         /** {@inheritDoc} */
222         @Override
223         public List<CPFCoordinate> getCoordinates() {
224             return Collections.unmodifiableList(this.coordinates);
225         }
226 
227         /** {@inheritDoc} */
228         @Override
229         public String getId() {
230             return id == null ? DEFAULT_ID : id;
231         }
232 
233         /** {@inheritDoc} */
234         @Override
235         public double getMu() {
236             return mu;
237         }
238 
239         /** Returns a list containing only {@code this}. */
240         @Override
241         public List<CPFEphemeris> getSegments() {
242             return Collections.singletonList(this);
243         }
244 
245         /** {@inheritDoc} */
246         @Override
247         public AbsoluteDate getStart() {
248             return coordinates.get(0).getDate();
249         }
250 
251         /** {@inheritDoc} */
252         @Override
253         public AbsoluteDate getStop() {
254             return coordinates.get(coordinates.size() - 1).getDate();
255         }
256 
257         /** {@inheritDoc} */
258         @Override
259         public BoundedPropagator getPropagator() {
260             return EphemerisSegment.super.getPropagator();
261         }
262 
263         /** {@inheritDoc} */
264         @Override
265         public BoundedPropagator getPropagator(final AttitudeProvider attitudeProvider) {
266             return EphemerisSegment.super.getPropagator(attitudeProvider);
267         }
268 
269         /** Get the list of Ephemerides data lines.
270          * @return a reference to the internal list of Ephemerides data lines
271          */
272         public List<CPFCoordinate> getEphemeridesDataLines() {
273             return this.coordinates;
274         }
275 
276     }
277 
278     /** A single record of position and possibility velocity in an SP3 file. */
279     public static class CPFCoordinate extends TimeStampedPVCoordinates {
280 
281         /** Serializable UID. */
282         private static final long serialVersionUID = 20201016L;
283 
284         /** Leap second flag. */
285         private final int leap;
286 
287         /**
288          * Constructor with null velocity vector.
289          * @param date date of coordinates validity
290          * @param position position vector
291          * @param leap leap second flag (= 0 or the value of the new leap second)
292          */
293         public CPFCoordinate(final AbsoluteDate date,
294                              final Vector3D position,
295                              final int leap) {
296             this(date, position, Vector3D.ZERO, leap);
297         }
298 
299         /**
300          * Constructor.
301          * @param date date of coordinates validity
302          * @param position position vector
303          * @param velocity velocity vector
304          * @param leap leap second flag (= 0 or the value of the new leap second)
305          */
306         public CPFCoordinate(final AbsoluteDate date,
307                              final Vector3D position,
308                              final Vector3D velocity,
309                              final int leap) {
310             super(date, position, velocity);
311             this.leap = leap;
312         }
313 
314         /**
315          * Get the leap second flag (= 0 or the value of the new leap second).
316          * @return the leap second flag
317          */
318         public int getLeap() {
319             return leap;
320         }
321 
322     }
323 
324 }