/*---------------------------------------------------------------------------*\
========= |
\\ / 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