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 steps.addAll(model.steps);
168
169 index = steps.size() - 1;
170 finalTime = (steps.get(index)).getCurrentState().getTime();
171
172 }
173
174
175
176
177
178
179 private void checkDimensionsEquality(final int d1, final int d2)
180 throws MathIllegalArgumentException {
181 if (d1 != d2) {
182 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
183 d2, d1);
184 }
185 }
186
187
188 @Override
189 public void init(final ODEStateAndDerivative initialState, final double targetTime) {
190 initialTime = initialState.getTime();
191 this.finalTime = targetTime;
192 forward = true;
193 index = 0;
194 steps.clear();
195 }
196
197
198 @Override
199 public void handleStep(final ODEStateInterpolator interpolator) {
200 if (steps.isEmpty()) {
201 initialTime = interpolator.getPreviousState().getTime();
202 forward = interpolator.isForward();
203 }
204 steps.add(interpolator);
205 }
206
207
208 @Override
209 public void finish(final ODEStateAndDerivative finalState) {
210 finalTime = finalState.getTime();
211 index = steps.size() - 1;
212 }
213
214
215
216
217
218 public double getInitialTime() {
219 return initialTime;
220 }
221
222
223
224
225
226 public double getFinalTime() {
227 return finalTime;
228 }
229
230
231
232
233
234
235 public ODEStateAndDerivative getInterpolatedState(final double time) {
236
237
238 int iMin = 0;
239 final ODEStateInterpolator sMin = steps.get(iMin);
240 double tMin = 0.5 * (sMin.getPreviousState().getTime() + sMin.getCurrentState().getTime());
241
242 int iMax = steps.size() - 1;
243 final ODEStateInterpolator sMax = steps.get(iMax);
244 double tMax = 0.5 * (sMax.getPreviousState().getTime() + sMax.getCurrentState().getTime());
245
246
247
248 if (locatePoint(time, sMin) <= 0) {
249 index = iMin;
250 return sMin.getInterpolatedState(time);
251 }
252 if (locatePoint(time, sMax) >= 0) {
253 index = iMax;
254 return sMax.getInterpolatedState(time);
255 }
256
257
258 while (iMax - iMin > 5) {
259
260
261 final ODEStateInterpolator si = steps.get(index);
262 final int location = locatePoint(time, si);
263 if (location < 0) {
264 iMax = index;
265 tMax = 0.5 * (si.getPreviousState().getTime() + si.getCurrentState().getTime());
266 } else if (location > 0) {
267 iMin = index;
268 tMin = 0.5 * (si.getPreviousState().getTime() + si.getCurrentState().getTime());
269 } else {
270
271 return si.getInterpolatedState(time);
272 }
273
274
275 final int iMed = (iMin + iMax) / 2;
276 final ODEStateInterpolator sMed = steps.get(iMed);
277 final double tMed = 0.5 * (sMed.getPreviousState().getTime() + sMed.getCurrentState().getTime());
278
279 if ((FastMath.abs(tMed - tMin) < 1e-6) || (FastMath.abs(tMax - tMed) < 1e-6)) {
280
281 index = iMed;
282 } else {
283
284
285
286 final double d12 = tMax - tMed;
287 final double d23 = tMed - tMin;
288 final double d13 = tMax - tMin;
289 final double dt1 = time - tMax;
290 final double dt2 = time - tMed;
291 final double dt3 = time - tMin;
292 final double iLagrange = ((dt2 * dt3 * d23) * iMax -
293 (dt1 * dt3 * d13) * iMed +
294 (dt1 * dt2 * d12) * iMin) /
295 (d12 * d23 * d13);
296 index = (int) FastMath.rint(iLagrange);
297 }
298
299
300 final int low = FastMath.max(iMin + 1, (9 * iMin + iMax) / 10);
301 final int high = FastMath.min(iMax - 1, (iMin + 9 * iMax) / 10);
302 if (index < low) {
303 index = low;
304 } else if (index > high) {
305 index = high;
306 }
307
308 }
309
310
311 index = iMin;
312 while ((index <= iMax) && (locatePoint(time, steps.get(index)) > 0)) {
313 ++index;
314 }
315
316 return steps.get(index).getInterpolatedState(time);
317
318 }
319
320
321
322
323
324
325
326
327 private int locatePoint(final double time, final ODEStateInterpolator interval) {
328 if (forward) {
329 if (time < interval.getPreviousState().getTime()) {
330 return -1;
331 } else if (time > interval.getCurrentState().getTime()) {
332 return +1;
333 } else {
334 return 0;
335 }
336 }
337 if (time > interval.getPreviousState().getTime()) {
338 return -1;
339 } else if (time < interval.getCurrentState().getTime()) {
340 return +1;
341 } else {
342 return 0;
343 }
344 }
345
346 }