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