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