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