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 org.hipparchus.linear.RealMatrix;
20 import org.orekit.attitudes.Attitude;
21 import org.orekit.attitudes.AttitudeProvider;
22 import org.orekit.attitudes.FrameAlignedProvider;
23 import org.orekit.orbits.Orbit;
24 import org.orekit.orbits.OrbitType;
25 import org.orekit.orbits.PositionAngleType;
26 import org.orekit.propagation.AbstractMatricesHarvester;
27 import org.orekit.propagation.SpacecraftState;
28 import org.orekit.time.AbsoluteDate;
29 import org.orekit.utils.DoubleArrayDictionary;
30 import org.orekit.utils.TimeSpanMap;
31
32 /** Simple Keplerian orbit propagator.
33 * @see Orbit
34 * @author Guylaine Prat
35 */
36 public class KeplerianPropagator extends AbstractAnalyticalPropagator {
37
38 /** All states. */
39 private TimeSpanMap<SpacecraftState> states;
40
41 /** Build a propagator from orbit only.
42 * <p>The central attraction coefficient μ is set to the same value used
43 * for the initial orbit definition. Mass and attitude provider are set to
44 * unspecified non-null arbitrary values.</p>
45 *
46 * @param initialOrbit initial orbit
47 * @see #KeplerianPropagator(Orbit, AttitudeProvider)
48 */
49 public KeplerianPropagator(final Orbit initialOrbit) {
50 this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
51 initialOrbit.getMu(), DEFAULT_MASS);
52 }
53
54 /** Build a propagator from orbit and central attraction coefficient μ.
55 * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
56 *
57 * @param initialOrbit initial orbit
58 * @param mu central attraction coefficient (m³/s²)
59 * @see #KeplerianPropagator(Orbit, AttitudeProvider, double)
60 */
61 public KeplerianPropagator(final Orbit initialOrbit, final double mu) {
62 this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
63 mu, DEFAULT_MASS);
64 }
65
66 /** Build a propagator from orbit and attitude provider.
67 * <p>The central attraction coefficient μ is set to the same value
68 * used for the initial orbit definition. Mass is set to an unspecified
69 * non-null arbitrary value.</p>
70 * @param initialOrbit initial orbit
71 * @param attitudeProv attitude provider
72 */
73 public KeplerianPropagator(final Orbit initialOrbit,
74 final AttitudeProvider attitudeProv) {
75 this(initialOrbit, attitudeProv, initialOrbit.getMu(), DEFAULT_MASS);
76 }
77
78 /** Build a propagator from orbit, attitude provider and central attraction
79 * coefficient μ.
80 * <p>Mass is set to an unspecified non-null arbitrary value.</p>
81 * @param initialOrbit initial orbit
82 * @param attitudeProv attitude provider
83 * @param mu central attraction coefficient (m³/s²)
84 */
85 public KeplerianPropagator(final Orbit initialOrbit,
86 final AttitudeProvider attitudeProv,
87 final double mu) {
88 this(initialOrbit, attitudeProv, mu, DEFAULT_MASS);
89 }
90
91 /** Build propagator from orbit, attitude provider, central attraction
92 * coefficient μ and mass.
93 * @param initialOrbit initial orbit
94 * @param attitudeProv attitude provider
95 * @param mu central attraction coefficient (m³/s²)
96 * @param mass spacecraft mass (kg)
97 */
98 public KeplerianPropagator(final Orbit initialOrbit, final AttitudeProvider attitudeProv,
99 final double mu, final double mass) {
100
101 super(attitudeProv);
102
103 // ensure the orbit use the specified mu and has no non-Keplerian derivatives
104 final SpacecraftState initial = fixState(initialOrbit,
105 getAttitudeProvider().getAttitude(initialOrbit,
106 initialOrbit.getDate(),
107 initialOrbit.getFrame()),
108 mass, mu, null, null);
109 states = new TimeSpanMap<SpacecraftState>(initial);
110 super.resetInitialState(initial);
111
112 }
113
114 /** Fix state to use a specified mu and remove derivatives.
115 * <p>
116 * This ensures the propagation model (which is based on calling
117 * {@link Orbit#shiftedBy(double)}) is Keplerian only and uses a specified mu.
118 * </p>
119 * @param orbit orbit to fix
120 * @param attitude current attitude
121 * @param mass current mass
122 * @param mu gravity coefficient to use
123 * @param additionalStates additional states (may be null)
124 * @param additionalStatesDerivatives additional states derivatives (may be null)
125 * @return fixed orbit
126 */
127 private SpacecraftState fixState(final Orbit orbit, final Attitude attitude, final double mass, final double mu,
128 final DoubleArrayDictionary additionalStates,
129 final DoubleArrayDictionary additionalStatesDerivatives) {
130 final OrbitType type = orbit.getType();
131 final double[] stateVector = new double[6];
132 final PositionAngleType positionAngleType = PositionAngleType.MEAN;
133 type.mapOrbitToArray(orbit, positionAngleType, stateVector, null);
134 final Orbit fixedOrbit = type.mapArrayToOrbit(stateVector, null, positionAngleType,
135 orbit.getDate(), mu, orbit.getFrame());
136 SpacecraftState fixedState = new SpacecraftState(fixedOrbit, attitude, mass);
137 if (additionalStates != null) {
138 for (final DoubleArrayDictionary.Entry entry : additionalStates.getData()) {
139 fixedState = fixedState.addAdditionalState(entry.getKey(), entry.getValue());
140 }
141 }
142 if (additionalStatesDerivatives != null) {
143 for (final DoubleArrayDictionary.Entry entry : additionalStatesDerivatives.getData()) {
144 fixedState = fixedState.addAdditionalStateDerivative(entry.getKey(), entry.getValue());
145 }
146 }
147 return fixedState;
148 }
149
150 /** {@inheritDoc} */
151 public void resetInitialState(final SpacecraftState state) {
152
153 // ensure the orbit use the specified mu and has no non-Keplerian derivatives
154 final SpacecraftState formerInitial = getInitialState();
155 final double mu = formerInitial == null ? state.getMu() : formerInitial.getMu();
156 final SpacecraftState fixedState = fixState(state.getOrbit(),
157 state.getAttitude(),
158 state.getMass(),
159 mu,
160 state.getAdditionalStatesValues(),
161 state.getAdditionalStatesDerivatives());
162
163 states = new TimeSpanMap<SpacecraftState>(fixedState);
164 super.resetInitialState(fixedState);
165
166 }
167
168 /** {@inheritDoc} */
169 protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
170 if (forward) {
171 states.addValidAfter(state, state.getDate(), false);
172 } else {
173 states.addValidBefore(state, state.getDate(), false);
174 }
175 stateChanged(state);
176 }
177
178 /** {@inheritDoc} */
179 protected Orbit propagateOrbit(final AbsoluteDate date) {
180
181 // propagate orbit
182 Orbit orbit = states.get(date).getOrbit();
183 do {
184 // we use a loop here to compensate for very small date shifts error
185 // that occur with long propagation time
186 orbit = orbit.shiftedBy(date.durationFrom(orbit.getDate()));
187 } while (!date.equals(orbit.getDate()));
188
189 return orbit;
190
191 }
192
193 /** {@inheritDoc}*/
194 protected double getMass(final AbsoluteDate date) {
195 return states.get(date).getMass();
196 }
197
198 /** {@inheritDoc} */
199 @Override
200 protected AbstractMatricesHarvester createHarvester(final String stmName, final RealMatrix initialStm,
201 final DoubleArrayDictionary initialJacobianColumns) {
202 // Create the harvester
203 final KeplerianHarvester harvester = new KeplerianHarvester(this, stmName, initialStm, initialJacobianColumns);
204 // Update the list of additional state provider
205 addAdditionalStateProvider(harvester);
206 // Return the configured harvester
207 return harvester;
208 }
209
210 }