1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 import java.util.Comparator;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.SortedSet;
27 import java.util.TreeSet;
28
29 import org.apache.commons.math.analysis.solvers.BracketingNthOrderBrentSolver;
30 import org.apache.commons.math.analysis.solvers.UnivariateRealSolver;
31 import org.apache.commons.math.exception.DimensionMismatchException;
32 import org.apache.commons.math.exception.MathIllegalArgumentException;
33 import org.apache.commons.math.exception.MathIllegalStateException;
34 import org.apache.commons.math.exception.MaxCountExceededException;
35 import org.apache.commons.math.exception.NumberIsTooSmallException;
36 import org.apache.commons.math.exception.util.LocalizedFormats;
37 import org.apache.commons.math.ode.events.EventHandler;
38 import org.apache.commons.math.ode.events.EventState;
39 import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
40 import org.apache.commons.math.ode.sampling.StepHandler;
41 import org.apache.commons.math.util.FastMath;
42 import org.apache.commons.math.util.Incrementor;
43 import org.apache.commons.math.util.MathUtils;
44 import org.apache.commons.math.util.Precision;
45
46
47
48
49
50
51 public abstract class AbstractIntegrator implements FirstOrderIntegrator {
52
53
54 protected Collection<StepHandler> stepHandlers;
55
56
57 protected double stepStart;
58
59
60 protected double stepSize;
61
62
63 protected boolean isLastStep;
64
65
66 protected boolean resetOccurred;
67
68
69 private Collection<EventState> eventsStates;
70
71
72 private boolean statesInitialized;
73
74
75 private final String name;
76
77
78 private Incrementor evaluations;
79
80
81 private transient ExpandableStatefulODE expandable;
82
83
84
85
86 public AbstractIntegrator(final String name) {
87 this.name = name;
88 stepHandlers = new ArrayList<StepHandler>();
89 stepStart = Double.NaN;
90 stepSize = Double.NaN;
91 eventsStates = new ArrayList<EventState>();
92 statesInitialized = false;
93 evaluations = new Incrementor();
94 setMaxEvaluations(-1);
95 resetEvaluations();
96 }
97
98
99
100 protected AbstractIntegrator() {
101 this(null);
102 }
103
104
105 public String getName() {
106 return name;
107 }
108
109
110 public void addStepHandler(final StepHandler handler) {
111 stepHandlers.add(handler);
112 }
113
114
115 public Collection<StepHandler> getStepHandlers() {
116 return Collections.unmodifiableCollection(stepHandlers);
117 }
118
119
120 public void clearStepHandlers() {
121 stepHandlers.clear();
122 }
123
124
125 public void addEventHandler(final EventHandler handler,
126 final double maxCheckInterval,
127 final double convergence,
128 final int maxIterationCount) {
129 addEventHandler(handler, maxCheckInterval, convergence,
130 maxIterationCount,
131 new BracketingNthOrderBrentSolver(convergence, 5));
132 }
133
134
135 public void addEventHandler(final EventHandler handler,
136 final double maxCheckInterval,
137 final double convergence,
138 final int maxIterationCount,
139 final UnivariateRealSolver solver) {
140 eventsStates.add(new EventState(handler, maxCheckInterval, convergence,
141 maxIterationCount, solver));
142 }
143
144
145 public Collection<EventHandler> getEventHandlers() {
146 final List<EventHandler> list = new ArrayList<EventHandler>();
147 for (EventState state : eventsStates) {
148 list.add(state.getEventHandler());
149 }
150 return Collections.unmodifiableCollection(list);
151 }
152
153
154 public void clearEventHandlers() {
155 eventsStates.clear();
156 }
157
158
159 public double getCurrentStepStart() {
160 return stepStart;
161 }
162
163
164 public double getCurrentSignedStepsize() {
165 return stepSize;
166 }
167
168
169 public void setMaxEvaluations(int maxEvaluations) {
170 evaluations.setMaximalCount((maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations);
171 }
172
173
174 public int getMaxEvaluations() {
175 return evaluations.getMaximalCount();
176 }
177
178
179 public int getEvaluations() {
180 return evaluations.getCount();
181 }
182
183
184
185 protected void resetEvaluations() {
186 evaluations.resetCount();
187 }
188
189
190
191
192 protected void setEquations(final ExpandableStatefulODE equations) {
193 this.expandable = equations;
194 }
195
196
197 public double integrate(final FirstOrderDifferentialEquations equations,
198 final double t0, final double[] y0, final double t, final double[] y)
199 throws MathIllegalStateException, MathIllegalArgumentException {
200
201 if (y0.length != equations.getDimension()) {
202 throw new DimensionMismatchException(y0.length, equations.getDimension());
203 }
204 if (y.length != equations.getDimension()) {
205 throw new DimensionMismatchException(y.length, equations.getDimension());
206 }
207
208
209 final ExpandableStatefulODE expandableODE = new ExpandableStatefulODE(equations);
210 expandableODE.setTime(t0);
211 expandableODE.setPrimaryState(y0);
212
213
214 integrate(expandableODE, t);
215
216
217 System.arraycopy(expandableODE.getPrimaryState(), 0, y, 0, y.length);
218 return expandableODE.getTime();
219
220 }
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239 public abstract void integrate(ExpandableStatefulODE equations, double t)
240 throws MathIllegalStateException, MathIllegalArgumentException;
241
242
243
244
245
246
247
248 public void computeDerivatives(final double t, final double[] y, final double[] yDot)
249 throws MaxCountExceededException {
250 evaluations.incrementCount();
251 expandable.computeDerivatives(t, y, yDot);
252 }
253
254
255
256
257
258
259
260
261 protected void setStateInitialized(final boolean stateInitialized) {
262 this.statesInitialized = stateInitialized;
263 }
264
265
266
267
268
269
270
271
272
273
274
275 protected double acceptStep(final AbstractStepInterpolator interpolator,
276 final double[] y, final double[] yDot, final double tEnd)
277 throws MathIllegalStateException {
278
279 double previousT = interpolator.getGlobalPreviousTime();
280 final double currentT = interpolator.getGlobalCurrentTime();
281 resetOccurred = false;
282
283
284 if (! statesInitialized) {
285 for (EventState state : eventsStates) {
286 state.reinitializeBegin(interpolator);
287 }
288 statesInitialized = true;
289 }
290
291
292 final int orderingSign = interpolator.isForward() ? +1 : -1;
293 SortedSet<EventState> occuringEvents = new TreeSet<EventState>(new Comparator<EventState>() {
294
295
296 public int compare(EventState es0, EventState es1) {
297 return orderingSign * Double.compare(es0.getEventTime(), es1.getEventTime());
298 }
299
300 });
301
302 for (final EventState state : eventsStates) {
303 if (state.evaluateStep(interpolator)) {
304
305 occuringEvents.add(state);
306 }
307 }
308
309 while (!occuringEvents.isEmpty()) {
310
311
312 final Iterator<EventState> iterator = occuringEvents.iterator();
313 final EventState currentEvent = iterator.next();
314 iterator.remove();
315
316
317 final double eventT = currentEvent.getEventTime();
318 interpolator.setSoftPreviousTime(previousT);
319 interpolator.setSoftCurrentTime(eventT);
320
321
322 interpolator.setInterpolatedTime(eventT);
323 final double[] eventY = interpolator.getInterpolatedState();
324 currentEvent.stepAccepted(eventT, eventY);
325 isLastStep = currentEvent.stop();
326
327
328 for (final StepHandler handler : stepHandlers) {
329 handler.handleStep(interpolator, isLastStep);
330 }
331
332 if (isLastStep) {
333
334 System.arraycopy(eventY, 0, y, 0, y.length);
335 return eventT;
336 }
337
338 if (currentEvent.reset(eventT, eventY)) {
339
340
341 System.arraycopy(eventY, 0, y, 0, y.length);
342 computeDerivatives(eventT, y, yDot);
343 resetOccurred = true;
344 return eventT;
345 }
346
347
348 previousT = eventT;
349 interpolator.setSoftPreviousTime(eventT);
350 interpolator.setSoftCurrentTime(currentT);
351
352
353 if (currentEvent.evaluateStep(interpolator)) {
354
355 occuringEvents.add(currentEvent);
356 }
357
358 }
359
360 interpolator.setInterpolatedTime(currentT);
361 final double[] currentY = interpolator.getInterpolatedState();
362 for (final EventState state : eventsStates) {
363 state.stepAccepted(currentT, currentY);
364 isLastStep = isLastStep || state.stop();
365 }
366 isLastStep = isLastStep || Precision.equals(currentT, tEnd, 1);
367
368
369 for (StepHandler handler : stepHandlers) {
370 handler.handleStep(interpolator, isLastStep);
371 }
372
373 return currentT;
374
375 }
376
377
378
379
380
381
382 protected void sanityChecks(final ExpandableStatefulODE equations, final double t)
383 throws NumberIsTooSmallException {
384
385 final double threshold = 1000 * FastMath.ulp(FastMath.max(FastMath.abs(equations.getTime()),
386 FastMath.abs(t)));
387 final double dt = FastMath.abs(equations.getTime() - t);
388 if (dt <= threshold) {
389 throw new NumberIsTooSmallException(LocalizedFormats.TOO_SMALL_INTEGRATION_INTERVAL,
390 dt, threshold, false);
391 }
392
393 }
394
395 }