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