SCOPELaminarFlameSpeed.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2023 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 "IFstream.H"
27 #include "SCOPELaminarFlameSpeed.H"
29 
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
31 
32 namespace Foam
33 {
34 namespace laminarFlameSpeedModels
35 {
37 
39  (
41  SCOPE,
43  );
44 }
45 }
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
50 Foam::laminarFlameSpeedModels::SCOPE::polynomial::polynomial
51 (
52  const dictionary& polyDict
53 )
54 :
55  FixedList<scalar, 7>(polyDict.lookup("coefficients")),
56  ll(polyDict.lookup<scalar>("lowerLimit")),
57  ul(polyDict.lookup<scalar>("upperLimit")),
58  llv(polyPhi(ll, *this)),
59  ulv(polyPhi(ul, *this)),
60  lu(0)
61 {}
62 
63 
65 (
66  const dictionary& dict,
67  const psiuMulticomponentThermo& ct
68 )
69 :
71 
72  coeffsDict_
73  (
75  (
76  IFstream
77  (
78  fileName
79  (
80  dict.lookup("fuelFile")
81  )
82  )()
83  ).optionalSubDict(typeName + "Coeffs")
84  ),
85  LFL_(coeffsDict_.lookup<scalar>("lowerFlamabilityLimit")),
86  UFL_(coeffsDict_.lookup<scalar>("upperFlamabilityLimit")),
87  SuPolyL_(coeffsDict_.subDict("lowerSuPolynomial")),
88  SuPolyU_(coeffsDict_.subDict("upperSuPolynomial")),
89  Texp_(coeffsDict_.lookup<scalar>("Texp")),
90  pexp_(coeffsDict_.lookup<scalar>("pexp")),
91  MaPolyL_(coeffsDict_.subDict("lowerMaPolynomial")),
92  MaPolyU_(coeffsDict_.subDict("upperMaPolynomial"))
93 {
94  SuPolyL_.ll = max(SuPolyL_.ll, LFL_) + small;
95  SuPolyU_.ul = min(SuPolyU_.ul, UFL_) - small;
96 
97  SuPolyL_.lu = 0.5*(SuPolyL_.ul + SuPolyU_.ll);
98  SuPolyU_.lu = SuPolyL_.lu - small;
99 
100  MaPolyL_.lu = 0.5*(MaPolyL_.ul + MaPolyU_.ll);
101  MaPolyU_.lu = MaPolyL_.lu - small;
102 
103  if (debug)
104  {
105  Info<< "phi Su (T = Tref, p = pref)" << endl;
106  label n = 200;
107  for (int i=0; i<n; i++)
108  {
109  scalar phi = (2.0*i)/n;
110  Info<< phi << token::TAB << SuRef(phi) << endl;
111  }
112  }
113 }
114 
115 
116 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
117 
119 {}
120 
121 
122 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
123 
124 inline Foam::scalar Foam::laminarFlameSpeedModels::SCOPE::polyPhi
125 (
126  scalar phi,
127  const polynomial& a
128 )
129 {
130  scalar x = phi - 1.0;
131 
132  return
133  a[0]
134  *(
135  scalar(1)
136  + x*(a[1] + x*(a[2] + x*(a[3] + x*(a[4] + x*(a[5] + x*a[6])))))
137  );
138 }
139 
140 
141 inline Foam::scalar Foam::laminarFlameSpeedModels::SCOPE::SuRef
142 (
143  scalar phi
144 ) const
145 {
146  if (phi < LFL_ || phi > UFL_)
147  {
148  // Return 0 beyond the flamibility limits
149  return scalar(0);
150  }
151  else if (phi < SuPolyL_.ll)
152  {
153  // Use linear interpolation between the low end of the
154  // lower polynomial and the lower flamibility limit
155  return SuPolyL_.llv*(phi - LFL_)/(SuPolyL_.ll - LFL_);
156  }
157  else if (phi > SuPolyU_.ul)
158  {
159  // Use linear interpolation between the upper end of the
160  // upper polynomial and the upper flamibility limit
161  return SuPolyU_.ulv*(UFL_ - phi)/(UFL_ - SuPolyU_.ul);
162  }
163  else if (phi < SuPolyL_.lu)
164  {
165  // Evaluate the lower polynomial
166  return polyPhi(phi, SuPolyL_);
167  }
168  else if (phi > SuPolyU_.lu)
169  {
170  // Evaluate the upper polynomial
171  return polyPhi(phi, SuPolyU_);
172  }
173  else
174  {
176  << "phi = " << phi
177  << " cannot be handled by SCOPE function with the "
178  "given coefficients"
179  << exit(FatalError);
180 
181  return scalar(0);
182  }
183 }
184 
185 
187 (
188  scalar phi
189 ) const
190 {
191  if (phi < MaPolyL_.ll)
192  {
193  // Beyond the lower limit assume Ma is constant
194  return MaPolyL_.llv;
195  }
196  else if (phi > MaPolyU_.ul)
197  {
198  // Beyond the upper limit assume Ma is constant
199  return MaPolyU_.ulv;
200  }
201  else if (phi < SuPolyL_.lu)
202  {
203  // Evaluate the lower polynomial
204  return polyPhi(phi, MaPolyL_);
205  }
206  else if (phi > SuPolyU_.lu)
207  {
208  // Evaluate the upper polynomial
209  return polyPhi(phi, MaPolyU_);
210  }
211  else
212  {
214  << "phi = " << phi
215  << " cannot be handled by SCOPE function with the "
216  "given coefficients"
217  << exit(FatalError);
218 
219  return scalar(0);
220  }
221 }
222 
223 
224 inline Foam::scalar Foam::laminarFlameSpeedModels::SCOPE::Su0pTphi
225 (
226  scalar p,
227  scalar Tu,
228  scalar phi
229 ) const
230 {
231  static const scalar Tref = 300.0;
232  static const scalar pRef = 1.013e5;
233 
234  return SuRef(phi)*pow((Tu/Tref), Texp_)*pow((p/pRef), pexp_);
235 }
236 
237 
238 Foam::tmp<Foam::volScalarField> Foam::laminarFlameSpeedModels::SCOPE::Su0pTphi
239 (
240  const volScalarField& p,
241  const volScalarField& Tu,
242  scalar phi
243 ) const
244 {
245  tmp<volScalarField> tSu0
246  (
248  (
249  "Su0",
250  p.mesh(),
252  )
253  );
254 
255  volScalarField& Su0 = tSu0.ref();
256 
257  forAll(Su0, celli)
258  {
259  Su0[celli] = Su0pTphi(p[celli], Tu[celli], phi);
260  }
261 
262  volScalarField::Boundary& Su0Bf = Su0.boundaryFieldRef();
263 
264  forAll(Su0Bf, patchi)
265  {
266  scalarField& Su0p = Su0Bf[patchi];
267  const scalarField& pp = p.boundaryField()[patchi];
268  const scalarField& Tup = Tu.boundaryField()[patchi];
269 
270  forAll(Su0p, facei)
271  {
272  Su0p[facei] = Su0pTphi(pp[facei], Tup[facei], phi);
273  }
274  }
275 
276  return tSu0;
277 }
278 
279 
280 Foam::tmp<Foam::volScalarField> Foam::laminarFlameSpeedModels::SCOPE::Su0pTphi
281 (
282  const volScalarField& p,
283  const volScalarField& Tu,
284  const volScalarField& phi
285 ) const
286 {
287  tmp<volScalarField> tSu0
288  (
290  (
291  "Su0",
292  p.mesh(),
294  )
295  );
296 
297  volScalarField& Su0 = tSu0.ref();
298 
299  forAll(Su0, celli)
300  {
301  Su0[celli] = Su0pTphi(p[celli], Tu[celli], phi[celli]);
302  }
303 
304  volScalarField::Boundary& Su0Bf = Su0.boundaryFieldRef();
305 
306  forAll(Su0Bf, patchi)
307  {
308  scalarField& Su0p = Su0Bf[patchi];
309  const scalarField& pp = p.boundaryField()[patchi];
310  const scalarField& Tup = Tu.boundaryField()[patchi];
311  const scalarField& phip = phi.boundaryField()[patchi];
312 
313  forAll(Su0p, facei)
314  {
315  Su0p[facei] =
316  Su0pTphi
317  (
318  pp[facei],
319  Tup[facei],
320  phip[facei]
321  );
322  }
323  }
324 
325  return tSu0;
326 }
327 
328 
330 (
331  const volScalarField& phi
332 ) const
333 {
334  tmp<volScalarField> tMa
335  (
337  (
338  "Ma",
339  phi.mesh(),
341  )
342  );
343 
344  volScalarField& ma = tMa.ref();
345 
346  forAll(ma, celli)
347  {
348  ma[celli] = Ma(phi[celli]);
349  }
350 
351  volScalarField::Boundary& maBf = ma.boundaryFieldRef();
352 
353  forAll(maBf, patchi)
354  {
355  scalarField& map = maBf[patchi];
356  const scalarField& phip = phi.boundaryField()[patchi];
357 
358  forAll(map, facei)
359  {
360  map[facei] = Ma(phip[facei]);
361  }
362  }
363 
364  return tMa;
365 }
366 
367 
370 {
371  if (psiuMulticomponentThermo_.composition().contains("ft"))
372  {
373  const volScalarField& ft =
374  psiuMulticomponentThermo_.composition().Y("ft");
375 
376  return Ma
377  (
379  (
380  "stoichiometricAirFuelMassRatio",
381  dimless,
382  psiuMulticomponentThermo_.properties()
383  )*ft/(scalar(1) - ft)
384  );
385  }
386  else
387  {
388  const fvMesh& mesh = psiuMulticomponentThermo_.p().mesh();
389 
390  return tmp<volScalarField>
391  (
393  (
394  "Ma",
395  mesh,
396  dimensionedScalar(dimless, Ma(equivalenceRatio_))
397  )
398  );
399  }
400 }
401 
402 
405 {
406  if (psiuMulticomponentThermo_.composition().contains("ft"))
407  {
408  const volScalarField& ft =
409  psiuMulticomponentThermo_.composition().Y("ft");
410 
411  return Su0pTphi
412  (
413  psiuMulticomponentThermo_.p(),
414  psiuMulticomponentThermo_.Tu(),
416  (
417  "stoichiometricAirFuelMassRatio",
418  dimless,
419  psiuMulticomponentThermo_.properties()
420  )*ft/(scalar(1) - ft)
421  );
422  }
423  else
424  {
425  return Su0pTphi
426  (
427  psiuMulticomponentThermo_.p(),
428  psiuMulticomponentThermo_.Tu(),
429  equivalenceRatio_
430  );
431  }
432 }
433 
434 
435 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Macros for easy insertion into run-time selection tables.
Generic GeometricField class.
GeometricBoundaryField< Type, PatchField, GeoMesh > Boundary
Type of the boundary field.
static tmp< GeometricField< Type, PatchField, GeoMesh > > New(const word &name, const Internal &, const PtrList< PatchField< Type >> &)
Return a temporary field constructed from name,.
Input from file stream.
Definition: IFstream.H:85
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
A class for handling file names.
Definition: fileName.H:82
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:101
Laminar flame speed obtained from the SCOPE correlation.
tmp< volScalarField > Ma() const
Return the Markstein number.
tmp< volScalarField > operator()() const
Return the laminar flame speed [m/s].
SCOPE(const dictionary &, const psiuMulticomponentThermo &)
Construct from dictionary and psiuMulticomponentThermo.
Abstract class for laminar flame speed.
Base-class for combustion fluid thermodynamic properties based on compressibility.
A class for managing temporary objects.
Definition: tmp.H:55
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
label patchi
addToRunTimeSelectionTable(laminarFlameSpeed, constant, dictionary)
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
const dimensionSet dimless
messageStream Info
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
VolField< scalar > volScalarField
Definition: volFieldsFwd.H:61
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
const dimensionSet dimVelocity
error FatalError
dictionary dict
volScalarField & p