Strange behaviour of propagation with maneuver force models

Good evening, I am having some trouble to understand the behaviour of the propagator when using finite maneuvers. I am sharing part of the code to show the problems.

final FactoryManagedFrame eme2000 = FramesFactory.getEME2000();
final AbsoluteDate date = new AbsoluteDate(new DateComponents(2022, 01, 01),
        new TimeComponents(12, 00, 00.000),
        TimeScalesFactory.getUTC());
KeplerianOrbit orbit = new  KeplerianOrbit(6871000, 0.00101606133264409, 
        FastMath.toRadians(50),
        FastMath.toRadians(0), FastMath.toRadians(45),
        FastMath.toRadians(0), PositionAngle.TRUE,
        FramesFactory.getEME2000(), date, Constants.IERS2010_EARTH_MU);
final SpacecraftState initialState = new SpacecraftState(orbit, 250.0);
final OrbitType orbitType = OrbitType.EQUINOCTIAL;
final double[][] tol = NumericalPropagator.tolerances(1.0, orbit, orbitType);
final AdaptiveStepsizeIntegrator integrator =
new DormandPrince853Integrator(0.1,2.0,tol[0],tol[1]);
final NumericalPropagator propagator = new NumericalPropagator(integrator);
propagator.setOrbitType(orbitType);
propagator.setInitialState(initialState);
Vector3D thrustVector = new Vector3D(0,0,10);
AttitudeProvider attitudeOverride = new LofOffset(FramesFactory.getEME2000(), LOFType.VNC);
final AbsoluteDate firingDate = new AbsoluteDate(new DateComponents(2022, 01,
        02),
        new TimeComponents(12, 05, 00.000),
        TimeScalesFactory.getUTC());

final DateDetector start_fire = new DateDetector(firingDate);
final DateDetector end_fire = new DateDetector(firingDate.shiftedBy(15));
final EventBasedManeuverTriggers triggers = new 
        EventBasedManeuverTriggers(start_fire,
        end_fire, false);
final PropulsionModel propulsionModel =
        new BasicConstantThrustPropulsionModel(thrustVector.getNorm(), 150,
        Vector3D.PLUS_I,
        "apogee-engine");
propagator.addForceModel(new Maneuver(attitudeOverride, triggers,
        propulsionModel));

To propagate I am using the ephemeris generator and the bounded propagator as described in the folowing code:

EphemerisGenerator ephemerisGenerator = propagator.getEphemerisGenerator();
propagator.propagate(firingDate.shiftedBy(300),firingDate.shiftedBy(-300));
BoundedPropagator boundedPropagator = ephemerisGenerator.getGeneratedEphemeris();
List<AbsoluteDate> orekitPropagationPointsList = new ArrayList<AbsoluteDate>();
orekitPropagationPointsList.add(firingDate.shiftedBy(0));
orekitPropagationPointsList.add(firingDate.shiftedBy(10));
orekitPropagationPointsList.add(firingDate.shiftedBy(60));       
orekitPropagationPointsList.add(firingDate.shiftedBy(300));
for (int i = 0; i < orekitPropagationPointsList.size(); i++) {
            SpacecraftState orekitCurrentSpacecraftState = 
            boundedPropagator.propagate(orekitPropagationPointsList.get(i));
            System.out.print(orekitCurrentSpacecraftState.getDate() + "    ");
            System.out.print(orekitCurrentSpacecraftState.getA() + "    ");
            System.out.print(orekitCurrentSpacecraftState.getE() + "    ");    
            System.out.print(Math.toDegrees(orekitCurrentSpacecraftState.getI()) + "\n"); 
}

My questions are two:

  1. Even if the flag “allowBackwardPropagation” is set to false, why is it working with the current propagation times? I am propagating backward and it works perfectly.

  2. Even if the “firingDate” is outside the propagation interval, the code computes the maneuver and the propagation does not stop at “firingDate.shiftedBy(300)” but consider also the maneuver. Is this behaviour due to the default set of the date detector to stop the propagation at the first event date occurrence?

I hope this is clear, thank everyone for your support.

Hi Gabri,

I don’t know if this is related to your issue, but you need to be aware that the default behaviour of a numerical propagator in Orekit is to reset its initial state to the last propagation date used. Use resetAtEnd to change that.

Best,
Romain.

Hi again Gabri,

Here is (part of) the code inside EventBasedManeuverTriggers.init method:

forward  = target.isAfterOrEqualTo(initialState);
if (!forward && !allowBackwardPropagation) {
    // backward propagation was forbidden
    throw new OrekitException(OrekitMessages.BACKWARD_PROPAGATION_NOT_ALLOWED);
}

Your re expecting an exception but:

  • initial state date is 2022-01-01T12:00:00
  • target is the final date in propagate, so firingDate.shiftedBy(-300), which is 2022-01-02T12:00:00

So forward is true and the exception is not triggered.

What’s happening here is that:

  • first the state is propagated forward from initialState.getDate() (2022-01-01T12:00:00) to the starting date of your propagation firingDate.shiftedBy(300) (2022-01-02T12:10:00)
  • then the state is propagated backward from starting date to end date of the propagation, the latter being firingDate.shiftedBy(-300) (2022-01-02T12:00:00).
    And the ephemeris is generated only during this second part of propagation.

I’m not sure I understand this one, here your propagation interval for the ephemeris is [firing_date+300s, firing_date-300s] so the maneuver is right in the middle of it and should definitely be triggered/considered.
Could you please elaborate on that point ? And maybe provide an example where the error occured and where your propagation interval does not contain the maneuver ?

Note that your code is a bit tricky because the maneuver will be considered only during the second leg (the backward one) of the propagation and not in the first, so in the end you will end up with a reverse maneuver compared to what you expect…
Let me explain that: I couldn’t find it in the technical documentation but the events are only considered during the propagation interval set by the user.
Look at the code of AbstractIntegratedPropagator.propagate(tStart, tEnd) @l.404 :

if (!tStart.equals(getInitialState().getDate())) {
                // if propagation start date is not initial date,
                // propagate from initial to start date without event detection
                try (IntegratorResetter startResetter = new IntegratorResetter(integrator)) {
                    integrateDynamics(tStart);
                }
            }

The comments are the important things to notice here.
Event detectors are not considered between initialState.getDate() and tStart.
In your case, the first leg of propagation from 2022-01-01T12:00:00 to 2022-01-02T12:10:00 does not see any maneuver (since the event detectors are off).
Then the second leg, from 2022-01-02T12:10:00 to 2022-01-02T12:00:00 will perform an opposite maneuver to what you entered, since it is backward propagation.
So you should end up with a weird state at 2022-01-02T12:00:00, the maneuver was triggered but in a reverse way and your orbit is not what you expect.

This is not what you want, I think that you should first propagate to firingDate.shiftedBy(300) before the second snippet of code where you define the ephemeris generator.

propagator.propagate(firingDate.shiftedBy(300))

Here the maneuver will be naturally triggered in the right direction, and then when you will propagate backward it will be “cancelled” when you pass again through the firing dates.
Thus the state at firingDate.shiftedBy(-300) will be as expected.

I’m not sure this is very clear I’m sorry. Tell me if I should elaborate further.

Last thing, as I said in your previous post, prefer DateBasedManeuverTriggers to EventBased ones with DateDetectors.

Maxime

@MaximeJ, thank you again for your help. It is very precious.

Related to this question, I think I did something wrong the first time, because now everything is working fine and if the window of the propgation does not contain the trigger for the maneuver the maneuver does not happen. So no problem on that.
Thanks again.