/*---------------------------------------------------------------------------*\ ========= | \\ / 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \*---------------------------------------------------------------------------*/ #include "polyMeshGeometry.H" #include "pyramidPointFaceRef.H" #include "syncTools.H" #include "mathConstants.H" namespace Foam { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // defineTypeNameAndDebug(polyMeshGeometry, 0); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::polyMeshGeometry::updateFaceCentresAndAreas ( const pointField& p, const labelList& changedFaces ) { const faceList& fs = mesh_.faces(); forAll(changedFaces, i) { label facei = changedFaces[i]; const labelList& f = fs[facei]; label nPoints = f.size(); // If the face is a triangle, do a direct calculation for efficiency // and to avoid round-off error-related problems if (nPoints == 3) { faceCentres_[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]); faceAreas_[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]])); } else { vector sumN = vector::zero; scalar sumA = 0.0; vector sumAc = vector::zero; point fCentre = p[f[0]]; for (label pi = 1; pi < nPoints; pi++) { fCentre += p[f[pi]]; } fCentre /= nPoints; for (label pi = 0; pi < nPoints; pi++) { const point& nextPoint = p[f[(pi + 1) % nPoints]]; vector c = p[f[pi]] + nextPoint + fCentre; vector n = (nextPoint - p[f[pi]])^(fCentre - p[f[pi]]); scalar a = mag(n); sumN += n; sumA += a; sumAc += a*c; } faceCentres_[facei] = (1.0/3.0)*sumAc/(sumA + VSMALL); faceAreas_[facei] = 0.5*sumN; } } } void Foam::polyMeshGeometry::updateCellCentresAndVols ( const labelList& changedCells, const labelList& changedFaces ) { // Clear the fields for accumulation UIndirectList(cellCentres_, changedCells) = vector::zero; UIndirectList(cellVolumes_, changedCells) = 0.0; const labelList& own = mesh_.faceOwner(); const labelList& nei = mesh_.faceNeighbour(); // first estimate the approximate cell centre as the average of face centres vectorField cEst(mesh_.nCells()); UIndirectList(cEst, changedCells) = vector::zero; scalarField nCellFaces(mesh_.nCells()); UIndirectList(nCellFaces, changedCells) = 0.0; forAll(changedFaces, i) { label faceI = changedFaces[i]; cEst[own[faceI]] += faceCentres_[faceI]; nCellFaces[own[faceI]] += 1; if (mesh_.isInternalFace(faceI)) { cEst[nei[faceI]] += faceCentres_[faceI]; nCellFaces[nei[faceI]] += 1; } } forAll(changedCells, i) { label cellI = changedCells[i]; cEst[cellI] /= nCellFaces[cellI]; } forAll(changedFaces, i) { label faceI = changedFaces[i]; // Calculate 3*face-pyramid volume scalar pyr3Vol = max ( faceAreas_[faceI] & (faceCentres_[faceI] - cEst[own[faceI]]), VSMALL ); // Calculate face-pyramid centre vector pc = (3.0/4.0)*faceCentres_[faceI] + (1.0/4.0)*cEst[own[faceI]]; // Accumulate volume-weighted face-pyramid centre cellCentres_[own[faceI]] += pyr3Vol*pc; // Accumulate face-pyramid volume cellVolumes_[own[faceI]] += pyr3Vol; if (mesh_.isInternalFace(faceI)) { // Calculate 3*face-pyramid volume scalar pyr3Vol = max ( faceAreas_[faceI] & (cEst[nei[faceI]] - faceCentres_[faceI]), VSMALL ); // Calculate face-pyramid centre vector pc = (3.0/4.0)*faceCentres_[faceI] + (1.0/4.0)*cEst[nei[faceI]]; // Accumulate volume-weighted face-pyramid centre cellCentres_[nei[faceI]] += pyr3Vol*pc; // Accumulate face-pyramid volume cellVolumes_[nei[faceI]] += pyr3Vol; } } forAll(changedCells, i) { label cellI = changedCells[i]; cellCentres_[cellI] /= cellVolumes_[cellI] + VSMALL; cellVolumes_[cellI] *= (1.0/3.0); } } Foam::labelList Foam::polyMeshGeometry::affectedCells ( const polyMesh& mesh, const labelList& changedFaces ) { const labelList& own = mesh.faceOwner(); const labelList& nei = mesh.faceNeighbour(); labelHashSet affectedCells(2*changedFaces.size()); forAll(changedFaces, i) { label faceI = changedFaces[i]; affectedCells.insert(own[faceI]); if (mesh.isInternalFace(faceI)) { affectedCells.insert(nei[faceI]); } } return affectedCells.toc(); } Foam::scalar Foam::polyMeshGeometry::checkNonOrtho ( const polyMesh& mesh, const bool report, const scalar severeNonorthogonalityThreshold, const label faceI, const vector& s, // face area vector const vector& d, // cc-cc vector label& severeNonOrth, label& errorNonOrth, labelHashSet* setPtr ) { scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL); if (dDotS < severeNonorthogonalityThreshold) { label nei = -1; if (mesh.isInternalFace(faceI)) { nei = mesh.faceNeighbour()[faceI]; } if (dDotS > SMALL) { if (report) { // Severe non-orthogonality but mesh still OK Pout<< "Severe non-orthogonality for face " << faceI << " between cells " << mesh.faceOwner()[faceI] << " and " << nei << ": Angle = " << ::acos(dDotS)/constant::math::pi*180.0 << " deg." << endl; } severeNonOrth++; } else { // Non-orthogonality greater than 90 deg if (report) { WarningIn ( "polyMeshGeometry::checkFaceDotProduct" "(const bool, const scalar, const labelList&" ", labelHashSet*)" ) << "Severe non-orthogonality detected for face " << faceI << " between cells " << mesh.faceOwner()[faceI] << " and " << nei << ": Angle = " << ::acos(dDotS)/constant::math::pi*180.0 << " deg." << endl; } errorNonOrth++; } if (setPtr) { setPtr->insert(faceI); } } return dDotS; } Foam::scalar Foam::polyMeshGeometry::calcSkewness ( const point& ownCc, const point& neiCc, const point& fc ) { scalar dOwn = mag(fc - ownCc); scalar dNei = mag(fc - neiCc); point faceIntersection = ownCc*dNei/(dOwn+dNei+VSMALL) + neiCc*dOwn/(dOwn+dNei+VSMALL); return mag(fc - faceIntersection) / ( mag(neiCc-ownCc) + VSMALL ); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // Construct from components Foam::polyMeshGeometry::polyMeshGeometry(const polyMesh& mesh) : mesh_(mesh) { correct(); } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // //- Take over properties from mesh void Foam::polyMeshGeometry::correct() { faceAreas_ = mesh_.faceAreas(); faceCentres_ = mesh_.faceCentres(); cellCentres_ = mesh_.cellCentres(); cellVolumes_ = mesh_.cellVolumes(); } //- Recalculate on selected faces void Foam::polyMeshGeometry::correct ( const pointField& p, const labelList& changedFaces ) { // Update face quantities updateFaceCentresAndAreas(p, changedFaces); // Update cell quantities from face quantities updateCellCentresAndVols(affectedCells(mesh_, changedFaces), changedFaces); } bool Foam::polyMeshGeometry::checkFaceDotProduct ( const bool report, const scalar orthWarn, const polyMesh& mesh, const vectorField& cellCentres, const vectorField& faceAreas, const labelList& checkFaces, const List& baffles, labelHashSet* setPtr ) { // for all internal and coupled faces check theat the d dot S product // is positive const labelList& own = mesh.faceOwner(); const labelList& nei = mesh.faceNeighbour(); const polyBoundaryMesh& patches = mesh.boundaryMesh(); // Severe nonorthogonality threshold const scalar severeNonorthogonalityThreshold = ::cos(orthWarn/180.0*constant::math::pi); // Calculate coupled cell centre vectorField neiCc(mesh.nFaces()-mesh.nInternalFaces()); for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++) { neiCc[faceI-mesh.nInternalFaces()] = cellCentres[own[faceI]]; } syncTools::swapBoundaryFaceList(mesh, neiCc, true); scalar minDDotS = GREAT; scalar sumDDotS = 0; label nDDotS = 0; label severeNonOrth = 0; label errorNonOrth = 0; forAll(checkFaces, i) { label faceI = checkFaces[i]; const point& ownCc = cellCentres[own[faceI]]; if (mesh.isInternalFace(faceI)) { scalar dDotS = checkNonOrtho ( mesh, report, severeNonorthogonalityThreshold, faceI, faceAreas[faceI], cellCentres[nei[faceI]] - ownCc, severeNonOrth, errorNonOrth, setPtr ); if (dDotS < minDDotS) { minDDotS = dDotS; } sumDDotS += dDotS; nDDotS++; } else { label patchI = patches.whichPatch(faceI); if (patches[patchI].coupled()) { scalar dDotS = checkNonOrtho ( mesh, report, severeNonorthogonalityThreshold, faceI, faceAreas[faceI], neiCc[faceI-mesh.nInternalFaces()] - ownCc, severeNonOrth, errorNonOrth, setPtr ); if (dDotS < minDDotS) { minDDotS = dDotS; } sumDDotS += dDotS; nDDotS++; } } } forAll(baffles, i) { label face0 = baffles[i].first(); label face1 = baffles[i].second(); const point& ownCc = cellCentres[own[face0]]; scalar dDotS = checkNonOrtho ( mesh, report, severeNonorthogonalityThreshold, face0, faceAreas[face0], cellCentres[own[face1]] - ownCc, severeNonOrth, errorNonOrth, setPtr ); if (dDotS < minDDotS) { minDDotS = dDotS; } sumDDotS += dDotS; nDDotS++; } reduce(minDDotS, minOp()); reduce(sumDDotS, sumOp()); reduce(nDDotS, sumOp