1 /* Copyright 2002-2025 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.propagation;
18
19 import java.util.Collection;
20 import java.util.List;
21
22 import org.hipparchus.geometry.euclidean.threed.Rotation;
23 import org.hipparchus.geometry.euclidean.threed.Vector3D;
24 import org.hipparchus.linear.RealMatrix;
25 import org.orekit.attitudes.AttitudeProvider;
26 import org.orekit.attitudes.FrameAlignedProvider;
27 import org.orekit.frames.Frame;
28 import org.orekit.frames.Frames;
29 import org.orekit.orbits.PositionAngleType;
30 import org.orekit.propagation.events.EventDetector;
31 import org.orekit.propagation.sampling.OrekitFixedStepHandler;
32 import org.orekit.propagation.sampling.OrekitStepHandler;
33 import org.orekit.propagation.sampling.StepHandlerMultiplexer;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.utils.DoubleArrayDictionary;
36 import org.orekit.utils.PVCoordinatesProvider;
37 import org.orekit.utils.TimeStampedPVCoordinates;
38
39 /** This interface provides a way to propagate an orbit at any time.
40 *
41 * <p>This interface is the top-level abstraction for orbit propagation.
42 * It only allows propagation to a predefined date.
43 * It is implemented by analytical models which have no time limit,
44 * by orbit readers based on external data files, by numerical integrators
45 * using rich force models and by continuous models built after numerical
46 * integration has been completed and dense output data as been
47 * gathered.</p>
48 * <p>Note that one single propagator cannot be called from multiple threads.
49 * Its configuration can be changed as there is at least a {@link
50 * #resetInitialState(SpacecraftState)} method, and even propagators that do
51 * not support resetting state (like the {@link
52 * org.orekit.propagation.analytical.tle.TLEPropagator TLEPropagator} do
53 * cache some internal data during computation. However, as long as they
54 * are configured with independent building blocks (mainly event handlers
55 * and step handlers that may preserve some internal state), and as long
56 * as they are called from one thread only, they <em>can</em> be used in
57 * multi-threaded applications. Synchronizing several propagators to run in
58 * parallel is also possible using {@link PropagatorsParallelizer}.</p>
59 * @author Luc Maisonobe
60 * @author Véronique Pommier-Maurussane
61 *
62 */
63
64 public interface Propagator extends PVCoordinatesProvider {
65
66 /** Default mass. */
67 double DEFAULT_MASS = 1000.0;
68
69 /**
70 * Get a default law using the given frames.
71 *
72 * @param frames the set of frames to use.
73 * @return attitude law.
74 */
75 static AttitudeProvider getDefaultLaw(final Frames frames) {
76 return new FrameAlignedProvider(Rotation.IDENTITY, frames.getEME2000());
77 }
78
79 /** Get the multiplexer holding all step handlers.
80 * @return multiplexer holding all step handlers
81 * @since 11.0
82 */
83 StepHandlerMultiplexer getMultiplexer();
84
85 /** Remove all step handlers.
86 * <p>This convenience method is equivalent to call {@code getMultiplexer().clear()}</p>
87 * @see #getMultiplexer()
88 * @see StepHandlerMultiplexer#clear()
89 * @since 11.0
90 */
91 default void clearStepHandlers() {
92 getMultiplexer().clear();
93 }
94
95 /** Set a single handler for fixed stepsizes.
96 * <p>This convenience method is equivalent to call {@code getMultiplexer().clear()}
97 * followed by {@code getMultiplexer().add(h, handler)}</p>
98 * @param h fixed stepsize (s)
99 * @param handler handler called at the end of each finalized step
100 * @see #getMultiplexer()
101 * @see StepHandlerMultiplexer#add(double, OrekitFixedStepHandler)
102 * @since 11.0
103 */
104 default void setStepHandler(final double h, final OrekitFixedStepHandler handler) {
105 getMultiplexer().clear();
106 getMultiplexer().add(h, handler);
107 }
108
109 /** Set a single handler for variable stepsizes.
110 * <p>This convenience method is equivalent to call {@code getMultiplexer().clear()}
111 * followed by {@code getMultiplexer().add(handler)}</p>
112 * @param handler handler called at the end of each finalized step
113 * @see #getMultiplexer()
114 * @see StepHandlerMultiplexer#add(OrekitStepHandler)
115 * @since 11.0
116 */
117 default void setStepHandler(final OrekitStepHandler handler) {
118 getMultiplexer().clear();
119 getMultiplexer().add(handler);
120 }
121
122 /**
123 * Set up an ephemeris generator that will monitor the propagation for building
124 * an ephemeris from it once completed.
125 *
126 * <p>
127 * This generator can be used when the user needs fast random access to the orbit
128 * state at any time between the initial and target times. A typical example is the
129 * implementation of search and iterative algorithms that may navigate forward and
130 * backward inside the propagation range before finding their result even if the
131 * propagator used is integration-based and only goes from one initial time to one
132 * target time.
133 * </p>
134 * <p>
135 * Beware that when used with integration-based propagators, the generator will
136 * store <strong>all</strong> intermediate results. It is therefore memory intensive
137 * for long integration-based ranges and high precision/short time steps. When
138 * used with analytical propagators, the generator only stores start/stop time
139 * and a reference to the analytical propagator itself to call it back as needed,
140 * so it is less memory intensive.
141 * </p>
142 * <p>
143 * The returned ephemeris generator will be initially empty, it will be filled
144 * with propagation data when a subsequent call to either {@link #propagate(AbsoluteDate)
145 * propagate(target)} or {@link #propagate(AbsoluteDate, AbsoluteDate)
146 * propagate(start, target)} is called. The proper way to use this method is
147 * therefore to do:
148 * </p>
149 * <pre>
150 * EphemerisGenerator generator = propagator.getEphemerisGenerator();
151 * propagator.propagate(target);
152 * BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
153 * </pre>
154 * @return ephemeris generator
155 */
156 EphemerisGenerator getEphemerisGenerator();
157
158 /** Get the propagator initial state.
159 * @return initial state
160 */
161 SpacecraftState getInitialState();
162
163 /** Reset the propagator initial state.
164 * @param state new initial state to consider
165 */
166 void resetInitialState(SpacecraftState state);
167
168 /** Add a set of user-specified data to be computed along with the orbit propagation.
169 * @param additionalDataProvider provider for additional data
170 */
171 void addAdditionalDataProvider(AdditionalDataProvider<?> additionalDataProvider);
172
173 /** Get an unmodifiable list of providers for additional data.
174 * @return providers for the additional data
175 */
176 List<AdditionalDataProvider<?>> getAdditionalDataProviders();
177
178 /** Check if an additional data is managed.
179 * <p>
180 * Managed data are the ones for which the propagators know how to compute
181 * its evolution. They correspond to additional data for which a
182 * {@link AdditionalDataProvider provider} has been registered by calling the
183 * {@link #addAdditionalDataProvider(AdditionalDataProvider) addAdditionalDataProvider} method.
184 * </p>
185 * <p>
186 * Additional data that are present in the {@link #getInitialState() initial state}
187 * but have no evolution method registered are <em>not</em> considered as managed data.
188 * These unmanaged additional data are not lost during propagation, though. Their
189 * value are piecewise constant between state resets that may change them if some
190 * event handler {@link
191 * org.orekit.propagation.events.handlers.EventHandler#resetState(EventDetector,
192 * SpacecraftState) resetState} method is called at an event occurrence and happens
193 * to change the unmanaged additional data.
194 * </p>
195 * @param name name of the additional data
196 * @return true if the additional data is managed
197 */
198 boolean isAdditionalDataManaged(String name);
199
200 /** Get all the names of all managed additional data.
201 * @return names of all managed additional data
202 */
203 String[] getManagedAdditionalData();
204
205 /** Add an event detector.
206 * @param detector event detector to add
207 * @see #clearEventsDetectors()
208 * @see #getEventDetectors()
209 * @param <T> class type for the generic version
210 */
211 <T extends EventDetector> void addEventDetector(T detector);
212
213 /** Get all the events detectors that have been added.
214 * @return an unmodifiable collection of the added detectors
215 * @see #addEventDetector(EventDetector)
216 * @see #clearEventsDetectors()
217 */
218 Collection<EventDetector> getEventDetectors();
219
220 /** Remove all events detectors.
221 * @see #addEventDetector(EventDetector)
222 * @see #getEventDetectors()
223 */
224 void clearEventsDetectors();
225
226 /** Get attitude provider.
227 * @return attitude provider
228 */
229 AttitudeProvider getAttitudeProvider();
230
231 /** Set attitude provider.
232 * @param attitudeProvider attitude provider
233 */
234 void setAttitudeProvider(AttitudeProvider attitudeProvider);
235
236 /** Get the frame in which the orbit is propagated.
237 * <p>
238 * The propagation frame is the definition frame of the initial
239 * state, so this method should be called after this state has
240 * been set, otherwise it may return null.
241 * </p>
242 * @return frame in which the orbit is propagated
243 * @see #resetInitialState(SpacecraftState)
244 */
245 Frame getFrame();
246
247 /** Set up computation of State Transition Matrix and Jacobians matrix with respect to parameters.
248 * <p>
249 * If this method is called, both State Transition Matrix and Jacobians with respect to the
250 * force models parameters that will be selected when propagation starts will be automatically
251 * computed, and the harvester will allow to retrieve them.
252 * </p>
253 * <p>
254 * The arguments for initial matrices <em>must</em> be compatible with the {@link org.orekit.orbits.OrbitType
255 * orbit type} and {@link PositionAngleType position angle} that will be used by the propagator.
256 * </p>
257 * <p>
258 * The default implementation throws an exception as the method is not supported by all propagators.
259 * </p>
260 * @param stmName State Transition Matrix state name
261 * @param initialStm initial State Transition Matrix ∂Y/∂Y₀,
262 * if null (which is the most frequent case), assumed to be 6x6 identity
263 * @param initialJacobianColumns initial columns of the Jacobians matrix with respect to parameters,
264 * if null or if some selected parameters are missing from the dictionary, the corresponding
265 * initial column is assumed to be 0
266 * @return harvester to retrieve computed matrices during and after propagation
267 * @since 11.1
268 */
269 default MatricesHarvester setupMatricesComputation(final String stmName, final RealMatrix initialStm,
270 final DoubleArrayDictionary initialJacobianColumns) {
271 throw new UnsupportedOperationException();
272 }
273
274 /** Propagate towards a target date.
275 * <p>Simple propagators use only the target date as the specification for
276 * computing the propagated state. More feature rich propagators can consider
277 * other information and provide different operating modes or G-stop
278 * facilities to stop at pinpointed events occurrences. In these cases, the
279 * target date is only a hint, not a mandatory objective.</p>
280 * @param target target date towards which orbit state should be propagated
281 * @return propagated state
282 */
283 SpacecraftState propagate(AbsoluteDate target);
284
285 /** Propagate from a start date towards a target date.
286 * <p>Those propagators use a start date and a target date to
287 * compute the propagated state. For propagators using event detection mechanism,
288 * if the provided start date is different from the initial state date, a first,
289 * simple propagation is performed, without processing any event computation.
290 * Then complete propagation is performed from start date to target date.</p>
291 * @param start start date from which orbit state should be propagated
292 * @param target target date to which orbit state should be propagated
293 * @return propagated state
294 */
295 SpacecraftState propagate(AbsoluteDate start, AbsoluteDate target);
296
297 /** {@inheritDoc} */
298 @Override
299 default TimeStampedPVCoordinates getPVCoordinates(AbsoluteDate date, Frame frame) {
300 return propagate(date).getPVCoordinates(frame);
301 }
302
303 /** {@inheritDoc} */
304 @Override
305 default Vector3D getPosition(AbsoluteDate date, Frame frame) {
306 return propagate(date).getPosition(frame);
307 }
308
309 }