Differentiation.java

  1. /* Copyright 2002-2018 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.UnivariateDifferentiableFunction;
  24. import org.hipparchus.analysis.differentiation.UnivariateDifferentiableVectorFunction;
  25. import org.orekit.attitudes.AttitudeProvider;
  26. import org.orekit.errors.OrekitException;
  27. import org.orekit.errors.OrekitExceptionWrapper;
  28. import org.orekit.errors.OrekitMessages;
  29. import org.orekit.orbits.Orbit;
  30. import org.orekit.orbits.OrbitType;
  31. import org.orekit.orbits.PositionAngle;
  32. import org.orekit.propagation.SpacecraftState;
  33. import org.orekit.propagation.numerical.NumericalPropagator;

  34. /** Utility class for differentiating various kinds of functions.
  35.  * @author Luc Maisonobe
  36.  * @since 8.0
  37.  */
  38. public class Differentiation {

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

  41.     /** Private constructor for utility class.
  42.      */
  43.     private Differentiation() {
  44.     }

  45.     /** Differentiate a scalar function using finite differences.
  46.      * @param function function to differentiate
  47.      * @param driver driver for the parameter
  48.      * @param nbPoints number of points used for finite differences
  49.      * @param step step for finite differences
  50.      * @return scalar function evaluating to the derivative of the original function
  51.      */
  52.     public static ParameterFunction differentiate(final ParameterFunction function,
  53.                                                   final ParameterDriver driver,
  54.                                                   final int nbPoints, final double step) {

  55.         final UnivariateFunction uf = new UnivariateFunction() {
  56.             /** {@inheritDoc} */
  57.             @Override
  58.             public double value(final double normalizedValue)
  59.                 throws OrekitExceptionWrapper {
  60.                 try {
  61.                     final double saved = driver.getNormalizedValue();
  62.                     driver.setNormalizedValue(normalizedValue);
  63.                     final double functionValue = function.value(driver);
  64.                     driver.setNormalizedValue(saved);
  65.                     return functionValue;
  66.                 } catch (OrekitException oe) {
  67.                     throw new OrekitExceptionWrapper(oe);
  68.                 }
  69.             }
  70.         };

  71.         final FiniteDifferencesDifferentiator differentiator  =
  72.                         new FiniteDifferencesDifferentiator(nbPoints, step);
  73.         final UnivariateDifferentiableFunction differentiated =
  74.                         differentiator.differentiate(uf);

  75.         return new ParameterFunction() {
  76.             /** {@inheritDoc} */
  77.             @Override
  78.             public double value(final ParameterDriver parameterDriver)
  79.                 throws OrekitException {
  80.                 if (!parameterDriver.getName().equals(driver.getName())) {
  81.                     throw new OrekitException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME,
  82.                                               parameterDriver.getName(), driver.getName());
  83.                 }
  84.                 try {
  85.                     final DerivativeStructure dsParam = FACTORY.variable(0, parameterDriver.getNormalizedValue());
  86.                     final DerivativeStructure dsValue = differentiated.value(dsParam);
  87.                     return dsValue.getPartialDerivative(1);
  88.                 } catch (OrekitExceptionWrapper oew) {
  89.                     throw oew.getException();
  90.                 }
  91.             }
  92.         };

  93.     }

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

  109.             @Override
  110.             public double[][] value(final SpacecraftState state) throws OrekitException {
  111.                 try {
  112.                     final double[] tolerances =
  113.                             NumericalPropagator.tolerances(dP, state.getOrbit(), orbitType)[0];
  114.                     final double[][] jacobian = new double[dimension][6];
  115.                     for (int j = 0; j < 6; ++j) {

  116.                         // compute partial derivatives with respect to state component j
  117.                         final UnivariateVectorFunction componentJ =
  118.                                 new StateComponentFunction(j, function, provider, state,
  119.                                                            orbitType, positionAngle);
  120.                         final FiniteDifferencesDifferentiator differentiator =
  121.                                 new FiniteDifferencesDifferentiator(nbPoints, tolerances[j]);
  122.                         final UnivariateDifferentiableVectorFunction differentiatedJ =
  123.                                 differentiator.differentiate(componentJ);

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

  125.                         // populate the j-th column of the Jacobian
  126.                         for (int i = 0; i < dimension; ++i) {
  127.                             jacobian[i][j] = c[i].getPartialDerivative(1);
  128.                         }

  129.                     }

  130.                     return jacobian;

  131.                 } catch (OrekitExceptionWrapper oew) {
  132.                     throw oew.getException();
  133.                 }
  134.             }

  135.         };
  136.     }

  137.     /** Restriction of a {@link StateFunction} to a function of a single state component.
  138.      */
  139.     private static class StateComponentFunction implements UnivariateVectorFunction {

  140.         /** Component index in the mapped orbit array. */
  141.         private final int             index;

  142.         /** State-dependent function. */
  143.         private final StateFunction   f;

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

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

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

  150.         /** Attitude provider to use for modified states. */
  151.         private final AttitudeProvider provider;

  152.         /** Simple constructor.
  153.          * @param index component index in the mapped orbit array
  154.          * @param f state-dependent function
  155.          * @param provider attitude provider to use for modified states
  156.          * @param baseState base state, of which only one component will change
  157.          * @param orbitType type used to map the orbit to a one dimensional array
  158.          * @param positionAngle type of the position angle used for orbit mapping to array
  159.          */
  160.         StateComponentFunction(final int index, final StateFunction f,
  161.                                final AttitudeProvider provider, final SpacecraftState baseState,
  162.                                final OrbitType orbitType, final PositionAngle positionAngle) {
  163.             this.index         = index;
  164.             this.f             = f;
  165.             this.provider      = provider;
  166.             this.orbitType     = orbitType;
  167.             this.positionAngle = positionAngle;
  168.             this.baseState     = baseState;
  169.         }

  170.         /** {@inheritDoc} */
  171.         @Override
  172.         public double[] value(final double x) throws OrekitExceptionWrapper {
  173.             try {
  174.                 final double[] array = new double[6];
  175.                 final double[] arrayDot = new double[6];
  176.                 orbitType.mapOrbitToArray(baseState.getOrbit(), positionAngle, array, arrayDot);
  177.                 array[index] += x;
  178.                 final Orbit orbit = orbitType.mapArrayToOrbit(array, arrayDot,
  179.                                                               positionAngle,
  180.                                                               baseState.getDate(),
  181.                                                               baseState.getMu(),
  182.                                                               baseState.getFrame());
  183.                 final SpacecraftState state =
  184.                         new SpacecraftState(orbit,
  185.                                             provider.getAttitude(orbit, orbit.getDate(), orbit.getFrame()),
  186.                                             baseState.getMass());
  187.                 return f.value(state);
  188.             } catch (OrekitException oe) {
  189.                 throw new OrekitExceptionWrapper(oe);
  190.             }
  191.         }

  192.     }

  193. }