1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.ode;
24
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.hipparchus.exception.LocalizedCoreFormats;
30 import org.hipparchus.exception.MathIllegalArgumentException;
31 import org.hipparchus.exception.MathIllegalStateException;
32 import org.hipparchus.ode.sampling.ODEStateInterpolator;
33 import org.hipparchus.ode.sampling.ODEStepHandler;
34 import org.hipparchus.util.FastMath;
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
82
83
84
85
86
87
88
89
90
91
92 public class DenseOutputModel implements ODEStepHandler, Serializable {
93
94
95 private static final long serialVersionUID = 20160328L;
96
97
98 private double initialTime;
99
100
101 private double finalTime;
102
103
104 private boolean forward;
105
106
107 private int index;
108
109
110 private List<ODEStateInterpolator> steps;
111
112
113
114
115 public DenseOutputModel() {
116 steps = new ArrayList<>();
117 initialTime = Double.NaN;
118 finalTime = Double.NaN;
119 forward = true;
120 index = 0;
121 }
122
123
124
125
126
127
128
129
130
131 public void append(final DenseOutputModel model)
132 throws MathIllegalArgumentException, MathIllegalStateException {
133
134 if (model.steps.isEmpty()) {
135 return;
136 }
137
138 if (steps.isEmpty()) {
139 initialTime = model.initialTime;
140 forward = model.forward;
141 } else {
142
143 final ODEStateAndDerivative s1 = steps.get(0).getPreviousState();
144 final ODEStateAndDerivative s2 = model.steps.get(0).getPreviousState();
145 checkDimensionsEquality(s1.getPrimaryStateDimension(), s2.getPrimaryStateDimension());
146 checkDimensionsEquality(s1.getNumberOfSecondaryStates(), s2.getNumberOfSecondaryStates());
147 for (int i = 0; i < s1.getNumberOfSecondaryStates(); ++i) {
148 checkDimensionsEquality(s1.getSecondaryStateDimension(i), s2.getSecondaryStateDimension(i));
149 }
150
151 if (forward ^ model.forward) {
152 throw new MathIllegalArgumentException(LocalizedODEFormats.PROPAGATION_DIRECTION_MISMATCH);
153 }
154
155 final ODEStateInterpolator lastInterpolator = steps.get(index);
156 final double current = lastInterpolator.getCurrentState().getTime();
157 final double previous = lastInterpolator.getPreviousState().getTime();
158 final double step = current - previous;
159 final double gap = model.getInitialTime() - current;
160 if (FastMath.abs(gap) > 1.0e-3 * FastMath.abs(step)) {
161 throw new MathIllegalArgumentException(LocalizedODEFormats.HOLE_BETWEEN_MODELS_TIME_RANGES,
162 FastMath.abs(gap));
163 }
164
165 }
166
167 for (ODEStateInterpolator interpolator : model.steps) {
168 steps.add(interpolator);
169 }
170
171 index = steps.size() - 1;
172 finalTime = (steps.get(index)).getCurrentState().getTime();
173
174 }
175
176
177
178
179
180
181 private void checkDimensionsEquality(final int d1, final int d2)
182 throws MathIllegalArgumentException {
183 if (d1 != d2) {
184 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
185 d2, d1);
186 }
187 }
188
189
190 @Override
191 public void init(final ODEStateAndDerivative initialState, final double targetTime) {
192 initialTime = initialState.getTime();
193 this.finalTime = targetTime;
194 forward = true;
195 index = 0;
196 steps.clear();
197 }
198
199
200 @Override
201 public void handleStep(final ODEStateInterpolator interpolator) {
202 if (steps.isEmpty()) {
203 initialTime = interpolator.getPreviousState().getTime();
204 forward = interpolator.isForward();
205 }
206 steps.add(interpolator);
207 }
208
209
210 @Override
211 public void finish(final ODEStateAndDerivative finalState) {
212 finalTime = finalState.getTime();
213 index = steps.size() - 1;
214 }
215
216
217
218
219
220 public double getInitialTime() {
221 return initialTime;
222 }
223
224
225
226
227
228 public double getFinalTime() {
229 return finalTime;
230 }
231
232
233
234
235
236
237 public ODEStateAndDerivative getInterpolatedState(final double time) {
238
239
240 int iMin = 0;
241 final ODEStateInterpolator sMin = steps.get(iMin);
242 double tMin = 0.5 * (sMin.getPreviousState().getTime() + sMin.getCurrentState().getTime());
243
244 int iMax = steps.size() - 1;
245 final ODEStateInterpolator sMax = steps.get(iMax);
246 double tMax = 0.5 * (sMax.getPreviousState().getTime() + sMax.getCurrentState().getTime());
247
248
249
250 if (locatePoint(time, sMin) <= 0) {
251 index = iMin;
252 return sMin.getInterpolatedState(time);
253 }
254 if (locatePoint(time, sMax) >= 0) {
255 index = iMax;
256 return sMax.getInterpolatedState(time);
257 }
258
259
260 while (iMax - iMin > 5) {
261
262
263 final ODEStateInterpolator si = steps.get(index);
264 final int location = locatePoint(time, si);
265 if (location < 0) {
266 iMax = index;
267 tMax = 0.5 * (si.getPreviousState().getTime() + si.getCurrentState().getTime());
268 } else if (location > 0) {
269 iMin = index;
270 tMin = 0.5 * (si.getPreviousState().getTime() + si.getCurrentState().getTime());
271 } else {
272
273 return si.getInterpolatedState(time);
274 }
275
276
277 final int iMed = (iMin + iMax) / 2;
278 final ODEStateInterpolator sMed = steps.get(iMed);
279 final double tMed = 0.5 * (sMed.getPreviousState().getTime() + sMed.getCurrentState().getTime());
280
281 if ((FastMath.abs(tMed - tMin) < 1e-6) || (FastMath.abs(tMax - tMed) < 1e-6)) {
282
283 index = iMed;
284 } else {
285
286
287
288 final double d12 = tMax - tMed;
289 final double d23 = tMed - tMin;
290 final double d13 = tMax - tMin;
291 final double dt1 = time - tMax;
292 final double dt2 = time - tMed;
293 final double dt3 = time - tMin;
294 final double iLagrange = ((dt2 * dt3 * d23) * iMax -
295 (dt1 * dt3 * d13) * iMed +
296 (dt1 * dt2 * d12) * iMin) /
297 (d12 * d23 * d13);
298 index = (int) FastMath.rint(iLagrange);
299 }
300
301
302 final int low = FastMath.max(iMin + 1, (9 * iMin + iMax) / 10);
303 final int high = FastMath.min(iMax - 1, (iMin + 9 * iMax) / 10);
304 if (index < low) {
305 index = low;
306 } else if (index > high) {
307 index = high;
308 }
309
310 }
311
312
313 index = iMin;
314 while ((index <= iMax) && (locatePoint(time, steps.get(index)) > 0)) {
315 ++index;
316 }
317
318 return steps.get(index).getInterpolatedState(time);
319
320 }
321
322
323
324
325
326
327
328
329 private int locatePoint(final double time, final ODEStateInterpolator interval) {
330 if (forward) {
331 if (time < interval.getPreviousState().getTime()) {
332 return -1;
333 } else if (time > interval.getCurrentState().getTime()) {
334 return +1;
335 } else {
336 return 0;
337 }
338 }
339 if (time > interval.getPreviousState().getTime()) {
340 return -1;
341 } else if (time < interval.getCurrentState().getTime()) {
342 return +1;
343 } else {
344 return 0;
345 }
346 }
347
348 }