AbstractGradientConverter.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.propagation.integration;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.analysis.differentiation.Gradient;
  21. import org.hipparchus.analysis.differentiation.GradientField;
  22. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  23. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  24. import org.orekit.attitudes.AttitudeProvider;
  25. import org.orekit.attitudes.FieldAttitude;
  26. import org.orekit.orbits.CartesianOrbit;
  27. import org.orekit.orbits.OrbitType;
  28. import org.orekit.orbits.FieldCartesianOrbit;
  29. import org.orekit.orbits.FieldEquinoctialOrbit;
  30. import org.orekit.orbits.FieldOrbit;
  31. import org.orekit.orbits.PositionAngleType;
  32. import org.orekit.propagation.FieldSpacecraftState;
  33. import org.orekit.propagation.SpacecraftState;
  34. import org.orekit.time.AbsoluteDate;
  35. import org.orekit.time.FieldAbsoluteDate;
  36. import org.orekit.utils.DerivativeStateUtils;
  37. import org.orekit.utils.FieldAngularCoordinates;
  38. import org.orekit.utils.FieldPVCoordinates;
  39. import org.orekit.utils.FieldAbsolutePVCoordinates;
  40. import org.orekit.utils.ParameterDriver;
  41. import org.orekit.utils.ParameterDriversProvider;
  42. import org.orekit.utils.TimeStampedFieldAngularCoordinates;
  43. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  44. import org.orekit.utils.TimeSpanMap.Span;

  45. /** Converter for states and parameters arrays.
  46.  *  @author Luc Maisonobe
  47.  *  @author Bryan Cazabonne
  48.  *  @since 10.2
  49.  */
  50. public abstract class AbstractGradientConverter {

  51.     /** Dimension of the state. */
  52.     private final int freeStateParameters;

  53.     /** States with various number of additional parameters. */
  54.     private final List<FieldSpacecraftState<Gradient>> gStates;

  55.     /** Simple constructor.
  56.      * @param freeStateParameters number of free parameters
  57.      */
  58.     protected AbstractGradientConverter(final int freeStateParameters) {
  59.         this.freeStateParameters = freeStateParameters;
  60.         this.gStates             = new ArrayList<>();
  61.     }

  62.     /** Get the number of free state parameters.
  63.      * @return number of free state parameters
  64.      */
  65.     public int getFreeStateParameters() {
  66.         return freeStateParameters;
  67.     }

  68.     /** Initialize first state with 0 parameters.
  69.      * @param zeroParametersState state with zero parameters
  70.      * @since 11.2
  71.      */
  72.     protected void initStates(final FieldSpacecraftState<Gradient> zeroParametersState) {
  73.         gStates.clear();
  74.         gStates.add(zeroParametersState);
  75.     }

  76.     /** Add zero derivatives.
  77.      * @param original original scalar
  78.      * @param freeParameters total number of free parameters in the gradient
  79.      * @return extended scalar
  80.      */
  81.     protected Gradient extend(final Gradient original, final int freeParameters) {
  82.         final double[] originalDerivatives = original.getGradient();
  83.         final double[] extendedDerivatives = new double[freeParameters];
  84.         System.arraycopy(originalDerivatives, 0, extendedDerivatives, 0, originalDerivatives.length);
  85.         return new Gradient(original.getValue(), extendedDerivatives);
  86.     }

  87.     /**
  88.      * Add zero derivatives.
  89.      *
  90.      * @param original       original date
  91.      * @param freeParameters total number of free parameters in the gradient
  92.      * @return extended date
  93.      */
  94.     protected FieldAbsoluteDate<Gradient> extend(final FieldAbsoluteDate<Gradient> original, final int freeParameters) {
  95.         final AbsoluteDate date = original.toAbsoluteDate();
  96.         final Gradient gradient = original.durationFrom(date);
  97.         return new FieldAbsoluteDate<>(date, extend(gradient, freeParameters));
  98.     }

  99.     /** Add zero derivatives.
  100.      * @param original original vector
  101.      * @param freeParameters total number of free parameters in the gradient
  102.      * @return extended vector
  103.      */
  104.     protected FieldVector3D<Gradient> extend(final FieldVector3D<Gradient> original, final int freeParameters) {
  105.         return new FieldVector3D<>(extend(original.getX(), freeParameters),
  106.                                    extend(original.getY(), freeParameters),
  107.                                    extend(original.getZ(), freeParameters));
  108.     }

  109.     /** Add zero derivatives.
  110.      * @param original original rotation
  111.      * @param freeParameters total number of free parameters in the gradient
  112.      * @return extended rotation
  113.      */
  114.     protected FieldRotation<Gradient> extend(final FieldRotation<Gradient> original, final int freeParameters) {
  115.         return new FieldRotation<>(extend(original.getQ0(), freeParameters),
  116.                                    extend(original.getQ1(), freeParameters),
  117.                                    extend(original.getQ2(), freeParameters),
  118.                                    extend(original.getQ3(), freeParameters),
  119.                                    false);
  120.     }

  121.     /** Process a state into a Gradient version without force model parameter.
  122.      * @param state state
  123.      * @param freeStateParameters number of free parameters
  124.      * @param provider attitude provider
  125.      * @return Gradient version of the state
  126.      * @since 12.0
  127.      */
  128.     protected static FieldSpacecraftState<Gradient> buildBasicGradientSpacecraftState(final SpacecraftState state,
  129.                                                                                       final int freeStateParameters,
  130.                                                                                       final AttitudeProvider provider) {

  131.         // Derivative field
  132.         final GradientField field =  GradientField.getField(freeStateParameters);

  133.         if (state.isOrbitDefined()) {
  134.             final CartesianOrbit cartesianOrbit = (CartesianOrbit) OrbitType.CARTESIAN.convertType(state.getOrbit());
  135.             final SpacecraftState cartesianState = new SpacecraftState(cartesianOrbit, state.getAttitude()).withMass(state.getMass());
  136.             return DerivativeStateUtils.buildSpacecraftStateGradient(field, cartesianState, provider);
  137.         } else {
  138.             return DerivativeStateUtils.buildSpacecraftStateGradient(field, state, provider);
  139.         }

  140.     }

  141.     /**
  142.      * Get the state with the number of parameters consistent with parametric model.
  143.      * @param parametricModel parametric model
  144.      * @return state with the number of parameters consistent with parametric model
  145.      */
  146.     public FieldSpacecraftState<Gradient> getState(final ParameterDriversProvider parametricModel) {

  147.         // count the required number of parameters
  148.         int nbParams = 0;
  149.         for (final ParameterDriver driver : parametricModel.getParametersDrivers()) {
  150.             if (driver.isSelected()) {
  151.                 nbParams += driver.getNbOfValues();
  152.             }
  153.         }

  154.         // fill in intermediate slots
  155.         while (gStates.size() < nbParams + 1) {
  156.             gStates.add(null);
  157.         }

  158.         if (gStates.get(nbParams) == null) {
  159.             // it is the first time we need this number of parameters
  160.             // we need to create the state
  161.             final int freeParameters = freeStateParameters + nbParams;
  162.             final FieldSpacecraftState<Gradient> s0 = gStates.get(0);
  163.             final AbsoluteDate date = s0.getDate().toAbsoluteDate();

  164.             // attitude
  165.             final FieldAngularCoordinates<Gradient> ac0 = s0.getAttitude().getOrientation();
  166.             final FieldAttitude<Gradient> gAttitude =
  167.                     new FieldAttitude<>(s0.getAttitude().getReferenceFrame(),
  168.                             new TimeStampedFieldAngularCoordinates<>(date,
  169.                                     extend(ac0.getRotation(), freeParameters),
  170.                                     extend(ac0.getRotationRate(), freeParameters),
  171.                                     extend(ac0.getRotationAcceleration(), freeParameters)));

  172.             // mass
  173.             final Gradient gMass = extend(s0.getMass(), freeParameters);

  174.             // orbit or absolute position-velocity coordinates
  175.             final FieldPVCoordinates<Gradient> pv0 = s0.getPVCoordinates();
  176.             final TimeStampedFieldPVCoordinates<Gradient> timeStampedFieldPVCoordinates = new TimeStampedFieldPVCoordinates<>(
  177.                     date,
  178.                     extend(pv0.getPosition(),     freeParameters),
  179.                     extend(pv0.getVelocity(),     freeParameters),
  180.                     extend(pv0.getAcceleration(), freeParameters));
  181.             final FieldSpacecraftState<Gradient> spacecraftState;
  182.             if (s0.isOrbitDefined()) {
  183.                 final FieldOrbit<Gradient> orbit = s0.getOrbit();
  184.                 if (orbit.getType().equals(OrbitType.EQUINOCTIAL)) {
  185.                     // for DSST, which always uses EquinoctialOrbit, not CartesianOrbit
  186.                     spacecraftState =
  187.                         new FieldSpacecraftState<>(new FieldEquinoctialOrbit<>(extend(orbit.getA(), freeParameters),
  188.                                                                                extend(orbit.getEquinoctialEx(), freeParameters),
  189.                                                                                extend(orbit.getEquinoctialEy(), freeParameters),
  190.                                                                                extend(orbit.getHx(), freeParameters),
  191.                                                                                extend(orbit.getHy(), freeParameters),
  192.                                                                                extend(orbit.getLM(), freeParameters),
  193.                                                                                PositionAngleType.MEAN,
  194.                                                                                s0.getFrame(),
  195.                                                                                extend(s0.getDate(), freeParameters),
  196.                                                                                extend(orbit.getMu(), freeParameters)),
  197.                             gAttitude).withMass(gMass);
  198.                 } else {
  199.                     spacecraftState =
  200.                         new FieldSpacecraftState<>(new FieldCartesianOrbit<>(timeStampedFieldPVCoordinates,
  201.                                                                              s0.getFrame(),
  202.                                                                              extend(orbit.getMu(), freeParameters)),
  203.                                                    gAttitude).withMass(gMass);
  204.                 }
  205.             } else {
  206.                 spacecraftState =
  207.                     new FieldSpacecraftState<>(new FieldAbsolutePVCoordinates<>(s0.getFrame(),
  208.                                                                                 timeStampedFieldPVCoordinates),
  209.                                                gAttitude).withMass(gMass);
  210.             }

  211.             gStates.set(nbParams, spacecraftState);

  212.         }

  213.         return gStates.get(nbParams);

  214.     }

  215.     /** Get the parametric model parameters, return gradient values for each span of each driver (several gradient
  216.      * values for each parameter).
  217.      * Different from {@link #getParametersAtStateDate(FieldSpacecraftState, ParameterDriversProvider)}
  218.      * which return a Gradient list containing for each driver the gradient value at state date (only 1 gradient
  219.      * value for each parameter).
  220.      * @param state state as returned by {@link #getState(ParameterDriversProvider) getState(parametricModel)}
  221.      * @param parametricModel parametric model associated with the parameters
  222.      * @return parametric model parameters (for all span of each driver)
  223.      */
  224.     public Gradient[] getParameters(final FieldSpacecraftState<Gradient> state,
  225.                                     final ParameterDriversProvider parametricModel) {
  226.         final int freeParameters = state.getMass().getFreeParameters();
  227.         final List<ParameterDriver> drivers = parametricModel.getParametersDrivers();
  228.         int sizeDrivers = 0;
  229.         for ( ParameterDriver driver : drivers) {
  230.             sizeDrivers += driver.getNbOfValues();
  231.         }
  232.         final Gradient[] parameters = new Gradient[sizeDrivers];
  233.         int index = freeStateParameters;
  234.         int i = 0;
  235.         for (ParameterDriver driver : drivers) {
  236.             // Loop on the spans
  237.             for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
  238.                 parameters[i++] = driver.isSelected() ?
  239.                                   Gradient.variable(freeParameters, index++, span.getData()) :
  240.                                   Gradient.constant(freeParameters, span.getData());
  241.             }
  242.         }
  243.         return parameters;
  244.     }

  245.     /** Get the parametric model parameters, return gradient values at state date for each driver (only 1 gradient
  246.      * value for each parameter).
  247.      * Different from {@link #getParameters(FieldSpacecraftState, ParameterDriversProvider)}
  248.      * which return a Gradient list containing for each driver the gradient values for each span value (several gradient
  249.      * values for each parameter).
  250.      * @param state state as returned by {@link #getState(ParameterDriversProvider) getState(parametricModel)}
  251.      * @param parametricModel parametric model associated with the parameters
  252.      * @return parametric model parameters (for all span of each driver)
  253.      */
  254.     public Gradient[] getParametersAtStateDate(final FieldSpacecraftState<Gradient> state,
  255.             final ParameterDriversProvider parametricModel) {
  256.         final int freeParameters = state.getMass().getFreeParameters();
  257.         final List<ParameterDriver> drivers = parametricModel.getParametersDrivers();

  258.         final Gradient[] parameters = new Gradient[drivers.size()];
  259.         int index = freeStateParameters;
  260.         int i = 0;
  261.         for (ParameterDriver driver : drivers) {
  262.             for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
  263.                 if (span.getData().equals(driver.getNameSpan(state.getDate().toAbsoluteDate()))) {
  264.                     parameters[i++] = driver.isSelected() ?
  265.                                           Gradient.variable(freeParameters, index, driver.getValue(state.getDate().toAbsoluteDate())) :
  266.                                           Gradient.constant(freeParameters, driver.getValue(state.getDate().toAbsoluteDate()));
  267.                 }
  268.                 index = driver.isSelected() ? index + 1 : index;
  269.             }
  270.         }
  271.         return parameters;
  272.     }


  273. }