/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | cfMesh: A library for mesh generation
\\ / O peration |
\\ / A nd | Copyright held by the origina author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of cfMesh.
cfMesh 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.
cfMesh 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 cfMesh. If not, see .
\*---------------------------------------------------------------------------*/
#include "polyMeshGenChecks.H"
#include "polyMeshGenAddressing.H"
#include "pyramidPointFaceRef.H"
#include "tetrahedron.H"
# ifdef USE_OMP
#include
# endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace polyMeshGenChecks
{
bool checkClosedBoundary(const polyMeshGen& mesh, const bool report)
{
// Loop through all boundary faces and sum up the face area vectors.
// For a closed boundary, this should be zero in all vector components
vector sumClosed(vector::zero);
scalar sumMagClosedBoundary = 0;
const vectorField& areas = mesh.addressingData().faceAreas();
for(label faceI = mesh.nInternalFaces();faceI());
reduce(maxOpen, maxOp());
if( maxOpen > SMALL*max(1.0, sumMagClosedBoundary) )
{
SeriousErrorIn
(
"bool checkClosedBoundary(const polyMeshGen&, const bool report)"
) << "Possible hole in boundary description" << endl;
Info<< "Boundary openness in x-direction = "
<< sumClosed.component(vector::X) << endl;
Info<< "Boundary openness in y-direction = "
<< sumClosed.component(vector::Y) << endl;
Info<< "Boundary openness in z-direction = "
<< sumClosed.component(vector::Z) << endl;
return true;
}
else
{
if( report )
{
Info<< "Boundary openness in x-direction = "
<< sumClosed.component(vector::X) << endl;
Info<< "Boundary openness in y-direction = "
<< sumClosed.component(vector::Y) << endl;
Info<< "Boundary openness in z-direction = "
<< sumClosed.component(vector::Z) << endl;
Info<< "Boundary closed (OK)." << endl;
}
return false;
}
}
bool checkClosedCells
(
const polyMeshGen& mesh,
const bool report,
const scalar aspectWarn,
labelHashSet* setPtr
)
{
// Check that all cells labels are valid
const cellListPMG& cells = mesh.cells();
const label nFaces = mesh.faces().size();
label nErrorClosed = 0;
# ifdef USE_OMP
# pragma omp parallel for schedule(guided) reduction(+ : nErrorClosed)
# endif
forAll(cells, cI)
{
const cell& curCell = cells[cI];
if( min(curCell) < 0 || max(curCell) > nFaces )
{
WarningIn
(
"bool checkClosedCells("
"const polyMeshGen&, const bool, const scalar, labelHashSet*)"
) << "Cell " << cI << " contains face labels out of range: "
<< curCell << " Max face index = " << nFaces << endl;
if( setPtr )
{
# ifdef USE_OMP
# pragma omp critical
# endif
setPtr->insert(cI);
}
++nErrorClosed;
}
}
if( nErrorClosed > 0 )
{
SeriousErrorIn
(
"bool checkClosedCells("
"const polyMeshGen&, const bool, const scalar, labelHashSet*)"
) << nErrorClosed << " cells with invalid face labels found"
<< endl;
return true;
}
// Loop through cell faces and sum up the face area vectors for each cell.
// This should be zero in all vector components
vectorField sumClosed(cells.size(), vector::zero);
scalarField sumMagClosed(cells.size(), 0.0);
const labelList& own = mesh.owner();
const labelList& nei = mesh.neighbour();
const vectorField& areas = mesh.addressingData().faceAreas();
forAll(own, faceI)
{
// Add to owner
sumClosed[own[faceI]] += areas[faceI];
sumMagClosed[own[faceI]] += mag(areas[faceI]);
if( nei[faceI] == -1 )
continue;
// Subtract from neighbour
sumClosed[nei[faceI]] -= areas[faceI];
sumMagClosed[nei[faceI]] += mag(areas[faceI]);
}
label nOpen = 0;
scalar maxOpenCell = 0;
label nAspect = 0;
scalar maxAspectRatio = 0;
const scalarField& vols = mesh.addressingData().cellVolumes();
// Check the sums
forAll(sumClosed, cellI)
{
scalar maxOpen = max
(
sumClosed[cellI].component(vector::X),
max
(
sumClosed[cellI].component(vector::Y),
sumClosed[cellI].component(vector::Z)
)
);
maxOpenCell = max(maxOpenCell, maxOpen);
if( maxOpen > SMALL*max(1.0, sumMagClosed[cellI]) )
{
if( report )
{
Pout<< "Cell " << cellI << " is not closed. "
<< "Face area vectors sum up to " << mag(sumClosed[cellI])
<< " directionwise " << sumClosed[cellI] << " or "
<< mag(sumClosed[cellI])
/(mag(sumMagClosed[cellI]) + VSMALL)
<< " of the area of all faces of the cell. " << endl
<< " Area magnitudes sum up to "
<< sumMagClosed[cellI] << endl;
}
if( setPtr )
{
setPtr->insert(cellI);
}
++nOpen;
}
scalar aspectRatio =
1.0/6.0*sumMagClosed[cellI]/pow(vols[cellI], 2.0/3.0);
maxAspectRatio = max(maxAspectRatio, aspectRatio);
if( aspectRatio > aspectWarn )
{
if( report )
{
Pout<< "High aspect ratio for cell " << cellI
<< ": " << aspectRatio << endl;
}
++nAspect;
}
}
reduce(nOpen, sumOp