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 "cyclicPolyPatch.H"
28 #include "processorPolyPatch.H"
29 #include "globalIndex.H"
30 #include "syncTools.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 
37 defineTypeNameAndDebug(regionSplit, 0);
38 
39 }
40 
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 
43 // Handle (non-processor) coupled faces.
44 void Foam::regionSplit::transferCoupledFaceRegion
45 (
46  const label facei,
47  const label otherFacei,
48 
49  labelList& faceRegion,
50  DynamicList<label>& newChangedFaces
51 ) const
52 {
53  if (faceRegion[facei] >= 0)
54  {
55  if (faceRegion[otherFacei] == -1)
56  {
57  faceRegion[otherFacei] = faceRegion[facei];
58  newChangedFaces.append(otherFacei);
59  }
60  else if (faceRegion[otherFacei] == -2)
61  {
62  // otherFacei blocked but facei is not. Is illegal for coupled
63  // faces, not for explicit connections.
64  }
65  else if (faceRegion[otherFacei] != faceRegion[facei])
66  {
68  << "Problem : coupled face " << facei
69  << " on patch " << mesh().boundaryMesh().whichPatch(facei)
70  << " has region " << faceRegion[facei]
71  << " but coupled face " << otherFacei
72  << " has region " << faceRegion[otherFacei]
73  << endl
74  << "Is your blocked faces specification"
75  << " synchronized across coupled boundaries?"
76  << abort(FatalError);
77  }
78  }
79  else if (faceRegion[facei] == -1)
80  {
81  if (faceRegion[otherFacei] >= 0)
82  {
83  faceRegion[facei] = faceRegion[otherFacei];
84  newChangedFaces.append(facei);
85  }
86  else if (faceRegion[otherFacei] == -2)
87  {
88  // otherFacei blocked but facei is not. Is illegal for coupled
89  // faces, not for explicit connections.
90  }
91  }
92 }
93 
94 
95 void Foam::regionSplit::fillSeedMask
96 (
97  const List<labelPair>& explicitConnections,
98  labelList& cellRegion,
99  labelList& faceRegion,
100  const label seedCellID,
101  const label markValue
102 ) const
103 {
104  // Do seed cell
105  cellRegion[seedCellID] = markValue;
106 
107 
108  // Collect faces on seed cell
109  const cell& cFaces = mesh().cells()[seedCellID];
110 
111  label nFaces = 0;
112 
113  labelList changedFaces(cFaces.size());
114 
115  forAll(cFaces, i)
116  {
117  label facei = cFaces[i];
118 
119  if (faceRegion[facei] == -1)
120  {
121  faceRegion[facei] = markValue;
122  changedFaces[nFaces++] = facei;
123  }
124  }
125  changedFaces.setSize(nFaces);
126 
127 
128  // Loop over changed faces. FaceCellWave in small.
129 
130  while (changedFaces.size())
131  {
132  //if (debug)
133  //{
134  // Pout<< "regionSplit::fillSeedMask : changedFaces:"
135  // << changedFaces.size() << endl;
136  //}
137 
138  DynamicList<label> changedCells(changedFaces.size());
139 
140  forAll(changedFaces, i)
141  {
142  label facei = changedFaces[i];
143 
144  label own = mesh().faceOwner()[facei];
145 
146  if (cellRegion[own] == -1)
147  {
148  cellRegion[own] = markValue;
149  changedCells.append(own);
150  }
151 
152  if (mesh().isInternalFace(facei))
153  {
154  label nei = mesh().faceNeighbour()[facei];
155 
156  if (cellRegion[nei] == -1)
157  {
158  cellRegion[nei] = markValue;
159  changedCells.append(nei);
160  }
161  }
162  }
163 
164 
165  //if (debug)
166  //{
167  // Pout<< "regionSplit::fillSeedMask : changedCells:"
168  // << changedCells.size() << endl;
169  //}
170 
171  // Loop over changedCells and collect faces
172  DynamicList<label> newChangedFaces(changedCells.size());
173 
174  forAll(changedCells, i)
175  {
176  label celli = changedCells[i];
177 
178  const cell& cFaces = mesh().cells()[celli];
179 
180  forAll(cFaces, cFacei)
181  {
182  label facei = cFaces[cFacei];
183 
184  if (faceRegion[facei] == -1)
185  {
186  faceRegion[facei] = markValue;
187  newChangedFaces.append(facei);
188  }
189  }
190  }
191 
192 
193  //if (debug)
194  //{
195  // Pout<< "regionSplit::fillSeedMask : changedFaces before sync:"
196  // << changedFaces.size() << endl;
197  //}
198 
199 
200  // Check for changes to any locally coupled face.
201  // Global connections are done later.
202 
203  const polyBoundaryMesh& patches = mesh().boundaryMesh();
204 
205  forAll(patches, patchi)
206  {
207  const polyPatch& pp = patches[patchi];
208 
209  if
210  (
211  isA<cyclicPolyPatch>(pp)
212  && refCast<const cyclicPolyPatch>(pp).owner()
213  )
214  {
215  // Transfer from neighbourPatch to here or vice versa.
216 
217  const cyclicPolyPatch& cycPatch =
218  refCast<const cyclicPolyPatch>(pp);
219 
220  label facei = cycPatch.start();
221 
222  forAll(cycPatch, i)
223  {
224  label otherFacei = cycPatch.transformGlobalFace(facei);
225 
226  transferCoupledFaceRegion
227  (
228  facei,
229  otherFacei,
230  faceRegion,
231  newChangedFaces
232  );
233 
234  facei++;
235  }
236  }
237  }
238  forAll(explicitConnections, i)
239  {
240  transferCoupledFaceRegion
241  (
242  explicitConnections[i][0],
243  explicitConnections[i][1],
244  faceRegion,
245  newChangedFaces
246  );
247  }
248 
249  //if (debug)
250  //{
251  // Pout<< "regionSplit::fillSeedMask : changedFaces after sync:"
252  // << newChangedFaces.size() << endl;
253  //}
254 
255  changedFaces.transfer(newChangedFaces);
256  }
257 }
258 
259 
260 Foam::label Foam::regionSplit::calcLocalRegionSplit
261 (
262  const boolList& blockedFace,
263  const List<labelPair>& explicitConnections,
264 
265  labelList& cellRegion
266 ) const
267 {
268  if (debug)
269  {
270  if (blockedFace.size())
271  {
272  // Check that blockedFace is synced.
273  boolList syncBlockedFace(blockedFace);
274  syncTools::swapFaceList(mesh(), syncBlockedFace);
275 
276  forAll(syncBlockedFace, facei)
277  {
278  if (syncBlockedFace[facei] != blockedFace[facei])
279  {
281  << "Face " << facei << " not synchronised. My value:"
282  << blockedFace[facei] << " coupled value:"
283  << syncBlockedFace[facei]
284  << abort(FatalError);
285  }
286  }
287  }
288  }
289 
290  // Region per face.
291  // -1 unassigned
292  // -2 blocked
293  labelList faceRegion(mesh().nFaces(), -1);
294 
295  if (blockedFace.size())
296  {
297  forAll(blockedFace, facei)
298  {
299  if (blockedFace[facei])
300  {
301  faceRegion[facei] = -2;
302  }
303  }
304  }
305 
306 
307  // Assign local regions
308  // ~~~~~~~~~~~~~~~~~~~~
309 
310  // Start with region 0
311  label nLocalRegions = 0;
312 
313  label unsetCelli = 0;
314 
315  do
316  {
317  // Find first unset cell
318 
319  for (; unsetCelli < mesh().nCells(); unsetCelli++)
320  {
321  if (cellRegion[unsetCelli] == -1)
322  {
323  break;
324  }
325  }
326 
327  if (unsetCelli >= mesh().nCells())
328  {
329  break;
330  }
331 
332  fillSeedMask
333  (
334  explicitConnections,
335  cellRegion,
336  faceRegion,
337  unsetCelli,
338  nLocalRegions
339  );
340 
341  // Current unsetCell has now been handled. Go to next region.
342  nLocalRegions++;
343  unsetCelli++;
344  }
345  while (true);
346 
347 
348  if (debug)
349  {
350  forAll(cellRegion, celli)
351  {
352  if (cellRegion[celli] < 0)
353  {
355  << "cell:" << celli << " region:" << cellRegion[celli]
356  << abort(FatalError);
357  }
358  }
359 
360  forAll(faceRegion, facei)
361  {
362  if (faceRegion[facei] == -1)
363  {
365  << "face:" << facei << " region:" << faceRegion[facei]
366  << abort(FatalError);
367  }
368  }
369  }
370 
371  return nLocalRegions;
372 }
373 
374 
375 Foam::autoPtr<Foam::globalIndex> Foam::regionSplit::calcRegionSplit
376 (
377  const bool doGlobalRegions,
378  const boolList& blockedFace,
379  const List<labelPair>& explicitConnections,
380 
381  labelList& cellRegion
382 ) const
383 {
384  // See header in regionSplit.H
385 
386  // 1. Do local analysis
387  label nLocalRegions = calcLocalRegionSplit
388  (
389  blockedFace,
390  explicitConnections,
391  cellRegion
392  );
393 
394  if (!doGlobalRegions)
395  {
396  return autoPtr<globalIndex>(new globalIndex(nLocalRegions));
397  }
398 
399 
400  // 2. Assign global regions
401  // ~~~~~~~~~~~~~~~~~~~~~~~~
402  // Offset local regions to create unique global regions.
403 
404  globalIndex globalRegions(nLocalRegions);
405 
406 
407  // Convert regions to global ones
408  forAll(cellRegion, celli)
409  {
410  cellRegion[celli] = globalRegions.toGlobal(cellRegion[celli]);
411  }
412 
413 
414  // 3. Merge global regions
415  // ~~~~~~~~~~~~~~~~~~~~~~~
416  // Regions across non-blocked proc patches get merged.
417  // This will set merged global regions to be the min of both.
418  // (this will create gaps in the global region list so they will get
419  // merged later on)
420 
421  while (true)
422  {
423  if (debug)
424  {
425  Pout<< nl << "-- Starting Iteration --" << endl;
426  }
427 
428 
429  const polyBoundaryMesh& patches = mesh().boundaryMesh();
430 
431  labelList nbrRegion(mesh().nFaces()-mesh().nInternalFaces(), -1);
432  forAll(patches, patchi)
433  {
434  const polyPatch& pp = patches[patchi];
435 
436  if (pp.coupled())
437  {
438  const labelList& patchCells = pp.faceCells();
439  SubList<label> patchNbrRegion
440  (
441  nbrRegion,
442  pp.size(),
443  pp.start()-mesh().nInternalFaces()
444  );
445 
446  forAll(patchCells, i)
447  {
448  label facei = pp.start()+i;
449  if (!blockedFace.size() || !blockedFace[facei])
450  {
451  patchNbrRegion[i] = cellRegion[patchCells[i]];
452  }
453  }
454  }
455  }
457 
458  Map<label> globalToMerged(mesh().nFaces()-mesh().nInternalFaces());
459 
460  forAll(patches, patchi)
461  {
462  const polyPatch& pp = patches[patchi];
463 
464  if (pp.coupled())
465  {
466  const labelList& patchCells = pp.faceCells();
467  SubList<label> patchNbrRegion
468  (
469  nbrRegion,
470  pp.size(),
471  pp.start()-mesh().nInternalFaces()
472  );
473 
474  forAll(patchCells, i)
475  {
476  label facei = pp.start()+i;
477 
478  if (!blockedFace.size() || !blockedFace[facei])
479  {
480  if (patchNbrRegion[i] < cellRegion[patchCells[i]])
481  {
482  //Pout<< "on patch:" << pp.name()
483  // << " cell:" << patchCells[i]
484  // << " at:"
485  // << mesh().cellCentres()[patchCells[i]]
486  // << " was:" << cellRegion[patchCells[i]]
487  // << " nbr:" << patchNbrRegion[i]
488  // << endl;
489 
490  globalToMerged.insert
491  (
492  cellRegion[patchCells[i]],
493  patchNbrRegion[i]
494  );
495  }
496  }
497  }
498  }
499  }
500 
501 
502  label nMerged = returnReduce(globalToMerged.size(), sumOp<label>());
503 
504  if (debug)
505  {
506  Pout<< "nMerged:" << nMerged << endl;
507  }
508 
509  if (nMerged == 0)
510  {
511  break;
512  }
513 
514  // Renumber the regions according to the globalToMerged
515  forAll(cellRegion, celli)
516  {
517  label regionI = cellRegion[celli];
518  Map<label>::const_iterator iter = globalToMerged.find(regionI);
519  if (iter != globalToMerged.end())
520  {
521  cellRegion[celli] = iter();
522  }
523  }
524  }
525 
526 
527  // Now our cellRegion will have non-local elements in it. So compact
528  // it.
529 
530  // 4a: count. Use a labelHashSet to count regions only once.
531  label nCompact = 0;
532  {
533  labelHashSet localRegion(mesh().nFaces()-mesh().nInternalFaces());
534  forAll(cellRegion, celli)
535  {
536  if
537  (
538  globalRegions.isLocal(cellRegion[celli])
539  && localRegion.insert(cellRegion[celli])
540  )
541  {
542  nCompact++;
543  }
544  }
545  }
546 
547  if (debug)
548  {
549  Pout<< "Compacted from " << nLocalRegions
550  << " down to " << nCompact << " local regions." << endl;
551  }
552 
553 
554  // Global numbering for compacted local regions
555  autoPtr<globalIndex> globalCompactPtr(new globalIndex(nCompact));
556  const globalIndex& globalCompact = globalCompactPtr();
557 
558 
559  // 4b: renumber
560  // Renumber into compact indices. Note that since we've already made
561  // all regions global we now need a Map to store the compacting information
562  // instead of a labelList - otherwise we could have used a straight
563  // labelList.
564 
565  // Local compaction map
566  Map<label> globalToCompact(2*nCompact);
567  // Remote regions we want the compact number for
568  List<labelHashSet> nonLocal(Pstream::nProcs());
569  forAll(nonLocal, proci)
570  {
571  nonLocal[proci].resize((nLocalRegions-nCompact)/Pstream::nProcs());
572  }
573 
574  forAll(cellRegion, celli)
575  {
576  label region = cellRegion[celli];
577  if (globalRegions.isLocal(region))
578  {
579  Map<label>::const_iterator iter = globalToCompact.find(region);
580  if (iter == globalToCompact.end())
581  {
582  label compactRegion = globalCompact.toGlobal
583  (
584  globalToCompact.size()
585  );
586  globalToCompact.insert(region, compactRegion);
587  }
588  }
589  else
590  {
591  nonLocal[globalRegions.whichProcID(region)].insert(region);
592  }
593  }
594 
595 
596  // Now we have all the local regions compacted. Now we need to get the
597  // non-local ones from the processors to whom they are local.
598  // Convert the nonLocal (labelHashSets) to labelLists.
599 
600  labelListList sendNonLocal(Pstream::nProcs());
601  labelList nNonLocal(Pstream::nProcs(), 0);
602  forAll(sendNonLocal, proci)
603  {
604  sendNonLocal[proci].setSize(nonLocal[proci].size());
605  forAllConstIter(labelHashSet, nonLocal[proci], iter)
606  {
607  sendNonLocal[proci][nNonLocal[proci]++] = iter.key();
608  }
609  }
610 
611  if (debug)
612  {
613  forAll(nNonLocal, proci)
614  {
615  Pout<< " from processor " << proci
616  << " want " << nNonLocal[proci]
617  << " region numbers."
618  << endl;
619  }
620  Pout<< endl;
621  }
622 
623 
624  // Get the wanted region labels into recvNonLocal
625  labelListList recvNonLocal;
626  Pstream::exchange<labelList, label>(sendNonLocal, recvNonLocal);
627 
628  // Now we have the wanted compact region labels that proci wants in
629  // recvNonLocal[proci]. Construct corresponding list of compact
630  // region labels to send back.
631 
632  labelListList sendWantedLocal(Pstream::nProcs());
633  forAll(recvNonLocal, proci)
634  {
635  const labelList& nonLocal = recvNonLocal[proci];
636  sendWantedLocal[proci].setSize(nonLocal.size());
637 
638  forAll(nonLocal, i)
639  {
640  sendWantedLocal[proci][i] = globalToCompact[nonLocal[i]];
641  }
642  }
643 
644 
645  // Send back (into recvNonLocal)
646  recvNonLocal.clear();
647  Pstream::exchange<labelList, label>(sendWantedLocal, recvNonLocal);
648  sendWantedLocal.clear();
649 
650  // Now recvNonLocal contains for every element in setNonLocal the
651  // corresponding compact number. Insert these into the local compaction
652  // map.
653 
654  forAll(recvNonLocal, proci)
655  {
656  const labelList& wantedRegions = sendNonLocal[proci];
657  const labelList& compactRegions = recvNonLocal[proci];
658 
659  forAll(wantedRegions, i)
660  {
661  globalToCompact.insert(wantedRegions[i], compactRegions[i]);
662  }
663  }
664 
665  // Finally renumber the regions
666  forAll(cellRegion, celli)
667  {
668  cellRegion[celli] = globalToCompact[cellRegion[celli]];
669  }
670 
671  return globalCompactPtr;
672 }
673 
674 
675 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
676 
677 Foam::regionSplit::regionSplit(const polyMesh& mesh, const bool doGlobalRegions)
678 :
680  labelList(mesh.nCells(), -1)
681 {
682  globalNumberingPtr_ = calcRegionSplit
683  (
684  doGlobalRegions, //do global regions
685  boolList(0, false), //blockedFaces
686  List<labelPair>(0), //explicitConnections,
687  *this
688  );
689 }
690 
691 
693 (
694  const polyMesh& mesh,
695  const boolList& blockedFace,
696  const bool doGlobalRegions
697 )
698 :
700  labelList(mesh.nCells(), -1)
701 {
702  globalNumberingPtr_ = calcRegionSplit
703  (
704  doGlobalRegions,
705  blockedFace, //blockedFaces
706  List<labelPair>(0), //explicitConnections,
707  *this
708  );
709 }
710 
711 
713 (
714  const polyMesh& mesh,
715  const boolList& blockedFace,
716  const List<labelPair>& explicitConnections,
717  const bool doGlobalRegions
718 )
719 :
721  labelList(mesh.nCells(), -1)
722 {
723  globalNumberingPtr_ = calcRegionSplit
724  (
725  doGlobalRegions,
726  blockedFace, //blockedFaces
727  explicitConnections, //explicitConnections,
728  *this
729  );
730 }
731 
732 
733 // ************************************************************************* //
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:116
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
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
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
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:421
label nCells() 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
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:97
List< label > labelList
A List of labels.
Definition: labelList.H:56
static void swapFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled face values.
Definition: syncTools.H:463
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
static const char nl
Definition: Ostream.H:262
defineTypeNameAndDebug(combustionModel, 0)
regionSplit(const polyMesh &, const bool doGlobalRegions=Pstream::parRun())
Construct from mesh.
Definition: regionSplit.C:677
void setSize(const label)
Reset size of List.
Definition: List.C:295
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:399
label patchi
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1023
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:430
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1017
label nInternalFaces() const
Namespace for OpenFOAM.