Reaction.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-2021 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 "Reaction.H"
27 
28 
29 // * * * * * * * * * * * * * * * * Static Data * * * * * * * * * * * * * * * //
30 
31 template<class ReactionThermo>
33 
34 template<class ReactionThermo>
36 
37 
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 
40 template<class ReactionThermo>
42 (
43  const HashPtrTable<ReactionThermo>& thermoDatabase
44 )
45 {
46  typename ReactionThermo::thermoType rhsThermo
47  (
48  rhs()[0].stoichCoeff
49  *(*thermoDatabase[species()[rhs()[0].index]]).W()
50  *(*thermoDatabase[species()[rhs()[0].index]])
51  );
52 
53  for (label i=1; i<rhs().size(); ++i)
54  {
55  rhsThermo +=
56  rhs()[i].stoichCoeff
57  *(*thermoDatabase[species()[rhs()[i].index]]).W()
58  *(*thermoDatabase[species()[rhs()[i].index]]);
59  }
60 
61  typename ReactionThermo::thermoType lhsThermo
62  (
63  lhs()[0].stoichCoeff
64  *(*thermoDatabase[species()[lhs()[0].index]]).W()
65  *(*thermoDatabase[species()[lhs()[0].index]])
66  );
67 
68  for (label i=1; i<lhs().size(); ++i)
69  {
70  lhsThermo +=
71  lhs()[i].stoichCoeff
72  *(*thermoDatabase[species()[lhs()[i].index]]).W()
73  *(*thermoDatabase[species()[lhs()[i].index]]);
74  }
75 
76  // Check for mass imbalance in the reaction
77  // A value of 1 corresponds to an error of 1 H atom in the reaction,
78  // i.e. 1 kg/kmol
79  if (mag(lhsThermo.Y() - rhsThermo.Y()) > 0.1)
80  {
82  << "Mass imbalance for reaction " << name() << ": "
83  << mag(lhsThermo.Y() - rhsThermo.Y()) << " kg/kmol"
84  << exit(FatalError);
85  }
86 
87  ReactionThermo::thermoType::operator=(lhsThermo == rhsThermo);
88 }
89 
90 
91 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
92 
93 template<class ReactionThermo>
95 (
96  const speciesTable& species,
97  const List<specieCoeffs>& lhs,
98  const List<specieCoeffs>& rhs,
99  const HashPtrTable<ReactionThermo>& thermoDatabase
100 )
101 :
102  reaction(species, lhs, rhs),
103  ReactionThermo::thermoType(*thermoDatabase[species[0]]),
104  Tlow_(TlowDefault),
105  Thigh_(ThighDefault)
106 {
107  setThermo(thermoDatabase);
108 }
109 
110 
111 template<class ReactionThermo>
113 (
114  const Reaction<ReactionThermo>& r,
115  const speciesTable& species
116 )
117 :
118  reaction(r, species),
119  ReactionThermo::thermoType(r),
120  Tlow_(r.Tlow()),
121  Thigh_(r.Thigh())
122 {}
123 
124 
125 template<class ReactionThermo>
127 (
128  const speciesTable& species,
129  const HashPtrTable<ReactionThermo>& thermoDatabase,
130  const dictionary& dict
131 )
132 :
133  reaction(species, dict),
134  ReactionThermo::thermoType(*thermoDatabase[species[0]]),
135  Tlow_(dict.lookupOrDefault<scalar>("Tlow", TlowDefault)),
136  Thigh_(dict.lookupOrDefault<scalar>("Thigh", ThighDefault))
137 {
138  setThermo(thermoDatabase);
139 }
140 
141 
142 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
143 
144 template<class ReactionThermo>
147 (
148  const speciesTable& species,
149  const HashPtrTable<ReactionThermo>& thermoDatabase,
150  const dictionary& dict
151 )
152 {
153  const word& reactionTypeName = dict.lookup("type");
154 
155  typename dictionaryConstructorTable::iterator cstrIter =
156  dictionaryConstructorTablePtr_->find(reactionTypeName);
157 
158  // Backwards compatibility check. Reaction names used to have "Reaction"
159  // (Reaction<ReactionThermo>::typeName_()) appended. This was removed as it
160  // is unnecessary given the context in which the reaction is specified. If
161  // this reaction name was not found, search also for the old name.
162  if (cstrIter == dictionaryConstructorTablePtr_->end())
163  {
164  cstrIter = dictionaryConstructorTablePtr_->find
165  (
166  reactionTypeName.removeTrailing(typeName_())
167  );
168  }
169 
170  if (cstrIter == dictionaryConstructorTablePtr_->end())
171  {
173  << "Unknown reaction type "
174  << reactionTypeName << nl << nl
175  << "Valid reaction types are :" << nl
176  << dictionaryConstructorTablePtr_->sortedToc()
177  << exit(FatalError);
178  }
179 
181  (
182  cstrIter()(species, thermoDatabase, dict)
183  );
184 }
185 
186 
187 template<class ReactionThermo>
190 (
191  const speciesTable& species,
192  const HashPtrTable<ReactionThermo>& thermoDatabase,
193  const objectRegistry& ob,
194  const dictionary& dict
195 )
196 {
197  // If the objectRegistry constructor table is empty
198  // use the dictionary constructor table only
199  if (!objectRegistryConstructorTablePtr_)
200  {
201  return New(species, thermoDatabase, dict);
202  }
203 
204  const word& reactionTypeName = dict.lookup("type");
205 
206  typename objectRegistryConstructorTable::iterator cstrIter =
207  objectRegistryConstructorTablePtr_->find(reactionTypeName);
208 
209  // Backwards compatibility check. See above.
210  if (cstrIter == objectRegistryConstructorTablePtr_->end())
211  {
212  cstrIter = objectRegistryConstructorTablePtr_->find
213  (
214  reactionTypeName.removeTrailing(typeName_())
215  );
216  }
217 
218  if (cstrIter == objectRegistryConstructorTablePtr_->end())
219  {
220  typename dictionaryConstructorTable::iterator cstrIter =
221  dictionaryConstructorTablePtr_->find(reactionTypeName);
222 
223  // Backwards compatibility check. See above.
224  if (cstrIter == dictionaryConstructorTablePtr_->end())
225  {
226  cstrIter = dictionaryConstructorTablePtr_->find
227  (
228  reactionTypeName.removeTrailing(typeName_())
229  );
230  }
231 
232  if (cstrIter == dictionaryConstructorTablePtr_->end())
233  {
235  << "Unknown reaction type "
236  << reactionTypeName << nl << nl
237  << "Valid reaction types are :" << nl
238  << dictionaryConstructorTablePtr_->sortedToc()
239  << objectRegistryConstructorTablePtr_->sortedToc()
240  << exit(FatalError);
241  }
242 
244  (
245  cstrIter()(species, thermoDatabase, dict)
246  );
247  }
248 
250  (
251  cstrIter()(species, thermoDatabase, ob, dict)
252  );
253 }
254 
255 
256 template<class ReactionThermo>
259 (
260  const speciesTable& species,
261  const PtrList<ReactionThermo>& speciesThermo,
262  const dictionary& dict
263 )
264 {
265  HashPtrTable<ReactionThermo> thermoDatabase;
266  forAll(speciesThermo, i)
267  {
268  thermoDatabase.insert
269  (
270  speciesThermo[i].name(),
271  speciesThermo[i].clone().ptr()
272  );
273  }
274 
275  return New(species, thermoDatabase, dict);
276 }
277 
278 
279 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
280 
281 template<class ReactionThermo>
283 {
284  reaction::write(os);
285 }
286 
287 
288 template<class ReactionThermo>
290 (
291  const scalar p,
292  const scalar T,
293  const scalarField& c,
294  const label li,
295  scalarField& dcdt
296 ) const
297 {
298  scalar omegaf, omegar;
299 
300  const scalar omegaI = omega(p, T, c, li, omegaf, omegar);
301 
302  forAll(lhs(), i)
303  {
304  const label si = lhs()[i].index;
305  const scalar sl = lhs()[i].stoichCoeff;
306  dcdt[si] -= sl*omegaI;
307  }
308  forAll(rhs(), i)
309  {
310  const label si = rhs()[i].index;
311  const scalar sr = rhs()[i].stoichCoeff;
312  dcdt[si] += sr*omegaI;
313  }
314 }
315 
316 
317 template<class ReactionThermo>
319 (
320  const scalar p,
321  const scalar T,
322  const scalarField& c,
323  const label li,
324  scalar& omegaf,
325  scalar& omegar
326 ) const
327 {
328  scalar clippedT = min(max(T, this->Tlow()), this->Thigh());
329 
330  omegaf = this->kf(p, clippedT, c, li);
331  omegar = this->kr(omegaf, p, clippedT, c, li);
332 
333  forAll(lhs(), i)
334  {
335  const label si = lhs()[i].index;
336  const scalar el = lhs()[i].exponent;
337  omegaf *= c[si] >= small || el >= 1 ? pow(max(c[si], 0), el) : 0;
338  }
339  forAll(rhs(), i)
340  {
341  const label si = rhs()[i].index;
342  const scalar er = rhs()[i].exponent;
343  omegar *= c[si] >= small || er >= 1 ? pow(max(c[si], 0), er) : 0;
344  }
345 
346  return omegaf - omegar;
347 }
348 
349 
350 template<class ReactionThermo>
352 (
353  const scalar p,
354  const scalar T,
355  const scalarField& c,
356  const label li,
358  scalarField& dcdt,
359  scalar& omegaI,
360  scalar& kfwd,
361  scalar& kbwd,
362  const bool reduced,
363  const List<label>& c2s
364 ) const
365 {
366  scalar omegaf, omegar;
367 
368  omegaI = omega(p, T, c, li, omegaf, omegar);
369 
370  forAll(lhs(), i)
371  {
372  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
373  const scalar sl = lhs()[i].stoichCoeff;
374  dcdt[si] -= sl*omegaI;
375  }
376  forAll(rhs(), i)
377  {
378  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
379  const scalar sr = rhs()[i].stoichCoeff;
380  dcdt[si] += sr*omegaI;
381  }
382 
383  kfwd = this->kf(p, T, c, li);
384  kbwd = this->kr(kfwd, p, T, c, li);
385 
386  forAll(lhs(), j)
387  {
388  const label sj = reduced ? c2s[lhs()[j].index] : lhs()[j].index;
389  scalar kf = kfwd;
390  forAll(lhs(), i)
391  {
392  const label si = lhs()[i].index;
393  const scalar el = lhs()[i].exponent;
394  if (i == j)
395  {
396  kf *=
397  c[si] >= small || el >= 1
398  ? el*pow(max(c[si], 0), el - 1)
399  : 0;
400  }
401  else
402  {
403  kf *=
404  c[si] >= small || el >= 1
405  ? pow(max(c[si], 0), el)
406  : 0;
407  }
408  }
409 
410  forAll(lhs(), i)
411  {
412  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
413  const scalar sl = lhs()[i].stoichCoeff;
414  J(si, sj) -= sl*kf;
415  }
416  forAll(rhs(), i)
417  {
418  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
419  const scalar sr = rhs()[i].stoichCoeff;
420  J(si, sj) += sr*kf;
421  }
422  }
423 
424  forAll(rhs(), j)
425  {
426  const label sj = reduced ? c2s[rhs()[j].index] : rhs()[j].index;
427  scalar kr = kbwd;
428  forAll(rhs(), i)
429  {
430  const label si = rhs()[i].index;
431  const scalar er = rhs()[i].exponent;
432  if (i == j)
433  {
434  kr *=
435  c[si] >= small || er >= 1
436  ? er*pow(max(c[si], 0), er - 1)
437  : 0;
438  }
439  else
440  {
441  kr *=
442  c[si] >= small || er >= 1
443  ? pow(max(c[si], 0), er)
444  : 0;
445  }
446  }
447 
448  forAll(lhs(), i)
449  {
450  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
451  const scalar sl = lhs()[i].stoichCoeff;
452  J(si, sj) += sl*kr;
453  }
454  forAll(rhs(), i)
455  {
456  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
457  const scalar sr = rhs()[i].stoichCoeff;
458  J(si, sj) -= sr*kr;
459  }
460  }
461 
462  // When third-body species are involved, additional terms are added
463  // beta function returns an empty list when third-body are not involved
464  const List<Tuple2<label, scalar>>& beta = this->beta();
465  if (notNull(beta))
466  {
467  // This temporary array needs to be cached for efficiency
468  scalarField dcidc(beta.size());
469  this->dcidc(p, T, c, li, dcidc);
470 
471  forAll(beta, j)
472  {
473  label sj = beta[j].first();
474  sj = reduced ? c2s[sj] : sj;
475  if (sj != -1)
476  {
477  forAll(lhs(), i)
478  {
479  const label si =
480  reduced ? c2s[lhs()[i].index] : lhs()[i].index;
481  const scalar sl = lhs()[i].stoichCoeff;
482  J(si, sj) -= sl*dcidc[j]*omegaI;
483  }
484  forAll(rhs(), i)
485  {
486  const label si =
487  reduced ? c2s[rhs()[i].index] : rhs()[i].index;
488  const scalar sr = rhs()[i].stoichCoeff;
489  J(si, sj) += sr*dcidc[j]*omegaI;
490  }
491  }
492  }
493  }
494 }
495 
496 
497 template<class ReactionThermo>
499 (
500  const scalar p,
501  const scalar T,
502  const scalarField& c,
503  const label li,
504  const scalar omegaI,
505  const scalar kfwd,
506  const scalar kbwd,
508  const bool reduced,
509  const List<label>& c2s,
510  const label indexT
511 ) const
512 {
513  scalar dkfdT = this->dkfdT(p, T, c, li);
514  scalar dkrdT = this->dkrdT(p, T, c, li, dkfdT, kbwd);
515 
516  forAll(lhs(), i)
517  {
518  const label si = lhs()[i].index;
519  const scalar el = lhs()[i].exponent;
520  dkfdT *= c[si] >= small || el >= 1 ? pow(max(c[si], 0), el) : 0;
521  }
522  forAll(rhs(), i)
523  {
524  const label si = rhs()[i].index;
525  const scalar er = rhs()[i].exponent;
526  dkrdT *= c[si] >= small || er >= 1 ? pow(max(c[si], 0), er) : 0;
527  }
528 
529  const scalar dqidT = dkfdT - dkrdT;
530 
531  // For reactions including third-body efficiencies or pressure dependent
532  // reaction, an additional term is needed
533  const scalar dcidT = omegaI*this->dcidT(p, T, c, li);
534 
535  // J(i, indexT) = sum_reactions nu_i dqdT
536  forAll(lhs(), i)
537  {
538  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
539  const scalar sl = lhs()[i].stoichCoeff;
540  J(si, indexT) -= sl*(dqidT + dcidT);
541  }
542  forAll(rhs(), i)
543  {
544  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
545  const scalar sr = rhs()[i].stoichCoeff;
546  J(si, indexT) += sr*(dqidT + dcidT);
547  }
548 }
549 
550 
551 // ************************************************************************* //
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
combustionModel & reaction
void dwdc(const scalar p, const scalar T, const scalarField &c, const label li, scalarSquareMatrix &J, scalarField &dcdt, scalar &omegaI, scalar &kfwd, scalar &kbwd, const bool reduced, const List< label > &c2s) const
Derivative of the net reaction rate for each species involved.
Definition: Reaction.C:352
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
virtual void write(Ostream &) const
Write.
Definition: Reaction.C:282
A HashTable specialisation for hashing pointers.
Definition: HashPtrTable.H:50
T & first()
Return the first element of the list.
Definition: UListI.H:114
Simple extension of ReactionThermo to handle reaction kinetics in addition to the equilibrium thermod...
Definition: Reaction.H:55
void omega(const scalar p, const scalar T, const scalarField &c, const label li, scalarField &dcdt) const
Net reaction rate for individual species.
Definition: Reaction.C:290
static scalar TlowDefault
Default temperature limits of applicability of reaction rates.
Definition: Reaction.H:79
bool insert(const Key &, const T * &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
scalar Tlow() const
Return the lower temperature limit for the reaction.
Definition: ReactionI.H:31
T clone(const T &t)
Definition: List.H:54
autoPtr< BasicCompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const typename BasicCompressibleMomentumTransportModel::transportModel &transport)
A class for handling words, derived from string.
Definition: word.H:59
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
scalar Thigh() const
Return the upper temperature limit for the reaction.
Definition: ReactionI.H:38
static scalar ThighDefault
Definition: Reaction.H:79
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:54
static const char nl
Definition: Ostream.H:260
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
bool notNull(const T &t)
Return true if t is not a reference to the nullObject of type T.
Definition: nullObjectI.H:52
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Reaction(const speciesTable &species, const List< specieCoeffs > &lhs, const List< specieCoeffs > &rhs, const HashPtrTable< ReactionThermo > &thermoDatabase)
Construct from components.
Definition: Reaction.C:95
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
A wordList with hashed indices for faster lookup by name.
static autoPtr< Reaction< ReactionThermo > > New(const speciesTable &species, const HashPtrTable< ReactionThermo > &thermoDatabase, const dictionary &dict)
Return a pointer to new patchField created on freestore.
Definition: Reaction.C:147
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:70
const scalarList W(::W(thermo))
dimensioned< scalar > mag(const dimensioned< Type > &)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
void dwdT(const scalar p, const scalar T, const scalarField &c, const label li, const scalar omegaI, const scalar kfwd, const scalar kbwd, scalarSquareMatrix &J, const bool reduced, const List< label > &c2s, const label indexT) const
Derivative of the net reaction rate for each species involved.
Definition: Reaction.C:499
Registry of regIOobjects.
bool removeTrailing(const char)
Remove trailing character returning true if string changed.
Definition: string.C:154
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:844