diff --git a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/Make/files b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/Make/files
index f7eb685454..4b72b7ff33 100644
--- a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/Make/files
+++ b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/Make/files
@@ -1,3 +1,4 @@
+moments/moments.C
sizeDistribution/sizeDistribution.C
phaseForces/phaseForces.C
phaseMap/phaseMap.C
diff --git a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.C b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.C
new file mode 100644
index 0000000000..e8e5bbb4d1
--- /dev/null
+++ b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.C
@@ -0,0 +1,972 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "moments.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+ defineTypeNameAndDebug(moments, 0);
+ addToRunTimeSelectionTable(functionObject, moments, dictionary);
+}
+}
+
+
+namespace Foam
+{
+ template<>
+ const char* NamedEnum
+ <
+ Foam::functionObjects::moments::momentType,
+ 4
+ >::names[] = {"integerMoment", "mean", "variance", "stdDev"};
+}
+
+
+const Foam::NamedEnum
+<
+ Foam::functionObjects::moments::momentType,
+ 4
+>
+Foam::functionObjects::moments::momentTypeNames_;
+
+
+namespace Foam
+{
+ template<>
+ const char* NamedEnum
+ <
+ Foam::functionObjects::moments::coordinateType,
+ 3
+ >::names[] = {"volume", "area", "diameter"};
+}
+
+
+const Foam::NamedEnum
+<
+ Foam::functionObjects::moments::coordinateType,
+ 3
+>
+Foam::functionObjects::moments::coordinateTypeNames_;
+
+
+namespace Foam
+{
+ template<>
+ const char* NamedEnum
+ <
+ Foam::functionObjects::moments::weightType,
+ 3
+ >::names[] =
+ {
+ "numberConcentration",
+ "volumeConcentration",
+ "areaConcentration"
+ };
+}
+
+
+const Foam::NamedEnum
+<
+ Foam::functionObjects::moments::weightType,
+ 3
+>
+Foam::functionObjects::moments::weightTypeNames_;
+
+
+namespace Foam
+{
+ template<>
+ const char* NamedEnum
+ <
+ Foam::functionObjects::moments::meanType,
+ 3
+ >::names[] = {"arithmetic", "geometric", "notApplicable"};
+}
+
+
+const Foam::NamedEnum
+<
+ Foam::functionObjects::moments::meanType,
+ 3
+>
+Foam::functionObjects::moments::meanTypeNames_;
+
+
+// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
+
+Foam::word Foam::functionObjects::moments::coordinateTypeSymbolicName()
+{
+ word coordinateTypeSymbolicName(word::null);
+
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ coordinateTypeSymbolicName = "v";
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ coordinateTypeSymbolicName = "a";
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ coordinateTypeSymbolicName = "d";
+
+ break;
+ }
+ }
+
+ return coordinateTypeSymbolicName;
+}
+
+
+Foam::word Foam::functionObjects::moments::weightTypeSymbolicName()
+{
+ word weightTypeSymbolicName(word::null);
+
+ switch (weightType_)
+ {
+ case weightType::numberConcentration:
+ {
+ weightTypeSymbolicName = "N";
+
+ break;
+ }
+ case weightType::volumeConcentration:
+ {
+ weightTypeSymbolicName = "V";
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ weightTypeSymbolicName = "A";
+
+ break;
+ }
+ }
+
+ return weightTypeSymbolicName;
+}
+
+
+Foam::word Foam::functionObjects::moments::defaultFldName()
+{
+ word meanName
+ (
+ meanType_ == meanType::geometric
+ ? word(meanTypeNames_[meanType_]).capitalise()
+ : word("")
+ );
+
+ return
+ word
+ (
+ IOobject::groupName
+ (
+ "weighted"
+ + meanName
+ + word(momentTypeNames_[momentType_]).capitalise()
+ + "("
+ + weightTypeSymbolicName()
+ + ","
+ + coordinateTypeSymbolicName()
+ + ")",
+ popBal_.name()
+ )
+ );
+}
+
+
+Foam::word Foam::functionObjects::moments::integerMomentFldName()
+{
+ return
+ word
+ (
+ IOobject::groupName
+ (
+ word(momentTypeNames_[momentType_])
+ + Foam::name(order_)
+ + "("
+ + weightTypeSymbolicName()
+ + ","
+ + coordinateTypeSymbolicName()
+ + ")",
+ popBal_.name()
+ )
+ );
+}
+
+
+void Foam::functionObjects::moments::setDimensions
+(
+ volScalarField& fld,
+ momentType momType
+)
+{
+ switch (momType)
+ {
+ case momentType::integerMoment:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ fld.dimensions().reset
+ (
+ pow(dimVolume, order_)/dimVolume
+ );
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ fld.dimensions().reset
+ (
+ pow(dimArea, order_)/dimVolume
+ );
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ fld.dimensions().reset
+ (
+ pow(dimLength, order_)/dimVolume
+ );
+
+ break;
+ }
+ }
+
+ switch (weightType_)
+ {
+ case weightType::volumeConcentration:
+ {
+ fld.dimensions().reset(fld.dimensions()*dimVolume);
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ fld.dimensions().reset(fld.dimensions()*dimArea);
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ break;
+ }
+ case momentType::mean:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ fld.dimensions().reset(dimVolume);
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ fld.dimensions().reset(dimArea);
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ fld.dimensions().reset(dimLength);
+
+ break;
+ }
+ }
+
+ break;
+ }
+ case momentType::variance:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ fld.dimensions().reset(sqr(dimVolume));
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ fld.dimensions().reset(sqr(dimArea));
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ fld.dimensions().reset(sqr(dimLength));
+
+ break;
+ }
+ }
+
+ if (meanType_ == meanType::geometric)
+ {
+ fld.dimensions().reset(dimless);
+ }
+
+ break;
+ }
+ case momentType::stdDev:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ fld.dimensions().reset(dimVolume);
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ fld.dimensions().reset(dimArea);
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ fld.dimensions().reset(dimLength);
+
+ break;
+ }
+ }
+
+ if (meanType_ == meanType::geometric)
+ {
+ fld.dimensions().reset(dimless);
+ }
+
+ break;
+ }
+ }
+}
+
+
+Foam::tmp
+Foam::functionObjects::moments::totalConcentration()
+{
+ tmp tTotalConcentration
+ (
+ volScalarField::New
+ (
+ "totalConcentration",
+ mesh_,
+ dimensionedScalar(inv(dimVolume), Zero)
+ )
+ );
+
+ volScalarField& totalConcentration = tTotalConcentration.ref();
+
+ switch (weightType_)
+ {
+ case weightType::volumeConcentration:
+ {
+ totalConcentration.dimensions().reset
+ (
+ totalConcentration.dimensions()*dimVolume
+ );
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ totalConcentration.dimensions().reset
+ (
+ totalConcentration.dimensions()*dimArea
+ );
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ forAll(popBal_.sizeGroups(), i)
+ {
+ const Foam::diameterModels::sizeGroup& fi = popBal_.sizeGroups()[i];
+
+ switch (weightType_)
+ {
+ case weightType::numberConcentration:
+ {
+ totalConcentration += fi*fi.phase()/fi.x();
+
+ break;
+ }
+ case weightType::volumeConcentration:
+ {
+ totalConcentration += fi*fi.phase();
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ totalConcentration += fi.a()*fi*fi.phase()/fi.x();
+
+ break;
+ }
+ }
+ }
+
+ return tTotalConcentration;
+}
+
+
+Foam::tmp Foam::functionObjects::moments::mean()
+{
+ tmp tMean
+ (
+ volScalarField::New
+ (
+ "mean",
+ mesh_,
+ dimensionedScalar(dimless, Zero)
+ )
+ );
+
+ volScalarField& mean = tMean.ref();
+
+ setDimensions(mean, momentType::mean);
+
+ volScalarField totalConcentration(this->totalConcentration());
+
+ forAll(popBal_.sizeGroups(), i)
+ {
+ const Foam::diameterModels::sizeGroup& fi = popBal_.sizeGroups()[i];
+
+ volScalarField concentration(fi*fi.phase()/fi.x());
+
+ switch (weightType_)
+ {
+ case weightType::volumeConcentration:
+ {
+ concentration *= fi.x();
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ concentration *= fi.a();
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ switch (meanType_)
+ {
+ case meanType::geometric:
+ {
+ mean.dimensions().reset(dimless);
+
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ dimensionedScalar unitVolume(dimVolume, 1);
+
+ mean +=
+ Foam::log(fi.x()/unitVolume)
+ *concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ dimensionedScalar unitArea(dimArea, 1);
+
+ mean +=
+ Foam::log(fi.a()/unitArea)
+ *concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ dimensionedScalar unitLength(dimLength, 1);
+
+ mean +=
+ Foam::log(fi.d()/unitLength)
+ *concentration/totalConcentration;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ mean += fi.x()*concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ mean += fi.a()*concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ mean += fi.d()*concentration/totalConcentration;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (meanType_ == meanType::geometric)
+ {
+ mean = exp(mean);
+
+ setDimensions(mean, momentType::mean);
+ }
+
+ return tMean;
+}
+
+
+Foam::tmp Foam::functionObjects::moments::variance()
+{
+ tmp tVariance
+ (
+ volScalarField::New
+ (
+ "variance",
+ mesh_,
+ dimensionedScalar(dimless, Zero)
+ )
+ );
+
+ volScalarField& variance = tVariance.ref();
+
+ setDimensions(variance, momentType::variance);
+
+ volScalarField totalConcentration(this->totalConcentration());
+ volScalarField mean(this->mean());
+
+ forAll(popBal_.sizeGroups(), i)
+ {
+ const Foam::diameterModels::sizeGroup& fi = popBal_.sizeGroups()[i];
+
+ volScalarField concentration(fi*fi.phase()/fi.x());
+
+ switch (weightType_)
+ {
+ case weightType::volumeConcentration:
+ {
+ concentration *= fi.x();
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ concentration *= fi.a();
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ switch (meanType_)
+ {
+ case meanType::geometric:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ variance +=
+ sqr(Foam::log(fi.x()/mean))
+ *concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ variance +=
+ sqr(Foam::log(fi.a()/mean))
+ *concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ variance +=
+ sqr(Foam::log(fi.d()/mean))
+ *concentration/totalConcentration;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ variance +=
+ sqr(fi.x() - mean)*concentration/totalConcentration;
+
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ variance +=
+ sqr(fi.a() - mean)*concentration/totalConcentration;
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ variance +=
+ sqr(fi.d() - mean)*concentration/totalConcentration;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return tVariance;
+}
+
+
+Foam::tmp
+Foam::functionObjects::moments::stdDev()
+{
+ switch (meanType_)
+ {
+ case meanType::geometric:
+ {
+ return exp(sqrt(this->variance()));
+ }
+ default:
+ {
+ return sqrt(this->variance());
+ }
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::functionObjects::moments::moments
+(
+ const word& name,
+ const Time& runTime,
+ const dictionary& dict
+)
+:
+ fvMeshFunctionObject(name, runTime, dict),
+ popBal_
+ (
+ obr_.lookupObject
+ (
+ dict.lookup("populationBalance")
+ )
+ ),
+ momentType_(momentTypeNames_.read(dict.lookup("momentType"))),
+ coordinateType_(coordinateTypeNames_.read(dict.lookup("coordinateType"))),
+ weightType_
+ (
+ dict.found("weight")
+ ? weightTypeNames_.read(dict.lookup("weightType"))
+ : weightType::numberConcentration
+ ),
+ meanType_(meanType::notApplicable),
+ order_(-1),
+ fldPtr_(nullptr)
+{
+ read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
+
+Foam::functionObjects::moments::~moments()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+bool Foam::functionObjects::moments::read(const dictionary& dict)
+{
+ fvMeshFunctionObject::read(dict);
+
+ switch (momentType_)
+ {
+ case momentType::integerMoment:
+ {
+ order_ = dict.lookup("order");
+
+ break;
+ }
+ default:
+ {
+ meanType_ =
+ dict.found("meanType")
+ ? meanTypeNames_.read(dict.lookup("meanType"))
+ : meanType::arithmetic;
+
+ break;
+ }
+ }
+
+ switch (momentType_)
+ {
+ case momentType::integerMoment:
+ {
+ fldPtr_.set
+ (
+ new volScalarField
+ (
+ IOobject
+ (
+ this->integerMomentFldName(),
+ mesh_.time().timeName(),
+ mesh_,
+ IOobject::NO_READ,
+ IOobject::NO_WRITE
+ ),
+ mesh_,
+ dimensionedScalar(dimless, Zero)
+ )
+ );
+
+ volScalarField& integerMoment = fldPtr_();
+
+ setDimensions(integerMoment, momentType::integerMoment);
+
+ break;
+ }
+ case momentType::mean:
+ {
+ fldPtr_.set
+ (
+ new volScalarField
+ (
+ IOobject
+ (
+ this->defaultFldName(),
+ mesh_.time().timeName(),
+ mesh_,
+ IOobject::NO_READ,
+ IOobject::NO_WRITE
+ ),
+ this->mean()
+ )
+ );
+
+ break;
+ }
+ case momentType::variance:
+ {
+ fldPtr_.set
+ (
+ new volScalarField
+ (
+ IOobject
+ (
+ this->defaultFldName(),
+ mesh_.time().timeName(),
+ mesh_,
+ IOobject::NO_READ,
+ IOobject::NO_WRITE
+ ),
+ this->variance()
+ )
+ );
+
+ break;
+ }
+ case momentType::stdDev:
+ {
+ fldPtr_.set
+ (
+ new volScalarField
+ (
+ IOobject
+ (
+ this->defaultFldName(),
+ mesh_.time().timeName(),
+ mesh_,
+ IOobject::NO_READ,
+ IOobject::NO_WRITE
+ ),
+ this->stdDev()
+ )
+ );
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool Foam::functionObjects::moments::execute()
+{
+ switch (momentType_)
+ {
+ case momentType::integerMoment:
+ {
+ volScalarField& integerMoment = fldPtr_();
+
+ integerMoment = Zero;
+
+ forAll(popBal_.sizeGroups(), i)
+ {
+ const Foam::diameterModels::sizeGroup& fi =
+ popBal_.sizeGroups()[i];
+
+ volScalarField concentration(fi*fi.phase()/fi.x());
+
+ switch (weightType_)
+ {
+ case weightType::volumeConcentration:
+ {
+ concentration *= fi.x();
+
+ break;
+ }
+ case weightType::areaConcentration:
+ {
+ concentration *= fi.a();
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ switch (coordinateType_)
+ {
+ case coordinateType::volume:
+ {
+ integerMoment +=
+ pow(fi.x(), order_)*concentration;
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ integerMoment +=
+ pow(fi.a(), order_)*concentration;
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ integerMoment +=
+ pow(fi.d(), order_)*concentration;
+
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case momentType::mean:
+ {
+ fldPtr_() = this->mean();
+
+ break;
+ }
+ case momentType::variance:
+ {
+ fldPtr_() = this->variance();
+
+ break;
+ }
+ case momentType::stdDev:
+ {
+ fldPtr_() = sqrt(this->variance());
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool Foam::functionObjects::moments::write()
+{
+ writeObject(fldPtr_->name());
+
+ return true;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.H b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.H
new file mode 100644
index 0000000000..c337a0fc85
--- /dev/null
+++ b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/moments/moments.H
@@ -0,0 +1,258 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Class
+ Foam::functionObjects::moments
+
+Description
+ Calculates and writes out integral (integer moments) or mean properties
+ (mean, variance, standard deviation) of a size distribution computed with
+ multiphaseEulerFoam. Requires solver post-processing.
+
+ The following function object specification for example returns the first
+ moment of the volume-based number density function which is equivalent to
+ the phase fraction of the particulate phase:
+
+ \verbatim
+ moments
+ {
+ type moments;
+ libs ("libmultiphaseEulerFoamFunctionObjects.so");
+ executeControl timeStep;
+ writeControl writeTime;
+ populationBalance bubbles;
+ momentType integerMoment;
+ coordinateType volume;
+ order 1;
+ }
+ \endverbatim
+
+Usage
+ \table
+ Property | Description | Required | Default
+ populationBalance | population balance name | yes |
+ momentType | desired moment of the distribution\\
+ | yes |
+ coordinateType | particle property | yes |
+ weightType | number/volume/area concentration\\
+ | no\\
+ | numberConcentration
+ order | order of integer moment | for integer moments |
+ meanType | arithmetic or geometric | for non-integer moments\\
+ | arithmetic
+ \endtable
+
+See also
+ Foam::diameterModels::populationBalanceModel
+ Foam::functionObjects::fvMeshFunctionObject
+ Foam::functionObject
+
+SourceFiles
+ moments.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef functionObjects_moments_H
+#define functionObjects_moments_H
+
+#include "fvMeshFunctionObject.H"
+#include "populationBalanceModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+
+/*---------------------------------------------------------------------------*\
+ Class moments Declaration
+\*---------------------------------------------------------------------------*/
+
+class moments
+:
+ public fvMeshFunctionObject
+{
+public:
+
+ //- Enumeration for the moment types
+ enum class momentType
+ {
+ integerMoment,
+ mean,
+ variance,
+ stdDev
+ };
+
+ //- Names of the moment types
+ static const NamedEnum momentTypeNames_;
+
+ //- Enumeration for the coordinate types
+ enum class coordinateType
+ {
+ volume,
+ area,
+ diameter
+ };
+
+ //- Names of the coordinate types
+ static const NamedEnum coordinateTypeNames_;
+
+ //- Enumeration for the weight types
+ enum class weightType
+ {
+ numberConcentration,
+ volumeConcentration,
+ areaConcentration
+ };
+
+ //- Names of the weight types
+ static const NamedEnum weightTypeNames_;
+
+ //- Enumeration for the mean types
+ enum class meanType
+ {
+ arithmetic,
+ geometric,
+ notApplicable
+ };
+
+ //- Names of the mean types
+ static const NamedEnum meanTypeNames_;
+
+
+private:
+
+ // Private Data
+
+ //- Reference to population balance
+ const Foam::diameterModels::populationBalanceModel& popBal_;
+
+ //- Moment type
+ momentType momentType_;
+
+ //- Coordinate type
+ coordinateType coordinateType_;
+
+ //- Weight type
+ weightType weightType_;
+
+ //- Mean type
+ meanType meanType_;
+
+ //- Integer moment order
+ int order_;
+
+ //- Result field
+ autoPtr fldPtr_;
+
+
+ // Private Member Functions
+
+ //- Coordinate type symbolic name for shorter field names
+ word coordinateTypeSymbolicName();
+
+ //- Weight type symbolic name for shorter field names
+ word weightTypeSymbolicName();
+
+ //- Default field name
+ word defaultFldName();
+
+ //- Integer moment field name
+ word integerMomentFldName();
+
+ //- Set dimensions
+ void setDimensions(volScalarField& fld, momentType momType);
+
+ //- Total concentration
+ tmp totalConcentration();
+
+ //- Mean value
+ tmp mean();
+
+ //- Variance
+ tmp variance();
+
+ //- Standard deviation
+ tmp stdDev();
+
+
+public:
+
+ //- Runtime type information
+ TypeName("moments");
+
+
+ // Constructors
+
+ //- Construct from Time and dictionary
+ moments
+ (
+ const word& name,
+ const Time& runTime,
+ const dictionary&
+ );
+
+ //- Disallow default bitwise copy construction
+ moments(const moments&) = delete;
+
+
+ //- Destructor
+ virtual ~moments();
+
+
+ // Member Functions
+
+ //- Read the data
+ virtual bool read(const dictionary&);
+
+ //- Return the list of fields required
+ virtual wordList fields() const
+ {
+ return wordList::null();
+ }
+
+ //- Calculate the force fields
+ virtual bool execute();
+
+ //- Write the force fields
+ virtual bool write();
+
+
+ // Member Operators
+
+ //- Disallow default bitwise assignment
+ void operator=(const moments&) = delete;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace functionObjects
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/etc/caseDicts/postProcessing/multiphase/moments b/etc/caseDicts/postProcessing/multiphase/moments
new file mode 100644
index 0000000000..912b856118
--- /dev/null
+++ b/etc/caseDicts/postProcessing/multiphase/moments
@@ -0,0 +1,34 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Version: dev
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+Description
+ Calculates and writes out integral (integer moments) or mean properties
+ (mean, variance, standard deviation) of a size distribution computed with
+ multiphaseEulerFoam. Requires solver post-processing.
+
+\*---------------------------------------------------------------------------*/
+
+type moments;
+libs ("libmultiphaseEulerFoamFunctionObjects.so");
+
+populationBalance ;
+momentType ; // integerMoment, mean, variance,
+ // stdDev
+coordinateType ; // volume, area, diameter
+weightType numberConcentration; // volumeConcentration,
+ // areaConcentration
+ // defaults to numberConcentration
+order 0; // relevant for integer moments only
+mean arithmetic; // geometric
+ // relevant for non-integer moments,
+ // defaults to arithmetic
+
+executeControl timeStep;
+writeControl writeTime;
+
+
+// ************************************************************************* //
diff --git a/etc/caseDicts/postProcessing/forces/phaseForces b/etc/caseDicts/postProcessing/multiphase/phaseForces
similarity index 100%
rename from etc/caseDicts/postProcessing/forces/phaseForces
rename to etc/caseDicts/postProcessing/multiphase/phaseForces
diff --git a/etc/caseDicts/postProcessing/fields/phaseMap b/etc/caseDicts/postProcessing/multiphase/phaseMap
similarity index 100%
rename from etc/caseDicts/postProcessing/fields/phaseMap
rename to etc/caseDicts/postProcessing/multiphase/phaseMap
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/Allclean b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/Allclean
index fa9dc48dcc..70690e08bb 100755
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/Allclean
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/Allclean
@@ -6,6 +6,6 @@ cd "${0%/*}" || exit 1
# Source clean functions
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
-cleanCase && rm -f moments.eps numberDensity.eps
+cleanCase && rm -rf *.eps 0/d.air 0/uniform/ 0/integerMoment*
#------------------------------------------------------------------------------
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/system/controlDict b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/system/controlDict
index 780adb1fe2..ae82fc9175 100644
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/system/controlDict
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/system/controlDict
@@ -28,7 +28,7 @@ deltaT 0.01;
writeControl runTime;
-writeInterval 6;
+writeInterval 0.2;
purgeWrite 0;
@@ -68,21 +68,30 @@ functions
densityFunction yes;
}
- moments
- {
- type sizeDistribution;
- functionObjectLibs ("libmultiphaseEulerFoamFunctionObjects.so");
+ #includeFunc moments
+ (
+ populationBalance=bubbles,
+ momentType=integerMoment,
+ coordinateType=volume,
+ order=1
+ )
- writeControl runTime;
- writeInterval 0.1;
+ #includeFunc moments
+ (
+ populationBalance=bubbles,
+ momentType=integerMoment,
+ coordinateType=volume,
+ order=0
+ )
- setFormat raw;
-
- populationBalance bubbles;
- functionType moments;
- coordinateType volume;
- maxOrder 1;
- }
+ #includeFunc probes
+ (
+ funcName=probes,
+ points=((0.5 0.5 0.5)),
+ integerMoment0(N,v).bubbles,
+ integerMoment1(N,v).bubbles,
+ writeControl=writeTime
+ )
}
// ************************************************************************* //
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/validation/createGraphs b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/validation/createGraphs
index 1520907a1b..924d77fbac 100755
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/drift/validation/createGraphs
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/drift/validation/createGraphs
@@ -36,9 +36,9 @@ gnuplot<