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