JacobiansMapper.java

  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. import org.hipparchus.linear.Array2DRowRealMatrix;
  19. import org.hipparchus.linear.DecompositionSolver;
  20. import org.hipparchus.linear.QRDecomposition;
  21. import org.hipparchus.linear.RealMatrix;
  22. import org.orekit.orbits.Orbit;
  23. import org.orekit.orbits.OrbitType;
  24. import org.orekit.orbits.PositionAngle;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.propagation.integration.AbstractJacobiansMapper;
  27. import org.orekit.utils.ParameterDriversList;

  28. /** Mapper between two-dimensional Jacobian matrices and one-dimensional {@link
  29.  * SpacecraftState#getAdditionalState(String) additional state arrays}.
  30.  * <p>
  31.  * This class does not hold the states by itself. Instances of this class are guaranteed
  32.  * to be immutable.
  33.  * </p>
  34.  * @author Luc Maisonobe
  35.  * @see org.orekit.propagation.numerical.NumericalPropagator
  36.  * @see SpacecraftState#getAdditionalState(String)
  37.  * @see org.orekit.propagation.AbstractPropagator
  38.  */
  39. public class JacobiansMapper extends AbstractJacobiansMapper {

  40.     /** State dimension, fixed to 6.
  41.      * @since 9.0
  42.      */
  43.     public static final int STATE_DIMENSION = 6;

  44.     /** Name. */
  45.     private String name;

  46.     /** Orbit type. */
  47.     private final OrbitType orbitType;

  48.     /** Position angle type. */
  49.     private final PositionAngle angleType;

  50.     /** Simple constructor.
  51.      * @param name name of the Jacobians
  52.      * @param parameters selected parameters for Jacobian computation
  53.      * @param orbitType orbit type
  54.      * @param angleType position angle type
  55.      */
  56.     JacobiansMapper(final String name, final ParameterDriversList parameters,
  57.                     final OrbitType orbitType, final PositionAngle angleType) {
  58.         super(name, parameters);
  59.         this.orbitType  = orbitType;
  60.         this.angleType  = angleType;
  61.         this.name = name;
  62.     }

  63.     /** Get the conversion Jacobian between state parameters and parameters used for derivatives.
  64.      * <p>
  65.      * For DSST and TLE propagators, state parameters and parameters used for derivatives are the same,
  66.      * so the Jacobian is simply the identity.
  67.      * </p>
  68.      * <p>
  69.      * For Numerical propagator, parameters used for derivatives are cartesian
  70.      * and they can be different from state parameters because the numerical propagator can accept different type
  71.      * of orbits.
  72.      * </p>
  73.      * @param state spacecraft state
  74.      * @return conversion Jacobian
  75.      */
  76.     protected double[][] getConversionJacobian(final SpacecraftState state) {

  77.         final double[][] dYdC = new double[STATE_DIMENSION][STATE_DIMENSION];

  78.         // make sure the state is in the desired orbit type
  79.         final Orbit orbit = orbitType.convertType(state.getOrbit());

  80.         // compute the Jacobian, taking the position angle type into account
  81.         orbit.getJacobianWrtCartesian(angleType, dYdC);

  82.         return dYdC;

  83.     }

  84.     /** {@inheritDoc}
  85.      * <p>
  86.      * This method converts the Jacobians to Cartesian parameters and put the converted data
  87.      * in the one-dimensional {@code p} array.
  88.      * </p>
  89.      */
  90.     public void setInitialJacobians(final SpacecraftState state, final double[][] dY1dY0,
  91.                                     final double[][] dY1dP, final double[] p) {

  92.         // set up a converter
  93.         final RealMatrix dY1dC1 = new Array2DRowRealMatrix(getConversionJacobian(state), false);
  94.         final DecompositionSolver solver = new QRDecomposition(dY1dC1).getSolver();

  95.         // convert the provided state Jacobian
  96.         final RealMatrix dC1dY0 = solver.solve(new Array2DRowRealMatrix(dY1dY0, false));

  97.         // map the converted state Jacobian to one-dimensional array
  98.         int index = 0;
  99.         for (int i = 0; i < STATE_DIMENSION; ++i) {
  100.             for (int j = 0; j < STATE_DIMENSION; ++j) {
  101.                 p[index++] = dC1dY0.getEntry(i, j);
  102.             }
  103.         }

  104.         if (getParameters() != 0) {
  105.             // convert the provided state Jacobian
  106.             final RealMatrix dC1dP = solver.solve(new Array2DRowRealMatrix(dY1dP, false));

  107.             // map the converted parameters Jacobian to one-dimensional array
  108.             for (int i = 0; i < STATE_DIMENSION; ++i) {
  109.                 for (int j = 0; j < getParameters(); ++j) {
  110.                     p[index++] = dC1dP.getEntry(i, j);
  111.                 }
  112.             }
  113.         }

  114.     }

  115.     /** {@inheritDoc} */
  116.     public void getStateJacobian(final SpacecraftState state, final double[][] dYdY0) {

  117.         // get the conversion Jacobian
  118.         final double[][] dYdC = getConversionJacobian(state);

  119.         // extract the additional state
  120.         final double[] p = state.getAdditionalState(name);

  121.         // compute dYdY0 = dYdC * dCdY0, without allocating new arrays
  122.         for (int i = 0; i < STATE_DIMENSION; i++) {
  123.             final double[] rowC = dYdC[i];
  124.             final double[] rowD = dYdY0[i];
  125.             for (int j = 0; j < STATE_DIMENSION; ++j) {
  126.                 double sum = 0;
  127.                 int pIndex = j;
  128.                 for (int k = 0; k < STATE_DIMENSION; ++k) {
  129.                     sum += rowC[k] * p[pIndex];
  130.                     pIndex += STATE_DIMENSION;
  131.                 }
  132.                 rowD[j] = sum;
  133.             }
  134.         }

  135.     }

  136.     /** {@inheritDoc} */
  137.     public void getParametersJacobian(final SpacecraftState state, final double[][] dYdP) {

  138.         if (getParameters() != 0) {

  139.             // get the conversion Jacobian
  140.             final double[][] dYdC = getConversionJacobian(state);

  141.             // extract the additional state
  142.             final double[] p = state.getAdditionalState(name);

  143.             // compute dYdP = dYdC * dCdP, without allocating new arrays
  144.             for (int i = 0; i < STATE_DIMENSION; i++) {
  145.                 final double[] rowC = dYdC[i];
  146.                 final double[] rowD = dYdP[i];
  147.                 for (int j = 0; j < getParameters(); ++j) {
  148.                     double sum = 0;
  149.                     int pIndex = j + STATE_DIMENSION * STATE_DIMENSION;
  150.                     for (int k = 0; k < STATE_DIMENSION; ++k) {
  151.                         sum += rowC[k] * p[pIndex];
  152.                         pIndex += getParameters();
  153.                     }
  154.                     rowD[j] = sum;
  155.                 }
  156.             }

  157.         }

  158.     }

  159. }