/*---------------------------------------------------------------------------*\
========= |
\\ / 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