1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math4.legacy.ode;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.apache.commons.math4.legacy.core.RealFieldElement;
24 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
25 import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
26 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
27 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
28 import org.apache.commons.math4.legacy.ode.sampling.FieldStepHandler;
29 import org.apache.commons.math4.legacy.ode.sampling.FieldStepInterpolator;
30 import org.apache.commons.math4.core.jdkmath.JdkMath;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class ContinuousOutputFieldModel<T extends RealFieldElement<T>>
82 implements FieldStepHandler<T> {
83
84
85 private T initialTime;
86
87
88 private T finalTime;
89
90
91 private boolean forward;
92
93
94 private int index;
95
96
97 private List<FieldStepInterpolator<T>> steps;
98
99
100
101
102 public ContinuousOutputFieldModel() {
103 steps = new ArrayList<>();
104 initialTime = null;
105 finalTime = null;
106 forward = true;
107 index = 0;
108 }
109
110
111
112
113
114
115
116
117
118
119
120 public void append(final ContinuousOutputFieldModel<T> model)
121 throws MathIllegalArgumentException, MaxCountExceededException {
122
123 if (model.steps.isEmpty()) {
124 return;
125 }
126
127 if (steps.isEmpty()) {
128 initialTime = model.initialTime;
129 forward = model.forward;
130 } else {
131
132
133 final FieldODEStateAndDerivative<T> s1 = steps.get(0).getPreviousState();
134 final FieldODEStateAndDerivative<T> s2 = model.steps.get(0).getPreviousState();
135 checkDimensionsEquality(s1.getStateDimension(), s2.getStateDimension());
136 checkDimensionsEquality(s1.getNumberOfSecondaryStates(), s2.getNumberOfSecondaryStates());
137 for (int i = 0; i < s1.getNumberOfSecondaryStates(); ++i) {
138 checkDimensionsEquality(s1.getSecondaryStateDimension(i), s2.getSecondaryStateDimension(i));
139 }
140
141 if (forward ^ model.forward) {
142 throw new MathIllegalArgumentException(LocalizedFormats.PROPAGATION_DIRECTION_MISMATCH);
143 }
144
145 final FieldStepInterpolator<T> lastInterpolator = steps.get(index);
146 final T current = lastInterpolator.getCurrentState().getTime();
147 final T previous = lastInterpolator.getPreviousState().getTime();
148 final T step = current.subtract(previous);
149 final T gap = model.getInitialTime().subtract(current);
150 if (gap.abs().subtract(step.abs().multiply(1.0e-3)).getReal() > 0) {
151 throw new MathIllegalArgumentException(LocalizedFormats.HOLE_BETWEEN_MODELS_TIME_RANGES,
152 gap.abs().getReal());
153 }
154 }
155
156 steps.addAll(model.steps);
157
158 index = steps.size() - 1;
159 finalTime = (steps.get(index)).getCurrentState().getTime();
160 }
161
162
163
164
165
166
167 private void checkDimensionsEquality(final int d1, final int d2)
168 throws DimensionMismatchException {
169 if (d1 != d2) {
170 throw new DimensionMismatchException(d2, d1);
171 }
172 }
173
174
175 @Override
176 public void init(final FieldODEStateAndDerivative<T> initialState, final T t) {
177 initialTime = initialState.getTime();
178 finalTime = t;
179 forward = true;
180 index = 0;
181 steps.clear();
182 }
183
184
185
186
187
188
189
190
191
192 @Override
193 public void handleStep(final FieldStepInterpolator<T> interpolator, final boolean isLast)
194 throws MaxCountExceededException {
195
196 if (steps.isEmpty()) {
197 initialTime = interpolator.getPreviousState().getTime();
198 forward = interpolator.isForward();
199 }
200
201 steps.add(interpolator);
202
203 if (isLast) {
204 finalTime = interpolator.getCurrentState().getTime();
205 index = steps.size() - 1;
206 }
207 }
208
209
210
211
212
213 public T getInitialTime() {
214 return initialTime;
215 }
216
217
218
219
220
221 public T getFinalTime() {
222 return finalTime;
223 }
224
225
226
227
228
229
230 public FieldODEStateAndDerivative<T> getInterpolatedState(final T time) {
231
232
233 int iMin = 0;
234 final FieldStepInterpolator<T> sMin = steps.get(iMin);
235 T tMin = sMin.getPreviousState().getTime().add(sMin.getCurrentState().getTime()).multiply(0.5);
236
237 int iMax = steps.size() - 1;
238 final FieldStepInterpolator<T> sMax = steps.get(iMax);
239 T tMax = sMax.getPreviousState().getTime().add(sMax.getCurrentState().getTime()).multiply(0.5);
240
241
242
243 if (locatePoint(time, sMin) <= 0) {
244 index = iMin;
245 return sMin.getInterpolatedState(time);
246 }
247 if (locatePoint(time, sMax) >= 0) {
248 index = iMax;
249 return sMax.getInterpolatedState(time);
250 }
251
252
253 while (iMax - iMin > 5) {
254
255
256 final FieldStepInterpolator<T> si = steps.get(index);
257 final int location = locatePoint(time, si);
258 if (location < 0) {
259 iMax = index;
260 tMax = si.getPreviousState().getTime().add(si.getCurrentState().getTime()).multiply(0.5);
261 } else if (location > 0) {
262 iMin = index;
263 tMin = si.getPreviousState().getTime().add(si.getCurrentState().getTime()).multiply(0.5);
264 } else {
265
266 return si.getInterpolatedState(time);
267 }
268
269
270 final int iMed = (iMin + iMax) / 2;
271 final FieldStepInterpolator<T> sMed = steps.get(iMed);
272 final T tMed = sMed.getPreviousState().getTime().add(sMed.getCurrentState().getTime()).multiply(0.5);
273
274 if (tMed.subtract(tMin).abs().subtract(1.0e-6).getReal() < 0 ||
275 tMax.subtract(tMed).abs().subtract(1.0e-6).getReal() < 0) {
276
277 index = iMed;
278 } else {
279
280
281
282 final T d12 = tMax.subtract(tMed);
283 final T d23 = tMed.subtract(tMin);
284 final T d13 = tMax.subtract(tMin);
285 final T dt1 = time.subtract(tMax);
286 final T dt2 = time.subtract(tMed);
287 final T dt3 = time.subtract(tMin);
288 final T iLagrange = dt2.multiply(dt3).multiply(d23).multiply(iMax).
289 subtract(dt1.multiply(dt3).multiply(d13).multiply(iMed)).
290 add( dt1.multiply(dt2).multiply(d12).multiply(iMin)).
291 divide(d12.multiply(d23).multiply(d13));
292 index = (int) JdkMath.rint(iLagrange.getReal());
293 }
294
295
296 final int low = JdkMath.max(iMin + 1, (9 * iMin + iMax) / 10);
297 final int high = JdkMath.min(iMax - 1, (iMin + 9 * iMax) / 10);
298 if (index < low) {
299 index = low;
300 } else if (index > high) {
301 index = high;
302 }
303 }
304
305
306 index = iMin;
307 while (index <= iMax && locatePoint(time, steps.get(index)) > 0) {
308 ++index;
309 }
310
311 return steps.get(index).getInterpolatedState(time);
312 }
313
314
315
316
317
318
319
320
321 private int locatePoint(final T time, final FieldStepInterpolator<T> interval) {
322 if (forward) {
323 if (time.subtract(interval.getPreviousState().getTime()).getReal() < 0) {
324 return -1;
325 } else if (time.subtract(interval.getCurrentState().getTime()).getReal() > 0) {
326 return +1;
327 } else {
328 return 0;
329 }
330 }
331 if (time.subtract(interval.getPreviousState().getTime()).getReal() > 0) {
332 return -1;
333 } else if (time.subtract(interval.getCurrentState().getTime()).getReal() < 0) {
334 return +1;
335 } else {
336 return 0;
337 }
338 }
339 }