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
9
* http://www.apache.org/licenses/LICENSE-2.0
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.
18
package org.apache.commons.math.ode.nonstiff;
22
* This class implements the 8(5,3) Dormand-Prince integrator for Ordinary
23
* Differential Equations.
25
* <p>This integrator is an embedded Runge-Kutta integrator
26
* of order 8(5,3) used in local extrapolation mode (i.e. the solution
27
* is computed using the high order formula) with stepsize control
28
* (and automatic step initialization) and continuous output. This
29
* method uses 12 functions evaluations per step for integration and 4
30
* evaluations for interpolation. However, since the first
31
* interpolation evaluation is the same as the first integration
32
* evaluation of the next step, we have included it in the integrator
33
* rather than in the interpolator and specified the method was an
34
* <i>fsal</i>. Hence, despite we have 13 stages here, the cost is
35
* really 12 evaluations per step even if no interpolation is done,
36
* and the overcost of interpolation is only 3 evaluations.</p>
38
* <p>This method is based on an 8(6) method by Dormand and Prince
39
* (i.e. order 8 for the integration and order 6 for error estimation)
40
* modified by Hairer and Wanner to use a 5th order error estimator
41
* with 3rd order correction. This modification was introduced because
42
* the original method failed in some cases (wrong steps can be
43
* accepted when step size is too large, for example in the
44
* Brusselator problem) and also had <i>severe difficulties when
45
* applied to problems with discontinuities</i>. This modification is
46
* explained in the second edition of the first volume (Nonstiff
47
* Problems) of the reference book by Hairer, Norsett and Wanner:
48
* <i>Solving Ordinary Differential Equations</i> (Springer-Verlag,
49
* ISBN 3-540-56670-8).</p>
51
* @version $Revision: 786881 $ $Date: 2009-06-20 14:53:08 -0400 (Sat, 20 Jun 2009) $
55
public class DormandPrince853Integrator extends EmbeddedRungeKuttaIntegrator {
57
/** Integrator method name. */
58
private static final String METHOD_NAME = "Dormand-Prince 8 (5, 3)";
60
/** Time steps Butcher array. */
61
private static final double[] staticC = {
62
(12.0 - 2.0 * Math.sqrt(6.0)) / 135.0, (6.0 - Math.sqrt(6.0)) / 45.0, (6.0 - Math.sqrt(6.0)) / 30.0,
63
(6.0 + Math.sqrt(6.0)) / 30.0, 1.0/3.0, 1.0/4.0, 4.0/13.0, 127.0/195.0, 3.0/5.0,
67
/** Internal weights Butcher array. */
68
private static final double[][] staticA = {
71
{(12.0 - 2.0 * Math.sqrt(6.0)) / 135.0},
74
{(6.0 - Math.sqrt(6.0)) / 180.0, (6.0 - Math.sqrt(6.0)) / 60.0},
77
{(6.0 - Math.sqrt(6.0)) / 120.0, 0.0, (6.0 - Math.sqrt(6.0)) / 40.0},
80
{(462.0 + 107.0 * Math.sqrt(6.0)) / 3000.0, 0.0,
81
(-402.0 - 197.0 * Math.sqrt(6.0)) / 1000.0, (168.0 + 73.0 * Math.sqrt(6.0)) / 375.0},
84
{1.0 / 27.0, 0.0, 0.0, (16.0 + Math.sqrt(6.0)) / 108.0, (16.0 - Math.sqrt(6.0)) / 108.0},
87
{19.0 / 512.0, 0.0, 0.0, (118.0 + 23.0 * Math.sqrt(6.0)) / 1024.0,
88
(118.0 - 23.0 * Math.sqrt(6.0)) / 1024.0, -9.0 / 512.0},
91
{13772.0 / 371293.0, 0.0, 0.0, (51544.0 + 4784.0 * Math.sqrt(6.0)) / 371293.0,
92
(51544.0 - 4784.0 * Math.sqrt(6.0)) / 371293.0, -5688.0 / 371293.0, 3072.0 / 371293.0},
95
{58656157643.0 / 93983540625.0, 0.0, 0.0,
96
(-1324889724104.0 - 318801444819.0 * Math.sqrt(6.0)) / 626556937500.0,
97
(-1324889724104.0 + 318801444819.0 * Math.sqrt(6.0)) / 626556937500.0,
98
96044563816.0 / 3480871875.0, 5682451879168.0 / 281950621875.0,
99
-165125654.0 / 3796875.0},
102
{8909899.0 / 18653125.0, 0.0, 0.0,
103
(-4521408.0 - 1137963.0 * Math.sqrt(6.0)) / 2937500.0,
104
(-4521408.0 + 1137963.0 * Math.sqrt(6.0)) / 2937500.0,
105
96663078.0 / 4553125.0, 2107245056.0 / 137915625.0,
106
-4913652016.0 / 147609375.0, -78894270.0 / 3880452869.0},
109
{-20401265806.0 / 21769653311.0, 0.0, 0.0,
110
(354216.0 + 94326.0 * Math.sqrt(6.0)) / 112847.0,
111
(354216.0 - 94326.0 * Math.sqrt(6.0)) / 112847.0,
112
-43306765128.0 / 5313852383.0, -20866708358144.0 / 1126708119789.0,
113
14886003438020.0 / 654632330667.0, 35290686222309375.0 / 14152473387134411.0,
114
-1477884375.0 / 485066827.0},
117
{39815761.0 / 17514443.0, 0.0, 0.0,
118
(-3457480.0 - 960905.0 * Math.sqrt(6.0)) / 551636.0,
119
(-3457480.0 + 960905.0 * Math.sqrt(6.0)) / 551636.0,
120
-844554132.0 / 47026969.0, 8444996352.0 / 302158619.0,
121
-2509602342.0 / 877790785.0, -28388795297996250.0 / 3199510091356783.0,
122
226716250.0 / 18341897.0, 1371316744.0 / 2131383595.0},
124
// k13 should be for interpolation only, but since it is the same
125
// stage as the first evaluation of the next step, we perform it
126
// here at no cost by specifying this is an fsal method
127
{104257.0/1920240.0, 0.0, 0.0, 0.0, 0.0, 3399327.0/763840.0,
128
66578432.0/35198415.0, -1674902723.0/288716400.0,
129
54980371265625.0/176692375811392.0, -734375.0/4826304.0,
130
171414593.0/851261400.0, 137909.0/3084480.0}
134
/** Propagation weights Butcher array. */
135
private static final double[] staticB = {
142
66578432.0/35198415.0,
143
-1674902723.0/288716400.0,
144
54980371265625.0/176692375811392.0,
146
171414593.0/851261400.0,
151
/** First error weights array, element 1. */
152
private static final double e1_01 = 116092271.0 / 8848465920.0;
154
// elements 2 to 5 are zero, so they are neither stored nor used
156
/** First error weights array, element 6. */
157
private static final double e1_06 = -1871647.0 / 1527680.0;
159
/** First error weights array, element 7. */
160
private static final double e1_07 = -69799717.0 / 140793660.0;
162
/** First error weights array, element 8. */
163
private static final double e1_08 = 1230164450203.0 / 739113984000.0;
165
/** First error weights array, element 9. */
166
private static final double e1_09 = -1980813971228885.0 / 5654156025964544.0;
168
/** First error weights array, element 10. */
169
private static final double e1_10 = 464500805.0 / 1389975552.0;
171
/** First error weights array, element 11. */
172
private static final double e1_11 = 1606764981773.0 / 19613062656000.0;
174
/** First error weights array, element 12. */
175
private static final double e1_12 = -137909.0 / 6168960.0;
178
/** Second error weights array, element 1. */
179
private static final double e2_01 = -364463.0 / 1920240.0;
181
// elements 2 to 5 are zero, so they are neither stored nor used
183
/** Second error weights array, element 6. */
184
private static final double e2_06 = 3399327.0 / 763840.0;
186
/** Second error weights array, element 7. */
187
private static final double e2_07 = 66578432.0 / 35198415.0;
189
/** Second error weights array, element 8. */
190
private static final double e2_08 = -1674902723.0 / 288716400.0;
192
/** Second error weights array, element 9. */
193
private static final double e2_09 = -74684743568175.0 / 176692375811392.0;
195
/** Second error weights array, element 10. */
196
private static final double e2_10 = -734375.0 / 4826304.0;
198
/** Second error weights array, element 11. */
199
private static final double e2_11 = 171414593.0 / 851261400.0;
201
/** Second error weights array, element 12. */
202
private static final double e2_12 = 69869.0 / 3084480.0;
204
/** Simple constructor.
205
* Build an eighth order Dormand-Prince integrator with the given step bounds
206
* @param minStep minimal step (must be positive even for backward
207
* integration), the last step can be smaller than this
208
* @param maxStep maximal step (must be positive even for backward
210
* @param scalAbsoluteTolerance allowed absolute error
211
* @param scalRelativeTolerance allowed relative error
213
public DormandPrince853Integrator(final double minStep, final double maxStep,
214
final double scalAbsoluteTolerance,
215
final double scalRelativeTolerance) {
216
super(METHOD_NAME, true, staticC, staticA, staticB,
217
new DormandPrince853StepInterpolator(),
218
minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
221
/** Simple constructor.
222
* Build an eighth order Dormand-Prince integrator with the given step bounds
223
* @param minStep minimal step (must be positive even for backward
224
* integration), the last step can be smaller than this
225
* @param maxStep maximal step (must be positive even for backward
227
* @param vecAbsoluteTolerance allowed absolute error
228
* @param vecRelativeTolerance allowed relative error
230
public DormandPrince853Integrator(final double minStep, final double maxStep,
231
final double[] vecAbsoluteTolerance,
232
final double[] vecRelativeTolerance) {
233
super(METHOD_NAME, true, staticC, staticA, staticB,
234
new DormandPrince853StepInterpolator(),
235
minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
240
public int getOrder() {
246
protected double estimateError(final double[][] yDotK,
247
final double[] y0, final double[] y1,
252
for (int j = 0; j < y0.length; ++j) {
253
final double errSum1 = e1_01 * yDotK[0][j] + e1_06 * yDotK[5][j] +
254
e1_07 * yDotK[6][j] + e1_08 * yDotK[7][j] +
255
e1_09 * yDotK[8][j] + e1_10 * yDotK[9][j] +
256
e1_11 * yDotK[10][j] + e1_12 * yDotK[11][j];
257
final double errSum2 = e2_01 * yDotK[0][j] + e2_06 * yDotK[5][j] +
258
e2_07 * yDotK[6][j] + e2_08 * yDotK[7][j] +
259
e2_09 * yDotK[8][j] + e2_10 * yDotK[9][j] +
260
e2_11 * yDotK[10][j] + e2_12 * yDotK[11][j];
262
final double yScale = Math.max(Math.abs(y0[j]), Math.abs(y1[j]));
263
final double tol = (vecAbsoluteTolerance == null) ?
264
(scalAbsoluteTolerance + scalRelativeTolerance * yScale) :
265
(vecAbsoluteTolerance[j] + vecRelativeTolerance[j] * yScale);
266
final double ratio1 = errSum1 / tol;
267
error1 += ratio1 * ratio1;
268
final double ratio2 = errSum2 / tol;
269
error2 += ratio2 * ratio2;
272
double den = error1 + 0.01 * error2;
277
return Math.abs(h) * error1 / Math.sqrt(y0.length * den);