00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "RK.H"
00027 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00028
00029
00030
00031 defineTypeNameAndDebug(Foam::RK, 0);
00032
00033 namespace Foam
00034 {
00035 addToRunTimeSelectionTable(ODESolver, RK, ODE);
00036
00037 const scalar
00038 RK::safety=0.9, RK::pGrow=-0.2, RK::pShrink=-0.25, RK::errCon=1.89e-4;
00039
00040 const scalar
00041 RK::a2 = 0.2, RK::a3 = 0.3, RK::a4 = 0.6, RK::a5 = 1.0, RK::a6 = 0.875,
00042 RK::b21 = 0.2, RK::b31 = 3.0/40.0, RK::b32 = 9.0/40.0,
00043 RK::b41 = 0.3, RK::b42 = -0.9, RK::b43 = 1.2,
00044 RK::b51 = -11.0/54.0, RK::b52 = 2.5, RK::b53 = -70.0/27.0,
00045 RK::b54 = 35.0/27.0,
00046 RK::b61 = 1631.0/55296.0, RK::b62 = 175.0/512.0, RK::b63 = 575.0/13824.0,
00047 RK::b64 = 44275.0/110592.0, RK::b65 = 253.0/4096.0,
00048 RK::c1 = 37.0/378.0, RK::c3 = 250.0/621.0,
00049 RK::c4 = 125.0/594.0, RK::c6 = 512.0/1771.0,
00050 RK::dc1 = RK::c1 - 2825.0/27648.0, RK::dc3 = RK::c3 - 18575.0/48384.0,
00051 RK::dc4 = RK::c4 - 13525.0/55296.0, RK::dc5 = -277.00/14336.0,
00052 RK::dc6 = RK::c6 - 0.25;
00053 };
00054
00055
00056
00057
00058 Foam::RK::RK(const ODE& ode)
00059 :
00060 ODESolver(ode),
00061 yTemp_(n_, 0.0),
00062 ak2_(n_, 0.0),
00063 ak3_(n_, 0.0),
00064 ak4_(n_, 0.0),
00065 ak5_(n_, 0.0),
00066 ak6_(n_, 0.0),
00067 yErr_(n_, 0.0),
00068 yTemp2_(n_, 0.0)
00069 {}
00070
00071
00072
00073
00074 void Foam::RK::solve
00075 (
00076 const ODE& ode,
00077 const scalar x,
00078 const scalarField& y,
00079 const scalarField& dydx,
00080 const scalar h,
00081 scalarField& yout,
00082 scalarField& yerr
00083 ) const
00084 {
00085 forAll(yTemp_, i)
00086 {
00087 yTemp_[i] = y[i] + b21*h*dydx[i];
00088 }
00089
00090 ode.derivatives(x + a2*h, yTemp_, ak2_);
00091
00092 forAll(yTemp_, i)
00093 {
00094 yTemp_[i] = y[i] + h*(b31*dydx[i] + b32*ak2_[i]);
00095 }
00096
00097 ode.derivatives(x + a3*h, yTemp_, ak3_);
00098
00099 forAll(yTemp_, i)
00100 {
00101 yTemp_[i] = y[i] + h*(b41*dydx[i] + b42*ak2_[i] + b43*ak3_[i]);
00102 }
00103
00104 ode.derivatives(x + a4*h, yTemp_, ak4_);
00105
00106 forAll(yTemp_, i)
00107 {
00108 yTemp_[i] = y[i]
00109 + h*(b51*dydx[i] + b52*ak2_[i] + b53*ak3_[i] + b54*ak4_[i]);
00110 }
00111
00112 ode.derivatives(x + a5*h, yTemp_, ak5_);
00113
00114 forAll(yTemp_, i)
00115 {
00116 yTemp_[i] = y[i]
00117 + h*
00118 (
00119 b61*dydx[i] + b62*ak2_[i] + b63*ak3_[i]
00120 + b64*ak4_[i] + b65*ak5_[i]
00121 );
00122 }
00123
00124 ode.derivatives(x + a6*h, yTemp_, ak6_);
00125
00126 forAll(yout, i)
00127 {
00128 yout[i] = y[i]
00129 + h*(c1*dydx[i] + c3*ak3_[i] + c4*ak4_[i] + c6*ak6_[i]);
00130 }
00131
00132 forAll(yerr, i)
00133 {
00134 yerr[i] =
00135 h*
00136 (
00137 dc1*dydx[i] + dc3*ak3_[i] + dc4*ak4_[i]
00138 + dc5*ak5_[i] + dc6*ak6_[i]
00139 );
00140 }
00141 }
00142
00143
00144 void Foam::RK::solve
00145 (
00146 const ODE& ode,
00147 scalar& x,
00148 scalarField& y,
00149 scalarField& dydx,
00150 const scalar eps,
00151 const scalarField& yScale,
00152 const scalar hTry,
00153 scalar& hDid,
00154 scalar& hNext
00155 ) const
00156 {
00157 scalar h = hTry;
00158 scalar maxErr = 0.0;
00159
00160 for (;;)
00161 {
00162 solve(ode, x, y, dydx, h, yTemp2_, yErr_);
00163
00164 maxErr = 0.0;
00165 for (register label i=0; i<n_; i++)
00166 {
00167 maxErr = max(maxErr, mag(yErr_[i]/yScale[i]));
00168 }
00169 maxErr /= eps;
00170
00171 if (maxErr <= 1.0)
00172 {
00173 break;
00174 }
00175
00176 {
00177 scalar hTemp = safety*h*pow(maxErr, pShrink);
00178 h = (h >= 0.0 ? max(hTemp, 0.1*h) : min(hTemp, 0.1*h));
00179 }
00180
00181 if (h < VSMALL)
00182 {
00183 FatalErrorIn("RK::solve")
00184 << "stepsize underflow"
00185 << exit(FatalError);
00186 }
00187 }
00188
00189 hDid = h;
00190
00191 x += h;
00192 y = yTemp2_;
00193
00194 if (maxErr > errCon)
00195 {
00196 hNext = safety*h*pow(maxErr, pGrow);
00197 }
00198 else
00199 {
00200 hNext = 5.0*h;
00201 }
00202 }
00203
00204
00205