QuadraticPenaltyCartesianFuel.java

  1. /* Copyright 2022-2025 Romain Serra
  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.control.indirect.adjoint.cost;

  18. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.propagation.SpacecraftState;
  21. import org.orekit.propagation.events.EventDetectionSettings;
  22. import org.orekit.propagation.events.EventDetector;

  23. import java.util.stream.Stream;

  24. /**
  25.  * Fuel cost penalized with a quadratic term. For epsilon equal to 1, one gets the bounded energy cost.
  26.  *
  27.  * @author Romain Serra
  28.  * @since 13.0
  29.  * @see BoundedCartesianEnergy
  30.  */
  31. public class QuadraticPenaltyCartesianFuel extends PenalizedCartesianFuelCost {

  32.     /** Detection settings for singularity events. */
  33.     private final EventDetectionSettings eventDetectionSettings;

  34.     /**
  35.      * Constructor.
  36.      *
  37.      * @param name                   adjoint name
  38.      * @param massFlowRateFactor     mass flow rate factor
  39.      * @param maximumThrustMagnitude maximum thrust magnitude
  40.      * @param epsilon                penalty weight
  41.      * @param eventDetectionSettings detection settings
  42.      */
  43.     public QuadraticPenaltyCartesianFuel(final String name, final double massFlowRateFactor,
  44.                                          final double maximumThrustMagnitude, final double epsilon,
  45.                                          final EventDetectionSettings eventDetectionSettings) {
  46.         super(name, massFlowRateFactor, maximumThrustMagnitude, epsilon);
  47.         this.eventDetectionSettings = eventDetectionSettings;
  48.     }

  49.     /**
  50.      * Constructor with default event detection settings.
  51.      *
  52.      * @param name                   adjoint name
  53.      * @param massFlowRateFactor     mass flow rate factor
  54.      * @param maximumThrustMagnitude maximum thrust magnitude
  55.      * @param epsilon                penalty weight
  56.      */
  57.     public QuadraticPenaltyCartesianFuel(final String name, final double massFlowRateFactor,
  58.                                          final double maximumThrustMagnitude, final double epsilon) {
  59.         this(name, massFlowRateFactor, maximumThrustMagnitude, epsilon,
  60.                 EventDetectionSettings.getDefaultEventDetectionSettings());
  61.     }

  62.     /**
  63.      * Getter for the event detection settings.
  64.      * @return detection settings
  65.      */
  66.     public EventDetectionSettings getEventDetectionSettings() {
  67.         return eventDetectionSettings;
  68.     }

  69.     /** {@inheritDoc} */
  70.     @Override
  71.     public double evaluatePenaltyFunction(final double controlNorm) {
  72.         return controlNorm * (controlNorm * getMaximumThrustMagnitude() / 2 - 1.);
  73.     }

  74.     /** {@inheritDoc} */
  75.     @Override
  76.     public Vector3D getThrustAccelerationVector(final double[] adjointVariables, final double mass) {
  77.         final double switchFunction = evaluateSwitchFunction(adjointVariables, mass);
  78.         if (switchFunction > 0) {
  79.             final double thrustForceMagnitude = FastMath.min(switchFunction, getMaximumThrustMagnitude());
  80.             return getThrustDirection(adjointVariables).scalarMultiply(thrustForceMagnitude / mass);
  81.         } else {
  82.             return Vector3D.ZERO;
  83.         }
  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     public void updateAdjointDerivatives(final double[] adjointVariables, final double mass,
  88.                                          final double[] adjointDerivatives) {
  89.         if (getAdjointDimension() > 6) {
  90.             final double switchFunction = evaluateSwitchFunction(adjointVariables, mass);
  91.             if (switchFunction > 0.) {
  92.                 adjointDerivatives[6] += getAdjointVelocityNorm(adjointVariables) *
  93.                         FastMath.min(switchFunction, getMaximumThrustMagnitude()) / (mass * mass);
  94.             }
  95.         }
  96.     }

  97.     /**
  98.      * Evaluate switching function (whose value determines the control profile).
  99.      * @param adjointVariables adjoint vector
  100.      * @param mass mass
  101.      * @return value of switch function
  102.      */
  103.     private double evaluateSwitchFunction(final double[] adjointVariables, final double mass) {
  104.         double epsilonIndependentTerm = getAdjointVelocityNorm(adjointVariables) / mass - 1.;
  105.         if (getAdjointDimension() > 6) {
  106.             epsilonIndependentTerm -= getMassFlowRateFactor() * adjointVariables[6];
  107.         }
  108.         return epsilonIndependentTerm / getEpsilon() + 1.;
  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public Stream<EventDetector> getEventDetectors() {
  113.         return Stream.of(new QuadraticPenalizedSwitchDetector(getEventDetectionSettings(), 0),
  114.                 new QuadraticPenalizedSwitchDetector(getEventDetectionSettings(), getMaximumThrustMagnitude()));
  115.     }

  116.     /**
  117.      * Event detector for control non-differentiability.
  118.      */
  119.     private class QuadraticPenalizedSwitchDetector extends ControlSwitchDetector {

  120.         /** Critical value at which the switching function has an event. */
  121.         private final double criticalValue;

  122.         /**
  123.          * Constructor.
  124.          * @param detectionSettings detection settings.
  125.          * @param criticalValue switch function value to detect
  126.          */
  127.         QuadraticPenalizedSwitchDetector(final EventDetectionSettings detectionSettings,
  128.                                          final double criticalValue) {
  129.             super(detectionSettings);
  130.             this.criticalValue = criticalValue;
  131.         }

  132.         /** {@inheritDoc} */
  133.         @Override
  134.         public double g(final SpacecraftState state) {
  135.             final double[] adjoint = state.getAdditionalState(getAdjointName());
  136.             return evaluateSwitchFunction(adjoint, state.getMass()) - criticalValue;
  137.         }
  138.     }
  139. }