/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2017 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 "checkTopology.H"
#include "polyMesh.H"
#include "Time.H"
#include "regionSplit.H"
#include "cellSet.H"
#include "faceSet.H"
#include "pointSet.H"
#include "IOmanip.H"
#include "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "surfaceWriter.H"
#include "checkTools.H"
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template
void Foam::checkPatch
(
const bool allGeometry,
const word& name,
const PatchType& pp,
pointSet& points
)
{
Info<< " "
<< setw(20) << name
<< setw(9) << returnReduce(pp.size(), sumOp())
<< setw(9) << returnReduce(pp.nPoints(), sumOp());
if (!Pstream::parRun())
{
typedef typename PatchType::surfaceTopo TopoType;
TopoType pTyp = pp.surfaceType();
if (pp.empty())
{
Info<< setw(34) << "ok (empty)";
}
else if (pTyp == TopoType::MANIFOLD)
{
if (pp.checkPointManifold(true, &points))
{
Info<< setw(34)
<< "multiply connected (shared point)";
}
else
{
Info<< setw(34) << "ok (closed singly connected)";
}
// Add points on non-manifold edges to make set complete
pp.checkTopology(false, &points);
}
else
{
pp.checkTopology(false, &points);
if (pTyp == TopoType::OPEN)
{
Info<< setw(34)
<< "ok (non-closed singly connected)";
}
else
{
Info<< setw(34)
<< "multiply connected (shared edge)";
}
}
}
if (allGeometry)
{
const labelList& mp = pp.meshPoints();
if (returnReduce(mp.size(), sumOp()) > 0)
{
boundBox bb(pp.points(), mp, true); // reduce
Info<< ' ' << bb;
}
}
}
Foam::label Foam::checkTopology
(
const polyMesh& mesh,
const bool allTopology,
const bool allGeometry,
const autoPtr& surfWriter,
const autoPtr>& setWriter
)
{
label noFailedChecks = 0;
Info<< "Checking topology..." << endl;
// Check if the boundary definition is unique
mesh.boundaryMesh().checkDefinition(true);
// Check that empty patches cover all sides of the mesh
{
label nEmpty = 0;
forAll(mesh.boundaryMesh(), patchi)
{
if (isA(mesh.boundaryMesh()[patchi]))
{
nEmpty += mesh.boundaryMesh()[patchi].size();
}
}
reduce(nEmpty, sumOp());
label nTotCells = returnReduce(mesh.cells().size(), sumOp());
// These are actually warnings, not errors.
if (nTotCells && (nEmpty % nTotCells))
{
Info<< " ***Total number of faces on empty patches"
<< " is not divisible by the number of cells in the mesh."
<< " Hence this mesh is not 1D or 2D."
<< endl;
}
}
// Check if the boundary processor patches are correct
mesh.boundaryMesh().checkParallelSync(true);
// Check names of zones are equal
mesh.cellZones().checkDefinition(true);
if (mesh.cellZones().checkParallelSync(true))
{
noFailedChecks++;
}
mesh.faceZones().checkDefinition(true);
if (mesh.faceZones().checkParallelSync(true))
{
noFailedChecks++;
}
mesh.pointZones().checkDefinition(true);
if (mesh.pointZones().checkParallelSync(true))
{
noFailedChecks++;
}
{
cellSet cells(mesh, "illegalCells", mesh.nCells()/100);
forAll(mesh.cells(), celli)
{
const cell& cFaces = mesh.cells()[celli];
if (cFaces.size() <= 3)
{
cells.insert(celli);
}
for (const label facei : cFaces)
{
if (facei < 0 || facei >= mesh.nFaces())
{
cells.insert(celli);
break;
}
}
}
const label nCells = returnReduce(cells.size(), sumOp());
if (nCells > 0)
{
Info<< " Illegal cells (less than 4 faces or out of range faces)"
<< " found, number of cells: " << nCells << endl;
noFailedChecks++;
Info<< " <());
Info<< " <());
if (nFaces > 0)
{
Info<< " <());
Info<< " <());
Info<< " <());
if (nFaces > 0)
{
Info<< " <());
if (nOneCells > 0)
{
Info<< " <());
if (nTwoCells > 0)
{
Info<< " <= 0 : single region
labelList pointToRegion(mesh.nPoints(), -1);
for
(
label facei = mesh.nInternalFaces();
facei < mesh.nFaces();
++facei
)
{
const label regioni = rs[mesh.faceOwner()[facei]];
const face& f = mesh.faces()[facei];
for (const label verti : f)
{
label& pRegion = pointToRegion[verti];
if (pRegion == -1)
{
pRegion = regioni;
}
else if (pRegion == -2)
{
// Already marked
regionDisconnected[regioni] = false;
}
else if (pRegion != regioni)
{
// Multiple regions
regionDisconnected[regioni] = false;
regionDisconnected[pRegion] = false;
pRegion = -2;
points.insert(verti);
}
}
}
Pstream::listCombineGather(regionDisconnected, andEqOp());
Pstream::listCombineScatter(regionDisconnected);
}
// write cellSet for each region
PtrList cellRegions(rs.nRegions());
for (label i = 0; i < rs.nRegions(); i++)
{
cellRegions.set
(
i,
new cellSet
(
mesh,
"region" + Foam::name(i),
mesh.nCells()/100
)
);
}
forAll(rs, i)
{
cellRegions[rs[i]].insert(i);
}
for (label i = 0; i < rs.nRegions(); i++)
{
Info<< " <())
<< " cells to cellSet " << cellRegions[i].name() << endl;
cellRegions[i].write();
}
label nPoints = returnReduce(points.size(), sumOp());
if (nPoints)
{
Info<< " <(pp))
{
checkPatch(allGeometry, pp.name(), pp, points);
Info<< endl;
}
}
//Info.setf(ios_base::right);
}
{
if (!Pstream::parRun())
{
Info<< "\nChecking faceZone topology for multiply connected"
<< " surfaces..." << endl;
}
else
{
Info<< "\nChecking basic faceZone addressing..." << endl;
}
Pout.setf(ios_base::left);
const faceZoneMesh& faceZones = mesh.faceZones();
if (faceZones.size())
{
Info<< " "
<< setw(20) << "FaceZone"
<< setw(9) << "Faces"
<< setw(9) << "Points";
if (!Pstream::parRun())
{
Info<< setw(34) << "Surface topology";
}
if (allGeometry)
{
Info<< " Bounding box";
}
Info<< endl;
for (const faceZone& fz : faceZones)
{
checkPatch(allGeometry, fz.name(), fz(), points);
Info<< endl;
}
}
else
{
Info<< " No faceZones found."<());
if (nPoints)
{
Info<< " <())
<< ' ' << setw(12)
<< returnReduce(isZonePoint.count(), sumOp())
<< ' ' << setw(12)
<< returnReduce(v, sumOp())
<< ' ' << bb << endl;
}
}
else
{
Info<< " No cellZones found."<