chemistryModel.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-2022 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 "chemistryModel.H"
27 #include "UniformField.H"
28 #include "localEulerDdtScheme.H"
29 #include "cpuLoad.H"
30 
31 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
32 
33 template<class ThermoType>
35 (
37 )
38 :
40  log_(this->lookupOrDefault("log", false)),
41  loadBalancing_(this->lookupOrDefault("loadBalancing", false)),
42  jacobianType_
43  (
44  this->found("jacobian")
45  ? jacobianTypeNames_.read(this->lookup("jacobian"))
46  : jacobianType::fast
47  ),
48  mixture_(refCast<const multicomponentMixture<ThermoType>>(this->thermo())),
49  specieThermos_(mixture_.specieThermos()),
50  reactions_(mixture_.species(), specieThermos_, this->mesh(), *this),
51  RR_(nSpecie_),
52  Y_(nSpecie_),
53  c_(nSpecie_),
54  YTpWork_(scalarField(nSpecie_ + 2)),
55  YTpYTpWork_(scalarSquareMatrix(nSpecie_ + 2)),
56  mechRedPtr_
57  (
58  chemistryReductionMethod<ThermoType>::New
59  (
60  *this,
61  *this
62  )
63  ),
64  mechRed_(*mechRedPtr_),
65  tabulationPtr_(chemistryTabulationMethod::New(*this, *this)),
66  tabulation_(*tabulationPtr_)
67 {
68  // Create the fields for the chemistry sources
69  forAll(RR_, fieldi)
70  {
71  RR_.set
72  (
73  fieldi,
75  (
76  IOobject
77  (
78  "RR." + Yvf_[fieldi].name(),
79  this->mesh().time().timeName(),
80  this->mesh(),
83  ),
84  thermo.mesh(),
86  )
87  );
88  }
89 
90  Info<< "chemistryModel: Number of species = " << nSpecie_
91  << " and reactions = " << nReaction() << endl;
92 
93  // When the mechanism reduction method is used, the 'active' flag for every
94  // species should be initialised (by default 'active' is true)
95  if (reduction_)
96  {
98 
99  forAll(Yvf_, i)
100  {
102  (
103  Yvf_[i].name(),
104  this->mesh().time().timeName(),
105  this->mesh(),
107  );
108 
109  // Check if the species file is provided, if not set inactive
110  // and NO_WRITE
111  if (!header.headerOk())
112  {
113  composition.setInactive(i);
114  }
115  }
116  }
117 
118  if (log_)
119  {
120  cpuSolveFile_ = logFile("cpu_solve.out");
121  }
122 }
123 
124 
125 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
126 
127 template<class ThermoType>
129 {}
130 
131 
132 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
133 
134 template<class ThermoType>
136 (
137  const scalar time,
138  const scalarField& YTp,
139  const label li,
140  scalarField& dYTpdt
141 ) const
142 {
143  if (reduction_)
144  {
145  forAll(sToc_, i)
146  {
147  Y_[sToc_[i]] = max(YTp[i], 0);
148  }
149  }
150  else
151  {
152  forAll(Y_, i)
153  {
154  Y_[i] = max(YTp[i], 0);
155  }
156  }
157 
158  const scalar T = YTp[nSpecie_];
159  const scalar p = YTp[nSpecie_ + 1];
160 
161  // Evaluate the mixture density
162  scalar rhoM = 0;
163  for (label i=0; i<Y_.size(); i++)
164  {
165  rhoM += Y_[i]/specieThermos_[i].rho(p, T);
166  }
167  rhoM = 1/rhoM;
168 
169  // Evaluate the concentrations
170  for (label i=0; i<Y_.size(); i ++)
171  {
172  c_[i] = rhoM/specieThermos_[i].W()*Y_[i];
173  }
174 
175  // Evaluate contributions from reactions
176  dYTpdt = Zero;
177  forAll(reactions_, ri)
178  {
179  if (!mechRed_.reactionDisabled(ri))
180  {
181  reactions_[ri].dNdtByV
182  (
183  p,
184  T,
185  c_,
186  li,
187  dYTpdt,
188  reduction_,
189  cTos_,
190  0
191  );
192  }
193  }
194 
195  // Reactions return dNdtByV, so we need to convert the result to dYdt
196  for (label i=0; i<nSpecie_; i++)
197  {
198  const scalar WiByrhoM = specieThermos_[sToc(i)].W()/rhoM;
199  scalar& dYidt = dYTpdt[i];
200  dYidt *= WiByrhoM;
201  }
202 
203  // Evaluate the effect on the thermodynamic system ...
204 
205  // Evaluate the mixture Cp
206  scalar CpM = 0;
207  for (label i=0; i<Y_.size(); i++)
208  {
209  CpM += Y_[i]*specieThermos_[i].Cp(p, T);
210  }
211 
212  // dT/dt
213  scalar& dTdt = dYTpdt[nSpecie_];
214  for (label i=0; i<nSpecie_; i++)
215  {
216  dTdt -= dYTpdt[i]*specieThermos_[sToc(i)].Ha(p, T);
217  }
218  dTdt /= CpM;
219 
220  // dp/dt = 0 (pressure is assumed constant)
221  scalar& dpdt = dYTpdt[nSpecie_ + 1];
222  dpdt = 0;
223 }
224 
225 
226 template<class ThermoType>
228 (
229  const scalar t,
230  const scalarField& YTp,
231  const label li,
232  scalarField& dYTpdt,
234 ) const
235 {
236  if (reduction_)
237  {
238  forAll(sToc_, i)
239  {
240  Y_[sToc_[i]] = max(YTp[i], 0);
241  }
242  }
243  else
244  {
245  forAll(c_, i)
246  {
247  Y_[i] = max(YTp[i], 0);
248  }
249  }
250 
251  const scalar T = YTp[nSpecie_];
252  const scalar p = YTp[nSpecie_ + 1];
253 
254  // Evaluate the specific volumes and mixture density
255  scalarField& v = YTpWork_[0];
256  for (label i=0; i<Y_.size(); i++)
257  {
258  v[i] = 1/specieThermos_[i].rho(p, T);
259  }
260  scalar rhoM = 0;
261  for (label i=0; i<Y_.size(); i++)
262  {
263  rhoM += Y_[i]*v[i];
264  }
265  rhoM = 1/rhoM;
266 
267  // Evaluate the concentrations
268  for (label i=0; i<Y_.size(); i ++)
269  {
270  c_[i] = rhoM/specieThermos_[i].W()*Y_[i];
271  }
272 
273  // Evaluate the derivatives of concentration w.r.t. mass fraction
274  scalarSquareMatrix& dcdY = YTpYTpWork_[0];
275  for (label i=0; i<nSpecie_; i++)
276  {
277  const scalar rhoMByWi = rhoM/specieThermos_[sToc(i)].W();
278  switch (jacobianType_)
279  {
280  case jacobianType::fast:
281  {
282  dcdY(i, i) = rhoMByWi;
283  }
284  break;
285  case jacobianType::exact:
286  for (label j=0; j<nSpecie_; j++)
287  {
288  dcdY(i, j) =
289  rhoMByWi*((i == j) - rhoM*v[sToc(j)]*Y_[sToc(i)]);
290  }
291  break;
292  }
293  }
294 
295  // Evaluate the mixture thermal expansion coefficient
296  scalar alphavM = 0;
297  for (label i=0; i<Y_.size(); i++)
298  {
299  alphavM += Y_[i]*rhoM*v[i]*specieThermos_[i].alphav(p, T);
300  }
301 
302  // Evaluate contributions from reactions
303  dYTpdt = Zero;
304  scalarSquareMatrix& ddNdtByVdcTp = YTpYTpWork_[1];
305  for (label i=0; i<nSpecie_ + 2; i++)
306  {
307  for (label j=0; j<nSpecie_ + 2; j++)
308  {
309  ddNdtByVdcTp[i][j] = 0;
310  }
311  }
312  forAll(reactions_, ri)
313  {
314  if (!mechRed_.reactionDisabled(ri))
315  {
316  reactions_[ri].ddNdtByVdcTp
317  (
318  p,
319  T,
320  c_,
321  li,
322  dYTpdt,
323  ddNdtByVdcTp,
324  reduction_,
325  cTos_,
326  0,
327  nSpecie_,
328  YTpWork_[1],
329  YTpWork_[2]
330  );
331  }
332  }
333 
334  // Reactions return dNdtByV, so we need to convert the result to dYdt
335  for (label i=0; i<nSpecie_; i++)
336  {
337  const scalar WiByrhoM = specieThermos_[sToc(i)].W()/rhoM;
338  scalar& dYidt = dYTpdt[i];
339  dYidt *= WiByrhoM;
340 
341  for (label j=0; j<nSpecie_; j++)
342  {
343  scalar ddNidtByVdYj = 0;
344  switch (jacobianType_)
345  {
346  case jacobianType::fast:
347  {
348  const scalar ddNidtByVdcj = ddNdtByVdcTp(i, j);
349  ddNidtByVdYj = ddNidtByVdcj*dcdY(j, j);
350  }
351  break;
352  case jacobianType::exact:
353  for (label k=0; k<nSpecie_; k++)
354  {
355  const scalar ddNidtByVdck = ddNdtByVdcTp(i, k);
356  ddNidtByVdYj += ddNidtByVdck*dcdY(k, j);
357  }
358  break;
359  }
360 
361  scalar& ddYidtdYj = J(i, j);
362  ddYidtdYj = WiByrhoM*ddNidtByVdYj + rhoM*v[sToc(j)]*dYidt;
363  }
364 
365  scalar ddNidtByVdT = ddNdtByVdcTp(i, nSpecie_);
366  for (label j=0; j<nSpecie_; j++)
367  {
368  const scalar ddNidtByVdcj = ddNdtByVdcTp(i, j);
369  ddNidtByVdT -= ddNidtByVdcj*c_[sToc(j)]*alphavM;
370  }
371 
372  scalar& ddYidtdT = J(i, nSpecie_);
373  ddYidtdT = WiByrhoM*ddNidtByVdT + alphavM*dYidt;
374 
375  scalar& ddYidtdp = J(i, nSpecie_ + 1);
376  ddYidtdp = 0;
377  }
378 
379  // Evaluate the effect on the thermodynamic system ...
380 
381  // Evaluate the mixture Cp and its derivative
382  scalarField& Cp = YTpWork_[3];
383  scalar CpM = 0, dCpMdT = 0;
384  for (label i=0; i<Y_.size(); i++)
385  {
386  Cp[i] = specieThermos_[i].Cp(p, T);
387  CpM += Y_[i]*Cp[i];
388  dCpMdT += Y_[i]*specieThermos_[i].dCpdT(p, T);
389  }
390 
391  // dT/dt
392  scalarField& Ha = YTpWork_[4];
393  scalar& dTdt = dYTpdt[nSpecie_];
394  for (label i=0; i<nSpecie_; i++)
395  {
396  Ha[sToc(i)] = specieThermos_[sToc(i)].Ha(p, T);
397  dTdt -= dYTpdt[i]*Ha[sToc(i)];
398  }
399  dTdt /= CpM;
400 
401  // dp/dt = 0 (pressure is assumed constant)
402  scalar& dpdt = dYTpdt[nSpecie_ + 1];
403  dpdt = 0;
404 
405  // d(dTdt)/dY
406  for (label i=0; i<nSpecie_; i++)
407  {
408  scalar& ddTdtdYi = J(nSpecie_, i);
409  ddTdtdYi = 0;
410  for (label j=0; j<nSpecie_; j++)
411  {
412  const scalar ddYjdtdYi = J(j, i);
413  ddTdtdYi -= ddYjdtdYi*Ha[sToc(j)];
414  }
415  ddTdtdYi -= Cp[sToc(i)]*dTdt;
416  ddTdtdYi /= CpM;
417  }
418 
419  // d(dTdt)/dT
420  scalar& ddTdtdT = J(nSpecie_, nSpecie_);
421  ddTdtdT = 0;
422  for (label i=0; i<nSpecie_; i++)
423  {
424  const scalar dYidt = dYTpdt[i];
425  const scalar ddYidtdT = J(i, nSpecie_);
426  ddTdtdT -= dYidt*Cp[sToc(i)] + ddYidtdT*Ha[sToc(i)];
427  }
428  ddTdtdT -= dTdt*dCpMdT;
429  ddTdtdT /= CpM;
430 
431  // d(dTdt)/dp = 0 (pressure is assumed constant)
432  scalar& ddTdtdp = J(nSpecie_, nSpecie_ + 1);
433  ddTdtdp = 0;
434 
435  // d(dpdt)/dYiTp = 0 (pressure is assumed constant)
436  for (label i=0; i<nSpecie_ + 2; i++)
437  {
438  scalar& ddpdtdYiTp = J(nSpecie_ + 1, i);
439  ddpdtdYiTp = 0;
440  }
441 }
442 
443 
444 template<class ThermoType>
447 (
448  const label reactioni
449 ) const
450 {
452  for (label i=0; i<nSpecie_; i++)
453  {
454  RR.set
455  (
456  i,
458  (
459  "RR." + Yvf_[i].name(),
460  this->mesh(),
462  ).ptr()
463  );
464  }
465 
466  if (!this->chemistry_ || mechRed_.reactionDisabled(reactioni))
467  {
468  return RR;
469  }
470 
471  tmp<volScalarField> trhovf(this->thermo().rho());
472  const volScalarField& rhovf = trhovf();
473 
474  const volScalarField& Tvf = this->thermo().T();
475  const volScalarField& pvf = this->thermo().p();
476 
477  scalarField& dNdtByV = YTpWork_[0];
478 
479  reactionEvaluationScope scope(*this);
480 
481  const Reaction<ThermoType>& R = reactions_[reactioni];
482 
483  forAll(rhovf, celli)
484  {
485  const scalar rho = rhovf[celli];
486  const scalar T = Tvf[celli];
487  const scalar p = pvf[celli];
488 
489  for (label i=0; i<nSpecie_; i++)
490  {
491  const scalar Yi = Yvf_[i][celli];
492  c_[i] = rho*Yi/specieThermos_[i].W();
493  }
494 
495  dNdtByV = Zero;
496 
497  R.dNdtByV
498  (
499  p,
500  T,
501  c_,
502  celli,
503  dNdtByV,
504  reduction_,
505  cTos_,
506  0
507  );
508 
509  for (label i=0; i<nSpecie_; i++)
510  {
511  RR[i][celli] = dNdtByV[i]*specieThermos_[i].W();
512  }
513  }
514 
515  return RR;
516 }
517 
518 
519 template<class ThermoType>
521 {
522  if (!this->chemistry_)
523  {
524  return;
525  }
526 
527  tmp<volScalarField> trhovf(this->thermo().rho());
528  const volScalarField& rhovf = trhovf();
529 
530  const volScalarField& Tvf = this->thermo().T();
531  const volScalarField& pvf = this->thermo().p();
532 
533  scalarField& dNdtByV = YTpWork_[0];
534 
535  reactionEvaluationScope scope(*this);
536 
537  forAll(rhovf, celli)
538  {
539  const scalar rho = rhovf[celli];
540  const scalar T = Tvf[celli];
541  const scalar p = pvf[celli];
542 
543  for (label i=0; i<nSpecie_; i++)
544  {
545  const scalar Yi = Yvf_[i][celli];
546  c_[i] = rho*Yi/specieThermos_[i].W();
547  }
548 
549  dNdtByV = Zero;
550 
551  forAll(reactions_, ri)
552  {
553  if (!mechRed_.reactionDisabled(ri))
554  {
555  reactions_[ri].dNdtByV
556  (
557  p,
558  T,
559  c_,
560  celli,
561  dNdtByV,
562  reduction_,
563  cTos_,
564  0
565  );
566  }
567  }
568 
569  for (label i=0; i<mechRed_.nActiveSpecies(); i++)
570  {
571  RR_[sToc(i)][celli] = dNdtByV[i]*specieThermos_[sToc(i)].W();
572  }
573  }
574 }
575 
576 
577 template<class ThermoType>
578 template<class DeltaTType>
580 (
581  const DeltaTType& deltaT
582 )
583 {
584  optionalCpuLoad& chemistryCpuTime
585  (
586  optionalCpuLoad::New(this->mesh(), "chemistryCpuTime", loadBalancing_)
587  );
588 
589  // CPU time logging
590  cpuTime solveCpuTime;
591  scalar totalSolveCpuTime = 0;
592 
593  if (!this->chemistry_)
594  {
595  return great;
596  }
597 
598  const volScalarField& rho0vf =
599  this->mesh().template lookupObject<volScalarField>
600  (
601  this->thermo().phasePropertyName("rho")
602  ).oldTime();
603 
604  const volScalarField& T0vf = this->thermo().T().oldTime();
605  const volScalarField& p0vf = this->thermo().p().oldTime();
606 
607  reactionEvaluationScope scope(*this);
608 
609  scalarField Y0(nSpecie_);
610 
611  // Composition vector (Yi, T, p, deltaT)
612  scalarField phiq(nEqns() + 1);
613  scalarField Rphiq(nEqns() + 1);
614 
615  // Minimum chemical timestep
616  scalar deltaTMin = great;
617 
618  tabulation_.reset();
619  chemistryCpuTime.reset();
620 
621  forAll(rho0vf, celli)
622  {
623  const scalar rho0 = rho0vf[celli];
624 
625  scalar p = p0vf[celli];
626  scalar T = T0vf[celli];
627 
628  for (label i=0; i<nSpecie_; i++)
629  {
630  Y_[i] = Y0[i] = Yvf_[i].oldTime()[celli];
631  }
632 
633  for (label i=0; i<nSpecie_; i++)
634  {
635  phiq[i] = Yvf_[i].oldTime()[celli];
636  }
637  phiq[nSpecie()] = T;
638  phiq[nSpecie() + 1] = p;
639  phiq[nSpecie() + 2] = deltaT[celli];
640 
641  // Initialise time progress
642  scalar timeLeft = deltaT[celli];
643 
644  // Not sure if this is necessary
645  Rphiq = Zero;
646 
647  // When tabulation is active (short-circuit evaluation for retrieve)
648  // It first tries to retrieve the solution of the system with the
649  // information stored through the tabulation method
650  if (tabulation_.retrieve(phiq, Rphiq))
651  {
652  // Retrieved solution stored in Rphiq
653  for (label i=0; i<nSpecie(); i++)
654  {
655  Y_[i] = Rphiq[i];
656  }
657  T = Rphiq[nSpecie()];
658  p = Rphiq[nSpecie() + 1];
659  }
660  // This position is reached when tabulation is not used OR
661  // if the solution is not retrieved.
662  // In the latter case, it adds the information to the tabulation
663  // (it will either expand the current data or add a new stored point).
664  else
665  {
666  if (reduction_)
667  {
668  // Compute concentrations
669  for (label i=0; i<nSpecie_; i++)
670  {
671  c_[i] = rho0*Y_[i]/specieThermos_[i].W();
672  }
673 
674  // Reduce mechanism change the number of species (only active)
675  mechRed_.reduceMechanism(p, T, c_, cTos_, sToc_, celli);
676 
677  // Set the simplified mass fraction field
678  sY_.setSize(nSpecie_);
679  for (label i=0; i<nSpecie_; i++)
680  {
681  sY_[i] = Y_[sToc(i)];
682  }
683  }
684 
685  if (log_)
686  {
687  // Reset the solve time
688  solveCpuTime.cpuTimeIncrement();
689  }
690 
691  // Calculate the chemical source terms
692  while (timeLeft > small)
693  {
694  scalar dt = timeLeft;
695  if (reduction_)
696  {
697  // Solve the reduced set of ODE
698  solve
699  (
700  p,
701  T,
702  sY_,
703  celli,
704  dt,
705  deltaTChem_[celli]
706  );
707 
708  for (label i=0; i<mechRed_.nActiveSpecies(); i++)
709  {
710  Y_[sToc_[i]] = sY_[i];
711  }
712  }
713  else
714  {
715  solve(p, T, Y_, celli, dt, deltaTChem_[celli]);
716  }
717  timeLeft -= dt;
718  }
719 
720  if (log_)
721  {
722  totalSolveCpuTime += solveCpuTime.cpuTimeIncrement();
723  }
724 
725  // If tabulation is used, we add the information computed here to
726  // the stored points (either expand or add)
727  if (tabulation_.tabulates())
728  {
729  forAll(Y_, i)
730  {
731  Rphiq[i] = Y_[i];
732  }
733  Rphiq[Rphiq.size()-3] = T;
734  Rphiq[Rphiq.size()-2] = p;
735  Rphiq[Rphiq.size()-1] = deltaT[celli];
736 
737  tabulation_.add
738  (
739  phiq,
740  Rphiq,
741  mechRed_.nActiveSpecies(),
742  celli,
743  deltaT[celli]
744  );
745  }
746 
747  // When operations are done and if mechanism reduction is active,
748  // the number of species (which also affects nEqns) is set back
749  // to the total number of species (stored in the mechRed object)
750  if (reduction_)
751  {
752  setNSpecie(mechRed_.nSpecie());
753  }
754 
755  deltaTMin = min(deltaTChem_[celli], deltaTMin);
756  deltaTChem_[celli] = min(deltaTChem_[celli], deltaTChemMax_);
757  }
758 
759  // Set the RR vector (used in the solver)
760  for (label i=0; i<nSpecie_; i++)
761  {
762  RR_[i][celli] = rho0*(Y_[i] - Y0[i])/deltaT[celli];
763  }
764 
765  if (loadBalancing_)
766  {
767  chemistryCpuTime.cpuTimeIncrement(celli);
768  }
769  }
770 
771  if (log_)
772  {
773  cpuSolveFile_()
774  << this->time().userTimeValue()
775  << " " << totalSolveCpuTime << endl;
776  }
777 
778  mechRed_.update();
779  tabulation_.update();
780 
781  if (reduction_ && Pstream::parRun())
782  {
784 
785  List<bool> active(composition.active());
788 
789  forAll(active, i)
790  {
791  if (active[i])
792  {
794  }
795  }
796  }
797 
798  return deltaTMin;
799 }
800 
801 
802 template<class ThermoType>
804 (
805  const scalar deltaT
806 )
807 {
808  // Don't allow the time-step to change more than a factor of 2
809  return min
810  (
812  2*deltaT
813  );
814 }
815 
816 
817 template<class ThermoType>
819 (
820  const scalarField& deltaT
821 )
822 {
823  return this->solve<scalarField>(deltaT);
824 }
825 
826 
827 template<class ThermoType>
830 {
832  (
834  (
835  "tc",
836  this->mesh(),
837  dimensionedScalar(dimTime, small),
838  extrapolatedCalculatedFvPatchScalarField::typeName
839  )
840  );
841  scalarField& tc = ttc.ref();
842 
843  if (!this->chemistry_)
844  {
845  ttc.ref().correctBoundaryConditions();
846  return ttc;
847  }
848 
849  tmp<volScalarField> trhovf(this->thermo().rho());
850  const volScalarField& rhovf = trhovf();
851 
852  const volScalarField& Tvf = this->thermo().T();
853  const volScalarField& pvf = this->thermo().p();
854 
855  reactionEvaluationScope scope(*this);
856 
857  forAll(rhovf, celli)
858  {
859  const scalar rho = rhovf[celli];
860  const scalar T = Tvf[celli];
861  const scalar p = pvf[celli];
862 
863  for (label i=0; i<nSpecie_; i++)
864  {
865  c_[i] = rho*Yvf_[i][celli]/specieThermos_[i].W();
866  }
867 
868  // A reaction's rate scale is calculated as it's molar
869  // production rate divided by the total number of moles in the
870  // system.
871  //
872  // The system rate scale is the average of the reactions' rate
873  // scales weighted by the reactions' molar production rates. This
874  // weighting ensures that dominant reactions provide the largest
875  // contribution to the system rate scale.
876  //
877  // The system time scale is then the reciprocal of the system rate
878  // scale.
879  //
880  // Contributions from forward and reverse reaction rates are
881  // handled independently and identically so that reversible
882  // reactions produce the same result as the equivalent pair of
883  // irreversible reactions.
884 
885  scalar sumW = 0, sumWRateByCTot = 0;
886  forAll(reactions_, i)
887  {
888  const Reaction<ThermoType>& R = reactions_[i];
889  scalar omegaf, omegar;
890  R.omega(p, T, c_, celli, omegaf, omegar);
891 
892  scalar wf = 0;
893  forAll(R.rhs(), s)
894  {
895  wf += R.rhs()[s].stoichCoeff*omegaf;
896  }
897  sumW += wf;
898  sumWRateByCTot += sqr(wf);
899 
900  scalar wr = 0;
901  forAll(R.lhs(), s)
902  {
903  wr += R.lhs()[s].stoichCoeff*omegar;
904  }
905  sumW += wr;
906  sumWRateByCTot += sqr(wr);
907  }
908 
909  tc[celli] =
910  sumWRateByCTot == 0 ? vGreat : sumW/sumWRateByCTot*sum(c_);
911  }
912 
913  ttc.ref().correctBoundaryConditions();
914  return ttc;
915 }
916 
917 
918 template<class ThermoType>
921 {
922  tmp<volScalarField> tQdot
923  (
925  (
926  "Qdot",
927  this->mesh_,
929  )
930  );
931 
932  if (!this->chemistry_)
933  {
934  return tQdot;
935  }
936 
937  reactionEvaluationScope scope(*this);
938 
939  scalarField& Qdot = tQdot.ref();
940 
941  forAll(Yvf_, i)
942  {
943  forAll(Qdot, celli)
944  {
945  const scalar hi = specieThermos_[i].Hf();
946  Qdot[celli] -= hi*RR_[i][celli];
947  }
948  }
949 
950  return tQdot;
951 }
952 
953 
954 // ************************************************************************* //
scalar Ha(const scalar p, const scalar T) const
Definition: EtoHthermo.H:20
scalar Cp(const scalar p, const scalar T) const
Definition: EtoHthermo.H:2
label k
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
static tmp< DimensionedField< Type, GeoMesh > > New(const word &name, const Mesh &mesh, const dimensionSet &, const Field< Type > &)
Return a temporary field constructed from name, mesh,.
Generic GeometricField class.
const GeometricField< Type, PatchField, GeoMesh > & oldTime() const
Return old time field.
static tmp< GeometricField< Type, PatchField, GeoMesh > > New(const word &name, const Internal &, const PtrList< PatchField< Type >> &)
Return a temporary field constructed from name,.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
const Time & time() const
Return time.
Definition: IOobject.C:318
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
Simple extension of ThermoType to handle reaction kinetics in addition to the equilibrium thermodynam...
Definition: Reaction.H:72
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
A class representing the concept of a uniform field which stores only the single value and providing ...
Definition: UniformField.H:48
const fluidMulticomponentThermo & thermo() const
Return const access to the thermo.
jacobianType
Enumeration for the type of Jacobian to be calculated by the.
const fvMesh & mesh() const
Return const access to the mesh.
Specialisation of basicMixture for a mixture consisting of a number for molecular species.
void setActive(label speciei) const
Set speciei active.
bool active(label speciei) const
Return true for active species.
virtual const fvMesh & mesh() const =0
Return const access to the mesh.
virtual const volScalarField & T() const =0
Temperature [K].
Extends base chemistry model by adding a thermo package, and ODE functions. Introduces chemistry equa...
virtual void jacobian(const scalar t, const scalarField &YTp, const label li, scalarField &dYTpdt, scalarSquareMatrix &J) const
Calculate the ODE jacobian.
virtual tmp< volScalarField > tc() const
Return the chemical time scale.
virtual void derivatives(const scalar t, const scalarField &YTp, const label li, scalarField &dYTpdt) const
Calculate the ODE derivatives.
virtual label nReaction() const
The number of reactions.
virtual ~chemistryModel()
Destructor.
virtual PtrList< volScalarField::Internal > reactionRR(const label reactioni) const
Return reaction rates of the species in reactioni [kg/m^3/s].
virtual tmp< volScalarField > Qdot() const
Return the heat release rate [kg/m/s^3].
virtual void calculate()
Calculates the reaction rates.
An abstract class for methods of chemical mechanism reduction.
An abstract class for chemistry tabulation.
Starts timing CPU usage and return elapsed time from start.
Definition: cpuTime.H:55
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTime.C:60
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:109
Base-class for multi-component fluid thermodynamic properties.
virtual basicSpecieMixture & composition()=0
Return the composition of the multi-component mixture.
virtual volScalarField & p()=0
Pressure [Pa].
Foam::multicomponentMixture.
Extends base chemistry model adding an ODESystem and the reduction maps needed for tabulation.
autoPtr< OFstream > logFile(const word &name) const
Create and return a TDAC log file of the given name.
virtual void reset()
Dummy reset function.
Definition: cpuLoad.H:95
virtual void cpuTimeIncrement(const label celli)
Dummy cpuTimeIncrement function.
Definition: cpuLoad.H:99
static optionalCpuLoad & New(const fvMesh &mesh, const word &name, const bool loadBalancing)
Definition: cpuLoad.C:64
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:181
Templated form of IOobject providing type information for file reading and header type checking.
Definition: IOobject.H:531
bool headerOk()
Read header (uses typeGlobalFile to find file) and check.
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.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
word timeName
Definition: getTimeIndex.H:3
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
const dimensionedScalar RR
Universal gas constant: default SI units: [J/kmol/K].
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
static const zero Zero
Definition: zero.H:97
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
const dimensionSet dimEnergy
dimensionedSymmTensor sqr(const dimensionedVector &dv)
To & refCast(From &r)
Reference type cast template function.
Definition: typeInfo.H:111
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
messageStream Info
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
const dimensionSet dimTime
const dimensionSet dimVolume
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
static scalar R(const scalar a, const scalar x)
Definition: invIncGamma.C:102
const dimensionSet dimMass
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
SolverPerformance< Type > solve(fvMatrix< Type > &, const word &)
Solve returning the solution statistics given convergence tolerance.
scalar rho0
const label nSpecie
scalarList Y0(nSpecie, 0.0)
scalar Qdot
Definition: solveChemistry.H:2
basicSpecieMixture & composition
volScalarField & p
fluidMulticomponentThermo & thermo
Definition: createFields.H:31