regionSplit.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-2015 OpenFOAM Foundation
6  \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
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 "regionSplit.H"
27 #include "cyclicPolyPatch.H"
28 #include "processorPolyPatch.H"
29 #include "globalIndex.H"
30 #include "syncTools.H"
31 #include "FaceCellWave.H"
32 #include "minData.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 
39 defineTypeNameAndDebug(regionSplit, 0);
40 
41 }
42 
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 
46 (
47  const globalIndex& globalFaces,
48  const boolList& blockedFace,
49  const List<labelPair>& explicitConnections,
50 
51  labelList& cellRegion
52 ) const
53 {
54  // Field on cells and faces.
55  List<minData> cellData(mesh().nCells());
56  List<minData> faceData(mesh().nFaces());
57 
58  // Take over blockedFaces by seeding a negative number
59  // (so is always less than the decomposition)
60  label nUnblocked = 0;
61  forAll(faceData, faceI)
62  {
63  if (blockedFace.size() && blockedFace[faceI])
64  {
65  faceData[faceI] = minData(-2);
66  }
67  else
68  {
69  nUnblocked++;
70  }
71  }
72 
73  // Seed unblocked faces
74  labelList seedFaces(nUnblocked);
75  List<minData> seedData(nUnblocked);
76  nUnblocked = 0;
77 
78 
79  forAll(faceData, faceI)
80  {
81  if (blockedFace.empty() || !blockedFace[faceI])
82  {
83  seedFaces[nUnblocked] = faceI;
84  // Seed face with globally unique number
85  seedData[nUnblocked] = minData(globalFaces.toGlobal(faceI));
86  nUnblocked++;
87  }
88  }
89 
90 
91  // Propagate information inwards
92  FaceCellWave<minData> deltaCalc
93  (
94  mesh(),
95  explicitConnections,
96  false, // disable walking through cyclicAMI for backwards compatibility
97  seedFaces,
98  seedData,
99  faceData,
100  cellData,
101  mesh().globalData().nTotalCells()+1
102  );
103 
104 
105  // And extract
106  cellRegion.setSize(mesh().nCells());
107  forAll(cellRegion, cellI)
108  {
109  if (cellData[cellI].valid(deltaCalc.data()))
110  {
111  cellRegion[cellI] = cellData[cellI].data();
112  }
113  else
114  {
115  // Unvisited cell -> only possible if surrounded by blocked faces.
116  // If so make up region from any of the faces
117  const cell& cFaces = mesh().cells()[cellI];
118  label faceI = cFaces[0];
119 
120  if (blockedFace.size() && !blockedFace[faceI])
121  {
123  << "Problem: unblocked face " << faceI
124  << " at " << mesh().faceCentres()[faceI]
125  << " on unassigned cell " << cellI
126  << mesh().cellCentres()[faceI]
127  << exit(FatalError);
128  }
129  cellRegion[cellI] = globalFaces.toGlobal(faceI);
130  }
131  }
132 }
133 
134 
136 (
137  const bool doGlobalRegions,
138  const boolList& blockedFace,
139  const List<labelPair>& explicitConnections,
140 
141  labelList& cellRegion
142 ) const
143 {
144  // See header in regionSplit.H
145 
146 
147  if (!doGlobalRegions)
148  {
149  // Block all parallel faces to avoid comms across
150  boolList coupledOrBlockedFace(blockedFace);
151  const polyBoundaryMesh& pbm = mesh().boundaryMesh();
152 
153  if (coupledOrBlockedFace.size())
154  {
155  forAll(pbm, patchI)
156  {
157  const polyPatch& pp = pbm[patchI];
158  if (isA<processorPolyPatch>(pp))
159  {
160  label faceI = pp.start();
161  forAll(pp, i)
162  {
163  coupledOrBlockedFace[faceI++] = true;
164  }
165  }
166  }
167  }
168 
169  // Create dummy (local only) globalIndex
170  labelList offsets(Pstream::nProcs()+1, 0);
171  for (label i = Pstream::myProcNo()+1; i < offsets.size(); i++)
172  {
173  offsets[i] = mesh().nFaces();
174  }
175  const globalIndex globalRegions(offsets.xfer());
176 
177  // Minimise regions across connected cells
178  // Note: still uses global decisions so all processors are running
179  // in lock-step, i.e. slowest determines overall time.
180  // To avoid this we could switch off Pstream::parRun.
181  calcNonCompactRegionSplit
182  (
183  globalRegions,
184  coupledOrBlockedFace,
185  explicitConnections,
186  cellRegion
187  );
188 
189  // Compact
190  Map<label> globalToCompact(mesh().nCells()/8);
191  forAll(cellRegion, cellI)
192  {
193  label region = cellRegion[cellI];
194 
195  label globalRegion;
196 
197  Map<label>::const_iterator fnd = globalToCompact.find(region);
198  if (fnd == globalToCompact.end())
199  {
200  globalRegion = globalRegions.toGlobal(globalToCompact.size());
201  globalToCompact.insert(region, globalRegion);
202  }
203  else
204  {
205  globalRegion = fnd();
206  }
207  cellRegion[cellI] = globalRegion;
208  }
209 
210 
211  // Return globalIndex with size = localSize and all regions local
212  labelList compactOffsets(Pstream::nProcs()+1, 0);
213  for (label i = Pstream::myProcNo()+1; i < compactOffsets.size(); i++)
214  {
215  compactOffsets[i] = globalToCompact.size();
216  }
217 
218  return autoPtr<globalIndex>(new globalIndex(compactOffsets.xfer()));
219  }
220 
221 
222 
223  // Initial global region numbers
224  const globalIndex globalRegions(mesh().nFaces());
225 
226  // Minimise regions across connected cells (including parallel)
227  calcNonCompactRegionSplit
228  (
229  globalRegions,
230  blockedFace,
231  explicitConnections,
232  cellRegion
233  );
234 
235 
236  // Now our cellRegion will have
237  // - non-local regions (i.e. originating from other processors)
238  // - non-compact locally originating regions
239  // so we'll need to compact
240 
241  // 4a: count per originating processor the number of regions
242  labelList nOriginating(Pstream::nProcs(), 0);
243  {
244  labelHashSet haveRegion(mesh().nCells()/8);
245 
246  forAll(cellRegion, cellI)
247  {
248  label region = cellRegion[cellI];
249 
250  // Count originating processor. Use isLocal as efficiency since
251  // most cells are locally originating.
252  if (globalRegions.isLocal(region))
253  {
254  if (haveRegion.insert(region))
255  {
256  nOriginating[Pstream::myProcNo()]++;
257  }
258  }
259  else
260  {
261  label procI = globalRegions.whichProcID(region);
262  if (haveRegion.insert(region))
263  {
264  nOriginating[procI]++;
265  }
266  }
267  }
268  }
269 
270  if (debug)
271  {
272  Pout<< "Counted " << nOriginating[Pstream::myProcNo()]
273  << " local regions." << endl;
274  }
275 
276 
277  // Global numbering for compacted local regions
278  autoPtr<globalIndex> globalCompactPtr
279  (
280  new globalIndex(nOriginating[Pstream::myProcNo()])
281  );
282  const globalIndex& globalCompact = globalCompactPtr();
283 
284 
285  // 4b: renumber
286  // Renumber into compact indices. Note that since we've already made
287  // all regions global we now need a Map to store the compacting information
288  // instead of a labelList - otherwise we could have used a straight
289  // labelList.
290 
291  // Local compaction map
292  Map<label> globalToCompact(2*nOriginating[Pstream::myProcNo()]);
293  // Remote regions we want the compact number for
294  List<labelHashSet> nonLocal(Pstream::nProcs());
295  forAll(nonLocal, procI)
296  {
297  if (procI != Pstream::myProcNo())
298  {
299  nonLocal[procI].resize(2*nOriginating[procI]);
300  }
301  }
302 
303  forAll(cellRegion, cellI)
304  {
305  label region = cellRegion[cellI];
306  if (globalRegions.isLocal(region))
307  {
308  // Insert new compact region (if not yet present)
309  globalToCompact.insert
310  (
311  region,
312  globalCompact.toGlobal(globalToCompact.size())
313  );
314  }
315  else
316  {
317  nonLocal[globalRegions.whichProcID(region)].insert(region);
318  }
319  }
320 
321 
322  // Now we have all the local regions compacted. Now we need to get the
323  // non-local ones from the processors to whom they are local.
324  // Convert the nonLocal (labelHashSets) to labelLists.
325 
326  labelListList sendNonLocal(Pstream::nProcs());
327  forAll(sendNonLocal, procI)
328  {
329  sendNonLocal[procI] = nonLocal[procI].toc();
330  }
331 
332  if (debug)
333  {
334  forAll(sendNonLocal, procI)
335  {
336  Pout<< " from processor " << procI
337  << " want " << sendNonLocal[procI].size()
338  << " region numbers."
339  << endl;
340  }
341  Pout<< endl;
342  }
343 
344 
345  // Get the wanted region labels into recvNonLocal
346  labelListList recvNonLocal(Pstream::nProcs());
347  labelListList sizes;
348  Pstream::exchange<labelList, label>
349  (
350  sendNonLocal,
351  recvNonLocal,
352  sizes
353  );
354 
355  // Now we have the wanted compact region labels that procI wants in
356  // recvNonLocal[procI]. Construct corresponding list of compact
357  // region labels to send back.
358 
359  labelListList sendWantedLocal(Pstream::nProcs());
360  forAll(recvNonLocal, procI)
361  {
362  const labelList& nonLocal = recvNonLocal[procI];
363  sendWantedLocal[procI].setSize(nonLocal.size());
364 
365  forAll(nonLocal, i)
366  {
367  sendWantedLocal[procI][i] = globalToCompact[nonLocal[i]];
368  }
369  }
370 
371 
372  // Send back (into recvNonLocal)
373  recvNonLocal.clear();
374  recvNonLocal.setSize(sendWantedLocal.size());
375  sizes.clear();
376  Pstream::exchange<labelList, label>
377  (
378  sendWantedLocal,
379  recvNonLocal,
380  sizes
381  );
382  sendWantedLocal.clear();
383 
384  // Now recvNonLocal contains for every element in setNonLocal the
385  // corresponding compact number. Insert these into the local compaction
386  // map.
387 
388  forAll(recvNonLocal, procI)
389  {
390  const labelList& wantedRegions = sendNonLocal[procI];
391  const labelList& compactRegions = recvNonLocal[procI];
392 
393  forAll(wantedRegions, i)
394  {
395  globalToCompact.insert(wantedRegions[i], compactRegions[i]);
396  }
397  }
398 
399  // Finally renumber the regions
400  forAll(cellRegion, cellI)
401  {
402  cellRegion[cellI] = globalToCompact[cellRegion[cellI]];
403  }
404 
405  return globalCompactPtr;
406 }
407 
408 
409 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
410 
411 Foam::regionSplit::regionSplit(const polyMesh& mesh, const bool doGlobalRegions)
412 :
414  labelList(mesh.nCells(), -1)
415 {
417  (
418  doGlobalRegions, //do global regions
419  boolList(0, false), //blockedFaces
420  List<labelPair>(0), //explicitConnections,
421  *this
422  );
423 }
424 
425 
427 (
428  const polyMesh& mesh,
429  const boolList& blockedFace,
430  const bool doGlobalRegions
431 )
432 :
434  labelList(mesh.nCells(), -1)
435 {
436  globalNumberingPtr_ = calcRegionSplit
437  (
438  doGlobalRegions,
439  blockedFace, //blockedFaces
440  List<labelPair>(0), //explicitConnections,
441  *this
442  );
443 }
444 
445 
447 (
448  const polyMesh& mesh,
449  const boolList& blockedFace,
450  const List<labelPair>& explicitConnections,
451  const bool doGlobalRegions
452 )
453 :
455  labelList(mesh.nCells(), -1)
456 {
457  globalNumberingPtr_ = calcRegionSplit
458  (
459  doGlobalRegions,
460  blockedFace, //blockedFaces
461  explicitConnections, //explicitConnections,
462  *this
463  );
464 }
465 
466 
467 // ************************************************************************* //
Foam::minData
For use with FaceCellWave. Transports minimum passive data.
Definition: minData.H:52
Foam::labelList
List< label > labelList
A List of labels.
Definition: labelList.H:56
Foam::polyBoundaryMesh
Foam::polyBoundaryMesh.
Definition: polyBoundaryMesh.H:60
cyclicPolyPatch.H
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::List::xfer
Xfer< List< T > > xfer()
Transfer contents to the Xfer container.
Definition: ListI.H:90
globalIndex.H
Foam::FaceCellWave::data
const TrackingData & data() const
Additional data to be passed into container.
Definition: FaceCellWave.H:331
Foam::Map< label >
Foam::globalIndex::isLocal
bool isLocal(const label i) const
Is on local processor.
Definition: globalIndexI.H:95
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::HashSet< label, Hash< label > >
syncTools.H
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
Foam::regionSplit::calcRegionSplit
autoPtr< globalIndex > calcRegionSplit(const bool doGlobalRegions, const boolList &blockedFace, const List< labelPair > &explicitConnections, labelList &cellRegion) const
Calculate global region split. Return globalIndex.
Definition: regionSplit.C:136
Foam::primitiveMesh::nCells
label nCells() const
Definition: primitiveMeshI.H:64
Foam::regionSplit::regionSplit
regionSplit(const polyMesh &, const bool doGlobalRegions=Pstream::parRun())
Construct from mesh.
Definition: regionSplit.C:411
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:59
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
regionSplit.H
Foam::regionSplit
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:119
Foam::List::resize
void resize(const label)
Alias for setSize(const label)
minData.H
Foam::FatalError
error FatalError
processorPolyPatch.H
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
Foam::boolList
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
Foam::polyPatch::start
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:312
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::List::setSize
void setSize(const label)
Reset size of List.
Foam::FaceCellWave
Wave propagation of information through grid. Every iteration information goes through one layer of c...
Definition: FaceCellWave.H:75
Foam::autoPtr< Foam::globalIndex >
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::regionSplit::calcNonCompactRegionSplit
void calcNonCompactRegionSplit(const globalIndex &globalFaces, const boolList &blockedFace, const List< labelPair > &explicitConnections, labelList &cellRegion) const
Calculate region split in non-compact (global) numbering.
Definition: regionSplit.C:46
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::globalIndex::whichProcID
label whichProcID(const label i) const
Which processor does global come from? Binary search.
Definition: globalIndexI.H:123
FaceCellWave.H
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: List.C:379
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
Foam::TopologicalMeshObject
Definition: MeshObject.H:202
Foam::MeshObject
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:81
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::regionSplit::globalNumberingPtr_
autoPtr< globalIndex > globalNumberingPtr_
Definition: regionSplit.H:126
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:56
Foam::globalIndex::toGlobal
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82