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-2016 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 "regionSplit.H"
27 #include "FaceCellWave.H"
28 #include "cyclicPolyPatch.H"
29 #include "processorPolyPatch.H"
30 #include "globalIndex.H"
31 #include "syncTools.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 
45 void Foam::regionSplit::calcNonCompactRegionSplit
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  {
122  FatalErrorIn("regionSplit::calcNonCompactRegionSplit(..)")
123  << "Problem: unblocked face " << facei
124  << " at " << mesh().faceCentres()[facei]
125  << " on unassigned cell " << celli
126  << mesh().cellCentres()[celli]
127  << exit(FatalError);
128  }
129  cellRegion[celli] = globalFaces.toGlobal(facei);
130  }
131  }
132 }
133 
134 
135 Foam::autoPtr<Foam::globalIndex> Foam::regionSplit::calcRegionSplit
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;
347  Pstream::exchange<labelList, label>(sendNonLocal, recvNonLocal);
348 
349  // Now we have the wanted compact region labels that proci wants in
350  // recvNonLocal[proci]. Construct corresponding list of compact
351  // region labels to send back.
352 
353  labelListList sendWantedLocal(Pstream::nProcs());
354  forAll(recvNonLocal, proci)
355  {
356  const labelList& nonLocal = recvNonLocal[proci];
357  sendWantedLocal[proci].setSize(nonLocal.size());
358 
359  forAll(nonLocal, i)
360  {
361  sendWantedLocal[proci][i] = globalToCompact[nonLocal[i]];
362  }
363  }
364 
365 
366  // Send back (into recvNonLocal)
367  recvNonLocal.clear();
368  Pstream::exchange<labelList, label>(sendWantedLocal, recvNonLocal);
369  sendWantedLocal.clear();
370 
371  // Now recvNonLocal contains for every element in setNonLocal the
372  // corresponding compact number. Insert these into the local compaction
373  // map.
374 
375  forAll(recvNonLocal, proci)
376  {
377  const labelList& wantedRegions = sendNonLocal[proci];
378  const labelList& compactRegions = recvNonLocal[proci];
379 
380  forAll(wantedRegions, i)
381  {
382  globalToCompact.insert(wantedRegions[i], compactRegions[i]);
383  }
384  }
385 
386  // Finally renumber the regions
387  forAll(cellRegion, celli)
388  {
389  cellRegion[celli] = globalToCompact[cellRegion[celli]];
390  }
391 
392  return globalCompactPtr;
393 }
394 
395 
396 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
397 
398 Foam::regionSplit::regionSplit(const polyMesh& mesh, const bool doGlobalRegions)
399 :
401  labelList(mesh.nCells(), -1)
402 {
403  globalNumberingPtr_ = calcRegionSplit
404  (
405  doGlobalRegions, //do global regions
406  boolList(0, false), //blockedFaces
407  List<labelPair>(0), //explicitConnections,
408  *this
409  );
410 }
411 
412 
414 (
415  const polyMesh& mesh,
416  const boolList& blockedFace,
417  const bool doGlobalRegions
418 )
419 :
421  labelList(mesh.nCells(), -1)
422 {
423  globalNumberingPtr_ = calcRegionSplit
424  (
425  doGlobalRegions,
426  blockedFace, //blockedFaces
427  List<labelPair>(0), //explicitConnections,
428  *this
429  );
430 }
431 
432 
434 (
435  const polyMesh& mesh,
436  const boolList& blockedFace,
437  const List<labelPair>& explicitConnections,
438  const bool doGlobalRegions
439 )
440 :
442  labelList(mesh.nCells(), -1)
443 {
444  globalNumberingPtr_ = calcRegionSplit
445  (
446  doGlobalRegions,
447  blockedFace, //blockedFaces
448  explicitConnections, //explicitConnections,
449  *this
450  );
451 }
452 
453 
454 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:424
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:119
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
error FatalError
label nFaces() const
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:418
label nCells() const
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
HashTable< label, label, Hash< label > >::const_iterator const_iterator
Definition: Map.H:59
const cellList & cells() const
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:210
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:85
dynamicFvMesh & mesh
List< label > labelList
A List of labels.
Definition: labelList.H:56
const vectorField & cellCentres() const
defineTypeNameAndDebug(combustionModel, 0)
regionSplit(const polyMesh &, const bool doGlobalRegions=Pstream::parRun())
Construct from mesh.
Definition: regionSplit.C:398
const vectorField & faceCentres() const
void setSize(const label)
Reset size of List.
Definition: List.C:281
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:400
label patchi
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
Namespace for OpenFOAM.