ParticleZoneInfo.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) 2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
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 "ParticleZoneInfo.H"
29#include "DynamicField.H"
30
31// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32
33namespace Foam
34{
35
37{
38 void operator()(particleInfo& p1, const particleInfo& p2) const
39 {
40 // p2 not set
41 if (p2.origID == -1)
42 {
43 return;
44 }
45
46 // p1 not set - initialise with p2
47 if (p1.origID == -1)
48 {
49 p1 = p2;
50 return;
51 }
52
53 // Set initial values
54 if (p2.time0 < p1.time0)
55 {
56 p1.time0 = p2.time0;
57 p1.d0 = p2.d0;
58 p1.mass0 = p2.mass0;
59 }
60
61 // Accumulate age
62 p1.age += p2.age;
63
64 // Set latest available values
65 if (p2.isOlderThan(p1))
66 {
67 p1.position = p2.position;
68 p1.d = p2.d;
69 p1.mass = p2.mass;
70 }
71 }
72};
73
74template<class Type>
76(
79)
80{
81 Field<Type> result(data.size());
82
83 forAll(data, i)
84 {
85 result[i] = data[i].*field;
86 }
87
88 return result;
89}
90
91} // End namespace Foam
92
93
94// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
95
96template<class CloudType>
98(
99 const UList<particleInfo>& data
100)
101{
102 coordSet coords
103 (
104 "zoneParticles",
105 "xyz",
106 getData(data, &particleInfo::position),
107 scalarList(data.size(), Zero)
108 );
109
110 writerPtr_->open(coords, this->baseTimeDir() / "zoneParticles");
111 writerPtr_->beginTime(this->owner().time());
112
113#undef writeLocal
114#define writeLocal(field) \
115 writerPtr_->write(#field, getData(data, &particleInfo::field));
116
117 writeLocal(origID);
118 writeLocal(origProc);
119 writeLocal(time0);
120 writeLocal(age);
121 writeLocal(d0);
122 writeLocal(d);
123 writeLocal(mass0);
124 writeLocal(mass);
125#undef writeLocal
126
127 writerPtr_->endTime();
128 writerPtr_->close();
129}
130
131
132template<class CloudType>
134{
135 this->writeHeaderValue(os, "cellZone", cellZoneName_);
136 this->writeHeaderValue(os, "time", this->owner().time().timeOutputValue());
137 this->writeHeader(os, "");
138 this->writeCommented(os, "origID");
139 os << tab << "origProc"
140 << tab << "(x y z)"
141 << tab << "time0"
142 << tab << "age"
143 << tab << "d0"
144 << tab << "d"
145 << tab << "mass0"
146 << tab << "mass"
147 << endl;
148}
149
150
151template<class CloudType>
152bool Foam::ParticleZoneInfo<CloudType>::inZone(const label celli) const
153{
154 return this->owner().mesh().cellZones()[cellZoneId_].whichCell(celli) != -1;
155}
156
157
158template<class CloudType>
160(
161 const particleInfo& p
162) const
163{
164 forAll(data_, i)
165 {
166 const auto& d = data_[i];
167 if ((d.origProc == p.origProc) && (d.origID == p.origID))
168 {
169 return i;
170 }
171 }
172
173 return -1;
174}
175
176
177// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
178
179template<class CloudType>
181(
182 const dictionary& dict,
183 CloudType& owner,
184 const word& modelName
185)
186:
187 CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
188 functionObjects::writeFile
189 (
190 owner,
191 this->localPath(),
192 typeName
193 ),
194 cellZoneName_(this->coeffDict().getWord("cellZone")),
195 cellZoneId_(-1),
196 data_(),
197 movedParticles_(),
198 maxIDs_(Pstream::nProcs(), Zero),
199 writerPtr_
200 (
201 Pstream::master()
203 (
204 this->coeffDict().getWord("writer"),
205 this->coeffDict().subOrEmptyDict("formatOptions")
206 )
207 : nullptr
208 )
209{
210 writeFile::read(this->coeffDict());
211
212 const auto& cellZones = owner.mesh().cellZones();
213
214 cellZoneId_ = cellZones.findZoneID(cellZoneName_);
215 if (cellZoneId_ == -1)
216 {
218 << "Unable to find cellZone " << cellZoneName_
219 << ". Available cellZones are:" << cellZones.names()
220 << exit(FatalIOError);
221 }
222
223 Info<< " Processing cellZone" << cellZoneName_ << " with id "
224 << cellZoneId_ << endl;
225
226 if (Pstream::master())
227 {
228 // Data was reduced on write
229 labelList maxIDs;
230
231 if (this->getModelProperty("maxIDs", maxIDs))
232 {
233 if (maxIDs.size() == Pstream::nProcs())
234 {
235 maxIDs_ = maxIDs;
236 this->getModelProperty("data", data_);
237
238 Info<< " Restarting with " << data_.size()
239 << " particles" << endl;
240 }
241 else
242 {
244 << "Case restarted with a different number of processors."
245 << " Restarting particle statistics." << endl;
246
247 // TODO
248 // - use Cloud for base storage instead of local particle list?
249 }
250 }
251 }
252}
253
254
255template<class CloudType>
257(
259)
260:
262 writeFile(pzi),
263 cellZoneName_(pzi.cellZoneName_),
264 cellZoneId_(pzi.cellZoneId_),
265 data_(pzi.data_),
266 movedParticles_(pzi.movedParticles_),
267 maxIDs_(Pstream::nProcs()),
268 writerPtr_(nullptr)
269{}
270
271
272// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
273
274template<class CloudType>
276(
277 const typename parcelType::trackingData& td
278)
279{}
280
281
282template<class CloudType>
284(
285 const typename parcelType::trackingData& td
286)
287{
288 Info<< this->type() << ":" << nl
289 << " Cell zone = " << cellZoneName_ << nl
290 << " Contributions = "
291 << returnReduce(movedParticles_.size(), sumOp<label>())
292 << endl;
293
294 if (!this->writeTime())
295 {
296 Info<< endl;
297 }
298
299 for (const auto& p : movedParticles_)
300 {
301 const label id = getParticleID(p);
302
303 if (id == -1)
304 {
305 // New particle
306 data_.append(p);
307 maxIDs_[p.origProc] = max(maxIDs_[p.origProc], p.origID);
308 }
309 else
310 {
311 // Add to existing particle
312 data_[id] += p;
313 }
314 }
315
316 movedParticles_.clear();
317
318 // Calls write
320}
321
322
323template<class CloudType>
325(
326 parcelType& p,
327 const scalar dt,
328 const point&,
329 bool&
330)
331{
332 if (inZone(p.cell()))
333 {
334 particleInfo newData;
335 newData.origID = p.origId();
336 newData.origProc = p.origProc();
337 newData.position = p.position();
338 newData.time0 = this->owner().time().value() + dt;
339 newData.age = dt;
340 newData.d0 = p.d();
341 newData.d = p.d();
342 newData.mass0 = p.mass();
343 newData.mass = newData.mass0;
344
345 movedParticles_.append(newData);
346 }
347}
348
349
350template<class CloudType>
352{
353 autoPtr<OFstream> osPtr =
354 this->createFile("particles", this->owner().time().timeOutputValue());
355
356 if (Pstream::parRun())
357 {
358 // Find number of particles per proc
359 labelList allMaxIDs(maxIDs_);
361 Pstream::broadcast(allMaxIDs);
362
363 // Combine into single list
364 label n = returnReduce(data_.size(), sumOp<label>());
365 DynamicList<particleInfo> globalParticles(n);
366 {
368 forAll(procParticles, proci)
369 {
370 procParticles[proci].resize(allMaxIDs[proci] + 1);
371 }
372
373 // Insert into bins for accumulation
374 for (const auto& d : data_)
375 {
376 procParticles[d.origProc][d.origID] = d;
377 }
378
379 for (auto& particles : procParticles)
380 {
382 for (const auto& p : particles)
383 {
384 if (p.origID != -1)
385 {
386 globalParticles.append(p);
387 }
388 }
389 }
390 }
391
392 if (Pstream::master())
393 {
394 writeWriter(globalParticles);
395
396 auto& os = osPtr();
397 writeFileHeader(os);
398
399 label nData = 0;
400
401 for (const auto& p : globalParticles)
402 {
403 if (p.origID != -1)
404 {
405 os << p << endl;
406 ++nData;
407 }
408 }
409
410 Info<< " Number of particles = " << nData << nl
411 << " Written data to " << os.name() << endl;
412
413 this->setModelProperty("data", globalParticles);
414 this->setModelProperty("maxIDs", allMaxIDs);
415 }
416 else
417 {
418 // Data only present on master
419 this->setModelProperty("data", List<particleInfo>());
420 this->setModelProperty("maxIDs", labelList());
421 }
422 }
423 else
424 {
425 writeWriter(data_);
426
427 auto& os = osPtr();
428 writeFileHeader(os);
429
430 for (const auto& p : data_)
431 {
432 os << p << nl;
433 }
434
435 Info<< " Number of particles = " << data_.size() << nl
436 << " Written data to " << os.name() << endl;
437
438 this->setModelProperty("data", data_);
439 this->setModelProperty("maxIDs", maxIDs_);
440 }
441
442 Info<< endl;
443}
444
445
446// ************************************************************************* //
#define writeLocal(field)
label n
Templated cloud function object base class.
const CloudType & owner() const
Return const access to the owner cloud.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:75
const fvMesh & mesh() const
Return reference to the mesh.
Definition: DSMCCloudI.H:44
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
Generic templated field type.
Definition: Field.H:82
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
virtual void postEvolve()
Post-evolve hook.
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
Reports cloud information for particles passing through a specified cell zone.
virtual void postMove(parcelType &p, const scalar dt, const point &position0, bool &keepParticle)
Post-move hook.
virtual void write()
Write.
virtual void preEvolve(const typename parcelType::trackingData &td)
Pre-evolve hook.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
Inter-processor communications stream.
Definition: Pstream.H:63
static void broadcast(Type &value, const label comm=UPstream::worldComm)
static void listCombineGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
Base class for writing coordSet(s) and tracks with fields.
Database for solution data, solver performance and other reduced data.
Definition: data.H:58
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Class used to pass data into container.
bool inZone() const
True if starting point is valid (ie, not point::max)
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:504
splitCell * master() const
Definition: splitCell.H:113
bool getModelProperty(const word &entryName, Type &value) const
Retrieve generic property from the sub-model.
const dictionary & coeffDict() const
Return const access to the coefficients dictionary.
Definition: subModelBase.C:131
A class for handling words, derived from Foam::string.
Definition: word.H:68
volScalarField & p
rDeltaTY field()
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
OBJstream os(runTime.globalPath()/outputName)
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
Field< Type > getData(const Foam::UList< Foam::particleInfo > &data, Type Foam::particleInfo::*field)
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:64
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
IOerror FatalIOError
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
void operator()(particleInfo &p1, const particleInfo &p2) const
scalar isOlderThan(const particleInfo &p) const