1 /* Copyright 2002-2022 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.conversion;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.orekit.attitudes.Attitude;
24 import org.orekit.attitudes.AttitudeProvider;
25 import org.orekit.attitudes.InertialProvider;
26 import org.orekit.estimation.leastsquares.DSSTBatchLSModel;
27 import org.orekit.estimation.leastsquares.ModelObserver;
28 import org.orekit.estimation.measurements.ObservedMeasurement;
29 import org.orekit.estimation.sequential.AbstractKalmanModel;
30 import org.orekit.estimation.sequential.CovarianceMatrixProvider;
31 import org.orekit.orbits.EquinoctialOrbit;
32 import org.orekit.orbits.Orbit;
33 import org.orekit.orbits.OrbitType;
34 import org.orekit.orbits.PositionAngle;
35 import org.orekit.propagation.PropagationType;
36 import org.orekit.propagation.Propagator;
37 import org.orekit.propagation.SpacecraftState;
38 import org.orekit.propagation.integration.AdditionalDerivativesProvider;
39 import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
40 import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
41 import org.orekit.propagation.semianalytical.dsst.forces.DSSTNewtonianAttraction;
42 import org.orekit.utils.ParameterDriver;
43 import org.orekit.utils.ParameterDriversList;
44
45 /** Builder for DSST propagator.
46 * @author Bryan Cazabonne
47 * @since 10.0
48 */
49 public class DSSTPropagatorBuilder extends AbstractPropagatorBuilder implements OrbitDeterminationPropagatorBuilder {
50
51 /** First order integrator builder for propagation. */
52 private final ODEIntegratorBuilder builder;
53
54 /** Force models used during the extrapolation of the orbit. */
55 private final List<DSSTForceModel> forceModels;
56
57 /** Current mass for initial state (kg). */
58 private double mass;
59
60 /** Type of the orbit used for the propagation.*/
61 private PropagationType propagationType;
62
63 /** Type of the elements used to define the orbital state.*/
64 private PropagationType stateType;
65
66 /** Build a new instance.
67 * <p>
68 * The reference orbit is used as a model to {@link
69 * #createInitialOrbit() create initial orbit}. It defines the
70 * inertial frame, the central attraction coefficient, and is also used together
71 * with the {@code positionScale} to convert from the {@link
72 * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
73 * callers of this builder to the real orbital parameters.
74 * </p>
75 *
76 * @param referenceOrbit reference orbit from which real orbits will be built
77 * @param builder first order integrator builder
78 * @param positionScale scaling factor used for orbital parameters normalization
79 * (typically set to the expected standard deviation of the position)
80 * @param propagationType type of the orbit used for the propagation (mean or osculating)
81 * @param stateType type of the elements used to define the orbital state (mean or osculating)
82 * @see #DSSTPropagatorBuilder(Orbit, ODEIntegratorBuilder, double, PropagationType,
83 * PropagationType, AttitudeProvider)
84 */
85 public DSSTPropagatorBuilder(final Orbit referenceOrbit,
86 final ODEIntegratorBuilder builder,
87 final double positionScale,
88 final PropagationType propagationType,
89 final PropagationType stateType) {
90 this(referenceOrbit, builder, positionScale, propagationType, stateType,
91 InertialProvider.of(referenceOrbit.getFrame()));
92 }
93
94 /** Build a new instance.
95 * <p>
96 * The reference orbit is used as a model to {@link
97 * #createInitialOrbit() create initial orbit}. It defines the
98 * inertial frame, the central attraction coefficient, and is also used together
99 * with the {@code positionScale} to convert from the {@link
100 * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
101 * callers of this builder to the real orbital parameters.
102 * </p>
103 * @param referenceOrbit reference orbit from which real orbits will be built
104 * @param builder first order integrator builder
105 * @param positionScale scaling factor used for orbital parameters normalization
106 * (typically set to the expected standard deviation of the position)
107 * @param propagationType type of the orbit used for the propagation (mean or osculating)
108 * @param stateType type of the elements used to define the orbital state (mean or osculating)
109 * @param attitudeProvider attitude law.
110 * @since 10.1
111 */
112 public DSSTPropagatorBuilder(final Orbit referenceOrbit,
113 final ODEIntegratorBuilder builder,
114 final double positionScale,
115 final PropagationType propagationType,
116 final PropagationType stateType,
117 final AttitudeProvider attitudeProvider) {
118 super(referenceOrbit, PositionAngle.MEAN, positionScale, true, attitudeProvider);
119 this.builder = builder;
120 this.forceModels = new ArrayList<DSSTForceModel>();
121 this.mass = Propagator.DEFAULT_MASS;
122 this.propagationType = propagationType;
123 this.stateType = stateType;
124 }
125
126 /** Get the type of the orbit used for the propagation (mean or osculating).
127 * @return the type of the orbit used for the propagation
128 */
129 public PropagationType getPropagationType() {
130 return propagationType;
131 }
132
133 /** Get the type of the elements used to define the orbital state (mean or osculating).
134 * @return the type of the elements used to define the orbital state
135 */
136 public PropagationType getStateType() {
137 return stateType;
138 }
139
140 /** Create a copy of a DSSTPropagatorBuilder object.
141 * @return Copied version of the DSSTPropagatorBuilder
142 */
143 public DSSTPropagatorBuilder copy() {
144 final DSSTPropagatorBuilder copyBuilder =
145 new DSSTPropagatorBuilder((EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit()),
146 builder,
147 getPositionScale(),
148 propagationType,
149 stateType,
150 getAttitudeProvider());
151 copyBuilder.setMass(mass);
152 for (DSSTForceModel model : forceModels) {
153 copyBuilder.addForceModel(model);
154 }
155 return copyBuilder;
156 }
157
158 /** Get the integrator builder.
159 * @return the integrator builder
160 */
161 public ODEIntegratorBuilder getIntegratorBuilder()
162 {
163 return builder;
164 }
165
166 /** Get the list of all force models.
167 * @return the list of all force models
168 */
169 public List<DSSTForceModel> getAllForceModels()
170 {
171 return Collections.unmodifiableList(forceModels);
172 }
173
174 /** Get the mass.
175 * @return the mass
176 */
177 public double getMass()
178 {
179 return mass;
180 }
181
182 /** Set the initial mass.
183 * @param mass the mass (kg)
184 */
185 public void setMass(final double mass) {
186 this.mass = mass;
187 }
188
189 /** Add a force model to the global perturbation model.
190 * <p>If this method is not called at all, the integrated orbit will follow
191 * a Keplerian evolution only.</p>
192 * @param model perturbing {@link DSSTForceModel} to add
193 */
194 public void addForceModel(final DSSTForceModel model) {
195 if (model instanceof DSSTNewtonianAttraction) {
196 // we want to add the central attraction force model
197 if (hasNewtonianAttraction()) {
198 // there is already a central attraction model, replace it
199 forceModels.set(forceModels.size() - 1, model);
200 } else {
201 // there are no central attraction model yet, add it at the end of the list
202 forceModels.add(model);
203 }
204 } else {
205 // we want to add a perturbing force model
206 if (hasNewtonianAttraction()) {
207 // insert the new force model before Newtonian attraction,
208 // which should always be the last one in the list
209 forceModels.add(forceModels.size() - 1, model);
210 } else {
211 // we only have perturbing force models up to now, just append at the end of the list
212 forceModels.add(model);
213 }
214 }
215
216 for (final ParameterDriver driver : model.getParametersDrivers()) {
217 addSupportedParameter(driver);
218 }
219 }
220
221 /** Reset the orbit in the propagator builder.
222 * @param newOrbit newOrbit New orbit to set in the propagator builder
223 * @param orbitType orbit type (MEAN or OSCULATING)
224 */
225 public void resetOrbit(final Orbit newOrbit, final PropagationType orbitType) {
226 this.stateType = orbitType;
227 super.resetOrbit(newOrbit);
228 }
229
230 /** {@inheritDoc} */
231 @SuppressWarnings("deprecation")
232 public DSSTPropagator buildPropagator(final double[] normalizedParameters) {
233
234 setParameters(normalizedParameters);
235 final EquinoctialOrbit orbit = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit());
236 final Attitude attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
237 final SpacecraftState state = new SpacecraftState(orbit, attitude, mass);
238
239 final DSSTPropagator propagator = new DSSTPropagator(
240 builder.buildIntegrator(orbit, OrbitType.EQUINOCTIAL),
241 propagationType,
242 getAttitudeProvider());
243
244 // Configure force models
245 if (!hasNewtonianAttraction()) {
246 // There are no central attraction model yet, add it at the end of the list
247 addForceModel(new DSSTNewtonianAttraction(orbit.getMu()));
248 }
249 for (DSSTForceModel model : forceModels) {
250 propagator.addForceModel(model);
251 }
252
253 propagator.setInitialState(state, stateType);
254
255 // Add additional derivatives providers to the propagator
256 for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
257 propagator.addAdditionalDerivativesProvider(provider);
258 }
259
260 // FIXME: remove in 12.0 when AdditionalEquations is removed
261 for (org.orekit.propagation.integration.AdditionalEquations equations : getAdditionalEquations()) {
262 propagator.addAdditionalDerivativesProvider(new org.orekit.propagation.integration.AdditionalEquationsAdapter(equations, propagator::getInitialState));
263 }
264
265 return propagator;
266
267 }
268
269 /** {@inheritDoc} */
270 @Override
271 public DSSTBatchLSModel buildLSModel(final OrbitDeterminationPropagatorBuilder[] builders,
272 final List<ObservedMeasurement<?>> measurements,
273 final ParameterDriversList estimatedMeasurementsParameters,
274 final ModelObserver observer) {
275 return new DSSTBatchLSModel(builders,
276 measurements,
277 estimatedMeasurementsParameters,
278 observer,
279 propagationType, stateType);
280 }
281
282 /** {@inheritDoc} */
283 @Override
284 @SuppressWarnings("deprecation")
285 public AbstractKalmanModel buildKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
286 final List<CovarianceMatrixProvider> covarianceMatricesProviders,
287 final ParameterDriversList estimatedMeasurementsParameters,
288 final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
289 // FIXME: remove in 12.0 when DSSTKalmanModel is removed
290 return new org.orekit.estimation.sequential.DSSTKalmanModel(propagatorBuilders,
291 covarianceMatricesProviders,
292 estimatedMeasurementsParameters,
293 measurementProcessNoiseMatrix,
294 propagationType, stateType);
295 }
296
297 /** Check if Newtonian attraction force model is available.
298 * <p>
299 * Newtonian attraction is always the last force model in the list.
300 * </p>
301 * @return true if Newtonian attraction force model is available
302 */
303 private boolean hasNewtonianAttraction() {
304 final int last = forceModels.size() - 1;
305 return last >= 0 && forceModels.get(last) instanceof DSSTNewtonianAttraction;
306 }
307
308 }