1   /* Copyright 2022-2025 Bryan Cazabonne
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    * Bryan Cazabonne 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.semianalytical.dsst.forces;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.util.MathArrays;
22  import org.orekit.attitudes.AttitudeProvider;
23  import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
24  import org.orekit.propagation.FieldSpacecraftState;
25  import org.orekit.propagation.PropagationType;
26  import org.orekit.propagation.SpacecraftState;
27  import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
28  import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
29  import org.orekit.utils.ParameterDriver;
30  
31  import java.util.Collections;
32  import java.util.List;
33  
34  /**
35   * Second order J2-squared force model.
36   * <p>
37   * The force model implements a closed-form of the J2-squared perturbation.
38   * The full realization of the model is based on a gaussian quadrature.
39   * Even if it is very accurate, a gaussian quadrature is usually time consuming.
40   * A closed-form is less accurate than a gaussian quadrature, but faster.
41   * </p>
42   * @author Bryan Cazabonne
43   * @since 12.0
44   */
45  public class DSSTJ2SquaredClosedForm implements DSSTForceModel {
46  
47      /** Model for second order terms. */
48      private final J2SquaredModel j2SquaredModel;
49  
50      /** Gravity field to use. */
51      private final UnnormalizedSphericalHarmonicsProvider provider;
52  
53      /**
54       * Constructor.
55       *
56       * @param j2SquaredModel model for second order terms
57       * @param provider       gravity field to use
58       */
59      public DSSTJ2SquaredClosedForm(final J2SquaredModel j2SquaredModel,
60                                     final UnnormalizedSphericalHarmonicsProvider provider) {
61          // Initialize fields
62          this.j2SquaredModel = j2SquaredModel;
63          this.provider = provider;
64      }
65  
66      /** {@inheritDoc}. */
67      @Override
68      public double[] getMeanElementRate(final SpacecraftState state,
69                                         final AuxiliaryElements auxiliaryElements,
70                                         final double[] parameters) {
71  
72          // Context
73          final DSSTJ2SquaredClosedFormContext context = new DSSTJ2SquaredClosedFormContext(auxiliaryElements, provider);
74  
75          // Second-order terms
76          final double[] delta = j2SquaredModel.computeMeanEquinoctialSecondOrderTerms(context);
77  
78          // J2
79          final double J2 = -provider.onDate(state.getDate()).getUnnormalizedCnm(2, 0);
80          final double J2SquaredOver2 = 0.5 * J2 * J2;
81  
82          // Mean elements rate
83          final double da = 0.0;
84          final double dk = J2SquaredOver2 * delta[1];
85          final double dh = J2SquaredOver2 * delta[2];
86          final double dq = J2SquaredOver2 * delta[3];
87          final double dp = J2SquaredOver2 * delta[4];
88          final double dM = J2SquaredOver2 * delta[5];
89  
90          // Return
91          return new double[] { da, dk, dh, dq, dp, dM };
92  
93      }
94  
95      /** {@inheritDoc}. */
96      @Override
97      public <T extends CalculusFieldElement<T>> T[] getMeanElementRate(final FieldSpacecraftState<T> state,
98                                                                        final FieldAuxiliaryElements<T> auxiliaryElements,
99                                                                        final T[] parameters) {
100 
101         // Field
102         final Field<T> field = state.getDate().getField();
103 
104         // Context
105         final FieldDSSTJ2SquaredClosedFormContext<T> context = new FieldDSSTJ2SquaredClosedFormContext<>(auxiliaryElements, provider);
106 
107         // Second-order terms
108         final T[] delta = j2SquaredModel.computeMeanEquinoctialSecondOrderTerms(context);
109 
110         // J2
111         final double J2 = -provider.onDate(state.getDate().toAbsoluteDate()).getUnnormalizedCnm(2, 0);
112         final double J2SquaredOver2 = 0.5 * J2 * J2;
113 
114         // Mean elements rate
115         final T da = field.getZero();
116         final T dk = delta[1].multiply(J2SquaredOver2);
117         final T dh = delta[2].multiply(J2SquaredOver2);
118         final T dq = delta[3].multiply(J2SquaredOver2);
119         final T dp = delta[4].multiply(J2SquaredOver2);
120         final T dM = delta[5].multiply(J2SquaredOver2);
121 
122         // Return
123         final T[] elements =  MathArrays.buildArray(field, 6);
124         elements[0] = da;
125         elements[1] = dk;
126         elements[2] = dh;
127         elements[3] = dq;
128         elements[4] = dp;
129         elements[5] = dM;
130 
131         return elements;
132 
133     }
134 
135     /** {@inheritDoc}. */
136     @Override
137     public List<ShortPeriodTerms> initializeShortPeriodTerms(final AuxiliaryElements auxiliaryElements,
138                                                              final PropagationType type,
139                                                              final double[] parameters) {
140         return j2SquaredModel.initializeShortPeriodTerms(auxiliaryElements, type, parameters);
141     }
142 
143     /** {@inheritDoc}. */
144     @Override
145     public <T extends CalculusFieldElement<T>> List<FieldShortPeriodTerms<T>> initializeShortPeriodTerms(final FieldAuxiliaryElements<T> auxiliaryElements,
146                                                                                                          final PropagationType type,
147                                                                                                          final T[] parameters) {
148         return j2SquaredModel.initializeShortPeriodTerms(auxiliaryElements, type, parameters);
149     }
150 
151     /** {@inheritDoc}. */
152     @Override
153     public List<ParameterDriver> getParametersDrivers() {
154         return Collections.emptyList();
155     }
156 
157     /** {@inheritDoc}. */
158     @Override
159     public void registerAttitudeProvider(final AttitudeProvider attitudeProvider) {
160         // Nothing is done since this contribution is not sensitive to attitude
161     }
162 
163     /** {@inheritDoc}. */
164     @Override
165     public void updateShortPeriodTerms(final double[] parameters, final SpacecraftState... meanStates) {
166         j2SquaredModel.updateShortPeriodTerms(parameters, meanStates);
167     }
168 
169     /** {@inheritDoc}. */
170     @Override
171     @SuppressWarnings("unchecked")
172     public <T extends CalculusFieldElement<T>> void updateShortPeriodTerms(final T[] parameters, final FieldSpacecraftState<T>... meanStates) {
173         j2SquaredModel.updateShortPeriodTerms(parameters, meanStates);
174     }
175 
176 }