1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.ode.events;
24
25 import org.hipparchus.analysis.UnivariateFunction;
26 import org.hipparchus.analysis.solvers.BracketedUnivariateSolver;
27 import org.hipparchus.analysis.solvers.BracketedUnivariateSolver.Interval;
28 import org.hipparchus.exception.MathIllegalArgumentException;
29 import org.hipparchus.exception.MathIllegalStateException;
30 import org.hipparchus.exception.MathRuntimeException;
31 import org.hipparchus.ode.LocalizedODEFormats;
32 import org.hipparchus.ode.ODEState;
33 import org.hipparchus.ode.ODEStateAndDerivative;
34 import org.hipparchus.ode.sampling.ODEStateInterpolator;
35 import org.hipparchus.util.FastMath;
36
37
38
39
40
41
42
43
44
45
46
47
48 public class DetectorBasedEventState implements EventState {
49
50
51
52
53 private final ODEEventDetector detector;
54
55
56
57
58 private final BracketedUnivariateSolver<UnivariateFunction> solver;
59
60
61 private final ODEEventHandler handler;
62
63
64 private double lastT;
65
66
67 private double lastG;
68
69
70 private double t0;
71
72
73 private double g0;
74
75
76 private boolean g0Positive;
77
78
79 private boolean pendingEvent;
80
81
82 private double pendingEventTime;
83
84
85
86
87
88 private double stopTime;
89
90
91 private double afterEvent;
92
93
94 private double afterG;
95
96
97 private double earliestTimeConsidered;
98
99
100 private boolean forward;
101
102
103
104
105
106 private boolean increasing;
107
108
109
110
111
112 public DetectorBasedEventState(final ODEEventDetector detector) {
113
114 this.detector = detector;
115 this.solver = detector.getSolver();
116 this.handler = detector.getHandler();
117
118
119 t0 = Double.NaN;
120 g0 = Double.NaN;
121 g0Positive = true;
122 pendingEvent = false;
123 pendingEventTime = Double.NaN;
124 increasing = true;
125 earliestTimeConsidered = Double.NaN;
126 afterEvent = Double.NaN;
127 afterG = Double.NaN;
128 }
129
130
131
132
133
134 public ODEEventDetector getEventDetector() {
135 return detector;
136 }
137
138
139 @Override
140 public void init(final ODEStateAndDerivative s0, final double t) {
141 detector.init(s0, t);
142 lastT = Double.NEGATIVE_INFINITY;
143 lastG = Double.NaN;
144 }
145
146
147
148
149
150
151
152 private double g(final ODEStateAndDerivative s) {
153 if (s.getTime() != lastT) {
154 lastG = detector.g(s);
155 lastT = s.getTime();
156 }
157 return lastG;
158 }
159
160
161
162
163
164
165 public void reinitializeBegin(final ODEStateInterpolator interpolator)
166 throws MathIllegalStateException {
167
168 forward = interpolator.isForward();
169 final ODEStateAndDerivative s0 = interpolator.getPreviousState();
170 t0 = s0.getTime();
171 g0 = g(s0);
172 while (g0 == 0) {
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 double tStart = t0 + (forward ? 0.5 : -0.5) * solver.getAbsoluteAccuracy();
188
189 if (tStart == t0) {
190 tStart = nextAfter(t0);
191 }
192 t0 = tStart;
193 g0 = g(interpolator.getInterpolatedState(tStart));
194 }
195 g0Positive = g0 > 0;
196
197 increasing = g0Positive;
198
199 }
200
201
202 @Override
203 public boolean evaluateStep(final ODEStateInterpolator interpolator)
204 throws MathIllegalArgumentException, MathIllegalStateException {
205
206 forward = interpolator.isForward();
207 final ODEStateAndDerivative s0 = interpolator.getPreviousState();
208 final ODEStateAndDerivative s1 = interpolator.getCurrentState();
209 final double t1 = s1.getTime();
210 final double dt = t1 - t0;
211 if (FastMath.abs(dt) < solver.getAbsoluteAccuracy()) {
212
213 pendingEvent = false;
214 pendingEventTime = Double.NaN;
215 return false;
216 }
217
218 double ta = t0;
219 double ga = g0;
220 for (ODEStateAndDerivative sb = nextCheck(s0, s1, interpolator);
221 sb != null;
222 sb = nextCheck(sb, s1, interpolator)) {
223
224
225 final double tb = sb.getTime();
226 final double gb = g(sb);
227
228
229 if (gb == 0.0 || (g0Positive ^ (gb > 0))) {
230
231 if (findRoot(interpolator, ta, ga, tb, gb)) {
232 return true;
233 }
234 } else {
235
236 ta = tb;
237 ga = gb;
238 }
239
240 }
241
242
243 pendingEvent = false;
244 pendingEventTime = Double.NaN;
245 return false;
246
247 }
248
249
250
251
252
253
254
255
256
257 private ODEStateAndDerivative nextCheck(final ODEStateAndDerivative done, final ODEStateAndDerivative target,
258 final ODEStateInterpolator interpolator) {
259 if (done == target) {
260
261 return null;
262 } else {
263
264
265 final double dt = target.getTime() - done.getTime();
266 final double maxCheck = detector.getMaxCheckInterval().currentInterval(done);
267 final int n = FastMath.max(1, (int) FastMath.ceil(FastMath.abs(dt) / maxCheck));
268 return n == 1 ? target : interpolator.getInterpolatedState(done.getTime() + dt / n);
269 }
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 private boolean findRoot(final ODEStateInterpolator interpolator,
286 final double ta,
287 final double ga,
288 final double tb,
289 final double gb) {
290
291 check(ga == 0.0 || gb == 0.0 || (ga > 0.0 && gb < 0.0) || (ga < 0.0 && gb > 0.0));
292
293 final int maxIterationCount = detector.getMaxIterationCount();
294 final UnivariateFunction f = t -> g(interpolator.getInterpolatedState(t));
295
296
297 double loopT = ta;
298 double loopG = ga;
299
300
301 double beforeRootT = Double.NaN;
302 double beforeRootG = Double.NaN;
303
304
305 double afterRootT = ta;
306 double afterRootG = 0.0;
307
308
309
310
311 if (ta == tb) {
312
313 beforeRootT = ta;
314 beforeRootG = ga;
315 afterRootT = shiftedBy(beforeRootT, solver.getAbsoluteAccuracy());
316 afterRootG = f.value(afterRootT);
317 } else if (ga != 0.0 && gb == 0.0) {
318
319
320
321 beforeRootT = tb;
322 beforeRootG = gb;
323 afterRootT = shiftedBy(beforeRootT, solver.getAbsoluteAccuracy());
324 afterRootG = f.value(afterRootT);
325 } else if (ga != 0.0) {
326 final double newGa = f.value(ta);
327 if (ga > 0 != newGa > 0) {
328
329 final double nextT = minTime(shiftedBy(ta, solver.getAbsoluteAccuracy()), tb);
330 final double nextG = f.value(nextT);
331 if (nextG > 0.0 == g0Positive) {
332
333
334
335
336 loopT = nextT;
337 loopG = nextG;
338 } else {
339 beforeRootT = ta;
340 beforeRootG = newGa;
341 afterRootT = nextT;
342 afterRootG = nextG;
343 }
344
345 }
346 }
347
348
349
350 while ((afterRootG == 0.0 || afterRootG > 0.0 == g0Positive) &&
351 strictlyAfter(afterRootT, tb)) {
352 if (loopG == 0.0) {
353
354
355 beforeRootT = loopT;
356 beforeRootG = loopG;
357 afterRootT = minTime(shiftedBy(beforeRootT, solver.getAbsoluteAccuracy()), tb);
358 afterRootG = f.value(afterRootT);
359 } else {
360
361 if (forward) {
362 try {
363 final Interval interval =
364 solver.solveInterval(maxIterationCount, f, loopT, tb);
365 beforeRootT = interval.getLeftAbscissa();
366 beforeRootG = interval.getLeftValue();
367 afterRootT = interval.getRightAbscissa();
368 afterRootG = interval.getRightValue();
369
370 } catch (RuntimeException e) {
371
372 throw new MathIllegalStateException(e, LocalizedODEFormats.FIND_ROOT,
373 detector, loopT, loopG, tb, gb, lastT, lastG);
374 }
375 } else {
376 try {
377 final Interval interval =
378 solver.solveInterval(maxIterationCount, f, tb, loopT);
379 beforeRootT = interval.getRightAbscissa();
380 beforeRootG = interval.getRightValue();
381 afterRootT = interval.getLeftAbscissa();
382 afterRootG = interval.getLeftValue();
383
384 } catch (RuntimeException e) {
385
386 throw new MathIllegalStateException(e, LocalizedODEFormats.FIND_ROOT,
387 detector, tb, gb, loopT, loopG, lastT, lastG);
388 }
389 }
390 }
391
392
393 if (beforeRootT == afterRootT) {
394 afterRootT = nextAfter(afterRootT);
395 afterRootG = f.value(afterRootT);
396 }
397
398 check((forward && afterRootT > beforeRootT) || (!forward && afterRootT < beforeRootT));
399
400 loopT = afterRootT;
401 loopG = afterRootG;
402 }
403
404
405 if (afterRootG == 0.0 || afterRootG > 0.0 == g0Positive) {
406
407 return false;
408 } else {
409
410 check(!Double.isNaN(beforeRootT) && !Double.isNaN(beforeRootG));
411
412 increasing = !g0Positive;
413 pendingEventTime = beforeRootT;
414 stopTime = beforeRootG == 0.0 ? beforeRootT : afterRootT;
415 pendingEvent = true;
416 afterEvent = afterRootT;
417 afterG = afterRootG;
418
419
420 check(afterG > 0 == increasing);
421 check(increasing == gb >= ga);
422
423 return true;
424 }
425
426 }
427
428
429
430
431
432
433
434 private double nextAfter(final double t) {
435
436 final double dir = forward ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
437 return FastMath.nextAfter(t, dir);
438 }
439
440
441 @Override
442 public double getEventTime() {
443 return pendingEvent ?
444 pendingEventTime :
445 (forward ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY);
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 public boolean tryAdvance(final ODEStateAndDerivative state,
463 final ODEStateInterpolator interpolator) {
464 final double t = state.getTime();
465
466 check(!pendingEvent || !strictlyAfter(pendingEventTime, t));
467
468 final boolean meFirst;
469
470 if (strictlyAfter(t, earliestTimeConsidered)) {
471
472 meFirst = false;
473 } else {
474
475 final double g = g(state);
476 final boolean positive = g > 0;
477
478 if (positive == g0Positive) {
479
480 g0 = g;
481 meFirst = false;
482 } else {
483
484 final double oldPendingEventTime = pendingEventTime;
485 final boolean foundRoot = findRoot(interpolator, t0, g0, t, g);
486
487 meFirst = foundRoot &&
488 (Double.isNaN(oldPendingEventTime) || oldPendingEventTime != pendingEventTime);
489 }
490 }
491
492 if (!meFirst) {
493
494 t0 = t;
495 }
496
497 return meFirst;
498 }
499
500
501 @Override
502 public EventOccurrence doEvent(final ODEStateAndDerivative state) {
503
504 check(pendingEvent);
505 check(state.getTime() == this.pendingEventTime);
506
507 final Action action = handler.eventOccurred(state, detector, increasing == forward);
508 final ODEState newState;
509 if (action == Action.RESET_STATE) {
510 newState = handler.resetState(detector, state);
511 } else {
512 newState = state;
513 }
514
515 pendingEvent = false;
516 pendingEventTime = Double.NaN;
517
518 earliestTimeConsidered = afterEvent;
519 t0 = afterEvent;
520 g0 = afterG;
521 g0Positive = increasing;
522
523 check(g0 == 0.0 || g0Positive == (g0 > 0));
524 return new EventOccurrence(action, newState, stopTime);
525 }
526
527
528
529
530
531
532
533
534
535 private double shiftedBy(final double t, final double delta) {
536 if (forward) {
537 final double ret = t + delta;
538 if (ret - t > delta) {
539 return FastMath.nextDown(ret);
540 } else {
541 return ret;
542 }
543 } else {
544 final double ret = t - delta;
545 if (t - ret > delta) {
546 return FastMath.nextUp(ret);
547 } else {
548 return ret;
549 }
550 }
551 }
552
553
554
555
556
557
558
559
560
561 private double minTime(final double a, final double b) {
562 return forward ? FastMath.min(a, b) : FastMath.max(a, b);
563 }
564
565
566
567
568
569
570
571
572
573 private boolean strictlyAfter(final double t1, final double t2) {
574 return forward ? t1 < t2 : t2 < t1;
575 }
576
577
578
579
580
581
582
583 private void check(final boolean condition) throws MathRuntimeException {
584 if (!condition) {
585 throw MathRuntimeException.createInternalError();
586 }
587 }
588
589 }