OEMWriter.java

  1. /* Copyright 2016 Applied Defense Solutions (ADS)
  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.  * ADS 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.ccsds;

  18. import java.io.IOException;
  19. import java.util.LinkedHashMap;
  20. import java.util.List;
  21. import java.util.Map;

  22. import org.orekit.errors.OrekitIllegalArgumentException;
  23. import org.orekit.errors.OrekitMessages;
  24. import org.orekit.files.ccsds.OEMFile.CovarianceMatrix;
  25. import org.orekit.files.ccsds.OEMFile.EphemeridesBlock;
  26. import org.orekit.files.ccsds.StreamingOemWriter.Segment;
  27. import org.orekit.files.general.EphemerisFile;
  28. import org.orekit.files.general.EphemerisFile.EphemerisSegment;
  29. import org.orekit.files.general.EphemerisFileWriter;
  30. import org.orekit.time.TimeScale;
  31. import org.orekit.utils.TimeStampedPVCoordinates;

  32. /**
  33.  * An OEM Writer class that can take in a general {@link EphemerisFile} object
  34.  * and export it as a valid OEM file.
  35.  *
  36.  * @author Hank Grabowski
  37.  * @author Evan Ward
  38.  * @since 9.0
  39.  * @see <a href="https://public.ccsds.org/Pubs/502x0b2c1.pdf">CCSDS 502.0-B-2 Orbit Data
  40.  *      Messages</a>
  41.  * @see <a href="https://public.ccsds.org/Pubs/500x0g4.pdf">CCSDS 500.0-G-4 Navigation
  42.  *      Data Definitions and Conventions</a>
  43.  * @see StreamingOemWriter
  44.  */
  45. public class OEMWriter implements EphemerisFileWriter {

  46.     /** Version number implemented. **/
  47.     public static final String CCSDS_OEM_VERS = "2.0";

  48.     /** Default interpolation method if the user specifies none. **/
  49.     public static final InterpolationMethod DEFAULT_INTERPOLATION_METHOD = InterpolationMethod.LAGRANGE;

  50.     /** Default originator field value if user specifies none. **/
  51.     public static final String DEFAULT_ORIGINATOR = "OREKIT";

  52.     /** The interpolation method for ephemeris data. */
  53.     private final InterpolationMethod interpolationMethod;

  54.     /** Originator name, usually the organization and/or country. **/
  55.     private final String originator;

  56.     /**
  57.      * Space object ID, usually an official international designator such as
  58.      * "1998-067A".
  59.      **/
  60.     private final String spaceObjectId;

  61.     /** Space object name, usually a common name for an object like "ISS". **/
  62.     private final String spaceObjectName;

  63.     /** Format for position ephemeris data output. */
  64.     private final String positionFormat;

  65.     /** Format for velocity ephemeris data output. */
  66.     private final String velocityFormat;

  67.     /**
  68.      * Standard default constructor that creates a writer with default
  69.      * configurations.
  70.      */
  71.     public OEMWriter() {
  72.         this(DEFAULT_INTERPOLATION_METHOD, DEFAULT_ORIGINATOR, null, null,
  73.              StreamingOemWriter.DEFAULT_POSITION_FORMAT,
  74.              StreamingOemWriter.DEFAULT_VELOCITY_FORMAT);
  75.     }

  76.     /**
  77.      * Constructor used to create a new OEM writer configured with the necessary
  78.      * parameters to successfully fill in all required fields that aren't part
  79.      * of a standard {@link EphemerisFile} object and using default formatting for
  80.      * {@link StreamingOemWriter#DEFAULT_POSITION_FORMAT position} and
  81.      * {@link StreamingOemWriter#DEFAULT_VELOCITY_FORMAT velocity} ephemeris data output.
  82.      *
  83.      * @param interpolationMethod
  84.      *            the interpolation method to specify in the OEM file
  85.      * @param originator
  86.      *            the originator field string
  87.      * @param spaceObjectId
  88.      *            the spacecraft ID
  89.      * @param spaceObjectName
  90.      *            the space object common name
  91.      */
  92.     public OEMWriter(final InterpolationMethod interpolationMethod, final String originator,
  93.             final String spaceObjectId, final String spaceObjectName) {
  94.         this(interpolationMethod, originator, spaceObjectId, spaceObjectName,
  95.                 StreamingOemWriter.DEFAULT_POSITION_FORMAT,
  96.                 StreamingOemWriter.DEFAULT_VELOCITY_FORMAT);
  97.     }

  98.     /**
  99.      * Constructor used to create a new OEM writer configured with the necessary
  100.      * parameters to successfully fill in all required fields that aren't part
  101.      * of a standard {@link EphemerisFile} object and user-defined position and
  102.      * velocity ephemeris data output {@link java.util.Formatter format}.
  103.      *
  104.      * @param interpolationMethod
  105.      *            the interpolation method to specify in the OEM file
  106.      * @param originator
  107.      *            the originator field string
  108.      * @param spaceObjectId
  109.      *            the spacecraft ID
  110.      * @param spaceObjectName
  111.      *            the space object common name
  112.      * @param positionFormat
  113.      *            format parameters for position ephemeris data output
  114.      * @param velocityFormat
  115.      *            format parameters for velocity ephemeris data output
  116.      */
  117.     public OEMWriter(final InterpolationMethod interpolationMethod, final String originator,
  118.             final String spaceObjectId, final String spaceObjectName,
  119.             final String positionFormat, final String velocityFormat) {
  120.         this.interpolationMethod = interpolationMethod;
  121.         this.originator = originator;
  122.         this.spaceObjectId = spaceObjectId;
  123.         this.spaceObjectName = spaceObjectName;
  124.         this.positionFormat = positionFormat;
  125.         this.velocityFormat = velocityFormat;
  126.     }

  127.     /** {@inheritDoc} */
  128.     @Override
  129.     public void write(final Appendable writer, final EphemerisFile ephemerisFile)
  130.             throws IOException {

  131.         if (writer == null) {
  132.             throw new OrekitIllegalArgumentException(OrekitMessages.NULL_ARGUMENT, "writer");
  133.         }

  134.         if (ephemerisFile == null) {
  135.             return;
  136.         }

  137.         final String idToProcess;
  138.         if (spaceObjectId != null) {
  139.             if (ephemerisFile.getSatellites().containsKey(spaceObjectId)) {
  140.                 idToProcess = spaceObjectId;
  141.             } else {
  142.                 throw new OrekitIllegalArgumentException(OrekitMessages.VALUE_NOT_FOUND, spaceObjectId, "ephemerisFile");
  143.             }
  144.         } else if (ephemerisFile.getSatellites().keySet().size() == 1) {
  145.             idToProcess = ephemerisFile.getSatellites().keySet().iterator().next();
  146.         } else {
  147.             throw new OrekitIllegalArgumentException(OrekitMessages.EPHEMERIS_FILE_NO_MULTI_SUPPORT);
  148.         }

  149.         // Get satellite and ephemeris segments to output.
  150.         final EphemerisFile.SatelliteEphemeris satEphem = ephemerisFile.getSatellites().get(idToProcess);
  151.         final List<? extends EphemerisSegment> segments = satEphem.getSegments();
  152.         if (segments.isEmpty()) {
  153.             // no data -> no output
  154.             return;
  155.         }
  156.         final EphemerisSegment firstSegment = segments.get(0);

  157.         final String objectName = this.spaceObjectName == null ?
  158.                 idToProcess : this.spaceObjectName;
  159.         // Only one time scale per OEM file, see Section 5.2.4.5
  160.         final TimeScale timeScale = firstSegment.getTimeScale();
  161.         // metadata that is constant for the whole OEM file
  162.         final Map<Keyword, String> metadata = new LinkedHashMap<>();
  163.         metadata.put(Keyword.TIME_SYSTEM, firstSegment.getTimeScaleString());
  164.         metadata.put(Keyword.ORIGINATOR, this.originator);
  165.         // Only one object in an OEM file, see Section 2.1
  166.         metadata.put(Keyword.OBJECT_ID, idToProcess);
  167.         metadata.put(Keyword.OBJECT_NAME, objectName);
  168.         metadata.put(Keyword.INTERPOLATION, this.interpolationMethod.toString());

  169.         // Header comments. If header comments are presents, they are assembled together in a single line
  170.         if (ephemerisFile instanceof OEMFile) {
  171.             // Cast to OEMFile
  172.             final OEMFile oemFile = (OEMFile) ephemerisFile;
  173.             if (!oemFile.getHeaderComment().isEmpty()) {
  174.                 // Loop on comments
  175.                 final StringBuffer buffer = new StringBuffer();
  176.                 for (String comment : oemFile.getHeaderComment()) {
  177.                     buffer.append(comment);
  178.                 }
  179.                 // Update metadata
  180.                 metadata.put(Keyword.COMMENT, buffer.toString());
  181.             }
  182.         }

  183.         final StreamingOemWriter oemWriter =
  184.                 new StreamingOemWriter(writer, timeScale, metadata, positionFormat, velocityFormat);
  185.         oemWriter.writeHeader();

  186.         for (final EphemerisSegment segment : segments) {
  187.             // segment specific metadata
  188.             metadata.clear();
  189.             metadata.put(Keyword.CENTER_NAME, segment.getFrameCenterString());
  190.             metadata.put(Keyword.REF_FRAME, segment.getFrameString());
  191.             metadata.put(Keyword.START_TIME, segment.getStart().toString(timeScale));
  192.             metadata.put(Keyword.STOP_TIME, segment.getStop().toString(timeScale));
  193.             metadata.put(Keyword.INTERPOLATION_DEGREE,
  194.                     String.valueOf(segment.getInterpolationSamples() - 1));

  195.             final Segment segmentWriter = oemWriter.newSegment(null, metadata);
  196.             segmentWriter.writeMetadata();
  197.             for (final TimeStampedPVCoordinates coordinates : segment.getCoordinates()) {
  198.                 segmentWriter.writeEphemerisLine(coordinates);
  199.             }

  200.             if (segment instanceof EphemeridesBlock) {
  201.                 final EphemeridesBlock curr_ephem_block = (EphemeridesBlock) segment;
  202.                 final List<CovarianceMatrix> covarianceMatrices = curr_ephem_block.getCovarianceMatrices();
  203.                 if (!covarianceMatrices.isEmpty()) {
  204.                     segmentWriter.writeCovarianceMatrices(covarianceMatrices);
  205.                 }
  206.             }
  207.         }
  208.     }

  209.     /** OEM interpolation method. See Table 5-3. */
  210.     public enum InterpolationMethod {
  211.         /** Hermite interpolation. */
  212.         HERMITE,
  213.         /** Lagrange interpolation. */
  214.         LAGRANGE,
  215.         /** Linear interpolation. */
  216.         LINEAR
  217.     }

  218. }