parLagrangianDistributor.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) 2015 OpenFOAM Foundation
9  Copyright (C) 2015-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "ListOps.H"
31 #include "passivePositionParticleCloud.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
36 
37 
38 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
39 
41 (
42  const fvMesh& srcMesh,
43  const fvMesh& tgtMesh,
44  const label nSrcCells,
45  const mapDistributePolyMesh& distMap
46 )
47 :
48  srcMesh_(srcMesh),
49  tgtMesh_(tgtMesh),
50  distMap_(distMap)
51 {
52  const mapDistribute& cellMap = distMap_.cellMap();
53 
54  // Get destination processors and cells
55  destinationProcID_ = labelList(tgtMesh_.nCells(), Pstream::myProcNo());
56  cellMap.reverseDistribute(nSrcCells, destinationProcID_);
57 
58  destinationCell_ = identity(tgtMesh_.nCells());
59  cellMap.reverseDistribute(nSrcCells, destinationCell_);
60 }
61 
62 
63 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
64 
65 // Find all clouds (on all processors) and for each cloud all the objects.
66 // Result will be synchronised on all processors
68 (
69  const fvMesh& mesh,
70  wordList& cloudNames,
71  List<wordList>& objectNames
72 )
73 {
74  fileNameList localCloudDirs
75  (
76  readDir
77  (
78  mesh.time().timePath()
79  / mesh.dbDir()
80  / cloud::prefix,
82  )
83  );
84 
85  cloudNames.setSize(localCloudDirs.size());
86  forAll(localCloudDirs, i)
87  {
88  cloudNames[i] = localCloudDirs[i];
89  }
90 
91  // Synchronise cloud names
92  Pstream::combineReduce(cloudNames, ListOps::uniqueEqOp<word>());
93  Foam::sort(cloudNames); // Consistent order
94 
95  objectNames.clear();
96  objectNames.resize(cloudNames.size());
97 
98  for (const fileName& localCloudName : localCloudDirs)
99  {
100  // Do local scan for valid cloud objects
101  IOobjectList localObjs
102  (
103  mesh,
104  mesh.time().timeName(),
105  cloud::prefix/localCloudName
106  );
107 
108  bool isCloud = false;
109  if (localObjs.erase("coordinates"))
110  {
111  isCloud = true;
112  }
113  if (localObjs.erase("positions"))
114  {
115  isCloud = true;
116  }
117 
118  if (isCloud)
119  {
120  // Has coordinates/positions - so must be a valid cloud
121 
122  const label cloudi = cloudNames.find(localCloudName);
123 
124  objectNames[cloudi] = localObjs.sortedNames();
125  }
126  }
127 
128  // Synchronise objectNames (per cloud)
129  for (wordList& objNames : objectNames)
130  {
131  Pstream::combineReduce(objNames, ListOps::uniqueEqOp<word>());
132  Foam::sort(objNames); // Consistent order
133  }
134 }
135 
136 
139 (
140  passivePositionParticleCloud& lpi
141 ) const
142 {
143  //Debug(lpi.size());
144 
145  const label oldLpi = lpi.size();
146 
147  labelListList subMap;
148 
149  // Allocate transfer buffers
150  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
151 
152  {
153  // List of lists of particles to be transferred for all of the
154  // neighbour processors
155  List<IDLList<passivePositionParticle>> particleTransferLists
156  (
158  );
159 
160  // Per particle the destination processor
161  labelList destProc(lpi.size());
162 
163  label particleI = 0;
164  for (passivePositionParticle& ppi : lpi)
165  {
166  const label destProcI = destinationProcID_[ppi.cell()];
167  const label destCellI = destinationCell_[ppi.cell()];
168 
169  ppi.cell() = destCellI;
170  destProc[particleI++] = destProcI;
171  particleTransferLists[destProcI].append(lpi.remove(&ppi));
172  }
173 
174 
175  // Per processor the indices of the particles to send
176  subMap = invertOneToMany(Pstream::nProcs(), destProc);
177 
178 
179  // Stream into send buffers
180  forAll(particleTransferLists, procI)
181  {
182  //Pout<< "To proc " << procI << " sending "
183  // << particleTransferLists[procI] << endl;
184  if (particleTransferLists[procI].size())
185  {
186  UOPstream particleStream(procI, pBufs);
187  particleStream << particleTransferLists[procI];
188  }
189  }
190  }
191 
192 
193  // Start sending
194  pBufs.finishedSends();
195 
196 
197  {
198  // Temporarily rename original cloud so we can construct a new one
199  // (to distribute the positions) without getting a duplicate
200  // registration warning
201  const word cloudName = lpi.name();
202  lpi.rename(cloudName + "_old");
203 
204  // New cloud on tgtMesh
205  passivePositionParticleCloud lagrangianPositions
206  (
207  tgtMesh_,
208  cloudName,
209  IDLList<passivePositionParticle>()
210  );
211 
212  // Retrieve from receive buffers
213  for (const int proci : pBufs.allProcs())
214  {
215  //Pout<< "Receive from processor" << proci << " : "
216  // << pBufs.recvDataCount(proci) << endl;
217 
218  if (pBufs.recvDataCount(proci))
219  {
220  UIPstream particleStream(proci, pBufs);
221 
222  // Receive particles and locate them
223  IDLList<passivePositionParticle> newParticles
224  (
225  particleStream,
226  passivePositionParticle::iNew(tgtMesh_)
227  );
228 
229  for (passivePositionParticle& newp : newParticles)
230  {
231  lagrangianPositions.addParticle(newParticles.remove(&newp));
232  }
233  }
234  }
235 
236  if (lagrangianPositions.size())
237  {
238  // Write coordinates file
239  IOPosition<passivePositionParticleCloud>
240  (
241  lagrangianPositions
242  ).write();
243 
244  // Optionally write positions file in v1706 format and earlier
246  {
247  IOPosition<passivePositionParticleCloud>
248  (
249  lagrangianPositions,
251  ).write();
252  }
253  }
254  else if (oldLpi)
255  {
256  // When running with -overwrite it should also delete the old
257  // files. Below works but is not optimal.
258 
259  // Remove any existing coordinates
260  const fileName oldCoords
261  (
262  IOPosition<passivePositionParticleCloud>
263  (
264  lagrangianPositions
265  ).objectPath()
266  );
267  Foam::rm(oldCoords);
268 
269  // Remove any existing positions
270  const fileName oldPos
271  (
272  IOPosition<passivePositionParticleCloud>
273  (
274  lagrangianPositions,
276  ).objectPath()
277  );
278  Foam::rm(oldPos);
279  }
280 
281  // Restore cloud name
282  lpi.rename(cloudName);
283  }
284 
285  // Until now (FEB-2023) we have always used processor ordering for the
286  // construct map (whereas mapDistribute has local transfers first),
287  // so we'll stick with that for now, but can likely just use the subMap
288  // directly with mapDistribute and have it determine the constructMap.
289 
290  labelList recvSizes;
291  Pstream::exchangeSizes(subMap, recvSizes);
292 
293  label constructSize = 0;
294  labelListList constructMap(Pstream::nProcs());
295 
296  forAll(constructMap, proci)
297  {
298  const label len = recvSizes[proci];
299  constructMap[proci] = identity(len, constructSize);
300  constructSize += len;
301  }
302 
304  (
305  constructSize,
306  std::move(subMap),
307  std::move(constructMap)
308  );
309 }
310 
311 
314 (
315  const word& cloudName
316 ) const
317 {
318  // Load cloud and send particle
319  passivePositionParticleCloud lpi(srcMesh_, cloudName, false);
320 
321  return distributeLagrangianPositions(lpi);
322 }
323 
324 
325 // ************************************************************************* //
static void findClouds(const fvMesh &, wordList &cloudNames, List< wordList > &objectNames)
Find all clouds (on all processors) and for each cloud all the objects. Result will be synchronised o...
static int verbose_
Output verbosity when writing.
fileName timePath() const
Return current time path.
Definition: Time.H:475
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:500
virtual const fileName & dbDir() const
Override the objectRegistry dbDir for a single-region case.
Definition: polyMesh.C:825
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:1029
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:362
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
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:1020
dynamicFvMesh & mesh
labelListList invertOneToMany(const label len, const labelUList &map)
Invert one-to-many map. Unmapped elements will be size 0.
Definition: ListOps.C:107
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:31
const word cloudName(propsDict.get< word >("cloud"))
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:348
const mapDistribute & cellMap() const noexcept
Cell distribute map.
static void combineReduce(const List< commsStruct > &comms, T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:770
parLagrangianDistributor(const parLagrangianDistributor &)=delete
No copy construct.
List< word > wordList
List of word.
Definition: fileName.H:58
static bool writeLagrangianPositions
Write particle positions file (v1706 format and earlier) Default is true (disable in etc/controlDict)...
Definition: particle.H:472
label nCells() const noexcept
Number of mesh cells.
static void exchangeSizes(const labelUList &sendProcs, const labelUList &recvProcs, const Container &sendBufs, labelList &sizes, const label tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Helper: exchange sizes of sendBufs for specified send/recv ranks.
"nonBlocking" : (MPI_Isend, MPI_Irecv)
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
List< fileName > fileNameList
List of fileName.
Definition: fileNameList.H:32
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: POSIX.C:963
autoPtr< mapDistributeBase > distributeLagrangianPositions(passivePositionParticleCloud &cloud) const
Redistribute and write lagrangian positions.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1404
static const word prefix
The prefix to local: lagrangian.
Definition: cloud.H:93