seulex.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2013-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "seulex.H"
28 
29 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
30 
31 namespace Foam
32 {
33  defineTypeNameAndDebug(seulex, 0);
34 
35  addToRunTimeSelectionTable(ODESolver, seulex, dictionary);
36 
37  const scalar
39  seulex::stepFactor2_ = 0.93,
43  seulex::kFactor1_ = 0.7,
44  seulex::kFactor2_ = 0.9;
45 }
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
51 :
52  ODESolver(ode, dict),
53  jacRedo_(min(1.0e-4, min(relTol_))),
54  nSeq_(iMaxx_),
55  cpu_(iMaxx_),
56  coeff_(iMaxx_, iMaxx_),
57  theta_(2.0*jacRedo_),
58  table_(kMaxx_, n_),
59  dfdx_(n_),
60  dfdy_(n_),
61  a_(n_),
62  pivotIndices_(n_),
63  dxOpt_(iMaxx_),
64  temp_(iMaxx_),
65  y0_(n_),
66  ySequence_(n_),
67  scale_(n_),
68  dy_(n_),
69  yTemp_(n_),
70  dydx_(n_)
71 {
72  // The CPU time factors for the major parts of the algorithm
73  const scalar cpuFunc = 1.0, cpuJac = 5.0, cpuLU = 1.0, cpuSolve = 1.0;
74 
75  nSeq_[0] = 2;
76  nSeq_[1] = 3;
77 
78  for (int i=2; i<iMaxx_; i++)
79  {
80  nSeq_[i] = 2*nSeq_[i-2];
81  }
82  cpu_[0] = cpuJac + cpuLU + nSeq_[0]*(cpuFunc + cpuSolve);
83 
84  for (int k=0; k<kMaxx_; k++)
85  {
86  cpu_[k+1] = cpu_[k] + (nSeq_[k+1]-1)*(cpuFunc + cpuSolve) + cpuLU;
87  }
88 
89  // Set the extrapolation coefficients array
90  for (int k=0; k<iMaxx_; k++)
91  {
92  for (int l=0; l<k; l++)
93  {
94  scalar ratio = scalar(nSeq_[k])/nSeq_[l];
95  coeff_[k][l] = 1.0/(ratio - 1.0);
96  }
97  }
98 }
99 
100 
101 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
102 
104 (
105  const scalar x0,
106  const scalarField& y0,
107  const scalar dxTot,
108  const label k,
109  scalarField& y,
110  const scalarField& scale
111 ) const
112 {
113  label nSteps = nSeq_[k];
114  scalar dx = dxTot/nSteps;
115 
116  for (label i=0; i<n_; i++)
117  {
118  for (label j=0; j<n_; j++)
119  {
120  a_[i][j] = -dfdy_[i][j];
121  }
122 
123  a_[i][i] += 1.0/dx;
124  }
125 
126  LUDecompose(a_, pivotIndices_);
127 
128  scalar xnew = x0 + dx;
129  odes_.derivatives(xnew, y0, dy_);
130  LUBacksubstitute(a_, pivotIndices_, dy_);
131 
132  yTemp_ = y0;
133 
134  for (label nn=1; nn<nSteps; nn++)
135  {
136  yTemp_ += dy_;
137  xnew += dx;
138 
139  if (nn == 1 && k<=1)
140  {
141  scalar dy1 = 0.0;
142  for (label i=0; i<n_; i++)
143  {
144  dy1 += sqr(dy_[i]/scale[i]);
145  }
146  dy1 = sqrt(dy1);
147 
148  odes_.derivatives(x0 + dx, yTemp_, dydx_);
149  for (label i=0; i<n_; i++)
150  {
151  dy_[i] = dydx_[i] - dy_[i]/dx;
152  }
153 
154  LUBacksubstitute(a_, pivotIndices_, dy_);
155 
156  scalar dy2 = 0.0;
157  for (label i=0; i<n_; i++)
158  {
159  dy2 += sqr(dy_[i]/scale[i]);
160  }
161  dy2 = sqrt(dy2);
162  theta_ = dy2/min(1.0, dy1 + SMALL);
163 
164  if (theta_ > 1.0)
165  {
166  return false;
167  }
168  }
169 
170  odes_.derivatives(xnew, yTemp_, dy_);
171  LUBacksubstitute(a_, pivotIndices_, dy_);
172  }
173 
174  for (label i=0; i<n_; i++)
175  {
176  y[i] = yTemp_[i] + dy_[i];
177  }
178 
179  return true;
180 }
181 
182 
184 (
185  const label k,
187  scalarField& y
188 ) const
189 {
190  for (int j=k-1; j>0; j--)
191  {
192  for (label i=0; i<n_; i++)
193  {
194  table[j-1][i] =
195  table[j][i] + coeff_[k][j]*(table[j][i] - table[j-1][i]);
196  }
197  }
198 
199  for (int i=0; i<n_; i++)
200  {
201  y[i] = table[0][i] + coeff_[k][0]*(table[0][i] - y[i]);
202  }
203 }
204 
205 
207 (
208  scalar& x,
209  scalarField& y,
210  stepState& step
211 ) const
212 {
213  temp_[0] = GREAT;
214  scalar dx = step.dxTry;
215  y0_ = y;
216  dxOpt_[0] = mag(0.1*dx);
217 
218  if (step.first || step.prevReject)
219  {
220  theta_ = 2.0*jacRedo_;
221  }
222 
223  if (step.first)
224  {
225  // NOTE: the first element of relTol_ and absTol_ are used here.
226  scalar logTol = -log10(relTol_[0] + absTol_[0])*0.6 + 0.5;
227  kTarg_ = max(1, min(kMaxx_ - 1, int(logTol)));
228  }
229 
230  forAll(scale_, i)
231  {
232  scale_[i] = absTol_[i] + relTol_[i]*mag(y[i]);
233  }
234 
235  bool jacUpdated = false;
236 
237  if (theta_ > jacRedo_)
238  {
239  odes_.jacobian(x, y, dfdx_, dfdy_);
240  jacUpdated = true;
241  }
242 
243  int k;
244  scalar dxNew = mag(dx);
245  bool firstk = true;
246 
247  while (firstk || step.reject)
248  {
249  dx = step.forward ? dxNew : -dxNew;
250  firstk = false;
251  step.reject = false;
252 
253  if (mag(dx) <= mag(x)*sqr(SMALL))
254  {
256  << "step size underflow :" << dx << endl;
257  }
258 
259  scalar errOld = 0;
260 
261  for (k=0; k<=kTarg_+1; k++)
262  {
263  bool success = seul(x, y0_, dx, k, ySequence_, scale_);
264 
265  if (!success)
266  {
267  step.reject = true;
268  dxNew = mag(dx)*stepFactor5_;
269  break;
270  }
271 
272  if (k == 0)
273  {
274  y = ySequence_;
275  }
276  else
277  {
278  forAll(ySequence_, i)
279  {
280  table_[k-1][i] = ySequence_[i];
281  }
282  }
283 
284  if (k != 0)
285  {
286  extrapolate(k, table_, y);
287  scalar err = 0.0;
288  forAll(scale_, i)
289  {
290  scale_[i] = absTol_[i] + relTol_[i]*mag(y0_[i]);
291  err += sqr((y[i] - table_[0][i])/scale_[i]);
292  }
293  err = sqrt(err/n_);
294  if (err > 1.0/SMALL || (k > 1 && err >= errOld))
295  {
296  step.reject = true;
297  dxNew = mag(dx)*stepFactor5_;
298  break;
299  }
300  errOld = min(4*err, 1);
301  scalar expo = 1.0/(k + 1);
302  scalar facmin = pow(stepFactor3_, expo);
303  scalar fac;
304  if (err == 0.0)
305  {
306  fac = 1.0/facmin;
307  }
308  else
309  {
310  fac = stepFactor2_/pow(err/stepFactor1_, expo);
311  fac = max(facmin/stepFactor4_, min(1.0/facmin, fac));
312  }
313  dxOpt_[k] = mag(dx*fac);
314  temp_[k] = cpu_[k]/dxOpt_[k];
315 
316  if ((step.first || step.last) && err <= 1.0)
317  {
318  break;
319  }
320 
321  if
322  (
323  k == kTarg_ - 1
324  && !step.prevReject
325  && !step.first && !step.last
326  )
327  {
328  if (err <= 1.0)
329  {
330  break;
331  }
332  else if (err > nSeq_[kTarg_]*nSeq_[kTarg_ + 1]*4.0)
333  {
334  step.reject = true;
335  kTarg_ = k;
336  if (kTarg_>1 && temp_[k-1] < kFactor1_*temp_[k])
337  {
338  kTarg_--;
339  }
340  dxNew = dxOpt_[kTarg_];
341  break;
342  }
343  }
344 
345  if (k == kTarg_)
346  {
347  if (err <= 1.0)
348  {
349  break;
350  }
351  else if (err > nSeq_[k + 1]*2.0)
352  {
353  step.reject = true;
354  if (kTarg_>1 && temp_[k-1] < kFactor1_*temp_[k])
355  {
356  kTarg_--;
357  }
358  dxNew = dxOpt_[kTarg_];
359  break;
360  }
361  }
362 
363  if (k == kTarg_+1)
364  {
365  if (err > 1.0)
366  {
367  step.reject = true;
368  if
369  (
370  kTarg_ > 1
371  && temp_[kTarg_-1] < kFactor1_*temp_[kTarg_]
372  )
373  {
374  kTarg_--;
375  }
376  dxNew = dxOpt_[kTarg_];
377  }
378  break;
379  }
380  }
381  }
382  if (step.reject)
383  {
384  step.prevReject = true;
385  if (!jacUpdated)
386  {
387  theta_ = 2.0*jacRedo_;
388 
389  if (theta_ > jacRedo_ && !jacUpdated)
390  {
391  odes_.jacobian(x, y, dfdx_, dfdy_);
392  jacUpdated = true;
393  }
394  }
395  }
396  }
397 
398  jacUpdated = false;
399 
400  step.dxDid = dx;
401  x += dx;
402 
403  label kopt;
404  if (k == 1)
405  {
406  kopt = 2;
407  }
408  else if (k <= kTarg_)
409  {
410  kopt=k;
411  if (temp_[k-1] < kFactor1_*temp_[k])
412  {
413  kopt = k - 1;
414  }
415  else if (temp_[k] < kFactor2_*temp_[k - 1])
416  {
417  kopt = min(k + 1, kMaxx_ - 1);
418  }
419  }
420  else
421  {
422  kopt = k - 1;
423  if (k > 2 && temp_[k-2] < kFactor1_*temp_[k - 1])
424  {
425  kopt = k - 2;
426  }
427  if (temp_[k] < kFactor2_*temp_[kopt])
428  {
429  kopt = min(k, kMaxx_ - 1);
430  }
431  }
432 
433  if (step.prevReject)
434  {
435  kTarg_ = min(kopt, k);
436  dxNew = min(mag(dx), dxOpt_[kTarg_]);
437  step.prevReject = false;
438  }
439  else
440  {
441  if (kopt <= k)
442  {
443  dxNew = dxOpt_[kopt];
444  }
445  else
446  {
447  if (k < kTarg_ && temp_[k] < kFactor2_*temp_[k - 1])
448  {
449  dxNew = dxOpt_[k]*cpu_[kopt + 1]/cpu_[k];
450  }
451  else
452  {
453  dxNew = dxOpt_[k]*cpu_[kopt]/cpu_[k];
454  }
455  }
456  kTarg_ = kopt;
457  }
458 
459  step.dxTry = step.forward ? dxNew : -dxNew;
460 }
461 
462 
463 // ************************************************************************* //
Foam::seulex::stepFactor3_
static const scalar stepFactor3_
Definition: seulex.H:73
Foam::ODESolver::stepState
Definition: ODESolver.H:95
Foam::seulex::stepFactor5_
static const scalar stepFactor5_
Definition: seulex.H:74
Foam::ODESolver::stepState::reject
bool reject
Definition: ODESolver.H:104
Foam::seulex::coeff_
scalarSquareMatrix coeff_
Definition: seulex.H:82
Foam::ODESolver
Abstract base-class for ODE system solvers.
Definition: ODESolver.H:50
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
success
bool success
Definition: LISASMDCalcMethod1.H:16
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
Foam::seulex::stepFactor4_
static const scalar stepFactor4_
Definition: seulex.H:74
Foam::seulex::kMaxx_
static const label kMaxx_
Definition: seulex.H:69
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::seulex::solve
void solve(scalar &x, scalarField &y, stepState &step) const
Solve the ODE system and the update the state.
Definition: seulex.C:207
Foam::seulex::stepFactor1_
static const scalar stepFactor1_
Definition: seulex.H:73
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::ODESolver::stepState::forward
const bool forward
Definition: ODESolver.H:99
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::seulex::nSeq_
labelField nSeq_
Definition: seulex.H:80
Foam::log10
dimensionedScalar log10(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:254
Foam::y0
dimensionedScalar y0(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:272
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:73
Foam::RectangularMatrix< scalar >
Foam::ode
An ODE solver for chemistry.
Definition: ode.H:50
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::ODESolver::stepState::dxTry
scalar dxTry
Definition: ODESolver.H:100
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::ODESolver::stepState::first
bool first
Definition: ODESolver.H:102
Foam::seulex::iMaxx_
static const label iMaxx_
Definition: seulex.H:70
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::LUBacksubstitute
void LUBacksubstitute(const scalarSquareMatrix &luMmatrix, const labelList &pivotIndices, List< Type > &source)
LU back-substitution with given source, returning the solution.
Definition: scalarMatricesTemplates.C:120
Foam::ODESolver::stepState::last
bool last
Definition: ODESolver.H:103
Foam::LUDecompose
void LUDecompose(scalarSquareMatrix &matrix, labelList &pivotIndices)
LU decompose the matrix with pivoting.
Definition: scalarMatrices.C:32
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
Foam::seulex::extrapolate
void extrapolate(const label k, scalarRectangularMatrix &table, scalarField &y) const
Polynomial extrpolation.
Definition: seulex.C:184
Foam::seulex::stepFactor2_
static const scalar stepFactor2_
Definition: seulex.H:73
Foam::ODESystem
Abstract base class for the systems of ordinary differential equations.
Definition: ODESystem.H:46
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:142
Foam::seulex::kFactor1_
static const scalar kFactor1_
Definition: seulex.H:75
k
label k
Boltzmann constant.
Definition: LISASMDCalcMethod2.H:41
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
seulex.H
x
x
Definition: LISASMDCalcMethod2.H:52
Foam::seulex::seul
bool seul(const scalar x0, const scalarField &y0, const scalar dxTot, const label k, scalarField &y, const scalarField &scale) const
Computes the j-th line of the extrapolation table.
Definition: seulex.C:104
Foam::seulex::kFactor2_
static const scalar kFactor2_
Definition: seulex.H:75
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::seulex::cpu_
scalarField cpu_
Definition: seulex.H:81
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
Foam::ODESolver::stepState::dxDid
scalar dxDid
Definition: ODESolver.H:101
Foam::ODESolver::stepState::prevReject
bool prevReject
Definition: ODESolver.H:105
Foam::seulex::seulex
seulex(const ODESystem &ode, const dictionary &dict)
Construct from ODE.
Definition: seulex.C:50
y
scalar y
Definition: LISASMDCalcMethod1.H:14