/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation \\/ M anipulation | Copyright (C) 2016-2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "isoSurfaceCell.H" #include "isoSurface.H" #include "dictionary.H" #include "polyMesh.H" #include "mergePoints.H" #include "tetMatcher.H" #include "syncTools.H" #include "triSurface.H" #include "triSurfaceTools.H" #include "Time.H" #include "triPoints.H" #include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(isoSurfaceCell, 0); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::scalar Foam::isoSurfaceCell::isoFraction ( const scalar s0, const scalar s1 ) const { const scalar d = s1-s0; if (mag(d) > VSMALL) { return (iso_-s0)/d; } return -1.0; } bool Foam::isoSurfaceCell::isTriCut ( const triFace& tri, const scalarField& pointValues ) const { const bool aLower = (pointValues[tri[0]] < iso_); const bool bLower = (pointValues[tri[1]] < iso_); const bool cLower = (pointValues[tri[2]] < iso_); return !(aLower == bLower && aLower == cLower); } Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType ( const bitSet& isTet, const scalarField& cellValues, const scalarField& pointValues, const label celli ) const { if (ignoreCells_.test(celli)) { return NOTCUT; } const cell& cFaces = mesh_.cells()[celli]; if (isTet.test(celli)) { for (const label facei : cFaces) { const face& f = mesh_.faces()[facei]; for (label fp = 1; fp < f.size() - 1; ++fp) { triFace tri(f[0], f[fp], f[f.fcIndex(fp)]); if (isTriCut(tri, pointValues)) { return CUT; } } } return NOTCUT; } const bool cellLower = (cellValues[celli] < iso_); // First check if there is any cut in cell bool edgeCut = false; for (const label facei : cFaces) { const face& f = mesh_.faces()[facei]; // Check pyramid edges (corner point to cell centre) for (const label pointi : f) { if (cellLower != (pointValues[pointi] < iso_)) { edgeCut = true; break; } } if (edgeCut) { break; } // Check (triangulated) face edges const label fp0 = mesh_.tetBasePtIs()[facei]; label fp = f.fcIndex(fp0); for (label i = 2; i < f.size(); ++i) { const label nextFp = f.fcIndex(fp); if (isTriCut(triFace(f[fp0], f[fp], f[nextFp]), pointValues)) { edgeCut = true; break; } fp = nextFp; } if (edgeCut) { break; } } if (edgeCut) { // Count actual cuts (expensive since addressing needed) // Note: not needed if you don't want to preserve maxima/minima // centred around cellcentre. In that case just always return CUT const labelList& cPoints = mesh_.cellPoints(celli); label nPyrEdgeCuts = 0; for (const label pointi : cPoints) { if (cellLower != (pointValues[pointi] < iso_)) { ++nPyrEdgeCuts; } } if (nPyrEdgeCuts == cPoints.size()) { return SPHERE; } else if (nPyrEdgeCuts) { // There is a pyramid edge cut. E.g. lopping off a tet from a corner return CUT; } } return NOTCUT; } void Foam::isoSurfaceCell::calcCutTypes ( const bitSet& isTet, const scalarField& cVals, const scalarField& pVals ) { cellCutType_.setSize(mesh_.nCells()); nCutCells_ = 0; // Some processor domains may require tetBasePtIs and others do not. // Do now to ensure things stay synchronized. (void)mesh_.tetBasePtIs(); forAll(mesh_.cells(), celli) { cellCutType_[celli] = calcCutType(isTet, cVals, pVals, celli); if (cellCutType_[celli] == CUT) { ++nCutCells_; } } if (debug) { Pout<< "isoSurfaceCell : candidate cut cells " << nCutCells_ << " / " << mesh_.nCells() << endl; } } Foam::labelPair Foam::isoSurfaceCell::findCommonPoints ( const labelledTri& tri0, const labelledTri& tri1 ) { labelPair common(-1, -1); label fp0 = 0; label fp1 = tri1.find(tri0[fp0]); if (fp1 == -1) { fp0 = 1; fp1 = tri1.find(tri0[fp0]); } if (fp1 != -1) { // So tri0[fp0] is tri1[fp1] // Find next common point label fp0p1 = tri0.fcIndex(fp0); label fp1p1 = tri1.fcIndex(fp1); label fp1m1 = tri1.rcIndex(fp1); if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1]) { common[0] = tri0[fp0]; common[1] = tri0[fp0p1]; } } return common; } Foam::point Foam::isoSurfaceCell::calcCentre(const triSurface& s) { vector sum = Zero; forAll(s, i) { sum += s[i].centre(s.points()); } return sum/s.size(); } Foam::pointIndexHit Foam::isoSurfaceCell::collapseSurface ( const label celli, pointField& localPoints, DynamicList& localTris ) const { pointIndexHit info(false, Zero, localTris.size()); if (localTris.size() == 1) { const labelledTri& tri = localTris[0]; info.setPoint(tri.centre(localPoints)); info.setHit(); } else if (localTris.size() == 2) { // Check if the two triangles share an edge. const labelledTri& tri0 = localTris[0]; const labelledTri& tri1 = localTris[1]; labelPair shared = findCommonPoints(tri0, tri1); if (shared[0] != -1) { const vector n0 = tri0.areaNormal(localPoints); const vector n1 = tri1.areaNormal(localPoints); // Merge any zero-sized triangles, // or if they point in the same direction. if ( mag(n0) <= ROOTVSMALL || mag(n1) <= ROOTVSMALL || (n0 & n1) >= 0 ) { info.setPoint ( 0.5 * ( tri0.centre(localPoints) + tri1.centre(localPoints) ) ); info.setHit(); } } } else if (localTris.size()) { // Check if single region. Rare situation. triSurface surf ( localTris, geometricSurfacePatchList(0), localPoints, true ); localTris.clearStorage(); labelList faceZone; label nZones = surf.markZones ( boolList(surf.nEdges(), false), faceZone ); if (nZones == 1) { // Check that all normals make a decent angle scalar minCos = GREAT; const vector& n0 = surf.faceNormals()[0]; for (label i = 1; i < surf.size(); ++i) { scalar cosAngle = (n0 & surf.faceNormals()[i]); if (cosAngle < minCos) { minCos = cosAngle; } } if (minCos > 0) { info.setPoint(calcCentre(surf)); info.setHit(); } } } return info; } void Foam::isoSurfaceCell::calcSnappedCc ( const bitSet& isTet, const scalarField& cVals, const scalarField& pVals, DynamicList& snappedPoints, labelList& snappedCc ) const { const pointField& cc = mesh_.cellCentres(); const pointField& pts = mesh_.points(); snappedCc.setSize(mesh_.nCells()); snappedCc = -1; // Work arrays DynamicList localPoints(64); DynamicList localTris(64); Map