Partial derivatives w.r.t Maneuver objects

Hi Orekit community,

I am searching for the best way to compute the differential effect of the thrust parameter on a given propagation.
When it comes to compute the partial derivatives of a fieldSpacecraftState propagated through a fieldPropagator starting from an initial fieldKeplerianOrbit, the DerivativesStructure methodology is just fine.
However, the thrust maneuver case seems more complicated.
First, I thought that using parameterDriver object can be the relevant tool, but I am not sure to understand how such tool permits to compute the partial derivatives of propagated fieldSpacecraftState w.r.t. the parameters of the thrust.
So, my question is how can be computed the partial derivatives of a propagated fieldSpacecraftState w.r.t a Maneuver-like object (for instance a ContantThrustManeuver object).

Christophe

Hi @ChristopheL,

The way the maneuver models are designed right now, it does not seem possible to do what you want easily.

That is if you are really bound to use a FieldPropagator.
In that case I think you will have to design your own “Fielded” maneuver model.
I’m talking about this a bit more below.

If it is ok for you to use a classical numerical propagator, there are two options:

  1. Propagate the state transition matrix and extract the Jacobian of the maneuver’s parameter drivers. For this you can use a method close to the one used in the batch least-square process, see for example the method AbstractBatchLSModel.fetchEvaluatedMeasurement#409 (note that you don’t need the measurement derivatives part)
  2. Use a SmallManeuverAnalyticalModel (if your maneuver is small) and extract the jacobians directly from the model.

Creating a fielded version of a Maneuver object:

This is a bit tricky since a Maneuver object is a force model and that a ForceModel already uses some fielded methods (addContribution and acceleration).
You’ll have to be very careful on how you handle the fields.
And the down side of the new (since 10.2) maneuvers package is that you will need to field several classes (maneuver, propulsion model and maneuver triggers) instead of just the maneuver class.

But maybe in your specific case you could just create a fielded version of a PropulsionModel, for example FieldConstantThrustPropulsionModel.

This model will implements the PropulsionModel and should have as attributes a RealFieldElement thrust, flowRate and isp and a FieldVector3D direction.

The problem with this is that, when you implement for example the fielded method getAcceleration, there is a conflict between the fielded parameters from the method signature and your fielded attributes.
To avoid this problem each of your attributes should be a Map<Field, RealFieldElement> and when you want to get your thrust attribute in the getAcceleration method you will have to do something like:

// Field from the methode signature (s = FieldSpacecraftState in input of the method)
final Field<T> field = s.getDate().getField();

// Thrust attribute, note that the field used in the propagator and in the model must be the same (which is usually the case)
final T fieldThrust = (T) thrust.get(field);

That way you don’t need to define two different type of fields in your class and you just let the propagator handle the different fields you want to propagate.

Example:

  • Define class, thrust attribute and field used
public class FieldConstantThrustPropulsionModel implements PropulsionModel {

    /** Thrust value (N). */
    private final Map<Field<?>, RealFieldElement<?>> thrust;

[...]

  /** Field used to define all the previous attributes.
     *  By construction it is unique.
     */
    private final Field<?> fieldUsed;
  • Constructor
public <T extends RealFieldElement<T>> FieldConstantThrustPropulsionModel(final T thrust,
                                                                              final T isp,
                                                                              final FieldVector3D<T> direction) {

        // Initialize the fields' maps
        this.thrust    = new HashMap<>();
        this.flowRate  = new HashMap<>();
        this.isp       = new HashMap<>();
        this.direction = new HashMap<>();

        // Extract the field
        this.fieldUsed = thrust.getField();

        this.thrust.put(fieldUsed, thrust);
        this.isp.put(fieldUsed, isp);
        this.flowRate.put(fieldUsed, thrust.negate().divide(isp.multiply(Constants.G0_STANDARD_GRAVITY)));
        this.direction.put(fieldUsed, direction.normalize());
    }
  • Fielded method getAcceleration
    @Override
    public <T extends RealFieldElement<T>> FieldVector3D<T>
        getAcceleration(final FieldSpacecraftState<T> s, final FieldAttitude<T> maneuverAttitude, final T[] parameters) {
        // Field from the method, i.e. from the propagator
        final Field<T> field = s.getDate().getField();

        // compute thrust acceleration in inertial frame
        final T fieldThrust = (T) thrust.get(field);
        final FieldVector3D<T> fieldDirection = (FieldVector3D<T>) direction.get(field);
        return new FieldVector3D<>(s.getMass().reciprocal().multiply(fieldThrust),
                                   maneuverAttitude.getRotation().applyInverseTo(fieldDirection));
    }
  • Then, build a Maneuver force model, assuming you have previously defined a DSFactory (see the FieldPropagation tutorial for more):
            // Define thrust derivative structure
            final double thrust = 10.;
            // Index 0 here means the thrust will be your first derivative parameter
            // factory is a DSFactory you would have built earlier
            final DerivativeStructure thrustDs = factory.variable(0, thrust);
           
            [...]

            // Get the field of the factory
            final Field<DerivativeStructure> field = thrustDs.getField();

            // Fielded propulsion model, only the thrust is derivative parameter here
            final double isp = 300.;
            final Vector3D direction = new Vector3D(1., 0., 0.);
            final double duration = 10.;
            final FieldConstantThrustPropulsionModel propModel =
                            new FieldConstantThrustPropulsionModel(thrustDs, field.getZero().add(isp), new FieldVector3D<>(field, direction));

           // Fielded maneuver, manDate is the maneuver date, frame is the propagation frame
           final AbsoluteDate manDate = ...
           final Frame frame = ...
           final Maneuver maneuver = new Maneuver(new LofOffset(frame, LOFType.TNW), new DateBasedManeuverTriggers(manDate, duration), propModel);
            [...]

            // Then, use this maneuver in a FieldNumericalPropagator

I hope this will work and will avoid you “fielding” the whole maneuver package.
Keep me posted on the results, I’m really interested!

Regards,
Maxime

1 Like

Hi Maxime,
Your help has been very precious! I managed to compute a propagated fieldOrbit that depend on the free variables so I can compute partial derivatives.
Thanks a lot!
Christophe

You’re very welcome Christophe !!
I’m glad it worked.
Do you think the FieldConstantThrustPropulsionModel would be worth contributing to Orekit?
If yes, would you like to do it?

It will be a very nice feature indeed. Your proposition is a elegant method to insert fielded options in maneuver objects. For instance, I adapted and used it to “field” AttitudeProvider object.
Anyway, when the time is right, it can be cool to contribute.