OMMFile.java

/* Copyright 2002-2016 CS Systèmes d'Information
 * Licensed to CS Systèmes d'Information (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.ccsds;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.math3.util.FastMath;
import org.orekit.errors.OrekitException;
import org.orekit.files.general.OrbitFile;
import org.orekit.orbits.CartesianOrbit;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;

/**
 * This class gathers the informations present in the Orbital Mean-Elements Message (OMM),
 * and contains methods to generate a {@link CartesianOrbit}, a {@link KeplerianOrbit},
 * a {@link SpacecraftState} and, eventually, a {@link TLE}.
 * @author sports
 * @since 6.1
 */
public class OMMFile extends OGMFile {

    /** Meta-data. */
    private final OMMMetaData metaData;

    /** Mean motion (the Keplerian Mean motion in revolutions per day). To be used instead of semi-major
     * axis if MEAN_ELEMENT_THEORY = SGP/SGP4. */
    private double meanMotion;

    /** Ephemeris Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the coding for
     * the EPHEMERIS_TYPE keyword: 1 = SGP, 2 = SGP4, 3 = SDP4, 4 = SGP8, 5 = SDP8. Default value = 0.
     */
    private int ephemerisType;

    /** Classification Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the
     *  following coding for the CLASSIFICATION_TYPE keyword: U = unclassified, S = secret. Default value = U.
     */
    private char classificationType;

    /** NORAD Catalog Number ("Satellite Number"), an integer of up to nine digits. */
    private Integer noradID;

    /** Element set number for this satellite, only required if MEAN_ELEMENT_THEORY = SGP/SGP4.
     * Normally incremented sequentially, but may be out of sync if it is generated from a backup source.
     * Used to distinguish different TLEs, and therefore only meaningful if TLE based data is being exchanged. */
    private String elementSetNo;

    /** Revolution Number, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
    private int revAtEpoch;

    /** SGP/SGP4 drag-like coefficient (in units 1/[Earth radii]), only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
    private Double bStar;

    /** First Time Derivative of the Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
    private Double meanMotionDot;

    /** Second Time Derivative of Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
    private Double meanMotionDotDot;

    /** TLE related parameters comments. The list contains a string for each line of comment. */
    private List<String> dataTleRelatedParametersComment;

    /** Create a new OMM file object. */
    OMMFile() {
        metaData = new OMMMetaData(this);
    };

    /** Get the meta data.
     * @return meta data
     */
    @Override
    public OMMMetaData getMetaData() {
        return metaData;
    }

    /** Get the orbit mean motion.
     * @return the orbit mean motion
     */
    public double getMeanMotion() {
        return meanMotion;
    }

    /** Set the orbit mean motion.
     * @param motion the mean motion to be set
     */
    void setMeanMotion(final double motion) {
        this.meanMotion = motion;
    }

    /** Get the ephemeris type.
     * @return the ephemerisType
     */
    public int getEphemerisType() {
        return ephemerisType;
    }

    /** Set the ephemeris type.
     * @param ephemerisType the ephemeris type to be set
     */
    void setEphemerisType(final int ephemerisType) {
        this.ephemerisType = ephemerisType;
    }

    /** Get the classification type.
     * @return the classificationType
     */
    public char getClassificationType() {
        return classificationType;
    }

    /** Set the classification type.
     * @param classificationType the classification type to be set
     */
    void setClassificationType(final char classificationType) {
        this.classificationType = classificationType;
    }

    /** Get the NORAD Catalog Number ("Satellite Number").
     * @return the NORAD Catalog Number
     */
    public Integer getNoradID() {
        return noradID;
    }

    /** Set the NORAD Catalog Number ("Satellite Number").
     * @param noradID the element set number to be set
     */
    void setNoradID(final Integer noradID) {
        this.noradID = noradID;
    }

    /** Get the element set number for this satellite.
     * @return the element set number for this satellite
     */
    public String getElementSetNumber() {
        return elementSetNo;
    }

    /** Set the element set number for this satellite.
     * @param elementSetNo the element set number to be set
     */
    void setElementSetNo(final String elementSetNo) {
        this.elementSetNo = elementSetNo;
    }

    /** Get the revolution rumber.
     * @return the revolution rumber
     */
    public int getRevAtEpoch() {
        return revAtEpoch;
    }

    /** Set the revolution rumber.
     * @param revAtEpoch the Revolution Number to be set
     */
    void setRevAtEpoch(final int revAtEpoch) {
        this.revAtEpoch = revAtEpoch;
    }

    /** Get the SGP/SGP4 drag-like coefficient.
     * @return the SGP/SGP4 drag-like coefficient
     */
    public double getBStar() {
        return bStar;
    }

    /** Set the SGP/SGP4 drag-like coefficient.
     * @param bStar the SGP/SGP4 drag-like coefficient to be set
     */
    void setbStar(final double bStar) {
        this.bStar = bStar;
    }

