package org.spaceroots.mantissa.ode;

import org.spaceroots.mantissa.ode.DerivativeException;

import java.util.ArrayList;
import java.util.Iterator;

/** This class handles several {@link SwitchingFunction switching
 * functions} during integration.
 *
 * @see SwitchingFunction
 *
 * @version $Id: SwitchingFunctionsHandler.java 1707 2006-11-19 20:08:32Z luc $
 * @author L. Maisonobe
 *
 */

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
   */
  public void add(SwitchingFunction function,
                  double maxCheckInterval, double convergence) {
    functions.add(new SwitchState(function, maxCheckInterval, convergence));
  }

  /** 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)
   */
  public boolean evaluateStep(StepInterpolator interpolator) {

    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 (DerivativeException e) {
      throw new RuntimeException("unexpected exception", e);
    }

  }

  /** 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 Double.NaN 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 independant time variable at the
   * end of the step
   * @param y array containing the current value of the state vector
   * at the end of the step
   */
  public void stepAccepted(double t, double[] y) {
    for (Iterator iter = functions.iterator(); iter.hasNext();) {
      ((SwitchState) iter.next()).stepAccepted(t, y);
    }
  }

  /** 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 independant time 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;

}

 

Ads help maintain this website.