View Javadoc

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.events;
19  
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.List;
24  
25  import org.apache.commons.math.ConvergenceException;
26  import org.apache.commons.math.ode.DerivativeException;
27  import org.apache.commons.math.ode.IntegratorException;
28  import org.apache.commons.math.ode.sampling.StepInterpolator;
29  
30  /** This class manages several {@link EventHandler event handlers} during integration.
31   *
32   * @see EventHandler
33   * @see EventState
34   * @version $Revision: 786881 $ $Date: 2009-06-20 14:53:08 -0400 (Sat, 20 Jun 2009) $
35   * @since 1.2
36   */
37  
38  public class CombinedEventsManager {
39  
40      /** Events states. */
41      private final List<EventState> states;
42  
43      /** First active event. */
44      private EventState first;
45  
46      /** Initialization indicator. */
47      private boolean initialized;
48  
49      /** Simple constructor.
50       * Create an empty manager
51       */
52      public CombinedEventsManager() {
53          states      = new ArrayList<EventState>();
54          first       = null;
55          initialized = false;
56      }
57  
58      /** Add an events handler.
59       * @param handler event handler
60       * @param maxCheckInterval maximal time interval between events
61       * checks (this interval prevents missing sign changes in
62       * case the integration steps becomes very large)
63       * @param convergence convergence threshold in the event time search
64       * @param maxIterationCount upper limit of the iteration count in
65       * the event time search
66       * @see #getEventsHandlers()
67       * @see #clearEventsHandlers()
68       */
69      public void addEventHandler(final EventHandler handler, final double maxCheckInterval,
70                                  final double convergence, final int maxIterationCount) {
71          states.add(new EventState(handler, maxCheckInterval,
72                                    convergence, maxIterationCount));
73      }
74  
75      /** Get all the events handlers that have been added to the manager.
76       * @return an unmodifiable collection of the added event handlers
77       * @see #addEventHandler(EventHandler, double, double, int)
78       * @see #clearEventsHandlers()
79       * @see #getEventsStates()
80       */
81      public Collection<EventHandler> getEventsHandlers() {
82          final List<EventHandler> list = new ArrayList<EventHandler>();
83          for (EventState state : states) {
84              list.add(state.getEventHandler());
85          }
86          return Collections.unmodifiableCollection(list);
87      }
88  
89      /** Remove all the events handlers that have been added to the manager.
90       * @see #addEventHandler(EventHandler, double, double, int)
91       * @see #getEventsHandlers()
92       */
93      public void clearEventsHandlers() {
94          states.clear();
95      }
96  
97      /** Get all the events state wrapping the handlers that have been added to the manager.
98       * @return a collection of the events states
99       * @see #getEventsHandlers()
100      */
101     public Collection<EventState> getEventsStates() {
102         return states;
103     }
104 
105     /** Check if the manager does not manage any event handlers.
106      * @return true if manager is empty
107      */
108     public boolean isEmpty() {
109         return states.isEmpty();
110     }
111 
112     /** Evaluate the impact of the proposed step on all managed
113      * event handlers.
114      * @param interpolator step interpolator for the proposed step
115      * @return true if at least one event handler triggers an event
116      * before the end of the proposed step (this implies the step should
117      * be rejected)
118      * @exception DerivativeException if the interpolator fails to
119      * compute the function somewhere within the step
120      * @exception IntegratorException if an event cannot be located
121      */
122     public boolean evaluateStep(final StepInterpolator interpolator)
123     throws DerivativeException, IntegratorException {
124 
125         try {
126 
127             first = null;
128             if (states.isEmpty()) {
129                 // there is nothing to do, return now to avoid setting the
130                 // interpolator time (and hence avoid unneeded calls to the
131                 // user function due to interpolator finalization)
132                 return false;
133             }
134 
135             if (! initialized) {
136 
137                 // initialize the events states
138                 final double t0 = interpolator.getPreviousTime();
139                 interpolator.setInterpolatedTime(t0);
140                 final double [] y = interpolator.getInterpolatedState();
141                 for (EventState state : states) {
142                     state.reinitializeBegin(t0, y);
143                 }
144 
145                 initialized = true;
146 
147             }
148 
149             // check events occurrence
150             for (EventState state : states) {
151 
152                 if (state.evaluateStep(interpolator)) {
153                     if (first == null) {
154                         first = state;
155                     } else {
156                         if (interpolator.isForward()) {
157                             if (state.getEventTime() < first.getEventTime()) {
158                                 first = state;
159                             }
160                         } else {
161                             if (state.getEventTime() > first.getEventTime()) {
162                                 first = state;
163                             }
164                         }
165                     }
166                 }
167 
168             }
169 
170             return first != null;
171 
172         } catch (EventException se) {
173             throw new IntegratorException(se);
174         } catch (ConvergenceException ce) {
175             throw new IntegratorException(ce);
176         }
177 
178     }
179 
180     /** Get the occurrence time of the first event triggered in the
181      * last evaluated step.
182      * @return occurrence time of the first event triggered in the last
183      * evaluated step, or </code>Double.NaN</code> if no event is
184      * triggered
185      */
186     public double getEventTime() {
187         return (first == null) ? Double.NaN : first.getEventTime();
188     }
189 
190     /** Inform the event handlers that the step has been accepted
191      * by the integrator.
192      * @param t value of the independent <i>time</i> variable at the
193      * end of the step
194      * @param y array containing the current value of the state vector
195      * at the end of the step
196      * @exception IntegratorException if the value of one of the
197      * events states cannot be evaluated
198      */
199     public void stepAccepted(final double t, final double[] y)
200     throws IntegratorException {
201         try {
202             for (EventState state : states) {
203                 state.stepAccepted(t, y);
204             }
205         } catch (EventException se) {
206             throw new IntegratorException(se);
207         }
208     }
209 
210     /** Check if the integration should be stopped at the end of the
211      * current step.
212      * @return true if the integration should be stopped
213      */
214     public boolean stop() {
215         for (EventState state : states) {
216             if (state.stop()) {
217                 return true;
218             }
219         }
220         return false;
221     }
222 
223     /** Let the event handlers reset the state if they want.
224      * @param t value of the independent <i>time</i> variable at the
225      * beginning of the next step
226      * @param y array were to put the desired state vector at the beginning
227      * of the next step
228      * @return true if the integrator should reset the derivatives too
229      * @exception IntegratorException if one of the events states
230      * that should reset the state fails to do it
231      */
232     public boolean reset(final double t, final double[] y)
233         throws IntegratorException {
234         try {
235             boolean resetDerivatives = false;
236             for (EventState state : states) {
237                 if (state.reset(t, y)) {
238                     resetDerivatives = true;
239                 }
240             }
241             return resetDerivatives;
242         } catch (EventException se) {
243             throw new IntegratorException(se);
244         }
245     }
246 
247 }