    /** Get the first time derivative of the mean motion.
     * @return the first time derivative of the mean motion
     */
    public double getMeanMotionDot() {
        return meanMotionDot;
    }

    /** Set the first time derivative of the mean motion.
     * @param meanMotionDot the first time derivative of the mean motion to be set
     */
    void setMeanMotionDot(final double meanMotionDot) {
        this.meanMotionDot = meanMotionDot;
    }

    /** Get the second time derivative of the mean motion.
     * @return the second time derivative of the mean motion
     */
    public double getMeanMotionDotDot() {
        return meanMotionDotDot;
    }

    /** Set the second time derivative of the mean motion.
     * @param meanMotionDotDot the second time derivative of the mean motion to be set
     */
    void setMeanMotionDotDot(final double meanMotionDotDot) {
        this.meanMotionDotDot = meanMotionDotDot;
    }

    /** Get the comment for TLE related parameters.
     * @return comment for TLE related parameters
     */
    public List<String> getTLERelatedParametersComment() {
        return Collections.unmodifiableList(dataTleRelatedParametersComment);
    }

    /** Set the comment for TLE related parameters.
     * @param comment comment to set
     */
    void setTLERelatedParametersComment(final List<String> comment) {
        dataTleRelatedParametersComment = new ArrayList<String>(comment);
    }

    /** {@inheritDoc} */
    @Override
    public String getCoordinateSystem() {
        return metaData.getFrame().toString();
    }

    /** {@inheritDoc} */
    @Override
    public OrbitFile.TimeSystem getTimeSystem() {
        return metaData.getTimeSystem();
    }

    /** Generate a {@link KeplerianOrbit} based on the OMM mean keplerian elements.
     * If the reference frame is not pseudo-inertial, an exception is raised.
     * @return the {@link KeplerianOrbit} generated from the OMM information
     * @exception OrekitException if the reference frame is not pseudo-inertial or if the central body
     * gravitational coefficient cannot be retrieved from the OMM
     */
    public KeplerianOrbit generateKeplerianOrbit() throws OrekitException {
        setMuUsed();
        final double a;
        if (Double.isNaN(getA())) {
            a = FastMath.cbrt(getMuUsed() / (meanMotion * meanMotion));
        } else {
            a = getA();
        }
        return new KeplerianOrbit(a, getE(), getI(), getPa(), getRaan(), getAnomaly(),
                                  PositionAngle.MEAN, metaData.getFrame(), getEpoch(), getMuUsed());
    }

    /** Generate a {@link CartesianOrbit} from the {@link KeplerianOrbit}.
     * @return the {@link CartesianOrbit} generated from the OPM information
     * @throws OrekitException if the Keplerian Orbit cannot be generated
     */
    public CartesianOrbit generateCartesianOrbit() throws OrekitException {
        return new CartesianOrbit(generateKeplerianOrbit());
    }

    /** Generate spacecraft state from the {@link KeplerianOrbit} generated by generateKeplerianOrbit.
     *  Raises an exception if OMM doesn't contain spacecraft mass information.
     * @return the spacecraft state of the OMM
     * @exception OrekitException if there is no spacecraft mass associated with the OMM
     */
    public SpacecraftState generateSpacecraftState()
        throws OrekitException {
        return new SpacecraftState(generateKeplerianOrbit(), getMass());
    }

    /** Generate TLE from OMM file. Launch Year, Launch Day and Launch Piece are not present in the
     * OMM file, they have to be set manually by the user with the AdditionalData static class.
     * @return the tle
     */
    public TLE generateTLE() {
        return new TLE(noradID, classificationType,
                       metaData.getLaunchYear(), metaData.getLaunchNumber(), metaData.getLaunchPiece(),
                       ephemerisType, Integer.parseInt(elementSetNo), getEpoch(),
                       meanMotion, meanMotionDot, meanMotionDotDot,
                       getE(), getI(), getPa(), getRaan(), getAnomaly(), revAtEpoch, bStar);
    }

    public static class OMMMetaData extends ODMMetaData {

        /** Description of the Mean Element Theory. Indicates the proper method to employ
         * to propagate the state. */
        private String meanElementTheory;

        /** Create a new meta-data.
         * @param ommFile OMM file to which these meta-data belongs
         */
        OMMMetaData(final OMMFile ommFile) {
            super(ommFile);
        }

        /** Get the description of the Mean Element Theory.
         * @return the mean element theory
         */
        public String getMeanElementTheory() {
            return meanElementTheory;
        }

        /** Set the description of the Mean Element Theory.
         * @param meanElementTheory the mean element theory to be set
         */
        void setMeanElementTheory(final String meanElementTheory) {
            this.meanElementTheory = meanElementTheory;
        }

    }

}