blob: 48fdf2c46aebb6bf3aa387956b114f580ac77a6d [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.commons.math.ode.nonstiff;
19
20import java.io.IOException;
21import java.io.ObjectInput;
22import java.io.ObjectOutput;
23
24import org.apache.commons.math.ode.sampling.AbstractStepInterpolator;
25import org.apache.commons.math.ode.sampling.StepInterpolator;
26import org.apache.commons.math.util.FastMath;
27
28/**
29 * This class implements an interpolator for the Gragg-Bulirsch-Stoer
30 * integrator.
31 *
32 * <p>This interpolator compute dense output inside the last step
33 * produced by a Gragg-Bulirsch-Stoer integrator.</p>
34 *
35 * <p>
36 * This implementation is basically a reimplementation in Java of the
37 * <a
38 * href="http://www.unige.ch/math/folks/hairer/prog/nonstiff/odex.f">odex</a>
39 * fortran code by E. Hairer and G. Wanner. The redistribution policy
40 * for this code is available <a
41 * href="http://www.unige.ch/~hairer/prog/licence.txt">here</a>, for
42 * convenience, it is reproduced below.</p>
43 * </p>
44 *
45 * <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0">
46 * <tr><td>Copyright (c) 2004, Ernst Hairer</td></tr>
47 *
48 * <tr><td>Redistribution and use in source and binary forms, with or
49 * without modification, are permitted provided that the following
50 * conditions are met:
51 * <ul>
52 * <li>Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.</li>
54 * <li>Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.</li>
57 * </ul></td></tr>
58 *
59 * <tr><td><strong>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
60 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
61 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
62 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
63 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
64 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
65 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
66 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
67 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
68 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</strong></td></tr>
70 * </table>
71 *
72 * @see GraggBulirschStoerIntegrator
73 * @version $Revision: 1061507 $ $Date: 2011-01-20 21:55:00 +0100 (jeu. 20 janv. 2011) $
74 * @since 1.2
75 */
76
77class GraggBulirschStoerStepInterpolator
78 extends AbstractStepInterpolator {
79
80 /** Serializable version identifier. */
81 private static final long serialVersionUID = 7320613236731409847L;
82
83 /** Slope at the beginning of the step. */
84 private double[] y0Dot;
85
86 /** State at the end of the step. */
87 private double[] y1;
88
89 /** Slope at the end of the step. */
90 private double[] y1Dot;
91
92 /** Derivatives at the middle of the step.
93 * element 0 is state at midpoint, element 1 is first derivative ...
94 */
95 private double[][] yMidDots;
96
97 /** Interpolation polynoms. */
98 private double[][] polynoms;
99
100 /** Error coefficients for the interpolation. */
101 private double[] errfac;
102
103 /** Degree of the interpolation polynoms. */
104 private int currentDegree;
105
106 /** Simple constructor.
107 * This constructor should not be used directly, it is only intended
108 * for the serialization process.
109 */
110 public GraggBulirschStoerStepInterpolator() {
111 y0Dot = null;
112 y1 = null;
113 y1Dot = null;
114 yMidDots = null;
115 resetTables(-1);
116 }
117
118 /** Simple constructor.
119 * @param y reference to the integrator array holding the current state
120 * @param y0Dot reference to the integrator array holding the slope
121 * at the beginning of the step
122 * @param y1 reference to the integrator array holding the state at
123 * the end of the step
124 * @param y1Dot reference to the integrator array holding the slope
125 * at the end of the step
126 * @param yMidDots reference to the integrator array holding the
127 * derivatives at the middle point of the step
128 * @param forward integration direction indicator
129 */
130 public GraggBulirschStoerStepInterpolator(final double[] y, final double[] y0Dot,
131 final double[] y1, final double[] y1Dot,
132 final double[][] yMidDots,
133 final boolean forward) {
134
135 super(y, forward);
136 this.y0Dot = y0Dot;
137 this.y1 = y1;
138 this.y1Dot = y1Dot;
139 this.yMidDots = yMidDots;
140
141 resetTables(yMidDots.length + 4);
142
143 }
144
145 /** Copy constructor.
146 * @param interpolator interpolator to copy from. The copy is a deep
147 * copy: its arrays are separated from the original arrays of the
148 * instance
149 */
150 public GraggBulirschStoerStepInterpolator
151 (final GraggBulirschStoerStepInterpolator interpolator) {
152
153 super(interpolator);
154
155 final int dimension = currentState.length;
156
157 // the interpolator has been finalized,
158 // the following arrays are not needed anymore
159 y0Dot = null;
160 y1 = null;
161 y1Dot = null;
162 yMidDots = null;
163
164 // copy the interpolation polynoms (up to the current degree only)
165 if (interpolator.polynoms == null) {
166 polynoms = null;
167 currentDegree = -1;
168 } else {
169 resetTables(interpolator.currentDegree);
170 for (int i = 0; i < polynoms.length; ++i) {
171 polynoms[i] = new double[dimension];
172 System.arraycopy(interpolator.polynoms[i], 0,
173 polynoms[i], 0, dimension);
174 }
175 currentDegree = interpolator.currentDegree;
176 }
177
178 }
179
180 /** Reallocate the internal tables.
181 * Reallocate the internal tables in order to be able to handle
182 * interpolation polynoms up to the given degree
183 * @param maxDegree maximal degree to handle
184 */
185 private void resetTables(final int maxDegree) {
186
187 if (maxDegree < 0) {
188 polynoms = null;
189 errfac = null;
190 currentDegree = -1;
191 } else {
192
193 final double[][] newPols = new double[maxDegree + 1][];
194 if (polynoms != null) {
195 System.arraycopy(polynoms, 0, newPols, 0, polynoms.length);
196 for (int i = polynoms.length; i < newPols.length; ++i) {
197 newPols[i] = new double[currentState.length];
198 }
199 } else {
200 for (int i = 0; i < newPols.length; ++i) {
201 newPols[i] = new double[currentState.length];
202 }
203 }
204 polynoms = newPols;
205
206 // initialize the error factors array for interpolation
207 if (maxDegree <= 4) {
208 errfac = null;
209 } else {
210 errfac = new double[maxDegree - 4];
211 for (int i = 0; i < errfac.length; ++i) {
212 final int ip5 = i + 5;
213 errfac[i] = 1.0 / (ip5 * ip5);
214 final double e = 0.5 * FastMath.sqrt (((double) (i + 1)) / ip5);
215 for (int j = 0; j <= i; ++j) {
216 errfac[i] *= e / (j + 1);
217 }
218 }
219 }
220
221 currentDegree = 0;
222
223 }
224
225 }
226
227 /** {@inheritDoc} */
228 @Override
229 protected StepInterpolator doCopy() {
230 return new GraggBulirschStoerStepInterpolator(this);
231 }
232
233
234 /** Compute the interpolation coefficients for dense output.
235 * @param mu degree of the interpolation polynomial
236 * @param h current step
237 */
238 public void computeCoefficients(final int mu, final double h) {
239
240 if ((polynoms == null) || (polynoms.length <= (mu + 4))) {
241 resetTables(mu + 4);
242 }
243
244 currentDegree = mu + 4;
245
246 for (int i = 0; i < currentState.length; ++i) {
247
248 final double yp0 = h * y0Dot[i];
249 final double yp1 = h * y1Dot[i];
250 final double ydiff = y1[i] - currentState[i];
251 final double aspl = ydiff - yp1;
252 final double bspl = yp0 - ydiff;
253
254 polynoms[0][i] = currentState[i];
255 polynoms[1][i] = ydiff;
256 polynoms[2][i] = aspl;
257 polynoms[3][i] = bspl;
258
259 if (mu < 0) {
260 return;
261 }
262
263 // compute the remaining coefficients
264 final double ph0 = 0.5 * (currentState[i] + y1[i]) + 0.125 * (aspl + bspl);
265 polynoms[4][i] = 16 * (yMidDots[0][i] - ph0);
266
267 if (mu > 0) {
268 final double ph1 = ydiff + 0.25 * (aspl - bspl);
269 polynoms[5][i] = 16 * (yMidDots[1][i] - ph1);
270
271 if (mu > 1) {
272 final double ph2 = yp1 - yp0;
273 polynoms[6][i] = 16 * (yMidDots[2][i] - ph2 + polynoms[4][i]);
274
275 if (mu > 2) {
276 final double ph3 = 6 * (bspl - aspl);
277 polynoms[7][i] = 16 * (yMidDots[3][i] - ph3 + 3 * polynoms[5][i]);
278
279 for (int j = 4; j <= mu; ++j) {
280 final double fac1 = 0.5 * j * (j - 1);
281 final double fac2 = 2 * fac1 * (j - 2) * (j - 3);
282 polynoms[j+4][i] =
283 16 * (yMidDots[j][i] + fac1 * polynoms[j+2][i] - fac2 * polynoms[j][i]);
284 }
285
286 }
287 }
288 }
289 }
290
291 }
292
293 /** Estimate interpolation error.
294 * @param scale scaling array
295 * @return estimate of the interpolation error
296 */
297 public double estimateError(final double[] scale) {
298 double error = 0;
299 if (currentDegree >= 5) {
300 for (int i = 0; i < scale.length; ++i) {
301 final double e = polynoms[currentDegree][i] / scale[i];
302 error += e * e;
303 }
304 error = FastMath.sqrt(error / scale.length) * errfac[currentDegree - 5];
305 }
306 return error;
307 }
308
309 /** {@inheritDoc} */
310 @Override
311 protected void computeInterpolatedStateAndDerivatives(final double theta,
312 final double oneMinusThetaH) {
313
314 final int dimension = currentState.length;
315
316 final double oneMinusTheta = 1.0 - theta;
317 final double theta05 = theta - 0.5;
318 final double tOmT = theta * oneMinusTheta;
319 final double t4 = tOmT * tOmT;
320 final double t4Dot = 2 * tOmT * (1 - 2 * theta);
321 final double dot1 = 1.0 / h;
322 final double dot2 = theta * (2 - 3 * theta) / h;
323 final double dot3 = ((3 * theta - 4) * theta + 1) / h;
324
325 for (int i = 0; i < dimension; ++i) {
326
327 final double p0 = polynoms[0][i];
328 final double p1 = polynoms[1][i];
329 final double p2 = polynoms[2][i];
330 final double p3 = polynoms[3][i];
331 interpolatedState[i] = p0 + theta * (p1 + oneMinusTheta * (p2 * theta + p3 * oneMinusTheta));
332 interpolatedDerivatives[i] = dot1 * p1 + dot2 * p2 + dot3 * p3;
333
334 if (currentDegree > 3) {
335 double cDot = 0;
336 double c = polynoms[currentDegree][i];
337 for (int j = currentDegree - 1; j > 3; --j) {
338 final double d = 1.0 / (j - 3);
339 cDot = d * (theta05 * cDot + c);
340 c = polynoms[j][i] + c * d * theta05;
341 }
342 interpolatedState[i] += t4 * c;
343 interpolatedDerivatives[i] += (t4 * cDot + t4Dot * c) / h;
344 }
345
346 }
347
348 if (h == 0) {
349 // in this degenerated case, the previous computation leads to NaN for derivatives
350 // we fix this by using the derivatives at midpoint
351 System.arraycopy(yMidDots[1], 0, interpolatedDerivatives, 0, dimension);
352 }
353
354 }
355
356 /** {@inheritDoc} */
357 @Override
358 public void writeExternal(final ObjectOutput out)
359 throws IOException {
360
361 final int dimension = (currentState == null) ? -1 : currentState.length;
362
363 // save the state of the base class
364 writeBaseExternal(out);
365
366 // save the local attributes (but not the temporary vectors)
367 out.writeInt(currentDegree);
368 for (int k = 0; k <= currentDegree; ++k) {
369 for (int l = 0; l < dimension; ++l) {
370 out.writeDouble(polynoms[k][l]);
371 }
372 }
373
374 }
375
376 /** {@inheritDoc} */
377 @Override
378 public void readExternal(final ObjectInput in)
379 throws IOException {
380
381 // read the base class
382 final double t = readBaseExternal(in);
383 final int dimension = (currentState == null) ? -1 : currentState.length;
384
385 // read the local attributes
386 final int degree = in.readInt();
387 resetTables(degree);
388 currentDegree = degree;
389
390 for (int k = 0; k <= currentDegree; ++k) {
391 for (int l = 0; l < dimension; ++l) {
392 polynoms[k][l] = in.readDouble();
393 }
394 }
395
396 // we can now set the interpolated time and state
397 setInterpolatedTime(t);
398
399 }
400
401}