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-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 "Reaction.H"
27 
28 
29 // * * * * * * * * * * * * * * * * Static Data * * * * * * * * * * * * * * * //
30 
31 template<class ThermoType>
33 
34 template<class ThermoType>
36 
37 
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 
40 template<class ThermoType>
42 (
43  const PtrList<ThermoType>& speciesThermo
44 )
45 {
46  typename ThermoType::thermoType rhsThermo
47  (
48  rhs()[0].stoichCoeff
49  *speciesThermo[rhs()[0].index].W()
50  *speciesThermo[rhs()[0].index]
51  );
52 
53  for (label i=1; i<rhs().size(); ++i)
54  {
55  rhsThermo +=
56  rhs()[i].stoichCoeff
57  *speciesThermo[rhs()[i].index].W()
58  *speciesThermo[rhs()[i].index];
59  }
60 
61  typename ThermoType::thermoType lhsThermo
62  (
63  lhs()[0].stoichCoeff
64  *speciesThermo[lhs()[0].index].W()
65  *speciesThermo[lhs()[0].index]
66  );
67 
68  for (label i=1; i<lhs().size(); ++i)
69  {
70  lhsThermo +=
71  lhs()[i].stoichCoeff
72  *speciesThermo[lhs()[i].index].W()
73  *speciesThermo[lhs()[i].index];
74  }
75 
76  // Check for mass imbalance in the reaction. A value of 1 corresponds to an
77  // error of 1 H atom in the reaction; i.e. 1 kg/kmol.
78  if (mag(lhsThermo.Y() - rhsThermo.Y()) > 0.1)
79  {
81  << "Mass imbalance for reaction " << name() << ": "
82  << mag(lhsThermo.Y() - rhsThermo.Y()) << " kg/kmol"
83  << exit(FatalError);
84  }
85 
86  ThermoType::thermoType::operator=(lhsThermo == rhsThermo);
87 }
88 
89 
90 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
91 
92 template<class ThermoType>
94 (
95  const speciesTable& species,
96  const PtrList<ThermoType>& speciesThermo,
97  const List<specieCoeffs>& lhs,
98  const List<specieCoeffs>& rhs
99 )
100 :
101  reaction(species, lhs, rhs),
102  ThermoType::thermoType(speciesThermo[0]),
103  Tlow_(TlowDefault),
104  Thigh_(ThighDefault)
105 {
106  setThermo(speciesThermo);
107 }
108 
109 
110 template<class ThermoType>
112 (
113  const Reaction<ThermoType>& r,
114  const speciesTable& species
115 )
116 :
117  reaction(r, species),
118  ThermoType::thermoType(r),
119  Tlow_(r.Tlow()),
120  Thigh_(r.Thigh())
121 {}
122 
123 
124 template<class ThermoType>
126 (
127  const speciesTable& species,
128  const PtrList<ThermoType>& speciesThermo,
129  const dictionary& dict
130 )
131 :
132  reaction(species, dict),
133  ThermoType::thermoType(speciesThermo[0]),
134  Tlow_(dict.lookupOrDefault<scalar>("Tlow", TlowDefault)),
135  Thigh_(dict.lookupOrDefault<scalar>("Thigh", ThighDefault))
136 {
137  setThermo(speciesThermo);
138 }
139 
140 
141 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
142 
143 template<class ThermoType>
146 (
147  const speciesTable& species,
148  const PtrList<ThermoType>& speciesThermo,
149  const dictionary& dict
150 )
151 {
152  const word& reactionTypeName = dict.lookup("type");
153 
154  typename dictionaryConstructorTable::iterator cstrIter =
155  dictionaryConstructorTablePtr_->find(reactionTypeName);
156 
157  // Backwards compatibility check. Reaction names used to have "Reaction"
158  // (Reaction<ThermoType>::typeName_()) appended. This was
159  // removed as it is unnecessary given the context in which the reaction is
160  // specified. If this reaction name was not found, search also for the old
161  // 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, speciesThermo, dict)
183  );
184 }
185 
186 
187 template<class ThermoType>
190 (
191  const speciesTable& species,
192  const PtrList<ThermoType>& speciesThermo,
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, speciesThermo, 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, speciesThermo, dict)
246  );
247  }
248 
250  (
251  cstrIter()(species, speciesThermo, ob, dict)
252  );
253 }
254 
255 
256 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
257 
258 template<class ThermoType>
260 {
261  reaction::write(os);
262 }
263 
264 
265 template<class ThermoType>
267 (
268  const scalar p,
269  const scalar T,
270  const scalarField& c,
271  const label li,
272  scalar& Cf,
273  scalar& Cr
274 ) const
275 {
276  Cf = Cr = 1;
277 
278  forAll(lhs(), i)
279  {
280  const label si = lhs()[i].index;
281  const specieExponent& el = lhs()[i].exponent;
282  Cf *= c[si] >= small || el >= 1 ? pow(max(c[si], 0), el) : 0;
283  }
284 
285  forAll(rhs(), i)
286  {
287  const label si = rhs()[i].index;
288  const specieExponent& er = rhs()[i].exponent;
289  Cr *= c[si] >= small || er >= 1 ? pow(max(c[si], 0), er) : 0;
290  }
291 }
292 
293 
294 template<class ThermoType>
296 (
297  const scalar p,
298  const scalar T,
299  const scalarField& c,
300  const label li,
301  scalar& omegaf,
302  scalar& omegar
303 ) const
304 {
305  const scalar clippedT = min(max(T, this->Tlow()), this->Thigh());
306 
307  // Rate constants
308  const scalar kf = this->kf(p, clippedT, c, li);
309  const scalar kr = this->kr(kf, p, clippedT, c, li);
310 
311  // Concentration products
312  scalar Cf, Cr;
313  this->C(p, T, c, li, Cf, Cr);
314 
315  omegaf = kf*Cf;
316  omegar = kr*Cr;
317 
318  return omegaf - omegar;
319 }
320 
321 
322 template<class ThermoType>
324 (
325  const scalar p,
326  const scalar T,
327  const scalarField& c,
328  const label li,
329  scalarField& dNdtByV,
330  const bool reduced,
331  const List<label>& c2s,
332  const label Nsi0
333 ) const
334 {
335  scalar omegaf, omegar;
336  const scalar omega = this->omega(p, T, c, li, omegaf, omegar);
337 
338  forAll(lhs(), i)
339  {
340  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
341  const scalar sl = lhs()[i].stoichCoeff;
342  dNdtByV[Nsi0 + si] -= sl*omega;
343  }
344  forAll(rhs(), i)
345  {
346  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
347  const scalar sr = rhs()[i].stoichCoeff;
348  dNdtByV[Nsi0 + si] += sr*omega;
349  }
350 }
351 
352 
353 template<class ThermoType>
355 (
356  const scalar p,
357  const scalar T,
358  const scalarField& c,
359  const label li,
360  scalarField& dNdtByV,
361  scalarSquareMatrix& ddNdtByVdcTp,
362  const bool reduced,
363  const List<label>& c2s,
364  const label Nsi0,
365  const label Tsi,
366  scalarField& cTpWork0,
367  scalarField& cTpWork1
368 ) const
369 {
370  // Rate constants
371  const scalar kf = this->kf(p, T, c, li);
372  const scalar kr = this->kr(kf, p, T, c, li);
373 
374  // Concentration products
375  scalar Cf, Cr;
376  this->C(p, T, c, li, Cf, Cr);
377 
378  // Overall reaction rate
379  const scalar omega = kf*Cf - kr*Cr;
380 
381  // Specie reaction rates
382  forAll(lhs(), i)
383  {
384  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
385  const scalar sl = lhs()[i].stoichCoeff;
386  dNdtByV[Nsi0 + si] -= sl*omega;
387  }
388  forAll(rhs(), i)
389  {
390  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
391  const scalar sr = rhs()[i].stoichCoeff;
392  dNdtByV[Nsi0 + si] += sr*omega;
393  }
394 
395  // Jacobian contributions from the derivative of the concentration products
396  // w.r.t. concentration
397  {
398  forAll(lhs(), j)
399  {
400  const label sj = reduced ? c2s[lhs()[j].index] : lhs()[j].index;
401 
402  scalar dCfdcj = 1;
403  forAll(lhs(), i)
404  {
405  const label si = lhs()[i].index;
406  const specieExponent& el = lhs()[i].exponent;
407  if (i == j)
408  {
409  dCfdcj *=
410  c[si] >= small || el >= 1
411  ? el*pow(max(c[si], 0), el - specieExponent(label(1)))
412  : 0;
413  }
414  else
415  {
416  dCfdcj *=
417  c[si] >= small || el >= 1
418  ? pow(max(c[si], 0), el)
419  : 0;
420  }
421  }
422 
423  forAll(lhs(), i)
424  {
425  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
426  const scalar sl = lhs()[i].stoichCoeff;
427  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sl*kf*dCfdcj;
428  }
429  forAll(rhs(), i)
430  {
431  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
432  const scalar sr = rhs()[i].stoichCoeff;
433  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sr*kf*dCfdcj;
434  }
435  }
436 
437  forAll(rhs(), j)
438  {
439  const label sj = reduced ? c2s[rhs()[j].index] : rhs()[j].index;
440 
441  scalar dCrcj = 1;
442  forAll(rhs(), i)
443  {
444  const label si = rhs()[i].index;
445  const specieExponent& er = rhs()[i].exponent;
446  if (i == j)
447  {
448  dCrcj *=
449  c[si] >= small || er >= 1
450  ? er*pow(max(c[si], 0), er - specieExponent(label(1)))
451  : 0;
452  }
453  else
454  {
455  dCrcj *=
456  c[si] >= small || er >= 1
457  ? pow(max(c[si], 0), er)
458  : 0;
459  }
460  }
461 
462  forAll(lhs(), i)
463  {
464  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
465  const scalar sl = lhs()[i].stoichCoeff;
466  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sl*kr*dCrcj;
467  }
468  forAll(rhs(), i)
469  {
470  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
471  const scalar sr = rhs()[i].stoichCoeff;
472  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sr*kr*dCrcj;
473  }
474  }
475  }
476 
477  // Jacobian contributions from the derivative of the rate constants
478  // w.r.t. temperature
479  {
480  const scalar dkfdT = this->dkfdT(p, T, c, li);
481  const scalar dkrdT = this->dkrdT(p, T, c, li, dkfdT, kr);
482 
483  const scalar dwdT = dkfdT*Cf - dkrdT*Cr;
484  forAll(lhs(), i)
485  {
486  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
487  const scalar sl = lhs()[i].stoichCoeff;
488  ddNdtByVdcTp(Nsi0 + si, Tsi) -= sl*dwdT;
489  }
490  forAll(rhs(), i)
491  {
492  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
493  const scalar sr = rhs()[i].stoichCoeff;
494  ddNdtByVdcTp(Nsi0 + si, Tsi) += sr*dwdT;
495  }
496  }
497 
498  // Jacobian contributions from the derivative of the rate constants
499  // w.r.t. concentration
500  if (hasDkdc())
501  {
502  scalarField& dkfdc = cTpWork0;
503  scalarField& dkrdc = cTpWork1;
504 
505  this->dkfdc(p, T, c, li, dkfdc);
506  this->dkrdc(p, T, c, li, dkfdc, kr, dkrdc);
507 
508  forAll(c, j)
509  {
510  const label sj = reduced ? c2s[j] : j;
511 
512  if (sj == -1) continue;
513 
514  const scalar dwdc = dkfdc[j]*Cf - dkrdc[j]*Cr;
515  forAll(lhs(), i)
516  {
517  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
518  const scalar sl = lhs()[i].stoichCoeff;
519  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sl*dwdc;
520  }
521  forAll(rhs(), i)
522  {
523  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
524  const scalar sr = rhs()[i].stoichCoeff;
525  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sr*dwdc;
526  }
527  }
528  }
529 }
530 
531 
532 // ************************************************************************* //
static const Foam::dimensionedScalar C("C", Foam::dimTemperature, 234.5)
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
Simple extension of ThermoType to handle reaction kinetics in addition to the equilibrium thermodynam...
Definition: Reaction.H:72
virtual void write(Ostream &) const
Write.
Definition: Reaction.C:259
static scalar TlowDefault
Default temperature limits of applicability of reaction rates.
Definition: Reaction.H:79
static scalar ThighDefault
Definition: Reaction.H:79
void ddNdtByVdcTp(const scalar p, const scalar T, const scalarField &c, const label li, scalarField &dNdtByV, scalarSquareMatrix &ddNdtByVdcTp, const bool reduced, const List< label > &c2s, const label csi0, const label Tsi, scalarField &cTpWork0, scalarField &cTpWork1) const
Derivative of the net reaction rate for each species involved.
Definition: Reaction.C:355
void C(const scalar p, const scalar T, const scalarField &c, const label li, scalar &Cf, scalar &Cr) const
Concentration powers.
Definition: Reaction.C:267
void dNdtByV(const scalar p, const scalar T, const scalarField &c, const label li, scalarField &dNdtByV, const bool reduced, const List< label > &c2s, const label Nsi0) const
The net reaction rate for each species involved.
Definition: Reaction.C:324
static autoPtr< Reaction< ThermoType > > New(const speciesTable &species, const PtrList< ThermoType > &speciesThermo, const dictionary &dict)
Return a pointer to new reaction created from a dictionary.
Definition: Reaction.C:146
scalar omega(const scalar p, const scalar T, const scalarField &c, const label li, scalar &omegaf, scalar &omegar) const
Net reaction rate.
Definition: Reaction.C:296
Reaction(const speciesTable &species, const PtrList< ThermoType > &speciesThermo, const List< specieCoeffs > &lhs, const List< specieCoeffs > &rhs)
Construct from components.
Definition: Reaction.C:94
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:860
A wordList with hashed indices for faster lookup by name.
Registry of regIOobjects.
Reaction base-class holding the specie names and coefficients.
Definition: reaction.H:57
void write(Ostream &) const
Write.
Definition: reaction.C:93
Type for exponents of species in reaction. Can take either integer or scalar value,...
bool removeTrailing(const char)
Remove trailing character returning true if string changed.
Definition: string.C:219
A class for handling words, derived from string.
Definition: word.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
const scalar omega
const dimensionedScalar c
Speed of light in a vacuum.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
dimensioned< scalar > mag(const dimensioned< Type > &)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
error FatalError
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
static const char nl
Definition: Ostream.H:260
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
const scalarList W(::W(thermo))
dictionary dict
volScalarField & p