summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java')
-rw-r--r--src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java b/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
new file mode 100644
index 0000000..c17f436
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
@@ -0,0 +1,440 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.MaxEvaluationsExceededException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.ode.events.CombinedEventsManager;
+import org.apache.commons.math.ode.events.EventException;
+import org.apache.commons.math.ode.events.EventHandler;
+import org.apache.commons.math.ode.events.EventState;
+import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
+import org.apache.commons.math.ode.sampling.StepHandler;
+import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Base class managing common boilerplate for all integrators.
+ * @version $Revision: 1073267 $ $Date: 2011-02-22 10:06:20 +0100 (mar. 22 févr. 2011) $
+ * @since 2.0
+ */
+public abstract class AbstractIntegrator implements FirstOrderIntegrator {
+
+ /** Step handler. */
+ protected Collection<StepHandler> stepHandlers;
+
+ /** Current step start time. */
+ protected double stepStart;
+
+ /** Current stepsize. */
+ protected double stepSize;
+
+ /** Indicator for last step. */
+ protected boolean isLastStep;
+
+ /** Indicator that a state or derivative reset was triggered by some event. */
+ protected boolean resetOccurred;
+
+ /** Events states. */
+ private Collection<EventState> eventsStates;
+
+ /** Initialization indicator of events states. */
+ private boolean statesInitialized;
+
+ /** Name of the method. */
+ private final String name;
+
+ /** Maximal number of evaluations allowed. */
+ private int maxEvaluations;
+
+ /** Number of evaluations already performed. */
+ private int evaluations;
+
+ /** Differential equations to integrate. */
+ private transient FirstOrderDifferentialEquations equations;
+
+ /** Build an instance.
+ * @param name name of the method
+ */
+ public AbstractIntegrator(final String name) {
+ this.name = name;
+ stepHandlers = new ArrayList<StepHandler>();
+ stepStart = Double.NaN;
+ stepSize = Double.NaN;
+ eventsStates = new ArrayList<EventState>();
+ statesInitialized = false;
+ setMaxEvaluations(-1);
+ resetEvaluations();
+ }
+
+ /** Build an instance with a null name.
+ */
+ protected AbstractIntegrator() {
+ this(null);
+ }
+
+ /** {@inheritDoc} */
+ public String getName() {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ public void addStepHandler(final StepHandler handler) {
+ stepHandlers.add(handler);
+ }
+
+ /** {@inheritDoc} */
+ public Collection<StepHandler> getStepHandlers() {
+ return Collections.unmodifiableCollection(stepHandlers);
+ }
+
+ /** {@inheritDoc} */
+ public void clearStepHandlers() {
+ stepHandlers.clear();
+ }
+
+ /** {@inheritDoc} */
+ public void addEventHandler(final EventHandler handler,
+ final double maxCheckInterval,
+ final double convergence,
+ final int maxIterationCount) {
+ eventsStates.add(new EventState(handler, maxCheckInterval, convergence, maxIterationCount));
+ }
+
+ /** {@inheritDoc} */
+ public Collection<EventHandler> getEventHandlers() {
+ final List<EventHandler> list = new ArrayList<EventHandler>();
+ for (EventState state : eventsStates) {
+ list.add(state.getEventHandler());
+ }
+ return Collections.unmodifiableCollection(list);
+ }
+
+ /** {@inheritDoc} */
+ public void clearEventHandlers() {
+ 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;
+ }
+
+ /** {@inheritDoc} */
+ public double getCurrentSignedStepsize() {
+ return stepSize;
+ }
+
+ /** {@inheritDoc} */
+ public void setMaxEvaluations(int maxEvaluations) {
+ this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations;
+ }
+
+ /** {@inheritDoc} */
+ public int getMaxEvaluations() {
+ return maxEvaluations;
+ }
+
+ /** {@inheritDoc} */
+ public int getEvaluations() {
+ return evaluations;
+ }
+
+ /** Reset the number of evaluations to zero.
+ */
+ protected void resetEvaluations() {
+ evaluations = 0;
+ }
+
+ /** Set the differential equations.
+ * @param equations differential equations to integrate
+ * @see #computeDerivatives(double, double[], double[])
+ */
+ protected void setEquations(final FirstOrderDifferentialEquations equations) {
+ this.equations = equations;
+ }
+
+ /** Compute the derivatives and check the number of evaluations.
+ * @param t current value of the independent <I>time</I> variable
+ * @param y array containing the current value of the state vector
+ * @param yDot placeholder array where to put the time derivative of the state vector
+ * @throws DerivativeException this user-defined exception should be used if an error is
+ * is triggered by user code
+ */
+ public void computeDerivatives(final double t, final double[] y, final double[] yDot)
+ throws DerivativeException {
+ if (++evaluations > maxEvaluations) {
+ throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
+ }
+ equations.computeDerivatives(t, y, yDot);
+ }
+
+ /** Set the stateInitialized flag.
+ * <p>This method must be called by integrators with the value
+ * {@code false} before they start integration, so a proper lazy
+ * initialization is done automatically on the first step.</p>
+ * @param stateInitialized new value for the flag
+ * @since 2.2
+ */
+ protected void setStateInitialized(final boolean stateInitialized) {
+ this.statesInitialized = stateInitialized;
+ }
+
+ /** Accept a step, triggering events and step handlers.
+ * @param interpolator step interpolator
+ * @param y state vector at step end time, must be reset if an event
+ * asks for resetting or if an events stops integration during the step
+ * @param yDot placeholder array where to put the time derivative of the state vector
+ * @param tEnd final integration time
+ * @return time at end of step
+ * @throws DerivativeException this exception is propagated to the caller if
+ * the underlying user function triggers one
+ * @exception IntegratorException if the value of one event state cannot be evaluated
+ * @since 2.2
+ */
+ protected double acceptStep(final AbstractStepInterpolator interpolator,
+ final double[] y, final double[] yDot, final double tEnd)
+ throws DerivativeException, IntegratorException {
+
+ try {
+ double previousT = interpolator.getGlobalPreviousTime();
+ final double currentT = interpolator.getGlobalCurrentTime();
+ resetOccurred = false;
+
+ // initialize the events states if needed
+ if (! statesInitialized) {
+ for (EventState state : eventsStates) {
+ state.reinitializeBegin(interpolator);
+ }
+ statesInitialized = true;
+ }
+
+ // search for next events that may occur during the step
+ final int orderingSign = interpolator.isForward() ? +1 : -1;
+ SortedSet<EventState> occuringEvents = new TreeSet<EventState>(new Comparator<EventState>() {
+
+ /** {@inheritDoc} */
+ public int compare(EventState es0, EventState es1) {
+ return orderingSign * Double.compare(es0.getEventTime(), es1.getEventTime());
+ }
+
+ });
+
+ for (final EventState state : eventsStates) {
+ if (state.evaluateStep(interpolator)) {
+ // the event occurs during the current step
+ occuringEvents.add(state);
+ }
+ }
+
+ while (!occuringEvents.isEmpty()) {
+
+ // handle the chronologically first event
+ final Iterator<EventState> iterator = occuringEvents.iterator();
+ final EventState currentEvent = iterator.next();
+ iterator.remove();
+
+ // restrict the interpolator to the first part of the step, up to the event
+ final double eventT = currentEvent.getEventTime();
+ interpolator.setSoftPreviousTime(previousT);
+ interpolator.setSoftCurrentTime(eventT);
+
+ // trigger the event
+ interpolator.setInterpolatedTime(eventT);
+ final double[] eventY = interpolator.getInterpolatedState();
+ currentEvent.stepAccepted(eventT, eventY);
+ isLastStep = currentEvent.stop();
+
+ // handle the first part of the step, up to the event
+ for (final StepHandler handler : stepHandlers) {
+ handler.handleStep(interpolator, isLastStep);
+ }
+
+ if (isLastStep) {
+ // the event asked to stop integration
+ System.arraycopy(eventY, 0, y, 0, y.length);
+ return eventT;
+ }
+
+ if (currentEvent.reset(eventT, eventY)) {
+ // 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;
+ return eventT;
+ }
+
+ // prepare handling of the remaining part of the step
+ previousT = eventT;
+ interpolator.setSoftPreviousTime(eventT);
+ interpolator.setSoftCurrentTime(currentT);
+
+ // check if the same event occurs again in the remaining part of the step
+ if (currentEvent.evaluateStep(interpolator)) {
+ // the event occurs during the current step
+ occuringEvents.add(currentEvent);
+ }
+
+ }
+
+ interpolator.setInterpolatedTime(currentT);
+ final double[] currentY = interpolator.getInterpolatedState();
+ for (final EventState state : eventsStates) {
+ state.stepAccepted(currentT, currentY);
+ isLastStep = isLastStep || state.stop();
+ }
+ isLastStep = isLastStep || MathUtils.equals(currentT, tEnd, 1);
+
+ // handle the remaining part of the step, after all events if any
+ for (StepHandler handler : stepHandlers) {
+ handler.handleStep(interpolator, isLastStep);
+ }
+
+ return currentT;
+ } catch (EventException se) {
+ final Throwable cause = se.getCause();
+ if ((cause != null) && (cause instanceof DerivativeException)) {
+ throw (DerivativeException) cause;
+ }
+ throw new IntegratorException(se);
+ } catch (ConvergenceException ce) {
+ throw new IntegratorException(ce);
+ }
+
+ }
+
+ /** Perform some sanity checks on the integration parameters.
+ * @param ode differential equations set
+ * @param t0 start time
+ * @param y0 state vector at t0
+ * @param t target time for the integration
+ * @param y placeholder where to put the state vector
+ * @exception IntegratorException if some inconsistency is detected
+ */
+ protected void sanityChecks(final FirstOrderDifferentialEquations ode,
+ final double t0, final double[] y0,
+ final double t, final double[] y)
+ throws IntegratorException {
+
+ if (ode.getDimension() != y0.length) {
+ throw new IntegratorException(
+ LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, ode.getDimension(), y0.length);
+ }
+
+ if (ode.getDimension() != y.length) {
+ throw new IntegratorException(
+ LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, ode.getDimension(), y.length);
+ }
+
+ if (FastMath.abs(t - t0) <= 1.0e-12 * FastMath.max(FastMath.abs(t0), FastMath.abs(t))) {
+ throw new IntegratorException(
+ LocalizedFormats.TOO_SMALL_INTEGRATION_INTERVAL,
+ FastMath.abs(t - t0));
+ }
+
+ }
+
+ /** Add an event handler for end time checking.
+ * <p>This method can be used to simplify handling of integration end time.
+ * It leverages the nominal stop condition with the exceptional stop
+ * conditions.</p>
+ * @param startTime integration start time
+ * @param endTime desired end time
+ * @param manager manager containing the user-defined handlers
+ * @return a new manager containing all the user-defined handlers plus a
+ * dedicated manager triggering a stop event at entTime
+ * @deprecated as of 2.2, this method is not used any more
+ */
+ @Deprecated
+ protected CombinedEventsManager addEndTimeChecker(final double startTime,
+ final double endTime,
+ final CombinedEventsManager manager) {
+ CombinedEventsManager newManager = new CombinedEventsManager();
+ for (final EventState state : manager.getEventsStates()) {
+ newManager.addEventHandler(state.getEventHandler(),
+ state.getMaxCheckInterval(),
+ state.getConvergence(),
+ state.getMaxIterationCount());
+ }
+ newManager.addEventHandler(new EndTimeChecker(endTime),
+ Double.POSITIVE_INFINITY,
+ FastMath.ulp(FastMath.max(FastMath.abs(startTime), FastMath.abs(endTime))),
+ 100);
+ return newManager;
+ }
+
+ /** Specialized event handler to stop integration.
+ * @deprecated as of 2.2, this class is not used anymore
+ */
+ @Deprecated
+ private static class EndTimeChecker implements EventHandler {
+
+ /** Desired end time. */
+ private final double endTime;
+
+ /** Build an instance.
+ * @param endTime desired time
+ */
+ public EndTimeChecker(final double endTime) {
+ this.endTime = endTime;
+ }
+
+ /** {@inheritDoc} */
+ public int eventOccurred(double t, double[] y, boolean increasing) {
+ return STOP;
+ }
+
+ /** {@inheritDoc} */
+ public double g(double t, double[] y) {
+ return t - endTime;
+ }
+
+ /** {@inheritDoc} */
+ public void resetState(double t, double[] y) {
+ }
+
+ }
+
+}