Forward compatibility: flex
[foam-extend-3.2.git] / src / meshTools / regionSplit / regionSplit.C
blobc112a1e42f6d41eae3fa59797faae68d3b196075
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "regionSplit.H"
27 #include "cyclicPolyPatch.H"
28 #include "processorPolyPatch.H"
29 #include "globalIndex.H"
30 #include "syncTools.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 namespace Foam
37 defineTypeNameAndDebug(regionSplit, 0);
41 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
43 // Handle (non-processor) coupled faces.
44 void Foam::regionSplit::transferCoupledFaceRegion
46     const label faceI,
47     const label otherFaceI,
49     labelList& faceRegion,
50     dynamicLabelList& newChangedFaces
51 ) const
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         {
67             FatalErrorIn
68             (
69                   "regionSplit::transferCoupledFaceRegion"
70                   "(const label, const label, labelList&, labelList&) const"
71               )   << "Problem : coupled face " << faceI
72                   << " on patch " << mesh_.boundaryMesh().whichPatch(faceI)
73                   << " has region " << faceRegion[faceI]
74                   << " but coupled face " << otherFaceI
75                   << " has region " << faceRegion[otherFaceI]
76                   << endl
77                   << "Is your blocked faces specification"
78                   << " synchronized across coupled boundaries?"
79                   << abort(FatalError);
80         }
81     }
82     else if (faceRegion[faceI] == -1)
83     {
84         if (faceRegion[otherFaceI] >= 0)
85         {
86             faceRegion[faceI] = faceRegion[otherFaceI];
87             newChangedFaces.append(faceI);
88         }
89         else if (faceRegion[otherFaceI] == -2)
90         {
91             // otherFaceI blocked but faceI is not. Is illegal for coupled
92             // faces, not for explicit connections.
93         }
94     }
98 void Foam::regionSplit::fillSeedMask
100     const List<labelPair>& explicitConnections,
101     labelList& cellRegion,
102     labelList& faceRegion,
103     const label seedCellID,
104     const label markValue
105 ) const
107     // Do seed cell
108     cellRegion[seedCellID] = markValue;
111     // Collect faces on seed cell
112     const cell& cFaces = mesh_.cells()[seedCellID];
114     label nFaces = 0;
116     labelList changedFaces(cFaces.size());
118     forAll(cFaces, i)
119     {
120         label faceI = cFaces[i];
122         if (faceRegion[faceI] == -1)
123         {
124             faceRegion[faceI] = markValue;
125             changedFaces[nFaces++] = faceI;
126         }
127     }
128     changedFaces.setSize(nFaces);
131     // Loop over changed faces. MeshWave in small.
133     while (changedFaces.size())
134     {
135         //if (debug)
136         //{
137         //    Pout<< "regionSplit::fillSeedMask : changedFaces:"
138         //        << changedFaces.size() << endl;
139         //}
141         dynamicLabelList changedCells(changedFaces.size());
143         forAll(changedFaces, i)
144         {
145             label faceI = changedFaces[i];
147             label own = mesh_.faceOwner()[faceI];
149             if (cellRegion[own] == -1)
150             {
151                 cellRegion[own] = markValue;
152                 changedCells.append(own);
153             }
155             if (mesh_.isInternalFace(faceI))
156             {
157                 label nei = mesh_.faceNeighbour()[faceI];
159                 if (cellRegion[nei] == -1)
160                 {
161                     cellRegion[nei] = markValue;
162                     changedCells.append(nei);
163                 }
164             }
165         }
168         //if (debug)
169         //{
170         //    Pout<< "regionSplit::fillSeedMask : changedCells:"
171         //        << changedCells.size() << endl;
172         //}
174         // Loop over changedCells and collect faces
175         dynamicLabelList newChangedFaces(changedCells.size());
177         forAll(changedCells, i)
178         {
179             label cellI = changedCells[i];
181             const cell& cFaces = mesh_.cells()[cellI];
183             forAll(cFaces, cFaceI)
184             {
185                 label faceI = cFaces[cFaceI];
187                 if (faceRegion[faceI] == -1)
188                 {
189                     faceRegion[faceI] = markValue;
190                     newChangedFaces.append(faceI);
191                 }
192             }
193         }
196         //if (debug)
197         //{
198         //    Pout<< "regionSplit::fillSeedMask : changedFaces before sync:"
199         //        << changedFaces.size() << endl;
200         //}
203         // Check for changes to any locally coupled face.
204         // Global connections are done later.
206         const polyBoundaryMesh& patches = mesh_.boundaryMesh();
208         forAll(patches, patchI)
209         {
210             const polyPatch& pp = patches[patchI];
212             if (isA<cyclicPolyPatch>(pp))
213             {
214                 label faceI = pp.start();
216                 label halfSz = pp.size()/2;
218                 for (label i = 0; i < halfSz; i++)
219                 {
220                     label otherFaceI = refCast<const cyclicPolyPatch>(pp)
221                         .transformGlobalFace(faceI);
223                     transferCoupledFaceRegion
224                     (
225                         faceI,
226                         otherFaceI,
227                         faceRegion,
228                         newChangedFaces
229                     );
231                     faceI++;
232                 }
233             }
234         }
235         forAll(explicitConnections, i)
236         {
237             transferCoupledFaceRegion
238             (
239                 explicitConnections[i][0],
240                 explicitConnections[i][1],
241                 faceRegion,
242                 newChangedFaces
243             );
244         }
246         //if (debug)
247         //{
248         //    Pout<< "regionSplit::fillSeedMask : changedFaces after sync:"
249         //        << newChangedFaces.size() << endl;
250         //}
252         changedFaces.transfer(newChangedFaces);
253     }
257 Foam::label Foam::regionSplit::calcRegionSplit
259     const boolList& blockedFace,
260     const List<labelPair>& explicitConnections,
262     labelList& cellRegion
263 ) const
265     if (debug)
266     {
267         if (blockedFace.size())
268         {
269             // Check that blockedFace is synced.
270             boolList syncBlockedFace(blockedFace);
271             syncTools::swapFaceList(mesh_, syncBlockedFace, false);
273             forAll(syncBlockedFace, faceI)
274             {
275                 if (syncBlockedFace[faceI] != blockedFace[faceI])
276                 {
277                     FatalErrorIn
278                     (
279                         "regionSplit::calcRegionSplit(..)"
280                     )   << "Face " << faceI << " not synchronised. My value:"
281                         << blockedFace[faceI] << "  coupled value:"
282                         << syncBlockedFace[faceI]
283                         << abort(FatalError);
284                 }
285             }
286         }
287     }
289     // Region per face.
290     // -1 unassigned
291     // -2 blocked
292     labelList faceRegion(mesh_.nFaces(), -1);
294     if (blockedFace.size())
295     {
296         forAll(blockedFace, faceI)
297         {
298             if (blockedFace[faceI])
299             {
300                 faceRegion[faceI] = -2;
301             }
302         }
303     }
306     // Assign local regions
307     // ~~~~~~~~~~~~~~~~~~~~
309     // Start with region 0
310     label nRegions = 0;
312     label unsetCellI = 0;
314     do
315     {
316         // Find first unset cell
318         for (; unsetCellI < mesh_.nCells(); unsetCellI++)
319         {
320             if (cellRegion[unsetCellI] == -1)
321             {
322                 break;
323             }
324         }
326         if (unsetCellI >= mesh_.nCells())
327         {
328             break;
329         }
331         fillSeedMask
332         (
333             explicitConnections,
334             cellRegion,
335             faceRegion,
336             unsetCellI,
337             nRegions
338         );
340         // Current unsetCell has now been handled. Go to next region.
341         nRegions++;
342         unsetCellI++;
343     }
344     while(true);
347     if (debug)
348     {
349         forAll(cellRegion, cellI)
350         {
351             if (cellRegion[cellI] < 0)
352             {
353                 FatalErrorIn("regionSplit::calcRegionSplit(..)")
354                     << "cell:" << cellI << " region:" << cellRegion[cellI]
355                     << abort(FatalError);
356             }
357         }
359         forAll(faceRegion, faceI)
360         {
361             if (faceRegion[faceI] == -1)
362             {
363                 FatalErrorIn("regionSplit::calcRegionSplit(..)")
364                     << "face:" << faceI << " region:" << faceRegion[faceI]
365                     << abort(FatalError);
366             }
367         }
368     }
372     // Assign global regions
373     // ~~~~~~~~~~~~~~~~~~~~~
374     // Offset local regions to create unique global regions.
376     globalIndex globalRegions(nRegions);
379     // Merge global regions
380     // ~~~~~~~~~~~~~~~~~~~~
381     // Regions across non-blocked proc patches get merged.
382     // This will set merged global regions to be the min of both.
383     // (this will create gaps in the global region list so they will get
384     // merged later on)
386     // Map from global to merged global
387     labelList mergedGlobal(identity(globalRegions.size()));
390     // See if any regions get merged. Only nessecary for parallel
391     while (Pstream::parRun())
392     {
393         if (debug)
394         {
395             Pout<< nl << "-- Starting Iteration --" << endl;
396         }
398         const polyBoundaryMesh& patches = mesh_.boundaryMesh();
400         // Send global regions across (or -2 if blocked face)
401         forAll(patches, patchI)
402         {
403             const polyPatch& pp = patches[patchI];
405             if (isA<processorPolyPatch>(pp))
406             {
407                 labelList myGlobalRegions(pp.size());
409                 label faceI = pp.start();
411                 forAll(pp, i)
412                 {
413                     if (faceRegion[faceI] < 0)
414                     {
415                         myGlobalRegions[i] = faceRegion[faceI];
416                     }
417                     else
418                     {
419                         myGlobalRegions[i] = mergedGlobal
420                         [globalRegions.toGlobal(faceRegion[faceI])];
421                     }
423                     faceI++;
424                 }
426                 OPstream toProcNbr
427                 (
428                     Pstream::blocking,
429                     refCast<const processorPolyPatch>(pp).neighbProcNo()
430                 );
432                 toProcNbr << myGlobalRegions;
433             }
434         }
437         // Receive global regions
439         label nMerged = 0;
441         forAll(patches, patchI)
442         {
443             const polyPatch& pp = patches[patchI];
445             if (isA<processorPolyPatch>(pp))
446             {
447                 const processorPolyPatch& procPp =
448                     refCast<const processorPolyPatch>(pp);
450                 IPstream fromProcNbr(Pstream::blocking, procPp.neighbProcNo());
452                 labelList nbrRegions(fromProcNbr);
455                 // Compare with my regions to see which get merged.
457                 label faceI = pp.start();
459                 forAll(pp, i)
460                 {
461                     if
462                     (
463                         faceRegion[faceI] < 0
464                      || nbrRegions[i] < 0
465                     )
466                     {
467                         if (faceRegion[faceI] != nbrRegions[i])
468                         {
469                             FatalErrorIn("regionSplit::calcRegionSplit(..)")
470                                 << "On patch:" << pp.name()
471                                 << " face:" << faceI
472                                 << " my local region:" << faceRegion[faceI]
473                                 << " neighbouring region:"
474                                 << nbrRegions[i] << nl
475                                 << "Maybe your blockedFaces are not"
476                                 << " synchronized across coupled faces?"
477                                 << abort(FatalError);
478                         }
479                     }
480                     else
481                     {
482                         label uncompactGlobal =
483                             globalRegions.toGlobal(faceRegion[faceI]);
485                         label myGlobal = mergedGlobal[uncompactGlobal];
487                         if (myGlobal != nbrRegions[i])
488                         {
489                             label minRegion = min(myGlobal, nbrRegions[i]);
491                             if (debug)
492                             {
493                                 Pout<< "Merging region " << myGlobal
494                                     << " (on proc " << Pstream::myProcNo()
495                                     << ") and region " << nbrRegions[i]
496                                     << " (on proc " << procPp.neighbProcNo()
497                                     << ") into region " << minRegion << endl;
498                             }
500                             mergedGlobal[uncompactGlobal] = minRegion;
501                             mergedGlobal[myGlobal] = minRegion;
502                             mergedGlobal[nbrRegions[i]] = minRegion;
504                             nMerged++;
505                         }
506                     }
508                     faceI++;
509                 }
510             }
511         }
514         reduce(nMerged, sumOp<label>());
516         if (debug)
517         {
518             Pout<< "nMerged:" << nMerged << endl;
519         }
521         if (nMerged == 0)
522         {
523             break;
524         }
526         // Merge the compacted regions.
527         Pstream::listCombineGather(mergedGlobal, minEqOp<label>());
528         Pstream::listCombineScatter(mergedGlobal);
529     }
532     // Compact global regions
533     // ~~~~~~~~~~~~~~~~~~~~~~
535     // All procs will have the same global mergedGlobal region.
536     // There might be gaps in it however so compact.
538     labelList mergedToCompacted(globalRegions.size(), -1);
540     label compactI = 0;
542     forAll(mergedGlobal, i)
543     {
544         label merged = mergedGlobal[i];
546         if (mergedToCompacted[merged] == -1)
547         {
548             mergedToCompacted[merged] = compactI++;
549         }
550     }
552     if (debug)
553     {
554         Pout<< "Compacted down to " << compactI << " regions." << endl;
555     }
557     // Renumber cellRegion to be global regions
558     forAll(cellRegion, cellI)
559     {
560         label region = cellRegion[cellI];
562         if (region >= 0)
563         {
564             label merged = mergedGlobal[globalRegions.toGlobal(region)];
566             cellRegion[cellI] = mergedToCompacted[merged];
567         }
568     }
570     return compactI;
574 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
576 Foam::regionSplit::regionSplit(const polyMesh& mesh)
578     labelList(mesh.nCells(), -1),
579     mesh_(mesh),
580     nRegions_(calcRegionSplit(boolList(0, false), List<labelPair>(0), *this))
584 Foam::regionSplit::regionSplit
586     const polyMesh& mesh,
587     const boolList& blockedFace
590     labelList(mesh.nCells(), -1),
591     mesh_(mesh),
592     nRegions_(calcRegionSplit(blockedFace, List<labelPair>(0), *this))
596 Foam::regionSplit::regionSplit
598     const polyMesh& mesh,
599     const boolList& blockedFace,
600     const List<labelPair>& explicitConnections
603     labelList(mesh.nCells(), -1),
604     mesh_(mesh),
605     nRegions_(calcRegionSplit(blockedFace, explicitConnections, *this))
609 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
612 // ************************************************************************* //