View Javadoc

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