00001
00002
00003
00004
00005
00006
00008 #include <cassert>
00009 #include <cmath>
00010
00011 #include "NumericalMethods/NmOdeStepperRKCK.h"
00012 #include "NumericalMethods/NmOdeDerivFunc.h"
00013 #include "MessageService/MsgService.h"
00014 CVSID("$Id: NmStepperRKCK.cxx,v 1.7 2009/02/28 21:46:15 gmieg Exp $");
00015
00016
00017 #define MAXMACRO(x,y) (((x)>(y))?(x):(y))
00018 #define MINMACRO(x,y) (((x)<(y))?(x):(y))
00019
00020
00021
00022 NmOdeStepperRKCK::NmOdeStepperRKCK() {}
00023
00024
00025
00026 NmOdeStepperRKCK::~NmOdeStepperRKCK() {}
00027
00028
00029
00030 void NmOdeStepperRKCK::Step(double* y,
00031 const double* dydx,
00032 int n,
00033 double* x,
00034 double hTry,
00035 double eps,
00036 const double* yScale,
00037 double* hDid,
00038 double* hNext,
00039 NmOdeDerivFunc& Derivs) {
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 register int i;
00056 double* yTemp = new double[n];
00057 double* yErr = new double[n];
00058 double errMax;
00059 double h;
00060
00061 static const double gSafety = 0.90;
00062 static const double gPgrow = -0.20;
00063 static const double gPshrink = -0.25;
00064 static const double gMaxGrow = 5.0;
00065 static const double gErrCon = pow(gMaxGrow/gSafety, 1.0/gPgrow);
00066
00067 h = hTry;
00068 for (;;) {
00069 double hTemp;
00070 double xNew;
00071
00072
00073 this->RKCKStep(y, dydx, n, *x, h, yTemp, yErr, Derivs);
00074
00075
00076 errMax = 0.0;
00077 for (i=0; i<n; i++) {
00078 if (yScale[i]!=0.0) {
00079 errMax = MAXMACRO(errMax,fabs(yErr[i]/yScale[i]));
00080 }
00081 }
00082 errMax /= eps;
00083
00084
00085 if (errMax < 1.0) break;
00086
00087
00088 hTemp = gSafety*h*pow(errMax, gPshrink);
00089 h = (h>=0.0 ? MAXMACRO(hTemp, 0.1*h) : MINMACRO(hTemp, 0.1*h));
00090 xNew = (*x)+h;
00091 if (xNew == *x) {
00092 MSG("Nm",Msg::kFatal)
00093 << "Step underflow. eps=" << eps << "\n";
00094 abort();
00095 }
00096 }
00097
00098
00099
00100 if (errMax > gErrCon) {
00101 *hNext = gSafety*h*pow(errMax, gPgrow);
00102 }
00103 else {
00104 *hNext = gMaxGrow*h;
00105 }
00106 *x += h;
00107 *hDid = h;
00108 for (i=0; i<n; ++i) y[i] = yTemp[i];
00109 delete []yTemp; yTemp = 0;
00110 delete []yErr; yErr = 0;
00111 }
00112
00113
00114
00115 void NmOdeStepperRKCK::RKCKStep(const double* y,
00116 const double* dydx,
00117 int n,
00118 double x,
00119 double h,
00120 double* yOut,
00121 double* yErr,
00122 NmOdeDerivFunc& Derivs) {
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 static const double
00139 a2=1./ 5., a3=3./10., a4=3./5., a5=1., a6=7./8.;
00140 static const double
00141 b21= 1./5.,
00142 b31= 3./40., b32= 9./40.,
00143 b41= 3./10., b42= -9./10., b43= 6./5.,
00144 b51= -11./54., b52= 5./2., b53= -70./27., b54=35./27.,
00145 b61=1631./55296., b62=175./512., b63=575./13824., b64=44275./110592.,
00146 b65=253./4096.;
00147 static const double
00148 c1 = 37./378.,
00149
00150 c3 = 250./621.,
00151 c4 = 125./594.,
00152 c5 = 0.0,
00153 c6 = 512./1771.;
00154 static const double
00155 dc1 = c1 - 2825./27648.,
00156
00157 dc3 = c3 - 18575./48384.,
00158 dc4 = c4 - 13525./55296.,
00159 dc5 = c5 - 277./14336.,
00160 dc6 = c6 - 1./4.;
00161 register int i;
00162
00163 double* ak2 = new double[n];
00164 double* ak3 = new double[n];
00165 double* ak4 = new double[n];
00166 double* ak5 = new double[n];
00167 double* ak6 = new double[n];
00168 double* yTemp = new double[n];
00169
00170 for (i=0; i<n; ++i) {
00171 yTemp[i] = y[i] + h*b21*dydx[i];
00172 }
00173 Derivs(x + a2*h, yTemp, ak2);
00174 for (i=0; i<n; ++i) {
00175 yTemp[i] = y[i] + h*(b31*dydx[i] + b32*ak2[i]);
00176 }
00177 Derivs(x + a3*h, yTemp, ak3);
00178 for (i=0; i<n; ++i) {
00179 yTemp[i] = y[i] + h*(b41*dydx[i] + b42*ak2[i] + b43*ak3[i]);
00180 }
00181 Derivs(x+a4*h, yTemp, ak4);
00182 for (i=0; i<n; ++i) {
00183 yTemp[i] = y[i] + h*(b51*dydx[i] + b52*ak2[i] + b53*ak3[i] + b54*ak4[i]);
00184 }
00185 Derivs(x + a5*h, yTemp, ak5);
00186 for (i=0; i<n; ++i) {
00187 yTemp[i] = y[i] +
00188 h*(b61*dydx[i] + b62*ak2[i] + b63*ak3[i] + b64*ak4[i] + b65*ak5[i]);
00189 }
00190 Derivs(x+a6*h, yTemp, ak6);
00191
00192
00193 for (i=0; i<n; ++i) {
00194 yOut[i] =
00195 y[i]+h*(c1*dydx[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]);
00196 }
00197
00198
00199 for (i=0; i<n; ++i) {
00200 yErr[i] = h*(dc1*dydx[i] + dc3*ak3[i] + dc4*ak4[i] + dc5*ak5[i] +
00201 dc6*ak6[i]);
00202 }
00203 delete []ak2; ak2 = 0;
00204 delete []ak3; ak3 = 0;
00205 delete []ak4; ak4 = 0;
00206 delete []ak5; ak5 = 0;
00207 delete []ak6; ak6 = 0;
00208 delete []yTemp; yTemp = 0;
00209 }
00210