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.sinex;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.models.earth.displacement.PsdCorrection;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.TimeSpanMap;
30  
31  /**
32   * Station model.
33   * <p>
34   * Since Orekit 11.1, this class handles multiple site antenna
35   * eccentricity.
36   * The {@link #getEccentricities(AbsoluteDate)} method can be
37   * used to access the site antenna eccentricity values for a
38   * given epoch.
39   * </p>
40   * @author Bryan Cazabonne
41   * @since 10.3
42   */
43  public class Station {
44  
45      /** Site code. */
46      private String siteCode;
47  
48      /** DOMES number. */
49      private String domes;
50  
51      /** Start of validity. */
52      private AbsoluteDate validFrom;
53  
54      /** End of validity. */
55      private AbsoluteDate validUntil;
56  
57      /** Eccentricity reference system. */
58      private ReferenceSystem eccRefSystem;
59  
60      /** TimeSpanMap of site antenna eccentricities. */
61      private final TimeSpanMap<Vector3D> eccentricitiesTimeSpanMap;
62  
63      /** Antenna type.
64       * @since 12.0
65       */
66      private final TimeSpanMap<String> antennaTypesMap;
67  
68      /** Post-Seismic Deformation.
69       * @since 12.0
70       */
71      private final TimeSpanMap<List<PsdCorrection>> psdMap;
72  
73      /** Station position. */
74      private Vector3D position;
75  
76      /** Station velocity. */
77      private Vector3D velocity;
78  
79      /** Coordinates reference epoch. */
80      private AbsoluteDate epoch;
81  
82      /**
83       * Constructor.
84       */
85      public Station() {
86          this.eccentricitiesTimeSpanMap = new TimeSpanMap<>(null);
87          this.antennaTypesMap           = new TimeSpanMap<>(null);
88          this.psdMap                    = new TimeSpanMap<>(null);
89          this.position                  = Vector3D.ZERO;
90          this.velocity                  = Vector3D.ZERO;
91      }
92  
93      /**
94       * Get the site code (station identifier).
95       * @return the site code
96       */
97      public String getSiteCode() {
98          return siteCode;
99      }
100 
101     /**
102      * Set the site code (station identifier).
103      * @param siteCode the site code to set
104      */
105     public void setSiteCode(final String siteCode) {
106         this.siteCode = siteCode;
107     }
108 
109     /**
110      * Get the site DOMES number.
111      * @return the DOMES number
112      */
113     public String getDomes() {
114         return domes;
115     }
116 
117     /**
118      * Set the DOMES number.
119      * @param domes the DOMES number to set
120      */
121     public void setDomes(final String domes) {
122         this.domes = domes;
123     }
124 
125     /**
126      * Get start of validity.
127      * @return start of validity
128      */
129     public AbsoluteDate getValidFrom() {
130         return validFrom;
131     }
132 
133     /**
134      * Set the start of validity.
135      * @param validFrom the start of validity to set
136      */
137     public void setValidFrom(final AbsoluteDate validFrom) {
138         this.validFrom = validFrom;
139     }
140 
141     /**
142      * Get end of validity.
143      * @return end of validity
144      */
145     public AbsoluteDate getValidUntil() {
146         return validUntil;
147     }
148 
149     /**
150      * Set the end of validity.
151      * @param validUntil the end of validity to set
152      */
153     public void setValidUntil(final AbsoluteDate validUntil) {
154         this.validUntil = validUntil;
155     }
156 
157     /**
158      * Get the reference system used to define the eccentricity vector (local or cartesian).
159      * @return the reference system used to define the eccentricity vector
160      */
161     public ReferenceSystem getEccRefSystem() {
162         return eccRefSystem;
163     }
164 
165     /**
166      * Set the reference system used to define the eccentricity vector (local or cartesian).
167      * @param eccRefSystem the reference system used to define the eccentricity vector
168      */
169     public void setEccRefSystem(final ReferenceSystem eccRefSystem) {
170         this.eccRefSystem = eccRefSystem;
171     }
172 
173     /**
174      * Get the station antenna eccentricities for the given epoch.
175      * <p>
176      * Vector convention: X-Y-Z or UP-NORTH-EAST.
177      * See {@link #getEccRefSystem()} method.
178      * <p>
179      * If there is no eccentricity values for the given epoch, an
180      * exception is thrown.
181      * @param date epoch
182      * @return station antenna eccentricities (m)
183      * @since 11.1
184      */
185     public Vector3D getEccentricities(final AbsoluteDate date) {
186         final Vector3D eccAtEpoch = eccentricitiesTimeSpanMap.get(date);
187         // If the entry is null, there is no valid eccentricity values for the input epoch
188         if (eccAtEpoch == null) {
189             // Throw an exception
190             throw new OrekitException(OrekitMessages.MISSING_STATION_DATA_FOR_EPOCH, date);
191         }
192         return eccAtEpoch;
193     }
194 
195     /**
196      * Get the TimeSpanMap of site antenna eccentricities.
197      * @return the TimeSpanMap of site antenna eccentricities
198      * @since 11.1
199      */
200     public TimeSpanMap<Vector3D> getEccentricitiesTimeSpanMap() {
201         return eccentricitiesTimeSpanMap;
202     }
203 
204     /** Add a station eccentricity vector entry valid before a limit date.<br>
205      * Using <code>addStationEccentricitiesValidBefore(entry, t)</code> will make <code>entry</code>
206      * valid in ]-∞, t[ (note the open bracket).
207      * @param entry station eccentricity vector entry
208      * @param latestValidityDate date before which the entry is valid
209      * (must be different from <b>all</b> dates already used for transitions)
210      * @since 11.1
211      */
212     public void addStationEccentricitiesValidBefore(final Vector3D entry, final AbsoluteDate latestValidityDate) {
213         eccentricitiesTimeSpanMap.addValidBefore(entry, latestValidityDate, false);
214     }
215 
216     /** Add a station eccentricity vector entry valid after a limit date.<br>
217      * Using <code>addStationEccentricitiesValidAfter(entry, t)</code> will make <code>entry</code>
218      * valid in [t, +∞[ (note the closed bracket).
219      * @param entry station eccentricity vector entry
220      * @param earliestValidityDate date after which the entry is valid
221      * (must be different from <b>all</b> dates already used for transitions)
222      * @since 11.1
223      */
224     public void addStationEccentricitiesValidAfter(final Vector3D entry, final AbsoluteDate earliestValidityDate) {
225         eccentricitiesTimeSpanMap.addValidAfter(entry, earliestValidityDate, false);
226     }
227 
228     /** Get the TimeSpanMap of Post-Seismic Deformation.
229      * @return the TimeSpanMap of Post-Seismic Deformation
230      * @since 12.1
231      */
232     public TimeSpanMap<List<PsdCorrection>> getPsdTimeSpanMap() {
233         return psdMap;
234     }
235 
236     /** Add a Post-Seismic Deformation entry valid after a limit date.<br>
237      * Using {@code addPsdCorrectionValidAfter(entry, t)} will make {@code entry}
238      * valid in [t, +∞[ (note the closed bracket).
239      * @param entry Post-Seismic Deformation entry
240      * @param earliestValidityDate date after which the entry is valid
241      * (must be different from <b>all</b> dates already used for transitions)
242      * @since 12.1
243      */
244     public void addPsdCorrectionValidAfter(final PsdCorrection entry, final AbsoluteDate earliestValidityDate) {
245 
246         // get the list of corrections active just after earthquake date
247         List<PsdCorrection> corrections = psdMap.get(earliestValidityDate.shiftedBy(1.0e-3));
248 
249         if (corrections == null ||
250             earliestValidityDate.durationFrom(corrections.get(0).getEarthquakeDate()) > 1.0e-3) {
251             // either this is the first earthquake we consider or
252             // this earthquake is after another one already considered
253             // we need to create a new list of corrections for this new earthquake
254             corrections = new ArrayList<>();
255             psdMap.addValidAfter(corrections, earliestValidityDate, false);
256         }
257 
258         // add the entry to the current list
259         corrections.add(entry);
260 
261     }
262 
263     /**
264      * Get the antenna type for the given epoch.
265      * If there is no antenna types for the given epoch, an
266      * exception is thrown.
267      * @param date epoch
268      * @return antenna type
269      * @since 12.0
270      */
271     public String getAntennaType(final AbsoluteDate date) {
272         final String typeAtEpoch = antennaTypesMap.get(date);
273         // If the entry is null, there is no valid type for the input epoch
274         if (typeAtEpoch == null) {
275             // Throw an exception
276             throw new OrekitException(OrekitMessages.MISSING_STATION_DATA_FOR_EPOCH, date);
277         }
278         return typeAtEpoch;
279     }
280 
281     /**
282      * Get the TimeSpanMap of site antenna type.
283      * @return the TimeSpanMap of site antenna type
284      * @since 12.0
285      */
286     public TimeSpanMap<String> getAntennaTypeTimeSpanMap() {
287         return antennaTypesMap;
288     }
289 
290     /** Add a antenna type entry valid before a limit date.<br>
291      * Using <code>addAntennaTypeValidBefore(entry, t)</code> will make <code>entry</code>
292      * valid in ]-∞, t[ (note the open bracket).
293      * @param entry antenna type entry
294      * @param latestValidityDate date before which the entry is valid
295      * (must be different from <b>all</b> dates already used for transitions)
296      * @since 12.0
297      */
298     public void addAntennaTypeValidBefore(final String entry, final AbsoluteDate latestValidityDate) {
299         antennaTypesMap.addValidBefore(entry, latestValidityDate, false);
300     }
301 
302     /** Add a antenna type entry valid after a limit date.<br>
303      * Using <code>addAntennaTypeValidAfter(entry, t)</code> will make <code>entry</code>
304      * valid in [t, +∞[ (note the closed bracket).
305      * @param entry antenna type entry
306      * @param earliestValidityDate date after which the entry is valid
307      * (must be different from <b>all</b> dates already used for transitions)
308      * @since 12.0
309      */
310     public void addAntennaTypeValidAfter(final String entry, final AbsoluteDate earliestValidityDate) {
311         antennaTypesMap.addValidAfter(entry, earliestValidityDate, false);
312     }
313 
314     /**
315      * Get the station position.
316      * @return the station position (m)
317      */
318     public Vector3D getPosition() {
319         return position;
320     }
321 
322     /**
323      * Set the station position.
324      * @param position the position to set
325      */
326     public void setPosition(final Vector3D position) {
327         this.position = position;
328     }
329 
330     /**
331      * Get the station velocity.
332      * @return the station velocity (m/s)
333      */
334     public Vector3D getVelocity() {
335         return velocity;
336     }
337 
338     /**
339      * Set the station velocity.
340      * @param velocity the velocity to set
341      */
342     public void setVelocity(final Vector3D velocity) {
343         this.velocity = velocity;
344     }
345 
346     /**
347      * Get the coordinates reference epoch.
348      * @return the coordinates reference epoch
349      */
350     public AbsoluteDate getEpoch() {
351         return epoch;
352     }
353 
354     /**
355      * Set the coordinates reference epoch.
356      * @param epoch the epoch to set
357      */
358     public void setEpoch(final AbsoluteDate epoch) {
359         this.epoch = epoch;
360     }
361 
362     /** Eccentricity reference system. */
363     public enum ReferenceSystem {
364 
365         /** Local reference system Up, North, East. */
366         UNE("UNE"),
367 
368         /** Cartesian reference system X, Y, Z. */
369         XYZ("XYZ");
370 
371         /** Codes map. */
372         private static final Map<String, ReferenceSystem> CODES_MAP = new HashMap<>();
373         static {
374             for (final ReferenceSystem type : values()) {
375                 CODES_MAP.put(type.getName(), type);
376             }
377         }
378 
379         /** Name used to define the reference system in SINEX file. */
380         private final String name;
381 
382         /**
383          * Constructor.
384          * @param name name used to define the reference system in SINEX file
385          */
386         ReferenceSystem(final String name) {
387             this.name = name;
388         }
389 
390         /**
391          * Get the name used to define the reference system in SINEX file.
392          * @return the name
393          */
394         public String getName() {
395             return name;
396         }
397 
398         /**
399          * Get the eccentricity reference system corresponding to the given value.
400          * @param value given value
401          * @return the corresponding eccentricity reference system
402          */
403         public static ReferenceSystem getEccRefSystem(final String value) {
404             return CODES_MAP.get(value);
405         }
406 
407     }
408 
409 }
410