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.DSSTBatchLSModel;
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.DSSTKalmanModel;
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.AdditionalEquations;
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     /** Create a copy of a DSSTPropagatorBuilder object.
127      * @return Copied version of the DSSTPropagatorBuilder
128      */
129     public DSSTPropagatorBuilder copy() {
130         final DSSTPropagatorBuilder copyBuilder =
131                         new DSSTPropagatorBuilder((EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit()),
132                                                   builder,
133                                                   getPositionScale(),
134                                                   propagationType,
135                                                   stateType,
136                                                   getAttitudeProvider());
137         copyBuilder.setMass(mass);
138         for (DSSTForceModel model : forceModels) {
139             copyBuilder.addForceModel(model);
140         }
141         return copyBuilder;
142     }
143 
144     /** Get the integrator builder.
145      * @return the integrator builder
146      */
147     public ODEIntegratorBuilder getIntegratorBuilder()
148     {
149         return builder;
150     }
151 
152     /** Get the list of all force models.
153      * @return the list of all force models
154      */
155     public List<DSSTForceModel> getAllForceModels()
156     {
157         return Collections.unmodifiableList(forceModels);
158     }
159 
160     /** Get the mass.
161      * @return the mass
162      */
163     public double getMass()
164     {
165         return mass;
166     }
167 
168     /** Set the initial mass.
169      * @param mass the mass (kg)
170      */
171     public void setMass(final double mass) {
172         this.mass = mass;
173     }
174 
175     /** Add a force model to the global perturbation model.
176      * <p>If this method is not called at all, the integrated orbit will follow
177      * a Keplerian evolution only.</p>
178      * @param model perturbing {@link DSSTForceModel} to add
179      */
180     public void addForceModel(final DSSTForceModel model) {
181         if (model instanceof DSSTNewtonianAttraction) {
182             // we want to add the central attraction force model
183             if (hasNewtonianAttraction()) {
184                 // there is already a central attraction model, replace it
185                 forceModels.set(forceModels.size() - 1, model);
186             } else {
187                 // there are no central attraction model yet, add it at the end of the list
188                 forceModels.add(model);
189             }
190         } else {
191             // we want to add a perturbing force model
192             if (hasNewtonianAttraction()) {
193                 // insert the new force model before Newtonian attraction,
194                 // which should always be the last one in the list
195                 forceModels.add(forceModels.size() - 1, model);
196             } else {
197                 // we only have perturbing force models up to now, just append at the end of the list
198                 forceModels.add(model);
199             }
200         }
201 
202         for (final ParameterDriver driver : model.getParametersDrivers()) {
203             addSupportedParameter(driver);
204         }
205     }
206 
207     /** {@inheritDoc} */
208     public DSSTPropagator buildPropagator(final double[] normalizedParameters) {
209 
210         setParameters(normalizedParameters);
211         final EquinoctialOrbit orbit    = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit());
212         final Attitude         attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
213         final SpacecraftState  state    = new SpacecraftState(orbit, attitude, mass);
214 
215         final DSSTPropagator propagator = new DSSTPropagator(
216                 builder.buildIntegrator(orbit, OrbitType.EQUINOCTIAL),
217                 propagationType,
218                 getAttitudeProvider());
219 
220         // Configure force models
221         if (!hasNewtonianAttraction()) {
222             // There are no central attraction model yet, add it at the end of the list
223             addForceModel(new DSSTNewtonianAttraction(orbit.getMu()));
224         }
225         for (DSSTForceModel model : forceModels) {
226             propagator.addForceModel(model);
227         }
228 
229         propagator.setInitialState(state, stateType);
230 
231         // Add additional equations to the propagator
232         for (AdditionalEquations equation: getAdditionalEquations()) {
233             propagator.addAdditionalEquations(equation);
234         }
235 
236         return propagator;
237     }
238 
239     /** {@inheritDoc} */
240     @Override
241     public DSSTBatchLSModel buildLSModel(final OrbitDeterminationPropagatorBuilder[] builders,
242                                 final List<ObservedMeasurement<?>> measurements,
243                                 final ParameterDriversList estimatedMeasurementsParameters,
244                                 final ModelObserver observer) {
245         return new DSSTBatchLSModel(builders,
246                                     measurements,
247                                     estimatedMeasurementsParameters,
248                                     observer,
249                                     propagationType, stateType);
250     }
251 
252     /** {@inheritDoc} */
253     @Override
254     public DSSTKalmanModel buildKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
255                                             final List<CovarianceMatrixProvider> covarianceMatricesProviders,
256                                             final ParameterDriversList estimatedMeasurementsParameters,
257                                             final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
258         return new DSSTKalmanModel(propagatorBuilders, covarianceMatricesProviders,
259                                    estimatedMeasurementsParameters, measurementProcessNoiseMatrix,
260                                    propagationType, stateType);
261     }
262 
263     /** Check if Newtonian attraction force model is available.
264      * <p>
265      * Newtonian attraction is always the last force model in the list.
266      * </p>
267      * @return true if Newtonian attraction force model is available
268      */
269     private boolean hasNewtonianAttraction() {
270         final int last = forceModels.size() - 1;
271         return last >= 0 && forceModels.get(last) instanceof DSSTNewtonianAttraction;
272     }
273 
274 }