Fixed an error in handling of very close events during ODE integration
JIRA: MATH-322 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@887794 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
335572b99e
commit
f7c0b403d2
|
@ -19,6 +19,7 @@ package org.apache.commons.math.ode.events;
|
|||
|
||||
import org.apache.commons.math.ConvergenceException;
|
||||
import org.apache.commons.math.FunctionEvaluationException;
|
||||
import org.apache.commons.math.MathRuntimeException;
|
||||
import org.apache.commons.math.analysis.UnivariateRealFunction;
|
||||
import org.apache.commons.math.analysis.solvers.BrentSolver;
|
||||
import org.apache.commons.math.ode.DerivativeException;
|
||||
|
@ -187,6 +188,26 @@ public class EventState {
|
|||
if (g0Positive ^ (gb >= 0)) {
|
||||
// there is a sign change: an event is expected during this step
|
||||
|
||||
if (ga * gb > 0) {
|
||||
// this is a corner case:
|
||||
// - there was an event near ta,
|
||||
// - there is another event between ta and tb
|
||||
// - when ta was computed, convergence was reached on the "wrong side" of the interval
|
||||
// this implies that the real sign of ga is the same as gb, so we need to slightly
|
||||
// shift ta to make sure ga and gb get opposite signs and the solver won't complain
|
||||
// about bracketing
|
||||
final double epsilon = (forward ? 0.25 : -0.25) * convergence;
|
||||
for (int k = 0; (k < 4) && (ga * gb > 0); ++k) {
|
||||
ta += epsilon;
|
||||
interpolator.setInterpolatedTime(ta);
|
||||
ga = handler.g(ta, interpolator.getInterpolatedState());
|
||||
}
|
||||
if (ga * gb > 0) {
|
||||
// this should never happen
|
||||
throw MathRuntimeException.createInternalError(null);
|
||||
}
|
||||
}
|
||||
|
||||
// variation direction, with respect to the integration direction
|
||||
increasing = gb >= ga;
|
||||
|
||||
|
@ -205,16 +226,9 @@ public class EventState {
|
|||
final BrentSolver solver = new BrentSolver();
|
||||
solver.setAbsoluteAccuracy(convergence);
|
||||
solver.setMaximalIterationCount(maxIterationCount);
|
||||
double root;
|
||||
try {
|
||||
root = (ta <= tb) ? solver.solve(f, ta, tb) : solver.solve(f, tb, ta);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// the interval did not really bracket a root
|
||||
root = Double.NaN;
|
||||
}
|
||||
if (Double.isNaN(root) ||
|
||||
((Math.abs(root - ta) <= convergence) &&
|
||||
(Math.abs(root - previousEventTime) <= convergence))) {
|
||||
final double root = (ta <= tb) ? solver.solve(f, ta, tb) : solver.solve(f, tb, ta);
|
||||
if ((Math.abs(root - ta) <= convergence) &&
|
||||
(Math.abs(root - previousEventTime) <= convergence)) {
|
||||
// we have either found nothing or found (again ?) a past event, we simply ignore it
|
||||
ta = tb;
|
||||
ga = gb;
|
||||
|
|
|
@ -39,6 +39,9 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
</properties>
|
||||
<body>
|
||||
<release version="2.1" date="TBD" description="TBD">
|
||||
<action dev="luc" type="fix" issue="MATH-322" >
|
||||
Fixed an error in handling very close events in ODE integration.
|
||||
</action>
|
||||
<action dev="psteitz" type="fix" issue="MATH-305" due-to="Erik van Ingen">
|
||||
Fixed an overflow error in MathUtils.distance that was causing KMeansPlusPlusClusterer
|
||||
to fail with a NullPointerException when component distances between points
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.math.ode.events;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.apache.commons.math.ConvergenceException;
|
||||
import org.apache.commons.math.ode.DerivativeException;
|
||||
import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
|
||||
import org.apache.commons.math.ode.sampling.DummyStepInterpolator;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EventStateTest {
|
||||
|
||||
// JIRA: MATH-322
|
||||
@Test
|
||||
public void closeEvents()
|
||||
throws EventException, ConvergenceException, DerivativeException {
|
||||
|
||||
final double r1 = 90.0;
|
||||
final double r2 = 135.0;
|
||||
final double gap = r2 - r1;
|
||||
EventHandler closeEventsGenerator = new EventHandler() {
|
||||
public void resetState(double t, double[] y) {
|
||||
}
|
||||
public double g(double t, double[] y) {
|
||||
return (t - r1) * (r2 - t);
|
||||
}
|
||||
public int eventOccurred(double t, double[] y, boolean increasing) {
|
||||
return CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
final double tolerance = 0.1;
|
||||
EventState es = new EventState(closeEventsGenerator, 1.5 * gap, tolerance, 10);
|
||||
|
||||
double t0 = r1 - 0.5 * gap;
|
||||
es.reinitializeBegin(t0, new double[0]);
|
||||
AbstractStepInterpolator interpolator =
|
||||
new DummyStepInterpolator(new double[0], true);
|
||||
interpolator.storeTime(t0);
|
||||
|
||||
interpolator.shift();
|
||||
interpolator.storeTime(0.5 * (r1 + r2));
|
||||
Assert.assertTrue(es.evaluateStep(interpolator));
|
||||
Assert.assertEquals(r1, es.getEventTime(), tolerance);
|
||||
es.stepAccepted(es.getEventTime(), new double[0]);
|
||||
|
||||
interpolator.shift();
|
||||
interpolator.storeTime(r2 + 0.4 * gap);
|
||||
Assert.assertTrue(es.evaluateStep(interpolator));
|
||||
Assert.assertEquals(r2, es.getEventTime(), tolerance);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue