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:
- 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)
- 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;
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