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