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.shooting.propagation;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.orekit.control.indirect.adjoint.CartesianAdjointDerivativesProvider;
22  import org.orekit.control.indirect.adjoint.CartesianAdjointEquationTerm;
23  import org.orekit.control.indirect.adjoint.FieldCartesianAdjointDerivativesProvider;
24  import org.orekit.control.indirect.adjoint.cost.BoundedCartesianEnergy;
25  import org.orekit.control.indirect.adjoint.cost.CartesianFlightDurationCost;
26  import org.orekit.control.indirect.adjoint.cost.CartesianFuelCost;
27  import org.orekit.control.indirect.adjoint.cost.FieldBoundedCartesianEnergy;
28  import org.orekit.control.indirect.adjoint.cost.FieldCartesianFlightDurationCost;
29  import org.orekit.control.indirect.adjoint.cost.FieldCartesianFuelCost;
30  import org.orekit.control.indirect.adjoint.cost.FieldLogarithmicBarrierCartesianFuel;
31  import org.orekit.control.indirect.adjoint.cost.FieldQuadraticPenaltyCartesianFuel;
32  import org.orekit.control.indirect.adjoint.cost.FieldUnboundedCartesianEnergy;
33  import org.orekit.control.indirect.adjoint.cost.FieldUnboundedCartesianEnergyNeglectingMass;
34  import org.orekit.control.indirect.adjoint.cost.LogarithmicBarrierCartesianFuel;
35  import org.orekit.control.indirect.adjoint.cost.QuadraticPenaltyCartesianFuel;
36  import org.orekit.control.indirect.adjoint.cost.UnboundedCartesianEnergy;
37  import org.orekit.control.indirect.adjoint.cost.UnboundedCartesianEnergyNeglectingMass;
38  import org.orekit.propagation.events.EventDetectionSettings;
39  import org.orekit.propagation.events.FieldEventDetectionSettings;
40  
41  /**
42   * Factory for common Cartesian adjoint dynamics providers.
43   *
44   * @see AdjointDynamicsProvider
45   * @author Romain Serra
46   * @since 13.0
47   */
48  public class CartesianAdjointDynamicsProviderFactory {
49  
50      /**
51       * Private constructor.
52       */
53      private CartesianAdjointDynamicsProviderFactory() {
54          // factory class
55      }
56  
57      /**
58       * Method building a provider with unbounded Cartesian energy and vanishing mass flow as cost.
59       * @param adjointName adjoint name
60       * @param massFlowRateFactor mass flow rate factor
61       * @param maximumThrustMagnitude maximum thrust magnitude
62       * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
63       * @return provider
64       */
65      public static CartesianAdjointDynamicsProvider buildFlightDurationProvider(final String adjointName,
66                                                                                 final double massFlowRateFactor,
67                                                                                 final double maximumThrustMagnitude,
68                                                                                 final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
69          return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
70  
71              @Override
72              public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
73                  return new CartesianAdjointDerivativesProvider(new CartesianFlightDurationCost(adjointName, massFlowRateFactor, maximumThrustMagnitude),
74                          cartesianAdjointEquationTerms);
75              }
76  
77              @Override
78              public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
79                  return new FieldCartesianAdjointDerivativesProvider<>(new FieldCartesianFlightDurationCost<>(adjointName,
80                          field.getZero().newInstance(massFlowRateFactor), field.getZero().newInstance(maximumThrustMagnitude)),
81                          cartesianAdjointEquationTerms);
82              }
83          };
84      }
85  
86      /**
87       * Method building a provider with unbounded Cartesian energy and vanishing mass flow as cost.
88       * @param adjointName adjoint name
89       * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
90       * @return provider
91       */
92      public static CartesianAdjointDynamicsProvider buildUnboundedEnergyProviderNeglectingMass(final String adjointName,
93                                                                                                final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
94          return new CartesianAdjointDynamicsProvider(adjointName, 6) {
95  
96              @Override
97              public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
98                  return new CartesianAdjointDerivativesProvider(new UnboundedCartesianEnergyNeglectingMass(adjointName),
99                          cartesianAdjointEquationTerms);
100             }
101 
102             @Override
103             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
104                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldUnboundedCartesianEnergyNeglectingMass<>(adjointName, field),
105                         cartesianAdjointEquationTerms);
106             }
107         };
108     }
109 
110     /**
111      * Method building a provider with unbounded Cartesian energy as cost.
112      * @param adjointName adjoint name
113      * @param massFlowRateFactor mass flow rate factor
114      * @param eventDetectionSettings detection settings for adjoint-related events
115      * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
116      * @return provider
117      */
118     public static CartesianAdjointDynamicsProvider buildUnboundedEnergyProvider(final String adjointName,
119                                                                                 final double massFlowRateFactor,
120                                                                                 final EventDetectionSettings eventDetectionSettings,
121                                                                                 final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
122         return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
123 
124             @Override
125             public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
126                 return new CartesianAdjointDerivativesProvider(new UnboundedCartesianEnergy(adjointName,
127                         massFlowRateFactor, eventDetectionSettings), cartesianAdjointEquationTerms);
128             }
129 
130             @Override
131             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
132                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldUnboundedCartesianEnergy<>(adjointName,
133                         field.getZero().newInstance(massFlowRateFactor), new FieldEventDetectionSettings<>(field,
134                         eventDetectionSettings)), cartesianAdjointEquationTerms);
135             }
136         };
137     }
138 
139     /**
140      * Method building a provider with bounded Cartesian energy as cost.
141      * @param adjointName adjoint name
142      * @param massFlowRateFactor mass flow rate factor
143      * @param maximumThrustMagnitude maximum thrust magnitude
144      * @param eventDetectionSettings detection settings for adjoint-related events
145      * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
146      * @return provider
147      */
148     public static CartesianAdjointDynamicsProvider buildBoundedEnergyProvider(final String adjointName,
149                                                                               final double massFlowRateFactor,
150                                                                               final double maximumThrustMagnitude,
151                                                                               final EventDetectionSettings eventDetectionSettings,
152                                                                               final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
153         return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
154 
155             @Override
156             public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
157                 return new CartesianAdjointDerivativesProvider(new BoundedCartesianEnergy(adjointName, massFlowRateFactor,
158                         maximumThrustMagnitude, eventDetectionSettings), cartesianAdjointEquationTerms);
159             }
160 
161             @Override
162             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
163                 final T zero = field.getZero();
164                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldBoundedCartesianEnergy<>(adjointName,
165                         zero.newInstance(massFlowRateFactor), zero.newInstance(maximumThrustMagnitude),
166                         new FieldEventDetectionSettings<>(field, eventDetectionSettings)), cartesianAdjointEquationTerms);
167             }
168         };
169     }
170 
171     /**
172      * Method building a provider with bounded Cartesian fuel as cost.
173      * @param adjointName adjoint name
174      * @param massFlowRateFactor mass flow rate factor
175      * @param maximumThrustMagnitude maximum thrust magnitude
176      * @param eventDetectionSettings detection settings for adjoint-related events
177      * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
178      * @return provider
179      */
180     public static CartesianAdjointDynamicsProvider buildBoundedFuelCostProvider(final String adjointName,
181                                                                                 final double massFlowRateFactor,
182                                                                                 final double maximumThrustMagnitude,
183                                                                                 final EventDetectionSettings eventDetectionSettings,
184                                                                                 final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
185         return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
186 
187             @Override
188             public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
189                 return new CartesianAdjointDerivativesProvider(new CartesianFuelCost(adjointName, massFlowRateFactor,
190                         maximumThrustMagnitude, eventDetectionSettings), cartesianAdjointEquationTerms);
191             }
192 
193             @Override
194             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
195                 final T zero = field.getZero();
196                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldCartesianFuelCost<>(adjointName,
197                         zero.newInstance(massFlowRateFactor), zero.newInstance(maximumThrustMagnitude),
198                         new FieldEventDetectionSettings<>(field, eventDetectionSettings)), cartesianAdjointEquationTerms);
199             }
200         };
201     }
202 
203     /**
204      * Method building a provider with bounded Cartesian fuel penalized with a quadratic term.
205      * @param adjointName adjoint name
206      * @param massFlowRateFactor mass flow rate factor
207      * @param maximumThrustMagnitude maximum thrust magnitude
208      * @param epsilon penalty weight
209      * @param eventDetectionSettings detection settings for adjoint-related events
210      * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
211      * @return provider
212      */
213     public static CartesianAdjointDynamicsProvider buildQuadraticPenaltyFuelCostProvider(final String adjointName,
214                                                                                          final double massFlowRateFactor,
215                                                                                          final double maximumThrustMagnitude,
216                                                                                          final double epsilon,
217                                                                                          final EventDetectionSettings eventDetectionSettings,
218                                                                                          final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
219         return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
220 
221             @Override
222             public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
223                 return new CartesianAdjointDerivativesProvider(new QuadraticPenaltyCartesianFuel(adjointName, massFlowRateFactor,
224                         maximumThrustMagnitude, epsilon, eventDetectionSettings), cartesianAdjointEquationTerms);
225             }
226 
227             @Override
228             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
229                 final T zero = field.getZero();
230                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldQuadraticPenaltyCartesianFuel<>(adjointName,
231                         zero.newInstance(massFlowRateFactor), zero.newInstance(maximumThrustMagnitude),
232                         zero.newInstance(epsilon), new FieldEventDetectionSettings<>(field, eventDetectionSettings)),
233                         cartesianAdjointEquationTerms);
234             }
235         };
236     }
237 
238     /**
239      * Method building a provider with bounded Cartesian fuel penalized with a logarithmic barrier.
240      * @param adjointName adjoint name
241      * @param massFlowRateFactor mass flow rate factor
242      * @param maximumThrustMagnitude maximum thrust magnitude
243      * @param epsilon penalty weight
244      * @param cartesianAdjointEquationTerms Cartesian adjoint equation terms
245      * @return provider
246      */
247     public static CartesianAdjointDynamicsProvider buildLogarithmicBarrierFuelCostProvider(final String adjointName,
248                                                                                            final double massFlowRateFactor,
249                                                                                            final double maximumThrustMagnitude,
250                                                                                            final double epsilon,
251                                                                                            final CartesianAdjointEquationTerm... cartesianAdjointEquationTerms) {
252         return new CartesianAdjointDynamicsProvider(adjointName, getDimension(massFlowRateFactor)) {
253 
254             @Override
255             public CartesianAdjointDerivativesProvider buildAdditionalDerivativesProvider() {
256                 return new CartesianAdjointDerivativesProvider(new LogarithmicBarrierCartesianFuel(adjointName, massFlowRateFactor,
257                         maximumThrustMagnitude, epsilon), cartesianAdjointEquationTerms);
258             }
259 
260             @Override
261             public <T extends CalculusFieldElement<T>> FieldCartesianAdjointDerivativesProvider<T> buildFieldAdditionalDerivativesProvider(final Field<T> field) {
262                 final T zero = field.getZero();
263                 return new FieldCartesianAdjointDerivativesProvider<>(new FieldLogarithmicBarrierCartesianFuel<>(adjointName,
264                         zero.newInstance(massFlowRateFactor), zero.newInstance(maximumThrustMagnitude),
265                         zero.newInstance(epsilon)), cartesianAdjointEquationTerms);
266             }
267         };
268     }
269 
270     /**
271      * Get the adjoint dimension.
272      * @param massFlowRateFactor mass flow rate factor
273      * @return dimension
274      */
275     private static int getDimension(final double massFlowRateFactor) {
276         return massFlowRateFactor == 0. ? 6 : 7;
277     }
278 }