AbstractGradientConverter.java

  1. /* Copyright 2002-2024 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.Field;
  21. import org.hipparchus.analysis.differentiation.Gradient;
  22. import org.hipparchus.analysis.differentiation.GradientField;
  23. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  24. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  25. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  26. import org.orekit.attitudes.AttitudeProvider;
  27. import org.orekit.attitudes.FieldAttitude;
  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.FieldAngularCoordinates;
  37. import org.orekit.utils.FieldPVCoordinates;
  38. import org.orekit.utils.FieldAbsolutePVCoordinates;
  39. import org.orekit.utils.ParameterDriver;
  40. import org.orekit.utils.ParameterDriversProvider;
  41. import org.orekit.utils.TimeStampedFieldAngularCoordinates;
  42. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  43. import org.orekit.utils.TimeSpanMap.Span;

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

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

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

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

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

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

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

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

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

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

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

  132.         // Derivative field
  133.         final Field<Gradient> field =  GradientField.getField(freeStateParameters);

  134.         // position always has derivatives
  135.         final Vector3D pos = state.getPosition();
  136.         final FieldVector3D<Gradient> posG = new FieldVector3D<>(
  137.                 Gradient.variable(freeStateParameters, 0, pos.getX()),
  138.                 Gradient.variable(freeStateParameters, 1, pos.getY()),
  139.                 Gradient.variable(freeStateParameters, 2, pos.getZ()));

  140.         // velocity may have derivatives or not
  141.         final Vector3D vel = state.getPVCoordinates().getVelocity();
  142.         final FieldVector3D<Gradient> velG;
  143.         if (freeStateParameters > 3) {
  144.             velG = new FieldVector3D<>(
  145.                     Gradient.variable(freeStateParameters, 3, vel.getX()),
  146.                     Gradient.variable(freeStateParameters, 4, vel.getY()),
  147.                     Gradient.variable(freeStateParameters, 5, vel.getZ()));
  148.         } else {
  149.             velG = new FieldVector3D<>(field, vel);
  150.         }

  151.         // acceleration never has derivatives
  152.         final Vector3D acc = state.getPVCoordinates().getAcceleration();
  153.         final FieldVector3D<Gradient> accG = new FieldVector3D<>(field, acc);

  154.         // mass never has derivatives
  155.         final Gradient gMass = Gradient.constant(freeStateParameters, state.getMass());

  156.         final TimeStampedFieldPVCoordinates<Gradient> timeStampedFieldPVCoordinates = new TimeStampedFieldPVCoordinates<>(
  157.                 state.getDate(), posG, velG, accG);

  158.         final FieldCartesianOrbit<Gradient> gOrbit;
  159.         final FieldAbsolutePVCoordinates<Gradient> gAbsolutePV;
  160.         if (state.isOrbitDefined()) {
  161.             final Gradient gMu = Gradient.constant(freeStateParameters, state.getMu());
  162.             gOrbit = new FieldCartesianOrbit<>(timeStampedFieldPVCoordinates, state.getFrame(), gMu);
  163.             gAbsolutePV = null;
  164.         } else {
  165.             gOrbit = null;
  166.             gAbsolutePV = new FieldAbsolutePVCoordinates<>(state.getFrame(), timeStampedFieldPVCoordinates);
  167.         }

  168.         final FieldAttitude<Gradient> gAttitude;
  169.         if (freeStateParameters > 3) {
  170.             // compute attitude partial derivatives with respect to position/velocity
  171.             gAttitude = provider.getAttitude((state.isOrbitDefined()) ? gOrbit : gAbsolutePV,
  172.                     timeStampedFieldPVCoordinates.getDate(), state.getFrame());
  173.         } else {
  174.             // force model does not depend on attitude, don't bother recomputing it
  175.             gAttitude = new FieldAttitude<>(field, state.getAttitude());
  176.         }

  177.         if (state.isOrbitDefined()) {
  178.             return new FieldSpacecraftState<>(gOrbit, gAttitude, gMass);
  179.         } else {
  180.             return new FieldSpacecraftState<>(gAbsolutePV, gAttitude, gMass);
  181.         }
  182.     }

  183.     /**
  184.      * Get the state with the number of parameters consistent with parametric model.
  185.      * @param parametricModel parametric model
  186.      * @return state with the number of parameters consistent with parametric model
  187.      */
  188.     public FieldSpacecraftState<Gradient> getState(final ParameterDriversProvider parametricModel) {

  189.         // count the required number of parameters
  190.         int nbParams = 0;
  191.         for (final ParameterDriver driver : parametricModel.getParametersDrivers()) {
  192.             if (driver.isSelected()) {
  193.                 nbParams += driver.getNbOfValues();
  194.             }
  195.         }

  196.         // fill in intermediate slots
  197.         while (gStates.size() < nbParams + 1) {
  198.             gStates.add(null);
  199.         }

  200.         if (gStates.get(nbParams) == null) {
  201.             // it is the first time we need this number of parameters
  202.             // we need to create the state
  203.             final int freeParameters = freeStateParameters + nbParams;
  204.             final FieldSpacecraftState<Gradient> s0 = gStates.get(0);
  205.             final AbsoluteDate date = s0.getDate().toAbsoluteDate();

  206.             // attitude
  207.             final FieldAngularCoordinates<Gradient> ac0 = s0.getAttitude().getOrientation();
  208.             final FieldAttitude<Gradient> gAttitude =
  209.                     new FieldAttitude<>(s0.getAttitude().getReferenceFrame(),
  210.                             new TimeStampedFieldAngularCoordinates<>(date,
  211.                                     extend(ac0.getRotation(), freeParameters),
  212.                                     extend(ac0.getRotationRate(), freeParameters),
  213.                                     extend(ac0.getRotationAcceleration(), freeParameters)));

  214.             // mass
  215.             final Gradient gMass = extend(s0.getMass(), freeParameters);

  216.             // orbit or absolute position-velocity coordinates
  217.             final FieldPVCoordinates<Gradient> pv0 = s0.getPVCoordinates();
  218.             final TimeStampedFieldPVCoordinates<Gradient> timeStampedFieldPVCoordinates = new TimeStampedFieldPVCoordinates<>(
  219.                     date,
  220.                     extend(pv0.getPosition(),     freeParameters),
  221.                     extend(pv0.getVelocity(),     freeParameters),
  222.                     extend(pv0.getAcceleration(), freeParameters));
  223.             final FieldSpacecraftState<Gradient> spacecraftState;
  224.             if (s0.isOrbitDefined()) {
  225.                 final FieldOrbit<Gradient> orbit = s0.getOrbit();
  226.                 if (orbit instanceof FieldEquinoctialOrbit) {
  227.                     // for DSST, which always uses EquinoctialOrbit, not CartesianOrbit
  228.                     // wish there was a way to do this without casting...
  229.                     final FieldEquinoctialOrbit<Gradient> equinoctialOrbit =
  230.                             (FieldEquinoctialOrbit<Gradient>) orbit;
  231.                     final PositionAngleType angleType =
  232.                             equinoctialOrbit.getCachedPositionAngleType();
  233.                     spacecraftState = new FieldSpacecraftState<>(
  234.                             new FieldEquinoctialOrbit<>(
  235.                                     extend(equinoctialOrbit.getA(), freeParameters),
  236.                                     extend(equinoctialOrbit.getEquinoctialEx(), freeParameters),
  237.                                     extend(equinoctialOrbit.getEquinoctialEy(), freeParameters),
  238.                                     extend(equinoctialOrbit.getHx(), freeParameters),
  239.                                     extend(equinoctialOrbit.getHy(), freeParameters),
  240.                                     extend(equinoctialOrbit.getL(angleType), freeParameters),
  241.                                     angleType,
  242.                                     s0.getFrame(),
  243.                                     extend(s0.getDate(), freeParameters),
  244.                                     extend(s0.getMu(), freeParameters)
  245.                             ),
  246.                             gAttitude,
  247.                             gMass);
  248.                 } else {
  249.                     spacecraftState = new FieldSpacecraftState<>(new FieldCartesianOrbit<>(timeStampedFieldPVCoordinates,
  250.                             s0.getFrame(), extend(s0.getMu(), freeParameters)), gAttitude, gMass);
  251.                 }
  252.             } else {
  253.                 spacecraftState = new FieldSpacecraftState<>(new FieldAbsolutePVCoordinates<>(s0.getFrame(),
  254.                         timeStampedFieldPVCoordinates), gAttitude, gMass);
  255.             }

  256.             gStates.set(nbParams, spacecraftState);

  257.         }

  258.         return gStates.get(nbParams);

  259.     }

  260.     /** Get the parametric model parameters, return gradient values for each span of each driver (several gradient
  261.      * values for each parameter).
  262.      * Different from {@link #getParametersAtStateDate(FieldSpacecraftState, ParameterDriversProvider)}
  263.      * which return a Gradient list containing for each driver the gradient value at state date (only 1 gradient
  264.      * value for each parameter).
  265.      * @param state state as returned by {@link #getState(ParameterDriversProvider) getState(parametricModel)}
  266.      * @param parametricModel parametric model associated with the parameters
  267.      * @return parametric model parameters (for all span of each driver)
  268.      */
  269.     public Gradient[] getParameters(final FieldSpacecraftState<Gradient> state,
  270.                                     final ParameterDriversProvider parametricModel) {
  271.         final int freeParameters = state.getMass().getFreeParameters();
  272.         final List<ParameterDriver> drivers = parametricModel.getParametersDrivers();
  273.         int sizeDrivers = 0;
  274.         for ( ParameterDriver driver : drivers) {
  275.             sizeDrivers += driver.getNbOfValues();
  276.         }
  277.         final Gradient[] parameters = new Gradient[sizeDrivers];
  278.         int index = freeStateParameters;
  279.         int i = 0;
  280.         for (ParameterDriver driver : drivers) {
  281.             // Loop on the spans
  282.             for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {

  283.                 parameters[i++] = driver.isSelected() ?
  284.                                   Gradient.variable(freeParameters, index++, span.getData()) :
  285.                                   Gradient.constant(freeParameters, span.getData());
  286.             }
  287.         }
  288.         return parameters;
  289.     }

  290.     /** Get the parametric model parameters, return gradient values at state date for each driver (only 1 gradient
  291.      * value for each parameter).
  292.      * Different from {@link #getParameters(FieldSpacecraftState, ParameterDriversProvider)}
  293.      * which return a Gradient list containing for each driver the gradient values for each span value (several gradient
  294.      * values for each parameter).
  295.      * @param state state as returned by {@link #getState(ParameterDriversProvider) getState(parametricModel)}
  296.      * @param parametricModel parametric model associated with the parameters
  297.      * @return parametric model parameters (for all span of each driver)
  298.      */
  299.     public Gradient[] getParametersAtStateDate(final FieldSpacecraftState<Gradient> state,
  300.             final ParameterDriversProvider parametricModel) {
  301.         final int freeParameters = state.getMass().getFreeParameters();
  302.         final List<ParameterDriver> drivers = parametricModel.getParametersDrivers();

  303.         final Gradient[] parameters = new Gradient[drivers.size()];
  304.         int index = freeStateParameters;
  305.         int i = 0;
  306.         for (ParameterDriver driver : drivers) {
  307.             for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
  308.                 if (span.getData().equals(driver.getNameSpan(state.getDate().toAbsoluteDate()))) {
  309.                     parameters[i++] = driver.isSelected() ?
  310.                                           Gradient.variable(freeParameters, index, driver.getValue(state.getDate().toAbsoluteDate())) :
  311.                                           Gradient.constant(freeParameters, driver.getValue(state.getDate().toAbsoluteDate()));
  312.                 }
  313.                 index = driver.isSelected() ? index + 1 : index;
  314.             }
  315.         }
  316.         return parameters;
  317.     }


  318. }