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: 811827 $ $Date: 2009-09-06 11:32:50 -0400 (Sun, 06 Sep 2009) $
033 * @since 2.0
034 */
035 public abstract class AbstractIntegrator implements FirstOrderIntegrator {
036
037 /** Step handler. */
038 protected Collection<StepHandler> stepHandlers;
039
040 /** Current step start time. */
041 protected double stepStart;
042
043 /** Current stepsize. */
044 protected double stepSize;
045
046 /** Events handlers manager. */
047 protected CombinedEventsManager eventsHandlersManager;
048
049 /** Name of the method. */
050 private final String name;
051
052 /** Maximal number of evaluations allowed. */
053 private int maxEvaluations;
054
055 /** Number of evaluations already performed. */
056 private int evaluations;
057
058 /** Differential equations to integrate. */
059 private transient FirstOrderDifferentialEquations equations;
060
061 /** Build an instance.
062 * @param name name of the method
063 */
064 public AbstractIntegrator(final String name) {
065 this.name = name;
066 stepHandlers = new ArrayList<StepHandler>();
067 stepStart = Double.NaN;
068 stepSize = Double.NaN;
069 eventsHandlersManager = new CombinedEventsManager();
070 setMaxEvaluations(-1);
071 resetEvaluations();
072 }
073
074 /** Build an instance with a null name.
075 */
076 protected AbstractIntegrator() {
077 this(null);
078 }
079
080 /** {@inheritDoc} */
081 public String getName() {
082 return name;
083 }
084
085 /** {@inheritDoc} */
086 public void addStepHandler(final StepHandler handler) {
087 stepHandlers.add(handler);
088 }
089
090 /** {@inheritDoc} */
091 public Collection<StepHandler> getStepHandlers() {
092 return Collections.unmodifiableCollection(stepHandlers);
093 }
094
095 /** {@inheritDoc} */
096 public void clearStepHandlers() {
097 stepHandlers.clear();
098 }
099
100 /** {@inheritDoc} */
101 public void addEventHandler(final EventHandler function,
102 final double maxCheckInterval,
103 final double convergence,
104 final int maxIterationCount) {
105 eventsHandlersManager.addEventHandler(function, maxCheckInterval,
106 convergence, maxIterationCount);
107 }
108
109 /** {@inheritDoc} */
110 public Collection<EventHandler> getEventHandlers() {
111 return eventsHandlersManager.getEventsHandlers();
112 }
113
114 /** {@inheritDoc} */
115 public void clearEventHandlers() {
116 eventsHandlersManager.clearEventsHandlers();
117 }
118
119 /** Check if one of the step handlers requires dense output.
120 * @return true if one of the step handlers requires dense output
121 */
122 protected boolean requiresDenseOutput() {
123 for (StepHandler handler : stepHandlers) {
124 if (handler.requiresDenseOutput()) {
125 return true;
126 }
127 }
128 return false;
129 }
130
131 /** {@inheritDoc} */
132 public double getCurrentStepStart() {
133 return stepStart;
134 }
135
136 /** {@inheritDoc} */
137 public double getCurrentSignedStepsize() {
138 return stepSize;
139 }
140
141 /** {@inheritDoc} */
142 public void setMaxEvaluations(int maxEvaluations) {
143 this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations;
144 }
145
146 /** {@inheritDoc} */
147 public int getMaxEvaluations() {
148 return maxEvaluations;
149 }
150
151 /** {@inheritDoc} */
152 public int getEvaluations() {
153 return evaluations;
154 }
155
156 /** Reset the number of evaluations to zero.
157 */
158 protected void resetEvaluations() {
159 evaluations = 0;
160 }
161
162 /** Set the differential equations.
163 * @param equations differential equations to integrate
164 * @see #computeDerivatives(double, double[], double[])
165 */
166 protected void setEquations(final FirstOrderDifferentialEquations equations) {
167 this.equations = equations;
168 }
169
170 /** Compute the derivatives and check the number of evaluations.
171 * @param t current value of the independent <I>time</I> variable
172 * @param y array containing the current value of the state vector
173 * @param yDot placeholder array where to put the time derivative of the state vector
174 * @throws DerivativeException this exception is propagated to the caller if the
175 * underlying user function triggers one
176 */
177 public void computeDerivatives(final double t, final double[] y, final double[] yDot)
178 throws DerivativeException {
179 if (++evaluations > maxEvaluations) {
180 throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
181 }
182 equations.computeDerivatives(t, y, yDot);
183 }
184
185 /** Perform some sanity checks on the integration parameters.
186 * @param ode differential equations set
187 * @param t0 start time
188 * @param y0 state vector at t0
189 * @param t target time for the integration
190 * @param y placeholder where to put the state vector
191 * @exception IntegratorException if some inconsistency is detected
192 */
193 protected void sanityChecks(final FirstOrderDifferentialEquations ode,
194 final double t0, final double[] y0,
195 final double t, final double[] y)
196 throws IntegratorException {
197
198 if (ode.getDimension() != y0.length) {
199 throw new IntegratorException(
200 "dimensions mismatch: ODE problem has dimension {0}," +
201 " initial state vector has dimension {1}",
202 ode.getDimension(), y0.length);
203 }
204
205 if (ode.getDimension() != y.length) {
206 throw new IntegratorException(
207 "dimensions mismatch: ODE problem has dimension {0}," +
208 " final state vector has dimension {1}",
209 ode.getDimension(), y.length);
210 }
211
212 if (Math.abs(t - t0) <= 1.0e-12 * Math.max(Math.abs(t0), Math.abs(t))) {
213 throw new IntegratorException(
214 "too small integration interval: length = {0}",
215 Math.abs(t - t0));
216 }
217
218 }
219
220 /** Add an event handler for end time checking.
221 * <p>This method can be used to simplify handling of integration end time.
222 * It leverages the nominal stop condition with the exceptional stop
223 * conditions.</p>
224 * @param startTime integration start time
225 * @param endTime desired end time
226 * @param manager manager containing the user-defined handlers
227 * @return a new manager containing all the user-defined handlers plus a
228 * dedicated manager triggering a stop event at entTime
229 */
230 protected CombinedEventsManager addEndTimeChecker(final double startTime,
231 final double endTime,
232 final CombinedEventsManager manager) {
233 CombinedEventsManager newManager = new CombinedEventsManager();
234 for (final EventState state : manager.getEventsStates()) {
235 newManager.addEventHandler(state.getEventHandler(),
236 state.getMaxCheckInterval(),
237 state.getConvergence(),
238 state.getMaxIterationCount());
239 }
240 newManager.addEventHandler(new EndTimeChecker(endTime),
241 Double.POSITIVE_INFINITY,
242 Math.ulp(Math.max(Math.abs(startTime), Math.abs(endTime))),
243 100);
244 return newManager;
245 }
246
247 /** Specialized event handler to stop integration. */
248 private static class EndTimeChecker implements EventHandler {
249
250 /** Desired end time. */
251 private final double endTime;
252
253 /** Build an instance.
254 * @param endTime desired time
255 */
256 public EndTimeChecker(final double endTime) {
257 this.endTime = endTime;
258 }
259
260 /** {@inheritDoc} */
261 public int eventOccurred(double t, double[] y, boolean increasing) {
262 return STOP;
263 }
264
265 /** {@inheritDoc} */
266 public double g(double t, double[] y) {
267 return t - endTime;
268 }
269
270 /** {@inheritDoc} */
271 public void resetState(double t, double[] y) {
272 }
273
274 }
275
276 }