Maneuver.java

  1. /* Copyright 2002-2023 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.forces.maneuvers;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;
  21. import java.util.stream.Stream;

  22. import org.hipparchus.CalculusFieldElement;
  23. import org.hipparchus.Field;
  24. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  25. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  26. import org.hipparchus.geometry.euclidean.threed.Rotation;
  27. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  28. import org.orekit.attitudes.Attitude;
  29. import org.orekit.attitudes.AttitudeProvider;
  30. import org.orekit.attitudes.FieldAttitude;
  31. import org.orekit.forces.ForceModel;
  32. import org.orekit.forces.maneuvers.propulsion.PropulsionModel;
  33. import org.orekit.forces.maneuvers.trigger.ManeuverTriggers;
  34. import org.orekit.propagation.FieldSpacecraftState;
  35. import org.orekit.propagation.SpacecraftState;
  36. import org.orekit.propagation.events.EventDetector;
  37. import org.orekit.propagation.events.FieldEventDetector;
  38. import org.orekit.propagation.numerical.FieldTimeDerivativesEquations;
  39. import org.orekit.propagation.numerical.TimeDerivativesEquations;
  40. import org.orekit.time.AbsoluteDate;
  41. import org.orekit.time.FieldAbsoluteDate;
  42. import org.orekit.utils.ParameterDriver;


  43. /** A generic model for maneuvers with finite-valued acceleration magnitude, as opposed to instantaneous changes
  44.  * in the velocity vector which are defined via detectors (in {@link org.orekit.forces.maneuvers.ImpulseManeuver} and
  45.  * {@link org.orekit.forces.maneuvers.FieldImpulseManeuver}).
  46.  * It contains:
  47.  *  - An attitude override, this is the attitude used during the maneuver, it can be different from the one
  48.  *    used for propagation;
  49.  *  - A maneuver triggers object from the trigger sub-package. It defines the triggers used to start and stop the maneuvers (dates or events for example).
  50.  *  - A propulsion model from sub-package propulsion. It defines the thrust or ΔV, isp, flow rate etc..
  51.  * Both the propulsion model and the maneuver triggers can contain parameter drivers (for estimation).
  52.  * The convention here is that the propulsion model drivers are given before the maneuver triggers when calling the
  53.  * method {@link #getParametersDrivers()}
  54.  * @author Maxime Journot
  55.  * @since 10.2
  56.  */
  57. public class Maneuver implements ForceModel {

  58.     /** The attitude to override during the maneuver, if set. */
  59.     private final AttitudeProvider attitudeOverride;

  60.     /** Propulsion model to use for the thrust. */
  61.     private final PropulsionModel propulsionModel;

  62.     /** Maneuver triggers. */
  63.     private final ManeuverTriggers maneuverTriggers;

  64.     /** Generic maneuver constructor.
  65.      * @param attitudeOverride attitude provider for the attitude during the maneuver
  66.      * @param maneuverTriggers maneuver triggers
  67.      * @param propulsionModel propulsion model
  68.      */
  69.     public Maneuver(final AttitudeProvider attitudeOverride,
  70.                     final ManeuverTriggers maneuverTriggers,
  71.                     final PropulsionModel propulsionModel) {
  72.         this.maneuverTriggers = maneuverTriggers;
  73.         this.attitudeOverride = attitudeOverride;
  74.         this.propulsionModel = propulsionModel;
  75.     }

  76.     /** Get the name of the maneuver.
  77.      * The name can be in the propulsion model, in the maneuver triggers or both.
  78.      * If it is in both it should be the same since it refers to the same maneuver.
  79.      * The name is inferred from the propulsion model first, then from the maneuver triggers if
  80.      * the propulsion model had an empty name.
  81.      * @return the name
  82.      */
  83.     public String getName() {

  84.         //FIXME: Potentially, throw an exception if both propulsion model
  85.         // and maneuver triggers define a name but they are different
  86.         String name = propulsionModel.getName();

  87.         if (name.length() < 1) {
  88.             name = maneuverTriggers.getName();
  89.         }
  90.         return name;
  91.     }

  92.     /** Get the attitude override used for the maneuver.
  93.      * @return the attitude override
  94.      */
  95.     public AttitudeProvider getAttitudeOverride() {
  96.         return attitudeOverride;
  97.     }

  98.     /** Get the control vector's cost type.
  99.      * @return control cost type
  100.      * @since 12.0
  101.      */
  102.     public Control3DVectorCostType getControl3DVectorCostType() {
  103.         return propulsionModel.getControl3DVectorCostType();
  104.     }

  105.     /** Get the propulsion model.
  106.      * @return the propulsion model
  107.      */
  108.     public PropulsionModel getPropulsionModel() {
  109.         return propulsionModel;
  110.     }

  111.     /** Get the maneuver triggers.
  112.      * @return the maneuver triggers
  113.      */
  114.     public ManeuverTriggers getManeuverTriggers() {
  115.         return maneuverTriggers;
  116.     }

  117.     /** {@inheritDoc} */
  118.     @Override
  119.     public boolean dependsOnPositionOnly() {
  120.         return false;
  121.     }

  122.     /** {@inheritDoc} */
  123.     @Override
  124.     public void init(final SpacecraftState initialState, final AbsoluteDate target) {
  125.         propulsionModel.init(initialState, target);
  126.         maneuverTriggers.init(initialState, target);
  127.     }

  128.     /** {@inheritDoc} */
  129.     @Override
  130.     public <T extends CalculusFieldElement<T>> void init(final FieldSpacecraftState<T> initialState, final FieldAbsoluteDate<T> target) {
  131.         propulsionModel.init(initialState, target);
  132.         maneuverTriggers.init(initialState, target);
  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder) {

  137.         // Get the parameters associated to the maneuver (from ForceModel)
  138.         final double[] parameters = getParameters(s.getDate());

  139.         // If the maneuver is active, compute and add its contribution
  140.         // Maneuver triggers are used to check if the maneuver is currently firing or not
  141.         // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
  142.         if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {

  143.             // Compute thrust acceleration in inertial frame
  144.             adder.addNonKeplerianAcceleration(acceleration(s, parameters));

  145.             // Compute flow rate using the propulsion model
  146.             // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
  147.             adder.addMassDerivative(propulsionModel.getMassDerivatives(s, getPropulsionModelParameters(parameters)));
  148.         }
  149.     }

  150.     /** {@inheritDoc} */
  151.     @Override
  152.     public <T extends CalculusFieldElement<T>> void addContribution(final FieldSpacecraftState<T> s,
  153.                         final FieldTimeDerivativesEquations<T> adder) {

  154.         // Get the parameters associated to the maneuver (from ForceModel)
  155.         final T[] parameters = getParameters(s.getDate().getField(), s.getDate());

  156.         // If the maneuver is active, compute and add its contribution
  157.         // Maneuver triggers are used to check if the maneuver is currently firing or not
  158.         // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
  159.         if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {

  160.             // Compute thrust acceleration in inertial frame
  161.             // the acceleration method extracts the parameter in its core, that is why we call it with
  162.             // parameters and not extracted parameters
  163.             adder.addNonKeplerianAcceleration(acceleration(s, parameters));

  164.             // Compute flow rate using the propulsion model
  165.             // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
  166.             adder.addMassDerivative(propulsionModel.getMassDerivatives(s, getPropulsionModelParameters(parameters)));
  167.         }
  168.     }

  169.     @Override
  170.     public Vector3D acceleration(final SpacecraftState s, final double[] parameters) {

  171.         // If the maneuver is active, compute and add its contribution
  172.         // Maneuver triggers are used to check if the maneuver is currently firing or not
  173.         // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
  174.         if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {

  175.             // Attitude during maneuver
  176.             final Attitude maneuverAttitude;
  177.             if (attitudeOverride == null) {
  178.                 maneuverAttitude = s.getAttitude();
  179.             } else {
  180.                 final Rotation rotation = attitudeOverride.getAttitudeRotation(s.getOrbit(), s.getDate(), s.getFrame());
  181.                 // use dummy rates to build full attitude as they should not be used
  182.                 maneuverAttitude = new Attitude(s.getDate(), s.getFrame(), rotation, Vector3D.ZERO, Vector3D.ZERO);
  183.             }

  184.             // Compute acceleration from propulsion model
  185.             // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
  186.             return propulsionModel.getAcceleration(s, maneuverAttitude, getPropulsionModelParameters(parameters));
  187.         } else {
  188.             // Constant (and null) acceleration when not firing
  189.             return Vector3D.ZERO;
  190.         }
  191.     }

  192.     @Override
  193.     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> s, final T[] parameters) {

  194.         // If the maneuver is active, compute and add its contribution
  195.         // Maneuver triggers are used to check if the maneuver is currently firing or not
  196.         // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
  197.         if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {

  198.             // Attitude during maneuver
  199.             final FieldAttitude<T> maneuverAttitude;
  200.             if (attitudeOverride == null) {
  201.                 maneuverAttitude = s.getAttitude();
  202.             } else {
  203.                 final FieldRotation<T> rotation = attitudeOverride.getAttitudeRotation(s.getOrbit(), s.getDate(), s.getFrame());
  204.                 // use dummy rates to build full attitude as they should not be used
  205.                 final FieldVector3D<T> zeroVector3D = FieldVector3D.getZero(s.getDate().getField());
  206.                 maneuverAttitude = new FieldAttitude<>(s.getDate(), s.getFrame(), rotation, zeroVector3D, zeroVector3D);
  207.             }

  208.             // Compute acceleration from propulsion model
  209.             // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
  210.             return propulsionModel.getAcceleration(s, maneuverAttitude, getPropulsionModelParameters(parameters));
  211.         } else {
  212.             // Constant (and null) acceleration when not firing
  213.             return FieldVector3D.getZero(s.getMu().getField());
  214.         }
  215.     }

  216.     /** {@inheritDoc} */
  217.     @Override
  218.     public Stream<EventDetector> getEventDetectors() {
  219.         // Event detectors are extracted from both the maneuver triggers and the propulsion model
  220.         return Stream.concat(maneuverTriggers.getEventDetectors(),
  221.                              propulsionModel.getEventDetectors());
  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
  226.         // Event detectors are extracted from both the maneuver triggers and the propulsion model
  227.         return Stream.concat(maneuverTriggers.getFieldEventDetectors(field),
  228.                              propulsionModel.getFieldEventDetectors(field));
  229.     }

  230.     @Override
  231.     public List<ParameterDriver> getParametersDrivers() {

  232.         // Extract parameter drivers from propulsion model and maneuver triggers
  233.         final List<ParameterDriver> propulsionModelDrivers  = propulsionModel.getParametersDrivers();
  234.         final List<ParameterDriver> maneuverTriggersDrivers = maneuverTriggers.getParametersDrivers();
  235.         final int propulsionModelDriversLength  = propulsionModelDrivers.size();
  236.         final int maneuverTriggersDriversLength = maneuverTriggersDrivers.size();

  237.         // Prepare final drivers' array
  238.         final List<ParameterDriver> drivers = new ArrayList<>(propulsionModelDriversLength + maneuverTriggersDriversLength);

  239.         // Convention: Propulsion drivers are given before maneuver triggers drivers
  240.         // Add propulsion drivers first
  241.         drivers.addAll(0, propulsionModelDrivers);

  242.         // Then maneuver triggers' drivers
  243.         drivers.addAll(propulsionModelDriversLength, maneuverTriggersDrivers);

  244.         // Return full drivers' array
  245.         return drivers;
  246.     }

  247.     /** Extract propulsion model parameters from the parameters' array called in by the ForceModel interface.
  248.      *  Convention: Propulsion parameters are given before maneuver triggers parameters
  249.      * @param parameters parameters' array called in by ForceModel interface
  250.      * @return propulsion model parameters
  251.      */
  252.     private double[] getPropulsionModelParameters(final double[] parameters) {
  253.         return Arrays.copyOfRange(parameters, 0, propulsionModel.getParametersDrivers().size());
  254.     }

  255.     /** Extract propulsion model parameters from the parameters' array called in by the ForceModel interface.
  256.      *  Convention: Propulsion parameters are given before maneuver triggers parameters
  257.      * @param parameters parameters' array called in by ForceModel interface
  258.      * @param <T> extends CalculusFieldElement&lt;T&gt;
  259.      * @return propulsion model parameters
  260.      */
  261.     private <T extends CalculusFieldElement<T>> T[] getPropulsionModelParameters(final T[] parameters) {
  262.         return Arrays.copyOfRange(parameters, 0, propulsionModel.getParametersDrivers().size());
  263.     }

  264.     /** Extract maneuver triggers' parameters from the parameters' array called in by the ForceModel interface.
  265.      *  Convention: Propulsion parameters are given before maneuver triggers parameters
  266.      * @param parameters parameters' array called in by ForceModel interface
  267.      * @return maneuver triggers' parameters
  268.      */
  269.     private double[] getManeuverTriggersParameters(final double[] parameters) {
  270.         final int nbPropulsionModelDrivers = propulsionModel.getParametersDrivers().size();
  271.         return Arrays.copyOfRange(parameters, nbPropulsionModelDrivers,
  272.                                   nbPropulsionModelDrivers + maneuverTriggers.getParametersDrivers().size());
  273.     }

  274.     /** Extract maneuver triggers' parameters from the parameters' array called in by the ForceModel interface.
  275.      *  Convention: Propulsion parameters are given before maneuver triggers parameters
  276.      * @param parameters parameters' array called in by ForceModel interface
  277.      * @param <T> extends CalculusFieldElement&lt;T&gt;
  278.      * @return maneuver triggers' parameters
  279.      */
  280.     private <T extends CalculusFieldElement<T>> T[] getManeuverTriggersParameters(final T[] parameters) {
  281.         final int nbPropulsionModelDrivers = propulsionModel.getParametersDrivers().size();
  282.         return Arrays.copyOfRange(parameters, nbPropulsionModelDrivers,
  283.                                   nbPropulsionModelDrivers + maneuverTriggers.getParametersDrivers().size());
  284.     }
  285. }