Standard_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-2026 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 
28 #include "cpuLoad.H"
29 
30 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
31 
32 template<class ThermoType>
34 (
36 )
37 :
39  log_(this->lookupOrDefault("log", false)),
40  cpuLoad_(this->lookupOrDefault("cpuLoad", false)),
41  jacobianType_
42  (
43  this->found("jacobian")
44  ? jacobianTypeNames.read(this->lookup("jacobian"))
45  : jacobianType::fast
46  ),
47  mixture_
48  (
49  dynamicCast<const multicomponentMixture<ThermoType>>(this->thermo())
50  ),
51  specieThermos_(mixture_.specieThermos()),
52  reactions_(thermo.species(), specieThermos_, this->mesh(), *this),
53  RR_(nSpecie_),
54  Y_(nSpecie_),
55  c_(nSpecie_),
56  YTpWork_(scalarField(nSpecie_ + 2)),
57  YTpYTpWork_(scalarSquareMatrix(nSpecie_ + 2)),
58  mechRedPtr_
59  (
60  chemistryReductionMethod<ThermoType>::New
61  (
62  *this,
63  *this
64  )
65  ),
66  mechRed_(*mechRedPtr_),
67  tabulationPtr_(chemistryTabulationMethod::New(*this, *this)),
68  tabulation_(*tabulationPtr_)
69 {
70  // Create the fields for the chemistry sources
71  forAll(RR_, fieldi)
72  {
73  RR_.set
74  (
75  fieldi,
77  (
78  IOobject
79  (
80  "RR." + Yvf_[fieldi].name(),
81  this->mesh().time().name(),
82  this->mesh(),
85  ),
86  thermo.mesh(),
88  )
89  );
90  }
91 
92  Info<< "chemistryModel: Number of species = " << nSpecie_
93  << " and reactions = " << nReaction() << endl;
94 
95  // When the mechanism reduction method is used, the 'active' flag for every
96  // species should be initialised (by default 'active' is true)
97  if (reduction_)
98  {
99  forAll(Yvf_, i)
100  {
102  (
103  Yvf_[i].name(),
104  this->mesh().time().name(),
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  this->thermo().setSpecieInactive(i);
114  }
115  }
116 
117  this->thermo().syncSpeciesActive();
118  }
119 
120  if (log_)
121  {
122  cpuSolveFile_ = logFile("cpu_solve.out");
123  }
124 }
125 
126 
127 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
128 
129 template<class ThermoType>
131 {}
132 
133 
134 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
135 
136 template<class ThermoType>
138 (
139  const scalar time,
140  const scalarField& YTp,
141  const label li,
142  scalarField& dYTpdt
143 ) const
144 {
145  if (reduction_)
146  {
147  forAll(sToc_, i)
148  {
149  Y_[sToc_[i]] = max(YTp[i], 0);
150  }
151  }
152  else
153  {
154  forAll(Y_, i)
155  {
156  Y_[i] = max(YTp[i], 0);
157  }
158  }
159 
160  const scalar T = YTp[nSpecie_];
161  const scalar p = YTp[nSpecie_ + 1];
162 
163  // Evaluate the mixture density
164  scalar rhoM = 0;
165  for (label i=0; i<Y_.size(); i++)
166  {
167  rhoM += Y_[i]/specieThermos_[i].rho(p, T);
168  }
169  rhoM = 1/rhoM;
170 
171  // Evaluate the concentrations
172  for (label i=0; i<Y_.size(); i ++)
173  {
174  c_[i] = rhoM/specieThermos_[i].W()*Y_[i];
175  }
176 
177  // Evaluate contributions from reactions
178  dYTpdt = Zero;
179  forAll(reactions_, ri)
180  {
181  if (!mechRed_.reactionDisabled(ri))
182  {
183  reactions_[ri].dNdtByV
184  (
185  p,
186  T,
187  c_,
188  li,
189  dYTpdt,
190  reduction_,
191  cTos_,
192  0
193  );
194  }
195  }
196 
197  // Reactions return dNdtByV, so we need to convert the result to dYdt
198  for (label i=0; i<nSpecie_; i++)
199  {
200  const scalar WiByrhoM = specieThermos_[sToc(i)].W()/rhoM;
201  scalar& dYidt = dYTpdt[i];
202  dYidt *= WiByrhoM;
203  }
204 
205  // Evaluate the effect on the thermodynamic system ...
206 
207  // Evaluate the mixture Cp
208  scalar CpM = 0;
209  for (label i=0; i<Y_.size(); i++)
210  {
211  CpM += Y_[i]*specieThermos_[i].Cp(p, T);
212  }
213 
214  // dT/dt
215  scalar& dTdt = dYTpdt[nSpecie_];
216  for (label i=0; i<nSpecie_; i++)
217  {
218  dTdt -= dYTpdt[i]*specieThermos_[sToc(i)].ha(p, T);
219  }
220  dTdt /= CpM;
221 
222  // dp/dt = 0 (pressure is assumed constant)
223  scalar& dpdt = dYTpdt[nSpecie_ + 1];
224  dpdt = 0;
225 }
226 
227 
228 template<class ThermoType>
230 (
231  const scalar t,
232  const scalarField& YTp,
233  const label li,
234  scalarField& dYTpdt,
236 ) const
237 {
238  if (reduction_)
239  {
240  forAll(sToc_, i)
241  {
242  Y_[sToc_[i]] = max(YTp[i], 0);
243  }
244  }
245  else
246  {
247  forAll(c_, i)
248  {
249  Y_[i] = max(YTp[i], 0);
250  }
251  }
252 
253  const scalar T = YTp[nSpecie_];
254  const scalar p = YTp[nSpecie_ + 1];
255 
256  // Evaluate the specific volumes and mixture density
257  scalarField& v = YTpWork_[0];
258  for (label i=0; i<Y_.size(); i++)
259  {
260  v[i] = 1/specieThermos_[i].rho(p, T);
261  }
262  scalar rhoM = 0;
263  for (label i=0; i<Y_.size(); i++)
264  {
265  rhoM += Y_[i]*v[i];
266  }
267  rhoM = 1/rhoM;
268 
269  // Evaluate the concentrations
270  for (label i=0; i<Y_.size(); i ++)
271  {
272  c_[i] = rhoM/specieThermos_[i].W()*Y_[i];
273  }
274 
275  // Evaluate the derivatives of concentration w.r.t. mass fraction
276  scalarSquareMatrix& dcdY = YTpYTpWork_[0];
277  for (label i=0; i<nSpecie_; i++)
278  {
279  const scalar rhoMByWi = rhoM/specieThermos_[sToc(i)].W();
280  switch (jacobianType_)
281  {
282  case jacobianType::fast:
283  {
284  dcdY(i, i) = rhoMByWi;
285  }
286  break;
287  case jacobianType::exact:
288  for (label j=0; j<nSpecie_; j++)
289  {
290  dcdY(i, j) =
291  rhoMByWi*((i == j) - rhoM*v[sToc(j)]*Y_[sToc(i)]);
292  }
293  break;
294  }
295  }
296 
297  // Evaluate the mixture thermal expansion coefficient
298  scalar alphavM = 0;
299  for (label i=0; i<Y_.size(); i++)
300  {
301  alphavM += Y_[i]*rhoM*v[i]*specieThermos_[i].alphav(p, T);
302  }
303 
304  // Evaluate contributions from reactions
305  dYTpdt = Zero;
306  scalarSquareMatrix& ddNdtByVdcTp = YTpYTpWork_[1];
307  for (label i=0; i<nSpecie_ + 2; i++)
308  {
309  for (label j=0; j<nSpecie_ + 2; j++)
310  {
311  ddNdtByVdcTp[i][j] = 0;
312  }
313  }
314  forAll(reactions_, ri)
315  {
316  if (!mechRed_.reactionDisabled(ri))
317  {
318  reactions_[ri].ddNdtByVdcTp
319  (
320  p,
321  T,
322  c_,
323  li,
324  dYTpdt,
325  ddNdtByVdcTp,
326  reduction_,
327  cTos_,
328  0,
329  nSpecie_,
330  YTpWork_[1],
331  YTpWork_[2]
332  );
333  }
334  }
335 
336  // Reactions return dNdtByV, so we need to convert the result to dYdt
337  for (label i=0; i<nSpecie_; i++)
338  {
339  const scalar WiByrhoM = specieThermos_[sToc(i)].W()/rhoM;
340  scalar& dYidt = dYTpdt[i];
341  dYidt *= WiByrhoM;
342 
343  for (label j=0; j<nSpecie_; j++)
344  {
345  scalar ddNidtByVdYj = 0;
346  switch (jacobianType_)
347  {
348  case jacobianType::fast:
349  {
350  const scalar ddNidtByVdcj = ddNdtByVdcTp(i, j);
351  ddNidtByVdYj = ddNidtByVdcj*dcdY(j, j);
352  }
353  break;
354  case jacobianType::exact:
355  for (label k=0; k<nSpecie_; k++)
356  {
357  const scalar ddNidtByVdck = ddNdtByVdcTp(i, k);
358  ddNidtByVdYj += ddNidtByVdck*dcdY(k, j);
359  }
360  break;
361  }
362 
363  scalar& ddYidtdYj = J(i, j);
364  ddYidtdYj = WiByrhoM*ddNidtByVdYj + rhoM*v[sToc(j)]*dYidt;
365  }
366 
367  scalar ddNidtByVdT = ddNdtByVdcTp(i, nSpecie_);
368  for (label j=0; j<nSpecie_; j++)
369  {
370  const scalar ddNidtByVdcj = ddNdtByVdcTp(i, j);
371  ddNidtByVdT -= ddNidtByVdcj*c_[sToc(j)]*alphavM;
372  }
373 
374  scalar& ddYidtdT = J(i, nSpecie_);
375  ddYidtdT = WiByrhoM*ddNidtByVdT + alphavM*dYidt;
376 
377  scalar& ddYidtdp = J(i, nSpecie_ + 1);
378  ddYidtdp = 0;
379  }
380 
381  // Evaluate the effect on the thermodynamic system ...
382 
383  // Evaluate the mixture Cp and its derivative
384  scalarField& Cp = YTpWork_[3];
385  scalar CpM = 0, dCpMdT = 0;
386  for (label i=0; i<Y_.size(); i++)
387  {
388  Cp[i] = specieThermos_[i].Cp(p, T);
389  CpM += Y_[i]*Cp[i];
390  dCpMdT += Y_[i]*specieThermos_[i].dCpdT(p, T);
391  }
392 
393  // dT/dt
394  scalarField& ha = YTpWork_[4];
395  scalar& dTdt = dYTpdt[nSpecie_];
396  for (label i=0; i<nSpecie_; i++)
397  {
398  ha[sToc(i)] = specieThermos_[sToc(i)].ha(p, T);
399  dTdt -= dYTpdt[i]*ha[sToc(i)];
400  }
401  dTdt /= CpM;
402 
403  // dp/dt = 0 (pressure is assumed constant)
404  scalar& dpdt = dYTpdt[nSpecie_ + 1];
405  dpdt = 0;
406 
407  // d(dTdt)/dY
408  for (label i=0; i<nSpecie_; i++)
409  {
410  scalar& ddTdtdYi = J(nSpecie_, i);
411  ddTdtdYi = 0;
412  for (label j=0; j<nSpecie_; j++)
413  {
414  const scalar ddYjdtdYi = J(j, i);
415  ddTdtdYi -= ddYjdtdYi*ha[sToc(j)];
416  }
417  ddTdtdYi -= Cp[sToc(i)]*dTdt;
418  ddTdtdYi /= CpM;
419  }
420 
421  // d(dTdt)/dT
422  scalar& ddTdtdT = J(nSpecie_, nSpecie_);
423  ddTdtdT = 0;
424  for (label i=0; i<nSpecie_; i++)
425  {
426  const scalar dYidt = dYTpdt[i];
427  const scalar ddYidtdT = J(i, nSpecie_);
428  ddTdtdT -= dYidt*Cp[sToc(i)] + ddYidtdT*ha[sToc(i)];
429  }
430  ddTdtdT -= dTdt*dCpMdT;
431  ddTdtdT /= CpM;
432 
433  // d(dTdt)/dp = 0 (pressure is assumed constant)
434  scalar& ddTdtdp = J(nSpecie_, nSpecie_ + 1);
435  ddTdtdp = 0;
436 
437  // d(dpdt)/dYiTp = 0 (pressure is assumed constant)
438  for (label i=0; i<nSpecie_ + 2; i++)
439  {
440  scalar& ddpdtdYiTp = J(nSpecie_ + 1, i);
441  ddpdtdYiTp = 0;
442  }
443 }
444 
445 
446 template<class ThermoType>
449 (
450  const label reactioni
451 ) const
452 {
455  (
456  "RR:" + reactions_[reactioni].name(),
457  this->mesh(),
459  );
461 
462  if (!this->chemistry_ || mechRed_.reactionDisabled(reactioni))
463  {
464  return tRR;
465  }
466 
467  tmp<volScalarField> trhovf(this->thermo().rho());
468  const volScalarField& rhovf = trhovf();
469 
470  const volScalarField& Tvf = this->thermo().T();
471  const volScalarField& pvf = this->thermo().p();
472 
473  reactionEvaluationScope scope(*this);
474 
475  const Reaction<ThermoType>& R = reactions_[reactioni];
476 
477  const label nZoneCells = zone_.nCells();
478  for(label zci = 0; zci<nZoneCells; zci++)
479  {
480  const label celli = zone_.celli(zci);
481 
482  const scalar rho = rhovf[celli];
483  const scalar T = Tvf[celli];
484  const scalar p = pvf[celli];
485 
486  for (label i=0; i<nSpecie_; i++)
487  {
488  const scalar Yi = Yvf_[i][celli];
489  c_[i] = rho*Yi/specieThermos_[i].W();
490  }
491 
492  scalar omegaf, omegar;
493 
494  RR[celli] =
495  R.omega
496  (
497  p,
498  T,
499  c_,
500  celli,
501  omegaf,
502  omegar
503  );
504  }
505 
506  return tRR;
507 }
508 
509 
510 template<class ThermoType>
513 (
514  const label reactioni
515 ) const
516 {
518  for (label i=0; i<nSpecie_; i++)
519  {
520  RR.set
521  (
522  i,
524  (
525  "RR:" + reactions_[reactioni].name() + ":" + Yvf_[i].name(),
526  this->mesh(),
528  ).ptr()
529  );
530  }
531 
532  if (!this->chemistry_ || mechRed_.reactionDisabled(reactioni))
533  {
534  return RR;
535  }
536 
537  tmp<volScalarField> trhovf(this->thermo().rho());
538  const volScalarField& rhovf = trhovf();
539 
540  const volScalarField& Tvf = this->thermo().T();
541  const volScalarField& pvf = this->thermo().p();
542 
543  scalarField& dNdtByV = YTpWork_[0];
544 
545  reactionEvaluationScope scope(*this);
546 
547  const Reaction<ThermoType>& R = reactions_[reactioni];
548 
549  const label nZoneCells = zone_.nCells();
550  for(label zci = 0; zci<nZoneCells; zci++)
551  {
552  const label celli = zone_.celli(zci);
553 
554  const scalar rho = rhovf[celli];
555  const scalar T = Tvf[celli];
556  const scalar p = pvf[celli];
557 
558  for (label i=0; i<nSpecie_; i++)
559  {
560  const scalar Yi = Yvf_[i][celli];
561  c_[i] = rho*Yi/specieThermos_[i].W();
562  }
563 
564  dNdtByV = Zero;
565 
566  R.dNdtByV
567  (
568  p,
569  T,
570  c_,
571  celli,
572  dNdtByV,
573  reduction_,
574  cTos_,
575  0
576  );
577 
578  for (label i=0; i<nSpecie_; i++)
579  {
580  RR[i][celli] = dNdtByV[i]*specieThermos_[i].W();
581  }
582  }
583 
584  return RR;
585 }
586 
587 
588 template<class ThermoType>
590 {
591  if (!this->chemistry_)
592  {
593  return;
594  }
595 
596  if (!zone_.all())
597  {
598  forAll(RR_, fieldi)
599  {
600  RR_[fieldi] = Zero;
601  }
602  }
603 
604  tmp<volScalarField> trhovf(this->thermo().rho());
605  const volScalarField& rhovf = trhovf();
606 
607  const volScalarField& Tvf = this->thermo().T();
608  const volScalarField& pvf = this->thermo().p();
609 
610  scalarField& dNdtByV = YTpWork_[0];
611 
612  reactionEvaluationScope scope(*this);
613 
614  const label nZoneCells = zone_.nCells();
615  for(label zci = 0; zci<nZoneCells; zci++)
616  {
617  const label celli = zone_.celli(zci);
618 
619  const scalar rho = rhovf[celli];
620  const scalar T = Tvf[celli];
621  const scalar p = pvf[celli];
622 
623  for (label i=0; i<nSpecie_; i++)
624  {
625  const scalar Yi = Yvf_[i][celli];
626  c_[i] = rho*Yi/specieThermos_[i].W();
627  }
628 
629  dNdtByV = Zero;
630 
631  forAll(reactions_, ri)
632  {
633  if (!mechRed_.reactionDisabled(ri))
634  {
635  reactions_[ri].dNdtByV
636  (
637  p,
638  T,
639  c_,
640  celli,
641  dNdtByV,
642  reduction_,
643  cTos_,
644  0
645  );
646  }
647  }
648 
649  for (label i=0; i<mechRed_.nActiveSpecies(); i++)
650  {
651  RR_[sToc(i)][celli] = dNdtByV[i]*specieThermos_[sToc(i)].W();
652  }
653  }
654 }
655 
656 
657 template<class ThermoType>
658 template<class DeltaTType>
660 (
661  const DeltaTType& deltaT
662 )
663 {
664  optionalCpuLoad& chemistryCpuLoad
665  (
666  optionalCpuLoad::New(name() + ":cpuLoad", this->mesh(), cpuLoad_)
667  );
668 
669  // CPU time logging
670  cpuTime solveCpuTime;
671  scalar totalSolveCpuTime = 0;
672 
673  if (!this->chemistry_)
674  {
675  return great;
676  }
677 
678  if (!zone_.all())
679  {
680  forAll(RR_, fieldi)
681  {
682  RR_[fieldi] = Zero;
683  }
684  }
685 
686  const volScalarField& rho0vf =
687  this->mesh().template lookupObject<volScalarField>
688  (
689  this->thermo().phasePropertyName("rho")
690  ).oldTime();
691 
692  const volScalarField& T0vf = this->thermo().T().oldTime();
693  const volScalarField& p0vf = this->thermo().p().oldTime();
694 
695  reactionEvaluationScope scope(*this);
696 
697  scalarField Y0(nSpecie_);
698 
699  // Composition vector (Yi, T, p, deltaT)
700  scalarField phiq(nEqns() + 1);
701  scalarField Rphiq(nEqns() + 1);
702 
703  // Minimum chemical timestep
704  scalar deltaTMin = great;
705 
706  tabulation_.reset();
707  chemistryCpuLoad.resetCpuTime();
708 
709  zone_.regenerate();
710  const label nZoneCells = zone_.nCells();
711  for(label zci = 0; zci<nZoneCells; zci++)
712  {
713  const label celli = zone_.celli(zci);
714 
715  const scalar rho0 = rho0vf[celli];
716 
717  scalar p = p0vf[celli];
718  scalar T = T0vf[celli];
719 
720  for (label i=0; i<nSpecie_; i++)
721  {
722  Y_[i] = Y0[i] = Yvf_[i].oldTime()[celli];
723  }
724 
725  for (label i=0; i<nSpecie_; i++)
726  {
727  phiq[i] = Yvf_[i].oldTime()[celli];
728  }
729  phiq[nSpecie()] = T;
730  phiq[nSpecie() + 1] = p;
731  phiq[nSpecie() + 2] = deltaT[celli];
732 
733  // Initialise time progress
734  scalar timeLeft = deltaT[celli];
735 
736  // Not sure if this is necessary
737  Rphiq = Zero;
738 
739  // When tabulation is active (short-circuit evaluation for retrieve)
740  // It first tries to retrieve the solution of the system with the
741  // information stored through the tabulation method
742  if (tabulation_.retrieve(phiq, Rphiq))
743  {
744  // Retrieved solution stored in Rphiq
745  for (label i=0; i<nSpecie(); i++)
746  {
747  Y_[i] = Rphiq[i];
748  }
749  T = Rphiq[nSpecie()];
750  p = Rphiq[nSpecie() + 1];
751  }
752  // This position is reached when tabulation is not used OR
753  // if the solution is not retrieved.
754  // In the latter case, it adds the information to the tabulation
755  // (it will either expand the current data or add a new stored point).
756  else
757  {
758  if (reduction_)
759  {
760  // Compute concentrations
761  for (label i=0; i<nSpecie_; i++)
762  {
763  c_[i] = rho0*Y_[i]/specieThermos_[i].W();
764  }
765 
766  // Reduce mechanism change the number of species (only active)
767  mechRed_.reduceMechanism(p, T, c_, cTos_, sToc_, celli);
768 
769  // Set the simplified mass fraction field
770  sY_.setSize(nSpecie_);
771  for (label i=0; i<nSpecie_; i++)
772  {
773  sY_[i] = Y_[sToc(i)];
774  }
775  }
776 
777  if (log_)
778  {
779  // Reset the solve time
780  solveCpuTime.cpuTimeIncrement();
781  }
782 
783  // Calculate the chemical source terms
784  while (timeLeft > small)
785  {
786  scalar dt = timeLeft;
787  if (reduction_)
788  {
789  // Solve the reduced set of ODE
790  solve
791  (
792  p,
793  T,
794  sY_,
795  celli,
796  dt,
797  deltaTChem_[celli]
798  );
799 
800  for (label i=0; i<mechRed_.nActiveSpecies(); i++)
801  {
802  Y_[sToc_[i]] = sY_[i];
803  }
804  }
805  else
806  {
807  solve(p, T, Y_, celli, dt, deltaTChem_[celli]);
808  }
809  timeLeft -= dt;
810  }
811 
812  if (log_)
813  {
814  totalSolveCpuTime += solveCpuTime.cpuTimeIncrement();
815  }
816 
817  // If tabulation is used, we add the information computed here to
818  // the stored points (either expand or add)
819  if (tabulation_.tabulates())
820  {
821  forAll(Y_, i)
822  {
823  Rphiq[i] = Y_[i];
824  }
825  Rphiq[Rphiq.size()-3] = T;
826  Rphiq[Rphiq.size()-2] = p;
827  Rphiq[Rphiq.size()-1] = deltaT[celli];
828 
829  tabulation_.add
830  (
831  phiq,
832  Rphiq,
833  mechRed_.nActiveSpecies(),
834  celli,
835  deltaT[celli]
836  );
837  }
838 
839  // When operations are done and if mechanism reduction is active,
840  // the number of species (which also affects nEqns) is set back
841  // to the total number of species (stored in the mechRed object)
842  if (reduction_)
843  {
844  setNSpecie(mechRed_.nSpecie());
845  }
846 
847  deltaTMin = min(deltaTChem_[celli], deltaTMin);
848  deltaTChem_[celli] = min(deltaTChem_[celli], deltaTChemMax_);
849  }
850 
851  // Set the RR vector (used in the solver)
852  for (label i=0; i<nSpecie_; i++)
853  {
854  RR_[i][celli] = rho0*(Y_[i] - Y0[i])/deltaT[celli];
855  }
856 
857  if (cpuLoad_)
858  {
859  chemistryCpuLoad.cpuTimeIncrement(celli);
860  }
861  }
862 
863  if (log_)
864  {
865  cpuSolveFile_()
866  << this->time().userTimeValue()
867  << " " << totalSolveCpuTime << endl;
868  }
869 
870  mechRed_.update();
871  tabulation_.update();
872 
873  if (reduction_)
874  {
875  this->thermo().syncSpeciesActive();
876  }
877 
878  return deltaTMin;
879 }
880 
881 
882 template<class ThermoType>
884 (
885  const scalar deltaT
886 )
887 {
888  // Don't allow the time-step to change more than a factor of 2
889  return min
890  (
892  2*deltaT
893  );
894 }
895 
896 
897 template<class ThermoType>
899 (
900  const scalarField& deltaT
901 )
902 {
903  return this->solve<scalarField>(deltaT);
904 }
905 
906 
907 template<class ThermoType>
910 {
912  (
914  (
915  "tc",
916  this->mesh(),
917  dimensionedScalar(dimTime, small),
919  )
920  );
921  scalarField& tc = ttc.ref();
922 
923  if (!this->chemistry_)
924  {
925  ttc.ref().correctBoundaryConditions();
926  return ttc;
927  }
928 
929  tmp<volScalarField> trhovf(this->thermo().rho());
930  const volScalarField& rhovf = trhovf();
931 
932  const volScalarField& Tvf = this->thermo().T();
933  const volScalarField& pvf = this->thermo().p();
934 
935  reactionEvaluationScope scope(*this);
936 
937  const label nZoneCells = zone_.nCells();
938  for(label zci = 0; zci<nZoneCells; zci++)
939  {
940  const label celli = zone_.celli(zci);
941 
942  const scalar rho = rhovf[celli];
943  const scalar T = Tvf[celli];
944  const scalar p = pvf[celli];
945 
946  for (label i=0; i<nSpecie_; i++)
947  {
948  c_[i] = rho*Yvf_[i][celli]/specieThermos_[i].W();
949  }
950 
951  // A reaction's rate scale is calculated as its molar
952  // production rate divided by the total number of moles in the
953  // system.
954  //
955  // The system rate scale is the average of the reactions' rate
956  // scales weighted by the reactions' molar production rates. This
957  // weighting ensures that dominant reactions provide the largest
958  // contribution to the system rate scale.
959  //
960  // The system time scale is then the reciprocal of the system rate
961  // scale.
962  //
963  // Contributions from forward and reverse reaction rates are
964  // handled independently and identically so that reversible
965  // reactions produce the same result as the equivalent pair of
966  // irreversible reactions.
967 
968  scalar sumW = 0, sumWRateByCTot = 0;
969  forAll(reactions_, i)
970  {
971  const Reaction<ThermoType>& R = reactions_[i];
972  scalar omegaf, omegar;
973  R.omega(p, T, c_, celli, omegaf, omegar);
974 
975  scalar wf = 0;
976  forAll(R.rhs(), s)
977  {
978  wf += R.rhs()[s].stoichCoeff*omegaf;
979  }
980  sumW += wf;
981  sumWRateByCTot += sqr(wf);
982 
983  scalar wr = 0;
984  forAll(R.lhs(), s)
985  {
986  wr += R.lhs()[s].stoichCoeff*omegar;
987  }
988  sumW += wr;
989  sumWRateByCTot += sqr(wr);
990  }
991 
992  tc[celli] =
993  sumWRateByCTot == 0 ? vGreat : sumW/sumWRateByCTot*sum(c_);
994  }
995 
996  ttc.ref().correctBoundaryConditions();
997  return ttc;
998 }
999 
1000 
1001 template<class ThermoType>
1004 {
1005  tmp<volScalarField> tQdot
1006  (
1008  (
1009  "Qdot",
1010  this->mesh_,
1012  )
1013  );
1014 
1015  if (!this->chemistry_)
1016  {
1017  return tQdot;
1018  }
1019 
1020  reactionEvaluationScope scope(*this);
1021 
1022  scalarField& Qdot = tQdot.ref();
1023 
1024  forAll(Yvf_, i)
1025  {
1026  const label nZoneCells = zone_.nCells();
1027  for(label zci = 0; zci<nZoneCells; zci++)
1028  {
1029  const label celli = zone_.celli(zci);
1030 
1031  const scalar hi = specieThermos_[i].hf();
1032  Qdot[celli] -= hi*RR_[i][celli];
1033  }
1034  }
1035 
1036  return tQdot;
1037 }
1038 
1039 
1040 template<class ThermoType>
1042 (
1043  scalar& p,
1044  scalar& T,
1045  scalarField& c,
1046  const label li,
1047  scalar& deltaT,
1048  scalar& subDeltaT
1049 ) const
1050 {
1051  // Reset the size of the ODE system to the simplified size when mechanism
1052  // reduction is active
1053  if (odeSolver_->resize())
1054  {
1055  odeSolver_->resizeField(cTp_);
1056  }
1057 
1058  const label nSpecie = this->nSpecie();
1059 
1060  // Copy the concentration, T and P to the total solve-vector
1061  for (int i=0; i<nSpecie; i++)
1062  {
1063  cTp_[i] = c[i];
1064  }
1065  cTp_[nSpecie] = T;
1066  cTp_[nSpecie+1] = p;
1067 
1068  if (debug)
1069  {
1070  scalarField dcTp(this->nEqns(), rootSmall);
1071  dcTp[nSpecie] = T*rootSmall;
1072  dcTp[nSpecie+1] = p*rootSmall;
1073  this->check(0, cTp_, dcTp, li);
1074  }
1075 
1076  odeSolver_->solve(0, deltaT, cTp_, li, subDeltaT);
1077 
1078  for (int i=0; i<nSpecie; i++)
1079  {
1080  c[i] = max(0.0, cTp_[i]);
1081  }
1082  T = cTp_[nSpecie];
1083  p = cTp_[nSpecie+1];
1084 }
1085 
1086 
1087 // ************************************************************************* //
scalar Cp(const scalar p, const scalar T) const
Definition: EtoHthermo.H:2
scalar ha(const scalar p, const scalar T) const
Definition: EtoHthermo.H:20
label k
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
static tmp< DimensionedField< Type, GeoMesh, PrimitiveField > > New(const word &name, const GeoMesh &mesh, const dimensionSet &, const PrimitiveField< Type > &)
Return a temporary field constructed from name, mesh,.
Generic GeometricField class.
static tmp< GeometricField< Type, GeoMesh, PrimitiveField > > New(const word &name, const Internal &, const PtrList< Patch > &, const HashPtrTable< Source > &=HashPtrTable< Source >())
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:315
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
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
A class representing the concept of a uniform field which stores only the single value and providing ...
Definition: UniformField.H:48
virtual const fvMesh & mesh() const =0
Return const access to the mesh.
const fluidMulticomponentThermo & thermo() const
Return const access to the thermo.
const fvMesh & mesh() const
Return const access to the mesh.
Extension to Foam::chemistryModels::standard templated on thermo and provides stiff ODE integration f...
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 tmp< volScalarField::Internal > reactionRR(const label reactioni) const
Return the rate of reactioni [kmol/m^3/s].
Standard(const fluidMulticomponentThermo &thermo)
Construct from thermo.
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 PtrList< volScalarField::Internal > specieReactionRR(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.
Non-templated Base class for Foam::chemistryModels::Standard.
jacobianType
Enumeration for the type of Jacobian to be calculated by the.
autoPtr< OFstream > logFile(const word &name) const
Create and return a TDAC log file of the given name.
const PtrList< volScalarField > & Yvf_
Reference to the field of specie mass fractions.
bool reduction_
Is chemistry reduction active.
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:111
Base-class for multi-component fluid thermodynamic properties.
Foam::multicomponentMixture.
void setSpecieInactive(const label speciei) const
Set specie inactive.
virtual void syncSpeciesActive() const =0
Synchronise the specie active flags.
virtual void resetCpuTime()
Reset the CPU time (dummy)
Definition: cpuLoad.H:101
virtual void cpuTimeIncrement(const label celli)
Cache the CPU time increment for celli (dummy)
Definition: cpuLoad.H:105
static optionalCpuLoad & New(const word &name, const polyMesh &mesh, const bool loadBalancing)
Construct from polyMesh if loadBalancing is true.
Definition: cpuLoad.C:63
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:197
Templated form of IOobject providing type information for file reading and header type checking.
Definition: IOobject.H:545
bool headerOk()
Read header (uses typeGlobalFile to find file) and check.
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
rho
Definition: pEqn.H:1
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
const dimensionedScalar RR
Universal gas constant: default SI units: [J/kmol/K].
const dimensionedScalar c
Speed of light in a vacuum.
const dimensionSet time
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
const dimensionSet & dimMoles
Definition: dimensions.C:144
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 & dimMass
Definition: dimensions.C:140
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
messageStream Info
const dimensionSet & dimVolume
Definition: dimensions.C:150
To & dynamicCast(From &r)
Reference type cast template function,.
Definition: typeInfo.H:98
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
const dimensionSet & dimTime
Definition: dimensions.C:142
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
static scalar R(const scalar a, const scalar x)
Definition: invIncGamma.C:102
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
const dimensionSet & dimEnergy
Definition: dimensions.C:160
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
void T(GeometricField< Type, GeoMesh, PrimitiveField1 > &gf, const GeometricField< Type, GeoMesh, PrimitiveField2 > &gf1)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
SolverPerformance< Type > solve(fvMatrix< Type > &, const word &)
Solve returning the solution statistics given convergence tolerance.
scalar Qdot
Definition: solveChemistry.H:2
scalar rho0
volScalarField & p
const label nSpecie
scalarList Y0(nSpecie, 0.0)
fluidMulticomponentThermo & thermo
Definition: createFields.H:15