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
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.AbstractIntegrator;
25import org.apache.commons.math.ode.DerivativeException;
26import org.apache.commons.math.ode.sampling.StepInterpolator;
27
28/**
29 * This class represents an interpolator over the last step during an
30 * ODE integration for the 8(5,3) Dormand-Prince integrator.
31 *
32 * @see DormandPrince853Integrator
33 *
34 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
35 * @since 1.2
36 */
37
38class DormandPrince853StepInterpolator
39  extends RungeKuttaStepInterpolator {
40
41    /** Serializable version identifier */
42    private static final long serialVersionUID = 7152276390558450974L;
43
44    /** Propagation weights, element 1. */
45    private static final double B_01 =         104257.0 / 1920240.0;
46
47    // elements 2 to 5 are zero, so they are neither stored nor used
48
49    /** Propagation weights, element 6. */
50    private static final double B_06 =        3399327.0 / 763840.0;
51
52    /** Propagation weights, element 7. */
53    private static final double B_07 =       66578432.0 / 35198415.0;
54
55    /** Propagation weights, element 8. */
56    private static final double B_08 =    -1674902723.0 / 288716400.0;
57
58    /** Propagation weights, element 9. */
59    private static final double B_09 = 54980371265625.0 / 176692375811392.0;
60
61    /** Propagation weights, element 10. */
62    private static final double B_10 =        -734375.0 / 4826304.0;
63
64    /** Propagation weights, element 11. */
65    private static final double B_11 =      171414593.0 / 851261400.0;
66
67    /** Propagation weights, element 12. */
68    private static final double B_12 =         137909.0 / 3084480.0;
69
70    /** Time step for stage 14 (interpolation only). */
71    private static final double C14    = 1.0 / 10.0;
72
73    /** Internal weights for stage 14, element 1. */
74    private static final double K14_01 =       13481885573.0 / 240030000000.0      - B_01;
75
76    // elements 2 to 5 are zero, so they are neither stored nor used
77
78    /** Internal weights for stage 14, element 6. */
79    private static final double K14_06 =                 0.0                       - B_06;
80
81    /** Internal weights for stage 14, element 7. */
82    private static final double K14_07 =      139418837528.0 / 549975234375.0      - B_07;
83
84    /** Internal weights for stage 14, element 8. */
85    private static final double K14_08 =   -11108320068443.0 / 45111937500000.0    - B_08;
86
87    /** Internal weights for stage 14, element 9. */
88    private static final double K14_09 = -1769651421925959.0 / 14249385146080000.0 - B_09;
89
90    /** Internal weights for stage 14, element 10. */
91    private static final double K14_10 =          57799439.0 / 377055000.0         - B_10;
92
93    /** Internal weights for stage 14, element 11. */
94    private static final double K14_11 =      793322643029.0 / 96734250000000.0    - B_11;
95
96    /** Internal weights for stage 14, element 12. */
97    private static final double K14_12 =        1458939311.0 / 192780000000.0      - B_12;
98
99    /** Internal weights for stage 14, element 13. */
100    private static final double K14_13 =             -4149.0 / 500000.0;
101
102    /** Time step for stage 15 (interpolation only). */
103    private static final double C15    = 1.0 / 5.0;
104
105
106    /** Internal weights for stage 15, element 1. */
107    private static final double K15_01 =     1595561272731.0 / 50120273500000.0    - B_01;
108
109    // elements 2 to 5 are zero, so they are neither stored nor used
110
111    /** Internal weights for stage 15, element 6. */
112    private static final double K15_06 =      975183916491.0 / 34457688031250.0    - B_06;
113
114    /** Internal weights for stage 15, element 7. */
115    private static final double K15_07 =    38492013932672.0 / 718912673015625.0   - B_07;
116
117    /** Internal weights for stage 15, element 8. */
118    private static final double K15_08 = -1114881286517557.0 / 20298710767500000.0 - B_08;
119
120    /** Internal weights for stage 15, element 9. */
121    private static final double K15_09 =                 0.0                       - B_09;
122
123    /** Internal weights for stage 15, element 10. */
124    private static final double K15_10 =                 0.0                       - B_10;
125
126    /** Internal weights for stage 15, element 11. */
127    private static final double K15_11 =    -2538710946863.0 / 23431227861250000.0 - B_11;
128
129    /** Internal weights for stage 15, element 12. */
130    private static final double K15_12 =        8824659001.0 / 23066716781250.0    - B_12;
131
132    /** Internal weights for stage 15, element 13. */
133    private static final double K15_13 =      -11518334563.0 / 33831184612500.0;
134
135    /** Internal weights for stage 15, element 14. */
136    private static final double K15_14 =        1912306948.0 / 13532473845.0;
137
138    /** Time step for stage 16 (interpolation only). */
139    private static final double C16    = 7.0 / 9.0;
140
141
142    /** Internal weights for stage 16, element 1. */
143    private static final double K16_01 =      -13613986967.0 / 31741908048.0       - B_01;
144
145    // elements 2 to 5 are zero, so they are neither stored nor used
146
147    /** Internal weights for stage 16, element 6. */
148    private static final double K16_06 =       -4755612631.0 / 1012344804.0        - B_06;
149
150    /** Internal weights for stage 16, element 7. */
151    private static final double K16_07 =    42939257944576.0 / 5588559685701.0     - B_07;
152
153    /** Internal weights for stage 16, element 8. */
154    private static final double K16_08 =    77881972900277.0 / 19140370552944.0    - B_08;
155
156    /** Internal weights for stage 16, element 9. */
157    private static final double K16_09 =    22719829234375.0 / 63689648654052.0    - B_09;
158
159    /** Internal weights for stage 16, element 10. */
160    private static final double K16_10 =                 0.0                       - B_10;
161
162    /** Internal weights for stage 16, element 11. */
163    private static final double K16_11 =                 0.0                       - B_11;
164
165    /** Internal weights for stage 16, element 12. */
166    private static final double K16_12 =                 0.0                       - B_12;
167
168    /** Internal weights for stage 16, element 13. */
169    private static final double K16_13 =       -1199007803.0 / 857031517296.0;
170
171    /** Internal weights for stage 16, element 14. */
172    private static final double K16_14 =      157882067000.0 / 53564469831.0;
173
174    /** Internal weights for stage 16, element 15. */
175    private static final double K16_15 =     -290468882375.0 / 31741908048.0;
176
177    /** Interpolation weights.
178     * (beware that only the non-null values are in the table)
179     */
180    private static final double[][] D = {
181
182      {        -17751989329.0 / 2106076560.0,               4272954039.0 / 7539864640.0,
183              -118476319744.0 / 38604839385.0,            755123450731.0 / 316657731600.0,
184        3692384461234828125.0 / 1744130441634250432.0,     -4612609375.0 / 5293382976.0,
185              2091772278379.0 / 933644586600.0,             2136624137.0 / 3382989120.0,
186                    -126493.0 / 1421424.0,                    98350000.0 / 5419179.0,
187                  -18878125.0 / 2053168.0,                 -1944542619.0 / 438351368.0},
188
189      {         32941697297.0 / 3159114840.0,             456696183123.0 / 1884966160.0,
190             19132610714624.0 / 115814518155.0,       -177904688592943.0 / 474986597400.0,
191       -4821139941836765625.0 / 218016305204281304.0,      30702015625.0 / 3970037232.0,
192            -85916079474274.0 / 2800933759800.0,           -5919468007.0 / 634310460.0,
193                    2479159.0 / 157936.0,                    -18750000.0 / 602131.0,
194                  -19203125.0 / 2053168.0,                 15700361463.0 / 438351368.0},
195
196      {         12627015655.0 / 631822968.0,              -72955222965.0 / 188496616.0,
197            -13145744952320.0 / 69488710893.0,          30084216194513.0 / 56998391688.0,
198        -296858761006640625.0 / 25648977082856624.0,         569140625.0 / 82709109.0,
199               -18684190637.0 / 18672891732.0,                69644045.0 / 89549712.0,
200                  -11847025.0 / 4264272.0,                  -978650000.0 / 16257537.0,
201                  519371875.0 / 6159504.0,                  5256837225.0 / 438351368.0},
202
203      {          -450944925.0 / 17550638.0,               -14532122925.0 / 94248308.0,
204              -595876966400.0 / 2573655959.0,             188748653015.0 / 527762886.0,
205        2545485458115234375.0 / 27252038150535163.0,       -1376953125.0 / 36759604.0,
206                53995596795.0 / 518691437.0,                 210311225.0 / 7047894.0,
207                   -1718875.0 / 39484.0,                      58000000.0 / 602131.0,
208                   -1546875.0 / 39484.0,                   -1262172375.0 / 8429834.0}
209
210    };
211
212    /** Last evaluations. */
213    private double[][] yDotKLast;
214
215    /** Vectors for interpolation. */
216    private double[][] v;
217
218    /** Initialization indicator for the interpolation vectors. */
219    private boolean vectorsInitialized;
220
221  /** Simple constructor.
222   * This constructor builds an instance that is not usable yet, the
223   * {@link #reinitialize} method should be called before using the
224   * instance in order to initialize the internal arrays. This
225   * constructor is used only in order to delay the initialization in
226   * some cases. The {@link EmbeddedRungeKuttaIntegrator} uses the
227   * prototyping design pattern to create the step interpolators by
228   * cloning an uninitialized model and latter initializing the copy.
229   */
230  public DormandPrince853StepInterpolator() {
231    super();
232    yDotKLast = null;
233    v         = null;
234    vectorsInitialized = false;
235  }
236
237  /** Copy constructor.
238   * @param interpolator interpolator to copy from. The copy is a deep
239   * copy: its arrays are separated from the original arrays of the
240   * instance
241   */
242  public DormandPrince853StepInterpolator(final DormandPrince853StepInterpolator interpolator) {
243
244    super(interpolator);
245
246    if (interpolator.currentState == null) {
247
248      yDotKLast = null;
249      v         = null;
250      vectorsInitialized = false;
251
252    } else {
253
254      final int dimension = interpolator.currentState.length;
255
256      yDotKLast    = new double[3][];
257      for (int k = 0; k < yDotKLast.length; ++k) {
258        yDotKLast[k] = new double[dimension];
259        System.arraycopy(interpolator.yDotKLast[k], 0, yDotKLast[k], 0,
260                         dimension);
261      }
262
263      v = new double[7][];
264      for (int k = 0; k < v.length; ++k) {
265        v[k] = new double[dimension];
266        System.arraycopy(interpolator.v[k], 0, v[k], 0, dimension);
267      }
268
269      vectorsInitialized = interpolator.vectorsInitialized;
270
271    }
272
273  }
274
275  /** {@inheritDoc} */
276  @Override
277  protected StepInterpolator doCopy() {
278    return new DormandPrince853StepInterpolator(this);
279  }
280
281  /** {@inheritDoc} */
282  @Override
283  public void reinitialize(final AbstractIntegrator integrator,
284                           final double[] y, final double[][] yDotK, final boolean forward) {
285
286    super.reinitialize(integrator, y, yDotK, forward);
287
288    final int dimension = currentState.length;
289
290    yDotKLast = new double[3][];
291    for (int k = 0; k < yDotKLast.length; ++k) {
292      yDotKLast[k] = new double[dimension];
293    }
294
295    v = new double[7][];
296    for (int k = 0; k < v.length; ++k) {
297      v[k]  = new double[dimension];
298    }
299
300    vectorsInitialized = false;
301
302  }
303
304  /** {@inheritDoc} */
305  @Override
306  public void storeTime(final double t) {
307    super.storeTime(t);
308    vectorsInitialized = false;
309  }
310
311  /** {@inheritDoc} */
312  @Override
313  protected void computeInterpolatedStateAndDerivatives(final double theta,
314                                          final double oneMinusThetaH)
315    throws DerivativeException {
316
317    if (! vectorsInitialized) {
318
319      if (v == null) {
320        v = new double[7][];
321        for (int k = 0; k < 7; ++k) {
322          v[k] = new double[interpolatedState.length];
323        }
324      }
325
326      // perform the last evaluations if they have not been done yet
327      finalizeStep();
328
329      // compute the interpolation vectors for this time step
330      for (int i = 0; i < interpolatedState.length; ++i) {
331          final double yDot1  = yDotK[0][i];
332          final double yDot6  = yDotK[5][i];
333          final double yDot7  = yDotK[6][i];
334          final double yDot8  = yDotK[7][i];
335          final double yDot9  = yDotK[8][i];
336          final double yDot10 = yDotK[9][i];
337          final double yDot11 = yDotK[10][i];
338          final double yDot12 = yDotK[11][i];
339          final double yDot13 = yDotK[12][i];
340          final double yDot14 = yDotKLast[0][i];
341          final double yDot15 = yDotKLast[1][i];
342          final double yDot16 = yDotKLast[2][i];
343          v[0][i] = B_01 * yDot1  + B_06 * yDot6 + B_07 * yDot7 +
344                    B_08 * yDot8  + B_09 * yDot9 + B_10 * yDot10 +
345                    B_11 * yDot11 + B_12 * yDot12;
346          v[1][i] = yDot1 - v[0][i];
347          v[2][i] = v[0][i] - v[1][i] - yDotK[12][i];
348          for (int k = 0; k < D.length; ++k) {
349              v[k+3][i] = D[k][0] * yDot1  + D[k][1]  * yDot6  + D[k][2]  * yDot7  +
350                          D[k][3] * yDot8  + D[k][4]  * yDot9  + D[k][5]  * yDot10 +
351                          D[k][6] * yDot11 + D[k][7]  * yDot12 + D[k][8]  * yDot13 +
352                          D[k][9] * yDot14 + D[k][10] * yDot15 + D[k][11] * yDot16;
353          }
354      }
355
356      vectorsInitialized = true;
357
358    }
359
360    final double eta      = 1 - theta;
361    final double twoTheta = 2 * theta;
362    final double theta2   = theta * theta;
363    final double dot1 = 1 - twoTheta;
364    final double dot2 = theta * (2 - 3 * theta);
365    final double dot3 = twoTheta * (1 + theta * (twoTheta -3));
366    final double dot4 = theta2 * (3 + theta * (5 * theta - 8));
367    final double dot5 = theta2 * (3 + theta * (-12 + theta * (15 - 6 * theta)));
368    final double dot6 = theta2 * theta * (4 + theta * (-15 + theta * (18 - 7 * theta)));
369
370    for (int i = 0; i < interpolatedState.length; ++i) {
371      interpolatedState[i] = currentState[i] -
372                             oneMinusThetaH * (v[0][i] -
373                                               theta * (v[1][i] +
374                                                        theta * (v[2][i] +
375                                                                 eta * (v[3][i] +
376                                                                        theta * (v[4][i] +
377                                                                                 eta * (v[5][i] +
378                                                                                        theta * (v[6][i])))))));
379      interpolatedDerivatives[i] =  v[0][i] + dot1 * v[1][i] + dot2 * v[2][i] +
380                                    dot3 * v[3][i] + dot4 * v[4][i] +
381                                    dot5 * v[5][i] + dot6 * v[6][i];
382    }
383
384  }
385
386  /** {@inheritDoc} */
387  @Override
388  protected void doFinalize()
389    throws DerivativeException {
390
391    if (currentState == null) {
392      // we are finalizing an uninitialized instance
393      return;
394    }
395
396    double s;
397    final double[] yTmp = new double[currentState.length];
398    final double pT = getGlobalPreviousTime();
399
400    // k14
401    for (int j = 0; j < currentState.length; ++j) {
402      s = K14_01 * yDotK[0][j]  + K14_06 * yDotK[5][j]  + K14_07 * yDotK[6][j] +
403          K14_08 * yDotK[7][j]  + K14_09 * yDotK[8][j]  + K14_10 * yDotK[9][j] +
404          K14_11 * yDotK[10][j] + K14_12 * yDotK[11][j] + K14_13 * yDotK[12][j];
405      yTmp[j] = currentState[j] + h * s;
406    }
407    integrator.computeDerivatives(pT + C14 * h, yTmp, yDotKLast[0]);
408
409    // k15
410    for (int j = 0; j < currentState.length; ++j) {
411     s = K15_01 * yDotK[0][j]  + K15_06 * yDotK[5][j]  + K15_07 * yDotK[6][j] +
412         K15_08 * yDotK[7][j]  + K15_09 * yDotK[8][j]  + K15_10 * yDotK[9][j] +
413         K15_11 * yDotK[10][j] + K15_12 * yDotK[11][j] + K15_13 * yDotK[12][j] +
414         K15_14 * yDotKLast[0][j];
415     yTmp[j] = currentState[j] + h * s;
416    }
417    integrator.computeDerivatives(pT + C15 * h, yTmp, yDotKLast[1]);
418
419    // k16
420    for (int j = 0; j < currentState.length; ++j) {
421      s = K16_01 * yDotK[0][j]  + K16_06 * yDotK[5][j]  + K16_07 * yDotK[6][j] +
422          K16_08 * yDotK[7][j]  + K16_09 * yDotK[8][j]  + K16_10 * yDotK[9][j] +
423          K16_11 * yDotK[10][j] + K16_12 * yDotK[11][j] + K16_13 * yDotK[12][j] +
424          K16_14 * yDotKLast[0][j] +  K16_15 * yDotKLast[1][j];
425      yTmp[j] = currentState[j] + h * s;
426    }
427    integrator.computeDerivatives(pT + C16 * h, yTmp, yDotKLast[2]);
428
429  }
430
431  /** {@inheritDoc} */
432  @Override
433  public void writeExternal(final ObjectOutput out)
434    throws IOException {
435
436    try {
437      // save the local attributes
438      finalizeStep();
439    } catch (DerivativeException e) {
440        IOException ioe = new IOException(e.getLocalizedMessage());
441        ioe.initCause(e);
442        throw ioe;
443    }
444    final int dimension = (currentState == null) ? -1 : currentState.length;
445    out.writeInt(dimension);
446    for (int i = 0; i < dimension; ++i) {
447      out.writeDouble(yDotKLast[0][i]);
448      out.writeDouble(yDotKLast[1][i]);
449      out.writeDouble(yDotKLast[2][i]);
450    }
451
452    // save the state of the base class
453    super.writeExternal(out);
454
455  }
456
457  /** {@inheritDoc} */
458  @Override
459  public void readExternal(final ObjectInput in)
460    throws IOException {
461
462    // read the local attributes
463    yDotKLast = new double[3][];
464    final int dimension = in.readInt();
465    yDotKLast[0] = (dimension < 0) ? null : new double[dimension];
466    yDotKLast[1] = (dimension < 0) ? null : new double[dimension];
467    yDotKLast[2] = (dimension < 0) ? null : new double[dimension];
468
469    for (int i = 0; i < dimension; ++i) {
470      yDotKLast[0][i] = in.readDouble();
471      yDotKLast[1][i] = in.readDouble();
472      yDotKLast[2][i] = in.readDouble();
473    }
474
475    // read the base state
476    super.readExternal(in);
477
478  }
479
480}
481