1 /* Copyright 2002-2026 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 package org.orekit.forces;
18
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.stream.Stream;
22
23 import org.hipparchus.CalculusFieldElement;
24 import org.hipparchus.Field;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.orekit.propagation.FieldSpacecraftState;
28 import org.orekit.propagation.SpacecraftState;
29 import org.orekit.propagation.events.EventDetector;
30 import org.orekit.propagation.events.EventDetectorsProvider;
31 import org.orekit.propagation.events.FieldEventDetector;
32 import org.orekit.propagation.numerical.FieldTimeDerivativesEquations;
33 import org.orekit.propagation.numerical.TimeDerivativesEquations;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.time.FieldAbsoluteDate;
36 import org.orekit.utils.drivers.ParameterDriver;
37 import org.orekit.utils.drivers.ParameterDriversProvider;
38
39 /** This interface represents a force modifying spacecraft motion.
40 *
41 * <p>
42 * Objects implementing this interface are intended to be added to a
43 * {@link org.orekit.propagation.numerical.NumericalPropagator numerical propagator}
44 * before the propagation is started.
45 *
46 * <p>
47 * The propagator will call at each step the {@link #addContribution(SpacecraftState,
48 * TimeDerivativesEquations)} method. The force model instance will extract all the
49 * state data it needs (date, position, velocity, frame, attitude, mass) from the first
50 * parameter. From these state data, it will compute the perturbing acceleration. It
51 * will then add this acceleration to the second parameter which will take this
52 * contribution into account and will use the Gauss equations to evaluate its impact
53 * on the global state derivative.
54 * </p>
55 * <p>
56 * Force models which create discontinuous acceleration patterns (typically for maneuvers
57 * start/stop or solar eclipses entry/exit) must provide one or more {@link
58 * org.orekit.propagation.events.EventDetector events detectors} to the
59 * propagator thanks to their {@link #getEventDetectors()} method. This method
60 * is called once just before propagation starts. The events states will be checked by
61 * the propagator to ensure accurate propagation and proper events handling.
62 * </p>
63 *
64 * @author Mathieu Roméro
65 * @author Luc Maisonobe
66 * @author Véronique Pommier-Maurussane
67 * @author Melina Vanel
68 */
69 public interface ForceModel extends ParameterDriversProvider, EventDetectorsProvider {
70
71 /**
72 * Initialize the force model at the start of propagation. This method will be called
73 * before any calls to {@link #addContribution(SpacecraftState, TimeDerivativesEquations)},
74 * {@link #addContribution(FieldSpacecraftState, FieldTimeDerivativesEquations)},
75 * {@link #acceleration(SpacecraftState, double[])} or {@link #acceleration(FieldSpacecraftState, CalculusFieldElement[])}
76 *
77 * <p> The default implementation of this method does nothing.</p>
78 *
79 * @param initialState spacecraft state at the start of propagation.
80 * @param target date of propagation. Not equal to {@code initialState.getDate()}.
81 */
82 default void init(final SpacecraftState initialState, final AbsoluteDate target) {
83 }
84
85 /**
86 * Initialize the force model at the start of propagation. This method will be called
87 * before any calls to {@link #addContribution(SpacecraftState, TimeDerivativesEquations)},
88 * {@link #addContribution(FieldSpacecraftState, FieldTimeDerivativesEquations)},
89 * {@link #acceleration(SpacecraftState, double[])} or {@link #acceleration(FieldSpacecraftState, CalculusFieldElement[])}
90 *
91 * <p> The default implementation of this method does nothing.</p>
92 *
93 * @param initialState spacecraft state at the start of propagation.
94 * @param target date of propagation. Not equal to {@code initialState.getDate()}.
95 * @param <T> type of the elements
96 */
97 default <T extends CalculusFieldElement<T>> void init(final FieldSpacecraftState<T> initialState, final FieldAbsoluteDate<T> target) {
98 init(initialState.toSpacecraftState(), target.toAbsoluteDate());
99 }
100
101 /** {@inheritDoc}.*/
102 @Override
103 default Stream<EventDetector> getEventDetectors() {
104 return getEventDetectors(getParametersDrivers());
105 }
106
107 /** {@inheritDoc}.*/
108 @Override
109 default <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
110 return getFieldEventDetectors(field, getParametersDrivers());
111 }
112
113 /** Compute the contribution of the force model to the perturbing
114 * acceleration.
115 * <p>
116 * The default implementation simply adds the {@link #acceleration(SpacecraftState, double[]) acceleration}
117 * as a non-Keplerian acceleration.
118 * </p>
119 * @param s current state information: date, kinematics, attitude
120 * @param adder object where the contribution should be added
121 */
122 default void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder) {
123 final double[] parameters = getParameters();
124 adder.addNonKeplerianAcceleration(acceleration(s, getParameters()));
125 adder.addMassDerivative(getMassDerivative(s, parameters));
126 }
127
128 /** Compute the contribution of the force model to the perturbing
129 * acceleration.
130 * @param s current state information: date, kinematics, attitude
131 * @param adder object where the contribution should be added
132 * @param <T> type of the elements
133 */
134 default <T extends CalculusFieldElement<T>> void addContribution(final FieldSpacecraftState<T> s,
135 final FieldTimeDerivativesEquations<T> adder) {
136 final T[] parameters = getParameters(s.getDate().getField());
137 adder.addNonKeplerianAcceleration(acceleration(s, parameters));
138 adder.addMassDerivative(getMassDerivative(s, parameters));
139 }
140
141 /**
142 * Compute the mass rate. Zero by default.
143 * @param state current state information: date, kinematics, attitude
144 * @param parameters values of the force model parameters at state date
145 * @return mass rate (kg/s)
146 * @since 13.1
147 */
148 default double getMassDerivative(final SpacecraftState state, final double[] parameters) {
149 return 0.;
150 }
151
152 /**
153 * Compute the mass rate. Zero by default.
154 * @param <T> field type
155 * @param state current state information: date, kinematics, attitude
156 * @param parameters values of the force model parameters at state date
157 * @return mass rate (kg/s)
158 * @since 13.1
159 */
160 default <T extends CalculusFieldElement<T>> T getMassDerivative(final FieldSpacecraftState<T> state, final T[] parameters) {
161 return state.getMass().getField().getZero();
162 }
163
164 /** Check if force model depends on position only at a given, fixed date.
165 * @return true if force model depends on position only, false
166 * if it depends on mass or velocity, either directly or due to a dependency on attitude. False by default.
167 * @since 9.0
168 */
169 default boolean dependsOnPositionOnly() {
170 return false;
171 }
172
173 /** Check if force model depends on attitude's rotation rate or acceleration at a given, fixed date.
174 * If false, it essentially means that at most the attitude's rotation is used when computing the acceleration vector.
175 * The default implementation returns false as common forces do not.
176 * @return true if force model depends on attitude derivatives
177 * @since 12.1
178 */
179 default boolean dependsOnAttitudeRate() {
180 return false;
181 }
182
183 /** Compute acceleration.
184 * @param s current state information: date, kinematics, attitude
185 * @param parameters values of the force model parameters at state date,
186 * only 1 value for each parameterDriver
187 * @return acceleration in same frame as state
188 * @since 9.0
189 */
190 Vector3D acceleration(SpacecraftState s, double[] parameters);
191
192 /** Compute acceleration.
193 * @param s current state information: date, kinematics, attitude
194 * @param parameters values of the force model parameters at state date,
195 * only 1 value for each parameterDriver
196 * @return acceleration in same frame as state
197 * @param <T> type of the elements
198 * @since 9.0
199 */
200 <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(FieldSpacecraftState<T> s, T[] parameters);
201
202 /** {@inheritDoc}
203 * By default, no parameters. Override, for instance, to enable partial derivatives.
204 * */
205 @Override
206 default List<ParameterDriver> getParametersDrivers() {
207 return Collections.emptyList();
208 }
209 }