/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2016-2022 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 . Application viewFactorsGen Group grpPreProcessingUtilities Description This view factors generation application uses a combined approach of double area integral (2AI) and double linear integral (2LI). 2AI is used when the two surfaces are 'far' apart and 2LI when they are 'close'. 2LI is integrated along edges using Gaussian quadrature. The distance between faces is calculating a ratio between averaged areas and the distance between face centres. The input from viewFactorsDict are: \verbatim GaussQuadTol 0.1; // GaussQuad error distTol 8; // R/Average(rm) alpha 0.22; // Use for common edges for 2LI \endverbatim For debugging purposes, the following entries can be set in viewFactorsDict: \verbatim writeViewFactorMatrix true; writeFacesAgglomeration false; dumpRays false; writeViewFactorMatrix writes the sum of the VF on each face. writeFacesAgglomeration writes the agglomeration dumpRays dumps rays \endverbatim The participating patches in the VF calculation have to be in the 'viewFactorWall' patch group (in the polyMesh/boundary file), e.g. \verbatim floor { type wall; inGroups 2(wall viewFactorWall); nFaces 100; startFace 3100; } \endverbatim Compile with -DNO_CGAL only if no CGAL present - CGAL AABB tree performs better than the built-in octree. \*---------------------------------------------------------------------------*/ #include "argList.H" #include "fvMesh.H" #include "volFields.H" #include "surfaceFields.H" #include "distributedTriSurfaceMesh.H" #include "meshTools.H" #include "constants.H" #include "indirectPrimitivePatch.H" #include "DynamicField.H" #include "scalarMatrices.H" #include "labelListIOList.H" #include "scalarListIOList.H" #include "singleCellFvMesh.H" #include "IOmapDistribute.H" #ifndef NO_CGAL // Silence boost bind deprecation warnings (before CGAL-5.2.1) #include "CGAL/version.h" #if defined(CGAL_VERSION_NR) && (CGAL_VERSION_NR < 1050211000) #define BOOST_BIND_GLOBAL_PLACEHOLDERS #endif #pragma clang diagnostic ignored "-Wbitwise-instead-of-logical" #include #include #include #include #include #include typedef CGAL::Simple_cartesian K; typedef K::Point_3 Point; typedef K::Direction_3 Vector3C; typedef K::Triangle_3 Triangle; typedef K::Segment_3 Segment; typedef std::vector::iterator Iterator; typedef CGAL::AABB_triangle_primitive Primitive; typedef CGAL::AABB_traits AABB_triangle_traits; typedef CGAL::AABB_tree Tree; typedef boost::optional < Tree::Intersection_and_primitive_id::Type > Segment_intersection; #endif // NO_CGAL using namespace Foam; using namespace Foam::constant; using namespace Foam::constant::mathematical; triSurface triangulate ( const polyBoundaryMesh& bMesh, const labelHashSet& includePatches, const labelListIOList& finalAgglom, labelList& triSurfaceToAgglom, const globalIndex& globalNumbering, const polyBoundaryMesh& coarsePatches ) { const polyMesh& mesh = bMesh.mesh(); // Storage for surfaceMesh. Size estimate. DynamicList triangles(mesh.nBoundaryFaces()); label newPatchI = 0; label localTriFaceI = 0; for (const label patchI : includePatches) { const polyPatch& patch = bMesh[patchI]; const pointField& points = patch.points(); label nTriTotal = 0; forAll(patch, patchFaceI) { const face& f = patch[patchFaceI]; faceList triFaces(f.nTriangles(points)); label nTri = 0; f.triangles(points, nTri, triFaces); forAll(triFaces, triFaceI) { const face& f = triFaces[triFaceI]; triangles.append(labelledTri(f[0], f[1], f[2], newPatchI)); nTriTotal++; triSurfaceToAgglom[localTriFaceI++] = globalNumbering.toGlobal ( Pstream::myProcNo(), finalAgglom[patchI][patchFaceI] + coarsePatches[patchI].start() ); } } newPatchI++; } //triSurfaceToAgglom.resize(localTriFaceI-1); triangles.shrink(); triSurface surface(triangles, mesh.points()); surface.compactPoints(); #ifndef NO_CGAL // CGAL : every processor has whole surface const globalIndex globalFaceIdx ( globalIndex::gatherOnly{}, surface.size() ); const globalIndex globalPointIdx ( globalIndex::gatherOnly{}, surface.points().size() ); List globalSurfaceTris(globalFaceIdx.gather(surface)); pointField globalSurfacePoints(globalPointIdx.gather(surface.points())); //label offset = 0; for (const label proci : globalPointIdx.allProcs()) { const label offset = globalPointIdx.localStart(proci); if (offset) { for ( labelledTri& tri : globalSurfaceTris.slice(globalFaceIdx.range(proci)) ) { tri[0] += offset; tri[1] += offset; tri[2] += offset; } } } surface = triSurface ( std::move(globalSurfaceTris), std::move(globalSurfacePoints) ); Pstream::broadcast(surface); #endif // Add patch names to surface surface.patches().setSize(newPatchI); newPatchI = 0; for (const label patchI : includePatches) { const polyPatch& patch = bMesh[patchI]; surface.patches()[newPatchI].index() = patchI; surface.patches()[newPatchI].name() = patch.name(); surface.patches()[newPatchI].geometricType() = patch.type(); newPatchI++; } return surface; } void writeRays ( const fileName& fName, const pointField& compactCf, const pointField& myFc, const labelListList& visibleFaceFaces ) { OFstream str(fName); label vertI = 0; Pout<< "Dumping rays to " << str.name() << endl; forAll(myFc, faceI) { const labelList visFaces = visibleFaceFaces[faceI]; forAll(visFaces, faceRemote) { label compactI = visFaces[faceRemote]; const point& remoteFc = compactCf[compactI]; meshTools::writeOBJ(str, myFc[faceI]); vertI++; meshTools::writeOBJ(str, remoteFc); vertI++; str << "l " << vertI-1 << ' ' << vertI << nl; } } str.flush(); } scalar calculateViewFactorFij2AI ( const vector& i, const vector& j, const vector& dAi, const vector& dAj ) { vector r = i - j; scalar rMag = mag(r); if (rMag > SMALL) { scalar dAiMag = mag(dAi); scalar dAjMag = mag(dAj); vector ni = dAi/dAiMag; vector nj = dAj/dAjMag; scalar cosThetaJ = mag(nj & r)/rMag; scalar cosThetaI = mag(ni & r)/rMag; return ( (cosThetaI*cosThetaJ*dAjMag*dAiMag) /(sqr(rMag)*constant::mathematical::pi) ); } else { return 0; } } void insertMatrixElements ( const globalIndex& globalNumbering, const label fromProcI, const labelListList& globalFaceFaces, const scalarListList& viewFactors, scalarSquareMatrix& matrix ) { forAll(viewFactors, faceI) { const scalarList& vf = viewFactors[faceI]; const labelList& globalFaces = globalFaceFaces[faceI]; label globalI = globalNumbering.toGlobal(fromProcI, faceI); forAll(globalFaces, i) { matrix[globalI][globalFaces[i]] = vf[i]; } } } scalar GaussQuad ( const scalarList& w, const scalarList& p, const scalar& magSi, const scalar& magSj, const vector& di, const vector& dj, const vector& ci, const vector& cj, const scalar cosij, const scalar alpha, label gi ) { scalar dIntFij = 0; if (gi == 0) { vector r(ci - cj); if (mag(r) < SMALL) { r = (alpha*magSi)*di; } dIntFij = max(cosij*Foam::log(r&r)*magSi*magSj, 0); } else { List pi(w.size()); forAll (pi, i) { pi[i] = ci + p[i]*(magSi/2)*di; } List pj(w.size()); forAll (pj, i) { pj[i] = cj + p[i]*(magSj/2)*dj; } forAll (w, i) { forAll (w, j) { vector r(pi[i] - pj[j]); if (mag(r) < SMALL) { r = (alpha*magSi)*di; dIntFij += cosij*w[i]*w[j]*Foam::log(r&r); } else { dIntFij += cosij*w[i]*w[j]*Foam::log(r&r); } } } dIntFij *= (magSi/2) * (magSj/2); } return dIntFij; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { argList::addNote ( "Calculate view factors from face agglomeration array." " The finalAgglom generated by faceAgglomerate utility." ); #include "addRegionOption.H" #include "setRootCase.H" #include "createTime.H" #include "createNamedMesh.H" // Read view factor dictionary IOdictionary viewFactorDict ( IOobject ( "viewFactorsDict", runTime.constant(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE ) ); const word viewFactorWall("viewFactorWall"); const bool writeViewFactors = viewFactorDict.getOrDefault("writeViewFactorMatrix", false); const bool dumpRays = viewFactorDict.getOrDefault("dumpRays", false); const label debug = viewFactorDict.getOrDefault