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 "meshOptimizer.H"
30 #include "polyMeshGenAddressing.H"
31 #include "partTetMesh.H"
34 #include "tetMeshOptimisation.H"
39 #include "helperFunctions.H"
40 #include "polyMeshGenModifier.H"
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 void meshOptimizer::untangleMeshFV()
52 Info << "Starting untangling the mesh" << endl;
55 partTetMesh tm(mesh_);
56 forAll(tm.tets(), tetI)
57 if( tm.tets()[tetI].mag(tm.points()) < 0.0 )
58 Info << "Tet " << tetI << " is inverted!" << endl;
59 polyMeshGen tetPolyMesh(mesh_.returnTime());
60 tm.createPolyMesh(tetPolyMesh);
61 polyMeshGenModifier(tetPolyMesh).removeUnusedVertices();
62 forAll(tm.smoothVertex(), pI)
63 if( !tm.smoothVertex()[pI] )
64 Info << "Point " << pI << " cannot be moved!" << endl;
66 const VRWGraph& pTets = tm.pointTets();
69 const LongList<partTet>& tets = tm.tets();
70 forAllRow(pTets, pointI, i)
71 if( tets[pTets(pointI, i)].whichPosition(pointI) < 0 )
72 FatalError << "Wrong partTet" << abort(FatalError);
74 partTetMeshSimplex simplex(tm, pointI);
77 boolList boundaryVertex(tetPolyMesh.points().size(), false);
78 const labelList& neighbour = tetPolyMesh.neighbour();
79 forAll(neighbour, faceI)
80 if( neighbour[faceI] == -1 )
82 const face& f = tetPolyMesh.faces()[faceI];
85 boundaryVertex[f[pI]] = true;
88 forAll(boundaryVertex, pI)
90 if( boundaryVertex[pI] && tm.smoothVertex()[pI] )
93 "void meshOptimizer::untangleMeshFV()"
94 ) << "Boundary vertex should not be moved!" << abort(FatalError);
98 label nBadFaces, nGlobalIter(0), nIter;
99 const label maxNumGlobalIterations(10);
101 const faceListPMG& faces = mesh_.faces();
102 boolList changedFace(faces.size(), true);
104 labelHashSet badFaces;
110 label minNumBadFaces(10 * faces.size()), minIter(-1);
113 nBadFaces = findBadFaces(badFaces, changedFace);
115 Info << "Iteration " << nIter
116 << ". Number of bad faces is " << nBadFaces << endl;
118 //- perform optimisation
122 if( nBadFaces < minNumBadFaces )
124 minNumBadFaces = nBadFaces;
128 partTetMesh tetMesh(mesh_, badFaces, (nGlobalIter / 5) + 1);
130 tetMeshOptimisation tmo(tetMesh);
132 tmo.optimiseUsingKnuppMetric();
134 tmo.optimiseUsingMeshUntangler();
136 tmo.optimiseUsingVolumeOptimizer();
138 tetMesh.updateOrigMesh(&changedFace);
140 } while( (nIter < minIter+5) && (++nIter < 50) );
142 if( (nBadFaces == 0) || (++nGlobalIter >= maxNumGlobalIterations) )
145 // move boundary vertices
150 nBadFaces = findBadFaces(badFaces, changedFace);
152 Info << "Iteration " << nIter
153 << ". Number of bad faces is " << nBadFaces << endl;
155 //- perform optimisation
159 partTetMesh tetMesh(mesh_, badFaces, 0);
160 tetMeshOptimisation tmo(tetMesh);
162 if( nGlobalIter < 2 )
164 //- the point stays in the plane determined by the point normal
165 tmo.optimiseBoundaryVolumeOptimizer(true);
167 else if( nGlobalIter < 5 )
169 //- move points without any constraints on the movement
170 tmo.optimiseBoundarySurfaceLaplace();
174 //- move boundary points without any constraints
175 tmo.optimiseBoundaryVolumeOptimizer(false);
178 tetMesh.updateOrigMesh(&changedFace);
180 } while( ++nIter < 2 );
184 Info << "Finished untangling the mesh" << endl;
187 void meshOptimizer::optimizeLowQualityFaces()
189 label nBadFaces, nIter(0);
191 const faceListPMG& faces = mesh_.faces();
192 boolList changedFace(faces.size(), true);
194 label minNumBadFaces(10 * faces.size()), minIter(-1);
197 labelHashSet lowQualityFaces;
198 nBadFaces = findLowQualityFaces(lowQualityFaces, changedFace);
201 forAllConstIter(labelHashSet, lowQualityFaces, it)
202 changedFace[it.key()] = true;
204 Info << "Iteration " << nIter
205 << ". Number of bad faces is " << nBadFaces << endl;
207 //- perform optimisation
211 if( nBadFaces < minNumBadFaces )
213 minNumBadFaces = nBadFaces;
217 partTetMesh tetMesh(mesh_, lowQualityFaces, 2);
219 tetMeshOptimisation tmo(tetMesh);
221 tmo.optimiseUsingKnuppMetric();
223 tmo.optimiseUsingMeshUntangler();
225 tmo.optimiseUsingVolumeOptimizer();
227 tetMesh.updateOrigMesh(&changedFace);
229 } while( (nIter < minIter+2) && (++nIter < 10) );
232 void meshOptimizer::optimizeMeshFV()
234 Info << "Starting smoothing the mesh" << endl;
236 laplaceSmoother lps(mesh_, vertexLocation_);
237 lps.optimizeLaplacianPC(5);
241 Info << "Finished smoothing the mesh" << endl;
244 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
246 } // End namespace Foam
248 // ************************************************************************* //