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 }