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 "stringListOps.H"
31 #include "ListOps.H"
32 #include "ListListOps.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 template<class CloudType>
38 {
39  this->writeHeaderValue(os, "nBin", nBins_);
40  this->writeHeaderValue(os, "min", range_.min());
41  this->writeHeaderValue(os, "max", range_.max());
42  this->writeHeader(os, "");
43  this->writeCommented(os, "dEdge1");
44  os << tab << "dEdge2"
45  << tab << "nParticles"
46  << tab << "nParticlesCumulative"
47  << endl;
48 }
49 
50 
51 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
52 
53 template<class CloudType>
55 (
56  const dictionary& dict,
57  CloudType& owner,
58  const word& modelName
59 )
60 :
61  CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
62  functionObjects::writeFile
63  (
64  owner,
65  this->localPath(),
66  typeName
67  ),
68  collector_(this->coeffDict(), owner.mesh()),
69  nBins_
70  (
71  this->coeffDict().template getCheck<label>("nBins", labelMinMax::ge(1))
72  ),
73  maxStoredParcels_(this->coeffDict().getScalar("maxStoredParcels")),
74  range_
75  (
76  this->coeffDict().getScalar("min"),
77  this->coeffDict().getScalar("max")
78  ),
79  binEdges_(nBins_ + 1),
80  nParticlesCumulative_(),
81  dParticles_(),
82  nParticles_()
83 {
84  writeFile::read(this->coeffDict());
85 
86  if (!range_.good())
87  {
89  << "Invalid histogram range: " << range_
90  << exit(FatalIOError);
91  }
92 
93  if (maxStoredParcels_ <= 0)
94  {
96  << "maxStoredParcels = " << maxStoredParcels_
97  << ", cannot be equal to or less than zero"
98  << exit(FatalIOError);
99  }
100 
101  // Compute histogram-bin properties
102  binEdges_[0] = range_.min();
103  const scalar delta = range_.span()/scalar(nBins_);
104  for (label i = 0; i < nBins_; ++i)
105  {
106  const scalar next = range_.min() + (i+1)*delta;
107  binEdges_[i+1] = next;
108  }
109 
110  const label sz = collector_.size();
111  nParticlesCumulative_ = List<scalarList>(sz, scalarList(nBins_, Zero));
112  dParticles_.resize(sz);
113  nParticles_.resize(sz);
114 }
115 
116 
117 template<class CloudType>
119 (
121 )
122 :
124  writeFile(ph),
125  collector_(ph.collector_),
126  nBins_(ph.nBins_),
127  maxStoredParcels_(ph.maxStoredParcels_),
128  range_(ph.range_),
129  binEdges_(ph.binEdges_),
130  nParticlesCumulative_(ph.nParticlesCumulative_),
131  dParticles_(ph.dParticles_),
132  nParticles_(ph.nParticles_)
133 {}
134 
135 
136 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
137 
138 template<class CloudType>
140 (
141  const parcelType& p,
142  const polyPatch& pp,
143  const typename parcelType::trackingData& td
144 )
145 {
146  if (!collector_.isPatch())
147  {
148  return true;
149  }
150 
151  const label patchi = pp.index();
152  const label localPatchi = collector_.IDs().find(patchi);
153 
154  if
155  (
156  localPatchi != -1
157  && dParticles_[localPatchi].size() < maxStoredParcels_
158  )
159  {
160  dParticles_[localPatchi].append(p.d());
161  nParticles_[localPatchi].append(p.nParticle());
162  }
164  return true;
165 }
166 
167 
168 template<class CloudType>
170 (
171  const parcelType& p,
172  const typename parcelType::trackingData& td
173 )
174 {
175  if (collector_.isPatch())
176  {
177  return true;
178  }
179 
180  const labelList& IDs = collector_.IDs();
181  const List<boundBox>& BBs = collector_.BBs();
182  const faceZoneMesh& fzm = this->owner().mesh().faceZones();
183 
184  forAll(IDs, i)
185  {
186  if (!BBs[i].contains(p.position()))
187  {
188  // Quick reject if the particle is not in the face zone bound box
189  continue;
190  }
191 
192  const label zonei = IDs[i];
193  const label localFacei = fzm[zonei].find(p.face());
194 
195  if
196  (
197  localFacei != -1
198  && dParticles_[i].size() < maxStoredParcels_
199  )
200  {
201  dParticles_[i].append(p.d());
202  nParticles_[i].append(p.nParticle());
203  }
204  }
205 
206  return true;
207 }
208 
209 
210 template<class CloudType>
212 {
213  const wordList& names = collector_.names();
214 
215  forAll(names, i)
216  {
217  List<scalarList> procDiameters(Pstream::nProcs());
218  procDiameters[Pstream::myProcNo()] = dParticles_[i];
219  Pstream::gatherList(procDiameters);
220 
221  List<scalarList> procParticles(Pstream::nProcs());
222  procParticles[Pstream::myProcNo()] = nParticles_[i];
223  Pstream::gatherList(procParticles);
224 
225  if (Pstream::master())
226  {
227  scalarList globalDiameters;
228  globalDiameters = ListListOps::combine<scalarList>
229  (
230  procDiameters,
231  accessOp<scalarList>()
232  );
233 
234  scalarList globalParticles;
235  globalParticles = ListListOps::combine<scalarList>
236  (
237  procParticles,
238  accessOp<scalarList>()
239  );
240 
241  // Compute histogram
242  scalarList nParticles(nBins_, Zero);
243  const scalar delta = range_.span()/scalar(nBins_);
244  forAll(globalDiameters, j)
245  {
246  const label bini = (globalDiameters[j] - range_.min())/delta;
247  if (bini >= 0 && bini < nBins_)
248  {
249  nParticles[bini] += globalParticles[j];
250  nParticlesCumulative_[i][bini] += globalParticles[j];
251  }
252  }
253 
254  if (this->writeToFile())
255  {
256  autoPtr<OFstream> osPtr = this->newFileAtTime
257  (
258  names[i],
259  this->owner().time().value()
260  );
261  OFstream& os = osPtr.ref();
262 
263  writeFileHeader(os);
264 
265  forAll(nParticles, j)
266  {
267  os << binEdges_[j] << tab
268  << binEdges_[j + 1] << tab
269  << nParticles[j] << tab
270  << nParticlesCumulative_[i][j]
271  << nl;
272  }
273  }
274  }
275 
276  dParticles_[i].clearStorage();
277  nParticles_[i].clearStorage();
278  }
279 }
280 
281 
282 // ************************************************************************* //
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
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
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
Operations on lists of strings.
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:1074
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:1065
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
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:670
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:627
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
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