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.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.InertialProvider;
26 import org.orekit.errors.OrekitIllegalArgumentException;
27 import org.orekit.forces.gravity.NewtonianAttraction;
28 import org.orekit.frames.Frame;
29 import org.orekit.orbits.Orbit;
30 import org.orekit.orbits.OrbitType;
31 import org.orekit.orbits.PositionAngle;
32 import org.orekit.propagation.integration.AdditionalDerivativesProvider;
33 import org.orekit.time.AbsoluteDate;
34 import org.orekit.utils.ParameterDriver;
35 import org.orekit.utils.ParameterDriversList;
36 import org.orekit.utils.ParameterDriversList.DelegatingDriver;
37 import org.orekit.utils.ParameterObserver;
38
39 /** Base class for propagator builders.
40 * @author Pascal Parraud
41 * @since 7.1
42 */
43 public abstract class AbstractPropagatorBuilder implements PropagatorBuilder {
44
45 /** Central attraction scaling factor.
46 * <p>
47 * We use a power of 2 to avoid numeric noise introduction
48 * in the multiplications/divisions sequences.
49 * </p>
50 */
51 private static final double MU_SCALE = FastMath.scalb(1.0, 32);
52
53 /** Date of the initial orbit. */
54 private AbsoluteDate initialOrbitDate;
55
56 /** Frame in which the orbit is propagated. */
57 private final Frame frame;
58
59 /** Central attraction coefficient (m³/s²). */
60 private double mu;
61
62 /** Drivers for orbital parameters. */
63 private final ParameterDriversList orbitalDrivers;
64
65 /** List of the supported parameters. */
66 private ParameterDriversList propagationDrivers;
67
68 /** Orbit type to use. */
69 private final OrbitType orbitType;
70
71 /** Position angle type to use. */
72 private final PositionAngle positionAngle;
73
74 /** Position scale to use for the orbital drivers. */
75 private final double positionScale;
76
77 /** Attitude provider for the propagator. */
78 private AttitudeProvider attitudeProvider;
79
80 /** Additional equations. */
81 @Deprecated
82 private List<org.orekit.propagation.integration.AdditionalEquations> additionalEquations;
83
84 /** Additional derivatives providers.
85 * @since 11.1
86 */
87 private List<AdditionalDerivativesProvider> additionalDerivativesProviders;
88
89 /** Build a new instance.
90 * <p>
91 * The template orbit is used as a model to {@link
92 * #createInitialOrbit() create initial orbit}. It defines the
93 * inertial frame, the central attraction coefficient, the orbit type, and is also
94 * used together with the {@code positionScale} to convert from the {@link
95 * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
96 * callers of this builder to the real orbital parameters. The initial attitude
97 * provider is aligned with the inertial frame.
98 * </p>
99 * <p>
100 * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
101 * are selected, which means that if the builder is used for orbit determination or
102 * propagator conversion, all orbital parameters will be estimated. If only a subset
103 * of the orbital parameters must be estimated, caller must retrieve the orbital
104 * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
105 * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
106 * </p>
107 * @param templateOrbit reference orbit from which real orbits will be built
108 * @param positionAngle position angle type to use
109 * @param positionScale scaling factor used for orbital parameters normalization
110 * (typically set to the expected standard deviation of the position)
111 * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
112 * be set up for central attraction coefficient
113 * @since 8.0
114 * @see #AbstractPropagatorBuilder(Orbit, PositionAngle, double, boolean,
115 * AttitudeProvider)
116 */
117 protected AbstractPropagatorBuilder(final Orbit templateOrbit, final PositionAngle positionAngle,
118 final double positionScale, final boolean addDriverForCentralAttraction) {
119 this(templateOrbit, positionAngle, positionScale, addDriverForCentralAttraction,
120 new InertialProvider(templateOrbit.getFrame()));
121 }
122
123 /** Build a new instance.
124 * <p>
125 * The template orbit is used as a model to {@link
126 * #createInitialOrbit() create initial orbit}. It defines the
127 * inertial frame, the central attraction coefficient, the orbit type, and is also
128 * used together with the {@code positionScale} to convert from the {@link
129 * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
130 * callers of this builder to the real orbital parameters.
131 * </p>
132 * <p>
133 * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
134 * are selected, which means that if the builder is used for orbit determination or
135 * propagator conversion, all orbital parameters will be estimated. If only a subset
136 * of the orbital parameters must be estimated, caller must retrieve the orbital
137 * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
138 * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
139 * </p>
140 * @param templateOrbit reference orbit from which real orbits will be built
141 * @param positionAngle position angle type to use
142 * @param positionScale scaling factor used for orbital parameters normalization
143 * (typically set to the expected standard deviation of the position)
144 * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
145 * be set up for central attraction coefficient
146 * @param attitudeProvider for the propagator.
147 * @since 10.1
148 * @see #AbstractPropagatorBuilder(Orbit, PositionAngle, double, boolean)
149 */
150 protected AbstractPropagatorBuilder(final Orbit templateOrbit,
151 final PositionAngle positionAngle,
152 final double positionScale,
153 final boolean addDriverForCentralAttraction,
154 final AttitudeProvider attitudeProvider) {
155
156 this.initialOrbitDate = templateOrbit.getDate();
157 this.frame = templateOrbit.getFrame();
158 this.mu = templateOrbit.getMu();
159 this.propagationDrivers = new ParameterDriversList();
160 this.orbitType = templateOrbit.getType();
161 this.positionAngle = positionAngle;
162 this.positionScale = positionScale;
163 this.orbitalDrivers = orbitType.getDrivers(positionScale, templateOrbit, positionAngle);
164 this.attitudeProvider = attitudeProvider;
165 for (final DelegatingDriver driver : orbitalDrivers.getDrivers()) {
166 driver.setSelected(true);
167 }
168
169 this.additionalEquations = new ArrayList<>();
170 this.additionalDerivativesProviders = new ArrayList<>();
171
172 if (addDriverForCentralAttraction) {
173 final ParameterDriver muDriver = new ParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
174 mu, MU_SCALE, 0, Double.POSITIVE_INFINITY);
175 muDriver.addObserver(new ParameterObserver() {
176 /** {@inheridDoc} */
177 @Override
178 public void valueChanged(final double previousValue, final ParameterDriver driver) {
179 AbstractPropagatorBuilder.this.mu = driver.getValue();
180 }
181 });
182 propagationDrivers.add(muDriver);
183 }
184
185 }
186
187 /** {@inheritDoc} */
188 public OrbitType getOrbitType() {
189 return orbitType;
190 }
191
192 /** {@inheritDoc} */
193 public PositionAngle getPositionAngle() {
194 return positionAngle;
195 }
196
197 /** {@inheritDoc} */
198 public AbsoluteDate getInitialOrbitDate() {
199 return initialOrbitDate;
200 }
201
202 /** {@inheritDoc} */
203 public Frame getFrame() {
204 return frame;
205 }
206
207 /** {@inheritDoc} */
208 public ParameterDriversList getOrbitalParametersDrivers() {
209 return orbitalDrivers;
210 }
211
212 /** {@inheritDoc} */
213 public ParameterDriversList getPropagationParametersDrivers() {
214 return propagationDrivers;
215 }
216
217 /**
218 * Get the attitude provider.
219 *
220 * @return the attitude provider
221 * @since 10.1
222 */
223 public AttitudeProvider getAttitudeProvider() {
224 return attitudeProvider;
225 }
226
227 /**
228 * Set the attitude provider.
229 *
230 * @param attitudeProvider attitude provider
231 * @since 10.1
232 */
233 public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
234 this.attitudeProvider = attitudeProvider;
235 }
236
237 /** Get the position scale.
238 * @return the position scale used to scale the orbital drivers
239 */
240 public double getPositionScale() {
241 return positionScale;
242 }
243
244 /** Get the central attraction coefficient (µ - m³/s²) value.
245 * @return the central attraction coefficient (µ - m³/s²) value
246 * @since 9.2
247 */
248 public double getMu() {
249 return mu;
250 }
251
252 /** Get the number of selected parameters.
253 * @return number of selected parameters
254 */
255 private int getNbSelected() {
256
257 int count = 0;
258
259 // count orbital parameters
260 for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
261 if (driver.isSelected()) {
262 ++count;
263 }
264 }
265
266 // count propagation parameters
267 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
268 if (driver.isSelected()) {
269 ++count;
270 }
271 }
272
273 return count;
274
275 }
276
277 /** {@inheritDoc} */
278 public double[] getSelectedNormalizedParameters() {
279
280 // allocate array
281 final double[] selected = new double[getNbSelected()];
282
283 // fill data
284 int index = 0;
285 for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
286 if (driver.isSelected()) {
287 selected[index++] = driver.getNormalizedValue();
288 }
289 }
290 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
291 if (driver.isSelected()) {
292 selected[index++] = driver.getNormalizedValue();
293 }
294 }
295
296 return selected;
297
298 }
299
300 /** Build an initial orbit using the current selected parameters.
301 * <p>
302 * This method is a stripped down version of {@link #buildPropagator(double[])}
303 * that only builds the initial orbit and not the full propagator.
304 * </p>
305 * @return an initial orbit
306 * @since 8.0
307 */
308 protected Orbit createInitialOrbit() {
309 final double[] unNormalized = new double[orbitalDrivers.getNbParams()];
310 for (int i = 0; i < unNormalized.length; ++i) {
311 unNormalized[i] = orbitalDrivers.getDrivers().get(i).getValue();
312 }
313 return getOrbitType().mapArrayToOrbit(unNormalized, null, positionAngle, initialOrbitDate, mu, frame);
314 }
315
316 /** Set the selected parameters.
317 * @param normalizedParameters normalized values for the selected parameters
318 */
319 protected void setParameters(final double[] normalizedParameters) {
320
321
322 if (normalizedParameters.length != getNbSelected()) {
323 throw new OrekitIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
324 normalizedParameters.length,
325 getNbSelected());
326 }
327
328 int index = 0;
329
330 // manage orbital parameters
331 for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
332 if (driver.isSelected()) {
333 driver.setNormalizedValue(normalizedParameters[index++]);
334 }
335 }
336
337 // manage propagation parameters
338 for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
339 if (driver.isSelected()) {
340 driver.setNormalizedValue(normalizedParameters[index++]);
341 }
342 }
343
344 }
345
346 /** Add a supported parameter.
347 * @param driver driver for the parameter
348 */
349 protected void addSupportedParameter(final ParameterDriver driver) {
350 propagationDrivers.add(driver);
351 propagationDrivers.sort();
352 }
353
354 /** Reset the orbit in the propagator builder.
355 * @param newOrbit New orbit to set in the propagator builder
356 */
357 public void resetOrbit(final Orbit newOrbit) {
358
359 // Map the new orbit in an array of double
360 final double[] orbitArray = new double[6];
361 orbitType.mapOrbitToArray(newOrbit, getPositionAngle(), orbitArray, null);
362
363 // Update all the orbital drivers, selected or unselected
364 // Reset values and reference values
365 final List<DelegatingDriver> orbitalDriversList = getOrbitalParametersDrivers().getDrivers();
366 int i = 0;
367 for (DelegatingDriver driver : orbitalDriversList) {
368 driver.setReferenceValue(orbitArray[i]);
369 driver.setValue(orbitArray[i++]);
370 }
371
372 // Change the initial orbit date in the builder
373 this.initialOrbitDate = newOrbit.getDate();
374 }
375
376 /** Add a set of user-specified equations to be integrated along with the orbit propagation (author Shiva Iyer).
377 * @param additional additional equations
378 * @since 10.1
379 * @deprecated as of 11.1, replaced by {@link #addAdditionalDerivativesProvider(AdditionalDerivativesProvider)}
380 */
381 @Deprecated
382 public void addAdditionalEquations(final org.orekit.propagation.integration.AdditionalEquations additional) {
383 additionalEquations.add(additional);
384 }
385
386 /** Get the list of additional equations.
387 * @return the list of additional equations
388 * @since 10.1
389 * @deprecated as of 11.1, replaced by {@link #addAdditionalDerivativesProvider(AdditionalDerivativesProvider)}
390 */
391 @Deprecated
392 protected List<org.orekit.propagation.integration.AdditionalEquations> getAdditionalEquations() {
393 return additionalEquations;
394 }
395
396 /** Add a set of user-specified equations to be integrated along with the orbit propagation (author Shiva Iyer).
397 * @param provider provider for additional derivatives
398 * @since 11.1
399 */
400 public void addAdditionalDerivativesProvider(final AdditionalDerivativesProvider provider) {
401 additionalDerivativesProviders.add(provider);
402 }
403
404 /** Get the list of additional equations.
405 * @return the list of additional equations
406 * @since 11.1
407 */
408 protected List<AdditionalDerivativesProvider> getAdditionalDerivativesProviders() {
409 return additionalDerivativesProviders;
410 }
411
412 /** Deselects orbital and propagation drivers. */
413 public void deselectDynamicParameters() {
414 for (ParameterDriver driver : getPropagationParametersDrivers().getDrivers()) {
415 driver.setSelected(false);
416 }
417 for (ParameterDriver driver : getOrbitalParametersDrivers().getDrivers()) {
418 driver.setSelected(false);
419 }
420 }
421
422 }