This repository has been archived on 2023-11-20. You can view files and clone it, but cannot push or open issues or pull requests.
foam-extend4.1-coherent-io/applications/utilities/mesh/advanced/selectCells/selectCells.C

520 lines
14 KiB
C++
Raw Normal View History

/*---------------------------------------------------------------------------*\
========= |
2013-12-11 16:09:41 +00:00
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 4.1
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
-------------------------------------------------------------------------------
License
2013-12-11 16:09:41 +00:00
This file is part of foam-extend.
2013-12-11 16:09:41 +00:00
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
2013-12-11 16:09:41 +00:00
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
2013-12-11 16:09:41 +00:00
foam-extend 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
2013-12-11 16:09:41 +00:00
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Description
Select cells in relation to surface.
Divides cells into three sets:
- cutCells : cells cut by surface or close to surface.
- outside : cells not in cutCells and reachable from set of
user-defined points (outsidePoints)
- inside : same but not reachable.
Finally the wanted sets are combined into a cellSet 'selected'. Apart
from straightforward adding the contents there are a few extra rules to
make sure that the surface of the 'outside' of the mesh is singly
connected.
\*---------------------------------------------------------------------------*/
#include "argList.H"
2013-11-03 20:28:05 +00:00
#include "objectRegistry.H"
#include "foamTime.H"
#include "polyMesh.H"
#include "IOdictionary.H"
#include "twoDPointCorrector.H"
#include "OFstream.H"
#include "meshTools.H"
#include "triSurface.H"
#include "triSurfaceSearch.H"
#include "meshSearch.H"
#include "cellClassification.H"
#include "cellSet.H"
#include "cellInfo.H"
#include "MeshWave.H"
#include "edgeStats.H"
#include "treeDataTriSurface.H"
#include "indexedOctree.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// cellType for cells included/not included in mesh.
static const label MESH = cellClassification::INSIDE;
static const label NONMESH = cellClassification::OUTSIDE;
void writeSet(const cellSet& cells, const string& msg)
{
Info<< "Writing " << msg << " (" << cells.size() << ") to cellSet "
<< cells.instance()/cells.local()/cells.name()
<< endl << endl;
cells.write();
}
void getType(const labelList& elems, const label type, labelHashSet& set)
{
forAll(elems, i)
{
if (elems[i] == type)
{
set.insert(i);
}
}
}
void cutBySurface
(
const polyMesh& mesh,
const meshSearch& queryMesh,
const triSurfaceSearch& querySurf,
const pointField& outsidePts,
const bool selectCut,
const bool selectInside,
const bool selectOutside,
const scalar nearDist,
cellClassification& cellType
)
{
// Cut with surface and classify as inside/outside/cut
cellType =
cellClassification
(
mesh,
queryMesh,
querySurf,
outsidePts
);
// Get inside/outside/cutCells cellSets.
cellSet inside(mesh, "inside", mesh.nCells()/10);
getType(cellType, cellClassification::INSIDE, inside);
writeSet(inside, "inside cells");
cellSet outside(mesh, "outside", mesh.nCells()/10);
getType(cellType, cellClassification::OUTSIDE, outside);
writeSet(outside, "outside cells");
cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
getType(cellType, cellClassification::CUT, cutCells);
writeSet(cutCells, "cells cut by surface");
// Change cellType to reflect selected part of mesh. Use
// MESH to denote selected part, NONMESH for all
// other cells.
// Is a bit of a hack but allows us to reuse all the functionality
// in cellClassification.
forAll(cellType, cellI)
{
label cType = cellType[cellI];
if (cType == cellClassification::CUT)
{
if (selectCut)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else if (cType == cellClassification::INSIDE)
{
if (selectInside)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else if (cType == cellClassification::OUTSIDE)
{
if (selectOutside)
{
cellType[cellI] = MESH;
}
else
{
cellType[cellI] = NONMESH;
}
}
else
{
FatalErrorIn("cutBySurface")
<< "Multiple mesh regions in original mesh" << endl
<< "Please use splitMeshRegions to separate these"
<< exit(FatalError);
}
}
if (nearDist > 0)
{
Info<< "Removing cells with points closer than " << nearDist
<< " to the surface ..." << nl << endl;
const pointField& pts = mesh.points();
const indexedOctree<treeDataTriSurface>& tree = querySurf.tree();
label nRemoved = 0;
forAll(pts, pointI)
{
const point& pt = pts[pointI];
pointIndexHit hitInfo = tree.findNearest(pt, sqr(nearDist));
if (hitInfo.hit())
{
const labelList& pCells = mesh.pointCells()[pointI];
forAll(pCells, i)
{
if (cellType[pCells[i]] != NONMESH)
{
cellType[pCells[i]] = NONMESH;
nRemoved++;
}
}
}
}
// tmp<pointField> tnearest = querySurf.calcNearest(pts);
// const pointField& nearest = tnearest();
//
// label nRemoved = 0;
//
// forAll(nearest, pointI)
// {
// if (mag(nearest[pointI] - pts[pointI]) < nearDist)
// {
// const labelList& pCells = mesh.pointCells()[pointI];
//
// forAll(pCells, i)
// {
// if (cellType[pCells[i]] != NONMESH)
// {
// cellType[pCells[i]] = NONMESH;
// nRemoved++;
// }
// }
// }
// }
Info<< "Removed " << nRemoved << " cells since too close to surface"
<< nl << endl;
}
}
// We're meshing the outside. Subset the currently selected mesh cells with the
// ones reachable from the outsidepoints.
label selectOutsideCells
(
const polyMesh& mesh,
const meshSearch& queryMesh,
const pointField& outsidePts,
cellClassification& cellType
)
{
//
// Check all outsidePts and for all of them inside a mesh cell
// collect the faces to start walking from
//
// Outside faces
labelHashSet outsideFacesMap(outsidePts.size() * 6 * 2);
dynamicLabelList outsideFaces(outsideFacesMap.size());
// CellInfo on outside faces
DynamicList<cellInfo> outsideFacesInfo(outsideFacesMap.size());
// cellInfo for mesh cell
const cellInfo meshInfo(MESH);
forAll(outsidePts, outsidePtI)
{
// Find cell containing point. Linear search.
label cellI = queryMesh.findCell(outsidePts[outsidePtI], -1, false);
if (cellType[cellI] == MESH)
{
Info<< "Marking cell " << cellI << " containing outside point "
<< outsidePts[outsidePtI] << " with type " << cellType[cellI]
<< " ..." << endl;
//
// Mark this cell and its faces to start walking from
//
// Mark faces of cellI
const labelList& cFaces = mesh.cells()[cellI];
forAll(cFaces, i)
{
label faceI = cFaces[i];
if (outsideFacesMap.insert(faceI))
{
outsideFaces.append(faceI);
outsideFacesInfo.append(meshInfo);
}
}
}
}
// Floodfill starting from outsideFaces (of type meshInfo)
MeshWave<cellInfo> regionCalc
(
mesh,
outsideFaces.shrink(),
outsideFacesInfo.shrink(),
mesh.nCells() // max iterations
);
// Now regionCalc should hold info on cells that are reachable from
// changedFaces. Use these to subset cellType
const List<cellInfo>& allCellInfo = regionCalc.allCellInfo();
label nChanged = 0;
forAll(allCellInfo, cellI)
{
if (cellType[cellI] == MESH)
{
// Original cell was selected for meshing. Check if cell was
// reached from outsidePoints
if (allCellInfo[cellI].type() != MESH)
{
cellType[cellI] = NONMESH;
nChanged++;
}
}
}
return nChanged;
}
// Main program:
int main(int argc, char *argv[])
{
argList::noParallel();
# include "setRootCase.H"
# include "createTime.H"
# include "createPolyMesh.H"
// Mesh edge statistics calculator
edgeStats edgeCalc(mesh);
IOdictionary refineDict
(
IOobject
(
"selectCellsDict",
runTime.system(),
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE
)
);
fileName surfName(refineDict.lookup("surface"));
pointField outsidePts(refineDict.lookup("outsidePoints"));
bool useSurface(readBool(refineDict.lookup("useSurface")));
bool selectCut(readBool(refineDict.lookup("selectCut")));
bool selectInside(readBool(refineDict.lookup("selectInside")));
bool selectOutside(readBool(refineDict.lookup("selectOutside")));
scalar nearDist(readScalar(refineDict.lookup("nearDistance")));
if (useSurface)
{
Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
<< " cells cut by surface : " << selectCut << nl
<< " cells inside of surface : " << selectInside << nl
<< " cells outside of surface : " << selectOutside << nl
<< " cells with points further than : " << nearDist << nl
<< endl;
}
else
{
Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
<< " cells reachable from outsidePoints:" << selectOutside << nl
<< endl;
}
// Print edge stats on original mesh.
(void)edgeCalc.minLen(Info);
// Search engine on mesh. Face decomposition since faces might be warped.
meshSearch queryMesh(mesh, true);
// Check all 'outside' points
forAll(outsidePts, outsideI)
{
const point& outsidePoint = outsidePts[outsideI];
if (queryMesh.findCell(outsidePoint, -1, false) == -1)
{
FatalErrorIn(args.executable())
<< "outsidePoint " << outsidePoint
<< " is not inside any cell"
<< exit(FatalError);
}
}
// Cell status (compared to surface if provided): inside/outside/cut.
// Start off from everything selected and cut later.
cellClassification cellType
(
mesh,
labelList
(
mesh.nCells(),
cellClassification::MESH
)
);
// Surface
autoPtr<triSurface> surf(nullptr);
// Search engine on surface.
autoPtr<triSurfaceSearch> querySurf(nullptr);
if (useSurface)
{
surf.reset(new triSurface(surfName));
// Dump some stats
surf().writeStats(Info);
// Search engine on surface.
querySurf.reset(new triSurfaceSearch(surf));
// Set cellType[cellI] according to relation to surface
cutBySurface
(
mesh,
queryMesh,
querySurf,
outsidePts,
selectCut,
selectInside,
selectOutside,
nearDist,
cellType
);
}
// Now 'trim' all the corners from the mesh so meshing/surface extraction
// becomes easier.
label nHanging, nRegionEdges, nRegionPoints, nOutside;
do
{
Info<< "Removing cells which after subsetting would have all points"
<< " on outside ..." << nl << endl;
nHanging = cellType.fillHangingCells
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
Info<< "Removing edges connecting cells unconnected by faces ..."
<< nl << endl;
nRegionEdges = cellType.fillRegionEdges
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
Info<< "Removing points connecting cells unconnected by faces ..."
<< nl << endl;
nRegionPoints = cellType.fillRegionPoints
(
MESH, // meshType
NONMESH, // fill type
mesh.nCells()
);
nOutside = 0;
if (selectOutside)
{
// Since we're selecting the cells reachable from outsidePoints
// and the set might have changed, redo the outsideCells
// calculation
nOutside = selectOutsideCells
(
mesh,
queryMesh,
outsidePts,
cellType
);
}
} while
(
nHanging != 0
|| nRegionEdges != 0
|| nRegionPoints != 0
|| nOutside != 0
);
cellSet selectedCells(mesh, "selected", mesh.nCells()/10);
getType(cellType, MESH, selectedCells);
writeSet(selectedCells, "cells selected for meshing");
Info << "End\n" << endl;
return 0;
}
// ************************************************************************* //