1   /* Copyright 2002-2026 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.EquinoctialOrbitFactory;
27  import org.orekit.orbits.Orbit;
28  import org.orekit.orbits.OrbitType;
29  import org.orekit.orbits.PositionAngleType;
30  import org.orekit.propagation.PropagationType;
31  import org.orekit.propagation.Propagator;
32  import org.orekit.propagation.SpacecraftState;
33  import org.orekit.propagation.integration.AdditionalDerivativesProvider;
34  import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
35  import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
36  import org.orekit.propagation.semianalytical.dsst.forces.DSSTNewtonianAttraction;
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
48      extends AbstractIntegratedPropagatorBuilder<DSSTPropagator, EquinoctialOrbit, EquinoctialOrbitFactory> {
49  
50      /** Force models used during the extrapolation of the orbit. */
51      private final List<DSSTForceModel> forceModels;
52  
53      /** Type of the elements used to define the orbital state.*/
54      private PropagationType stateType;
55  
56      /** Build a new instance.
57       * @param factory factory for initial orbit
58       * @param builder first order integrator builder
59       * @param propagationType type of the orbit used for the propagation (mean or osculating)
60       * @param stateType type of the elements used to define the orbital state (mean or osculating)
61       * @see #DSSTPropagatorBuilder(EquinoctialOrbitFactory, ODEIntegratorBuilder,
62       * PropagationType, PropagationType, AttitudeProvider)
63       * @since 14.0
64       */
65      public DSSTPropagatorBuilder(final EquinoctialOrbitFactory factory,
66                                   final ODEIntegratorBuilder builder,
67                                   final PropagationType propagationType,
68                                   final PropagationType stateType) {
69          this(factory, builder, propagationType, stateType,
70               FrameAlignedProvider.of(factory.getFrame()));
71      }
72  
73      /** Build a new instance.
74       * @param factory factory for initial orbit
75       * @param builder first order integrator builder
76       * @param propagationType type of the orbit used for the propagation (mean or osculating)
77       * @param stateType type of the elements used to define the orbital state (mean or osculating)
78       * @param attitudeProvider attitude law.
79       * @since 14.0
80       */
81      public DSSTPropagatorBuilder(final EquinoctialOrbitFactory factory,
82                                   final ODEIntegratorBuilder builder,
83                                   final PropagationType propagationType,
84                                   final PropagationType stateType,
85                                   final AttitudeProvider attitudeProvider) {
86          super(factory, builder, propagationType, attitudeProvider, Propagator.DEFAULT_MASS);
87          this.forceModels       = new ArrayList<>();
88          this.stateType         = stateType;
89      }
90  
91      /** {@inheritDoc}. */
92      @Override
93      public DSSTPropagatorBuilder clone() {
94          // Call to super clone() method to avoid warning
95          final DSSTPropagatorBuilder clonedBuilder = (DSSTPropagatorBuilder) super.clone();
96  
97          // Use cloned builder to unlink orbital drivers
98          final DSSTPropagatorBuilder copyBuilder =
99              new DSSTPropagatorBuilder((EquinoctialOrbitFactory) clonedBuilder.getOrbitalParameterFactory().clone(),
100                                       clonedBuilder.getIntegratorBuilder(),
101                                       clonedBuilder.getPropagationType(),
102                                       clonedBuilder.getStateType(),
103                                       clonedBuilder.getAttitudeProvider());
104 
105         // Update mass and force models
106         copyBuilder.setMass(getMass());
107         for (DSSTForceModel model : forceModels) {
108             copyBuilder.addForceModel(model);
109         }
110         return copyBuilder;
111 
112     }
113 
114     /** Get the type of the elements used to define the orbital state (mean or osculating).
115      * @return the type of the elements used to define the orbital state
116      */
117     public PropagationType getStateType() {
118         return stateType;
119     }
120 
121     /** Get the list of all force models.
122      * @return the list of all force models
123      */
124     public List<DSSTForceModel> getAllForceModels()
125     {
126         return Collections.unmodifiableList(forceModels);
127     }
128 
129     /** Add a force model to the global perturbation model.
130      * <p>If this method is not called at all, the integrated orbit will follow
131      * a Keplerian evolution only.</p>
132      * @param model perturbing {@link DSSTForceModel} to add
133      */
134     public void addForceModel(final DSSTForceModel model) {
135         if (model instanceof DSSTNewtonianAttraction) {
136             // we want to add the central attraction force model
137             if (hasNewtonianAttraction()) {
138                 // there is already a central attraction model, replace it
139                 forceModels.set(forceModels.size() - 1, model);
140             } else {
141                 // there are no central attraction model yet, add it at the end of the list
142                 forceModels.add(model);
143             }
144         } else {
145             // we want to add a perturbing force model
146             if (hasNewtonianAttraction()) {
147                 // insert the new force model before Newtonian attraction,
148                 // which should always be the last one in the list
149                 forceModels.add(forceModels.size() - 1, model);
150             } else {
151                 // we only have perturbing force models up to now, just append at the end of the list
152                 forceModels.add(model);
153             }
154         }
155 
156         addPropagationParameters(model.getParametersDrivers());
157     }
158 
159     /** Reset the orbit in the propagator builder.
160      * @param newOrbit newOrbit New orbit to set in the propagator builder
161      * @param orbitType orbit type (MEAN or OSCULATING)
162      */
163     public void resetOrbit(final Orbit newOrbit, final PropagationType orbitType) {
164         this.stateType = orbitType;
165         super.resetOrbit(newOrbit);
166     }
167 
168     /** {@inheritDoc} */
169     public DSSTPropagator buildPropagator(final double[] normalizedParameters) {
170 
171         setParameters(normalizedParameters);
172         final EquinoctialOrbit orbit    = getOrbitalParameterFactory().createFromDrivers();
173         final Attitude         attitude = getAttitudeProvider().getAttitude(orbit, orbit.getDate(), orbit.getFrame());
174         final SpacecraftState  state    = new SpacecraftState(orbit, attitude).withMass(getMass());
175 
176         final DSSTPropagator propagator = new DSSTPropagator(
177                 getIntegratorBuilder().buildIntegrator(orbit, OrbitType.EQUINOCTIAL, PositionAngleType.MEAN),
178                 getPropagationType(), getAttitudeProvider());
179 
180         // Configure force models
181         if (!hasNewtonianAttraction()) {
182             // There are no central attraction model yet, add it at the end of the list
183             addForceModel(new DSSTNewtonianAttraction(orbit.getMu()));
184         }
185         for (DSSTForceModel model : forceModels) {
186             propagator.addForceModel(model);
187         }
188 
189         propagator.setInitialState(state, stateType);
190 
191         // Add additional derivatives providers to the propagator
192         for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
193             propagator.addAdditionalDerivativesProvider(provider);
194         }
195 
196         return propagator;
197 
198     }
199 
200     /** {@inheritDoc} */
201     @Override
202     public DSSTBatchLSModel buildLeastSquaresModel(final PropagatorBuilder[] builders,
203                                                    final List<ObservedMeasurement<?>> measurements,
204                                                    final ParameterDriversList estimatedMeasurementsParameters,
205                                                    final ModelObserver observer) {
206         return new DSSTBatchLSModel(builders,
207                                     measurements,
208                                     estimatedMeasurementsParameters,
209                                     observer,
210                                     getPropagationType());
211     }
212 
213     /** Check if Newtonian attraction force model is available.
214      * <p>
215      * Newtonian attraction is always the last force model in the list.
216      * </p>
217      * @return true if Newtonian attraction force model is available
218      */
219     private boolean hasNewtonianAttraction() {
220         final int last = forceModels.size() - 1;
221         return last >= 0 && forceModels.get(last) instanceof DSSTNewtonianAttraction;
222     }
223 
224 }