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