DSSTHarvester.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.semianalytical.dsst;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.List;

  21. import org.hipparchus.analysis.differentiation.Gradient;
  22. import org.hipparchus.linear.MatrixUtils;
  23. import org.hipparchus.linear.RealMatrix;
  24. import org.orekit.propagation.AbstractMatricesHarvester;
  25. import org.orekit.propagation.FieldSpacecraftState;
  26. import org.orekit.propagation.PropagationType;
  27. import org.orekit.propagation.SpacecraftState;
  28. import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
  29. import org.orekit.propagation.semianalytical.dsst.forces.FieldShortPeriodTerms;
  30. import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
  31. import org.orekit.utils.DoubleArrayDictionary;
  32. import org.orekit.utils.ParameterDriver;

  33. /** Harvester between two-dimensional Jacobian matrices and one-dimensional {@link
  34.  * SpacecraftState#getAdditionalState(String) additional state arrays}.
  35.  * @author Luc Maisonobe
  36.  * @author Bryan Cazabonne
  37.  * @since 11.1
  38.  */
  39. public class DSSTHarvester extends AbstractMatricesHarvester {

  40.     /** Retrograde factor I.
  41.      *  <p>
  42.      *  DSST model needs equinoctial orbit as internal representation.
  43.      *  Classical equinoctial elements have discontinuities when inclination
  44.      *  is close to zero. In this representation, I = +1. <br>
  45.      *  To avoid this discontinuity, another representation exists and equinoctial
  46.      *  elements can be expressed in a different way, called "retrograde" orbit.
  47.      *  This implies I = -1. <br>
  48.      *  As Orekit doesn't implement the retrograde orbit, I is always set to +1.
  49.      *  But for the sake of consistency with the theory, the retrograde factor
  50.      *  has been kept in the formulas.
  51.      *  </p>
  52.      */
  53.     private static final int I = 1;

  54.     /** Propagator bound to this harvester. */
  55.     private final DSSTPropagator propagator;

  56.     /** Derivatives of the short period terms that apply to State Transition Matrix.*/
  57.     private final double[][] shortPeriodDerivativesStm;

  58.     /** Derivatives of the short period terms that apply to Jacobians columns. */
  59.     private final DoubleArrayDictionary shortPeriodDerivativesJacobianColumns;

  60.     /** Columns names for parameters. */
  61.     private List<String> columnsNames;

  62.     /** Field short periodic terms. */
  63.     private List<FieldShortPeriodTerms<Gradient>> fieldShortPeriodTerms;

  64.     /** Simple constructor.
  65.      * <p>
  66.      * The arguments for initial matrices <em>must</em> be compatible with the
  67.      * {@link org.orekit.orbits.OrbitType#EQUINOCTIAL equinoctial orbit type}
  68.      * and {@link org.orekit.orbits.PositionAngle position angle} that will be used by propagator
  69.      * </p>
  70.      * @param propagator propagator bound to this harvester
  71.      * @param stmName State Transition Matrix state name
  72.      * @param initialStm initial State Transition Matrix ∂Y/∂Y₀,
  73.      * if null (which is the most frequent case), assumed to be 6x6 identity
  74.      * @param initialJacobianColumns initial columns of the Jacobians matrix with respect to parameters,
  75.      * if null or if some selected parameters are missing from the dictionary, the corresponding
  76.      * initial column is assumed to be 0
  77.      */
  78.     DSSTHarvester(final DSSTPropagator propagator, final String stmName,
  79.                   final RealMatrix initialStm, final DoubleArrayDictionary initialJacobianColumns) {
  80.         super(stmName, initialStm, initialJacobianColumns);
  81.         this.propagator                            = propagator;
  82.         this.shortPeriodDerivativesStm             = new double[STATE_DIMENSION][STATE_DIMENSION];
  83.         this.shortPeriodDerivativesJacobianColumns = new DoubleArrayDictionary();
  84.         this.fieldShortPeriodTerms                 = new ArrayList<>();
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public RealMatrix getStateTransitionMatrix(final SpacecraftState state) {

  89.         final RealMatrix stm = super.getStateTransitionMatrix(state);

  90.         if (propagator.getPropagationType() == PropagationType.OSCULATING) {
  91.             // add the short period terms
  92.             for (int i = 0; i < STATE_DIMENSION; i++) {
  93.                 for (int j = 0; j < STATE_DIMENSION; j++) {
  94.                     stm.addToEntry(i, j, shortPeriodDerivativesStm[i][j]);
  95.                 }
  96.             }
  97.         }

  98.         return stm;

  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     public RealMatrix getParametersJacobian(final SpacecraftState state) {

  103.         final RealMatrix jacobian = super.getParametersJacobian(state);
  104.         if (jacobian != null && propagator.getPropagationType() == PropagationType.OSCULATING) {

  105.             // add the short period terms
  106.             final List<String> names = getJacobiansColumnsNames();
  107.             for (int j = 0; j < names.size(); ++j) {
  108.                 final double[] column = shortPeriodDerivativesJacobianColumns.get(names.get(j));
  109.                 for (int i = 0; i < STATE_DIMENSION; i++) {
  110.                     jacobian.addToEntry(i, j, column[i]);
  111.                 }
  112.             }

  113.         }

  114.         return jacobian;

  115.     }

  116.     /** Get the Jacobian matrix B1 (B1 = ∂εη/∂Y).
  117.      * <p>
  118.      * B1 represents the partial derivatives of the short period motion
  119.      * with respect to the mean equinoctial elements.
  120.      * </p>
  121.      * @return the B1 jacobian matrix
  122.      */
  123.     public RealMatrix getB1() {

  124.         // Initialize B1
  125.         final RealMatrix B1 = MatrixUtils.createRealMatrix(STATE_DIMENSION, STATE_DIMENSION);

  126.         // add the short period terms
  127.         for (int i = 0; i < STATE_DIMENSION; i++) {
  128.             for (int j = 0; j < STATE_DIMENSION; j++) {
  129.                 B1.addToEntry(i, j, shortPeriodDerivativesStm[i][j]);
  130.             }
  131.         }

  132.         // Return B1
  133.         return B1;

  134.     }

  135.     /** Get the Jacobian matrix B2 (B2 = ∂Y/∂Y₀).
  136.      * <p>
  137.      * B2 represents the partial derivatives of the mean equinoctial elements
  138.      * with respect to the initial ones.
  139.      * </p>
  140.      * @param state spacecraft state
  141.      * @return the B2 jacobian matrix
  142.      */
  143.     public RealMatrix getB2(final SpacecraftState state) {
  144.         return super.getStateTransitionMatrix(state);
  145.     }

  146.     /** Get the Jacobian matrix B3 (B3 = ∂Y/∂P).
  147.      * <p>
  148.      * B3 represents the partial derivatives of the mean equinoctial elements
  149.      * with respect to the estimated propagation parameters.
  150.      * </p>
  151.      * @param state spacecraft state
  152.      * @return the B3 jacobian matrix
  153.      */
  154.     public RealMatrix getB3(final SpacecraftState state) {
  155.         return super.getParametersJacobian(state);
  156.     }

  157.     /** Get the Jacobian matrix B4 (B4 = ∂εη/∂c).
  158.      * <p>
  159.      * B4 represents the partial derivatives of the short period motion
  160.      * with respect to the estimated propagation parameters.
  161.      * </p>
  162.      * @return the B4 jacobian matrix
  163.      */
  164.     public RealMatrix getB4() {

  165.         // Initialize B4
  166.         final List<String> names = getJacobiansColumnsNames();
  167.         final RealMatrix B4 = MatrixUtils.createRealMatrix(STATE_DIMENSION, names.size());

  168.         // add the short period terms
  169.         for (int j = 0; j < names.size(); ++j) {
  170.             final double[] column = shortPeriodDerivativesJacobianColumns.get(names.get(j));
  171.             for (int i = 0; i < STATE_DIMENSION; i++) {
  172.                 B4.addToEntry(i, j, column[i]);
  173.             }
  174.         }

  175.         // Return B4
  176.         return B4;

  177.     }

  178.     /** Freeze the names of the Jacobian columns.
  179.      * <p>
  180.      * This method is called when proagation starts, i.e. when configuration is completed
  181.      * </p>
  182.      */
  183.     public void freezeColumnsNames() {
  184.         columnsNames = getJacobiansColumnsNames();
  185.     }

  186.     /** {@inheritDoc} */
  187.     @Override
  188.     public List<String> getJacobiansColumnsNames() {
  189.         return columnsNames == null ? propagator.getJacobiansColumnsNames() : columnsNames;
  190.     }

  191.     /** Initialize the short periodic terms for the "field" elements.
  192.      * @param reference current mean spacecraft state
  193.      */
  194.     public void initializeFieldShortPeriodTerms(final SpacecraftState reference) {

  195.         // Converter
  196.         final DSSTGradientConverter converter = new DSSTGradientConverter(reference, propagator.getAttitudeProvider());

  197.         // Loop on force models
  198.         for (final DSSTForceModel forceModel : propagator.getAllForceModels()) {

  199.             // Convert to Gradient
  200.             final FieldSpacecraftState<Gradient> dsState = converter.getState(forceModel);
  201.             final Gradient[] dsParameters = converter.getParameters(dsState, forceModel);
  202.             final FieldAuxiliaryElements<Gradient> auxiliaryElements = new FieldAuxiliaryElements<>(dsState.getOrbit(), I);

  203.             // Initialize the "Field" short periodic terms in OSCULATING mode
  204.             fieldShortPeriodTerms.addAll(forceModel.initializeShortPeriodTerms(auxiliaryElements, PropagationType.OSCULATING, dsParameters));

  205.         }

  206.     }

  207.     /** Update the short periodic terms for the "field" elements.
  208.      * @param reference current mean spacecraft state
  209.      */
  210.     @SuppressWarnings("unchecked")
  211.     public void updateFieldShortPeriodTerms(final SpacecraftState reference) {

  212.         // Converter
  213.         final DSSTGradientConverter converter = new DSSTGradientConverter(reference, propagator.getAttitudeProvider());

  214.         // Loop on force models
  215.         for (final DSSTForceModel forceModel : propagator.getAllForceModels()) {

  216.             // Convert to Gradient
  217.             final FieldSpacecraftState<Gradient> dsState = converter.getState(forceModel);
  218.             final Gradient[] dsParameters = converter.getParameters(dsState, forceModel);

  219.             // Update the short periodic terms for the current force model
  220.             forceModel.updateShortPeriodTerms(dsParameters, dsState);

  221.         }

  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     public void setReferenceState(final SpacecraftState reference) {

  226.         // reset derivatives to zero
  227.         for (final double[] row : shortPeriodDerivativesStm) {
  228.             Arrays.fill(row, 0.0);
  229.         }

  230.         shortPeriodDerivativesJacobianColumns.clear();

  231.         final DSSTGradientConverter converter = new DSSTGradientConverter(reference, propagator.getAttitudeProvider());

  232.         // Compute Jacobian
  233.         for (final DSSTForceModel forceModel : propagator.getAllForceModels()) {

  234.             final FieldSpacecraftState<Gradient> dsState = converter.getState(forceModel);
  235.             final Gradient zero = dsState.getDate().getField().getZero();
  236.             final Gradient[] shortPeriod = new Gradient[6];
  237.             Arrays.fill(shortPeriod, zero);
  238.             for (final FieldShortPeriodTerms<Gradient> spt : fieldShortPeriodTerms) {
  239.                 final Gradient[] spVariation = spt.value(dsState.getOrbit());
  240.                 for (int i = 0; i < spVariation .length; i++) {
  241.                     shortPeriod[i] = shortPeriod[i].add(spVariation[i]);
  242.                 }
  243.             }

  244.             final double[] derivativesASP  = shortPeriod[0].getGradient();
  245.             final double[] derivativesExSP = shortPeriod[1].getGradient();
  246.             final double[] derivativesEySP = shortPeriod[2].getGradient();
  247.             final double[] derivativesHxSP = shortPeriod[3].getGradient();
  248.             final double[] derivativesHySP = shortPeriod[4].getGradient();
  249.             final double[] derivativesLSP  = shortPeriod[5].getGradient();

  250.             // update Jacobian with respect to state
  251.             addToRow(derivativesASP,  0);
  252.             addToRow(derivativesExSP, 1);
  253.             addToRow(derivativesEySP, 2);
  254.             addToRow(derivativesHxSP, 3);
  255.             addToRow(derivativesHySP, 4);
  256.             addToRow(derivativesLSP,  5);

  257.             int paramsIndex = converter.getFreeStateParameters();
  258.             for (ParameterDriver driver : forceModel.getParametersDrivers()) {
  259.                 if (driver.isSelected()) {

  260.                     // get the partials derivatives for this driver
  261.                     DoubleArrayDictionary.Entry entry = shortPeriodDerivativesJacobianColumns.getEntry(driver.getName());
  262.                     if (entry == null) {
  263.                         // create an entry filled with zeroes
  264.                         shortPeriodDerivativesJacobianColumns.put(driver.getName(), new double[STATE_DIMENSION]);
  265.                         entry = shortPeriodDerivativesJacobianColumns.getEntry(driver.getName());
  266.                     }

  267.                     // add the contribution of the current force model
  268.                     entry.increment(new double[] {
  269.                         derivativesASP[paramsIndex], derivativesExSP[paramsIndex], derivativesEySP[paramsIndex],
  270.                         derivativesHxSP[paramsIndex], derivativesHySP[paramsIndex], derivativesLSP[paramsIndex]
  271.                     });
  272.                     ++paramsIndex;

  273.                 }
  274.             }
  275.         }

  276.     }

  277.     /** Fill State Transition Matrix rows.
  278.      * @param derivatives derivatives of a component
  279.      * @param index component index (0 for a, 1 for ex, 2 for ey, 3 for hx, 4 for hy, 5 for l)
  280.      */
  281.     private void addToRow(final double[] derivatives, final int index) {
  282.         for (int i = 0; i < 6; i++) {
  283.             shortPeriodDerivativesStm[index][i] += derivatives[i];
  284.         }
  285.     }

  286. }