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 \*---------------------------------------------------------------------------*/
29 #include "polyMeshGenModifier.H"
30 #include "edgeExtractor.H"
31 #include "meshSurfaceEngine.H"
32 #include "meshSurfaceEngineModifier.H"
33 #include "meshSurfaceOptimizer.H"
34 #include "meshOctree.H"
36 #include "triSurfModifier.H"
37 #include "helperFunctions.H"
39 #include "labelPair.H"
40 #include "labelledScalar.H"
41 #include "labelledPoint.H"
42 #include "refLabelledPoint.H"
44 #include "triSurfacePartitioner.H"
45 #include "triSurfaceClassifyEdges.H"
46 #include "meshSurfaceMapper.H"
47 #include "meshSurfaceCheckInvertedVertices.H"
48 #include "meshSurfaceCheckEdgeTypes.H"
54 //#define DEBUGEdgeExtractor
59 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
60 // Private member functions
62 void edgeExtractor::calculateValence()
64 const meshSurfaceEngine& mse = this->surfaceEngine();
65 pointValence_.setSize(mse.boundaryPoints().size());
68 const faceList::subList& bFaces = mse.boundaryFaces();
69 const labelList& bp = mse.bp();
73 const face& bf = bFaces[bfI];
76 ++pointValence_[bp[bf[pI]]];
79 if( Pstream::parRun() )
81 const Map<label>& globalToLocal =
82 mse.globalToLocalBndPointAddressing();
83 const VRWGraph& bpAtProcs = mse.bpAtProcs();
84 const DynList<label>& bpNeiProcs = mse.bpNeiProcs();
86 std::map<label, LongList<labelPair> > exchangeData;
90 std::make_pair(bpNeiProcs[i], LongList<labelPair>())
93 forAllConstIter(Map<label>, globalToLocal, iter)
95 const label bpI = iter();
97 forAllRow(bpAtProcs, bpI, i)
99 const label neiProc = bpAtProcs(bpI, i);
101 if( neiProc == Pstream::myProcNo() )
104 exchangeData[neiProc].append
106 labelPair(iter.key(), pointValence_[bpI])
111 LongList<labelPair> receivedData;
112 help::exchangeMap(exchangeData, receivedData);
114 forAll(receivedData, i)
116 const labelPair& lp = receivedData[i];
118 pointValence_[globalToLocal[lp.first()]] += lp.second();
123 void edgeExtractor::calculateSingleCellEdge()
125 const meshSurfaceEngine& mse = this->surfaceEngine();
126 const edgeList& edges = mse.edges();
127 const VRWGraph& bpEdges = mse.boundaryPointEdges();
128 const VRWGraph& edgeFaces = mse.edgeFaces();
129 const labelList& faceCells = mse.faceOwners();
131 //- find the number of boundary faces for each cell in the mesh
132 edgeType_.setSize(edgeFaces.size());
135 forAll(edgeFaces, eI)
137 if( edgeFaces.sizeOfRow(eI) == 2 )
139 const label c0 = faceCells[edgeFaces(eI, 0)];
140 const label c1 = faceCells[edgeFaces(eI, 1)];
143 edgeType_[eI] |= SINGLECELLEDGE;
147 //- calculate the number of cells attache to a boundary edge
148 const labelList& bp = mse.bp();
149 const cellListPMG& cells = mse.mesh().cells();
150 const faceListPMG& faces = mse.faces();
152 nCellsAtEdge_.setSize(edgeFaces.size());
156 # pragma omp parallel for schedule(dynamic, 100)
160 const cell& c = cells[cellI];
162 DynList<edge> foundEdge;
166 const face& f = faces[c[fI]];
170 const edge e = f.faceEdge(eI);
172 const label bps = bp[e.start()];
177 forAllRow(bpEdges, bps, i)
179 const label beI = bpEdges(bps, i);
180 const edge& be = edges[beI];
182 if( (e == be) && !foundEdge.contains(be) )
184 foundEdge.append(be);
189 ++nCellsAtEdge_[beI];
197 void edgeExtractor::findPatchesNearSurfaceFace()
199 const meshSurfaceEngine& mse = this->surfaceEngine();
200 const pointFieldPMG& points = mse.points();
201 const faceList::subList& bFaces = mse.boundaryFaces();
202 const triSurf& surface = meshOctree_.surface();
204 patchesNearFace_.setSize(bFaces.size());
205 labelLongList nPatchesAtFace(bFaces.size());
208 # pragma omp parallel
211 labelLongList localData;
212 DynList<label> nearFacets;
215 # pragma omp for schedule(dynamic, 40)
219 const face& bf = bFaces[bfI];
221 const vector c = bf.centre(points);
223 // find a reasonable searching distance comparable to face size
226 d = Foam::max(d, Foam::mag(c - points[bf[pI]]));
227 d = 2.0 * d + VSMALL;
229 const boundBox bb(c - vector(d, d, d), c + vector(d, d, d));
231 //- get the patches near the current boundary face
232 meshOctree_.findTrianglesInBox(bb, nearFacets);
233 DynList<label> nearPatches;
234 forAll(nearFacets, i)
235 nearPatches.appendIfNotIn(surface[nearFacets[i]].region());
237 localData.append(bfI);
238 nPatchesAtFace[bfI] = nearPatches.size();
239 forAll(nearPatches, i)
240 localData.append(nearPatches[i]);
247 patchesNearFace_.setSizeAndRowSize(nPatchesAtFace);
251 patchesNearFace_.setSizeAndRowSize(nPatchesAtFace);
254 //- copy the data to the graph
256 while( counter < localData.size() )
258 const label edgeI = localData[counter++];
260 const label size = nPatchesAtFace[edgeI];
262 for(label i=0;i<size;++i)
263 patchesNearFace_(edgeI, i) = localData[counter++];
268 void edgeExtractor::findFeatureEdgesNearEdge()
270 const meshSurfaceEngine& mse = this->surfaceEngine();
271 const pointFieldPMG& points = mse.points();
272 const edgeList& edges = mse.edges();
274 featureEdgesNearEdge_.setSize(edges.size());
275 labelLongList nFeatureEdgesAtEdge(edges.size());
278 # pragma omp parallel
281 labelLongList localData;
282 DynList<label> nearEdges;
285 # pragma omp for schedule(dynamic, 40)
289 const edge& e = edges[edgeI];
290 const vector c = e.centre(points);
291 const scalar d = 1.5 * e.mag(points);
293 const boundBox bb(c - vector(d, d, d), c + vector(d, d, d));
295 //- get the edges near the current edge
296 meshOctree_.findEdgesInBox(bb, nearEdges);
297 forAllReverse(nearEdges, i)
299 const label pos = nearEdges.containsAtPosition(nearEdges[i]);
302 nearEdges.removeElement(i);
305 localData.append(edgeI);
306 nFeatureEdgesAtEdge[edgeI] = nearEdges.size();
308 localData.append(nearEdges[i]);
315 featureEdgesNearEdge_.setSizeAndRowSize(nFeatureEdgesAtEdge);
319 featureEdgesNearEdge_.setSizeAndRowSize(nFeatureEdgesAtEdge);
322 //- copy the data to the graph
324 while( counter < localData.size() )
326 const label edgeI = localData[counter++];
328 const label size = nFeatureEdgesAtEdge[edgeI];
330 for(label i=0;i<size;++i)
331 featureEdgesNearEdge_(edgeI, i) = localData[counter++];
336 void edgeExtractor::markPatchPoints(boolList& patchPoint)
338 const meshSurfaceEngine& mse = this->surfaceEngine();
339 const labelList& bPoints = mse.boundaryPoints();
340 const edgeList& edges = mse.edges();
341 const VRWGraph& edgeFaces = mse.edgeFaces();
342 const labelList& bp = mse.bp();
344 patchPoint.setSize(bPoints.size());
347 std::map<label, label> otherProcPatch;
348 if( Pstream::parRun() )
350 const Map<label>& otherProc = mse.otherEdgeFaceAtProc();
351 const Map<label>& globalToLocal =
352 mse.globalToLocalBndEdgeAddressing();
354 //- create communication matrix
355 std::map<label, labelLongList> exchangeData;
356 const DynList<label>& neiProcs = mse.beNeiProcs();
357 forAll(neiProcs, procI)
360 std::make_pair(neiProcs[procI], labelLongList())
363 forAllConstIter(Map<label>, globalToLocal, it)
365 const label beI = it();
367 if( edgeFaces.sizeOfRow(beI) == 1 )
369 labelLongList& dts = exchangeData[otherProc[beI]];
370 //- send data as follows:
371 //- 1. global edge label
372 //- 2. patch of the attached boundary face
373 dts.append(it.key());
374 dts.append(facePatch_[edgeFaces(beI, 0)]);
378 labelLongList receivedData;
379 help::exchangeMap(exchangeData, receivedData);
382 while( counter < receivedData.size() )
384 const label beI = globalToLocal[receivedData[counter++]];
385 const label fPatch = receivedData[counter++];
387 otherProcPatch[beI] = fPatch;
391 //- set the patchPoint to false for all vertices at feature edges
393 # pragma omp parallel for schedule(dynamic, 40)
395 forAll(edgeFaces, beI)
397 if( edgeFaces.sizeOfRow(beI) == 2 )
400 if( facePatch_[edgeFaces(beI, 0)] != facePatch_[edgeFaces(beI, 1)] )
402 const edge& e = edges[beI];
403 patchPoint[bp[e.start()]] = false;
404 patchPoint[bp[e.end()]] = false;
407 else if( edgeFaces.sizeOfRow(beI) == 1 )
409 //- an edge at a parallel interface
410 const label otherPatch = otherProcPatch[beI];
412 if( facePatch_[edgeFaces(beI, 0)] != otherPatch )
414 const edge& e = edges[beI];
415 patchPoint[bp[e.start()]] = false;
416 patchPoint[bp[e.end()]] = false;
421 //- this is a non-manifold edge
422 const edge& e = edges[beI];
423 patchPoint[bp[e.start()]] = false;
424 patchPoint[bp[e.end()]] = false;
428 if( Pstream::parRun() )
430 //- make sure that the information is spread to all processors
431 const VRWGraph& bpAtProcs = mse.bpAtProcs();
432 const DynList<label>& neiProcs = mse.bpNeiProcs();
433 const labelList& globalPointLabel =
434 mse.globalBoundaryPointLabel();
435 const Map<label>& globalToLocal =
436 mse.globalToLocalBndPointAddressing();
439 std::map<label, labelLongList> sendData;
441 sendData.insert(std::make_pair(neiProcs[i], labelLongList()));
443 forAll(bpAtProcs, bpI)
445 forAllRow(bpAtProcs, bpI, i)
447 const label neiProc = bpAtProcs(bpI, i);
449 if( neiProc != Pstream::myProcNo() )
450 sendData[neiProc].append(globalPointLabel[bpI]);
454 labelLongList receivedData;
455 help::exchangeMap(sendData, receivedData);
457 forAll(receivedData, i)
458 patchPoint[globalToLocal[receivedData[i]]] = false;
462 const meshSurfaceEngine& edgeExtractor::surfaceEngine() const
464 if( !surfaceEnginePtr_ )
467 # pragma omp critical
470 if( !surfaceEnginePtr_ )
472 surfaceEnginePtr_ = new meshSurfaceEngine(mesh_);
477 return *surfaceEnginePtr_;
480 const triSurfacePartitioner& edgeExtractor::partitioner() const
482 if( !surfPartitionerPtr_ )
485 # pragma omp critical
488 if( !surfPartitionerPtr_ )
490 surfPartitionerPtr_ =
491 new triSurfacePartitioner(meshOctree_.surface());
496 return *surfPartitionerPtr_;
499 const triSurfaceClassifyEdges& edgeExtractor::edgeClassifier() const
501 if( !surfEdgeClassificationPtr_ )
503 surfEdgeClassificationPtr_ =
504 new triSurfaceClassifyEdges(meshOctree_);
507 return *surfEdgeClassificationPtr_;
510 void edgeExtractor::findFaceCandidates
512 labelLongList& faceCandidates,
513 const labelList* facePatchPtr,
514 const Map<label>* otherFacePatchPtr
517 faceCandidates.clear();
519 facePatchPtr = &facePatch_;
521 const labelList& fPatches = *facePatchPtr;
523 if( !otherFacePatchPtr )
525 Map<label> otherFacePatch;
526 findOtherFacePatchesParallel(otherFacePatch, &fPatches);
528 otherFacePatchPtr = &otherFacePatch;
531 const Map<label>& otherFacePatch = *otherFacePatchPtr;
533 const meshSurfaceEngine& mse = surfaceEngine();
534 const VRWGraph& faceEdges = mse.faceEdges();
535 const VRWGraph& edgeFaces = mse.edgeFaces();
538 # pragma omp parallel if( faceEdges.size() > 1000 )
542 labelLongList procCandidates;
543 # pragma omp for schedule(dynamic, 40)
545 forAll(faceEdges, bfI)
547 DynList<label> allNeiPatches;
548 forAllRow(faceEdges, bfI, eI)
550 const label beI = faceEdges(bfI, eI);
552 if( edgeFaces.sizeOfRow(beI) == 2 )
554 label fNei = edgeFaces(beI, 0);
556 fNei = edgeFaces(faceEdges(bfI, eI), 1);
558 allNeiPatches.appendIfNotIn(fPatches[fNei]);
560 else if( edgeFaces.sizeOfRow(beI) == 1 )
562 allNeiPatches.appendIfNotIn(otherFacePatch[beI]);
566 if( allNeiPatches.size() > 1 )
568 //- this face is probably near some feature edge
570 procCandidates.append(bfI);
572 faceCandidates.append(bfI);
578 # pragma omp critical
580 forAll(procCandidates, i)
581 faceCandidates.append(procCandidates[i]);
587 void edgeExtractor::findOtherFacePatchesParallel
589 Map<label>& otherFacePatch,
590 const labelList* facePatchPtr
593 otherFacePatch.clear();
596 facePatchPtr = &facePatch_;
598 const labelList& fPatches = *facePatchPtr;
600 if( Pstream::parRun() )
602 const meshSurfaceEngine& mse = this->surfaceEngine();
603 const VRWGraph& edgeFaces = mse.edgeFaces();
604 const Map<label>& otherProc = mse.otherEdgeFaceAtProc();
605 const Map<label>& globalToLocal =
606 mse.globalToLocalBndEdgeAddressing();
608 //- create communication matrix
609 std::map<label, labelLongList> exchangeData;
610 const DynList<label>& neiProcs = mse.beNeiProcs();
611 forAll(neiProcs, procI)
614 std::make_pair(neiProcs[procI], labelLongList())
617 forAllConstIter(Map<label>, globalToLocal, it)
619 const label beI = it();
621 if( edgeFaces.sizeOfRow(beI) == 1 )
623 labelLongList& dts = exchangeData[otherProc[beI]];
624 //- send data as follows:
625 //- 1. global edge label
626 //- 2. patch of the attached boundary face
627 dts.append(it.key());
628 dts.append(fPatches[edgeFaces(beI, 0)]);
632 labelLongList receivedData;
633 help::exchangeMap(exchangeData, receivedData);
636 while( counter < receivedData.size() )
638 const label beI = globalToLocal[receivedData[counter++]];
639 const label fPatch = receivedData[counter++];
641 otherFacePatch.insert(beI, fPatch);
646 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
648 edgeExtractor::edgeExtractor
651 const meshOctree& octree
655 surfaceEnginePtr_(NULL),
657 surfPartitionerPtr_(NULL),
658 surfEdgeClassificationPtr_(NULL),
665 featureEdgesNearEdge_()
669 calculateSingleCellEdge();
671 findPatchesNearSurfaceFace();
673 findFeatureEdgesNearEdge();
676 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
679 edgeExtractor::~edgeExtractor()
681 deleteDemandDrivenData(surfaceEnginePtr_);
682 deleteDemandDrivenData(surfPartitionerPtr_);
683 deleteDemandDrivenData(surfEdgeClassificationPtr_);
686 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
688 void edgeExtractor::moveVerticesTowardsDiscontinuities(const label nIterations)
690 Info << "Reducing Hausdorff distance:" << flush;
692 const meshSurfaceEngine& mse = this->surfaceEngine();
693 const labelList& bPoints = mse.boundaryPoints();
694 const VRWGraph& pointFaces = mse.pointFaces();
695 const pointFieldPMG& points = mse.points();
696 const faceList::subList& bFaces = mse.boundaryFaces();
698 meshSurfaceEngineModifier modifier(mse);
700 vectorField faceCentreDisplacement(bFaces.size());
701 List<labelledPoint> pointDisplacements(bPoints.size());
703 for(label iterI=0;iterI<nIterations;++iterI)
706 # pragma omp parallel
709 //- find displacements of face centres
711 # pragma omp for schedule(dynamic, 40)
715 const vector centre = bFaces[bfI].centre(points);
719 label patchI, nearestTri;
720 meshOctree_.findNearestSurfacePoint
729 faceCentreDisplacement[bfI] = newP - centre;
732 //- initialise displacements
734 # pragma omp for schedule(dynamic, 40)
736 forAll(pointDisplacements, bpI)
737 pointDisplacements[bpI] = labelledPoint(0, vector::zero);
743 //- calculate displacements of boundary points as the average
744 //- of face centre displacements
746 # pragma omp for schedule(dynamic, 40)
748 forAll(pointFaces, bpI)
750 forAllRow(pointFaces, bpI, pfI)
752 pointDisplacements[bpI].coordinates() +=
753 faceCentreDisplacement[pointFaces(bpI, pfI)];
754 ++pointDisplacements[bpI].pointLabel();
759 if( Pstream::parRun() )
761 const Map<label>& globalToLocal =
762 mse.globalToLocalBndPointAddressing();
763 const DynList<label>& neiProcs = mse.bpNeiProcs();
764 const VRWGraph& bpAtProcs = mse.bpAtProcs();
766 std::map<label, LongList<refLabelledPoint> > exchangeData;
768 exchangeData[i] = LongList<refLabelledPoint>();
770 forAllConstIter(Map<label>, globalToLocal, iter)
772 const label bpI = iter();
774 forAllRow(bpAtProcs, bpI, i)
776 const label neiProc = bpAtProcs(bpI, i);
778 if( neiProc == Pstream::myProcNo() )
781 exchangeData[neiProc].append
783 refLabelledPoint(iter.key(), pointDisplacements[bpI])
788 LongList<refLabelledPoint> receivedData;
789 help::exchangeMap(exchangeData, receivedData);
791 forAll(receivedData, i)
793 const label globalLabel = receivedData[i].objectLabel();
794 const labelledPoint& lp = receivedData[i].lPoint();
796 const label bpI = globalToLocal[globalLabel];
798 pointDisplacements[bpI].coordinates() += lp.coordinates();
799 pointDisplacements[bpI].pointLabel() += lp.pointLabel();
804 # pragma omp parallel for schedule(dynamic, 40)
806 forAll(pointDisplacements, bpI)
808 const labelledPoint& lp = pointDisplacements[bpI];
810 points[bPoints[bpI]] + lp.coordinates() / lp.pointLabel();
812 //Info << "Original point " << bPoints[bpI] << " has coordinates "
813 // << points[bPoints[bpI]] << endl;
814 //Info << "Displacement vector " << lp.coordinates() / lp.pointLabel() << endl;
815 //Info << "Moved point " << mp << endl;
821 meshOctree_.findNearestSurfacePoint(newPoint, distSq, nt, patchI, mp);
823 //Info << "Mapped point " << newPoint << nl << endl;
825 modifier.moveBoundaryVertexNoUpdate(bpI, newPoint);
829 modifier.updateGeometry();
831 Info << '.' << flush;
837 void edgeExtractor::distributeBoundaryFaces()
839 const meshSurfaceEngine& mse = this->surfaceEngine();
840 const labelList& bPoints = mse.boundaryPoints();
841 const faceList::subList& bFaces = mse.boundaryFaces();
842 const pointFieldPMG& points = mse.points();
844 //- set the size of the facePatch list
845 facePatch_.setSize(bFaces.size());
847 //- check if the mesh already has patches
848 if( mesh_.boundaries().size() > 1 )
849 Warning << "Mesh patches are already assigned!" << endl;
851 //- set size of patchNames, newBoundaryFaces_ and newBoundaryOwners_
852 const triSurf& surface = meshOctree_.surface();
853 const label nPatches = surface.patches().size();
855 //- find patches to which the surface points are mapped to
856 pointPatch_.setSize(bPoints.size());
859 # pragma omp parallel for schedule(dynamic, 40)
863 const point& bp = points[bPoints[bpI]];
869 meshOctree_.findNearestSurfacePoint(p, distSq, nTri, fPatch, bp);
871 if( (fPatch > -1) && (fPatch < nPatches) )
873 pointPatch_[bpI] = fPatch;
879 "void meshSurfaceEdgeExtractorNonTopo::"
880 "distributeBoundaryFaces()"
881 ) << "Cannot distribute a boundary points " << bPoints[bpI]
882 << " into any surface patch!. Exiting.." << exit(FatalError);
886 //- find the patch for face by finding the patch nearest
887 //- to the face centre
889 # pragma omp parallel for schedule(dynamic, 40)
893 const face& bf = bFaces[bfI];
895 const point c = bf.centre(points);
897 //- find the nearest surface patch to face centre
902 meshOctree_.findNearestSurfacePoint(p, distSq, nTri, fPatch, c);
904 if( (fPatch > -1) && (fPatch < nPatches) )
906 facePatch_[bfI] = fPatch;
912 "void meshSurfaceEdgeExtractorNonTopo::"
913 "distributeBoundaryFaces()"
914 ) << "Cannot distribute a face " << bFaces[bfI] << " into any "
915 << "surface patch!. Exiting.." << exit(FatalError);
920 bool edgeExtractor::distributeBoundaryFacesNormalAlignment()
924 const pointFieldPMG& points = mesh_.points();
925 const meshSurfaceEngine& mse = this->surfaceEngine();
926 const faceList::subList& bFaces = mse.boundaryFaces();
927 const VRWGraph& faceEdges = mse.faceEdges();
928 const VRWGraph& edgeFaces = mse.edgeFaces();
930 const triSurf& surf = meshOctree_.surface();
931 const pointField& sPoints = surf.points();
933 label nCorrected, nIterations(0);
934 Map<label> otherProcNewPatch;
940 //- allocate a copy of boundary patches
941 labelList newBoundaryPatches(facePatch_);
943 //- check whether there exist situations where a boundary face
944 //- is surrounded by more faces in different patches than the
945 //- faces in the current patch
946 if( Pstream::parRun() )
948 findOtherFacePatchesParallel
955 //- find the faces which have neighbouring faces in other patches
956 labelLongList candidates;
957 findFaceCandidates(candidates, &facePatch_, &otherProcNewPatch);
959 //- go through the list of faces and check if they shall remain
960 //- in the current patch
962 # pragma omp parallel for schedule(dynamic, 40) \
963 reduction(+ : nCorrected)
965 forAll(candidates, i)
967 const label bfI = candidates[i];
968 const face& bf = bFaces[bfI];
970 DynList<label> allNeiPatches;
971 DynList<label> neiPatches;
972 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
974 forAllRow(faceEdges, bfI, eI)
976 const label beI = faceEdges(bfI, eI);
978 if( edgeFaces.sizeOfRow(beI) == 2 )
980 label fNei = edgeFaces(beI, 0);
982 fNei = edgeFaces(faceEdges(bfI, eI), 1);
984 allNeiPatches.appendIfNotIn(facePatch_[fNei]);
985 neiPatches[eI] = facePatch_[fNei];
987 else if( edgeFaces.sizeOfRow(beI) == 1 )
989 allNeiPatches.appendIfNotIn(otherProcNewPatch[beI]);
990 neiPatches[eI] = otherProcNewPatch[beI];
994 //- do not modify faces with all neighbours in the same patch
997 (allNeiPatches.size() == 1) &&
998 (allNeiPatches[0] == facePatch_[bfI])
1002 //- check whether there exist edges which are more suitable for
1003 //- projection onto feature edges than the currently selected ones
1005 DynList<scalar> normalAlignment(allNeiPatches.size());
1006 DynList<scalar> distanceSq(allNeiPatches.size());
1008 forAll(allNeiPatches, i)
1012 label nearestTriangle;
1014 point p = bf.centre(points);
1015 meshOctree_.findNearestSurfacePointInRegion
1024 maxDSq = Foam::max(dSq, maxDSq);
1026 //- calculate normal vectors
1027 vector tn = surf[nearestTriangle].normal(sPoints);
1028 tn /= (mag(tn) + VSMALL);
1029 vector fn = bf.normal(points);
1030 fn /= (mag(fn) + SMALL);
1032 //- calculate alignment
1033 normalAlignment[i] = mag(tn & fn);
1034 distanceSq[i] = dSq;
1037 scalar maxAlignment(0.0);
1038 forAll(normalAlignment, i)
1042 sqrt(maxDSq / (distanceSq[i] + VSMALL)) * normalAlignment[i]
1045 if( metric > maxAlignment )
1047 maxAlignment = metric;
1048 newPatch = allNeiPatches[i];
1052 if( (newPatch >= 0) && (newPatch != facePatch_[bfI]) )
1054 newBoundaryPatches[bfI] = newPatch;
1059 reduce(nCorrected, sumOp<label>());
1065 //- transfer the new patches back
1066 facePatch_.transfer(newBoundaryPatches);
1068 } while( (nCorrected != 0) && (++nIterations < 5) );
1073 void edgeExtractor::findEdgeCandidates()
1075 const triSurf& surface = meshOctree_.surface();
1076 const vectorField& sp = surface.points();
1077 const VRWGraph& facetEdges = surface.facetEdges();
1078 const VRWGraph& edgeFacets = surface.edgeFacets();
1080 const triSurfacePartitioner& partitioner = this->partitioner();
1082 const meshSurfaceEngine& mse = this->surfaceEngine();
1083 const pointFieldPMG& points = mse.points();
1084 const labelList& bPoints = mse.boundaryPoints();
1085 const labelList& bp = mse.bp();
1086 const VRWGraph& faceEdges = mse.faceEdges();
1088 Map<label> otherFacePatch;
1089 findOtherFacePatchesParallel(otherFacePatch, &facePatch_);
1090 labelLongList faceCandidates;
1091 findFaceCandidates(faceCandidates, &facePatch_, &otherFacePatch);
1094 # pragma omp parallel for schedule(dynamic, 40) \
1095 if( faceCandidates.size() > 100 )
1097 forAll(faceCandidates, fcI)
1099 const label bfI = faceCandidates[fcI];
1101 forAllRow(faceEdges, bfI, i)
1103 const label eI = faceEdges(bfI, i);
1104 edgeType_[eI] |= CANDIDATE;
1108 //- find distances of all vertices supporting CANDIDATE edges
1109 //- from feature edges separating various patches
1110 const VRWGraph& pEdges = mse.boundaryPointEdges();
1111 const edgeList& edges = mse.edges();
1113 List<List<labelledScalar> > featureEdgesNearPoint(bPoints.size());
1115 DynList<label> containedTriangles;
1117 # pragma omp parallel for schedule(dynamic, 40) private(containedTriangles)
1121 // TODO rewrite for execution on distributed machines
1123 forAllRow(pEdges, bpI, peI)
1125 const label eI = pEdges(bpI, peI);
1127 if( edgeType_[eI] & CANDIDATE )
1136 //- check the squared distance from the nearest feature edge
1138 forAllRow(pEdges, bpI, peI)
1140 const label eI = pEdges(bpI, peI);
1141 const edge& e = edges[eI];
1142 const scalar dSq = magSqr(points[e.start()] - points[e.end()]);
1144 rSq = Foam::max(rSq, dSq);
1148 const scalar r = Foam::sqrt(rSq);
1150 //- create a boundaing box used for searching neighbour edges
1151 const point& p = points[bPoints[bpI]];
1152 boundBox bb(p - point(r, r, r), p + point(r, r, r));
1154 //- find the surface triangles in the vicinity of the point
1155 //- check for potential feature edges
1156 containedTriangles.clear();
1157 meshOctree_.findTrianglesInBox(bb, containedTriangles);
1159 DynList<label> featureEdgeCandidates;
1161 forAll(containedTriangles, ctI)
1163 const label tI = containedTriangles[ctI];
1165 forAllRow(facetEdges, tI, feI)
1167 const label seI = facetEdges(tI, feI);
1169 if( edgeFacets.sizeOfRow(seI) == 2 )
1171 const label p0 = surface[edgeFacets(seI, 0)].region();
1172 const label p1 = surface[edgeFacets(seI, 1)].region();
1176 featureEdgeCandidates.appendIfNotIn(seI);
1181 featureEdgeCandidates.appendIfNotIn(seI);
1186 //- check the distance of the vertex from the candidates
1187 List<labelledScalar>& featureEdgeDistances =
1188 featureEdgesNearPoint[bpI];
1189 featureEdgeDistances.setSize(featureEdgeCandidates.size());
1190 forAll(featureEdgeCandidates, i)
1192 const label seI = featureEdgeCandidates[i];
1194 const point s = sp[edges[seI].start()];
1195 const point e = sp[edges[seI].end()];
1196 const point np = help::nearestPointOnTheEdgeExact(s, e, p);
1198 featureEdgeDistances[i] = labelledScalar(seI, magSqr(np - p));
1201 //- find nearest edges
1202 sort(featureEdgeDistances);
1206 //- start post-processing gathered data
1207 const labelList& edgeGroup = partitioner.edgeGroups();
1209 List<List<labelledScalar> > edgeGroupAndWeights(edges.size());
1212 # pragma omp parallel for schedule(dynamic, 40) \
1213 if( edges.size() > 1000 )
1215 forAll(edgeType_, edgeI)
1217 if( edgeType_[edgeI] & CANDIDATE )
1219 const edge& e = edges[edgeI];
1221 const List<labelledScalar>& sc =
1222 featureEdgesNearPoint[bp[e.start()]];
1223 const List<labelledScalar>& ec =
1224 featureEdgesNearPoint[bp[e.end()]];
1226 //- find the feature-edge partition for which the sum of
1227 //- node weights is minimal.
1228 DynList<labelledScalar> weights;
1231 const label sPart = edgeGroup[sc[i].scalarLabel()];
1235 const label ePart = edgeGroup[ec[j].scalarLabel()];
1237 if( (sPart >= 0) && (sPart == ePart) )
1244 sc[i].value() + ec[j].value()
1252 edgeGroupAndWeights[edgeI].setSize(weights.size());
1253 forAll(edgeGroupAndWeights[edgeI], epI)
1254 edgeGroupAndWeights[edgeI][epI] = weights[epI];
1256 //- sort the data according to the weights
1257 stableSort(edgeGroupAndWeights[edgeI]);
1261 Info << "Edge partitions and weights " << edgeGroupAndWeights << endl;
1264 void edgeExtractor::findNeiPatches
1267 const Map<label>& otherProcPatch,
1268 DynList<label>& neiPatches
1271 const meshSurfaceEngine& mse = surfaceEngine();
1273 const VRWGraph& faceEdges = mse.faceEdges();
1274 const VRWGraph& edgeFaces = mse.edgeFaces();
1276 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
1278 forAllRow(faceEdges, bfI, feI)
1280 const label beI = faceEdges(bfI, feI);
1282 if( edgeFaces.sizeOfRow(beI) == 2 )
1284 label nei = edgeFaces(beI, 0);
1286 nei = edgeFaces(beI, 1);
1288 neiPatches[feI] = facePatch_[nei];
1290 else if( edgeFaces.sizeOfRow(beI) == 1 )
1292 neiPatches[feI] = otherProcPatch[beI];
1297 scalar edgeExtractor::calculateAlignmentForEdge
1306 DynList<label> patches(2);
1307 patches[0] = patch0;
1308 patches[1] = patch1;
1310 const pointFieldPMG& points = surfaceEnginePtr_->mesh().points();
1312 const edge& e = surfaceEnginePtr_->edges()[beI];
1313 const point& ps = points[e.start()];
1314 const point& pe = points[e.end()];
1316 vector ev = e.vec(points);
1317 const scalar magE = mag(ev) + VSMALL;
1323 meshOctree_.findNearestPointToPatches(mps, dSqS, ps, patches);
1324 meshOctree_.findNearestPointToPatches(mpe, dSqE, pe, patches);
1326 vector fv = mpe - mps;
1327 fv /= (mag(fv) + VSMALL);
1329 val = 0.5 * (1.0 + (ev & fv));
1331 val = min(val, 1.0);
1332 val = max(val, 0.0);
1337 scalar edgeExtractor::calculateDeformationMetricForEdge
1346 DynList<label> patches(2);
1347 patches[0] = patch0;
1348 patches[1] = patch1;
1350 const pointFieldPMG& points = surfaceEnginePtr_->mesh().points();
1352 const edge& e = surfaceEnginePtr_->edges()[beI];
1353 const point& ps = points[e.start()];
1354 const point& pe = points[e.end()];
1356 vector ev = e.vec(points);
1357 const scalar magE = mag(ev) + VSMALL;
1363 meshOctree_.findNearestPointToPatches(mps, dSqS, ps, patches);
1364 meshOctree_.findNearestPointToPatches(mpe, dSqE, pe, patches);
1366 vector fv = mpe - mps;
1367 fv /= (mag(fv) + VSMALL);
1369 scalar c = min(fv & ev, 1.0);
1371 const scalar angle = acos(c);
1373 val = 0.5 * (sqrt(dSqS) + sqrt(dSqE)) + magE * angle;
1378 scalar edgeExtractor::calculateDeformationMetricForFace
1381 const DynList<label>& neiPatches,
1382 const label facePatch
1387 const VRWGraph& faceEdges = surfaceEnginePtr_->faceEdges();
1389 if( neiPatches.size() != faceEdges.sizeOfRow(bfI) )
1393 "scalar edgeExtractor::calculateDeformationMetricForFace"
1394 "(const label, const DynList<label>&, const label) const"
1395 ) << "Number of neiPatches and faceEdge does not match for face "
1396 << bfI << abort(FatalError);
1399 const label patch0 = facePatch == -1 ? facePatch_[bfI] : facePatch;
1401 forAllRow(faceEdges, bfI, i)
1403 const label beI = faceEdges(bfI, i);
1405 if( neiPatches[i] == patch0 )
1408 Enorm += calculateDeformationMetricForEdge(beI, patch0, neiPatches[i]);
1414 bool edgeExtractor::checkConcaveEdgeCells()
1416 bool changed(false);
1418 const triSurf& surf = meshOctree_.surface();
1419 const VRWGraph& edgeFacets = surf.edgeFacets();
1421 const pointFieldPMG& points = mesh_.points();
1422 const faceListPMG& faces = mesh_.faces();
1423 const cellListPMG& cells = mesh_.cells();
1424 const label bndStartFace = mesh_.boundaries()[0].patchStart();
1426 const meshSurfaceEngine& mse = this->surfaceEngine();
1427 const faceList::subList& bFaces = mse.boundaryFaces();
1428 const labelList& bp = mse.bp();
1429 const labelList& faceCells = mse.faceOwners();
1430 const VRWGraph& edgeFaces = mse.edgeFaces();
1432 //- analyse the surface mesh and find out which edges are concave or convex
1433 const triSurfaceClassifyEdges& edgeClassifier = this->edgeClassifier();
1434 const List<direction>& edgeType = edgeClassifier.edgeTypes();
1436 //- create a copy of facePatch array for local modifications
1437 labelList newBoundaryPatches(facePatch_);
1439 //- start checking the surface of the mesh
1442 boolList patchPoint(mse.boundaryPoints().size(), false);
1448 //- check which surface points are surrounded by boundary faces
1449 //- in the same surface patch
1450 markPatchPoints(patchPoint);
1452 //- check whether exist edges of a single cell which shall be projected
1453 //- onto a concave edge
1455 # pragma omp parallel for schedule(dynamic, 40) reduction(+ : nChanged)
1457 forAll(edgeType_, beI)
1459 if( !(edgeType_[beI] & SINGLECELLEDGE) )
1462 //- check if all faces are assigned to the same patch
1463 const label firstPatch = newBoundaryPatches[edgeFaces(beI, 0)];
1464 const label secondPatch = newBoundaryPatches[edgeFaces(beI, 1)];
1466 if( firstPatch == secondPatch )
1469 const cell& c = cells[faceCells[edgeFaces(beI, 0)]];
1471 //- find edges within the bounding box determined by the cell
1472 point pMin(VGREAT, VGREAT, VGREAT);
1473 point pMax(-VGREAT, -VGREAT, -VGREAT);
1476 const face& f = faces[c[fI]];
1480 pMin = Foam::min(pMin, points[f[pI]]);
1481 pMax = Foam::max(pMax, points[f[pI]]);
1485 const point cc = 0.5 * (pMin + pMax);
1486 const point diff = pMax - pMin;
1487 boundBox bb(cc-diff, cc+diff);
1488 DynList<label> containedEdges;
1489 meshOctree_.findEdgesInBox(bb, containedEdges);
1491 //- check if there exists concave edges boundaing patches
1492 //- assigned to boundary faces of the current cell
1493 forAll(containedEdges, ceI)
1495 const label eI = containedEdges[ceI];
1497 if( edgeFacets.sizeOfRow(eI) != 2 )
1499 if( !(edgeType[eI] & triSurfaceClassifyEdges::FEATUREEDGE) )
1502 if( edgeType[eI] & triSurfaceClassifyEdges::CONCAVEEDGE )
1504 const label patch0 = surf[edgeFacets(eI, 0)].region();
1505 const label patch1 = surf[edgeFacets(eI, 1)].region();
1509 ((firstPatch == patch0) && (secondPatch == patch1)) ||
1510 ((firstPatch == patch1) && (secondPatch == patch0))
1513 DynList<DynList<label>, 2> facesInPatch;
1514 facesInPatch.setSize(2);
1516 DynList<label, 2> nFacesInPatch;
1517 nFacesInPatch.setSize(2);
1520 DynList<bool, 2> hasPatchPoints;
1521 hasPatchPoints.setSize(2);
1522 hasPatchPoints = false;
1526 if( c[fI] < bndStartFace )
1529 const label bfI = c[fI] - bndStartFace;
1530 const face& bf = bFaces[bfI];
1532 if( newBoundaryPatches[bfI] == patch1 )
1534 facesInPatch[1].append(bfI);
1539 if( patchPoint[bp[bf[pI]]] )
1540 hasPatchPoints[1] = true;
1543 else if( newBoundaryPatches[bfI] == patch0 )
1545 facesInPatch[0].append(bfI);
1550 if( patchPoint[bp[bf[pI]]] )
1551 hasPatchPoints[0] = true;
1556 if( nFacesInPatch[1] > nFacesInPatch[0] )
1558 //- there exist more faces in patch 1
1559 //- assign all boundary faces to the same patch
1560 forAll(facesInPatch[0], i)
1561 newBoundaryPatches[facesInPatch[0][i]] = patch1;
1565 else if( nFacesInPatch[0] > nFacesInPatch[1] )
1567 //- there exist more faces in patch 0
1568 //- assign all boundary faces to the same patch
1569 forAll(facesInPatch[1], i)
1570 newBoundaryPatches[facesInPatch[1][i]] = patch0;
1576 if( hasPatchPoints[0] && !hasPatchPoints[1] )
1578 //- transfer all faces to patch 1
1579 forAll(facesInPatch[0], i)
1580 newBoundaryPatches[facesInPatch[0][i]] =
1585 else if( !hasPatchPoints[0] && hasPatchPoints[1] )
1587 //- transfer all faces to patch 0
1588 forAll(facesInPatch[1], i)
1589 newBoundaryPatches[facesInPatch[1][i]] =
1596 //- just transfer all faces to the same patch
1597 forAll(facesInPatch[1], i)
1598 newBoundaryPatches[facesInPatch[1][i]] =
1609 if( Pstream::parRun() )
1610 reduce(nChanged, sumOp<label>());
1615 } while( nChanged != 0 );
1617 //- transfer the information back to facePatch
1618 facePatch_.transfer(newBoundaryPatches);
1623 bool edgeExtractor::checkFacePatchesTopology()
1625 bool changed(false);
1627 const meshSurfaceEngine& mse = this->surfaceEngine();
1628 const faceList::subList& bFaces = mse.boundaryFaces();
1629 const labelList& bp = mse.bp();
1630 const VRWGraph& faceEdges = mse.faceEdges();
1631 const VRWGraph& edgeFaces = mse.edgeFaces();
1634 Map<label> otherProcNewPatch;
1639 # ifdef DEBUGEdgeExtractor
1641 const triSurf* surfPtr = surfaceWithPatches();
1642 surfPtr->writeSurface
1644 "surfaceTopologyIter_"+help::scalarToText(nIter)+".stl"
1652 //- allocate a copy of boundary patches
1653 labelList newBoundaryPatches(facePatch_);
1655 //- check whether there exist situations where a boundary face
1656 //- is surrounded by more faces in different patches than the
1657 //- faces in the current patch
1658 if( Pstream::parRun() )
1660 findOtherFacePatchesParallel
1667 //- find the faces which have neighbouring faces in other patches
1668 labelLongList candidates;
1669 findFaceCandidates(candidates, &facePatch_, &otherProcNewPatch);
1671 //- go through the list of faces and check if they shall remain
1672 //- in the current patch
1674 # pragma omp parallel for schedule(dynamic, 40) \
1675 reduction(+ : nCorrected)
1677 forAll(candidates, i)
1679 const label bfI = candidates[i];
1680 const face& bf = bFaces[bfI];
1682 //- do not change patches of faces where all points are mapped
1683 //- onto the same patch
1684 bool allInSamePatch(true);
1686 if( pointPatch_[bp[bf[pI]]] != facePatch_[bfI] )
1688 allInSamePatch = false;
1692 if( allInSamePatch )
1695 DynList<label> allNeiPatches;
1696 DynList<label> neiPatches;
1697 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
1699 forAllRow(faceEdges, bfI, eI)
1701 const label beI = faceEdges(bfI, eI);
1703 if( edgeFaces.sizeOfRow(beI) == 2 )
1705 label fNei = edgeFaces(beI, 0);
1707 fNei = edgeFaces(faceEdges(bfI, eI), 1);
1709 allNeiPatches.appendIfNotIn(facePatch_[fNei]);
1710 neiPatches[eI] = facePatch_[fNei];
1712 else if( edgeFaces.sizeOfRow(beI) == 1 )
1714 allNeiPatches.appendIfNotIn(otherProcNewPatch[beI]);
1715 neiPatches[eI] = otherProcNewPatch[beI];
1719 //- do not modify faces with all neighbours in the same patch
1722 (allNeiPatches.size() == 1) &&
1723 (allNeiPatches[0] == facePatch_[bfI])
1727 //- check whether there exist edges which are more suitable for
1728 //- projection onto feature edges than the currently selected ones
1731 //- check if some faces have to be distributed to another patch
1732 //- in order to reduce the number of feature edges
1733 Map<label> nNeiInPatch(allNeiPatches.size());
1734 forAll(allNeiPatches, i)
1735 nNeiInPatch.insert(allNeiPatches[i], 0);
1736 forAll(neiPatches, eI)
1737 ++nNeiInPatch[neiPatches[eI]];
1741 forAllConstIter(Map<label>, nNeiInPatch, it)
1743 if( it() > nNeiEdges )
1745 newPatch = it.key();
1750 (it() == nNeiEdges) && (it.key() == facePatch_[bfI])
1753 newPatch = it.key();
1757 //- do not swap in case the
1758 if( (newPatch < 0) || (newPatch == facePatch_[bfI]) )
1761 //- check whether the edges shared ith the neighbour patch form
1762 //- a singly linked chain
1763 DynList<bool> sharedEdge;
1764 sharedEdge.setSize(bFaces[bfI].size());
1767 forAll(neiPatches, eI)
1768 if( neiPatches[eI] == newPatch )
1769 sharedEdge[eI] = true;
1771 if( help::areElementsInChain(sharedEdge) )
1773 //- change the patch to the newPatch
1775 newBoundaryPatches[bfI] = newPatch;
1779 //- eavluate the new situation and ensure that no oscillation occur
1780 reduce(nCorrected, sumOp<label>());
1783 faceEvaluator faceEvaluator(*this);
1785 faceEvaluator.setNewBoundaryPatches(newBoundaryPatches);
1788 # pragma omp parallel for schedule(dynamic, 50)
1790 forAll(candidates, i)
1792 const label bfI = candidates[i];
1794 const label bestPatch =
1795 faceEvaluator.bestPatchAfterModification(bfI);
1797 newBoundaryPatches[bfI] = bestPatch;
1805 //- transfer the new patches back
1806 facePatch_.transfer(newBoundaryPatches);
1809 } while( nCorrected != 0 && (nIter++ < 30) );
1814 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
1816 namespace featureEdgeHelpers
1819 class featureEdgesNeiOp
1822 //- reference to meshSurfaceEngine
1823 const meshSurfaceEngine& mse_;
1825 //- refence to a list holding information which edges are feature edges
1826 const boolList& isFeatureEdge_;
1828 //- number of feature edges at a surface point
1829 labelList nFeatureEdgesAtPoint_;
1831 // Private member functions
1832 //- calculate the number of feature edges connected to a surface vertex
1833 void calculateNumberOfEdgesAtPoint()
1835 const labelList& bp = mse_.bp();
1836 const edgeList& edges = mse_.edges();
1838 nFeatureEdgesAtPoint_.setSize(mse_.boundaryPoints().size());
1839 nFeatureEdgesAtPoint_ = 0;
1841 forAll(isFeatureEdge_, edgeI)
1843 if( !isFeatureEdge_[edgeI] )
1846 const edge& e = edges[edgeI];
1847 ++nFeatureEdgesAtPoint_[bp[e.start()]];
1848 ++nFeatureEdgesAtPoint_[bp[e.end()]];
1851 if( Pstream::parRun() )
1853 const Map<label>& globalToLocal =
1854 mse_.globalToLocalBndPointAddressing();
1855 const DynList<label>& neiProcs = mse_.bpNeiProcs();
1856 const VRWGraph& bpAtProcs = mse_.bpAtProcs();
1858 std::map<label, DynList<labelPair> > exchangeData;
1860 exchangeData[neiProcs[i]].clear();
1862 //- fill the data from sending
1863 forAllConstIter(Map<label>, globalToLocal, it)
1865 const label bpI = it();
1867 forAllRow(bpAtProcs, bpI, i)
1869 const label neiProc = bpAtProcs(bpI, i);
1871 if( neiProc == Pstream::myProcNo() )
1874 exchangeData[neiProc].append
1876 labelPair(it.key(), nFeatureEdgesAtPoint_[bpI])
1881 //- exchange the data between the procesors
1882 LongList<labelPair> receivedData;
1883 help::exchangeMap(exchangeData, receivedData);
1885 forAll(receivedData, i)
1887 const labelPair& lp = receivedData[i];
1889 nFeatureEdgesAtPoint_[globalToLocal[lp.first()]] +=
1899 const meshSurfaceEngine& mse,
1900 const boolList& isFeatureEdge
1904 isFeatureEdge_(isFeatureEdge),
1905 nFeatureEdgesAtPoint_()
1907 calculateNumberOfEdgesAtPoint();
1912 return isFeatureEdge_.size();
1915 void operator()(const label beI, DynList<label>& neighbourEdges) const
1917 neighbourEdges.clear();
1919 const VRWGraph& bpEdges = mse_.boundaryPointEdges();
1920 const labelList& bp = mse_.bp();
1921 const edgeList& edges = mse_.edges();
1923 const edge& e = edges[beI];
1925 const label bps = bp[e.start()];
1926 const label bpe = bp[e.end()];
1928 if( nFeatureEdgesAtPoint_[bps] == 2 )
1930 forAllRow(bpEdges, bps, peI)
1932 const label beJ = bpEdges(bps, peI);
1934 if( (beJ == beI) || !isFeatureEdge_[beJ] )
1937 neighbourEdges.append(beJ);
1941 if( nFeatureEdgesAtPoint_[bpe] == 2 )
1943 forAllRow(bpEdges, bpe, peI)
1945 const label beJ = bpEdges(bpe, peI);
1947 if( (beJ == beI) || !isFeatureEdge_[beJ] )
1950 neighbourEdges.append(beJ);
1955 template<class labelListType>
1958 std::map<label, DynList<label> >& neiGroups,
1959 const labelListType& elementInGroup,
1960 const DynList<label>& localGroupLabel
1963 const Map<label>& globalToLocal = mse_.globalToLocalBndPointAddressing();
1964 const VRWGraph& bpAtProcs = mse_.bpAtProcs();
1965 const VRWGraph& bpEdges = mse_.boundaryPointEdges();
1967 const DynList<label>& neiProcs = mse_.beNeiProcs();
1969 std::map<label, DynList<labelPair> > exchangeData;
1971 exchangeData[neiProcs[i]].clear();
1973 forAllConstIter(Map<label>, globalToLocal, it)
1975 const label bpI = it();
1977 if( nFeatureEdgesAtPoint_[bpI] != 2 )
1980 forAllRow(bpEdges, bpI, i)
1982 const label beI = bpEdges(bpI, i);
1984 if( !isFeatureEdge_[beI] )
1987 const label groupI = elementInGroup[beI];
1989 forAllRow(bpAtProcs, bpI, ppI)
1991 const label neiProc = bpAtProcs(bpI, ppI);
1993 if( neiProc == Pstream::myProcNo() )
1996 exchangeData[neiProc].append
1998 labelPair(it.key(), localGroupLabel[groupI])
2004 LongList<labelPair> receivedData;
2005 help::exchangeMap(exchangeData, receivedData);
2007 forAll(receivedData, i)
2009 const labelPair& lp = receivedData[i];
2010 const label groupI = elementInGroup[globalToLocal[lp.first()]];
2012 DynList<label>& ng = neiGroups[localGroupLabel[groupI]];
2014 //- store the connection over the inter-processor boundary
2015 ng.appendIfNotIn(lp.second());
2020 class featureEdgesSelOp
2023 //- reference to a list holding information which edge is afeture edge
2024 const boolList& isFeatureEdge_;
2028 featureEdgesSelOp(const boolList& isFeatureEdge)
2030 isFeatureEdge_(isFeatureEdge)
2033 bool operator()(const label beI) const
2035 return isFeatureEdge_[beI];
2039 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
2041 } // End namespace featureEdgeHelpers
2043 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2045 bool edgeExtractor::checkFacePatchesGeometry()
2047 bool changed(false);
2049 const meshSurfaceEngine& mse = this->surfaceEngine();
2050 const labelList& bPoints = mse.boundaryPoints();
2051 const faceList::subList& bFaces = mse.boundaryFaces();
2052 const labelList& bp = mse.bp();
2054 //- allocate a copy of boundary patches
2055 labelList newBoundaryPatches(facePatch_.size());
2058 Map<label> otherProcNewPatch;
2060 boolList activePoints(bPoints.size(), true);
2061 labelLongList activePointLabel(bPoints.size());
2062 forAll(bPoints, bpI)
2063 activePointLabel[bpI] = bpI;
2069 # ifdef DEBUGEdgeExtractor
2071 const triSurf* surfPtr = surfaceWithPatches();
2072 surfPtr->writeSurface
2074 "surfaceIter_"+help::scalarToText(iter)+".stl"
2080 //- create feature edges and corners information
2081 meshSurfacePartitioner mPart(mse, facePatch_);
2083 //- project vertices onto the surface mesh
2084 meshSurfaceMapper(mPart, meshOctree_).mapVerticesOntoSurfacePatches
2089 //- stop after a certain number of iterations
2093 //- check if there exist any inverted faces
2094 meshSurfaceCheckInvertedVertices surfCheck(mse, activePoints);
2095 const labelHashSet& invertedPoints = surfCheck.invertedVertices();
2097 if( returnReduce(invertedPoints.size(), sumOp<label>()) == 0 )
2102 "void edgeExtractor::extractEdges()"
2103 ) << "Found " << invertedPoints.size()
2104 << " points with inverted surface normals. Getting rid of them..."
2107 //- untangle the surface
2108 activePointLabel.clear();
2109 forAllConstIter(labelHashSet, invertedPoints, it)
2110 activePointLabel.append(bp[it.key()]);
2112 //- update active points
2113 activePoints = false;
2114 forAll(activePointLabel, i)
2115 activePoints[activePointLabel[i]] = true;
2117 //- untangle the surface
2118 meshSurfaceOptimizer mso(*surfaceEnginePtr_, meshOctree_);
2119 mso.untangleSurface(activePointLabel, 1);
2122 newBoundaryPatches = facePatch_;
2124 //- check whether there exist situations where a boundary face
2125 //- is surrounded by more faces in different patches than the
2126 //- faces in the current patch
2127 if( Pstream::parRun() )
2129 findOtherFacePatchesParallel
2136 //- find the faces which have neighbouring faces in other patches
2137 labelLongList candidates;
2140 const face& bf = bFaces[bfI];
2143 if( invertedPoints.found(bf[pI]) )
2145 candidates.append(bfI);
2151 # pragma omp parallel for schedule(dynamic, 5) reduction(+ : nCorrected)
2153 forAll(candidates, i)
2155 const label bfI = candidates[i];
2157 DynList<label> neiPatches;
2158 findNeiPatches(bfI, otherProcNewPatch, neiPatches);
2160 DynList<label> allNeiPatches;
2161 forAll(neiPatches, i)
2162 allNeiPatches.appendIfNotIn(neiPatches[i]);
2164 //- check the deformation energy and find the minimum energy which
2165 //- can be achieved by switching face patch
2166 scalar minE(VGREAT);
2167 label minEPatch(-1);
2168 DynList<scalar> Enorm(allNeiPatches.size());
2169 forAll(allNeiPatches, i)
2172 calculateDeformationMetricForFace
2179 if( Enorm[i] < minE )
2182 minEPatch = allNeiPatches[i];
2186 if( minEPatch != facePatch_[bfI] )
2188 newBoundaryPatches[bfI] = minEPatch;
2193 //- check if any faces are re-assigned to some other patch
2194 reduce(nCorrected, sumOp<label>());
2195 if( nCorrected == 0 )
2198 //- update faceEvaluator with information after patches have been
2199 //- altered. It blocks chaning of patches if it causes oscillations
2200 faceEvaluator facePatchEvaluator(*this);
2201 facePatchEvaluator.setNewBoundaryPatches(newBoundaryPatches);
2203 //- compare face patches before and after
2204 //- disallow modification which may trigger oscillating behaviour
2205 labelHashSet changedFaces;
2206 forAll(newBoundaryPatches, bfI)
2208 if( newBoundaryPatches[bfI] != facePatch_[bfI] )
2210 const label patchI =
2211 facePatchEvaluator.bestPatchAfterModification(bfI);
2212 newBoundaryPatches[bfI] = patchI;
2214 if( patchI != facePatch_[bfI] )
2215 changedFaces.insert(bfI);
2219 nCorrected = changedFaces.size();
2221 reduce(nCorrected, sumOp<label>());
2226 facePatch_ = newBoundaryPatches;
2229 } while( nCorrected != 0 );
2234 void edgeExtractor::projectDeterminedFeatureVertices()
2236 List<DynList<label, 5> > pointPatches;
2237 pointPatches.setSize(pointValence_.size());
2239 const meshSurfaceEngine& mse = surfaceEngine();
2240 const pointFieldPMG& points = mse.mesh().points();
2241 const labelList& bPoints = mse.boundaryPoints();
2242 const labelList& bp = mse.bp();
2243 const faceList::subList& bFaces = mse.boundaryFaces();
2244 meshOctree_.surface().pointEdges();
2246 //- calculate patches for each point
2249 const face& bf = bFaces[bfI];
2252 pointPatches[bp[bf[pI]]].appendIfNotIn(facePatch_[bfI]);
2255 if( Pstream::parRun() )
2257 const Map<label>& globalToLocal =
2258 mse.globalToLocalBndPointAddressing();
2259 const VRWGraph& bpAtProcs = mse.bpAtProcs();
2260 const DynList<label>& bpNeiProcs = mse.bpNeiProcs();
2262 std::map<label, LongList<labelPair> > exchangeData;
2263 forAll(bpNeiProcs, i)
2266 std::make_pair(bpNeiProcs[i], LongList<labelPair>())
2269 //- collect the data distributed to others
2270 forAllConstIter(Map<label>, globalToLocal, it)
2272 const label bpI = it();
2274 const DynList<label, 5>& pPatches = pointPatches[bpI];
2276 forAllRow(bpAtProcs, bpI, i)
2278 const label neiProc = bpAtProcs(bpI, i);
2280 if( neiProc == Pstream::myProcNo() )
2283 LongList<labelPair>& data = exchangeData[neiProc];
2285 forAll(pPatches, ppI)
2286 data.append(labelPair(it.key(), pPatches[ppI]));
2290 //- exchange information
2291 LongList<labelPair> receivedData;
2292 help::exchangeMap(exchangeData, receivedData);
2295 forAll(receivedData, i)
2297 const labelPair& lp = receivedData[i];
2299 pointPatches[globalToLocal[lp.first()]].appendIfNotIn(lp.second());
2303 meshSurfaceEngineModifier surfMod(mse);
2306 # pragma omp parallel for schedule(dynamic, 10)
2308 forAll(pointPatches, bpI)
2310 if( pointPatches[bpI].size() < 2 )
2313 const DynList<label> pPatches = pointPatches[bpI];
2315 const point& p = points[bPoints[bpI]];
2317 //- find the nearest object on the surface mesh
2320 if( pPatches.size() == 2 )
2323 meshOctree_.findNearestEdgePoint(newP, dSqExact, nse, p, pPatches);
2328 meshOctree_.findNearestCorner(newP, dSqExact, nsp, p, pPatches);
2331 //- find the nearest object in an iterative procedure
2333 for(label iterI=0;iterI<20;++iterI)
2335 point inp(vector::zero);
2343 meshOctree_.findNearestSurfacePointInRegion
2355 inp /= pPatches.size();
2356 const scalar currDSq = magSqr(inp - pp);
2359 if( currDSq < 1e-2 * dSqExact )
2363 //- check if the exact position of the corner is further away
2364 //- than the iteratively found object
2365 if( dSqExact > 1.1 * magSqr(pp - p) )
2368 surfMod.moveBoundaryVertexNoUpdate(bpI, newP);
2371 surfMod.syncVerticesAtParallelBoundaries();
2372 surfMod.updateGeometry();
2375 bool edgeExtractor::untangleSurface()
2377 bool changed(false);
2379 meshSurfaceEngine& mse =
2380 const_cast<meshSurfaceEngine&>(this->surfaceEngine());
2381 meshSurfaceOptimizer optimizer(mse, meshOctree_);
2382 changed = optimizer.untangleSurface();
2387 void edgeExtractor::extractEdges()
2389 distributeBoundaryFaces();
2391 distributeBoundaryFacesNormalAlignment();
2393 # ifdef DEBUGEdgeExtractor
2394 const triSurf* sPtr = surfaceWithPatches();
2395 sPtr->writeSurface("initialDistributionOfPatches.stl");
2396 deleteDemandDrivenData(sPtr);
2399 Info << "Starting topological adjustment of patches" << endl;
2400 if( checkFacePatchesTopology() )
2402 Info << "Finished topological adjustment of patches" << endl;
2404 # ifdef DEBUGEdgeExtractor
2405 Info << "Changes due to face patches" << endl;
2406 fileName sName("checkFacePatches"+help::scalarToText(nIter)+".stl");
2407 sPtr = surfaceWithPatches();
2408 sPtr->writeSurface(sName);
2409 deleteDemandDrivenData(sPtr);
2414 Info << "No topological adjustment was needed" << endl;
2417 Info << "Starting geometrical adjustment of patches" << endl;
2418 if( checkFacePatchesGeometry() )
2420 Info << "Finished geometrical adjustment of patches" << endl;
2424 Info << "No geometrical adjustment was needed" << endl;
2427 // updateMeshPatches();
2429 // returnReduce(1, sumOp<label>());
2432 # ifdef DEBUGEdgeExtractor
2433 const triSurf* sPtr = surfaceWithPatches();
2434 sPtr->writeSurface("finalDistributionOfPatches.stl");
2435 deleteDemandDrivenData(sPtr);
2439 const triSurf* edgeExtractor::surfaceWithPatches() const
2441 //- allocate the memory for the surface mesh
2442 triSurf* surfPtr = new triSurf();
2444 //- surface of the volume mesh
2445 const meshSurfaceEngine& mse = surfaceEngine();
2446 const faceList::subList& bFaces = mse.boundaryFaces();
2447 const labelList& bp = mse.bp();
2448 const pointFieldPMG& points = mesh_.points();
2450 //- modifier of the new surface mesh
2451 triSurfModifier surfModifier(*surfPtr);
2452 surfModifier.patchesAccess() = meshOctree_.surface().patches();
2453 pointField& sPts = surfModifier.pointsAccess();
2454 sPts.setSize(mse.boundaryPoints().size());
2459 if( bp[pointI] < 0 )
2462 sPts[bp[pointI]] = points[pointI];
2465 //- create the triangulation of the volume mesh surface
2468 const face& bf = bFaces[bfI];
2471 tri.region() = facePatch_[bfI];
2474 for(label i=bf.size()-2;i>0;--i)
2477 tri[2] = bp[bf[i+1]];
2479 surfPtr->appendTriangle(tri);
2486 const triSurf* edgeExtractor::surfaceWithPatches(const label bpI) const
2488 //- allocate the memory for the surface mesh
2489 triSurf* surfPtr = new triSurf();
2491 //- surface of the volume mesh
2492 const meshSurfaceEngine& mse = surfaceEngine();
2493 const faceList::subList& bFaces = mse.boundaryFaces();
2494 const VRWGraph& pFaces = mse.pointFaces();
2495 const pointFieldPMG& points = mesh_.points();
2497 //- modifier of the new surface mesh
2498 triSurfModifier surfModifier(*surfPtr);
2499 surfModifier.patchesAccess() = meshOctree_.surface().patches();
2500 pointField& sPts = surfModifier.pointsAccess();
2502 //- create the triangulation of the volume mesh surface
2503 labelLongList newPointLabel(points.size(), -1);
2505 forAllRow(pFaces, bpI, pfI)
2507 const label bfI = pFaces(bpI, pfI);
2508 const face& bf = bFaces[bfI];
2511 if( newPointLabel[bf[pI]] == -1 )
2512 newPointLabel[bf[pI]] = nPoints++;
2515 tri.region() = facePatch_[bfI];
2516 tri[0] = newPointLabel[bf[0]];
2518 for(label i=bf.size()-2;i>0;--i)
2520 tri[1] = newPointLabel[bf[i]];
2521 tri[2] = newPointLabel[bf[i+1]];
2523 surfPtr->appendTriangle(tri);
2528 sPts.setSize(nPoints);
2529 forAll(newPointLabel, pointI)
2530 if( newPointLabel[pointI] != -1 )
2532 sPts[newPointLabel[pointI]] = points[pointI];
2538 void edgeExtractor::updateMeshPatches()
2540 const triSurf& surface = meshOctree_.surface();
2541 const label nPatches = surface.patches().size();
2543 const meshSurfaceEngine& mse = this->surfaceEngine();
2544 const faceList::subList& bFaces = mse.boundaryFaces();
2545 const labelList& faceOwner = mse.faceOwners();
2547 wordList patchNames(nPatches);
2548 VRWGraph newBoundaryFaces;
2549 labelLongList newBoundaryOwners(bFaces.size());
2550 labelLongList newBoundaryPatches(bFaces.size());
2553 forAll(surface.patches(), patchI)
2554 patchNames[patchI] = surface.patches()[patchI].name();
2556 //- append boundary faces
2559 newBoundaryFaces.appendList(bFaces[bfI]);
2560 newBoundaryOwners[bfI] = faceOwner[bfI];
2561 newBoundaryPatches[bfI] = facePatch_[bfI];
2564 //- replace the boundary with the new patches
2565 polyMeshGenModifier(mesh_).replaceBoundary
2574 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
2576 } // End namespace Foam
2578 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //