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.BracketedRealFieldUnivariateSolver;
21 import org.hipparchus.analysis.solvers.BracketedUnivariateSolver;
22 import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver;
23 import org.hipparchus.analysis.solvers.FieldBracketingNthOrderBrentSolver;
24 import org.hipparchus.ode.ExpandableODE;
25 import org.hipparchus.ode.FieldExpandableODE;
26 import org.hipparchus.ode.FieldODEIntegrator;
27 import org.hipparchus.ode.FieldODEState;
28 import org.hipparchus.ode.FieldODEStateAndDerivative;
29 import org.hipparchus.ode.FieldOrdinaryDifferentialEquation;
30 import org.hipparchus.ode.ODEIntegrator;
31 import org.hipparchus.ode.ODEState;
32 import org.hipparchus.ode.ODEStateAndDerivative;
33 import org.hipparchus.ode.OrdinaryDifferentialEquation;
34 import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
35 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
36 import org.hipparchus.util.Binary64;
37 import org.hipparchus.util.Binary64Field;
38 import org.junit.Assert;
39 import org.junit.Test;
40
41
42
43
44
45
46 public class EventsScheduling {
47
48 @Test
49 public void testForward() {
50 doTest(0.0, 1.0, 32);
51 }
52
53 @Test
54 public void testBackward() {
55 doTest(1.0, 0.0, 32);
56 }
57
58 @Test
59 public void testFieldForward() {
60 doTestField(0.0, 1.0, 32);
61 }
62
63 @Test
64 public void testFieldBackward() {
65 doTestField(1.0, 0.0, 32);
66 }
67
68 private static void doTest(final double start, final double stop, final int expectedCalls) {
69
70 final ODEIntegrator integrator =
71 new DormandPrince853Integrator(10, 100.0, 1e-7, 1e-7);
72
73
74
75 final ScheduleChecker checker = new ScheduleChecker(start, stop);
76 integrator.addStepHandler((interpolator) -> {
77 checker.callTime(interpolator.getPreviousState().getTime());
78 checker.callTime(interpolator.getCurrentState().getTime());
79 });
80
81 for (int i = 0; i < 10; ++i) {
82 integrator.addEventDetector(new SimpleDetector(0.0625 * (i + 1), checker,
83 1.0, 1.0e-9, 100));
84 }
85
86 final OrdinaryDifferentialEquation ode = new OrdinaryDifferentialEquation() {
87 public int getDimension() {
88 return 1;
89 }
90 public double[] computeDerivatives(double t, double[] y) {
91 return new double[] { 1 };
92 }
93 };
94
95 final ODEState initialState = new ODEState(start, new double[] { 0.0 });
96
97 integrator.integrate(new ExpandableODE(ode), initialState, stop);
98
99 Assert.assertEquals(expectedCalls, checker.calls);
100
101 }
102
103 private static void doTestField(final double start, final double stop, final int expectedCalls) {
104
105 final FieldODEIntegrator<Binary64> integrator =
106 new DormandPrince853FieldIntegrator<Binary64>(Binary64Field.getInstance(), 10, 100.0, 1e-7, 1e-7);
107
108
109
110 final ScheduleChecker checker = new ScheduleChecker(start, stop);
111 integrator.addStepHandler((interpolator) -> {
112 checker.callTime(interpolator.getPreviousState().getTime().getReal());
113 checker.callTime(interpolator.getCurrentState().getTime().getReal());
114 });
115
116 for (int i = 0; i < 10; ++i) {
117 integrator.addEventDetector(new SimpleFieldDetector(0.0625 * (i + 1), checker, 1.0, 1.0e-9, 100));
118 }
119
120 final FieldOrdinaryDifferentialEquation<Binary64> ode =
121 new FieldOrdinaryDifferentialEquation<Binary64>() {
122 public int getDimension() {
123 return 1;
124 }
125 public Binary64[] computeDerivatives(Binary64 t, Binary64[] y) {
126 return new Binary64[] { Binary64.ONE };
127 }
128 };
129
130 final FieldODEState<Binary64> initialState =
131 new FieldODEState<>(new Binary64(start), new Binary64[] { Binary64.ZERO });
132
133 integrator.integrate(new FieldExpandableODE<>(ode), initialState, new Binary64(stop));
134
135 Assert.assertEquals(expectedCalls, checker.calls);
136
137 }
138
139
140 private static class ScheduleChecker {
141
142 private final double start;
143 private final double stop;
144 private double last;
145 private int calls;
146
147 ScheduleChecker(final double start, final double stop) {
148 this.start = start;
149 this.stop = stop;
150 this.last = Double.NaN;
151 this.calls = 0;
152 }
153
154 void callTime(final double time) {
155 if (!Double.isNaN(last)) {
156
157 if (start < stop) {
158
159 Assert.assertTrue(time >= start);
160 Assert.assertTrue(time <= stop);
161 Assert.assertTrue(time >= last);
162 } else {
163
164 Assert.assertTrue(time <= start);
165 Assert.assertTrue(time >= stop);
166 Assert.assertTrue(time <= last);
167 }
168 }
169 last = time;
170 ++calls;
171 }
172
173 }
174
175 private static class SimpleDetector implements ODEEventDetector {
176
177 private final AdaptableInterval maxCheck;
178 private final int maxIter;
179 private final BracketingNthOrderBrentSolver solver;
180 private final double tEvent;
181 private final ScheduleChecker checker;
182 SimpleDetector(final double tEvent, final ScheduleChecker checker,
183 final double maxCheck, final double threshold, final int maxIter) {
184 this.maxCheck = s -> maxCheck;
185 this.maxIter = maxIter;
186 this.solver = new BracketingNthOrderBrentSolver(0, threshold, 0, 5);
187 this.tEvent = tEvent;
188 this.checker = checker;
189 }
190
191 public AdaptableInterval getMaxCheckInterval() {
192 return maxCheck;
193 }
194
195 public int getMaxIterationCount() {
196 return maxIter;
197 }
198
199 public BracketedUnivariateSolver<UnivariateFunction> getSolver() {
200 return solver;
201 }
202
203 public ODEEventHandler getHandler() {
204 return (state, detector, increasing) -> {
205 checker.callTime(state.getTime());
206 return Action.CONTINUE;
207 };
208 }
209
210 @Override
211 public double g(final ODEStateAndDerivative state) {
212 return state.getTime() - tEvent;
213 }
214
215 }
216
217 private static class SimpleFieldDetector implements FieldODEEventDetector<Binary64> {
218
219 private final FieldAdaptableInterval<Binary64> maxCheck;
220 private final int maxIter;
221 private final BracketedRealFieldUnivariateSolver<Binary64> solver;
222 private final double tEvent;
223 private final ScheduleChecker checker;
224
225 SimpleFieldDetector(final double tEvent, final ScheduleChecker checker,
226 final double maxCheck, final double threshold, final int maxIter) {
227 this.maxCheck = s -> maxCheck;
228 this.maxIter = maxIter;
229 this.solver = new FieldBracketingNthOrderBrentSolver<>(new Binary64(0),
230 new Binary64(threshold),
231 new Binary64(0),
232 5);
233 this.tEvent = tEvent;
234 this.checker = checker;
235 }
236
237 public FieldAdaptableInterval<Binary64> getMaxCheckInterval() {
238 return maxCheck;
239 }
240
241 public int getMaxIterationCount() {
242 return maxIter;
243 }
244
245 public BracketedRealFieldUnivariateSolver<Binary64> getSolver() {
246 return solver;
247 }
248
249 public FieldODEEventHandler<Binary64> getHandler() {
250 return (state, detector, increasing) -> {
251 checker.callTime(state.getTime().getReal());
252 return Action.CONTINUE;
253 };
254 }
255
256 @Override
257 public Binary64 g(final FieldODEStateAndDerivative<Binary64> state) {
258 return state.getTime().subtract(tEvent);
259 }
260
261 }
262
263 }