1 /* Copyright 2002-2022 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
18 package org.orekit.forces.maneuvers;
19
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.List;
23 import java.util.stream.Stream;
24
25 import org.hipparchus.CalculusFieldElement;
26 import org.hipparchus.Field;
27 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.orekit.attitudes.Attitude;
30 import org.orekit.attitudes.AttitudeProvider;
31 import org.orekit.attitudes.FieldAttitude;
32 import org.orekit.forces.AbstractForceModel;
33 import org.orekit.forces.maneuvers.propulsion.PropulsionModel;
34 import org.orekit.forces.maneuvers.trigger.ManeuverTriggers;
35 import org.orekit.propagation.FieldSpacecraftState;
36 import org.orekit.propagation.SpacecraftState;
37 import org.orekit.propagation.events.EventDetector;
38 import org.orekit.propagation.events.FieldEventDetector;
39 import org.orekit.propagation.numerical.FieldTimeDerivativesEquations;
40 import org.orekit.propagation.numerical.TimeDerivativesEquations;
41 import org.orekit.time.AbsoluteDate;
42 import org.orekit.time.FieldAbsoluteDate;
43 import org.orekit.utils.ParameterDriver;
44
45
46 /** A generic model for maneuvers.
47 * It contains:
48 * - An attitude override, this is the attitude used during the maneuver, it can be different than the one
49 * used for propagation;
50 * - 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).
51 * - A propulsion model from sub-package propulsion. It defines the thrust or ΔV, isp, flow rate etc..
52 * Both the propulsion model and the maneuver triggers can contain parameter drivers (for estimation).
53 * The convention here is that the propulsion model drivers are given before the maneuver triggers when calling the
54 * method {@link #getParametersDrivers()}
55 * @author Maxime Journot
56 * @since 10.2
57 */
58 public class Maneuver extends AbstractForceModel {
59
60 /** The attitude to override during the maneuver, if set. */
61 private final AttitudeProvider attitudeOverride;
62
63 /** Propulsion model to use for the thrust. */
64 private final PropulsionModel propulsionModel;
65
66 /** Maneuver triggers. */
67 private final ManeuverTriggers maneuverTriggers;
68
69 /** Generic maneuver constructor.
70 * @param attitudeOverride attitude provider for the attitude during the maneuver
71 * @param maneuverTriggers maneuver triggers
72 * @param propulsionModel propulsion model
73 */
74 public Maneuver(final AttitudeProvider attitudeOverride,
75 final ManeuverTriggers maneuverTriggers,
76 final PropulsionModel propulsionModel) {
77 this.maneuverTriggers = maneuverTriggers;
78 this.attitudeOverride = attitudeOverride;
79 this.propulsionModel = propulsionModel;
80 }
81
82 /** Get the name of the maneuver.
83 * The name can be in the propulsion model, in the maneuver triggers or both.
84 * If it is in both it should be the same since it refers to the same maneuver.
85 * The name is inferred from the propulsion model first, then from the maneuver triggers if
86 * the propulsion model had an empty name.
87 * @return the name
88 */
89 public String getName() {
90
91 //FIXME: Potentially, throw an exception if both propulsion model
92 // and maneuver triggers define a name but they are different
93 String name = propulsionModel.getName();
94
95 if (name.length() < 1) {
96 name = maneuverTriggers.getName();
97 }
98 return name;
99 }
100
101 /** Get the attitude override used for the maneuver.
102 * @return the attitude override
103 */
104 public AttitudeProvider getAttitudeOverride() {
105 return attitudeOverride;
106 }
107
108 /** Get the propulsion model.
109 * @return the propulsion model
110 */
111 public PropulsionModel getPropulsionModel() {
112 return propulsionModel;
113 }
114
115 /** Get the maneuver triggers.
116 * @return the maneuver triggers
117 */
118 public ManeuverTriggers getManeuverTriggers() {
119 return maneuverTriggers;
120 }
121
122 /** {@inheritDoc} */
123 @Override
124 public boolean dependsOnPositionOnly() {
125 return false;
126 }
127
128 /** {@inheritDoc} */
129 @Override
130 public void init(final SpacecraftState initialState, final AbsoluteDate target) {
131 propulsionModel.init(initialState, target);
132 maneuverTriggers.init(initialState, target);
133 }
134
135 /** {@inheritDoc} */
136 @Override
137 public <T extends CalculusFieldElement<T>> void init(final FieldSpacecraftState<T> initialState, final FieldAbsoluteDate<T> target) {
138 propulsionModel.init(initialState, target);
139 maneuverTriggers.init(initialState, target);
140 }
141
142 /** {@inheritDoc} */
143 @Override
144 public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder) {
145
146 // Get the parameters associated to the maneuver (from ForceModel)
147 final double[] parameters = getParameters();
148
149 // If the maneuver is active, compute and add its contribution
150 // Maneuver triggers are used to check if the maneuver is currently firing or not
151 // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
152 if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {
153
154 // Compute thrust acceleration in inertial frame
155 adder.addNonKeplerianAcceleration(acceleration(s, parameters));
156
157 // Compute flow rate using the propulsion model
158 // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
159 adder.addMassDerivative(propulsionModel.getMassDerivatives(s, getPropulsionModelParameters(parameters)));
160 }
161 }
162
163 /** {@inheritDoc} */
164 @Override
165 public <T extends CalculusFieldElement<T>> void addContribution(final FieldSpacecraftState<T> s,
166 final FieldTimeDerivativesEquations<T> adder) {
167
168 // Get the parameters associated to the maneuver (from ForceModel)
169 final T[] parameters = getParameters(s.getDate().getField());
170
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
176 // Compute thrust acceleration in inertial frame
177 adder.addNonKeplerianAcceleration(acceleration(s, parameters));
178
179 // Compute flow rate using the propulsion model
180 // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
181 adder.addMassDerivative(propulsionModel.getMassDerivatives(s, getPropulsionModelParameters(parameters)));
182 }
183 }
184
185 @Override
186 public Vector3D acceleration(final SpacecraftState s, final double[] parameters) {
187
188 // If the maneuver is active, compute and add its contribution
189 // Maneuver triggers are used to check if the maneuver is currently firing or not
190 // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
191 if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {
192
193 // Attitude during maneuver
194 final Attitude maneuverAttitude =
195 attitudeOverride == null ?
196 s.getAttitude() :
197 attitudeOverride.getAttitude(s.getOrbit(),
198 s.getDate(),
199 s.getFrame());
200
201 // Compute acceleration from propulsion model
202 // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
203 return propulsionModel.getAcceleration(s, maneuverAttitude, getPropulsionModelParameters(parameters));
204 } else {
205 // Constant (and null) acceleration when not firing
206 return Vector3D.ZERO;
207 }
208 }
209
210 @Override
211 public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> s, final T[] parameters) {
212
213 // If the maneuver is active, compute and add its contribution
214 // Maneuver triggers are used to check if the maneuver is currently firing or not
215 // Specific drivers for the triggers are extracted from the array given by the ForceModel interface
216 if (maneuverTriggers.isFiring(s.getDate(), getManeuverTriggersParameters(parameters))) {
217
218 // Attitude during maneuver
219 final FieldAttitude<T> maneuverAttitude =
220 attitudeOverride == null ?
221 s.getAttitude() :
222 attitudeOverride.getAttitude(s.getOrbit(),
223 s.getDate(),
224 s.getFrame());
225
226 // Compute acceleration from propulsion model
227 // Specific drivers for the propulsion model are extracted from the array given by the ForceModel interface
228 return propulsionModel.getAcceleration(s, maneuverAttitude, getPropulsionModelParameters(parameters));
229 } else {
230 // Constant (and null) acceleration when not firing
231 return FieldVector3D.getZero(s.getMu().getField());
232 }
233 }
234
235 /** {@inheritDoc} */
236 @Override
237 public Stream<EventDetector> getEventsDetectors() {
238 // Event detectors are extracted from the maneuver triggers
239 return maneuverTriggers.getEventsDetectors();
240 }
241
242 /** {@inheritDoc} */
243 @Override
244 public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
245 // Event detectors are extracted from the maneuver triggers
246 return maneuverTriggers.getFieldEventsDetectors(field);
247 }
248
249 @Override
250 public List<ParameterDriver> getParametersDrivers() {
251
252 // Extract parameter drivers from propulsion model and maneuver triggers
253 final List<ParameterDriver> propulsionModelDrivers = propulsionModel.getParametersDrivers();
254 final List<ParameterDriver> maneuverTriggersDrivers = maneuverTriggers.getParametersDrivers();
255 final int propulsionModelDriversLength = propulsionModelDrivers.size();
256 final int maneuverTriggersDriversLength = maneuverTriggersDrivers.size();
257
258 // Prepare final drivers' array
259 final List<ParameterDriver> drivers = new ArrayList<>(propulsionModelDriversLength + maneuverTriggersDriversLength);
260
261 // Convention: Propulsion drivers are given before maneuver triggers drivers
262 // Add propulsion drivers first
263 drivers.addAll(0, propulsionModelDrivers);
264
265 // Then maneuver triggers' drivers
266 drivers.addAll(propulsionModelDriversLength, maneuverTriggersDrivers);
267
268 // Return full drivers' array
269 return drivers;
270 }
271
272 /** Extract propulsion model parameters from the parameters' array called in by the ForceModel interface.
273 * Convention: Propulsion parameters are given before maneuver triggers parameters
274 * @param parameters parameters' array called in by ForceModel interface
275 * @return propulsion model parameters
276 */
277 private double[] getPropulsionModelParameters(final double[] parameters) {
278 return Arrays.copyOfRange(parameters, 0, propulsionModel.getParametersDrivers().size());
279 }
280
281 /** Extract propulsion model parameters from the parameters' array called in by the ForceModel interface.
282 * Convention: Propulsion parameters are given before maneuver triggers parameters
283 * @param parameters parameters' array called in by ForceModel interface
284 * @param <T> extends CalculusFieldElement<T>
285 * @return propulsion model parameters
286 */
287 private <T extends CalculusFieldElement<T>> T[] getPropulsionModelParameters(final T[] parameters) {
288 return Arrays.copyOfRange(parameters, 0, propulsionModel.getParametersDrivers().size());
289 }
290
291 /** Extract maneuver triggers' parameters from the parameters' array called in by the ForceModel interface.
292 * Convention: Propulsion parameters are given before maneuver triggers parameters
293 * @param parameters parameters' array called in by ForceModel interface
294 * @return maneuver triggers' parameters
295 */
296 private double[] getManeuverTriggersParameters(final double[] parameters) {
297 final int nbPropulsionModelDrivers = propulsionModel.getParametersDrivers().size();
298 return Arrays.copyOfRange(parameters, nbPropulsionModelDrivers,
299 nbPropulsionModelDrivers + maneuverTriggers.getParametersDrivers().size());
300 }
301
302 /** Extract maneuver triggers' parameters from the parameters' array called in by the ForceModel interface.
303 * Convention: Propulsion parameters are given before maneuver triggers parameters
304 * @param parameters parameters' array called in by ForceModel interface
305 * @param <T> extends CalculusFieldElement<T>
306 * @return maneuver triggers' parameters
307 */
308 private <T extends CalculusFieldElement<T>> T[] getManeuverTriggersParameters(final T[] parameters) {
309 final int nbPropulsionModelDrivers = propulsionModel.getParametersDrivers().size();
310 return Arrays.copyOfRange(parameters, nbPropulsionModelDrivers,
311 nbPropulsionModelDrivers + maneuverTriggers.getParametersDrivers().size());
312 }
313 }