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.HashMap;
20  import java.util.Map;
21  import java.util.regex.Pattern;
22  
23  import org.orekit.annotation.DefaultDataContext;
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitMessages;
26  import org.orekit.time.DateComponents;
27  import org.orekit.time.TimeScale;
28  import org.orekit.time.TimeScalesFactory;
29  
30  /**
31   * Container for Consolidated laser ranging Data Format (CDR) header.
32   * @author Bryan Cazabonne
33   * @author Rongwang Li
34   * @since 10.3
35   */
36  public class CRDHeader extends ILRSHeader {
37  
38      /** String delimiter regex of datetime. */
39      private static final String DATETIME_DELIMITER_REGEX = "[-:T]";
40  
41      /** Space. */
42      private static final String SPACE = " ";
43  
44      /** Pattern of delimiter of datetime. */
45      public static final Pattern PATTERN_DATETIME_DELIMITER_REGEX = Pattern.compile(DATETIME_DELIMITER_REGEX);
46  
47      /** Station name from official list. */
48      private String stationName;
49  
50      /** System identifier: Crustal Dynamics Project (CDP) Pad Identifier for SLR. */
51      private int systemIdentifier;
52  
53      /** System number: Crustal Dynamics Project (CDP) 2-digit system number for SLR. */
54      private int systemNumber;
55  
56      /** System occupancy: Crustal Dynamics Project (CDP) 2-digit occupancy sequence number for SLR. */
57      private int systemOccupancy;
58  
59      /** Station Epoch Time Scale. */
60      private int epochIdentifier;
61  
62      /** Station network. */
63      private String stationNetword;
64  
65      /** Spacecraft Epoch Time Scale (transponders only). */
66      private int spacecraftEpochTimeScale;
67  
68      /** Data type. */
69      private int dataType;
70  
71      /** A flag to indicate the data release. */
72      private int dataReleaseFlag;
73  
74      /** Tropospheric refraction correction applied indicator. */
75      private boolean isTroposphericRefractionApplied;
76  
77      /** Center of mass correction applied indicator. */
78      private boolean isCenterOfMassCorrectionApplied;
79  
80      /** Receive amplitude correction applied indicator. */
81      private boolean isReceiveAmplitudeCorrectionApplied;
82  
83      /** Station system delay applied indicator. */
84      private boolean isStationSystemDelayApplied;
85  
86      /** Spacecraft system delay applied (transponders) indicator. */
87      private boolean isTransponderDelayApplied;
88  
89      /** Range type. */
90      private RangeType rangeType;
91  
92      /** Data quality indicator. */
93      private int qualityIndicator;
94  
95      /** Prediction type (CPF or TLE). */
96      private int predictionType;
97  
98      /** Year of century from CPF or TLE. */
99      private int yearOfCentury;
100 
101     /**
102      * Date and time.
103      * CPF starting date and hour (MMDDHH) from CPF H2 record or
104      * TLE epoch day/fractional day.
105      */
106     private String dateAndTime;
107 
108     /** Prediction provider (CPF provider in H1 record or TLE source). */
109     private String predictionProvider;
110 
111     /** Empty constructor.
112      * <p>
113      * This constructor is not strictly necessary, but it prevents spurious
114      * javadoc warnings with JDK 18 and later.
115      * </p>
116      * @since 12.0
117      */
118     public CRDHeader() {
119         // nothing to do
120     }
121 
122     /**
123      * Get the station name from official list.
124      * @return the station name from official list
125      */
126     public String getStationName() {
127         return stationName;
128     }
129 
130     /**
131      * Set the station name from official list.
132      * @param stationName the station name to set
133      */
134     public void setStationName(final String stationName) {
135         this.stationName = stationName;
136     }
137 
138     /**
139      * Get the system identifier.
140      * @return the system identifier
141      */
142     public int getSystemIdentifier() {
143         return systemIdentifier;
144     }
145 
146     /**
147      * Set the system identifier.
148      * @param systemIdentifier the system identifier to set
149      */
150     public void setSystemIdentifier(final int systemIdentifier) {
151         this.systemIdentifier = systemIdentifier;
152     }
153 
154     /**
155      * Get the system number.
156      * @return the system number
157      */
158     public int getSystemNumber() {
159         return systemNumber;
160     }
161 
162     /**
163      * Set the system number.
164      * @param systemNumber the system number to set
165      */
166     public void setSystemNumber(final int systemNumber) {
167         this.systemNumber = systemNumber;
168     }
169 
170     /**
171      * Get the system occupancy.
172      * @return the system occupancy
173      */
174     public int getSystemOccupancy() {
175         return systemOccupancy;
176     }
177 
178     /**
179      * Set the system occupancy.
180      * @param systemOccupancy the system occupancy to set
181      */
182     public void setSystemOccupancy(final int systemOccupancy) {
183         this.systemOccupancy = systemOccupancy;
184     }
185 
186     /**
187      * Get the epoch identifier.
188      * <p>
189      * 3 = UTC (UNSO) ; 4 = UTC (GPS) ; 7 = UTC (BIPM) ; 10 = UTC (Station Time Scale)
190      * </p>
191      * @return the epoch identifier
192      */
193     public int getEpochIdentifier() {
194         return epochIdentifier;
195     }
196 
197     /**
198      * Set the epoch identifier.
199      * @param epochIdentifier the epoch identifier to set
200      */
201     public void setEpochIdentifier(final int epochIdentifier) {
202         this.epochIdentifier = epochIdentifier;
203     }
204 
205     /**
206      * Get the station network.
207      * @return the station network
208      */
209     public String getStationNetword() {
210         return stationNetword;
211     }
212 
213     /**
214      * Set the station network.
215      * @param stationNetword the station network to set
216      */
217     public void setStationNetword(final String stationNetword) {
218         this.stationNetword = stationNetword;
219     }
220 
221     /**
222      * Get the spacecraft epoch time scale.
223      * @return the spacecraft epoch time scale
224      */
225     public int getSpacecraftEpochTimeScale() {
226         return spacecraftEpochTimeScale;
227     }
228 
229     /**
230      * Set the spacecraft epoch time scale.
231      * @param spacecraftEpochTimeScale the spacecraft epoch time scale to set
232      */
233     public void setSpacecraftEpochTimeScale(final int spacecraftEpochTimeScale) {
234         this.spacecraftEpochTimeScale = spacecraftEpochTimeScale;
235     }
236 
237     /**
238      * Get the data type.
239      * <p>
240      * 0 = full rate ; 1 = normal point ; 2 = sampled engineering
241      * </p>
242      * @return the data type
243      */
244     public int getDataType() {
245         return dataType;
246     }
247 
248     /**
249      * Set the data type.
250      * @param dataType the data type to set
251      */
252     public void setDataType(final int dataType) {
253         this.dataType = dataType;
254     }
255 
256     /**
257      * Get the flag indicating the data release.
258      * @return the flag indicating the data release
259      */
260     public int getDataReleaseFlag() {
261         return dataReleaseFlag;
262     }
263 
264     /**
265      * Set the flag indicating the data release.
266      * @param dataReleaseFlag the flag to set
267      */
268     public void setDataReleaseFlag(final int dataReleaseFlag) {
269         this.dataReleaseFlag = dataReleaseFlag;
270     }
271 
272     /**
273      * Get the tropospheric refraction correction applied indicator.
274      * @return true if tropospheric refraction correction is applied
275      */
276     public boolean isTroposphericRefractionApplied() {
277         return isTroposphericRefractionApplied;
278     }
279 
280     /**
281      * Set the tropospheric refraction correction applied indicator.
282      * @param isTroposphericRefractionApplied true if tropospheric refraction correction is applied
283      */
284     public void setIsTroposphericRefractionApplied(final boolean isTroposphericRefractionApplied) {
285         this.isTroposphericRefractionApplied = isTroposphericRefractionApplied;
286     }
287 
288     /**
289      * Get the center of mass correction applied indicator.
290      * @return true if center of mass correction is applied
291      */
292     public boolean isCenterOfMassCorrectionApplied() {
293         return isCenterOfMassCorrectionApplied;
294     }
295 
296     /**
297      * Set the center of mass correction applied indicator.
298      * @param isCenterOfMassCorrectionApplied true if center of mass correction is applied
299      */
300     public void setIsCenterOfMassCorrectionApplied(final boolean isCenterOfMassCorrectionApplied) {
301         this.isCenterOfMassCorrectionApplied = isCenterOfMassCorrectionApplied;
302     }
303 
304     /**
305      * Get the receive amplitude correction applied indicator.
306      * @return true if receive amplitude correction is applied
307      */
308     public boolean isReceiveAmplitudeCorrectionApplied() {
309         return isReceiveAmplitudeCorrectionApplied;
310     }
311 
312     /**
313      * Set the receive amplitude correction applied indicator.
314      * @param isReceiveAmplitudeCorrectionApplied true if receive amplitude correction is applied
315      */
316     public void setIsReceiveAmplitudeCorrectionApplied(final boolean isReceiveAmplitudeCorrectionApplied) {
317         this.isReceiveAmplitudeCorrectionApplied = isReceiveAmplitudeCorrectionApplied;
318     }
319 
320     /**
321      * Get the station system delay applied indicator.
322      * @return true if station system delay is applied
323      */
324     public boolean isStationSystemDelayApplied() {
325         return isStationSystemDelayApplied;
326     }
327 
328     /**
329      * Set the station system delay applied indicator.
330      * @param isStationSystemDelayApplied true if station system delay is applied
331      */
332     public void setIsStationSystemDelayApplied(final boolean isStationSystemDelayApplied) {
333         this.isStationSystemDelayApplied = isStationSystemDelayApplied;
334     }
335 
336     /**
337      * Get the spacecraft system delay applied (transponders) indicator.
338      * @return true if transponder delay is applied
339      */
340     public boolean isTransponderDelayApplied() {
341         return isTransponderDelayApplied;
342     }
343 
344     /**
345      * Set the spacecraft system delay applied (transponders) indicator.
346      * @param isTransponderDelayApplied true if transponder delay is applied
347      */
348     public void setIsTransponderDelayApplied(final boolean isTransponderDelayApplied) {
349         this.isTransponderDelayApplied = isTransponderDelayApplied;
350     }
351 
352     /**
353      * Get the range type.
354      * @return the range type
355      */
356     public RangeType getRangeType() {
357         return rangeType;
358     }
359 
360     /**
361      * Set the range type indicator.
362      * @param indicator range type indicator
363      */
364     public void setRangeType(final int indicator) {
365         this.rangeType = RangeType.getRangeType(indicator);
366     }
367 
368     /**
369      * Get the data quality indicator.
370      * @return the data quality indicator
371      */
372     public int getQualityIndicator() {
373         return qualityIndicator;
374     }
375 
376     /**
377      * Set the data quality indicator.
378      * @param qualityIndicator the indicator to set
379      */
380     public void setQualityIndicator(final int qualityIndicator) {
381         this.qualityIndicator = qualityIndicator;
382     }
383 
384     /**
385      * Get the prediction type (CPF or TLE).
386      * @return the prediction type
387      */
388     public int getPredictionType() {
389         return predictionType;
390     }
391 
392     /**
393      * Set the prediction type.
394      * @param predictionType the prediction type to set
395      */
396     public void setPredictionType(final int predictionType) {
397         this.predictionType = predictionType;
398     }
399 
400     /**
401      * Get the year of century from CPF or TLE.
402      * @return the year of century from CPF or TLE
403      */
404     public int getYearOfCentury() {
405         return yearOfCentury;
406     }
407 
408     /**
409      * Set the year of century from CPF or TLE.
410      * @param yearOfCentury the year of century to set
411      */
412     public void setYearOfCentury(final int yearOfCentury) {
413         this.yearOfCentury = yearOfCentury;
414     }
415 
416 
417     /**
418      * Get the date and time as the string value.
419      * <p>
420      * Depending the prediction type, this value can represent the
421      * CPF starting date and hour (MMDDHH) from CPF H2 record or
422      * TLE epoch day/fractional day
423      * </p>
424      * @return the date and time as the string value
425      */
426     public String getDateAndTime() {
427         return dateAndTime;
428     }
429 
430     /**
431      * Set the string value of date and time.
432      * @param dateAndTime the date and time to set
433      */
434     public void setDateAndTime(final String dateAndTime) {
435         this.dateAndTime = dateAndTime;
436     }
437 
438     /**
439      * Get the prediction provider.
440      * @return the preditction provider
441      */
442     public String getPredictionProvider() {
443         return predictionProvider;
444     }
445 
446     /**
447      * Set the prediction provider.
448      * @param predictionProvider the prediction provider to set
449      */
450     public void setPredictionProvider(final String predictionProvider) {
451         this.predictionProvider = predictionProvider;
452     }
453 
454     /**
455      * Get a string representation of the H1 in the CRD format.
456      * @return a string representation of the H1, in the CRD format.
457      * @since 12.0
458      */
459     public String getH1CrdString() {
460         final DateComponents dc = getProductionEpoch();
461         return String.format("H1 %3s %2d %04d %02d %02d %02d", getFormat(),
462                 getVersion(), dc.getYear(), dc.getMonth(), dc.getDay(),
463                 getProductionHour());
464     }
465 
466     /**
467      * Get a string representation of the H2 in the CRD format.
468      * @return a string representation of the H2, in the CRD format.
469      * @since 12.0
470      */
471     public String getH2CrdString() {
472         return String.format("H2 %s %4d %02d %02d %2d %s", stationName,
473                 systemIdentifier, systemNumber, systemOccupancy,
474                 epochIdentifier, stationNetword);
475     }
476 
477     /**
478      * Get a string representation of the H3 in the CRD format.
479      * @return a string representation of the H3, in the CRD format.
480      * @since 12.0
481      */
482     public String getH3CrdString() {
483         final int targetLocation = getTargetLocation();
484         return String.format("H3 %s %7s %4s %5s %1d %1d %2s", getName(),
485                 getIlrsSatelliteId(), getSic(), getNoradId(),
486                 getSpacecraftEpochTimeScale(), getTargetClass(),
487                 CRD.formatIntegerOrNaN(targetLocation, -1));
488     }
489 
490     /**
491      * Get a string representation of the H4 in the CRD format.
492      * @return a string representation of the H4, in the CRD format.
493      * @since 12.0
494      */
495     @DefaultDataContext
496     public String getH4CrdString() {
497         // "2006-11-13T15:23:52" -- > "2006 11 13 15 23 52"
498         final TimeScale utc = TimeScalesFactory.getUTC();
499         final String startEpoch = getStartEpoch().toStringWithoutUtcOffset(utc, 0);
500         final String endEpoch = getEndEpoch().toStringWithoutUtcOffset(utc, 0);
501         return String.format("H4 %2d %s %s %d %d %d %d %d %d %d %d", getDataType(),
502                 PATTERN_DATETIME_DELIMITER_REGEX.matcher(startEpoch).replaceAll(SPACE),
503                 PATTERN_DATETIME_DELIMITER_REGEX.matcher(endEpoch).replaceAll(SPACE),
504                 dataReleaseFlag, isTroposphericRefractionApplied ? 1 : 0,
505                 isCenterOfMassCorrectionApplied ? 1 : 0,
506                 isReceiveAmplitudeCorrectionApplied ? 1 : 0,
507                 isStationSystemDelayApplied ? 1 : 0,
508                 isTransponderDelayApplied ? 1 : 0, rangeType.getIndicator(),
509                 qualityIndicator);
510     }
511 
512     /**
513      * Get a string representation of the H5 in the CRD format.
514      * @return a string representation of the H5, in the CRD format.
515      * @since 12.0
516      */
517     public String getH5CrdString() {
518         return String.format("H5 %2d %02d %s %3s %5d", getPredictionType(), getYearOfCentury(),
519                 getDateAndTime(), getPredictionProvider(), getSequenceNumber());
520     }
521 
522     /** Range type for SLR data. */
523     public enum RangeType {
524 
525         /** No ranges (i.e. transmit time only). */
526         NO_RANGES(0),
527 
528         /** One-way ranging. */
529         ONE_WAY(1),
530 
531         /** Two-way ranging. */
532         TWO_WAY(2),
533 
534         /** Received times only. */
535         RECEIVED_ONLY(3),
536 
537         /** Mixed. */
538         MIXED(4);
539 
540         /** Codes map. */
541         private static final Map<Integer, RangeType> CODES_MAP = new HashMap<>();
542         static {
543             for (final RangeType type : values()) {
544                 CODES_MAP.put(type.getIndicator(), type);
545             }
546         }
547 
548         /** range type indicator. */
549         private final int indicator;
550 
551         /**
552          * Constructor.
553          * @param indicator range type indicator
554          */
555         RangeType(final int indicator) {
556             this.indicator = indicator;
557         }
558 
559         /**
560          * Get the range type indicator.
561          * @return the range type indicator
562          */
563         public int getIndicator() {
564             return indicator;
565         }
566 
567         /**
568          * Get the range type for the given indicator.
569          * @param id indicator
570          * @return the range type corresponding to the indicator
571          */
572         public static RangeType getRangeType(final int id) {
573             final RangeType type = CODES_MAP.get(id);
574             if (type == null) {
575                // Invalid value. An exception is thrown
576                 throw new OrekitException(OrekitMessages.INVALID_RANGE_INDICATOR_IN_CRD_FILE, id);
577             }
578             return type;
579         }
580 
581     }
582 
583     /** Data type for CRD data.
584      * @since 12.0
585      */
586     public enum DataType {
587 
588         /** Full rate. */
589         FULL_RATE(0),
590 
591         /** Normal point. */
592         NORMAL_POINT(1),
593 
594         /** Sampled engineering. */
595         SAMPLED_ENGIEERING(2);
596 
597         /** Codes map. */
598         private static final Map<Integer, DataType> CODES_MAP = new HashMap<>();
599         static {
600             for (final DataType type : values()) {
601                 CODES_MAP.put(type.getIndicator(), type);
602             }
603         }
604 
605         /** data type indicator. */
606         private final int indicator;
607 
608         /**
609          * Constructor.
610          * @param indicator data type indicator
611          */
612         DataType(final int indicator) {
613             this.indicator = indicator;
614         }
615 
616         /**
617          * Get the data type indicator.
618          * @return the data type indicator
619          */
620         public int getIndicator() {
621             return indicator;
622         }
623 
624         /**
625          * Get the data type for the given indicator.
626          * @param id indicator
627          * @return the data type corresponding to the indicator
628          */
629         public static DataType getDataType(final int id) {
630             final DataType type = CODES_MAP.get(id);
631             if (type == null) {
632                // Invalid value. An exception is thrown
633                 throw new RuntimeException(String.format("Invalid data type indicator {0} in CRD file header", id));
634             }
635             return type;
636         }
637 
638     }
639 
640 }