1 /* Copyright 2002-2024 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.FrameAlignedProvider;
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.forces.ForceModel;
30 import org.orekit.forces.gravity.NewtonianAttraction;
31 import org.orekit.orbits.Orbit;
32 import org.orekit.orbits.PositionAngleType;
33 import org.orekit.propagation.Propagator;
34 import org.orekit.propagation.SpacecraftState;
35 import org.orekit.propagation.integration.AdditionalDerivativesProvider;
36 import org.orekit.propagation.numerical.NumericalPropagator;
37 import org.orekit.utils.ParameterDriver;
38 import org.orekit.utils.ParameterDriversList;
39
40 /** Builder for numerical propagator.
41 * @author Pascal Parraud
42 * @since 6.0
43 */
44 public class NumericalPropagatorBuilder extends AbstractPropagatorBuilder {
45
46 /** First order integrator builder for propagation. */
47 private final ODEIntegratorBuilder builder;
48
49 /** Force models used during the extrapolation of the orbit. */
50 private final List<ForceModel> forceModels;
51
52 /** Current mass for initial state (kg). */
53 private double mass;
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 positionAngleType position angle type to use
69 * @param positionScale scaling factor used for orbital parameters normalization
70 * (typically set to the expected standard deviation of the position)
71 * @since 8.0
72 * @see #NumericalPropagatorBuilder(Orbit, ODEIntegratorBuilder, PositionAngleType,
73 * double, AttitudeProvider)
74 */
75 public NumericalPropagatorBuilder(final Orbit referenceOrbit,
76 final ODEIntegratorBuilder builder,
77 final PositionAngleType positionAngleType,
78 final double positionScale) {
79 this(referenceOrbit, builder, positionAngleType, positionScale,
80 FrameAlignedProvider.of(referenceOrbit.getFrame()));
81 }
82
83 /** Build a new instance.
84 * <p>
85 * The reference orbit is used as a model to {@link
86 * #createInitialOrbit() create initial orbit}. It defines the
87 * inertial frame, the central attraction coefficient, and is also used together
88 * 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.
91 * </p>
92 * @param referenceOrbit reference orbit from which real orbits will be built
93 * @param builder first order integrator builder
94 * @param positionAngleType position angle type to use
95 * @param positionScale scaling factor used for orbital parameters normalization
96 * (typically set to the expected standard deviation of the position)
97 * @param attitudeProvider attitude law.
98 * @since 10.1
99 */
100 public NumericalPropagatorBuilder(final Orbit referenceOrbit,
101 final ODEIntegratorBuilder builder,
102 final PositionAngleType positionAngleType,
103 final double positionScale,
104 final AttitudeProvider attitudeProvider) {
105 super(referenceOrbit, positionAngleType, positionScale, true, attitudeProvider);
106 this.builder = builder;
107 this.forceModels = new ArrayList<ForceModel>();
108 this.mass = Propagator.DEFAULT_MASS;
109 }
110
111 /** Create a copy of a NumericalPropagatorBuilder object.
112 * @return Copied version of the NumericalPropagatorBuilder
113 */
114 public NumericalPropagatorBuilder copy() {
115 final NumericalPropagatorBuilder copyBuilder =
116 new NumericalPropagatorBuilder(createInitialOrbit(),
117 builder,
118 getPositionAngleType(),
119 getPositionScale(),
120 getAttitudeProvider());
121 copyBuilder.setMass(mass);
122 for (ForceModel model : forceModels) {
123 copyBuilder.addForceModel(model);
124 }
125 return copyBuilder;
126 }
127
128 /** Get the integrator builder.
129 * @return the integrator builder
130 * @since 9.2
131 */
132 public ODEIntegratorBuilder getIntegratorBuilder()
133 {
134 return builder;
135 }
136
137 /** Get the list of all force models.
138 * @return the list of all force models
139 * @since 9.2
140 */
141 public List<ForceModel> getAllForceModels()
142 {
143 return Collections.unmodifiableList(forceModels);
144 }
145
146 /** Add a force model to the global perturbation model.
147 * <p>If this method is not called at all, the integrated orbit will follow
148 * a Keplerian evolution only.</p>
149 * @param model perturbing {@link ForceModel} to add
150 */
151 public void addForceModel(final ForceModel model) {
152 if (model instanceof NewtonianAttraction) {
153 // we want to add the central attraction force model
154 if (hasNewtonianAttraction()) {
155 // there is already a central attraction model, replace it
156 forceModels.set(forceModels.size() - 1, model);
157 } else {
158 // there are no central attraction model yet, add it at the end of the list
159 forceModels.add(model);
160 }
161 } else {
162 // we want to add a perturbing force model
163 if (hasNewtonianAttraction()) {
164 // insert the new force model before Newtonian attraction,
165 // which should always be the last one in the list
166 forceModels.add(forceModels.size() - 1, model);
167 } else {
168 // we only have perturbing force models up to now, just append at the end of the list
169 forceModels.add(model);
170 }
171 }
172
173 addSupportedParameters(model.getParametersDrivers());
174 }
175
176 /** Get the mass.
177 * @return the mass
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 NumericalPropagator buildPropagator(final double[] normalizedParameters) {
194
195 setParameters(normalizedParameters);
196 final Orbit orbit = createInitialOrbit();
197 final Attitude attitude =
198 getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
199 final SpacecraftState state = new SpacecraftState(orbit, attitude, mass);
200
201 final NumericalPropagator propagator = new NumericalPropagator(
202 builder.buildIntegrator(orbit, getOrbitType()),
203 getAttitudeProvider());
204 propagator.setOrbitType(getOrbitType());
205 propagator.setPositionAngleType(getPositionAngleType());
206
207 // Configure force models
208 if (!hasNewtonianAttraction()) {
209 // There are no central attraction model yet, add it at the end of the list
210 addForceModel(new NewtonianAttraction(orbit.getMu()));
211 }
212 for (ForceModel model : forceModels) {
213 propagator.addForceModel(model);
214 }
215
216 propagator.resetInitialState(state);
217
218 // Add additional derivatives providers to the propagator
219 for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
220 propagator.addAdditionalDerivativesProvider(provider);
221 }
222
223 return propagator;
224
225 }
226
227 /** {@inheritDoc} */
228 @Override
229 public BatchLSModel buildLeastSquaresModel(final PropagatorBuilder[] builders,
230 final List<ObservedMeasurement<?>> measurements,
231 final ParameterDriversList estimatedMeasurementsParameters,
232 final ModelObserver observer) {
233 return new BatchLSModel(builders, measurements, estimatedMeasurementsParameters, observer);
234 }
235
236 /** Check if Newtonian attraction force model is available.
237 * <p>
238 * Newtonian attraction is always the last force model in the list.
239 * </p>
240 * @return true if Newtonian attraction force model is available
241 */
242 private boolean hasNewtonianAttraction() {
243 final int last = forceModels.size() - 1;
244 return last >= 0 && forceModels.get(last) instanceof NewtonianAttraction;
245 }
246
247 }