Differentiation.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.utils;

  18. import org.hipparchus.analysis.UnivariateFunction;
  19. import org.hipparchus.analysis.UnivariateVectorFunction;
  20. import org.hipparchus.analysis.differentiation.DSFactory;
  21. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  22. import org.hipparchus.analysis.differentiation.FiniteDifferencesDifferentiator;
  23. import org.hipparchus.analysis.differentiation.UnivariateDifferentiableVectorFunction;
  24. import org.orekit.attitudes.AttitudeProvider;
  25. import org.orekit.orbits.Orbit;
  26. import org.orekit.orbits.OrbitType;
  27. import org.orekit.orbits.PositionAngle;
  28. import org.orekit.propagation.SpacecraftState;
  29. import org.orekit.propagation.numerical.NumericalPropagator;

  30. /** Utility class for differentiating various kinds of functions.
  31.  * @author Luc Maisonobe
  32.  * @since 8.0
  33.  */
  34. public class Differentiation {

  35.     /** Factory for the DerivativeStructure instances. */
  36.     private static final DSFactory FACTORY = new DSFactory(1, 1);

  37.     /** Private constructor for utility class.
  38.      */
  39.     private Differentiation() {
  40.     }

  41.     /** Differentiate a scalar function using finite differences.
  42.      * @param function function to differentiate
  43.      * @param nbPoints number of points used for finite differences
  44.      * @param step step for finite differences, in <em>physical</em> units
  45.      * @return scalar function evaluating to the derivative of the original function
  46.      * @since 9.3
  47.      */
  48.     public static ParameterFunction differentiate(final ParameterFunction function,
  49.                                                   final int nbPoints, final double step) {

  50.         return new ParameterFunction() {

  51.             /** Finite differences differentiator to use. */
  52.             private final FiniteDifferencesDifferentiator differentiator  =
  53.                             new FiniteDifferencesDifferentiator(nbPoints, step);

  54.             /** {@inheritDoc} */
  55.             @Override
  56.             public double value(final ParameterDriver driver) {

  57.                 final UnivariateFunction uf = new UnivariateFunction() {
  58.                     /** {@inheritDoc} */
  59.                     @Override
  60.                     public double value(final double value) {
  61.                         final double saved = driver.getValue();
  62.                         driver.setValue(value);
  63.                         final double functionValue = function.value(driver);
  64.                         driver.setValue(saved);
  65.                         return functionValue;
  66.                     }
  67.                 };

  68.                 final DerivativeStructure dsParam = FACTORY.variable(0, driver.getValue());
  69.                 final DerivativeStructure dsValue = differentiator.differentiate(uf).value(dsParam);
  70.                 return dsValue.getPartialDerivative(1);

  71.             }
  72.         };

  73.     }

  74.     /** Differentiate a vector function using finite differences.
  75.      * @param function function to differentiate
  76.      * @param dimension dimension of the vector value of the function
  77.      * @param provider attitude provider to use for modified states
  78.      * @param orbitType type used to map the orbit to a one dimensional array
  79.      * @param positionAngle type of the position angle used for orbit mapping to array
  80.      * @param dP user specified position error, used for step size computation for finite differences
  81.      * @param nbPoints number of points used for finite differences
  82.      * @return matrix function evaluating to the Jacobian of the original function
  83.      */
  84.     public static StateJacobian differentiate(final StateFunction function, final int dimension,
  85.                                               final AttitudeProvider provider,
  86.                                               final OrbitType orbitType, final PositionAngle positionAngle,
  87.                                               final double dP, final int nbPoints) {
  88.         return new StateJacobian() {

  89.             @Override
  90.             public double[][] value(final SpacecraftState state) {
  91.                 final double[] tolerances =
  92.                         NumericalPropagator.tolerances(dP, state.getOrbit(), orbitType)[0];
  93.                 final double[][] jacobian = new double[dimension][6];
  94.                 for (int j = 0; j < 6; ++j) {

  95.                     // compute partial derivatives with respect to state component j
  96.                     final UnivariateVectorFunction componentJ =
  97.                             new StateComponentFunction(j, function, provider, state,
  98.                                                        orbitType, positionAngle);
  99.                     final FiniteDifferencesDifferentiator differentiator =
  100.                             new FiniteDifferencesDifferentiator(nbPoints, tolerances[j]);
  101.                     final UnivariateDifferentiableVectorFunction differentiatedJ =
  102.                             differentiator.differentiate(componentJ);

  103.                     final DerivativeStructure[] c = differentiatedJ.value(FACTORY.variable(0, 0.0));

  104.                     // populate the j-th column of the Jacobian
  105.                     for (int i = 0; i < dimension; ++i) {
  106.                         jacobian[i][j] = c[i].getPartialDerivative(1);
  107.                     }

  108.                 }

  109.                 return jacobian;

  110.             }

  111.         };
  112.     }

  113.     /** Restriction of a {@link StateFunction} to a function of a single state component.
  114.      */
  115.     private static class StateComponentFunction implements UnivariateVectorFunction {

  116.         /** Component index in the mapped orbit array. */
  117.         private final int             index;

  118.         /** State-dependent function. */
  119.         private final StateFunction   f;

  120.         /** Type used to map the orbit to a one dimensional array. */
  121.         private final OrbitType       orbitType;

  122.         /** Tpe of the position angle used for orbit mapping to array. */
  123.         private final PositionAngle   positionAngle;

  124.         /** Base state, of which only one component will change. */
  125.         private final SpacecraftState baseState;

  126.         /** Attitude provider to use for modified states. */
  127.         private final AttitudeProvider provider;

  128.         /** Simple constructor.
  129.          * @param index component index in the mapped orbit array
  130.          * @param f state-dependent function
  131.          * @param provider attitude provider to use for modified states
  132.          * @param baseState base state, of which only one component will change
  133.          * @param orbitType type used to map the orbit to a one dimensional array
  134.          * @param positionAngle type of the position angle used for orbit mapping to array
  135.          */
  136.         StateComponentFunction(final int index, final StateFunction f,
  137.                                final AttitudeProvider provider, final SpacecraftState baseState,
  138.                                final OrbitType orbitType, final PositionAngle positionAngle) {
  139.             this.index         = index;
  140.             this.f             = f;
  141.             this.provider      = provider;
  142.             this.orbitType     = orbitType;
  143.             this.positionAngle = positionAngle;
  144.             this.baseState     = baseState;
  145.         }

  146.         /** {@inheritDoc} */
  147.         @Override
  148.         public double[] value(final double x) {
  149.             final double[] array = new double[6];
  150.             final double[] arrayDot = new double[6];
  151.             orbitType.mapOrbitToArray(baseState.getOrbit(), positionAngle, array, arrayDot);
  152.             array[index] += x;
  153.             final Orbit orbit = orbitType.mapArrayToOrbit(array, arrayDot,
  154.                                                           positionAngle,
  155.                                                           baseState.getDate(),
  156.                                                           baseState.getMu(),
  157.                                                           baseState.getFrame());
  158.             final SpacecraftState state =
  159.                     new SpacecraftState(orbit,
  160.                                         provider.getAttitude(orbit, orbit.getDate(), orbit.getFrame()),
  161.                                         baseState.getMass());
  162.             return f.value(state);
  163.         }

  164.     }

  165. }