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