Differentiation.java

  1. /* Copyright 2002-2019 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.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 driver driver for the parameter
  44.      * @param nbPoints number of points used for finite differences
  45.      * @param normalizedStep step for finite differences, in <em>normalized</em> units
  46.      * @return scalar function evaluating to the derivative of the original function
  47.      * @deprecated as of 9.3, replaced by {@link #differentiate(ParameterFunction, int, double)}
  48.      */
  49.     @Deprecated
  50.     public static ParameterFunction differentiate(final ParameterFunction function, final ParameterDriver driver,
  51.                                                   final int nbPoints, final double normalizedStep) {
  52.         return differentiate(function, nbPoints, normalizedStep * driver.getScale());
  53.     }

  54.     /** Differentiate a scalar function using finite differences.
  55.      * @param function function to differentiate
  56.      * @param nbPoints number of points used for finite differences
  57.      * @param step step for finite differences, in <em>physical</em> units
  58.      * @return scalar function evaluating to the derivative of the original function
  59.      * @since 9.3
  60.      */
  61.     public static ParameterFunction differentiate(final ParameterFunction function,
  62.                                                   final int nbPoints, final double step) {

  63.         return new ParameterFunction() {

  64.             /** Finite differences differentiator to use. */
  65.             private final FiniteDifferencesDifferentiator differentiator  =
  66.                             new FiniteDifferencesDifferentiator(nbPoints, step);

  67.             /** {@inheritDoc} */
  68.             @Override
  69.             public double value(final ParameterDriver driver) {

  70.                 final UnivariateFunction uf = new UnivariateFunction() {
  71.                     /** {@inheritDoc} */
  72.                     @Override
  73.                     public double value(final double value) {
  74.                         final double saved = driver.getValue();
  75.                         driver.setValue(value);
  76.                         final double functionValue = function.value(driver);
  77.                         driver.setValue(saved);
  78.                         return functionValue;
  79.                     }
  80.                 };

  81.                 final DerivativeStructure dsParam = FACTORY.variable(0, driver.getValue());
  82.                 final DerivativeStructure dsValue = differentiator.differentiate(uf).value(dsParam);
  83.                 return dsValue.getPartialDerivative(1);

  84.             }
  85.         };

  86.     }

  87.     /** Differentiate a vector function using finite differences.
  88.      * @param function function to differentiate
  89.      * @param provider attitude provider to use for modified states
  90.      * @param dimension dimension of the vector value of the function
  91.      * @param orbitType type used to map the orbit to a one dimensional array
  92.      * @param positionAngle type of the position angle used for orbit mapping to array
  93.      * @param dP user specified position error, used for step size computation for finite differences
  94.      * @param nbPoints number of points used for finite differences
  95.      * @return matrix function evaluating to the Jacobian of the original function
  96.      */
  97.     public static StateJacobian differentiate(final StateFunction function, final int dimension,
  98.                                               final AttitudeProvider provider,
  99.                                               final OrbitType orbitType, final PositionAngle positionAngle,
  100.                                               final double dP, final int nbPoints) {
  101.         return new StateJacobian() {

  102.             @Override
  103.             public double[][] value(final SpacecraftState state) {
  104.                 final double[] tolerances =
  105.                         NumericalPropagator.tolerances(dP, state.getOrbit(), orbitType)[0];
  106.                 final double[][] jacobian = new double[dimension][6];
  107.                 for (int j = 0; j < 6; ++j) {

  108.                     // compute partial derivatives with respect to state component j
  109.                     final UnivariateVectorFunction componentJ =
  110.                             new StateComponentFunction(j, function, provider, state,
  111.                                                        orbitType, positionAngle);
  112.                     final FiniteDifferencesDifferentiator differentiator =
  113.                             new FiniteDifferencesDifferentiator(nbPoints, tolerances[j]);
  114.                     final UnivariateDifferentiableVectorFunction differentiatedJ =
  115.                             differentiator.differentiate(componentJ);

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

  117.                     // populate the j-th column of the Jacobian
  118.                     for (int i = 0; i < dimension; ++i) {
  119.                         jacobian[i][j] = c[i].getPartialDerivative(1);
  120.                     }

  121.                 }

  122.                 return jacobian;

  123.             }

  124.         };
  125.     }

  126.     /** Restriction of a {@link StateFunction} to a function of a single state component.
  127.      */
  128.     private static class StateComponentFunction implements UnivariateVectorFunction {

  129.         /** Component index in the mapped orbit array. */
  130.         private final int             index;

  131.         /** State-dependent function. */
  132.         private final StateFunction   f;

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

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

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

  139.         /** Attitude provider to use for modified states. */
  140.         private final AttitudeProvider provider;

  141.         /** Simple constructor.
  142.          * @param index component index in the mapped orbit array
  143.          * @param f state-dependent function
  144.          * @param provider attitude provider to use for modified states
  145.          * @param baseState base state, of which only one component will change
  146.          * @param orbitType type used to map the orbit to a one dimensional array
  147.          * @param positionAngle type of the position angle used for orbit mapping to array
  148.          */
  149.         StateComponentFunction(final int index, final StateFunction f,
  150.                                final AttitudeProvider provider, final SpacecraftState baseState,
  151.                                final OrbitType orbitType, final PositionAngle positionAngle) {
  152.             this.index         = index;
  153.             this.f             = f;
  154.             this.provider      = provider;
  155.             this.orbitType     = orbitType;
  156.             this.positionAngle = positionAngle;
  157.             this.baseState     = baseState;
  158.         }

  159.         /** {@inheritDoc} */
  160.         @Override
  161.         public double[] value(final double x) {
  162.             final double[] array = new double[6];
  163.             final double[] arrayDot = new double[6];
  164.             orbitType.mapOrbitToArray(baseState.getOrbit(), positionAngle, array, arrayDot);
  165.             array[index] += x;
  166.             final Orbit orbit = orbitType.mapArrayToOrbit(array, arrayDot,
  167.                                                           positionAngle,
  168.                                                           baseState.getDate(),
  169.                                                           baseState.getMu(),
  170.                                                           baseState.getFrame());
  171.             final SpacecraftState state =
  172.                     new SpacecraftState(orbit,
  173.                                         provider.getAttitude(orbit, orbit.getDate(), orbit.getFrame()),
  174.                                         baseState.getMass());
  175.             return f.value(state);
  176.         }

  177.     }

  178. }