I want to numerically propagate a low-thrust LEO satellite which executes hundreds of small burns. For concreteness, let each burn be a half-hour long, and let the time from the start of one burn to the next be an hour. Let the propagation duration be one month. Here is some sample code:
// Define scenario time.
final AbsoluteDate scenarioStartDate = new AbsoluteDate(2015, 01, 01, 00, 00, 00.000, OrekitGlobals.UTC);
final AbsoluteDate scenarioStopDate = new AbsoluteDate(2015, 02, 01, 00, 00, 00.000, OrekitGlobals.UTC);
// Define satellite parameters.
final double mass = 100.; // kg
final double specificImpulse = 1000.; // s
final double thrustForce = 0.01; // N
// Define satellite orbit.
final Orbit orbit = new KeplerianOrbit(7000000., 0.05, Math.toRadians(28.5), Math.toRadians(0.),
Math.toRadians(0.), Math.toRadians(0.), PositionAngle.MEAN, FramesFactory.getGCRF(), scenarioStartDate, MU);
final SpacecraftState initialSpacecraftState = new SpacecraftState(orbit, mass);
// Define propagator.
final double[][] tolerances = NumericalPropagator.tolerances(1e-6, orbit, OrbitType.CARTESIAN);
final var integrator = new DormandPrince853Integrator(1., 4. * 60., tolerances[0], tolerances[1]);
final NumericalPropagator propagator = new NumericalPropagator(integrator);
// Configure propagator.
propagator.setOrbitType(OrbitType.CARTESIAN);
propagator.setInitialState(initialSpacecraftState);
// Add force models.
propagator.addForceModel(new NewtonianAttraction(MU));
for (int i = 0; i < 31 * 24; ++i) {
final AbsoluteDate maneuverStartDate = scenarioStartDate.shiftedBy(3600. * i);
final double maneuverDuration = 1800.;
propagator.addForceModel(new ConstantThrustManeuver(maneuverStartDate, maneuverDuration, thrustForce,
specificImpulse, Vector3D.PLUS_I));
}
// Propagate.
long tick = System.currentTimeMillis();
propagator.propagate(scenarioStopDate);
tick = System.currentTimeMillis() - tick;
System.out.println(tick);
This takes 60 seconds to execute on my machine. If I comment out the addition of the maneuver force models then it takes less than one second. In fact if you play around with the number of maneuvers you quickly find that the runtime depends linearly on the number of maneuvers. Presumably the issue is that the numerical integrator has to call each force model at each time step to obtain a force contribution, so at each time step there is a huge for
loop.
The simplest way around this that I’ve been able to invent is to sequentially create a propagator for each maneuver, initializing each one with the propagation result of the last. However, I would really like to have a single propagator that incorporates all the maneuvers. I was not able to come up with a simple way, using the existing OreKit classes, to create a single ForceModel
which incorporates all the maneuvers. I looked into using a Maneuver
with a custom ManeuverTriggers
implementation but I think this runs into the same problem because one of the methods on ManeuverTriggers
is getEventsDetectors()
. There is a DateBasedManeuverTriggers
class for a single maneuver over a time interval which returns 2 event detectors from this method, one for the start of the time interval and one for the end of the time interval. I think I would have to return 2*n
event detectors where n
is the number of maneuvers–so I haven’t avoided the issue of lots of evaluations at every timestep. (Full disclosure: I haven’t actually pushed through to get a fully working implementation of what I’m describing here, but given the way the maneuvers
package is architected I don’t think it’s going to work.)
Before I spend much more time on this I thought I’d ask the forum: is there a clean way to do what I want in OreKit which doesn’t suffer from performance issues?