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&eacute;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 }