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.nonstiff;
19
20 import org.apache.commons.math4.legacy.core.Field;
21 import org.apache.commons.math4.legacy.core.RealFieldElement;
22 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
23 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
24 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
25 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
26 import org.apache.commons.math4.legacy.ode.AbstractFieldIntegrator;
27 import org.apache.commons.math4.legacy.ode.FieldEquationsMapper;
28 import org.apache.commons.math4.legacy.ode.FieldODEState;
29 import org.apache.commons.math4.legacy.ode.FieldODEStateAndDerivative;
30 import org.apache.commons.math4.core.jdkmath.JdkMath;
31 import org.apache.commons.math4.legacy.core.MathArrays;
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 public abstract class AdaptiveStepsizeFieldIntegrator<T extends RealFieldElement<T>>
70 extends AbstractFieldIntegrator<T> {
71
72
73 protected double scalAbsoluteTolerance;
74
75
76 protected double scalRelativeTolerance;
77
78
79 protected double[] vecAbsoluteTolerance;
80
81
82 protected double[] vecRelativeTolerance;
83
84
85 protected int mainSetDimension;
86
87
88 private T initialStep;
89
90
91 private T minStep;
92
93
94 private T maxStep;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public AdaptiveStepsizeFieldIntegrator(final Field<T> field, final String name,
110 final double minStep, final double maxStep,
111 final double scalAbsoluteTolerance,
112 final double scalRelativeTolerance) {
113
114 super(field, name);
115 setStepSizeControl(minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
116 resetInternalState();
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public AdaptiveStepsizeFieldIntegrator(final Field<T> field, final String name,
133 final double minStep, final double maxStep,
134 final double[] vecAbsoluteTolerance,
135 final double[] vecRelativeTolerance) {
136
137 super(field, name);
138 setStepSizeControl(minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
139 resetInternalState();
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 public void setStepSizeControl(final double minimalStep, final double maximalStep,
157 final double absoluteTolerance,
158 final double relativeTolerance) {
159
160 minStep = getField().getZero().add(JdkMath.abs(minimalStep));
161 maxStep = getField().getZero().add(JdkMath.abs(maximalStep));
162 initialStep = getField().getOne().negate();
163
164 scalAbsoluteTolerance = absoluteTolerance;
165 scalRelativeTolerance = relativeTolerance;
166 vecAbsoluteTolerance = null;
167 vecRelativeTolerance = null;
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 public void setStepSizeControl(final double minimalStep, final double maximalStep,
185 final double[] absoluteTolerance,
186 final double[] relativeTolerance) {
187
188 minStep = getField().getZero().add(JdkMath.abs(minimalStep));
189 maxStep = getField().getZero().add(JdkMath.abs(maximalStep));
190 initialStep = getField().getOne().negate();
191
192 scalAbsoluteTolerance = 0;
193 scalRelativeTolerance = 0;
194 vecAbsoluteTolerance = absoluteTolerance.clone();
195 vecRelativeTolerance = relativeTolerance.clone();
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209 public void setInitialStepSize(final T initialStepSize) {
210 if (initialStepSize.subtract(minStep).getReal() < 0 ||
211 initialStepSize.subtract(maxStep).getReal() > 0) {
212 initialStep = getField().getOne().negate();
213 } else {
214 initialStep = initialStepSize;
215 }
216 }
217
218
219 @Override
220 protected void sanityChecks(final FieldODEState<T> eqn, final T t)
221 throws DimensionMismatchException, NumberIsTooSmallException {
222
223 super.sanityChecks(eqn, t);
224
225 mainSetDimension = eqn.getStateDimension();
226
227 if (vecAbsoluteTolerance != null && vecAbsoluteTolerance.length != mainSetDimension) {
228 throw new DimensionMismatchException(mainSetDimension, vecAbsoluteTolerance.length);
229 }
230
231 if (vecRelativeTolerance != null && vecRelativeTolerance.length != mainSetDimension) {
232 throw new DimensionMismatchException(mainSetDimension, vecRelativeTolerance.length);
233 }
234 }
235
236
237
238
239
240
241
242
243
244
245
246 public T initializeStep(final boolean forward, final int order, final T[] scale,
247 final FieldODEStateAndDerivative<T> state0,
248 final FieldEquationsMapper<T> mapper)
249 throws MaxCountExceededException, DimensionMismatchException {
250
251 if (initialStep.getReal() > 0) {
252
253 return forward ? initialStep : initialStep.negate();
254 }
255
256
257
258 final T[] y0 = mapper.mapState(state0);
259 final T[] yDot0 = mapper.mapDerivative(state0);
260 T yOnScale2 = getField().getZero();
261 T yDotOnScale2 = getField().getZero();
262 for (int j = 0; j < scale.length; ++j) {
263 final T ratio = y0[j].divide(scale[j]);
264 yOnScale2 = yOnScale2.add(ratio.multiply(ratio));
265 final T ratioDot = yDot0[j].divide(scale[j]);
266 yDotOnScale2 = yDotOnScale2.add(ratioDot.multiply(ratioDot));
267 }
268
269 T h = (yOnScale2.getReal() < 1.0e-10 || yDotOnScale2.getReal() < 1.0e-10) ?
270 getField().getZero().add(1.0e-6) :
271 yOnScale2.divide(yDotOnScale2).sqrt().multiply(0.01);
272 if (! forward) {
273 h = h.negate();
274 }
275
276
277 final T[] y1 = MathArrays.buildArray(getField(), y0.length);
278 for (int j = 0; j < y0.length; ++j) {
279 y1[j] = y0[j].add(yDot0[j].multiply(h));
280 }
281 final T[] yDot1 = computeDerivatives(state0.getTime().add(h), y1);
282
283
284 T yDDotOnScale = getField().getZero();
285 for (int j = 0; j < scale.length; ++j) {
286 final T ratioDotDot = yDot1[j].subtract(yDot0[j]).divide(scale[j]);
287 yDDotOnScale = yDDotOnScale.add(ratioDotDot.multiply(ratioDotDot));
288 }
289 yDDotOnScale = yDDotOnScale.sqrt().divide(h);
290
291
292
293 final T maxInv2 = RealFieldElement.max(yDotOnScale2.sqrt(), yDDotOnScale);
294 final T h1 = maxInv2.getReal() < 1.0e-15 ?
295 RealFieldElement.max(getField().getZero().add(1.0e-6), h.abs().multiply(0.001)) :
296 maxInv2.multiply(100).reciprocal().pow(1.0 / order);
297 h = RealFieldElement.min(h.abs().multiply(100), h1);
298 h = RealFieldElement.max(h, state0.getTime().abs().multiply(1.0e-12));
299 h = RealFieldElement.max(minStep, RealFieldElement.min(maxStep, h));
300 if (! forward) {
301 h = h.negate();
302 }
303
304 return h;
305 }
306
307
308
309
310
311
312
313
314
315
316 protected T filterStep(final T h, final boolean forward, final boolean acceptSmall)
317 throws NumberIsTooSmallException {
318
319 T filteredH = h;
320 if (h.abs().subtract(minStep).getReal() < 0) {
321 if (acceptSmall) {
322 filteredH = forward ? minStep : minStep.negate();
323 } else {
324 throw new NumberIsTooSmallException(LocalizedFormats.MINIMAL_STEPSIZE_REACHED_DURING_INTEGRATION,
325 h.abs().getReal(), minStep.getReal(), true);
326 }
327 }
328
329 if (filteredH.subtract(maxStep).getReal() > 0) {
330 filteredH = maxStep;
331 } else if (filteredH.add(maxStep).getReal() < 0) {
332 filteredH = maxStep.negate();
333 }
334
335 return filteredH;
336 }
337
338
339 protected void resetInternalState() {
340 setStepStart(null);
341 setStepSize(minStep.multiply(maxStep).sqrt());
342 }
343
344
345
346
347 public T getMinStep() {
348 return minStep;
349 }
350
351
352
353
354 public T getMaxStep() {
355 return maxStep;
356 }
357 }