JacobiansMapper.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.apache.commons.math3.linear.Array2DRowRealMatrix;
  19. import org.apache.commons.math3.linear.DecompositionSolver;
  20. import org.apache.commons.math3.linear.QRDecomposition;
  21. import org.apache.commons.math3.linear.RealMatrix;
  22. import org.orekit.errors.OrekitException;
  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. /** Mapper between two-dimensional Jacobian matrices and one-dimensional {@link
  28.  * SpacecraftState#getAdditionalState(String) additional state arrays}.
  29.  * <p>
  30.  * This class does not hold the states by itself. Instances of this class are guaranteed
  31.  * to be immutable.
  32.  * </p>
  33.  * @author Luc Maisonobe
  34.  * @see org.orekit.propagation.numerical.PartialDerivativesEquations
  35.  * @see org.orekit.propagation.numerical.NumericalPropagator
  36.  * @see SpacecraftState#getAdditionalState(String)
  37.  * @see org.orekit.propagation.AbstractPropagator
  38.  */
  39. public class JacobiansMapper {

  40.     /** Name. */
  41.     private String name;

  42.     /** State vector dimension without additional parameters
  43.      * (either 6 or 7 depending on mass being included or not). */
  44.     private final int stateDimension;

  45.     /** Number of Parameters. */
  46.     private final int parameters;

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

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

  51.     /** Simple constructor.
  52.      * @param name name of the Jacobians
  53.      * @param stateDimension dimension of the state (either 6 or 7 depending on mass
  54.      * being included or not)
  55.      * @param parameters number of parameters
  56.      * @param orbitType orbit type
  57.      * @param angleType position angle type
  58.      */
  59.     JacobiansMapper(final String name, final int stateDimension, final int parameters,
  60.                     final OrbitType orbitType, final PositionAngle angleType) {
  61.         this.name           = name;
  62.         this.stateDimension = stateDimension;
  63.         this.parameters     = parameters;
  64.         this.orbitType      = orbitType;
  65.         this.angleType      = angleType;
  66.     }

  67.     /** Get the name of the partial Jacobians.
  68.      * @return name of the Jacobians
  69.      */
  70.     public String getName() {
  71.         return name;
  72.     }

  73.     /** Compute the length of the one-dimensional additional state array needed.
  74.      * @return length of the one-dimensional additional state array
  75.      */
  76.     public int getAdditionalStateDimension() {
  77.         return stateDimension * (stateDimension + parameters);
  78.     }

  79.     /** Get the state vector dimension.
  80.      * @return state vector dimension
  81.      */
  82.     public int getStateDimension() {
  83.         return stateDimension;
  84.     }

  85.     /** Get the number of parameters.
  86.      * @return number of parameters
  87.      */
  88.     public int getParameters() {
  89.         return parameters;
  90.     }

  91.     /** Get the conversion Jacobian between state parameters and cartesian parameters.
  92.      * @param state spacecraft state
  93.      * @return conversion Jacobian
  94.      */
  95.     private double[][] getdYdC(final SpacecraftState state) {

  96.         final double[][] dYdC = new double[stateDimension][stateDimension];

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

  99.         // compute the Jacobian, taking the position angle type into account
  100.         orbit.getJacobianWrtCartesian(angleType, dYdC);
  101.         for (int i = 6; i < stateDimension; ++i) {
  102.             dYdC[i][i] = 1.0;
  103.         }

  104.         return dYdC;

  105.     }

  106.     /** Set the Jacobian with respect to state into a one-dimensional additional state array.
  107.      * <p>
  108.      * This method converts the Jacobians to cartesian parameters and put the converted data
  109.      * in the one-dimensional {@code p} array.
  110.      * </p>
  111.      * @param state spacecraft state
  112.      * @param dY1dY0 Jacobian of current state at time t<sub>1</sub>
  113.      * with respect to state at some previous time t<sub>0</sub>
  114.      * @param dY1dP Jacobian of current state at time t<sub>1</sub>
  115.      * with respect to parameters (may be null if there are no parameters)
  116.      * @param p placeholder where to put the one-dimensional additional state
  117.      * @see #getStateJacobian(double[], double[][])
  118.      */
  119.     void setInitialJacobians(final SpacecraftState state, final double[][] dY1dY0,
  120.                              final double[][] dY1dP, final double[] p) {

  121.         // set up a converter between state parameters and cartesian parameters
  122.         final RealMatrix dY1dC1 = new Array2DRowRealMatrix(getdYdC(state), false);
  123.         final DecompositionSolver solver = new QRDecomposition(dY1dC1).getSolver();

  124.         // convert the provided state Jacobian to cartesian parameters
  125.         final RealMatrix dC1dY0 = solver.solve(new Array2DRowRealMatrix(dY1dY0, false));

  126.         // map the converted state Jacobian to one-dimensional array
  127.         int index = 0;
  128.         for (int i = 0; i < stateDimension; ++i) {
  129.             for (int j = 0; j < stateDimension; ++j) {
  130.                 p[index++] = dC1dY0.getEntry(i, j);
  131.             }
  132.         }

  133.         if (parameters > 0) {
  134.             // convert the provided state Jacobian to cartesian parameters
  135.             final RealMatrix dC1dP = solver.solve(new Array2DRowRealMatrix(dY1dP, false));

  136.             // map the converted parameters Jacobian to one-dimensional array
  137.             for (int i = 0; i < stateDimension; ++i) {
  138.                 for (int j = 0; j < parameters; ++j) {
  139.                     p[index++] = dC1dP.getEntry(i, j);
  140.                 }
  141.             }
  142.         }

  143.     }

  144.     /** Get the Jacobian with respect to state from a one-dimensional additional state array.
  145.      * <p>
  146.      * This method extract the data from the {@code state} and put it in the
  147.      * {@code dYdY0} array.
  148.      * </p>
  149.      * @param state spacecraft state
  150.      * @param dYdY0 placeholder where to put the Jacobian with respect to state
  151.      * @exception OrekitException if state does not contain the Jacobian additional state
  152.      * @see #getParametersJacobian(SpacecraftState, double[][])
  153.      */
  154.     public void getStateJacobian(final SpacecraftState state,  final double[][] dYdY0)
  155.         throws OrekitException {

  156.         // get the conversion Jacobian between state parameters and cartesian parameters
  157.         final double[][] dYdC = getdYdC(state);

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

  160.         // compute dYdY0 = dYdC * dCdY0, without allocating new arrays
  161.         for (int i = 0; i < stateDimension; i++) {
  162.             final double[] rowC = dYdC[i];
  163.             final double[] rowD = dYdY0[i];
  164.             for (int j = 0; j < stateDimension; ++j) {
  165.                 double sum = 0;
  166.                 int pIndex = j;
  167.                 for (int k = 0; k < stateDimension; ++k) {
  168.                     sum += rowC[k] * p[pIndex];
  169.                     pIndex += stateDimension;
  170.                 }
  171.                 rowD[j] = sum;
  172.             }
  173.         }

  174.     }

  175.     /** Get theJacobian with respect to parameters from a one-dimensional additional state array.
  176.      * <p>
  177.      * This method extract the data from the {@code p} array and put it in the
  178.      * {@code dYdP} array.
  179.      * </p>
  180.      * <p>
  181.      * If no parameters have been set in the constructor, the method returns immediately and
  182.      * does not reference {@code dYdP} which can safely be null in this case.
  183.      * </p>
  184.      * @param state spacecraft state
  185.      * @param dYdP placeholder where to put the Jacobian with respect to parameters
  186.      * @exception OrekitException if state does not contain the Jacobian additional state
  187.      * @see #getStateJacobian(SpacecraftState, double[][])
  188.      */
  189.     public void getParametersJacobian(final SpacecraftState state, final double[][] dYdP)
  190.         throws OrekitException {

  191.         if (parameters > 0) {

  192.             // get the conversion Jacobian between state parameters and cartesian parameters
  193.             final double[][] dYdC = getdYdC(state);

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

  196.             // compute dYdP = dYdC * dCdP, without allocating new arrays
  197.             for (int i = 0; i < stateDimension; i++) {
  198.                 final double[] rowC = dYdC[i];
  199.                 final double[] rowD = dYdP[i];
  200.                 for (int j = 0; j < parameters; ++j) {
  201.                     double sum = 0;
  202.                     int pIndex = j + stateDimension * stateDimension;
  203.                     for (int k = 0; k < stateDimension; ++k) {
  204.                         sum += rowC[k] * p[pIndex];
  205.                         pIndex += parameters;
  206.                     }
  207.                     rowD[j] = sum;
  208.                 }
  209.             }

  210.         }

  211.     }

  212. }