001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math.ode;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.Collections;
023
024 import org.apache.commons.math.MaxEvaluationsExceededException;
025 import org.apache.commons.math.ode.events.CombinedEventsManager;
026 import org.apache.commons.math.ode.events.EventHandler;
027 import org.apache.commons.math.ode.events.EventState;
028 import org.apache.commons.math.ode.sampling.StepHandler;
029
030 /**
031 * Base class managing common boilerplate for all integrators.
032 * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
033 * @since 2.0
034 */
035 public abstract class AbstractIntegrator implements FirstOrderIntegrator {
036
037
038 /** Name of the method. */
039 private final String name;
040
041 /** Maximal number of evaluations allowed. */
042 private int maxEvaluations;
043
044 /** Number of evaluations already performed. */
045 private int evaluations;
046
047 /** Differential equations to integrate. */
048 private transient FirstOrderDifferentialEquations equations;
049
050 /** Step handler. */
051 protected Collection<StepHandler> stepHandlers;
052
053 /** Current step start time. */
054 protected double stepStart;
055
056 /** Current stepsize. */
057 protected double stepSize;
058
059 /** Events handlers manager. */
060 protected CombinedEventsManager eventsHandlersManager;
061
062 /** Build an instance.
063 * @param name name of the method
064 */
065 public AbstractIntegrator(final String name) {
066 this.name = name;
067 stepHandlers = new ArrayList<StepHandler>();
068 stepStart = Double.NaN;
069 stepSize = Double.NaN;
070 eventsHandlersManager = new CombinedEventsManager();
071 setMaxEvaluations(-1);
072 resetEvaluations();
073 }
074
075 /** Build an instance with a null name.
076 */
077 protected AbstractIntegrator() {
078 this(null);
079 }
080
081 /** {@inheritDoc} */
082 public String getName() {
083 return name;
084 }
085
086 /** {@inheritDoc} */
087 public void addStepHandler(final StepHandler handler) {
088 stepHandlers.add(handler);
089 }
090
091 /** {@inheritDoc} */
092 public Collection<StepHandler> getStepHandlers() {
093 return Collections.unmodifiableCollection(stepHandlers);
094 }
095
096 /** {@inheritDoc} */
097 public void clearStepHandlers() {
098 stepHandlers.clear();
099 }
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 }