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