Cloud.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 | Copyright (C) 2011-2017 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "Cloud.H"
27 #include "processorPolyPatch.H"
28 #include "globalMeshData.H"
30 #include "mapPolyMesh.H"
31 #include "Time.H"
32 #include "OFstream.H"
33 #include "wallPolyPatch.H"
34 #include "cyclicAMIPolyPatch.H"
35 
36 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
37 
38 template<class ParticleType>
40 {
41  const polyBoundaryMesh& pbm = polyMesh_.boundaryMesh();
42  bool ok = true;
43  forAll(pbm, patchi)
44  {
45  if (isA<cyclicAMIPolyPatch>(pbm[patchi]))
46  {
47  const cyclicAMIPolyPatch& cami =
48  refCast<const cyclicAMIPolyPatch>(pbm[patchi]);
49 
50  if (cami.owner())
51  {
52  ok = ok && (cami.AMI().singlePatchProc() != -1);
53  }
54  }
55  }
56 
57  if (!ok)
58  {
60  << "Particle tracking across AMI patches is only currently "
61  << "supported for cases where the AMI patches reside on a "
62  << "single processor" << abort(FatalError);
63  }
64 }
65 
66 
67 template<class ParticleType>
69 {
70  cellWallFacesPtr_.reset(new PackedBoolList(pMesh().nCells(), false));
71 
72  PackedBoolList& cellWallFaces = cellWallFacesPtr_();
73 
74  const polyBoundaryMesh& patches = polyMesh_.boundaryMesh();
75 
76  forAll(patches, patchi)
77  {
78  if (isA<wallPolyPatch>(patches[patchi]))
79  {
80  const polyPatch& patch = patches[patchi];
81 
82  const labelList& pFaceCells = patch.faceCells();
83 
84  forAll(pFaceCells, pFCI)
85  {
86  cellWallFaces[pFaceCells[pFCI]] = true;
87  }
88  }
89  }
90 }
91 
92 
93 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
94 
95 template<class ParticleType>
97 (
98  const polyMesh& pMesh,
99  const word& cloudName,
100  const IDLList<ParticleType>& particles
101 )
102 :
103  cloud(pMesh, cloudName),
105  polyMesh_(pMesh),
106  labels_(),
107  nTrackingRescues_(),
108  cellWallFacesPtr_(),
109  globalPositionsPtr_()
110 {
111  checkPatches();
112 
113  // Ask for the tetBasePtIs to trigger all processors to build
114  // them, otherwise, if some processors have no particles then
115  // there is a comms mismatch.
116  polyMesh_.tetBasePtIs();
117 
118  if (particles.size())
119  {
121  }
122 }
123 
124 
125 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
126 
127 template<class ParticleType>
129 const
130 {
131  if (!cellWallFacesPtr_.valid())
132  {
133  calcCellWallFaces();
134  }
135 
136  return cellWallFacesPtr_();
137 }
138 
139 
140 template<class ParticleType>
142 {
143  this->append(pPtr);
144 }
145 
146 
147 template<class ParticleType>
149 {
150  delete(this->remove(&p));
151 }
152 
153 
154 template<class ParticleType>
156 {
157  forAllIter(typename Cloud<ParticleType>, *this, pIter)
158  {
159  ParticleType& p = pIter();
160 
161  if (p.cell() == -1)
162  {
164  << "deleting lost particle at position " << p.position()
165  << endl;
166 
167  deleteParticle(p);
168  }
169  }
170 }
171 
172 
173 template<class ParticleType>
175 {
176  // Reset particle cound and particles only
177  // - not changing the cloud object registry or reference to the polyMesh
178  ParticleType::particleCount_ = 0;
180 }
181 
182 
183 template<class ParticleType>
184 template<class TrackData>
185 void Foam::Cloud<ParticleType>::move(TrackData& td, const scalar trackTime)
186 {
187  const polyBoundaryMesh& pbm = pMesh().boundaryMesh();
188  const globalMeshData& pData = polyMesh_.globalData();
189 
190  // Which patches are processor patches
191  const labelList& procPatches = pData.processorPatches();
192 
193  // Indexing of patches into the procPatches list
194  const labelList& procPatchIndices = pData.processorPatchIndices();
195 
196  // Indexing of equivalent patch on neighbour processor into the
197  // procPatches list on the neighbour
198  const labelList& procPatchNeighbours = pData.processorPatchNeighbours();
199 
200  // Which processors this processor is connected to
201  const labelList& neighbourProcs = pData[Pstream::myProcNo()];
202 
203  // Indexing from the processor number into the neighbourProcs list
204  labelList neighbourProcIndices(Pstream::nProcs(), -1);
205 
206  forAll(neighbourProcs, i)
207  {
208  neighbourProcIndices[neighbourProcs[i]] = i;
209  }
210 
211  // Initialise the stepFraction moved for the particles
212  forAllIter(typename Cloud<ParticleType>, *this, pIter)
213  {
214  pIter().stepFraction() = 0;
215  }
216 
217  // Reset nTrackingRescues
218  nTrackingRescues_ = 0;
219 
220 
221  // List of lists of particles to be transfered for all of the
222  // neighbour processors
223  List<IDLList<ParticleType>> particleTransferLists
224  (
225  neighbourProcs.size()
226  );
227 
228  // List of destination processorPatches indices for all of the
229  // neighbour processors
230  List<DynamicList<label>> patchIndexTransferLists
231  (
232  neighbourProcs.size()
233  );
234 
235  // Allocate transfer buffers
236  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
237 
238  // Clear the global positions as there are about to change
239  globalPositionsPtr_.clear();
240 
241  // While there are particles to transfer
242  while (true)
243  {
244  particleTransferLists = IDLList<ParticleType>();
245  forAll(patchIndexTransferLists, i)
246  {
247  patchIndexTransferLists[i].clear();
248  }
249 
250  // Loop over all particles
251  forAllIter(typename Cloud<ParticleType>, *this, pIter)
252  {
253  ParticleType& p = pIter();
254 
255  // Move the particle
256  bool keepParticle = p.move(td, trackTime);
257 
258  // If the particle is to be kept
259  // (i.e. it hasn't passed through an inlet or outlet)
260  if (keepParticle)
261  {
262  // If we are running in parallel and the particle is on a
263  // boundary face
264  if
265  (
266  Pstream::parRun()
267  && td.switchProcessor
268  && p.face() >= pMesh().nInternalFaces()
269  )
270  {
271  label patchi = pbm.whichPatch(p.face());
272 
273  // ... and the face is on a processor patch
274  // prepare it for transfer
275  if (procPatchIndices[patchi] != -1)
276  {
277  label n = neighbourProcIndices
278  [
279  refCast<const processorPolyPatch>
280  (
281  pbm[patchi]
282  ).neighbProcNo()
283  ];
284 
285  p.prepareForParallelTransfer(patchi, td);
286 
287  particleTransferLists[n].append(this->remove(&p));
288 
289  patchIndexTransferLists[n].append
290  (
291  procPatchNeighbours[patchi]
292  );
293  }
294  }
295  }
296  else
297  {
298  deleteParticle(p);
299  }
300  }
301 
302  if (!Pstream::parRun())
303  {
304  break;
305  }
306 
307 
308  // Clear transfer buffers
309  pBufs.clear();
310 
311  // Stream into send buffers
312  forAll(particleTransferLists, i)
313  {
314  if (particleTransferLists[i].size())
315  {
316  UOPstream particleStream
317  (
318  neighbourProcs[i],
319  pBufs
320  );
321 
322  particleStream
323  << patchIndexTransferLists[i]
324  << particleTransferLists[i];
325  }
326  }
327 
328 
329  // Start sending. Sets number of bytes transferred
330  labelList allNTrans(Pstream::nProcs());
331  pBufs.finishedSends(allNTrans);
332 
333 
334  bool transfered = false;
335 
336  forAll(allNTrans, i)
337  {
338  if (allNTrans[i])
339  {
340  transfered = true;
341  break;
342  }
343  }
344  reduce(transfered, orOp<bool>());
345 
346  if (!transfered)
347  {
348  break;
349  }
350 
351  // Retrieve from receive buffers
352  forAll(neighbourProcs, i)
353  {
354  label neighbProci = neighbourProcs[i];
355 
356  label nRec = allNTrans[neighbProci];
357 
358  if (nRec)
359  {
360  UIPstream particleStream(neighbProci, pBufs);
361 
362  labelList receivePatchIndex(particleStream);
363 
364  IDLList<ParticleType> newParticles
365  (
366  particleStream,
367  typename ParticleType::iNew(polyMesh_)
368  );
369 
370  label pI = 0;
371 
372  forAllIter(typename Cloud<ParticleType>, newParticles, newpIter)
373  {
374  ParticleType& newp = newpIter();
375 
376  label patchi = procPatches[receivePatchIndex[pI++]];
377 
378  newp.correctAfterParallelTransfer(patchi, td);
379 
380  addParticle(newParticles.remove(&newp));
381  }
382  }
383  }
384  }
385 
386  if (cloud::debug)
387  {
388  reduce(nTrackingRescues_, sumOp<label>());
389 
390  if (nTrackingRescues_ > 0)
391  {
392  Info<< nTrackingRescues_ << " tracking rescue corrections" << endl;
393  }
394  }
395 }
396 
397 
398 template<class ParticleType>
400 {
401  if (!globalPositionsPtr_.valid())
402  {
404  << "Global positions are not available. "
405  << "Cloud::storeGlobalPositions has not been called."
406  << exit(FatalError);
407  }
408 
409  // Reset stored data that relies on the mesh
410  // polyMesh_.clearCellTree();
411  cellWallFacesPtr_.clear();
412 
413  // Ask for the tetBasePtIs to trigger all processors to build
414  // them, otherwise, if some processors have no particles then
415  // there is a comms mismatch.
416  polyMesh_.tetBasePtIs();
417 
418  const vectorField& positions = globalPositionsPtr_();
419 
420  label i = 0;
421  forAllIter(typename Cloud<ParticleType>, *this, iter)
422  {
423  iter().autoMap(positions[i], mapper);
424  ++ i;
425  }
426 }
427 
428 
429 template<class ParticleType>
431 {
432  OFstream pObj
433  (
434  this->db().time().path()/this->name() + "_positions.obj"
435  );
436 
437  forAllConstIter(typename Cloud<ParticleType>, *this, pIter)
438  {
439  const ParticleType& p = pIter();
440  pObj<< "v " << p.position().x() << " " << p.position().y() << " "
441  << p.position().z() << nl;
442  }
443 
444  pObj.flush();
445 }
446 
447 
448 template<class ParticleType>
450 {
451  // Store the global positions for later use by autoMap. It would be
452  // preferable not to need this. If the mapPolyMesh object passed to autoMap
453  // had a copy of the old mesh then the global positions could be recovered
454  // within autoMap, and this pre-processing would not be necessary.
455 
456  globalPositionsPtr_.reset(new vectorField(this->size()));
457 
458  vectorField& positions = globalPositionsPtr_();
459 
460  label i = 0;
461  forAllConstIter(typename Cloud<ParticleType>, *this, iter)
462  {
463  positions[i] = iter().position();
464  ++ i;
465  }
466 }
467 
468 
469 // * * * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * //
470 
471 #include "CloudIO.C"
472 
473 // ************************************************************************* //
Template class for intrusive linked lists.
Definition: ILList.H:50
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:424
const labelList & processorPatchIndices() const
Return list of indices into processorPatches_ for each patch.
void cloudReset(const Cloud< ParticleType > &c)
Reset the particles.
Definition: Cloud.C:174
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
const labelList & processorPatches() const
Return list of processor patch labels.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
void deleteParticle(ParticleType &)
Remove particle from cloud and delete.
Definition: Cloud.C:148
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
label nInternalFaces() const
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:453
Output to file stream.
Definition: OFstream.H:82
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Cloud(const polyMesh &mesh, const word &cloudName, const IDLList< ParticleType > &particles)
Construct from mesh and a list of particles.
Definition: Cloud.C:97
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
volVectorField vectorField(fieldObject, mesh)
void autoMap(const mapPolyMesh &)
Remap the cells of particles corresponding to the.
Definition: Cloud.C:399
Combination-Reduction operation for a parallel run. The information from all nodes is collected on th...
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:53
void addParticle(ParticleType *pPtr)
Transfer particle to cloud.
Definition: Cloud.C:141
void storeGlobalPositions() const
Call this before a topology change. Stores the particles global.
Definition: Cloud.C:449
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:124
A class for handling words, derived from string.
Definition: word.H:59
A cloud is a collection of lagrangian particles.
Definition: cloud.H:51
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:184
virtual void flush()
Flush stream.
Definition: OSstream.C:246
List< label > labelList
A List of labels.
Definition: labelList.H:56
T * remove(T *p)
Remove and return element.
Definition: UILList.H:139
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Base cloud calls templated on particle type.
Definition: Cloud.H:52
Foam::polyBoundaryMesh.
void move(TrackData &td, const scalar trackTime)
Move the particles.
Definition: Cloud.C:185
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:54
static const char nl
Definition: Ostream.H:262
const PackedBoolList & cellHasWallFaces() const
Whether each cell has any wall faces (demand driven data)
Definition: Cloud.C:128
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
const labelList & processorPatchNeighbours() const
Return processorPatchIndices of the neighbours.
Buffers for inter-processor communications streams (UOPstream, UIPstream).
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
void deleteLostParticles()
Remove lost particles from cloud and delete.
Definition: Cloud.C:155
A bit-packed bool list.
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
messageStream Info
label n
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
volScalarField & p
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
void writePositions() const
Write positions to <cloudName>_positions.obj file.
Definition: Cloud.C:430