1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
26 #include "SprayParcel.H"
27 #include "CompositionModel.H"
28 #include "AtomizationModel.H"
30 // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
32 template<class ParcelType>
33 template<class TrackData>
34 void Foam::SprayParcel<ParcelType>::setCellValues
41 ParcelType::setCellValues(td, dt, cellI);
45 template<class ParcelType>
46 template<class TrackData>
47 void Foam::SprayParcel<ParcelType>::cellValueSourceCorrection
54 ParcelType::cellValueSourceCorrection(td, dt, cellI);
58 template<class ParcelType>
59 template<class TrackData>
60 void Foam::SprayParcel<ParcelType>::calc
67 bool coupled = td.cloud().solution().coupled();
69 // check if parcel belongs to liquid core
70 if (liquidCore() > 0.5)
72 // liquid core parcels should not interact with the gas
73 if (td.cloud().solution().coupled())
75 td.cloud().solution().coupled() = false;
79 // store the parcel properties
80 const scalarField& Y(this->Y());
81 scalarField X(td.cloud().composition().liquids().X(Y));
83 scalar T0 = this->T();
84 this->Cp() = td.cloud().composition().liquids().Cp(this->pc_, T0, X);
85 scalar rho0 = td.cloud().composition().liquids().rho(this->pc_, T0, X);
88 ParcelType::calc(td, dt, cellI);
92 // update Cp, diameter and density due to change in temperature
94 scalar T1 = this->T();
95 const scalarField& Y1(this->Y());
96 scalarField X1(td.cloud().composition().liquids().X(Y1));
98 this->Cp() = td.cloud().composition().liquids().Cp(this->pc_, T1, X1);
100 scalar rho1 = td.cloud().composition().liquids().rho(this->pc_, T1, X1);
102 scalar d1 = this->d()*cbrt(rho0/rho1);
105 if (liquidCore() > 0.5)
107 calcAtomization(td, dt, cellI);
109 // preserve the total mass/volume by increasing the number of
110 // particles in parcels due to breakup
111 scalar d2 = this->d();
112 this->nParticle() *= pow3(d1/d2);
116 calcBreakup(td, dt, cellI);
121 td.cloud().solution().coupled() = coupled;
125 template<class ParcelType>
126 template<class TrackData>
127 void Foam::SprayParcel<ParcelType>::calcAtomization
134 typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
135 const CompositionModel<reactingCloudType>& composition =
136 td.cloud().composition();
138 typedef typename TrackData::cloudType::sprayCloudType sprayCloudType;
139 const AtomizationModel<sprayCloudType>& atomization =
140 td.cloud().atomization();
143 // cell state info is updated in ReactingParcel calc
144 const scalarField& Y(this->Y());
145 scalarField X(composition.liquids().X(Y));
147 scalar rho = composition.liquids().rho(this->pc(), this->T(), X);
148 scalar mu = composition.liquids().mu(this->pc(), this->T(), X);
149 scalar sigma = composition.liquids().sigma(this->pc(), this->T(), X);
151 // Average molecular weight of carrier mix - assumes perfect gas
152 scalar Wc = this->rhoc_*specie::RR*this->Tc()/this->pc();
153 scalar R = specie::RR/Wc;
154 scalar Tav = atomization.Taverage(this->T(), this->Tc());
156 // calculate average gas density based on average temperature
157 scalar rhoAv = this->pc()/(R*Tav);
159 scalar soi = td.cloud().injection().timeStart();
160 scalar currentTime = td.cloud().db().time().value();
161 const vector& pos = this->position();
162 const vector& injectionPos = this->position0();
164 // disregard the continous phase when calculating the relative velocity
165 // (in line with the deactivated coupled assumption)
166 scalar Urel = mag(this->U());
168 scalar t0 = max(0.0, currentTime - this->age() - soi);
169 scalar t1 = min(t0 + dt, td.cloud().injection().timeEnd() - soi);
170 // this should be the vol flow rate from when the parcel was injected
171 scalar volFlowRate = td.cloud().injection().volumeToInject(t0, t1)/dt;
174 if (atomization.calcChi())
176 chi = this->chi(td, X);
193 td.cloud().pAmbient(),
200 template<class ParcelType>
201 template<class TrackData>
202 void Foam::SprayParcel<ParcelType>::calcBreakup
209 typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
210 const CompositionModel<reactingCloudType>& composition =
211 td.cloud().composition();
213 typedef typename TrackData::cloudType cloudType;
214 typedef typename cloudType::parcelType parcelType;
215 typedef typename cloudType::forceType forceType;
217 const parcelType& p = static_cast<const parcelType&>(*this);
218 const forceType& forces = td.cloud().forces();
220 if (td.cloud().breakup().solveOscillationEq())
225 // cell state info is updated in ReactingParcel calc
226 const scalarField& Y(this->Y());
227 scalarField X(composition.liquids().X(Y));
229 scalar rho = composition.liquids().rho(this->pc(), this->T(), X);
230 scalar mu = composition.liquids().mu(this->pc(), this->T(), X);
231 scalar sigma = composition.liquids().sigma(this->pc(), this->T(), X);
233 // Average molecular weight of carrier mix - assumes perfect gas
234 scalar Wc = this->rhoc()*specie::RR*this->Tc()/this->pc();
235 scalar R = specie::RR/Wc;
236 scalar Tav = td.cloud().atomization().Taverage(this->T(), this->Tc());
238 // calculate average gas density based on average temperature
239 scalar rhoAv = this->pc()/(R*Tav);
240 scalar muAv = this->muc();
241 vector Urel = this->U() - this->Uc();
242 scalar Urmag = mag(Urel);
243 scalar Re = this->Re(this->U(), this->d(), rhoAv, muAv);
245 const scalar mass = p.mass();
246 const forceSuSp Fcp = forces.calcCoupled(p, dt, mass, Re, muAv);
247 const forceSuSp Fncp = forces.calcNonCoupled(p, dt, mass, Re, muAv);
248 scalar tMom = 1.0/(Fcp.Sp() + Fncp.Sp());
250 const vector g = td.cloud().g().value();
252 scalar massChild = 0.0;
256 td.cloud().breakup().update
277 td.cloud().averageParcelMass(),
284 scalar Re = rhoAv*Urmag*dChild/muAv;
285 this->mass0() -= massChild;
287 // Add child parcel as copy of parent
288 SprayParcel<ParcelType>* child = new SprayParcel<ParcelType>(*this);
289 child->mass0() = massChild;
291 child->nParticle() = massChild/rho*this->volume(dChild);
293 const forceSuSp Fcp =
294 forces.calcCoupled(*child, dt, massChild, Re, muAv);
295 const forceSuSp Fncp =
296 forces.calcNonCoupled(*child, dt, massChild, Re, muAv);
298 child->liquidCore() = 0.0;
299 child->KHindex() = 1.0;
300 child->y() = td.cloud().breakup().y0();
301 child->yDot() = td.cloud().breakup().yDot0();
302 child->tc() = -GREAT;
304 child->injector() = this->injector();
305 child->tMom() = 1.0/(Fcp.Sp() + Fncp.Sp());
307 child->setCellValues(td, dt, cellI);
309 td.cloud().addParticle(child);
314 template<class ParcelType>
315 template<class TrackData>
316 Foam::scalar Foam::SprayParcel<ParcelType>::chi
322 // modifications to take account of the flash boiling on primary break-up
324 static label nIter = 200;
326 typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
327 const CompositionModel<reactingCloudType>& composition =
328 td.cloud().composition();
331 scalar T0 = this->T();
332 scalar Tc0 = this->Tc();
333 scalar p0 = this->pc();
334 scalar pAmb = td.cloud().pAmbient();
336 scalar pv = composition.liquids().pv(p0, T0, X);
338 forAll(composition.liquids(), i)
340 if (pv >= 0.999*pAmb)
342 // liquid is boiling - calc boiling temperature
344 const liquidProperties& liq = composition.liquids().properties()[i];
347 for (label k=0; k<nIter; k++)
349 scalar pBoil = liq.pv(p0, TBoil);
353 TBoil = TBoil - (T0 - Tc0)/nIter;
361 scalar hl = liq.hl(pAmb, TBoil);
362 scalar iTp = liq.h(pAmb, T0) - liq.rho(pAmb, T0);
363 scalar iTb = liq.h(pAmb, TBoil) - pAmb/liq.rho(pAmb, TBoil);
365 chi += X[i]*(iTp - iTb)/hl;
369 chi = min(1.0, max(chi, 0.0));
375 template<class ParcelType>
376 template<class TrackData>
377 void Foam::SprayParcel<ParcelType>::solveTABEq
383 typedef typename TrackData::cloudType::reactingCloudType reactingCloudType;
384 const CompositionModel<reactingCloudType>& composition =
385 td.cloud().composition();
387 const scalar& TABCmu = td.cloud().breakup().TABCmu();
388 const scalar& TABWeCrit = td.cloud().breakup().TABWeCrit();
389 const scalar& TABComega = td.cloud().breakup().TABComega();
391 scalar r = 0.5*this->d();
395 const scalarField& Y(this->Y());
396 scalarField X(composition.liquids().X(Y));
398 scalar rho = composition.liquids().rho(this->pc(), this->T(), X);
399 scalar mu = composition.liquids().mu(this->pc(), this->T(), X);
400 scalar sigma = composition.liquids().sigma(this->pc(), this->T(), X);
402 // inverse of characteristic viscous damping time
403 scalar rtd = 0.5*TABCmu*mu/(rho*r2);
405 // oscillation frequency (squared)
406 scalar omega2 = TABComega*sigma/(rho*r3) - rtd*rtd;
410 scalar omega = sqrt(omega2);
411 scalar rhoc = this->rhoc();
412 scalar Wetmp = this->We(this->U(), r, rhoc, sigma)/TABWeCrit;
414 scalar y1 = this->y() - Wetmp;
415 scalar y2 = this->yDot()/omega;
417 // update distortion parameters
418 scalar c = cos(omega*dt);
419 scalar s = sin(omega*dt);
420 scalar e = exp(-rtd*dt);
421 y2 = (this->yDot() + y1*rtd)/omega;
423 this->y() = Wetmp + e*(y1*c + y2*s);
431 this->yDot() = (Wetmp - this->y())*rtd + e*omega*(y2*c - y1*s);
436 // reset distortion parameters
443 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
445 template <class ParcelType>
446 Foam::SprayParcel<ParcelType>::SprayParcel(const SprayParcel<ParcelType>& p)
450 position0_(p.position0_),
451 liquidCore_(p.liquidCore_),
452 KHindex_(p.KHindex_),
457 injector_(p.injector_),
463 template <class ParcelType>
464 Foam::SprayParcel<ParcelType>::SprayParcel
466 const SprayParcel<ParcelType>& p,
472 position0_(p.position0_),
473 liquidCore_(p.liquidCore_),
474 KHindex_(p.KHindex_),
479 injector_(p.injector_),
485 // * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * * * //
487 #include "SprayParcelIO.C"
490 // ************************************************************************* //