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 }