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 "SIBS.H"
00027 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00028
00029
00030
00031 defineTypeNameAndDebug(Foam::SIBS, 0);
00032
00033 namespace Foam
00034 {
00035 addToRunTimeSelectionTable(ODESolver, SIBS, ODE);
00036
00037 const label SIBS::nSeq_[iMaxX_] = {2, 6, 10, 14, 22, 34, 50, 70};
00038
00039 const scalar
00040 SIBS::safe1 = 0.25,
00041 SIBS::safe2 = 0.7,
00042 SIBS::redMax = 1.0e-5,
00043 SIBS::redMin = 0.7,
00044 SIBS::scaleMX = 0.1;
00045 };
00046
00047
00048
00049
00050 Foam::SIBS::SIBS(const ODE& ode)
00051 :
00052 ODESolver(ode),
00053 a_(iMaxX_, 0.0),
00054 alpha_(kMaxX_, kMaxX_, 0.0),
00055 d_p_(n_, kMaxX_, 0.0),
00056 x_p_(kMaxX_, 0.0),
00057 err_(kMaxX_, 0.0),
00058
00059 yTemp_(n_, 0.0),
00060 ySeq_(n_, 0.0),
00061 yErr_(n_, 0.0),
00062 dfdx_(n_, 0.0),
00063 dfdy_(n_, n_, 0.0),
00064 first_(1),
00065 epsOld_(-1.0)
00066 {}
00067
00068
00069
00070
00071 void Foam::SIBS::solve
00072 (
00073 const ODE& ode,
00074 scalar& x,
00075 scalarField& y,
00076 scalarField& dydx,
00077 const scalar eps,
00078 const scalarField& yScale,
00079 const scalar hTry,
00080 scalar& hDid,
00081 scalar& hNext
00082 ) const
00083 {
00084 bool exitflag = false;
00085
00086 if (eps != epsOld_)
00087 {
00088 hNext = xNew_ = -GREAT;
00089 scalar eps1 = safe1*eps;
00090 a_[0] = nSeq_[0] + 1;
00091
00092 for (register label k=0; k<kMaxX_; k++)
00093 {
00094 a_[k + 1] = a_[k] + nSeq_[k + 1];
00095 }
00096
00097 for (register label iq = 1; iq<kMaxX_; iq++)
00098 {
00099 for (register label k=0; k<iq; k++)
00100 {
00101 alpha_[k][iq] =
00102 pow(eps1, (a_[k + 1] - a_[iq + 1])
00103 /((a_[iq + 1] - a_[0] + 1.0)*(2*k + 3)));
00104 }
00105 }
00106
00107 epsOld_ = eps;
00108 a_[0] += n_;
00109
00110 for (register label k=0; k<kMaxX_; k++)
00111 {
00112 a_[k + 1] = a_[k] + nSeq_[k + 1];
00113 }
00114
00115 for (kOpt_ = 1; kOpt_<kMaxX_ - 1; kOpt_++)
00116 {
00117 if (a_[kOpt_ + 1] > a_[kOpt_]*alpha_[kOpt_ - 1][kOpt_])
00118 {
00119 break;
00120 }
00121 }
00122
00123 kMax_ = kOpt_;
00124 }
00125
00126 label k=0;
00127 scalar h = hTry;
00128 yTemp_ = y;
00129
00130 ode.jacobian(x, y, dfdx_, dfdy_);
00131
00132 if (x != xNew_ || h != hNext)
00133 {
00134 first_ = 1;
00135 kOpt_ = kMax_;
00136 }
00137
00138 label km=0;
00139 label reduct=0;
00140 scalar maxErr = SMALL;
00141
00142 for (;;)
00143 {
00144 scalar red = 1.0;
00145
00146 for (k=0; k <= kMax_; k++)
00147 {
00148 xNew_ = x + h;
00149
00150 if (xNew_ == x)
00151 {
00152 FatalErrorIn("ODES::SIBS")
00153 << "step size underflow"
00154 << exit(FatalError);
00155 }
00156
00157 SIMPR(ode, x, yTemp_, dydx, dfdx_, dfdy_, h, nSeq_[k], ySeq_);
00158 scalar xest = sqr(h/nSeq_[k]);
00159
00160 polyExtrapolate(k, xest, ySeq_, y, yErr_, x_p_, d_p_);
00161
00162 if (k != 0)
00163 {
00164 maxErr = SMALL;
00165 for (register label i=0; i<n_; i++)
00166 {
00167 maxErr = max(maxErr, mag(yErr_[i]/yScale[i]));
00168 }
00169 maxErr /= eps;
00170 km = k - 1;
00171 err_[km] = pow(maxErr/safe1, 1.0/(2*km + 3));
00172 }
00173
00174 if (k != 0 && (k >= kOpt_ - 1 || first_))
00175 {
00176 if (maxErr < 1.0)
00177 {
00178 exitflag = true;
00179 break;
00180 }
00181
00182 if (k == kMax_ || k == kOpt_ + 1)
00183 {
00184 red = safe2/err_[km];
00185 break;
00186 }
00187 else if (k == kOpt_ && alpha_[kOpt_ - 1][kOpt_] < err_[km])
00188 {
00189 red = 1.0/err_[km];
00190 break;
00191 }
00192 else if (kOpt_ == kMax_ && alpha_[km][kMax_ - 1] < err_[km])
00193 {
00194 red = alpha_[km][kMax_ - 1]*safe2/err_[km];
00195 break;
00196 }
00197 else if (alpha_[km][kOpt_] < err_[km])
00198 {
00199 red = alpha_[km][kOpt_ - 1]/err_[km];
00200 break;
00201 }
00202 }
00203 }
00204
00205 if (exitflag)
00206 {
00207 break;
00208 }
00209
00210 red = min(red, redMin);
00211 red = max(red, redMax);
00212 h *= red;
00213 reduct = 1;
00214 }
00215
00216 x = xNew_;
00217 hDid = h;
00218 first_=0;
00219 scalar wrkmin = GREAT;
00220 scalar scale = 1.0;
00221
00222 for (register label kk=0; kk<=km; kk++)
00223 {
00224 scalar fact = max(err_[kk], scaleMX);
00225 scalar work = fact*a_[kk + 1];
00226 if (work < wrkmin)
00227 {
00228 scale = fact;
00229 wrkmin = work;
00230 kOpt_ = kk + 1;
00231 }
00232 }
00233
00234 hNext = h/scale;
00235
00236 if (kOpt_ >= k && kOpt_ != kMax_ && !reduct)
00237 {
00238 scalar fact = max(scale/alpha_[kOpt_ - 1][kOpt_], scaleMX);
00239 if (a_[kOpt_ + 1]*fact <= wrkmin)
00240 {
00241 hNext = h/fact;
00242 kOpt_++;
00243 }
00244 }
00245 }
00246
00247
00248