RinexClockHeader.java
/* Copyright 2022-2025 Thales Alenia Space
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.files.rinex.clock;
import org.orekit.files.rinex.section.CommonLabel;
import org.orekit.files.rinex.section.Label;
import org.orekit.files.rinex.section.RinexClockObsBaseHeader;
import org.orekit.files.rinex.utils.ParsingUtils;
import org.orekit.files.rinex.utils.RinexFileType;
import org.orekit.frames.Frame;
import org.orekit.gnss.ObservationType;
import org.orekit.gnss.SatInSystem;
import org.orekit.gnss.SatelliteSystem;
import org.orekit.gnss.TimeSystem;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScales;
import org.orekit.utils.TimeSpanMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** Header for Rinex Clock.
* @author Luc Maisonobe
* @since 14.0
*/
public class RinexClockHeader extends RinexClockObsBaseHeader {
/** Index of label in header lines before 3.04. */
public static final int LABEL_INDEX_300_302 = 60;
/** Index of label in header lines for version 3.04 and later. */
public static final int LABEL_INDEX_304_PLUS = 65;
/** Indicator for header before version 3.04. */
private boolean before304;
/** System time scale. */
private TimeScale timeScale;
/** Number of leap seconds separating UTC and TAI. */
private int leapSecondsTAI;
/** Earth centered frame. */
private Frame frame;
/** Earth centered frame name as a string. */
private String frameName;
/** Time system. */
private TimeSystem timeSystem;
/** Station name for calibration and discontinuity data. */
private String stationName;
/** Station identifier for calibration and discontinuity data. */
private String stationIdentifier;
/** External reference clock identifier for calibration. */
private String externalClockReference;
/** Analysis center ID. */
private String analysisCenterID;
/** Full analysis center name. */
private String analysisCenterName;
/** Reference clocks. */
private final TimeSpanMap<List<ReferenceClock>> referenceClocks;
/** Satellite system code. */
private final Map<SatelliteSystem, List<ObservationType>> systemObservationTypes;
/** List of the data types in the file. */
private final List<ClockDataType> clockDataTypes;
/** List of the receivers in the file. */
private final List<Receiver> receivers;
/** List of the satellites in the file. */
private final List<SatInSystem> satellites;
/** Merged satellites systems. */
private SatelliteSystem mergedSystems;
/** Simple constructor.
*/
public RinexClockHeader() {
super(RinexFileType.CLOCK);
this.frameName = "";
this.systemObservationTypes = new HashMap<>();
this.clockDataTypes = new ArrayList<>();
this.timeSystem = null;
this.stationIdentifier = "";
this.stationName = "";
this.externalClockReference = "";
this.analysisCenterID = "";
this.analysisCenterName = "";
this.referenceClocks = new TimeSpanMap<>(null);
this.receivers = new ArrayList<>();
this.satellites = new ArrayList<>();
}
/** {@inheritDoc} */
@Override
public void setFormatVersion(final double formatVersion) {
super.setFormatVersion(formatVersion);
before304 = formatVersion < 3.04;
}
/** Check if header corresponds to a version before 3.04.
* @return true if header corresponds to a version before 3.04
*/
boolean isBefore304() {
return before304;
}
/** {@inheritDoc} */
@Override
public SatelliteSystem parseSatelliteSystem(final String line, final SatelliteSystem defaultSatelliteSystem) {
final String satSystemString = (getFormatVersion() < 3.04 ? line.substring(40, 41) : line.substring(42, 43)).trim();
return SatelliteSystem.parseSatelliteSystem(satSystemString, defaultSatelliteSystem);
}
/** {@inheritDoc} */
@Override
public void parseProgramRunByDate(final String line, final TimeScales timeScales) {
if (getFormatVersion() < 3.04) {
parseProgramRunByDate(ParsingUtils.parseString(line, 0, 20),
ParsingUtils.parseString(line, 20, 20),
ParsingUtils.parseString(line, 40, 20),
timeScales);
} else {
parseProgramRunByDate(ParsingUtils.parseString(line, 0, 19),
ParsingUtils.parseString(line, 21, 19),
ParsingUtils.parseString(line, 42, 21),
timeScales);
}
}
/** Getter for the file time system.
* @return the file time system
*/
public TimeSystem getTimeSystem() {
return timeSystem;
}
/** Setter for the file time system.
* @param timeSystem the file time system to set
*/
public void setTimeSystem(final TimeSystem timeSystem) {
this.timeSystem = timeSystem;
}
/** Get the system time scale.
* @return system time scale
*/
public TimeScale getTimeScale() {
return timeScale;
}
/** Set the system time scale.
* @param timeScale system time scale
*/
public void setTimeScale(final TimeScale timeScale) {
this.timeScale = timeScale;
}
/** Getter for the station name.
* @return the station name
*/
public String getStationName() {
return stationName;
}
/** Setter for the station name.
* @param stationName the station name to set
*/
public void setStationName(final String stationName) {
this.stationName = stationName;
}
/** Getter for the station identifier.
* @return the station identifier
*/
public String getStationIdentifier() {
return stationIdentifier;
}
/** Setter for the station identifier.
* @param stationIdentifier the station identifier to set
*/
public void setStationIdentifier(final String stationIdentifier) {
this.stationIdentifier = stationIdentifier;
}
/** Getter for the external clock reference.
* @return the external clock reference
*/
public String getExternalClockReference() {
return externalClockReference;
}
/** Setter for the external clock reference.
* @param externalClockReference the external clock reference to set
*/
public void setExternalClockReference(final String externalClockReference) {
this.externalClockReference = externalClockReference;
}
/** Getter for the analysis center ID.
* @return the analysis center ID
*/
public String getAnalysisCenterID() {
return analysisCenterID;
}
/** Setter for the analysis center ID.
* @param analysisCenterID the analysis center ID to set
*/
public void setAnalysisCenterID(final String analysisCenterID) {
this.analysisCenterID = analysisCenterID;
}
/** Getter for the analysis center name.
* @return the analysis center name
*/
public String getAnalysisCenterName() {
return analysisCenterName;
}
/** Setter for the analysis center name.
* @param analysisCenterName the analysis center name to set
*/
public void setAnalysisCenterName(final String analysisCenterName) {
this.analysisCenterName = analysisCenterName;
}
/** Getter for the reference clocks.
* @return the time span map of the different refence clocks
*/
public TimeSpanMap<List<ReferenceClock>> getReferenceClocks() {
return referenceClocks;
}
/** Add a list of reference clocks which will be used after a specified date.
* If the reference map has not been already created, it will be.
* @param referenceClockList the reference clock list
* @param startDate start date of list validity
* @param endDate end date of validity
*/
public void addReferenceClockList(final List<ReferenceClock> referenceClockList,
final AbsoluteDate startDate, final AbsoluteDate endDate) {
referenceClocks.addValidBetween(referenceClockList, startDate, endDate);
}
/** Getter for the different observation type for each satellite system.
* @return the map of the different observation type per satellite system
*/
public Map<SatelliteSystem, List<ObservationType>> getSystemObservationTypes() {
return Collections.unmodifiableMap(systemObservationTypes);
}
/** Add an observation type for a specified satellite system.
* @param satSystem the satellite system to add observation type
* @param observationType the system observation type to set
*/
public void addSystemObservationType(final SatelliteSystem satSystem,
final ObservationType observationType) {
final List<ObservationType> list;
synchronized (systemObservationTypes) {
list = systemObservationTypes.computeIfAbsent(satSystem, s -> new ArrayList<>());
}
list.add(observationType);
}
/** Get the number of observation types for a given system.
* @param system the satellite system to consider
* @return the number of observation types for a given system
*/
public int numberOfObsTypes(final SatelliteSystem system) {
if (systemObservationTypes.containsKey(system)) {
return systemObservationTypes.get(system).size();
} else {
return 0;
}
}
/** Getter for the different clock data types.
* @return the list of the different clock data types
*/
public List<ClockDataType> getClockDataTypes() {
return Collections.unmodifiableList(clockDataTypes);
}
/** Add a clock data types.
* @param clockDataType the clock data types to add
*/
public void addClockDataType(final ClockDataType clockDataType) {
clockDataTypes.add(clockDataType);
}
/** Get the number of different clock data types in the file.
* @return the number of different clock data types
*/
public int getNumberOfClockDataTypes() {
return clockDataTypes.size();
}
/** Set the Number of leap seconds separating UTC and TAI.
* @param leapSecondsTAI Number of leap seconds separating UTC and TAI
*/
public void setLeapSecondsTAI(final int leapSecondsTAI) {
this.leapSecondsTAI = leapSecondsTAI;
}
/** Get the Number of leap seconds separating UTC and TAI.
* @return Number of leap seconds separating UTC and TAI
*/
public int getLeapSecondsTAI() {
return leapSecondsTAI;
}
/** Get the reference frame for the station positions.
* @return the reference frame for station positions
*/
public Frame getFrame() {
return frame;
}
/** Set the reference frame for the station positions.
* @param frame reference frame for station positions
*/
public void setFrame(final Frame frame) {
this.frame = frame;
}
/** Getter for the frame name.
* @return the frame name
*/
public String getFrameName() {
return frameName;
}
/** Setter for the frame name.
* @param frameName the frame name to set
*/
public void setFrameName(final String frameName) {
this.frameName = frameName;
}
/** Add a new satellite with a given identifier to the list of stored satellites.
* @param satId the satellite identifier
*/
public void addSatellite(final SatInSystem satId) {
// only add satellites which have not been added before
if (!satellites.contains(satId)) {
satellites.add(satId);
// check if we have only one satellite system or mixed systems
if (mergedSystems == null) {
mergedSystems = satId.getSystem();
} else if (satId.getSystem() != mergedSystems) {
mergedSystems = SatelliteSystem.MIXED;
}
}
}
/** Get the merged satellites systems.
* @return merged satellites systems
* @since 14.0
*/
SatelliteSystem getMergedSystem() {
return mergedSystems;
}
/** Add a new receiver to the list of stored receivers.
* @param receiver the receiver
*/
public void addReceiver(final Receiver receiver) {
boolean notInList = true;
for (Receiver rec : receivers) {
if (rec.getDesignator().equals(receiver.getDesignator())) {
notInList = false;
break;
}
}
// only add satellites which have not been added before
if (notInList) {
receivers.add(receiver);
}
}
/** Get the number of receivers that are considered in the file.
* @return the number of receivers that are considered in the file
*/
public int getNumberOfReceivers() {
return receivers.size();
}
/** Get the number of satellites that are considered in the file.
* @return the number of satellites that are considered in the file
*/
public int getNumberOfSatellites() {
return satellites.size();
}
/** Getter for the receivers.
* @return the list of the receivers
*/
public List<Receiver> getReceivers() {
return Collections.unmodifiableList(receivers);
}
/** Getter for the satellites.
* @return the list of the satellites
*/
public List<SatInSystem> getSatellites() {
return Collections.unmodifiableList(satellites);
}
/** {@inheritDoc} */
@Override
public void checkType(final String line, final String name) {
checkType(line, getFormatVersion() < 3.04 ? 20 : 21, name);
}
/** {@inheritDoc} */
@Override
public int getLabelIndex() {
return getFormatVersion() < 3.04 ? LABEL_INDEX_300_302 : LABEL_INDEX_304_PLUS;
}
/** {@inheritDoc} */
@Override
public boolean matchFound(final Label label, final String line) {
// the position of the labels changes depending on version
if (label == CommonLabel.VERSION) {
// we are parsing the line RINEX VERSION / TYPE itself, the version is not known yet
// so we try both positions
return label.matches(line.substring(LABEL_INDEX_300_302).trim()) ||
label.matches(line.substring(LABEL_INDEX_304_PLUS).trim());
} else {
return label.matches(line.substring(getLabelIndex()).trim());
}
}
}