regionSplit.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 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 {
39 }
40 
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 
43 void Foam::regionSplit::calcNonCompactRegionSplit
44 (
45  const globalIndex& globalFaces,
46  const boolList& blockedFace,
47  const List<labelPair>& explicitConnections,
48 
49  labelList& cellRegion
50 ) const
51 {
52  // Field on cells and faces.
53  List<minData> cellData(mesh().nCells());
54  List<minData> faceData(mesh().nFaces());
55 
56  // Take over blockedFaces by seeding a negative number
57  // (so is always less than the decomposition)
58  label nUnblocked = 0;
59  forAll(faceData, facei)
60  {
61  if (blockedFace.size() && blockedFace[facei])
62  {
63  faceData[facei] = minData(-2);
64  }
65  else
66  {
67  nUnblocked++;
68  }
69  }
70 
71  // Seed unblocked faces
72  labelList seedFaces(nUnblocked);
73  List<minData> seedData(nUnblocked);
74  nUnblocked = 0;
75 
76 
77  forAll(faceData, facei)
78  {
79  if (blockedFace.empty() || !blockedFace[facei])
80  {
81  seedFaces[nUnblocked] = facei;
82  // Seed face with globally unique number
83  seedData[nUnblocked] = minData(globalFaces.toGlobal(facei));
84  nUnblocked++;
85  }
86  }
87 
88 
89  // Propagate information inwards
90  FaceCellWave<minData> deltaCalc
91  (
92  mesh(),
93  explicitConnections,
94  seedFaces,
95  seedData,
96  faceData,
97  cellData,
98  mesh().globalData().nTotalCells()+1
99  );
100 
101 
102  // And extract
103  cellRegion.setSize(mesh().nCells());
104  forAll(cellRegion, celli)
105  {
106  if (cellData[celli].valid(deltaCalc.data()))
107  {
108  cellRegion[celli] = cellData[celli].data();
109  }
110  else
111  {
112  // Unvisited cell -> only possible if surrounded by blocked faces.
113  // If so make up region from any of the faces
114  const cell& cFaces = mesh().cells()[celli];
115  label facei = cFaces[0];
116 
117  if (blockedFace.size() && !blockedFace[facei])
118  {
119  FatalErrorIn("regionSplit::calcNonCompactRegionSplit(..)")
120  << "Problem: unblocked face " << facei
121  << " at " << mesh().faceCentres()[facei]
122  << " on unassigned cell " << celli
123  << mesh().cellCentres()[celli]
124  << exit(FatalError);
125  }
126  cellRegion[celli] = globalFaces.toGlobal(facei);
127  }
128  }
129 }
130 
131 
132 Foam::autoPtr<Foam::globalIndex> Foam::regionSplit::calcRegionSplit
133 (
134  const bool doGlobalRegions,
135  const boolList& blockedFace,
136  const List<labelPair>& explicitConnections,
137 
138  labelList& cellRegion
139 ) const
140 {
141  // See header in regionSplit.H
142 
143 
144  if (!doGlobalRegions)
145  {
146  // Block all parallel faces to avoid comms across
147  boolList coupledOrBlockedFace(blockedFace);
148  const polyBoundaryMesh& pbm = mesh().boundaryMesh();
149 
150  if (coupledOrBlockedFace.size())
151  {
152  forAll(pbm, patchi)
153  {
154  const polyPatch& pp = pbm[patchi];
155  if (isA<processorPolyPatch>(pp))
156  {
157  label facei = pp.start();
158  forAll(pp, i)
159  {
160  coupledOrBlockedFace[facei++] = true;
161  }
162  }
163  }
164  }
165 
166  // Create dummy (local only) globalIndex
167  labelList offsets(Pstream::nProcs()+1, 0);
168  for (label i = Pstream::myProcNo()+1; i < offsets.size(); i++)
169  {
170  offsets[i] = mesh().nFaces();
171  }
172  const globalIndex globalRegions(move(offsets));
173 
174  // Minimise regions across connected cells
175  // Note: still uses global decisions so all processors are running
176  // in lock-step, i.e. slowest determines overall time.
177  // To avoid this we could switch off Pstream::parRun.
178  calcNonCompactRegionSplit
179  (
180  globalRegions,
181  coupledOrBlockedFace,
182  explicitConnections,
183  cellRegion
184  );
185 
186  // Compact
187  Map<label> globalToCompact(mesh().nCells()/8);
188  forAll(cellRegion, celli)
189  {
190  label region = cellRegion[celli];
191 
192  label globalRegion;
193 
194  Map<label>::const_iterator fnd = globalToCompact.find(region);
195  if (fnd == globalToCompact.end())
196  {
197  globalRegion = globalRegions.toGlobal(globalToCompact.size());
198  globalToCompact.insert(region, globalRegion);
199  }
200  else
201  {
202  globalRegion = fnd();
203  }
204  cellRegion[celli] = globalRegion;
205  }
206 
207 
208  // Return globalIndex with size = localSize and all regions local
209  labelList compactOffsets(Pstream::nProcs()+1, 0);
210  for (label i = Pstream::myProcNo()+1; i < compactOffsets.size(); i++)
211  {
212  compactOffsets[i] = globalToCompact.size();
213  }
214 
215  return autoPtr<globalIndex>(new globalIndex(move(compactOffsets)));
216  }
217 
218 
219 
220  // Initial global region numbers
221  const globalIndex globalRegions(mesh().nFaces());
222 
223  // Minimise regions across connected cells (including parallel)
224  calcNonCompactRegionSplit
225  (
226  globalRegions,
227  blockedFace,
228  explicitConnections,
229  cellRegion
230  );
231 
232 
233  // Now our cellRegion will have
234  // - non-local regions (i.e. originating from other processors)
235  // - non-compact locally originating regions
236  // so we'll need to compact
237 
238  // 4a: count per originating processor the number of regions
239  labelList nOriginating(Pstream::nProcs(), 0);
240  {
241  labelHashSet haveRegion(mesh().nCells()/8);
242 
243  forAll(cellRegion, celli)
244  {
245  label region = cellRegion[celli];
246 
247  // Count originating processor. Use isLocal as efficiency since
248  // most cells are locally originating.
249  if (globalRegions.isLocal(region))
250  {
251  if (haveRegion.insert(region))
252  {
253  nOriginating[Pstream::myProcNo()]++;
254  }
255  }
256  else
257  {
258  label proci = globalRegions.whichProcID(region);
259  if (haveRegion.insert(region))
260  {
261  nOriginating[proci]++;
262  }
263  }
264  }
265  }
266 
267  if (debug)
268  {
269  Pout<< "Counted " << nOriginating[Pstream::myProcNo()]
270  << " local regions." << endl;
271  }
272 
273 
274  // Global numbering for compacted local regions
275  autoPtr<globalIndex> globalCompactPtr
276  (
277  new globalIndex(nOriginating[Pstream::myProcNo()])
278  );
279  const globalIndex& globalCompact = globalCompactPtr();
280 
281 
282  // 4b: renumber
283  // Renumber into compact indices. Note that since we've already made
284  // all regions global we now need a Map to store the compacting information
285  // instead of a labelList - otherwise we could have used a straight
286  // labelList.
287 
288  // Local compaction map
289  Map<label> globalToCompact(2*nOriginating[Pstream::myProcNo()]);
290  // Remote regions we want the compact number for
291  List<labelHashSet> nonLocal(Pstream::nProcs());
292  forAll(nonLocal, proci)
293  {
294  if (proci != Pstream::myProcNo())
295  {
296  nonLocal[proci].resize(2*nOriginating[proci]);
297  }
298  }
299 
300  forAll(cellRegion, celli)
301  {
302  label region = cellRegion[celli];
303  if (globalRegions.isLocal(region))
304  {
305  // Insert new compact region (if not yet present)
306  globalToCompact.insert
307  (
308  region,
309  globalCompact.toGlobal(globalToCompact.size())
310  );
311  }
312  else
313  {
314  nonLocal[globalRegions.whichProcID(region)].insert(region);
315  }
316  }
317 
318 
319  // Now we have all the local regions compacted. Now we need to get the
320  // non-local ones from the processors to whom they are local.
321  // Convert the nonLocal (labelHashSets) to labelLists.
322 
323  labelListList sendNonLocal(Pstream::nProcs());
324  forAll(sendNonLocal, proci)
325  {
326  sendNonLocal[proci] = nonLocal[proci].toc();
327  }
328 
329  if (debug)
330  {
331  forAll(sendNonLocal, proci)
332  {
333  Pout<< " from processor " << proci
334  << " want " << sendNonLocal[proci].size()
335  << " region numbers."
336  << endl;
337  }
338  Pout<< endl;
339  }
340 
341 
342  // Get the wanted region labels into recvNonLocal
343  labelListList recvNonLocal;
344  Pstream::exchange<labelList, label>(sendNonLocal, recvNonLocal);
345 
346  // Now we have the wanted compact region labels that proci wants in
347  // recvNonLocal[proci]. Construct corresponding list of compact
348  // region labels to send back.
349 
350  labelListList sendWantedLocal(Pstream::nProcs());
351  forAll(recvNonLocal, proci)
352  {
353  const labelList& nonLocal = recvNonLocal[proci];
354  sendWantedLocal[proci].setSize(nonLocal.size());
355 
356  forAll(nonLocal, i)
357  {
358  sendWantedLocal[proci][i] = globalToCompact[nonLocal[i]];
359  }
360  }
361 
362 
363  // Send back (into recvNonLocal)
364  recvNonLocal.clear();
365  Pstream::exchange<labelList, label>(sendWantedLocal, recvNonLocal);
366  sendWantedLocal.clear();
367 
368  // Now recvNonLocal contains for every element in setNonLocal the
369  // corresponding compact number. Insert these into the local compaction
370  // map.
371 
372  forAll(recvNonLocal, proci)
373  {
374  const labelList& wantedRegions = sendNonLocal[proci];
375  const labelList& compactRegions = recvNonLocal[proci];
376 
377  forAll(wantedRegions, i)
378  {
379  globalToCompact.insert(wantedRegions[i], compactRegions[i]);
380  }
381  }
382 
383  // Finally renumber the regions
384  forAll(cellRegion, celli)
385  {
386  cellRegion[celli] = globalToCompact[cellRegion[celli]];
387  }
388 
389  return globalCompactPtr;
390 }
391 
392 
393 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
394 
395 Foam::regionSplit::regionSplit(const polyMesh& mesh, const bool doGlobalRegions)
396 :
397  labelList(mesh.nCells(), -1),
398  mesh_(mesh)
399 {
400  globalNumberingPtr_ = calcRegionSplit
401  (
402  doGlobalRegions, // do global regions
403  boolList(0, false), // blockedFaces
404  List<labelPair>(0), // explicitConnections,
405  *this
406  );
407 }
408 
409 
411 (
412  const polyMesh& mesh,
413  const boolList& blockedFace,
414  const bool doGlobalRegions
415 )
416 :
417  labelList(mesh.nCells(), -1),
418  mesh_(mesh)
419 {
420  globalNumberingPtr_ = calcRegionSplit
421  (
422  doGlobalRegions,
423  blockedFace, // blockedFaces
424  List<labelPair>(0), // explicitConnections,
425  *this
426  );
427 }
428 
429 
431 (
432  const polyMesh& mesh,
433  const boolList& blockedFace,
434  const List<labelPair>& explicitConnections,
435  const bool doGlobalRegions
436 )
437 :
438  labelList(mesh.nCells(), -1),
439  mesh_(mesh)
440 {
441  globalNumberingPtr_ = calcRegionSplit
442  (
443  doGlobalRegions,
444  blockedFace, // blockedFaces
445  explicitConnections, // explicitConnections,
446  *this
447  );
448 }
449 
450 
451 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
void setSize(const label)
Reset size of List.
Definition: List.C:281
HashTable< label, label, Hash< label > >::const_iterator const_iterator
Definition: Map.H:59
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const vectorField & faceCentres() const
const vectorField & cellCentres() const
const cellList & cells() const
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:118
regionSplit(const polyMesh &, const bool doGlobalRegions=Pstream::parRun())
Construct from mesh.
Definition: regionSplit.C:395
const polyMesh & mesh() const
Return reference to the polyMesh.
Definition: regionSplit.H:190
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:301
label patchi
bool valid(const PtrList< ModelType > &l)
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
defineTypeNameAndDebug(combustionModel, 0)
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:211
error FatalError