1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.ode.events;
18
19 import org.hipparchus.analysis.UnivariateFunction;
20 import org.hipparchus.analysis.solvers.BracketedUnivariateSolver;
21 import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver;
22 import org.hipparchus.ode.ODEIntegrator;
23 import org.hipparchus.ode.ODEState;
24 import org.hipparchus.ode.ODEStateAndDerivative;
25 import org.hipparchus.ode.OrdinaryDifferentialEquation;
26 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
27 import org.hipparchus.ode.nonstiff.LutherIntegrator;
28 import org.hipparchus.ode.sampling.ODEStateInterpolator;
29 import org.hipparchus.ode.sampling.ODEStepHandler;
30 import org.hipparchus.util.FastMath;
31 import org.junit.jupiter.api.Test;
32
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36
37 import static org.junit.jupiter.api.Assertions.assertEquals;
38 import static org.junit.jupiter.api.Assertions.assertFalse;
39 import static org.junit.jupiter.api.Assertions.assertSame;
40 import static org.junit.jupiter.api.Assertions.assertTrue;
41 import static org.junit.jupiter.api.Assertions.fail;
42
43
44
45
46
47
48 class CloseEventsTest {
49
50 @Test
51 void testEventAtFinalTime() {
52 final DormandPrince853Integrator integrator = new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
53 final IntervalDetector detector = new IntervalDetector(720, 1e-10, 100, Action.RESET_DERIVATIVES, 16296.238, 17016.238);
54 integrator.addEventDetector(detector);
55 integrator.integrate(new Equation(), new ODEState(0.0, new double[2]), 17016.238);
56 assertEquals(2, detector.getEvents().size());
57 }
58
59 @Test
60 void testCloseEventsFirstOneIsReset() {
61
62
63
64
65
66
67
68
69
70
71 ODEIntegrator integrator =
72 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
73
74 TimeDetector detector1 = new TimeDetector(10, 1e-9, 100, Action.RESET_DERIVATIVES, 9);
75 integrator.addEventDetector(detector1);
76 TimeDetector detector2 = new TimeDetector(11, 1e-9, 100, 9 + 1e-15, 9 + 4.9);
77 integrator.addEventDetector(detector2);
78
79
80 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20);
81
82
83 List<Event> events1 = detector1.getEvents();
84 assertEquals(1, events1.size());
85 assertEquals(9, events1.get(0).getT(), 0.0);
86 List<Event> events2 = detector2.getEvents();
87 assertEquals(0, events2.size());
88 }
89
90 @Test
91 void testCloseEvents() {
92
93 double e = 1e-15;
94 ODEIntegrator integrator =
95 new DormandPrince853Integrator(e, 100.0, 1e-7, 1e-7);
96
97 TimeDetector detector1 = new TimeDetector(10, 1, 100, 5);
98 integrator.addEventDetector(detector1);
99 TimeDetector detector2 = new TimeDetector(10, 1, 100, 5.5);
100 integrator.addEventDetector(detector2);
101
102
103 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20);
104
105
106 List<Event> events1 = detector1.getEvents();
107 assertEquals(1, events1.size());
108 assertEquals(5, events1.get(0).getT(), 0.0);
109 List<Event> events2 = detector2.getEvents();
110 assertEquals(1, events2.size());
111 assertEquals(5.5, events2.get(0).getT(), 0.0);
112 }
113
114 @Test
115 void testSimultaneousEvents() {
116
117 ODEIntegrator integrator =
118 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
119
120 TimeDetector detector1 = new TimeDetector(10, 1, 100, 5);
121 integrator.addEventDetector(detector1);
122 TimeDetector detector2 = new TimeDetector(10, 1, 100, 5);
123 integrator.addEventDetector(detector2);
124
125
126 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20);
127
128
129 List<Event> events1 = detector1.getEvents();
130 assertEquals(1, events1.size());
131 assertEquals(5, events1.get(0).getT(), 0.0);
132 List<Event> events2 = detector2.getEvents();
133 assertEquals(1, events2.size());
134 assertEquals(5, events2.get(0).getT(), 0.0);
135 }
136
137
138
139
140
141
142 @Test
143 void testSimultaneousEventsReset() {
144
145 double tol = 1e-10;
146 ODEIntegrator integrator =
147 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
148 boolean[] firstEventOccurred = {false};
149 List<Event> events = new ArrayList<>();
150
151 TimeDetector detector1 = new TimeDetector(10, tol, 100, events, 5) {
152 @Override
153 public ODEEventHandler getHandler() {
154 return (state, detector, increasing) -> {
155 firstEventOccurred[0] = true;
156 super.getHandler().eventOccurred(state, detector, increasing);
157 return Action.RESET_STATE;
158 };
159 }
160 };
161 integrator.addEventDetector(detector1);
162
163 TimeDetector detector2 = new TimeDetector(1, tol, 100, events, 1, 3, 5) {
164 @Override
165 public double g(final ODEStateAndDerivative state) {
166 if (firstEventOccurred[0]) {
167 return super.g(state);
168 }
169 return new TimeDetector(1, tol, 100, 5).g(state);
170 }
171 };
172 integrator.addEventDetector(detector2);
173
174
175 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20);
176
177
178
179 assertEquals(5, events.get(0).getT(), 0.0);
180 assertTrue(events.get(0).isIncreasing());
181 assertEquals(detector1, events.get(0).getDetector());
182 assertEquals(5, events.get(1).getT(), 0.0);
183 assertTrue(events.get(1).isIncreasing());
184 assertEquals(detector2, events.get(1).getDetector());
185 assertEquals(2, events.size());
186 }
187
188
189
190
191
192
193
194 @Test
195 void testSimultaneousDiscontinuousEventsAfterReset() {
196
197 double t = FastMath.PI;
198 double tol = 1e-10;
199 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
200 List<Event> events = new ArrayList<>();
201
202 TimeDetector resetDetector =
203 new ResetDetector(10, tol, 100, events, new ODEState(t, new double[]{1e100, 0}), t);
204 integrator.addEventDetector(resetDetector);
205 List<BaseDetector> detectors = new ArrayList<>();
206 for (int i = 0; i < 2; i++) {
207 BaseDetector detector1 = new StateDetector(10, tol, 100, events, 0.0);
208 integrator.addEventDetector(detector1);
209 detectors.add(detector1);
210 }
211
212
213 integrator.integrate(new Equation(), new ODEState(0, new double[]{-1e100, 0}), 10);
214
215
216 assertEquals(t, events.get(0).getT(), tol);
217 assertTrue(events.get(0).isIncreasing());
218 assertEquals(resetDetector, events.get(0).getDetector());
219
220 assertEquals(t, events.get(1).getT(), tol);
221 assertTrue(events.get(1).isIncreasing());
222 assertEquals(detectors.get(0), events.get(1).getDetector());
223 assertEquals(t, events.get(2).getT(), tol);
224 assertTrue(events.get(2).isIncreasing());
225 assertEquals(detectors.get(1), events.get(2).getDetector());
226 assertEquals(3, events.size());
227 }
228
229
230
231
232
233
234 @Test
235 void testFastSwitching() {
236
237
238 ODEIntegrator integrator =
239 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
240
241 TimeDetector detector1 = new TimeDetector(10, 0.2, 100, 9.9, 10.1, 12);
242 integrator.addEventDetector(detector1);
243
244
245 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20);
246
247
248
249 List<Event> events1 = detector1.getEvents();
250 assertEquals(1, events1.size());
251 assertEquals(9.9, events1.get(0).getT(), 0.1);
252 assertTrue(events1.get(0).isIncreasing());
253 }
254
255
256 @Test
257 void testTrickyCaseLower() {
258
259 double maxCheck = 10;
260 double tolerance = 1e-6;
261 double t1 = 1.0, t2 = 15, t3 = 16, t4 = 17, t5 = 18;
262
263 List<Event> events = new ArrayList<>();
264 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t3);
265 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, -10, t1, t2, t5);
266 TimeDetector detectorC = new TimeDetector(maxCheck, tolerance, 100, Action.RESET_DERIVATIVES, events, t4);
267
268 ODEIntegrator integrator =
269 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
270 integrator.addEventDetector(detectorA);
271 integrator.addEventDetector(detectorB);
272 integrator.addEventDetector(detectorC);
273
274
275 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
276
277
278
279
280 assertEquals(5, events.size());
281 assertEquals(t1, events.get(0).getT(), tolerance);
282 assertFalse(events.get(0).isIncreasing());
283 assertEquals(t2, events.get(1).getT(), tolerance);
284 assertTrue(events.get(1).isIncreasing());
285 assertEquals(t3, events.get(2).getT(), tolerance);
286 assertTrue(events.get(2).isIncreasing());
287 assertEquals(t4, events.get(3).getT(), tolerance);
288 assertTrue(events.get(3).isIncreasing());
289 assertEquals(t5, events.get(4).getT(), tolerance);
290 assertFalse(events.get(4).isIncreasing());
291 }
292
293
294
295
296
297
298 @Test
299 void testRootFindingTolerance() {
300
301 double maxCheck = 10;
302 double t2 = 11, t3 = t2 + 1e-5;
303 List<Event> events = new ArrayList<>();
304 TimeDetector detectorA = new TimeDetector(maxCheck, 1e-6, 100, events, t2);
305 TimeDetector detectorB = new FlatDetector(maxCheck, 0.5, 100, events, t3);
306 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
307 integrator.addEventDetector(detectorA);
308 integrator.addEventDetector(detectorB);
309
310
311 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
312
313
314
315
316 assertSame(detectorB, events.get(0).getDetector());
317 assertSame(detectorA, events.get(1).getDetector());
318 assertTrue(events.get(0).getT() < events.get(1).getT());
319
320
321 assertEquals(2, events.size());
322 assertEquals(t3, events.get(0).getT(), 0.5);
323 assertTrue(events.get(0).isIncreasing());
324 assertEquals(t2, events.get(1).getT(), 1e-6);
325 assertTrue(events.get(1).isIncreasing());
326 }
327
328
329 @Test
330 void testRootPlusToleranceHasWrongSign() {
331
332 double maxCheck = 10;
333 double tolerance = 1e-6;
334 final double toleranceB = 0.3;
335 double t1 = 11, t2 = 11.1, t3 = 11.2;
336
337 List<Event> events = new ArrayList<>();
338 TimeDetector detectorA = new TimeDetector(maxCheck, 1e-6, 100, events, t2);
339 TimeDetector detectorB = new TimeDetector(maxCheck, toleranceB, 100, events, t1, t3);
340 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
341 integrator.addEventDetector(detectorA);
342 integrator.addEventDetector(detectorB);
343
344
345 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
346
347
348
349 assertEquals(3, events.size());
350 assertEquals(t1, events.get(0).getT(), toleranceB);
351 assertTrue(events.get(0).isIncreasing());
352 assertSame(detectorB, events.get(0).getDetector());
353 assertEquals(t3, events.get(1).getT(), toleranceB);
354 assertFalse(events.get(1).isIncreasing());
355 assertSame(detectorB, events.get(1).getDetector());
356 assertEquals(t2, events.get(2).getT(), tolerance);
357 assertTrue(events.get(2).isIncreasing());
358 assertSame(detectorA, events.get(2).getDetector());
359
360 for (int i = 1; i < events.size(); i++) {
361 assertTrue(events.get(i).getT() >= events.get(i - 1).getT());
362 }
363 }
364
365
366 @Test
367 void testRootPlusToleranceHasWrongSignAndLessThanTb() {
368
369
370 double maxCheck = 10;
371 double tolerance = 0.5;
372 double t1 = 11, t2 = 11.4, t3 = 12.0;
373
374 List<Event> events = new ArrayList<>();
375 TimeDetector detectorB = new FlatDetector(maxCheck, tolerance, 100, events, t1, t2, t3);
376 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
377 integrator.addEventDetector(detectorB);
378
379
380 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
381
382
383
384 assertEquals(1, events.size());
385 assertEquals(t1, events.get(0).getT(), tolerance);
386 assertTrue(events.get(0).isIncreasing());
387 assertSame(detectorB, events.get(0).getDetector());
388 }
389
390
391
392
393
394 @Test
395 void testDoubleRoot() {
396
397 double maxCheck = 10;
398 double tolerance = 1e-6;
399 double t1 = 11;
400
401 List<Event> events = new ArrayList<>();
402 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t1);
403 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, t1, t1);
404 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
405 integrator.addEventDetector(detectorA);
406 integrator.addEventDetector(detectorB);
407
408
409 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
410
411
412 assertEquals(1, events.size());
413 assertEquals(t1, events.get(0).getT(), 0.0);
414 assertTrue(events.get(0).isIncreasing());
415 assertSame(detectorA, events.get(0).getDetector());
416
417 assertEquals(0.0, detectorB.g(state(t1)));
418 assertTrue(detectorB.g(state(t1 - 1e-6)) < 0);
419 assertTrue(detectorB.g(state(t1 + 1e-6)) < 0);
420 }
421
422
423
424
425
426 @Test
427 void testDoubleRootOppositeSign() {
428
429 double maxCheck = 10;
430 double tolerance = 1e-6;
431 double t1 = 11;
432
433 List<Event> events = new ArrayList<>();
434 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t1);
435 TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, -20, t1, t1);
436 detectorB.g(state(t1));
437 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
438 integrator.addEventDetector(detectorA);
439 integrator.addEventDetector(detectorB);
440
441
442 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
443
444
445 assertEquals(1, events.size());
446 assertEquals(t1, events.get(0).getT(), 0.0);
447 assertTrue(events.get(0).isIncreasing());
448 assertSame(detectorA, events.get(0).getDetector());
449
450 assertEquals(0.0, detectorB.g(state(t1)), 0.0);
451 assertTrue(detectorB.g(state(t1 - 1e-6)) > 0);
452 assertTrue(detectorB.g(state(t1 + 1e-6)) > 0);
453 }
454
455
456 @Test
457 void testZeroAtBeginningAndEndOfInterval() {
458
459 double maxCheck = 10;
460 double tolerance = 1e-6;
461 double t1 = 10, t2 = 20;
462
463 List<Event> events = new ArrayList<>();
464 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1, t2);
465 ODEIntegrator integrator =
466 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
467 integrator.addEventDetector(detectorA);
468
469
470 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
471
472
473 assertEquals(2, events.size());
474 assertEquals(t1, events.get(0).getT(), 0.0);
475 assertTrue(events.get(0).isIncreasing());
476 assertSame(detectorA, events.get(0).getDetector());
477 assertEquals(t2, events.get(1).getT(), 0.0);
478 assertFalse(events.get(1).isIncreasing());
479 assertSame(detectorA, events.get(1).getDetector());
480 }
481
482
483 @Test
484 void testZeroAtBeginningAndEndOfIntervalOppositeSign() {
485
486 double maxCheck = 10;
487 double tolerance = 1e-6;
488 double t1 = 10, t2 = 20;
489
490 List<Event> events = new ArrayList<>();
491 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, -10, t1, t2);
492 ODEIntegrator integrator =
493 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
494 integrator.addEventDetector(detectorA);
495
496
497 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
498
499
500 assertEquals(2, events.size());
501 assertEquals(t1, events.get(0).getT(), 0.0);
502 assertFalse(events.get(0).isIncreasing());
503 assertSame(detectorA, events.get(0).getDetector());
504 assertEquals(t2, events.get(1).getT(), 0.0);
505 assertTrue(events.get(1).isIncreasing());
506 assertSame(detectorA, events.get(1).getDetector());
507 }
508
509
510 @Test
511 void testMultipleBackups() {
512
513 double maxCheck = 10;
514 double tolerance = 1e-6;
515 double t1 = 11.0, t2 = 12, t3 = 13, t4 = 14, t5 = 15, t6 = 16, t7 = 17;
516
517 List<Event> events = new ArrayList<>();
518 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t6);
519 TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t1, t3, t4, t7);
520 TimeDetector detectorC = new ContinuousDetector(maxCheck, tolerance, 100, events, t2, t5);
521
522 ODEIntegrator integrator =
523 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
524 integrator.addEventDetector(detectorA);
525 integrator.addEventDetector(detectorB);
526 integrator.addEventDetector(detectorC);
527
528
529 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
530
531
532
533 assertEquals(5, events.size());
534 assertEquals(t1, events.get(0).getT(), tolerance);
535 assertTrue(events.get(0).isIncreasing());
536 assertEquals(detectorB, events.get(0).getDetector());
537 assertEquals(t2, events.get(1).getT(), tolerance);
538 assertTrue(events.get(1).isIncreasing());
539 assertEquals(detectorC, events.get(1).getDetector());
540
541
542
543
544
545
546
547
548
549
550 assertEquals(t5, events.get(2).getT(), tolerance);
551 assertFalse(events.get(2).isIncreasing());
552 assertEquals(detectorC, events.get(2).getDetector());
553 assertEquals(t6, events.get(3).getT(), tolerance);
554 assertTrue(events.get(3).isIncreasing());
555 assertEquals(detectorA, events.get(3).getDetector());
556 assertEquals(t7, events.get(4).getT(), tolerance);
557 assertFalse(events.get(4).isIncreasing());
558 assertEquals(detectorB, events.get(4).getDetector());
559 }
560
561
562 @Test
563 void testEventCausedByStateReset() {
564
565 double maxCheck = 10;
566 double tolerance = 1e-6;
567 double t1 = 15.0;
568 final ODEState newState = new ODEState(t1, new double[]{-20, 0});
569
570 List<Event> events = new ArrayList<>();
571 TimeDetector detectorA = new ResetDetector(maxCheck, tolerance, 100, events, newState, t1);
572 BaseDetector detectorB = new StateDetector(maxCheck, tolerance, 100, events, -1);
573
574 ODEIntegrator integrator =
575 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
576 integrator.addEventDetector(detectorA);
577 integrator.addEventDetector(detectorB);
578
579
580 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 40.0);
581
582
583
584 assertEquals(3, events.size());
585 assertEquals(t1, events.get(0).getT(), tolerance);
586 assertTrue(events.get(0).isIncreasing());
587 assertEquals(detectorA, events.get(0).getDetector());
588 assertEquals(t1, events.get(1).getT(), tolerance);
589 assertFalse(events.get(1).isIncreasing());
590 assertEquals(detectorB, events.get(1).getDetector());
591 assertEquals(t1 + 19, events.get(2).getT(), tolerance);
592 assertTrue(events.get(2).isIncreasing());
593 assertEquals(detectorB, events.get(2).getDetector());
594 }
595
596
597 @Test
598 void testConvergenceTooTight() {
599
600 double maxCheck = 10;
601 double tolerance = 1e-18;
602 double t1 = 15;
603
604 List<Event> events = new ArrayList<>();
605 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1);
606 ODEIntegrator integrator =
607 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
608 integrator.addEventDetector(detectorA);
609
610
611 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
612
613
614 assertEquals(1, events.size());
615 assertEquals(t1, events.get(0).getT(), 0.0);
616 assertTrue(events.get(0).isIncreasing());
617 assertSame(detectorA, events.get(0).getDetector());
618 }
619
620
621 @Test
622 void testToleranceMismatch() {
623
624 double maxCheck = 10;
625 double tolerance = 1e-18;
626 double t1 = 15.1;
627
628 List<Event> events = new ArrayList<>();
629 TimeDetector detectorA = new FlatDetector(maxCheck, tolerance, 100, events, t1);
630 ODEIntegrator integrator =
631 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
632 integrator.addEventDetector(detectorA);
633
634
635 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
636
637
638 assertEquals(1, events.size());
639
640 assertEquals(t1, events.get(0).getT(), 1e-3);
641 assertTrue(events.get(0).isIncreasing());
642 assertSame(detectorA, events.get(0).getDetector());
643 }
644
645
646
647
648
649
650
651
652 @Test
653 void testEventChangesGFunctionDefinition() {
654
655 double maxCheck = 5;
656 double tolerance = 1e-6;
657 double t1 = 11, t2 = 19;
658
659 List<Event> events = new ArrayList<>();
660
661 boolean[] swap = new boolean[1];
662 final TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1) {
663 @Override
664 public ODEEventHandler getHandler() {
665 return (state, detector, increasing) -> {
666 swap[0] = true;
667 return super.getHandler().eventOccurred(state, detector, increasing);
668 };
669 }
670 };
671 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
672 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
673
674 @Override
675 public double g(ODEStateAndDerivative state) {
676 if (swap[0]) {
677 return detectorB.g(state);
678 } else {
679 return -1;
680 }
681 }
682
683 };
684 ODEIntegrator integrator =
685 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
686 integrator.addEventDetector(detectorA);
687 integrator.addEventDetector(detectorC);
688
689
690 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
691
692
693 assertEquals(2, events.size());
694 assertEquals(t1, events.get(0).getT(), tolerance);
695 assertTrue(events.get(0).isIncreasing());
696 assertSame(detectorA, events.get(0).getDetector());
697 assertEquals(t2, events.get(1).getT(), tolerance);
698 assertTrue(events.get(1).isIncreasing());
699 assertSame(detectorC, events.get(1).getDetector());
700 }
701
702
703
704
705
706
707 @Test
708 void testEventChangesGFunctionDefinitionCancel() {
709
710 double maxCheck = 5;
711 double tolerance = 1e-6;
712 double t1 = 11, t2 = 11.1;
713
714 List<Event> events = new ArrayList<>();
715
716 boolean[] swap = new boolean[1];
717 final TimeDetector detectorA =
718 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
719 @Override
720 public ODEEventHandler getHandler() {
721 return (state, detector, increasing) -> {
722 swap[0] = true;
723 return super.getHandler().eventOccurred(state, detector, increasing);
724 };
725 }
726 };
727 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
728 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
729
730 @Override
731 public double g(ODEStateAndDerivative state) {
732 if (!swap[0]) {
733 return detectorB.g(state);
734 } else {
735 return -1;
736 }
737 }
738
739 };
740 ODEIntegrator integrator =
741 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
742 integrator.addEventDetector(detectorA);
743 integrator.addEventDetector(detectorC);
744
745
746 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
747
748
749 assertEquals(1, events.size());
750 assertEquals(t1, events.get(0).getT(), tolerance);
751 assertTrue(events.get(0).isIncreasing());
752 assertSame(detectorA, events.get(0).getDetector());
753 }
754
755
756
757
758
759
760 @Test
761 void testEventChangesGFunctionDefinitionDelay() {
762
763 double maxCheck = 5;
764 double tolerance = 1e-6;
765 double t1 = 11, t2 = 11.1, t3 = 11.2;
766
767 List<Event> events = new ArrayList<>();
768
769 boolean[] swap = new boolean[1];
770 final TimeDetector detectorA =
771 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
772 @Override
773 public ODEEventHandler getHandler() {
774 return (state, detector, increasing) -> {
775 swap[0] = true;
776 return super.getHandler().eventOccurred(state, detector, increasing);
777 };
778 }
779 };
780 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
781 final TimeDetector detectorD = new ContinuousDetector(maxCheck, tolerance, 100, events, t3);
782 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
783
784 @Override
785 public double g(ODEStateAndDerivative state) {
786 if (!swap[0]) {
787 return detectorB.g(state);
788 } else {
789 return detectorD.g(state);
790 }
791 }
792
793 };
794 ODEIntegrator integrator =
795 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
796 integrator.addEventDetector(detectorA);
797 integrator.addEventDetector(detectorC);
798
799
800 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
801
802
803 assertEquals(2, events.size());
804 assertEquals(t1, events.get(0).getT(), tolerance);
805 assertTrue(events.get(0).isIncreasing());
806 assertSame(detectorA, events.get(0).getDetector());
807 assertEquals(t3, events.get(1).getT(), tolerance);
808 assertTrue(events.get(1).isIncreasing());
809 assertSame(detectorC, events.get(1).getDetector());
810 }
811
812
813
814
815
816
817 @Test
818 void testEventChangesGFunctionDefinitionAccelerate() {
819
820 double maxCheck = 5;
821 double tolerance = 1e-6;
822 double t1 = 11, t2 = 11.1, t3 = 11.2;
823
824 List<Event> events = new ArrayList<>();
825
826 boolean[] swap = new boolean[1];
827 final TimeDetector detectorA =
828 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
829 @Override
830 public ODEEventHandler getHandler() {
831 return (state, detector, increasing) -> {
832 swap[0] = true;
833 return super.getHandler().eventOccurred(state, detector, increasing);
834 };
835 }
836 };
837 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
838 final TimeDetector detectorD = new ContinuousDetector(maxCheck, tolerance, 100, events, t3);
839 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
840
841 @Override
842 public double g(ODEStateAndDerivative state) {
843 if (swap[0]) {
844 return detectorB.g(state);
845 } else {
846 return detectorD.g(state);
847 }
848 }
849
850 };
851 ODEIntegrator integrator =
852 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
853 integrator.addEventDetector(detectorA);
854 integrator.addEventDetector(detectorC);
855
856
857 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
858
859
860 assertEquals(2, events.size());
861 assertEquals(t1, events.get(0).getT(), tolerance);
862 assertTrue(events.get(0).isIncreasing());
863 assertSame(detectorA, events.get(0).getDetector());
864 assertEquals(t2, events.get(1).getT(), tolerance);
865 assertTrue(events.get(1).isIncreasing());
866 assertSame(detectorC, events.get(1).getDetector());
867 }
868
869
870 @Test
871 void testToleranceStop() {
872
873 double maxCheck = 10;
874 double tolerance = 1e-18;
875 double t1 = 15.1;
876
877 List<Event> events = new ArrayList<>();
878 TimeDetector detectorA = new FlatDetector(maxCheck, tolerance, 100, Action.STOP, events, t1);
879 ODEIntegrator integrator =
880 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
881 integrator.addEventDetector(detectorA);
882
883
884 ODEStateAndDerivative finalState =
885 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
886
887
888 assertEquals(1, events.size());
889
890 assertEquals(t1, events.get(0).getT(), tolerance);
891 assertTrue(events.get(0).isIncreasing());
892 assertSame(detectorA, events.get(0).getDetector());
893 assertEquals(t1, finalState.getTime(), tolerance);
894
895
896 finalState = integrator.integrate(new Equation(), finalState, 30.0);
897
898
899 assertEquals(30.0, finalState.getTime(), 0.0);
900 }
901
902
903
904
905
906 @Test
907 void testLongInitialZero() {
908
909 double maxCheck = 10;
910 double tolerance = 1;
911
912 List<Event> events = new ArrayList<>();
913 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, Action.STOP, events, -50) {
914 @Override
915 public double g(ODEStateAndDerivative state) {
916 if (state.getTime() < 2) {
917 return 0;
918 } else {
919 return super.g(state);
920 }
921 }
922 };
923 ODEIntegrator integrator =
924 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
925 integrator.addEventDetector(detectorA);
926
927
928 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
929
930
931 assertEquals(0, events.size());
932 }
933
934
935
936
937
938
939 @Test
940 void testShortBracketingInterval() {
941
942 double maxCheck = 10;
943 double tolerance = 1e-6;
944 final double t1 = FastMath.nextUp(10.0), t2 = 10.5;
945
946 List<Event> events = new ArrayList<>();
947
948 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events) {
949 @Override
950 public double g(ODEStateAndDerivative state) {
951 final double t = state.getTime();
952 if (t < t1) {
953 return -1;
954 } else if (t < t2) {
955 return 1;
956 } else {
957 return -1;
958 }
959 }
960 };
961 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, t1);
962 ODEIntegrator integrator =
963 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
964 integrator.addEventDetector(detectorA);
965 integrator.addEventDetector(detectorB);
966
967
968 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 30.0);
969
970
971 assertEquals(3, events.size());
972 assertEquals(t1, events.get(0).getT(), tolerance);
973 assertTrue(events.get(0).isIncreasing());
974 assertSame(detectorA, events.get(0).getDetector());
975 assertEquals(t1, events.get(1).getT(), tolerance);
976 assertTrue(events.get(1).isIncreasing());
977 assertSame(detectorB, events.get(1).getDetector());
978 assertEquals(t2, events.get(2).getT(), tolerance);
979 assertFalse(events.get(2).isIncreasing());
980 assertSame(detectorA, events.get(2).getDetector());
981 }
982
983
984 @Test
985 void testEventStepHandler() {
986
987 double tolerance = 1e-18;
988 ODEIntegrator integrator =
989 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
990 integrator.addEventDetector(new TimeDetector(100, tolerance, 100, 5));
991 StepHandler stepHandler = new StepHandler();
992 integrator.addStepHandler(stepHandler);
993
994
995 ODEStateAndDerivative finalState = integrator
996 .integrate(new Equation(), new ODEState(0, new double[2]), 10);
997
998
999 assertEquals(10.0, finalState.getTime(), tolerance);
1000 assertEquals(0.0,
1001 stepHandler.initialState.getTime(), tolerance);
1002 assertEquals(10.0, stepHandler.finalTime, tolerance);
1003 assertEquals(10.0,
1004 stepHandler.finalState.getTime(), tolerance);
1005 ODEStateInterpolator interpolator = stepHandler.interpolators.get(0);
1006 assertEquals(0.0,
1007 interpolator.getPreviousState().getTime(), tolerance);
1008 assertEquals(5.0,
1009 interpolator.getCurrentState().getTime(), tolerance);
1010 interpolator = stepHandler.interpolators.get(1);
1011 assertEquals(5.0,
1012 interpolator.getPreviousState().getTime(), tolerance);
1013 assertEquals(10.0,
1014 interpolator.getCurrentState().getTime(), tolerance);
1015 assertEquals(2, stepHandler.interpolators.size());
1016 }
1017
1018
1019 @Test
1020 void testEventCausedByDerivativesReset() {
1021
1022 TimeDetector detectorA = new TimeDetector(10, 1e-6, 100, Action.RESET_STATE, 15.0) {
1023 @Override
1024 public ODEEventHandler getHandler() {
1025 return new ODEEventHandler() {
1026 @Override
1027 public Action eventOccurred(ODEStateAndDerivative state, ODEEventDetector detector, boolean increasing) {
1028 return Action.RESET_STATE;
1029 }
1030 @Override
1031 public ODEState resetState(ODEEventDetector detector, ODEStateAndDerivative state) {
1032 return null;
1033 }
1034 };
1035 }
1036 };
1037 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1038 integrator.addEventDetector(detectorA);
1039
1040 try {
1041
1042 integrator.integrate(new Equation(), new ODEState(0, new double[2]), 20.0);
1043 fail("Expected Exception");
1044 } catch (NullPointerException e) {
1045
1046 }
1047 }
1048
1049 @Test
1050 void testResetChangesSign() {
1051 OrdinaryDifferentialEquation equation = new OrdinaryDifferentialEquation() {
1052 public int getDimension() { return 1; }
1053 public double[] computeDerivatives(double t, double[] y) { return new double[] { 1.0 }; }
1054 };
1055
1056 LutherIntegrator integrator = new LutherIntegrator(20.0);
1057 final double small = 1.0e-10;
1058 ResetChangesSignGenerator eventsGenerator = new ResetChangesSignGenerator(6.0, 9.0, -0.5 * small, 8.0, small, 1000);
1059 integrator.addEventDetector(eventsGenerator);
1060 final ODEStateAndDerivative end = integrator.integrate(equation, new ODEState(0.0, new double[1]), 100.0);
1061 assertEquals(2, eventsGenerator.getCount());
1062 assertEquals(9.0, end.getCompleteState()[0], 1.0e-12);
1063 assertEquals(9.0 + 0.5 * small, end.getTime(), 1.0e-12);
1064 }
1065
1066
1067
1068
1069
1070
1071 @Test
1072 void testCloseEventsFirstOneIsResetReverse() {
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 ODEIntegrator integrator =
1084 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
1085
1086
1087 double t1 = -1;
1088 TimeDetector detector1 = new TimeDetector(10, 1e-9, 100, Action.RESET_DERIVATIVES, t1);
1089 integrator.addEventDetector(detector1);
1090 TimeDetector detector2 = new TimeDetector(11, 1e-9, 100, t1 - 1e-15, t1 - 4.9);
1091 integrator.addEventDetector(detector2);
1092
1093
1094 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20);
1095
1096
1097 List<Event> events1 = detector1.getEvents();
1098 assertEquals(1, events1.size());
1099 assertEquals(t1, events1.get(0).getT(), 0.0);
1100 List<Event> events2 = detector2.getEvents();
1101 assertEquals(0, events2.size());
1102 }
1103
1104 @Test
1105 void testCloseEventsReverse() {
1106
1107 double e = 1e-15;
1108 ODEIntegrator integrator =
1109 new DormandPrince853Integrator(e, 100.0, 1e-7, 1e-7);
1110
1111 TimeDetector detector1 = new TimeDetector(10, 1, 100, -5);
1112 integrator.addEventDetector(detector1);
1113 TimeDetector detector2 = new TimeDetector(10, 1, 100, -5.5);
1114 integrator.addEventDetector(detector2);
1115
1116
1117 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20);
1118
1119
1120 List<Event> events1 = detector1.getEvents();
1121 assertEquals(1, events1.size());
1122 assertEquals(-5, events1.get(0).getT(), 0.0);
1123 List<Event> events2 = detector2.getEvents();
1124 assertEquals(1, events2.size());
1125 assertEquals(-5.5, events2.get(0).getT(), 0.0);
1126 }
1127
1128 @Test
1129 void testSimultaneousEventsReverse() {
1130
1131 ODEIntegrator integrator =
1132 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
1133
1134 TimeDetector detector1 = new TimeDetector(10, 1, 100, -5);
1135 integrator.addEventDetector(detector1);
1136 TimeDetector detector2 = new TimeDetector(10, 1, 100, -5);
1137 integrator.addEventDetector(detector2);
1138
1139
1140 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20);
1141
1142
1143 List<Event> events1 = detector1.getEvents();
1144 assertEquals(1, events1.size());
1145 assertEquals(-5, events1.get(0).getT(), 0.0);
1146 List<Event> events2 = detector2.getEvents();
1147 assertEquals(1, events2.size());
1148 assertEquals(-5, events2.get(0).getT(), 0.0);
1149 }
1150
1151
1152
1153
1154
1155
1156 @Test
1157 void testSimultaneousEventsResetReverse() {
1158
1159 double tol = 1e-10;
1160 ODEIntegrator integrator =
1161 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
1162 boolean[] firstEventOccurred = {false};
1163 List<Event> events = new ArrayList<>();
1164
1165 TimeDetector detector1 = new TimeDetector(10, tol, 100, events, -5) {
1166 @Override
1167 public ODEEventHandler getHandler() {
1168 return (state, detector, increasing) -> {
1169 firstEventOccurred[0] = true;
1170 super.getHandler().eventOccurred(state, detector, increasing);
1171 return Action.RESET_STATE;
1172 };
1173 }
1174 };
1175 integrator.addEventDetector(detector1);
1176
1177 TimeDetector detector2 = new TimeDetector(1, tol, 100, events, -1, -3, -5) {
1178 @Override
1179 public double g(final ODEStateAndDerivative state) {
1180 if (firstEventOccurred[0]) {
1181 return super.g(state);
1182 }
1183 return new TimeDetector(1, tol, 100, -5).g(state);
1184 }
1185 };
1186 integrator.addEventDetector(detector2);
1187
1188
1189 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20);
1190
1191
1192
1193 assertEquals(-5, events.get(0).getT(), 0.0);
1194 assertTrue(events.get(0).isIncreasing());
1195 assertEquals(detector1, events.get(0).getDetector());
1196 assertEquals(-5, events.get(1).getT(), 0.0);
1197 assertTrue(events.get(1).isIncreasing());
1198 assertEquals(detector2, events.get(1).getDetector());
1199 assertEquals(2, events.size());
1200 }
1201
1202
1203
1204
1205
1206
1207
1208 @Test
1209 void testSimultaneousDiscontinuousEventsAfterResetReverse() {
1210
1211 double t = -FastMath.PI;
1212 double tol = 1e-10;
1213 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1214 List<Event> events = new ArrayList<>();
1215
1216 TimeDetector resetDetector =
1217 new ResetDetector(10, tol, 100, events, new ODEState(t, new double[]{1e100, 0}), t);
1218 integrator.addEventDetector(resetDetector);
1219 List<BaseDetector> detectors = new ArrayList<>();
1220 for (int i = 0; i < 2; i++) {
1221 BaseDetector detector1 = new StateDetector(10, tol, 100, events, 0.0);
1222 integrator.addEventDetector(detector1);
1223 detectors.add(detector1);
1224 }
1225
1226
1227 integrator.integrate(new Equation(), new ODEState(0, new double[]{-1e100, 0}), -10);
1228
1229
1230 assertEquals(t, events.get(0).getT(), tol);
1231 assertTrue(events.get(0).isIncreasing());
1232 assertEquals(resetDetector, events.get(0).getDetector());
1233
1234 assertEquals(t, events.get(1).getT(), tol);
1235 assertFalse(events.get(1).isIncreasing());
1236 assertEquals(detectors.get(0), events.get(1).getDetector());
1237 assertEquals(t, events.get(2).getT(), tol);
1238 assertFalse(events.get(2).isIncreasing());
1239 assertEquals(detectors.get(1), events.get(2).getDetector());
1240 assertEquals(3, events.size());
1241 }
1242
1243
1244
1245
1246
1247
1248 @Test
1249 void testFastSwitchingReverse() {
1250
1251
1252 ODEIntegrator integrator =
1253 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1254
1255 TimeDetector detector1 = new TimeDetector(10, 0.2, 100, -9.9, -10.1, -12);
1256 integrator.addEventDetector(detector1);
1257
1258
1259 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20);
1260
1261
1262
1263 List<Event> events1 = detector1.getEvents();
1264 assertEquals(1, events1.size());
1265 assertEquals(-9.9, events1.get(0).getT(), 0.2);
1266 assertTrue(events1.get(0).isIncreasing());
1267 }
1268
1269
1270 @Test
1271 void testTrickyCaseLowerReverse() {
1272
1273 double maxCheck = 10;
1274 double tolerance = 1e-6;
1275 double t1 = -1.0, t2 = -15, t3 = -16, t4 = -17, t5 = -18;
1276
1277 List<Event> events = new ArrayList<>();
1278 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t3);
1279 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, -50, t1, t2, t5);
1280 TimeDetector detectorC = new TimeDetector(maxCheck, tolerance, 100, Action.RESET_DERIVATIVES, events, t4);
1281
1282 ODEIntegrator integrator =
1283 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1284 integrator.addEventDetector(detectorA);
1285 integrator.addEventDetector(detectorB);
1286 integrator.addEventDetector(detectorC);
1287
1288
1289 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1290
1291
1292
1293
1294 assertEquals(5, events.size());
1295 assertEquals(t1, events.get(0).getT(), tolerance);
1296 assertFalse(events.get(0).isIncreasing());
1297 assertEquals(t2, events.get(1).getT(), tolerance);
1298 assertTrue(events.get(1).isIncreasing());
1299 assertEquals(t3, events.get(2).getT(), tolerance);
1300 assertTrue(events.get(2).isIncreasing());
1301 assertEquals(t4, events.get(3).getT(), tolerance);
1302 assertTrue(events.get(3).isIncreasing());
1303 assertEquals(t5, events.get(4).getT(), tolerance);
1304 assertFalse(events.get(4).isIncreasing());
1305 }
1306
1307
1308
1309
1310
1311
1312 @Test
1313 void testRootFindingToleranceReverse() {
1314
1315 double maxCheck = 10;
1316 double t2 = -11, t3 = t2 - 1e-5;
1317 List<Event> events = new ArrayList<>();
1318 TimeDetector detectorA = new TimeDetector(maxCheck, 1e-6, 100, events, t2);
1319 FlatDetector detectorB = new FlatDetector(maxCheck, 0.5, 100, events, t3);
1320 ODEIntegrator integrator =
1321 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1322 integrator.addEventDetector(detectorA);
1323 integrator.addEventDetector(detectorB);
1324
1325
1326 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1327
1328
1329
1330
1331 assertSame(detectorB, events.get(0).getDetector());
1332 assertSame(detectorA, events.get(1).getDetector());
1333 assertTrue(events.get(0).getT() > events.get(1).getT());
1334
1335
1336 assertEquals(2, events.size());
1337 assertEquals(t3, events.get(0).getT(), 0.5);
1338 assertTrue(events.get(0).isIncreasing());
1339 assertEquals(t2, events.get(1).getT(), 1e-6);
1340 assertTrue(events.get(1).isIncreasing());
1341 }
1342
1343
1344 @Test
1345 void testRootPlusToleranceHasWrongSignReverse() {
1346
1347 double maxCheck = 10;
1348 double tolerance = 1e-6;
1349 final double toleranceB = 0.3;
1350 double t1 = -11, t2 = -11.1, t3 = -11.2;
1351
1352 List<Event> events = new ArrayList<>();
1353 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t2);
1354 TimeDetector detectorB = new TimeDetector(maxCheck, toleranceB, 100, events, -50, t1, t3);
1355 ODEIntegrator integrator =
1356 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1357 integrator.addEventDetector(detectorA);
1358 integrator.addEventDetector(detectorB);
1359
1360
1361 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1362
1363
1364
1365 assertEquals(3, events.size());
1366 assertEquals(t1, events.get(0).getT(), toleranceB);
1367 assertTrue(events.get(0).isIncreasing());
1368 assertSame(detectorB, events.get(0).getDetector());
1369 assertEquals(t3, events.get(1).getT(), toleranceB);
1370 assertFalse(events.get(1).isIncreasing());
1371 assertSame(detectorB, events.get(1).getDetector());
1372 assertEquals(t2, events.get(2).getT(), tolerance);
1373 assertTrue(events.get(2).isIncreasing());
1374 assertSame(detectorA, events.get(2).getDetector());
1375
1376 assertTrue(events.get(0).getT() >= events.get(1).getT());
1377 assertTrue(events.get(1).getT() >= events.get(2).getT());
1378 }
1379
1380
1381 @Test
1382 void testRootPlusToleranceHasWrongSignAndLessThanTbReverse() {
1383
1384
1385 double maxCheck = 10;
1386 double tolerance = 0.5;
1387 double t1 = -11, t2 = -11.4, t3 = -12.0;
1388
1389 List<Event> events = new ArrayList<>();
1390 TimeDetector detectorB = new FlatDetector(maxCheck, tolerance, 100, events, t1, t2, t3);
1391 ODEIntegrator integrator =
1392 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1393 integrator.addEventDetector(detectorB);
1394
1395
1396 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1397
1398
1399
1400 assertEquals(1, events.size());
1401 assertEquals(t1, events.get(0).getT(), tolerance);
1402 assertTrue(events.get(0).isIncreasing());
1403 assertSame(detectorB, events.get(0).getDetector());
1404 }
1405
1406
1407
1408
1409
1410 @Test
1411 void testDoubleRootReverse() {
1412
1413 double maxCheck = 10;
1414 double tolerance = 1e-6;
1415 double t1 = -11;
1416
1417 List<Event> events = new ArrayList<>();
1418 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t1);
1419 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, t1, t1);
1420 ODEIntegrator integrator =
1421 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1422 integrator.addEventDetector(detectorA);
1423 integrator.addEventDetector(detectorB);
1424
1425
1426 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1427
1428
1429 assertEquals(1, events.size());
1430 assertEquals(t1, events.get(0).getT(), 0.0);
1431 assertTrue(events.get(0).isIncreasing());
1432 assertSame(detectorA, events.get(0).getDetector());
1433
1434 assertEquals(0.0, detectorB.g(state(t1)));
1435 assertTrue(detectorB.g(state(t1 + 1e-6)) < 0);
1436 assertTrue(detectorB.g(state(t1 - 1e-6)) < 0);
1437 }
1438
1439
1440
1441
1442
1443 @Test
1444 void testDoubleRootOppositeSignReverse() {
1445
1446 double maxCheck = 10;
1447 double tolerance = 1e-6;
1448 double t1 = -11;
1449
1450 List<Event> events = new ArrayList<>();
1451 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events, t1);
1452 TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, -50, t1, t1);
1453 detectorB.g(state(t1));
1454 ODEIntegrator integrator =
1455 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1456 integrator.addEventDetector(detectorA);
1457 integrator.addEventDetector(detectorB);
1458
1459
1460 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1461
1462
1463 assertEquals(1, events.size());
1464 assertEquals(t1, events.get(0).getT(), 0.0);
1465 assertTrue(events.get(0).isIncreasing());
1466 assertSame(detectorA, events.get(0).getDetector());
1467
1468 assertEquals(0.0, detectorB.g(state(t1)), 0.0);
1469 assertTrue(detectorB.g(state(t1 + 1e-6)) > 0);
1470 assertTrue(detectorB.g(state(t1 - 1e-6)) > 0);
1471 }
1472
1473
1474 @Test
1475 void testZeroAtBeginningAndEndOfIntervalReverse() {
1476
1477 double maxCheck = 10;
1478 double tolerance = 1e-6;
1479 double t1 = -10, t2 = -20;
1480
1481 List<Event> events = new ArrayList<>();
1482 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, -50, t1, t2);
1483 ODEIntegrator integrator =
1484 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1485 integrator.addEventDetector(detectorA);
1486
1487
1488 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1489
1490
1491 assertEquals(2, events.size());
1492 assertEquals(t1, events.get(0).getT(), 0.0);
1493 assertTrue(events.get(0).isIncreasing());
1494 assertSame(detectorA, events.get(0).getDetector());
1495 assertEquals(t2, events.get(1).getT(), 0.0);
1496 assertFalse(events.get(1).isIncreasing());
1497 assertSame(detectorA, events.get(1).getDetector());
1498 }
1499
1500
1501 @Test
1502 void testZeroAtBeginningAndEndOfIntervalOppositeSignReverse() {
1503
1504 double maxCheck = 10;
1505 double tolerance = 1e-6;
1506 double t1 = -10, t2 = -20;
1507
1508 List<Event> events = new ArrayList<>();
1509 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1, t2);
1510 ODEIntegrator integrator =
1511 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1512 integrator.addEventDetector(detectorA);
1513
1514
1515 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1516
1517
1518 assertEquals(2, events.size());
1519 assertEquals(t1, events.get(0).getT(), 0.0);
1520 assertFalse(events.get(0).isIncreasing());
1521 assertSame(detectorA, events.get(0).getDetector());
1522 assertEquals(t2, events.get(1).getT(), 0.0);
1523 assertTrue(events.get(1).isIncreasing());
1524 assertSame(detectorA, events.get(1).getDetector());
1525 }
1526
1527
1528 @Test
1529 void testMultipleBackupsReverse() {
1530
1531 double maxCheck = 10;
1532 double tolerance = 1e-6;
1533 double t1 = -11.0, t2 = -12, t3 = -13, t4 = -14, t5 = -15, t6 = -16, t7 = -17;
1534
1535 List<Event> events = new ArrayList<>();
1536 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t6);
1537 TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, -50, t1, t3, t4, t7);
1538 TimeDetector detectorC = new ContinuousDetector(maxCheck, tolerance, 100, events, -50, t2, t5);
1539
1540 ODEIntegrator integrator =
1541 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1542 integrator.addEventDetector(detectorA);
1543 integrator.addEventDetector(detectorB);
1544 integrator.addEventDetector(detectorC);
1545
1546
1547 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1548
1549
1550
1551 assertEquals(5, events.size());
1552 assertEquals(t1, events.get(0).getT(), tolerance);
1553 assertTrue(events.get(0).isIncreasing());
1554 assertEquals(detectorB, events.get(0).getDetector());
1555 assertEquals(t2, events.get(1).getT(), tolerance);
1556 assertTrue(events.get(1).isIncreasing());
1557 assertEquals(detectorC, events.get(1).getDetector());
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568 assertEquals(t5, events.get(2).getT(), tolerance);
1569 assertFalse(events.get(2).isIncreasing());
1570 assertEquals(detectorC, events.get(2).getDetector());
1571 assertEquals(t6, events.get(3).getT(), tolerance);
1572 assertTrue(events.get(3).isIncreasing());
1573 assertEquals(detectorA, events.get(3).getDetector());
1574 assertEquals(t7, events.get(4).getT(), tolerance);
1575 assertFalse(events.get(4).isIncreasing());
1576 assertEquals(detectorB, events.get(4).getDetector());
1577 }
1578
1579
1580 @Test
1581 void testEventCausedByStateResetReverse() {
1582
1583 double maxCheck = 10;
1584 double tolerance = 1e-6;
1585 double t1 = -15.0;
1586 final ODEState newState = new ODEState(t1, new double[]{20, 0});
1587
1588 List<Event> events = new ArrayList<>();
1589 TimeDetector detectorA = new ResetDetector(maxCheck, tolerance, 100, events, newState, t1);
1590 BaseDetector detectorB = new StateDetector(maxCheck, tolerance, 100, events, 1);
1591
1592 ODEIntegrator integrator =
1593 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1594 integrator.addEventDetector(detectorA);
1595 integrator.addEventDetector(detectorB);
1596
1597
1598 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -40.0);
1599
1600
1601
1602 assertEquals(3, events.size());
1603 assertEquals(t1, events.get(0).getT(), tolerance);
1604 assertTrue(events.get(0).isIncreasing());
1605 assertEquals(detectorA, events.get(0).getDetector());
1606 assertEquals(t1, events.get(1).getT(), tolerance);
1607 assertFalse(events.get(1).isIncreasing());
1608 assertEquals(detectorB, events.get(1).getDetector());
1609 assertEquals(t1 - 19, events.get(2).getT(), tolerance);
1610 assertTrue(events.get(2).isIncreasing());
1611 assertEquals(detectorB, events.get(2).getDetector());
1612 }
1613
1614
1615 @Test
1616 void testConvergenceTooTightReverse() {
1617
1618 double maxCheck = 10;
1619 double tolerance = 1e-18;
1620 double t1 = -15;
1621
1622 List<Event> events = new ArrayList<>();
1623 TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1);
1624 ODEIntegrator integrator =
1625 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1626 integrator.addEventDetector(detectorA);
1627
1628
1629 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1630
1631
1632 assertEquals(1, events.size());
1633 assertEquals(t1, events.get(0).getT(), 0.0);
1634 assertTrue(events.get(0).isIncreasing());
1635 assertSame(detectorA, events.get(0).getDetector());
1636 }
1637
1638
1639 @Test
1640 void testToleranceMismatchReverse() {
1641
1642 double maxCheck = 10;
1643 double tolerance = 1e-18;
1644 double t1 = -15.1;
1645
1646 List<Event> events = new ArrayList<>();
1647 TimeDetector detectorA = new FlatDetector(maxCheck, tolerance, 100, events, t1);
1648 ODEIntegrator integrator =
1649 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1650 integrator.addEventDetector(detectorA);
1651
1652
1653 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1654
1655
1656 assertEquals(1, events.size());
1657
1658 assertEquals(t1, events.get(0).getT(), 1e-3);
1659 assertTrue(events.get(0).isIncreasing());
1660 assertSame(detectorA, events.get(0).getDetector());
1661 }
1662
1663
1664
1665
1666
1667
1668
1669 @Test
1670 void testEventChangesGFunctionDefinitionReverse() {
1671
1672 double maxCheck = 5;
1673 double tolerance = 1e-6;
1674 double t1 = -11, t2 = -19;
1675
1676 List<Event> events = new ArrayList<>();
1677
1678 boolean[] swap = new boolean[1];
1679 final TimeDetector detectorA = new ContinuousDetector(maxCheck, tolerance, 100, events, t1) {
1680 @Override
1681 public ODEEventHandler getHandler() {
1682 return (state, detector, increasing) -> {
1683 swap[0] = true;
1684 return super.getHandler().eventOccurred(state, detector, increasing);
1685 };
1686 }
1687 };
1688 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
1689 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
1690
1691 @Override
1692 public double g(ODEStateAndDerivative state) {
1693 if (swap[0]) {
1694 return detectorB.g(state);
1695 } else {
1696 return 1;
1697 }
1698 }
1699
1700 };
1701 ODEIntegrator integrator =
1702 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1703 integrator.addEventDetector(detectorA);
1704 integrator.addEventDetector(detectorC);
1705
1706
1707 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1708
1709
1710 assertEquals(2, events.size());
1711 assertEquals(t1, events.get(0).getT(), tolerance);
1712 assertTrue(events.get(0).isIncreasing());
1713 assertSame(detectorA, events.get(0).getDetector());
1714 assertEquals(t2, events.get(1).getT(), tolerance);
1715 assertTrue(events.get(1).isIncreasing());
1716 assertSame(detectorC, events.get(1).getDetector());
1717 }
1718
1719
1720
1721
1722
1723
1724 @Test
1725 void testEventChangesGFunctionDefinitionCancelReverse() {
1726
1727 double maxCheck = 5;
1728 double tolerance = 1e-6;
1729 double t1 = -11, t2 = -11.1;
1730
1731 List<Event> events = new ArrayList<>();
1732
1733 boolean[] swap = new boolean[1];
1734 final TimeDetector detectorA =
1735 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
1736 @Override
1737 public ODEEventHandler getHandler() {
1738 return (state, detector, increasing) -> {
1739 swap[0] = true;
1740 return super.getHandler().eventOccurred(state, detector, increasing);
1741 };
1742 }
1743 };
1744 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
1745 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
1746
1747 @Override
1748 public double g(ODEStateAndDerivative state) {
1749 if (!swap[0]) {
1750 return detectorB.g(state);
1751 } else {
1752 return 1;
1753 }
1754 }
1755
1756 };
1757 ODEIntegrator integrator =
1758 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1759 integrator.addEventDetector(detectorA);
1760 integrator.addEventDetector(detectorC);
1761
1762
1763 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1764
1765
1766 assertEquals(1, events.size());
1767 assertEquals(t1, events.get(0).getT(), tolerance);
1768 assertTrue(events.get(0).isIncreasing());
1769 assertSame(detectorA, events.get(0).getDetector());
1770 }
1771
1772
1773
1774
1775
1776
1777
1778 @Test
1779 void testEventChangesGFunctionDefinitionDelayReverse() {
1780
1781 double maxCheck = 5;
1782 double tolerance = 1e-6;
1783 double t1 = -11, t2 = -11.1, t3 = -11.2;
1784
1785 List<Event> events = new ArrayList<>();
1786
1787 boolean[] swap = new boolean[1];
1788 final TimeDetector detectorA =
1789 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
1790 @Override
1791 public ODEEventHandler getHandler() {
1792 return (state, detector, increasing) -> {
1793 swap[0] = true;
1794 return super.getHandler().eventOccurred(state, detector, increasing);
1795 };
1796 }
1797 };
1798 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
1799 final TimeDetector detectorD = new ContinuousDetector(maxCheck, tolerance, 100, events, t3);
1800 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
1801
1802 @Override
1803 public double g(ODEStateAndDerivative state) {
1804 if (!swap[0]) {
1805 return detectorB.g(state);
1806 } else {
1807 return detectorD.g(state);
1808 }
1809 }
1810
1811 };
1812 ODEIntegrator integrator =
1813 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1814 integrator.addEventDetector(detectorA);
1815 integrator.addEventDetector(detectorC);
1816
1817
1818 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1819
1820
1821 assertEquals(2, events.size());
1822 assertEquals(t1, events.get(0).getT(), tolerance);
1823 assertTrue(events.get(0).isIncreasing());
1824 assertSame(detectorA, events.get(0).getDetector());
1825 assertEquals(t3, events.get(1).getT(), tolerance);
1826 assertTrue(events.get(1).isIncreasing());
1827 assertSame(detectorC, events.get(1).getDetector());
1828 }
1829
1830
1831
1832
1833
1834
1835 @Test
1836 void testEventChangesGFunctionDefinitionAccelerateReverse() {
1837
1838 double maxCheck = 5;
1839 double tolerance = 1e-6;
1840 double t1 = -11, t2 = -11.1, t3 = -11.2;
1841
1842 List<Event> events = new ArrayList<>();
1843
1844 boolean[] swap = new boolean[1];
1845 final TimeDetector detectorA =
1846 new ContinuousDetector(maxCheck, tolerance, 100, Action.RESET_EVENTS, events, t1) {
1847 @Override
1848 public ODEEventHandler getHandler() {
1849 return (state, detector, increasing) -> {
1850 swap[0] = true;
1851 return super.getHandler().eventOccurred(state, detector, increasing);
1852 };
1853 }
1854 };
1855 final TimeDetector detectorB = new ContinuousDetector(maxCheck, tolerance, 100, events, t2);
1856 final TimeDetector detectorD = new ContinuousDetector(maxCheck, tolerance, 100, events, t3);
1857 BaseDetector detectorC = new BaseDetector(maxCheck, tolerance, 100, Action.CONTINUE, events) {
1858
1859 @Override
1860 public double g(ODEStateAndDerivative state) {
1861 if (swap[0]) {
1862 return detectorB.g(state);
1863 } else {
1864 return detectorD.g(state);
1865 }
1866 }
1867
1868 };
1869 ODEIntegrator integrator =
1870 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1871 integrator.addEventDetector(detectorA);
1872 integrator.addEventDetector(detectorC);
1873
1874
1875 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1876
1877
1878 assertEquals(2, events.size());
1879 assertEquals(t1, events.get(0).getT(), tolerance);
1880 assertTrue(events.get(0).isIncreasing());
1881 assertSame(detectorA, events.get(0).getDetector());
1882 assertEquals(t2, events.get(1).getT(), tolerance);
1883 assertTrue(events.get(1).isIncreasing());
1884 assertSame(detectorC, events.get(1).getDetector());
1885 }
1886
1887
1888 @Test
1889 void testToleranceStopReverse() {
1890
1891 double maxCheck = 10;
1892 double tolerance = 1e-18;
1893 double t1 = -15.1;
1894
1895 List<Event> events = new ArrayList<>();
1896 TimeDetector detectorA = new FlatDetector(maxCheck, tolerance, 100, Action.STOP, events, t1);
1897 ODEIntegrator integrator =
1898 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1899 integrator.addEventDetector(detectorA);
1900
1901
1902 ODEStateAndDerivative finalState =
1903 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1904
1905
1906 assertEquals(1, events.size());
1907
1908 assertEquals(t1, events.get(0).getT(), tolerance);
1909 assertTrue(events.get(0).isIncreasing());
1910 assertSame(detectorA, events.get(0).getDetector());
1911 assertEquals(t1, finalState.getTime(), tolerance);
1912
1913
1914 finalState = integrator.integrate(new Equation(), finalState, -30.0);
1915
1916
1917 assertEquals(-30.0, finalState.getTime(), 0.0);
1918 }
1919
1920
1921
1922
1923
1924 @Test
1925 void testLongInitialZeroReverse() {
1926
1927 double maxCheck = 10;
1928 double tolerance = 1;
1929
1930 List<Event> events = new ArrayList<>();
1931 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, Action.STOP, events, 50) {
1932 @Override
1933 public double g(ODEStateAndDerivative state) {
1934 if (state.getTime() > -2) {
1935 return 0;
1936 } else {
1937 return super.g(state);
1938 }
1939 }
1940 };
1941 ODEIntegrator integrator =
1942 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1943 integrator.addEventDetector(detectorA);
1944
1945
1946 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1947
1948
1949 assertEquals(0, events.size());
1950 }
1951
1952
1953
1954
1955
1956
1957 @Test
1958 void testShortBracketingIntervalReverse() {
1959
1960 double maxCheck = 10;
1961 double tolerance = 1e-6;
1962 final double t1 = FastMath.nextDown(-10.0), t2 = -10.5;
1963
1964 List<Event> events = new ArrayList<>();
1965
1966 TimeDetector detectorA = new TimeDetector(maxCheck, tolerance, 100, events) {
1967 @Override
1968 public double g(ODEStateAndDerivative state) {
1969 final double t = state.getTime();
1970 if (t > t1) {
1971 return -1;
1972 } else if (t > t2) {
1973 return 1;
1974 } else {
1975 return -1;
1976 }
1977 }
1978 };
1979 TimeDetector detectorB = new TimeDetector(maxCheck, tolerance, 100, events, t1);
1980 ODEIntegrator integrator =
1981 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
1982 integrator.addEventDetector(detectorA);
1983 integrator.addEventDetector(detectorB);
1984
1985
1986 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -30.0);
1987
1988
1989 assertEquals(3, events.size());
1990 assertEquals(t1, events.get(0).getT(), tolerance);
1991 assertFalse(events.get(0).isIncreasing());
1992 assertSame(detectorA, events.get(0).getDetector());
1993 assertEquals(t1, events.get(1).getT(), tolerance);
1994 assertTrue(events.get(1).isIncreasing());
1995 assertSame(detectorB, events.get(1).getDetector());
1996 assertEquals(t2, events.get(2).getT(), tolerance);
1997 assertTrue(events.get(2).isIncreasing());
1998 assertSame(detectorA, events.get(2).getDetector());
1999 }
2000
2001
2002 @Test
2003 void testEventStepHandlerReverse() {
2004
2005 double tolerance = 1e-18;
2006 ODEIntegrator integrator =
2007 new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
2008 integrator.addEventDetector(new TimeDetector(100, tolerance, 100, -5));
2009 StepHandler stepHandler = new StepHandler();
2010 integrator.addStepHandler(stepHandler);
2011
2012
2013 ODEStateAndDerivative finalState = integrator
2014 .integrate(new Equation(), new ODEState(0, new double[2]), -10);
2015
2016
2017 assertEquals(-10.0, finalState.getTime(), tolerance);
2018 assertEquals(0.0,
2019 stepHandler.initialState.getTime(), tolerance);
2020 assertEquals(-10.0, stepHandler.finalTime, tolerance);
2021 assertEquals(-10.0,
2022 stepHandler.finalState.getTime(), tolerance);
2023 ODEStateInterpolator interpolator = stepHandler.interpolators.get(0);
2024 assertEquals(0.0,
2025 interpolator.getPreviousState().getTime(), tolerance);
2026 assertEquals(-5.0,
2027 interpolator.getCurrentState().getTime(), tolerance);
2028 interpolator = stepHandler.interpolators.get(1);
2029 assertEquals(-5.0,
2030 interpolator.getPreviousState().getTime(), tolerance);
2031 assertEquals(-10.0,
2032 interpolator.getCurrentState().getTime(), tolerance);
2033 assertEquals(2, stepHandler.interpolators.size());
2034 }
2035
2036
2037 @Test
2038 void testEventCausedByDerivativesResetReverse() {
2039
2040 TimeDetector detectorA = new TimeDetector(10, 1e-6, 100, Action.RESET_STATE, -15.0) {
2041 @Override
2042 public ODEEventHandler getHandler() {
2043 return new ODEEventHandler() {
2044 @Override
2045 public Action eventOccurred(ODEStateAndDerivative state,
2046 ODEEventDetector detector, boolean increasing) {
2047 return Action.RESET_STATE;
2048 }
2049 @Override
2050 public ODEState resetState(ODEEventDetector detector, ODEStateAndDerivative state) {
2051 return null;
2052 }
2053 };
2054 }
2055 };
2056 ODEIntegrator integrator = new DormandPrince853Integrator(10, 10, 1e-7, 1e-7);
2057 integrator.addEventDetector(detectorA);
2058
2059 try {
2060
2061 integrator.integrate(new Equation(), new ODEState(0, new double[2]), -20.0);
2062 fail("Expected Exception");
2063 } catch (NullPointerException e) {
2064
2065 }
2066 }
2067
2068 @Test
2069 void testResetChangesSignReverse() {
2070 OrdinaryDifferentialEquation equation = new OrdinaryDifferentialEquation() {
2071 public int getDimension() { return 1; }
2072 public double[] computeDerivatives(double t, double[] y) { return new double[] { 1.0 }; }
2073 };
2074
2075 LutherIntegrator integrator = new LutherIntegrator(20.0);
2076 final double small = 1.0e-10;
2077 ResetChangesSignGenerator eventsGenerator = new ResetChangesSignGenerator(-6.0, -9.0, +0.5 * small, 8.0, small, 1000);
2078 integrator.addEventDetector(eventsGenerator);
2079 final ODEStateAndDerivative end = integrator.integrate(equation, new ODEState(0.0, new double[1]), -100.0);
2080 assertEquals(2, eventsGenerator.getCount());
2081 assertEquals(-9.0, end.getCompleteState()[0], 1.0e-12);
2082 assertEquals(-9.0 - 0.5 * small, end.getTime(), 1.0e-12);
2083 }
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093 private ODEStateAndDerivative state(double t) {
2094 return new ODEStateAndDerivative(t, new double[0], new double[0]);
2095 }
2096
2097
2098 private static abstract class BaseDetector implements ODEEventDetector {
2099
2100 private final AdaptableInterval maxCheck;
2101 private final int maxIter;
2102 private final BracketingNthOrderBrentSolver solver;
2103 protected final Action action;
2104
2105
2106 private final List<Event> events;
2107
2108 public BaseDetector(final double maxCheck, final double threshold, final int maxIter,
2109 Action action, List<Event> events) {
2110 this.maxCheck = (s, isForward) -> maxCheck;
2111 this.maxIter = maxIter;
2112 this.solver = new BracketingNthOrderBrentSolver(0, threshold, 0, 5);
2113 this.action = action;
2114 this.events = events;
2115 }
2116
2117 public AdaptableInterval getMaxCheckInterval() {
2118 return maxCheck;
2119 }
2120
2121 public int getMaxIterationCount() {
2122 return maxIter;
2123 }
2124
2125 public BracketedUnivariateSolver<UnivariateFunction> getSolver() {
2126 return solver;
2127 }
2128
2129
2130
2131
2132
2133
2134 public List<Event> getEvents() {
2135 return events;
2136 }
2137
2138 @Override
2139 public ODEEventHandler getHandler() {
2140 return new ODEEventHandler() {
2141 @Override
2142 public Action eventOccurred(ODEStateAndDerivative state,
2143 ODEEventDetector detector, boolean increasing) {
2144 events.add(new Event(state, detector, increasing));
2145 return action;
2146 }
2147 };
2148 }
2149
2150 }
2151
2152
2153 private static class IntervalDetector extends BaseDetector implements ODEEventDetector {
2154
2155
2156 protected final double start;
2157
2158
2159 protected final double end;
2160
2161 public IntervalDetector(final double maxCheck, final double threshold, final int maxIter,
2162 final Action action, final double startTime, final double endTime) {
2163 super(maxCheck, threshold, maxIter, action, new ArrayList<>());
2164 this.start = startTime;
2165 this.end = endTime;
2166 }
2167
2168 @Override
2169 public double g(final ODEStateAndDerivative state) {
2170 final double t = state.getTime();
2171 return (t - start) * (end - t);
2172 }
2173
2174 }
2175
2176
2177 private static class TimeDetector extends BaseDetector implements ODEEventDetector {
2178
2179
2180 protected final double[] eventTs;
2181
2182
2183
2184
2185
2186
2187 public TimeDetector(final double maxCheck, final double threshold, final int maxIter,
2188 double... eventTs) {
2189 this(maxCheck, threshold, maxIter, Action.CONTINUE, eventTs);
2190 }
2191
2192 public TimeDetector(final double maxCheck, final double threshold, final int maxIter,
2193 List<Event> events, double... eventTs) {
2194 this(maxCheck, threshold, maxIter, Action.CONTINUE, events, eventTs);
2195 }
2196
2197 public TimeDetector(final double maxCheck, final double threshold, final int maxIter,
2198 Action action, double... eventTs) {
2199 this(maxCheck, threshold, maxIter, action, new ArrayList<Event>(), eventTs);
2200 }
2201
2202 public TimeDetector(final double maxCheck, final double threshold, final int maxIter,
2203 Action action, List<Event> events, double... eventTs) {
2204 super(maxCheck, threshold, maxIter, action, events);
2205 this.eventTs = eventTs.clone();
2206 Arrays.sort(this.eventTs);
2207 }
2208
2209 @Override
2210 public double g(final ODEStateAndDerivative state) {
2211 final double t = state.getTime();
2212 int i = 0;
2213 while (i < eventTs.length && t > eventTs[i]) {
2214 i++;
2215 }
2216 i--;
2217 if (i < 0) {
2218 return t - eventTs[0];
2219 } else {
2220 int sign = (i % 2) * 2 - 1;
2221 return -sign * (t - eventTs[i]);
2222 }
2223 }
2224
2225 }
2226
2227 private static class Event {
2228
2229 private final ODEStateAndDerivative state;
2230 private final boolean increasing;
2231 private final ODEEventDetector detector;
2232
2233 public Event(ODEStateAndDerivative state, ODEEventDetector detector, boolean increasing) {
2234 this.increasing = increasing;
2235 this.state = state;
2236 this.detector = detector;
2237 }
2238
2239 public boolean isIncreasing() {
2240 return increasing;
2241 }
2242
2243 public double getT() {
2244 return state.getTime();
2245 }
2246
2247 public ODEEventDetector getDetector() {
2248 return detector;
2249 }
2250
2251 @Override
2252 public String toString() {
2253 return "Event{" +
2254 "increasing=" + increasing +
2255 ", time=" + state.getTime() +
2256 ", state=" + Arrays.toString(state.getCompleteState()) +
2257 '}';
2258 }
2259 }
2260
2261
2262
2263
2264
2265 private static class FlatDetector extends TimeDetector {
2266
2267 public FlatDetector(double maxCheck, double threshold, int maxIter,
2268 double... eventTs) {
2269 super(maxCheck, threshold, maxIter, eventTs);
2270 }
2271
2272 public FlatDetector(double maxCheck, double threshold, int maxIter,
2273 List<Event> events, double... eventTs) {
2274 super(maxCheck, threshold, maxIter, events, eventTs);
2275 }
2276
2277 public FlatDetector(double maxCheck, double threshold, int maxIter,
2278 Action action, List<Event> events, double... eventTs) {
2279 super(maxCheck, threshold, maxIter, action, events, eventTs);
2280 }
2281
2282 @Override
2283 public double g(ODEStateAndDerivative state) {
2284 final double g = super.g(state);
2285 return FastMath.signum(g);
2286 }
2287
2288 }
2289
2290
2291 private static class ContinuousDetector extends TimeDetector {
2292
2293 public ContinuousDetector(double maxCheck, double threshold, int maxIter,
2294 List<Event> events, double... eventTs) {
2295 super(maxCheck, threshold, maxIter, events, eventTs);
2296 }
2297
2298 public ContinuousDetector(double maxCheck, double threshold, int maxIter,
2299 Action action, List<Event> events, double... eventTs) {
2300 super(maxCheck, threshold, maxIter, action, events, eventTs);
2301 }
2302
2303 @Override
2304 public double g(ODEStateAndDerivative state) {
2305 final double t = state.getTime();
2306 int i = 0;
2307 while (i < eventTs.length && t > eventTs[i]) {
2308 i++;
2309 }
2310 i--;
2311 if (i < 0) {
2312 return t - eventTs[0];
2313 } else if (i < eventTs.length - 1) {
2314 int sign = (i % 2) * 2 - 1;
2315 return -sign * (t - eventTs[i]) * (eventTs[i + 1] - t);
2316 } else {
2317 int sign = (i % 2) * 2 - 1;
2318 return -sign * (t - eventTs[i]);
2319 }
2320 }
2321 }
2322
2323
2324 private static class ResetDetector extends TimeDetector {
2325
2326 private final ODEState resetState;
2327
2328 public ResetDetector(double maxCheck, double threshold, int maxIter,
2329 List<Event> events, ODEState state, double eventT) {
2330 super(maxCheck, threshold, maxIter, Action.RESET_STATE, events, eventT);
2331 this.resetState = state;
2332 }
2333
2334 @Override
2335 public ODEEventHandler getHandler() {
2336 return new ODEEventHandler() {
2337 @Override
2338 public Action eventOccurred(ODEStateAndDerivative state,
2339 ODEEventDetector detector, boolean increasing) {
2340 return ResetDetector.super.getHandler().eventOccurred(state, detector, increasing);
2341 }
2342 @Override
2343 public ODEState resetState(ODEEventDetector detector, ODEStateAndDerivative state) {
2344 assertEquals(eventTs[0], state.getTime(), 0);
2345 return resetState;
2346 }
2347 };
2348 }
2349
2350 }
2351
2352
2353 private static class StateDetector extends BaseDetector {
2354
2355 private final double triggerState;
2356
2357 public StateDetector(double maxCheck, double threshold, int maxIter,
2358 List<Event> events, double triggerState) {
2359 super(maxCheck, threshold, maxIter, Action.CONTINUE, events);
2360 this.triggerState = triggerState;
2361 }
2362
2363 @Override
2364 public double g(ODEStateAndDerivative state) {
2365 return state.getPrimaryState()[0] - this.triggerState;
2366 }
2367 }
2368
2369
2370 public static class Equation implements OrdinaryDifferentialEquation {
2371
2372 public int getDimension() {
2373 return 2;
2374 }
2375
2376 public double[] computeDerivatives(double t, double[] y) {
2377 return new double[]{1.0, 2.0};
2378 }
2379
2380 }
2381
2382 private static class StepHandler implements ODEStepHandler {
2383
2384 private ODEStateAndDerivative initialState;
2385 private double finalTime;
2386 private List<ODEStateInterpolator> interpolators = new ArrayList<>();
2387 private ODEStateAndDerivative finalState;
2388
2389 @Override
2390 public void init(ODEStateAndDerivative initialState, double finalTime) {
2391 this.initialState = initialState;
2392 this.finalTime = finalTime;
2393 }
2394
2395 @Override
2396 public void handleStep(ODEStateInterpolator interpolator) {
2397 this.interpolators.add(interpolator);
2398 }
2399
2400 @Override
2401 public void finish(ODEStateAndDerivative finalState) {
2402 this.finalState = finalState;
2403 }
2404 }
2405
2406 private class ResetChangesSignGenerator implements ODEEventDetector {
2407
2408 private final AdaptableInterval maxCheck;
2409 private final int maxIter;
2410 private final BracketingNthOrderBrentSolver solver;
2411 final double y1;
2412 final double y2;
2413 final double change;
2414 int count;
2415
2416 public ResetChangesSignGenerator(final double y1, final double y2, final double change,
2417 final double maxCheck, final double threshold, final int maxIter) {
2418 this.maxCheck = (s, isForward) -> maxCheck;
2419 this.maxIter = maxIter;
2420 this.solver = new BracketingNthOrderBrentSolver(0, threshold, 0, 5);
2421 this.y1 = y1;
2422 this.y2 = y2;
2423 this.change = change;
2424 this.count = 0;
2425 }
2426
2427 public AdaptableInterval getMaxCheckInterval() {
2428 return maxCheck;
2429 }
2430
2431 public int getMaxIterationCount() {
2432 return maxIter;
2433 }
2434
2435 public BracketedUnivariateSolver<UnivariateFunction> getSolver() {
2436 return solver;
2437 }
2438
2439 public ODEEventHandler getHandler() {
2440 return new ODEEventHandler() {
2441 public Action eventOccurred(ODEStateAndDerivative s, ODEEventDetector detector, boolean increasing) {
2442 return ++count < 2 ? Action.RESET_STATE : Action.STOP;
2443 }
2444
2445 public ODEState resetState(ODEEventDetector detector, ODEStateAndDerivative s) {
2446 return new ODEState(s.getTime(), new double[] { s.getCompleteState()[0] + change });
2447 }
2448 };
2449 }
2450
2451 public double g(ODEStateAndDerivative s) {
2452 return (s.getCompleteState()[0] - y1) * (s.getCompleteState()[0] - y2);
2453 }
2454
2455 public int getCount() {
2456 return count;
2457 }
2458
2459 }
2460
2461 }