1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 Semi-Implicit Burlisch-Stoer scheme for stiff equation sets
27 Numerical Recipes in C, Secn 16.6 page 742-747
28 Alternative reference in Numerical Recipes in C++
30 \*---------------------------------------------------------------------------*/
33 #include "addToRunTimeSelectionTable.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 defineTypeNameAndDebug(Foam::SIBS, 0);
41 addToRunTimeSelectionTable(ODESolver, SIBS, ODE);
43 const label SIBS::nSeq_[iMaxX_] = {2, 6, 10, 14, 22, 34, 50, 70};
46 SIBS::safe1 = 0.25, SIBS::safe2 = 0.7,
47 SIBS::redMax = 1.0e-5, SIBS::redMin = 0.0, SIBS::scaleMX = 0.1;
51 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
53 Foam::SIBS::SIBS(ODE& ode)
57 alpha_(kMaxX_, kMaxX_),
58 d_p_(ode_.nEqns(), kMaxX_),
66 dfdy_(ode_.nEqns(), ode_.nEqns()),
72 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
74 void Foam::SIBS::solve
80 const scalarField& yScale,
86 bool exitflag = false;
87 const label nEqns = ode_.nEqns();
91 hNext = xNew_ = -GREAT;
92 scalar eps1 = safe1*eps;
95 for (register label k=0; k<kMaxX_; k++)
97 a_[k + 1] = a_[k] + nSeq_[k + 1];
100 for (register label iq = 1; iq<kMaxX_; iq++)
102 for (register label k=0; k<iq; k++)
105 pow(eps1, (a_[k + 1] - a_[iq + 1])
106 /((a_[iq + 1] - a_[0] + 1.0)*(2*k + 3)));
113 for (register label k=0; k<kMaxX_; k++)
115 a_[k + 1] = a_[k] + nSeq_[k + 1];
118 for (kOpt_ = 1; kOpt_<kMaxX_ - 1; kOpt_++)
120 if (a_[kOpt_ + 1] > a_[kOpt_]*alpha_[kOpt_ - 1][kOpt_])
133 ode_.jacobian(x, y, dfdx_, dfdy_);
135 if (x != xNew_ || h != hNext)
143 scalar maxErr = SMALL;
149 for (k=0; k <= kMax_; k++)
155 FatalErrorIn("ODES::SIBS")
156 << "step size underflow"
160 SIMPR(x, yTemp_, dydx, dfdx_, dfdy_, h, nSeq_[k], ySeq_);
161 scalar xest = sqr(h/nSeq_[k]);
163 polyExtrapolate(k, xest, ySeq_, y, yErr_, x_p_, d_p_);
168 for (register label i=0; i<nEqns; i++)
170 maxErr = max(maxErr, mag(yErr_[i]/yScale[i]));
174 err_[km] = pow(maxErr/safe1, 1.0/(2*km + 3));
177 if (k != 0 && (k >= kOpt_ - 1 || first_))
185 if (k == kMax_ || k == kOpt_ + 1)
187 red = safe2/err_[km];
190 else if (k == kOpt_ && alpha_[kOpt_ - 1][kOpt_] < err_[km])
195 else if (kOpt_ == kMax_ && alpha_[km][kMax_ - 1] < err_[km])
197 red = alpha_[km][kMax_ - 1]*safe2/err_[km];
200 else if (alpha_[km][kOpt_] < err_[km])
202 red = alpha_[km][kOpt_ - 1]/err_[km];
213 red = min(red, redMin);
214 red = max(red, redMax);
222 scalar wrkmin = GREAT;
225 for (register label kk=0; kk<=km; kk++)
227 scalar fact = max(err_[kk], scaleMX);
228 scalar work = fact*a_[kk + 1];
239 if (kOpt_ >= k && kOpt_ != kMax_ && !reduct)
241 scalar fact = max(scale/alpha_[kOpt_ - 1][kOpt_], scaleMX);
242 if (a_[kOpt_ + 1]*fact <= wrkmin)
251 // ************************************************************************* //