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