Differentiation.java

  1. /* Copyright 2002-2025 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.ToleranceProvider;
  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 state -> {
  90.             final double[] tolerances =
  91.                     ToleranceProvider.getDefaultToleranceProvider(dP).getTolerances(state.getOrbit(), orbitType)[0];
  92.             final double[][] jacobian = new double[dimension][6];
  93.             for (int j = 0; j < 6; ++j) {

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

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

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

  107.             }

  108.             return jacobian;

  109.         };
  110.     }

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

  114.         /** Component index in the mapped orbit array. */
  115.         private final int             index;

  116.         /** State-dependent function. */
  117.         private final StateFunction   f;

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

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

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

  124.         /** Attitude provider to use for modified states. */
  125.         private final AttitudeProvider provider;

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

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

  161.     }

  162. }