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