1   /* Copyright 2002-2021 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.Collections;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.errors.OrekitException;
27  import org.orekit.errors.OrekitMessages;
28  import org.orekit.frames.Frame;
29  import org.orekit.propagation.sampling.StepHandlerMultiplexer;
30  import org.orekit.time.AbsoluteDate;
31  import org.orekit.utils.TimeSpanMap;
32  import org.orekit.utils.TimeStampedPVCoordinates;
33  
34  /** Common handling of {@link Propagator} methods for analytical propagators.
35   * <p>
36   * This abstract class allows to provide easily the full set of {@link Propagator}
37   * methods, including all propagation modes support and discrete events support for
38   * any simple propagation method.
39   * </p>
40   * @author Luc Maisonobe
41   */
42  public abstract class AbstractPropagator implements Propagator {
43  
44      /** Multiplexer for step handlers. */
45      private StepHandlerMultiplexer multiplexer;
46  
47      /** Start date. */
48      private AbsoluteDate startDate;
49  
50      /** Attitude provider. */
51      private AttitudeProvider attitudeProvider;
52  
53      /** Additional state providers. */
54      private final List<AdditionalStateProvider> additionalStateProviders;
55  
56      /** States managed by neither additional equations nor state providers. */
57      private final Map<String, TimeSpanMap<double[]>> unmanagedStates;
58  
59      /** Initial state. */
60      private SpacecraftState initialState;
61  
62      /** Build a new instance.
63       */
64      protected AbstractPropagator() {
65          multiplexer              = new StepHandlerMultiplexer();
66          additionalStateProviders = new ArrayList<AdditionalStateProvider>();
67          unmanagedStates          = new HashMap<>();
68      }
69  
70      /** Set a start date.
71       * @param startDate start date
72       */
73      protected void setStartDate(final AbsoluteDate startDate) {
74          this.startDate = startDate;
75      }
76  
77      /** Get the start date.
78       * @return start date
79       */
80      protected AbsoluteDate getStartDate() {
81          return startDate;
82      }
83  
84      /**  {@inheritDoc} */
85      public AttitudeProvider getAttitudeProvider() {
86          return attitudeProvider;
87      }
88  
89      /**  {@inheritDoc} */
90      public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
91          this.attitudeProvider = attitudeProvider;
92      }
93  
94      /** {@inheritDoc} */
95      public SpacecraftState getInitialState() {
96          return initialState;
97      }
98  
99      /** {@inheritDoc} */
100     public Frame getFrame() {
101         return initialState.getFrame();
102     }
103 
104     /** {@inheritDoc} */
105     public void resetInitialState(final SpacecraftState state) {
106         initialState = state;
107         setStartDate(state.getDate());
108     }
109 
110     /** {@inheritDoc} */
111     public StepHandlerMultiplexer getMultiplexer() {
112         return multiplexer;
113     }
114 
115     /** {@inheritDoc} */
116     public void addAdditionalStateProvider(final AdditionalStateProvider additionalStateProvider) {
117 
118         // check if the name is already used
119         if (isAdditionalStateManaged(additionalStateProvider.getName())) {
120             // this additional state is already registered, complain
121             throw new OrekitException(OrekitMessages.ADDITIONAL_STATE_NAME_ALREADY_IN_USE,
122                                       additionalStateProvider.getName());
123         }
124 
125         // this is really a new name, add it
126         additionalStateProviders.add(additionalStateProvider);
127 
128     }
129 
130     /** {@inheritDoc} */
131     public List<AdditionalStateProvider> getAdditionalStateProviders() {
132         return Collections.unmodifiableList(additionalStateProviders);
133     }
134 
135     /** Update state by adding all additional states.
136      * @param original original state
137      * @return updated state, with all additional states included
138      * @see #addAdditionalStateProvider(AdditionalStateProvider)
139      */
140     protected SpacecraftState updateAdditionalStates(final SpacecraftState original) {
141 
142         // start with original state,
143         // which may already contain additional states, for example in interpolated ephemerides
144         SpacecraftState updated = original;
145 
146         // update the states not managed by providers
147         for (final Map.Entry<String, TimeSpanMap<double[]>> entry : unmanagedStates.entrySet()) {
148             updated = updated.addAdditionalState(entry.getKey(),
149                                                  entry.getValue().get(original.getDate()));
150         }
151 
152         // update the additional states managed by providers
153         for (final AdditionalStateProvider provider : additionalStateProviders) {
154             updated = updated.addAdditionalState(provider.getName(),
155                                                  provider.getAdditionalState(updated));
156         }
157 
158         return updated;
159 
160     }
161 
162     /** {@inheritDoc} */
163     public boolean isAdditionalStateManaged(final String name) {
164         for (final AdditionalStateProvider provider : additionalStateProviders) {
165             if (provider.getName().equals(name)) {
166                 return true;
167             }
168         }
169         return false;
170     }
171 
172     /** {@inheritDoc} */
173     public String[] getManagedAdditionalStates() {
174         final String[] managed = new String[additionalStateProviders.size()];
175         for (int i = 0; i < managed.length; ++i) {
176             managed[i] = additionalStateProviders.get(i).getName();
177         }
178         return managed;
179     }
180 
181     /** {@inheritDoc} */
182     public SpacecraftState propagate(final AbsoluteDate target) {
183         if (startDate == null) {
184             startDate = getInitialState().getDate();
185         }
186         return propagate(startDate, target);
187     }
188 
189     /** {@inheritDoc} */
190     public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
191         return propagate(date).getPVCoordinates(frame);
192     }
193 
194     /** Initialize propagation.
195      * @since 10.1
196      */
197     protected void initializePropagation() {
198 
199         unmanagedStates.clear();
200 
201         if (initialState != null) {
202             // there is an initial state
203             // (null initial states occur for example in interpolated ephemerides)
204             // copy the additional states present in initialState but otherwise not managed
205             for (final Map.Entry<String, double[]> initial : initialState.getAdditionalStates().entrySet()) {
206                 if (!isAdditionalStateManaged(initial.getKey())) {
207                     // this additional state is in the initial state, but is unknown to the propagator
208                     // we store it in a way event handlers may change it
209                     unmanagedStates.put(initial.getKey(), new TimeSpanMap<>(initial.getValue()));
210                 }
211             }
212         }
213     }
214 
215     /** Notify about a state change.
216      * @param state new state
217      */
218     protected void stateChanged(final SpacecraftState state) {
219         final AbsoluteDate date    = state.getDate();
220         final boolean      forward = date.durationFrom(getStartDate()) >= 0.0;
221         for (final Map.Entry<String, double[]> changed : state.getAdditionalStates().entrySet()) {
222             final TimeSpanMap<double[]> tsm = unmanagedStates.get(changed.getKey());
223             if (tsm != null) {
224                 // this is an unmanaged state
225                 if (forward) {
226                     tsm.addValidAfter(changed.getValue(), date);
227                 } else {
228                     tsm.addValidBefore(changed.getValue(), date);
229                 }
230             }
231         }
232     }
233 
234 }