DerivativeStateUtils.java

  1. /* Copyright 2022-2025 Romain Serra
  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.differentiation.Gradient;
  19. import org.hipparchus.analysis.differentiation.GradientField;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.linear.RealMatrix;
  22. import org.orekit.attitudes.Attitude;
  23. import org.orekit.attitudes.AttitudeProvider;
  24. import org.orekit.attitudes.FieldAttitude;
  25. import org.orekit.frames.Frame;
  26. import org.orekit.orbits.FieldOrbit;
  27. import org.orekit.orbits.Orbit;
  28. import org.orekit.orbits.PositionAngleBased;
  29. import org.orekit.orbits.PositionAngleType;
  30. import org.orekit.propagation.FieldSpacecraftState;
  31. import org.orekit.propagation.SpacecraftState;
  32. import org.orekit.time.FieldAbsoluteDate;

  33. /**
  34.  * Utility class used to convert state vectors in Taylor differential algebra.
  35.  *
  36.  * @author Romain Serra
  37.  * @since 13.1
  38.  * @see Gradient
  39.  */
  40. public class DerivativeStateUtils {

  41.     /** Private constructor. */
  42.     private DerivativeStateUtils() {
  43.         // Empty constructor
  44.     }

  45.     /**
  46.      * Method creating a Gradient version of the input state from a given transition matrix.
  47.      * The number of independent variables equals the number of columns.
  48.      * The number of rows tells how many state variables are considered to be the dependent variables in the Taylor differential algebra.
  49.      * If the number of state variables is greater than 6, mass will be considered one.
  50.      * Additional data and derivatives are ignored.
  51.      * @param state full state
  52.      * @param partialDerivatives Jacobian matrix of state variables to consider as dependent ones, w.r.t. unknown parameters
  53.      * @param attitudeProvider provider to recompute attitude, can be null
  54.      * @return fielded state
  55.      * @see FieldSpacecraftState
  56.      * @see SpacecraftState
  57.      */
  58.     public static FieldSpacecraftState<Gradient> buildSpacecraftStateTransitionGradient(final SpacecraftState state,
  59.                                                                                         final RealMatrix partialDerivatives,
  60.                                                                                         final AttitudeProvider attitudeProvider) {
  61.         final int freeParameters = partialDerivatives.getColumnDimension();
  62.         final GradientField field = GradientField.getField(freeParameters);
  63.         final int j = partialDerivatives.getRowDimension();
  64.         final double mass = state.getMass();
  65.         final Gradient fieldMass = (j >= 7) ? new Gradient(mass, partialDerivatives.getRow(6)) : Gradient.constant(freeParameters, mass);
  66.         if (state.isOrbitDefined()) {
  67.             final double[] stateValues = new double[6];
  68.             final double[] stateDerivatives = stateValues.clone();
  69.             final Orbit orbit = state.getOrbit();
  70.             final PositionAngleType positionAngleType = extractPositionAngleType(orbit);
  71.             orbit.getType().mapOrbitToArray(orbit, positionAngleType, stateValues, stateDerivatives);
  72.             final Gradient[] stateVariables = new Gradient[stateValues.length];
  73.             for (int i = 0; i < stateVariables.length; i++) {
  74.                 stateVariables[i] = (i < freeParameters) ? new Gradient(stateValues[i], partialDerivatives.getRow(i)) :
  75.                         Gradient.constant(freeParameters, stateValues[i]);
  76.             }
  77.             final FieldOrbit<Gradient> fieldOrbit = buildFieldOrbit(field, orbit, stateVariables, stateDerivatives);
  78.             return buildFieldStateFromFieldOrbit(fieldOrbit, fieldMass, state.getAttitude(), attitudeProvider);
  79.         } else {
  80.             // state is not orbit defined
  81.             final AbsolutePVCoordinates coordinates = state.getAbsPVA();
  82.             final double[] constants = buildPVArray(coordinates.getPVCoordinates());
  83.             final Gradient[] stateVariables = new Gradient[constants.length];
  84.             for (int i = 0; i < stateVariables.length; i++) {
  85.                 stateVariables[i] = (i < freeParameters) ? new Gradient(constants[i], partialDerivatives.getRow(i)) :
  86.                         Gradient.constant(freeParameters, constants[i]);
  87.             }
  88.             final FieldVector3D<Gradient> position = new FieldVector3D<>(stateVariables[0], stateVariables[1],
  89.                     stateVariables[2]);
  90.             final FieldVector3D<Gradient> velocity = new FieldVector3D<>(stateVariables[3], stateVariables[4],
  91.                     stateVariables[5]);
  92.             final FieldAbsolutePVCoordinates<Gradient> fieldPV = buildFieldAbsolutePV(position, velocity, coordinates);
  93.             return buildFieldStateFromFieldPV(fieldPV, fieldMass, state.getAttitude(), attitudeProvider);
  94.         }
  95.     }

  96.     /**
  97.      * Method creating a Gradient version of the input state, using the state vector as the independent variables of a first-
  98.      * order Taylor algebra. If the number of variables is greater than 6, mass will be considered one.
  99.      * Additional data and derivatives are ignored.
  100.      * @param field gradient field
  101.      * @param state full state
  102.      * @param attitudeProvider provider to recompute attitude, can be null
  103.      * @return fielded state
  104.      * @see FieldSpacecraftState
  105.      * @see SpacecraftState
  106.      */
  107.     public static FieldSpacecraftState<Gradient> buildSpacecraftStateGradient(final GradientField field,
  108.                                                                               final SpacecraftState state,
  109.                                                                               final AttitudeProvider attitudeProvider) {
  110.         final int freeParameters = field.getZero().getFreeParameters();
  111.         final double mass = state.getMass();
  112.         final Gradient fieldMass = (freeParameters >= 7) ? Gradient.variable(freeParameters, 6, mass) :
  113.                 Gradient.constant(freeParameters, mass);
  114.         final Attitude oldAttitude = state.getAttitude();
  115.         if (state.isOrbitDefined()) {
  116.             final FieldOrbit<Gradient> fieldOrbit = buildOrbitGradient(field, state.getOrbit());
  117.             return buildFieldStateFromFieldOrbit(fieldOrbit, fieldMass, oldAttitude, attitudeProvider);
  118.         } else {
  119.             // state is not orbit defined
  120.             final FieldAbsolutePVCoordinates<Gradient> fieldPV = buildAbsolutePVGradient(field, state.getAbsPVA());
  121.             return buildFieldStateFromFieldPV(fieldPV, fieldMass, oldAttitude, attitudeProvider);
  122.         }
  123.     }

  124.     /**
  125.      * Add or recompute attitude to fill in full state from orbit.
  126.      * @param fieldOrbit orbit
  127.      * @param fieldMass mass
  128.      * @param attitude constant attitude
  129.      * @param attitudeProvider provider to recompute attitude, can be null
  130.      * @return state
  131.      */
  132.     private static FieldSpacecraftState<Gradient> buildFieldStateFromFieldOrbit(final FieldOrbit<Gradient> fieldOrbit,
  133.                                                                                 final Gradient fieldMass, final Attitude attitude,
  134.                                                                                 final AttitudeProvider attitudeProvider) {
  135.         final FieldAttitude<Gradient> fieldAttitude = (attitudeProvider == null) ?
  136.                 new FieldAttitude<>(fieldMass.getField(), attitude) :
  137.                 attitudeProvider.getAttitude(fieldOrbit, fieldOrbit.getDate(), fieldOrbit.getFrame());
  138.         return new FieldSpacecraftState<>(fieldOrbit, fieldAttitude).withMass(fieldMass);
  139.     }

  140.     /**
  141.      * Add or recompute attitude to fill in full state.
  142.      * @param fieldPV coordinates
  143.      * @param fieldMass mass
  144.      * @param attitude constant attitude
  145.      * @param attitudeProvider provider to recompute attitude, can be null
  146.      * @return state
  147.      */
  148.     private static FieldSpacecraftState<Gradient> buildFieldStateFromFieldPV(final FieldAbsolutePVCoordinates<Gradient> fieldPV,
  149.                                                                              final Gradient fieldMass, final Attitude attitude,
  150.                                                                              final AttitudeProvider attitudeProvider) {
  151.         final FieldAttitude<Gradient> fieldAttitude = (attitudeProvider == null) ?
  152.                 new FieldAttitude<>(fieldMass.getField(), attitude) :
  153.                 attitudeProvider.getAttitude(fieldPV, fieldPV.getDate(), fieldPV.getFrame());
  154.         return new FieldSpacecraftState<>(fieldPV, fieldAttitude).withMass(fieldMass);
  155.     }

  156.     /**
  157.      * Method creating a Gradient version of the input orbit, using the state vector as the independent variables of a first-
  158.      * order Taylor algebra. If the number of variables is greater than 6, mass will be considered one.
  159.      * @param field gradient field
  160.      * @param orbit orbit
  161.      * @return fielded orbit
  162.      * @see org.orekit.orbits.FieldOrbit
  163.      * @see org.orekit.orbits.Orbit
  164.      */
  165.     public static FieldOrbit<Gradient> buildOrbitGradient(final GradientField field, final Orbit orbit) {
  166.         final int freeParameters = field.getZero().getFreeParameters();
  167.         final double[] stateValues = new double[6];
  168.         final double[] stateDerivatives = stateValues.clone();
  169.         final PositionAngleType positionAngleType = extractPositionAngleType(orbit);
  170.         orbit.getType().mapOrbitToArray(orbit, positionAngleType, stateValues, stateDerivatives);
  171.         final Gradient[] stateVariables = new Gradient[stateValues.length];
  172.         for (int i = 0; i < stateVariables.length; i++) {
  173.             stateVariables[i] = (i < freeParameters) ? Gradient.variable(freeParameters, i, stateValues[i]) :
  174.                     Gradient.constant(freeParameters, stateValues[i]);
  175.         }
  176.         return buildFieldOrbit(field, orbit, stateVariables, stateDerivatives);
  177.     }

  178.     /**
  179.      * Create the field orbit.
  180.      * @param field gradient field
  181.      * @param orbit orbit
  182.      * @param stateVariables state in Taylor differential algebra
  183.      * @param stateDerivatives state derivatives
  184.      * @return orbit in Taylor differential algebra
  185.      */
  186.     private static FieldOrbit<Gradient> buildFieldOrbit(final GradientField field, final Orbit orbit,
  187.                                                         final Gradient[] stateVariables, final double[] stateDerivatives) {
  188.         final FieldAbsoluteDate<Gradient> date = new FieldAbsoluteDate<>(field, orbit.getDate());
  189.         final int freeParameters = field.getZero().getFreeParameters();
  190.         final Gradient mu = Gradient.constant(freeParameters, orbit.getMu());
  191.         final Gradient[] fieldStateDerivatives = new Gradient[stateVariables.length];
  192.         for (int i = 0; i < stateVariables.length; i++) {
  193.             fieldStateDerivatives[i] = Gradient.constant(freeParameters, stateDerivatives[i]);
  194.         }
  195.         final PositionAngleType positionAngleType = extractPositionAngleType(orbit);
  196.         final Frame frame = orbit.getFrame();
  197.         return orbit.getType().mapArrayToOrbit(stateVariables, fieldStateDerivatives, positionAngleType, date, mu, frame);
  198.     }

  199.     /**
  200.      * Extract position angle type.
  201.      * @param orbit orbit
  202.      * @return angle type
  203.      */
  204.     private static PositionAngleType extractPositionAngleType(final Orbit orbit) {
  205.         if (orbit instanceof PositionAngleBased<?>) {
  206.             final PositionAngleBased<?> positionAngleBased = (PositionAngleBased<?>) orbit;
  207.             return positionAngleBased.getCachedPositionAngleType();
  208.         }
  209.         return null;
  210.     }

  211.     /**
  212.      * Method creating a Gradient version of the input coordinates, using the state vector as the independent variables of a first-
  213.      * order Taylor algebra. If the number of variables is greater than 6, mass will be considered one.
  214.      * @param field gradient field
  215.      * @param coordinates absolute coordinates
  216.      * @return fielded coordinates
  217.      * @see AbsolutePVCoordinates
  218.      * @see FieldAbsolutePVCoordinates
  219.      */
  220.     public static FieldAbsolutePVCoordinates<Gradient> buildAbsolutePVGradient(final GradientField field,
  221.                                                                                final AbsolutePVCoordinates coordinates) {
  222.         final int freeParameters = field.getZero().getFreeParameters();
  223.         final double[] constants = buildPVArray(coordinates.getPVCoordinates());
  224.         final Gradient[] stateVariables = new Gradient[constants.length];
  225.         for (int i = 0; i < stateVariables.length; i++) {
  226.             stateVariables[i] = (i < freeParameters) ? Gradient.variable(freeParameters, i, constants[i]) :
  227.                     Gradient.constant(freeParameters, constants[i]);
  228.         }
  229.         final FieldVector3D<Gradient> position = new FieldVector3D<>(stateVariables[0], stateVariables[1],
  230.                 stateVariables[2]);
  231.         final FieldVector3D<Gradient> velocity = new FieldVector3D<>(stateVariables[3], stateVariables[4],
  232.                 stateVariables[5]);
  233.         return buildFieldAbsolutePV(position, velocity, coordinates);
  234.     }

  235.     /**
  236.      * Build array from position-velocity.
  237.      * @param pvCoordinates coordinates
  238.      * @return array
  239.      */
  240.     private static double[] buildPVArray(final PVCoordinates pvCoordinates) {
  241.         final double[] constants = new double[6];
  242.         System.arraycopy(pvCoordinates.getPosition().toArray(), 0, constants, 0, 3);
  243.         System.arraycopy(pvCoordinates.getVelocity().toArray(), 0, constants, 3, 3);
  244.         return constants;
  245.     }

  246.     /**
  247.      * Create field position-velocity.
  248.      * @param fieldPosition position in Taylor differential algebra
  249.      * @param fieldVelocity velocity in Taylor differential algebra
  250.      * @param coordinates coordinates
  251.      * @return fielded position-velocity
  252.      */
  253.     private static FieldAbsolutePVCoordinates<Gradient> buildFieldAbsolutePV(final FieldVector3D<Gradient> fieldPosition,
  254.                                                                              final FieldVector3D<Gradient> fieldVelocity,
  255.                                                                              final AbsolutePVCoordinates coordinates) {
  256.         final GradientField field = fieldPosition.getX().getField();
  257.         final FieldVector3D<Gradient> acceleration = new FieldVector3D<>(field, coordinates.getAcceleration());
  258.         final FieldAbsoluteDate<Gradient> date = new FieldAbsoluteDate<>(field, coordinates.getDate());
  259.         return new FieldAbsolutePVCoordinates<>(coordinates.getFrame(), date, fieldPosition, fieldVelocity, acceleration);
  260.     }
  261. }