openfoam/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/primitiveMeshCheckMotion.C
Mark Olesen a50f01b079 STYLE: use forAllIter, forAllConstIter instead of long-hand version
STYLE: use 'forAll(' NOT 'forAll (', as per coding guide
2010-04-12 11:18:38 +02:00

267 lines
7.6 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ 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 <http://www.gnu.org/licenses/>.
Description
Given a set of points, find out if the mesh resulting from point motion will
be valid without actually changing the mesh.
\*---------------------------------------------------------------------------*/
#include "primitiveMesh.H"
#include "pyramidPointFaceRef.H"
#include "cell.H"
#include "unitConversion.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::primitiveMesh::checkMeshMotion
(
const pointField& newPoints,
const bool report
) const
{
if (debug || report)
{
Pout<< "bool primitiveMesh::checkMeshMotion("
<< "const pointField& newPoints, const bool report) const: "
<< "checking mesh motion" << endl;
}
bool error = false;
const faceList& f = faces();
const labelList& own = faceOwner();
const labelList& nei = faceNeighbour();
vectorField fCtrs(nFaces());
vectorField fAreas(nFaces());
makeFaceCentresAndAreas(newPoints, fCtrs, fAreas);
// Check cell volumes and calculate new cell centres
vectorField cellCtrs(nCells());
scalarField cellVols(nCells());
makeCellCentresAndVols(fCtrs, fAreas, cellCtrs, cellVols);
scalar minVolume = GREAT;
label nNegVols = 0;
forAll(cellVols, cellI)
{
if (cellVols[cellI] < VSMALL)
{
if (debug || report)
{
Pout<< "Zero or negative cell volume detected for cell "
<< cellI << ". Volume = " << cellVols[cellI] << endl;
}
nNegVols++;
}
minVolume = min(minVolume, cellVols[cellI]);
}
if (nNegVols > 0)
{
error = true;
Pout<< "Zero or negative cell volume in mesh motion in " << nNegVols
<< " cells. Min volume: " << minVolume << endl;
}
else
{
if (debug || report)
{
Pout<< "Min volume = " << minVolume
<< ". Total volume = " << sum(cellVols)
<< ". Cell volumes OK." << endl;
}
}
// Check face areas
scalar minArea = GREAT;
label nNegAreas = 0;
label nPyrErrors = 0;
label nDotProductErrors = 0;
forAll(f, faceI)
{
const scalar a = Foam::mag(fAreas[faceI]);
if (a < VSMALL)
{
if (debug || report)
{
if (isInternalFace(faceI))
{
Pout<< "Zero or negative face area detected for "
<< "internal face "<< faceI << " between cells "
<< own[faceI] << " and " << nei[faceI]
<< ". Face area magnitude = " << a << endl;
}
else
{
Pout<< "Zero or negative face area detected for "
<< "boundary face " << faceI << " next to cell "
<< own[faceI] << ". Face area magnitude = "
<< a << endl;
}
}
nNegAreas++;
}
minArea = min(minArea, a);
// Create the owner pyramid - it will have negative volume
scalar pyrVol =
pyramidPointFaceRef(f[faceI], cellCtrs[own[faceI]]).mag(newPoints);
if (pyrVol > SMALL)
{
if (debug || report)
{
Pout<< "Negative pyramid volume: " << -pyrVol
<< " for face " << faceI << " " << f[faceI]
<< " and owner cell: " << own[faceI] << endl
<< "Owner cell vertex labels: "
<< cells()[own[faceI]].labels(f)
<< endl;
}
nPyrErrors++;
}
if (isInternalFace(faceI))
{
// Create the neighbour pyramid - it will have positive volume
scalar pyrVol =
pyramidPointFaceRef
(
f[faceI],
cellCtrs[nei[faceI]]
).mag(newPoints);
if (pyrVol < -SMALL)
{
if (debug || report)
{
Pout<< "Negative pyramid volume: " << pyrVol
<< " for face " << faceI << " " << f[faceI]
<< " and neighbour cell: " << nei[faceI] << nl
<< "Neighbour cell vertex labels: "
<< cells()[nei[faceI]].labels(f)
<< endl;
}
nPyrErrors++;
}
const vector d = cellCtrs[nei[faceI]] - cellCtrs[own[faceI]];
const vector& s = fAreas[faceI];
scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
// Only write full message the first time
if (dDotS < SMALL && nDotProductErrors == 0)
{
// Non-orthogonality greater than 90 deg
WarningIn
(
"primitiveMesh::checkMeshMotion"
"(const pointField& newPoints, const bool report) const"
) << "Severe non-orthogonality in mesh motion for face "
<< faceI
<< " between cells " << own[faceI] << " and " << nei[faceI]
<< ": Angle = " << radToDeg(::acos(dDotS))
<< " deg." << endl;
nDotProductErrors++;
}
}
}
if (nNegAreas > 0)
{
error = true;
WarningIn
(
"primitiveMesh::checkMeshMotion"
"(const pointField& newPoints, const bool report) const"
) << "Zero or negative face area in mesh motion in " << nNegAreas
<< " faces. Min area: " << minArea << endl;
}
else
{
if (debug || report)
{
Pout<< "Min area = " << minArea
<< ". Face areas OK." << endl;
}
}
if (nPyrErrors > 0)
{
Pout<< "Detected " << nPyrErrors
<< " negative pyramid volume in mesh motion" << endl;
error = true;
}
else
{
if (debug || report)
{
Pout<< "Pyramid volumes OK." << endl;
}
}
if (nDotProductErrors > 0)
{
Pout<< "Detected " << nDotProductErrors
<< " in non-orthogonality in mesh motion." << endl;
error = true;
}
else
{
if (debug || report)
{
Pout<< "Non-orthogonality check OK." << endl;
}
}
if (!error && (debug || report))
{
Pout << "Mesh motion check OK." << endl;
}
return error;
}
// ************************************************************************* //