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;
19  
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  
24  import org.apache.commons.math.MaxEvaluationsExceededException;
25  import org.apache.commons.math.ode.events.CombinedEventsManager;
26  import org.apache.commons.math.ode.events.EventHandler;
27  import org.apache.commons.math.ode.events.EventState;
28  import org.apache.commons.math.ode.sampling.StepHandler;
29  
30  /**
31   * Base class managing common boilerplate for all integrators.
32   * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
33   * @since 2.0
34   */
35  public abstract class AbstractIntegrator implements FirstOrderIntegrator {
36  
37      
38      /** Name of the method. */
39      private final String name;
40  
41      /** Maximal number of evaluations allowed. */
42      private int maxEvaluations;
43  
44      /** Number of evaluations already performed. */
45      private int evaluations;
46  
47      /** Differential equations to integrate. */
48      private transient FirstOrderDifferentialEquations equations;
49  
50      /** Step handler. */
51      protected Collection<StepHandler> stepHandlers;
52  
53      /** Current step start time. */
54      protected double stepStart;
55  
56      /** Current stepsize. */
57      protected double stepSize;
58  
59      /** Events handlers manager. */
60      protected CombinedEventsManager eventsHandlersManager;
61  
62      /** Build an instance.
63       * @param name name of the method
64       */
65      public AbstractIntegrator(final String name) {
66          this.name = name;
67          stepHandlers = new ArrayList<StepHandler>();
68          stepStart = Double.NaN;
69          stepSize  = Double.NaN;
70          eventsHandlersManager = new CombinedEventsManager();
71          setMaxEvaluations(-1);
72          resetEvaluations();
73      }
74  
75      /** Build an instance with a null name.
76       */
77      protected AbstractIntegrator() {
78          this(null);
79      }
80      
81      /** {@inheritDoc} */
82      public String getName() {
83          return name;
84      }
85  
86      /** {@inheritDoc} */
87      public void addStepHandler(final StepHandler handler) {
88          stepHandlers.add(handler);
89      }
90  
91      /** {@inheritDoc} */
92      public Collection<StepHandler> getStepHandlers() {
93          return Collections.unmodifiableCollection(stepHandlers);
94      }
95  
96      /** {@inheritDoc} */
97      public void clearStepHandlers() {
98          stepHandlers.clear();
99      }
100 
101     /** {@inheritDoc} */
102     public void addEventHandler(final EventHandler function,
103                                 final double maxCheckInterval,
104                                 final double convergence,
105                                 final int maxIterationCount) {
106         eventsHandlersManager.addEventHandler(function, maxCheckInterval,
107                                               convergence, maxIterationCount);
108     }
109 
110     /** {@inheritDoc} */
111     public Collection<EventHandler> getEventHandlers() {
112         return eventsHandlersManager.getEventsHandlers();
113     }
114 
115     /** {@inheritDoc} */
116     public void clearEventHandlers() {
117         eventsHandlersManager.clearEventsHandlers();
118     }
119 
120     /** Check if one of the step handlers requires dense output.
121      * @return true if one of the step handlers requires dense output
122      */
123     protected boolean requiresDenseOutput() {
124         for (StepHandler handler : stepHandlers) {
125             if (handler.requiresDenseOutput()) {
126                 return true;
127             }
128         }
129         return false;
130     }
131 
132     /** {@inheritDoc} */
133     public double getCurrentStepStart() {
134         return stepStart;
135     }
136 
137     /** {@inheritDoc} */
138     public double getCurrentSignedStepsize() {
139         return stepSize;
140     }
141 
142     /** {@inheritDoc} */
143     public void setMaxEvaluations(int maxEvaluations) {
144         this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations;
145     }
146 
147     /** {@inheritDoc} */
148     public int getMaxEvaluations() {
149         return maxEvaluations;
150     }
151 
152     /** {@inheritDoc} */
153     public int getEvaluations() {
154         return evaluations;
155     }
156 
157     /** Reset the number of evaluations to zero.
158      */
159     protected void resetEvaluations() {
160         evaluations = 0;
161     }
162 
163     /** Set the differential equations.
164      * @param equations differential equations to integrate
165      * @see #computeDerivatives(double, double[], double[])
166      */
167     protected void setEquations(final FirstOrderDifferentialEquations equations) {
168         this.equations = equations;
169     }
170 
171     /** Compute the derivatives and check the number of evaluations.
172      * @param t current value of the independent <I>time</I> variable
173      * @param y array containing the current value of the state vector
174      * @param yDot placeholder array where to put the time derivative of the state vector
175      * @throws DerivativeException this exception is propagated to the caller if the
176      * underlying user function triggers one
177      */
178     public void computeDerivatives(final double t, final double[] y, final double[] yDot)
179         throws DerivativeException {
180         if (++evaluations > maxEvaluations) {
181             throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
182         }
183         equations.computeDerivatives(t, y, yDot);
184     }
185 
186     /** Perform some sanity checks on the integration parameters.
187      * @param equations differential equations set
188      * @param t0 start time
189      * @param y0 state vector at t0
190      * @param t target time for the integration
191      * @param y placeholder where to put the state vector
192      * @exception IntegratorException if some inconsistency is detected
193      */
194     protected void sanityChecks(final FirstOrderDifferentialEquations equations,
195                                 final double t0, final double[] y0,
196                                 final double t, final double[] y)
197         throws IntegratorException {
198 
199         if (equations.getDimension() != y0.length) {
200             throw new IntegratorException(
201                     "dimensions mismatch: ODE problem has dimension {0}," +
202                     " initial state vector has dimension {1}",
203                     equations.getDimension(), y0.length);
204         }
205 
206         if (equations.getDimension() != y.length) {
207             throw new IntegratorException(
208                     "dimensions mismatch: ODE problem has dimension {0}," +
209                     " final state vector has dimension {1}",
210                     equations.getDimension(), y.length);
211         }
212 
213         if (Math.abs(t - t0) <= 1.0e-12 * Math.max(Math.abs(t0), Math.abs(t))) {
214             throw new IntegratorException(
215                     "too small integration interval: length = {0}",
216                     Math.abs(t - t0));
217         }
218 
219     }
220 
221     /** Add an event handler for end time checking.
222      * <p>This method can be used to simplify handling of integration end time.
223      * It leverages the nominal stop condition with the exceptional stop
224      * conditions.</p>
225      * @param startTime integration start time
226      * @param endTime desired end time
227      * @param manager manager containing the user-defined handlers
228      * @return a new manager containing all the user-defined handlers plus a
229      * dedicated manager triggering a stop event at entTime
230      */
231     protected CombinedEventsManager addEndTimeChecker(final double startTime,
232                                                       final double endTime,
233                                                       final CombinedEventsManager manager) {
234         CombinedEventsManager newManager = new CombinedEventsManager();
235         for (final EventState state : manager.getEventsStates()) {
236             newManager.addEventHandler(state.getEventHandler(),
237                                        state.getMaxCheckInterval(),
238                                        state.getConvergence(),
239                                        state.getMaxIterationCount());
240         }
241         newManager.addEventHandler(new EndTimeChecker(endTime),
242                                    Double.POSITIVE_INFINITY,
243                                    Math.ulp(Math.max(Math.abs(startTime), Math.abs(endTime))),
244                                    100);
245         return newManager;
246     }
247 
248     /** Specialized event handler to stop integration. */
249     private static class EndTimeChecker implements EventHandler {
250 
251         /** Desired end time. */
252         private final double endTime;
253 
254         /** Build an instance.
255          * @param endTime desired time
256          */
257         public EndTimeChecker(final double endTime) {
258             this.endTime = endTime;
259         }
260 
261         /** {@inheritDoc} */
262         public int eventOccurred(double t, double[] y, boolean increasing) {
263             return STOP;
264         }
265 
266         /** {@inheritDoc} */
267         public double g(double t, double[] y) {
268             return t - endTime;
269         }
270 
271         /** {@inheritDoc} */
272         public void resetState(double t, double[] y) {
273         }
274         
275     }
276 
277 }