FieldQuadraticPenaltyCartesianFuel.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.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.propagation.FieldSpacecraftState;
  23. import org.orekit.propagation.events.EventDetectionSettings;
  24. import org.orekit.propagation.events.FieldEventDetectionSettings;
  25. import org.orekit.propagation.events.FieldEventDetector;

  26. import java.util.stream.Stream;

  27. /**
  28.  * Fuel cost penalized with a quadratic term. For epsilon equal to 1, one gets the bounded energy cost.
  29.  *
  30.  * @author Romain Serra
  31.  * @since 13.0
  32.  * @see BoundedCartesianEnergy
  33.  */
  34. public class FieldQuadraticPenaltyCartesianFuel<T extends CalculusFieldElement<T>>
  35.         extends FieldPenalizedCartesianFuelCost<T> {

  36.     /** Detection settings for singularity detection. */
  37.     private final FieldEventDetectionSettings<T> eventDetectionSettings;

  38.     /**
  39.      * Constructor.
  40.      *
  41.      * @param name                   adjoint name
  42.      * @param massFlowRateFactor     mass flow rate factor
  43.      * @param maximumThrustMagnitude maximum thrust magnitude
  44.      * @param epsilon                penalty weight
  45.      * @param eventDetectionSettings detection settings
  46.      */
  47.     public FieldQuadraticPenaltyCartesianFuel(final String name, final T massFlowRateFactor,
  48.                                               final T maximumThrustMagnitude, final T epsilon,
  49.                                               final FieldEventDetectionSettings<T> eventDetectionSettings) {
  50.         super(name, massFlowRateFactor, maximumThrustMagnitude, epsilon);
  51.         this.eventDetectionSettings = eventDetectionSettings;
  52.     }

  53.     /**
  54.      * Constructor with default event detection settings.
  55.      *
  56.      * @param name                   adjoint name
  57.      * @param massFlowRateFactor     mass flow rate factor
  58.      * @param maximumThrustMagnitude maximum thrust magnitude
  59.      * @param epsilon                penalty weight
  60.      */
  61.     public FieldQuadraticPenaltyCartesianFuel(final String name, final T massFlowRateFactor,
  62.                                               final T maximumThrustMagnitude, final T epsilon) {
  63.         this(name, massFlowRateFactor, maximumThrustMagnitude, epsilon, new FieldEventDetectionSettings<>(massFlowRateFactor.getField(),
  64.                 EventDetectionSettings.getDefaultEventDetectionSettings()));
  65.     }

  66.     /**
  67.      * Getter for the event detection settings.
  68.      * @return detection settings
  69.      */
  70.     public FieldEventDetectionSettings<T> getEventDetectionSettings() {
  71.         return eventDetectionSettings;
  72.     }

  73.     /** {@inheritDoc} */
  74.     @Override
  75.     public T evaluateFieldPenaltyFunction(final T controlNorm) {
  76.         return controlNorm.multiply(controlNorm.multiply(getMaximumThrustMagnitude()).divide(2).subtract(1.));
  77.     }

  78.     /** {@inheritDoc} */
  79.     @Override
  80.     public FieldVector3D<T> getFieldThrustAccelerationVector(final T[] adjointVariables, final T mass) {
  81.         final T switchFunction = evaluateSwitchFunction(adjointVariables, mass);
  82.         if (switchFunction.getReal() > 0) {
  83.             final T thrustForceMagnitude = FastMath.min(switchFunction, getMaximumThrustMagnitude());
  84.             return getFieldThrustDirection(adjointVariables).scalarMultiply(thrustForceMagnitude.divide(mass));
  85.         } else {
  86.             return FieldVector3D.getZero(mass.getField());
  87.         }
  88.     }

  89.     /** {@inheritDoc} */
  90.     @Override
  91.     public void updateFieldAdjointDerivatives(final T[] adjointVariables, final T mass, final T[] adjointDerivatives) {
  92.         if (getAdjointDimension() > 6) {
  93.             final T switchFunction = evaluateSwitchFunction(adjointVariables, mass);
  94.             if (switchFunction.getReal() > 0.) {
  95.                 final T minimum = FastMath.min(switchFunction, getMaximumThrustMagnitude());
  96.                 adjointDerivatives[6] = adjointDerivatives[6].add(getFieldAdjointVelocityNorm(adjointVariables)
  97.                         .multiply(minimum).divide(mass.square()));
  98.             }
  99.         }
  100.     }

  101.     /**
  102.      * Evaluate switching function (whose value determines the control profile).
  103.      * @param adjointVariables adjoint vector
  104.      * @param mass mass
  105.      * @return value of switch function
  106.      */
  107.     private T evaluateSwitchFunction(final T[] adjointVariables, final T mass) {
  108.         T epsilonIndependentTerm = getFieldAdjointVelocityNorm(adjointVariables).divide(mass).subtract(1.);
  109.         if (getAdjointDimension() > 6) {
  110.             epsilonIndependentTerm = epsilonIndependentTerm.subtract(adjointVariables[6].multiply(getMassFlowRateFactor()));
  111.         }
  112.         return epsilonIndependentTerm.divide(getEpsilon()).add(1);
  113.     }

  114.     /** {@inheritDoc} */
  115.     @Override
  116.     public Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
  117.         return Stream.of(new FieldQuadraticPenalizedSwitchDetector(getEventDetectionSettings(), field.getZero()),
  118.                 new FieldQuadraticPenalizedSwitchDetector(getEventDetectionSettings(), getMaximumThrustMagnitude()));
  119.     }

  120.     /**
  121.      * Event detector for control non-differentiability.
  122.      */
  123.     private class FieldQuadraticPenalizedSwitchDetector extends FieldControlSwitchDetector<T> {

  124.         /** Critical value at which the switching function has an event. */
  125.         private final T criticalValue;

  126.         /**
  127.          * Constructor.
  128.          * @param detectionSettings detection settings.
  129.          * @param criticalValue switch function value to detect
  130.          */
  131.         FieldQuadraticPenalizedSwitchDetector(final FieldEventDetectionSettings<T> detectionSettings,
  132.                                               final T criticalValue) {
  133.             super(detectionSettings);
  134.             this.criticalValue = criticalValue;
  135.         }

  136.         /** {@inheritDoc} */
  137.         @Override
  138.         public T g(final FieldSpacecraftState<T> state) {
  139.             final T[] adjoint = state.getAdditionalState(getAdjointName());
  140.             return evaluateSwitchFunction(adjoint, state.getMass()).subtract(criticalValue);
  141.         }
  142.     }

  143.     /** {@inheritDoc} */
  144.     @Override
  145.     public QuadraticPenaltyCartesianFuel toCartesianCost() {
  146.         return new QuadraticPenaltyCartesianFuel(getAdjointName(), getMassFlowRateFactor().getReal(),
  147.                 getMaximumThrustMagnitude().getReal(), getEpsilon().getReal(),
  148.                 getEventDetectionSettings().toEventDetectionSettings());
  149.     }
  150. }