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.analytical;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitMessages;
26  import org.orekit.orbits.Orbit;
27  import org.orekit.propagation.Propagator;
28  import org.orekit.propagation.SpacecraftState;
29  import org.orekit.time.AbsoluteDate;
30  
31  /** Orbit propagator that adapts an underlying propagator, adding {@link
32   * DifferentialEffect differential effects}.
33   * <p>
34   * This propagator is used when a reference propagator does not handle
35   * some effects that we need. A typical example would be an ephemeris
36   * that was computed for a reference orbit, and we want to compute a
37   * station-keeping maneuver on top of this ephemeris, changing its
38   * final state. The principal is to add one or more {@link
39   * org.orekit.forces.maneuvers.SmallManeuverAnalyticalModel small maneuvers
40   * analytical models} to it and use it as a new propagator, which takes the
41   * maneuvers into account.
42   * </p>
43   * <p>
44   * From a space flight dynamics point of view, this is a differential
45   * correction approach. From a computer science point of view, this is
46   * a use of the decorator design pattern.
47   * </p>
48   * @see Propagator
49   * @see org.orekit.forces.maneuvers.SmallManeuverAnalyticalModel
50   * @author Luc Maisonobe
51   */
52  public class AdapterPropagator extends AbstractAnalyticalPropagator {
53  
54      /** Interface for orbit differential effects. */
55      public interface DifferentialEffect {
56  
57          /** Apply the effect to a {@link SpacecraftState spacecraft state}.
58           * <p>
59           * Applying the effect may be a no-op in some cases. A typical example
60           * is maneuvers, for which the state is changed only for time <em>after</em>
61           * the maneuver occurrence.
62           * </p>
63           * @param original original state <em>without</em> the effect
64           * @return updated state at the same date, taking the effect
65           * into account if meaningful
66           */
67          SpacecraftState apply(SpacecraftState original);
68  
69      }
70  
71      /** Underlying reference propagator. */
72      private Propagator reference;
73  
74      /** Effects to add. */
75      private List<DifferentialEffect> effects;
76  
77      /** Build a propagator from an underlying reference propagator.
78       * <p>The reference propagator can be almost anything, numerical,
79       * analytical, and even an ephemeris. It may already take some maneuvers
80       * into account.</p>
81       * @param reference reference propagator
82       */
83      public AdapterPropagator(final Propagator reference) {
84          super(reference.getAttitudeProvider());
85          this.reference = reference;
86          this.effects = new ArrayList<DifferentialEffect>();
87      }
88  
89      /** Add a differential effect.
90       * @param effect differential effect
91       */
92      public void addEffect(final DifferentialEffect effect) {
93          effects.add(effect);
94      }
95  
96      /** Get the reference propagator.
97       * @return reference propagator
98       */
99      public Propagator getPropagator() {
100         return reference;
101     }
102 
103     /** Get the differential effects.
104      * @return differential effects models, as an unmodifiable list
105      */
106     public List<DifferentialEffect> getEffects() {
107         return Collections.unmodifiableList(effects);
108     }
109 
110     /** {@inheritDoc} */
111     public SpacecraftState getInitialState() {
112         return reference.getInitialState();
113     }
114 
115     /** {@inheritDoc} */
116     @Override
117     public void resetInitialState(final SpacecraftState state) {
118         reference.resetInitialState(state);
119     }
120 
121     /** {@inheritDoc} */
122     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
123         if (reference instanceof AbstractAnalyticalPropagator) {
124             ((AbstractAnalyticalPropagator) reference).resetIntermediateState(state, forward);
125         } else {
126             throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
127         }
128     }
129 
130     /** {@inheritDoc} */
131     @Override
132     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
133 
134         // compute reference state
135         SpacecraftState state = reference.propagate(date);
136         final Map<String, double[]> before = state.getAdditionalStates();
137 
138         // add all the effects
139         for (final DifferentialEffect effect : effects) {
140             state = effect.apply(state);
141         }
142 
143         // forward additional states from the reference propagator
144         for (final Map.Entry<String, double[]> entry : before.entrySet()) {
145             if (!state.hasAdditionalState(entry.getKey())) {
146                 state = state.addAdditionalState(entry.getKey(), entry.getValue());
147             }
148         }
149 
150         return state;
151 
152     }
153 
154     /** {@inheritDoc} */
155     protected Orbit propagateOrbit(final AbsoluteDate date) {
156         return basicPropagate(date).getOrbit();
157     }
158 
159     /** {@inheritDoc}*/
160     protected double getMass(final AbsoluteDate date) {
161         return basicPropagate(date).getMass();
162     }
163 
164 }