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