From b9507c21f98372c90ebad377213759a2f20ba532 Mon Sep 17 00:00:00 2001 From: sergio <s.ferraris@opencfd.co.uk> Date: Fri, 8 Apr 2022 10:30:25 -0700 Subject: [PATCH] ENH: Adding viewFactorsGenExt which uses pbrt for ray tracing --- .../preProcessing/viewFactorsGen/shootRays.H | 1 + .../viewFactorsGenExt/Make/files | 3 + .../viewFactorsGenExt/Make/options | 39 + .../viewFactorsGenExt/searchingEngineExt.H | 121 ++ .../viewFactorsGenExt/shootRaysExt.H | 196 +++ .../viewFactorsGenExt/viewFactorsGenExt.C | 1224 +++++++++++++++++ .../radiationModels/viewFactor/viewFactor.C | 2 + 7 files changed, 1586 insertions(+) create mode 100644 applications/utilities/preProcessing/viewFactorsGenExt/Make/files create mode 100644 applications/utilities/preProcessing/viewFactorsGenExt/Make/options create mode 100644 applications/utilities/preProcessing/viewFactorsGenExt/searchingEngineExt.H create mode 100644 applications/utilities/preProcessing/viewFactorsGenExt/shootRaysExt.H create mode 100644 applications/utilities/preProcessing/viewFactorsGenExt/viewFactorsGenExt.C diff --git a/applications/utilities/preProcessing/viewFactorsGen/shootRays.H b/applications/utilities/preProcessing/viewFactorsGen/shootRays.H index 1df6e108f01..e35b2d4268c 100644 --- a/applications/utilities/preProcessing/viewFactorsGen/shootRays.H +++ b/applications/utilities/preProcessing/viewFactorsGen/shootRays.H @@ -49,6 +49,7 @@ for (const int proci : Pstream::allProcs()) const vector d(remFc - fc); + if (((d & fA) < 0.) && ((d & remA) > 0)) { start.append(fc + 0.001*d); diff --git a/applications/utilities/preProcessing/viewFactorsGenExt/Make/files b/applications/utilities/preProcessing/viewFactorsGenExt/Make/files new file mode 100644 index 00000000000..6d18b01b2c5 --- /dev/null +++ b/applications/utilities/preProcessing/viewFactorsGenExt/Make/files @@ -0,0 +1,3 @@ +viewFactorsGenExt.C + +EXE = $(FOAM_APPBIN)/viewFactorsGenExt diff --git a/applications/utilities/preProcessing/viewFactorsGenExt/Make/options b/applications/utilities/preProcessing/viewFactorsGenExt/Make/options new file mode 100644 index 00000000000..2c9476be08f --- /dev/null +++ b/applications/utilities/preProcessing/viewFactorsGenExt/Make/options @@ -0,0 +1,39 @@ +PBRT = /home/sergio/pub/pbrt +PBRTSRC = $(PBRT)/pbrt-v3/src +EXTSRC = $(PBRT)/pbrt-v3/src/ext +GLOGSRC = $(EXTSRC)/glog/src + +PBRTBUILD = /home/sergio/pub/pbrt/pbrt-v3-build +EXTBUILD = $(PBRTBUILD)/src/ext +GLOGBUILD = $(EXTBUILD)/glog + +EXE_INC = \ + -Wno-old-style-cast \ + -I$(PBRTSRC)/core \ + -I$(PBRTSRC)/accelerators \ + -I$(PBRTSRC)/shapes \ + -I$(PBRTSRC) \ + -I$(EXTSRC) \ + -I$(GLOGSRC) \ + -I$(GLOGBUILD) \ + -I./rays \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/surfMesh/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/parallel/distributed/lnInclude \ + +EXE_LIBS = \ + -L$(GLOGBUILD) -lglog \ + -L$(PBRTBUILD) -lpbrt \ + -L$(EXTBUILD)/openexr/OpenEXR/IlmImf -lIlmImf \ + -L$(EXTBUILD)/openexr/IlmBase/Imath -lImath \ + -L$(EXTBUILD)/openexr/IlmBase/Half -lHalf \ + -L$(EXTBUILD)/openexr/IlmBase/Iex -lIex \ + -L$(EXTBUILD)/openexr/IlmBase/IexMath -lIexMath \ + -L$(EXTBUILD)/openexr/IlmBase/IlmThread -lIlmThread \ + -L$(EXTBUILD)/ptex/src/ptex -lPtex \ + -lfiniteVolume \ + -lsurfMesh \ + -lmeshTools \ + -ldistributed \ + -lradiationModels diff --git a/applications/utilities/preProcessing/viewFactorsGenExt/searchingEngineExt.H b/applications/utilities/preProcessing/viewFactorsGenExt/searchingEngineExt.H new file mode 100644 index 00000000000..678899fc7dc --- /dev/null +++ b/applications/utilities/preProcessing/viewFactorsGenExt/searchingEngineExt.H @@ -0,0 +1,121 @@ +Random rndGen(653213); + +// Determine mesh bounding boxes: +List<treeBoundBox> meshBb +( + 1, + treeBoundBox + ( + boundBox(coarseMesh.points(), false) + ).extend(rndGen, 1e-3) +); + +// Dummy bounds dictionary +dictionary dict; +dict.add("bounds", meshBb); +dict.add +( + "distributionType", + distributedTriSurfaceMesh::distributionTypeNames_ + [ + distributedTriSurfaceMesh::FROZEN + ] +); +dict.add("mergeDistance", SMALL); + +labelList triSurfaceToAgglom(5*nFineFaces); + +const triSurface localSurface = triangulate +( + patches, + includePatches, + finalAgglom, + triSurfaceToAgglom, + globalNumbering, + coarsePatches +); + + +distributedTriSurfaceMesh surfacesMesh +( + IOobject + ( + "wallSurface.stl", + runTime.constant(), // directory + "triSurface", // instance + runTime, // registry + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + localSurface, + dict +); + + +triSurfaceToAgglom.resize(surfacesMesh.size()); + +// pbrt surface +std::vector<Point3f> vertices; + +const pointField& pts = surfacesMesh.localPoints(); +for (const auto& pt : pts) +{ + vertices.push_back(Point3f(pt[0], pt[1], pt[2])); +} + +std::vector<int> indices; +for (const auto& tri : surfacesMesh.localFaces()) +{ + indices.push_back(tri[0]); + indices.push_back(tri[1]); + indices.push_back(tri[2]); +} + +std::vector<int> faceIndices; +faceIndices.reserve(surfacesMesh.localFaces().size()); + +for (label faceI = 0; faceI < surfacesMesh.localFaces().size(); faceI++) +{ + faceIndices.push_back(faceI); +} + +Transform o2w; +Transform w2o; + +std::vector<std::shared_ptr<Shape>> surfacesMesh_pbrt +( + CreateTriangleMesh + ( + &o2w, + &w2o, + false, // bool reverseOrientation + surfacesMesh.size(), // int nTriangles + &indices[0], // int *vertexIndices + vertices.size(), + &vertices[0], + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + &faceIndices[0] + ) +); + +std::vector<std::shared_ptr<Primitive>> prims; + +prims.reserve(surfacesMesh_pbrt.size()); +for (auto s : surfacesMesh_pbrt) +{ + prims.push_back + ( + std::make_shared<GeometricPrimitive> + (s, nullptr, nullptr, nullptr) + ); +} + +std::shared_ptr<Primitive> accel; + +ParamSet paramSet; + +accel = CreateBVHAccelerator(std::move(prims), paramSet); diff --git a/applications/utilities/preProcessing/viewFactorsGenExt/shootRaysExt.H b/applications/utilities/preProcessing/viewFactorsGenExt/shootRaysExt.H new file mode 100644 index 00000000000..29ace62fe62 --- /dev/null +++ b/applications/utilities/preProcessing/viewFactorsGenExt/shootRaysExt.H @@ -0,0 +1,196 @@ +// All rays expressed as start face (local) index end end face (global) +// Pre-size by assuming a certain percentage is visible. + +// Maximum length for dynamicList +const label maxDynListLength +( + viewFactorDict.getOrDefault<label>("maxDynListLength", 1000000000) +); + +for (const int proci : Pstream::allProcs()) +{ + + std::vector<pbrt::Point3f> start; + start.reserve(coarseMesh.nFaces()); + std::vector<pbrt::Vector3f> dir; + dir.reserve(start.size()); + + std::vector<pbrt::Point3f> end(start.size()); + end.reserve(start.size()); + + DynamicList<label> startIndex(start.size()); + DynamicList<label> endIndex(start.size()); + + DynamicList<label> startAgg(start.size()); + DynamicList<label> endAgg(start.size()); + + const pointField& myFc = remoteCoarseCf[Pstream::myProcNo()]; + const vectorField& myArea = remoteCoarseSf[Pstream::myProcNo()]; + const labelField& myAgg = remoteCoarseAgg[Pstream::myProcNo()]; + + const pointField& remoteArea = remoteCoarseSf[proci]; + const pointField& remoteFc = remoteCoarseCf[proci]; + const labelField& remoteAgg = remoteCoarseAgg[proci]; + + pbrt::Vector3f smallV(SMALL, SMALL, SMALL); + + label i = 0; + label j = 0; + do + { + for (; i < myFc.size(); i++) + { + const point& fc = myFc[i]; + const vector& fA = myArea[i]; + const label& fAgg = myAgg[i]; + + for (; j < remoteFc.size(); j++) + { + if (proci != Pstream::myProcNo() || i != j) + { + const point& remFc = remoteFc[j]; + const vector& remA = remoteArea[j]; + const label& remAgg = remoteAgg[j]; + + const vector d = remFc - fc; + + const vector nd = d/mag(d); + const vector nfA = fA/mag(fA); + const vector nremA = remA/mag(remA); + + if (((nd & nfA) < 0) && ((nd & nremA) > 0)) + { + pbrt::Vector3f direction(d[0], d[1], d[2]); + direction += smallV; + pbrt::Point3f s(fc[0], fc[1], fc[2]); + end.push_back(s + direction); + + s += pbrt::Point3f(0.01*d[0], 0.01*d[1], 0.01*d[2]); + + start.push_back(s); + startIndex.append(i); + startAgg.append(globalNumbering.toGlobal(proci, fAgg)); + + dir.push_back(direction); + + label globalI = globalNumbering.toGlobal(proci, j); + endIndex.append(globalI); + endAgg.append(globalNumbering.toGlobal(proci, remAgg)); + if (startIndex.size() > maxDynListLength) + { + FatalErrorInFunction + << "Dynamic list need from capacity." + << "Actual size maxDynListLength : " + << maxDynListLength + << abort(FatalError); + } + } + } + } + + if (j == remoteFc.size()) + { + j = 0; + } + } + + } while (i < myFc.size()); + + label totalRays(startIndex.size()); + reduce(totalRays, sumOp<scalar>()); + + if (Pstream::master() && debug) + { + Info<< "Number of rays :" << totalRays << endl; + } + + DynamicList<label> dRayIs; + + std::vector<pbrt::Ray> raysInt; + raysInt.reserve(start.size()); + + std::vector<int> raysTriIndex; + raysTriIndex.reserve(start.size()); + + for (unsigned long rayI = 0; rayI < start.size(); ++rayI) + { + pbrt::Ray ray(start[rayI], dir[rayI]); + + pbrt::SurfaceInteraction isect; + bool intersects = accel->Intersect(ray, &isect); + const Triangle* tri = dynamic_cast<const Triangle *>(isect.shape); + + if (intersects) + { + const int index = tri->faceIndex; + + const Vector3f delta(ray(ray.tMax) - end[rayI]); + + if (delta.Length() < 1e-4) + { + rayStartFace.append(startIndex[rayI]); + rayEndFace.append(endIndex[rayI]); + } + else if (triSurfaceToAgglom[index] == startAgg[rayI]) + { + dRayIs.append(rayI); + raysInt.push_back(ray); + raysTriIndex.push_back(index); + } + } + } + start.clear(); + + labelField rayIs; + rayIs.transfer(dRayIs); + dRayIs.clear(); + + boolList converged(rayIs.size(), false); + label nConverged = 0; + label iter = 0; + do + { + forAll(rayIs, rayI) + { + const label rayID = rayIs[rayI]; + pbrt::Ray& rayHit = raysInt[rayI]; + const int index = raysTriIndex[rayI]; + + if (!converged[rayI]) + { + if (triSurfaceToAgglom[index] == startAgg[rayID]) + { + rayHit.tMax *= 1.1; + rayHit.o = rayHit(rayHit.tMax); + + pbrt::SurfaceInteraction isect; + bool intersects = accel->Intersect(rayHit, &isect); + if (intersects) + { + const Triangle* tri = + dynamic_cast<const Triangle *>(isect.shape); + const int index = tri->faceIndex; + + raysTriIndex[rayI] = index; + } + } + else if (triSurfaceToAgglom[index] == endAgg[rayID]) + { + converged[rayI] = true; + nConverged++; + rayStartFace.append(startIndex[rayID]); + rayEndFace.append(endIndex[rayID]); + } + } + } + + iter ++; + + } while (nConverged < converged.size() && iter < 10); + + startIndex.clear(); + end.clear(); + endIndex.clear(); + startAgg.clear(); + endAgg.clear(); +} diff --git a/applications/utilities/preProcessing/viewFactorsGenExt/viewFactorsGenExt.C b/applications/utilities/preProcessing/viewFactorsGenExt/viewFactorsGenExt.C new file mode 100644 index 00000000000..ed63ff59752 --- /dev/null +++ b/applications/utilities/preProcessing/viewFactorsGenExt/viewFactorsGenExt.C @@ -0,0 +1,1224 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 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 <http://www.gnu.org/licenses/>. + +Application + viewFactorsGenExt + +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 whenre 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: + + tolGaussQuad 0.1; // GaussQuad error + distTol 8; // R/Average(rm) + alpha 0.22; // Use for common edges for 2LI + + + For debugging purposes, the following entries can be set in viewFactorsDict: + + writeViewFactorMatrix true; + writeFacesAgglomeration false; + dumpRays false; + + + writeViewFactorMatrix writes the sum of the VF on each face. + writeFacesAgglomeration writes the agglomeration + dumpRays dumps rays + + + In order to specify the participants patches in the VF calculation the + keywaord viewFactorWall should be added to the boundary file. + + floor + { + type wall; + inGroups 2(wall viewFactorWall); + nFaces 100; + startFace 3100; + } + +\*---------------------------------------------------------------------------*/ + +#include "argList.H" +#include "fvMesh.H" +#include "volFields.H" +#include "surfaceFields.H" +#include "distributedTriSurfaceMesh.H" +#include "meshTools.H" +#include "constants.H" + +#include "uindirectPrimitivePatch.H" +#include "DynamicField.H" +#include "unitConversion.H" + +#include "scalarMatrices.H" +#include "labelListIOList.H" +#include "scalarListIOList.H" + +#include "singleCellFvMesh.H" + +#include "IOmapDistribute.H" + +#define PBRT_CONSTEXPR constexpr +#define PBRT_THREAD_LOCAL thread_local + +#include "pbrt.h" +#include "shape.h" +#include "triangle.h" +#include "geometry.h" +#include "paramset.h" + +#include "accelerators/bvh.h" + +using namespace Foam; +using namespace Foam::constant; +using namespace Foam::constant::mathematical; +using namespace pbrt; + + +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<labelledTri> 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 rawSurface(triangles, mesh.points()); + + triSurface surface + ( + rawSurface.localFaces(), + rawSurface.localPoints() + ); + + // Combine the triSurfaces across all processors + if (Pstream::parRun()) + { + List<List<labelledTri>> surfaceProcTris(Pstream::nProcs()); + List<pointField> surfaceProcPoints(Pstream::nProcs()); + + surfaceProcTris[Pstream::myProcNo()] = surface; + surfaceProcPoints[Pstream::myProcNo()] = surface.points(); + + Pstream::gatherList(surfaceProcTris); + Pstream::scatterList(surfaceProcTris); + Pstream::gatherList(surfaceProcPoints); + Pstream::scatterList(surfaceProcPoints); + + label nTris = 0; + forAll(surfaceProcTris, i) + { + nTris += surfaceProcTris[i].size(); + } + + List<labelledTri> globalSurfaceTris(nTris); + label trii = 0; + label offset = 0; + forAll(surfaceProcTris, i) + { + forAll(surfaceProcTris[i], j) + { + globalSurfaceTris[trii] = surfaceProcTris[i][j]; + globalSurfaceTris[trii][0] += offset; + globalSurfaceTris[trii][1] += offset; + globalSurfaceTris[trii][2] += offset; + trii++; + } + offset += surfaceProcPoints[i].size(); + } + + label nPoints = 0; + forAll(surfaceProcPoints, i) + { + nPoints += surfaceProcPoints[i].size(); + } + + pointField globalSurfacePoints(nPoints); + + label pointi = 0; + forAll(surfaceProcPoints, i) + { + forAll(surfaceProcPoints[i], j) + { + globalSurfacePoints[pointi++] = surfaceProcPoints[i][j]; + } + } + + surface = triSurface(globalSurfaceTris, globalSurfacePoints); + } + + // 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<vector> pi(w.size()); + forAll (pi, i) + { + pi[i] = ci + p[i]*(magSi/2)*di; + } + + + List<vector> 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_IF_MODIFIED, + 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<label>("debug", 0); + + const scalar tolGaussQuad = + viewFactorDict.getOrDefault<scalar>("tolGaussQuad", 0.01); + + const scalar distTol = + viewFactorDict.getOrDefault<scalar>("distTol", 8); + + const scalar alpha = + viewFactorDict.getOrDefault<scalar>("alpha", 0.21); + + // Read agglomeration map + labelListIOList finalAgglom + ( + IOobject + ( + "finalAgglom", + mesh.facesInstance(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ); + + // Create the coarse mesh using agglomeration + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + if (debug) + { + Pout << "\nCreating single cell mesh..." << endl; + } + + singleCellFvMesh coarseMesh + ( + IOobject + ( + "coarse:" + mesh.name(), + runTime.timeName(), + runTime, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh, + finalAgglom + ); + + if (debug) + { + Pout << "\nCreated single cell mesh..." << endl; + } + + + // Calculate total number of fine and coarse faces + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + label nCoarseFaces = 0; //total number of coarse faces + label nFineFaces = 0; //total number of fine faces + + const polyBoundaryMesh& patches = mesh.boundaryMesh(); + const polyBoundaryMesh& coarsePatches = coarseMesh.boundaryMesh(); + + labelList viewFactorsPatches(patches.indices(viewFactorWall)); + for (const label patchi : viewFactorsPatches) + { + nCoarseFaces += coarsePatches[patchi].size(); + nFineFaces += patches[patchi].size(); + } + + // total number of coarse faces + label totalNCoarseFaces = nCoarseFaces; + + reduce(totalNCoarseFaces, sumOp<label>()); + + if (Pstream::master()) + { + Info << "\nTotal number of coarse faces: "<< totalNCoarseFaces << endl; + } + + if (Pstream::master() && debug) + { + Pout << "\nView factor patches included in the calculation : " + << viewFactorsPatches << endl; + } + + // Collect local Cf and Sf on coarse mesh + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + DynamicList<point> localCoarseCf(nCoarseFaces); + DynamicList<point> localCoarseSf(nCoarseFaces); + DynamicList<label> localAgg(nCoarseFaces); + labelHashSet includePatches; + + for (const label patchID : viewFactorsPatches) + { + const polyPatch& pp = patches[patchID]; + const labelList& agglom = finalAgglom[patchID]; + + includePatches.insert(patchID); + + if (agglom.size() > 0) + { + label nAgglom = max(agglom)+1; + labelListList coarseToFine(invertOneToMany(nAgglom, agglom)); + const labelList& coarsePatchFace = + coarseMesh.patchFaceMap()[patchID]; + + const pointField& coarseCf = + coarseMesh.Cf().boundaryField()[patchID]; + const pointField& coarseSf = + coarseMesh.Sf().boundaryField()[patchID]; + + forAll(coarseCf, faceI) + { + point cf = coarseCf[faceI]; + + const label coarseFaceI = coarsePatchFace[faceI]; + const labelList& fineFaces = coarseToFine[coarseFaceI]; + const label agglomI = + agglom[fineFaces[0]] + coarsePatches[patchID].start(); + + // Construct single face + uindirectPrimitivePatch upp + ( + UIndirectList<face>(pp, fineFaces), + pp.points() + ); + + List<point> availablePoints + ( + upp.faceCentres().size() + + upp.localPoints().size() + ); + + SubList<point> + ( + availablePoints, + upp.faceCentres().size() + ) = upp.faceCentres(); + + SubList<point> + ( + availablePoints, + upp.localPoints().size(), + upp.faceCentres().size() + ) = upp.localPoints(); + + point cfo = cf; + scalar dist = GREAT; + forAll(availablePoints, iPoint) + { + point cfFine = availablePoints[iPoint]; + if (mag(cfFine-cfo) < dist) + { + dist = mag(cfFine-cfo); + cf = cfFine; + } + } + + point sf = coarseSf[faceI]; + localCoarseCf.append(cf); + localCoarseSf.append(sf); + localAgg.append(agglomI); + + } + } + } + + // Distribute local coarse Cf and Sf for shooting rays + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + List<pointField> remoteCoarseCf(Pstream::nProcs()); + List<pointField> remoteCoarseSf(Pstream::nProcs()); + List<labelField> remoteCoarseAgg(Pstream::nProcs()); + + remoteCoarseCf[Pstream::myProcNo()] = localCoarseCf; + remoteCoarseSf[Pstream::myProcNo()] = localCoarseSf; + remoteCoarseAgg[Pstream::myProcNo()] = localAgg; + + Pstream::gatherList(remoteCoarseCf); + Pstream::scatterList(remoteCoarseCf); + Pstream::gatherList(remoteCoarseSf); + Pstream::scatterList(remoteCoarseSf); + Pstream::gatherList(remoteCoarseAgg); + Pstream::scatterList(remoteCoarseAgg); + + + globalIndex globalNumbering(nCoarseFaces); + + // Set up searching engine for obstacles + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + #include "searchingEngineExt.H" + + // Determine rays between coarse face centres + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + DynamicList<label> rayStartFace(nCoarseFaces + 0.01*nCoarseFaces); + + DynamicList<label> rayEndFace(rayStartFace.size()); + + // Return rayStartFace in local index and rayEndFace in global index + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + #include "shootRaysExt.H" + + // Calculate number of visible faces from local index + labelList nVisibleFaceFaces(nCoarseFaces, Zero); + + forAll(rayStartFace, i) + { + nVisibleFaceFaces[rayStartFace[i]]++; + } + + labelListList visibleFaceFaces(nCoarseFaces); + + label nViewFactors = 0; + forAll(nVisibleFaceFaces, faceI) + { + visibleFaceFaces[faceI].setSize(nVisibleFaceFaces[faceI]); + nViewFactors += nVisibleFaceFaces[faceI]; + } + + // - Construct compact numbering + // - return map from remote to compact indices + // (per processor (!= myProcNo) a map from remote index to compact index) + // - construct distribute map + // - renumber rayEndFace into compact addressing + + List<Map<label>> compactMap(Pstream::nProcs()); + + mapDistribute map(globalNumbering, rayEndFace, compactMap); + + // visibleFaceFaces has: + // (local face, local viewed face) = compact viewed face + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + nVisibleFaceFaces = 0; + forAll(rayStartFace, i) + { + label faceI = rayStartFace[i]; + label compactI = rayEndFace[i]; + visibleFaceFaces[faceI][nVisibleFaceFaces[faceI]++] = compactI; + } + + // Construct data in compact addressing + // (2AA) need coarse (Ai), fine Sf (dAi) and fine Cf(r) to calculate Fij + // (2LI) need edges (li) + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + pointField compactCoarseCf(map.constructSize(), Zero); + pointField compactCoarseSf(map.constructSize(), Zero); + List<List<point>> compactFineSf(map.constructSize()); + List<List<point>> compactFineCf(map.constructSize()); + + DynamicList<List<point>> compactPoints(map.constructSize()); + + DynamicList<label> compactPatchId(map.constructSize()); + + // Insert my coarse local values + SubList<point>(compactCoarseSf, nCoarseFaces) = localCoarseSf; + SubList<point>(compactCoarseCf, nCoarseFaces) = localCoarseCf; + + const faceList& faces = mesh.faces(); + + // Insert my fine local values + label compactI = 0; + forAll(viewFactorsPatches, i) + { + label patchID = viewFactorsPatches[i]; + + const labelList& agglom = finalAgglom[patchID]; + if (agglom.size() > 0) + { + label nAgglom = max(agglom)+1; + labelListList coarseToFine(invertOneToMany(nAgglom, agglom)); + const labelList& coarsePatchFace = + coarseMesh.patchFaceMap()[patchID]; + + const polyPatch& pp = patches[patchID]; + + forAll(coarseToFine, coarseI) + { + compactPatchId.append(patchID); + List<point>& fineCf = compactFineCf[compactI]; + List<point>& fineSf = compactFineSf[compactI]; + + label startFace = pp.start(); + + const vectorField locPoints + ( + mesh.points(), + faces[coarseI + startFace] + ); + + const label coarseFaceI = coarsePatchFace[coarseI]; + const labelList& fineFaces = coarseToFine[coarseFaceI]; + + fineCf.setSize(fineFaces.size()); + fineSf.setSize(fineFaces.size()); + + compactPoints.append(locPoints); + + fineCf = UIndirectList<point> + ( + mesh.Cf().boundaryField()[patchID], + coarseToFine[coarseFaceI] + ); + fineSf = UIndirectList<point> + ( + mesh.Sf().boundaryField()[patchID], + coarseToFine[coarseFaceI] + ); + + compactI++; + } + } + } + + if (Pstream::master()) + { + Info<< "map distribute..." << endl; + } + + // Do all swapping + map.distribute(compactCoarseSf); + map.distribute(compactCoarseCf); + map.distribute(compactFineCf); + map.distribute(compactFineSf); + + map.distribute(compactPoints); + + map.distribute(compactPatchId); + + // Plot all rays between visible faces. + if (dumpRays) + { + writeRays + ( + runTime.path()/"allVisibleFaces.obj", + compactCoarseCf, + remoteCoarseCf[Pstream::myProcNo()], + visibleFaceFaces + ); + } + + + // Fill local view factor matrix + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + scalarListIOList F2LI + ( + IOobject + ( + "F", + mesh.facesInstance(), + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ), + nCoarseFaces + ); + + label totalPatches = coarsePatches.size(); + reduce(totalPatches, maxOp<label>()); + + // Matrix sum in j(Fij) for each i (if enclosure sum = 1) + scalarSquareMatrix sumViewFactorPatch + ( + totalPatches, + 0.0 + ); + + scalarList patchArea(totalPatches, Zero); + + if (Pstream::master()) + { + Info<< "\nCalculating view factors..." << endl; + } + + List<scalarList> GaussPoints(5); + GaussPoints[0].setSize(1); + GaussPoints[0] = 0; + + GaussPoints[1].setSize(2); + GaussPoints[1][0] = 1/std::sqrt(3); + GaussPoints[1][1] = -1/std::sqrt(3); + + GaussPoints[2].setSize(3); + GaussPoints[2][0] = 0; + GaussPoints[2][1] = 0.774597; + GaussPoints[2][2] = -0.774597; + + GaussPoints[3].setSize(4); + GaussPoints[3][0] = 0.339981; + GaussPoints[3][1] = -0.339981; + GaussPoints[3][2] = 0.861136; + GaussPoints[3][3] = -0.861136; + + GaussPoints[4].setSize(5); + GaussPoints[4][0] = 0; + GaussPoints[4][1] = 0.538469; + GaussPoints[4][2] = -0.538469; + GaussPoints[4][3] = 0.90618; + GaussPoints[4][4] = -0.90618; + + + List<scalarList> GaussWeights(5); + GaussWeights[0].setSize(1); + GaussWeights[0] = 2; + + GaussWeights[1].setSize(2); + GaussWeights[1][0] = 1; + GaussWeights[1][1] = 1; + + GaussWeights[2].setSize(3); + GaussWeights[2][0] = 0.888889; + GaussWeights[2][1] = 0.555556; + GaussWeights[2][2] = 0.555556; + + GaussWeights[3].setSize(4); + GaussWeights[3][0] = 0.652145; + GaussWeights[3][1] = 0.652145; + GaussWeights[3][2] = 0.347855; + GaussWeights[3][3] = 0.347855; + + GaussWeights[4].setSize(5); + GaussWeights[4][0] = 0.568889; + GaussWeights[4][1] = 0.478629; + GaussWeights[4][2] = 0.478629; + GaussWeights[4][3] = 0.236927; + GaussWeights[4][4] = 0.236927; + + label maxQuadOrder = 5; + + if (mesh.nSolutionD() == 3) + { + forAll(localCoarseSf, coarseFaceI) + { + const List<point>& localFineSf = compactFineSf[coarseFaceI]; + const vector Ai = sum(localFineSf); + const List<point>& localFineCf = compactFineCf[coarseFaceI]; + const label fromPatchId = compactPatchId[coarseFaceI]; + + const List<point>& lPoints = compactPoints[coarseFaceI]; + + patchArea[fromPatchId] += mag(Ai); + + const labelList& visCoarseFaces = visibleFaceFaces[coarseFaceI]; + + forAll(visCoarseFaces, visCoarseFaceI) + { + //F2AI[coarseFaceI].setSize(visCoarseFaces.size()); + F2LI[coarseFaceI].setSize(visCoarseFaces.size()); + label compactJ = visCoarseFaces[visCoarseFaceI]; + const List<point>& remoteFineSj = compactFineSf[compactJ]; + const List<point>& remoteFineCj = compactFineCf[compactJ]; + + const List<point>& rPointsCj = compactPoints[compactJ]; + + const label toPatchId = compactPatchId[compactJ]; + + bool far(false); + // Relative distance + forAll(localFineSf, i) + { + const scalar dAi = + Foam::sqrt + ( + mag(localFineSf[i])/constant::mathematical::pi + ); + const vector& dCi = localFineCf[i]; + + forAll(remoteFineSj, j) + { + const scalar dAj = + Foam::sqrt + ( + mag(remoteFineSj[j])/constant::mathematical::pi + ); + const vector& dCj = remoteFineCj[j]; + + const scalar dist = mag(dCi - dCj)/((dAi + dAj)/2); + + if (dist > distTol) + { + far = true; + } + } + } + + if (far) + { + // 2AI method + scalar F2AIij = 0; + + forAll(localFineSf, i) + { + const vector& dAi = localFineSf[i]; + const vector& dCi = localFineCf[i]; + + forAll(remoteFineSj, j) + { + const vector& dAj = remoteFineSj[j]; + const vector& dCj = remoteFineCj[j]; + + scalar dIntFij = calculateViewFactorFij2AI + ( + dCi, + dCj, + dAi, + dAj + ); + + F2AIij += dIntFij; + } + } + F2LI[coarseFaceI][visCoarseFaceI] = F2AIij/mag(Ai); + } + else + { + // 2LI method + label nLocal = lPoints.size(); + label nRemote = rPointsCj.size(); + + // Using sub-divisions (quadrature) + scalar oldEToeInt = 0; + for (label gi=0; gi < maxQuadOrder; gi++) + { + scalar F2LIij = 0; + for(label i=0; i<nLocal; i++) + { + vector si; + vector ci; + + vector sj; + vector cj; + + if (i == 0) + { + si = lPoints[i] - lPoints[nLocal-1]; + ci = (lPoints[i] + lPoints[nLocal-1])/2; + } + else + { + si = lPoints[i] - lPoints[i-1]; + ci = (lPoints[i] + lPoints[i-1])/2; + } + + for(label j=0; j<nRemote; j++) + { + if (j == 0) + { + sj = rPointsCj[j]-rPointsCj[nRemote-1]; + cj = (rPointsCj[j]+rPointsCj[nRemote-1])/2; + } + else + { + sj = rPointsCj[j] - rPointsCj[j-1]; + cj = (rPointsCj[j] + rPointsCj[j-1])/2; + } + + + scalar magSi = mag(si); + scalar magSj = mag(sj); + scalar cosij = (si & sj)/(magSi * magSj); + + vector di = si/magSi; + vector dj = sj/magSj; + + label quadOrder = gi; + const vector r(ci - cj); + // Common edges use n = 0 + if (mag(r) < SMALL) + { + quadOrder = 0; + } + + scalar dIntFij = + GaussQuad + ( + GaussWeights[gi], + GaussPoints[gi], + magSi, + magSj, + di, + dj, + ci, + cj, + cosij, + alpha, + quadOrder + ); + + F2LIij += dIntFij; + } + } + + scalar err = (F2LIij-oldEToeInt)/F2LIij; + + if + ( + (mag(err) < tolGaussQuad && gi > 0) + || gi == maxQuadOrder-1 + ) + { + //DebugVar(gi) + F2LI[coarseFaceI][visCoarseFaceI] = + F2LIij/mag(Ai)/4/constant::mathematical::pi; + break; + } + else + { + oldEToeInt = F2LIij; + } + } + } + + sumViewFactorPatch[fromPatchId][toPatchId] += + F2LI[coarseFaceI][visCoarseFaceI]*mag(Ai); + } + } + } + else + { + FatalErrorInFunction + << " View factors are not available in 2D " + << exit(FatalError); + } + + + + // Write view factors matrix in listlist form + F2LI.write(); + + reduce(sumViewFactorPatch, sumOp<scalarSquareMatrix>()); + reduce(patchArea, sumOp<scalarList>()); + + if (Pstream::master() && debug) + { + forAll(viewFactorsPatches, i) + { + label patchI = viewFactorsPatches[i]; + for (label j=i; j<viewFactorsPatches.size(); j++) + { + label patchJ = viewFactorsPatches[j]; + + Info << "F" << patchI << patchJ << ": " + << sumViewFactorPatch[patchI][patchJ]/patchArea[patchI] + << endl; + } + } + } + + if (writeViewFactors) + { + if (Pstream::master()) + { + Info << "Writing view factor matrix..." << endl; + } + + volScalarField viewFactorField + ( + IOobject + ( + "viewFactorField", + mesh.time().timeName(), + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh, + dimensionedScalar(dimless, Zero) + ); + + label compactI = 0; + + volScalarField::Boundary& vfbf = viewFactorField.boundaryFieldRef(); + forAll(viewFactorsPatches, i) + { + label patchID = viewFactorsPatches[i]; + const labelList& agglom = finalAgglom[patchID]; + if (agglom.size() > 0) + { + label nAgglom = max(agglom)+1; + labelListList coarseToFine(invertOneToMany(nAgglom, agglom)); + const labelList& coarsePatchFace = + coarseMesh.patchFaceMap()[patchID]; + + forAll(coarseToFine, coarseI) + { + scalar FiSum = sum(F2LI[compactI]); + + const label coarseFaceID = coarsePatchFace[coarseI]; + const labelList& fineFaces = coarseToFine[coarseFaceID]; + forAll(fineFaces, fineId) + { + const label faceID = fineFaces[fineId]; + vfbf[patchID][faceID] = FiSum; + } + compactI++; + } + } + } + viewFactorField.write(); + } + + + // Invert compactMap (from processor+localface to compact) to go + // from compact to processor+localface (expressed as a globalIndex) + // globalIndex globalCoarFaceNum(coarseMesh.nFaces()); + labelList compactToGlobal(map.constructSize()); + + // Local indices first (note: are not in compactMap) + for (label i = 0; i < globalNumbering.localSize(); i++) + { + compactToGlobal[i] = globalNumbering.toGlobal(i); + } + + + forAll(compactMap, procI) + { + const Map<label>& localToCompactMap = compactMap[procI]; + + forAllConstIters(localToCompactMap, iter) + { + compactToGlobal[*iter] = globalNumbering.toGlobal + ( + procI, + iter.key() + ); + } + } + + + labelListList globalFaceFaces(visibleFaceFaces.size()); + + // Create globalFaceFaces needed to insert view factors + // in F to the global matrix Fmatrix + forAll(globalFaceFaces, faceI) + { + globalFaceFaces[faceI] = renumber + ( + compactToGlobal, + visibleFaceFaces[faceI] + ); + } + + labelListIOList IOglobalFaceFaces + ( + IOobject + ( + "globalFaceFaces", + mesh.facesInstance(), + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ), + std::move(globalFaceFaces) + ); + IOglobalFaceFaces.write(); + + + IOmapDistribute IOmapDist + ( + IOobject + ( + "mapDist", + mesh.facesInstance(), + mesh, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + std::move(map) + ); + + IOmapDist.write(); + + Info<< "End\n" << endl; + return 0; +} + + +// ************************************************************************* // diff --git a/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C b/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C index e1f8e4c8cff..cbfa9005bea 100644 --- a/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C +++ b/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C @@ -35,6 +35,8 @@ License #include "boundaryRadiationProperties.H" #include "lduCalculatedProcessorField.H" + + using namespace Foam::constant; // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -- GitLab