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 "objectRegistry.H"
31 #include "polyMeshGenModifier.H"
32 #include "edgeExtractor.H"
33 #include "meshSurfaceEngine.H"
34 #include "meshSurfaceEngineModifier.H"
35 #include "meshSurfaceOptimizer.H"
36 #include "meshOctree.H"
38 #include "triSurfModifier.H"
39 #include "helperFunctions.H"
41 #include "labelPair.H"
42 #include "labelledScalar.H"
43 #include "labelledPoint.H"
44 #include "refLabelledPoint.H"
46 #include "triSurfacePartitioner.H"
47 #include "triSurfaceClassifyEdges.H"
48 #include "meshSurfaceMapper.H"
49 #include "meshSurfaceCheckInvertedVertices.H"
50 #include "meshSurfaceCheckEdgeTypes.H"
56 //#define DEBUGEdgeExtractor
61 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
62 // Private member functions
64 void edgeExtractor::calculateValence()
66 const meshSurfaceEngine& mse = this->surfaceEngine();
67 pointValence_.setSize(mse.boundaryPoints().size());
70 const faceList::subList& bFaces = mse.boundaryFaces();
71 const labelList& bp = mse.bp();
75 const face& bf = bFaces[bfI];
78 ++pointValence_[bp[bf[pI]]];
81 if( Pstream::parRun() )
83 const Map<label>& globalToLocal =
84 mse.globalToLocalBndPointAddressing();
85 const VRWGraph& bpAtProcs = mse.bpAtProcs();
86 const DynList<label>& bpNeiProcs = mse.bpNeiProcs();
88 std::map<label, LongList<labelPair> > exchangeData;
92 std::make_pair(bpNeiProcs[i], LongList<labelPair>())
95 forAllConstIter(Map<label>, globalToLocal, iter)
97 const label bpI = iter();
99 forAllRow(bpAtProcs, bpI, i)
101 const label neiProc = bpAtProcs(bpI, i);
103 if( neiProc == Pstream::myProcNo() )
106 exchangeData[neiProc].append
108 labelPair(iter.key(), pointValence_[bpI])
113 LongList<labelPair> receivedData;
114 help::exchangeMap(exchangeData, receivedData);
116 forAll(receivedData, i)
118 const labelPair& lp = receivedData[i];
120 pointValence_[globalToLocal[lp.first()]] += lp.second();
125 void edgeExtractor::calculateSingleCellEdge()
127 const meshSurfaceEngine& mse = this->surfaceEngine();
128 const edgeList& edges = mse.edges();
129 const VRWGraph& bpEdges = mse.boundaryPointEdges();
130 const VRWGraph& edgeFaces = mse.edgeFaces();
131 const labelList& faceCells = mse.faceOwners();
133 //- find the number of boundary faces for each cell in the mesh
134 edgeType_.setSize(edgeFaces.size());
137 forAll(edgeFaces, eI)
139 if( edgeFaces.sizeOfRow(eI) == 2 )
141 const label c0 = faceCells[edgeFaces(eI, 0)];
142 const label c1 = faceCells[edgeFaces(eI, 1)];
145 edgeType_[eI] |= SINGLECELLEDGE;
149 //- calculate the number of cells attache to a boundary edge
150 const labelList& bp = mse.bp();
151 const cellListPMG& cells = mse.mesh().cells();
152 const faceListPMG& faces = mse.faces();
154 nCellsAtEdge_.setSize(edgeFaces.size());
158 # pragma omp parallel for schedule(dynamic, 100)
162 const cell& c = cells[cellI];
164 DynList<edge> foundEdge;
168 const face& f = faces[c[fI]];
172 const edge e = f.faceEdge(eI);
174 const label bps = bp[e.start()];
179 forAllRow(bpEdges, bps, i)
181 const label beI = bpEdges(bps, i);
182 const edge& be = edges[beI];
184 if( (e == be) && !foundEdge.contains(be) )
186 foundEdge.append(be);
191 ++nCellsAtEdge_[beI];
199 void edgeExtractor::findPatchesNearSurfaceFace()
201 const meshSurfaceEngine& mse = this->surfaceEngine();
202 const pointFieldPMG& points = mse.points();
203 const faceList::subList& bFaces = mse.boundaryFaces();
204 const triSurf& surface = meshOctree_.surface();
206 patchesNearFace_.setSize(bFaces.size());
207 labelLongList nPatchesAtFace(bFaces.size());
210 # pragma omp parallel
213 labelLongList localData;
214 DynList<label> nearFacets;
217 # pragma omp for schedule(dynamic, 40)
221 const face& bf = bFaces[bfI];
223 const vector c = bf.centre(points);
225 // find a reasonable searching distance comparable to face size
228 d = Foam::max(d, Foam::mag(c - points[bf[pI]]));
229 d = 2.0 * d + VSMALL;
231 const boundBox bb(c - vector(d, d, d), c + vector(d, d, d));
233 //- get the patches near the current boundary face
234 meshOctree_.findTrianglesInBox(bb, nearFacets);
235 DynList<label> nearPatches;
236 forAll(nearFacets, i)
237 nearPatches.appendIfNotIn(surface[nearFacets[i]].region());
239 localData.append(bfI);
240 nPatchesAtFace[bfI] = nearPatches.size();
241 forAll(nearPatches, i)
242 localData.append(nearPatches[i]);
249 patchesNearFace_.setSizeAndRowSize(nPatchesAtFace);
253 patchesNearFace_.setSizeAndRowSize(nPatchesAtFace);
256 //- copy the data to the graph
258 while( counter < localData.size() )
260 const label edgeI = localData[counter++];
262 const label size = nPatchesAtFace[edgeI];
264 for(label i=0;i<size;++i)
265 patchesNearFace_(edgeI, i) = localData[counter++];
270 void edgeExtractor::findFeatureEdgesNearEdge()
272 const meshSurfaceEngine& mse = this->surfaceEngine();
273 const pointFieldPMG& points = mse.points();
274 const edgeList& edges = mse.edges();
276 featureEdgesNearEdge_.setSize(edges.size());
277 labelLongList nFeatureEdgesAtEdge(edges.size());
280 # pragma omp parallel
283 labelLongList localData;
284 DynList<label> nearEdges;
287 # pragma omp for schedule(dynamic, 40)
291 const edge& e = edges[edgeI];
292 const vector c = e.centre(points);
293 const scalar d = 1.5 * e.mag(points);
295 const boundBox bb(c - vector(d, d, d), c + vector(d, d, d));
297 //- get the edges near the current edge
298 meshOctree_.findEdgesInBox(bb, nearEdges);
299 forAllReverse(nearEdges, i)
301 const label pos = nearEdges.containsAtPosition(nearEdges[i]);
304 nearEdges.removeElement(i);
307 localData.append(edgeI);
308 nFeatureEdgesAtEdge[edgeI] = nearEdges.size();
310 localData.append(nearEdges[i]);
317 featureEdgesNearEdge_.setSizeAndRowSize(nFeatureEdgesAtEdge);
321 featureEdgesNearEdge_.setSizeAndRowSize(nFeatureEdgesAtEdge);
324 //- copy the data to the graph
326 while( counter < localData.size() )
328 const label edgeI = localData[counter++];
330 const label size = nFeatureEdgesAtEdge[edgeI];
332 for(label i=0;i<size;++i)
333 featureEdgesNearEdge_(edgeI, i) = localData[counter++];
338 void edgeExtractor::markPatchPoints(boolList& patchPoint)
340 const meshSurfaceEngine& mse = this->surfaceEngine();
341 const labelList& bPoints = mse.boundaryPoints();
342 const edgeList& edges = mse.edges();
343 const VRWGraph& edgeFaces = mse.edgeFaces();
344 const labelList& bp = mse.bp();
346 patchPoint.setSize(bPoints.size());
349 std::map<label, label> otherProcPatch;
350 if( Pstream::parRun() )
352 const Map<label>& otherProc = mse.otherEdgeFaceAtProc();
353 const Map<label>& globalToLocal =
354 mse.globalToLocalBndEdgeAddressing();
356 //- create communication matrix
357 std::map<label, labelLongList> exchangeData;
358 const DynList<label>& neiProcs = mse.beNeiProcs();
359 forAll(neiProcs, procI)
362 std::make_pair(neiProcs[procI], labelLongList())
365 forAllConstIter(Map<label>, globalToLocal, it)
367 const label beI = it();
369 if( edgeFaces.sizeOfRow(beI) == 1 )
371 labelLongList& dts = exchangeData[otherProc[beI]];
372 //- send data as follows:
373 //- 1. global edge label
374 //- 2. patch of the attached boundary face
375 dts.append(it.key());
376 dts.append(facePatch_[edgeFaces(beI, 0)]);
380 labelLongList receivedData;
381 help::exchangeMap(exchangeData, receivedData);
384 while( counter < receivedData.size() )
386 const label beI = globalToLocal[receivedData[counter++]];
387 const label fPatch = receivedData[counter++];
389 otherProcPatch[beI] = fPatch;
393 //- set the patchPoint to false for all vertices at feature edges
395 # pragma omp parallel for schedule(dynamic, 40)
397 forAll(edgeFaces, beI)
399 if( edgeFaces.sizeOfRow(beI) == 2 )
402 if( facePatch_[edgeFaces(beI, 0)] != facePatch_[edgeFaces(beI, 1)] )
404 const edge& e = edges[beI];
405 patchPoint[bp[e.start()]] = false;
406 patchPoint[bp[e.end()]] = false;
409 else if( edgeFaces.sizeOfRow(beI) == 1 )
411 //- an edge at a parallel interface
412 const label otherPatch = otherProcPatch[beI];
414 if( facePatch_[edgeFaces(beI, 0)] != otherPatch )
416 const edge& e = edges[beI];
417 patchPoint[bp[e.start()]] = false;
418 patchPoint[bp[e.end()]] = false;
423 //- this is a non-manifold edge
424 const edge& e = edges[beI];
425 patchPoint[bp[e.start()]] = false;
426 patchPoint[bp[e.end()]] = false;
430 if( Pstream::parRun() )
432 //- make sure that the information is spread to all processors
433 const VRWGraph& bpAtProcs = mse.bpAtProcs();
434 const DynList<label>& neiProcs = mse.bpNeiProcs();
435 const labelList& globalPointLabel =
436 mse.globalBoundaryPointLabel();
437 const Map<label>& globalToLocal =
438 mse.globalToLocalBndPointAddressing();
441 std::map<label, labelLongList> sendData;
443 sendData.insert(std::make_pair(neiProcs[i], labelLongList()));
445 forAll(bpAtProcs, bpI)
447 forAllRow(bpAtProcs, bpI, i)
449 const label neiProc = bpAtProcs(bpI, i);
451 if( neiProc != Pstream::myProcNo() )
452 sendData[neiProc].append(globalPointLabel[bpI]);
456 labelLongList receivedData;
457 help::exchangeMap(sendData, receivedData);
459 forAll(receivedData, i)
460 patchPoint[globalToLocal[receivedData[i]]] = false;
464 const meshSurfaceEngine& edgeExtractor::surfaceEngine() const
466 if( !surfaceEnginePtr_ )
469 # pragma omp critical
472 if( !surfaceEnginePtr_ )
474 surfaceEnginePtr_ = new meshSurfaceEngine(mesh_);
479 return *surfaceEnginePtr_;
482 const triSurfacePartitioner& edgeExtractor::partitioner() const
484 if( !surfPartitionerPtr_ )
487 # pragma omp critical
490 if( !surfPartitionerPtr_ )
492 surfPartitionerPtr_ =
493 new triSurfacePartitioner(meshOctree_.surface());
498 return *surfPartitionerPtr_;
501 const triSurfaceClassifyEdges& edgeExtractor::edgeClassifier() const
503 if( !surfEdgeClassificationPtr_ )
505 surfEdgeClassificationPtr_ =
506 new triSurfaceClassifyEdges(meshOctree_);
509 return *surfEdgeClassificationPtr_;
512 void edgeExtractor::findFaceCandidates
514 labelLongList& faceCandidates,
515 const labelList* facePatchPtr,
516 const Map<label>* otherFacePatchPtr
519 faceCandidates.clear();
521 facePatchPtr = &facePatch_;
523 const labelList& fPatches = *facePatchPtr;
525 if( !otherFacePatchPtr )
527 Map<label> otherFacePatch;
528 findOtherFacePatchesParallel(otherFacePatch, &fPatches);
530 otherFacePatchPtr = &otherFacePatch;
533 const Map<label>& otherFacePatch = *otherFacePatchPtr;
535 const meshSurfaceEngine& mse = surfaceEngine();
536 const VRWGraph& faceEdges = mse.faceEdges();
537 const VRWGraph& edgeFaces = mse.edgeFaces();
540 # pragma omp parallel if( faceEdges.size() > 1000 )
544 labelLongList procCandidates;
545 # pragma omp for schedule(dynamic, 40)
547 forAll(faceEdges, bfI)
549 DynList<label> allNeiPatches;
550 forAllRow(faceEdges, bfI, eI)
552 const label beI = faceEdges(bfI, eI);
554 if( edgeFaces.sizeOfRow(beI) == 2 )
556 label fNei = edgeFaces(beI, 0);
558 fNei = edgeFaces(faceEdges(bfI, eI), 1);
560 allNeiPatches.appendIfNotIn(fPatches[fNei]);
562 else if( edgeFaces.sizeOfRow(beI) == 1 )
564 allNeiPatches.appendIfNotIn(otherFacePatch[beI]);
568 if( allNeiPatches.size() > 1 )
570 //- this face is probably near some feature edge
572 procCandidates.append(bfI);
574 faceCandidates.append(bfI);
580 # pragma omp critical
582 forAll(procCandidates, i)
583 faceCandidates.append(procCandidates[i]);
589 void edgeExtractor::findOtherFacePatchesParallel
591 Map<label>& otherFacePatch,
592 const labelList* facePatchPtr
595 otherFacePatch.clear();
598 facePatchPtr = &facePatch_;
600 const labelList& fPatches = *facePatchPtr;
602 if( Pstream::parRun() )
604 const meshSurfaceEngine& mse = this->surfaceEngine();
605 const VRWGraph& edgeFaces = mse.edgeFaces();
606 const Map<label>& otherProc = mse.otherEdgeFaceAtProc();
607 const Map<label>& globalToLocal =
608 mse.globalToLocalBndEdgeAddressing();
610 //- create communication matrix
611 std::map<label, labelLongList> exchangeData;
612 const DynList<label>& neiProcs = mse.beNeiProcs();
613 forAll(neiProcs, procI)
616 std::make_pair(neiProcs[procI], labelLongList())
619 forAllConstIter(Map<label>, globalToLocal, it)
621 const label beI = it();
623 if( edgeFaces.sizeOfRow(beI) == 1 )
625 labelLongList& dts = exchangeData[otherProc[beI]];
626 //- send data as follows:
627 //- 1. global edge label
628 //- 2. patch of the attached boundary face
629 dts.append(it.key());
630 dts.append(fPatches[edgeFaces(beI, 0)]);
634 labelLongList receivedData;
635 help::exchangeMap(exchangeData, receivedData);
638 while( counter < receivedData.size() )
640 const label beI = globalToLocal[receivedData[counter++]];
641 const label fPatch = receivedData[counter++];
643 otherFacePatch.insert(beI, fPatch);
648 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
650 edgeExtractor::edgeExtractor
653 const meshOctree& octree
657 surfaceEnginePtr_(NULL),
659 surfPartitionerPtr_(NULL),
660 surfEdgeClassificationPtr_(NULL),
667 featureEdgesNearEdge_()
671 calculateSingleCellEdge();
673 findPatchesNearSurfaceFace();
675 findFeatureEdgesNearEdge();
678 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
681 edgeExtractor::~edgeExtractor()
683 deleteDemandDrivenData(surfaceEnginePtr_);
684 deleteDemandDrivenData(surfPartitionerPtr_);
685 deleteDemandDrivenData(surfEdgeClassificationPtr_);
688 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
690 void edgeExtractor::moveVerticesTowardsDiscontinuities(const label nIterations)
692 Info << "Reducing Hausdorff distance:" << flush;
694 const meshSurfaceEngine& mse = this->surfaceEngine();
695 const labelList& bPoints = mse.boundaryPoints();
696 const VRWGraph& pointFaces = mse.pointFaces();
697 const pointFieldPMG& points = mse.points();
698 const faceList::subList& bFaces = mse.boundaryFaces();
700 meshSurfaceEngineModifier modifier(mse);
702 vectorField faceCentreDisplacement(bFaces.size());
703 List<labelledPoint> pointDisplacements(bPoints.size());
705 for(label iterI=0;iterI<nIterations;++iterI)
708 # pragma omp parallel
711 //- find displacements of face centres
713 # pragma omp for schedule(dynamic, 40)
717 const vector centre = bFaces[bfI].centre(points);
721 label patchI, nearestTri;
722 meshOctree_.findNearestSurfacePoint
731 faceCentreDisplacement[bfI] = newP - centre;
734 //- initialise displacements
736 # pragma omp for schedule(dynamic, 40)
738 forAll(pointDisplacements, bpI)
739 pointDisplacements[bpI] = labelledPoint(0, vector::zero);
745 //- calculate displacements of boundary points as the average
746 //- of face centre displacements
748 # pragma omp for schedule(dynamic, 40)
750 forAll(pointFaces, bpI)
752 forAllRow(pointFaces, bpI, pfI)
754 pointDisplacements[bpI].coordinates() +=
755 faceCentreDisplacement[pointFaces(bpI, pfI)];
756 ++pointDisplacements[bpI].pointLabel();
761 if( Pstream::parRun() )
763 const Map<label>& globalToLocal =
764 mse.globalToLocalBndPointAddressing();
765 const DynList<label>& neiProcs = mse.bpNeiProcs();
766 const VRWGraph& bpAtProcs = mse.bpAtProcs();
768 std::map<label, LongList<refLabelledPoint> > exchangeData;
770 exchangeData[i] = LongList<refLabelledPoint>();
772 forAllConstIter(Map<label>, globalToLocal, iter)
774 const label bpI = iter();
776 forAllRow(bpAtProcs, bpI, i)
778 const label neiProc = bpAtProcs(bpI, i);
780 if( neiProc == Pstream::myProcNo() )
783 exchangeData[neiProc].append
785 refLabelledPoint(iter.key(), pointDisplacements[bpI])
790 LongList<refLabelledPoint> receivedData;
791 help::exchangeMap(exchangeData, receivedData);
793 forAll(receivedData, i)
795 const label globalLabel = receivedData[i].objectLabel();
796 const labelledPoint& lp = receivedData[i].lPoint();
798 const label bpI = globalToLocal[globalLabel];
800 pointDisplacements[bpI].coordinates() += lp.coordinates();
801 pointDisplacements[bpI].pointLabel() += lp.pointLabel();
806 # pragma omp parallel for schedule(dynamic, 40)
808 forAll(pointDisplacements, bpI)
810 const labelledPoint& lp = pointDisplacements[bpI];
812 points[bPoints[bpI]] + lp.coordinates() / lp.pointLabel();
814 //Info << "Original point " << bPoints[bpI] << " has coordinates "
815 // << points[bPoints[bpI]] << endl;
816 //Info << "Displacement vector " << lp.coordinates() / lp.pointLabel() << endl;
817 //Info << "Moved point " << mp << endl;
823 meshOctree_.findNearestSurfacePoint(newPoint, distSq, nt, patchI, mp);
825 //Info << "Mapped point " << newPoint << nl << endl;
827 modifier.moveBoundaryVertexNoUpdate(bpI, newPoint);
831 modifier.updateGeometry();
833 Info << '.' << flush;
839 void edgeExtractor::distributeBoundaryFaces()
841 const meshSurfaceEngine& mse = this->surfaceEngine();
842 const labelList& bPoints = mse.boundaryPoints();
843 const faceList::subList& bFaces = mse.boundaryFaces();
844 const pointFieldPMG& points = mse.points();
846 //- set the size of the facePatch list
847 facePatch_.setSize(bFaces.size());
849 //- check if the mesh already has patches
850 if( mesh_.boundaries().size() > 1 )
851 Warning << "Mesh patches are already assigned!" << endl;
853 //- set size of patchNames, newBoundaryFaces_ and newBoundaryOwners_
854 const triSurf& surface = meshOctree_.surface();
855 const label nPatches = surface.patches().size();
857 //- find patches to which the surface points are mapped to
858 pointPatch_.setSize(bPoints.size());
861 # pragma omp parallel for schedule(dynamic, 40)
865 const point& bp = points[bPoints[bpI]];
871 meshOctree_.findNearestSurfacePoint(p, distSq, nTri, fPatch, bp);
873 if( (fPatch > -1) && (fPatch < nPatches) )
875 pointPatch_[bpI] = fPatch;
879 pointPatch_[bpI] = nPatches;
882 "void meshSurfaceEdgeExtractorNonTopo::"
883 "distributeBoundaryFaces()"
884 ) << "Cannot distribute a boundary points " << bPoints[bpI]
885 << " into any surface patch!. Exiting.." << exit(FatalError);
889 //- find the patch for face by finding the patch nearest
890 //- to the face centre
892 # pragma omp parallel for schedule(dynamic, 40)
896 const face& bf = bFaces[bfI];
898 const point c = bf.centre(points);
900 //- find the nearest surface patch to face centre
905 meshOctree_.findNearestSurfacePoint(p, distSq, nTri, fPatch, c);
907 if( (fPatch > -1) && (fPatch < nPatches) )
909 facePatch_[bfI] = fPatch;
913 facePatch_[bfI] = nPatches;
917 "void meshSurfaceEdgeExtractorNonTopo::"
918 "distributeBoundaryFaces()"
919 ) << "Cannot distribute a face " << bFaces[bfI] << " into any "
920 << "surface patch!. Exiting.." << exit(FatalError);
925 bool edgeExtractor::distributeBoundaryFacesNormalAlignment()
929 const pointFieldPMG& points = mesh_.points();
930 const meshSurfaceEngine& mse = this->surfaceEngine();
931 const faceList::subList& bFaces = mse.boundaryFaces();
932 const VRWGraph& faceEdges = mse.faceEdges();
933 const VRWGraph& edgeFaces = mse.edgeFaces();
935 const triSurf& surf = meshOctree_.surface();
936 const pointField& sPoints = surf.points();
938 label nCorrected, nIterations(0);
939 Map<label> otherProcNewPatch;
945 //- allocate a copy of boundary patches
946 labelList newBoundaryPatches(facePatch_);
948 //- check whether there exist situations where a boundary face
949 //- is surrounded by more faces in different patches than the
950 //- faces in the current patch
951 if( Pstream::parRun() )
953 findOtherFacePatchesParallel
960 //- find the faces which have neighbouring faces in other patches
961 labelLongList candidates;
962 findFaceCandidates(candidates, &facePatch_, &otherProcNewPatch);
964 //- go through the list of faces and check if they shall remain
965 //- in the current patch
967 # pragma omp parallel for schedule(dynamic, 40) \
968 reduction(+ : nCorrected)
970 forAll(candidates, i)
972 const label bfI = candidates[i];
973 const face& bf = bFaces[bfI];
975 DynList<label> allNeiPatches;
976 DynList<label> neiPatches;
977 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
979 forAllRow(faceEdges, bfI, eI)
981 const label beI = faceEdges(bfI, eI);
983 if( edgeFaces.sizeOfRow(beI) == 2 )
985 label fNei = edgeFaces(beI, 0);
987 fNei = edgeFaces(faceEdges(bfI, eI), 1);
989 allNeiPatches.appendIfNotIn(facePatch_[fNei]);
990 neiPatches[eI] = facePatch_[fNei];
992 else if( edgeFaces.sizeOfRow(beI) == 1 )
994 allNeiPatches.appendIfNotIn(otherProcNewPatch[beI]);
995 neiPatches[eI] = otherProcNewPatch[beI];
999 //- do not modify faces with all neighbours in the same patch
1002 (allNeiPatches.size() == 1) &&
1003 (allNeiPatches[0] == facePatch_[bfI])
1007 //- check whether there exist edges which are more suitable for
1008 //- projection onto feature edges than the currently selected ones
1010 DynList<scalar> normalAlignment(allNeiPatches.size());
1011 DynList<scalar> distanceSq(allNeiPatches.size());
1013 forAll(allNeiPatches, i)
1017 label nearestTriangle;
1019 point p = bf.centre(points);
1020 meshOctree_.findNearestSurfacePointInRegion
1029 maxDSq = Foam::max(dSq, maxDSq);
1031 //- calculate normal vectors
1032 vector tn = surf[nearestTriangle].normal(sPoints);
1033 tn /= (mag(tn) + VSMALL);
1034 vector fn = bf.normal(points);
1035 fn /= (mag(fn) + SMALL);
1037 //- calculate alignment
1038 normalAlignment[i] = mag(tn & fn);
1039 distanceSq[i] = dSq;
1042 scalar maxAlignment(0.0);
1043 forAll(normalAlignment, i)
1047 sqrt(maxDSq / (distanceSq[i] + VSMALL)) * normalAlignment[i]
1050 if( metric > maxAlignment )
1052 maxAlignment = metric;
1053 newPatch = allNeiPatches[i];
1057 if( (newPatch >= 0) && (newPatch != facePatch_[bfI]) )
1059 newBoundaryPatches[bfI] = newPatch;
1064 reduce(nCorrected, sumOp<label>());
1070 //- transfer the new patches back
1071 facePatch_.transfer(newBoundaryPatches);
1073 } while( (nCorrected != 0) && (++nIterations < 5) );
1078 void edgeExtractor::findEdgeCandidates()
1080 const triSurf& surface = meshOctree_.surface();
1081 const vectorField& sp = surface.points();
1082 const VRWGraph& facetEdges = surface.facetEdges();
1083 const VRWGraph& edgeFacets = surface.edgeFacets();
1085 const triSurfacePartitioner& partitioner = this->partitioner();
1087 const meshSurfaceEngine& mse = this->surfaceEngine();
1088 const pointFieldPMG& points = mse.points();
1089 const labelList& bPoints = mse.boundaryPoints();
1090 const labelList& bp = mse.bp();
1091 const VRWGraph& faceEdges = mse.faceEdges();
1093 Map<label> otherFacePatch;
1094 findOtherFacePatchesParallel(otherFacePatch, &facePatch_);
1095 labelLongList faceCandidates;
1096 findFaceCandidates(faceCandidates, &facePatch_, &otherFacePatch);
1099 # pragma omp parallel for schedule(dynamic, 40) \
1100 if( faceCandidates.size() > 100 )
1102 forAll(faceCandidates, fcI)
1104 const label bfI = faceCandidates[fcI];
1106 forAllRow(faceEdges, bfI, i)
1108 const label eI = faceEdges(bfI, i);
1109 edgeType_[eI] |= CANDIDATE;
1113 //- find distances of all vertices supporting CANDIDATE edges
1114 //- from feature edges separating various patches
1115 const VRWGraph& pEdges = mse.boundaryPointEdges();
1116 const edgeList& edges = mse.edges();
1118 List<List<labelledScalar> > featureEdgesNearPoint(bPoints.size());
1120 DynList<label> containedTriangles;
1122 # pragma omp parallel for schedule(dynamic, 40) private(containedTriangles)
1126 // TODO rewrite for execution on distributed machines
1128 forAllRow(pEdges, bpI, peI)
1130 const label eI = pEdges(bpI, peI);
1132 if( edgeType_[eI] & CANDIDATE )
1141 //- check the squared distance from the nearest feature edge
1143 forAllRow(pEdges, bpI, peI)
1145 const label eI = pEdges(bpI, peI);
1146 const edge& e = edges[eI];
1147 const scalar dSq = magSqr(points[e.start()] - points[e.end()]);
1149 rSq = Foam::max(rSq, dSq);
1153 const scalar r = Foam::sqrt(rSq);
1155 //- create a boundaing box used for searching neighbour edges
1156 const point& p = points[bPoints[bpI]];
1157 boundBox bb(p - point(r, r, r), p + point(r, r, r));
1159 //- find the surface triangles in the vicinity of the point
1160 //- check for potential feature edges
1161 containedTriangles.clear();
1162 meshOctree_.findTrianglesInBox(bb, containedTriangles);
1164 DynList<label> featureEdgeCandidates;
1166 forAll(containedTriangles, ctI)
1168 const label tI = containedTriangles[ctI];
1170 forAllRow(facetEdges, tI, feI)
1172 const label seI = facetEdges(tI, feI);
1174 if( edgeFacets.sizeOfRow(seI) == 2 )
1176 const label p0 = surface[edgeFacets(seI, 0)].region();
1177 const label p1 = surface[edgeFacets(seI, 1)].region();
1181 featureEdgeCandidates.appendIfNotIn(seI);
1186 featureEdgeCandidates.appendIfNotIn(seI);
1191 //- check the distance of the vertex from the candidates
1192 List<labelledScalar>& featureEdgeDistances =
1193 featureEdgesNearPoint[bpI];
1194 featureEdgeDistances.setSize(featureEdgeCandidates.size());
1195 forAll(featureEdgeCandidates, i)
1197 const label seI = featureEdgeCandidates[i];
1199 const point s = sp[edges[seI].start()];
1200 const point e = sp[edges[seI].end()];
1201 const point np = help::nearestPointOnTheEdgeExact(s, e, p);
1203 featureEdgeDistances[i] = labelledScalar(seI, magSqr(np - p));
1206 //- find nearest edges
1207 sort(featureEdgeDistances);
1211 //- start post-processing gathered data
1212 const labelList& edgeGroup = partitioner.edgeGroups();
1214 List<List<labelledScalar> > edgeGroupAndWeights(edges.size());
1217 # pragma omp parallel for schedule(dynamic, 40) \
1218 if( edges.size() > 1000 )
1220 forAll(edgeType_, edgeI)
1222 if( edgeType_[edgeI] & CANDIDATE )
1224 const edge& e = edges[edgeI];
1226 const List<labelledScalar>& sc =
1227 featureEdgesNearPoint[bp[e.start()]];
1228 const List<labelledScalar>& ec =
1229 featureEdgesNearPoint[bp[e.end()]];
1231 //- find the feature-edge partition for which the sum of
1232 //- node weights is minimal.
1233 DynList<labelledScalar> weights;
1236 const label sPart = edgeGroup[sc[i].scalarLabel()];
1240 const label ePart = edgeGroup[ec[j].scalarLabel()];
1242 if( (sPart >= 0) && (sPart == ePart) )
1249 sc[i].value() + ec[j].value()
1257 edgeGroupAndWeights[edgeI].setSize(weights.size());
1258 forAll(edgeGroupAndWeights[edgeI], epI)
1259 edgeGroupAndWeights[edgeI][epI] = weights[epI];
1261 //- sort the data according to the weights
1262 stableSort(edgeGroupAndWeights[edgeI]);
1266 Info << "Edge partitions and weights " << edgeGroupAndWeights << endl;
1269 void edgeExtractor::findNeiPatches
1272 const Map<label>& otherProcPatch,
1273 DynList<label>& neiPatches
1276 const meshSurfaceEngine& mse = surfaceEngine();
1278 const VRWGraph& faceEdges = mse.faceEdges();
1279 const VRWGraph& edgeFaces = mse.edgeFaces();
1281 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
1283 forAllRow(faceEdges, bfI, feI)
1285 const label beI = faceEdges(bfI, feI);
1287 if( edgeFaces.sizeOfRow(beI) == 2 )
1289 label nei = edgeFaces(beI, 0);
1291 nei = edgeFaces(beI, 1);
1293 neiPatches[feI] = facePatch_[nei];
1295 else if( edgeFaces.sizeOfRow(beI) == 1 )
1297 neiPatches[feI] = otherProcPatch[beI];
1302 scalar edgeExtractor::calculateAlignmentForEdge
1311 DynList<label> patches(2);
1312 patches[0] = patch0;
1313 patches[1] = patch1;
1315 const pointFieldPMG& points = surfaceEnginePtr_->mesh().points();
1317 const edge& e = surfaceEnginePtr_->edges()[beI];
1318 const point& ps = points[e.start()];
1319 const point& pe = points[e.end()];
1321 vector ev = e.vec(points);
1322 const scalar magE = mag(ev) + VSMALL;
1328 meshOctree_.findNearestPointToPatches(mps, dSqS, ps, patches);
1329 meshOctree_.findNearestPointToPatches(mpe, dSqE, pe, patches);
1331 vector fv = mpe - mps;
1332 fv /= (mag(fv) + VSMALL);
1334 val = 0.5 * (1.0 + (ev & fv));
1336 val = min(val, 1.0);
1337 val = max(val, 0.0);
1342 scalar edgeExtractor::calculateDeformationMetricForEdge
1351 DynList<label> patches(2);
1352 patches[0] = patch0;
1353 patches[1] = patch1;
1355 const pointFieldPMG& points = surfaceEnginePtr_->mesh().points();
1357 const edge& e = surfaceEnginePtr_->edges()[beI];
1358 const point& ps = points[e.start()];
1359 const point& pe = points[e.end()];
1361 vector ev = e.vec(points);
1362 const scalar magE = mag(ev) + VSMALL;
1368 meshOctree_.findNearestPointToPatches(mps, dSqS, ps, patches);
1369 meshOctree_.findNearestPointToPatches(mpe, dSqE, pe, patches);
1371 vector fv = mpe - mps;
1372 fv /= (mag(fv) + VSMALL);
1374 scalar c = min(fv & ev, 1.0);
1376 const scalar angle = acos(c);
1378 val = 0.5 * (sqrt(dSqS) + sqrt(dSqE)) + magE * angle;
1383 scalar edgeExtractor::calculateDeformationMetricForFace
1386 const DynList<label>& neiPatches,
1387 const label facePatch
1392 const VRWGraph& faceEdges = surfaceEnginePtr_->faceEdges();
1394 if( neiPatches.size() != faceEdges.sizeOfRow(bfI) )
1398 "scalar edgeExtractor::calculateDeformationMetricForFace"
1399 "(const label, const DynList<label>&, const label) const"
1400 ) << "Number of neiPatches and faceEdge does not match for face "
1401 << bfI << abort(FatalError);
1404 const label patch0 = facePatch == -1 ? facePatch_[bfI] : facePatch;
1406 forAllRow(faceEdges, bfI, i)
1408 const label beI = faceEdges(bfI, i);
1410 if( neiPatches[i] == patch0 )
1413 Enorm += calculateDeformationMetricForEdge(beI, patch0, neiPatches[i]);
1419 bool edgeExtractor::checkConcaveEdgeCells()
1421 bool changed(false);
1423 const triSurf& surf = meshOctree_.surface();
1424 const VRWGraph& edgeFacets = surf.edgeFacets();
1426 const pointFieldPMG& points = mesh_.points();
1427 const faceListPMG& faces = mesh_.faces();
1428 const cellListPMG& cells = mesh_.cells();
1429 const label bndStartFace = mesh_.boundaries()[0].patchStart();
1431 const meshSurfaceEngine& mse = this->surfaceEngine();
1432 const faceList::subList& bFaces = mse.boundaryFaces();
1433 const labelList& bp = mse.bp();
1434 const labelList& faceCells = mse.faceOwners();
1435 const VRWGraph& edgeFaces = mse.edgeFaces();
1437 //- analyse the surface mesh and find out which edges are concave or convex
1438 const triSurfaceClassifyEdges& edgeClassifier = this->edgeClassifier();
1439 const List<direction>& edgeType = edgeClassifier.edgeTypes();
1441 //- create a copy of facePatch array for local modifications
1442 labelList newBoundaryPatches(facePatch_);
1444 //- start checking the surface of the mesh
1447 boolList patchPoint(mse.boundaryPoints().size(), false);
1453 //- check which surface points are surrounded by boundary faces
1454 //- in the same surface patch
1455 markPatchPoints(patchPoint);
1457 //- check whether exist edges of a single cell which shall be projected
1458 //- onto a concave edge
1460 # pragma omp parallel for schedule(dynamic, 40) reduction(+ : nChanged)
1462 forAll(edgeType_, beI)
1464 if( !(edgeType_[beI] & SINGLECELLEDGE) )
1467 //- check if all faces are assigned to the same patch
1468 const label firstPatch = newBoundaryPatches[edgeFaces(beI, 0)];
1469 const label secondPatch = newBoundaryPatches[edgeFaces(beI, 1)];
1471 if( firstPatch == secondPatch )
1474 const cell& c = cells[faceCells[edgeFaces(beI, 0)]];
1476 //- find edges within the bounding box determined by the cell
1477 point pMin(VGREAT, VGREAT, VGREAT);
1478 point pMax(-VGREAT, -VGREAT, -VGREAT);
1481 const face& f = faces[c[fI]];
1485 pMin = Foam::min(pMin, points[f[pI]]);
1486 pMax = Foam::max(pMax, points[f[pI]]);
1490 const point cc = 0.5 * (pMin + pMax);
1491 const point diff = pMax - pMin;
1492 boundBox bb(cc-diff, cc+diff);
1493 DynList<label> containedEdges;
1494 meshOctree_.findEdgesInBox(bb, containedEdges);
1496 //- check if there exists concave edges boundaing patches
1497 //- assigned to boundary faces of the current cell
1498 forAll(containedEdges, ceI)
1500 const label eI = containedEdges[ceI];
1502 if( edgeFacets.sizeOfRow(eI) != 2 )
1504 if( !(edgeType[eI] & triSurfaceClassifyEdges::FEATUREEDGE) )
1507 if( edgeType[eI] & triSurfaceClassifyEdges::CONCAVEEDGE )
1509 const label patch0 = surf[edgeFacets(eI, 0)].region();
1510 const label patch1 = surf[edgeFacets(eI, 1)].region();
1514 ((firstPatch == patch0) && (secondPatch == patch1)) ||
1515 ((firstPatch == patch1) && (secondPatch == patch0))
1518 DynList<DynList<label>, 2> facesInPatch;
1519 facesInPatch.setSize(2);
1521 DynList<label, 2> nFacesInPatch;
1522 nFacesInPatch.setSize(2);
1525 DynList<bool, 2> hasPatchPoints;
1526 hasPatchPoints.setSize(2);
1527 hasPatchPoints = false;
1531 if( c[fI] < bndStartFace )
1534 const label bfI = c[fI] - bndStartFace;
1535 const face& bf = bFaces[bfI];
1537 if( newBoundaryPatches[bfI] == patch1 )
1539 facesInPatch[1].append(bfI);
1544 if( patchPoint[bp[bf[pI]]] )
1545 hasPatchPoints[1] = true;
1548 else if( newBoundaryPatches[bfI] == patch0 )
1550 facesInPatch[0].append(bfI);
1555 if( patchPoint[bp[bf[pI]]] )
1556 hasPatchPoints[0] = true;
1561 if( nFacesInPatch[1] > nFacesInPatch[0] )
1563 //- there exist more faces in patch 1
1564 //- assign all boundary faces to the same patch
1565 forAll(facesInPatch[0], i)
1566 newBoundaryPatches[facesInPatch[0][i]] = patch1;
1570 else if( nFacesInPatch[0] > nFacesInPatch[1] )
1572 //- there exist more faces in patch 0
1573 //- assign all boundary faces to the same patch
1574 forAll(facesInPatch[1], i)
1575 newBoundaryPatches[facesInPatch[1][i]] = patch0;
1581 if( hasPatchPoints[0] && !hasPatchPoints[1] )
1583 //- transfer all faces to patch 1
1584 forAll(facesInPatch[0], i)
1585 newBoundaryPatches[facesInPatch[0][i]] =
1590 else if( !hasPatchPoints[0] && hasPatchPoints[1] )
1592 //- transfer all faces to patch 0
1593 forAll(facesInPatch[1], i)
1594 newBoundaryPatches[facesInPatch[1][i]] =
1601 //- just transfer all faces to the same patch
1602 forAll(facesInPatch[1], i)
1603 newBoundaryPatches[facesInPatch[1][i]] =
1614 if( Pstream::parRun() )
1615 reduce(nChanged, sumOp<label>());
1620 } while( nChanged != 0 );
1622 //- transfer the information back to facePatch
1623 facePatch_.transfer(newBoundaryPatches);
1628 bool edgeExtractor::checkFacePatchesTopology()
1630 bool changed(false);
1632 const meshSurfaceEngine& mse = this->surfaceEngine();
1633 const faceList::subList& bFaces = mse.boundaryFaces();
1634 const labelList& bp = mse.bp();
1635 const VRWGraph& faceEdges = mse.faceEdges();
1636 const VRWGraph& edgeFaces = mse.edgeFaces();
1639 Map<label> otherProcNewPatch;
1644 # ifdef DEBUGEdgeExtractor
1646 const triSurf* surfPtr = surfaceWithPatches();
1647 surfPtr->writeSurface
1649 "surfaceTopologyIter_"+help::scalarToText(nIter)+".stl"
1657 //- allocate a copy of boundary patches
1658 labelList newBoundaryPatches(facePatch_);
1660 //- check whether there exist situations where a boundary face
1661 //- is surrounded by more faces in different patches than the
1662 //- faces in the current patch
1663 if( Pstream::parRun() )
1665 findOtherFacePatchesParallel
1672 //- find the faces which have neighbouring faces in other patches
1673 labelLongList candidates;
1674 findFaceCandidates(candidates, &facePatch_, &otherProcNewPatch);
1676 //- go through the list of faces and check if they shall remain
1677 //- in the current patch
1679 # pragma omp parallel for schedule(dynamic, 40) \
1680 reduction(+ : nCorrected)
1682 forAll(candidates, i)
1684 const label bfI = candidates[i];
1685 const face& bf = bFaces[bfI];
1687 //- do not change patches of faces where all points are mapped
1688 //- onto the same patch
1689 bool allInSamePatch(true);
1691 if( pointPatch_[bp[bf[pI]]] != facePatch_[bfI] )
1693 allInSamePatch = false;
1697 if( allInSamePatch )
1700 DynList<label> allNeiPatches;
1701 DynList<label> neiPatches;
1702 neiPatches.setSize(faceEdges.sizeOfRow(bfI));
1704 forAllRow(faceEdges, bfI, eI)
1706 const label beI = faceEdges(bfI, eI);
1708 if( edgeFaces.sizeOfRow(beI) == 2 )
1710 label fNei = edgeFaces(beI, 0);
1712 fNei = edgeFaces(faceEdges(bfI, eI), 1);
1714 allNeiPatches.appendIfNotIn(facePatch_[fNei]);
1715 neiPatches[eI] = facePatch_[fNei];
1717 else if( edgeFaces.sizeOfRow(beI) == 1 )
1719 allNeiPatches.appendIfNotIn(otherProcNewPatch[beI]);
1720 neiPatches[eI] = otherProcNewPatch[beI];
1724 //- do not modify faces with all neighbours in the same patch
1727 (allNeiPatches.size() == 1) &&
1728 (allNeiPatches[0] == facePatch_[bfI])
1732 //- check whether there exist edges which are more suitable for
1733 //- projection onto feature edges than the currently selected ones
1736 //- check if some faces have to be distributed to another patch
1737 //- in order to reduce the number of feature edges
1738 Map<label> nNeiInPatch(allNeiPatches.size());
1739 forAll(allNeiPatches, i)
1740 nNeiInPatch.insert(allNeiPatches[i], 0);
1741 forAll(neiPatches, eI)
1742 ++nNeiInPatch[neiPatches[eI]];
1746 forAllConstIter(Map<label>, nNeiInPatch, it)
1748 if( it() > nNeiEdges )
1750 newPatch = it.key();
1755 (it() == nNeiEdges) && (it.key() == facePatch_[bfI])
1758 newPatch = it.key();
1762 //- do not swap in case the
1763 if( (newPatch < 0) || (newPatch == facePatch_[bfI]) )
1766 //- check whether the edges shared ith the neighbour patch form
1767 //- a singly linked chain
1768 DynList<bool> sharedEdge;
1769 sharedEdge.setSize(bFaces[bfI].size());
1772 forAll(neiPatches, eI)
1773 if( neiPatches[eI] == newPatch )
1774 sharedEdge[eI] = true;
1776 if( help::areElementsInChain(sharedEdge) )
1778 //- change the patch to the newPatch
1780 newBoundaryPatches[bfI] = newPatch;
1784 //- evaluate the new situation and ensure that no oscillation occur
1785 reduce(nCorrected, sumOp<label>());
1788 faceEvaluator faceEvaluator(*this);
1790 faceEvaluator.setNewBoundaryPatches(newBoundaryPatches);
1793 # pragma omp parallel for schedule(dynamic, 50)
1795 forAll(candidates, i)
1797 const label bfI = candidates[i];
1799 const label bestPatch =
1800 faceEvaluator.bestPatchAfterModification(bfI);
1802 newBoundaryPatches[bfI] = bestPatch;
1810 //- transfer the new patches back
1811 facePatch_.transfer(newBoundaryPatches);
1814 } while( nCorrected != 0 && (nIter++ < 3) );
1819 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
1821 namespace featureEdgeHelpers
1824 class featureEdgesNeiOp
1827 //- reference to meshSurfaceEngine
1828 const meshSurfaceEngine& mse_;
1830 //- refence to a list holding information which edges are feature edges
1831 const boolList& isFeatureEdge_;
1833 //- number of feature edges at a surface point
1834 labelList nFeatureEdgesAtPoint_;
1836 // Private member functions
1837 //- calculate the number of feature edges connected to a surface vertex
1838 void calculateNumberOfEdgesAtPoint()
1840 const labelList& bp = mse_.bp();
1841 const edgeList& edges = mse_.edges();
1843 nFeatureEdgesAtPoint_.setSize(mse_.boundaryPoints().size());
1844 nFeatureEdgesAtPoint_ = 0;
1846 forAll(isFeatureEdge_, edgeI)
1848 if( !isFeatureEdge_[edgeI] )
1851 const edge& e = edges[edgeI];
1852 ++nFeatureEdgesAtPoint_[bp[e.start()]];
1853 ++nFeatureEdgesAtPoint_[bp[e.end()]];
1856 if( Pstream::parRun() )
1858 const Map<label>& globalToLocal =
1859 mse_.globalToLocalBndPointAddressing();
1860 const DynList<label>& neiProcs = mse_.bpNeiProcs();
1861 const VRWGraph& bpAtProcs = mse_.bpAtProcs();
1863 std::map<label, DynList<labelPair> > exchangeData;
1865 exchangeData[neiProcs[i]].clear();
1867 //- fill the data from sending
1868 forAllConstIter(Map<label>, globalToLocal, it)
1870 const label bpI = it();
1872 forAllRow(bpAtProcs, bpI, i)
1874 const label neiProc = bpAtProcs(bpI, i);
1876 if( neiProc == Pstream::myProcNo() )
1879 exchangeData[neiProc].append
1881 labelPair(it.key(), nFeatureEdgesAtPoint_[bpI])
1886 //- exchange the data between the procesors
1887 LongList<labelPair> receivedData;
1888 help::exchangeMap(exchangeData, receivedData);
1890 forAll(receivedData, i)
1892 const labelPair& lp = receivedData[i];
1894 nFeatureEdgesAtPoint_[globalToLocal[lp.first()]] +=
1904 const meshSurfaceEngine& mse,
1905 const boolList& isFeatureEdge
1909 isFeatureEdge_(isFeatureEdge),
1910 nFeatureEdgesAtPoint_()
1912 calculateNumberOfEdgesAtPoint();
1917 return isFeatureEdge_.size();
1920 void operator()(const label beI, DynList<label>& neighbourEdges) const
1922 neighbourEdges.clear();
1924 const VRWGraph& bpEdges = mse_.boundaryPointEdges();
1925 const labelList& bp = mse_.bp();
1926 const edgeList& edges = mse_.edges();
1928 const edge& e = edges[beI];
1930 const label bps = bp[e.start()];
1931 const label bpe = bp[e.end()];
1933 if( nFeatureEdgesAtPoint_[bps] == 2 )
1935 forAllRow(bpEdges, bps, peI)
1937 const label beJ = bpEdges(bps, peI);
1939 if( (beJ == beI) || !isFeatureEdge_[beJ] )
1942 neighbourEdges.append(beJ);
1946 if( nFeatureEdgesAtPoint_[bpe] == 2 )
1948 forAllRow(bpEdges, bpe, peI)
1950 const label beJ = bpEdges(bpe, peI);
1952 if( (beJ == beI) || !isFeatureEdge_[beJ] )
1955 neighbourEdges.append(beJ);
1960 template<class labelListType>
1963 std::map<label, DynList<label> >& neiGroups,
1964 const labelListType& elementInGroup,
1965 const DynList<label>& localGroupLabel
1968 const Map<label>& globalToLocal = mse_.globalToLocalBndPointAddressing();
1969 const VRWGraph& bpAtProcs = mse_.bpAtProcs();
1970 const VRWGraph& bpEdges = mse_.boundaryPointEdges();
1972 const DynList<label>& neiProcs = mse_.beNeiProcs();
1974 std::map<label, DynList<labelPair> > exchangeData;
1976 exchangeData[neiProcs[i]].clear();
1978 forAllConstIter(Map<label>, globalToLocal, it)
1980 const label bpI = it();
1982 if( nFeatureEdgesAtPoint_[bpI] != 2 )
1985 forAllRow(bpEdges, bpI, i)
1987 const label beI = bpEdges(bpI, i);
1989 if( !isFeatureEdge_[beI] )
1992 const label groupI = elementInGroup[beI];
1994 forAllRow(bpAtProcs, bpI, ppI)
1996 const label neiProc = bpAtProcs(bpI, ppI);
1998 if( neiProc == Pstream::myProcNo() )
2001 exchangeData[neiProc].append
2003 labelPair(it.key(), localGroupLabel[groupI])
2009 LongList<labelPair> receivedData;
2010 help::exchangeMap(exchangeData, receivedData);
2012 forAll(receivedData, i)
2014 const labelPair& lp = receivedData[i];
2015 const label groupI = elementInGroup[globalToLocal[lp.first()]];
2017 DynList<label>& ng = neiGroups[localGroupLabel[groupI]];
2019 //- store the connection over the inter-processor boundary
2020 ng.appendIfNotIn(lp.second());
2025 class featureEdgesSelOp
2028 //- reference to a list holding information which edge is afeture edge
2029 const boolList& isFeatureEdge_;
2033 featureEdgesSelOp(const boolList& isFeatureEdge)
2035 isFeatureEdge_(isFeatureEdge)
2038 bool operator()(const label beI) const
2040 return isFeatureEdge_[beI];
2044 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
2046 } // End namespace featureEdgeHelpers
2048 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2050 bool edgeExtractor::checkFacePatchesGeometry()
2052 bool changed(false);
2054 const meshSurfaceEngine& mse = this->surfaceEngine();
2055 const labelList& bPoints = mse.boundaryPoints();
2056 const faceList::subList& bFaces = mse.boundaryFaces();
2057 const labelList& bp = mse.bp();
2059 //- allocate a copy of boundary patches
2060 labelList newBoundaryPatches(facePatch_.size());
2063 Map<label> otherProcNewPatch;
2065 boolList activePoints(bPoints.size(), true);
2066 labelLongList activePointLabel(bPoints.size());
2067 forAll(bPoints, bpI)
2068 activePointLabel[bpI] = bpI;
2074 # ifdef DEBUGEdgeExtractor
2076 const triSurf* surfPtr = surfaceWithPatches();
2077 surfPtr->writeSurface
2079 "surfaceIter_"+help::scalarToText(iter)+".stl"
2085 //- create feature edges and corners information
2086 meshSurfacePartitioner mPart(mse, facePatch_);
2088 //- project vertices onto the surface mesh
2089 meshSurfaceMapper(mPart, meshOctree_).mapVerticesOntoSurfacePatches
2094 //- stop after a certain number of iterations
2098 //- update surface geometry data
2099 meshSurfaceEngineModifier(mse).updateGeometry();
2101 //- check if there exist any inverted faces
2102 meshSurfaceCheckInvertedVertices surfCheck(mPart, activePoints);
2103 const labelHashSet& invertedPoints = surfCheck.invertedVertices();
2105 if( returnReduce(invertedPoints.size(), sumOp<label>()) == 0 )
2110 "void edgeExtractor::extractEdges()"
2111 ) << "Found " << invertedPoints.size()
2112 << " points with inverted surface normals. Getting rid of them..."
2115 //- untangle the surface
2116 activePointLabel.clear();
2117 activePoints = false;
2118 forAllConstIter(labelHashSet, invertedPoints, it)
2120 activePointLabel.append(bp[it.key()]);
2121 activePoints[bp[it.key()]] = true;
2124 //- untangle the surface
2125 meshSurfaceOptimizer mso(mPart, meshOctree_);
2126 mso.untangleSurface(activePointLabel, 1);
2129 newBoundaryPatches = facePatch_;
2131 //- check whether there exist situations where a boundary face
2132 //- is surrounded by more faces in different patches than the
2133 //- faces in the current patch
2134 if( Pstream::parRun() )
2136 findOtherFacePatchesParallel
2143 //- find the faces which have neighbouring faces in other patches
2144 labelLongList candidates;
2147 const face& bf = bFaces[bfI];
2150 if( invertedPoints.found(bf[pI]) )
2152 candidates.append(bfI);
2158 # pragma omp parallel for schedule(dynamic, 5) reduction(+ : nCorrected)
2160 forAll(candidates, i)
2162 const label bfI = candidates[i];
2164 DynList<label> neiPatches;
2165 findNeiPatches(bfI, otherProcNewPatch, neiPatches);
2167 DynList<label> allNeiPatches;
2168 forAll(neiPatches, i)
2169 allNeiPatches.appendIfNotIn(neiPatches[i]);
2171 //- check the deformation energy and find the minimum energy which
2172 //- can be achieved by switching face patch
2173 scalar minE(VGREAT);
2174 label minEPatch(-1);
2175 DynList<scalar> Enorm(allNeiPatches.size());
2176 forAll(allNeiPatches, i)
2179 calculateDeformationMetricForFace
2186 if( Enorm[i] < minE )
2189 minEPatch = allNeiPatches[i];
2193 if( minEPatch != facePatch_[bfI] )
2195 newBoundaryPatches[bfI] = minEPatch;
2200 //- check if any faces are re-assigned to some other patch
2201 reduce(nCorrected, sumOp<label>());
2202 if( nCorrected == 0 )
2205 //- update faceEvaluator with information after patches have been
2206 //- altered. It blocks chaning of patches if it causes oscillations
2207 faceEvaluator facePatchEvaluator(*this);
2208 facePatchEvaluator.setNewBoundaryPatches(newBoundaryPatches);
2210 //- compare face patches before and after
2211 //- disallow modification which may trigger oscillating behaviour
2212 labelLongList changedFaces;
2213 forAll(newBoundaryPatches, bfI)
2215 if( newBoundaryPatches[bfI] != facePatch_[bfI] )
2217 const label patchI =
2218 facePatchEvaluator.bestPatchAfterModification(bfI);
2219 newBoundaryPatches[bfI] = patchI;
2221 if( patchI != facePatch_[bfI] )
2222 changedFaces.append(bfI);
2226 nCorrected = changedFaces.size();
2228 reduce(nCorrected, sumOp<label>());
2233 facePatch_ = newBoundaryPatches;
2236 } while( nCorrected != 0 );
2241 void edgeExtractor::projectDeterminedFeatureVertices()
2243 List<DynList<label, 5> > pointPatches;
2244 pointPatches.setSize(pointValence_.size());
2246 const meshSurfaceEngine& mse = surfaceEngine();
2247 const pointFieldPMG& points = mse.mesh().points();
2248 const labelList& bPoints = mse.boundaryPoints();
2249 const labelList& bp = mse.bp();
2250 const faceList::subList& bFaces = mse.boundaryFaces();
2251 meshOctree_.surface().pointEdges();
2253 //- calculate patches for each point
2256 const face& bf = bFaces[bfI];
2259 pointPatches[bp[bf[pI]]].appendIfNotIn(facePatch_[bfI]);
2262 if( Pstream::parRun() )
2264 const Map<label>& globalToLocal =
2265 mse.globalToLocalBndPointAddressing();
2266 const VRWGraph& bpAtProcs = mse.bpAtProcs();
2267 const DynList<label>& bpNeiProcs = mse.bpNeiProcs();
2269 std::map<label, LongList<labelPair> > exchangeData;
2270 forAll(bpNeiProcs, i)
2273 std::make_pair(bpNeiProcs[i], LongList<labelPair>())
2276 //- collect the data distributed to others
2277 forAllConstIter(Map<label>, globalToLocal, it)
2279 const label bpI = it();
2281 const DynList<label, 5>& pPatches = pointPatches[bpI];
2283 forAllRow(bpAtProcs, bpI, i)
2285 const label neiProc = bpAtProcs(bpI, i);
2287 if( neiProc == Pstream::myProcNo() )
2290 LongList<labelPair>& data = exchangeData[neiProc];
2292 forAll(pPatches, ppI)
2293 data.append(labelPair(it.key(), pPatches[ppI]));
2297 //- exchange information
2298 LongList<labelPair> receivedData;
2299 help::exchangeMap(exchangeData, receivedData);
2302 forAll(receivedData, i)
2304 const labelPair& lp = receivedData[i];
2306 pointPatches[globalToLocal[lp.first()]].appendIfNotIn(lp.second());
2310 meshSurfaceEngineModifier surfMod(mse);
2313 # pragma omp parallel for schedule(dynamic, 10)
2315 forAll(pointPatches, bpI)
2317 if( pointPatches[bpI].size() < 2 )
2320 const DynList<label> pPatches = pointPatches[bpI];
2322 const point& p = points[bPoints[bpI]];
2324 //- find the nearest object on the surface mesh
2327 if( pPatches.size() == 2 )
2330 meshOctree_.findNearestEdgePoint(newP, dSqExact, nse, p, pPatches);
2335 meshOctree_.findNearestCorner(newP, dSqExact, nsp, p, pPatches);
2338 //- find the nearest object in an iterative procedure
2340 for(label iterI=0;iterI<20;++iterI)
2342 point inp(vector::zero);
2350 meshOctree_.findNearestSurfacePointInRegion
2362 inp /= pPatches.size();
2363 const scalar currDSq = magSqr(inp - pp);
2366 if( currDSq < 1e-2 * dSqExact )
2370 //- check if the exact position of the corner is further away
2371 //- than the iteratively found object
2372 if( dSqExact > 1.1 * magSqr(pp - p) )
2375 surfMod.moveBoundaryVertexNoUpdate(bpI, newP);
2378 surfMod.syncVerticesAtParallelBoundaries();
2379 surfMod.updateGeometry();
2382 bool edgeExtractor::untangleSurface()
2384 bool changed(false);
2386 meshSurfaceEngine& mse =
2387 const_cast<meshSurfaceEngine&>(this->surfaceEngine());
2388 meshSurfaceOptimizer optimizer(mse, meshOctree_);
2389 changed = optimizer.untangleSurface();
2394 void edgeExtractor::extractEdges()
2396 distributeBoundaryFaces();
2398 distributeBoundaryFacesNormalAlignment();
2400 # ifdef DEBUGEdgeExtractor
2401 const triSurf* sPtr = surfaceWithPatches();
2402 sPtr->writeSurface("initialDistributionOfPatches.stl");
2403 deleteDemandDrivenData(sPtr);
2406 Info << "Starting topological adjustment of patches" << endl;
2407 if( checkFacePatchesTopology() )
2409 Info << "Finished topological adjustment of patches" << endl;
2411 # ifdef DEBUGEdgeExtractor
2412 Info << "Changes due to face patches" << endl;
2413 fileName sName("checkFacePatches"+help::scalarToText(nIter)+".stl");
2414 sPtr = surfaceWithPatches();
2415 sPtr->writeSurface(sName);
2416 deleteDemandDrivenData(sPtr);
2421 Info << "No topological adjustment was needed" << endl;
2424 Info << "Starting geometrical adjustment of patches" << endl;
2425 if( checkFacePatchesGeometry() )
2427 Info << "Finished geometrical adjustment of patches" << endl;
2431 Info << "No geometrical adjustment was needed" << endl;
2434 # ifdef DEBUGEdgeExtractor
2435 const triSurf* sPtr = surfaceWithPatches();
2436 sPtr->writeSurface("finalDistributionOfPatches.stl");
2437 deleteDemandDrivenData(sPtr);
2441 const triSurf* edgeExtractor::surfaceWithPatches() const
2443 //- allocate the memory for the surface mesh
2444 triSurf* surfPtr = new triSurf();
2446 //- surface of the volume mesh
2447 const meshSurfaceEngine& mse = surfaceEngine();
2448 const faceList::subList& bFaces = mse.boundaryFaces();
2449 const labelList& bp = mse.bp();
2450 const pointFieldPMG& points = mesh_.points();
2452 //- modifier of the new surface mesh
2453 triSurfModifier surfModifier(*surfPtr);
2454 surfModifier.patchesAccess() = meshOctree_.surface().patches();
2455 pointField& sPts = surfModifier.pointsAccess();
2456 sPts.setSize(mse.boundaryPoints().size());
2461 if( bp[pointI] < 0 )
2464 sPts[bp[pointI]] = points[pointI];
2467 //- create the triangulation of the volume mesh surface
2470 const face& bf = bFaces[bfI];
2473 tri.region() = facePatch_[bfI];
2476 for(label i=bf.size()-2;i>0;--i)
2479 tri[2] = bp[bf[i+1]];
2481 surfPtr->appendTriangle(tri);
2488 const triSurf* edgeExtractor::surfaceWithPatches(const label bpI) const
2490 //- allocate the memory for the surface mesh
2491 triSurf* surfPtr = new triSurf();
2493 //- surface of the volume mesh
2494 const meshSurfaceEngine& mse = surfaceEngine();
2495 const faceList::subList& bFaces = mse.boundaryFaces();
2496 const VRWGraph& pFaces = mse.pointFaces();
2497 const pointFieldPMG& points = mesh_.points();
2499 //- modifier of the new surface mesh
2500 triSurfModifier surfModifier(*surfPtr);
2501 surfModifier.patchesAccess() = meshOctree_.surface().patches();
2502 pointField& sPts = surfModifier.pointsAccess();
2504 //- create the triangulation of the volume mesh surface
2505 labelLongList newPointLabel(points.size(), -1);
2507 forAllRow(pFaces, bpI, pfI)
2509 const label bfI = pFaces(bpI, pfI);
2510 const face& bf = bFaces[bfI];
2513 if( newPointLabel[bf[pI]] == -1 )
2514 newPointLabel[bf[pI]] = nPoints++;
2517 tri.region() = facePatch_[bfI];
2518 tri[0] = newPointLabel[bf[0]];
2520 for(label i=bf.size()-2;i>0;--i)
2522 tri[1] = newPointLabel[bf[i]];
2523 tri[2] = newPointLabel[bf[i+1]];
2525 surfPtr->appendTriangle(tri);
2530 sPts.setSize(nPoints);
2531 forAll(newPointLabel, pointI)
2532 if( newPointLabel[pointI] != -1 )
2534 sPts[newPointLabel[pointI]] = points[pointI];
2540 void edgeExtractor::updateMeshPatches()
2542 const triSurf& surface = meshOctree_.surface();
2543 const geometricSurfacePatchList& surfPatches = surface.patches();
2544 const label nPatches = surfPatches.size();
2546 const meshSurfaceEngine& mse = this->surfaceEngine();
2547 const faceList::subList& bFaces = mse.boundaryFaces();
2548 const labelList& faceOwner = mse.faceOwners();
2550 wordList patchNames(nPatches);
2551 VRWGraph newBoundaryFaces;
2552 labelLongList newBoundaryOwners(bFaces.size());
2553 labelLongList newBoundaryPatches(bFaces.size());
2556 forAll(surface.patches(), patchI)
2557 patchNames[patchI] = surface.patches()[patchI].name();
2559 //- append boundary faces
2562 newBoundaryFaces.appendList(bFaces[bfI]);
2563 newBoundaryOwners[bfI] = faceOwner[bfI];
2564 newBoundaryPatches[bfI] = facePatch_[bfI];
2567 //- replace the boundary with the new patches
2568 polyMeshGenModifier meshModifier(mesh_);
2569 meshModifier.replaceBoundary
2577 //- set the new patch types
2578 PtrList<boundaryPatch>& boundaries = meshModifier.boundariesAccess();
2580 forAll(surfPatches, patchI)
2581 boundaries[patchI].patchType() = surfPatches[patchI].geometricType();
2584 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
2586 } // End namespace Foam
2588 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //