SprayParcel.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 | Copyright (C) 2011-2015 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 "SprayParcel.H"
27 #include "BreakupModel.H"
28 #include "CompositionModel.H"
29 #include "AtomizationModel.H"
30 
31 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
32 
33 template<class ParcelType>
34 template<class TrackData>
36 (
37  TrackData& td,
38  const scalar dt,
39  const label cellI
40 )
41 {
42  ParcelType::setCellValues(td, dt, cellI);
43 }
44 
45 
46 template<class ParcelType>
47 template<class TrackData>
49 (
50  TrackData& td,
51  const scalar dt,
52  const label cellI
53 )
54 {
55  ParcelType::cellValueSourceCorrection(td, dt, cellI);
56 }
57 
58 
59 template<class ParcelType>
60 template<class TrackData>
62 (
63  TrackData& td,
64  const scalar dt,
65  const label cellI
66 )
67 {
68  typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
70  td.cloud().composition();
71 
72  // Check if parcel belongs to liquid core
73  if (liquidCore() > 0.5)
74  {
75  // Liquid core parcels should not experience coupled forces
76  td.cloud().forces().setCalcCoupled(false);
77  }
78 
79  // Get old mixture composition
80  scalarField X0(composition.liquids().X(this->Y()));
81 
82  // Check if we have critical or boiling conditions
83  scalar TMax = composition.liquids().Tc(X0);
84  const scalar T0 = this->T();
85  const scalar pc0 = this->pc_;
86  if (composition.liquids().pv(pc0, T0, X0) >= pc0*0.999)
87  {
88  // Set TMax to boiling temperature
89  TMax = composition.liquids().pvInvert(pc0, X0);
90  }
91 
92  // Set the maximum temperature limit
93  td.cloud().constProps().setTMax(TMax);
94 
95  // Store the parcel properties
96  this->Cp() = composition.liquids().Cp(pc0, T0, X0);
97  sigma_ = composition.liquids().sigma(pc0, T0, X0);
98  const scalar rho0 = composition.liquids().rho(pc0, T0, X0);
99  this->rho() = rho0;
100  const scalar mass0 = this->mass();
101  mu_ = composition.liquids().mu(pc0, T0, X0);
102 
103  ParcelType::calc(td, dt, cellI);
104 
105  if (td.keepParticle)
106  {
107  // Reduce the stripped parcel mass due to evaporation
108  // assuming the number of particles remains unchanged
109  this->ms() -= this->ms()*(mass0 - this->mass())/mass0;
110 
111  // Update Cp, sigma, density and diameter due to change in temperature
112  // and/or composition
113  scalar T1 = this->T();
114  scalarField X1(composition.liquids().X(this->Y()));
115 
116  this->Cp() = composition.liquids().Cp(this->pc_, T1, X1);
117 
118  sigma_ = composition.liquids().sigma(this->pc_, T1, X1);
119 
120  scalar rho1 = composition.liquids().rho(this->pc_, T1, X1);
121  this->rho() = rho1;
122 
123  mu_ = composition.liquids().mu(this->pc_, T1, X1);
124 
125  scalar d1 = this->d()*cbrt(rho0/rho1);
126  this->d() = d1;
127 
128  if (liquidCore() > 0.5)
129  {
130  calcAtomization(td, dt, cellI);
131 
132  // Preserve the total mass/volume by increasing the number of
133  // particles in parcels due to breakup
134  scalar d2 = this->d();
135  this->nParticle() *= pow3(d1/d2);
136  }
137  else
138  {
139  calcBreakup(td, dt, cellI);
140  }
141  }
142 
143  // Restore coupled forces
144  td.cloud().forces().setCalcCoupled(true);
145 }
146 
147 
148 template<class ParcelType>
149 template<class TrackData>
151 (
152  TrackData& td,
153  const scalar dt,
154  const label cellI
155 )
156 {
157  typedef typename TrackData::cloudType::sprayCloudType sprayCloudType;
158  const AtomizationModel<sprayCloudType>& atomization =
159  td.cloud().atomization();
160 
161  if (!atomization.active())
162  {
163  return;
164  }
165 
166  typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
168  td.cloud().composition();
169 
170 
171  // Average molecular weight of carrier mix - assumes perfect gas
172  scalar Wc = this->rhoc_*RR*this->Tc()/this->pc();
173  scalar R = RR/Wc;
174  scalar Tav = atomization.Taverage(this->T(), this->Tc());
175 
176  // Calculate average gas density based on average temperature
177  scalar rhoAv = this->pc()/(R*Tav);
178 
179  scalar soi = td.cloud().injectors().timeStart();
180  scalar currentTime = td.cloud().db().time().value();
181  const vector& pos = this->position();
182  const vector& injectionPos = this->position0();
183 
184  // Disregard the continous phase when calculating the relative velocity
185  // (in line with the deactivated coupled assumption)
186  scalar Urel = mag(this->U());
187 
188  scalar t0 = max(0.0, currentTime - this->age() - soi);
189  scalar t1 = min(t0 + dt, td.cloud().injectors().timeEnd() - soi);
190 
191  // This should be the vol flow rate from when the parcel was injected
192  scalar volFlowRate = td.cloud().injectors().volumeToInject(t0, t1)/dt;
193 
194  scalar chi = 0.0;
195  if (atomization.calcChi())
196  {
197  chi = this->chi(td, composition.liquids().X(this->Y()));
198  }
199 
200  atomization.update
201  (
202  dt,
203  this->d(),
204  this->liquidCore(),
205  this->tc(),
206  this->rho(),
207  mu_,
208  sigma_,
209  volFlowRate,
210  rhoAv,
211  Urel,
212  pos,
213  injectionPos,
214  td.cloud().pAmbient(),
215  chi,
216  td.cloud().rndGen()
217  );
218 }
219 
220 
221 template<class ParcelType>
222 template<class TrackData>
224 (
225  TrackData& td,
226  const scalar dt,
227  const label cellI
228 )
229 {
230  typedef typename TrackData::cloudType cloudType;
231  typedef typename cloudType::parcelType parcelType;
232  typedef typename cloudType::forceType forceType;
233  typedef typename TrackData::cloudType::sprayCloudType sprayCloudType;
234 
235  BreakupModel<sprayCloudType>& breakup = td.cloud().breakup();
236 
237  if (!breakup.active())
238  {
239  return;
240  }
241 
242  const parcelType& p = static_cast<const parcelType&>(*this);
243  const forceType& forces = td.cloud().forces();
244 
245  if (breakup.solveOscillationEq())
246  {
247  solveTABEq(td, dt);
248  }
249 
250  // Average molecular weight of carrier mix - assumes perfect gas
251  scalar Wc = this->rhoc()*RR*this->Tc()/this->pc();
252  scalar R = RR/Wc;
253  scalar Tav = td.cloud().atomization().Taverage(this->T(), this->Tc());
254 
255  // Calculate average gas density based on average temperature
256  scalar rhoAv = this->pc()/(R*Tav);
257  scalar muAv = this->muc();
258  vector Urel = this->U() - this->Uc();
259  scalar Urmag = mag(Urel);
260  scalar Re = this->Re(this->U(), this->d(), rhoAv, muAv);
261 
262  const scalar mass = p.mass();
263  const forceSuSp Fcp = forces.calcCoupled(p, dt, mass, Re, muAv);
264  const forceSuSp Fncp = forces.calcNonCoupled(p, dt, mass, Re, muAv);
265  this->tMom() = mass/(Fcp.Sp() + Fncp.Sp() + ROOTVSMALL);
266 
267  const vector g = td.cloud().g().value();
268 
269  scalar parcelMassChild = 0.0;
270  scalar dChild = 0.0;
271  if
272  (
273  breakup.update
274  (
275  dt,
276  g,
277  this->d(),
278  this->tc(),
279  this->ms(),
280  this->nParticle(),
281  this->KHindex(),
282  this->y(),
283  this->yDot(),
284  this->d0(),
285  this->rho(),
286  mu_,
287  sigma_,
288  this->U(),
289  rhoAv,
290  muAv,
291  Urel,
292  Urmag,
293  this->tMom(),
294  dChild,
295  parcelMassChild
296  )
297  )
298  {
299  scalar Re = rhoAv*Urmag*dChild/muAv;
300 
301  // Add child parcel as copy of parent
303  child->d() = dChild;
304  child->d0() = dChild;
305  const scalar massChild = child->mass();
306  child->mass0() = massChild;
307  child->nParticle() = parcelMassChild/massChild;
308 
309  const forceSuSp Fcp =
310  forces.calcCoupled(*child, dt, massChild, Re, muAv);
311  const forceSuSp Fncp =
312  forces.calcNonCoupled(*child, dt, massChild, Re, muAv);
313 
314  child->age() = 0.0;
315  child->liquidCore() = 0.0;
316  child->KHindex() = 1.0;
317  child->y() = td.cloud().breakup().y0();
318  child->yDot() = td.cloud().breakup().yDot0();
319  child->tc() = 0.0;
320  child->ms() = -GREAT;
321  child->injector() = this->injector();
322  child->tMom() = massChild/(Fcp.Sp() + Fncp.Sp());
323  child->user() = 0.0;
324  child->setCellValues(td, dt, cellI);
325 
326  td.cloud().addParticle(child);
327  }
328 }
329 
330 
331 template<class ParcelType>
332 template<class TrackData>
334 (
335  TrackData& td,
336  const scalarField& X
337 ) const
338 {
339  // Modifications to take account of the flash boiling on primary break-up
340 
341  typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
343  td.cloud().composition();
344 
345  scalar chi = 0.0;
346  scalar T0 = this->T();
347  scalar p0 = this->pc();
348  scalar pAmb = td.cloud().pAmbient();
349 
350  scalar pv = composition.liquids().pv(p0, T0, X);
351 
352  forAll(composition.liquids(), i)
353  {
354  if (pv >= 0.999*pAmb)
355  {
356  // Liquid is boiling - calc boiling temperature
357 
358  const liquidProperties& liq = composition.liquids().properties()[i];
359  scalar TBoil = liq.pvInvert(p0);
360 
361  scalar hl = liq.hl(pAmb, TBoil);
362  scalar iTp = liq.h(pAmb, T0) - pAmb/liq.rho(pAmb, T0);
363  scalar iTb = liq.h(pAmb, TBoil) - pAmb/liq.rho(pAmb, TBoil);
364 
365  chi += X[i]*(iTp - iTb)/hl;
366  }
367  }
368 
369  chi = min(1.0, max(chi, 0.0));
370 
371  return chi;
372 }
373 
374 
375 template<class ParcelType>
376 template<class TrackData>
378 (
379  TrackData& td,
380  const scalar dt
381 )
382 {
383  const scalar& TABCmu = td.cloud().breakup().TABCmu();
384  const scalar& TABtwoWeCrit = td.cloud().breakup().TABtwoWeCrit();
385  const scalar& TABComega = td.cloud().breakup().TABComega();
386 
387  scalar r = 0.5*this->d();
388  scalar r2 = r*r;
389  scalar r3 = r*r2;
390 
391  // Inverse of characteristic viscous damping time
392  scalar rtd = 0.5*TABCmu*mu_/(this->rho()*r2);
393 
394  // Oscillation frequency (squared)
395  scalar omega2 = TABComega*sigma_/(this->rho()*r3) - rtd*rtd;
396 
397  if (omega2 > 0)
398  {
399  scalar omega = sqrt(omega2);
400  scalar rhoc = this->rhoc();
401  scalar We = this->We(this->U(), r, rhoc, sigma_)/TABtwoWeCrit;
402 
403  // Initial values for y and yDot
404  scalar y0 = this->y() - We;
405  scalar yDot0 = this->yDot() + y0*rtd;
406 
407  // Update distortion parameters
408  scalar c = cos(omega*dt);
409  scalar s = sin(omega*dt);
410  scalar e = exp(-rtd*dt);
411 
412  this->y() = We + e*(y0*c + (yDot0/omega)*s);
413  this->yDot() = (We - this->y())*rtd + e*(yDot0*c - omega*y0*s);
414  }
415  else
416  {
417  // Reset distortion parameters
418  this->y() = 0;
419  this->yDot() = 0;
420  }
421 }
422 
423 
424 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
425 
426 template<class ParcelType>
428 :
429  ParcelType(p),
430  d0_(p.d0_),
431  position0_(p.position0_),
432  sigma_(p.sigma_),
433  mu_(p.mu_),
434  liquidCore_(p.liquidCore_),
435  KHindex_(p.KHindex_),
436  y_(p.y_),
437  yDot_(p.yDot_),
438  tc_(p.tc_),
439  ms_(p.ms_),
440  injector_(p.injector_),
441  tMom_(p.tMom_),
442  user_(p.user_)
443 {}
444 
445 
446 template<class ParcelType>
448 (
449  const SprayParcel<ParcelType>& p,
450  const polyMesh& mesh
451 )
452 :
453  ParcelType(p, mesh),
454  d0_(p.d0_),
455  position0_(p.position0_),
456  sigma_(p.sigma_),
457  mu_(p.mu_),
458  liquidCore_(p.liquidCore_),
459  KHindex_(p.KHindex_),
460  y_(p.y_),
461  yDot_(p.yDot_),
462  tc_(p.tc_),
463  ms_(p.ms_),
464  injector_(p.injector_),
465  tMom_(p.tMom_),
466  user_(p.user_)
467 {}
468 
469 
470 // * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * * * //
471 
472 #include "SprayParcelIO.C"
473 
474 
475 // ************************************************************************* //
Foam::constant::thermodynamic::RR
const scalar RR
Universal gas constant (default in [J/(kmol K)])
Definition: thermodynamicConstants.C:44
Foam::forceSuSp::Sp
scalar Sp() const
Return const access to the implicit coefficient [kg/s].
Definition: forceSuSpI.H:62
Foam::SprayParcel::y
scalar y() const
Return const access to spherical deviation.
Definition: SprayParcelI.H:259
Foam::SprayParcel::tc
scalar tc() const
Return const access to atomization characteristic time.
Definition: SprayParcelI.H:273
p
p
Definition: pEqn.H:62
Foam::BreakupModel::solveOscillationEq
const Switch & solveOscillationEq() const
Definition: BreakupModel.H:125
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::liquidProperties::hl
virtual scalar hl(scalar p, scalar T) const
Heat of vapourisation [J/kg].
Definition: liquidProperties.C:237
Foam::AtomizationModel::calcChi
virtual bool calcChi() const =0
Flag to indicate if chi needs to be calculated.
Foam::sin
dimensionedScalar sin(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:255
Foam::calc
void calc(const argList &args, const Time &runTime, const fvMesh &mesh)
Definition: Lambda2.C:38
Foam::Re
scalarField Re(const UList< complex > &cf)
Definition: complexFields.C:97
Foam::AtomizationModel
Templated atomization model class.
Definition: SprayCloud.H:47
SprayParcelIO.C
g
const dimensionedVector & g
Definition: setRegionFluidFields.H:33
Foam::exp
dimensionedScalar exp(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:252
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::liquidProperties::h
virtual scalar h(scalar p, scalar T) const
Liquid enthalpy [J/kg] - reference to 298.15 K.
Definition: liquidProperties.C:251
U
U
Definition: pEqn.H:46
Foam::SprayParcel::ms
scalar ms() const
Return const access to stripped parcel mass.
Definition: SprayParcelI.H:280
Foam::CompositionModel
Templated reacting parcel composition model class Consists of carrier species (via thermo package),...
Definition: ReactingCloud.H:52
Foam::SprayParcel::user
scalar user() const
Return const access to passive user scalar.
Definition: SprayParcelI.H:301
Foam::liquidProperties
The thermophysical properties of a liquidProperties.
Definition: liquidProperties.H:53
R
#define R(A, B, C, D, E, F, K, M)
X0
scalarList X0(nSpecie, 0.0)
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::pow3
dimensionedScalar pow3(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:87
Foam::forceSuSp
Helper container for force Su and Sp terms.
Definition: forceSuSp.H:58
AtomizationModel.H
Foam::y0
dimensionedScalar y0(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:272
Foam::SprayParcel::solveTABEq
void solveTABEq(TrackData &td, const scalar dt)
Solve the TAB equation.
Definition: SprayParcel.C:378
Foam::SprayParcel::injector
scalar injector() const
Return const access to injector id.
Definition: SprayParcelI.H:287
Foam::liquidProperties::rho
virtual scalar rho(scalar p, scalar T) const
Liquid rho [kg/m^3].
Definition: liquidProperties.C:223
Foam::SprayParcel::chi
scalar chi(TrackData &td, const scalarField &X) const
Calculate the chi-factor for flash-boiling for the.
Foam::SprayParcel::yDot
scalar yDot() const
Return const access to rate of change of spherical deviation.
Definition: SprayParcelI.H:266
Foam::SprayParcel
Reacing spray parcel, with added functionality for atomization and breakup.
Definition: SprayParcel.H:43
Foam::SprayParcel::cellValueSourceCorrection
void cellValueSourceCorrection(TrackData &td, const scalar dt, const label cellI)
Correct cell values using latest transfer information.
Definition: SprayParcel.C:49
Foam::liquidProperties::pvInvert
virtual scalar pvInvert(scalar p) const
Invert the vapour pressure relationship to retrieve the.
Definition: liquidProperties.C:314
Urel
Urel
Definition: pEqn.H:45
Foam::SprayParcel::tMom
scalar tMom() const
Return const access to momentum relaxation time.
Definition: SprayParcelI.H:294
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
rho1
rho1
Definition: pEqn.H:124
Foam::SprayParcel::setCellValues
void setCellValues(TrackData &td, const scalar dt, const label cellI)
Set cell values.
Definition: SprayParcel.C:36
Foam::SprayParcel::KHindex
scalar KHindex() const
Return const access to Kelvin-Helmholtz breakup index.
Definition: SprayParcelI.H:252
s
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))
Foam::SprayParcel::calcBreakup
void calcBreakup(TrackData &td, const scalar dt, const label cellI)
Correct parcel properties according to breakup model.
Definition: SprayParcel.C:224
Foam::BreakupModel
Templated break-up model class.
Definition: SprayCloud.H:50
Foam::SprayParcel::calc
void calc(TrackData &td, const scalar dt, const label cellI)
Update parcel properties over the time interval.
Definition: SprayParcel.C:62
rho
rho
Definition: pEqn.H:3
Foam::forces
This function object calculates the forces and moments by integrating the pressure and skin-friction ...
Definition: forces.H:234
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
BreakupModel.H
rho0
scalar rho0
Definition: readInitialConditions.H:97
Foam::BreakupModel::update
virtual bool update(const scalar dt, const vector &g, scalar &d, scalar &tc, scalar &ms, scalar &nParticle, scalar &KHindex, scalar &y, scalar &yDot, const scalar d0, const scalar rho, const scalar mu, const scalar sigma, const vector &U, const scalar rhoc, const scalar muc, const vector &Urel, const scalar Urmag, const scalar tMom, scalar &dChild, scalar &massChild)=0
Update the parcel properties and return true if a child parcel.
T
const volScalarField & T
Definition: createFields.H:25
Foam::SprayParcel::liquidCore
scalar liquidCore() const
Return const access to liquid core.
Definition: SprayParcelI.H:245
SprayParcel.H
Foam::Vector< scalar >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:142
CompositionModel.H
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: doubleFloat.H:94
Foam::AtomizationModel::update
virtual void update(const scalar dt, scalar &d, scalar &liquidCore, scalar &tc, const scalar rho, const scalar mu, const scalar sigma, const scalar volFlowRate, const scalar rhoAv, const scalar Urel, const vector &pos, const vector &injectionPos, const scalar pAmbient, const scalar chi, cachedRandom &rndGen) const =0
composition
basicMultiComponentMixture & composition
Definition: createFields.H:35
Foam::SprayParcel::calcAtomization
void calcAtomization(TrackData &td, const scalar dt, const label cellI)
Correct parcel properties according to atomization model.
Definition: SprayParcel.C:151
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::SprayParcel::SprayParcel
SprayParcel(const polyMesh &mesh, const vector &position, const label cellI, const label tetFaceI, const label tetPtI)
Construct from owner, position, and cloud owner.
Definition: SprayParcelI.H:108
Foam::cbrt
dimensionedScalar cbrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:153
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::AtomizationModel::Taverage
scalar Taverage(const scalar &Tliq, const scalar &Tc) const
Average temperature calculation.
Definition: AtomizationModel.C:73
Foam::SprayParcel::d0
scalar d0() const
Return const access to initial droplet diameter.
Definition: SprayParcelI.H:217
Foam::forces::forces
forces(const forces &)
Disallow default bitwise copy construct.
y
scalar y
Definition: LISASMDCalcMethod1.H:14
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:256
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:190