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 \*---------------------------------------------------------------------------*/
30 #include "demandDrivenData.H"
31 #include "meshOptimizer.H"
32 #include "polyMeshGenAddressing.H"
33 #include "polyMeshGenChecks.H"
34 #include "partTetMesh.H"
37 #include "tetMeshOptimisation.H"
38 #include "boundaryLayerOptimisation.H"
39 #include "refineBoundaryLayers.H"
40 #include "meshSurfaceEngine.H"
45 #include "helperFunctions.H"
46 #include "polyMeshGenModifier.H"
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
54 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56 void meshOptimizer::untangleMeshFV
58 const label maxNumGlobalIterations,
59 const label maxNumIterations,
60 const label maxNumSurfaceIterations,
61 const bool relaxedCheck
64 Info << "Starting untangling the mesh" << endl;
67 partTetMesh tm(mesh_);
68 forAll(tm.tets(), tetI)
69 if( tm.tets()[tetI].mag(tm.points()) < 0.0 )
70 Info << "Tet " << tetI << " is inverted!" << endl;
71 polyMeshGen tetPolyMesh(mesh_.returnTime());
72 tm.createPolyMesh(tetPolyMesh);
73 polyMeshGenModifier(tetPolyMesh).removeUnusedVertices();
74 forAll(tm.smoothVertex(), pI)
75 if( !tm.smoothVertex()[pI] )
76 Info << "Point " << pI << " cannot be moved!" << endl;
78 const VRWGraph& pTets = tm.pointTets();
81 const LongList<partTet>& tets = tm.tets();
82 forAllRow(pTets, pointI, i)
83 if( tets[pTets(pointI, i)].whichPosition(pointI) < 0 )
84 FatalError << "Wrong partTet" << abort(FatalError);
86 partTetMeshSimplex simplex(tm, pointI);
89 boolList boundaryVertex(tetPolyMesh.points().size(), false);
90 const labelList& neighbour = tetPolyMesh.neighbour();
91 forAll(neighbour, faceI)
92 if( neighbour[faceI] == -1 )
94 const face& f = tetPolyMesh.faces()[faceI];
97 boundaryVertex[f[pI]] = true;
100 forAll(boundaryVertex, pI)
102 if( boundaryVertex[pI] && tm.smoothVertex()[pI] )
105 "void meshOptimizer::untangleMeshFV()"
106 ) << "Boundary vertex should not be moved!" << abort(FatalError);
110 label nBadFaces, nGlobalIter(0), nIter;
112 const faceListPMG& faces = mesh_.faces();
114 boolList changedFace(faces.size(), true);
116 //- check if any points in the tet mesh shall not move
117 labelLongList lockedPoints;
118 forAll(vertexLocation_, pointI)
120 if( vertexLocation_[pointI] & LOCKED )
121 lockedPoints.append(pointI);
124 labelHashSet badFaces;
130 label minNumBadFaces(10 * faces.size()), minIter(-1);
136 polyMeshGenChecks::findBadFaces
147 polyMeshGenChecks::findBadFacesRelaxed
156 Info << "Iteration " << nIter
157 << ". Number of bad faces is " << nBadFaces << endl;
159 //- perform optimisation
163 if( nBadFaces < minNumBadFaces )
165 minNumBadFaces = nBadFaces;
169 //- create a tet mesh from the mesh and the labels of bad faces
175 (nGlobalIter / 2) + 1
178 //- construct tetMeshOptimisation and improve positions of
179 //- points in the tet mesh
180 tetMeshOptimisation tmo(tetMesh);
182 tmo.optimiseUsingKnuppMetric();
184 tmo.optimiseUsingMeshUntangler();
186 tmo.optimiseUsingVolumeOptimizer();
188 //- update points in the mesh from the coordinates in the tet mesh
189 tetMesh.updateOrigMesh(&changedFace);
191 } while( (nIter < minIter+5) && (++nIter < maxNumIterations) );
193 if( (nBadFaces == 0) || (++nGlobalIter >= maxNumGlobalIterations) )
196 // move boundary vertices
199 while( nIter++ < maxNumSurfaceIterations );
204 polyMeshGenChecks::findBadFaces
215 polyMeshGenChecks::findBadFacesRelaxed
224 Info << "Iteration " << nIter
225 << ". Number of bad faces is " << nBadFaces << endl;
227 //- perform optimisation
232 else if( enforceConstraints_ )
234 const label subsetId =
235 mesh_.addPointSubset(badPointsSubsetName_);
237 forAllConstIter(labelHashSet, badFaces, it)
239 const face& f = faces[it.key()];
241 mesh_.addPointToSubset(subsetId, f[pI]);
246 "void meshOptimizer::untangleMeshFV()"
247 ) << "Writing mesh with " << badPointsSubsetName_
248 << " subset. These points cannot be untangled"
249 << " without sacrificing geometry constraints. Exitting.."
252 returnReduce(1, sumOp<label>());
253 throw std::logic_error
255 "void meshOptimizer::untangleMeshFV()"
256 "Cannot untangle mesh!!"
260 //- create tethrahedral mesh from the cells which shall be smoothed
261 partTetMesh tetMesh(mesh_, lockedPoints, badFaces, 0);
263 //- contruct tetMeshOptimisation
264 tetMeshOptimisation tmo(tetMesh);
266 if( nGlobalIter < 2 )
268 //- the point stays in the plane determined by the point normal
269 tmo.optimiseBoundaryVolumeOptimizer(true);
271 else if( nGlobalIter < 5 )
273 //- move points without any constraints on the movement
274 tmo.optimiseBoundarySurfaceLaplace();
278 //- move boundary points without any constraints
279 tmo.optimiseBoundaryVolumeOptimizer(false);
282 tetMesh.updateOrigMesh(&changedFace);
286 } while( nBadFaces );
290 label subsetId = mesh_.faceSubsetIndex("badFaces");
292 mesh_.removeFaceSubset(subsetId);
293 subsetId = mesh_.addFaceSubset("badFaces");
295 forAllConstIter(labelHashSet, badFaces, it)
296 mesh_.addFaceToSubset(subsetId, it.key());
299 Info << "Finished untangling the mesh" << endl;
302 void meshOptimizer::optimizeBoundaryLayer(const bool addBufferLayer)
304 if( mesh_.returnTime().foundObject<IOdictionary>("meshDict") )
306 const dictionary& meshDict =
307 mesh_.returnTime().lookupObject<IOdictionary>("meshDict");
309 bool smoothLayer(false);
311 if( meshDict.found("boundaryLayers") )
313 const dictionary& layersDict = meshDict.subDict("boundaryLayers");
315 if( layersDict.found("optimiseLayer") )
316 smoothLayer = readBool(layersDict.lookup("optimiseLayer"));
324 //- create a buffer layer which will not be modified by the smoother
325 refineBoundaryLayers refLayers(mesh_);
327 refineBoundaryLayers::readSettings(meshDict, refLayers);
329 refLayers.activateSpecialMode();
331 refLayers.refineLayers();
334 calculatePointLocations();
337 Info << "Starting optimising boundary layer" << endl;
339 const meshSurfaceEngine& mse = meshSurface();
340 const labelList& faceOwner = mse.faceOwners();
342 boundaryLayerOptimisation optimiser(mesh_, mse);
344 boundaryLayerOptimisation::readSettings(meshDict, optimiser);
346 optimiser.optimiseLayer();
348 //- check if the bnd layer is tangled somewhere
349 labelLongList bndLayerCells;
350 const boolList& baseFace = optimiser.isBaseFace();
353 const label blCellsId = mesh_.addCellSubset("blCells");
356 forAll(baseFace, bfI)
360 bndLayerCells.append(faceOwner[bfI]);
363 mesh_.addCellToSubset(blCellsId, faceOwner[bfI]);
369 mesh_.clearAddressingData();
371 //- lock boundary layer points, faces and cells
372 lockCells(bndLayerCells);
375 pointField origPoints(mesh_.points().size());
376 forAll(origPoints, pI)
377 origPoints[pI] = mesh_.points()[pI];
380 //- optimize mesh quality
381 optimizeMeshFV(5, 1, 50, 0);
383 //- untangle remaining faces and lock the boundary layer cells
384 untangleMeshFV(2, 50, 0);
387 forAll(vertexLocation_, pI)
389 if( vertexLocation_[pI] & LOCKED )
391 if( mag(origPoints[pI] - mesh_.points()[pI]) > SMALL )
392 FatalError << "Locked points were moved"
393 << abort(FatalError);
398 //- unlock bnd layer points
399 removeUserConstraints();
401 Info << "Finished optimising boundary layer" << endl;
405 void meshOptimizer::untangleBoundaryLayer()
407 bool untangleLayer(true);
408 if( mesh_.returnTime().foundObject<IOdictionary>("meshDict") )
410 const dictionary& meshDict =
411 mesh_.returnTime().lookupObject<IOdictionary>("meshDict");
413 if( meshDict.found("boundaryLayers") )
415 const dictionary& layersDict = meshDict.subDict("boundaryLayers");
417 if( layersDict.found("untangleLayers") )
420 readBool(layersDict.lookup("untangleLayers"));
427 labelHashSet badFaces;
428 polyMeshGenChecks::checkFacePyramids(mesh_, false, VSMALL, &badFaces);
430 const label nInvalidFaces =
431 returnReduce(badFaces.size(), sumOp<label>());
433 if( nInvalidFaces != 0 )
435 const labelList& owner = mesh_.owner();
436 const labelList& neighbour = mesh_.neighbour();
438 const label badBlCellsId =
439 mesh_.addCellSubset("invalidBoundaryLayerCells");
441 forAllConstIter(labelHashSet, badFaces, it)
443 mesh_.addCellToSubset(badBlCellsId, owner[it.key()]);
445 if( neighbour[it.key()] < 0 )
448 mesh_.addCellToSubset(badBlCellsId, neighbour[it.key()]);
451 returnReduce(1, sumOp<label>());
453 throw std::logic_error
455 "void meshOptimizer::untangleBoundaryLayer()"
456 "Found invalid faces in the boundary layer."
457 " Cannot untangle mesh!!"
463 optimizeLowQualityFaces();
464 removeUserConstraints();
465 untangleMeshFV(2, 50, 1, true);
469 void meshOptimizer::optimizeLowQualityFaces(const label maxNumIterations)
471 label nBadFaces, nIter(0);
473 const faceListPMG& faces = mesh_.faces();
474 boolList changedFace(faces.size(), true);
476 //- check if any points in the tet mesh shall not move
477 labelLongList lockedPoints;
478 forAll(vertexLocation_, pointI)
480 if( vertexLocation_[pointI] & LOCKED )
481 lockedPoints.append(pointI);
486 labelHashSet lowQualityFaces;
488 polyMeshGenChecks::findLowQualityFaces
497 forAllConstIter(labelHashSet, lowQualityFaces, it)
498 changedFace[it.key()] = true;
500 Info << "Iteration " << nIter
501 << ". Number of bad faces is " << nBadFaces << endl;
503 //- perform optimisation
507 partTetMesh tetMesh(mesh_, lockedPoints, lowQualityFaces, 2);
509 //- construct tetMeshOptimisation and improve positions
510 //- of points in the tet mesh
511 tetMeshOptimisation tmo(tetMesh);
513 tmo.optimiseUsingVolumeOptimizer();
515 //- update points in the mesh from the new coordinates in the tet mesh
516 tetMesh.updateOrigMesh(&changedFace);
518 } while( ++nIter < maxNumIterations );
521 void meshOptimizer::optimizeMeshNearBoundaries
523 const label maxNumIterations,
524 const label numLayersOfCells
529 const faceListPMG& faces = mesh_.faces();
530 boolList changedFace(faces.size(), true);
532 //- check if any points in the tet mesh shall not move
533 labelLongList lockedPoints;
534 forAll(vertexLocation_, pointI)
536 if( vertexLocation_[pointI] & LOCKED )
537 lockedPoints.append(pointI);
540 partTetMesh tetMesh(mesh_, lockedPoints, numLayersOfCells);
541 tetMeshOptimisation tmo(tetMesh);
542 Info << "Iteration:" << flush;
545 tmo.optimiseUsingVolumeOptimizer(1);
547 tetMesh.updateOrigMesh(&changedFace);
549 Info << "." << flush;
551 } while( ++nIter < maxNumIterations );
556 void meshOptimizer::optimizeMeshFV
558 const label numLaplaceIterations,
559 const label maxNumGlobalIterations,
560 const label maxNumIterations,
561 const label maxNumSurfaceIterations
564 Info << "Starting smoothing the mesh" << endl;
566 laplaceSmoother lps(mesh_, vertexLocation_);
567 lps.optimizeLaplacianPC(numLaplaceIterations);
571 maxNumGlobalIterations,
573 maxNumSurfaceIterations
576 Info << "Finished smoothing the mesh" << endl;
579 void meshOptimizer::optimizeMeshFVBestQuality
581 const label maxNumIterations,
582 const scalar threshold
585 label nBadFaces, nIter(0);
588 const faceListPMG& faces = mesh_.faces();
589 boolList changedFace(faces.size(), true);
591 //- check if any points in the tet mesh shall not move
592 labelLongList lockedPoints;
593 forAll(vertexLocation_, pointI)
595 if( vertexLocation_[pointI] & LOCKED )
596 lockedPoints.append(pointI);
599 label minNumBadFaces(10 * faces.size());
602 labelHashSet lowQualityFaces;
604 polyMeshGenChecks::findWorstQualityFaces
614 forAllConstIter(labelHashSet, lowQualityFaces, it)
615 changedFace[it.key()] = true;
617 Info << "Iteration " << nIter
618 << ". Number of worst quality faces is " << nBadFaces << endl;
620 //- perform optimisation
624 if( nBadFaces < minNumBadFaces )
626 minNumBadFaces = nBadFaces;
628 //- update the iteration number when the minimum is achieved
632 partTetMesh tetMesh(mesh_, lockedPoints, lowQualityFaces, 2);
634 //- construct tetMeshOptimisation and improve positions
635 //- of points in the tet mesh
636 tetMeshOptimisation tmo(tetMesh);
638 tmo.optimiseUsingVolumeOptimizer(20);
640 //- update points in the mesh from the new coordinates in the tet mesh
641 tetMesh.updateOrigMesh(&changedFace);
643 } while( (nIter < minIter+5) && (++nIter < maxNumIterations) );
646 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
648 } // End namespace Foam
650 // ************************************************************************* //