Commit d10fec42 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Allow Jacobian wrt dates to be interrupted and restarted.

parent a376b2e6
......@@ -23,9 +23,12 @@ import org.hipparchus.linear.RealMatrix;
import org.hipparchus.linear.RealVector;
import org.orekit.forces.maneuvers.Maneuver;
import org.orekit.forces.maneuvers.trigger.ManeuverTriggersResetter;
import org.orekit.time.AbsoluteDate;
/** Generator for one column of a Jacobian matrix for special case of trigger dates.
* <p>
* Typical use cases for this are estimation of maneuver start and stop date during
* either orbit determination or maneuver optimisation.
* </p>
* <p>
* Let \((t_0, y_0)\) be the state at propagation start, \((t_1, y_1)\) be the state at
* maneuver trigger time, \((t_t, y_t)\) be the state at any arbitrary time \(t\) during
......@@ -56,6 +59,11 @@ import org.orekit.time.AbsoluteDate;
* where \(c_1\) is the signed contribution of maneuver at \(t_1\) and is computed at trigger time
* by solving \(\frac{\partial y_1}{\partial y_0} c_1 = \pm f_m(t_1, y_1)\).
* </p>
* <p>
* The implementation takes care to <em>not</em> resetting anything at propagation start.
* This allows to get proper Jacobian if we interrupt propagation in the middle of a maneuver
* and restart propagation where it left.
* </p>
* @author Luc Maisonobe
* @since 11.1
*/
......@@ -121,6 +129,11 @@ public class TriggerDateJacobianColumnGenerator
return !state.hasAdditionalState(stmName);
}
// note that we do NOT implement init
// in particular we reset NEITHER contribution nor triggered
// this allows to get proper Jacobian if we interrupt propagation
// in the middle of a maneuver and restart propagation where it left
/** {@inheritDoc} */
@Override
public double[] getAdditionalState(final SpacecraftState state) {
......@@ -130,13 +143,6 @@ public class TriggerDateJacobianColumnGenerator
return contribution == null ? ZERO : getStm(state).operate(contribution);
}
/** {@inheritDoc}*/
@Override
public void init(final SpacecraftState initialState, final AbsoluteDate target) {
contribution = null;
triggered = false;
}
/** {@inheritDoc}*/
@Override
public void maneuverTriggered(final SpacecraftState state, final boolean start) {
......
......@@ -60,6 +60,46 @@ import org.orekit.utils.IERSConventions;
public class TriggersDerivativesTest {
@Test
public void testInterrupt() {
final AbsoluteDate firing = new AbsoluteDate(new DateComponents(2004, 1, 2),
new TimeComponents(4, 15, 34.080),
TimeScalesFactory.getUTC());
final double duration = 200.0;
// first propagation, covering the maneuver
final NumericalPropagator propagator1 = buildPropagator(OrbitType.EQUINOCTIAL, PositionAngle.TRUE, 20,
firing, duration, true, 0);
setUpManeuverJcobianComputation(true, propagator1);
final MatricesHarvester harvester1 = propagator1.setupMatricesComputation("stm", null, null);
final SpacecraftState state1 = propagator1.propagate(firing.shiftedBy(2 * duration));
final RealMatrix stm1 = harvester1.getStateTransitionMatrix(state1);
final RealMatrix jacobian1 = harvester1.getParametersJacobian(state1);
// second propagation, interrupted during maneuver
final NumericalPropagator propagator2 = buildPropagator(OrbitType.EQUINOCTIAL, PositionAngle.TRUE, 20,
firing, duration, true, 0);
setUpManeuverJcobianComputation(true, propagator2);
final MatricesHarvester harvester2 = propagator2.setupMatricesComputation("stm", null, null);
final SpacecraftState intermediate = propagator2.propagate(firing.shiftedBy(0.5 * duration));
final RealMatrix stmI = harvester2.getStateTransitionMatrix(intermediate);
final RealMatrix jacobianI = harvester2.getParametersJacobian(intermediate);
// intermediate state has really different matrices, they are still building up
Assert.assertEquals(0.1253, stmI.subtract(stm1).getNorm1() / stm1.getNorm1(), 1.0e-4);
Assert.assertEquals(0.0172, jacobianI.subtract(jacobian1).getNorm1() / jacobian1.getNorm1(), 1.0e-4);
// restarting propagation where we left it
final SpacecraftState state2 = propagator2.propagate(firing.shiftedBy(2 * duration));
final RealMatrix stm2 = harvester2.getStateTransitionMatrix(state2);
final RealMatrix jacobian2 = harvester2.getParametersJacobian(state2);
// after completing the two-stage propagation, we get the same matrices
Assert.assertEquals(0.0, stm2.subtract(stm1).getNorm1(), 1.0e-13 * stm1.getNorm1());
Assert.assertEquals(0.0, jacobian2.subtract(jacobian1).getNorm1(), 2.0e-14 * jacobian1.getNorm1());
}
@Test
public void testDerivativeWrtStartTimeCartesian() {
doTestDerivativeWrtTime(true, OrbitType.CARTESIAN,
......@@ -105,12 +145,7 @@ public class TriggersDerivativesTest {
// the central propagator (k = 4) will compute derivatives autonomously using State and TriggersDerivatives
final NumericalPropagator autonomous = (NumericalPropagator) propagators.get(4);
final MatricesHarvester harvester = autonomous.setupMatricesComputation("stm", null, null);
autonomous.
getAllForceModels().
forEach(fm -> fm.getParametersDrivers().
stream().
filter(d -> d.getName().equals(start ? "MAN_0_START" : "MAN_0_STOP")).
forEach(d -> d.setSelected(true)));
setUpManeuverJcobianComputation(start, autonomous);
DerivativesSampler sampler = new DerivativesSampler(harvester, orbitType, positionAngle,
firing, duration, h, samplingtep);
......@@ -133,6 +168,16 @@ public class TriggersDerivativesTest {
}
private void setUpManeuverJcobianComputation(final boolean start, final NumericalPropagator propagator) {
propagator.
getAllForceModels().
forEach(fm -> fm.
getParametersDrivers().
stream().
filter(d -> d.getName().equals(start ? "MAN_0_START" : "MAN_0_STOP")).
forEach(d -> d.setSelected(true)));
}
private NumericalPropagator buildPropagator(final OrbitType orbitType, final PositionAngle positionAngle,
final int degree, final AbsoluteDate firing, final double duration,
final boolean start, final double shift) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment