SinexParseInfo.java

/* Copyright 2002-2024 CS GROUP
 * 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.sinex;

import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.models.earth.displacement.PsdCorrection;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScales;

import java.util.HashMap;
import java.util.Map;

/** Parse information for Solution INdependent EXchange (SINEX) files.
 * @author Bryan Cazabonne
 * @author Luc Maisonobe
 * @since 13.0
 */
public class SinexParseInfo extends ParseInfo<Sinex> {

    /** Station data. */
    private final Map<String, Station> stations;

    /** Earth Orientation Parameters data. */
    private final Map<AbsoluteDate, SinexEopEntry> eop;

    /** Station position X coordinate. */
    private double px;

    /** Station position Y coordinate. */
    private double py;

    /** Station position Z coordinate. */
    private double pz;

    /** Station velocity X coordinate. */
    private double vx;

    /** Station velocity Y coordinate. */
    private double vy;

    /** Station velocity Z coordinate. */
    private double vz;

    /** Correction axis. */
    private PsdCorrection.Axis axis;

    /** Correction time evolution. */
    private PsdCorrection.TimeEvolution evolution;

    /** Correction amplitude. */
    private double amplitude;

    /** Correction relaxation time. */
    private double relaxationTime;

    /** Simple constructor.
     * @param timeScales time scales
     */
    SinexParseInfo(final TimeScales timeScales) {
        super(timeScales);
        this.stations = new HashMap<>();
        this.eop = new HashMap<>();
    }

    /** {@inheritDoc} */
    @Override
    void newSource(final String name) {
        super.newSource(name);
        resetPosition();
        resetVelocity();
        resetPsdCorrection();
    }

    /** Add station.
     * @param station station to add
     */
    void addStation(final Station station) {
        stations.putIfAbsent(station.getSiteCode(), station);
    }

    /** Get station from current line.
     * @param index index of station in current line
     * @return station
     */
    Station getCurrentLineStation(final int index) {
        return stations.get(parseString(index, 4));
    }

    /** Get start date from current line.
     * @return start date
     */
    AbsoluteDate getCurrentLineStartDate() {
        return stringEpochToAbsoluteDate(parseString(16, 12), true);
    }

    /** Get end date from current line.
     * @return end date
     */
    AbsoluteDate getCurrentLineEndDate() {
        return stringEpochToAbsoluteDate(parseString(29, 12), false);
    }

    /** Set station position X coordinate.
     * @param x station position X coordinate
     * @param station station
     * @param epoch   coordinates epoch
     */
    void setPx(final double x, final Station station, final AbsoluteDate epoch) {
        this.px = x;
        finalizePositionIfComplete(station, epoch);
    }

    /** Set station position Y coordinate.
     * @param y station position Y coordinate
     * @param station station
     * @param epoch   coordinates epoch
     */
    void setPy(final double y, final Station station, final AbsoluteDate epoch) {
        this.py = y;
        finalizePositionIfComplete(station, epoch);
    }

    /** Set station position Z coordinate.
     * @param z station position Z coordinate
     * @param station station
     * @param epoch   coordinates epoch
     */
    void setPz(final double z, final Station station, final AbsoluteDate epoch) {
        this.pz = z;
        finalizePositionIfComplete(station, epoch);
    }

    /** Finalize station position if complete.
     * @param station station
     * @param epoch   coordinates epoch
     */
    private void finalizePositionIfComplete(final Station station, final AbsoluteDate epoch) {
        if (!Double.isNaN(px + py + pz)) {
            // all coordinates are available, position is complete
            station.setEpoch(epoch);
            station.setPosition(new Vector3D(px, py, pz));
            resetPosition();
        }
    }

    /** Reset position.
     */
    void resetPosition() {
        px = Double.NaN;
        py = Double.NaN;
        pz = Double.NaN;
    }

    /** Set station velocity X coordinate.
     * @param x station velocity X coordinate
     * @param station station
     */
    void setVx(final double x, final Station station) {
        this.vx = x;
        finalizeVelocityIfComplete(station);
    }

    /** Set station velocity Y coordinate.
     * @param y station velocity Y coordinate
     * @param station station
     */
    void setVy(final double y, final Station station) {
        this.vy = y;
        finalizeVelocityIfComplete(station);
    }

    /** Set station velocity Z coordinate.
     * @param z station velocity Z coordinate
     * @param station station
     */
    void setVz(final double z, final Station station) {
        this.vz = z;
        finalizeVelocityIfComplete(station);
    }

    /** Finalize station velocity if complete.
     * @param station station
     */
    private void finalizeVelocityIfComplete(final Station station) {
        if (!Double.isNaN(vx + vy + vz)) {
            // all coordinates are available, velocity is complete
            station.setVelocity(new Vector3D(vx, vy, vz));
            resetVelocity();
        }
    }

    /** Reset velocity.
     */
    void resetVelocity() {
        vx = Double.NaN;
        vy = Double.NaN;
        vz = Double.NaN;
    }

    /** Set correction axis.
     * @param axis correction axis
     */
    void setAxis(final PsdCorrection.Axis axis) {
        this.axis = axis;
    }

    /** Set correction time evolution.
     * @param evolution correction time evolution
     */
    void setEvolution(final PsdCorrection.TimeEvolution evolution) {
        this.evolution = evolution;
    }

    /** Set correction amplitude.
     * @param correctionAmplitude correction amplitude
     * @param station station
     * @param epoch   coordinates epoch
     */
    void setAmplitude(final double correctionAmplitude, final Station station, final AbsoluteDate epoch) {
        this.amplitude = correctionAmplitude;
        finalizePsdCorrectionIfComplete(station, epoch);
    }

    /** Set correction relaxation time.
     * @param correctionRelaxationTime correction relaxation time
     * @param station station
     * @param epoch   coordinates epoch
     */
    void setRelaxationTime(final double correctionRelaxationTime,
                           final Station station, final AbsoluteDate epoch) {
        this.relaxationTime = correctionRelaxationTime;
        finalizePsdCorrectionIfComplete(station, epoch);
    }

    /** Finalize a Post-Seismic Deformation correction model if complete.
     * @param station station
     * @param epoch   coordinates epoch
     */
    private void finalizePsdCorrectionIfComplete(final Station station, final AbsoluteDate epoch) {
        if (!Double.isNaN(amplitude + relaxationTime)) {
            // both amplitude and relaxation time are available, correction is complete
            final PsdCorrection correction = new PsdCorrection(axis, evolution, epoch, amplitude, relaxationTime);
            station.addPsdCorrectionValidAfter(correction, epoch);
            resetPsdCorrection();
        }
    }

    /** Reset Post-Seismic Deformation correction model.
     */
    private void resetPsdCorrection() {
        axis           = null;
        evolution      = null;
        amplitude      = Double.NaN;
        relaxationTime = Double.NaN;
    }

    /** Create EOP entry.
     * @param date EOP date
     * @return EOP entry at date, creating it if needed
     */
    SinexEopEntry createEOPEntry(final AbsoluteDate date) {
        return eop.computeIfAbsent(date, SinexEopEntry::new);
    }

    /** {@inheritDoc} */
    @Override
    protected Sinex build() {
        return new Sinex(getTimeScales(), getCreationDate(), getStartDate(), getEndDate(), stations, eop);
    }

}