ManeuverFieldType.java

  1. /* Copyright 2002-2024 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.ccsds.ndm.odm.ocm;

  18. import org.hipparchus.util.Precision;
  19. import org.orekit.errors.OrekitException;
  20. import org.orekit.errors.OrekitMessages;
  21. import org.orekit.files.ccsds.definitions.OnOff;
  22. import org.orekit.files.ccsds.definitions.TimeConverter;
  23. import org.orekit.files.ccsds.utils.ContextBinding;
  24. import org.orekit.time.DateTimeComponents;
  25. import org.orekit.utils.AccurateFormatter;
  26. import org.orekit.utils.units.Unit;

  27. /** Maneuver field type used in CCSDS {@link Ocm Orbit Comprehensive Messages}.
  28.  * @author Luc Maisonobe
  29.  * @since 11.0
  30.  */
  31. public enum ManeuverFieldType {

  32.     // CHECKSTYLE: stop MultipleStringLiterals check

  33.     /** Absolute epoch time. */
  34.     TIME_ABSOLUTE("n/a",
  35.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDate(context.getTimeSystem().getConverter(context).parse(field)),
  36.         (u, converter, maneuver) -> {
  37.             final DateTimeComponents dt = converter.components(maneuver.getDate());
  38.             return AccurateFormatter.format(dt.getDate().getYear(), dt.getDate().getMonth(), dt.getDate().getDay(),
  39.                                             dt.getTime().getHour(), dt.getTime().getMinute(), dt.getTime().getSecond());
  40.         }),

  41.     /** Relative epoch time. */
  42.     TIME_RELATIVE("s",
  43.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDate(context.getReferenceDate().shiftedBy(toSI(field, u))),
  44.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(converter.offset(maneuver.getDate())))),

  45.     /** Maneuver duration. */
  46.     MAN_DURA("s",
  47.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDuration(toSI(field, u)),
  48.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDuration()))),

  49.     /** Mass change. */
  50.     DELTA_MASS("kg",
  51.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeltaMass(toSI(field, u)),
  52.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeltaMass()))),

  53.     /** Acceleration along X axis. */
  54.     ACC_X("km/s²",
  55.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setAcceleration(0, toSI(field, u)),
  56.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getAcceleration().getX()))),

  57.     /** Acceleration along Y axis. */
  58.     ACC_Y("km/s²",
  59.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setAcceleration(1, toSI(field, u)),
  60.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getAcceleration().getY()))),

  61.     /** Acceleration along Z axis. */
  62.     ACC_Z("km/s²",
  63.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setAcceleration(2, toSI(field, u)),
  64.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getAcceleration().getZ()))),

  65.     /** Interpolation mode between current and next acceleration line. */
  66.     ACC_INTERP("n/a",
  67.         (field, u, context, maneuver, lineNumber, fileName) -> {
  68.             try {
  69.                 maneuver.setAccelerationInterpolation(OnOff.valueOf(field));
  70.             } catch (IllegalArgumentException iae) {
  71.                 throw new OrekitException(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD,
  72.                                           lineNumber, fileName, field);
  73.             }
  74.         },
  75.         (u, converter, maneuver) -> maneuver.getAccelerationInterpolation().name()),

  76.     /** One σ percent error on acceleration magnitude. */
  77.     ACC_MAG_SIGMA("%",
  78.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setAccelerationMagnitudeSigma(toSI(field, u)),
  79.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getAccelerationMagnitudeSigma()))),

  80.     /** One σ off-nominal acceleration direction. */
  81.     ACC_DIR_SIGMA("°",
  82.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setAccelerationDirectionSigma(toSI(field, u)),
  83.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getAccelerationDirectionSigma()))),

  84.     /** Velocity increment along X axis. */
  85.     DV_X("km/s",
  86.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDv(0, toSI(field, u)),
  87.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDv().getX()))),

  88.     /** Velocity increment along Y axis. */
  89.     DV_Y("km/s",
  90.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDv(1, toSI(field, u)),
  91.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDv().getY()))),

  92.     /** Velocity increment along Z axis. */
  93.     DV_Z("km/s",
  94.         (field, u, context, maneuver, lineNumber, fileName) ->  maneuver.setDv(2, toSI(field, u)),
  95.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDv().getZ()))),

  96.     /** One σ percent error on ΔV magnitude. */
  97.     DV_MAG_SIGMA("%",
  98.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDvMagSigma(toSI(field, u)),
  99.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDvMagSigma()))),

  100.     /** One σ angular off-nominal ΔV direction. */
  101.     DV_DIR_SIGMA("°",
  102.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDvDirSigma(toSI(field, u)),
  103.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDvDirSigma()))),

  104.     /** Thrust component along X axis. */
  105.     THR_X("N",
  106.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrust(0, toSI(field, u)),
  107.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrust().getX()))),

  108.     /** Thrust component along Y axis. */
  109.     THR_Y("N",
  110.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrust(1, toSI(field, u)),
  111.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrust().getY()))),

  112.     /** Thrust component along Z axis. */
  113.     THR_Z("N",
  114.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrust(2, toSI(field, u)),
  115.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrust().getZ()))),

  116.     /** Thrust efficiency η typically between 0.0 and 1.0. */
  117.     THR_EFFIC("n/a",
  118.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrustEfficiency(toSI(field, u)),
  119.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrustEfficiency()))),

  120.     /** Interpolation mode between current and next acceleration line. */
  121.     THR_INTERP("n/a",
  122.         (field, u, context, maneuver, lineNumber, fileName) -> {
  123.             try {
  124.                 maneuver.setThrustInterpolation(OnOff.valueOf(field));
  125.             } catch (IllegalArgumentException iae) {
  126.                 throw new OrekitException(OrekitMessages.CCSDS_UNEXPECTED_KEYWORD,
  127.                                           lineNumber, fileName, field);
  128.             }
  129.         },
  130.         (u, converter, maneuver) -> maneuver.getThrustInterpolation().name()),

  131.     /** Thrust specific impulse. */
  132.     THR_ISP("s",
  133.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrustIsp(toSI(field, u)),
  134.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrustIsp()))),

  135.     /** One σ percent error on thrust magnitude. */
  136.     THR_MAG_SIGMA("%",
  137.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrustMagnitudeSigma(toSI(field, u)),
  138.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrustMagnitudeSigma()))),

  139.     /** One σ angular off-nominal thrust direction. */
  140.     THR_DIR_SIGMA("°",
  141.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setThrustDirectionSigma(toSI(field, u)),
  142.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getThrustDirectionSigma()))),

  143.     /** Identifier of resulting "child" object deployed from this host. */
  144.     DEPLOY_ID("n/a",
  145.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployId(field),
  146.         (u, converter, maneuver) -> maneuver.getDeployId()),

  147.     /** Velocity increment of deployed "child" object along X axis. */
  148.     DEPLOY_DV_X("km/s",
  149.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDv(0, toSI(field, u)),
  150.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDv().getX()))),

  151.     /** Velocity increment of deployed "child" object along Y axis. */
  152.     DEPLOY_DV_Y("km/s",
  153.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDv(1, toSI(field, u)),
  154.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDv().getY()))),

  155.     /** Velocity increment of deployed "child" object along Z axis. */
  156.     DEPLOY_DV_Z("km/s",
  157.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDv(2, toSI(field, u)),
  158.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDv().getZ()))),

  159.     /** Decrement in host mass as a result of deployment (shall be ≤ 0). */
  160.     DEPLOY_MASS("kg",
  161.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployMass(toSI(field, u)),
  162.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployMass()))),

  163.     /** One σ percent error on deployment ΔV magnitude. */
  164.     DEPLOY_DV_SIGMA("%",
  165.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDvSigma(toSI(field, u)),
  166.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDvSigma()))),

  167.     /** One σ angular off-nominal deployment vector direction. */
  168.     DEPLOY_DIR_SIGMA("°",
  169.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDirSigma(toSI(field, u)),
  170.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDirSigma()))),

  171.     /** Ratio of child-to-host ΔV vectors. */
  172.     DEPLOY_DV_RATIO("n/a",
  173.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDvRatio(toSI(field, u)),
  174.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDvRatio()))),

  175.     /** Typical (50th percentile) product of drag coefficient times cross-sectional area of deployed "child" object. */
  176.     DEPLOY_DV_CDA("m²",
  177.         (field, u, context, maneuver, lineNumber, fileName) -> maneuver.setDeployDvCda(toSI(field, u)),
  178.         (u, converter, maneuver) -> AccurateFormatter.format(u.fromSI(maneuver.getDeployDvCda())));

  179.     // CHECKSTYLE: resume MultipleStringLiterals check

  180.     /** Elements units. */
  181.     private final Unit unit;

  182.     /** Processing method. */
  183.     private final transient FieldProcessor processor;

  184.     /** Writing method. */
  185.     private final transient FieldWriter writer;

  186.     /** Simple constructor.
  187.      * @param unitSpecifications field unit specifications
  188.      * @param processor field processing method
  189.      * @param writer field writing method
  190.      */
  191.     ManeuverFieldType(final String unitSpecifications, final FieldProcessor processor, final FieldWriter writer) {
  192.         this.unit      = Unit.parse(unitSpecifications);
  193.         this.processor = processor;
  194.         this.writer    = writer;
  195.     }

  196.     /** Get the field unit.
  197.      * @return field unit
  198.      */
  199.     public Unit getUnit() {
  200.         return unit;
  201.     }

  202.     /** Check if parsed unit is compatible with field type.
  203.      * @param parsedUnit unit to check
  204.      */
  205.     public void checkUnit(final Unit parsedUnit) {
  206.         if (unit == Unit.NONE ^ parsedUnit == Unit.NONE ||
  207.             !(unit.sameDimension(parsedUnit) && Precision.equals(unit.getScale(), parsedUnit.getScale(), 1))) {
  208.             throw new OrekitException(OrekitMessages.INCOMPATIBLE_UNITS,
  209.                                       unit.getName(), parsedUnit.getName());
  210.         }
  211.     }

  212.     /** Check if a field is a time field.
  213.      * @return true if field is a time field
  214.      */
  215.     public boolean isTime() {
  216.         return this == TIME_ABSOLUTE || this == TIME_RELATIVE;
  217.     }

  218.     /** Get the value in SI units corresponding to a field.
  219.      * @param field text field
  220.      * @param unit unit to use
  221.      * @return double value in SI units
  222.      */
  223.     private static double toSI(final String field, final Unit unit) {
  224.         return unit.toSI(Double.parseDouble(field));
  225.     }

  226.     /** Process one field.
  227.      * @param field field to process
  228.      * @param context context binding
  229.      * @param maneuver maneuver to fill
  230.      * @param lineNumber line number at which the field occurs
  231.      * @param fileName name of the file in which the field occurs
  232.      */
  233.     public void process(final String field, final ContextBinding context, final OrbitManeuver maneuver,
  234.                         final int lineNumber, final String fileName) {
  235.         processor.process(field, unit, context, maneuver, lineNumber, fileName);
  236.     }

  237.     /** Output one maneuver field.
  238.          * @param converter converter for dates
  239.      * @param maneuver maneuver containing the field to output
  240.      * @return output field
  241.      */
  242.     public String outputField(final TimeConverter converter, final OrbitManeuver maneuver) {
  243.         return writer.output(unit, converter, maneuver);
  244.     }

  245.     /** Interface for processing one field. */
  246.     interface FieldProcessor {
  247.         /** Process one field.
  248.          * @param field field to process
  249.          * @param unit unit to use
  250.          * @param context context binding
  251.          * @param maneuver maneuver to fill
  252.          * @param lineNumber line number at which the field occurs
  253.          * @param fileName name of the file in which the field occurs
  254.          */
  255.         void process(String field, Unit unit, ContextBinding context, OrbitManeuver maneuver,
  256.                      int lineNumber, String fileName);
  257.     }

  258.     /** Interface for writing one field. */
  259.     interface FieldWriter {
  260.         /** Process one field.
  261.          * @param unit unit to use
  262.          * @param converter converter for dates
  263.          * @param maneuver maneuver containing the field to output
  264.          * @return output field
  265.          */
  266.         String output(Unit unit, TimeConverter converter, OrbitManeuver maneuver);
  267.     }

  268. }