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  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.orekit.propagation.events.EventDetectionSettings;
22  import org.orekit.propagation.events.FieldEventDetectionSettings;
23  import org.orekit.propagation.events.FieldEventDetector;
24  
25  import java.util.stream.Stream;
26  
27  /**
28   * Class for unbounded energy cost with Cartesian coordinates.
29   * Here, the control vector is chosen as the thrust force, expressed in the propagation frame.
30   * This leads to the optimal thrust being in the same direction as the adjoint velocity.
31   *
32   * @param <T> field type
33   * @author Romain Serra
34   * @see FieldUnboundedCartesianEnergyNeglectingMass
35   * @see UnboundedCartesianEnergy
36   * @since 13.0
37   */
38  public class FieldUnboundedCartesianEnergy<T extends CalculusFieldElement<T>> extends FieldCartesianEnergyConsideringMass<T> {
39  
40      /**
41       * Constructor.
42       * @param name name
43       * @param massFlowRateFactor mass flow rate factor
44       * @param eventDetectionSettings detection settings for singularity detections
45       */
46      public FieldUnboundedCartesianEnergy(final String name, final T massFlowRateFactor,
47                                           final FieldEventDetectionSettings<T> eventDetectionSettings) {
48          super(name, massFlowRateFactor, eventDetectionSettings);
49      }
50  
51      /**
52       * Constructor.
53       * @param name name
54       * @param massFlowRateFactor mass flow rate factor
55       */
56      public FieldUnboundedCartesianEnergy(final String name, final T massFlowRateFactor) {
57          this(name, massFlowRateFactor, new FieldEventDetectionSettings<>(massFlowRateFactor.getField(),
58                  EventDetectionSettings.getDefaultEventDetectionSettings()));
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      protected T getFieldThrustForceNorm(final T[] adjointVariables, final T mass) {
64          final T adjointVelocityNorm = getFieldAdjointVelocityNorm(adjointVariables);
65          T factor = adjointVelocityNorm.divide(mass);
66          if (getAdjointDimension() > 6) {
67              factor = factor.subtract(adjointVariables[6].multiply(getMassFlowRateFactor()));
68          }
69          if (factor.getReal() < 0.) {
70              return adjointVelocityNorm.getField().getZero();
71          } else {
72              return factor;
73          }
74      }
75  
76      /** {@inheritDoc} */
77      @Override
78      public Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
79          return Stream.of(new FieldSingularityDetector(getEventDetectionSettings(), field.getZero()));
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public UnboundedCartesianEnergy toCartesianCost() {
85          return new UnboundedCartesianEnergy(getAdjointName(), getMassFlowRateFactor().getReal(),
86                  getEventDetectionSettings().toEventDetectionSettings());
87      }
88  }