1   /* Copyright 2002-2021 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.semianalytical.dsst;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.hipparchus.analysis.differentiation.Gradient;
25  import org.orekit.errors.OrekitInternalError;
26  import org.orekit.propagation.FieldSpacecraftState;
27  import org.orekit.propagation.PropagationType;
28  import org.orekit.propagation.SpacecraftState;
29  import org.orekit.propagation.integration.AbstractJacobiansMapper;
30  import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
31  import org.orekit.propagation.semianalytical.dsst.forces.FieldShortPeriodTerms;
32  import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
33  import org.orekit.utils.ParameterDriver;
34  import org.orekit.utils.ParameterDriversList;
35  
36  /** Mapper between two-dimensional Jacobian matrices and one-dimensional {@link
37   * SpacecraftState#getAdditionalState(String) additional state arrays}.
38   * <p>
39   * This class does not hold the states by itself. Instances of this class are guaranteed
40   * to be immutable.
41   * </p>
42   * @author Luc Maisonobe
43   * @author Bryan Cazabonne
44   * @see org.orekit.propagation.semianalytical.dsst.DSSTPartialDerivativesEquations
45   * @see org.orekit.propagation.semianalytical.dsst.DSSTPropagator
46   * @see SpacecraftState#getAdditionalState(String)
47   * @see org.orekit.propagation.AbstractPropagator
48   */
49  public class DSSTJacobiansMapper extends AbstractJacobiansMapper {
50  
51      /** State dimension, fixed to 6.
52       * @since 9.0
53       */
54      public static final int STATE_DIMENSION = 6;
55  
56      /** Retrograde factor I.
57       *  <p>
58       *  DSST model needs equinoctial orbit as internal representation.
59       *  Classical equinoctial elements have discontinuities when inclination
60       *  is close to zero. In this representation, I = +1. <br>
61       *  To avoid this discontinuity, another representation exists and equinoctial
62       *  elements can be expressed in a different way, called "retrograde" orbit.
63       *  This implies I = -1. <br>
64       *  As Orekit doesn't implement the retrograde orbit, I is always set to +1.
65       *  But for the sake of consistency with the theory, the retrograde factor
66       *  has been kept in the formulas.
67       *  </p>
68       */
69      private static final int I = 1;
70  
71      /** Name. */
72      private String name;
73  
74      /** Selected parameters for Jacobian computation. */
75      private final ParameterDriversList parameters;
76  
77      /** Parameters map. */
78      private Map<ParameterDriver, Integer> map;
79  
80      /** Propagator computing state evolution. */
81      private final DSSTPropagator propagator;
82  
83      /** Placeholder for the derivatives of the short period terms.*/
84      private double[] shortPeriodDerivatives;
85  
86      /** Type of the orbit used for the propagation.*/
87      private PropagationType propagationType;
88  
89      /** Simple constructor.
90       * @param name name of the Jacobians
91       * @param parameters selected parameters for Jacobian computation
92       * @param propagator the propagator that will handle the orbit propagation
93       * @param map parameters map
94       * @param propagationType type of the orbit used for the propagation (mean or osculating)
95       */
96      DSSTJacobiansMapper(final String name,
97                          final ParameterDriversList parameters,
98                          final DSSTPropagator propagator,
99                          final Map<ParameterDriver, Integer> map,
100                         final PropagationType propagationType) {
101 
102         super(name, parameters);
103 
104         shortPeriodDerivatives = null;
105 
106         this.parameters      = parameters;
107         this.name            = name;
108         this.propagator      = propagator;
109         this.map             = map;
110         this.propagationType = propagationType;
111 
112     }
113 
114     /** {@inheritDoc} */
115     public void setInitialJacobians(final SpacecraftState state, final double[][] dY1dY0,
116                                     final double[][] dY1dP, final double[] p) {
117 
118         // map the converted state Jacobian to one-dimensional array
119         int index = 0;
120         for (int i = 0; i < STATE_DIMENSION; ++i) {
121             for (int j = 0; j < STATE_DIMENSION; ++j) {
122                 p[index++] = (i == j) ? 1.0 : 0.0;
123             }
124         }
125 
126         if (parameters.getNbParams() != 0) {
127 
128             // map the converted parameters Jacobian to one-dimensional array
129             for (int i = 0; i < STATE_DIMENSION; ++i) {
130                 for (int j = 0; j < parameters.getNbParams(); ++j) {
131                     p[index++] = dY1dP[i][j];
132                 }
133             }
134         }
135 
136     }
137 
138     /** {@inheritDoc} */
139     public void getStateJacobian(final SpacecraftState state, final double[][] dYdY0) {
140 
141         // extract additional state
142         final double[] p = state.getAdditionalState(name);
143 
144         for (int i = 0; i < STATE_DIMENSION; i++) {
145             final double[] row = dYdY0[i];
146             for (int j = 0; j < STATE_DIMENSION; j++) {
147                 row[j] = p[i * STATE_DIMENSION + j] + shortPeriodDerivatives[i * STATE_DIMENSION + j];
148             }
149         }
150 
151     }
152 
153 
154     /** {@inheritDoc} */
155     public void getParametersJacobian(final SpacecraftState state, final double[][] dYdP) {
156 
157         if (parameters.getNbParams() != 0) {
158 
159             // extract the additional state
160             final double[] p = state.getAdditionalState(name);
161 
162             for (int i = 0; i < STATE_DIMENSION; i++) {
163                 final double[] row = dYdP[i];
164                 for (int j = 0; j < parameters.getNbParams(); j++) {
165                     row[j] = p[STATE_DIMENSION * STATE_DIMENSION + (j + parameters.getNbParams() * i)] +
166                              shortPeriodDerivatives[STATE_DIMENSION * STATE_DIMENSION + (j + parameters.getNbParams() * i)];
167                 }
168             }
169 
170         }
171 
172     }
173 
174     /** Compute the derivatives of the short period terms related to the additional state parameters.
175     * @param s Current state information: date, kinematics, attitude, and additional state
176     */
177     @SuppressWarnings("unchecked")
178     public void setShortPeriodJacobians(final SpacecraftState s) {
179 
180         final double[] p = s.getAdditionalState(name);
181         if (shortPeriodDerivatives == null) {
182             shortPeriodDerivatives = new double[p.length];
183         }
184 
185         switch (propagationType) {
186             case MEAN :
187                 break;
188             case OSCULATING :
189                 // initialize Jacobians to zero
190                 final int paramDim = parameters.getNbParams();
191                 final int dim = 6;
192                 final double[][] dShortPerioddState = new double[dim][dim];
193                 final double[][] dShortPerioddParam = new double[dim][paramDim];
194                 final DSSTGradientConverter converter = new DSSTGradientConverter(s, propagator.getAttitudeProvider());
195 
196                 // Compute Jacobian
197                 for (final DSSTForceModel forceModel : propagator.getAllForceModels()) {
198 
199                     final FieldSpacecraftState<Gradient> dsState = converter.getState(forceModel);
200                     final Gradient[] dsParameters = converter.getParameters(dsState, forceModel);
201                     final FieldAuxiliaryElements<Gradient> auxiliaryElements = new FieldAuxiliaryElements<>(dsState.getOrbit(), I);
202 
203                     final Gradient zero = dsState.getDate().getField().getZero();
204                     final List<FieldShortPeriodTerms<Gradient>> shortPeriodTerms = new ArrayList<>();
205                     shortPeriodTerms.addAll(forceModel.initializeShortPeriodTerms(auxiliaryElements, propagationType, dsParameters));
206                     forceModel.updateShortPeriodTerms(dsParameters, dsState);
207                     final Gradient[] shortPeriod = new Gradient[6];
208                     Arrays.fill(shortPeriod, zero);
209                     for (final FieldShortPeriodTerms<Gradient> spt : shortPeriodTerms) {
210                         final Gradient[] spVariation = spt.value(dsState.getOrbit());
211                         for (int i = 0; i < spVariation .length; i++) {
212                             shortPeriod[i] = shortPeriod[i].add(spVariation[i]);
213                         }
214                     }
215 
216                     final double[] derivativesASP  = shortPeriod[0].getGradient();
217                     final double[] derivativesExSP = shortPeriod[1].getGradient();
218                     final double[] derivativesEySP = shortPeriod[2].getGradient();
219                     final double[] derivativesHxSP = shortPeriod[3].getGradient();
220                     final double[] derivativesHySP = shortPeriod[4].getGradient();
221                     final double[] derivativesLSP  = shortPeriod[5].getGradient();
222 
223                     // update Jacobian with respect to state
224                     addToRow(derivativesASP,  0, dShortPerioddState);
225                     addToRow(derivativesExSP, 1, dShortPerioddState);
226                     addToRow(derivativesEySP, 2, dShortPerioddState);
227                     addToRow(derivativesHxSP, 3, dShortPerioddState);
228                     addToRow(derivativesHySP, 4, dShortPerioddState);
229                     addToRow(derivativesLSP,  5, dShortPerioddState);
230 
231                     int index = converter.getFreeStateParameters();
232                     for (ParameterDriver driver : forceModel.getParametersDrivers()) {
233                         if (driver.isSelected()) {
234                             final int parameterIndex = map.get(driver);
235                             dShortPerioddParam[0][parameterIndex] += derivativesASP[index];
236                             dShortPerioddParam[1][parameterIndex] += derivativesExSP[index];
237                             dShortPerioddParam[2][parameterIndex] += derivativesEySP[index];
238                             dShortPerioddParam[3][parameterIndex] += derivativesHxSP[index];
239                             dShortPerioddParam[4][parameterIndex] += derivativesHySP[index];
240                             dShortPerioddParam[5][parameterIndex] += derivativesLSP[index];
241                             ++index;
242                         }
243                     }
244                 }
245 
246                 // Get orbital short period derivatives with respect orbital elements.
247                 for (int i = 0; i < dim; i++) {
248                     for (int j = 0; j < dim; j++) {
249                         shortPeriodDerivatives[j + dim * i] = dShortPerioddState[i][j];
250                     }
251                 }
252 
253                 // Get orbital short period derivatives with respect to model parameters.
254                 final int columnTop = dim * dim;
255                 for (int k = 0; k < paramDim; k++) {
256                     for (int i = 0; i < dim; ++i) {
257                         shortPeriodDerivatives[columnTop + (i + dim * k)] = dShortPerioddParam[i][k];
258                     }
259                 }
260                 break;
261             default:
262                 throw new OrekitInternalError(null);
263         }
264     }
265 
266     /** Fill Jacobians rows.
267      * @param derivatives derivatives of a component
268      * @param index component index (0 for a, 1 for ex, 2 for ey, 3 for hx, 4 for hy, 5 for l)
269      * @param dMeanElementRatedElement Jacobian of mean elements rate with respect to mean elements
270      */
271     private void addToRow(final double[] derivatives, final int index,
272                           final double[][] dMeanElementRatedElement) {
273 
274         for (int i = 0; i < 6; i++) {
275             dMeanElementRatedElement[index][i] += derivatives[i];
276         }
277 
278     }
279 
280 }