added a way to handle errors in user-defined switching functions

previously, only the function evaluation could trigger errors,
not the other functions of the interface

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/branches/MATH_2_0@651514 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2008-04-25 07:25:58 +00:00
parent de621a4151
commit 03b9e6771e
6 changed files with 109 additions and 50 deletions

View File

@ -0,0 +1,50 @@
/*
* 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;
import org.apache.commons.math.MathException;
/**
* This exception is made available to users to report
* the error conditions that are triggered by {@link SwitchingFunction}
* @version $Revision: 620312 $ $Date: 2008-02-10 20:28:59 +0100 (dim., 10 févr. 2008) $
* @since 2.0
*/
public class SwitchException extends MathException {
/** Serialization UID. */
private static final long serialVersionUID = -3662133702316614545L;
/** Simple constructor.
* Build an exception by translating and formating a message
* @param specifier format specifier (to be translated)
* @param parts to insert in the format (no translation)
*/
public SwitchException(String specifier, Object[] parts) {
super(specifier, parts);
}
/**
* Create an exception with a given root cause.
* @param cause the exception or error that caused this exception to be thrown
*/
public SwitchException(Throwable cause) {
super(cause);
}
}

View File

@ -42,7 +42,7 @@ import org.apache.commons.math.analysis.UnivariateRealSolver;
class SwitchState implements Serializable { class SwitchState implements Serializable {
/** Serializable version identifier. */ /** Serializable version identifier. */
private static final long serialVersionUID = -7307007422156119622L; private static final long serialVersionUID = -7307007422156119622L;
/** Switching function. */ /** Switching function. */
private SwitchingFunction function; private SwitchingFunction function;
@ -50,10 +50,10 @@ class SwitchState implements Serializable {
/** Maximal time interval between switching function checks. */ /** Maximal time interval between switching function checks. */
private double maxCheckInterval; private double maxCheckInterval;
/** Convergence threshold for event localisation. */ /** Convergence threshold for event localization. */
private double convergence; private double convergence;
/** Upper limit in the iteration count for event localisation. */ /** Upper limit in the iteration count for event localization. */
private int maxIterationCount; private int maxIterationCount;
/** Time at the beginning of the step. */ /** Time at the beginning of the step. */
@ -115,11 +115,11 @@ class SwitchState implements Serializable {
* beginning of the step * beginning of the step
* @param y0 array containing the current value of the state vector * @param y0 array containing the current value of the state vector
* at the beginning of the step * at the beginning of the step
* @exception FunctionEvaluationException if the switching function * @exception SwitchException if the switching function
* value cannot be evaluated at the beginning of the step * value cannot be evaluated at the beginning of the step
*/ */
public void reinitializeBegin(double t0, double[] y0) public void reinitializeBegin(double t0, double[] y0)
throws FunctionEvaluationException { throws SwitchException {
this.t0 = t0; this.t0 = t0;
g0 = function.g(t0, y0); g0 = function.g(t0, y0);
g0Positive = (g0 >= 0); g0Positive = (g0 >= 0);
@ -132,12 +132,12 @@ class SwitchState implements Serializable {
* rejected) * rejected)
* @exception DerivativeException if the interpolator fails to * @exception DerivativeException if the interpolator fails to
* compute the function somewhere within the step * compute the function somewhere within the step
* @exception FunctionEvaluationException if the switching function * @exception SwitchException if the switching function
* cannot be evaluated * cannot be evaluated
* @exception ConvergenceException if an event cannot be located * @exception ConvergenceException if an event cannot be located
*/ */
public boolean evaluateStep(final StepInterpolator interpolator) public boolean evaluateStep(final StepInterpolator interpolator)
throws DerivativeException, FunctionEvaluationException, ConvergenceException { throws DerivativeException, SwitchException, ConvergenceException {
try { try {
@ -169,6 +169,8 @@ class SwitchState implements Serializable {
return function.g(t, interpolator.getInterpolatedState()); return function.g(t, interpolator.getInterpolatedState());
} catch (DerivativeException e) { } catch (DerivativeException e) {
throw new FunctionEvaluationException(t, e); throw new FunctionEvaluationException(t, e);
} catch (SwitchException e) {
throw new FunctionEvaluationException(t, e);
} }
} }
}); });
@ -205,10 +207,12 @@ class SwitchState implements Serializable {
} catch (FunctionEvaluationException e) { } catch (FunctionEvaluationException e) {
Throwable cause = e.getCause(); Throwable cause = e.getCause();
if ((cause != null) && (cause instanceof DerivativeException)) { if ((cause != null) && (cause instanceof DerivativeException)) {
throw (DerivativeException) cause; throw (DerivativeException) cause;
} } else if ((cause != null) && (cause instanceof SwitchException)) {
throw e; throw (SwitchException) cause;
}
throw new SwitchException(e);
} }
} }
@ -227,11 +231,10 @@ class SwitchState implements Serializable {
* end of the step * end of the step
* @param y array containing the current value of the state vector * @param y array containing the current value of the state vector
* at the end of the step * at the end of the step
* @exception FunctionEvaluationException if the value of the switching * @exception SwitchException if the value of the switching
* function cannot be evaluated * function cannot be evaluated
*/ */
public void stepAccepted(double t, double[] y) public void stepAccepted(double t, double[] y) throws SwitchException {
throws FunctionEvaluationException {
t0 = t; t0 = t;
g0 = function.g(t, y); g0 = function.g(t, y);
@ -261,8 +264,10 @@ class SwitchState implements Serializable {
* @param y array were to put the desired state vector at the beginning * @param y array were to put the desired state vector at the beginning
* of the next step * of the next step
* @return true if the integrator should reset the derivatives too * @return true if the integrator should reset the derivatives too
* @exception SwitchException if the state cannot be reseted by the switching
* function
*/ */
public boolean reset(double t, double[] y) { public boolean reset(double t, double[] y) throws SwitchException {
if (! pendingEvent) { if (! pendingEvent) {
return false; return false;

View File

@ -19,8 +19,6 @@ package org.apache.commons.math.ode;
import java.io.Serializable; import java.io.Serializable;
import org.apache.commons.math.FunctionEvaluationException;
/** This interface represents a switching function. /** This interface represents a switching function.
* *
* <p>A switching function allows to handle discrete events in * <p>A switching function allows to handle discrete events in
@ -93,10 +91,9 @@ public interface SwitchingFunction extends Serializable {
* @param t current value of the independent <i>time</i> variable * @param t current value of the independent <i>time</i> variable
* @param y array containing the current value of the state vector * @param y array containing the current value of the state vector
* @return value of the g function * @return value of the g function
* @exception FunctionEvaluationException if the value of the function * @exception SwitchException if the switching function cannot be evaluated
* cannot be evaluated
*/ */
public double g(double t, double[] y) throws FunctionEvaluationException; public double g(double t, double[] y) throws SwitchException;
/** Handle an event and choose what to do next. /** Handle an event and choose what to do next.
@ -131,8 +128,9 @@ public interface SwitchingFunction extends Serializable {
* @return indication of what the integrator should do next, this * @return indication of what the integrator should do next, this
* value must be one of {@link #STOP}, {@link #RESET_STATE}, * value must be one of {@link #STOP}, {@link #RESET_STATE},
* {@link #RESET_DERIVATIVES} or {@link #CONTINUE} * {@link #RESET_DERIVATIVES} or {@link #CONTINUE}
* @exception SwitchException if the event occurrence triggers an error
*/ */
public int eventOccurred(double t, double[] y); public int eventOccurred(double t, double[] y) throws SwitchException;
/** Reset the state prior to continue the integration. /** Reset the state prior to continue the integration.
@ -148,7 +146,8 @@ public interface SwitchingFunction extends Serializable {
* @param t current value of the independent <i>time</i> variable * @param t current value of the independent <i>time</i> variable
* @param y array containing the current value of the state vector * @param y array containing the current value of the state vector
* the new state should be put in the same array * the new state should be put in the same array
* @exception SwitchException if the state cannot be reseted
*/ */
public void resetState(double t, double[] y); public void resetState(double t, double[] y) throws SwitchException;
} }

View File

@ -17,15 +17,14 @@
package org.apache.commons.math.ode; package org.apache.commons.math.ode;
import org.apache.commons.math.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.commons.math.ConvergenceException;
/** This class handles several {@link SwitchingFunction switching /** This class handles several {@link SwitchingFunction switching
* functions} during integration. * functions} during integration.
* *
@ -147,8 +146,8 @@ public class SwitchingFunctionsHandler {
return first != null; return first != null;
} catch (FunctionEvaluationException fee) { } catch (SwitchException se) {
throw new IntegratorException(fee); throw new IntegratorException(se);
} catch (ConvergenceException ce) { } catch (ConvergenceException ce) {
throw new IntegratorException(ce); throw new IntegratorException(ce);
} }
@ -180,8 +179,8 @@ public class SwitchingFunctionsHandler {
for (Iterator iter = functions.iterator(); iter.hasNext();) { for (Iterator iter = functions.iterator(); iter.hasNext();) {
((SwitchState) iter.next()).stepAccepted(t, y); ((SwitchState) iter.next()).stepAccepted(t, y);
} }
} catch (FunctionEvaluationException fee) { } catch (SwitchException se) {
throw new IntegratorException(fee); throw new IntegratorException(se);
} }
} }
@ -204,15 +203,21 @@ public class SwitchingFunctionsHandler {
* @param y array were to put the desired state vector at the beginning * @param y array were to put the desired state vector at the beginning
* of the next step * of the next step
* @return true if the integrator should reset the derivatives too * @return true if the integrator should reset the derivatives too
* @exception IntegratorException if one of the switching functions
* that should reset the state fails to do it
*/ */
public boolean reset(double t, double[] y) { public boolean reset(double t, double[] y) throws IntegratorException {
boolean resetDerivatives = false; try {
for (Iterator iter = functions.iterator(); iter.hasNext();) { boolean resetDerivatives = false;
if (((SwitchState) iter.next()).reset(t, y)) { for (Iterator iter = functions.iterator(); iter.hasNext();) {
resetDerivatives = true; if (((SwitchState) iter.next()).reset(t, y)) {
resetDerivatives = true;
}
}
return resetDerivatives;
} catch (SwitchException se) {
throw new IntegratorException(se);
} }
}
return resetDerivatives;
} }
/** Switching functions. */ /** Switching functions. */

View File

@ -35,11 +35,16 @@ The <action> type attribute can be add,update,fix,remove.
<document> <document>
<properties> <properties>
<title> <title>Commons Math Release Notes</title>
Commons Math Release Notes</title>
</properties> </properties>
<body> <body>
<release version="2.0" date="TBD" description="TBD"> <release version="2.0" date="TBD" description="TBD">
<action dev="luc" type="add" >
Switching functions can now throw dedicated SwitchException from all their
method. At upper call level, the various ODE integrators handle these new
exceptions and wrap them into IntegratorException instances, hence the
integrators methods signature did not change.
</action>
<action dev="luc" type="add" issue="MATH-202"> <action dev="luc" type="add" issue="MATH-202">
Added the getSwitchingFunctions and clearSwitchingFunctions to the Added the getSwitchingFunctions and clearSwitchingFunctions to the
FirstOrderIntegrator interface and all its implementations FirstOrderIntegrator interface and all its implementations

View File

@ -17,17 +17,11 @@
package org.apache.commons.math.ode; package org.apache.commons.math.ode;
import org.apache.commons.math.ConvergenceException; import junit.framework.Test;
import org.apache.commons.math.FunctionEvaluationException; import junit.framework.TestCase;
import org.apache.commons.math.ode.DerivativeException; import junit.framework.TestSuite;
import org.apache.commons.math.ode.FirstOrderIntegrator;
import org.apache.commons.math.ode.HighamHall54Integrator;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.StepHandler;
import org.apache.commons.math.ode.StepInterpolator;
import org.apache.commons.math.ode.SwitchingFunction;
import junit.framework.*; import org.apache.commons.math.ConvergenceException;
public class HighamHall54IntegratorTest public class HighamHall54IntegratorTest
extends TestCase { extends TestCase {
@ -185,11 +179,12 @@ public class HighamHall54IntegratorTest
public int eventOccurred(double t, double[] y) { public int eventOccurred(double t, double[] y) {
return SwitchingFunction.CONTINUE; return SwitchingFunction.CONTINUE;
} }
public double g(double t, double[] y) throws FunctionEvaluationException { public double g(double t, double[] y) throws SwitchException {
double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2; double middle = (pb.getInitialTime() + pb.getFinalTime()) / 2;
double offset = t - middle; double offset = t - middle;
if (offset > 0) { if (offset > 0) {
throw new FunctionEvaluationException(t); throw new SwitchException("Evaluation failed for argument = {0}",
new Object[] { new Double(t) });
} }
return offset; return offset;
} }