1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.ode.events;
18
19 import org.apache.commons.math4.legacy.analysis.solvers.BracketingNthOrderBrentSolver;
20 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
21 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
22 import org.apache.commons.math4.legacy.exception.NoBracketingException;
23 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
24 import org.apache.commons.math4.legacy.ode.FirstOrderDifferentialEquations;
25 import org.apache.commons.math4.legacy.ode.FirstOrderIntegrator;
26 import org.apache.commons.math4.legacy.ode.nonstiff.DormandPrince853Integrator;
27 import org.apache.commons.rng.UniformRandomProvider;
28 import org.apache.commons.rng.simple.RandomSource;
29 import org.apache.commons.math4.core.jdkmath.JdkMath;
30 import org.junit.Assert;
31 import org.junit.Test;
32
33 public class EventFilterTest {
34
35 @Test
36 public void testHistoryIncreasingForward() {
37
38
39 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
40 0.5 * JdkMath.PI, 30.5 * JdkMath.PI, JdkMath.PI, -1);
41
42
43 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
44 0, 30.5 * JdkMath.PI, JdkMath.PI, -1);
45
46
47 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
48 1.5 * JdkMath.PI, 30.5 * JdkMath.PI, JdkMath.PI, +1);
49 }
50
51 @Test
52 public void testHistoryIncreasingBackward() {
53
54
55 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
56 0.5 * JdkMath.PI, -30.5 * JdkMath.PI, JdkMath.PI, -1);
57
58
59 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
60 0, -30.5 * JdkMath.PI, JdkMath.PI, +1);
61
62
63 testHistory(FilterType.TRIGGER_ONLY_INCREASING_EVENTS,
64 1.5 * JdkMath.PI, -30.5 * JdkMath.PI, JdkMath.PI, -1);
65 }
66
67 @Test
68 public void testHistoryDecreasingForward() {
69
70
71 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
72 0.5 * JdkMath.PI, 30.5 * JdkMath.PI, 0, +1);
73
74
75 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
76 0, 30.5 * JdkMath.PI, 0, +1);
77
78
79 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
80 1.5 * JdkMath.PI, 30.5 * JdkMath.PI, 0, +1);
81 }
82
83 @Test
84 public void testHistoryDecreasingBackward() {
85
86
87 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
88 0.5 * JdkMath.PI, -30.5 * JdkMath.PI, 0, -1);
89
90
91 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
92 0, -30.5 * JdkMath.PI, 0, -1);
93
94
95 testHistory(FilterType.TRIGGER_ONLY_DECREASING_EVENTS,
96 1.5 * JdkMath.PI, -30.5 * JdkMath.PI, 0, +1);
97 }
98
99 public void testHistory(FilterType type, double t0, double t1, double refSwitch, double signEven) {
100 Event onlyIncreasing = new Event(false, true);
101 EventFilter eventFilter =
102 new EventFilter(onlyIncreasing, type);
103 eventFilter.init(t0, new double[] {1.0, 0.0}, t1);
104
105
106 double h = JdkMath.copySign(0.05, t1 - t0);
107 double n = (int) JdkMath.floor((t1 - t0) / h);
108 for (int i = 0; i < n; ++i) {
109 double t = t0 + i * h;
110 eventFilter.g(t, new double[] { JdkMath.sin(t), JdkMath.cos(t) });
111 }
112
113
114 UniformRandomProvider rng = RandomSource.TWO_CMRES.create(0xb0e7401265af8cd3L);
115 for (int i = 0; i < 5000; i++) {
116 double t = t0 + (t1 - t0) * rng.nextDouble();
117 double g = eventFilter.g(t, new double[] { JdkMath.sin(t), JdkMath.cos(t) });
118 int turn = (int) JdkMath.floor((t - refSwitch) / (2 * JdkMath.PI));
119 if ((turn & 1) == 0) {
120 Assert.assertEquals( signEven * JdkMath.sin(t), g, 1.0e-10);
121 } else {
122 Assert.assertEquals(-signEven * JdkMath.sin(t), g, 1.0e-10);
123 }
124 }
125 }
126
127 @Test
128 public void testIncreasingOnly()
129 throws DimensionMismatchException, NumberIsTooSmallException,
130 MaxCountExceededException, NoBracketingException {
131 double e = 1e-15;
132 FirstOrderIntegrator integrator;
133 integrator = new DormandPrince853Integrator(1.0e-3, 100.0, 1e-7, 1e-7);
134 Event allEvents = new Event(true, true);
135 integrator.addEventHandler(allEvents, 0.1, e, 1000,
136 new BracketingNthOrderBrentSolver(1.0e-7, 5));
137 Event onlyIncreasing = new Event(false, true);
138 integrator.addEventHandler(new EventFilter(onlyIncreasing,
139 FilterType.TRIGGER_ONLY_INCREASING_EVENTS),
140 0.1, e, 100,
141 new BracketingNthOrderBrentSolver(1.0e-7, 5));
142 double t0 = 0.5 * JdkMath.PI;
143 double tEnd = 5.5 * JdkMath.PI;
144 double[] y = { 0.0, 1.0 };
145 Assert.assertEquals(tEnd,
146 integrator.integrate(new SineCosine(), t0, y, tEnd, y),
147 1.0e-7);
148
149 Assert.assertEquals(5, allEvents.getEventCount());
150 Assert.assertEquals(2, onlyIncreasing.getEventCount());
151 }
152
153 @Test
154 public void testDecreasingOnly()
155 throws DimensionMismatchException, NumberIsTooSmallException,
156 MaxCountExceededException, NoBracketingException {
157 double e = 1e-15;
158 FirstOrderIntegrator integrator;
159 integrator = new DormandPrince853Integrator(1.0e-3, 100.0, 1e-7, 1e-7);
160 Event allEvents = new Event(true, true);
161 integrator.addEventHandler(allEvents, 0.1, e, 1000,
162 new BracketingNthOrderBrentSolver(1.0e-7, 5));
163 Event onlyDecreasing = new Event(true, false);
164 integrator.addEventHandler(new EventFilter(onlyDecreasing,
165 FilterType.TRIGGER_ONLY_DECREASING_EVENTS),
166 0.1, e, 1000,
167 new BracketingNthOrderBrentSolver(1.0e-7, 5));
168 double t0 = 0.5 * JdkMath.PI;
169 double tEnd = 5.5 * JdkMath.PI;
170 double[] y = { 0.0, 1.0 };
171 Assert.assertEquals(tEnd,
172 integrator.integrate(new SineCosine(), t0, y, tEnd, y),
173 1.0e-7);
174
175 Assert.assertEquals(5, allEvents.getEventCount());
176 Assert.assertEquals(3, onlyDecreasing.getEventCount());
177 }
178
179 @Test
180 public void testTwoOppositeFilters()
181 throws DimensionMismatchException, NumberIsTooSmallException,
182 MaxCountExceededException, NoBracketingException {
183 double e = 1e-15;
184 FirstOrderIntegrator integrator;
185 integrator = new DormandPrince853Integrator(1.0e-3, 100.0, 1e-7, 1e-7);
186 Event allEvents = new Event(true, true);
187 integrator.addEventHandler(allEvents, 0.1, e, 1000,
188 new BracketingNthOrderBrentSolver(1.0e-7, 5));
189 Event onlyIncreasing = new Event(false, true);
190 integrator.addEventHandler(new EventFilter(onlyIncreasing,
191 FilterType.TRIGGER_ONLY_INCREASING_EVENTS),
192 0.1, e, 1000,
193 new BracketingNthOrderBrentSolver(1.0e-7, 5));
194 Event onlyDecreasing = new Event(true, false);
195 integrator.addEventHandler(new EventFilter(onlyDecreasing,
196 FilterType.TRIGGER_ONLY_DECREASING_EVENTS),
197 0.1, e, 1000,
198 new BracketingNthOrderBrentSolver(1.0e-7, 5));
199 double t0 = 0.5 * JdkMath.PI;
200 double tEnd = 5.5 * JdkMath.PI;
201 double[] y = { 0.0, 1.0 };
202 Assert.assertEquals(tEnd,
203 integrator.integrate(new SineCosine(), t0, y, tEnd, y),
204 1.0e-7);
205
206 Assert.assertEquals(5, allEvents.getEventCount());
207 Assert.assertEquals(2, onlyIncreasing.getEventCount());
208 Assert.assertEquals(3, onlyDecreasing.getEventCount());
209 }
210
211 private static final class SineCosine implements FirstOrderDifferentialEquations {
212 @Override
213 public int getDimension() {
214 return 2;
215 }
216
217 @Override
218 public void computeDerivatives(double t, double[] y, double[] yDot) {
219 yDot[0] = y[1];
220 yDot[1] = -y[0];
221 }
222 }
223
224
225 protected static class Event implements EventHandler {
226
227 private final boolean expectDecreasing;
228 private final boolean expectIncreasing;
229 private int eventCount;
230
231 public Event(boolean expectDecreasing, boolean expectIncreasing) {
232 this.expectDecreasing = expectDecreasing;
233 this.expectIncreasing = expectIncreasing;
234 }
235
236 public int getEventCount() {
237 return eventCount;
238 }
239
240 @Override
241 public void init(double t0, double[] y0, double t) {
242 eventCount = 0;
243 }
244
245 @Override
246 public double g(double t, double[] y) {
247 return y[0];
248 }
249
250 @Override
251 public Action eventOccurred(double t, double[] y, boolean increasing) {
252 if (increasing) {
253 Assert.assertTrue(expectIncreasing);
254 } else {
255 Assert.assertTrue(expectDecreasing);
256 }
257 eventCount++;
258 return Action.RESET_STATE;
259 }
260
261 @Override
262 public void resetState(double t, double[] y) {
263
264 }
265 }
266 }