47 namespace diameterModels
56 void Foam::diameterModels::populationBalanceModel::initialiseDmdtfs()
60 HashTable<const diameterModels::velocityGroup*>,
65 const diameterModels::velocityGroup& velGrp1 = *iter1();
69 HashTable<const diameterModels::velocityGroup*>,
74 const diameterModels::velocityGroup& velGrp2 = *iter2();
76 const phaseInterface interface(velGrp1.phase(), velGrp2.phase());
82 !dmdtfs_.
found(interface)
86 <diameterModels::populationBalanceModel>(interface);
113 void Foam::diameterModels::populationBalanceModel::precompute()
115 forAll(coalescenceModels_, model)
117 coalescenceModels_[model].precompute();
120 forAll(breakupModels_, model)
122 breakupModels_[model].precompute();
124 breakupModels_[model].dsdPtr()->precompute();
127 forAll(binaryBreakupModels_, model)
129 binaryBreakupModels_[model].precompute();
134 drift_[model].precompute();
137 forAll(nucleation_, model)
139 nucleation_[model].precompute();
144 void Foam::diameterModels::populationBalanceModel::birthByCoalescence
150 const sizeGroup& fj = sizeGroups()[j];
151 const sizeGroup& fk = sizeGroups()[
k];
156 for (
label i = j; i < sizeGroups().size(); i++)
160 if (Eta.value() == 0)
continue;
162 const sizeGroup& fi = sizeGroups()[i];
167 0.5*fi.x()/(fj.x()*fk.x())*Eta
168 *coalescenceRate_()*fj*fj.phase()*fk*fk.phase();
173 fi.x()/(fj.x()*fk.x())*Eta
174 *coalescenceRate_()*fj*fj.phase()*fk*fk.phase();
179 const phaseInterface interfaceij(fi.phase(), fj.phase());
181 if (dmdtfs_.found(interfaceij))
183 const scalar dmdtSign =
184 interfaceij.index(fi.phase()) == 0 ? +1 : -1;
186 *dmdtfs_[interfaceij] += dmdtSign*fj.x()/v*Sui_*fj.phase().rho();
189 const phaseInterface interfaceik(fi.phase(), fk.phase());
191 if (dmdtfs_.found(interfaceik))
193 const scalar dmdtSign =
194 interfaceik.index(fi.phase()) == 0 ? +1 : -1;
196 *dmdtfs_[interfaceik] += dmdtSign*fk.x()/v*Sui_*fk.phase().rho();
199 sizeGroups_[i].shapeModelPtr()->addCoalescence(Sui_, fj, fk);
204 void Foam::diameterModels::populationBalanceModel::deathByCoalescence
210 const sizeGroup& fi = sizeGroups()[i];
211 const sizeGroup& fj = sizeGroups()[j];
213 Sp_[i] += coalescenceRate_()*fi.phase()*fj*fj.phase()/fj.x();
217 Sp_[j] += coalescenceRate_()*fj.phase()*fi*fi.phase()/fi.x();
222 void Foam::diameterModels::populationBalanceModel::birthByBreakup
228 const sizeGroup& fk = sizeGroups()[
k];
230 for (
label i = 0; i <=
k; i++)
232 const sizeGroup& fi = sizeGroups()[i];
235 fi.x()*breakupModels_[model].dsdPtr()().nik(i,
k)/fk.x()
236 *breakupRate_()*fk*fk.phase();
240 const phaseInterface interface(fi.phase(), fk.phase());
242 if (dmdtfs_.found(interface))
244 const scalar dmdtSign =
245 interface.index(fi.phase()) == 0 ? +1 : -1;
247 *dmdtfs_[interface] += dmdtSign*Sui_*fk.phase().rho();
250 sizeGroups_[i].shapeModelPtr()->addBreakup(Sui_, fk);
255 void Foam::diameterModels::populationBalanceModel::deathByBreakup(
const label i)
257 Sp_[i] += breakupRate_()*sizeGroups()[i].phase();
261 void Foam::diameterModels::populationBalanceModel::calcDeltas()
265 if (delta_[i].empty())
267 for (
label j = 0; j <= sizeGroups().size() - 1; j++)
269 const sizeGroup& fj = sizeGroups()[j];
277 v_[i+1].value() - v_[i].value()
283 v_[i].value() < 0.5*fj.x().value()
285 0.5*fj.x().value() < v_[i+1].value()
288 delta_[i][j] =
mag(0.5*fj.x() - v_[i]);
290 else if (0.5*fj.x().value() <= v_[i].value())
292 delta_[i][j].value() = 0;
300 void Foam::diameterModels::populationBalanceModel::birthByBinaryBreakup
306 const sizeGroup& fi = sizeGroups()[i];
307 const sizeGroup& fj = sizeGroups()[j];
311 Sui_ = fi.x()*delta_[i][j]/fj.x()*
Su;
315 sizeGroups_[i].shapeModelPtr()->addBreakup(Sui_, fj);
317 const phaseInterface interfaceij(fi.phase(), fj.phase());
319 if (dmdtfs_.found(interfaceij))
321 const scalar dmdtSign =
322 interfaceij.index(fi.phase()) == 0 ? +1 : -1;
324 *dmdtfs_[interfaceij] += dmdtSign*Sui_*fj.phase().rho();
334 if (Eta.value() == 0)
continue;
336 const sizeGroup& fk = sizeGroups()[
k];
340 Suk = fk.x()*delta_[i][j]*Eta/fj.x()*
Su;
344 const phaseInterface interfacekj(fk.phase(), fj.phase());
346 if (dmdtfs_.found(interfacekj))
348 const scalar dmdtSign =
349 interfacekj.index(fk.phase()) == 0 ? +1 : -1;
351 *dmdtfs_[interfacekj] += dmdtSign*Suk*fj.phase().rho();
354 sizeGroups_[
k].shapeModelPtr()->addBreakup(Suk, fj);
359 void Foam::diameterModels::populationBalanceModel::deathByBinaryBreakup
365 Sp_[i] += sizeGroups()[i].phase()*binaryBreakupRate_()*delta_[j][i];
369 void Foam::diameterModels::populationBalanceModel::drift
375 model.addToDriftRate(driftRate_(), i);
377 const sizeGroup& fp = sizeGroups()[i];
379 if (i < sizeGroups().size() - 1)
381 const sizeGroup& fe = sizeGroups()[i+1];
384 Sp_[i] += 1/(fe.x() - fp.x())*
pos(driftRate_())*driftRate_();
387 fe.x()/(fp.x()*(fe.x() - fp.x()))*
pos(driftRate_())*driftRate_()*fp;
391 const phaseInterface interfacepe(fp.phase(), fe.phase());
393 if (dmdtfs_.found(interfacepe))
395 const scalar dmdtSign =
396 interfacepe.index(fp.phase()) == 0 ? +1 : -1;
398 *dmdtfs_[interfacepe] -= dmdtSign*Sue*fp.phase().rho();
401 sizeGroups_[i+1].shapeModelPtr()->addDrift(Sue, fp, model);
404 if (i == sizeGroups().size() - 1)
406 Sp_[i] -=
pos(driftRate_())*driftRate_()/fp.x();
411 const sizeGroup& fw = sizeGroups()[i-1];
414 Sp_[i] += 1/(fw.x() - fp.x())*
neg(driftRate_())*driftRate_();
417 fw.x()/(fp.x()*(fw.x() - fp.x()))*
neg(driftRate_())*driftRate_()*fp;
421 const phaseInterface interfacepw(fp.phase(), fw.phase());
423 if (dmdtfs_.found(interfacepw))
425 const scalar dmdtSign =
426 interfacepw.index(fp.phase()) == 0 ? +1 : -1;
428 *dmdtfs_[interfacepw] -= dmdtSign*Suw*fp.phase().rho();
431 sizeGroups_[i-1].shapeModelPtr()->addDrift(Suw, fp, model);
436 Sp_[i] -=
neg(driftRate_())*driftRate_()/fp.x();
441 void Foam::diameterModels::populationBalanceModel::nucleation
444 nucleationModel& model
447 const sizeGroup& fi = sizeGroups()[i];
449 model.addToNucleationRate(nucleationRate_(), i);
451 Sui_ = fi.x()*nucleationRate_();
455 sizeGroups_[i].shapeModelPtr()->addNucleation(Sui_, fi, model);
459 void Foam::diameterModels::populationBalanceModel::sources()
463 sizeGroups_[i].shapeModelPtr()->reset();
473 forAll(coalescencePairs_, coalescencePairi)
475 label i = coalescencePairs_[coalescencePairi].first();
476 label j = coalescencePairs_[coalescencePairi].second();
478 coalescenceRate_() =
Zero;
480 forAll(coalescenceModels_, model)
482 coalescenceModels_[model].addToCoalescenceRate
490 birthByCoalescence(i, j);
492 deathByCoalescence(i, j);
495 forAll(binaryBreakupPairs_, binaryBreakupPairi)
497 label i = binaryBreakupPairs_[binaryBreakupPairi].first();
498 label j = binaryBreakupPairs_[binaryBreakupPairi].second();
500 binaryBreakupRate_() =
Zero;
502 forAll(binaryBreakupModels_, model)
504 binaryBreakupModels_[model].addToBinaryBreakupRate
506 binaryBreakupRate_(),
512 birthByBinaryBreakup(j, i);
514 deathByBinaryBreakup(j, i);
519 forAll(breakupModels_, model)
521 breakupModels_[model].setBreakupRate(breakupRate_(), i);
523 birthByBreakup(i, model);
532 drift(i, drift_[model]);
535 forAll(nucleation_, model)
537 nucleationRate_() =
Zero;
539 nucleation(i, nucleation_[model]);
545 void Foam::diameterModels::populationBalanceModel::correctDilatationError()
549 HashTable<volScalarField>,
555 const word& phaseName = iter.key();
556 const phaseModel& phase = fluid_.phases()[phaseName];
557 const velocityGroup& velGroup = *velocityGroupPtrs_[phaseName];
565 forAll(velGroup.sizeGroups(), i)
567 const sizeGroup& fi = velGroup.sizeGroups()[i];
569 dilatationError -= Su_[fi.i()] -
fvc::Sp(Sp_[fi.i()], fi);
575 void Foam::diameterModels::populationBalanceModel::calcAlphas()
579 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
581 const phaseModel& phase = iter()->phase();
583 alphas_() +=
max(phase, phase.residualAlpha());
589 Foam::diameterModels::populationBalanceModel::calcDsm()
591 tmp<volScalarField> tInvDsm
603 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
605 const phaseModel& phase = iter()->phase();
607 invDsm +=
max(phase, phase.residualAlpha())/(phase.d()*alphas_());
614 void Foam::diameterModels::populationBalanceModel::calcVelocity()
618 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
620 const phaseModel& phase = iter()->phase();
622 U_() +=
max(phase, phase.residualAlpha())*phase.U()/alphas_();
626 bool Foam::diameterModels::populationBalanceModel::updateSources()
628 const bool result = sourceUpdateCounter_ % sourceUpdateInterval() == 0;
630 ++ sourceUpdateCounter_;
636 template<
class EtaType,
class VType>
637 EtaType Foam::diameterModels::populationBalanceModel::eta
643 const label n = sizeGroups().size();
649 i > 0 ? sizeGroups()[i - 1].x() : rootVSmallV;
652 i <
n - 1 ? sizeGroups()[i + 1].x() : rootVSmallV;
654 return max(
min((v - x0)/(xi - x0), (x1 - v)/(x1 - xi)), z);
658 template<
class EtaType,
class VType>
659 EtaType Foam::diameterModels::populationBalanceModel::etaV
665 const label n = sizeGroups().size();
672 i > 0 ? 1/sizeGroups()[i - 1].x() : rootVGreatInvV;
675 i <
n - 1 ? 1/sizeGroups()[i + 1].x() : rootVSmallInvV;
679 1/
min(
max(v, sizeGroups().
first().
x()), sizeGroups().last().
x())
682 return max(
min((invV - x0)/(xi - x0), (x1 - invV)/(x1 - xi)), z);
705 mesh_(fluid_.mesh()),
709 fluid_.subDict(
"populationBalanceCoeffs").subDict(name_)
715 IOobject::groupName(
"alpha", dict_.lookup(
"continuousPhase"))
736 dict_.lookup(
"coalescenceModels"),
743 dict_.lookup(
"breakupModels"),
749 dict_.lookup(
"binaryBreakupModels"),
752 binaryBreakupRate_(),
753 binaryBreakupPairs_(),
756 dict_.lookup(
"driftModels"),
762 dict_.lookup(
"nucleationModels"),
769 sourceUpdateCounter_(0)
776 <<
"The populationBalance " << name_
777 <<
" requires a minimum number of three sizeGroups to be specified."
791 dilatationErrors_.insert
864 this->initialiseDmdtfs();
866 if (coalescenceModels_.size() != 0)
885 for (
label j = 0; j <= i; j++)
887 coalescencePairs_.append(
labelPair(i, j));
892 if (breakupModels_.size() != 0)
910 if (binaryBreakupModels_.size() != 0)
912 binaryBreakupRate_.set
938 while (delta_[j][i].value() != 0)
940 binaryBreakupPairs_.append(
labelPair(i, j));
946 if (drift_.size() != 0)
964 if (nucleation_.size() != 0)
987 if (velocityGroupPtrs_.size() > 1)
1069 return eta<dimensionedScalar>(i, v);
1074 Foam::diameterModels::populationBalanceModel::eta
1080 return eta<tmp<volScalarField::Internal>>(i, v);
1090 return etaV<dimensionedScalar>(i, v);
1095 Foam::diameterModels::populationBalanceModel::etaV
1101 return etaV<tmp<volScalarField::Internal>>(i, v);
1121 continuousPhase_.name()
1128 if (!solveOnFinalIterOnly() || fluid_.pimple().finalIter())
1130 const label nCorr = this->nCorr();
1131 const scalar tolerance =
1132 mesh_.solution().solverDict(name_).lookup<scalar>(
"tolerance");
1134 const bool updateSrc = updateSources();
1136 if (nCorr > 0 && updateSrc)
1142 scalar maxInitialResidual = 1;
1144 while (++iCorr <= nCorr && maxInitialResidual > tolerance)
1146 Info<<
"populationBalance "
1157 correctDilatationError();
1159 maxInitialResidual = 0;
1168 dilatationErrors_[phase.
name()];
1174 +
fvm::Sp(-(1 - small)*dilatationError, fi)
1185 /this->mesh().time().deltaT(),
1191 sizeGroupEqn.
relax();
1193 fluid_.fvConstraints().constrain(sizeGroupEqn);
1195 maxInitialResidual =
max
1197 sizeGroupEqn.
solve().initialResidual(),
1201 fluid_.fvConstraints().constrain(fi);
1207 sizeGroups().
first()*sizeGroups().
first().phase()
1212 sizeGroups().last()*sizeGroups().last().phase()
1215 Info<< this->
name() <<
" sizeGroup phase fraction first, last = "
1225 if (velocityGroupPtrs_.size() > 1)
#define forAll(list, i)
Loop across all elements in list.
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
dimensioned< Type > weightedAverage(const DimensionedField< scalar, GeoMesh > &) const
Calculate and return weighted average.
Generic GeometricField class.
static tmp< GeometricField< Type, PatchField, GeoMesh > > New(const word &name, const Internal &, const PtrList< PatchField< Type >> &, const HashPtrTable< Source > &=HashPtrTable< Source >())
Return a temporary field constructed from name,.
An STL-conforming hash table.
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
bool found(const Key &) const
Return true if hashedEntry is found in table.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
const Time & time() const
Return time.
IOobject(const word &name, const fileName &instance, const objectRegistry ®istry, readOption r=NO_READ, writeOption w=NO_WRITE, bool registerObject=true)
Construct from name, instance, registry, io options.
const word & name() const
Return name.
static word groupName(Name name, const word &group)
bool good() const
Return true if next operation might succeed.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
const phaseModel & phase() const
Return the phase.
Base class for binary breakup models that provide a breakup rate between a size class pair directly,...
Base class for breakup models which provide a total breakup rate and a separate daughter size distrib...
Base class for coalescence models.
Constant dispersed-phase particle diameter model.
Base class for drift models.
Base class for nucleation models.
static void retrieve(const populationBalanceModel &popBal, HashTable< const velocityGroup * > &velGroupPtrs, UPtrList< sizeGroup > &szGroupPtrs)
Retrieve the pointers.
Return a pointer to a new populationBalanceModel object created on.
Model for tracking the evolution of a dispersed phase size distribution due to coalescence (synonymou...
bool writeData(Ostream &) const
Dummy write for regIOobject.
void correct()
Correct derived quantities.
autoPtr< populationBalanceModel > clone() const
Return clone.
populationBalanceModel(const phaseSystem &fluid, const word &name)
Construct for a fluid.
const UPtrList< sizeGroup > & sizeGroups() const
Return the size groups belonging to this populationBalance.
const tmp< volScalarField > sigmaWithContinuousPhase(const phaseModel &dispersedPhase) const
Return the surface tension coefficient between a given dispersed.
const fvMesh & mesh() const
Return reference to the mesh.
const phaseCompressibleMomentumTransportModel & continuousTurbulence() const
Return reference to momentumTransport model of the continuous phase.
virtual ~populationBalanceModel()
Destructor.
void solve()
Solve the population balance equation.
Single size class fraction field representing a fixed particle volume as defined by the user through ...
const phaseModel & phase() const
Return const-reference to the phase.
Computes the Sauter mean diameter based on a user specified size distribution, defined in terms of si...
const word & name() const
Return const reference to name.
A special matrix type and solver, designed for finite volume solutions of scalar equations....
void relax(const scalar alpha)
Relax matrix (for steady-state solution).
SolverPerformance< Type > solve(const dictionary &)
Solve segregated or coupled returning the solution statistics.
const Time & time() const
Return the top-level database.
Templated abstract base class for multiphase compressible turbulence models.
Class to represent an interface between phases. Derivations can further specify the configuration of ...
tmp< volScalarField > sigma() const
Surface tension coefficient.
const dimensionedScalar & residualAlpha() const
Return the residual phase-fraction for given phase.
const word & name() const
Return the name of this phase.
virtual const volScalarField & rho() const =0
Return the density field.
virtual tmp< surfaceScalarField > alphaPhi() const =0
Return the volumetric flux of the phase.
Class to represent a system of phases and model interfacial transfers between them.
void validateMassTransfer(const phaseInterface &interface) const
Check that mass transfer is supported across the given interface.
HashPtrTable< volScalarField, phaseInterfaceKey, phaseInterfaceKey::hash > dmdtfTable
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
A class for managing temporary objects.
A class for handling words, derived from string.
#define notImplemented(functionName)
Issue a FatalErrorIn for a function not currently implemented.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Calculate the first temporal derivative.
Calculate the divergence of the given field.
Calculate the field for explicit evaluation of implicit and explicit sources.
Calculate the matrix for the first temporal derivative.
Calculate the matrix for the divergence of the given field and flux.
Calculate the matrix for implicit and explicit sources.
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
defineTypeNameAndDebug(constant, 0)
tmp< VolField< Type > > ddt(const dimensioned< Type > dt, const fvMesh &mesh)
tmp< VolField< Type > > Su(const VolField< Type > &su, const VolField< Type > &vf)
tmp< VolField< Type > > Sp(const volScalarField &sp, const VolField< Type > &vf)
tmp< VolField< Type > > div(const SurfaceField< Type > &ssf)
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const VolField< Type > &vf, const word &name)
tmp< fvMatrix< Type > > Sp(const volScalarField::Internal &, const VolField< Type > &)
tmp< fvMatrix< Type > > SuSp(const volScalarField::Internal &, const VolField< Type > &)
tmp< fvMatrix< Type > > ddt(const VolField< Type > &vf)
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensionedScalar pos(const dimensionedScalar &ds)
Pair< label > labelPair
Label pair.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Ostream & endl(Ostream &os)
Add newline and flush stream.
word name(const bool)
Return a word representation of a bool.
const dimensionSet dimless
const dimensionSet dimLength
labelList first(const UList< labelPair > &p)
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
const dimensionSet dimTime
const dimensionSet dimDensity
const dimensionSet dimVolume
VolField< scalar > volScalarField
dimensioned< scalar > mag(const dimensioned< Type > &)
word typedName(Name name)
Return the name of the object within the given type.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix.
dimensionedScalar neg(const dimensionedScalar &ds)
const dimensionSet dimVelocity
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.