ParticleHistogram.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2020-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ParticleHistogram.H"
29 #include "Pstream.H"
30 #include "ListOps.H"
31 #include "ListListOps.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 template<class CloudType>
37 {
38  this->writeHeaderValue(os, "nBin", nBins_);
39  this->writeHeaderValue(os, "min", range_.min());
40  this->writeHeaderValue(os, "max", range_.max());
41  this->writeHeader(os, "");
42  this->writeCommented(os, "dEdge1");
43  os << tab << "dEdge2"
44  << tab << "nParticles"
45  << tab << "nParticlesCumulative"
46  << endl;
47 }
48 
49 
50 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
51 
52 template<class CloudType>
54 (
55  const dictionary& dict,
56  CloudType& owner,
57  const word& modelName
58 )
59 :
60  CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
61  functionObjects::writeFile
62  (
63  owner,
64  this->localPath(),
65  typeName
66  ),
67  collector_(this->coeffDict(), owner.mesh()),
68  nBins_
69  (
70  this->coeffDict().template getCheck<label>("nBins", labelMinMax::ge(1))
71  ),
72  maxStoredParcels_(this->coeffDict().getScalar("maxStoredParcels")),
73  range_
74  (
75  this->coeffDict().getScalar("min"),
76  this->coeffDict().getScalar("max")
77  ),
78  binEdges_(nBins_ + 1),
79  nParticlesCumulative_(),
80  dParticles_(),
81  nParticles_()
82 {
83  writeFile::read(this->coeffDict());
84 
85  if (!range_.good())
86  {
88  << "Invalid histogram range: " << range_
89  << exit(FatalIOError);
90  }
91 
92  if (maxStoredParcels_ <= 0)
93  {
95  << "maxStoredParcels = " << maxStoredParcels_
96  << ", cannot be equal to or less than zero"
97  << exit(FatalIOError);
98  }
99 
100  // Compute histogram-bin properties
101  binEdges_[0] = range_.min();
102  const scalar delta = range_.span()/scalar(nBins_);
103  for (label i = 0; i < nBins_; ++i)
104  {
105  const scalar next = range_.min() + (i+1)*delta;
106  binEdges_[i+1] = next;
107  }
108 
109  const label sz = collector_.size();
110  nParticlesCumulative_ = List<scalarList>(sz, scalarList(nBins_, Zero));
111  dParticles_.resize(sz);
112  nParticles_.resize(sz);
113 }
114 
115 
116 template<class CloudType>
118 (
120 )
121 :
123  writeFile(ph),
124  collector_(ph.collector_),
125  nBins_(ph.nBins_),
126  maxStoredParcels_(ph.maxStoredParcels_),
127  range_(ph.range_),
128  binEdges_(ph.binEdges_),
129  nParticlesCumulative_(ph.nParticlesCumulative_),
130  dParticles_(ph.dParticles_),
131  nParticles_(ph.nParticles_)
132 {}
133 
134 
135 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
136 
137 template<class CloudType>
139 (
140  const parcelType& p,
141  const polyPatch& pp,
142  const typename parcelType::trackingData& td
143 )
144 {
145  if (!collector_.isPatch())
146  {
147  return true;
148  }
149 
150  const label patchi = pp.index();
151  const label localPatchi = collector_.IDs().find(patchi);
152 
153  if
154  (
155  localPatchi != -1
156  && dParticles_[localPatchi].size() < maxStoredParcels_
157  )
158  {
159  dParticles_[localPatchi].append(p.d());
160  nParticles_[localPatchi].append(p.nParticle());
161  }
163  return true;
164 }
165 
166 
167 template<class CloudType>
169 (
170  const parcelType& p,
171  const typename parcelType::trackingData& td
172 )
173 {
174  if (collector_.isPatch())
175  {
176  return true;
177  }
178 
179  const labelList& IDs = collector_.IDs();
180  const List<boundBox>& BBs = collector_.BBs();
181  const faceZoneMesh& fzm = this->owner().mesh().faceZones();
182 
183  forAll(IDs, i)
184  {
185  if (!BBs[i].contains(p.position()))
186  {
187  // Quick reject if the particle is not in the face zone bound box
188  continue;
189  }
190 
191  const label zonei = IDs[i];
192  const label localFacei = fzm[zonei].find(p.face());
193 
194  if
195  (
196  localFacei != -1
197  && dParticles_[i].size() < maxStoredParcels_
198  )
199  {
200  dParticles_[i].append(p.d());
201  nParticles_[i].append(p.nParticle());
202  }
203  }
204 
205  return true;
206 }
207 
208 
209 template<class CloudType>
211 {
212  const wordList& names = collector_.names();
213 
214  forAll(names, i)
215  {
216  List<scalarList> procDiameters(Pstream::nProcs());
217  procDiameters[Pstream::myProcNo()] = dParticles_[i];
218  Pstream::gatherList(procDiameters);
219 
220  List<scalarList> procParticles(Pstream::nProcs());
221  procParticles[Pstream::myProcNo()] = nParticles_[i];
222  Pstream::gatherList(procParticles);
223 
224  if (Pstream::master())
225  {
226  scalarList globalDiameters;
227  globalDiameters = ListListOps::combine<scalarList>
228  (
229  procDiameters,
230  accessOp<scalarList>()
231  );
232 
233  scalarList globalParticles;
234  globalParticles = ListListOps::combine<scalarList>
235  (
236  procParticles,
237  accessOp<scalarList>()
238  );
239 
240  // Compute histogram
241  scalarList nParticles(nBins_, Zero);
242  const scalar delta = range_.span()/scalar(nBins_);
243  forAll(globalDiameters, j)
244  {
245  const label bini = (globalDiameters[j] - range_.min())/delta;
246  if (bini >= 0 && bini < nBins_)
247  {
248  nParticles[bini] += globalParticles[j];
249  nParticlesCumulative_[i][bini] += globalParticles[j];
250  }
251  }
252 
253  if (this->writeToFile())
254  {
255  autoPtr<OFstream> osPtr = this->newFileAtTime
256  (
257  names[i],
258  this->owner().time().value()
259  );
260  OFstream& os = osPtr.ref();
261 
262  writeFileHeader(os);
263 
264  forAll(nParticles, j)
265  {
266  os << binEdges_[j] << tab
267  << binEdges_[j + 1] << tab
268  << nParticles[j] << tab
269  << nParticlesCumulative_[i][j]
270  << nl;
271  }
272  }
273  }
274 
275  dParticles_[i].clearStorage();
276  nParticles_[i].clearStorage();
277  }
278 }
279 
280 
281 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
scalar delta
dictionary dict
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
ParticleHistogram(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
List of names generated by calling name() for each list item and filtered for matches.
static void writeHeader(Ostream &os, const word &fieldName)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
wallPoints::trackData td(isBlockedFace, regionToBlockSize)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
virtual bool postFace(const parcelType &p, const typename parcelType::trackingData &td)
Post-face hook.
A min/max value pair with additional methods. In addition to conveniently storing values...
Definition: HashSet.H:72
virtual bool postPatch(const parcelType &p, const polyPatch &pp, const typename parcelType::trackingData &td)
Post-patch hook.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static void gatherList(const UList< commsStruct > &comms, UList< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
bool good() const
Range is non-inverted.
Definition: MinMaxI.H:165
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
virtual void write()
Write post-processing info.
Computes a histogram for the distribution of particle diameters and corresponding number of particles...
const T & min() const noexcept
The min value (first)
Definition: MinMaxI.H:107
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
dynamicFvMesh & mesh
A class for handling words, derived from Foam::string.
Definition: word.H:63
label size() const noexcept
Return number of collectors (zones or patches)
const dictionary & coeffDict() const
Return const access to the coefficients dictionary.
Definition: subModelBase.C:122
void read(Istream &, label &val, const dictionary &)
In-place read with dictionary lookup.
OBJstream os(runTime.globalPath()/outputName)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:671
List< word > wordList
List of word.
Definition: fileName.H:59
const fvMesh & mesh() const
Return reference to the mesh.
Definition: DSMCCloudI.H:37
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:637
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
T span() const
The min to max span. Zero if the range is invalid.
Definition: MinMaxI.H:143
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:67
Templated cloud function object base class.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127