1   /* Copyright 2002-2020 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.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.orekit.attitudes.AttitudeProvider;
27  import org.orekit.errors.OrekitException;
28  import org.orekit.errors.OrekitMessages;
29  import org.orekit.frames.Frame;
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.OrekitStepNormalizer;
34  import org.orekit.time.AbsoluteDate;
35  import org.orekit.utils.TimeSpanMap;
36  import org.orekit.utils.TimeStampedPVCoordinates;
37  
38  /** Common handling of {@link Propagator} methods for analytical propagators.
39   * <p>
40   * This abstract class allows to provide easily the full set of {@link Propagator}
41   * methods, including all propagation modes support and discrete events support for
42   * any simple propagation method.
43   * </p>
44   * @author Luc Maisonobe
45   */
46  public abstract class AbstractPropagator implements Propagator {
47  
48      /** Propagation mode. */
49      private int mode;
50  
51      /** Fixed step size. */
52      private double fixedStepSize;
53  
54      /** Step handler. */
55      private OrekitStepHandler stepHandler;
56  
57      /** Start date. */
58      private AbsoluteDate startDate;
59  
60      /** Attitude provider. */
61      private AttitudeProvider attitudeProvider;
62  
63      /** Additional state providers. */
64      private final List<AdditionalStateProvider> additionalStateProviders;
65  
66      /** States managed by neither additional equations nor state providers. */
67      private final Map<String, TimeSpanMap<double[]>> unmanagedStates;
68  
69      /** Initial state. */
70      private SpacecraftState initialState;
71  
72      /** Build a new instance.
73       */
74      protected AbstractPropagator() {
75          mode                     = SLAVE_MODE;
76          stepHandler              = null;
77          fixedStepSize            = Double.NaN;
78          additionalStateProviders = new ArrayList<AdditionalStateProvider>();
79          unmanagedStates          = new HashMap<>();
80      }
81  
82      /** Set a start date.
83       * @param startDate start date
84       */
85      protected void setStartDate(final AbsoluteDate startDate) {
86          this.startDate = startDate;
87      }
88  
89      /** Get the start date.
90       * @return start date
91       */
92      protected AbsoluteDate getStartDate() {
93          return startDate;
94      }
95  
96      /**  {@inheritDoc} */
97      public AttitudeProvider getAttitudeProvider() {
98          return attitudeProvider;
99      }
100 
101     /**  {@inheritDoc} */
102     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
103         this.attitudeProvider = attitudeProvider;
104     }
105 
106     /** {@inheritDoc} */
107     public SpacecraftState getInitialState() {
108         return initialState;
109     }
110 
111     /** {@inheritDoc} */
112     public int getMode() {
113         return mode;
114     }
115 
116     /** {@inheritDoc} */
117     public Frame getFrame() {
118         return initialState.getFrame();
119     }
120 
121     /** {@inheritDoc} */
122     public void resetInitialState(final SpacecraftState state) {
123         initialState = state;
124         setStartDate(state.getDate());
125     }
126 
127     /** {@inheritDoc} */
128     public void setSlaveMode() {
129         mode          = SLAVE_MODE;
130         stepHandler   = null;
131         fixedStepSize = Double.NaN;
132     }
133 
134     /** {@inheritDoc} */
135     public void setMasterMode(final double h,
136                               final OrekitFixedStepHandler handler) {
137         setMasterMode(new OrekitStepNormalizer(h, handler));
138         fixedStepSize = h;
139     }
140 
141     /** {@inheritDoc} */
142     public void setMasterMode(final OrekitStepHandler handler) {
143         mode          = MASTER_MODE;
144         stepHandler   = handler;
145         fixedStepSize = Double.NaN;
146     }
147 
148     /** {@inheritDoc} */
149     public void setEphemerisMode() {
150         mode          = EPHEMERIS_GENERATION_MODE;
151         stepHandler   = null;
152         fixedStepSize = Double.NaN;
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public void setEphemerisMode(final OrekitStepHandler handler) {
158         mode          = EPHEMERIS_GENERATION_MODE;
159         stepHandler   = handler;
160         fixedStepSize = Double.NaN;
161     }
162 
163     /** {@inheritDoc} */
164     public void addAdditionalStateProvider(final AdditionalStateProvider additionalStateProvider) {
165 
166         // check if the name is already used
167         if (isAdditionalStateManaged(additionalStateProvider.getName())) {
168             // this additional state is already registered, complain
169             throw new OrekitException(OrekitMessages.ADDITIONAL_STATE_NAME_ALREADY_IN_USE,
170                                       additionalStateProvider.getName());
171         }
172 
173         // this is really a new name, add it
174         additionalStateProviders.add(additionalStateProvider);
175 
176     }
177 
178     /** {@inheritDoc} */
179     public List<AdditionalStateProvider> getAdditionalStateProviders() {
180         return Collections.unmodifiableList(additionalStateProviders);
181     }
182 
183     /** Update state by adding all additional states.
184      * @param original original state
185      * @return updated state, with all additional states included
186      * @see #addAdditionalStateProvider(AdditionalStateProvider)
187      */
188     protected SpacecraftStateate">SpacecraftState updateAdditionalStates(final SpacecraftState original) {
189 
190         // start with original state,
191         // which may already contain additional states, for example in interpolated ephemerides
192         SpacecraftState updated = original;
193 
194         // update the states not managed by providers
195         for (final Map.Entry<String, TimeSpanMap<double[]>> entry : unmanagedStates.entrySet()) {
196             updated = updated.addAdditionalState(entry.getKey(),
197                                                  entry.getValue().get(original.getDate()));
198         }
199 
200         // update the additional states managed by providers
201         for (final AdditionalStateProvider provider : additionalStateProviders) {
202             updated = updated.addAdditionalState(provider.getName(),
203                                                  provider.getAdditionalState(updated));
204         }
205 
206         return updated;
207 
208     }
209 
210     /** {@inheritDoc} */
211     public boolean isAdditionalStateManaged(final String name) {
212         for (final AdditionalStateProvider provider : additionalStateProviders) {
213             if (provider.getName().equals(name)) {
214                 return true;
215             }
216         }
217         return false;
218     }
219 
220     /** {@inheritDoc} */
221     public String[] getManagedAdditionalStates() {
222         final String[] managed = new String[additionalStateProviders.size()];
223         for (int i = 0; i < managed.length; ++i) {
224             managed[i] = additionalStateProviders.get(i).getName();
225         }
226         return managed;
227     }
228 
229     /** Get the fixed step size.
230      * @return fixed step size (or NaN if there are no fixed step size).
231      */
232     protected double getFixedStepSize() {
233         return fixedStepSize;
234     }
235 
236     /** Get the step handler.
237      * @return step handler
238      */
239     protected OrekitStepHandler getStepHandler() {
240         return stepHandler;
241     }
242 
243     /** {@inheritDoc} */
244     public abstract BoundedPropagator getGeneratedEphemeris();
245 
246     /** {@inheritDoc} */
247     public abstract <T extends EventDetector> void addEventDetector(T detector);
248 
249     /** {@inheritDoc} */
250     public abstract Collection<EventDetector> getEventsDetectors();
251 
252     /** {@inheritDoc} */
253     public abstract void clearEventsDetectors();
254 
255     /** {@inheritDoc} */
256     public SpacecraftState propagate(final AbsoluteDate target) {
257         if (startDate == null) {
258             startDate = getInitialState().getDate();
259         }
260         return propagate(startDate, target);
261     }
262 
263     /** {@inheritDoc} */
264     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
265         return propagate(date).getPVCoordinates(frame);
266     }
267 
268     /** Initialize propagation.
269      * @since 10.1
270      */
271     protected void initializePropagation() {
272 
273         unmanagedStates.clear();
274 
275         if (initialState != null) {
276             // there is an initial state
277             // (null initial states occur for example in interpolated ephemerides)
278             // copy the additional states present in initialState but otherwise not managed
279             for (final Map.Entry<String, double[]> initial : initialState.getAdditionalStates().entrySet()) {
280                 if (!isAdditionalStateManaged(initial.getKey())) {
281                     // this additional state is in the initial state, but is unknown to the propagator
282                     // we store it in a way event handlers may change it
283                     unmanagedStates.put(initial.getKey(), new TimeSpanMap<>(initial.getValue()));
284                 }
285             }
286         }
287     }
288 
289     /** Notify about a state change.
290      * @param state new state
291      */
292     protected void stateChanged(final SpacecraftState state) {
293         final AbsoluteDate date    = state.getDate();
294         final boolean      forward = date.durationFrom(getStartDate()) >= 0.0;
295         for (final Map.Entry<String, double[]> changed : state.getAdditionalStates().entrySet()) {
296             final TimeSpanMap<double[]> tsm = unmanagedStates.get(changed.getKey());
297             if (tsm != null) {
298                 // this is an unmanaged state
299                 if (forward) {
300                     tsm.addValidAfter(changed.getValue(), date);
301                 } else {
302                     tsm.addValidBefore(changed.getValue(), date);
303                 }
304             }
305         }
306     }
307 
308 }