blob: 1f9894316e092246cbe3c114f43bb7c9a002afdf [file] [log] [blame]
/*
* 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.ConvergenceException;
import org.apache.commons.math.FunctionEvaluationException;
import java.util.ArrayList;
import java.util.Iterator;
/** This class handles several {@link SwitchingFunction switching
* functions} during integration.
*
* @see SwitchingFunction
* @version $Revision$ $Date$
* @since 1.2
*/
public class SwitchingFunctionsHandler {
/** Simple constructor.
* Create an empty handler
*/
public SwitchingFunctionsHandler() {
functions = new ArrayList();
first = null;
initialized = false;
}
/** Add a switching function.
* @param function switching function
* @param maxCheckInterval maximal time interval between switching
* function checks (this interval prevents missing sign changes in
* case the integration steps becomes very large)
* @param convergence convergence threshold in the event time search
* @param maxIterationCount upper limit of the iteration count in
* the event time search
*/
public void add(SwitchingFunction function, double maxCheckInterval,
double convergence, int maxIterationCount) {
functions.add(new SwitchState(function, maxCheckInterval,
convergence, maxIterationCount));
}
/** Check if the handler does not have any condition.
* @return true if handler is empty
*/
public boolean isEmpty() {
return functions.isEmpty();
}
/** Evaluate the impact of the proposed step on all handled
* switching functions.
* @param interpolator step interpolator for the proposed step
* @return true if at least one switching function triggers an event
* before the end of the proposed step (this implies the step should
* be rejected)
* @exception DerivativeException if the interpolator fails to
* compute the function somewhere within the step
* @exception IntegratorException if an event cannot be located
*/
public boolean evaluateStep(StepInterpolator interpolator)
throws DerivativeException, IntegratorException {
try {
first = null;
if (functions.isEmpty()) {
// there is nothing to do, return now to avoid setting the
// interpolator time (and hence avoid unneeded calls to the
// user function due to interpolator finalization)
return false;
}
if (! initialized) {
// initialize the switching functions
double t0 = interpolator.getPreviousTime();
interpolator.setInterpolatedTime(t0);
double [] y = interpolator.getInterpolatedState();
for (Iterator iter = functions.iterator(); iter.hasNext();) {
((SwitchState) iter.next()).reinitializeBegin(t0, y);
}
initialized = true;
}
// check events occurrence
for (Iterator iter = functions.iterator(); iter.hasNext();) {
SwitchState state = (SwitchState) iter.next();
if (state.evaluateStep(interpolator)) {
if (first == null) {
first = state;
} else {
if (interpolator.isForward()) {
if (state.getEventTime() < first.getEventTime()) {
first = state;
}
} else {
if (state.getEventTime() > first.getEventTime()) {
first = state;
}
}
}
}
}
return first != null;
} catch (FunctionEvaluationException fee) {
throw new IntegratorException(fee);
} catch (ConvergenceException ce) {
throw new IntegratorException(ce);
}
}
/** Get the occurrence time of the first event triggered in the
* last evaluated step.
* @return occurrence time of the first event triggered in the last
* evaluated step, or </code>Double.NaN</code> if no event is
* triggered
*/
public double getEventTime() {
return (first == null) ? Double.NaN : first.getEventTime();
}
/** Inform the switching functions that the step has been accepted
* by the integrator.
* @param t value of the independent <i>time</i> variable at the
* end of the step
* @param y array containing the current value of the state vector
* at the end of the step
* @exception IntegratorException if the value of one of the
* switching functions cannot be evaluated
*/
public void stepAccepted(double t, double[] y)
throws IntegratorException {
try {
for (Iterator iter = functions.iterator(); iter.hasNext();) {
((SwitchState) iter.next()).stepAccepted(t, y);
}
} catch (FunctionEvaluationException fee) {
throw new IntegratorException(fee);
}
}
/** Check if the integration should be stopped at the end of the
* current step.
* @return true if the integration should be stopped
*/
public boolean stop() {
for (Iterator iter = functions.iterator(); iter.hasNext();) {
if (((SwitchState) iter.next()).stop()) {
return true;
}
}
return false;
}
/** Let the switching functions reset the state if they want.
* @param t value of the independent <i>time</i> variable at the
* beginning of the next step
* @param y array were to put the desired state vector at the beginning
* of the next step
* @return true if the integrator should reset the derivatives too
*/
public boolean reset(double t, double[] y) {
boolean resetDerivatives = false;
for (Iterator iter = functions.iterator(); iter.hasNext();) {
if (((SwitchState) iter.next()).reset(t, y)) {
resetDerivatives = true;
}
}
return resetDerivatives;
}
/** Switching functions. */
private ArrayList functions;
/** First active switching function. */
private SwitchState first;
/** Initialization indicator. */
private boolean initialized;
}