Differentiation.java

  1. /* Copyright 2002-2023 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.PositionAngleType;
  28. import org.orekit.propagation.SpacecraftState;
  29. import org.orekit.propagation.numerical.NumericalPropagator;
  30. import org.orekit.time.AbsoluteDate;

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

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

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

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

  51.         return new ParameterFunction() {

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

  55.             /** {@inheritDoc} */
  56.             @Override
  57.             public double value(final ParameterDriver driver, final AbsoluteDate date) {

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

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

  72.             }
  73.         };

  74.     }

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

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

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

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

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

  109.                 }

  110.                 return jacobian;

  111.             }

  112.         };
  113.     }

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

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

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

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

  123.         /** Tpe of the position angle used for orbit mapping to array. */
  124.         private final PositionAngleType positionAngleType;

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

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

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

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

  165.     }

  166. }