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.AttitudeProvider;
20  import org.orekit.attitudes.FrameAlignedProvider;
21  import org.orekit.forces.gravity.potential.GravityFieldFactory;
22  import org.orekit.forces.gravity.potential.TideSystem;
23  import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
24  import org.orekit.orbits.Orbit;
25  import org.orekit.orbits.OrbitType;
26  import org.orekit.orbits.PositionAngleType;
27  import org.orekit.propagation.Propagator;
28  import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
29  
30  /** Builder for Eckstein-Hechler propagator.
31   * @author Pascal Parraud
32   * @since 6.0
33   */
34  public class EcksteinHechlerPropagatorBuilder extends AbstractAnalyticalPropagatorBuilder<EcksteinHechlerPropagator> {
35  
36      /** Provider for un-normalized coefficients. */
37      private final UnnormalizedSphericalHarmonicsProvider provider;
38  
39      /** Build a new instance.
40       * <p>
41       * The template orbit is used as a model to {@link
42       * #createInitialOrbit() create initial orbit}. It defines the
43       * inertial frame, the central attraction coefficient, the orbit type, and is also
44       * used together with the {@code positionScale} to convert from the {@link
45       * org.orekit.utils.ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
46       * callers of this builder to the real orbital parameters.
47       * The default attitude provider is aligned with the orbit's inertial frame.
48       * </p>
49       *
50       * @param templateOrbit reference orbit from which real orbits will be built
51       * (note that the mu from this orbit will be overridden with the mu from the
52       * {@code provider})
53       * @param provider for un-normalized zonal coefficients
54       * @param positionAngleType position angle type to use
55       * @param positionScale scaling factor used for orbital parameters normalization
56       * (typically set to the expected standard deviation of the position)
57       * @since 8.0
58       * @see #EcksteinHechlerPropagatorBuilder(Orbit,
59       * UnnormalizedSphericalHarmonicsProvider, PositionAngleType, double, AttitudeProvider)
60       */
61      public EcksteinHechlerPropagatorBuilder(final Orbit templateOrbit,
62                                              final UnnormalizedSphericalHarmonicsProvider provider,
63                                              final PositionAngleType positionAngleType,
64                                              final double positionScale) {
65          this(templateOrbit, provider, positionAngleType, positionScale,
66               FrameAlignedProvider.of(templateOrbit.getFrame()));
67      }
68  
69      /** Build a new instance.
70       * <p>
71       * The template orbit is used as a model to {@link
72       * #createInitialOrbit() create initial orbit}. It defines the
73       * inertial frame, the central attraction coefficient, the orbit type, and is also
74       * used together with the {@code positionScale} to convert from the {@link
75       * org.orekit.utils.ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
76       * callers of this builder to the real orbital parameters.
77       * </p>
78       * @param templateOrbit reference orbit from which real orbits will be built
79       * (note that the mu from this orbit will be overridden with the mu from the
80       * {@code provider})
81       * @param provider for un-normalized zonal coefficients
82       * @param positionAngleType position angle type to use
83       * @param positionScale scaling factor used for orbital parameters normalization
84       * (typically set to the expected standard deviation of the position)
85       * @param attitudeProvider attitude law to use.
86       * @since 10.1
87       */
88      public EcksteinHechlerPropagatorBuilder(final Orbit templateOrbit,
89                                              final UnnormalizedSphericalHarmonicsProvider provider,
90                                              final PositionAngleType positionAngleType,
91                                              final double positionScale,
92                                              final AttitudeProvider attitudeProvider) {
93          super(overrideMu(templateOrbit, provider, positionAngleType), positionAngleType,
94                positionScale, true, attitudeProvider, Propagator.DEFAULT_MASS);
95          this.provider = provider;
96      }
97  
98      /** Build a new instance.
99       * <p>
100      * The template orbit is used as a model to {@link
101      * #createInitialOrbit() create initial orbit}. It defines the
102      * inertial frame, the central attraction coefficient, the orbit type, and is also
103      * used together with the {@code positionScale} to convert from the {@link
104      * org.orekit.utils.ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
105      * callers of this builder to the real orbital parameters.
106      * </p>
107      *
108      * @param templateOrbit reference orbit from which real orbits will be built
109      * (note that the mu from this orbit will be overridden with the mu from the
110      * {@code provider})
111      * @param referenceRadius reference radius of the Earth for the potential model (m)
112      * @param mu central attraction coefficient (m³/s²)
113      * @param tideSystem tide system
114      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
115      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
116      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
117      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
118      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
119      * @param orbitType orbit type to use
120      * @param positionAngleType position angle type to use
121      * @param positionScale scaling factor used for orbital parameters normalization
122      * (typically set to the expected standard deviation of the position)
123      * @since 8.0
124      * @see #EcksteinHechlerPropagatorBuilder(Orbit,
125      * UnnormalizedSphericalHarmonicsProvider, PositionAngleType, double, AttitudeProvider)
126      */
127     public EcksteinHechlerPropagatorBuilder(final Orbit templateOrbit,
128                                             final double referenceRadius,
129                                             final double mu,
130                                             final TideSystem tideSystem,
131                                             final double c20,
132                                             final double c30,
133                                             final double c40,
134                                             final double c50,
135                                             final double c60,
136                                             final OrbitType orbitType,
137                                             final PositionAngleType positionAngleType,
138                                             final double positionScale) {
139         this(templateOrbit,
140              GravityFieldFactory.getUnnormalizedProvider(referenceRadius, mu, tideSystem,
141                                                          new double[][] {
142                                                              {
143                                                                  0
144                                                              }, {
145                                                                  0
146                                                              }, {
147                                                                  c20
148                                                              }, {
149                                                                  c30
150                                                              }, {
151                                                                  c40
152                                                              }, {
153                                                                  c50
154                                                              }, {
155                                                                  c60
156                                                              }
157                                                          }, new double[][] {
158                                                              {
159                                                                  0
160                                                              }, {
161                                                                  0
162                                                              }, {
163                                                                  0
164                                                              }, {
165                                                                  0
166                                                              }, {
167                                                                  0
168                                                              }, {
169                                                                  0
170                                                              }, {
171                                                                  0
172                                                              }
173                                                          }),
174                 positionAngleType, positionScale);
175     }
176 
177     /** Copy constructor.
178      * @param builder builder to copy from
179      */
180     private EcksteinHechlerPropagatorBuilder(final EcksteinHechlerPropagatorBuilder builder) {
181         this(builder.createInitialOrbit(), builder.provider, builder.getPositionAngleType(),
182              builder.getPositionScale(), builder.getAttitudeProvider());
183     }
184 
185     /** {@inheritDoc}. */
186     @Override
187     public EcksteinHechlerPropagatorBuilder clone() {
188         // Call to super clone() method to avoid warning
189         final EcksteinHechlerPropagatorBuilder clonedBuilder = (EcksteinHechlerPropagatorBuilder) super.clone();
190 
191         // Use copy constructor to unlink orbital drivers
192         final EcksteinHechlerPropagatorBuilder builder = new EcksteinHechlerPropagatorBuilder(clonedBuilder);
193 
194         // Set mass
195         builder.setMass(getMass());
196 
197         // Return cloned builder
198         return builder;
199     }
200 
201     /** Override central attraction coefficient.
202      * @param templateOrbit template orbit
203      * @param provider gravity field provider
204      * @param positionAngleType position angle type to use
205      * @return orbit with overridden central attraction coefficient
206      */
207     private static Orbit overrideMu(final Orbit templateOrbit,
208                                     final UnnormalizedSphericalHarmonicsProvider provider,
209                                     final PositionAngleType positionAngleType) {
210         final double[] parameters    = new double[6];
211         final double[] parametersDot = parameters.clone();
212         templateOrbit.getType().mapOrbitToArray(templateOrbit, positionAngleType, parameters, parametersDot);
213         return templateOrbit.getType().mapArrayToOrbit(parameters, parametersDot, positionAngleType,
214                                                        templateOrbit.getDate(),
215                                                        provider.getMu(),
216                                                        templateOrbit.getFrame());
217     }
218 
219     /** {@inheritDoc} */
220     public EcksteinHechlerPropagator buildPropagator(final double[] normalizedParameters) {
221         setParameters(normalizedParameters);
222         final EcksteinHechlerPropagator propagator = new EcksteinHechlerPropagator(createInitialOrbit(), getAttitudeProvider(),
223             getMass(), provider);
224         getImpulseManeuvers().forEach(propagator::addEventDetector);
225         return propagator;
226     }
227 
228 }