diff --git a/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H b/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H index 4615278aa00d2d80b22ebb424042a0140304c6c4..ed6c4f6bf95e21c263d23f90aeb2caba1ce0a842 100644 --- a/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H +++ b/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2018 OpenFOAM Foundation + Copyright (C) 2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -37,6 +38,7 @@ License #include "ParticleTrap.H" #include "PatchCollisionDensity.H" #include "PatchPostProcessing.H" +#include "PatchParticleHistogram.H" #include "RemoveParcels.H" #include "VoidFraction.H" @@ -53,6 +55,7 @@ License makeCloudFunctionObjectType(ParticleTrap, CloudType); \ makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \ makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \ + makeCloudFunctionObjectType(PatchParticleHistogram, CloudType); \ makeCloudFunctionObjectType(RemoveParcels, CloudType); \ makeCloudFunctionObjectType(VoidFraction, CloudType); diff --git a/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H b/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H index a11f3de2e2cd9f2c1fa1ae93b58e907fd2ae0468..dd45507c68b131bcdcff2e4920fab76895c65d04 100644 --- a/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H +++ b/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H @@ -38,6 +38,7 @@ License #include "ParticleTrap.H" #include "PatchCollisionDensity.H" #include "PatchPostProcessing.H" +#include "PatchParticleHistogram.H" #include "RemoveParcels.H" #include "VoidFraction.H" #include "WeberNumberReacting.H" @@ -55,6 +56,7 @@ License makeCloudFunctionObjectType(ParticleTrap, CloudType); \ makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \ makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \ + makeCloudFunctionObjectType(PatchParticleHistogram, CloudType); \ makeCloudFunctionObjectType(RemoveParcels, CloudType); \ makeCloudFunctionObjectType(VoidFraction, CloudType); \ makeCloudFunctionObjectType(WeberNumberReacting, CloudType); diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.C b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.C new file mode 100644 index 0000000000000000000000000000000000000000..d60f1723dc14eba7cc8c1a666311e1dcf26a18d7 --- /dev/null +++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.C @@ -0,0 +1,254 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "PatchParticleHistogram.H" +#include "Pstream.H" +#include "stringListOps.H" +#include "ListOps.H" +#include "ListListOps.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +template<class CloudType> +Foam::label Foam::PatchParticleHistogram<CloudType>::applyToPatch +( + const label globalPatchi +) const +{ + return patchIDs_.find(globalPatchi); +} + + +// * * * * * * * * * * * * * protected Member Functions * * * * * * * * * * // + +template<class CloudType> +void Foam::PatchParticleHistogram<CloudType>::write() +{ + forAll(times_, i) + { + List<List<scalar>> procTimes(Pstream::nProcs()); + procTimes[Pstream::myProcNo()] = times_[i]; + Pstream::gatherList(procTimes); + + List<List<scalar>> procDiameters(Pstream::nProcs()); + procDiameters[Pstream::myProcNo()] = patchDiameters_[i]; + Pstream::gatherList(procDiameters); + + List<List<scalar>> procParticles(Pstream::nProcs()); + procParticles[Pstream::myProcNo()] = patchParticles_[i]; + Pstream::gatherList(procParticles); + + if (Pstream::master()) + { + const fvMesh& mesh = this->owner().mesh(); + + mkDir(this->writeTimeDir()); + + const word& patchName = mesh.boundaryMesh()[patchIDs_[i]].name(); + + OFstream patchOutFile + ( + this->writeTimeDir()/patchName + ".post", + IOstream::ASCII, + IOstream::currentVersion, + mesh.time().writeCompression() + ); + + List<scalar> globalTimes; + globalTimes = ListListOps::combine<List<scalar>> + ( + procTimes, + accessOp<List<scalar>>() + ); + + List<scalar> globalDiameters; + globalDiameters = ListListOps::combine<List<scalar>> + ( + procDiameters, + accessOp<List<scalar>>() + ); + + List<scalar> globalParticles; + globalParticles = ListListOps::combine<List<scalar>> + ( + procParticles, + accessOp<List<scalar>>() + ); + + // Compute histogram + List<scalar> nParticles(nBins_, Zero); + forAll(globalDiameters, j) + { + const label bini = (globalDiameters[j] - min_)/delta_; + if (bini >= 0 && bini < nBins_) + { + nParticles[bini] += globalParticles[j]; + nParticlesCumulative_[i][bini] += globalParticles[j]; + } + } + + patchOutFile + << "# nBin=" << nBins_ + << "; min=" << min_ + << "; max=" << max_ << nl + << "# d nParticles nParticlesCumulative" + << endl; + + forAll(nParticles, j) + { + patchOutFile + << binEdges_[j] + << "-" + << binEdges_[j + 1] + << " " + << nParticles[j] + << " " + << nParticlesCumulative_[i][j] + << nl; + } + } + + times_[i].clearStorage(); + patchDiameters_[i].clearStorage(); + patchParticles_[i].clearStorage(); + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class CloudType> +Foam::PatchParticleHistogram<CloudType>::PatchParticleHistogram +( + const dictionary& dict, + CloudType& owner, + const word& modelName +) +: + CloudFunctionObject<CloudType>(dict, owner, modelName, typeName), + nBins_(dict.getCheck<label>("nBins", labelMinMax::ge(1))), + min_(dict.getScalar("min")), + max_(dict.getScalar("max")), + delta_((max_ - min_)/scalar(nBins_)), + maxStoredParcels_(dict.getScalar("maxStoredParcels")), + binEdges_(nBins_ + 1), + patchIDs_(), + nParticlesCumulative_(), + times_(), + patchDiameters_(), + patchParticles_() +{ + if (min_ >= max_) + { + FatalIOErrorInFunction(dict) + << "Histogram minimum = " << min_ + << ", cannot be larger than histogram maximum = " << max_ + << exit(FatalIOError); + } + + if (maxStoredParcels_ <= 0) + { + FatalIOErrorInFunction(dict) + << "maxStoredParcels = " << maxStoredParcels_ + << ", cannot be equal to or less than zero" + << exit(FatalIOError); + } + + // Compute histogram-bin properties + binEdges_[0] = min_; + for (label i = 0; i < nBins_; ++i) + { + const scalar next = min_ + (i+1)*delta_; + binEdges_[i+1] = next; + } + + // Compute histogram-patch properties + const wordRes patchMatcher(dict.get<wordRes>("patches")); + + patchIDs_ = patchMatcher.matching(owner.mesh().boundaryMesh().names()); + + if (patchIDs_.empty()) + { + FatalIOErrorInFunction(dict) + << "No matching patches found: " + << flatOutput(patchMatcher) << nl + << exit(FatalIOError); + } + + nParticlesCumulative_ = + List<List<scalar>>(patchIDs_.size(), List<scalar>(nBins_, Zero)); + + times_.setSize(patchIDs_.size()); + patchDiameters_.setSize(patchIDs_.size()); + patchParticles_.setSize(patchIDs_.size()); +} + + +template<class CloudType> +Foam::PatchParticleHistogram<CloudType>::PatchParticleHistogram +( + const PatchParticleHistogram<CloudType>& ppm +) +: + CloudFunctionObject<CloudType>(ppm), + nBins_(ppm.nBins_), + min_(ppm.min_), + max_(ppm.max_), + delta_(ppm.delta_), + maxStoredParcels_(ppm.maxStoredParcels_), + binEdges_(ppm.binEdges_), + patchIDs_(ppm.patchIDs_), + nParticlesCumulative_(ppm.nParticlesCumulative_), + times_(ppm.times_), + patchDiameters_(ppm.patchDiameters_), + patchParticles_(ppm.patchParticles_) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class CloudType> +void Foam::PatchParticleHistogram<CloudType>::postPatch +( + const parcelType& p, + const polyPatch& pp, + bool& +) +{ + const label patchi = pp.index(); + const label localPatchi = applyToPatch(patchi); + + if (localPatchi != -1 && times_[localPatchi].size() < maxStoredParcels_) + { + times_[localPatchi].append(this->owner().time().value()); + patchDiameters_[localPatchi].append(p.d()); + patchParticles_[localPatchi].append(p.nParticle()); + } +} + + +// ************************************************************************* // diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.H b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.H new file mode 100644 index 0000000000000000000000000000000000000000..c8b3b99239c078c113f8820c384fba84110db16c --- /dev/null +++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchParticleHistogram/PatchParticleHistogram.H @@ -0,0 +1,222 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +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 <http://www.gnu.org/licenses/>. + +Class + Foam::PatchParticleHistogram + +Description + Computes a histogram for the distribution of particle diameters + and corresponding number of particles hitting on a given list of patches. + + Operands: + \table + Operand | Type | Location + input | - | - + output file | dat | $FOAM_CASE/postProcessing/\<FO\>/\<time\>/\<file\> + output field | - | - + \endtable + + The output file contains two columns, the first is the bin edges of + the particle diameter (i.e. \c d), and the second is the number of + particles whose diameter falling into the corresponding bin + (i.e. \c nParticles). + +Usage + Minimal example by using + \c constant/reactingCloud1Properties.cloudFunctions: + \verbatim + patchParticleHistogram1 + { + // Mandatory entries (unmodifiable) + type patchParticleHistogram; + patches (<patch1> <patch2> ... <patchN>); + nBins 10; + min 0.1; + max 10.0; + maxStoredParcels 20; + } + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Reqd | Dflt + type | Type name: patchParticleHistogram | word | yes | - + patches | Names of operand patches | wordList | yes | - + nBins | Number of histogram bins | label | yes | - + max | Maximum value of histogram data | scalar | yes | - + min | Minimum value of histogram data | scalar | yes | - + maxStoredParcels | Maximum number of parcels to process | label | yes | - + \endtable + +Note + - The underlying type of \c maxStoredParcels is set as a scalar for I/O. + +SourceFiles + PatchParticleHistogram.C + +\*---------------------------------------------------------------------------*/ + +#ifndef PatchParticleHistogram_H +#define PatchParticleHistogram_H + +#include "CloudFunctionObject.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class PatchParticleHistogram Declaration +\*---------------------------------------------------------------------------*/ + +template<class CloudType> +class PatchParticleHistogram +: + public CloudFunctionObject<CloudType> +{ + // Private Data + + //- Convenience typedef for parcel type + typedef typename CloudType::particleType parcelType; + + //- Number of data bins + const label nBins_; + + //- Minimum value of histogram data + const scalar min_; + + //- Maximum value of histogram data + const scalar max_; + + //- Bin width of histogram + const scalar delta_; + + //- Maximum number of parcels to store - set as a scalar for I/O + const scalar maxStoredParcels_; + + //- Bin edges of histogram + scalarField binEdges_; + + //- List of patch indices to post-process + labelList patchIDs_; + + //- Accumulated number of particles per patch + //- binned according to the histogram settings + List<List<scalar>> nParticlesCumulative_; + + //- List of time for each data record + List<DynamicList<scalar>> times_; + + // List of patch-hit particle diameters + List<DynamicList<scalar>> patchDiameters_; + + // List of number of patch-hit particles + List<DynamicList<scalar>> patchParticles_; + + + // Private Member Functions + + //- Return local patchi if patch is in patchIds_ list + label applyToPatch(const label globalPatchi) const; + + +protected: + + // Protected Member Functions + + //- Write post-processing info + void write(); + + +public: + + //- Runtime type information + TypeName("patchParticleHistogram"); + + + // Constructors + + //- No default construct + PatchParticleHistogram() = delete; + + //- Construct from dictionary + PatchParticleHistogram + ( + const dictionary& dict, + CloudType& owner, + const word& modelName + ); + + //- Copy construct + PatchParticleHistogram(const PatchParticleHistogram<CloudType>& ppm); + + //- No copy assignment + void operator=(const PatchParticleHistogram<CloudType>&) = delete; + + //- Construct and return a clone + virtual autoPtr<CloudFunctionObject<CloudType>> clone() const + { + return autoPtr<CloudFunctionObject<CloudType>> + ( + new PatchParticleHistogram<CloudType>(*this) + ); + } + + + //- Destructor + virtual ~PatchParticleHistogram() = default; + + + // Member Functions + + // Evaluation + + //- Post-patch hook + virtual void postPatch + ( + const parcelType& p, + const polyPatch& pp, + bool& keepParticle + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "PatchParticleHistogram.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties b/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties index 7b9340864666063f255ea0fb6c100915d3a9f8db..bbda9f138c2f6c68d5620e8870be403fad0b58b3 100644 --- a/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties +++ b/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties @@ -161,6 +161,20 @@ subModels cloudFunctions { + patchParticleHistogram1 + { + type patchParticleHistogram; + patches + ( + cycLeft_half0 + cycLeft_half1 + ); + nBins 30; + min 0.0009; + max 0.001; + maxStoredParcels 20; + } + patchPostProcessing1 { type patchPostProcessing;