/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- 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 "cellClassification.H" #include "triSurfaceSearch.H" #include "indexedOctree.H" #include "treeDataFace.H" #include "meshSearch.H" #include "cellInfo.H" #include "polyMesh.H" #include "MeshWave.H" #include "ListOps.H" #include "meshTools.H" #include "cpuTime.H" #include "globalMeshData.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // defineTypeNameAndDebug(Foam::cellClassification, 0); // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::label Foam::cellClassification::count ( const labelList& elems, const label elem ) { label cnt = 0; forAll(elems, elemI) { if (elems[elemI] == elem) { cnt++; } } return cnt; } // Mark all faces that are cut by the surface. Two pass: // Pass1: mark all mesh edges that intersect surface (quick since triangle // pierce test). // Pass2: Check for all point neighbours of these faces whether any of their // faces are pierced. Foam::boolList Foam::cellClassification::markFaces ( const triSurfaceSearch& search ) const { cpuTime timer; boolList cutFace(mesh_.nFaces(), false); label nCutFaces = 0; // Intersect mesh edges with surface (is fast) and mark all faces that // use edge. forAll(mesh_.edges(), edgeI) { if (debug && (edgeI % 10000 == 0)) { Pout<< "Intersecting mesh edge " << edgeI << " with surface" << endl; } const edge& e = mesh_.edges()[edgeI]; const point& p0 = mesh_.points()[e.start()]; const point& p1 = mesh_.points()[e.end()]; pointIndexHit pHit(search.tree().findLineAny(p0, p1)); if (pHit.hit()) { const labelList& myFaces = mesh_.edgeFaces()[edgeI]; forAll(myFaces, myFaceI) { label faceI = myFaces[myFaceI]; if (!cutFace[faceI]) { cutFace[faceI] = true; nCutFaces++; } } } } if (debug) { Pout<< "Intersected edges of mesh with surface in = " << timer.cpuTimeIncrement() << " s\n" << endl << endl; } // // Construct octree on faces that have not yet been marked as cut // labelList allFaces(mesh_.nFaces() - nCutFaces); label allFaceI = 0; forAll(cutFace, faceI) { if (!cutFace[faceI]) { allFaces[allFaceI++] = faceI; } } if (debug) { Pout<< "Testing " << allFaceI << " faces for piercing by surface" << endl; } treeBoundBox allBb(mesh_.points()); // Extend domain slightly (also makes it 3D if was 2D) scalar tol = 1e-6 * allBb.avgDim(); point& bbMin = allBb.min(); bbMin.x() -= tol; bbMin.y() -= tol; bbMin.z() -= tol; point& bbMax = allBb.max(); bbMax.x() += 2*tol; bbMax.y() += 2*tol; bbMax.z() += 2*tol; indexedOctree faceTree ( treeDataFace(false, mesh_, allFaces), allBb, // overall search domain 8, // maxLevel 10, // leafsize 3.0 // duplicity ); const triSurface& surf = search.surface(); const edgeList& edges = surf.edges(); const pointField& localPoints = surf.localPoints(); label nAddFaces = 0; forAll(edges, edgeI) { if (debug && (edgeI % 10000 == 0)) { Pout<< "Intersecting surface edge " << edgeI << " with mesh faces" << endl; } const edge& e = edges[edgeI]; const point& start = localPoints[e.start()]; const point& end = localPoints[e.end()]; vector edgeNormal(end - start); const scalar edgeMag = mag(edgeNormal); const vector smallVec = 1e-9*edgeNormal; edgeNormal /= edgeMag+VSMALL; // Current start of pierce test point pt = start; while (true) { pointIndexHit pHit(faceTree.findLine(pt, end)); if (!pHit.hit()) { break; } else { label faceI = faceTree.shapes().faceLabels()[pHit.index()]; if (!cutFace[faceI]) { cutFace[faceI] = true; nAddFaces++; } // Restart from previous endpoint pt = pHit.hitPoint() + smallVec; if (((pt-start) & edgeNormal) >= edgeMag) { break; } } } } if (debug) { Pout<< "Detected an additional " << nAddFaces << " faces cut" << endl; Pout<< "Intersected edges of surface with mesh faces in = " << timer.cpuTimeIncrement() << " s\n" << endl << endl; } return cutFace; } // Determine faces cut by surface and use to divide cells into types. See // cellInfo. All cells reachable from outsidePts are considered to be of type // 'outside' void Foam::cellClassification::markCells ( const meshSearch& queryMesh, const boolList& piercedFace, const pointField& outsidePts ) { // Use meshwave to partition mesh, starting from outsidePt // Construct null; sets type to NOTSET List cellInfoList(mesh_.nCells()); // Mark cut cells first forAll(piercedFace, faceI) { if (piercedFace[faceI]) { cellInfoList[mesh_.faceOwner()[faceI]] = cellInfo(cellClassification::CUT); if (mesh_.isInternalFace(faceI)) { cellInfoList[mesh_.faceNeighbour()[faceI]] = cellInfo(cellClassification::CUT); } } } // // Mark cells containing outside points as being outside // // Coarse guess number of faces labelHashSet outsideFacesMap(outsidePts.size() * 6 * 2); forAll(outsidePts, outsidePtI) { // Use linear search for points. label cellI = queryMesh.findCell(outsidePts[outsidePtI], -1, false); if (returnReduce(cellI, maxOp