1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.math.ode; 19 20 import org.apache.commons.math.ConvergenceException; 21 import org.apache.commons.math.FunctionEvaluationException; 22 23 import java.util.ArrayList; 24 import java.util.Iterator; 25 26 /** This class handles several {@link SwitchingFunction switching 27 * functions} during integration. 28 * 29 * @see SwitchingFunction 30 * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $ 31 * @since 1.2 32 */ 33 34 public class SwitchingFunctionsHandler { 35 36 /** Simple constructor. 37 * Create an empty handler 38 */ 39 public SwitchingFunctionsHandler() { 40 functions = new ArrayList(); 41 first = null; 42 initialized = false; 43 } 44 45 /** Add a switching function. 46 * @param function switching function 47 * @param maxCheckInterval maximal time interval between switching 48 * function checks (this interval prevents missing sign changes in 49 * case the integration steps becomes very large) 50 * @param convergence convergence threshold in the event time search 51 * @param maxIterationCount upper limit of the iteration count in 52 * the event time search 53 */ 54 public void add(SwitchingFunction function, double maxCheckInterval, 55 double convergence, int maxIterationCount) { 56 functions.add(new SwitchState(function, maxCheckInterval, 57 convergence, maxIterationCount)); 58 } 59 60 /** Check if the handler does not have any condition. 61 * @return true if handler is empty 62 */ 63 public boolean isEmpty() { 64 return functions.isEmpty(); 65 } 66 67 /** Evaluate the impact of the proposed step on all handled 68 * switching functions. 69 * @param interpolator step interpolator for the proposed step 70 * @return true if at least one switching function triggers an event 71 * before the end of the proposed step (this implies the step should 72 * be rejected) 73 * @exception DerivativeException if the interpolator fails to 74 * compute the function somewhere within the step 75 * @exception IntegratorException if an event cannot be located 76 */ 77 public boolean evaluateStep(StepInterpolator interpolator) 78 throws DerivativeException, IntegratorException { 79 80 try { 81 82 first = null; 83 if (functions.isEmpty()) { 84 // there is nothing to do, return now to avoid setting the 85 // interpolator time (and hence avoid unneeded calls to the 86 // user function due to interpolator finalization) 87 return false; 88 } 89 90 if (! initialized) { 91 92 // initialize the switching functions 93 double t0 = interpolator.getPreviousTime(); 94 interpolator.setInterpolatedTime(t0); 95 double [] y = interpolator.getInterpolatedState(); 96 for (Iterator iter = functions.iterator(); iter.hasNext();) { 97 ((SwitchState) iter.next()).reinitializeBegin(t0, y); 98 } 99 100 initialized = true; 101 102 } 103 104 // check events occurrence 105 for (Iterator iter = functions.iterator(); iter.hasNext();) { 106 107 SwitchState state = (SwitchState) iter.next(); 108 if (state.evaluateStep(interpolator)) { 109 if (first == null) { 110 first = state; 111 } else { 112 if (interpolator.isForward()) { 113 if (state.getEventTime() < first.getEventTime()) { 114 first = state; 115 } 116 } else { 117 if (state.getEventTime() > first.getEventTime()) { 118 first = state; 119 } 120 } 121 } 122 } 123 124 } 125 126 return first != null; 127 128 } catch (FunctionEvaluationException fee) { 129 throw new IntegratorException(fee); 130 } catch (ConvergenceException ce) { 131 throw new IntegratorException(ce); 132 } 133 134 } 135 136 /** Get the occurrence time of the first event triggered in the 137 * last evaluated step. 138 * @return occurrence time of the first event triggered in the last 139 * evaluated step, or </code>Double.NaN</code> if no event is 140 * triggered 141 */ 142 public double getEventTime() { 143 return (first == null) ? Double.NaN : first.getEventTime(); 144 } 145 146 /** Inform the switching functions that the step has been accepted 147 * by the integrator. 148 * @param t value of the independent <i>time</i> variable at the 149 * end of the step 150 * @param y array containing the current value of the state vector 151 * at the end of the step 152 * @exception IntegratorException if the value of one of the 153 * switching functions cannot be evaluated 154 */ 155 public void stepAccepted(double t, double[] y) 156 throws IntegratorException { 157 try { 158 for (Iterator iter = functions.iterator(); iter.hasNext();) { 159 ((SwitchState) iter.next()).stepAccepted(t, y); 160 } 161 } catch (FunctionEvaluationException fee) { 162 throw new IntegratorException(fee); 163 } 164 } 165 166 /** Check if the integration should be stopped at the end of the 167 * current step. 168 * @return true if the integration should be stopped 169 */ 170 public boolean stop() { 171 for (Iterator iter = functions.iterator(); iter.hasNext();) { 172 if (((SwitchState) iter.next()).stop()) { 173 return true; 174 } 175 } 176 return false; 177 } 178 179 /** Let the switching functions reset the state if they want. 180 * @param t value of the independent <i>time</i> variable at the 181 * beginning of the next step 182 * @param y array were to put the desired state vector at the beginning 183 * of the next step 184 * @return true if the integrator should reset the derivatives too 185 */ 186 public boolean reset(double t, double[] y) { 187 boolean resetDerivatives = false; 188 for (Iterator iter = functions.iterator(); iter.hasNext();) { 189 if (((SwitchState) iter.next()).reset(t, y)) { 190 resetDerivatives = true; 191 } 192 } 193 return resetDerivatives; 194 } 195 196 /** Switching functions. */ 197 private ArrayList functions; 198 199 /** First active switching function. */ 200 private SwitchState first; 201 202 /** Initialization indicator. */ 203 private boolean initialized; 204 205 }