/*---------------------------------------------------------------------------*\ ========= | \\ / 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 "primitiveMeshGeometry.H" #include "pyramidPointFaceRef.H" namespace Foam { // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // defineTypeNameAndDebug(primitiveMeshGeometry, 0); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::primitiveMeshGeometry::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::primitiveMeshGeometry::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]; cellVolumes_[cellI] *= (1.0/3.0); } } Foam::labelList Foam::primitiveMeshGeometry::affectedCells ( const labelList& changedFaces ) const { 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(); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // Construct from components Foam::primitiveMeshGeometry::primitiveMeshGeometry ( const primitiveMesh& mesh ) : mesh_(mesh) { correct(); } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // //- Take over properties from mesh void Foam::primitiveMeshGeometry::correct() { faceAreas_ = mesh_.faceAreas(); faceCentres_ = mesh_.faceCentres(); cellCentres_ = mesh_.cellCentres(); cellVolumes_ = mesh_.cellVolumes(); } //- Recalculate on selected faces void Foam::primitiveMeshGeometry::correct ( const pointField& p, const labelList& changedFaces ) { // Update face quantities updateFaceCentresAndAreas(p, changedFaces); // Update cell quantities from face quantities updateCellCentresAndVols(affectedCells(changedFaces), changedFaces); } bool Foam::primitiveMeshGeometry::checkFaceDotProduct ( const bool report, const scalar orthWarn, const primitiveMesh& mesh, const vectorField& cellCentres, const vectorField& faceAreas, const labelList& checkFaces, labelHashSet* setPtr ) { // for all internal faces check theat the d dot S product is positive const labelList& own = mesh.faceOwner(); const labelList& nei = mesh.faceNeighbour(); // Severe nonorthogonality threshold const scalar severeNonorthogonalityThreshold = ::cos(orthWarn/180.0*mathematicalConstant::pi); scalar minDDotS = GREAT; scalar sumDDotS = 0; label severeNonOrth = 0; label errorNonOrth = 0; forAll(checkFaces, i) { label faceI = checkFaces[i]; if (mesh.isInternalFace(faceI)) { vector d = cellCentres[nei[faceI]] - cellCentres[own[faceI]]; const vector& s = faceAreas[faceI]; scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL); if (dDotS < severeNonorthogonalityThreshold) { if (dDotS > SMALL) { if (report) { // Severe non-orthogonality but mesh still OK Pout<< "Severe non-orthogonality for face " << faceI << " between cells " << own[faceI] << " and " << nei[faceI] << ": Angle = " << ::acos(dDotS)/mathematicalConstant::pi*180.0 << " deg." << endl; } if (setPtr) { setPtr->insert(faceI); } severeNonOrth++; } else { // Non-orthogonality greater than 90 deg if (report) { WarningIn ( "primitiveMeshGeometry::checkFaceDotProduct" "(const bool, const scalar, const labelList&" ", labelHashSet*)" ) << "Severe non-orthogonality detected for face " << faceI << " between cells " << own[faceI] << " and " << nei[faceI] << ": Angle = " << ::acos(dDotS)/mathematicalConstant::pi*180.0 << " deg." << endl; } errorNonOrth++; if (setPtr) { setPtr->insert(faceI); } } } if (dDotS < minDDotS) { minDDotS = dDotS; } sumDDotS += dDotS; } } reduce(minDDotS, minOp()); reduce(sumDDotS, sumOp()); reduce(severeNonOrth, sumOp