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.analytical;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  
23  import org.orekit.errors.OrekitException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.orbits.Orbit;
26  import org.orekit.propagation.Propagator;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.DoubleArrayDictionary;
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          // Sets initial state
88          super.resetInitialState(getInitialState());
89      }
90  
91      /** Add a differential effect.
92       * @param effect differential effect
93       */
94      public void addEffect(final DifferentialEffect effect) {
95          effects.add(effect);
96      }
97  
98      /** Get the reference propagator.
99       * @return reference propagator
100      */
101     public Propagator getPropagator() {
102         return reference;
103     }
104 
105     /** Get the differential effects.
106      * @return differential effects models, as an unmodifiable list
107      */
108     public List<DifferentialEffect> getEffects() {
109         return Collections.unmodifiableList(effects);
110     }
111 
112     /** {@inheritDoc} */
113     public SpacecraftState getInitialState() {
114         return reference.getInitialState();
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public void resetInitialState(final SpacecraftState state) {
120         reference.resetInitialState(state);
121     }
122 
123     /** {@inheritDoc} */
124     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
125         if (reference instanceof AbstractAnalyticalPropagator) {
126             ((AbstractAnalyticalPropagator) reference).resetIntermediateState(state, forward);
127         } else {
128             throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
129         }
130     }
131 
132     /** {@inheritDoc} */
133     @Override
134     protected SpacecraftState basicPropagate(final AbsoluteDate date) {
135 
136         // compute reference state
137         SpacecraftState state = reference.propagate(date);
138         final DoubleArrayDictionary additionalBefore    = state.getAdditionalStatesValues();
139         final DoubleArrayDictionary additionalDotBefore = state.getAdditionalStatesDerivatives();
140 
141         // add all the effects
142         for (final DifferentialEffect effect : effects) {
143             state = effect.apply(state);
144         }
145 
146         // forward additional states and derivatives from the reference propagator
147         for (final DoubleArrayDictionary.Entry entry : additionalBefore.getData()) {
148             if (!state.hasAdditionalState(entry.getKey())) {
149                 state = state.addAdditionalState(entry.getKey(), entry.getValue());
150             }
151         }
152         for (final DoubleArrayDictionary.Entry entry : additionalDotBefore.getData()) {
153             if (!state.hasAdditionalState(entry.getKey())) {
154                 state = state.addAdditionalStateDerivative(entry.getKey(), entry.getValue());
155             }
156         }
157 
158         return state;
159 
160     }
161 
162     /** {@inheritDoc} */
163     protected Orbit propagateOrbit(final AbsoluteDate date) {
164         return basicPropagate(date).getOrbit();
165     }
166 
167     /** {@inheritDoc}*/
168     protected double getMass(final AbsoluteDate date) {
169         return basicPropagate(date).getMass();
170     }
171 
172 }