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 }