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/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.C b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.C
index 02b761dc47..c3a6bb68a8 100644
--- a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.C
+++ b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.C
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
- \\ / A nd | Copyright (C) 2017-2021 OpenFOAM Foundation
+ \\ / A nd | Copyright (C) 2017-2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@@ -24,10 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "sizeDistribution.H"
-#include "Time.H"
-#include "fvMesh.H"
#include "addToRunTimeSelectionTable.H"
-#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -45,19 +42,21 @@ const char*
Foam::NamedEnum
<
Foam::functionObjects::sizeDistribution::functionType,
- 4
+ 6
>::names[] =
{
- "moments",
- "standardDeviation",
- "number",
- "volume"
+ "numberConcentration",
+ "numberDensity",
+ "volumeConcentration",
+ "volumeDensity",
+ "areaConcentration",
+ "areaDensity"
};
const Foam::NamedEnum
<
Foam::functionObjects::sizeDistribution::functionType,
- 4
+ 6
> Foam::functionObjects::sizeDistribution::functionTypeNames_;
template<>
@@ -80,10 +79,122 @@ const Foam::NamedEnum
4
> Foam::functionObjects::sizeDistribution::coordinateTypeNames_;
+
+namespace Foam
+{
+ template<>
+ const char* NamedEnum
+ <
+ Foam::functionObjects::sizeDistribution::weightType,
+ 4
+ >::names[] =
+ {
+ "numberConcentration",
+ "volumeConcentration",
+ "areaConcentration",
+ "cellVolume"
+ };
+}
+
+
+const Foam::NamedEnum
+<
+ Foam::functionObjects::sizeDistribution::weightType,
+ 4
+>
+Foam::functionObjects::sizeDistribution::weightTypeNames_;
+
using Foam::constant::mathematical::pi;
-// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
+// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
+
+Foam::word Foam::functionObjects::sizeDistribution::functionTypeSymbolicName()
+{
+ word functionTypeSymbolicName(word::null);
+
+ switch (functionType_)
+ {
+ case functionType::numberConcentration:
+ {
+ functionTypeSymbolicName = "N";
+
+ break;
+ }
+ case functionType::numberDensity:
+ {
+ functionTypeSymbolicName = "n";
+
+ break;
+ }
+ case functionType::volumeConcentration:
+ {
+ functionTypeSymbolicName = "V";
+
+ break;
+ }
+ case functionType::volumeDensity:
+ {
+ functionTypeSymbolicName = "v";
+
+ break;
+ }
+ case functionType::areaConcentration:
+ {
+ functionTypeSymbolicName = "A";
+
+ break;
+ }
+ case functionType::areaDensity:
+ {
+ functionTypeSymbolicName = "a";
+
+ break;
+ }
+ }
+
+ return functionTypeSymbolicName;
+}
+
+
+Foam::word Foam::functionObjects::sizeDistribution::coordinateTypeSymbolicName
+(
+ const coordinateType& cType
+)
+{
+ word coordinateTypeSymbolicName(word::null);
+
+ switch (cType)
+ {
+ case coordinateType::volume:
+ {
+ coordinateTypeSymbolicName = "v";
+
+ break;
+ }
+ case coordinateType::area:
+ {
+ coordinateTypeSymbolicName = "a";
+
+ break;
+ }
+ case coordinateType::diameter:
+ {
+ coordinateTypeSymbolicName = "d";
+
+ break;
+ }
+ case coordinateType::projectedAreaDiameter:
+ {
+ coordinateTypeSymbolicName = "dPa";
+
+ break;
+ }
+ }
+
+ return coordinateTypeSymbolicName;
+}
+
Foam::tmp
Foam::functionObjects::sizeDistribution::filterField
@@ -102,252 +213,120 @@ Foam::functionObjects::sizeDistribution::filterField
}
-void Foam::functionObjects::sizeDistribution::correctVolAverages()
+Foam::scalar Foam::functionObjects::sizeDistribution::averageCoordinateValue
+(
+ const Foam::diameterModels::sizeGroup& fi,
+ const coordinateType& cType
+)
{
- forAll(N_, i)
+ scalar averageCoordinateValue(Zero);
+
+ switch (cType)
{
- const Foam::diameterModels::sizeGroup& fi = popBal_.sizeGroups()[i];
-
- scalarField Ni(filterField(fi*fi.phase()/fi.x()));
- scalarField V(filterField(mesh_.V()));
- scalarField ai(filterField(fi.a()));
- scalarField di(Ni.size());
-
- switch (coordinateType_)
+ case coordinateType::volume:
{
- case ctProjectedAreaDiameter:
- {
- di = sqrt(ai/pi);
-
- break;
- }
- default:
- {
- di = fi.d();
-
- break;
- }
- }
-
- N_[i] = gSum(V*Ni)/this->V();
- V_[i] = fi.x().value();
- a_[i] = gSum(V*ai)/this->V();
- d_[i] = gSum(V*di)/this->V();
- }
-}
-
-
-void Foam::functionObjects::sizeDistribution::writeMoments()
-{
- logFiles::write();
-
- Log << " writing moments of size distribution." << endl;
-
- if (Pstream::master())
- {
- writeTime(file());
- }
-
- const scalarField& bin = this->bin();
-
- for (label k = 0; k <= maxOrder_; k++)
- {
- scalar result = 0;
-
- forAll(N_, i)
- {
- result += pow(bin[i], k)*N_[i];
- }
-
- if (Pstream::master())
- {
- file() << tab << result;
- }
- }
-
- if (Pstream::master())
- {
- file() << endl;
- }
-}
-
-
-void Foam::functionObjects::sizeDistribution::writeStdDev()
-{
- logFiles::write();
-
- Log << " writing standard deviation of size distribution."
- << endl;
-
- if (Pstream::master())
- {
- writeTime(file());
- }
-
- scalar stdDev = 0;
- scalar mean = 0;
- scalar var = 0;
-
- const scalarField& bin = this->bin();
-
- if (sum(N_) != 0)
- {
- if (geometric_)
- {
- mean = exp(sum(Foam::log(bin)*N_/sum(N_)));
-
- var =
- sum(sqr(Foam::log(bin) - Foam::log(mean))
- *N_/sum(N_));
-
- stdDev = exp(sqrt(var));
- }
- else
- {
- mean = sum(bin*N_/sum(N_));
-
- var = sum(sqr(bin - mean)*N_/sum(N_));
-
- stdDev = sqrt(var);
- }
- }
-
- if (Pstream::master())
- {
- file() << tab << stdDev << tab << mean << tab << var << endl;
- }
-}
-
-
-void Foam::functionObjects::sizeDistribution::writeDistribution()
-{
- scalarField result(N_);
-
- const scalarField& bin = this->bin();
-
- switch (functionType_)
- {
- case ftNumber:
- {
- Log << " writing number distribution. "
- << endl;
+ averageCoordinateValue = fi.x().value();
break;
}
- case ftVolume:
+ case coordinateType::area:
{
- Log << " writing volume distribution. "
- << endl;
-
- result *= V_;
+ averageCoordinateValue =
+ weightedAverage(fi.a(), fi);
break;
}
- default:
+ case coordinateType::diameter:
{
+ averageCoordinateValue =
+ weightedAverage(fi.d(), fi);
+
break;
}
+ case coordinateType::projectedAreaDiameter:
+ {
+ averageCoordinateValue =
+ weightedAverage(sqrt(fi.a()/pi), fi);
+ break;
+ }
}
- if (normalise_)
+ return averageCoordinateValue;
+}
+
+
+Foam::scalar Foam::functionObjects::sizeDistribution::weightedAverage
+(
+ const Foam::scalarField& fld,
+ const Foam::diameterModels::sizeGroup& fi
+)
+{
+ scalar weightedAverage(Zero);
+
+ switch (weightType_)
{
- if(sum(result) != 0)
+ case weightType::numberConcentration:
{
- result /= sum(result);
- }
+ scalarField Ni(filterField(fi*fi.phase()/fi.x().value()));
- }
-
- if (densityFunction_)
- {
- List bndrs(N_.size() + 1);
-
- bndrs.first() = bin.first();
- bndrs.last() = bin.last();
-
- for (label i = 1; i < N_.size(); i++)
- {
- bndrs[i] = (bin[i]+ bin[i-1])/2.0;
- }
-
- forAll(result, i)
- {
- if (geometric_)
+ if (gSum(Ni) == 0)
{
- result[i] /=
- (Foam::log(bndrs[i+1]) - Foam::log(bndrs[i]));
+ weightedAverage =
+ gSum(filterField(mesh_.V()*fld))/this->V();
}
else
{
- result[i] /= (bndrs[i+1] - bndrs[i]);
+ weightedAverage =
+ gSum(Ni*filterField(fld))/gSum(Ni);
}
+
+ break;
}
- }
-
- if (Pstream::master())
- {
- formatterPtr_->write
- (
- file_.baseTimeDir(),
- name(),
- coordSet(true, "volume", V_),
- "area",
- a_,
- "diameter",
- d_,
- word(functionTypeNames_[functionType_])
- + (densityFunction_ ? "Density" : "Concentration"),
- result
- );
- }
-}
-
-
-void Foam::functionObjects::sizeDistribution::writeFileHeader
-(
- const label i
-)
-{
- volRegion::writeFileHeader(*this, file());
-
- writeHeaderValue
- (
- file(),
- "Coordinate",
- word(coordinateTypeNames_[coordinateType_])
- );
-
- word str("Time");
-
- switch (functionType_)
- {
- case ftMoments:
+ case weightType::volumeConcentration:
{
- for (label k = 0; k <= maxOrder_; k++)
+ scalarField Vi(filterField(fi*fi.phase()));
+
+ if (gSum(Vi) == 0)
{
- str += (" k=" + std::to_string(k));
+ weightedAverage =
+ gSum(filterField(mesh_.V()*fld))/this->V();
+ }
+ else
+ {
+ weightedAverage =
+ gSum(Vi*filterField(fld))/gSum(Vi);
}
break;
}
-
- case ftStdDev:
+ case weightType::areaConcentration:
{
- str += " standardDeviation mean variance";
+ scalarField Ai(filterField(fi.a().ref()*fi.phase()));
+
+ if (gSum(Ai) == 0)
+ {
+ weightedAverage =
+ gSum(filterField(mesh_.V()*fld))/this->V();
+ }
+ else
+ {
+ weightedAverage =
+ gSum(Ai*filterField(fld))/gSum(Ai);
+ }
break;
}
-
- default:
+ case weightType::cellVolume:
{
+ weightedAverage =
+ gSum(filterField(mesh_.V()*fld))/this->V();
+
break;
}
}
- writeCommented(file(), str);
-
- file() << endl;
+ return weightedAverage;
}
@@ -362,9 +341,8 @@ Foam::functionObjects::sizeDistribution::sizeDistribution
:
fvMeshFunctionObject(name, runTime, dict),
volRegion(fvMeshFunctionObject::mesh_, dict),
- logFiles(obr_, name),
- mesh_(fvMeshFunctionObject::mesh_),
file_(obr_, name),
+ mesh_(fvMeshFunctionObject::mesh_),
popBal_
(
obr_.lookupObject
@@ -374,10 +352,26 @@ Foam::functionObjects::sizeDistribution::sizeDistribution
),
functionType_(functionTypeNames_.read(dict.lookup("functionType"))),
coordinateType_(coordinateTypeNames_.read(dict.lookup("coordinateType"))),
- N_(popBal_.sizeGroups().size(), 0),
- V_(popBal_.sizeGroups().size(), 0),
- a_(popBal_.sizeGroups().size(), 0),
- d_(popBal_.sizeGroups().size(), 0)
+ allCoordinates_
+ (
+ dict.lookupOrDefault("allCoordinates", false)
+ ),
+ normalise_(dict.lookupOrDefault("normalise", false)),
+ logTransform_
+ (
+ dict.lookupOrDefaultBackwardsCompatible
+ (
+ {"logTransform", "geometric"},
+ false
+ )
+ ),
+ weightType_
+ (
+ dict.found("weightType")
+ ? weightTypeNames_.read(dict.lookup("weightType"))
+ : weightType::numberConcentration
+ ),
+ formatterPtr_(nullptr)
{
read(dict);
}
@@ -393,17 +387,12 @@ Foam::functionObjects::sizeDistribution::~sizeDistribution()
bool Foam::functionObjects::sizeDistribution::read(const dictionary& dict)
{
+ Log << type() << " " << name() << ":" << nl;
+
fvMeshFunctionObject::read(dict);
- normalise_ = dict.lookupOrDefault("normalise", false);
- densityFunction_ = dict.lookupOrDefault("densityFunction", false);
- geometric_ = dict.lookupOrDefault("geometric", false);
- maxOrder_ = dict.lookupOrDefault("maxOrder", 3);
-
formatterPtr_ = setWriter::New(dict.lookup("setFormat"), dict);
- resetName(name());
-
return false;
}
@@ -414,43 +403,255 @@ bool Foam::functionObjects::sizeDistribution::execute()
}
-bool Foam::functionObjects::sizeDistribution::end()
-{
- return true;
-}
-
-
bool Foam::functionObjects::sizeDistribution::write()
{
Log << type() << " " << name() << " write:" << nl;
- correctVolAverages();
+ const UPtrList& sizeGroups =
+ popBal_.sizeGroups();
+
+ scalarField coordinateValues(sizeGroups.size());
+ scalarField boundaryValues(sizeGroups.size() + 1);
+ scalarField resultValues(sizeGroups.size());
+
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ coordinateValues[i] = averageCoordinateValue(fi, coordinateType_);
+ }
+
+ if
+ (
+ functionType_ == functionType::numberDensity
+ || functionType_ == functionType::volumeDensity
+ || functionType_ == functionType::areaDensity
+ )
+ {
+ if (logTransform_)
+ {
+ boundaryValues.first() = Foam::log(coordinateValues.first());
+ boundaryValues.last() = Foam::log(coordinateValues.last());
+
+ for (label i = 1; i < boundaryValues.size() - 1; i++)
+ {
+ boundaryValues[i] =
+ 0.5
+ *(
+ Foam::log(coordinateValues[i])
+ + Foam::log(coordinateValues[i-1])
+ );
+ }
+ }
+ else
+ {
+ boundaryValues.first() = coordinateValues.first();
+ boundaryValues.last() = coordinateValues.last();
+
+ for (label i = 1; i < boundaryValues.size() - 1; i++)
+ {
+ boundaryValues[i] =
+ (coordinateValues[i] + coordinateValues[i-1])/2;
+ }
+ }
+ }
switch (functionType_)
{
- case ftMoments:
+ case functionType::numberConcentration:
{
- writeMoments();
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum(filterField(mesh_.V()*fi*fi.phase()/fi.x()))*this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
break;
}
-
- case ftStdDev:
+ case functionType::numberDensity:
{
- writeStdDev();
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum(filterField(mesh_.V()*fi*fi.phase()/fi.x()))*this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
+
+ forAll(resultValues, i)
+ {
+ resultValues[i] /= (boundaryValues[i+1] - boundaryValues[i]);
+ }
break;
}
-
- default:
+ case functionType::volumeConcentration:
{
- writeDistribution();
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum(filterField(mesh_.V()*fi*fi.phase()))*this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
+
+ break;
+ }
+ case functionType::volumeDensity:
+ {
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum(filterField(mesh_.V()*fi*fi.phase()))*this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
+
+ forAll(resultValues, i)
+ {
+ resultValues[i] /= (boundaryValues[i+1] - boundaryValues[i]);
+ }
+
+ break;
+ }
+ case functionType::areaConcentration:
+ {
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum
+ (
+ filterField(mesh_.V()*fi.a().ref()*fi*fi.phase()/fi.x())
+ )
+ *this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
+
+ break;
+ }
+ case functionType::areaDensity:
+ {
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ resultValues[i] =
+ gSum
+ (
+ filterField(mesh_.V()*fi.a().ref()*fi*fi.phase()/fi.x())
+ )
+ *this->V();
+ }
+
+ if (normalise_ && sum(resultValues) != 0)
+ {
+ resultValues /= sum(resultValues);
+ }
+
+ forAll(resultValues, i)
+ {
+ resultValues[i] /= (boundaryValues[i+1] - boundaryValues[i]);
+ }
break;
}
}
- Log << endl;
+
+ if (allCoordinates_)
+ {
+ wordList otherCoordinateSymbolicNames(coordinateTypeNames_.size());
+ PtrList otherCoordinateValues(coordinateTypeNames_.size());
+ typedef NamedEnum namedEnumCoordinateType;
+
+ forAllConstIter(namedEnumCoordinateType, coordinateTypeNames_, iter)
+ {
+ const coordinateType cType = coordinateTypeNames_[iter.key()];
+
+ otherCoordinateSymbolicNames[cType] =
+ coordinateTypeSymbolicName(cType);
+
+ otherCoordinateValues.set
+ (
+ cType,
+ new scalarField(popBal_.sizeGroups().size())
+ );
+
+ forAll(sizeGroups, i)
+ {
+ const diameterModels::sizeGroup& fi = sizeGroups[i];
+
+ otherCoordinateValues[cType][i] =
+ averageCoordinateValue(fi, cType);
+ }
+ }
+
+ if (Pstream::master())
+ {
+ formatterPtr_->write
+ (
+ file_.baseTimeDir(),
+ name(),
+ coordSet
+ (
+ true,
+ coordinateTypeSymbolicName(coordinateType_),
+ coordinateValues
+ ),
+ functionTypeSymbolicName(),
+ resultValues,
+ otherCoordinateSymbolicNames,
+ otherCoordinateValues
+ );
+ }
+ }
+ else
+ {
+ if (Pstream::master())
+ {
+ formatterPtr_->write
+ (
+ file_.baseTimeDir(),
+ name(),
+ coordSet
+ (
+ true,
+ coordinateTypeSymbolicName(coordinateType_),
+ coordinateValues
+ ),
+ functionTypeSymbolicName(),
+ resultValues
+ );
+ }
+ }
return true;
}
diff --git a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.H b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.H
index ea684746cc..b08ec2773b 100644
--- a/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.H
+++ b/applications/solvers/multiphase/multiphaseEulerFoam/functionObjects/sizeDistribution/sizeDistribution.H
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
- \\ / A nd | Copyright (C) 2017-2021 OpenFOAM Foundation
+ \\ / A nd | Copyright (C) 2017-2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@@ -25,42 +25,42 @@ Class
Foam::functionObjects::sizeDistribution
Description
- This function object calculates and outputs volume-averaged information
- about the size distribution of the dispersed phase, such as the number
- density function or its moments. It is designed to be used exclusively with
- the population balance modeling functionality of the multiphaseEulerFoam
- solver. It can be applied to a specific cellZone or the entire domain. The
- function type determines whether the density function and its moments are
- based on the number of dispersed phase elements in a size group or their
- total volume.
+ Writes out the size distribution computed with multiphaseEulerFoam for the
+ entire domain or a volume region. Requires solver post-processing.
+
+ The following function object specification for example returns the volume-
+ based number density function:
Example of function object specification:
\verbatim
numberDensity
{
- type sizeDistribution;
- libs ("libmultiphaseEulerFoamFunctionObjects.so");
- ...
+ type sizeDistribution;
+ libs ("libmultiphaseEulerFoamFunctionObjects.so");
+ writeControl writeTime;
populationBalance bubbles;
- regionType cellZone;
- name zone0;
- functionType number;
+ functionType numberDensity;
coordinateType volume;
- densityFunction yes;
+ setFormat raw;
}
\endverbatim
Usage
\table
- Property | Description | Required | Default value
- type | type name: sizeDistribution | yes |
- populationBalance | corresponding populationBalance | yes |
- functionType | number/volume/moments/stdDev | yes |
- coordinateType | used for density/moment calculation | yes |
- normalise | normalise concentrations | no | no
- densityFunction | compute densityFunction | no | no
- logBased | use log of coordinate for density | no | no
- maxOrder | maxim order of moment output | no | 3
+ Property | Description | Required | Default
+ populationBalance | population balance name | yes |
+ functionType | function type | yes |
+ coordinateType | particle property | yes |
+ allCoordinates | write all coordinate values | no | false
+ normalise | divide by total concentration | no | false
+ logTransform | class width based on log of coordinate\\
+ | no | false
+ weightType | weighting in case of field-dependent particle\\
+ properties | no\\
+ | numberConcentration
+ regionType | cellZone or all | no | all
+ name | name of cellZone if required | no |
+ setFormat | output format | yes |
\endtable
SourceFiles
@@ -73,7 +73,6 @@ SourceFiles
#include "fvMeshFunctionObject.H"
#include "volRegion.H"
-#include "logFiles.H"
#include "populationBalanceModel.H"
#include "writeFile.H"
#include "setWriter.H"
@@ -92,8 +91,7 @@ namespace functionObjects
class sizeDistribution
:
public fvMeshFunctionObject,
- public volRegion,
- public logFiles
+ public volRegion
{
public:
@@ -102,111 +100,101 @@ public:
//- Function type enumeration
enum functionType
{
- ftMoments,
- ftStdDev,
- ftNumber,
- ftVolume
+ numberConcentration,
+ numberDensity,
+ volumeConcentration,
+ volumeDensity,
+ areaConcentration,
+ areaDensity
};
- //- Ordinate type names
- static const NamedEnum functionTypeNames_;
+ //- Function type names
+ static const NamedEnum functionTypeNames_;
//- Coordinate type enumeration
enum coordinateType
{
- ctVolume,
- ctArea,
- ctDiameter,
- ctProjectedAreaDiameter
+ volume,
+ area,
+ diameter,
+ projectedAreaDiameter
};
//- Coordinate type names
static const NamedEnum coordinateTypeNames_;
+ //- Enumeration for the weight types
+ enum class weightType
+ {
+ numberConcentration,
+ volumeConcentration,
+ areaConcentration,
+ cellVolume
+ };
-protected:
+ //- Names of the weight types
+ static const NamedEnum weightTypeNames_;
- // Protected Data
- //- Reference to fvMesh
- const fvMesh& mesh_;
+private:
- //- File containing data for all functionTypes except moments
+ // Private Data
+
+ //- Write file
writeFile file_;
- //- Output formatter
- autoPtr formatterPtr_;
+ //- Reference to mesh
+ const fvMesh& mesh_;
- //- Reference to populationBalanceModel
+ //- Reference to population balance
const Foam::diameterModels::populationBalanceModel& popBal_;
- //- Function to evaluate
+ //- Function type
functionType functionType_;
- //- Abscissa type
+ //- Coordinate type
coordinateType coordinateType_;
- //- List of volume-averaged number concentrations
- scalarField N_;
+ //- Add values for all coordinate types to output
+ Switch allCoordinates_;
- //- ???
- scalarField V_;
-
- //- List of volume-averaged surface areas
- scalarField a_;
-
- //- List of volume-averaged diameters
- scalarField d_;
-
- //- Normalise number/volume concentrations
+ //- Normalise result through division by sum
Switch normalise_;
- //- Determines whether density function is calculated
- Switch densityFunction_;
+ //- Log transform
+ Switch logTransform_;
- //- Geometric standard deviation/density function
- Switch geometric_;
+ //- Weight types, relevant if particle properties are field dependent
+ weightType weightType_;
- //- Highest moment order
- label maxOrder_;
+ //- Set formatter
+ autoPtr formatterPtr_;
- // Protected Member Functions
+ // Private Member Functions
- //- Filter field according to cellIds
+ //- Function type symbolic name for shorter file header
+ word functionTypeSymbolicName();
+
+ //- Coordinate type symbolic name for shorter file header
+ word coordinateTypeSymbolicName(const coordinateType& cType);
+
+ //- Filter a field according to cellIds
tmp filterField(const scalarField& field) const;
- //- Bin component used according to chosen coordinate type
- inline const scalarField& bin() const
- {
- switch (coordinateType_)
- {
- case ctVolume:
- return V_;
- case ctArea:
- return a_;
- case ctDiameter:
- return d_;
- case ctProjectedAreaDiameter:
- return d_;
- }
- return scalarField::null();
- }
+ //- Field averaged coordinate value
+ scalar averageCoordinateValue
+ (
+ const diameterModels::sizeGroup& fi,
+ const coordinateType& cType
+ );
- //- Correct volume averages
- void correctVolAverages();
-
- //- Write moments
- void writeMoments();
-
- //- Write standard deviation
- void writeStdDev();
-
- //- Write distribution
- void writeDistribution();
-
- //- Output file header information for functionType moments
- virtual void writeFileHeader(const label i);
+ //- Weighted average
+ scalar weightedAverage
+ (
+ const scalarField& fld,
+ const diameterModels::sizeGroup& fi
+ );
public:
@@ -235,21 +223,18 @@ public:
// Member Functions
- //- Read the sizeDistribution data
- virtual bool read(const dictionary&);
-
//- Return the list of fields required
virtual wordList fields() const
{
return wordList::null();
}
+ //- Read the sizeDistribution data
+ virtual bool read(const dictionary&);
+
//- Execute, currently does nothing
virtual bool execute();
- //- Execute at the final time-loop, currently does nothing
- virtual bool end();
-
//- Calculate and write the size distribution
virtual bool write();
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/etc/caseDicts/postProcessing/multiphase/sizeDistribution b/etc/caseDicts/postProcessing/multiphase/sizeDistribution
new file mode 100644
index 0000000000..71e9034a92
--- /dev/null
+++ b/etc/caseDicts/postProcessing/multiphase/sizeDistribution
@@ -0,0 +1,41 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Version: dev
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+Description
+ Writes out the size distribution computed with multiphaseEulerFoam for the
+ entire domain or a volume region. Requires solver post-processing.
+
+\*---------------------------------------------------------------------------*/
+
+type sizeDistribution;
+libs ("libmultiphaseEulerFoamFunctionObjects.so");
+
+populationBalance ;
+functionType ; // numberConcentration, numberDensity
+ // volumeConcentration, volumeDensity
+ // areaConcentration, areaDensity
+coordinateType ; // volume, area, diameter,
+ // projectedAreaDiameter
+allCoordinates false; // defaults to false
+normalise false; // defaults to false
+logTransform false; // defaults to false, only relevant
+ // for density functions
+weightType numberConcentration; // volumeConcentration,
+ // areaConcentration, cellVolume
+ // relevant for field-dependent
+ // particle properties, defaults to
+ // numberConcentration
+regionType all; // cellZone
+ // defaults to all
+name cellZoneName; // relevant for regionType all
+
+
+setFormat raw;
+writeControl writeTime;
+
+
+// ************************************************************************* //
diff --git a/src/sampling/sampledSet/writers/setWriter.H b/src/sampling/sampledSet/writers/setWriter.H
index 965d5b53f7..8f4aa2d5cd 100644
--- a/src/sampling/sampledSet/writers/setWriter.H
+++ b/src/sampling/sampledSet/writers/setWriter.H
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
- \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
+ \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@@ -69,24 +69,26 @@ public:
//- Helper for variadic write
template
- static inline void setTypeValueSet
+ static inline void appendTypeValueSet
(
UPtrList>& valueSets,
- const label valueSeti,
- const Field& valueSet
- )
- {}
-
- //- Helper for variadic write
- template
- static inline void setTypeValueSet
- (
- UPtrList>& valueSets,
- const label valueSeti,
const Field& valueSet
)
{
- valueSets.set(valueSeti, &valueSet);
+ valueSets.resize(valueSets.size() + 1);
+ valueSets.set(valueSets.size() - 1, nullptr);
+ }
+
+ //- Helper for variadic write
+ template
+ static inline void appendTypeValueSet
+ (
+ UPtrList>& valueSets,
+ const Field& valueSet
+ )
+ {
+ valueSets.resize(valueSets.size() + 1);
+ valueSets.set(valueSets.size() - 1, &valueSet);
}
//- Helper for variadic write
@@ -114,14 +116,11 @@ public:
Args& ... args
)
{
- const label valueSeti =
- valueSetNames.size() - 1 - sizeof...(Args)/2;
-
- valueSetNames[valueSeti] = valueSetName;
- #define SetTypeValueSet(Type, nullArg) \
- setTypeValueSet(Type##ValueSets, valueSeti, valueSet);
- FOR_ALL_FIELD_TYPES(SetTypeValueSet);
- #undef SetTypeValueSet
+ valueSetNames.append(valueSetName);
+ #define AppendTypeValueSet(Type, nullArg) \
+ appendTypeValueSet(Type##ValueSets, valueSet);
+ FOR_ALL_FIELD_TYPES(AppendTypeValueSet);
+ #undef AppendTypeValueSet
unpackTypeValueSets
(
@@ -134,6 +133,68 @@ public:
);
}
+ //- Helper for variadic write
+ template
+ static inline void unpackTypeValueSets
+ (
+ wordList& valueSetNames
+ #define TypeValueSetsNonConstArg(Type, nullArg) \
+ , UPtrList>& Type##ValueSets
+ FOR_ALL_FIELD_TYPES(TypeValueSetsNonConstArg),
+ #undef TypeValueSetsNonConstArg
+ const wordList& valueSetNamesPart,
+ const UPtrList>& valueSetsPart,
+ Args& ... args
+ )
+ {
+ forAll(valueSetNamesPart, i)
+ {
+ valueSetNames.append(valueSetNamesPart[i]);
+ #define AppendTypeValueSet(Type, nullArg) \
+ appendTypeValueSet(Type##ValueSets, valueSetsPart[i]);
+ FOR_ALL_FIELD_TYPES(AppendTypeValueSet);
+ #undef AppendTypeValueSet
+ }
+
+ unpackTypeValueSets
+ (
+ valueSetNames
+ #define TypeValueSetsParameter(Type, nullArg) \
+ , Type##ValueSets
+ FOR_ALL_FIELD_TYPES(TypeValueSetsParameter),
+ #undef TypeValueSetsParameter
+ args ...
+ );
+ }
+
+ //- Helper for variadic write
+ template
+ static inline void unpackTypeValueSets
+ (
+ wordList& valueSetNames
+ #define TypeValueSetsNonConstArg(Type, nullArg) \
+ , UPtrList>& Type##ValueSets
+ FOR_ALL_FIELD_TYPES(TypeValueSetsNonConstArg),
+ #undef TypeValueSetsNonConstArg
+ const wordList& valueSetNamesPart,
+ const PtrList>& valueSetsPart,
+ Args& ... args
+ )
+ {
+ unpackTypeValueSets
+ (
+ valueSetNames
+ #define TypeValueSetsParameter(Type, nullArg) \
+ , Type##ValueSets
+ FOR_ALL_FIELD_TYPES(TypeValueSetsParameter),
+ #undef TypeValueSetsParameter
+ valueSetNamesPart,
+ reinterpret_cast>&>
+ (valueSetsPart),
+ args ...
+ );
+ }
+
protected:
@@ -345,11 +406,9 @@ public:
const Args& ... args
) const
{
- const label nFields = sizeof...(Args)/2;
-
- wordList valueSetNames(nFields);
+ wordList valueSetNames;
#define DeclareTypeValueSets(Type, nullArg) \
- UPtrList> Type##ValueSets(nFields);
+ UPtrList> Type##ValueSets;
FOR_ALL_FIELD_TYPES(DeclareTypeValueSets);
#undef DeclareTypeValueSets
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/system/controlDict b/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/system/controlDict
index f52e70d8d2..e49e4664ff 100644
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/system/controlDict
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/system/controlDict
@@ -52,21 +52,13 @@ maxDeltaT 1;
functions
{
- numberDensity
- {
- type sizeDistribution;
- functionObjectLibs ("libmultiphaseEulerFoamFunctionObjects.so");
-
- writeControl outputTime;
- writeInterval 1;
-
- setFormat raw;
-
- populationBalance bubbles;
- functionType number;
- coordinateType volume;
- densityFunction yes;
- }
+ #includeFunc sizeDistribution
+ (
+ populationBalance=bubbles,
+ functionType=numberDensity,
+ coordinateType=volume,
+ funcName=numberDensity
+ )
}
// ************************************************************************* //
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/validation/createGraphs b/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/validation/createGraphs
index 8b7909d56c..a3fd7df831 100755
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/validation/createGraphs
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/binaryBreakup/validation/createGraphs
@@ -31,9 +31,9 @@ gnuplot<
-50
-(
-0.00300040563
-0.00300110488
-0.00300180018
-0.00300249358
-0.00300318666
-0.00300387818
-0.00300457055
-0.00300526257
-0.00300595539
-0.00300664879
-0.00300734302
-0.00300803811
-0.00300873419
-0.00300943126
-0.00301012937
-0.00301082851
-0.00301152868
-0.00301222987
-0.00301293204
-0.00301363515
-0.00301433916
-0.00301504402
-0.00301574966
-0.00301645602
-0.00301716301
-0.00301787056
-0.00301857858
-0.00301928697
-0.00301999563
-0.00302070448
-0.00302141342
-0.00302212238
-0.00302283129
-0.00302354009
-0.00302424876
-0.00302495726
-0.0030256656
-0.00302637377
-0.00302708181
-0.00302778974
-0.0030284976
-0.00302920541
-0.00302991328
-0.00303062095
-0.00303132989
-0.00303203401
-0.00303275902
-0.00303342196
-0.00303447928
-0.00303514582
-)
-;
-
-boundaryField
-{
- inlet
- {
- type calculated;
- value uniform 0.00300000033;
- }
- outlet
- {
- type calculated;
- value uniform 0.00303514582;
- }
- walls
- {
- type calculated;
- value nonuniform List
-200
-(
-0.00300040563
-0.00300110488
-0.00300180018
-0.00300249358
-0.00300318666
-0.00300387818
-0.00300457055
-0.00300526257
-0.00300595539
-0.00300664879
-0.00300734302
-0.00300803811
-0.00300873419
-0.00300943126
-0.00301012937
-0.00301082851
-0.00301152868
-0.00301222987
-0.00301293204
-0.00301363515
-0.00301433916
-0.00301504402
-0.00301574966
-0.00301645602
-0.00301716301
-0.00301787056
-0.00301857858
-0.00301928697
-0.00301999563
-0.00302070448
-0.00302141342
-0.00302212238
-0.00302283129
-0.00302354009
-0.00302424876
-0.00302495726
-0.0030256656
-0.00302637377
-0.00302708181
-0.00302778974
-0.0030284976
-0.00302920541
-0.00302991328
-0.00303062095
-0.00303132989
-0.00303203401
-0.00303275902
-0.00303342196
-0.00303447928
-0.00303514582
-0.00300040563
-0.00300110488
-0.00300180018
-0.00300249358
-0.00300318666
-0.00300387818
-0.00300457055
-0.00300526257
-0.00300595539
-0.00300664879
-0.00300734302
-0.00300803811
-0.00300873419
-0.00300943126
-0.00301012937
-0.00301082851
-0.00301152868
-0.00301222987
-0.00301293204
-0.00301363515
-0.00301433916
-0.00301504402
-0.00301574966
-0.00301645602
-0.00301716301
-0.00301787056
-0.00301857858
-0.00301928697
-0.00301999563
-0.00302070448
-0.00302141342
-0.00302212238
-0.00302283129
-0.00302354009
-0.00302424876
-0.00302495726
-0.0030256656
-0.00302637377
-0.00302708181
-0.00302778974
-0.0030284976
-0.00302920541
-0.00302991328
-0.00303062095
-0.00303132989
-0.00303203401
-0.00303275902
-0.00303342196
-0.00303447928
-0.00303514582
-0.00300040563
-0.00300110488
-0.00300180018
-0.00300249358
-0.00300318666
-0.00300387818
-0.00300457055
-0.00300526257
-0.00300595539
-0.00300664879
-0.00300734302
-0.00300803811
-0.00300873419
-0.00300943126
-0.00301012937
-0.00301082851
-0.00301152868
-0.00301222987
-0.00301293204
-0.00301363515
-0.00301433916
-0.00301504402
-0.00301574966
-0.00301645602
-0.00301716301
-0.00301787056
-0.00301857858
-0.00301928697
-0.00301999563
-0.00302070448
-0.00302141342
-0.00302212238
-0.00302283129
-0.00302354009
-0.00302424876
-0.00302495726
-0.0030256656
-0.00302637377
-0.00302708181
-0.00302778974
-0.0030284976
-0.00302920541
-0.00302991328
-0.00303062095
-0.00303132989
-0.00303203401
-0.00303275902
-0.00303342196
-0.00303447928
-0.00303514582
-0.00300040563
-0.00300110488
-0.00300180018
-0.00300249358
-0.00300318666
-0.00300387818
-0.00300457055
-0.00300526257
-0.00300595539
-0.00300664879
-0.00300734302
-0.00300803811
-0.00300873419
-0.00300943126
-0.00301012937
-0.00301082851
-0.00301152868
-0.00301222987
-0.00301293204
-0.00301363515
-0.00301433916
-0.00301504402
-0.00301574966
-0.00301645602
-0.00301716301
-0.00301787056
-0.00301857858
-0.00301928697
-0.00301999563
-0.00302070448
-0.00302141342
-0.00302212238
-0.00302283129
-0.00302354009
-0.00302424876
-0.00302495726
-0.0030256656
-0.00302637377
-0.00302708181
-0.00302778974
-0.0030284976
-0.00302920541
-0.00302991328
-0.00303062095
-0.00303132989
-0.00303203401
-0.00303275902
-0.00303342196
-0.00303447928
-0.00303514582
-)
-;
- }
-}
-
-
-// ************************************************************************* //
diff --git a/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/Allclean b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/Allclean
index fa9dc48dcc..70690e08bb 100755
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/Allclean
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/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/negativeDrift/system/controlDict b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/system/controlDict
index b16b25fcfd..829675d7d3 100644
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/system/controlDict
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/system/controlDict
@@ -28,7 +28,7 @@ deltaT 0.01;
writeControl runTime;
-writeInterval 4;
+writeInterval 0.2;
purgeWrite 0;
@@ -52,37 +52,38 @@ maxDeltaT 1;
functions
{
- numberDensity
- {
- type sizeDistribution;
- functionObjectLibs ("libmultiphaseEulerFoamFunctionObjects.so");
+ #includeFunc sizeDistribution
+ (
+ populationBalance=bubbles,
+ functionType=numberDensity,
+ coordinateType=volume,
+ funcName=numberDensity
+ )
- writeControl outputTime;
- writeInterval 1;
+ #includeFunc moments
+ (
+ populationBalance=bubbles,
+ momentType=integerMoment,
+ coordinateType=volume,
+ order=1
+ )
- setFormat raw;
+ #includeFunc moments
+ (
+ populationBalance=bubbles,
+ momentType=integerMoment,
+ coordinateType=volume,
+ order=0
+ )
- populationBalance bubbles;
- functionType number;
- coordinateType volume;
- densityFunction yes;
- }
-
- moments
- {
- type sizeDistribution;
- functionObjectLibs ("libmultiphaseEulerFoamFunctionObjects.so");
-
- writeControl runTime;
- writeInterval 0.1;
-
- 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/negativeDrift/validation/createGraphs b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/validation/createGraphs
index a635a60ae5..be0d849e47 100755
--- a/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/validation/createGraphs
+++ b/test/multiphase/multiphaseEulerFoam/populationBalance/negativeDrift/validation/createGraphs
@@ -23,7 +23,7 @@ gnuplot<