00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "ReactingParcel_.H"
00027 #include <OpenFOAM/mathematicalConstants.H>
00028 #include <specie/specie.H>
00029
00030
00031
00032 template<class ParcelType>
00033 template<class TrackData>
00034 void Foam::ReactingParcel<ParcelType>::setCellValues
00035 (
00036 TrackData& td,
00037 const scalar dt,
00038 const label cellI
00039 )
00040 {
00041 ThermoParcel<ParcelType>::setCellValues(td, dt, cellI);
00042
00043 pc_ = td.pInterp().interpolate(this->position(), cellI);
00044 if (pc_ < td.constProps().pMin())
00045 {
00046 WarningIn
00047 (
00048 "void Foam::ReactingParcel<ParcelType>::setCellValues"
00049 "("
00050 "TrackData&, "
00051 "const scalar, "
00052 "const label"
00053 ")"
00054 ) << "Limiting observed pressure in cell " << cellI << " to "
00055 << td.constProps().pMin() << nl << endl;
00056
00057 pc_ = td.constProps().pMin();
00058 }
00059 }
00060
00061
00062 template<class ParcelType>
00063 template<class TrackData>
00064 void Foam::ReactingParcel<ParcelType>::cellValueSourceCorrection
00065 (
00066 TrackData& td,
00067 const scalar dt,
00068 const label cellI
00069 )
00070 {
00071 scalar massCell = this->massCell(cellI);
00072
00073 scalar addedMass = 0.0;
00074 forAll(td.cloud().rhoTrans(), i)
00075 {
00076 addedMass += td.cloud().rhoTrans(i)[cellI];
00077 }
00078
00079 this->rhoc_ += addedMass/td.cloud().pMesh().cellVolumes()[cellI];
00080
00081 scalar massCellNew = massCell + addedMass;
00082 this->Uc_ += td.cloud().UTrans()[cellI]/massCellNew;
00083
00084 scalar cpEff = 0;
00085 if (addedMass > ROOTVSMALL)
00086 {
00087 forAll(td.cloud().rhoTrans(), i)
00088 {
00089 scalar Y = td.cloud().rhoTrans(i)[cellI]/addedMass;
00090 cpEff +=
00091 Y*td.cloud().mcCarrierThermo().speciesData()[i].Cp(this->Tc_);
00092 }
00093 }
00094 const scalar cpc = td.cpInterp().psi()[cellI];
00095 this->cpc_ = (massCell*cpc + addedMass*cpEff)/massCellNew;
00096
00097 this->Tc_ += td.cloud().hsTrans()[cellI]/(this->cpc_*massCellNew);
00098 }
00099
00100
00101 template<class ParcelType>
00102 template<class TrackData>
00103 void Foam::ReactingParcel<ParcelType>::correctSurfaceValues
00104 (
00105 TrackData& td,
00106 const label cellI,
00107 const scalar T,
00108 const scalarField& Cs,
00109 scalar& rhos,
00110 scalar& mus,
00111 scalar& Pr,
00112 scalar& kappa
00113 )
00114 {
00115
00116 if (sum(Cs) < SMALL)
00117 {
00118 return;
00119 }
00120
00121
00122 scalarField Xinf(td.cloud().mcCarrierThermo().speciesData().size());
00123
00124 forAll(Xinf, i)
00125 {
00126 Xinf[i] =
00127 td.cloud().mcCarrierThermo().Y(i)[cellI]
00128 /td.cloud().mcCarrierThermo().speciesData()[i].W();
00129 }
00130 Xinf /= sum(Xinf);
00131
00132
00133 const scalar Xsff = 1.0 - min(sum(Cs)*specie::RR*this->T_/pc_, 1.0);
00134
00135
00136 const scalar CsTot = pc_/(specie::RR*this->T_);
00137
00138
00139 scalarField Xs(Xinf.size());
00140
00141
00142 scalarField Ys(Xinf.size());
00143
00144 forAll(Xs, i)
00145 {
00146
00147 const scalar Csi = Cs[i] + Xsff*Xinf[i]*CsTot;
00148
00149 Xs[i] = (2.0*Csi + Xinf[i]*CsTot)/3.0;
00150 Ys[i] = Xs[i]*td.cloud().mcCarrierThermo().speciesData()[i].W();
00151 }
00152 Xs /= sum(Xs);
00153 Ys /= sum(Ys);
00154
00155
00156 rhos = 0;
00157 mus = 0;
00158 kappa = 0;
00159 scalar cps = 0;
00160 scalar sumYiSqrtW = 0;
00161 scalar sumYiCbrtW = 0;
00162
00163 forAll(Ys, i)
00164 {
00165 const scalar sqrtW =
00166 sqrt(td.cloud().mcCarrierThermo().speciesData()[i].W());
00167 const scalar cbrtW =
00168 cbrt(td.cloud().mcCarrierThermo().speciesData()[i].W());
00169
00170 rhos += Xs[i]*td.cloud().mcCarrierThermo().speciesData()[i].W();
00171 mus += Ys[i]*sqrtW*td.cloud().mcCarrierThermo().speciesData()[i].mu(T);
00172 kappa +=
00173 Ys[i]*cbrtW*td.cloud().mcCarrierThermo().speciesData()[i].kappa(T);
00174 cps += Xs[i]*td.cloud().mcCarrierThermo().speciesData()[i].Cp(T);
00175
00176 sumYiSqrtW += Ys[i]*sqrtW;
00177 sumYiCbrtW += Ys[i]*cbrtW;
00178 }
00179
00180 rhos *= pc_/(specie::RR*T);
00181 mus /= sumYiSqrtW;
00182 kappa /= sumYiCbrtW;
00183 Pr = cps*mus/kappa;
00184 }
00185
00186
00187 template<class ParcelType>
00188 Foam::scalar Foam::ReactingParcel<ParcelType>::updateMassFraction
00189 (
00190 const scalar mass0,
00191 const scalarField& dMass,
00192 scalarField& Y
00193 ) const
00194 {
00195 scalar mass1 = mass0 - sum(dMass);
00196
00197
00198 if (mass1 > ROOTVSMALL)
00199 {
00200 forAll(Y, i)
00201 {
00202 Y[i] = (Y[i]*mass0 - dMass[i])/mass1;
00203 }
00204 }
00205
00206 return mass1;
00207 }
00208
00209
00210 template<class ParcelType>
00211 template<class TrackData>
00212 void Foam::ReactingParcel<ParcelType>::calc
00213 (
00214 TrackData& td,
00215 const scalar dt,
00216 const label cellI
00217 )
00218 {
00219
00220
00221 const scalar np0 = this->nParticle_;
00222 const scalar d0 = this->d_;
00223 const vector& U0 = this->U_;
00224 const scalar rho0 = this->rho_;
00225 const scalar T0 = this->T_;
00226 const scalar cp0 = this->cp_;
00227 const scalar mass0 = this->mass();
00228
00229
00230
00231
00232 scalar Ts, rhos, mus, Pr, kappa;
00233 this->calcSurfaceValues(td, cellI, T0, Ts, rhos, mus, Pr, kappa);
00234
00235
00236 scalar Re = this->Re(U0, d0, rhos, mus);
00237
00238
00239
00240
00241
00242
00243 vector Su = vector::zero;
00244
00245
00246 vector dUTrans = vector::zero;
00247
00248
00249 scalar Sh = 0.0;
00250
00251
00252 scalar dhsTrans = 0.0;
00253
00254
00255
00256
00257
00258
00259 scalarField dMassPC(Y_.size(), 0.0);
00260
00261
00262 scalar Ne = 0.0;
00263
00264
00265 scalar NCpW = 0.0;
00266
00267
00268 scalarField Cs(td.cloud().mcCarrierThermo().species().size(), 0.0);
00269
00270
00271 calcPhaseChange
00272 (
00273 td,
00274 dt,
00275 cellI,
00276 Re,
00277 Ts,
00278 mus/rhos,
00279 d0,
00280 T0,
00281 mass0,
00282 0,
00283 1.0,
00284 Y_,
00285 dMassPC,
00286 Sh,
00287 Ne,
00288 NCpW,
00289 Cs
00290 );
00291
00292
00293 correctSurfaceValues(td, cellI, Ts, Cs, rhos, mus, Pr, kappa);
00294
00295
00296 scalar mass1 = updateMassFraction(mass0, dMassPC, Y_);
00297
00298
00299
00300
00301
00302
00303 scalar T1 =
00304 this->calcHeatTransfer
00305 (
00306 td,
00307 dt,
00308 cellI,
00309 Re,
00310 Pr,
00311 kappa,
00312 d0,
00313 rho0,
00314 T0,
00315 cp0,
00316 NCpW,
00317 Sh,
00318 dhsTrans
00319 );
00320
00321
00322
00323
00324
00325
00326 vector U1 =
00327 this->calcVelocity
00328 (
00329 td,
00330 dt,
00331 cellI,
00332 Re,
00333 mus,
00334 d0,
00335 U0,
00336 rho0,
00337 mass0,
00338 Su,
00339 dUTrans
00340 );
00341
00342 dUTrans += 0.5*(mass0 - mass1)*(U0 + U1);
00343
00344
00345
00346 if (td.cloud().coupled())
00347 {
00348
00349 forAll(dMassPC, i)
00350 {
00351 label gid = td.cloud().composition().localToGlobalCarrierId(0, i);
00352 td.cloud().rhoTrans(gid)[cellI] += np0*dMassPC[i];
00353 }
00354
00355
00356 td.cloud().UTrans()[cellI] += np0*dUTrans;
00357
00358
00359 td.cloud().hsTrans()[cellI] += np0*dhsTrans;
00360 }
00361
00362
00363
00364
00365 if (mass1 < td.constProps().minParticleMass())
00366 {
00367 td.keepParticle = false;
00368
00369 if (td.cloud().coupled())
00370 {
00371
00372 forAll(Y_, i)
00373 {
00374 label gid =
00375 td.cloud().composition().localToGlobalCarrierId(0, i);
00376 td.cloud().rhoTrans(gid)[cellI] += np0*mass1*Y_[i];
00377 }
00378 td.cloud().UTrans()[cellI] += np0*mass1*U1;
00379 td.cloud().hsTrans()[cellI] +=
00380 np0*mass1*td.cloud().composition().H(0, Y_, pc_, T1);
00381 }
00382 }
00383
00384
00385
00386
00387
00388 else
00389 {
00390 this->cp_ = td.cloud().composition().cp(0, Y_, pc_, T1);
00391 this->T_ = T1;
00392 this->U_ = U1;
00393
00394
00395 if (td.constProps().constantVolume())
00396 {
00397 this->rho_ = mass1/this->volume();
00398 }
00399 else
00400 {
00401 this->d_ = cbrt(mass1/this->rho_*6.0/mathematicalConstant::pi);
00402 }
00403 }
00404 }
00405
00406
00407 template<class ParcelType>
00408 template<class TrackData>
00409 void Foam::ReactingParcel<ParcelType>::calcPhaseChange
00410 (
00411 TrackData& td,
00412 const scalar dt,
00413 const label cellI,
00414 const scalar Re,
00415 const scalar Ts,
00416 const scalar nus,
00417 const scalar d,
00418 const scalar T,
00419 const scalar mass,
00420 const label idPhase,
00421 const scalar YPhase,
00422 const scalarField& YComponents,
00423 scalarField& dMassPC,
00424 scalar& Sh,
00425 scalar& N,
00426 scalar& NCpW,
00427 scalarField& Cs
00428 )
00429 {
00430 typedef PhaseChangeModel
00431 <
00432 typename ReactingParcel<ParcelType>::trackData::cloudType
00433 > phaseChangeModelType;
00434
00435 if
00436 (
00437 !td.cloud().phaseChange().active()
00438 || T < td.constProps().Tvap()
00439 || YPhase < SMALL
00440 )
00441 {
00442 return;
00443 }
00444
00445
00446 td.cloud().phaseChange().calculate
00447 (
00448 dt,
00449 cellI,
00450 Re,
00451 d,
00452 nus,
00453 T,
00454 Ts,
00455 pc_,
00456 dMassPC
00457 );
00458
00459
00460 dMassPC = min(mass*YPhase*YComponents, dMassPC);
00461
00462 scalar dMassTot = sum(dMassPC);
00463
00464
00465 td.cloud().addToMassPhaseChange(this->nParticle_*dMassTot);
00466
00467
00468 scalar Wc = this->rhoc_*specie::RR*this->Tc_/this->pc_;
00469
00470 forAll(YComponents, i)
00471 {
00472 const label idc =
00473 td.cloud().composition().localToGlobalCarrierId(idPhase, i);
00474 const label idl = td.cloud().composition().globalIds(idPhase)[i];
00475
00476
00477 if
00478 (
00479 td.cloud().phaseChange().enthalpyTransfer()
00480 == phaseChangeModelType::etLatentHeat
00481 )
00482 {
00483 scalar hlp =
00484 td.cloud().composition().liquids().properties()[idl].hl(pc_, T);
00485
00486 Sh -= dMassPC[i]*hlp/dt;
00487 }
00488 else
00489 {
00490
00491 scalar hc = td.cloud().mcCarrierThermo().speciesData()[idc].H(T);
00492 scalar hp =
00493 td.cloud().composition().liquids().properties()[idl].h(pc_, T);
00494
00495 Sh -= dMassPC[i]*(hc - hp)/dt;
00496 }
00497
00498
00499 const scalar Dab =
00500 td.cloud().composition().liquids().properties()[idl].D(pc_, Ts, Wc);
00501
00502 const scalar Cp =
00503 td.cloud().mcCarrierThermo().speciesData()[idc].Cp(Ts);
00504 const scalar W = td.cloud().mcCarrierThermo().speciesData()[idc].W();
00505 const scalar Ni = dMassPC[i]/(this->areaS(d)*dt*W);
00506
00507
00508 N += Ni;
00509
00510
00511 NCpW += Ni*Cp*W;
00512
00513
00514 Cs[idc] += Ni*d/(2.0*Dab);
00515 }
00516 }
00517
00518
00519
00520
00521 template <class ParcelType>
00522 Foam::ReactingParcel<ParcelType>::ReactingParcel
00523 (
00524 const ReactingParcel<ParcelType>& p
00525 )
00526 :
00527 ThermoParcel<ParcelType>(p),
00528 mass0_(p.mass0_),
00529 Y_(p.Y_),
00530 pc_(p.pc_)
00531 {}
00532
00533
00534
00535
00536 #include "ReactingParcelIO.C"
00537
00538
00539