1 /* Copyright 2002-2026 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.List;
21
22 import org.hipparchus.exception.LocalizedCoreFormats;
23 import org.hipparchus.util.FastMath;
24 import org.orekit.attitudes.AttitudeProvider;
25 import org.orekit.attitudes.FrameAlignedProvider;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitIllegalArgumentException;
28 import org.orekit.errors.OrekitMessages;
29 import org.orekit.forces.gravity.NewtonianAttraction;
30 import org.orekit.orbits.Orbit;
31 import org.orekit.orbits.OrbitalState;
32 import org.orekit.orbits.OrbitalStateFactory;
33 import org.orekit.propagation.AbstractPropagator;
34 import org.orekit.propagation.Propagator;
35 import org.orekit.propagation.integration.AdditionalDerivativesProvider;
36 import org.orekit.time.TimeInterval;
37 import org.orekit.utils.drivers.ParameterDriver;
38 import org.orekit.utils.drivers.ParameterDriversList;
39 import org.orekit.utils.drivers.ParameterObserver;
40
41 /** Base class for propagator builders.
42 * @param <T> type of the propagator
43 * @param <O> type of the orbital parameters
44 * @param <F> type of the orbital parameters factory
45 * @author Pascal Parraud
46 * @since 7.1
47 */
48 public abstract class AbstractPropagatorBuilder<T extends AbstractPropagator,
49 O extends OrbitalState,
50 F extends OrbitalStateFactory<O>>
51 implements PropagatorBuilder {
52
53 /** Central attraction scaling factor.
54 * <p>
55 * We use a power of 2 to avoid numeric noise introduction
56 * in the multiplications/divisions sequences.
57 * </p>
58 */
59 private static final double MU_SCALE = FastMath.scalb(1.0, 32);
60
61 /** Factory for initial orbit.
62 * @since 14.0
63 */
64 private final F factory;
65
66 /** Initial mass. */
67 private double mass;
68
69 /** List of the supported propagation parameters. */
70 private final ParameterDriversList propagationDrivers;
71
72 /** Attitude provider for the propagator. */
73 private AttitudeProvider attitudeProvider;
74
75 /** Additional derivatives providers.
76 * @since 11.1
77 */
78 private final List<AdditionalDerivativesProvider> additionalDerivativesProviders;
79
80 /** Build a new instance.
81 * <p>
82 * By default, all the orbital parameters drivers
83 * are selected, which means that if the builder is used for orbit determination or
84 * propagator conversion, all orbital parameters will be estimated. If only a subset
85 * of the orbital parameters must be estimated, caller must retrieve the orbital
86 * parameters by calling {@link #getOrbitalStateFactory()}.{@link OrbitalStateFactory#getOrbitalParametersDrivers()}
87 * and then call {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
88 * </p>
89 * @param factory factory for initial orbit
90 * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
91 * be set up for central attraction coefficient
92 * @since 14.0
93 */
94 protected AbstractPropagatorBuilder(final F factory,
95 final boolean addDriverForCentralAttraction) {
96 this(factory, addDriverForCentralAttraction,
97 new FrameAlignedProvider(factory.getFrame()), Propagator.DEFAULT_MASS);
98 }
99 /** Build a new instance.
100 * <p>
101 * By default, all the orbital parameters drivers
102 * are selected, which means that if the builder is used for orbit determination or
103 * propagator conversion, all orbital parameters will be estimated. If only a subset
104 * of the orbital parameters must be estimated, caller must retrieve the orbital
105 * parameters by calling {@link #getOrbitalStateFactory()}.{@link OrbitalStateFactory#getOrbitalParametersDrivers()}
106 * and then call {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
107 * </p>
108 * @param factory factory for initial orbit
109 * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
110 * be set up for central attraction coefficient
111 * @param attitudeProvider for the propagator.
112 * @since 14.0
113 */
114 protected AbstractPropagatorBuilder(final F factory,
115 final boolean addDriverForCentralAttraction,
116 final AttitudeProvider attitudeProvider) {
117 this(factory, addDriverForCentralAttraction, attitudeProvider,
118 Propagator.DEFAULT_MASS);
119 }
120
121 /** Build a new instance.
122 * <p>
123 * By default, all the orbital parameters drivers
124 * are selected, which means that if the builder is used for orbit determination or
125 * propagator conversion, all orbital parameters will be estimated. If only a subset
126 * of the orbital parameters must be estimated, caller must retrieve the orbital
127 * parameters by calling {@link #getOrbitalStateFactory()}.{@link OrbitalStateFactory#getOrbitalParametersDrivers()}
128 * and then call {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
129 * </p>
130 * @param factory factory for initial orbit
131 * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
132 * be set up for central attraction coefficient
133 * @param attitudeProvider for the propagator.
134 * @param initialMass mass
135 * @since 14.0
136 */
137 protected AbstractPropagatorBuilder(final F factory,
138 final boolean addDriverForCentralAttraction,
139 final AttitudeProvider attitudeProvider, final double initialMass) {
140
141 this.factory = factory;
142 this.attitudeProvider = attitudeProvider;
143 this.mass = initialMass;
144 for (final ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
145 // by default, we always select the orbital parameters
146 driver.setSelected(true);
147 }
148
149 this.additionalDerivativesProviders = new ArrayList<>();
150
151 if (addDriverForCentralAttraction) {
152
153 // we need to use a separate list, to avoid messing with the one from the factory
154 // when adding the driver for mu
155 propagationDrivers = new ParameterDriversList();
156 factory.getNonKeplerianParametersDrivers().getDrivers().forEach(propagationDrivers::add);
157
158 final ParameterDriver muDriver = new ParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
159 factory.getMu(), MU_SCALE, 0, Double.POSITIVE_INFINITY,
160 TimeInterval.UNLIMITED);
161 muDriver.addObserver(new ParameterObserver() {
162 /** {@inheritDoc} */
163 @Override
164 public void valueChanged(final double previousValue, final ParameterDriver driver) {
165 factory.setMu(driver.getValue());
166 }
167 });
168 propagationDrivers.add(muDriver);
169 } else {
170 // we just reuse the original list from the factory
171 propagationDrivers = factory.getNonKeplerianParametersDrivers();
172 }
173
174 }
175
176 /** Get the mass.
177 * @return the mass (kg)
178 * @since 9.2
179 */
180 public double getMass()
181 {
182 return mass;
183 }
184
185 /** Set the initial mass.
186 * @param mass the mass (kg)
187 */
188 public void setMass(final double mass) {
189 this.mass = mass;
190 }
191
192 /** {@inheritDoc} */
193 public F getOrbitalStateFactory() {
194 return factory;
195 }
196
197 /** {@inheritDoc} */
198 public ParameterDriversList getPropagationParametersDrivers() {
199 return propagationDrivers;
200 }
201
202 /** {@inheritDoc}. */
203 @Override
204 @SuppressWarnings("unchecked")
205 public AbstractPropagatorBuilder<T, O, F> clone() {
206 try {
207 return (AbstractPropagatorBuilder<T, O, F>) super.clone();
208 } catch (CloneNotSupportedException cnse) {
209 throw new OrekitException(OrekitMessages.PROPAGATOR_BUILDER_NOT_CLONEABLE);
210 }
211 }
212
213 /**
214 * Get the attitude provider.
215 *
216 * @return the attitude provider
217 * @since 10.1
218 */
219 public AttitudeProvider getAttitudeProvider() {
220 return attitudeProvider;
221 }
222
223 /**
224 * Set the attitude provider.
225 *
226 * @param attitudeProvider attitude provider
227 * @since 10.1
228 */
229 public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
230 this.attitudeProvider = attitudeProvider;
231 }
232
233 /** Get the number of estimated values for selected parameters.
234 * @return number of estimated values for selected parameters
235 */
236 private int getNbValuesForSelected() {
237
238 int count = 0;
239
240 // count orbital parameters
241 for (final ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
242 if (driver.isSelected()) {
243 count++;
244 }
245 }
246
247 // count propagation parameters
248 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
249 if (driver.isSelected()) {
250 count++;
251 }
252 }
253
254 return count;
255
256 }
257
258 /** {@inheritDoc} */
259 public double[] getSelectedNormalizedParameters() {
260
261 // allocate array
262 final double[] selected = new double[getNbValuesForSelected()];
263
264 // fill data
265 int index = 0;
266 for (final ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
267 if (driver.isSelected()) {
268 selected[index++] = driver.getNormalizedValue();
269 }
270 }
271 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
272 if (driver.isSelected()) {
273 selected[index++] = driver.getNormalizedValue();
274 }
275 }
276
277 return selected;
278
279 }
280
281 /** {@inheritDoc} */
282 @Override
283 public abstract T buildPropagator(double[] normalizedParameters);
284
285 /** {@inheritDoc} */
286 @Override
287 public T buildPropagator() {
288 return buildPropagator(getSelectedNormalizedParameters());
289 }
290
291 /** Set the selected parameters.
292 * @param normalizedParameters normalized values for the selected parameters
293 */
294 protected void setParameters(final double[] normalizedParameters) {
295
296
297 if (normalizedParameters.length != getNbValuesForSelected()) {
298 throw new OrekitIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
299 normalizedParameters.length,
300 getNbValuesForSelected());
301 }
302
303 int index = 0;
304
305 // manage orbital parameters
306 for (final ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
307 if (driver.isSelected()) {
308 driver.setNormalizedValue(normalizedParameters[index++]);
309 }
310 }
311
312 // manage propagation parameters
313 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
314 if (driver.isSelected()) {
315 driver.setNormalizedValue(normalizedParameters[index++]);
316 }
317 }
318 }
319
320 /**
321 * Add propagation parameters.
322 *
323 * @param drivers drivers for the propagation parameters
324 */
325 protected void addPropagationParameters(final List<ParameterDriver> drivers) {
326 drivers.forEach(propagationDrivers::add);
327 propagationDrivers.sort();
328 }
329
330 /** Reset the orbit in the propagator builder.
331 * @param newOrbit New orbit to set in the propagator builder
332 */
333 public void resetOrbit(final Orbit newOrbit) {
334 factory.reset(newOrbit);
335 }
336
337 /** Add a set of user-specified equations to be integrated along with the orbit propagation (author Shiva Iyer).
338 * @param provider provider for additional derivatives
339 * @since 11.1
340 */
341 public void addAdditionalDerivativesProvider(final AdditionalDerivativesProvider provider) {
342 additionalDerivativesProviders.add(provider);
343 }
344
345 /** Get the list of additional equations.
346 * @return the list of additional equations
347 * @since 11.1
348 */
349 protected List<AdditionalDerivativesProvider> getAdditionalDerivativesProviders() {
350 return additionalDerivativesProviders;
351 }
352
353 /** Deselects orbital and propagation drivers. */
354 public void deselectDynamicParameters() {
355 for (ParameterDriver driver : getPropagationParametersDrivers().getDrivers()) {
356 driver.setSelected(false);
357 }
358 for (ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
359 driver.setSelected(false);
360 }
361 }
362 }