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.numerical;
18
19 import org.hipparchus.linear.Array2DRowRealMatrix;
20 import org.hipparchus.linear.DecompositionSolver;
21 import org.hipparchus.linear.QRDecomposition;
22 import org.hipparchus.linear.RealMatrix;
23 import org.orekit.orbits.Orbit;
24 import org.orekit.orbits.OrbitType;
25 import org.orekit.orbits.PositionAngle;
26 import org.orekit.propagation.SpacecraftState;
27 import org.orekit.propagation.integration.AbstractJacobiansMapper;
28 import org.orekit.utils.ParameterDriversList;
29
30 /** Mapper between two-dimensional Jacobian matrices and one-dimensional {@link
31 * SpacecraftState#getAdditionalState(String) additional state arrays}.
32 * <p>
33 * This class does not hold the states by itself. Instances of this class are guaranteed
34 * to be immutable.
35 * </p>
36 * @author Luc Maisonobe
37 * @see org.orekit.propagation.numerical.PartialDerivativesEquations
38 * @see org.orekit.propagation.numerical.NumericalPropagator
39 * @see SpacecraftState#getAdditionalState(String)
40 * @see org.orekit.propagation.AbstractPropagator
41 */
42 public class JacobiansMapper extends AbstractJacobiansMapper {
43
44 /** State dimension, fixed to 6.
45 * @since 9.0
46 */
47 public static final int STATE_DIMENSION = 6;
48
49 /** Selected parameters for Jacobian computation. */
50 private final ParameterDriversList parameters;
51
52 /** Name. */
53 private String name;
54
55 /** Orbit type. */
56 private final OrbitType orbitType;
57
58 /** Position angle type. */
59 private final PositionAngle angleType;
60
61 /** Simple constructor.
62 * @param name name of the Jacobians
63 * @param parameters selected parameters for Jacobian computation
64 * @param orbitType orbit type
65 * @param angleType position angle type
66 */
67 JacobiansMapper(final String name, final ParameterDriversList parameters,
68 final OrbitType orbitType, final PositionAngle angleType) {
69 super(name, parameters);
70 this.orbitType = orbitType;
71 this.angleType = angleType;
72 this.parameters = parameters;
73 this.name = name;
74 }
75
76 /** Get the conversion Jacobian between state parameters and parameters used for derivatives.
77 * <p>
78 * For DSST and TLE propagators, state parameters and parameters used for derivatives are the same,
79 * so the Jocabian is simply the identity.
80 * </p>
81 * <p>
82 * For Numerical propagator, parameters used for derivatives are cartesian
83 * and they can be different from state parameters because the numerical propagator can accept different type
84 * of orbits.
85 * </p>
86 * @param state spacecraft state
87 * @return conversion Jacobian
88 */
89 protected double[][] getConversionJacobian(final SpacecraftState state) {
90
91 final double[][] dYdC = new double[STATE_DIMENSION][STATE_DIMENSION];
92
93 // make sure the state is in the desired orbit type
94 final Orbit orbit = orbitType.convertType(state.getOrbit());
95
96 // compute the Jacobian, taking the position angle type into account
97 orbit.getJacobianWrtCartesian(angleType, dYdC);
98
99 return dYdC;
100
101 }
102
103 /** {@inheritDoc}
104 * <p>
105 * This method converts the Jacobians to Cartesian parameters and put the converted data
106 * in the one-dimensional {@code p} array.
107 * </p>
108 */
109 public void setInitialJacobians(final SpacecraftState state, final double[][] dY1dY0,
110 final double[][] dY1dP, final double[] p) {
111
112 // set up a converter
113 final RealMatrix dY1dC1 = new Array2DRowRealMatrix(getConversionJacobian(state), false);
114 final DecompositionSolver solver = new QRDecomposition(dY1dC1).getSolver();
115
116 // convert the provided state Jacobian
117 final RealMatrix dC1dY0 = solver.solve(new Array2DRowRealMatrix(dY1dY0, false));
118
119 // map the converted state Jacobian to one-dimensional array
120 int index = 0;
121 for (int i = 0; i < STATE_DIMENSION; ++i) {
122 for (int j = 0; j < STATE_DIMENSION; ++j) {
123 p[index++] = dC1dY0.getEntry(i, j);
124 }
125 }
126
127 if (parameters.getNbParams() != 0) {
128 // convert the provided state Jacobian
129 final RealMatrix dC1dP = solver.solve(new Array2DRowRealMatrix(dY1dP, false));
130
131 // map the converted parameters Jacobian to one-dimensional array
132 for (int i = 0; i < STATE_DIMENSION; ++i) {
133 for (int j = 0; j < parameters.getNbParams(); ++j) {
134 p[index++] = dC1dP.getEntry(i, j);
135 }
136 }
137 }
138
139 }
140
141 /** {@inheritDoc} */
142 public void getStateJacobian(final SpacecraftState state, final double[][] dYdY0) {
143
144 // get the conversion Jacobian
145 final double[][] dYdC = getConversionJacobian(state);
146
147 // extract the additional state
148 final double[] p = state.getAdditionalState(name);
149
150 // compute dYdY0 = dYdC * dCdY0, without allocating new arrays
151 for (int i = 0; i < STATE_DIMENSION; i++) {
152 final double[] rowC = dYdC[i];
153 final double[] rowD = dYdY0[i];
154 for (int j = 0; j < STATE_DIMENSION; ++j) {
155 double sum = 0;
156 int pIndex = j;
157 for (int k = 0; k < STATE_DIMENSION; ++k) {
158 sum += rowC[k] * p[pIndex];
159 pIndex += STATE_DIMENSION;
160 }
161 rowD[j] = sum;
162 }
163 }
164
165 }
166
167 /** {@inheritDoc} */
168 public void getParametersJacobian(final SpacecraftState state, final double[][] dYdP) {
169
170 if (parameters.getNbParams() != 0) {
171
172 // get the conversion Jacobian
173 final double[][] dYdC = getConversionJacobian(state);
174
175 // extract the additional state
176 final double[] p = state.getAdditionalState(name);
177
178 // compute dYdP = dYdC * dCdP, without allocating new arrays
179 for (int i = 0; i < STATE_DIMENSION; i++) {
180 final double[] rowC = dYdC[i];
181 final double[] rowD = dYdP[i];
182 for (int j = 0; j < parameters.getNbParams(); ++j) {
183 double sum = 0;
184 int pIndex = j + STATE_DIMENSION * STATE_DIMENSION;
185 for (int k = 0; k < STATE_DIMENSION; ++k) {
186 sum += rowC[k] * p[pIndex];
187 pIndex += parameters.getNbParams();
188 }
189 rowD[j] = sum;
190 }
191 }
192
193 }
194
195 }
196
197 }