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 "demandDrivenData.H"
29 #include "correctEdgesBetweenPatches.H"
30 #include "decomposeFaces.H"
31 #include "triSurface.H"
32 #include "meshSurfaceEngine.H"
33 #include "meshSurfaceCheckEdgeTypes.H"
34 #include "meshSurfacePartitioner.H"
35 #include "helperFunctions.H"
36 #include "helperFunctionsPar.H"
44 //#define DEBUGMapping
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
53 void correctEdgesBetweenPatches::decomposeProblematicFaces()
55 Info << "Decomposing problematic faces" << endl;
56 const meshSurfaceEngine& mse = meshSurface();
57 const labelList& bp = mse.bp();
58 const edgeList& edges = mse.edges();
59 const VRWGraph& pointEdges = mse.boundaryPointEdges();
60 const VRWGraph& faceEdges = mse.faceEdges();
61 const VRWGraph& edgeFaces = mse.edgeFaces();
62 const labelList& facePatches = mse.boundaryFacePatches();
64 //- mark feature edges
65 boolList featureBndEdge(edgeFaces.size(), false);
67 forAll(edgeFaces, beI)
69 if( edgeFaces.sizeOfRow(beI) != 2 )
72 if( facePatches[edgeFaces(beI, 0)] != facePatches[edgeFaces(beI, 1)] )
73 featureBndEdge[beI] = true;
76 if( Pstream::parRun() )
78 //- find feature edges at parallel boundaries and propagate the
79 //- information to all processors
80 const Map<label>& globalToLocalEdge =
81 mse.globalToLocalBndEdgeAddressing();
82 const VRWGraph& beAtProcs = mse.beAtProcs();
83 const Map<label>& otherProcPatch = mse.otherEdgeFacePatch();
84 forAllConstIter(Map<label>, globalToLocalEdge, it)
86 const label beI = it();
88 if( edgeFaces.sizeOfRow(beI) != 1 )
90 if( facePatches[edgeFaces(beI, 0)] != otherProcPatch[beI] )
91 featureBndEdge[beI] = true;
94 //- propagate information to all processors that need this information
95 std::map<label, labelLongList> exchangeData;
96 forAll(mse.beNeiProcs(), i)
99 std::make_pair(mse.beNeiProcs()[i], labelLongList())
102 //- append labels of feature edges that need to be sent to other
103 //- processors sharing that edge
104 forAllConstIter(Map<label>, globalToLocalEdge, it)
106 const label beI = it();
108 if( featureBndEdge[beI] )
110 forAllRow(beAtProcs, beI, i)
112 const label procI = beAtProcs(beI, i);
113 if( procI == Pstream::myProcNo() )
116 exchangeData[procI].append(it.key());
121 labelLongList receivedData;
122 help::exchangeMap(exchangeData, receivedData);
125 while( counter < receivedData.size() )
127 featureBndEdge[globalToLocalEdge[receivedData[counter++]]] = true;
131 const polyMeshGen& mesh = mse.mesh();
132 const faceListPMG& faces = mesh.faces();
133 const labelList& owner = mesh.owner();
134 const labelList& neighbour = mesh.neighbour();
136 boolList decomposeFace(faces.size(), false);
137 label nDecomposedFaces(0);
139 //- decompose internal faces with more than one feature edge
140 const label nIntFaces = mesh.nInternalFaces();
142 # pragma omp parallel for schedule(guided) reduction(+ : nDecomposedFaces)
144 for(label faceI=0;faceI<nIntFaces;++faceI)
146 const face& f = faces[faceI];
148 label nFeatureEdges(0);
152 const edge e = f.faceEdge(eI);
154 const label bs = bp[e[0]];
155 const label be = bp[e[1]];
156 if( (bs != -1) && (be != -1) )
158 //- check if this edge is a boundary edges and a feature edge
159 forAllRow(pointEdges, bs, i)
161 const label beI = pointEdges(bs, i);
163 if( (edges[beI] == e) && featureBndEdge[beI] )
169 if( nFeatureEdges > 1 )
172 decomposeFace[faceI] = true;
173 decomposeCell_[owner[faceI]] = true;
174 decomposeCell_[neighbour[faceI]] = true;
178 //- decompose boundary faces in case the feature edges are not connected
179 //- into a single open chain of edges
181 # pragma omp parallel for schedule(guided) reduction(+ : nDecomposedFaces)
183 forAll(faceEdges, bfI)
185 boolList featureEdge(faceEdges.sizeOfRow(bfI), false);
187 forAllRow(faceEdges, bfI, feI)
188 if( featureBndEdge[faceEdges(bfI, feI)] )
189 featureEdge[feI] = true;
191 if( !help::areElementsInChain(featureEdge) )
194 decomposeFace[nIntFaces+bfI] = true;
195 decomposeCell_[owner[nIntFaces+bfI]] = true;
199 if( Pstream::parRun() )
201 //- decompose processor faces having more than one feature edge
202 const PtrList<processorBoundaryPatch>& procBoundaries =
203 mesh.procBoundaries();
205 forAll(procBoundaries, patchI)
207 const label start = procBoundaries[patchI].patchStart();
208 const label end = start + procBoundaries[patchI].patchSize();
211 # pragma omp parallel for schedule(guided) \
212 reduction(+ : nDecomposedFaces)
214 for(label faceI=start;faceI<end;++faceI)
216 const face& f = faces[faceI];
218 label nFeatureEdges(0);
222 const edge e = f.faceEdge(eI);
224 const label bs = bp[e[0]];
225 const label be = bp[e[1]];
226 if( (bs != -1) && (be != -1) )
228 //- check if this edge is a boundary edge
229 //- and a feature edge
230 forAllRow(pointEdges, bs, i)
232 const label beI = pointEdges(bs, i);
234 if( (edges[beI] == e) && featureBndEdge[beI] )
240 if( nFeatureEdges > 1 )
243 decomposeFace[faceI] = true;
244 decomposeCell_[owner[faceI]] = true;
250 reduce(nDecomposedFaces, sumOp<label>());
252 if( nDecomposedFaces != 0 )
254 Info << nDecomposedFaces << " faces decomposed into triangles" << endl;
257 decomposeFaces df(mesh_);
258 df.decomposeMeshFaces(decomposeFace);
261 mesh_.clearAddressingData();
264 Info << "Finished decomposing problematic faces" << endl;
267 void correctEdgesBetweenPatches::decomposeConcaveFaces()
269 const meshSurfaceEngine& mse = meshSurface();
270 const labelList& bPoints = mse.boundaryPoints();
271 const labelList& bp = mse.bp();
272 const edgeList& edges = mse.edges();
273 const VRWGraph& edgeFaces = mse.edgeFaces();
274 const VRWGraph& bpEdges = mse.boundaryPointEdges();
275 const labelList& facePatch = mse.boundaryFacePatches();
277 //- classify edges at the surface
278 meshSurfaceCheckEdgeTypes edgeChecker(mse);
279 const List<direction>& edgeType = edgeChecker.edgeTypes();
281 //- find concave points
282 boolList concavePoint(bPoints.size(), false);
284 labelList edgeInPatch(edges.size(), -1);
286 direction problematicTypes = 0;
287 problematicTypes |= meshSurfaceCheckEdgeTypes::CONCAVEEDGE;
288 problematicTypes |= meshSurfaceCheckEdgeTypes::UNDETERMINED;
291 # pragma omp parallel for schedule(dynamic, 100)
295 if( edgeType[eI] & meshSurfaceCheckEdgeTypes::PATCHEDGE )
297 if( edgeFaces.sizeOfRow(eI) )
298 edgeInPatch[eI] = facePatch[edgeFaces(eI, 0)];
303 if( edgeType[eI] & problematicTypes)
305 const edge& e = edges[eI];
307 concavePoint[bp[e.start()]] = true;
308 concavePoint[bp[e.end()]] = true;
312 if( Pstream::parRun() )
314 const Map<label>& globalToLocal =
315 mse.globalToLocalBndEdgeAddressing();
316 const VRWGraph& beAtProcs = mse.beAtProcs();
318 std::map<label, labelLongList> exchangeData;
319 forAll(mse.beNeiProcs(), i)
320 exchangeData[mse.beNeiProcs()[i]].clear();
322 forAllConstIter(Map<label>, globalToLocal, it)
324 const label beI = it();
326 if( edgeInPatch[beI] < 0 )
329 forAllRow(beAtProcs, beI, i)
331 const label neiProc = beAtProcs(beI, i);
333 if( neiProc == Pstream::myProcNo() )
336 labelLongList& dts = exchangeData[neiProc];
338 dts.append(it.key());
339 dts.append(edgeInPatch[beI]);
343 labelLongList receivedData;
344 help::exchangeMap(exchangeData, receivedData);
346 for(label i=0;i<receivedData.size();)
348 const label beI = globalToLocal[receivedData[i++]];
349 const label patchI = receivedData[i++];
350 if( edgeInPatch[beI] == -1 )
352 edgeInPatch[beI] = patchI;
354 else if( edgeInPatch[beI] != patchI )
358 "void correctEdgesBetweenPatches::decomposeConcaveFaces()"
359 ) << "Invalid patch!" << abort(FatalError);
364 //- decompose internal faces attached to concave vertices which have two
365 //- or more edges at the boundary
366 const faceListPMG& faces = mesh_.faces();
367 const labelList& owner = mesh_.owner();
368 const labelList& neighbour = mesh_.neighbour();
370 boolList decomposeFace(faces.size(), false);
371 label nDecomposed(0);
374 # pragma omp parallel for schedule(dynamic, 100) \
375 reduction(+ : nDecomposed)
377 for(label faceI=0;faceI<mesh_.nInternalFaces();++faceI)
379 const face& f = faces[faceI];
381 bool hasConcave(false);
383 DynList<label> bndEdgePatches;
387 const label bpI = bp[f[pI]];
392 if( concavePoint[bpI] )
395 //- points is at a concave edge
396 //- count the number of boundary edge
397 const edge e = f.faceEdge(pI);
399 forAllRow(bpEdges, bpI, bpeI)
401 const label beI = bpEdges(bpI, bpeI);
402 const edge& ee = edges[beI];
407 bndEdgePatches.appendIfNotIn(edgeInPatch[beI]);
413 if( hasConcave && (nBndEdges > 1) && (bndEdgePatches.size() > 1) )
415 //- the face has two or more edges at the boundary
416 //- Hence, it is marked for decomposition
417 decomposeFace[faceI] = true;
419 decomposeCell_[owner[faceI]] = true;
420 decomposeCell_[neighbour[faceI]] = true;
426 //- finally, perform decomposition of marked faces
427 if( returnReduce(nDecomposed, sumOp<label>()) != 0 )
429 Info << "Decomposing " << nDecomposed << " internal faces" << endl;
430 decomposeFaces(mesh_).decomposeMeshFaces(decomposeFace);
435 mesh_.clearAddressingData();
439 void correctEdgesBetweenPatches::patchCorrection()
441 Info << "Performing patch correction" << endl;
443 const meshSurfaceEngine& mse = meshSurface();
445 meshSurfacePartitioner surfacePartitioner(mse);
447 const labelList& bPoints = mse.boundaryPoints();
448 const VRWGraph& faceEdges = mse.faceEdges();
449 const VRWGraph& edgeFaces = mse.edgeFaces();
450 const faceList::subList& bFaces = mse.boundaryFaces();
451 const labelList& bp = mse.bp();
452 const labelList& boundaryFaceOwners = mse.faceOwners();
453 const labelList& facePatches = mse.boundaryFacePatches();
455 //- set flag 1 to corner vertices, flag 2 to edge vertices
456 List<direction> nodeType(bPoints.size(), direction(0));
459 const labelHashSet& corners = surfacePartitioner.corners();
460 forAllConstIter(labelHashSet, corners, it)
461 nodeType[it.key()] |= 1;
463 //- set flgs to edge vertices
464 const labelHashSet& edgePoints = surfacePartitioner.edgePoints();
465 forAllConstIter(labelHashSet, edgePoints, it)
466 nodeType[it.key()] |= 2;
468 //- set flags for feature edges
469 boolList featureEdge(edgeFaces.size(), false);
472 # pragma omp parallel for schedule(guided)
474 forAll(edgeFaces, eI)
476 if( edgeFaces.sizeOfRow(eI) != 2 )
479 if( facePatches[edgeFaces(eI, 0)] != facePatches[edgeFaces(eI, 1)] )
480 featureEdge[eI] = true;
483 if( Pstream::parRun() )
485 //- set flags for edges at parallel boundaries
486 const Map<label>& otherProcPatch = mse.otherEdgeFacePatch();
488 forAllConstIter(Map<label>, otherProcPatch, it)
489 if( facePatches[edgeFaces(it.key(), 0)] != it() )
490 featureEdge[it.key()] = true;
493 //- decompose bad faces into triangles
494 newBoundaryFaces_.clear();
495 newBoundaryOwners_.clear();
496 newBoundaryPatches_.clear();
499 label nDecomposedFaces(0);
502 const face& bf = bFaces[bfI];
509 (nodeType[bp[bf[i]]] == direction(2)) &&
510 featureEdge[faceEdges(bfI, i)] &&
511 featureEdge[faceEdges(bfI, bf.rcIndex(i))]
518 decomposeCell_[boundaryFaceOwners[bfI]] = true;
521 //- decompose into triangles
522 const point p = bf.centre(mesh_.points());
523 triF[2] = mesh_.points().size();
524 mesh_.points().append(p);
529 triF[1] = bf.nextLabel(j);
531 newBoundaryFaces_.appendList(triF);
532 newBoundaryOwners_.append(boundaryFaceOwners[bfI]);
533 newBoundaryPatches_.append(facePatches[bfI]);
538 else if( bf.size() == 4 )
542 decomposeCell_[boundaryFaceOwners[bfI]] = true;
545 //- decompose the quad into 2 triangles
548 triF[1] = bf.nextLabel(i);
549 triF[2] = bf[(i+2)%4];
550 newBoundaryFaces_.appendList(triF);
551 newBoundaryOwners_.append(boundaryFaceOwners[bfI]);
552 newBoundaryPatches_.append(facePatches[bfI]);
554 triF[1] = bf[(i+2)%4];
555 triF[2] = bf.prevLabel(i);
556 newBoundaryFaces_.appendList(triF);
557 newBoundaryOwners_.append(boundaryFaceOwners[bfI]);
558 newBoundaryPatches_.append(facePatches[bfI]);
567 //- face has not been altered
568 newBoundaryFaces_.appendList(bf);
569 newBoundaryOwners_.append(boundaryFaceOwners[bfI]);
570 newBoundaryPatches_.append(facePatches[bfI]);
574 reduce(decompose_, maxOp<bool>());
576 if( returnReduce(nDecomposedFaces, sumOp<label>()) != 0 )
580 mesh_.clearAddressingData();
583 Info << "Finished with patch correction" << endl;
586 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
588 } // End namespace Foam
590 // ************************************************************************* //