1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
16 cfMesh is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "demandDrivenData.H"
29 #include "meshSurfaceOptimizer.H"
30 #include "meshSurfaceEngineModifier.H"
31 #include "meshSurfaceCheckInvertedVertices.H"
32 #include "meshOctree.H"
34 #include "helperFunctionsPar.H"
35 #include "meshSurfaceMapper.H"
36 #include "meshSurfaceMapper2D.H"
37 #include "polyMeshGen2DEngine.H"
38 #include "polyMeshGenAddressing.H"
39 #include "polyMeshGenChecks.H"
40 #include "labelledPoint.H"
41 #include "FIFOStack.H"
52 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
57 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
59 label meshSurfaceOptimizer::findInvertedVertices
61 boolList& smoothVertex,
62 const label nAdditionalLayers
65 const labelList& bPoints = surfaceEngine_.boundaryPoints();
66 const VRWGraph& pPoints = surfaceEngine_.pointPoints();
68 if( smoothVertex.size() != bPoints.size() )
70 smoothVertex.setSize(bPoints.size());
74 label nInvertedTria(0);
76 //- check the vertices at the surface
77 //- mark the ones where the mesh is tangled
78 meshSurfaceCheckInvertedVertices vrtCheck(*partitionerPtr_, smoothVertex);
79 const labelHashSet& inverted = vrtCheck.invertedVertices();
84 if( inverted.found(bPoints[bpI]) )
87 smoothVertex[bpI] = true;
91 if( Pstream::parRun() )
92 reduce(nInvertedTria, sumOp<label>());
93 Info << "Number of inverted boundary faces is " << nInvertedTria << endl;
95 if( nInvertedTria == 0 )
98 //- add additional layers around inverted points
99 for(label i=0;i<nAdditionalLayers;++i)
101 boolList originallySelected = smoothVertex;
102 forAll(smoothVertex, bpI)
103 if( originallySelected[bpI] )
104 forAllRow(pPoints, bpI, ppI)
105 smoothVertex[pPoints(bpI, ppI)] = true;
107 if( Pstream::parRun() )
109 //- exchange global labels of inverted points
110 const labelList& globalPointLabel =
111 surfaceEngine_.globalBoundaryPointLabel();
112 const Map<label>& globalToLocal =
113 surfaceEngine_.globalToLocalBndPointAddressing();
114 const VRWGraph& bpAtProcs = surfaceEngine_.bpAtProcs();
115 const DynList<label>& neiProcs = surfaceEngine_.bpNeiProcs();
117 std::map<label, labelLongList> shareData;
118 forAll(neiProcs, procI)
121 std::make_pair(neiProcs[procI], labelLongList())
124 forAllConstIter(Map<label>, globalToLocal, iter)
126 const label bpI = iter();
128 if( !smoothVertex[bpI] )
131 forAllRow(bpAtProcs, bpI, procI)
133 const label neiProc = bpAtProcs(bpI, procI);
135 if( neiProc == Pstream::myProcNo() )
138 shareData[neiProc].append(globalPointLabel[bpI]);
142 //- exchange data with other processors
143 labelLongList receivedData;
144 help::exchangeMap(shareData, receivedData);
146 forAll(receivedData, j)
148 const label bpI = globalToLocal[receivedData[j]];
150 smoothVertex[bpI] = true;
155 return nInvertedTria;
158 void meshSurfaceOptimizer::smoothEdgePoints
160 const labelLongList& edgePoints,
161 const labelLongList& procEdgePoints
164 List<LongList<labelledPoint> > newPositions(1);
166 newPositions.setSize(omp_get_num_procs());
169 //- smooth edge vertices
171 # pragma omp parallel num_threads(newPositions.size())
175 LongList<labelledPoint>& newPos =
176 newPositions[omp_get_thread_num()];
178 LongList<labelledPoint>& newPos = newPositions[0];
182 # pragma omp for schedule(dynamic, 40)
184 forAll(edgePoints, i)
186 const label bpI = edgePoints[i];
188 if( vertexType_[bpI] & (PROCBND | LOCKED) )
191 newPos.append(labelledPoint(bpI, newEdgePositionLaplacian(bpI)));
195 if( Pstream::parRun() )
196 edgeNodeDisplacementParallel(procEdgePoints);
198 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
199 forAll(newPositions, threadI)
201 const LongList<labelledPoint>& newPos = newPositions[threadI];
204 surfaceModifier.moveBoundaryVertexNoUpdate
206 newPos[i].pointLabel(),
207 newPos[i].coordinates()
211 surfaceModifier.updateGeometry(edgePoints);
214 void meshSurfaceOptimizer::smoothLaplacianFC
216 const labelLongList& selectedPoints,
217 const labelLongList& selectedProcPoints,
221 List<LongList<labelledPoint> > newPositions(1);
223 newPositions.setSize(omp_get_num_procs());
227 # pragma omp parallel num_threads(newPositions.size())
231 LongList<labelledPoint>& newPos =
232 newPositions[omp_get_thread_num()];
234 LongList<labelledPoint>& newPos = newPositions[0];
238 # pragma omp for schedule(dynamic, 40)
240 forAll(selectedPoints, i)
242 const label bpI = selectedPoints[i];
244 if( vertexType_[bpI] & (PROCBND | LOCKED) )
249 labelledPoint(bpI, newPositionLaplacianFC(bpI, transform))
254 if( Pstream::parRun() )
255 nodeDisplacementLaplacianFCParallel(selectedProcPoints, transform);
257 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
260 # pragma omp parallel num_threads(newPositions.size())
264 const label threadI = omp_get_thread_num();
266 const label threadI = 0;
269 const LongList<labelledPoint>& newPos = newPositions[threadI];
272 surfaceModifier.moveBoundaryVertexNoUpdate
274 newPos[i].pointLabel(),
275 newPos[i].coordinates()
279 surfaceModifier.updateGeometry(selectedPoints);
282 void meshSurfaceOptimizer::smoothSurfaceOptimizer
284 const labelLongList& selectedPoints,
285 const labelLongList& selectedProcPoints
288 //- create partTriMesh is it is not yet present
291 //- update coordinates of the triangulation
292 updateTriMesh(selectedPoints);
294 pointField newPositions(selectedPoints.size());
297 # pragma omp parallel for schedule(dynamic, 20)
299 forAll(selectedPoints, i)
301 const label bpI = selectedPoints[i];
303 newPositions[i] = newPositionSurfaceOptimizer(bpI);
306 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
309 # pragma omp parallel for schedule(dynamic, 100)
311 forAll(newPositions, i)
313 const label bpI = selectedPoints[i];
315 surfaceModifier.moveBoundaryVertexNoUpdate(bpI, newPositions[i]);
318 //- ensure that vertices at inter-processor boundaries are at the same
319 //- location at all processors
320 surfaceModifier.syncVerticesAtParallelBoundaries(selectedProcPoints);
322 //- update geometry addressing for moved points
323 surfaceModifier.updateGeometry(selectedPoints);
326 bool meshSurfaceOptimizer::untangleSurface
328 const labelLongList& selectedBoundaryPoints,
329 const label nAdditionalLayers
332 Info << "Starting untangling the surface of the volume mesh" << endl;
336 const labelList& bPoints = surfaceEngine_.boundaryPoints();
337 const pointFieldPMG& points = surfaceEngine_.points();
338 surfaceEngine_.pointFaces();
339 surfaceEngine_.faceCentres();
340 surfaceEngine_.pointPoints();
341 surfaceEngine_.boundaryFacePatches();
342 surfaceEngine_.pointNormals();
343 surfaceEngine_.boundaryPointEdges();
345 if( Pstream::parRun() )
347 surfaceEngine_.bpAtProcs();
348 surfaceEngine_.globalToLocalBndPointAddressing();
349 surfaceEngine_.globalBoundaryPointLabel();
350 surfaceEngine_.bpNeiProcs();
353 boolList smoothVertex(bPoints.size(), false);
355 # pragma omp parallel for schedule(dynamic, 50)
357 forAll(selectedBoundaryPoints, i)
359 if( vertexType_[selectedBoundaryPoints[i]] & LOCKED )
362 smoothVertex[selectedBoundaryPoints[i]] = true;
365 meshSurfaceEngineModifier surfaceModifier(surfaceEngine_);
367 meshSurfaceMapper* mapperPtr = NULL;
369 mapperPtr = new meshSurfaceMapper(*partitionerPtr_, *octreePtr_);
371 bool remapVertex(true);
373 label nGlobalIter(0);
375 labelLongList procBndPoints, movedPoints;
376 labelLongList procEdgePoints, movedEdgePoints;
378 label minNumInverted(bPoints.size());
379 FIFOStack<label> nInvertedHistory;
380 pointField minInvertedPoints(bPoints.size());
384 label nIter(0), nAfterRefresh(0);
389 findInvertedVertices(smoothVertex, nAdditionalLayers);
391 if( nInvertedTria == 0 )
395 else if( enforceConstraints_ && !remapVertex )
398 const_cast<polyMeshGen&>(surfaceEngine_.mesh());
400 const label subsetId =
401 mesh.addPointSubset(badPointsSubsetName_);
403 forAll(smoothVertex, bpI)
404 if( smoothVertex[bpI] )
405 mesh.addPointToSubset(subsetId, bPoints[bpI]);
409 "bool meshSurfaceOptimizer::untangleSurface"
410 "(const labelLongList&, const label)"
411 ) << "Writing mesh with " << badPointsSubsetName_
412 << " subset. These points cannot be untangled"
413 << " without sacrificing geometry constraints. Exitting.."
416 returnReduce(1, sumOp<label>());
418 throw std::logic_error
420 "bool meshSurfaceOptimizer::untangleSurface"
421 "(const labelLongList&, const label)"
422 "Cannot untangle mesh!!"
426 //- find the min number of inverted points and
427 //- add the last number to the stack
428 if( nInvertedTria < minNumInverted )
430 minNumInverted = nInvertedTria;
434 # pragma omp parallel for schedule(dynamic, 100)
437 minInvertedPoints[bpI] = points[bPoints[bpI]];
440 //- count the number of iteration after the last minimum occurence
444 nInvertedHistory.push(nInvertedTria);
445 if( nInvertedHistory.size() > 2 )
446 nInvertedHistory.pop();
448 //- check if the number of inverted points reduces
449 bool minimumInStack(false);
450 forAllConstIter(FIFOStack<label>, nInvertedHistory, it)
451 if( it() == minNumInverted )
452 minimumInStack = true;
454 //- stop if the procedure does not minimise
455 //- the number of inverted points
456 if( !minimumInStack || (nAfterRefresh > 2) )
459 //- find points which will be handled by the smoothers
462 procBndPoints.clear();
464 procEdgePoints.clear();
465 movedEdgePoints.clear();
469 if( !smoothVertex[bpI] )
472 if( vertexType_[bpI] & PARTITION )
474 movedPoints.append(bpI);
476 if( vertexType_[bpI] & PROCBND )
477 procBndPoints.append(bpI);
479 else if( vertexType_[bpI] & EDGE )
481 movedEdgePoints.append(bpI);
483 if( vertexType_[bpI] & PROCBND )
484 procEdgePoints.append(bpI);
488 //- smooth edge vertices
489 smoothEdgePoints(movedEdgePoints, procEdgePoints);
490 if( remapVertex && mapperPtr )
491 mapperPtr->mapEdgeNodes(movedEdgePoints);
492 surfaceModifier.updateGeometry(movedEdgePoints);
494 //- use laplacian smoothing
495 smoothLaplacianFC(movedPoints, procBndPoints);
496 surfaceModifier.updateGeometry(movedPoints);
498 //- use surface optimizer
499 smoothSurfaceOptimizer(movedPoints, procBndPoints);
501 if( remapVertex && mapperPtr )
502 mapperPtr->mapVerticesOntoSurface(movedPoints);
504 //- update normals and other geometric data
505 surfaceModifier.updateGeometry(movedPoints);
507 } while( nInvertedTria && (++nIter < 20) );
509 if( nInvertedTria > 0 )
511 //- use the combination with the minimum number of inverted points
512 meshSurfaceEngineModifier sMod(surfaceEngine_);
513 forAll(minInvertedPoints, bpI)
514 sMod.moveBoundaryVertexNoUpdate(bpI, minInvertedPoints[bpI]);
516 sMod.updateGeometry();
521 Info << "Smoothing remaining inverted vertices " << endl;
524 procBndPoints.clear();
525 forAll(smoothVertex, bpI)
526 if( smoothVertex[bpI] )
528 movedPoints.append(bpI);
530 if( vertexType_[bpI] & PROCBND )
531 procBndPoints.append(bpI);
534 smoothLaplacianFC(movedPoints, procBndPoints, false);
536 if( remapVertex && mapperPtr )
537 mapperPtr->mapVerticesOntoSurface(movedPoints);
539 //- update normals and other geometric data
540 surfaceModifier.updateGeometry(movedPoints);
542 if( nGlobalIter > 5 )
546 } while( nInvertedTria && (++nGlobalIter < 10) );
548 deleteDemandDrivenData(mapperPtr);
550 if( nInvertedTria != 0 )
552 //- the procedure has given up without success
553 //- there exist some remaining inverted faces in the mesh
555 const_cast<polyMeshGen&>(surfaceEngine_.mesh());
557 label subsetId = mesh.pointSubsetIndex(badPointsSubsetName_);
559 mesh.removePointSubset(subsetId);
560 subsetId = mesh.addPointSubset(badPointsSubsetName_);
562 forAll(smoothVertex, bpI)
563 if( smoothVertex[bpI] )
564 mesh.addPointToSubset(subsetId, bPoints[bpI]);
567 Info << "Finished untangling the surface of the volume mesh" << endl;
572 bool meshSurfaceOptimizer::untangleSurface(const label nAdditionalLayers)
574 labelLongList selectedPts(surfaceEngine_.boundaryPoints().size());
575 forAll(selectedPts, i)
578 return untangleSurface(selectedPts, nAdditionalLayers);
581 void meshSurfaceOptimizer::optimizeSurface(const label nIterations)
583 const labelList& bPoints = surfaceEngine_.boundaryPoints();
585 //- needed for parallel execution
586 surfaceEngine_.pointFaces();
587 surfaceEngine_.faceCentres();
588 surfaceEngine_.pointPoints();
589 surfaceEngine_.boundaryPointEdges();
590 surfaceEngine_.boundaryFacePatches();
591 surfaceEngine_.pointNormals();
592 surfaceEngine_.boundaryPointEdges();
594 meshSurfaceMapper* mapperPtr = NULL;
596 mapperPtr = new meshSurfaceMapper(*partitionerPtr_, *octreePtr_);
598 labelLongList procBndPoints, edgePoints, partitionPoints, procPoints;
601 if( vertexType_[bpI] & LOCKED )
604 if( vertexType_[bpI] & EDGE )
606 edgePoints.append(bpI);
608 if( vertexType_[bpI] & PROCBND )
609 procBndPoints.append(bpI);
611 else if( vertexType_[bpI] & PARTITION )
613 partitionPoints.append(bpI);
615 if( vertexType_[bpI] & PROCBND )
616 procPoints.append(bpI);
620 //- optimize edge vertices
621 Info << "Optimizing edges. Iteration:" << flush;
622 for(label i=0;i<nIterations;++i)
624 Info << "." << flush;
626 meshSurfaceEngineModifier bMod(surfaceEngine_);
628 smoothEdgePoints(edgePoints, procBndPoints);
630 //- project vertices back onto the boundary
632 mapperPtr->mapEdgeNodes(edgePoints);
634 //- update the geometry information
635 bMod.updateGeometry(edgePoints);
639 //- delete the mapper
640 deleteDemandDrivenData(mapperPtr);
642 //- optimize positions of surface vertices which are not on surface edges
643 Info << "Optimizing surface vertices. Iteration:";
644 for(label i=0;i<nIterations;++i)
646 smoothLaplacianFC(partitionPoints, procPoints, true);
648 smoothSurfaceOptimizer(partitionPoints, procPoints);
650 Info << "." << flush;
658 void meshSurfaceOptimizer::optimizeSurface2D(const label nIterations)
660 const labelList& bPoints = surfaceEngine_.boundaryPoints();
661 const edgeList& edges = surfaceEngine_.edges();
662 const labelList& bp = surfaceEngine_.bp();
664 polyMeshGen2DEngine mesh2DEngine
666 const_cast<polyMeshGen&>(surfaceEngine_.mesh())
668 const boolList& zMinPoint = mesh2DEngine.zMinPoints();
670 //- needed for parallel execution
671 surfaceEngine_.pointFaces();
672 surfaceEngine_.faceCentres();
673 surfaceEngine_.pointPoints();
674 surfaceEngine_.boundaryPointEdges();
675 surfaceEngine_.boundaryFacePatches();
676 surfaceEngine_.pointNormals();
678 labelLongList procBndPoints, movedPoints, activeEdges, updatePoints;
681 const edge& e = edges[beI];
683 if( zMinPoint[e.start()] ^ zMinPoint[e.end()] )
685 label bpI = bp[e.start()];
686 if( !zMinPoint[e.start()] )
689 if( vertexType_[bpI] & EDGE )
691 activeEdges.append(beI);
693 updatePoints.append(bp[e.start()]);
694 updatePoints.append(bp[e.end()]);
696 movedPoints.append(bpI);
698 if( vertexType_[bpI] & PROCBND )
699 procBndPoints.append(bpI);
704 meshSurfaceMapper2D* mapperPtr = NULL;
706 mapperPtr = new meshSurfaceMapper2D(surfaceEngine_, *octreePtr_);
708 //- optimize edge vertices
709 meshSurfaceEngineModifier bMod(surfaceEngine_);
711 Info << "Optimizing edges. Iteration:" << flush;
712 for(label i=0;i<nIterations;++i)
714 Info << "." << flush;
716 smoothEdgePoints(movedPoints, procBndPoints);
718 //- move points with maximum z coordinate
719 mesh2DEngine.correctPoints();
721 //- map boundary edges to the surface
722 mapperPtr->mapVerticesOntoSurfacePatches(activeEdges);
724 //- update normal, centres, etc, after the surface has been modified
725 bMod.updateGeometry(updatePoints);
729 //- optimize Pts of surface vertices which are not on surface edges
730 procBndPoints.clear();
733 if( zMinPoint[bPoints[bpI]] && (vertexType_[bpI] & PARTITION) )
735 movedPoints.append(bpI);
737 if( vertexType_[bpI] & PROCBND )
738 procBndPoints.append(bpI);
740 Info << "Optimizing surface vertices. Iteration:";
741 for(label i=0;i<nIterations;++i)
743 Info << "." << flush;
745 smoothSurfaceOptimizer(movedPoints, procBndPoints);
747 //- move the points which are not at minimum z coordinate
748 mesh2DEngine.correctPoints();
750 //- update geometrical data due to movement of vertices
751 bMod.updateGeometry();
756 deleteDemandDrivenData(mapperPtr);
759 void meshSurfaceOptimizer::untangleSurface2D()
761 const polyMeshGen& mesh = surfaceEngine_.mesh();
762 const faceListPMG& faces = mesh.faces();
763 const VRWGraph& pointFaces = mesh.addressingData().pointFaces();
765 const labelList& bPoints = surfaceEngine_.boundaryPoints();
766 const labelList& bp = surfaceEngine_.bp();
768 polyMeshGen2DEngine mesh2DEngine(const_cast<polyMeshGen&>(mesh));
769 const boolList& zMinPoint = mesh2DEngine.zMinPoints();
770 const boolList& activeFace = mesh2DEngine.activeFace();
772 //- needed for parallel execution
773 surfaceEngine_.pointFaces();
774 surfaceEngine_.faceCentres();
775 surfaceEngine_.pointPoints();
776 surfaceEngine_.boundaryPointEdges();
777 surfaceEngine_.boundaryFacePatches();
778 surfaceEngine_.pointNormals();
780 boolList activeBoundaryPoint(bPoints.size());
781 boolList changedFace(activeFace.size(), true);
786 labelHashSet badFaces;
787 const label nBadFaces =
788 polyMeshGenChecks::findBadFaces
796 Info << "Iteration " << iterationI
797 << ". Number of bad faces " << nBadFaces << endl;
802 //- update active points and faces affected by the movement
804 activeBoundaryPoint = false;
806 forAllConstIter(labelHashSet, badFaces, it)
808 const face& f = faces[it.key()];
812 if( zMinPoint[f[pI]] )
814 activeBoundaryPoint[bp[f[pI]]] = true;
816 forAllRow(pointFaces, f[pI], pfI)
817 changedFace[pointFaces(f[pI], pfI)] = true;
822 if( Pstream::parRun() )
824 const Map<label>& globalToLocal =
825 surfaceEngine_.globalToLocalBndPointAddressing();
826 const DynList<label>& neiProcs = surfaceEngine_.bpNeiProcs();
827 const VRWGraph& bpNeiProcs = surfaceEngine_.bpAtProcs();
829 std::map<label, labelLongList> exchangeData;
831 exchangeData[neiProcs[i]].clear();
833 //- collect active points at inter-processor boundaries
834 forAllConstIter(Map<label>, globalToLocal, it)
836 const label bpI = it();
838 if( activeBoundaryPoint[bpI] )
840 forAllRow(bpNeiProcs, bpI, i)
842 const label neiProc = bpNeiProcs(bpI, i);
844 if( neiProc == Pstream::myProcNo() )
847 exchangeData[neiProc].append(it.key());
852 //- exchange active points among the processors
853 labelLongList receivedData;
854 help::exchangeMap(exchangeData, receivedData);
856 //- ensure that all processors have the same Pts active
857 forAll(receivedData, i)
859 const label bpI = globalToLocal[receivedData[i]];
861 //- activate this boundary point
862 activeBoundaryPoint[bpI] = true;
864 //- set the changeFaces for the faces attached to this point
865 forAllRow(pointFaces, bPoints[bpI], pfI)
866 changedFace[pointFaces(bPoints[bpI], pfI)] = true;
870 //- apply smoothing to the activated points
871 meshSurfaceEngineModifier bMod(surfaceEngine_);
873 labelLongList movedPts, procBndPts, edgePts, procEdgePts;
876 if( !activeBoundaryPoint[bpI] )
879 if( vertexType_[bpI] & EDGE )
883 if( vertexType_[bpI] & PROCBND )
884 procEdgePts.append(bpI);
886 else if( vertexType_[bpI] & PARTITION )
888 movedPts.append(bpI);
890 if( vertexType_[bpI] & PROCBND )
891 procBndPts.append(bpI);
895 for(label i=0;i<5;++i)
897 smoothEdgePoints(edgePts, procEdgePts);
899 bMod.updateGeometry(edgePts);
901 smoothSurfaceOptimizer(movedPts, procBndPts);
903 bMod.updateGeometry(movedPts);
906 //- move the points which are not at minimum z coordinate
907 mesh2DEngine.correctPoints();
909 //- update geometrical data due to movement of vertices
910 bMod.updateGeometry();
912 //- update cell centres and face centres
913 const_cast<polyMeshGenAddressing&>
915 mesh.addressingData()
916 ).updateGeometry(changedFace);
918 } while( ++iterationI < 20 );
920 //- delete invalid data
921 mesh.clearAddressingData();
924 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
926 } // End namespace Foam
928 // ************************************************************************* //