OrekitAttitudeEphemerisFile.java

  1. /* Copyright 2002-2020 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.general;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.concurrent.ConcurrentHashMap;

  23. import org.hipparchus.geometry.euclidean.threed.RotationOrder;
  24. import org.orekit.annotation.DefaultDataContext;
  25. import org.orekit.bodies.CelestialBody;
  26. import org.orekit.data.DataContext;
  27. import org.orekit.errors.OrekitIllegalArgumentException;
  28. import org.orekit.errors.OrekitMessages;
  29. import org.orekit.files.ccsds.AEMAttitudeType;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.propagation.SpacecraftState;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.time.TimeScale;
  34. import org.orekit.utils.AngularDerivativesFilter;
  35. import org.orekit.utils.TimeStampedAngularCoordinates;

  36. /**
  37.  * A class for encapsulating Orekit propagators within an {@link AttitudeEphemerisFile}
  38.  * complaint object that makes for easy serialization to external ephemeris
  39.  * formats like AEM.
  40.  *
  41.  * @author Raphaël Fermé
  42.  * @since 10.3
  43.  *
  44.  */
  45. public class OrekitAttitudeEphemerisFile implements AttitudeEphemerisFile {

  46.     /** Hashmap of satellite ephemeris. **/
  47.     private final Map<String, OrekitSatelliteAttitudeEphemeris> satellites;

  48.     /**
  49.      * Standard default constructor.
  50.      */
  51.     public OrekitAttitudeEphemerisFile() {
  52.         this.satellites = new ConcurrentHashMap<>();
  53.     }

  54.     /** {@inheritDoc} */
  55.     @Override
  56.     public Map<String, OrekitSatelliteAttitudeEphemeris> getSatellites() {
  57.         return Collections.unmodifiableMap(satellites);
  58.     }

  59.     /**
  60.      * Adds a new satellite to this object.
  61.      *
  62.      * @param id
  63.      *            ID to use for this satellite
  64.      * @return the new satellite object
  65.      */
  66.     public OrekitSatelliteAttitudeEphemeris addSatellite(final String id) {
  67.         final OrekitSatelliteAttitudeEphemeris newSat = new OrekitSatelliteAttitudeEphemeris(id);
  68.         this.satellites.put(id, newSat);
  69.         return newSat;
  70.     }

  71.     /**
  72.      * Inner class of {@link OrekitAttitudeEphemerisFile} that defines the
  73.      * {@link OrekitSatelliteAttitudeEphemeris} corresponding object for this ephemeris type.
  74.      *
  75.      */
  76.     public static class OrekitSatelliteAttitudeEphemeris implements SatelliteAttitudeEphemeris {

  77.         /** Default interpolation sample size if it is not specified. **/
  78.         public static final String DEFAULT_INTERPOLATION_METHOD = "LINEAR";

  79.         /** Default interpolation sample size if it is not specified. **/
  80.         public static final int DEFAULT_INTERPOLATION_SIZE = 2;

  81.         /** Default quaternion order if it is not specified. **/
  82.         public static final String DEFAULT_ATTITUDE_TYPE = "QUATERNION";

  83.         /** Default quaternion order if it is not specified. **/
  84.         public static final boolean DEFAULT_IS_FIRST = false;

  85.         /** Default rotation order if it is not specified. **/
  86.         public static final RotationOrder DEFAULT_ROTATION_ORDER = RotationOrder.ZYX;

  87.         /** Default reference frame A name if it is not specified. **/
  88.         public static final String DEFAULT_REF_FRAME_A = "EME2000";

  89.         /** Default reference frame B name if it is not specified. **/
  90.         public static final String DEFAULT_REF_FRAME_B = "SC_BODY_1";

  91.         /** Default attitude rotation direction if it is not specified. **/
  92.         public static final String DEFAULT_ATTITUDE_DIR = "A2B";

  93.         /** ID of the space object encapsulated here. **/
  94.         private final String id;

  95.         /** Earliest date of this file. **/
  96.         private AbsoluteDate startDate;

  97.         /** Latest date of this file. **/
  98.         private AbsoluteDate stopDate;

  99.         /** List of segments in the file. **/
  100.         private final List<OrekitAttitudeEphemerisSegment> segments;

  101.         /**
  102.          * Standard constructor for building the satellite Ephemeris object.
  103.          *
  104.          * @param id
  105.          *            the ID of the space object for this data
  106.          */
  107.         public OrekitSatelliteAttitudeEphemeris(final String id) {
  108.             this.id = id;
  109.             this.segments = new ArrayList<OrekitAttitudeEphemerisSegment>();
  110.         }

  111.         /** {@inheritDoc} */
  112.         @Override
  113.         public String getId() {
  114.             return id;
  115.         }

  116.         /** {@inheritDoc} */
  117.         @Override
  118.         public List<? extends AttitudeEphemerisSegment> getSegments() {
  119.             return Collections.unmodifiableList(this.segments);
  120.         }

  121.         /** {@inheritDoc} */
  122.         @Override
  123.         public AbsoluteDate getStart() {
  124.             return this.startDate;
  125.         }

  126.         /** {@inheritDoc} */
  127.         @Override
  128.         public AbsoluteDate getStop() {
  129.             return this.stopDate;
  130.         }

  131.         /**
  132.          * Injects pre-computed satellite states into this attitude ephemeris file object,
  133.          * returning the generated {@link OrekitAttitudeEphemerisSegment} that has been stored
  134.          * internally. Defaults the celestial body to earth, time scale to UTC, the interpolation
  135.          * size and method, the attitude type, the reference frames to default values.
  136.          *
  137.          * <p>This method uses the {@link DataContext#getDefault() default data context}.
  138.          *
  139.          * @param states
  140.          *            a list of {@link SpacecraftState} that will comprise this
  141.          *            new unit.
  142.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  143.          */
  144.         @DefaultDataContext
  145.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states) {
  146.             return this.addNewSegment(states, DEFAULT_INTERPOLATION_METHOD, DEFAULT_INTERPOLATION_SIZE);
  147.         }

  148.         /**
  149.          * Injects pre-computed satellite states into this attitude ephemeris file object,
  150.          * returning the generated {@link OrekitAttitudeEphemerisSegment} that has been stored
  151.          * internally. Defaults the celestial body to earth, time scale to UTC, the attitude type,
  152.          * the reference frames to default values.
  153.          *
  154.          * <p>This method uses the {@link DataContext#getDefault() default data context}.
  155.          *
  156.          * @param states
  157.          *          a list of {@link SpacecraftState} that will comprise this
  158.          *          new unit
  159.          * @param interpolationMethod
  160.          *          the interpolation method that should be used when processed
  161.          *          by another system
  162.          * @param interpolationSamples
  163.          *          the number of interpolation samples that should be used
  164.          *          when processed by another system
  165.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  166.          */
  167.         @DefaultDataContext
  168.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states,
  169.                                                 final String interpolationMethod, final int interpolationSamples) {
  170.             return this.addNewSegment(states, interpolationMethod, interpolationSamples, DEFAULT_ATTITUDE_TYPE,
  171.                                       DEFAULT_IS_FIRST, DEFAULT_ROTATION_ORDER);
  172.         }

  173.         /**
  174.          * Injects pre-computed satellite states into this attitude ephemeris file object,
  175.          * returning the generated {@link OrekitAttitudeEphemerisSegment} that has been stored
  176.          * internally. Defaults the celestial body to earth, time scale to UTC, the reference
  177.          * frames to default values.
  178.          *
  179.          * <p>This method uses the {@link DataContext#getDefault() default data context}.
  180.          *
  181.          * @param states
  182.          *          a list of {@link SpacecraftState} that will comprise this
  183.          *          new unit
  184.          * @param interpolationMethod
  185.          *          the interpolation method that should be used when processed
  186.          *          by another system
  187.          * @param interpolationSamples
  188.          *          the number of interpolation samples that should be used
  189.          *          when processed by another system
  190.          * @param attitudeType
  191.          *          type of attitude for the attitude ephemeris segment. Must correspond
  192.          *          to the names in {@link AEMAttitudeType} enumerate.
  193.          * @param isFirst
  194.          *          flag for placement of the scalar part of the quaternion
  195.          *          (used if quaternions are chosen in the attitude type)
  196.          * @param rotationOrder
  197.          *          the rotation order for Euler angles (used if Euler angles
  198.          *          are chosen in the attitude type)
  199.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  200.          */
  201.         @DefaultDataContext
  202.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states, final String interpolationMethod,
  203.                                                             final int interpolationSamples, final String attitudeType,
  204.                                                             final boolean isFirst, final RotationOrder rotationOrder) {
  205.             return this.addNewSegment(states, interpolationMethod, interpolationSamples, attitudeType,
  206.                                       isFirst, rotationOrder, DEFAULT_REF_FRAME_A, DEFAULT_REF_FRAME_B,
  207.                                       DEFAULT_ATTITUDE_DIR);
  208.         }

  209.         /**
  210.          * Injects pre-computed satellite states into this attitude ephemeris file object,
  211.          * returning the generated {@link OrekitAttitudeEphemerisSegment} that has been stored
  212.          * internally. Defaults the celestial body to earth, time scale to UTC.
  213.          *
  214.          * <p>This method uses the {@link DataContext#getDefault() default data context}.
  215.          *
  216.          * @param states
  217.          *          a list of {@link SpacecraftState} that will comprise this
  218.          *          new unit
  219.          * @param interpolationMethod
  220.          *          the interpolation method that should be used when processed
  221.          *          by another system
  222.          * @param interpolationSamples
  223.          *          the number of interpolation samples that should be used
  224.          *          when processed by another system
  225.          * @param attitudeType
  226.          *          type of attitude for the attitude ephemeris segment. Must correspond
  227.          *          to the names in {@link AEMAttitudeType} enumerate.
  228.          * @param isFirst
  229.          *          flag for placement of the scalar part of the quaternion
  230.          *          (used if quaternions are chosen in the attitude type)
  231.          * @param rotationOrder
  232.          *          the rotation order for Euler angles (used if Euler angles
  233.          *          are chosen in the attitude type)
  234.          * @param refFrameA
  235.          *          name of reference frame A
  236.          * @param refFrameB
  237.          *          name of reference frame B
  238.          * @param attitudeDir
  239.          *          rotation direction of the attitude: "A2B" or "B2A"
  240.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  241.          */
  242.         @DefaultDataContext
  243.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states, final String interpolationMethod,
  244.                                                             final int interpolationSamples, final String attitudeType,
  245.                                                             final boolean isFirst, final RotationOrder rotationOrder,
  246.                                                             final String refFrameA, final String refFrameB,
  247.                                                             final String attitudeDir) {
  248.             return this.addNewSegment(states, interpolationMethod, interpolationSamples, attitudeType,
  249.                                       isFirst, rotationOrder, refFrameA, refFrameB,
  250.                                       attitudeDir, DataContext.getDefault().getCelestialBodies().getEarth());
  251.         }

  252.         /**
  253.          * Injects pre-computed satellite states into this attitude ephemeris file object,
  254.          * returning the generated {@link OrekitAttitudeEphemerisSegment} that has been stored
  255.          * internally. Defaults the time scale to UTC.
  256.          *
  257.          * <p>This method uses the {@link DataContext#getDefault() default data context}.
  258.          *
  259.          * @param states
  260.          *          a list of {@link SpacecraftState} that will comprise this
  261.          *          new unit
  262.          * @param interpolationMethod
  263.          *          the interpolation method that should be used when processed
  264.          *          by another system
  265.          * @param interpolationSamples
  266.          *          the number of interpolation samples that should be used
  267.          *          when processed by another system
  268.          * @param attitudeType
  269.          *          type of attitude for the attitude ephemeris segment. Must correspond
  270.          *          to the names in {@link AEMAttitudeType} enumerate.
  271.          * @param isFirst
  272.          *          flag for placement of the scalar part of the quaternion
  273.          *          (used if quaternions are chosen in the attitude type)
  274.          * @param rotationOrder
  275.          *          the rotation order for Euler angles (used if Euler angles
  276.          *          are chosen in the attitude type)
  277.          * @param refFrameA
  278.          *          name of reference frame A
  279.          * @param refFrameB
  280.          *          name of reference frame B
  281.          * @param attitudeDir
  282.          *          rotation direction of the attitude: "A2B" or "B2A"
  283.          * @param body
  284.          *          the celestial body from which the frames are defined
  285.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  286.          */
  287.         @DefaultDataContext
  288.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states, final String interpolationMethod,
  289.                                                             final int interpolationSamples, final String attitudeType,
  290.                                                             final boolean isFirst, final RotationOrder rotationOrder,
  291.                                                             final String refFrameA, final String refFrameB,
  292.                                                             final String attitudeDir, final CelestialBody body) {
  293.             return this.addNewSegment(states, interpolationMethod, interpolationSamples, attitudeType,
  294.                                       isFirst, rotationOrder, refFrameA, refFrameB, attitudeDir, body,
  295.                                       DataContext.getDefault().getTimeScales().getUTC());
  296.         }

  297.         /**
  298.          * Injects pre-computed satellite states into this attitude ephemeris file
  299.          * object, returning the generated {@link OrekitAttitudeEphemerisSegment} that
  300.          * has been stored internally.
  301.          *
  302.          * @param states
  303.          *          a list of {@link SpacecraftState} that will comprise this
  304.          *          new unit
  305.          * @param body
  306.          *          the celestial body from which the frames are defined
  307.          * @param refFrameA
  308.          *          name of reference frame A
  309.          * @param refFrameB
  310.          *          name of reference frame B
  311.          * @param attitudeDir
  312.          *          rotation direction of the attitude: "A2B" or "B2A"
  313.          * @param attitudeType
  314.          *          type of attitude for the attitude ephemeris segment.
  315.          * @param isFirst
  316.          *          flag for placement of the scalar part of the quaternion
  317.          *          (used if quaternions are chosen in the attitude type)
  318.          * @param rotationOrder
  319.          *          the rotation order for Euler angles (used if Euler angles
  320.          *          are chosen in the attitude type)
  321.          * @param timeScale
  322.          *          the time scale used in the new segment.
  323.          * @param interpolationMethod
  324.          *          the interpolation method that should be used when processed
  325.          *          by another system
  326.          * @param interpolationSamples
  327.          *          the number of interpolation samples that should be used
  328.          *          when processed by another system
  329.          * @return the generated {@link OrekitAttitudeEphemerisSegment}
  330.          */
  331.         public OrekitAttitudeEphemerisSegment addNewSegment(final List<SpacecraftState> states, final String interpolationMethod,
  332.                                                             final int interpolationSamples, final String attitudeType,
  333.                                                             final boolean isFirst, final RotationOrder rotationOrder,
  334.                                                             final String refFrameA, final String refFrameB,
  335.                                                             final String attitudeDir, final CelestialBody body,
  336.                                                             final TimeScale timeScale) {
  337.             final int minimumSampleSize = 2;
  338.             if (states == null || states.size() == 0) {
  339.                 throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "states");
  340.             }

  341.             if (interpolationSamples < minimumSampleSize) {
  342.                 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA_FOR_INTERPOLATION,
  343.                         interpolationSamples);
  344.             }

  345.             final AbsoluteDate start = states.get(0).getDate();
  346.             final AbsoluteDate stop = states.get(states.size() - 1).getDate();

  347.             if (this.startDate == null || start.compareTo(this.startDate) < 0) {
  348.                 this.startDate = start;
  349.             }

  350.             if (this.stopDate == null || stop.compareTo(this.stopDate) > 0) {
  351.                 this.stopDate = stop;
  352.             }

  353.             final List<TimeStampedAngularCoordinates> attitudeDataLines = new ArrayList<TimeStampedAngularCoordinates>();
  354.             for (SpacecraftState state : states) {
  355.                 attitudeDataLines.add(state.getAttitude().getOrientation());
  356.             }

  357.             final OrekitAttitudeEphemerisSegment newSeg = new OrekitAttitudeEphemerisSegment(attitudeDataLines, body.getName(), refFrameA,
  358.                                                                         refFrameB, attitudeDir, attitudeType, isFirst, rotationOrder,
  359.                                                                         timeScale, interpolationMethod, interpolationSamples, states.get(0).getFrame());
  360.             this.segments.add(newSeg);
  361.             return newSeg;
  362.         }
  363.     }

  364.     public static class OrekitAttitudeEphemerisSegment implements AttitudeEphemerisSegment {

  365.         /** List of attitude data lines. */
  366.         private List<TimeStampedAngularCoordinates> attitudeDataLines;

  367.         /** The name of the frame center. **/
  368.         private final String frameCenterString;

  369.         /** The reference frame A specifier, as it appeared in the file. */
  370.         private String refFrameAString;

  371.         /** The reference frame B specifier, as it appeared in the file. */
  372.         private String refFrameBString;

  373.         /** Rotation direction of the attitude. */
  374.         private String attitudeDir;

  375.         /** The format of the data lines in the message. */
  376.         private String attitudeType;

  377.         /** The placement of the scalar portion of the quaternion (QC) in the attitude data. */
  378.         private boolean isFirst;

  379.         /** The rotation order. */
  380.         private RotationOrder rotationOrder;

  381.         /** The time scale identifier, as specified in the ephemeris file. **/
  382.         private final String timeScaleString;

  383.         /** The time scale for this segment. **/
  384.         private final TimeScale timeScale;

  385.         /** The interpolation method to be used. */
  386.         private String interpolationMethod;

  387.         /** The number of interpolation samples. */
  388.         private int interpolationSamples;

  389.         /** Enumerate for selecting which derivatives to use in {@link #attitudeDataLines} interpolation. */
  390.         private AngularDerivativesFilter angularDerivativesFilter;

  391.         /** Reference frame from which attitude is defined. */
  392.         private Frame referenceFrame;

  393.         /**
  394.          * Constructor for OrekitAttitudeEphemerisSegment.
  395.          *
  396.          * @param attitudeDataLines
  397.          *          attitude data lines for this segment.
  398.          * @param frameCenterString
  399.          *          the name of celestial body the frame is attached to.
  400.          * @param refFrameAString
  401.          *          the name of the reference frame A.
  402.          * @param refFrameBString
  403.          *          the name of the reference frame B.
  404.          * @param attitudeDir
  405.          *          the rotation direction of the attitude.
  406.          * @param attitudeType
  407.          *          the format of the attitude data.
  408.          * @param isFirst
  409.          *          true if QC is the first element in the attitude data.
  410.          * @param rotationOrder
  411.          *          the rotation order for Euler angles.
  412.          * @param timeScale
  413.          *          the time scale of these ephemerides data.
  414.          * @param interpolationMethod
  415.          *          the interpolation method to use.
  416.          * @param interpolationSamples
  417.          *          the number of samples to use during interpolation.
  418.          * @param referenceFrame
  419.          *          reference frame from which the attitude is defined
  420.          */
  421.         public OrekitAttitudeEphemerisSegment(final List<TimeStampedAngularCoordinates> attitudeDataLines, final String frameCenterString,
  422.                 final String refFrameAString, final String refFrameBString, final String attitudeDir, final String attitudeType,
  423.                 final boolean isFirst, final RotationOrder rotationOrder, final TimeScale timeScale,
  424.                 final String interpolationMethod, final int interpolationSamples,
  425.                 final Frame referenceFrame) {
  426.             this.attitudeDataLines        = attitudeDataLines;
  427.             this.frameCenterString        = frameCenterString;
  428.             this.refFrameAString          = refFrameAString;
  429.             this.refFrameBString          = refFrameBString;
  430.             this.attitudeDir              = attitudeDir;
  431.             this.attitudeType             = attitudeType;
  432.             this.isFirst                  = isFirst;
  433.             this.rotationOrder            = rotationOrder;
  434.             this.timeScaleString          = timeScale.getName();
  435.             this.timeScale                = timeScale;
  436.             this.interpolationMethod      = interpolationMethod;
  437.             this.interpolationSamples     = interpolationSamples;
  438.             this.referenceFrame           = referenceFrame;
  439.             this.angularDerivativesFilter = AEMAttitudeType.getAttitudeType(attitudeType).getAngularDerivativesFilter();
  440.         }

  441.         /** {@inheritDoc} */
  442.         @Override
  443.         public List<TimeStampedAngularCoordinates> getAngularCoordinates() {
  444.             return Collections.unmodifiableList(attitudeDataLines);
  445.         }

  446.         /** {@inheritDoc} */
  447.         @Override
  448.         public String getFrameCenterString() {
  449.             return frameCenterString;
  450.         }

  451.         /** {@inheritDoc} */
  452.         @Override
  453.         public String getRefFrameAString() {
  454.             return refFrameAString;
  455.         }

  456.         /** {@inheritDoc} */
  457.         @Override
  458.         public String getRefFrameBString() {
  459.             return refFrameBString;
  460.         }

  461.         /** {@inheritDoc} */
  462.         @Override
  463.         public Frame getReferenceFrame() {
  464.             return referenceFrame;
  465.         }

  466.         /** {@inheritDoc} */
  467.         @Override
  468.         public String getAttitudeDirection() {
  469.             return attitudeDir;
  470.         }

  471.         /** {@inheritDoc} */
  472.         @Override
  473.         public String getAttitudeType() {
  474.             return attitudeType;
  475.         }

  476.         /** {@inheritDoc} */
  477.         @Override
  478.         public boolean isFirst() {
  479.             return isFirst;
  480.         }

  481.         /** {@inheritDoc} */
  482.         @Override
  483.         public RotationOrder getRotationOrder() {
  484.             return rotationOrder;
  485.         }

  486.         /** {@inheritDoc} */
  487.         @Override
  488.         public String getTimeScaleString() {
  489.             return timeScaleString;
  490.         }

  491.         /** {@inheritDoc} */
  492.         @Override
  493.         public TimeScale getTimeScale() {
  494.             return timeScale;
  495.         }

  496.         /** {@inheritDoc} */
  497.         @Override
  498.         public AbsoluteDate getStart() {
  499.             return attitudeDataLines.get(0).getDate();
  500.         }

  501.         /** {@inheritDoc} */
  502.         @Override
  503.         public AbsoluteDate getStop() {
  504.             return attitudeDataLines.get(attitudeDataLines.size() - 1).getDate();
  505.         }

  506.         /** {@inheritDoc} */
  507.         @Override
  508.         public String getInterpolationMethod() {
  509.             return interpolationMethod;
  510.         }

  511.         /** {@inheritDoc} */
  512.         @Override
  513.         public int getInterpolationSamples() {
  514.             return interpolationSamples;
  515.         }

  516.         /** {@inheritDoc} */
  517.         @Override
  518.         public AngularDerivativesFilter getAvailableDerivatives() {
  519.             return angularDerivativesFilter;
  520.         }

  521.     }

  522. }