1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh 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 cfMesh 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
21 You should have received a copy of the GNU General Public License
22 along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "detectBoundaryLayers.H"
29 #include "meshSurfacePartitioner.H"
30 #include "helperFunctions.H"
31 #include "polyMeshGenAddressing.H"
32 #include "polyMeshGen2DEngine.H"
33 #include "VRWGraphList.H"
35 #include "labelledPair.H"
36 #include "labelledScalar.H"
44 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
54 class meshBndLayerNeighbourOperator
56 const meshSurfaceEngine& mse_;
61 meshBndLayerNeighbourOperator(const meshSurfaceEngine& mse)
64 size_(mse.boundaryFaces().size())
72 void operator()(const label bfI, DynList<label>& neighbourFaces) const
74 neighbourFaces.clear();
76 const cellListPMG& cells = mse_.cells();
78 const labelList& faceOwner = mse_.faceOwners();
79 const label cellI = faceOwner[bfI];
80 const cell& c = cells[cellI];
82 const VRWGraph& faceEdges = mse_.faceEdges();
83 const VRWGraph& edgeFaces = mse_.edgeFaces();
85 forAllRow(faceEdges, bfI, feI)
87 const label edgeI = faceEdges(bfI, feI);
89 if( edgeFaces.sizeOfRow(edgeI) == 2 )
91 label nei = edgeFaces(edgeI, 0);
94 nei = edgeFaces(edgeI, 1);
96 //- faces must not be part of the same cell
97 if( faceOwner[nei] == cellI )
100 //- owner cell of the other face must
101 //- have cellI as its neighbour
102 const cell& neiC = cells[faceOwner[nei]];
103 bool sharedFace(false);
108 if( c[fI] == neiC[fJ] )
120 neighbourFaces.append(nei);
125 template<class labelListType>
128 std::map<label, DynList<label> >& neiGroups,
129 const labelListType& elementInGroup,
130 const DynList<label>& localGroupLabel
133 const polyMeshGen& mesh = mse_.mesh();
134 const faceListPMG& faces = mesh.faces();
135 const cellListPMG& cells = mesh.cells();
137 const edgeList& edges = mse_.edges();
138 const labelList& faceOwner = mse_.faceOwners();
139 const VRWGraph& edgeFaces = mse_.edgeFaces();
140 const Map<label>& otherProc = mse_.otherEdgeFaceAtProc();
141 const Map<label>& globalToLocal =
142 mse_.globalToLocalBndEdgeAddressing();
144 std::map<label, LongList<labelPair> > exchangeData;
145 forAll(mse_.beNeiProcs(), procI)
146 exchangeData[mse_.beNeiProcs()[procI]].clear();
148 forAllConstIter(Map<label>, globalToLocal, it)
150 const label beI = it();
152 //- combine data if the cell attached to this face has a face
153 //- attached to the inter-processor boundary
154 //- this must hold for boundary layer cells
155 const cell& c = cells[faceOwner[edgeFaces(beI, 0)]];
157 bool validCell(false);
160 const face& f = faces[c[fI]];
164 const edge fe = f.faceEdge(eI);
168 (fe == edges[beI]) &&
169 (mesh.faceIsInProcPatch(c[fI]) >= 0)
184 const label groupI = elementInGroup[edgeFaces(beI, 0)];
189 const label lgI = localGroupLabel[groupI];
190 exchangeData[otherProc[beI]].append(labelPair(it.key(), lgI));
193 LongList<labelPair> receivedData;
194 help::exchangeMap(exchangeData, receivedData);
196 forAll(receivedData, i)
198 const labelPair& lp = receivedData[i];
200 const label beI = globalToLocal[lp.first()];
202 const cell& c = cells[faceOwner[edgeFaces(beI, 0)]];
204 //- combine data if the cell attached to this face has a face
205 //- attached to the inter-processor boundary
206 //- this must hold for boundary layer cells
207 bool validCell(false);
210 const face& f = faces[c[fI]];
214 const edge fe = f.faceEdge(eI);
218 (fe == edges[beI]) &&
219 (mesh.faceIsInProcPatch(c[fI]) >= 0)
234 const label groupI = elementInGroup[edgeFaces(beI, 0)];
239 DynList<label>& ng = neiGroups[localGroupLabel[groupI]];
241 //- store the connection over the inter-processor boundary
242 ng.appendIfNotIn(lp.second());
247 class meshBndLayerSelectorOperator
249 const meshSurfaceEngine& mse_;
253 meshBndLayerSelectorOperator(const meshSurfaceEngine& mse)
258 bool operator()(const label bfI) const
260 const labelList& faceOwner = mse_.faceOwners();
261 const polyMeshGen& mesh = mse_.mesh();
262 const faceListPMG& faces = mesh.faces();
264 const cell& c = mesh.cells()[faceOwner[bfI]];
265 const PtrList<boundaryPatch>& boundaries = mesh.boundaries();
266 const label start = boundaries[0].patchStart();
268 label nBndFaces(0), baseFace(-1), otherBase(-1), nQuads(0);
271 if( faces[c[fI]].size() == 4 )
274 if( (c[fI] - start) == bfI )
287 if( (nQuads + 2) != c.size() )
293 label nQuadsAttachedToBaseFace(0);
300 help::shareAnEdge(faces[c[baseFace]], faces[c[fI]]);
302 if( (faces[c[fI]].size() == 4) && sEdge )
304 ++nQuadsAttachedToBaseFace;
308 if( otherBase != -1 )
318 ((nQuadsAttachedToBaseFace + 2) == c.size()) &&
320 !help::shareAnEdge(faces[c[baseFace]], faces[c[otherBase]])
329 } // End namespace bndLayerOps
331 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
333 void detectBoundaryLayers::analyseLayers()
335 Info << "Analysing mesh for bnd layer existence" << endl;
337 const meshSurfaceEngine& mse = meshSurface_.surfaceEngine();
338 const polyMeshGen& mesh = mse.mesh();
339 const PtrList<boundaryPatch>& boundaries = mesh.boundaries();
341 //- allocate data needed in parallel loops
346 mse.boundaryPointEdges();
348 //- find layers in patch
353 bndLayerOps::meshBndLayerNeighbourOperator(mse),
354 bndLayerOps::meshBndLayerSelectorOperator(mse)
358 labelList layerSubsetId(nFirstLayers_);
359 polyMeshGen& pmg = const_cast<polyMeshGen&>(mesh);
360 forAll(layerSubsetId, i)
361 layerSubsetId[i] = pmg.addCellSubset("bndLayer"+help::scalarToText(i));
364 forAll(layerAtBndFace_, bfI)
366 if( layerAtBndFace_[bfI] < 0 )
371 layerSubsetId[layerAtBndFace_[bfI]],
372 mse.faceOwners()[bfI]
379 polyMeshGen2DEngine mesh2DEngine(mse.mesh());
380 const boolList& zMinPoint = mesh2DEngine.zMinPoints();
381 const boolList& zMaxPoint = mesh2DEngine.zMaxPoints();
383 const faceList::subList& bFaces = mse.boundaryFaces();
386 # pragma omp parallel for schedule(dynamic, 50)
390 const face& bf = bFaces[bfI];
392 bool allZMin(true), allZMax(true);
395 if( !zMinPoint[bf[pI]] )
397 if( !zMaxPoint[bf[pI]] )
401 if( allZMax ^ allZMin )
402 layerAtBndFace_[bfI] = -1;
406 //- check the number of layer found at a patch
407 typedef std::map<label, DynList<label> > patchToLayerType;
408 patchToLayerType patchToLayer;
410 const labelList& facePatch = meshSurface_.boundaryFacePatches();
412 forAll(facePatch, bfI)
414 patchToLayer[facePatch[bfI]].appendIfNotIn(layerAtBndFace_[bfI]);
417 //- all faces of a patch must be in the same layer
418 layerAtPatch_.setSize(boundaries.size());
419 forAll(layerAtPatch_, i)
420 layerAtPatch_[i].clear();
424 patchToLayerType::const_iterator it=patchToLayer.begin();
425 it!=patchToLayer.end();
429 const DynList<label>& layersAtPatch = it->second;
431 forAll(layersAtPatch, i)
433 if( layersAtPatch[i] < 0 )
435 layerAtPatch_[it->first].clear();
440 layerAtPatch_[it->first].append(layersAtPatch[i]);
445 //- set the layer ID to -1 for all faces where the patch is set to -1
446 forAll(facePatch, bfI)
448 if( layerAtPatch_[facePatch[bfI]].size() == 0 )
449 layerAtBndFace_[bfI] = -1;
453 Info << "Layer at patch " << layerAtPatch_ << endl;
454 forAll(layerAtBndFace_, bfI)
455 if( layerAtBndFace_[bfI] < 0 )
456 Info << "0.2 No layer at boundary face " << bfI << endl;
460 bool detectBoundaryLayers::findHairsForFace
463 DynList<edge>& hairEdges
466 const meshSurfaceEngine& mse = meshSurface_.surfaceEngine();
467 const polyMeshGen& mesh = mse.mesh();
469 const label nInternalFaces = mesh.boundaries()[0].patchStart();
471 const labelList& faceOwner = mse.faceOwners();
473 const faceListPMG& faces = mesh.faces();
474 const cell& c = mesh.cells()[faceOwner[bfI]];
476 //- check cell topology
477 DynList<edge, 48> edges;
478 DynList<DynList<label, 2>, 48> edgeFaces;
479 DynList<DynList<label, 10>, 24> faceEdges;
480 faceEdges.setSize(c.size());
484 if( c[fI] - nInternalFaces == bfI )
489 const face& f = faces[c[fI]];
490 faceEdges[fI].setSize(f.size());
494 const edge e = f.faceEdge(eI);
496 label pos = edges.containsAtPosition(e);
502 edgeFaces.setSize(pos+1);
505 edgeFaces[pos].append(fI);
506 faceEdges[fI][eI] = pos;
510 //- check does the base face exist and is the number of faces
511 //- in the cell corresponding to a prism cell
512 if( (baseFace < 0) || ((c.size() - faces[c[baseFace]].size()) != 2) )
515 //- check if all faces attached to the base face are quads
518 const face& bf = faces[c[baseFace]];
519 hairEdges.setSize(bf.size());
523 const label nextEdge = faceEdges[baseFace][pI];
524 const label prevEdge = faceEdges[baseFace][bf.rcIndex(pI)];
526 if( edgeFaces[nextEdge].size() != 2 || edgeFaces[prevEdge].size() != 2 )
532 //- find the face attached to the edge after the current point
533 label otherNextFace = edgeFaces[nextEdge][0];
534 if( otherNextFace == baseFace )
535 otherNextFace = edgeFaces[nextEdge][1];
537 //- find the face attached to the edge before the current point
538 label otherPrevFace = edgeFaces[prevEdge][0];
539 if( otherPrevFace == baseFace )
540 otherPrevFace = edgeFaces[prevEdge][1];
543 for(commonEdge=0;commonEdge<edges.size();++commonEdge)
545 edgeFaces[commonEdge].contains(otherNextFace) &&
546 edgeFaces[commonEdge].contains(otherPrevFace)
550 if( commonEdge == edges.size() )
556 //- there exists a common edge which shall be used as a hair
557 if( edges[commonEdge].start() == bf[pI] )
559 hairEdges[pI] = edges[commonEdge];
563 hairEdges[pI] = edges[commonEdge].reverseEdge();
570 void detectBoundaryLayers::generateHairEdges()
573 hairEdgesAtBoundaryPoint_.clear();
575 const meshSurfaceEngine& mse = meshSurface_.surfaceEngine();
576 const faceList::subList& bFaces = mse.boundaryFaces();
578 const VRWGraph& pFaces = mse.pointFaces();
579 const labelList& bp = mse.bp();
582 # pragma omp parallel if( bFaces.size() > 1000 )
585 edgeLongList localEdges;
588 # pragma omp for schedule(dynamic, 100)
592 if( layerAtBndFace_[bfI] < 0 )
595 //- find hair edges for this face
596 DynList<edge> hairEdges;
597 if( !findHairsForFace(bfI, hairEdges) )
600 const face& bf = bFaces[bfI];
604 //- store hair edges in a list
605 const edge& he = hairEdges[pI];
607 if( he.start() != bf[pI] )
610 "void detectBoundaryLayers::generateHairEdges()"
611 ) << "Wrong starting point" << abort(FatalError);
613 localEdges.append(he);
618 //- find the starting element for this thread
620 # pragma omp critical
622 startEl = hairEdges_.size();
624 hairEdges_.setSize(startEl+localEdges.size());
629 //- copy the local data to splitEdges_
630 forAll(localEdges, i)
631 hairEdges_[startEl++] = localEdges[i];
633 //- just transfer the data to splitEdges_
634 hairEdges_.transfer(localEdges);
638 //- filter out duplicate edges
640 pHairEdges.reverseAddressing(hairEdges_);
642 boolList duplicateEdge(hairEdges_.size(), false);
644 # pragma omp parallel for schedule(dynamic, 50)
646 forAll(pHairEdges, pointI)
648 forAllRow(pHairEdges, pointI, pheI)
650 const label heI = pHairEdges(pointI, pheI);
651 const edge& he = hairEdges_[heI];
653 for(label pheJ=pheI+1;pheJ<pHairEdges.sizeOfRow(pointI);++pheJ)
655 const label heJ = pHairEdges(pointI, pheJ);
656 const edge& nhe = hairEdges_[heJ];
659 duplicateEdge[heJ] = true;
665 forAll(hairEdges_, heI)
667 if( !duplicateEdge[heI] )
671 hairEdges_[counter++] = hairEdges_[heI];
680 hairEdges_.setSize(counter);
682 //- create point to split edges addressing
683 hairEdgesAtBoundaryPoint_.setSize(pFaces.size());
685 forAll(hairEdges_, heI)
687 const edge& he = hairEdges_[heI];
688 hairEdgesAtBoundaryPoint_.append(bp[he.start()], heI);
692 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
694 } // End namespace Foam
696 // ************************************************************************* //