From c81abfef05e37eafff890ea9f87966f51e1f8772 Mon Sep 17 00:00:00 2001 From: Henry Weller Date: Fri, 8 Feb 2019 14:45:54 +0000 Subject: [PATCH] isoSurface: Fix for isoSurface 'eroding' surfaces down to nothing The occurrence is from cells with vertices that are shared between two faces only (these vertices can originate from hex refinement). Decomposing both faces can occasionally produce triangles with identical vertices and this results in a non-manifold edge which triggers the erosion procedure. Avoided by detecting cells with these special vertices and making sure the tet-decomposition never uses the same points on the faces using them. Patch contributed by Mattijs Janssens --- .../polyMeshTetDecomposition.C | 141 +++++----- .../polyMeshTetDecomposition.H | 13 +- .../sampledSurface/isoSurface/isoSurface.C | 250 ++++++++++++++++-- .../sampledSurface/isoSurface/isoSurface.H | 14 +- 4 files changed, 304 insertions(+), 114 deletions(-) diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C index f68bbd476c..3ff3071a77 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C +++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -35,6 +35,59 @@ const Foam::scalar Foam::polyMeshTetDecomposition::minTetQuality = sqr(small); // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // +Foam::scalar Foam::polyMeshTetDecomposition::minQuality +( + const polyMesh& mesh, + const point& cC, + const label fI, + const bool isOwner, + const label faceBasePtI +) +{ + // Does fan decomposition of face (starting at faceBasePti) and determines + // min quality over all resulting tets. + + const pointField& pPts = mesh.points(); + const face& f = mesh.faces()[fI]; + const point& tetBasePt = pPts[f[faceBasePtI]]; + + scalar thisBaseMinTetQuality = vGreat; + + for (label tetPtI = 1; tetPtI < f.size() - 1; tetPtI++) + { + label facePtI = (tetPtI + faceBasePtI) % f.size(); + label otherFacePtI = f.fcIndex(facePtI); + + label ptAI = -1; + label ptBI = -1; + + if (isOwner) + { + ptAI = f[facePtI]; + ptBI = f[otherFacePtI]; + } + else + { + ptAI = f[otherFacePtI]; + ptBI = f[facePtI]; + } + + const point& pA = pPts[ptAI]; + const point& pB = pPts[ptBI]; + + tetPointRef tet(cC, tetBasePt, pA, pB); + + scalar tetQuality = tet.quality(); + + if (tetQuality < thisBaseMinTetQuality) + { + thisBaseMinTetQuality = tetQuality; + } + } + return thisBaseMinTetQuality; +} + + Foam::label Foam::polyMeshTetDecomposition::findSharedBasePoint ( const polyMesh& mesh, @@ -45,7 +98,6 @@ Foam::label Foam::polyMeshTetDecomposition::findSharedBasePoint ) { const faceList& pFaces = mesh.faces(); - const pointField& pPts = mesh.points(); const vectorField& pC = mesh.cellCentres(); const labelList& pOwner = mesh.faceOwner(); @@ -55,52 +107,12 @@ Foam::label Foam::polyMeshTetDecomposition::findSharedBasePoint const point& oCc = pC[oCI]; - List tetQualities(2, 0.0); - forAll(f, faceBasePtI) { - scalar thisBaseMinTetQuality = vGreat; + scalar minQ = minQuality(mesh, oCc, fI, true, faceBasePtI); + minQ = min(minQ, minQuality(mesh, nCc, fI, false, faceBasePtI)); - const point& tetBasePt = pPts[f[faceBasePtI]]; - - for (label tetPtI = 1; tetPtI < f.size() - 1; tetPtI++) - { - label facePtI = (tetPtI + faceBasePtI) % f.size(); - label otherFacePtI = f.fcIndex(facePtI); - - { - // owner cell tet - label ptAI = f[facePtI]; - label ptBI = f[otherFacePtI]; - - const point& pA = pPts[ptAI]; - const point& pB = pPts[ptBI]; - - tetPointRef tet(oCc, tetBasePt, pA, pB); - - tetQualities[0] = tet.quality(); - } - - { - // neighbour cell tet - label ptAI = f[otherFacePtI]; - label ptBI = f[facePtI]; - - const point& pA = pPts[ptAI]; - const point& pB = pPts[ptBI]; - - tetPointRef tet(nCc, tetBasePt, pA, pB); - - tetQualities[1] = tet.quality(); - } - - if (min(tetQualities) < thisBaseMinTetQuality) - { - thisBaseMinTetQuality = min(tetQualities); - } - } - - if (thisBaseMinTetQuality > tol) + if (minQ > tol) { return faceBasePtI; } @@ -140,7 +152,6 @@ Foam::label Foam::polyMeshTetDecomposition::findBasePoint ) { const faceList& pFaces = mesh.faces(); - const pointField& pPts = mesh.points(); const vectorField& pC = mesh.cellCentres(); const labelList& pOwner = mesh.faceOwner(); @@ -154,43 +165,9 @@ Foam::label Foam::polyMeshTetDecomposition::findBasePoint forAll(f, faceBasePtI) { - scalar thisBaseMinTetQuality = vGreat; + scalar quality = minQuality(mesh, cC, fI, own, faceBasePtI); - const point& tetBasePt = pPts[f[faceBasePtI]]; - - for (label tetPtI = 1; tetPtI < f.size() - 1; tetPtI++) - { - label facePtI = (tetPtI + faceBasePtI) % f.size(); - label otherFacePtI = f.fcIndex(facePtI); - - label ptAI = -1; - label ptBI = -1; - - if (own) - { - ptAI = f[facePtI]; - ptBI = f[otherFacePtI]; - } - else - { - ptAI = f[otherFacePtI]; - ptBI = f[facePtI]; - } - - const point& pA = pPts[ptAI]; - const point& pB = pPts[ptBI]; - - tetPointRef tet(cC, tetBasePt, pA, pB); - - scalar tetQuality = tet.quality(); - - if (tetQuality < thisBaseMinTetQuality) - { - thisBaseMinTetQuality = tetQuality; - } - } - - if (thisBaseMinTetQuality > tol) + if (quality > tol) { return faceBasePtI; } diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H index 1b8b55f343..03c7b9d7a2 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H +++ b/src/OpenFOAM/meshes/polyMesh/polyMeshTetDecomposition/polyMeshTetDecomposition.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -67,6 +67,17 @@ public: // Member Functions + //- Given a face and cc and starting index for triangulation determine + // the worst tet quality. + static scalar minQuality + ( + const polyMesh& mesh, + const point& cC, + const label fI, + const bool isOwner, + const label faceBasePtI + ); + //- Find the first suitable base point to use for a minimum // triangle decomposition of the face, suiting owner and // neighbour cells. Finds the first base point on the face diff --git a/src/sampling/sampledSurface/isoSurface/isoSurface.C b/src/sampling/sampledSurface/isoSurface/isoSurface.C index 94d15f1a7a..9f86c30572 100644 --- a/src/sampling/sampledSurface/isoSurface/isoSurface.C +++ b/src/sampling/sampledSurface/isoSurface/isoSurface.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | Website: https://openfoam.org - \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -28,6 +28,8 @@ License #include "tetMatcher.H" #include "tetPointRef.H" #include "DynamicField.H" +#include "syncTools.H" +#include "polyMeshTetDecomposition.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -106,7 +108,14 @@ Foam::isoSurface::cellCutType Foam::isoSurface::calcCutType break; } - const label fp0 = mesh_.tetBasePtIs()[facei]; + label fp0 = tetBasePtIs_[facei]; + + // Fall back for problem decompositions + if (fp0 < 0) + { + fp0 = 0; + } + label fp = f.fcIndex(fp0); for (label i = 2; i < f.size(); i++) { @@ -191,6 +200,184 @@ Foam::label Foam::isoSurface::calcCutTypes } +Foam::scalar Foam::isoSurface::minTetQ +( + const label facei, + const label faceBasePtI +) const +{ + scalar q = polyMeshTetDecomposition::minQuality + ( + mesh_, + mesh_.cellCentres()[mesh_.faceOwner()[facei]], + facei, + true, + faceBasePtI + ); + + if (mesh_.isInternalFace(facei)) + { + q = min + ( + q, + polyMeshTetDecomposition::minQuality + ( + mesh_, + mesh_.cellCentres()[mesh_.faceNeighbour()[facei]], + facei, + false, + faceBasePtI + ) + ); + } + return q; +} + + +void Foam::isoSurface::fixTetBasePtIs() +{ + // Determine points used by two faces on the same cell + const cellList& cells = mesh_.cells(); + const faceList& faces = mesh_.faces(); + const labelList& faceOwner = mesh_.faceOwner(); + const labelList& faceNeighbour = mesh_.faceNeighbour(); + + + // Get face triangulation base point + tetBasePtIs_ = mesh_.tetBasePtIs(); + + + // Pre-filter: mark all cells with illegal base points + labelHashSet problemCells(cells.size()/128); + forAll(tetBasePtIs_, facei) + { + if (tetBasePtIs_[facei] == -1) + { + problemCells.insert(faceOwner[facei]); + if (mesh_.isInternalFace(facei)) + { + problemCells.insert(faceNeighbour[facei]); + } + } + } + + + label nAdapted = 0; + + + // Number of times a point occurs in a cell. Used to detect dangling + // vertices (count = 2) + Map