ReactingParcel.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ReactingParcel.H"
29 #include "specie.H"
30 #include "CompositionModel.H"
31 #include "PhaseChangeModel.H"
32 #include "mathematicalConstants.H"
33 
34 using namespace Foam::constant::mathematical;
35 
36 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
37 
38 template<class ParcelType>
39 template<class TrackCloudType>
41 (
42  TrackCloudType& cloud,
43  trackingData& td,
44  const scalar dt,
45  const scalar Re,
46  const scalar Pr,
47  const scalar Ts,
48  const scalar nus,
49  const scalar d,
50  const scalar T,
51  const scalar mass,
52  const label idPhase,
53  const scalar YPhase,
54  const scalarField& Y,
55  scalarField& dMassPC,
56  scalar& Sh,
57  scalar& N,
58  scalar& NCpW,
60 )
61 {
62  const auto& composition = cloud.composition();
63  auto& phaseChange = cloud.phaseChange();
64 
65  if (!phaseChange.active() || (YPhase < SMALL))
66  {
67  return;
68  }
69 
70  scalarField X(composition.liquids().X(Y));
71 
72  scalar Tvap = phaseChange.Tvap(X);
73 
74  if (T < Tvap)
75  {
76  return;
77  }
78 
79  const scalar TMax = phaseChange.TMax(td.pc(), X);
80  const scalar Tdash = min(T, TMax);
81  const scalar Tsdash = min(Ts, TMax);
82 
83  // Calculate mass transfer due to phase change
84  phaseChange.calculate
85  (
86  dt,
87  this->cell(),
88  Re,
89  Pr,
90  d,
91  nus,
92  Tdash,
93  Tsdash,
94  td.pc(),
95  td.Tc(),
96  X,
97  dMassPC
98  );
99 
100  // Limit phase change mass by availability of each specie
101  dMassPC = min(mass*YPhase*Y, dMassPC);
102 
103  const scalar dMassTot = sum(dMassPC);
104 
105  // Add to cumulative phase change mass
106  phaseChange.addToPhaseChangeMass(this->nParticle_*dMassTot);
107 
108  forAll(dMassPC, i)
109  {
110  const label cid = composition.localToCarrierId(idPhase, i);
111 
112  const scalar dh = phaseChange.dh(cid, i, td.pc(), Tdash);
113  Sh -= dMassPC[i]*dh/dt;
114  }
115 
116 
117  // Update molar emissions
118  if (cloud.heatTransfer().BirdCorrection())
119  {
120  // Average molecular weight of carrier mix - assumes perfect gas
121  const scalar Wc = td.rhoc()*RR*td.Tc()/td.pc();
122 
123  forAll(dMassPC, i)
124  {
125  const label cid = composition.localToCarrierId(idPhase, i);
126 
127  const scalar Cp = composition.carrier().Cp(cid, td.pc(), Tsdash);
128  const scalar W = composition.carrier().W(cid);
129  const scalar Ni = dMassPC[i]/(this->areaS(d)*dt*W);
130 
131  const scalar Dab =
132  composition.liquids().properties()[i].D(td.pc(), Tsdash, Wc);
133 
134  // Molar flux of species coming from the particle (kmol/m^2/s)
135  N += Ni;
136 
137  // Sum of Ni*Cpi*Wi of emission species
138  NCpW += Ni*Cp*W;
139 
140  // Concentrations of emission species
141  Cs[cid] += Ni*d/(2.0*Dab);
142  }
143  }
144 }
145 
146 
147 template<class ParcelType>
149 (
150  const scalar mass0,
151  const scalarField& dMass,
152  scalarField& Y
153 ) const
154 {
155  scalar mass1 = mass0 - sum(dMass);
156 
157  // only update the mass fractions if the new particle mass is finite
158  if (mass1 > ROOTVSMALL)
159  {
160  forAll(Y, i)
161  {
162  Y[i] = (Y[i]*mass0 - dMass[i])/mass1;
163  }
164  }
165 
166  return mass1;
167 }
168 
169 
170 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
171 
172 template<class ParcelType>
174 (
176 )
177 :
178  ParcelType(p),
179  mass0_(p.mass0_),
180  Y_(p.Y_)
181 {}
182 
183 
184 template<class ParcelType>
186 (
187  const ReactingParcel<ParcelType>& p,
188  const polyMesh& mesh
189 )
190 :
191  ParcelType(p, mesh),
192  mass0_(p.mass0_),
193  Y_(p.Y_)
194 {}
195 
196 
197 // * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * * //
198 
199 template<class ParcelType>
200 template<class TrackCloudType>
202 (
203  TrackCloudType& cloud,
204  trackingData& td
205 )
206 {
207  ParcelType::setCellValues(cloud, td);
208 
209  td.pc() = td.pInterp().interpolate
210  (
211  this->coordinates(),
212  this->currentTetIndices()
213  );
214 
215  if (td.pc() < cloud.constProps().pMin())
216  {
217  if (debug)
218  {
220  << "Limiting observed pressure in cell " << this->cell()
221  << " to " << cloud.constProps().pMin() << nl << endl;
222  }
223 
224  td.pc() = cloud.constProps().pMin();
225  }
226 }
227 
228 
229 template<class ParcelType>
230 template<class TrackCloudType>
232 (
233  TrackCloudType& cloud,
234  trackingData& td,
235  const scalar dt
236 )
237 {
238  scalar addedMass = 0.0;
239  scalar maxMassI = 0.0;
240  forAll(cloud.rhoTrans(), i)
241  {
242  scalar dm = cloud.rhoTrans(i)[this->cell()];
243  maxMassI = max(maxMassI, mag(dm));
244  addedMass += dm;
245  }
246 
247  if (maxMassI < ROOTVSMALL)
248  {
249  return;
250  }
251 
252  const scalar massCell = this->massCell(td);
253 
254  td.rhoc() += addedMass/cloud.pMesh().cellVolumes()[this->cell()];
255 
256  const scalar massCellNew = massCell + addedMass;
257  td.Uc() = (td.Uc()*massCell + cloud.UTrans()[this->cell()])/massCellNew;
258 
259  scalar CpEff = 0.0;
260  forAll(cloud.rhoTrans(), i)
261  {
262  scalar Y = cloud.rhoTrans(i)[this->cell()]/addedMass;
263  CpEff += Y*cloud.composition().carrier().Cp(i, td.pc(), td.Tc());
264  }
265 
266  const scalar Cpc = td.CpInterp().psi()[this->cell()];
267  td.Cpc() = (massCell*Cpc + addedMass*CpEff)/massCellNew;
268 
269  td.Tc() += cloud.hsTrans()[this->cell()]/(td.Cpc()*massCellNew);
270 
271  if (td.Tc() < cloud.constProps().TMin())
272  {
273  if (debug)
274  {
276  << "Limiting observed temperature in cell " << this->cell()
277  << " to " << cloud.constProps().TMin() << nl << endl;
278  }
279 
280  td.Tc() = cloud.constProps().TMin();
281  }
282 }
283 
284 
285 template<class ParcelType>
286 template<class TrackCloudType>
288 (
289  TrackCloudType& cloud,
290  trackingData& td,
291  const scalar T,
292  const scalarField& Cs,
293  scalar& rhos,
294  scalar& mus,
295  scalar& Prs,
296  scalar& kappas
297 )
298 {
299  // No correction if total concentration of emitted species is small
300  if (!cloud.heatTransfer().BirdCorrection() || (sum(Cs) < SMALL))
301  {
302  return;
303  }
304 
305  const SLGThermo& thermo = cloud.thermo();
306 
307  // Far field carrier molar fractions
308  scalarField Xinf(thermo.carrier().species().size());
309 
310  forAll(Xinf, i)
311  {
312  Xinf[i] = thermo.carrier().Y(i)[this->cell()]/thermo.carrier().W(i);
313  }
314  Xinf /= sum(Xinf);
315 
316  // Molar fraction of far field species at particle surface
317  const scalar Xsff = 1.0 - min(sum(Cs)*RR*this->T_/td.pc(), 1.0);
318 
319  // Surface carrier total molar concentration
320  const scalar CsTot = td.pc()/(RR*this->T_);
321 
322  // Surface carrier composition (molar fraction)
323  scalarField Xs(Xinf.size());
324 
325  // Surface carrier composition (mass fraction)
326  scalarField Ys(Xinf.size());
327 
328  forAll(Xs, i)
329  {
330  // Molar concentration of species at particle surface
331  const scalar Csi = Cs[i] + Xsff*Xinf[i]*CsTot;
332 
333  Xs[i] = (2.0*Csi + Xinf[i]*CsTot)/3.0;
334  Ys[i] = Xs[i]*thermo.carrier().W(i);
335  }
336  Xs /= sum(Xs);
337  Ys /= sum(Ys);
338 
339 
340  rhos = 0;
341  mus = 0;
342  kappas = 0;
343  scalar Cps = 0;
344  scalar sumYiSqrtW = 0;
345  scalar sumYiCbrtW = 0;
346 
347  forAll(Ys, i)
348  {
349  const scalar W = thermo.carrier().W(i);
350  const scalar sqrtW = sqrt(W);
351  const scalar cbrtW = cbrt(W);
352 
353  rhos += Xs[i]*W;
354  mus += Ys[i]*sqrtW*thermo.carrier().mu(i, td.pc(), T);
355  kappas += Ys[i]*cbrtW*thermo.carrier().kappa(i, td.pc(), T);
356  Cps += Xs[i]*thermo.carrier().Cp(i, td.pc(), T);
357 
358  sumYiSqrtW += Ys[i]*sqrtW;
359  sumYiCbrtW += Ys[i]*cbrtW;
360  }
361 
362  Cps = max(Cps, ROOTVSMALL);
363 
364  rhos *= td.pc()/(RR*T);
365  rhos = max(rhos, ROOTVSMALL);
366 
367  mus /= sumYiSqrtW;
368  mus = max(mus, ROOTVSMALL);
369 
370  kappas /= sumYiCbrtW;
371  kappas = max(kappas, ROOTVSMALL);
372 
373  Prs = Cps*mus/kappas;
374 }
375 
376 
377 template<class ParcelType>
378 template<class TrackCloudType>
380 (
381  TrackCloudType& cloud,
382  trackingData& td,
383  const scalar dt
384 )
385 {
386  const auto& composition = cloud.composition();
387 
388 
389  // Define local properties at beginning of time step
390  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
391 
392  const scalar np0 = this->nParticle_;
393  const scalar d0 = this->d_;
394  const vector& U0 = this->U_;
395  const scalar T0 = this->T_;
396  const scalar mass0 = this->mass();
397 
398 
399  // Calc surface values
400  scalar Ts, rhos, mus, Prs, kappas;
401  this->calcSurfaceValues(cloud, td, T0, Ts, rhos, mus, Prs, kappas);
402  scalar Res = this->Re(rhos, U0, td.Uc(), d0, mus);
403 
404 
405  // Sources
406  // ~~~~~~~
407 
408  // Explicit momentum source for particle
409  vector Su = Zero;
410 
411  // Linearised momentum source coefficient
412  scalar Spu = 0.0;
413 
414  // Momentum transfer from the particle to the carrier phase
415  vector dUTrans = Zero;
416 
417  // Explicit enthalpy source for particle
418  scalar Sh = 0.0;
419 
420  // Linearised enthalpy source coefficient
421  scalar Sph = 0.0;
422 
423  // Sensible enthalpy transfer from the particle to the carrier phase
424  scalar dhsTrans = 0.0;
425 
426 
427  // 1. Compute models that contribute to mass transfer - U, T held constant
428  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
429 
430  // Phase change
431  // ~~~~~~~~~~~~
432 
433  // Mass transfer due to phase change
434  scalarField dMassPC(Y_.size(), Zero);
435 
436  // Molar flux of species emitted from the particle (kmol/m^2/s)
437  scalar Ne = 0.0;
438 
439  // Sum Ni*Cpi*Wi of emission species
440  scalar NCpW = 0.0;
441 
442  // Surface concentrations of emitted species
443  scalarField Cs(composition.carrier().species().size(), Zero);
444 
445  // Calc mass and enthalpy transfer due to phase change
446  calcPhaseChange
447  (
448  cloud,
449  td,
450  dt,
451  Res,
452  Prs,
453  Ts,
454  mus/rhos,
455  d0,
456  T0,
457  mass0,
458  0,
459  1.0,
460  Y_,
461  dMassPC,
462  Sh,
463  Ne,
464  NCpW,
465  Cs
466  );
467 
468 
469  // 2. Update the parcel properties due to change in mass
470  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
471 
472  scalarField dMass(dMassPC);
473  scalar mass1 = updateMassFraction(mass0, dMass, Y_);
474 
475  this->Cp_ = composition.Cp(0, Y_, td.pc(), T0);
476 
477  // Update particle density or diameter
478  if (cloud.constProps().constantVolume())
479  {
480  this->rho_ = mass1/this->volume();
481  }
482  else
483  {
484  this->d_ = cbrt(mass1/this->rho_*6.0/pi);
485  }
486 
487  // Remove the particle when mass falls below minimum threshold
488  if (np0*mass1 < cloud.constProps().minParcelMass())
489  {
490  td.keepParticle = false;
491 
492  if (cloud.solution().coupled())
493  {
494  scalar dm = np0*mass0;
495 
496  // Absorb parcel into carrier phase
497  forAll(Y_, i)
498  {
499  scalar dmi = dm*Y_[i];
500  label gid = composition.localToCarrierId(0, i);
501  scalar hs = composition.carrier().Hs(gid, td.pc(), T0);
502 
503  cloud.rhoTrans(gid)[this->cell()] += dmi;
504  cloud.hsTrans()[this->cell()] += dmi*hs;
505  }
506  cloud.UTrans()[this->cell()] += dm*U0;
507 
508  cloud.phaseChange().addToPhaseChangeMass(np0*mass1);
509  }
510 
511  return;
512  }
513 
514  // Correct surface values due to emitted species
515  correctSurfaceValues(cloud, td, Ts, Cs, rhos, mus, Prs, kappas);
516  Res = this->Re(rhos, U0, td.Uc(), this->d(), mus);
517 
518 
519  // 3. Compute heat- and momentum transfers
520  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
521 
522  // Heat transfer
523  // ~~~~~~~~~~~~~
524 
525  // Calculate new particle temperature
526  this->T_ =
527  this->calcHeatTransfer
528  (
529  cloud,
530  td,
531  dt,
532  Res,
533  Prs,
534  kappas,
535  NCpW,
536  Sh,
537  dhsTrans,
538  Sph
539  );
540 
541  this->Cp_ = composition.Cp(0, Y_, td.pc(), T0);
542 
543 
544  // Motion
545  // ~~~~~~
546 
547  // Calculate new particle velocity
548  this->U_ =
549  this->calcVelocity(cloud, td, dt, Res, mus, mass1, Su, dUTrans, Spu);
550 
551 
552  // 4. Accumulate carrier phase source terms
553  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
554 
555  if (cloud.solution().coupled())
556  {
557  // Transfer mass lost to carrier mass, momentum and enthalpy sources
558  forAll(dMass, i)
559  {
560  scalar dm = np0*dMass[i];
561  label gid = composition.localToCarrierId(0, i);
562  scalar hs = composition.carrier().Hs(gid, td.pc(), T0);
563 
564  cloud.rhoTrans(gid)[this->cell()] += dm;
565  cloud.UTrans()[this->cell()] += dm*U0;
566  cloud.hsTrans()[this->cell()] += dm*hs;
567  }
568 
569  // Update momentum transfer
570  cloud.UTrans()[this->cell()] += np0*dUTrans;
571  cloud.UCoeff()[this->cell()] += np0*Spu;
572 
573  // Update sensible enthalpy transfer
574  cloud.hsTrans()[this->cell()] += np0*dhsTrans;
575  cloud.hsCoeff()[this->cell()] += np0*Sph;
576 
577  // Update radiation fields
578  if (cloud.radiation())
579  {
580  const scalar ap = this->areaP();
581  const scalar T4 = pow4(T0);
582  cloud.radAreaP()[this->cell()] += dt*np0*ap;
583  cloud.radT4()[this->cell()] += dt*np0*T4;
584  cloud.radAreaPT4()[this->cell()] += dt*np0*ap*T4;
585  }
586  }
587 }
588 
589 
590 // * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * * * //
591 
592 #include "ReactingParcelIO.C"
593 
594 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::constant::thermodynamic::RR
const scalar RR
Universal gas constant: default in [J/(kmol K)].
Definition: thermodynamicConstants.C:46
ReactingParcel.H
mathematicalConstants.H
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::ReactingParcel::trackingData::pInterp
const interpolation< scalar > & pInterp() const
Return const access to the interpolator for continuous phase.
Definition: ReactingParcelTrackingDataI.H:51
Foam::SLGThermo
Thermo package for (S)olids (L)iquids and (G)ases Takes reference to thermo package,...
Definition: SLGThermo.H:64
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::basicMultiComponentMixture::species
const speciesTable & species() const
Return the table of species.
Definition: basicMultiComponentMixtureI.H:29
thermo
Basic thermodynamics type based on the use of fitting functions for cp, h, s obtained from the templa...
Foam::ReactingParcel::calc
void calc(TrackCloudType &cloud, trackingData &td, const scalar dt)
Update parcel properties over the time interval.
Definition: ReactingParcel.C:380
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::fieldTypes::volume
const wordList volume
Standard volume field types (scalar, vector, tensor, etc)
PhaseChangeModel.H
ReactingParcelIO.C
specie.H
composition
basicSpecieMixture & composition
Definition: createFieldRefs.H:6
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::ReactingParcel::trackingData::pc
scalar pc() const
Return the continuous phase pressure.
Definition: ReactingParcelTrackingDataI.H:58
Foam::basicSpecieMixture::Hs
virtual scalar Hs(const label speciei, const scalar p, const scalar T) const =0
Sensible enthalpy [J/kg].
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Su
zeroField Su
Definition: alphaSuSp.H:1
Foam::ReactingParcel::calcPhaseChange
void calcPhaseChange(TrackCloudType &cloud, trackingData &td, const scalar dt, const scalar Re, const scalar Pr, const scalar Ts, const scalar nus, const scalar d, const scalar T, const scalar mass, const label idPhase, const scalar YPhase, const scalarField &YComponents, scalarField &dMassPC, scalar &Sh, scalar &N, scalar &NCpW, scalarField &Cs)
Calculate Phase change.
Definition: ReactingParcel.C:41
Foam::pow4
dimensionedScalar pow4(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:100
Foam::Field< scalar >
Foam::ReactingParcel::setCellValues
void setCellValues(TrackCloudType &cloud, trackingData &td)
Set cell values.
Definition: ReactingParcel.C:202
coordinates
PtrList< coordinateSystem > coordinates(solidRegions.size())
Pr
dimensionedScalar Pr("Pr", dimless, laminarTransport)
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:58
Foam::ReactingParcel::trackingData
Definition: ReactingParcel.H:119
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::ReactingParcel::ReactingParcel
ReactingParcel(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label tetFacei, const label tetPti)
Construct from mesh, coordinates and topology.
Definition: ReactingParcelI.H:67
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::ReactingParcel::cellValueSourceCorrection
void cellValueSourceCorrection(TrackCloudType &cloud, trackingData &td, const scalar dt)
Correct cell values using latest transfer information.
Definition: ReactingParcel.C:232
Y
PtrList< volScalarField > & Y
Definition: createFieldRefs.H:7
Foam::cloud
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:57
Foam::constant::mathematical
Mathematical constants.
Foam::constant::mathematical::pi
constexpr scalar pi(M_PI)
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Vector< scalar >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
CompositionModel.H
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::Re
scalarField Re(const UList< complex > &cf)
Extract real component.
Definition: complexField.C:159
Cp
const volScalarField & Cp
Definition: EEqn.H:7
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
Cs
const scalarField & Cs
Definition: solveBulkSurfactant.H:10
N
const Vector< label > N(dict.get< Vector< label >>("N"))
Foam::ReactingParcel::correctSurfaceValues
void correctSurfaceValues(TrackCloudType &cloud, trackingData &td, const scalar T, const scalarField &Cs, scalar &rhos, scalar &mus, scalar &Prs, scalar &kappas)
Correct surface values due to emitted species.
Definition: ReactingParcel.C:288
Foam::cbrt
dimensionedScalar cbrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:155
Foam::interpolation::interpolate
virtual Type interpolate(const vector &position, const label celli, const label facei=-1) const =0
Interpolate field to the given point in the given cell.
Foam::ReactingParcel
Reacting parcel class with one/two-way coupling with the continuous phase.
Definition: ReactingParcel.H:56
T0
scalar T0
Definition: createFields.H:22
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:298
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::ReactingParcel::updateMassFraction
scalar updateMassFraction(const scalar mass0, const scalarField &dMass, scalarField &Y) const
Update mass fraction.
Definition: ReactingParcel.C:149
Foam::basicSpecieMixture::Cp
virtual scalar Cp(const label speciei, const scalar p, const scalar T) const =0
Heat capacity at constant pressure [J/(kg K)].