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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
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 "Cloud.H"
29 #include "processorPolyPatch.H"
30 #include "globalMeshData.H"
32 #include "mapPolyMesh.H"
33 #include "Time.H"
34 #include "OFstream.H"
35 #include "wallPolyPatch.H"
36 #include "cyclicAMIPolyPatch.H"
37 
38 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
39 
40 template<class ParticleType>
42 {
43  const polyBoundaryMesh& pbm = polyMesh_.boundaryMesh();
44  bool ok = true;
45  for (const polyPatch& pp : pbm)
46  {
47  if (isA<cyclicAMIPolyPatch>(pp))
48  {
49  const cyclicAMIPolyPatch& cami =
50  refCast<const cyclicAMIPolyPatch>(pp);
51 
52  if (cami.owner())
53  {
54  ok = ok && (cami.AMI().singlePatchProc() != -1);
55  }
56  }
57  }
58 
59  if (!ok)
60  {
62  << "Particle tracking across AMI patches is only currently "
63  << "supported for cases where the AMI patches reside on a "
64  << "single processor" << abort(FatalError);
65  }
66 }
67 
68 
69 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
70 
71 template<class ParticleType>
73 (
74  const polyMesh& pMesh,
75  const word& cloudName,
76  const IDLList<ParticleType>& particles
77 )
78 :
79  cloud(pMesh, cloudName),
81  polyMesh_(pMesh),
82  labels_(),
83  globalPositionsPtr_(),
84  geometryType_(cloud::geometryType::COORDINATES)
85 {
86  checkPatches();
87 
88  // Ask for the tetBasePtIs to trigger all processors to build
89  // them, otherwise, if some processors have no particles then
90  // there is a comms mismatch.
91  polyMesh_.tetBasePtIs();
92 
93  if (particles.size())
94  {
96  }
97 }
98 
99 
100 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
101 
102 template<class ParticleType>
104 {
105  this->append(pPtr);
106 }
107 
108 
109 template<class ParticleType>
111 {
112  delete(this->remove(&p));
113 }
114 
115 
116 template<class ParticleType>
118 {
119  for (ParticleType& p : *this)
120  {
121  if (p.cell() == -1)
122  {
124  << "deleting lost particle at position " << p.position()
125  << endl;
126 
127  deleteParticle(p);
128  }
129  }
130 }
131 
132 
133 template<class ParticleType>
135 {
136  // Reset particle count and particles only
137  // - not changing the cloud object registry or reference to the polyMesh
138  ParticleType::particleCount_ = 0;
140 }
141 
142 
143 template<class ParticleType>
144 template<class TrackCloudType>
146 (
147  TrackCloudType& cloud,
148  typename ParticleType::trackingData& td,
149  const scalar trackTime
150 )
151 {
152  const polyBoundaryMesh& pbm = pMesh().boundaryMesh();
153  const globalMeshData& pData = polyMesh_.globalData();
154 
155  // Which patches are processor patches
156  const labelList& procPatches = pData.processorPatches();
157 
158  // Indexing of equivalent patch on neighbour processor into the
159  // procPatches list on the neighbour
160  const labelList& procPatchNeighbours = pData.processorPatchNeighbours();
161 
162  // Which processors this processor is connected to
163  const labelList& neighbourProcs = pData[Pstream::myProcNo()];
164 
165  // Indexing from the processor number into the neighbourProcs list
166  labelList neighbourProcIndices(Pstream::nProcs(), -1);
167 
168  forAll(neighbourProcs, i)
169  {
170  neighbourProcIndices[neighbourProcs[i]] = i;
171  }
172 
173  // Initialise the stepFraction moved for the particles
174  forAllIters(*this, pIter)
175  {
176  pIter().stepFraction() = 0;
177  }
178 
179  // List of lists of particles to be transferred for all of the
180  // neighbour processors
181  List<IDLList<ParticleType>> particleTransferLists
182  (
183  neighbourProcs.size()
184  );
185 
186  // List of destination processorPatches indices for all of the
187  // neighbour processors
188  List<DynamicList<label>> patchIndexTransferLists
189  (
190  neighbourProcs.size()
191  );
192 
193  // Allocate transfer buffers
194  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
195 
196  // Clear the global positions as there are about to change
197  globalPositionsPtr_.clear();
198 
199  // While there are particles to transfer
200  while (true)
201  {
202  particleTransferLists = IDLList<ParticleType>();
203  forAll(patchIndexTransferLists, i)
204  {
205  patchIndexTransferLists[i].clear();
206  }
207 
208  // Loop over all particles
209  for (ParticleType& p : *this)
210  {
211  // Move the particle
212  bool keepParticle = p.move(cloud, td, trackTime);
213 
214  // If the particle is to be kept
215  // (i.e. it hasn't passed through an inlet or outlet)
216  if (keepParticle)
217  {
218  if (td.switchProcessor)
219  {
220  #ifdef FULLDEBUG
221  if
222  (
223  !Pstream::parRun()
224  || !p.onBoundaryFace()
225  || procPatchNeighbours[p.patch()] < 0
226  )
227  {
229  << "Switch processor flag is true when no parallel "
230  << "transfer is possible. This is a bug."
231  << exit(FatalError);
232  }
233  #endif
234 
235  const label patchi = p.patch();
236 
237  const label n = neighbourProcIndices
238  [
239  refCast<const processorPolyPatch>
240  (
241  pbm[patchi]
242  ).neighbProcNo()
243  ];
244 
245  p.prepareForParallelTransfer();
246 
247  particleTransferLists[n].append(this->remove(&p));
248 
249  patchIndexTransferLists[n].append
250  (
251  procPatchNeighbours[patchi]
252  );
253  }
254  }
255  else
256  {
257  deleteParticle(p);
258  }
259  }
260 
261  if (!Pstream::parRun())
262  {
263  break;
264  }
265 
266 
267  // Clear transfer buffers
268  pBufs.clear();
269 
270  // Stream into send buffers
271  forAll(particleTransferLists, i)
272  {
273  if (particleTransferLists[i].size())
274  {
275  UOPstream particleStream
276  (
277  neighbourProcs[i],
278  pBufs
279  );
280 
281  particleStream
282  << patchIndexTransferLists[i]
283  << particleTransferLists[i];
284  }
285  }
286 
287 
288  // Start sending. Sets number of bytes transferred
289  labelList allNTrans(Pstream::nProcs());
290  pBufs.finishedSends(allNTrans);
291 
292 
293  bool transferred = false;
294 
295  for (const label n : allNTrans)
296  {
297  if (n)
298  {
299  transferred = true;
300  break;
301  }
302  }
303  reduce(transferred, orOp<bool>());
304 
305  if (!transferred)
306  {
307  break;
308  }
309 
310  // Retrieve from receive buffers
311  for (const label neighbProci : neighbourProcs)
312  {
313  label nRec = allNTrans[neighbProci];
314 
315  if (nRec)
316  {
317  UIPstream particleStream(neighbProci, pBufs);
318 
319  labelList receivePatchIndex(particleStream);
320 
321  IDLList<ParticleType> newParticles
322  (
323  particleStream,
324  typename ParticleType::iNew(polyMesh_)
325  );
326 
327  label pI = 0;
328 
329  for (ParticleType& newp : newParticles)
330  {
331  label patchi = procPatches[receivePatchIndex[pI++]];
332 
333  newp.correctAfterParallelTransfer(patchi, td);
334 
335  addParticle(newParticles.remove(&newp));
336  }
337  }
338  }
339  }
340 }
341 
342 
343 template<class ParticleType>
345 {
346  if (!globalPositionsPtr_.valid())
347  {
349  << "Global positions are not available. "
350  << "Cloud::storeGlobalPositions has not been called."
351  << exit(FatalError);
352  }
353 
354  // Reset stored data that relies on the mesh
355  // polyMesh_.clearCellTree();
356  cellWallFacesPtr_.clear();
357 
358  // Ask for the tetBasePtIs to trigger all processors to build
359  // them, otherwise, if some processors have no particles then
360  // there is a comms mismatch.
361  polyMesh_.tetBasePtIs();
362 
363  const vectorField& positions = globalPositionsPtr_();
364 
365  label i = 0;
366  forAllIters(*this, iter)
367  {
368  iter().autoMap(positions[i], mapper);
369  ++i;
370  }
371 }
372 
373 
374 template<class ParticleType>
376 {
377  OFstream pObj
378  (
379  this->db().time().path()/this->name() + "_positions.obj"
380  );
381 
382  forAllConstIters(*this, pIter)
383  {
384  const ParticleType& p = pIter();
385  const point position(p.position());
386  pObj<< "v " << position.x() << " " << position.y() << " "
387  << position.z() << nl;
388  }
389 
390  pObj.flush();
391 }
392 
393 
394 template<class ParticleType>
396 {
397  // Store the global positions for later use by autoMap. It would be
398  // preferable not to need this. If the mapPolyMesh object passed to autoMap
399  // had a copy of the old mesh then the global positions could be recovered
400  // within autoMap, and this pre-processing would not be necessary.
401 
402  globalPositionsPtr_.reset(new vectorField(this->size()));
403 
404  vectorField& positions = globalPositionsPtr_();
405 
406  label i = 0;
407  forAllConstIters(*this, iter)
408  {
409  positions[i] = iter().position();
410  ++i;
411  }
412 }
413 
414 
415 // * * * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * //
416 
417 #include "CloudIO.C"
418 
419 // ************************************************************************* //
Foam::Cloud::addParticle
void addParticle(ParticleType *pPtr)
Transfer particle to cloud.
Definition: Cloud.C:103
p
volScalarField & p
Definition: createFieldRefs.H:8
cloudName
const word cloudName(propsDict.get< word >("cloud"))
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::UOPstream
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:57
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::globalMeshData::processorPatches
const labelList & processorPatches() const
Return list of processor patch labels.
Definition: globalMeshData.H:404
globalMeshData.H
Foam::Cloud::writePositions
void writePositions() const
Write positions to <cloudName>_positions.obj file.
Definition: Cloud.C:375
mapPolyMesh.H
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:88
wallPolyPatch.H
Cloud.H
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:435
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
CloudIO.C
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
OFstream.H
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
PstreamCombineReduceOps.H
Combination-Reduction operation for a parallel run. The information from all nodes is collected on th...
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::label
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:62
Foam::Field< vector >
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::Cloud::storeGlobalPositions
void storeGlobalPositions() const
Call this before a topology change.
Definition: Cloud.C:395
Foam::Cloud::deleteParticle
void deleteParticle(ParticleType &p)
Remove particle from cloud and delete.
Definition: Cloud.C:110
Foam::Cloud::autoMap
void autoMap(const mapPolyMesh &)
Remap the cells of particles corresponding to the.
Definition: Cloud.C:344
Foam::Cloud::deleteLostParticles
void deleteLostParticles()
Remove lost particles from cloud and delete.
Definition: Cloud.C:117
forAllIters
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:217
Foam::ILList
Template class for intrusive linked lists.
Definition: ILList.H:52
Foam::Cloud::move
void move(TrackCloudType &cloud, typename ParticleType::trackingData &td, const scalar trackTime)
Move the particles.
Definition: Cloud.C:146
Foam::FatalError
error FatalError
processorPolyPatch.H
Foam::globalMeshData
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
Definition: globalMeshData.H:106
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
Foam::globalMeshData::processorPatchNeighbours
const labelList & processorPatchNeighbours() const
Return processorPatchIndices of the neighbours.
Definition: globalMeshData.H:419
cyclicAMIPolyPatch.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:99
Foam::Cloud::cloudReset
void cloudReset(const Cloud< ParticleType > &c)
Reset the particles.
Definition: Cloud.C:134
Time.H
Foam::cloud
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:57
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::nl
constexpr char nl
Definition: Ostream.H:372
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::Vector< scalar >
Foam::List< label >
Foam::Cloud
Base cloud calls templated on particle type.
Definition: Cloud.H:54
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:115
path
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
Foam::Cloud::Cloud
Cloud(const polyMesh &mesh, const word &cloudName, const IDLList< ParticleType > &particles)
Construct from mesh and a list of particles.
Definition: Cloud.C:73
Foam::mapPolyMesh
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:160
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
append
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
Foam::UIPstream
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:56
Foam::orOp
Definition: ops.H:234
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::OSstream::flush
virtual void flush()
Flush stream.
Definition: OSstream.C:260