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