Removed the requiresDenseOutput method from the StepHandler interface. Now integrators always

consider dense output is required and set up the appropriate state interpolators, so step
handlers can rely on them.

JIRA: MATH-596, MATH-604

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1139831 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2011-06-26 16:26:48 +00:00
parent c005c8d4da
commit 57e2712f50
25 changed files with 51 additions and 228 deletions

View File

@ -153,22 +153,6 @@ public abstract class AbstractIntegrator implements FirstOrderIntegrator {
eventsStates.clear();
}
/** Check if dense output is needed.
* @return true if there is at least one event handler or if
* one of the step handlers requires dense output
*/
protected boolean requiresDenseOutput() {
if (!eventsStates.isEmpty()) {
return true;
}
for (StepHandler handler : stepHandlers) {
if (handler.requiresDenseOutput()) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
public double getCurrentStepStart() {
return stepStart;

View File

@ -167,16 +167,6 @@ public class ContinuousOutputModel
}
/** Determines whether this handler needs dense output.
* <p>The essence of this class is to provide dense output over all
* steps, hence it requires the internal steps to provide themselves
* dense output. The method therefore returns always true.</p>
* @return always true
*/
public boolean requiresDenseOutput() {
return true;
}
/** Reset the step handler.
* Initialize the internal data as required before the first step is
* handled.

View File

@ -383,11 +383,6 @@ public abstract class MultistepIntegrator extends AdaptiveStepsizeIntegrator {
}
/** {@inheritDoc} */
public boolean requiresDenseOutput() {
return true;
}
/** {@inheritDoc} */
public void reset() {
// nothing to do

View File

@ -20,8 +20,6 @@ package org.apache.commons.math.ode.nonstiff;
import org.apache.commons.math.exception.MathUserException;
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
import org.apache.commons.math.ode.sampling.DummyStepInterpolator;
import org.apache.commons.math.ode.sampling.StepHandler;
import org.apache.commons.math.util.FastMath;
@ -211,14 +209,8 @@ public abstract class EmbeddedRungeKuttaIntegrator
final double[] yDotTmp = new double[y0.length];
// set up an interpolator sharing the integrator arrays
AbstractStepInterpolator interpolator;
if (requiresDenseOutput()) {
final RungeKuttaStepInterpolator rki = (RungeKuttaStepInterpolator) prototype.copy();
rki.reinitialize(this, yTmp, yDotK, forward);
interpolator = rki;
} else {
interpolator = new DummyStepInterpolator(yTmp, yDotK[stages - 1], forward);
}
final RungeKuttaStepInterpolator interpolator = (RungeKuttaStepInterpolator) prototype.copy();
interpolator.reinitialize(this, yTmp, yDotK, forward);
interpolator.storeTime(t0);
// set up integration control objects

View File

@ -23,7 +23,6 @@ import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.events.EventHandler;
import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
import org.apache.commons.math.ode.sampling.DummyStepInterpolator;
import org.apache.commons.math.ode.sampling.StepHandler;
import org.apache.commons.math.util.FastMath;
@ -372,16 +371,9 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
optimalStep = new double[size];
}
if (requiresDenseOutput()) {
// step size sequence: 2, 6, 10, 14, ...
for (int k = 0; k < size; ++k) {
// step size sequence: 2, 6, 10, 14, ...
for (int k = 0; k < size; ++k) {
sequence[k] = 4 * k + 2;
}
} else {
// step size sequence: 2, 4, 6, 8, ...
for (int k = 0; k < size; ++k) {
sequence[k] = 2 * (k + 1);
}
}
// initialize the order selection cost array
@ -592,18 +584,8 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
System.arraycopy(y0, 0, y, 0, y0.length);
}
double[] yDot1 = new double[y0.length];
double[][] yMidDots = null;
final boolean denseOutput = requiresDenseOutput();
if (denseOutput) {
yMidDots = new double[1 + 2 * sequence.length][];
for (int j = 0; j < yMidDots.length; ++j) {
yMidDots[j] = new double[y0.length];
}
} else {
yMidDots = new double[1][];
yMidDots[0] = new double[y0.length];
}
final double[] yDot1 = new double[y0.length];
final double[][] yMidDots = new double[1 + 2 * sequence.length][y0.length];
// initial scaling
final double[] scale = new double[mainSetDimension];
@ -618,14 +600,10 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
(int) FastMath.floor(0.5 - 0.6 * log10R)));
// set up an interpolator sharing the integrator arrays
AbstractStepInterpolator interpolator = null;
if (denseOutput) {
interpolator = new GraggBulirschStoerStepInterpolator(y, yDot0,
y1, yDot1,
yMidDots, forward);
} else {
interpolator = new DummyStepInterpolator(y, yDot1, forward);
}
final AbstractStepInterpolator interpolator =
new GraggBulirschStoerStepInterpolator(y, yDot0,
y1, yDot1,
yMidDots, forward);
interpolator.storeTime(t0);
stepStart = t0;
@ -817,7 +795,7 @@ public class GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
// dense output handling
double hInt = getMaxStep();
if (denseOutput && ! reject) {
if (! reject) {
// extrapolate state at middle point of the step
for (int j = 1; j <= k; ++j) {

View File

@ -22,8 +22,6 @@ import org.apache.commons.math.exception.MathUserException;
import org.apache.commons.math.ode.AbstractIntegrator;
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
import org.apache.commons.math.ode.sampling.DummyStepInterpolator;
import org.apache.commons.math.ode.sampling.StepHandler;
import org.apache.commons.math.util.FastMath;
@ -115,14 +113,8 @@ public abstract class RungeKuttaIntegrator extends AbstractIntegrator {
final double[] yDotTmp = new double[y0.length];
// set up an interpolator sharing the integrator arrays
AbstractStepInterpolator interpolator;
if (requiresDenseOutput()) {
final RungeKuttaStepInterpolator rki = (RungeKuttaStepInterpolator) prototype.copy();
rki.reinitialize(this, yTmp, yDotK, forward);
interpolator = rki;
} else {
interpolator = new DummyStepInterpolator(yTmp, yDotK[stages - 1], forward);
}
final RungeKuttaStepInterpolator interpolator = (RungeKuttaStepInterpolator) prototype.copy();
interpolator.reinitialize(this, yTmp, yDotK, forward);
interpolator.storeTime(t0);
// set up integration control objects

View File

@ -50,14 +50,6 @@ public class DummyStepHandler implements StepHandler {
return LazyHolder.INSTANCE;
}
/** Determines whether this handler needs dense output.
* Since this handler does nothing, it does not require dense output.
* @return always false
*/
public boolean requiresDenseOutput() {
return false;
}
/** Reset the step handler.
* Initialize the internal data as required before the first step is
* handled.

View File

@ -41,16 +41,6 @@ import org.apache.commons.math.exception.MathUserException;
public interface StepHandler {
/** Determines whether this handler needs dense output.
* <p>This method allows the integrator to avoid performing extra
* computation if the handler does not need dense output. If this
* method returns false, the integrator will call the {@link
* #handleStep} method with a {@link DummyStepInterpolator} rather
* than a custom interpolator.</p>
* @return true if the handler needs dense output
*/
boolean requiresDenseOutput();
/** Reset the step handler.
* Initialize the internal data as required before the first step is
* handled.

View File

@ -171,16 +171,6 @@ public class StepNormalizer implements StepHandler {
reset();
}
/** Determines whether this handler needs dense output.
* This handler needs dense output in order to provide data at
* regularly spaced steps regardless of the steps the integrator
* uses, so this method always returns true.
* @return always true
*/
public boolean requiresDenseOutput() {
return true;
}
/** Reset the step handler.
* Initialize the internal data as required before the first step is
* handled.

View File

@ -52,6 +52,11 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="3.0" date="TBD" description="TBD">
<action dev="luc" type="fix" issue="MATH-596,MATH-604">
Removed the requiresDenseOutput method from the StepHandler interface. Now integrators always
consider dense output is required and set up the appropriate state interpolators, so step
handlers can rely on them.
</action>
<action dev="eran" type="add" issue="MATH-599" due-to="Dennis Hendriks">
Modified "SecantSolver" to comply with the original algorithm. Added several
secant-based solvers.

View File

@ -130,8 +130,6 @@ dp853.integrate(ode, 0.0, y, 16.0, y); // now y contains final state at time t=1
StepHandler stepHandler = new StepHandler() {
public void reset() {}
public boolean requiresDenseOutput() { return false; }
public void handleStep(StepInterpolator interpolator, boolean isLast) throws MathUserException {
double t = interpolator.getCurrentTime();
double[] y = interpolator.getInterpolatedState();

View File

@ -60,10 +60,6 @@ public class TestProblemHandler
reset();
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
maxValueError = 0;
maxTimeError = 0;

View File

@ -251,9 +251,6 @@ public class ClassicalRungeKuttaIntegratorTest {
this.pb = pb;
reset();
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
maxError = 0;
}
@ -292,9 +289,6 @@ public class ClassicalRungeKuttaIntegratorTest {
1.0e-12);
}
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
});

View File

@ -137,10 +137,6 @@ public class DormandPrince54IntegratorTest {
this.minStep = minStep;
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
@ -284,9 +280,6 @@ public class DormandPrince54IntegratorTest {
this.pb = pb;
reset();
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
nbSteps = 0;
maxError = 0;
@ -328,9 +321,6 @@ public class DormandPrince54IntegratorTest {
minStep = 0;
maxStep = 0;
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
firstTime = true;
minStep = 0;

View File

@ -136,9 +136,6 @@ public class DormandPrince54StepInterpolatorTest {
}
}
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
}
});

View File

@ -27,8 +27,6 @@ import org.apache.commons.math.ode.TestProblem4;
import org.apache.commons.math.ode.TestProblem5;
import org.apache.commons.math.ode.TestProblemHandler;
import org.apache.commons.math.ode.events.EventHandler;
import org.apache.commons.math.ode.nonstiff.DormandPrince853Integrator;
import org.apache.commons.math.ode.sampling.DummyStepHandler;
import org.apache.commons.math.ode.sampling.StepHandler;
import org.apache.commons.math.ode.sampling.StepInterpolator;
import org.apache.commons.math.util.FastMath;
@ -292,37 +290,6 @@ public class DormandPrince853IntegratorTest {
Assert.assertEquals("Dormand-Prince 8 (5, 3)", integ.getName());
}
@Test
public void testNoDenseOutput()
throws MathUserException, IntegratorException {
TestProblem1 pb1 = new TestProblem1();
TestProblem1 pb2 = pb1.copy();
double minStep = 0.1 * (pb1.getFinalTime() - pb1.getInitialTime());
double maxStep = pb1.getFinalTime() - pb1.getInitialTime();
double scalAbsoluteTolerance = 1.0e-4;
double scalRelativeTolerance = 1.0e-4;
FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
scalAbsoluteTolerance,
scalRelativeTolerance);
integ.addStepHandler(DummyStepHandler.getInstance());
integ.integrate(pb1,
pb1.getInitialTime(), pb1.getInitialState(),
pb1.getFinalTime(), new double[pb1.getDimension()]);
int callsWithoutDenseOutput = pb1.getCalls();
Assert.assertEquals(integ.getEvaluations(), callsWithoutDenseOutput);
integ.addStepHandler(new InterpolatingStepHandler());
integ.integrate(pb2,
pb2.getInitialTime(), pb2.getInitialState(),
pb2.getFinalTime(), new double[pb2.getDimension()]);
int callsWithDenseOutput = pb2.getCalls();
Assert.assertEquals(integ.getEvaluations(), callsWithDenseOutput);
Assert.assertTrue(callsWithDenseOutput > callsWithoutDenseOutput);
}
@Test
public void testUnstableDerivative()
throws MathUserException, IntegratorException {
@ -340,9 +307,6 @@ public class DormandPrince853IntegratorTest {
this.pb = pb;
reset();
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
nbSteps = 0;
maxError = 0;
@ -382,9 +346,6 @@ public class DormandPrince853IntegratorTest {
public VariableHandler() {
reset();
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
firstTime = true;
minStep = 0;
@ -418,19 +379,4 @@ public class DormandPrince853IntegratorTest {
private double maxStep = 0;
}
private static class InterpolatingStepHandler implements StepHandler {
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
}
public void handleStep(StepInterpolator interpolator,
boolean isLast)
throws MathUserException {
double prev = interpolator.getPreviousTime();
double curr = interpolator.getCurrentTime();
interpolator.setInterpolatedTime(0.5*(prev + curr));
}
}
}

View File

@ -136,9 +136,6 @@ public class DormandPrince853StepInterpolatorTest {
}
}
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
}
});

View File

@ -170,9 +170,6 @@ public class EulerIntegratorTest {
1.0e-12);
}
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
});

View File

@ -186,9 +186,6 @@ public class GillIntegratorTest {
this.pb = pb;
reset();
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
maxError = 0;
}
@ -227,9 +224,6 @@ public class GillIntegratorTest {
1.0e-12);
}
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
});

View File

@ -18,6 +18,7 @@
package org.apache.commons.math.ode.nonstiff;
import org.apache.commons.math.exception.MathUserException;
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
import org.apache.commons.math.ode.FirstOrderIntegrator;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.TestProblem1;
@ -285,14 +286,42 @@ public class GraggBulirschStoerIntegratorTest {
Assert.assertEquals(8.0, y[0], 1.0e-12);
}
@Test
public void testIssue596() throws MathUserException, IntegratorException {
FirstOrderIntegrator integ = new GraggBulirschStoerIntegrator(1e-10, 100.0, 1e-7, 1e-7);
integ.addStepHandler(new StepHandler() {
public void reset() {}
public void handleStep(StepInterpolator interpolator, boolean isLast) throws MathUserException {
double t = interpolator.getCurrentTime();
interpolator.setInterpolatedTime(t);
double[] y = interpolator.getInterpolatedState();
double[] yDot = interpolator.getInterpolatedDerivatives();
Assert.assertEquals(3.0 * t - 5.0, y[0], 1.0e-14);
Assert.assertEquals(3.0, yDot[0], 1.0e-14);
}
});
double[] y = {4.0};
double t0 = 3.0;
double tend = 10.0;
integ.integrate(new FirstOrderDifferentialEquations() {
public int getDimension() {
return 1;
}
public void computeDerivatives(double t, double[] y, double[] yDot) {
yDot[0] = 3.0;
}
}, t0, y, tend, y);
}
private static class KeplerStepHandler implements StepHandler {
public KeplerStepHandler(TestProblem3 pb) {
this.pb = pb;
reset();
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
nbSteps = 0;
maxError = 0;
@ -332,9 +361,6 @@ public class GraggBulirschStoerIntegratorTest {
public VariableStepHandler() {
reset();
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
firstTime = true;
minStep = 0;
@ -360,7 +386,7 @@ public class GraggBulirschStoerIntegratorTest {
if (isLast) {
Assert.assertTrue(minStep < 8.2e-3);
Assert.assertTrue(maxStep > 1.7);
Assert.assertTrue(maxStep > 1.5);
}
}
private boolean firstTime;

View File

@ -138,9 +138,6 @@ public class GraggBulirschStoerStepInterpolatorTest {
}
}
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
}
});

View File

@ -136,9 +136,6 @@ public class HighamHall54StepInterpolatorTest {
}
}
}
public boolean requiresDenseOutput() {
return true;
}
public void reset() {
}
});

View File

@ -170,9 +170,6 @@ public class MidpointIntegratorTest {
1.0e-12);
}
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
});

View File

@ -177,10 +177,6 @@ public class ThreeEighthesIntegratorTest {
maxError = 0;
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
maxError = 0;
}
@ -222,9 +218,6 @@ public class ThreeEighthesIntegratorTest {
1.0e-12);
}
}
public boolean requiresDenseOutput() {
return false;
}
public void reset() {
}
});

View File

@ -32,10 +32,6 @@ public class StepInterpolatorTestUtils {
throws MathUserException, IntegratorException {
integrator.addStepHandler(new StepHandler() {
public boolean requiresDenseOutput() {
return true;
}
public void handleStep(StepInterpolator interpolator, boolean isLast)
throws MathUserException {