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.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.BatchLSModel;
27 import org.orekit.estimation.leastsquares.ModelObserver;
28 import org.orekit.estimation.measurements.ObservedMeasurement;
29 import org.orekit.estimation.sequential.CovarianceMatrixProvider;
30 import org.orekit.estimation.sequential.KalmanModel;
31 import org.orekit.forces.ForceModel;
32 import org.orekit.forces.gravity.NewtonianAttraction;
33 import org.orekit.orbits.Orbit;
34 import org.orekit.orbits.PositionAngle;
35 import org.orekit.propagation.Propagator;
36 import org.orekit.propagation.SpacecraftState;
37 import org.orekit.propagation.integration.AdditionalEquations;
38 import org.orekit.propagation.numerical.NumericalPropagator;
39 import org.orekit.utils.ParameterDriver;
40 import org.orekit.utils.ParameterDriversList;
41
42 /** Builder for numerical propagator.
43 * @author Pascal Parraud
44 * @since 6.0
45 */
46 public class NumericalPropagatorBuilder extends AbstractPropagatorBuilder implements OrbitDeterminationPropagatorBuilder {
47
48 /** First order integrator builder for propagation. */
49 private final ODEIntegratorBuilder builder;
50
51 /** Force models used during the extrapolation of the orbit. */
52 private final List<ForceModel> forceModels;
53
54 /** Current mass for initial state (kg). */
55 private double mass;
56
57 /** Build a new instance.
58 * <p>
59 * The reference orbit is used as a model to {@link
60 * #createInitialOrbit() create initial orbit}. It defines the
61 * inertial frame, the central attraction coefficient, and is also used together
62 * with the {@code positionScale} to convert from the {@link
63 * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
64 * callers of this builder to the real orbital parameters.
65 * </p>
66 *
67 * @param referenceOrbit reference orbit from which real orbits will be built
68 * @param builder first order integrator builder
69 * @param positionAngle position angle type to use
70 * @param positionScale scaling factor used for orbital parameters normalization
71 * (typically set to the expected standard deviation of the position)
72 * @since 8.0
73 * @see #NumericalPropagatorBuilder(Orbit, ODEIntegratorBuilder, PositionAngle,
74 * double, AttitudeProvider)
75 */
76 public NumericalPropagatorBuilder(final Orbit referenceOrbit,
77 final ODEIntegratorBuilder builder,
78 final PositionAngle positionAngle,
79 final double positionScale) {
80 this(referenceOrbit, builder, positionAngle, positionScale,
81 InertialProvider.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 positionAngle position angle type to use
96 * @param positionScale scaling factor used for orbital parameters normalization
97 * (typically set to the expected standard deviation of the position)
98 * @param attitudeProvider attitude law.
99 * @since 10.1
100 */
101 public NumericalPropagatorBuilder(final Orbit referenceOrbit,
102 final ODEIntegratorBuilder builder,
103 final PositionAngle positionAngle,
104 final double positionScale,
105 final AttitudeProvider attitudeProvider) {
106 super(referenceOrbit, positionAngle, positionScale, true, attitudeProvider);
107 this.builder = builder;
108 this.forceModels = new ArrayList<ForceModel>();
109 this.mass = Propagator.DEFAULT_MASS;
110 }
111
112 /** Create a copy of a NumericalPropagatorBuilder object.
113 * @return Copied version of the NumericalPropagatorBuilder
114 */
115 public NumericalPropagatorBuilder copy() {
116 final NumericalPropagatorBuilder copyBuilder =
117 new NumericalPropagatorBuilder(createInitialOrbit(),
118 builder,
119 getPositionAngle(),
120 getPositionScale(),
121 getAttitudeProvider());
122 copyBuilder.setMass(mass);
123 for (ForceModel model : forceModels) {
124 copyBuilder.addForceModel(model);
125 }
126 return copyBuilder;
127 }
128
129 /** Get the integrator builder.
130 * @return the integrator builder
131 * @since 9.2
132 */
133 public ODEIntegratorBuilder getIntegratorBuilder()
134 {
135 return builder;
136 }
137
138 /** Get the list of all force models.
139 * @return the list of all force models
140 * @since 9.2
141 */
142 public List<ForceModel> getAllForceModels()
143 {
144 return Collections.unmodifiableList(forceModels);
145 }
146
147 /** Add a force model to the global perturbation model.
148 * <p>If this method is not called at all, the integrated orbit will follow
149 * a Keplerian evolution only.</p>
150 * @param model perturbing {@link ForceModel} to add
151 */
152 public void addForceModel(final ForceModel model) {
153 if (model instanceof NewtonianAttraction) {
154 // we want to add the central attraction force model
155 if (hasNewtonianAttraction()) {
156 // there is already a central attraction model, replace it
157 forceModels.set(forceModels.size() - 1, model);
158 } else {
159 // there are no central attraction model yet, add it at the end of the list
160 forceModels.add(model);
161 }
162 } else {
163 // we want to add a perturbing force model
164 if (hasNewtonianAttraction()) {
165 // insert the new force model before Newtonian attraction,
166 // which should always be the last one in the list
167 forceModels.add(forceModels.size() - 1, model);
168 } else {
169 // we only have perturbing force models up to now, just append at the end of the list
170 forceModels.add(model);
171 }
172 }
173
174 for (final ParameterDriver driver : model.getParametersDrivers()) {
175 addSupportedParameter(driver);
176 }
177 }
178
179 /** Get the mass.
180 * @return the mass
181 * @since 9.2
182 */
183 public double getMass()
184 {
185 return mass;
186 }
187
188 /** Set the initial mass.
189 * @param mass the mass (kg)
190 */
191 public void setMass(final double mass) {
192 this.mass = mass;
193 }
194
195 /** {@inheritDoc} */
196 public NumericalPropagator buildPropagator(final double[] normalizedParameters) {
197
198 setParameters(normalizedParameters);
199 final Orbit orbit = createInitialOrbit();
200 final Attitude attitude =
201 getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
202 final SpacecraftState state = new SpacecraftState(orbit, attitude, mass);
203
204 final NumericalPropagator propagator = new NumericalPropagator(
205 builder.buildIntegrator(orbit, getOrbitType()),
206 getAttitudeProvider());
207 propagator.setOrbitType(getOrbitType());
208 propagator.setPositionAngleType(getPositionAngle());
209
210 // Configure force models
211 if (!hasNewtonianAttraction()) {
212 // There are no central attraction model yet, add it at the end of the list
213 addForceModel(new NewtonianAttraction(orbit.getMu()));
214 }
215 for (ForceModel model : forceModels) {
216 propagator.addForceModel(model);
217 }
218
219 propagator.resetInitialState(state);
220
221 // Add additional equations to the propagator
222 for (AdditionalEquations equation: getAdditionalEquations()) {
223 propagator.addAdditionalEquations(equation);
224 }
225
226 return propagator;
227 }
228
229 /** {@inheritDoc} */
230 public BatchLSModel buildLSModel(final OrbitDeterminationPropagatorBuilder[] builders,
231 final List<ObservedMeasurement<?>> measurements,
232 final ParameterDriversList estimatedMeasurementsParameters,
233 final ModelObserver observer) {
234 return new BatchLSModel(builders, measurements, estimatedMeasurementsParameters, observer);
235 }
236
237 /** {@inheritDoc} */
238 @Override
239 public KalmanModel buildKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
240 final List<CovarianceMatrixProvider> covarianceMatricesProviders,
241 final ParameterDriversList estimatedMeasurementsParameters,
242 final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
243 return new KalmanModel(propagatorBuilders, covarianceMatricesProviders,
244 estimatedMeasurementsParameters, measurementProcessNoiseMatrix);
245 }
246
247 /** Check if Newtonian attraction force model is available.
248 * <p>
249 * Newtonian attraction is always the last force model in the list.
250 * </p>
251 * @return true if Newtonian attraction force model is available
252 */
253 private boolean hasNewtonianAttraction() {
254 final int last = forceModels.size() - 1;
255 return last >= 0 && forceModels.get(last) instanceof NewtonianAttraction;
256 }
257
258 }