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