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-2024 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  scalar order = 0;
262  forAll(lhs(), i)
263  {
264  order += lhs()[i].exponent;
265  }
266  return pow(dimMoles/dimVolume, 1 - order)/dimTime;
267 }
268 
269 
270 template<class ThermoType>
272 {
273  scalar order = 0;
274  forAll(rhs(), i)
275  {
276  order += rhs()[i].exponent;
277  }
278  return pow(dimMoles/dimVolume, 1 - order)/dimTime;
279 }
280 
281 
282 template<class ThermoType>
284 (
285  const scalar p,
286  const scalar T,
287  const scalarField& c,
288  const label li,
289  scalar& Cf,
290  scalar& Cr
291 ) const
292 {
293  Cf = Cr = 1;
294 
295  forAll(lhs(), i)
296  {
297  const label si = lhs()[i].index;
298  const specieExponent& el = lhs()[i].exponent;
299  Cf *= c[si] >= small || el >= 1 ? pow(max(c[si], 0), el) : 0;
300  }
301 
302  forAll(rhs(), i)
303  {
304  const label si = rhs()[i].index;
305  const specieExponent& er = rhs()[i].exponent;
306  Cr *= c[si] >= small || er >= 1 ? pow(max(c[si], 0), er) : 0;
307  }
308 }
309 
310 
311 template<class ThermoType>
313 (
314  const scalar p,
315  const scalar T,
316  const scalarField& c,
317  const label li,
318  scalar& omegaf,
319  scalar& omegar
320 ) const
321 {
322  const scalar clippedT = min(max(T, this->Tlow()), this->Thigh());
323 
324  // Rate constants
325  const scalar kf = this->kf(p, clippedT, c, li);
326  const scalar kr = this->kr(kf, p, clippedT, c, li);
327 
328  // Concentration products
329  scalar Cf, Cr;
330  this->C(p, T, c, li, Cf, Cr);
331 
332  omegaf = kf*Cf;
333  omegar = kr*Cr;
334 
335  return omegaf - omegar;
336 }
337 
338 
339 template<class ThermoType>
341 (
342  const scalar p,
343  const scalar T,
344  const scalarField& c,
345  const label li,
346  scalarField& dNdtByV,
347  const bool reduced,
348  const List<label>& c2s,
349  const label Nsi0
350 ) const
351 {
352  scalar omegaf, omegar;
353  const scalar omega = this->omega(p, T, c, li, omegaf, omegar);
354 
355  forAll(lhs(), i)
356  {
357  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
358  const scalar sl = lhs()[i].stoichCoeff;
359  dNdtByV[Nsi0 + si] -= sl*omega;
360  }
361  forAll(rhs(), i)
362  {
363  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
364  const scalar sr = rhs()[i].stoichCoeff;
365  dNdtByV[Nsi0 + si] += sr*omega;
366  }
367 }
368 
369 
370 template<class ThermoType>
372 (
373  const scalar p,
374  const scalar T,
375  const scalarField& c,
376  const label li,
377  scalarField& dNdtByV,
378  scalarSquareMatrix& ddNdtByVdcTp,
379  const bool reduced,
380  const List<label>& c2s,
381  const label Nsi0,
382  const label Tsi,
383  scalarField& cTpWork0,
384  scalarField& cTpWork1
385 ) const
386 {
387  // Rate constants
388  const scalar kf = this->kf(p, T, c, li);
389  const scalar kr = this->kr(kf, p, T, c, li);
390 
391  // Concentration products
392  scalar Cf, Cr;
393  this->C(p, T, c, li, Cf, Cr);
394 
395  // Overall reaction rate
396  const scalar omega = kf*Cf - kr*Cr;
397 
398  // Specie reaction rates
399  forAll(lhs(), i)
400  {
401  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
402  const scalar sl = lhs()[i].stoichCoeff;
403  dNdtByV[Nsi0 + si] -= sl*omega;
404  }
405  forAll(rhs(), i)
406  {
407  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
408  const scalar sr = rhs()[i].stoichCoeff;
409  dNdtByV[Nsi0 + si] += sr*omega;
410  }
411 
412  // Jacobian contributions from the derivative of the concentration products
413  // w.r.t. concentration
414  {
415  forAll(lhs(), j)
416  {
417  const label sj = reduced ? c2s[lhs()[j].index] : lhs()[j].index;
418 
419  scalar dCfdcj = 1;
420  forAll(lhs(), i)
421  {
422  const label si = lhs()[i].index;
423  const specieExponent& el = lhs()[i].exponent;
424  if (i == j)
425  {
426  dCfdcj *=
427  c[si] >= small || el >= 1
428  ? el*pow(max(c[si], 0), el - specieExponent(label(1)))
429  : 0;
430  }
431  else
432  {
433  dCfdcj *=
434  c[si] >= small || el >= 1
435  ? pow(max(c[si], 0), el)
436  : 0;
437  }
438  }
439 
440  forAll(lhs(), i)
441  {
442  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
443  const scalar sl = lhs()[i].stoichCoeff;
444  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sl*kf*dCfdcj;
445  }
446  forAll(rhs(), i)
447  {
448  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
449  const scalar sr = rhs()[i].stoichCoeff;
450  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sr*kf*dCfdcj;
451  }
452  }
453 
454  forAll(rhs(), j)
455  {
456  const label sj = reduced ? c2s[rhs()[j].index] : rhs()[j].index;
457 
458  scalar dCrcj = 1;
459  forAll(rhs(), i)
460  {
461  const label si = rhs()[i].index;
462  const specieExponent& er = rhs()[i].exponent;
463  if (i == j)
464  {
465  dCrcj *=
466  c[si] >= small || er >= 1
467  ? er*pow(max(c[si], 0), er - specieExponent(label(1)))
468  : 0;
469  }
470  else
471  {
472  dCrcj *=
473  c[si] >= small || er >= 1
474  ? pow(max(c[si], 0), er)
475  : 0;
476  }
477  }
478 
479  forAll(lhs(), i)
480  {
481  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
482  const scalar sl = lhs()[i].stoichCoeff;
483  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sl*kr*dCrcj;
484  }
485  forAll(rhs(), i)
486  {
487  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
488  const scalar sr = rhs()[i].stoichCoeff;
489  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sr*kr*dCrcj;
490  }
491  }
492  }
493 
494  // Jacobian contributions from the derivative of the rate constants
495  // w.r.t. temperature
496  {
497  const scalar dkfdT = this->dkfdT(p, T, c, li);
498  const scalar dkrdT = this->dkrdT(p, T, c, li, dkfdT, kr);
499 
500  const scalar dwdT = dkfdT*Cf - dkrdT*Cr;
501  forAll(lhs(), i)
502  {
503  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
504  const scalar sl = lhs()[i].stoichCoeff;
505  ddNdtByVdcTp(Nsi0 + si, Tsi) -= sl*dwdT;
506  }
507  forAll(rhs(), i)
508  {
509  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
510  const scalar sr = rhs()[i].stoichCoeff;
511  ddNdtByVdcTp(Nsi0 + si, Tsi) += sr*dwdT;
512  }
513  }
514 
515  // Jacobian contributions from the derivative of the rate constants
516  // w.r.t. concentration
517  if (hasDkdc())
518  {
519  scalarField& dkfdc = cTpWork0;
520  scalarField& dkrdc = cTpWork1;
521 
522  this->dkfdc(p, T, c, li, dkfdc);
523  this->dkrdc(p, T, c, li, dkfdc, kr, dkrdc);
524 
525  forAll(c, j)
526  {
527  const label sj = reduced ? c2s[j] : j;
528 
529  if (sj == -1) continue;
530 
531  const scalar dwdc = dkfdc[j]*Cf - dkrdc[j]*Cr;
532  forAll(lhs(), i)
533  {
534  const label si = reduced ? c2s[lhs()[i].index] : lhs()[i].index;
535  const scalar sl = lhs()[i].stoichCoeff;
536  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) -= sl*dwdc;
537  }
538  forAll(rhs(), i)
539  {
540  const label si = reduced ? c2s[rhs()[i].index] : rhs()[i].index;
541  const scalar sr = rhs()[i].stoichCoeff;
542  ddNdtByVdcTp(Nsi0 + si, Nsi0 + sj) += sr*dwdc;
543  }
544  }
545  }
546 }
547 
548 
549 template<class ThermoType>
551 {
552  reaction::write(os);
553 }
554 
555 
556 // ************************************************************************* //
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:550
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:372
void C(const scalar p, const scalar T, const scalarField &c, const label li, scalar &Cf, scalar &Cr) const
Concentration powers.
Definition: Reaction.C:284
dimensionSet kfDims() const
Dimensions of the forward rate.
Definition: Reaction.C:259
dimensionSet krDims() const
Dimensions of the reverse rate.
Definition: Reaction.C:271
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:341
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:313
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:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
Dimension set for the base types.
Definition: dimensionSet.H:125
A wordList with hashed indices for faster lookup by name.
Registry of regIOobjects.
Convenience class to handle the input of constant rotational speed. Reads an omega entry with default...
Definition: omega.H:54
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:334
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
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
int order(const scalar s)
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
const dimensionSet dimTime
const dimensionSet dimVolume
dimensioned< scalar > mag(const dimensioned< Type > &)
const dimensionSet dimMoles
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
static const char nl
Definition: Ostream.H:266
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
const scalarList W(::W(thermo))
dictionary dict
volScalarField & p