1   /* Copyright 2002-2025 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 AbstractIntegratedPropagatorBuilder<DSSTPropagator> {
48  
49      /** Force models used during the extrapolation of the orbit. */
50      private final List<DSSTForceModel> forceModels;
51  
52      /** Type of the elements used to define the orbital state.*/
53      private PropagationType stateType;
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 positionScale scaling factor used for orbital parameters normalization
69       * (typically set to the expected standard deviation of the position)
70       * @param propagationType type of the orbit used for the propagation (mean or osculating)
71       * @param stateType type of the elements used to define the orbital state (mean or osculating)
72       * @see #DSSTPropagatorBuilder(Orbit, ODEIntegratorBuilder, double, PropagationType,
73       * PropagationType, AttitudeProvider)
74       */
75      public DSSTPropagatorBuilder(final Orbit referenceOrbit,
76                                   final ODEIntegratorBuilder builder,
77                                   final double positionScale,
78                                   final PropagationType propagationType,
79                                   final PropagationType stateType) {
80          this(referenceOrbit, builder, positionScale, propagationType, stateType,
81               FrameAlignedProvider.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 positionScale scaling factor used for orbital parameters normalization
96       * (typically set to the expected standard deviation of the position)
97       * @param propagationType type of the orbit used for the propagation (mean or osculating)
98       * @param stateType type of the elements used to define the orbital state (mean or osculating)
99       * @param attitudeProvider attitude law.
100      * @since 10.1
101      */
102     public DSSTPropagatorBuilder(final Orbit referenceOrbit,
103                                  final ODEIntegratorBuilder builder,
104                                  final double positionScale,
105                                  final PropagationType propagationType,
106                                  final PropagationType stateType,
107                                  final AttitudeProvider attitudeProvider) {
108         super(referenceOrbit, builder, PositionAngleType.MEAN, positionScale, propagationType, attitudeProvider, Propagator.DEFAULT_MASS);
109         this.forceModels       = new ArrayList<>();
110         this.stateType         = stateType;
111     }
112 
113     /** Get the type of the elements used to define the orbital state (mean or osculating).
114      * @return the type of the elements used to define the orbital state
115      */
116     public PropagationType getStateType() {
117         return stateType;
118     }
119 
120     /** Get the list of all force models.
121      * @return the list of all force models
122      */
123     public List<DSSTForceModel> getAllForceModels()
124     {
125         return Collections.unmodifiableList(forceModels);
126     }
127 
128     /** Add a force model to the global perturbation model.
129      * <p>If this method is not called at all, the integrated orbit will follow
130      * a Keplerian evolution only.</p>
131      * @param model perturbing {@link DSSTForceModel} to add
132      */
133     public void addForceModel(final DSSTForceModel model) {
134         if (model instanceof DSSTNewtonianAttraction) {
135             // we want to add the central attraction force model
136             if (hasNewtonianAttraction()) {
137                 // there is already a central attraction model, replace it
138                 forceModels.set(forceModels.size() - 1, model);
139             } else {
140                 // there are no central attraction model yet, add it at the end of the list
141                 forceModels.add(model);
142             }
143         } else {
144             // we want to add a perturbing force model
145             if (hasNewtonianAttraction()) {
146                 // insert the new force model before Newtonian attraction,
147                 // which should always be the last one in the list
148                 forceModels.add(forceModels.size() - 1, model);
149             } else {
150                 // we only have perturbing force models up to now, just append at the end of the list
151                 forceModels.add(model);
152             }
153         }
154 
155         addSupportedParameters(model.getParametersDrivers());
156     }
157 
158     /** Reset the orbit in the propagator builder.
159      * @param newOrbit newOrbit New orbit to set in the propagator builder
160      * @param orbitType orbit type (MEAN or OSCULATING)
161      */
162     public void resetOrbit(final Orbit newOrbit, final PropagationType orbitType) {
163         this.stateType = orbitType;
164         super.resetOrbit(newOrbit);
165     }
166 
167     /** {@inheritDoc} */
168     public DSSTPropagator buildPropagator(final double[] normalizedParameters) {
169 
170         setParameters(normalizedParameters);
171         final EquinoctialOrbit orbit    = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(createInitialOrbit());
172         final Attitude         attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
173         final SpacecraftState  state    = new SpacecraftState(orbit, attitude).withMass(getMass());
174 
175         final DSSTPropagator propagator = new DSSTPropagator(
176                 getIntegratorBuilder().buildIntegrator(orbit, OrbitType.EQUINOCTIAL, PositionAngleType.MEAN),
177                 getPropagationType(), getAttitudeProvider());
178 
179         // Configure force models
180         if (!hasNewtonianAttraction()) {
181             // There are no central attraction model yet, add it at the end of the list
182             addForceModel(new DSSTNewtonianAttraction(orbit.getMu()));
183         }
184         for (DSSTForceModel model : forceModels) {
185             propagator.addForceModel(model);
186         }
187 
188         propagator.setInitialState(state, stateType);
189 
190         // Add additional derivatives providers to the propagator
191         for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
192             propagator.addAdditionalDerivativesProvider(provider);
193         }
194 
195         return propagator;
196 
197     }
198 
199     /** {@inheritDoc} */
200     @Override
201     public DSSTBatchLSModel buildLeastSquaresModel(final PropagatorBuilder[] builders,
202                                                    final List<ObservedMeasurement<?>> measurements,
203                                                    final ParameterDriversList estimatedMeasurementsParameters,
204                                                    final ModelObserver observer) {
205         return new DSSTBatchLSModel(builders,
206                                     measurements,
207                                     estimatedMeasurementsParameters,
208                                     observer,
209                                     getPropagationType());
210     }
211 
212     /** Check if Newtonian attraction force model is available.
213      * <p>
214      * Newtonian attraction is always the last force model in the list.
215      * </p>
216      * @return true if Newtonian attraction force model is available
217      */
218     private boolean hasNewtonianAttraction() {
219         final int last = forceModels.size() - 1;
220         return last >= 0 && forceModels.get(last) instanceof DSSTNewtonianAttraction;
221     }
222 
223 }