33 #include "surfaceTensionModel.H" 46 namespace diameterModels
55 void Foam::diameterModels::populationBalanceModel::registerVelocityGroups()
59 if (isA<velocityGroup>(fluid_.phases()[
phasei].dPtr()()))
61 const velocityGroup& velGroup =
62 refCast<const velocityGroup>(fluid_.phases()[
phasei].dPtr()());
64 if (velGroup.popBalName() == this->
name())
66 velocityGroupPtrs_.insert(velGroup.phase().name(), &velGroup);
68 dilatationErrors_.insert
70 velGroup.phase().name(),
78 velGroup.phase().name()
80 fluid_.time().timeName(),
88 forAll(velGroup.sizeGroups(), i)
90 this->registerSizeGroups
92 const_cast<sizeGroup&>(velGroup.sizeGroups()[i])
101 void Foam::diameterModels::populationBalanceModel::registerSizeGroups
108 sizeGroups().size() != 0
110 group.x().value() <= sizeGroups().last().x().value()
114 <<
"Size groups must be entered according to their representative" 119 sizeGroups_.resize(sizeGroups().size() + 1);
120 sizeGroups_.set(sizeGroups().size() - 1, &group);
122 if (sizeGroups().size() == 1)
129 sizeGroups().last().
x()
138 sizeGroups().last().
x()
147 sizeGroups()[sizeGroups().size()-2].x()
148 + sizeGroups().last().x()
156 sizeGroups().last().
x()
161 delta_.append(
new PtrList<dimensionedScalar>());
170 fluid_.time().timeName(),
185 fluid_.time().timeName(),
195 void Foam::diameterModels::populationBalanceModel::precompute()
197 forAll(coalescenceModels_, model)
199 coalescenceModels_[model].precompute();
202 forAll(breakupModels_, model)
204 breakupModels_[model].precompute();
206 breakupModels_[model].dsdPtr()->precompute();
209 forAll(binaryBreakupModels_, model)
211 binaryBreakupModels_[model].precompute();
216 drift_[model].precompute();
219 forAll(nucleation_, model)
221 nucleation_[model].precompute();
226 void Foam::diameterModels::populationBalanceModel::birthByCoalescence
232 const sizeGroup& fj = sizeGroups()[j];
233 const sizeGroup& fk = sizeGroups()[
k];
238 for (
label i = j; i < sizeGroups().size(); i++)
242 if (Eta.value() == 0)
continue;
244 const sizeGroup& fi = sizeGroups()[i];
249 0.5*fi.x()/(fj.x()*fk.x())*Eta
250 *coalescenceRate_()*fj*fj.phase()*fk*fk.phase();
255 fi.x()/(fj.x()*fk.x())*Eta
256 *coalescenceRate_()*fj*fj.phase()*fk*fk.phase();
261 const phaseInterface interfaceij(fi.phase(), fj.phase());
263 if (pDmdt_.found(interfaceij))
265 const scalar dmdtSign =
266 interfaceij.index(fi.phase()) == 0 ? +1 : -1;
268 *pDmdt_[interfaceij] += dmdtSign*fj.x()/v*Sui_*fj.phase().rho();
271 const phaseInterface interfaceik(fi.phase(), fk.phase());
273 if (pDmdt_.found(interfaceik))
275 const scalar dmdtSign =
276 interfaceik.index(fi.phase()) == 0 ? +1 : -1;
278 *pDmdt_[interfaceik] += dmdtSign*fk.x()/v*Sui_*fk.phase().rho();
281 sizeGroups_[i].shapeModelPtr()->addCoalescence(Sui_, fj, fk);
286 void Foam::diameterModels::populationBalanceModel::deathByCoalescence
292 const sizeGroup& fi = sizeGroups()[i];
293 const sizeGroup& fj = sizeGroups()[j];
295 Sp_[i] += coalescenceRate_()*fi.phase()*fj*fj.phase()/fj.x();
299 Sp_[j] += coalescenceRate_()*fj.phase()*fi*fi.phase()/fi.x();
304 void Foam::diameterModels::populationBalanceModel::birthByBreakup
310 const sizeGroup& fk = sizeGroups()[
k];
312 for (
label i = 0; i <=
k; i++)
314 const sizeGroup& fi = sizeGroups()[i];
317 fi.x()*breakupModels_[model].dsdPtr()().nik(i, k)/fk.x()
318 *breakupRate_()*fk*fk.phase();
322 const phaseInterface interface(fi.phase(), fk.phase());
324 if (pDmdt_.found(interface))
326 const scalar dmdtSign =
327 interface.index(fi.phase()) == 0 ? +1 : -1;
329 *pDmdt_[interface] += dmdtSign*Sui_*fk.phase().rho();
332 sizeGroups_[i].shapeModelPtr()->addBreakup(Sui_, fk);
337 void Foam::diameterModels::populationBalanceModel::deathByBreakup(
const label i)
339 Sp_[i] += breakupRate_()*sizeGroups()[i].phase();
343 void Foam::diameterModels::populationBalanceModel::calcDeltas()
347 if (delta_[i].empty())
349 for (
label j = 0; j <= sizeGroups().size() - 1; j++)
351 const sizeGroup& fj = sizeGroups()[j];
359 v_[i+1].value() - v_[i].value()
365 v_[i].value() < 0.5*fj.x().value()
367 0.5*fj.x().value() < v_[i+1].value()
370 delta_[i][j] =
mag(0.5*fj.x() - v_[i]);
372 else if (0.5*fj.x().value() <= v_[i].value())
374 delta_[i][j].
value() = 0;
382 void Foam::diameterModels::populationBalanceModel::birthByBinaryBreakup
388 const sizeGroup& fi = sizeGroups()[i];
389 const sizeGroup& fj = sizeGroups()[j];
393 Sui_ = fi.x()*delta_[i][j]/fj.x()*
Su;
397 sizeGroups_[i].shapeModelPtr()->addBreakup(Sui_, fj);
399 const phaseInterface interfaceij(fi.phase(), fj.phase());
401 if (pDmdt_.found(interfaceij))
403 const scalar dmdtSign =
404 interfaceij.index(fi.phase()) == 0 ? +1 : -1;
406 *pDmdt_[interfaceij] += dmdtSign*Sui_*fj.phase().rho();
412 for (
label k = 0; k <= j; k++)
416 if (Eta.value() == 0)
continue;
418 const sizeGroup& fk = sizeGroups()[
k];
422 Suk = fk.x()*delta_[i][j]*Eta/fj.x()*
Su;
426 const phaseInterface interfacekj(fk.phase(), fj.phase());
428 if (pDmdt_.found(interfacekj))
430 const scalar dmdtSign =
431 interfacekj.index(fk.phase()) == 0 ? +1 : -1;
433 *pDmdt_[interfacekj] += dmdtSign*Suk*fj.phase().rho();
436 sizeGroups_[
k].shapeModelPtr()->addBreakup(Suk, fj);
441 void Foam::diameterModels::populationBalanceModel::deathByBinaryBreakup
447 Sp_[i] += sizeGroups()[i].phase()*binaryBreakupRate_()*delta_[j][i];
451 void Foam::diameterModels::populationBalanceModel::drift
457 model.addToDriftRate(driftRate_(), i);
459 const sizeGroup& fp = sizeGroups()[i];
461 if (i < sizeGroups().size() - 1)
463 const sizeGroup& fe = sizeGroups()[i+1];
466 Sp_[i] += 1/(fe.x() - fp.x())*
pos(driftRate_())*driftRate_();
469 fe.x()/(fp.x()*(fe.x() - fp.x()))*
pos(driftRate_())*driftRate_()*fp;
473 const phaseInterface interfacepe(fp.phase(), fe.phase());
475 if (pDmdt_.found(interfacepe))
477 const scalar dmdtSign =
478 interfacepe.index(fp.phase()) == 0 ? +1 : -1;
480 *pDmdt_[interfacepe] -= dmdtSign*Sue*fp.phase().rho();
483 sizeGroups_[i+1].shapeModelPtr()->addDrift(Sue, fp, model);
486 if (i == sizeGroups().size() - 1)
488 Sp_[i] -=
pos(driftRate_())*driftRate_()/fp.x();
493 const sizeGroup& fw = sizeGroups()[i-1];
496 Sp_[i] += 1/(fw.x() - fp.x())*
neg(driftRate_())*driftRate_();
499 fw.x()/(fp.x()*(fw.x() - fp.x()))*
neg(driftRate_())*driftRate_()*fp;
503 const phaseInterface interfacepw(fp.phase(), fw.phase());
505 if (pDmdt_.found(interfacepw))
507 const scalar dmdtSign =
508 interfacepw.index(fp.phase()) == 0 ? +1 : -1;
510 *pDmdt_[interfacepw] -= dmdtSign*Suw*fp.phase().rho();
513 sizeGroups_[i-1].shapeModelPtr()->addDrift(Suw, fp, model);
518 Sp_[i] -=
neg(driftRate_())*driftRate_()/fp.x();
523 void Foam::diameterModels::populationBalanceModel::nucleation
526 nucleationModel& model
529 const sizeGroup& fi = sizeGroups()[i];
531 model.addToNucleationRate(nucleationRate_(), i);
533 Sui_ = fi.x()*nucleationRate_();
537 sizeGroups_[i].shapeModelPtr()->addNucleation(Sui_, fi, model);
541 void Foam::diameterModels::populationBalanceModel::sources()
545 sizeGroups_[i].shapeModelPtr()->reset();
555 forAll(coalescencePairs_, coalescencePairi)
557 label i = coalescencePairs_[coalescencePairi].first();
558 label j = coalescencePairs_[coalescencePairi].second();
560 coalescenceRate_() =
Zero;
562 forAll(coalescenceModels_, model)
564 coalescenceModels_[model].addToCoalescenceRate
572 birthByCoalescence(i, j);
574 deathByCoalescence(i, j);
577 forAll(binaryBreakupPairs_, binaryBreakupPairi)
579 label i = binaryBreakupPairs_[binaryBreakupPairi].first();
580 label j = binaryBreakupPairs_[binaryBreakupPairi].second();
582 binaryBreakupRate_() =
Zero;
584 forAll(binaryBreakupModels_, model)
586 binaryBreakupModels_[model].addToBinaryBreakupRate
588 binaryBreakupRate_(),
594 birthByBinaryBreakup(j, i);
596 deathByBinaryBreakup(j, i);
601 forAll(breakupModels_, model)
603 breakupModels_[model].setBreakupRate(breakupRate_(), i);
605 birthByBreakup(i, model);
614 drift(i, drift_[model]);
617 forAll(nucleation_, model)
619 nucleationRate_() =
Zero;
621 nucleation(i, nucleation_[model]);
627 void Foam::diameterModels::populationBalanceModel::correctDilatationError()
631 HashTable<volScalarField>,
637 const word& phaseName = iter.key();
638 const phaseModel& phase = fluid_.phases()[phaseName];
639 const velocityGroup& velGroup = *velocityGroupPtrs_[phaseName];
645 - (fluid_.fvModels().source(alpha, rho) &
rho)/rho;
647 forAll(velGroup.sizeGroups(), i)
649 const sizeGroup& fi = velGroup.sizeGroups()[i];
651 dilatationError -= Su_[fi.i()] -
fvc::Sp(Sp_[fi.i()], fi);
657 void Foam::diameterModels::populationBalanceModel::calcAlphas()
661 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
663 const phaseModel& phase = iter()->phase();
665 alphas_() +=
max(phase, phase.residualAlpha());
671 Foam::diameterModels::populationBalanceModel::calcDsm()
673 tmp<volScalarField> tInvDsm
685 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
687 const phaseModel& phase = iter()->phase();
689 invDsm +=
max(phase, phase.residualAlpha())/(phase.d()*alphas_());
696 void Foam::diameterModels::populationBalanceModel::calcVelocity()
700 forAllConstIter(HashTable<const velocityGroup*>, velocityGroupPtrs_, iter)
702 const phaseModel& phase = iter()->phase();
704 U_() +=
max(phase, phase.residualAlpha())*phase.U()/alphas_();
708 bool Foam::diameterModels::populationBalanceModel::updateSources()
710 const bool result = sourceUpdateCounter_ % sourceUpdateInterval() == 0;
712 ++ sourceUpdateCounter_;
722 const phaseSystem& fluid,
732 fluid.time().constant(),
738 mesh_(fluid_.
mesh()),
742 fluid_.subDict(
"populationBalanceCoeffs").subDict(name_)
744 pimple_(mesh_.lookupObject<pimpleControl>(
"solutionControl")),
747 mesh_.lookupObject<phaseModel>
749 IOobject::groupName(
"alpha", dict_.
lookup(
"continuousPhase"))
770 dict_.
lookup(
"coalescenceModels"),
771 coalescenceModel::iNew(*this)
777 dict_.
lookup(
"breakupModels"),
778 breakupModel::iNew(*this)
783 dict_.
lookup(
"binaryBreakupModels"),
784 binaryBreakupModel::iNew(*this)
786 binaryBreakupRate_(),
787 binaryBreakupPairs_(),
790 dict_.
lookup(
"driftModels"),
791 driftModel::iNew(*this)
796 dict_.
lookup(
"nucleationModels"),
797 nucleationModel::iNew(*this)
803 sourceUpdateCounter_(0)
805 this->registerVelocityGroups();
807 if (sizeGroups().size() < 3)
810 <<
"The populationBalance " << name_
811 <<
" requires a minimum number of three sizeGroups to be specified." 816 if (coalescenceModels_.size() != 0)
825 mesh_.time().timeName(),
835 for (
label j = 0; j <= i; j++)
837 coalescencePairs_.append(
labelPair(i, j));
842 if (breakupModels_.size() != 0)
851 fluid_.time().timeName(),
860 if (binaryBreakupModels_.size() != 0)
862 binaryBreakupRate_.set
869 fluid_.time().timeName(),
888 while (delta_[j][i].value() != 0)
890 binaryBreakupPairs_.append(
labelPair(i, j));
896 if (drift_.size() != 0)
905 fluid_.time().timeName(),
914 if (nucleation_.size() != 0)
923 fluid_.time().timeName(),
937 if (velocityGroupPtrs_.size() > 1)
946 fluid_.time().timeName(),
963 fluid_.time().timeName(),
980 fluid_.time().timeName(),
1003 return autoPtr<populationBalanceModel>(
nullptr);
1026 if (i != 0) lowerBoundary = sizeGroups()[i-1].x();
1028 if (i != sizeGroups().size() - 1) upperBoundary = sizeGroups()[i+1].x();
1030 if ((i == 0 && v < x0) || (i == sizeGroups().size() - 1 && v > xm))
1034 else if (v < lowerBoundary || v > upperBoundary)
1038 else if (v.value() == xi.value())
1044 return (upperBoundary - v)/(upperBoundary - xi);
1048 return (v - lowerBoundary)/(xi - lowerBoundary);
1056 const phaseModel& dispersedPhase
1059 return phaseInterface(dispersedPhase, continuousPhase_).sigma();
1071 momentumTransportModel::typeName,
1072 continuousPhase_.name()
1080 if (!solveOnFinalIterOnly() || pimple_.finalPimpleIter())
1083 const scalar tolerance =
1084 mesh_.solution().solverDict(name_).lookup<scalar>(
"tolerance");
1092 scalar maxInitialResidual = 1;
1094 while (++iCorr <= nCorr && maxInitialResidual > tolerance)
1096 Info<<
"populationBalance " 1102 if (updateSources())
1107 correctDilatationError();
1109 maxInitialResidual = 0;
1113 sizeGroup& fi = sizeGroups_[i];
1114 const phaseModel& phase = fi.phase();
1118 dilatationErrors_[phase.name()];
1124 -
fvm::Sp(dilatationError, fi)
1128 + fluid_.fvModels().source(alpha, rho, fi)/rho
1133 max(phase.residualAlpha() -
alpha, scalar(0))
1134 /this->
mesh().time().deltaT(),
1140 sizeGroupEqn.relax();
1141 fluid_.fvConstraints().constrain(sizeGroupEqn);
1143 maxInitialResidual =
max 1145 sizeGroupEqn.solve().initialResidual(),
1149 fluid_.fvConstraints().constrain(fi);
1155 sizeGroups().
first()*sizeGroups().
first().phase()
1160 sizeGroups().last()*sizeGroups().last().phase()
1163 Info<< this->
name() <<
" sizeGroup phase fraction first, last = " 1164 << fAlpha0.weightedAverage(this->
mesh().V()).value()
1165 <<
' ' << fAlphaN.weightedAverage(this->
mesh().V()).value()
1173 if (velocityGroupPtrs_.size() > 1)
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix.
labelList first(const UList< labelPair > &p)
fvMatrix< scalar > fvScalarMatrix
#define forAll(list, i)
Loop across all elements in list.
Templated abstract base class for multiphase compressible turbulence models.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
virtual ~populationBalanceModel()
Destructor.
errorManipArg< error, int > exit(error &err, const int errNo=1)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
populationBalanceModel(const phaseSystem &fluid, const word &name, HashPtrTable< volScalarField, phaseInterfaceKey, phaseInterfaceKey::hash > &pDmdt)
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
volScalarField alpha(IOobject("alpha", runTime.timeName(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
static tmp< GeometricField< scalar, fvPatchField, volMesh > > New(const word &name, const Internal &, const PtrList< fvPatchField< scalar >> &)
Return a temporary field constructed from name,.
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
const phaseCompressible::momentumTransportModel & continuousTurbulence() const
Return reference to turbulence model of the continuous phase.
Ostream & endl(Ostream &os)
Add newline and flush stream.
tmp< GeometricField< Type, fvPatchField, volMesh > > Sp(const volScalarField &sp, const GeometricField< Type, fvPatchField, volMesh > &vf)
const dimensionSet dimless
label k
Boltzmann constant.
Generic dimensioned Type class.
bool writeData(Ostream &) const
Dummy write for regIOobject.
tmp< fvMatrix< Type > > Sp(const volScalarField::Internal &, const GeometricField< Type, fvPatchField, volMesh > &)
GeometricField< vector, fvPatchField, volMesh > volVectorField
dimensionedScalar neg(const dimensionedScalar &ds)
const dimensionedScalar eta(const label i, const dimensionedScalar &v) const
Return allocation coefficient.
const dimensionSet dimLength
tmp< GeometricField< Type, fvPatchField, volMesh > > ddt(const dimensioned< Type > dt, const fvMesh &mesh)
autoPtr< populationBalanceModel > clone() const
Return clone.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Calculate the first temporal derivative.
dimensionedScalar pos(const dimensionedScalar &ds)
stressControl lookup("compactNormalStress") >> compactNormalStress
static word groupName(Name name, const word &group)
virtual void precompute()
Precompute diameter independent expressions.
tmp< fvMatrix< Type > > ddt(const GeometricField< Type, fvPatchField, volMesh > &vf)
Calculate the matrix for the first temporal derivative.
const Type & value() const
Return const reference to value.
void correct()
Correct derived quantities.
Pair< label > labelPair
Label pair.
Calculate the field for explicit evaluation of implicit and explicit sources.
Calculate the divergence of the given field.
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
const dimensionSet dimVelocity
defineTypeNameAndDebug(combustionModel, 0)
HashPtrTable< volScalarField, phaseInterfaceKey, phaseInterfaceKey::hash > dmdtfTable
word name(const complex &)
Return a string representation of a complex.
Internal & ref()
Return a reference to the dimensioned internal field.
Calculate the matrix for the divergence of the given field and flux.
#define notImplemented(functionName)
Issue a FatalErrorIn for a function not currently implemented.
phaseCompressibleMomentumTransportModel momentumTransportModel
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
const dimensionSet dimVolume
dimensioned< scalar > mag(const dimensioned< Type > &)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
const tmp< volScalarField > sigmaWithContinuousPhase(const phaseModel &dispersedPhase) const
Return the surface tension coefficient between a given dispersed.
const tmp< volScalarField::Internal > & Su
A class for managing temporary objects.
void solve()
Solve the population balance equation.
tmp< GeometricField< Type, fvPatchField, volMesh > > Su(const GeometricField< Type, fvPatchField, volMesh > &su, const GeometricField< Type, fvPatchField, volMesh > &vf)
Calculate the matrix for implicit and explicit sources.