EFA.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) 2016-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 "EFA.H"
27 #include "SortableListEFA.H"
28 
29 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
30 
31 template<class ThermoType>
33 (
34  const IOdictionary& dict,
36 )
37 :
39  sC_(this->nSpecie_,0),
40  sH_(this->nSpecie_,0),
41  sO_(this->nSpecie_,0),
42  sN_(this->nSpecie_,0),
43  sortPart_(0.05)
44 {
45  for (label i=0; i<this->nSpecie_; i++)
46  {
47  const List<specieElement>& curSpecieComposition =
48  chemistry.mixture().specieComposition(i);
49 
50  // for all elements in the current species
51  forAll(curSpecieComposition, j)
52  {
53  const specieElement& curElement =
54  curSpecieComposition[j];
55  if (curElement.name() == "C")
56  {
57  sC_[i] = curElement.nAtoms();
58  }
59  else if (curElement.name() == "H")
60  {
61  sH_[i] = curElement.nAtoms();
62  }
63  else if (curElement.name() == "O")
64  {
65  sO_[i] = curElement.nAtoms();
66  }
67  else if (curElement.name() == "N")
68  {
69  sN_[i] = curElement.nAtoms();
70  }
71  else
72  {
73  Info<< "element not considered"<< endl;
74  }
75  }
76  }
77  if (this->coeffsDict_.found("sortPart"))
78  {
79  sortPart_ = this->coeffsDict_.template lookup<scalar>("sortPart");
80  }
81 }
82 
83 
84 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
85 
86 template<class ThermoType>
88 {}
89 
90 
91 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
92 
93 template<class ThermoType>
95 (
96  const scalar p,
97  const scalar T,
98  const scalarField& c,
99  const label li
100 )
101 {
102  scalarField& completeC(this->chemistry_.completeC());
103  scalarField c1(this->chemistry_.nEqns(), 0.0);
104 
105  for (label i=0; i<this->nSpecie_; i++)
106  {
107  c1[i] = c[i];
108  completeC[i] = c[i];
109  }
110 
111  c1[this->nSpecie_] = T;
112  c1[this->nSpecie_+1] = p;
113 
114 
115  // Number of initialised rAB for each lines
116  Field<label> NbrABInit(this->nSpecie_,0);
117 
118  // Position of the initialised rAB, -1 when not initialised
119  RectangularMatrix<label> rABPos(this->nSpecie_, this->nSpecie_, -1);
120  RectangularMatrix<scalar> CFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
121  RectangularMatrix<scalar> HFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
122  RectangularMatrix<scalar> OFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
123  RectangularMatrix<scalar> NFluxAB(this->nSpecie_, this->nSpecie_, 0.0);
124  scalar CFlux(0.0), HFlux(0.0), OFlux(0.0), NFlux(0.0);
125  label nbPairs(0);
126 
127  // Index of the other species involved in the rABNum
128  RectangularMatrix<label> rABOtherSpec(this->nSpecie_, this->nSpecie_, -1);
129 
130  forAll(this->chemistry_.reactions(), i)
131  {
132  const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
133 
134  // for each reaction compute omegai
135  scalar omegaf, omegar;
136  R.omega(p, T, c1, li, omegaf, omegar);
137 
138  scalar fr = mag(omegaf) + mag(omegar);
139  scalar NCi(0.0),NHi(0.0),NOi(0.0),NNi(0.0);
140  forAll(R.lhs(),s)
141  {
142  label curIndex = R.lhs()[s].index;
143  scalar stoicCoeff = R.lhs()[s].stoichCoeff;
144  NCi += sC_[curIndex]*stoicCoeff;
145  NHi += sH_[curIndex]*stoicCoeff;
146  NOi += sO_[curIndex]*stoicCoeff;
147  NNi += sN_[curIndex]*stoicCoeff;
148  }
149  // element conservation means that total number of element is
150  // twice the number on the left
151  NCi *=2;
152  NHi *=2;
153  NOi *=2;
154  NNi *=2;
155  // then for each source/sink pairs, compute the element flux
156  forAll(R.lhs(), Ai)// compute the element flux
157  {
158  label A = R.lhs()[Ai].index;
159  scalar Acoeff = R.lhs()[Ai].stoichCoeff;
160 
161  forAll(R.rhs(), Bi)
162  {
163  label B = R.rhs()[Bi].index;
164  scalar Bcoeff = R.rhs()[Bi].stoichCoeff;
165  // if a pair in the reversed way has not been initialised
166  if (rABPos(B, A)==-1)
167  {
168  label otherS = rABPos(A, B);
169  if (otherS==-1)
170  {
171  rABPos(A, B) = NbrABInit[A]++;
172  otherS = rABPos(A, B);
173  nbPairs++;
174  rABOtherSpec(A, otherS) = B;
175  }
176  if (NCi>vSmall)
177  {
178  CFluxAB(A, otherS) +=
179  fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
180  }
181  if (NHi>vSmall)
182  {
183  HFluxAB(A, otherS) +=
184  fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
185  }
186  if (NOi>vSmall)
187  {
188  OFluxAB(A, otherS) +=
189  fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
190  }
191  if (NNi>vSmall)
192  {
193  NFluxAB(A, otherS) +=
194  fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
195  }
196  }
197  // If a pair BA is initialised,
198  // add the element flux to this pair
199  else
200  {
201  label otherS = rABPos(B, A);
202  if (NCi>vSmall)
203  {
204  CFluxAB(B, otherS) +=
205  fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
206  }
207  if (NHi>vSmall)
208  {
209  HFluxAB(B, otherS) +=
210  fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
211  }
212  if (NOi>vSmall)
213  {
214  OFluxAB(B, otherS) +=
215  fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
216  }
217  if (NNi>vSmall)
218  {
219  NFluxAB(B, otherS) +=
220  fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
221  }
222  }
223  if (NCi>vSmall)
224  {
225  CFlux += fr*Acoeff*sC_[A]*Bcoeff*sC_[B]/NCi;
226  }
227  if (NHi>vSmall)
228  {
229  HFlux += fr*Acoeff*sH_[A]*Bcoeff*sH_[B]/NHi;
230  }
231  if (NOi>vSmall)
232  {
233  OFlux += fr*Acoeff*sO_[A]*Bcoeff*sO_[B]/NOi;
234  }
235  if (NNi>vSmall)
236  {
237  NFlux += fr*Acoeff*sN_[A]*Bcoeff*sN_[B]/NNi;
238  }
239  }
240  }
241  }
242 
243  // Select species according to the total flux cutoff (1-tolerance)
244  // of the flux is included
245  label speciesNumber = 0;
246  for (label i=0; i<this->nSpecie_; i++)
247  {
248  this->activeSpecies_[i] = false;
249  }
250 
251  if (CFlux > vSmall)
252  {
253  SortableListEFA<scalar> pairsFlux(nbPairs);
254  labelList source(nbPairs);
255  labelList sink(nbPairs);
256  label nP(0);
257  for (int A=0; A<this->nSpecie_ ; A++)
258  {
259  for (int j=0; j<NbrABInit[A]; j++)
260  {
261  label pairIndex = nP++;
262  pairsFlux[pairIndex] = 0.0;
263  label B = rABOtherSpec(A, j);
264  pairsFlux[pairIndex] += CFluxAB(A, j);
265  source[pairIndex] = A;
266  sink[pairIndex] = B;
267  }
268  }
269 
270  // Sort in descending orders the source/sink pairs until the cutoff is
271  // reached. The sorting is done on part of the pairs because a small
272  // part of these pairs are responsible for a large part of the element
273  // flux
274  scalar cumFlux(0.0);
275  scalar threshold((1-this->tolerance())*CFlux);
276  label startPoint(0);
277  label nbToSort(static_cast<label> (nbPairs*sortPart_));
278  nbToSort = max(nbToSort,1);
279 
280  bool cumRespected(false);
281  while(!cumRespected)
282  {
283  if (startPoint >= nbPairs)
284  {
286  << "startPoint outside number of pairs without reaching"
287  << "100% flux"
288  << exit(FatalError);
289  }
290 
291  label nbi = min(nbToSort, nbPairs-startPoint);
292  pairsFlux.partialSort(nbi, startPoint);
293  const labelList& idx = pairsFlux.indices();
294  for (int i=0; i<nbi; i++)
295  {
296  cumFlux += pairsFlux[idx[startPoint+i]];
297  if (!this->activeSpecies_[source[idx[startPoint+i]]])
298  {
299  this->activeSpecies_[source[idx[startPoint+i]]] = true;
300  speciesNumber++;
301  }
302  if (!this->activeSpecies_[sink[idx[startPoint+i]]])
303  {
304  this->activeSpecies_[sink[idx[startPoint+i]]] = true;
305  speciesNumber++;
306  }
307  if (cumFlux >= threshold)
308  {
309  cumRespected = true;
310  break;
311  }
312  }
313  startPoint += nbToSort;
314  }
315  }
316 
317  if (HFlux > vSmall)
318  {
319  SortableListEFA<scalar> pairsFlux(nbPairs);
320  labelList source(nbPairs);
321  labelList sink(nbPairs);
322  label nP(0);
323  for (int A=0; A<this->nSpecie_ ; A++)
324  {
325  for (int j=0; j<NbrABInit[A]; j++)
326  {
327  label pairIndex = nP++;
328  pairsFlux[pairIndex] = 0.0;
329  label B = rABOtherSpec(A, j);
330  pairsFlux[pairIndex] += HFluxAB(A, j);
331  source[pairIndex] = A;
332  sink[pairIndex] = B;
333  }
334  }
335 
336  scalar cumFlux(0.0);
337  scalar threshold((1-this->tolerance())*HFlux);
338  label startPoint(0);
339  label nbToSort(static_cast<label> (nbPairs*sortPart_));
340  nbToSort = max(nbToSort,1);
341 
342  bool cumRespected(false);
343  while(!cumRespected)
344  {
345  if (startPoint >= nbPairs)
346  {
348  << "startPoint outside number of pairs without reaching"
349  << "100% flux"
350  << exit(FatalError);
351  }
352 
353  label nbi = min(nbToSort, nbPairs-startPoint);
354  pairsFlux.partialSort(nbi, startPoint);
355  const labelList& idx = pairsFlux.indices();
356  for (int i=0; i<nbi; i++)
357  {
358  cumFlux += pairsFlux[idx[startPoint+i]];
359 
360  if (!this->activeSpecies_[source[idx[startPoint+i]]])
361  {
362  this->activeSpecies_[source[idx[startPoint+i]]] = true;
363  speciesNumber++;
364  }
365  if (!this->activeSpecies_[sink[idx[startPoint+i]]])
366  {
367  this->activeSpecies_[sink[idx[startPoint+i]]] = true;
368  speciesNumber++;
369  }
370  if (cumFlux >= threshold)
371  {
372  cumRespected = true;
373  break;
374  }
375  }
376  startPoint += nbToSort;
377  }
378  }
379 
380  if (OFlux > vSmall)
381  {
382  SortableListEFA<scalar> pairsFlux(nbPairs);
383  labelList source(nbPairs);
384  labelList sink(nbPairs);
385  label nP(0);
386  for (int A=0; A<this->nSpecie_ ; A++)
387  {
388  for (int j=0; j<NbrABInit[A]; j++)
389  {
390  label pairIndex = nP++;
391  pairsFlux[pairIndex] = 0.0;
392  label B = rABOtherSpec(A, j);
393  pairsFlux[pairIndex] += OFluxAB(A, j);
394  source[pairIndex] = A;
395  sink[pairIndex] = B;
396  }
397  }
398  scalar cumFlux(0.0);
399  scalar threshold((1-this->tolerance())*OFlux);
400  label startPoint(0);
401  label nbToSort(static_cast<label> (nbPairs*sortPart_));
402  nbToSort = max(nbToSort,1);
403 
404  bool cumRespected(false);
405  while(!cumRespected)
406  {
407  if (startPoint >= nbPairs)
408  {
410  << "startPoint outside number of pairs without reaching"
411  << "100% flux"
412  << exit(FatalError);
413  }
414 
415  label nbi = min(nbToSort, nbPairs-startPoint);
416  pairsFlux.partialSort(nbi, startPoint);
417  const labelList& idx = pairsFlux.indices();
418  for (int i=0; i<nbi; i++)
419  {
420  cumFlux += pairsFlux[idx[startPoint+i]];
421 
422  if (!this->activeSpecies_[source[idx[startPoint+i]]])
423  {
424  this->activeSpecies_[source[idx[startPoint+i]]] = true;
425  speciesNumber++;
426  }
427  if (!this->activeSpecies_[sink[idx[startPoint+i]]])
428  {
429  this->activeSpecies_[sink[idx[startPoint+i]]] = true;
430  speciesNumber++;
431  }
432  if (cumFlux >= threshold)
433  {
434  cumRespected = true;
435  break;
436  }
437  }
438  startPoint += nbToSort;
439  }
440  }
441 
442  if (NFlux > vSmall)
443  {
444  SortableListEFA<scalar> pairsFlux(nbPairs);
445  labelList source(nbPairs);
446  labelList sink(nbPairs);
447  label nP(0);
448  for (int A=0; A<this->nSpecie_ ; A++)
449  {
450  for (int j=0; j<NbrABInit[A]; j++)
451  {
452  label pairIndex = nP++;
453  pairsFlux[pairIndex] = 0.0;
454  label B = rABOtherSpec(A, j);
455  pairsFlux[pairIndex] += NFluxAB(A, j);
456  source[pairIndex] = A;
457  sink[pairIndex] = B;
458  }
459  }
460  scalar cumFlux(0.0);
461  scalar threshold((1-this->tolerance())*NFlux);
462  label startPoint(0);
463  label nbToSort(static_cast<label> (nbPairs*sortPart_));
464  nbToSort = max(nbToSort,1);
465 
466  bool cumRespected(false);
467  while(!cumRespected)
468  {
469  if (startPoint >= nbPairs)
470  {
472  << "startPoint outside number of pairs without reaching"
473  << "100% flux"
474  << exit(FatalError);
475  }
476 
477  label nbi = min(nbToSort, nbPairs-startPoint);
478  pairsFlux.partialSort(nbi, startPoint);
479  const labelList& idx = pairsFlux.indices();
480  for (int i=0; i<nbi; i++)
481  {
482  cumFlux += pairsFlux[idx[startPoint+i]];
483 
484  if (!this->activeSpecies_[source[idx[startPoint+i]]])
485  {
486  this->activeSpecies_[source[idx[startPoint+i]]] = true;
487  speciesNumber++;
488  }
489  if (!this->activeSpecies_[sink[idx[startPoint+i]]])
490  {
491  this->activeSpecies_[sink[idx[startPoint+i]]] = true;
492  speciesNumber++;
493  }
494  if (cumFlux >= threshold)
495  {
496  cumRespected = true;
497  break;
498  }
499  }
500  startPoint += nbToSort;
501  }
502  }
503 
504  // Put a flag on the reactions containing at least one removed species
505  forAll(this->chemistry_.reactions(), i)
506  {
507  const Reaction<ThermoType>& R = this->chemistry_.reactions()[i];
508  this->chemistry_.reactionsDisabled()[i] = false;
509  forAll(R.lhs(), s)
510  {
511  label ss = R.lhs()[s].index;
512  if (!this->activeSpecies_[ss])
513  {
514  this->chemistry_.reactionsDisabled()[i] = true;
515  break;
516  }
517  }
518  if (!this->chemistry_.reactionsDisabled()[i])
519  {
520  forAll(R.rhs(), s)
521  {
522  label ss = R.rhs()[s].index;
523  if (!this->activeSpecies_[ss])
524  {
525  this->chemistry_.reactionsDisabled()[i] = true;
526  break;
527  }
528  }
529  }
530  }
531 
532  this->NsSimp_ = speciesNumber;
533  scalarField& simplifiedC(this->chemistry_.simplifiedC());
534  simplifiedC.setSize(this->NsSimp_+2);
535  DynamicList<label>& s2c(this->chemistry_.simplifiedToCompleteIndex());
536  s2c.setSize(this->NsSimp_);
537  Field<label>& c2s(this->chemistry_.completeToSimplifiedIndex());
538  label j = 0;
539 
540  for (label i=0; i<this->nSpecie_; i++)
541  {
542  if (this->activeSpecies_[i])
543  {
544  s2c[j] = i;
545  simplifiedC[j] = c[i];
546  c2s[i] = j++;
547  if (!this->chemistry_.active(i))
548  {
549  this->chemistry_.setActive(i);
550  }
551  }
552  else
553  {
554  c2s[i] = -1;
555  }
556  }
557  simplifiedC[this->NsSimp_] = T;
558  simplifiedC[this->NsSimp_+1] = p;
559  this->chemistry_.setNsDAC(this->NsSimp_);
560  // change temporary Ns in chemistryModel
561  // to make the function nEqns working
562  this->chemistry_.setNSpecie(this->NsSimp_);
563 }
564 
565 
566 // ************************************************************************* //
Extends standardChemistryModel by adding the TDAC method.
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
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
A list that is sorted upon construction or when explicitly requested with the sort() method...
const List< specieCoeffs > & lhs() const
Return the components of the left hand side.
Definition: reactionI.H:36
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
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:53
const dimensionedScalar c1
First radiation constant: default SI units: [W/m^2].
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
void setSize(const label)
Alter the addressed list size.
Definition: DynamicListI.H:175
virtual void reduceMechanism(const scalar p, const scalar T, const scalarField &c, const label li)
Reduce the mechanism.
Definition: EFA.C:95
EFA(const IOdictionary &dict, TDACChemistryModel< ThermoType > &chemistry)
Construct from components.
Definition: EFA.C:33
const word & name() const
Return the name of the element.
label nAtoms() const
Return the number of atoms of this element in the specie.
A templated 2D rectangular m x n matrix of objects of <Type>.
basicChemistryModel & chemistry
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
const volScalarField & T
void setSize(const label)
Reset size of List.
Definition: List.C:281
const List< specieCoeffs > & rhs() const
Return the components of the right hand side.
Definition: reactionI.H:42
virtual ~EFA()
Destructor.
Definition: EFA.C:87
fvModels source(alpha1, mixture.thermo1().rho())
#define R(A, B, C, D, E, F, K, M)
messageStream Info
const multiComponentMixture< ThermoType > & mixture() const
Return reference to the mixture.
dimensioned< scalar > mag(const dimensioned< Type > &)
void partialSort(int M, int start)
Partial sort the list (if changed after construction time)
An abstract class for methods of chemical mechanism reduction.
volScalarField & p