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.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.DSSTBatchLSModel;
27  import org.orekit.estimation.leastsquares.ModelObserver;
28  import org.orekit.estimation.measurements.ObservedMeasurement;
29  import org.orekit.estimation.sequential.AbstractKalmanModel;
30  import org.orekit.estimation.sequential.CovarianceMatrixProvider;
31  import org.orekit.orbits.EquinoctialOrbit;
32  import org.orekit.orbits.Orbit;
33  import org.orekit.orbits.OrbitType;
34  import org.orekit.orbits.PositionAngle;
35  import org.orekit.propagation.PropagationType;
36  import org.orekit.propagation.Propagator;
37  import org.orekit.propagation.SpacecraftState;
38  import org.orekit.propagation.integration.AdditionalDerivativesProvider;
39  import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
40  import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
41  import org.orekit.propagation.semianalytical.dsst.forces.DSSTNewtonianAttraction;
42  import org.orekit.utils.ParameterDriver;
43  import org.orekit.utils.ParameterDriversList;
44  
45  /** Builder for DSST propagator.
46   * @author Bryan Cazabonne
47   * @since 10.0
48   */
49  public class DSSTPropagatorBuilder extends AbstractPropagatorBuilder implements OrbitDeterminationPropagatorBuilder {
50  
51      /** First order integrator builder for propagation. */
52      private final ODEIntegratorBuilder builder;
53  
54      /** Force models used during the extrapolation of the orbit. */
55      private final List<DSSTForceModel> forceModels;
56  
57      /** Current mass for initial state (kg). */
58      private double mass;
59  
60      /** Type of the orbit used for the propagation.*/
61      private PropagationType propagationType;
62  
63      /** Type of the elements used to define the orbital state.*/
64      private PropagationType stateType;
65  
66      /** Build a new instance.
67       * <p>
68       * The reference orbit is used as a model to {@link
69       * #createInitialOrbit() create initial orbit}. It defines the
70       * inertial frame, the central attraction coefficient, and is also used together
71       * with the {@code positionScale} to convert from the {@link
72       * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
73       * callers of this builder to the real orbital parameters.
74       * </p>
75       *
76       * @param referenceOrbit reference orbit from which real orbits will be built
77       * @param builder first order integrator builder
78       * @param positionScale scaling factor used for orbital parameters normalization
79       * (typically set to the expected standard deviation of the position)
80       * @param propagationType type of the orbit used for the propagation (mean or osculating)
81       * @param stateType type of the elements used to define the orbital state (mean or osculating)
82       * @see #DSSTPropagatorBuilder(Orbit, ODEIntegratorBuilder, double, PropagationType,
83       * PropagationType, AttitudeProvider)
84       */
85      public DSSTPropagatorBuilder(final Orbit referenceOrbit,
86                                   final ODEIntegratorBuilder builder,
87                                   final double positionScale,
88                                   final PropagationType propagationType,
89                                   final PropagationType stateType) {
90          this(referenceOrbit, builder, positionScale, propagationType, stateType,
91                  InertialProvider.of(referenceOrbit.getFrame()));
92      }
93  
94      /** Build a new instance.
95       * <p>
96       * The reference orbit is used as a model to {@link
97       * #createInitialOrbit() create initial orbit}. It defines the
98       * inertial frame, the central attraction coefficient, and is also used together
99       * with the {@code positionScale} to convert from the {@link
100      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
101      * callers of this builder to the real orbital parameters.
102      * </p>
103      * @param referenceOrbit reference orbit from which real orbits will be built
104      * @param builder first order integrator builder
105      * @param positionScale scaling factor used for orbital parameters normalization
106      * (typically set to the expected standard deviation of the position)
107      * @param propagationType type of the orbit used for the propagation (mean or osculating)
108      * @param stateType type of the elements used to define the orbital state (mean or osculating)
109      * @param attitudeProvider attitude law.
110      * @since 10.1
111      */
112     public DSSTPropagatorBuilder(final Orbit referenceOrbit,
113                                  final ODEIntegratorBuilder builder,
114                                  final double positionScale,
115                                  final PropagationType propagationType,
116                                  final PropagationType stateType,
117                                  final AttitudeProvider attitudeProvider) {
118         super(referenceOrbit, PositionAngle.MEAN, positionScale, true, attitudeProvider);
119         this.builder           = builder;
120         this.forceModels       = new ArrayList<DSSTForceModel>();
121         this.mass              = Propagator.DEFAULT_MASS;
122         this.propagationType   = propagationType;
123         this.stateType         = stateType;
124     }
125 
126     /** Get the type of the orbit used for the propagation (mean or osculating).
127      * @return the type of the orbit used for the propagation
128      */
129     public PropagationType getPropagationType() {
130         return propagationType;
131     }
132 
133     /** Get the type of the elements used to define the orbital state (mean or osculating).
134      * @return the type of the elements used to define the orbital state
135      */
136     public PropagationType getStateType() {
137         return stateType;
138     }
139 
140     /** Create a copy of a DSSTPropagatorBuilder object.
141      * @return Copied version of the DSSTPropagatorBuilder
142      */
143     public DSSTPropagatorBuilder copy() {
144         final DSSTPropagatorBuilder copyBuilder =
145                         new DSSTPropagatorBuilder((EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit()),
146                                                   builder,
147                                                   getPositionScale(),
148                                                   propagationType,
149                                                   stateType,
150                                                   getAttitudeProvider());
151         copyBuilder.setMass(mass);
152         for (DSSTForceModel model : forceModels) {
153             copyBuilder.addForceModel(model);
154         }
155         return copyBuilder;
156     }
157 
158     /** Get the integrator builder.
159      * @return the integrator builder
160      */
161     public ODEIntegratorBuilder getIntegratorBuilder()
162     {
163         return builder;
164     }
165 
166     /** Get the list of all force models.
167      * @return the list of all force models
168      */
169     public List<DSSTForceModel> getAllForceModels()
170     {
171         return Collections.unmodifiableList(forceModels);
172     }
173 
174     /** Get the mass.
175      * @return the mass
176      */
177     public double getMass()
178     {
179         return mass;
180     }
181 
182     /** Set the initial mass.
183      * @param mass the mass (kg)
184      */
185     public void setMass(final double mass) {
186         this.mass = mass;
187     }
188 
189     /** Add a force model to the global perturbation model.
190      * <p>If this method is not called at all, the integrated orbit will follow
191      * a Keplerian evolution only.</p>
192      * @param model perturbing {@link DSSTForceModel} to add
193      */
194     public void addForceModel(final DSSTForceModel model) {
195         if (model instanceof DSSTNewtonianAttraction) {
196             // we want to add the central attraction force model
197             if (hasNewtonianAttraction()) {
198                 // there is already a central attraction model, replace it
199                 forceModels.set(forceModels.size() - 1, model);
200             } else {
201                 // there are no central attraction model yet, add it at the end of the list
202                 forceModels.add(model);
203             }
204         } else {
205             // we want to add a perturbing force model
206             if (hasNewtonianAttraction()) {
207                 // insert the new force model before Newtonian attraction,
208                 // which should always be the last one in the list
209                 forceModels.add(forceModels.size() - 1, model);
210             } else {
211                 // we only have perturbing force models up to now, just append at the end of the list
212                 forceModels.add(model);
213             }
214         }
215 
216         for (final ParameterDriver driver : model.getParametersDrivers()) {
217             addSupportedParameter(driver);
218         }
219     }
220 
221     /** Reset the orbit in the propagator builder.
222      * @param newOrbit newOrbit New orbit to set in the propagator builder
223      * @param orbitType orbit type (MEAN or OSCULATING)
224      */
225     public void resetOrbit(final Orbit newOrbit, final PropagationType orbitType) {
226         this.stateType = orbitType;
227         super.resetOrbit(newOrbit);
228     }
229 
230     /** {@inheritDoc} */
231     @SuppressWarnings("deprecation")
232     public DSSTPropagator buildPropagator(final double[] normalizedParameters) {
233 
234         setParameters(normalizedParameters);
235         final EquinoctialOrbit orbit    = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit());
236         final Attitude         attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
237         final SpacecraftState  state    = new SpacecraftState(orbit, attitude, mass);
238 
239         final DSSTPropagator propagator = new DSSTPropagator(
240                 builder.buildIntegrator(orbit, OrbitType.EQUINOCTIAL),
241                 propagationType,
242                 getAttitudeProvider());
243 
244         // Configure force models
245         if (!hasNewtonianAttraction()) {
246             // There are no central attraction model yet, add it at the end of the list
247             addForceModel(new DSSTNewtonianAttraction(orbit.getMu()));
248         }
249         for (DSSTForceModel model : forceModels) {
250             propagator.addForceModel(model);
251         }
252 
253         propagator.setInitialState(state, stateType);
254 
255         // Add additional derivatives providers to the propagator
256         for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
257             propagator.addAdditionalDerivativesProvider(provider);
258         }
259 
260         // FIXME: remove in 12.0 when AdditionalEquations is removed
261         for (org.orekit.propagation.integration.AdditionalEquations equations : getAdditionalEquations()) {
262             propagator.addAdditionalDerivativesProvider(new org.orekit.propagation.integration.AdditionalEquationsAdapter(equations, propagator::getInitialState));
263         }
264 
265         return propagator;
266 
267     }
268 
269     /** {@inheritDoc} */
270     @Override
271     public DSSTBatchLSModel buildLSModel(final OrbitDeterminationPropagatorBuilder[] builders,
272                                 final List<ObservedMeasurement<?>> measurements,
273                                 final ParameterDriversList estimatedMeasurementsParameters,
274                                 final ModelObserver observer) {
275         return new DSSTBatchLSModel(builders,
276                                     measurements,
277                                     estimatedMeasurementsParameters,
278                                     observer,
279                                     propagationType, stateType);
280     }
281 
282     /** {@inheritDoc} */
283     @Override
284     @SuppressWarnings("deprecation")
285     public AbstractKalmanModel buildKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
286                                                 final List<CovarianceMatrixProvider> covarianceMatricesProviders,
287                                                 final ParameterDriversList estimatedMeasurementsParameters,
288                                                 final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
289         // FIXME: remove in 12.0 when DSSTKalmanModel is removed
290         return new org.orekit.estimation.sequential.DSSTKalmanModel(propagatorBuilders,
291                                                                     covarianceMatricesProviders,
292                                                                     estimatedMeasurementsParameters,
293                                                                     measurementProcessNoiseMatrix,
294                                                                     propagationType, stateType);
295     }
296 
297     /** Check if Newtonian attraction force model is available.
298      * <p>
299      * Newtonian attraction is always the last force model in the list.
300      * </p>
301      * @return true if Newtonian attraction force model is available
302      */
303     private boolean hasNewtonianAttraction() {
304         final int last = forceModels.size() - 1;
305         return last >= 0 && forceModels.get(last) instanceof DSSTNewtonianAttraction;
306     }
307 
308 }