Fixed missing update in ODE event handlers.

When a RESET_STATE was triggered, event states for events not triggered
in the same step were not updated properly.

JIRA: MATH-950

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1458294 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2013-03-19 14:09:08 +00:00
parent d18a6b8510
commit 424cbd201c
3 changed files with 83 additions and 10 deletions

View File

@ -55,6 +55,9 @@ This is a minor release: It combines bug fixes and new features.
Changes to existing features were made in a backwards-compatible
way such as to allow drop-in replacement of the v3.1[.1] JAR file.
">
<action dev="luc" type="fix" issue="MATH-950" >
Fixed missing update in ODE event handlers, when a RESET_STATE is triggered.
</action>
<action dev="psteitz" type="update" issue="MATH-671">
Made EmpiricalDisribution smoothing kernel pluggable.
</action>

View File

@ -338,11 +338,15 @@ public abstract class AbstractIntegrator implements FirstOrderIntegrator {
interpolator.setSoftPreviousTime(previousT);
interpolator.setSoftCurrentTime(eventT);
// trigger the event
// get state at event time
interpolator.setInterpolatedTime(eventT);
final double[] eventY = interpolator.getInterpolatedState().clone();
currentEvent.stepAccepted(eventT, eventY);
isLastStep = currentEvent.stop();
// advance all event states to current time
for (final EventState state : eventsStates) {
state.stepAccepted(eventT, eventY);
isLastStep = isLastStep || state.stop();
}
// handle the first part of the step, up to the event
for (final StepHandler handler : stepHandlers) {
@ -352,21 +356,19 @@ public abstract class AbstractIntegrator implements FirstOrderIntegrator {
if (isLastStep) {
// the event asked to stop integration
System.arraycopy(eventY, 0, y, 0, y.length);
for (final EventState remaining : occuringEvents) {
remaining.stepAccepted(eventT, eventY);
}
return eventT;
}
if (currentEvent.reset(eventT, eventY)) {
boolean needReset = false;
for (final EventState state : eventsStates) {
needReset = needReset || state.reset(eventT, eventY);
}
if (needReset) {
// some event handler has triggered changes that
// invalidate the derivatives, we need to recompute them
System.arraycopy(eventY, 0, y, 0, y.length);
computeDerivatives(eventT, y, yDot);
resetOccurred = true;
for (final EventState remaining : occuringEvents) {
remaining.stepAccepted(eventT, eventY);
}
return eventT;
}
@ -383,6 +385,7 @@ public abstract class AbstractIntegrator implements FirstOrderIntegrator {
}
// last part of the step, after the last event
interpolator.setInterpolatedTime(currentT);
final double[] currentY = interpolator.getInterpolatedState();
for (final EventState state : eventsStates) {

View File

@ -333,6 +333,73 @@ public class DormandPrince853IntegratorTest {
Assert.assertEquals(8.0, y[0], 1.0e-12);
}
@Test
public void testEventsScheduling() {
FirstOrderDifferentialEquations sincos = new FirstOrderDifferentialEquations() {
public int getDimension() {
return 2;
}
public void computeDerivatives(double t, double[] y, double[] yDot) {
yDot[0] = y[1];
yDot[1] = -y[0];
}
};
SchedulingChecker sinChecker = new SchedulingChecker(0); // events at 0, PI, 2PI ...
SchedulingChecker cosChecker = new SchedulingChecker(1); // events at PI/2, 3PI/2, 5PI/2 ...
FirstOrderIntegrator integ =
new DormandPrince853Integrator(0.001, 1.0, 1.0e-12, 0.0);
integ.addEventHandler(sinChecker, 0.01, 1.0e-7, 100);
integ.addStepHandler(sinChecker);
integ.addEventHandler(cosChecker, 0.01, 1.0e-7, 100);
integ.addStepHandler(cosChecker);
double t0 = 0.5;
double[] y0 = new double[] { FastMath.sin(t0), FastMath.cos(t0) };
double t = 10.0;
double[] y = new double[2];
integ.integrate(sincos, t0, y0, t, y);
}
private static class SchedulingChecker implements StepHandler, EventHandler {
int index;
double tMin;
public SchedulingChecker(int index) {
this.index = index;
}
public void init(double t0, double[] y0, double t) {
tMin = t0;
}
public void handleStep(StepInterpolator interpolator, boolean isLast) {
tMin = interpolator.getCurrentTime();
}
public double g(double t, double[] y) {
// once a step has been handled by handleStep,
// events checking should only refer to dates after the step
Assert.assertTrue(t >= tMin);
return y[index];
}
public Action eventOccurred(double t, double[] y, boolean increasing) {
return Action.RESET_STATE;
}
public void resetState(double t, double[] y) {
// in fact, we don't need to reset anything for the test
}
}
private static class KeplerHandler implements StepHandler {
public KeplerHandler(TestProblem3 pb) {
this.pb = pb;