diff --git a/applications/utilities/preProcessing/createViewFactors/Allwmake b/applications/utilities/preProcessing/createViewFactors/Allwmake new file mode 100755 index 0000000000000000000000000000000000000000..9de13a5b033475b4a416150305a0e8467984c408 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/Allwmake @@ -0,0 +1,11 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory + + . "$WM_PROJECT_DIR"/wmake/scripts/AllwmakeParseArguments + +#------------------------------------------------------------------------------ + +wmake $targetType viewFactorModels +wmake $targetType createViewFactors + +#------------------------------------------------------------------------------ diff --git a/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/files b/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..3f36ae84ca3c63749236d04150032f210a9ed0d2 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/files @@ -0,0 +1,3 @@ +createViewFactors.C + +EXE = $(FOAM_APPBIN)/createViewFactors diff --git a/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/options b/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/options new file mode 100644 index 0000000000000000000000000000000000000000..71f2b983ab772cd5be2b024557291d0631d3a301 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/createViewFactors/Make/options @@ -0,0 +1,7 @@ +EXE_INC = \ + -I../viewFactorModels/lnInclude \ + -I$(LIB_SRC)/finiteVolume/lnInclude + +EXE_LIBS = \ + -lviewFactorModels \ + -lfiniteVolume diff --git a/applications/utilities/preProcessing/createViewFactors/createViewFactors/createViewFactors.C b/applications/utilities/preProcessing/createViewFactors/createViewFactors/createViewFactors.C new file mode 100644 index 0000000000000000000000000000000000000000..84ad369a99c67a71488945ea16268015ef015a6b --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/createViewFactors/createViewFactors.C @@ -0,0 +1,165 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023 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 + createViewFactors + +Group + grpPreProcessingUtilities + +Description + Creates view factors to be used in the view-factor radiation model. + + Operands: + \table + Operand | Type | Location + input | dictionary | \<constant\>/viewFactorsDict + input | dictionary | \<constant\>/finalAgglom + output | scalarListList | \<constant\>/F + output | mapDistribute | \<constant\>/mapDist + output | labelListList | \<constant\>/globalFaceFaces + output | volScalarField | \<time\>/viewVectorField + output | OBJ | allVisibleFaces.obj + \endtable + + where the dictionaries mean: + \table + Dictionary | Description + viewFactorsDict | Main-control dictionary + finalAgglom | (Optional) Agglomeration addressing (from faceAgglomerate) + F | View factors (matrix) + mapDist | Map used for parallel running + globalFaceFaces | Face addressing + viewVectorField | View factors as a volume field + allVisibleFaces.obj | The visualisation of the rays + \endtable + +Usage + Minimal example in \c <constant>/viewFactorsDict: + \verbatim + // Inherited entries + raySearchEngine <word>; + agglomerate <bool>; + nRayPerFace <label>; + writeViewFactors <bool>; + writeRays <bool>; + ... + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Reqd | Deflt + raySearchEngine | Ray search engine type | word | yes | - + agglomerate | Flag to agglomeration | bool | yes | - + nRayPerFace | Number of rays issued per face | label | yes | - + writeViewFactors | Flag to write the view factor field | bool | yes |- + writeRays | Flag to write the ray geometry | bool | no | false + \endtable + + Options for the \c raySearchEngine entry: + \verbatim + voxel | Ray search engine discretising space into uniform voxels + \endverbatim + + The inherited entries are elaborated in: + - \link viewFactorModel.H \endlink + - \link raySearchEngine.H \endlink + +Note + + - Participating patches must be in the \c vewFactorWall group, i.e. using the + \c inGroups entry of the "\<case\>/polyMesh/boundary" file. + + \verbatim + myPatch + { + type wall; + inGroups 2(wall viewFactorWall); + ... + } + \endverbatim + + Reads: + + - <constant>/viewFactorsDict : main controls + - <constant>/finalAgglom : agglomeration addressing (from faceAgglomerate) + + + Generates: + + - <constant>/F : view factors (matrix) + - <constant>/mapDist : map used for parallel running + - <constant>/globalFaceFaces : face addressing + +SeeAlso +- Foam::VF::raySearchEngine +- Foam::VE::viewFactorModel + +\*---------------------------------------------------------------------------*/ + +#include "argList.H" +#include "Time.H" +#include "fvMesh.H" +#include "viewFactorModel.H" + +using namespace Foam; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +int main(int argc, char *argv[]) +{ + #include "addRegionOption.H" + #include "setRootCase.H" + #include "createTime.H" + #include "createNamedMesh.H" + + IOdictionary dict + ( + IOobject + ( + "viewFactorsDict", + runTime.constant(), + mesh, + IOobject::MUST_READ + ) + ); + + + // Calculate the view factors + auto modelPtr = VF::viewFactorModel::New(mesh, dict); + + modelPtr->calculate(); + + Info<< nl; + + runTime.printExecutionTime(Info); + + Info<< "End\n" << endl; + + return 0; +} + + +// ************************************************************************* // \ No newline at end of file diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/files b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..eddbe68d672cb51ff132a2a792ebb6c1cc206627 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/files @@ -0,0 +1,12 @@ +raySearchEngine/raySearchEngine/raySearchEngine.C +raySearchEngine/raySearchEngine/raySearchEngineNew.C +raySearchEngine/voxel/voxelRaySearchEngine.C +/* raySearchEngine/nonUniformVoxel/nonUniformVoxelRaySearchEngine.C */ +/* raySearchEngine/allToAll/allToAllRaySearchEngine.C */ +viewFactorModel/viewFactorModel/viewFactorModel.C +viewFactorModel/viewFactorModel/viewFactorModelNew.C +viewFactorModel/viewFactor2AI/viewFactor2AI.C +viewFactorModel/viewFactor2LI/viewFactor2LI.C +viewFactorModel/viewFactorHottel/viewFactorHottel.C + +LIB = $(FOAM_LIBBIN)/libviewFactorModels diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/options b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/options new file mode 100644 index 0000000000000000000000000000000000000000..ddcc52fdc7bfa96f701e0225c7149bd8e5263eb9 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/Make/options @@ -0,0 +1,14 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/surfMesh/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/parallel/distributed/lnInclude \ + -I$(LIB_SRC)/fileFormats/lnInclude + +EXE_LIBS = \ + -lfiniteVolume \ + -lsurfMesh \ + -lmeshTools \ + -ldistributed \ + -lradiationModels \ + -lfileFormats diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C new file mode 100644 index 0000000000000000000000000000000000000000..f1a37bbc5f389adc3274f29c3adf730e272c5d76 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C @@ -0,0 +1,620 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "raySearchEngine.H" +#include "surfaceFields.H" +#include "volFields.H" +#include "meshTools.H" + +using namespace Foam::constant; + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(raySearchEngine, 0); + defineRunTimeSelectionTable(raySearchEngine, mesh); + + const label raySearchEngine::maxDynListLength = 1000000000; +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::VF::raySearchEngine::check +( + const labelList& nVisibleFaceFaces +) +{ + label nRay = 0; + label nFaceMin = labelMax; + label nFaceMax = labelMin; + for (const label n : nVisibleFaceFaces) + { + nFaceMin = min(nFaceMin, n); + nFaceMax = max(nFaceMax, n); + nRay += n; + } + + const label nFace = nVisibleFaceFaces.size(); + const label nGlobalRays = returnReduce(nRay, sumOp<label>()); + + if (nGlobalRays == 0) + { + FatalErrorInFunction + << "No rays identified - view factors will not be calculated" + << exit(FatalError); + } + + const label globalNFacesMin = returnReduce(nFaceMin, minOp<label>()); + const label globalNFacesMax = returnReduce(nFaceMax, maxOp<label>()); + const label nGlobalFaces = returnReduce(nFace, sumOp<label>()); + const scalar avgFaces = nGlobalRays/scalar(nGlobalFaces); + + Info<< "\nRay summary:" << nl + << " Number of rays: " << nGlobalRays << nl + << " Number of rays-per-face (min, max, average): (" + << globalNFacesMin << ", " + << globalNFacesMax << ", " + << avgFaces << ")" << endl; +} + + +Foam::label Foam::VF::raySearchEngine::closestPointIndex +( + const point& p0, + const List<point>& pts +) +{ + label pointi = -1; + + scalar distSqr = GREAT; + forAll(pts, pti) + { + const scalar d2 = magSqr(pts[pti] - p0); + if (d2 < distSqr) + { + pointi = pti; + distSqr = d2; + } + } + + return pointi; +} + + +void Foam::VF::raySearchEngine::createAgglomeration(const IOobject& io) +{ + Info<< "\nFace agglomeration: active" << nl + << " Reading file " << io.name() << endl; + + // Read agglomeration map + const labelListIOList finalAgglom(io); + + Info<< " Creating coarse mesh" << nl; + + agglomMeshPtr_.reset + ( + new singleCellFvMesh + ( + IOobject + ( + IOobject::scopedName("agglom", mesh_.name()), + mesh_.time().timeName(), + mesh_.time(), + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + finalAgglom + ) + ); + + const auto& coarseMesh = agglomMeshPtr_(); + + + // Calculate total number of fine and coarse faces + + nCoarseFace_ = 0; + nFace_ = 0; + + const polyBoundaryMesh& finePatches = mesh_.boundaryMesh(); + const polyBoundaryMesh& coarsePatches = coarseMesh.boundaryMesh(); + + for (const label patchi : patchIDs_) + { + nCoarseFace_ += coarsePatches[patchi].size(); + nFace_ += finePatches[patchi].size(); + } + + Info<< "\nTotal number of coarse faces: " + << returnReduce(nCoarseFace_, sumOp<label>()) + << endl; + + Info<< "\nTotal number of fine faces: " + << returnReduce(nFace_, sumOp<label>()) + << endl; + + // Collect local Cf, Sf, agglom index on coarse mesh + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + DynamicList<point> localCf(nCoarseFace_); + DynamicList<vector> localSf(nCoarseFace_); + DynamicList<label> localAgg(nCoarseFace_); + + for (const label patchi : patchIDs_) + { + const labelList& agglom = finalAgglom[patchi]; + + if (agglom.empty()) continue; + + label nAgglom = max(agglom) + 1; + const labelListList coarseToFine(invertOneToMany(nAgglom, agglom)); + const labelList& coarsePatchFace = coarseMesh.patchFaceMap()[patchi]; + + const pointField& coarseCf = coarseMesh.Cf().boundaryField()[patchi]; + const vectorField& coarseSf = coarseMesh.Sf().boundaryField()[patchi]; + + const polyPatch& pp = finePatches[patchi]; + patchAreas_[patchi] += sum(coarseMesh.magSf().boundaryField()[patchi]); + + forAll(coarseCf, facei) + { + const label coarseFacei = coarsePatchFace[facei]; + const label agglomi = coarseFacei + coarsePatches[patchi].start(); + + // Construct single coarse face + const labelList& fineFaces = coarseToFine[coarseFacei]; + uindirectPrimitivePatch cf + ( + UIndirectList<face>(pp, fineFaces), + pp.points() + ); + + // Collect all points (vertices, face centres) + const label nFaces = cf.faceCentres().size(); + const label nPoints = cf.localPoints().size(); + List<point> allPoints(nFaces + nPoints); + SubList<point>(allPoints, nFaces) = cf.faceCentres(); + SubList<point>(allPoints, nPoints, nFaces) = cf.localPoints(); + + // Coarse face centre set to closest point + const label pti = closestPointIndex(coarseCf[facei], allPoints); + + if (pti != -1) + { + localCf.push_back(allPoints[pti]); + localSf.push_back(coarseSf[facei]); + localAgg.push_back(agglomi); + } + } + } + + Info<< "\nAssembled coarse patch data" << endl; + + // Distribute local coarse Cf and Sf for shooting rays + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + allCf_[Pstream::myProcNo()].transfer(localCf); + allSf_[Pstream::myProcNo()].transfer(localSf); + allAgg_[Pstream::myProcNo()].transfer(localAgg); + + Pstream::allGatherList(allCf_); + Pstream::allGatherList(allSf_); + Pstream::allGatherList(allAgg_); + + Pstream::listCombineGather(patchAreas_, plusEqOp<scalar>()); + Pstream::broadcast(patchAreas_); + + globalNumbering_ = globalIndex(nCoarseFace_); +} + + +void Foam::VF::raySearchEngine::createGeometry() +{ + DynamicList<point> localCf(mesh_.nBoundaryFaces()); + DynamicList<vector> localSf(mesh_.nBoundaryFaces()); + + const auto& pbm = mesh_.boundaryMesh(); + + for (const label patchi : patchIDs_) + { + localCf.push_back(pbm[patchi].faceCentres()); + localSf.push_back(pbm[patchi].faceAreas()); + + patchAreas_[patchi] += sum(mesh_.magSf().boundaryField()[patchi]); + } + + Info<< "\nAssembled patch data" << endl; + + nFace_ = localCf.size(); + nCoarseFace_ = -1; + + allCf_[Pstream::myProcNo()].transfer(localCf); + allSf_[Pstream::myProcNo()].transfer(localSf); + + Pstream::allGatherList(allCf_); + Pstream::allGatherList(allSf_); + + Pstream::listCombineGather(patchAreas_, plusEqOp<scalar>()); + Pstream::broadcast(patchAreas_); + + globalNumbering_ = globalIndex(nFace_); +} + + +void Foam::VF::raySearchEngine::createParallelAddressing +( + labelList& rayEndFace +) const +{ + // 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 + + DebugInfo << "\nCreating map distribute" << endl; + + List<Map<label>> compactMap(Pstream::nProcs()); + mapPtr_.reset(new mapDistribute(globalNumbering_, rayEndFace, compactMap)); + + DebugInfo << "\nCreating compact-to-global addressing" << endl; + + // Invert compactMap (from processor+localface to compact) to go + // from compact to processor+localface (expressed as a globalIndex) + compactToGlobal_.resize_nocopy(mapPtr_->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()); + } + } +} + + +Foam::coordSystem::cartesian Foam::VF::raySearchEngine::createCoordSystem +( + const point& origin, + const vector& dir +) const +{ + vector axis(Zero); + + for (direction d=0; d<3; ++d) + { + axis = dir^tensor::I.col(d); + + // Remove empty direction for 2D + if (mesh_.nSolutionD() == 2) + { + meshTools::constrainDirection(mesh_, mesh_.solutionD(), axis); + } + + if (magSqr(axis) > 0) + { + axis.normalise(); + break; + } + } + + return coordSystem::cartesian(origin, dir, axis); +} + + +Foam::tmp<Foam::pointField> Foam::VF::raySearchEngine::createHemiPoints +( + const label nRayPerFace +) const +{ + auto themiPts = tmp<pointField>::New(nRayPerFace); + auto& hemiPts = themiPts.ref(); + + const label nPoints = hemiPts.size(); + + if (mesh_.nSolutionD() == 3) + { + // Point in range -1 < x < 1; -1 < y < 1; 0 < z 1 + + forAll(hemiPts, pointi) + { + const scalar phi = Foam::acos(1 - (pointi + 0.5)/nPoints); + const scalar theta = + mathematical::pi*(1 + Foam::sqrt(5.0))*(pointi + 0.5); + + hemiPts[pointi] = + vector + ( + Foam::cos(theta)*Foam::sin(phi), + Foam::sin(theta)*Foam::sin(phi), + Foam::cos(phi) + ); + } + } + else if (mesh_.nSolutionD() == 2) + { + // Point in range -1 < x < 1; y = 0; 0 < z < 1; _\|/_ + + forAll(hemiPts, pointi) + { + const scalar theta = mathematical::pi*(pointi+0.5)/nPoints; + hemiPts[pointi] = vector(Foam::cos(theta), 0, Foam::sin(theta)); + } + } + + return themiPts; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::raySearchEngine::raySearchEngine +( + const fvMesh& mesh, + const dictionary& dict +) +: + mesh_(mesh), + mapPtr_(nullptr), + compactToGlobal_(), + globalNumbering_(), + patchGroup_(dict.getOrDefault<word>("patchGroup", "viewFactorWall")), + patchIDs_(mesh_.boundaryMesh().indices(patchGroup_)), + patchAreas_(mesh_.boundaryMesh().nNonProcessor(), Zero), + agglomerate_(dict.get<bool>("agglomerate")), + agglomMeshPtr_(nullptr), + nFace_(-1), + nCoarseFace_(-1), + allCf_(UPstream::nProcs()), + allSf_(UPstream::nProcs()), + allAgg_(UPstream::nProcs()) +{ + Info<< "\nParticipating patches:" << endl; + + forAll(patchIDs_, i) + { + const label patchi = patchIDs_[i]; + Info<< " " << i << ": " << mesh_.boundaryMesh()[patchi].name() + << endl; + } + + const word agglomName(dict.getOrDefault<word>("agglom", "finalAgglom")); + + IOobject agglomIO + ( + agglomName, + mesh_.facesInstance(), + mesh_, + IOobject::MUST_READ + ); + + + if (agglomerate_) + { + // Sets allCf_, allSf_, allAgg_ based on coarse mesh + // Sets nFace_, nCoarseFace_ + createAgglomeration(agglomIO); + } + else + { + // Check for presence of finalAgglom - will cause problems in later + // calculations with viewFactor radiation model + if (agglomIO.typeHeaderOk<labelListIOList>()) + { + WarningInFunction + << "Found agglomeration file: " << agglomIO.objectPath() << nl + << " This is inconsistent with the view factor calculation " + << "and should be removed" << nl << endl; + } + + // Sets allCf_, allSf_ based on fine mesh + // Sets nFace_; nCoarseFace_ remains unset (-1) + createGeometry(); + } + + globalNumbering_ = + nCoarseFace_ == -1 ? globalIndex(nFace_) : globalIndex(nCoarseFace_); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::VF::raySearchEngine::correct +( + labelListList& visibleFaceFaces +) const +{ + labelList rayStartFace; + labelList rayEndFace; + shootRays(rayStartFace, rayEndFace); + + const label nFace = nParticipatingFaces(); + + // Calculate number of visible faces from each local start face + labelList nVisibleFaceFaces(nFace, Zero); + for (const label facei : rayStartFace) + { + ++nVisibleFaceFaces[facei]; + } + + check(nVisibleFaceFaces); + + createParallelAddressing(rayEndFace); + + // Set visible face-faces + + // visibleFaceFaces has: + // (local face, local viewed face) = compact viewed face + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + visibleFaceFaces.resize_nocopy(nFace); + forAll(nVisibleFaceFaces, facei) + { + visibleFaceFaces[facei].resize_nocopy(nVisibleFaceFaces[facei]); + } + + nVisibleFaceFaces = 0; + forAll(rayStartFace, i) + { + const label facei = rayStartFace[i]; + const label sloti = rayEndFace[i]; + visibleFaceFaces[facei][nVisibleFaceFaces[facei]++] = sloti; + } +} + + +void Foam::VF::raySearchEngine::compactAddressing +( + const mapDistribute& map, + pointField& compactCf, + vectorField& compactSf, + List<List<vector>>& compactFineSf, + List<List<point>>& compactFineCf, + DynamicList<List<point>>& compactPoints, + DynamicList<label>& compactPatchId +) const +{ + compactCf.resize_nocopy(map.constructSize()); + compactSf.resize_nocopy(map.constructSize()); + compactFineSf.resize_nocopy(map.constructSize()); + compactFineCf.resize_nocopy(map.constructSize()); + compactPoints.setCapacity(map.constructSize()); + compactPatchId.setCapacity(map.constructSize()); + + // Insert my local values area and centre values + if (agglomMeshPtr_) + { + SubList<vector>(compactSf, nCoarseFace_) = allSf_[Pstream::myProcNo()]; + SubList<point>(compactCf, nCoarseFace_) = allCf_[Pstream::myProcNo()]; + + const auto& coarseMesh = agglomMeshPtr_(); + const auto& coarsePatches = coarseMesh.boundaryMesh(); + const auto& coarseFaces = coarseMesh.faces(); + const auto& coarsePoints = coarseMesh.points(); + + const auto& finalAgglom = coarseMesh.patchFaceAgglomeration(); + + // Insert my fine local values per coarse face + label sloti = 0; + for (const label patchi : patchIDs_) + { + const auto& fineCfp = mesh_.Cf().boundaryField()[patchi]; + const auto& fineSfp = mesh_.Sf().boundaryField()[patchi]; + const labelList& agglom = finalAgglom[patchi]; + + if (agglom.empty()) continue; + + const label nAgglom = max(agglom) + 1; + const labelListList coarseToFine = invertOneToMany(nAgglom, agglom); + const labelList& coarsePatchFace = + coarseMesh.patchFaceMap()[patchi]; + + const label coarseStart = coarsePatches[patchi].start(); + + forAll(coarseToFine, coarsei) + { + compactPatchId.push_back(patchi); + + const vectorField localPoints + ( + coarsePoints, + coarseFaces[coarseStart + coarsei] + ); + compactPoints.push_back(localPoints); + + const label coarseFacei = coarsePatchFace[coarsei]; + const labelList& fineFaces = coarseToFine[coarseFacei]; + + List<point>& fineCf = compactFineCf[sloti]; + fineCf.resize_nocopy(fineFaces.size()); + fineCf = UIndirectList<point>(fineCfp, fineFaces); + + List<vector>& fineSf = compactFineSf[sloti]; + fineSf.resize_nocopy(fineFaces.size()); + fineSf = UIndirectList<vector>(fineSfp, fineFaces); + + ++sloti; + } + } + } + else + { + SubList<vector>(compactSf, nFace_) = allSf_[Pstream::myProcNo()]; + SubList<point>(compactCf, nFace_) = allCf_[Pstream::myProcNo()]; + + const auto& patches = mesh_.boundaryMesh(); + const faceList& faces = mesh_.faces(); + + label sloti = 0; + + for (const label patchi : patchIDs_) + { + const auto& Sfp = mesh_.Sf().boundaryField()[patchi]; + const auto& Cfp = mesh_.Cf().boundaryField()[patchi]; + + const polyPatch& pp = patches[patchi]; + + forAll(pp, facei) + { + compactPatchId.push_back(patchi); + + const auto& fpts = faces[facei + pp.start()]; + compactPoints.push_back(List<point>(mesh_.points(), fpts)); + + compactFineCf[sloti] = List<point>({Cfp[facei]}); + compactFineSf[sloti] = List<vector>({Sfp[facei]}); + ++sloti; + } + } + } + + + // Do all swapping + map.distribute(compactSf); + map.distribute(compactCf); + map.distribute(compactFineCf); + map.distribute(compactFineSf); + map.distribute(compactPoints); + map.distribute(compactPatchId); +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.H new file mode 100644 index 0000000000000000000000000000000000000000..31a6d6f8d95a08f8130dd51708c65a6b677a8ae7 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.H @@ -0,0 +1,289 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Class + Foam::VF::raySearchEngine + +Description + Base class for ray search engines + + Participating patches must be in the \c viewFactorWall group, i.e. using the + \c inGroups entry of the "\<case\>/polyMesh/boundary" file. + + \verbatim + myPatch + { + type wall; + inGroups 2(wall viewFactorWall); + ... + } + \endverbatim + + Face agglomeration can be employed, created using the \c faceAgglomerate + utility. The file name to be read can be user-defined: + + \verbatim + // Name of agglomeration file; default = finalAgglom + agglom finalAgglom; + \endverbatim + +SourceFiles + raySearchEngine.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_raySearchEngine_H +#define Foam_vf_raySearchEngine_H + +#include "cartesianCS.H" +#include "mapDistribute.H" +#include "singleCellFvMesh.H" +#include "runTimeSelectionTables.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace VF +{ + +/*---------------------------------------------------------------------------*\ + Class raySearchEngine Declaration +\*---------------------------------------------------------------------------*/ + +class raySearchEngine +{ +protected: + + // Protected Data + + //- Reference to the mesh + const fvMesh& mesh_; + + //- Parallel map + mutable autoPtr<mapDistribute> mapPtr_; + + //- Compact to global addressing + mutable labelList compactToGlobal_; + + //- Global numbering + globalIndex globalNumbering_; + + //- Name of patch group to identify participating patches + const word patchGroup_; + + //- List of participating patch IDs + labelList patchIDs_; + + //- Patch areas + scalarList patchAreas_; + + //- Agglomeration flag + bool agglomerate_; + + //- Agglomerated mesh representation + autoPtr<singleCellFvMesh> agglomMeshPtr_; + + //- Number of original faces + label nFace_; + + //- Number of coarse faces + label nCoarseFace_; + + //- List of all face centres per processor + List<pointField> allCf_; + + //- List of all face areas per processor + List<vectorField> allSf_; + + //- List of all face agglomeration index per processor + List<labelField> allAgg_; + + + // Protected Member Functions + + static void check(const labelList& nVisibleFaceFaces); + + static label closestPointIndex + ( + const point& p0, + const List<point>& pts + ); + + //- Create patch geometry based on the original mesh + void createGeometry(); + + //- Create parallel addressing - map, compact-to-global + void createParallelAddressing(labelList& rayEndFace) const; + + //- Create Cartesian co-ordinate system + coordSystem::cartesian createCoordSystem + ( + const point& origin, + const vector& dir + ) const; + + //- Create patch geometry based on the agglomerated mesh + void createAgglomeration(const IOobject& io); + + //- Create a set of points describing a hemisphere + // Note: origin is (0 0 0) + tmp<pointField> createHemiPoints(const label nRayPerFace) const; + + +public: + + static const label maxDynListLength; + + //- Run-time type information + TypeName("raySearchEngine"); + + //- Selection table + declareRunTimeSelectionTable + ( + autoPtr, + raySearchEngine, + mesh, + ( + const fvMesh& mesh, + const dictionary& dict + ), + (mesh, dict) + ); + + //- Selector + static autoPtr<raySearchEngine> New + ( + const fvMesh& mesh, + const dictionary& dict + ); + + + // Generated Methods + + //- No copy construct + raySearchEngine(const raySearchEngine&) = delete; + + //- No copy assignment + void operator=(const raySearchEngine&) = delete; + + + //- Constructor + raySearchEngine(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~raySearchEngine() = default; + + + // Public Member Functions + + // Access + + //- Reference to the mesh + inline const fvMesh& mesh() const noexcept; + + //- Parallel map + inline const mapDistribute& map() const; + + //- Compact to global addressing + inline const labelList& compactToGlobal() const noexcept; + + //- Global numbering + inline const globalIndex& globalNumbering() const noexcept; + + //- List of participating patch IDs + inline const labelList& patchIDs() const noexcept; + + //- Patch areas + inline const scalarList& patchAreas() const noexcept; + + //- Number of participating faces + inline label nParticipatingFaces() const; + + //- List of all face centres per processor + inline const List<pointField>& allCf() const noexcept; + + //- List of all face areas per processor + inline const List<vectorField>& allSf() const noexcept; + + //- List of all face agglomeration index per processor + inline const List<labelField>& allAgg() const noexcept; + + + // Main calculation functions + + //- Shoot rays; returns lists of ray start and end faces + virtual void shootRays + ( + labelList& rayStartFaceOut, + labelList& rayEndFaceOut + ) const = 0; + + //- Correct + virtual void correct(labelListList& visibleFaceFaces) const; + + //- Create compact addressing + void compactAddressing + ( + const mapDistribute& map, + pointField& compactCf, + vectorField& compactSf, + List<List<vector>>& compactFineSf, + List<List<point>>& compactFineCf, + DynamicList<List<point>>& compactPoints, + DynamicList<label>& compactPatchId + ) const; + + //- Interpolate field + template<class Type> + void interpolate + ( + GeometricField<Type, fvPatchField, volMesh>& fld, + const List<List<Type>>& values + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "raySearchEngineI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "raySearchEngineTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineI.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineI.H new file mode 100644 index 0000000000000000000000000000000000000000..bc410e8b21b9548f582aeb7ee06ec421d00d9a48 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineI.H @@ -0,0 +1,101 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +const Foam::fvMesh& Foam::VF::raySearchEngine::mesh() const noexcept +{ + return mesh_; +} + + +const Foam::mapDistribute& Foam::VF::raySearchEngine::map() const +{ + if (!mapPtr_) + { + FatalErrorInFunction + << "mapDistribute has not been set" + << abort(FatalError); + } + + return mapPtr_; +} + + +const Foam::labelList& +Foam::VF::raySearchEngine::compactToGlobal() const noexcept +{ + return compactToGlobal_; +} + + +const Foam::globalIndex& +Foam::VF::raySearchEngine::globalNumbering() const noexcept +{ + return globalNumbering_; +} + + +const Foam::labelList& Foam::VF::raySearchEngine::patchIDs() const noexcept +{ + return patchIDs_; +} + + +const Foam::scalarList& Foam::VF::raySearchEngine::patchAreas() const noexcept +{ + return patchAreas_; +} + + +Foam::label Foam::VF::raySearchEngine::nParticipatingFaces() const +{ + if (nCoarseFace_ == -1) return nFace_; + return nCoarseFace_; +} + + +const Foam::List<Foam::pointField>& +Foam::VF::raySearchEngine::allCf() const noexcept +{ + return allCf_; +} + + +const Foam::List<Foam::vectorField>& +Foam::VF::raySearchEngine::allSf() const noexcept +{ + return allSf_; +} + + +const Foam::List<Foam::labelField>& +Foam::VF::raySearchEngine::allAgg() const noexcept +{ + return allAgg_; +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineNew.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineNew.C new file mode 100644 index 0000000000000000000000000000000000000000..78af6adc5222ac4e4c5f7e222ef2663dd23523be --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineNew.C @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "raySearchEngine.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::VF::raySearchEngine> Foam::VF::raySearchEngine::New +( + const fvMesh& mesh, + const dictionary& dict +) +{ + const word modelType(dict.get<word>("raySearchEngine")); + + Info<< "Selecting " << typeName << ": " << modelType << endl; + + auto* ctorPtr = meshConstructorTable(modelType); + + if (!ctorPtr) + { + FatalIOErrorInLookup + ( + dict, + typeName, + modelType, + *meshConstructorTablePtr_ + ) << exit(FatalIOError); + } + + return autoPtr<raySearchEngine>(ctorPtr(mesh, dict)); +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineTemplates.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..b345451ada9f120c1cf74ea98f846f683ed7e420 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngineTemplates.C @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +template<class Type> +void Foam::VF::raySearchEngine::interpolate +( + GeometricField<Type, fvPatchField, volMesh>& fld, + const List<List<Type>>& values +) const +{ + label compacti = 0; + + auto& vfbf = fld.boundaryFieldRef(); + + if (agglomMeshPtr_) + { + const auto& coarseMesh = agglomMeshPtr_(); + const auto& finalAgglom = coarseMesh.patchFaceAgglomeration(); + + for (const label patchi : patchIDs_) + { + const labelList& agglom = finalAgglom[patchi]; + + if (agglom.empty()) continue; + + label nAgglom = max(agglom) + 1; + const labelListList coarseToFine(invertOneToMany(nAgglom, agglom)); + const labelList& coarsePatchFace = + coarseMesh.patchFaceMap()[patchi]; + + forAll(coarseToFine, i) + { + const label coarseFacei = coarsePatchFace[i]; + const labelList& fineFaces = coarseToFine[coarseFacei]; + const Type sumValues = sum(values[compacti]); + + for (const label fineFacei : fineFaces) + { + vfbf[patchi][fineFacei] = sumValues; + } + + ++compacti; + } + } + } + else + { + label compacti = 0; + for (const label patchi : patchIDs_) + { + auto& vfp = vfbf[patchi]; + + for (Type& vfi : vfp) + { + vfi = sum(values[compacti++]); + } + } + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.C new file mode 100644 index 0000000000000000000000000000000000000000..757f1620443708e5e5e3cd47e0ccb6cb5d9aa1bb --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.C @@ -0,0 +1,948 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "voxelRaySearchEngine.H" +#include "processorPolyPatch.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(voxel, 0); + addToRunTimeSelectionTable(raySearchEngine, voxel, mesh); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::VF::voxel::setTriangulation(const fvMesh& mesh) +{ + Info<< "\nCreating triangulated surface" << endl; + + // Storage for surfaceMesh. Size estimate. + DynamicList<labelledTri> triangles(mesh.nBoundaryFaces()); + DynamicList<label> globalFaces(mesh.nBoundaryFaces()); + label nFace = 0; + + const auto& pbm = mesh.boundaryMesh(); + + forAll(patchIDs_, i) + { + const label patchi = patchIDs_[i]; + const polyPatch& patch = pbm[patchi]; + const pointField& points = patch.points(); + + for (const face& f : patch) + { + label nTri = 0; + faceList triFaces(f.nTriangles(points)); + f.triangles(points, nTri, triFaces); + + const label globalFacei = + globalNumbering_.toGlobal(Pstream::myProcNo(), nFace++); + + for (const face& f : triFaces) + { + triangles.push_back(labelledTri(f[0], f[1], f[2], i)); + globalFaces.push_back(globalFacei); + } + } + } + + triToGlobalFace_.transfer(globalFaces); + + Info<< " Total number of triangles: " + << returnReduce(triangles.size(), sumOp<label>()) + << endl; + + triangles.shrink(); + surface_ = triSurface(triangles, mesh.points()); + surface_.compactPoints(); +} + + +Foam::labelList Foam::VF::voxel::setFaceVertexHits +( + const fvMesh& mesh, + const labelList& patchIDs +) +{ + labelList vertHits(mesh.points().size(), Zero); + + if (mesh.nSolutionD() == 3) + { + const auto& pbm = mesh.boundaryMesh(); + + // Create a new triangulation based on the surface agglomeration + for (const label patchI : patchIDs) + { + const polyPatch& patch = pbm[patchI]; + for (const face& f : patch) + { + for (const label fpi : f) + { + ++vertHits[fpi]; + } + } + } + + for (const auto& pp : pbm) + { + const labelList& meshPts = pp.meshPoints(); + + if (pp.size()) + { + if (isA<processorPolyPatch>(pp)) + { + // Add all processor patch points + for (const label pi : meshPts) + { + ++vertHits[pi]; + } + } + else + { + // Add boundary points + + const auto& bndyPts = pp.boundaryPoints(); + + for (const label pi : bndyPts) + { + ++vertHits[meshPts[pi]]; + } + } + } + } + } + + return vertHits; +} + + +void Foam::VF::voxel::setCoarseTriangulation(const fvMesh& mesh) +{ + Info<< "\nCreating triangulated surface" << endl; + + + // Filter out fine mesh points along coarse mesh faces + + + // Storage for surfaceMesh. Size estimate. + DynamicList<labelledTri> triangles(mesh.nBoundaryFaces()); + DynamicList<label> globalFaces(mesh.nBoundaryFaces()); + labelList vertHits = setFaceVertexHits(mesh, patchIDs_); + + + // Only simplifying edges for 3D + const label nVertMin = mesh.nSolutionD() == 3 ? 2 : 0; + + label nInvalid = 0; + label nFace = 0; + + const auto& pbm = mesh.boundaryMesh(); + + for (const label patchi : patchIDs_) + { + const polyPatch& patch = pbm[patchi]; + const pointField& points = patch.points(); + + for (const face& f : patch) + { + DynamicList<label> faceVerts; + for (const label fpi : f) + { + if (vertHits[fpi] > nVertMin) + { + faceVerts.push_back(fpi); + } + } + + if (faceVerts.size() < 3) + { + ++nInvalid; + continue; + } + + label nTri = 0; + const face reducedFace(faceVerts); + faceList triFaces(reducedFace.nTriangles(points)); + reducedFace.triangles(points, nTri, triFaces); + + const label globalFacei = + globalNumbering_.toGlobal(Pstream::myProcNo(), nFace++); + + for (const face& f : triFaces) + { + triangles.push_back(labelledTri(f[0], f[1], f[2], patchi)); + globalFaces.push_back(globalFacei); + } + } + } + + triToGlobalFace_.transfer(globalFaces); + + Info<< " Total number of triangles: " + << returnReduce(triangles.size(), sumOp<label>()) + << "\n Number of invalid (removed) triangles: " + << returnReduce(nInvalid, sumOp<label>()) + << endl; + + triangles.shrink(); + surface_ = triSurface(triangles, mesh.points()); + surface_.compactPoints(); +} + + +void Foam::VF::voxel::broadcast() +{ + // Every processor has whole surface + const globalIndex globalFaceIdx(globalIndex::gatherOnly{}, surface_.size()); + const globalIndex globalPointIdx + ( + globalIndex::gatherOnly{}, + surface_.points().size() + ); + + List<labelledTri> globalSurfaceTris(globalFaceIdx.gather(surface_)); + pointField globalSurfacePoints(globalPointIdx.gather(surface_.points())); + List<label> globalTriToGlobalFace(globalFaceIdx.gather(triToGlobalFace_)); + + + 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_); + + triToGlobalFace_ = std::move(globalTriToGlobalFace); + Pstream::broadcast(triToGlobalFace_); +} + + +Foam::pointHit Foam::VF::voxel::rayTriIntersect +( + const label trii, + const point& origin, + const vector& direction +) const +{ + // Note: origin was made relative to voxel mesh on entry to hit function + // - need to convert back into global position to be consistent with + // triangles for intersection tests + + const auto& ind = surface_[trii]; + const auto& pts = surface_.points(); + + // Note: flipped orientation of triangle (into domain) so that we can use + // visibility check when performing ray-triangle intersections + const triPointRef tri(pts[ind[0]], pts[ind[2]], pts[ind[1]]); + + static scalar tolerance = 1e-6; + + return + tri.intersection + ( + globalPosition(origin), + direction, + intersection::VISIBLE, + tolerance + ); +} + + +void Foam::VF::voxel::writeBox +( + OBJstream& os, + bool lines, + const boundBox& bb +) const +{ + os.write(treeBoundBox(bb), lines); +} + + +void Foam::VF::voxel::writeVoxels(const word& fName) const +{ + if (!UPstream::master()) return; + + OBJstream os(fName); + Info<< "Writing voxels to " << os.name() << endl; + + boundBox bb; + const bool lines = true; + for (label i = 0; i < nijk_[0]; ++i) + { + for (label j = 0; j < nijk_[1]; ++j) + { + for (label k = 0; k < nijk_[2]; ++k) + { + bb.min() = voxelMin(i, j, k); + bb.max() = voxelMax(i, j, k); + writeBox(os, lines, bb); + } + } + } + + Info<< "- done" << endl; +} + + +void Foam::VF::voxel::writeTriBoundBoxes(const word& fName) const +{ + if (!UPstream::master()) return; + + OBJstream os(fName); + Info<< "Writing triangle boundBoxes to " << os.name() << endl; + + const bool lines = true; + for (const auto& voxeli : objects_) + { + for (const label trii : voxeli) + { + writeBox(os, lines, objectBbs_[trii]); + } + } + + Info<< "- done" << endl; +} + + +void Foam::VF::voxel::writeHitObjects +( + const label voxeli, + const point& origin, + const vector& dir +) const +{ + OBJstream os("voxel_" + Foam::name(voxeli) + ".obj"); + + // Write voxel + labelVector ijk = this->ijk(voxeli); + + boundBox voxelBb; + voxelBb.min() = voxelMin(ijk[0], ijk[1], ijk[2]); + voxelBb.max() = voxelMax(ijk[0], ijk[1], ijk[2]); + + writeBox(os, true, voxelBb); + + for (const auto& trii : objects_[voxeli]) + { + writeBox(os, true, objectBbs_[trii]); + + const auto& ind = surface_[trii]; + const auto& pts = surface_.points(); + const triPointRef tri(pts[ind[0]], pts[ind[1]], pts[ind[2]]); + os.write(tri, false); + } +} + + +Foam::pointIndexHit Foam::VF::voxel::hitObject +( + const label voxeli, + const point& origin, + const vector& dir, + const vector& t, + const scalar minDistance +) const +{ + if (objects_[voxeli].empty()) return pointIndexHit(); + + // boundBox rayBb; + // rayBb.add(origin); + // rayBb.add(origin + dir*(dir & t)); + + label triHiti = -1; + //rayBb.add(origin + dir); + //rayBb.inflate(0.01); + + if (debug > 2) + { + writeHitObjects(voxeli, origin, dir); + } + + // Determine all triangles that intersect with ray + // - only keep nearest hit + + pointHit closestHit; + for (const auto& trii : objects_[voxeli]) + { + // Only perform ray/tri intersection if bound boxes intersect + //if (objectBbs_[trii].overlaps(rayBb)) + { + pointHit pi = rayTriIntersect(trii, origin, dir); + + if + ( + pi.hit() + && ( + pi.distance() > minDistance + && pi.distance() < closestHit.distance() + ) + ) + { + triHiti = trii; + closestHit = pi; + } + } + } + + return pointIndexHit(closestHit, triHiti); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::voxel::voxel(const fvMesh& mesh, const dictionary& dict) +: + raySearchEngine(mesh, dict), + bb0_(), + span0_(Zero), + nijk_(Zero), + dxyz_(Zero), + nRayPerFace_(dict.get<label>("nRayPerFace")), + nTriPerVoxelMax_(dict.getOrDefault<label>("nTriPerVoxelMax", 50)), + depthMax_(dict.getOrDefault<label>("depthMax", 5)), + objects_(), + objectBbs_() +{ + if (agglomMeshPtr_) + { + setCoarseTriangulation(*agglomMeshPtr_); + } + else + { + setTriangulation(mesh); + } + + broadcast(); + + objectBbs_.resize_nocopy(surface_.size()); + + bb0_.add(surface_.points()); + bb0_.inflate(0.01); + span0_ = bb0_.span(); + + { + scalar maxDx = span0_.x(); + scalar maxDy = span0_.y(); + scalar maxDz = span0_.z(); + + const label refDn = 8; + scalar maxDim = max(maxDx, max(maxDy, maxDz)); + + setVoxelDims + ( + refDn*maxDx/maxDim, + refDn*maxDy/maxDim, + refDn*maxDz/maxDim + ); + + objects_.resize_nocopy(nVoxel()); + } + + label depth = 0; + label trii = 0; + voxelise(objects_, trii, depth); + + Info<< "\nCreated voxel mesh: " << nijk_ << endl; + + if ((debug > 3) && UPstream::master()) + { + writeVoxels("voxels.obj"); + writeTriBoundBoxes("triBoundBoxes.obj"); + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::VF::voxel::refineObjects +( + List<DynamicList<label>>& objects, + const label triMax +) +{ + refineVoxelDims(); + + if (debug > 2) Pout<< "Refining voxels: n=" << nijk_ << endl; + + List<DynamicList<label>> objectsNew(objects.size()*8); + + for (label trii = 0; trii <= triMax; ++trii) + { + addBbToVoxels(objectBbs_[trii], trii, objectsNew); + } + + objects.transfer(objectsNew); +} + + +Foam::label Foam::VF::voxel::addBbToVoxels +( + const boundBox& bb, + const label trii, + List<DynamicList<label>>& objects +) const +{ + //Pout<< "addBbToVoxels: trii=" << trii << " n=" << nijk_ << endl; + + const point minbb(localPosition(bb.min())); + const label i0 = max(0, floor(minbb.x()/dxyz_[0])); + const label j0 = max(0, floor(minbb.y()/dxyz_[1])); + const label k0 = max(0, floor(minbb.z()/dxyz_[2])); + + const point maxbb(localPosition(bb.max())); + const label i1 = min(nijk_[0], ceil(maxbb.x()/dxyz_[0])); + const label j1 = min(nijk_[1], ceil(maxbb.y()/dxyz_[1])); + const label k1 = min(nijk_[2], ceil(maxbb.z()/dxyz_[2])); + + label nTriMax = 0; + + for (label ii = i0; ii < i1; ++ii) + { + for (label jj = j0; jj < j1; ++jj) + { + for (label kk = k0; kk < k1; ++kk) + { + const label voxeli = this->voxeli(ii, jj, kk); + + objects[voxeli].push_back(trii); + nTriMax = max(nTriMax, objects[voxeli].size()); + } + } + } + + return nTriMax; +} + + +void Foam::VF::voxel::voxelise +( + List<DynamicList<label>>& objects, + const label trii0, + const label depth +) +{ + if (debug > 2) + { + Pout<< "voxelise - start at tri=" << trii0 + << " depth=" << depth + << endl; + } + + const auto& points = surface_.points(); + + for (label trii = trii0; trii < surface_.size(); ++trii) + { + // Triangle bounding box + boundBox bb(points, surface_[trii]); + bb.inflate(0.01); + objectBbs_[trii] = bb; + + const label nVoxelMax = addBbToVoxels(bb, trii, objects); + + // Number of triangles per voxel - if exceed limit, refine voxels... + if (nVoxelMax > nTriPerVoxelMax_ && depth < depthMax_) + { + refineObjects(objects, trii); + voxelise(objects, trii + 1, depth + 1); + break; + } + } +} + + +Foam::pointIndexHit Foam::VF::voxel::hit +( + const label tri0, + const vector& direction0 +) const +{ + if (tri0 > surface_.size()-1) + { + FatalErrorInFunction + << "Index tri0 out of bounds: " << tri0 + << ". Surface size: " << surface_.size() + << abort(FatalError); + } + + return hit(surface_.faceCentres()[tri0], direction0); +} + + +Foam::pointIndexHit Foam::VF::voxel::hit +( + const point& origin0, + const vector& direction0 +) const +{ + // Initialise return value + pointIndexHit hitInfo; + + const point origin(localPosition(origin0)); + + if (cmptMin(origin) < 0) + { + FatalErrorInFunction + << "Point located outside voxel mesh" + << " - possible coarsening problem?" + << abort(FatalError); + } + + if (magSqr(direction0) < ROOTVSMALL) + { + WarningInFunction + << "Supplied direction has zero size" + << endl; + + return hitInfo; + } + + const vector dir(normalised(direction0)); + + labelVector ijk(Zero); + labelVector step(Zero); + vector tDelta(vector::max); + vector tMax(vector::max); + + for (direction d = 0; d < 3; ++d) + { + ijk[d] = floor(origin[d]/dxyz_[d]); + step[d] = sign0(dir[d]); + if (step[d] != 0) + { + tDelta[d] = mag(dxyz_[d]/dir[d]); + + scalar voxelMax = (1 + ijk[d] - neg(dir[d]))*dxyz_[d]; + tMax[d] = (voxelMax - origin[d])/dir[d]; + } + } + + if (debug > 2) + { + Info<< "surfBb:" << boundBox(surface_.points()) + << " bb:" << bb0_ + << " origin" << origin0 + << " voxel_origin:" << origin + << " ijk:" << ijk + << " step:" << step + << " dxyz:" << dxyz_ + << " tDelta:" << tDelta + << " tMax:" << tMax + << endl; + } + + auto traverse = [&](const label i) + { + ijk[i] += step[i]; + if (outOfBounds(ijk, i)) return false; + tMax[i] += tDelta[i]; + return true; + }; + + + while (true) + { + const label voxeli = this->voxeli(ijk); + + if (debug > 2) + { + Info<< "ijk:" << ijk + << " voxeli:" << voxeli + << " t:" << tMax + << " objs:" << objects_[voxeli].size() + << endl; + } + + hitInfo = hitObject(voxeli, origin, dir, tMax); + + if (hitInfo.hit()) + { + // Valid hit + break; + } + else + { + if (tMax[0] < tMax[1] && tMax[0] < tMax[2]) + { + if (!traverse(0)) break; + } + else if (tMax[1] < tMax[2]) + { + if (!traverse(1)) break; + } + else + { + if (!traverse(2)) break; + } + } + } + + return hitInfo; +} + + +void Foam::VF::voxel::shootRays +( + labelList& rayStartFaceOut, + labelList& rayEndFaceOut +) const +{ + (void)mesh_.time().cpuTimeIncrement(); + + const pointField& myFc = allCf_[Pstream::myProcNo()]; + const vectorField& myArea = allSf_[Pstream::myProcNo()]; + + const label nTotalRays = myFc.size()*nRayPerFace_; + if (nTotalRays > maxDynListLength) + { + FatalErrorInFunction + << "Dynamic list needs more capacity to support " << nRayPerFace_ + << " rays per face (" << nTotalRays << "). " + << "Limit set by maxDynListLength: " << maxDynListLength + << abort(FatalError); + } + + DynamicList<label> rayStartFace(nTotalRays); + DynamicList<label> rayEndFace(rayStartFace.size()); + + DynamicList<label> endFacei(nTotalRays); + DynamicList<label> startFacei(nTotalRays); + + const pointField hemi(createHemiPoints(nRayPerFace_)); + + Info<< "\nShooting rays" << endl; + + const scalar nDiv = 10; + const label nStep = floor(myFc.size()/nDiv); + labelHashSet localFaceHits; + + for (label stepi=0; stepi<nDiv; ++stepi) + { + const label step0 = stepi*nStep; + const label step1 = stepi == nDiv - 1 ? myFc.size() : (stepi+1)*nStep; + + for (label i = step0; i < step1; ++i) + { + // Info<< "i/N = " << i << "/" << (myFc.size()-1) + // << " step0:" << step0 << " step1:" << step1 + // << endl; + + localFaceHits.clear(); + + const point& origin = myFc[i]; + const vector dir(-normalised(myArea[i])); + + const coordSystem::cartesian cs = createCoordSystem(origin, dir); + + const vectorField pts(cs.transformPoint(hemi)); + + for (const auto& p : pts) + { + const pointIndexHit hitInfo = hit(origin, p-origin); + + if (hitInfo.hit()) + { + label hitFacei = triToGlobalFace_[hitInfo.index()]; + + if (localFaceHits.insert(hitFacei)) + { + endFacei.push_back(hitFacei); + startFacei.push_back(i); + } + } + else + { + // Miss + } + } + } + + const label globalStepi = returnReduce(stepi, minOp<label>()) + 1; + + Info<< " " << globalStepi/nDiv*100 << "% complete" << endl; + } + + + // Ensure all rays are unique/filter out duplicates + // - add symmetric connections for non-self-intersecting rays + + if (UPstream::parRun()) + { + edgeHashSet uniqueRays; + List<DynamicList<label>> remoteStartFace(Pstream::nProcs()); + List<DynamicList<label>> remoteEndFace(Pstream::nProcs()); + + const labelList globalStartFaceIDs + ( + globalNumbering_.toGlobal(startFacei) + ); + + forAll(globalStartFaceIDs, rayi) + { + label start = globalStartFaceIDs[rayi]; + label end = endFacei[rayi]; + + const label endProci = globalNumbering_.whichProcID(end); + + if (start > end) Swap(start, end); + + if (uniqueRays.insert(edge(start, end))) + { + if (endProci != UPstream::myProcNo()) + { + // Convert local face into global face and vice-versa + remoteStartFace[endProci].push_back(start); + remoteEndFace[endProci].push_back(end); + } + } + } + + PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking); + + // Send remote data + for (const int domain : Pstream::allProcs()) + { + if (domain != Pstream::myProcNo()) + { + UOPstream str(domain, pBufs); + str << remoteStartFace[domain] + << remoteEndFace[domain]; + } + } + + pBufs.finishedSends(); + + // Consume + for (const int domain : Pstream::allProcs()) + { + if (domain != Pstream::myProcNo()) + { + UIPstream is(domain, pBufs); + is >> remoteStartFace[domain] + >> remoteEndFace[domain]; + + forAll(remoteStartFace[domain], i) + { + const label start = remoteStartFace[domain][i]; + const label end = remoteEndFace[domain][i]; + uniqueRays.insert(edge(start, end)); + } + } + } + + // Populate ray addressing based on uniqueRays + for (const edge& e : uniqueRays) + { + const label start = e.first(); + const label end = e.second(); + + bool sameFace = start == end; + + if (globalNumbering_.isLocal(start)) + { + // Ray originates from this processor + const label localStart = globalNumbering_.toLocal(start); + + rayStartFace.append(localStart); + rayEndFace.append(end); + } + + if (!sameFace && globalNumbering_.isLocal(end)) + { + // Ray hits this processor + // - add symmetric ray from end->start + const label localEnd = globalNumbering_.toLocal(end); + + rayStartFace.append(localEnd); + rayEndFace.append(start); + } + } + } + else + { + // Populate ray addressing based on uniqueRays + + edgeHashSet uniqueRays; + + forAll(startFacei, rayi) + { + label start = startFacei[rayi]; + label end = endFacei[rayi]; + + if (start > end) Swap(start, end); + + if (uniqueRays.insert(edge(start, end))) + { + rayStartFace.append(start); + rayEndFace.append(end); + + if (start != end) + { + // Add symmetric ray from end->start + rayStartFace.append(end); + rayEndFace.append(start); + } + } + } + } + + rayStartFaceOut.transfer(rayStartFace); + rayEndFaceOut.transfer(rayEndFace); + + Info<< " Time taken: " << mesh_.time().cpuTimeIncrement() << " s" + << endl; +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.H new file mode 100644 index 0000000000000000000000000000000000000000..1103e1a881ceea25283207420c60c96abd700720 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngine.H @@ -0,0 +1,284 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Class + Foam::VF::voxel + +Description + Ray search engine based on discretising space into uniform voxels + + Voxels are refined using 2x2x2 refinement. + + The number of rays per face is supplied by the user, whereby rays are + issued uniformly across a hemisphere. + +Usage + Minimal example by using \c <constant>/viewFactorsDict: + \verbatim + // Mandatory entries + nRayPerFace <label>; + + // Optional entries + nTriPerVoxelMax <label>; + depthMax <label>; + + // Inherited entries + ... + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Reqd | Deflt + nRayPerFace | Number of rays issued per face | label | yes | - + nRayPerFace | Target number of triangles per voxel | label | no | 50 + depthMax | Maximum voxel refinement depth | label | no | 5 + \endtable + + The inherited entries are elaborated in: + - \link raySearchEngine.H \endlink + +SourceFiles + voxelRaySearchEngine.C + +SeeAlso +- Foam::VF::raySearchEngine + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_voxelRaySearchEngine_H +#define Foam_vf_voxelRaySearchEngine_H + +#include "raySearchEngine.H" +#include "labelVector.H" +#include "OBJstream.H" +#include "pointIndexHit.H" +#include "triSurface.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace VF +{ + +/*---------------------------------------------------------------------------*\ + Class voxel Declaration +\*---------------------------------------------------------------------------*/ + +class voxel +: + public raySearchEngine +{ + // Private Data + + //- Triangulation of view factor patches + triSurface surface_; + + //- Triangle to mesh face addressing + labelList triToGlobalFace_; + + //- Surface bounding box + boundBox bb0_; + + //- Span of surface bounding box + vector span0_; + + //- Voxel discretisation + labelVector nijk_; + + //- Voxel dimensions + vector dxyz_; + + //- Number of rays issued per face + const label nRayPerFace_; + + //- Maximum number of triangles per voxel (trigger to refine voxels) + const label nTriPerVoxelMax_; + + //- Maximum depth of voxel refinement. Note: voxels are refined 2x2x2 + const label depthMax_; + + //- List of triangle per voxel + List<DynamicList<label>> objects_; + + //- List of triangle bounding boxes + List<boundBox> objectBbs_; + + + // Private Member Functions + + inline bool outOfBounds(const labelVector& ijk, const label dir) const; + + inline point localPosition(const vector& globalPosition) const; + + inline point globalPosition(const vector& localPosition) const; + + inline void setVoxelDims(const label i, const label j, const label k); + + inline void refineVoxelDims(); + + inline point voxelMin + ( + const label i, + const label j, + const label k + ) const; + + inline point voxelMax + ( + const label i, + const label j, + const label k + ) const; + + inline constexpr label sign0(const scalar x) const; + + //- Set triangulation based on original mesh + void setTriangulation(const fvMesh& mesh); + + //- Set the participating face vertices when simplifying edges + static labelList setFaceVertexHits + ( + const fvMesh& mesh, + const labelList& patchIDs + ); + + //- Set triangulation based on agglomeration + void setCoarseTriangulation(const fvMesh& mesh); + + //- Broadcast triangulation across all procs + void broadcast(); + + void refineObjects + ( + List<DynamicList<label>>& objects, + const label triMax + ); + + label addBbToVoxels + ( + const boundBox& bb, + const label trii, + List<DynamicList<label>>& objects + ) const; + + void voxelise + ( + List<DynamicList<label>>& objects, + const label trii0, + const label depth + ); + + pointHit rayTriIntersect + ( + const label trii, + const point& origin, + const vector& direction + ) const; + + pointIndexHit hitObject + ( + const label voxeli, + const point& origin, + const vector& direction, + const vector& t, + const scalar minDistance = 1e-6 + ) const; + + void writeBox + ( + OBJstream& os, + bool lines, + const boundBox& bb + ) const; + + void writeVoxels(const word& fName) const; + + void writeTriBoundBoxes(const word& fName) const; + + void writeHitObjects + ( + const label voxeli, + const point& origin, + const vector& dir + ) const; + + +public: + + //- Runtime type information + TypeName("voxel"); + + //- Constructor + voxel(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~voxel() = default; + + + // Public Member Functions + + inline labelVector nijk() const noexcept; + + inline label nVoxel() const noexcept; + + inline label voxeli(const labelVector ijk) const noexcept; + + inline label voxeli + ( + const label i, + const label j, + const label k + ) const noexcept; + + inline labelVector ijk(const label voxeli) const noexcept; + + pointIndexHit hit(const point& origin, const vector& dir) const; + + pointIndexHit hit(const label tri0, const vector& dir) const; + + virtual void shootRays + ( + labelList& rayStartFaceOut, + labelList& rayEndFaceOut + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "voxelRaySearchEngineI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngineI.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngineI.H new file mode 100644 index 0000000000000000000000000000000000000000..a46ca7e1da5fae77d5a8f03cae70ba02a742e945 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/voxel/voxelRaySearchEngineI.H @@ -0,0 +1,155 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +bool Foam::VF::voxel::outOfBounds +( + const labelVector& ijk, + const label dir +) const +{ + return (ijk[dir] < 0 || ijk[dir] >= nijk_[dir]); +}; + + +Foam::point Foam::VF::voxel::localPosition(const vector& globalPosition) const +{ + return globalPosition - bb0_.min(); +} + + +Foam::point Foam::VF::voxel::globalPosition(const vector& localPosition) const +{ + return bb0_.min() + localPosition; +} + + +void Foam::VF::voxel::setVoxelDims(const label i, const label j, const label k) +{ + nijk_[0] = max(1, i); + nijk_[1] = max(1, j); + nijk_[2] = max(1, k); + + dxyz_[0] = span0_[0]/nijk_[0]; + dxyz_[1] = span0_[1]/nijk_[1]; + dxyz_[2] = span0_[2]/nijk_[2]; +} + + +void Foam::VF::voxel::refineVoxelDims() +{ + nijk_ *= 2; + + // Do not refine empty direction for 2D + const auto& solutionD = mesh_.solutionD(); + for (direction d=0; d<3; ++d) + { + if (solutionD[d] == -1) + { + nijk_[d] = 1; + } + } + + setVoxelDims(nijk_[0], nijk_[1], nijk_[2]); +} + + +Foam::point Foam::VF::voxel::voxelMin +( + const label i, + const label j, + const label k +) const +{ + return point(i*dxyz_[0], j*dxyz_[1], k*dxyz_[2]); +} + + +Foam::point Foam::VF::voxel::voxelMax +( + const label i, + const label j, + const label k +) const +{ + return voxelMin(i+1, j+1, k+1); +} + + +constexpr Foam::label Foam::VF::voxel::sign0(const scalar x) const +{ + if (x > 0) return 1; + if (x < 0) return -1; + return 0; +}; + + +Foam::labelVector Foam::VF::voxel::nijk() const noexcept +{ + return nijk_; +} + + +Foam::label Foam::VF::voxel::nVoxel() const noexcept +{ + return nijk_[0]*nijk_[1]*nijk_[2]; +} + + +Foam::label Foam::VF::voxel::voxeli +( + const labelVector ijk +) const noexcept +{ + return voxeli(ijk[0], ijk[1], ijk[2]); +} + + +Foam::label Foam::VF::voxel::voxeli +( + const label i, + const label j, + const label k +) const noexcept +{ + return i + (nijk_[0]*(j + (nijk_[1]*k))); +} + + +Foam::labelVector Foam::VF::voxel::ijk(const label voxeli) const noexcept +{ + const label nx = nijk_[0]; + const label ny = nijk_[1]; + + const label i = voxeli%nx; + const label k = voxeli/nx/ny; + const label j = (voxeli/nx)%ny; + + return labelVector(i, j, k); +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.C new file mode 100644 index 0000000000000000000000000000000000000000..2b7afe34bff644309a57a8532eaa415eb71ca37d --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.C @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "viewFactor2AI.H" +#include "mathematicalConstants.H" +#include "addToRunTimeSelectionTable.H" + +using namespace Foam::constant; + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(viewFactor2AI, 0); + addToRunTimeSelectionTable(viewFactorModel, viewFactor2AI, mesh); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::scalar Foam::VF::viewFactor2AI::calculateFij +( + const point& xi, + const point& xj, + const vector& dAi, + const vector& dAj +) +{ + const vector r(xj - xi); + const scalar rMag = mag(r); + const scalar dAiMag(mag(dAi)); + const scalar dAjMag(mag(dAj)); + + if (rMag > SMALL && dAiMag > SMALL && dAjMag > SMALL) + { + const vector nr(r/rMag); + const vector ni(dAi/dAiMag); + const vector nj(dAj/dAjMag); + + const scalar Fij = + -(nr & ni)*(nr & nj)/sqr(rMag)*dAjMag*dAiMag/mathematical::pi; + + if (Fij > 0) return Fij; + } + + return 0; +} + + +Foam::scalarListList Foam::VF::viewFactor2AI::calculate +( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId +) const +{ + // Fill local view factor matrix + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + scalarListList Fij(visibleFaceFaces.size()); + + forAll(visibleFaceFaces, facei) + { + if (debug > 1) + { + Pout<< "facei:" << facei << "/" << visibleFaceFaces.size() + << endl; + } + + const labelList& visibleFaces = visibleFaceFaces[facei]; + + Fij[facei].resize(visibleFaces.size(), Zero); + + const point& dCi = compactCf[facei]; + const vector& Ai = compactSf[facei]; + const scalar magAi = mag(Ai); + + if (magAi < SMALL) continue; + + forAll(visibleFaces, visibleFacei) + { + const label sloti = visibleFaces[visibleFacei]; + const point& dCj = compactCf[sloti]; + const vector& Aj = compactSf[sloti]; + + const scalar Fij2AI = calculateFij(dCi, dCj, Ai, Aj); + + Fij[facei][visibleFacei] = Fij2AI/magAi; + } + } + + + return Fij; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::viewFactor2AI::viewFactor2AI +( + const fvMesh& mesh, + const dictionary& dict +) +: + viewFactorModel(mesh, dict) +{} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.H new file mode 100644 index 0000000000000000000000000000000000000000..9ba377435b4d55193731e0d6ef6b1012e01888ca --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2AI/viewFactor2AI.H @@ -0,0 +1,117 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Class + Foam::VF::viewFactor2AI + +Description + Computes view factors according to the double area integral (2AI) method. + +Usage + Minimal example in \c <constant>/viewFactorsDict: + \verbatim + // Inherited entries + ... + \endverbatim + + The inherited entries are elaborated in: + - \link viewFactorModel.H \endlink + +SourceFiles + viewFactorModel.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_viewFactor2AI_H +#define Foam_vf_viewFactor2AI_H + +#include "viewFactorModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace VF +{ + +/*---------------------------------------------------------------------------*\ + Class viewFactor2AI Declaration +\*---------------------------------------------------------------------------*/ + +class viewFactor2AI +: + public viewFactorModel +{ + +protected: + + // Protected Member Functions + + //- Calculate view factor using the double-area integral + static scalar calculateFij + ( + const point& xi, + const point& xj, + const vector& dAi, + const vector& dAj + ); + + //- Calculate + virtual scalarListList calculate + ( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId + ) const; + + +public: + + //- Runtime type information + TypeName("viewFactor2AI"); + + //- Constructor + viewFactor2AI(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~viewFactor2AI() = default; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.C new file mode 100644 index 0000000000000000000000000000000000000000..273b5c2ac5e3f22ccddd99c6de10960989cb8b85 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.C @@ -0,0 +1,141 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "viewFactor2LI.H" +#include "mathematicalConstants.H" +#include "addToRunTimeSelectionTable.H" + +using namespace Foam::constant; + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(viewFactor2LI, 0); + addToRunTimeSelectionTable(viewFactorModel, viewFactor2LI, mesh); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::scalar Foam::VF::viewFactor2LI::calculateFij +( + const List<point>& lPoints, + const List<point>& rPoints, + const scalar alpha +) +{ + scalar Fij = 0; + + forAll(lPoints, i) + { + // Edge vector and centroid of edge i + const vector si(lPoints[i] - lPoints.rcValue(i)); + const point ci(0.5*(lPoints[i] + lPoints.rcValue(i))); + + forAll(rPoints, j) + { + // Edge vector and centroid of edge j + const vector sj(rPoints[j] - rPoints.rcValue(j)); + const point cj(0.5*(rPoints[j] + rPoints.rcValue(j))); + + vector r(ci - cj); + if (mag(r) < SMALL) + { + r = alpha*si; + } + + Fij += (si & sj)*Foam::log(r & r); + } + } + + return max(0, 0.25*Fij/mathematical::pi); +} + + +Foam::scalarListList Foam::VF::viewFactor2LI::calculate +( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId +) const +{ + // Fill local view factor matrix + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + scalarListList Fij(visibleFaceFaces.size()); + + forAll(visibleFaceFaces, facei) + { + if (debug > 1) + { + Pout<< "facei:" << facei << "/" << visibleFaceFaces.size() + << endl; + } + + const labelList& visibleFaces = visibleFaceFaces[facei]; + + Fij[facei].resize(visibleFaces.size(), Zero); + + const vector& Ai = compactSf[facei]; + const scalar magAi = mag(Ai); + + forAll(visibleFaces, visibleFacei) + { + const label sloti = visibleFaces[visibleFacei]; + const List<point>& lPoints = compactPoints[facei]; + const List<point>& rPoints = compactPoints[sloti]; + + const scalar Fij2LI = calculateFij(lPoints, rPoints, alpha_); + + Fij[facei][visibleFacei] = Fij2LI/magAi; + } + } + + return Fij; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::viewFactor2LI::viewFactor2LI +( + const fvMesh& mesh, + const dictionary& dict +) +: + viewFactorModel(mesh, dict), + alpha_(dict.getOrDefault("alpha", 0.21)) +{} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.H new file mode 100644 index 0000000000000000000000000000000000000000..0d2c0d273d3403cc4000dc32a54d1d093aecfb12 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactor2LI/viewFactor2LI.H @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Class + Foam::VF::viewFactor2LI + +Description + Computes view factors according to the double line integral (2LI) method. + +Usage + Minimal example in \c <constant>/viewFactorsDict: + \verbatim + // Optional entries + alpha <scalar>; + + // Inherited entries + ... + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Reqd | Deflt + alpha | Perturbation for common edges | scalar | no | 0.21 + \endtable + + The inherited entries are elaborated in: + - \link viewFactorModel.H \endlink + +SourceFiles + viewFactorModel.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_viewFactor2LI_H +#define Foam_vf_viewFactor2LI_H + +#include "viewFactorModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace VF +{ + +/*---------------------------------------------------------------------------*\ + Class viewFactor2LI Declaration +\*---------------------------------------------------------------------------*/ + +class viewFactor2LI +: + public viewFactorModel +{ +protected: + + // Protected Data + + //- Perturbation for common edges; default = 0.21 + const scalar alpha_; + + + // Protected Member Functions + + //- Calculate view factor using the double-area integral + static scalar calculateFij + ( + const List<point>& lPoints, + const List<point>& rPoints, + const scalar alpha + ); + + //- Calculate + virtual scalarListList calculate + ( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId + ) const; + + +public: + + //- Runtime type information + TypeName("viewFactor2LI"); + + //- Constructor + viewFactor2LI(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~viewFactor2LI() = default; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.C new file mode 100644 index 0000000000000000000000000000000000000000..3b352ab69f8c976833f9566fe2977a5c054ebf22 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.C @@ -0,0 +1,153 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "viewFactorHottel.H" +#include "mathematicalConstants.H" +#include "fvMesh.H" +#include "meshTools.H" +//#include "addToRunTimeSelectionTable.H" + +using namespace Foam::constant; + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(viewFactorHottel, 0); +// addToRunTimeSelectionTable(viewFactorModel, viewFactorHottel, mesh); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::scalar Foam::VF::viewFactorHottel::calculateFij +( + const point& p0, + const point& p1, + const point& p2, + const point& p3 +) +{ + return 0.5*(mag(p2-p1) + mag(p3-p0) - mag(p2-p0) - mag(p3-p1)); +} + + +Foam::scalarListList Foam::VF::viewFactorHottel::calculate +( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId +) const +{ + // Fill local view factor matrix + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + scalarListList Fij(visibleFaceFaces.size()); + + forAll(visibleFaceFaces, facei) + { + if (debug > 1) + { + Pout<< "facei:" << facei << "/" << visibleFaceFaces.size() + << endl; + } + + const labelList& visibleFaces = visibleFaceFaces[facei]; + + Fij[facei].resize_nocopy(visibleFaces.size()); + + const point& dCi = compactCf[facei]; + const vector& Ai = compactSf[facei]; + const scalar magAi = mag(Ai); + + const vector d1((Ai/magAi) ^ emptyDir_); + const vector l1(0.5*magAi/w_*d1); + const point p0(dCi + l1); + const point p1(dCi - l1); + + forAll(visibleFaces, visibleFacei) + { + const label sloti = visibleFaces[visibleFacei]; + + const point& dCj = compactCf[sloti]; + const vector& Aj = compactSf[sloti]; + const scalar magAj = mag(Aj); + + const vector d2((Aj/magAj) ^ emptyDir_); + const vector l2(0.5*magAj/w_*d2); + const point p2(dCj - l2); + const point p3(dCj + l2); + + const scalar FijH = calculateFij(p0, p1, p2, p3); + + Fij[facei][visibleFacei] = FijH/(magAi/w_); + } + } + + + return Fij; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::viewFactorHottel::viewFactorHottel +( + const fvMesh& mesh, + const dictionary& dict +) +: + viewFactorModel(mesh, dict), + emptyDir_(vector::one), + w_(0) +{ + if (mesh.nSolutionD() != 2) + { + FatalErrorInFunction + << "Hottel crossed strings method only applicable to 2D cases" + << exit(FatalError); + } + + meshTools::constrainDirection(mesh, mesh.solutionD(), emptyDir_); + emptyDir_ = vector::one - emptyDir_; + emptyDir_.normalise(); + + // 2D width - assume slab + // TODO: warn wedge/axisymmetric? + w_ = mesh.bounds().span() & emptyDir_; + + Info<< "\nEmpty direction: " << emptyDir_ + << "\nWidth: " << w_ << endl; +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.H new file mode 100644 index 0000000000000000000000000000000000000000..da7bade587b3356ca40c9e4dfa406c362eee8cc8 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorHottel/viewFactorHottel.H @@ -0,0 +1,135 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Class + Foam::VF::viewFactorHottel + +Description + Computes view factors according to Hottel's crossed strings method. + + Reference: + \verbatim + Hottel, H. C., & Saforim, A. F. (1967). + Radiative transfer. + McGraw-Hill Book Company, New York. + \endverbatim + +Usage + Minimal example in \c <constant>/viewFactorsDict: + \verbatim + // Inherited entries + ... + \endverbatim + + The inherited entries are elaborated in: + - \link viewFactorModel.H \endlink + +Note + Only applicable to 2D cases + +SourceFiles + viewFactorModel.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_viewFactorHottel_H +#define Foam_vf_viewFactorHottel_H + +#include "viewFactorModel.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace VF +{ + +/*---------------------------------------------------------------------------*\ + Class viewFactorHottel Declaration +\*---------------------------------------------------------------------------*/ + +class viewFactorHottel +: + public viewFactorModel +{ + // Private Data + + //- Mesh empty direction + vector emptyDir_; + + //- Mesh 2D width + scalar w_; + + +protected: + + // Protected Member Functions + + //- Calculate view factor using the double-area integral + static scalar calculateFij + ( + const point& p0, + const point& p1, + const point& p2, + const point& p3 + ); + + //- Calculate + virtual scalarListList calculate + ( + const labelListList& visibleFaceFaces, + const pointField& compactCf, + const vectorField& compactSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId + ) const; + + +public: + + //- Runtime type information + TypeName("viewFactorHottel"); + + //- Constructor + viewFactorHottel(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~viewFactorHottel() = default; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.C new file mode 100644 index 0000000000000000000000000000000000000000..cc4e1442f6cc596342acc4f6f6011d86b6648a4e --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.C @@ -0,0 +1,290 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "viewFactorModel.H" +#include "raySearchEngine.H" +#include "OBJstream.H" +#include "volFields.H" +#include "IOmapDistribute.H" +#include "scalarListIOList.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace VF +{ + defineTypeNameAndDebug(viewFactorModel, 0); + defineRunTimeSelectionTable(viewFactorModel, mesh); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::VF::viewFactorModel::writeRays +( + const fileName& fName, + const pointField& compactCf, + const labelListList& visibleFaceFaces +) +{ + OBJstream str(fName); + + Pout<< "Writing rays to " << str.name() << endl; + + forAll(visibleFaceFaces, facei) + { + const labelList& visibleSlots = visibleFaceFaces[facei]; + + for (const label sloti : visibleSlots) + { + str.write(linePointRef(compactCf[facei], compactCf[sloti])); + } + } + + str.flush(); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::VF::viewFactorModel::viewFactorModel +( + const fvMesh& mesh, + const dictionary& dict +) +: + mesh_(mesh), + searchEnginePtr_(raySearchEngine::New(mesh, dict)), + writeViewFactors_(dict.get<bool>("writeViewFactors")), + writeRays_(dict.getOrDefault<bool>("writeRays", false)) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::VF::viewFactorModel::~viewFactorModel() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::VF::viewFactorModel::calculate() +{ + const auto& searchEngine = *searchEnginePtr_; + + labelListList visibleFaceFaces; + searchEngine.correct(visibleFaceFaces); + const auto& map = searchEngine.map(); + + // Construct data in compact addressing + // Compact addressing has all local data, followed by remote contributions + + pointField compactCf; + vectorField compactSf; + List<List<vector>> compactFineSf; + List<List<point>> compactFineCf; + DynamicList<List<point>> compactPoints; + DynamicList<label> compactPatchId; + + searchEngine.compactAddressing + ( + map, + compactCf, + compactSf, + compactFineSf, + compactFineCf, + compactPoints, + compactPatchId + ); + + if (writeRays_) + { + // Write all rays between visible faces using .OBJ format + + writeRays + ( + mesh_.time().path()/"allVisibleFaces.obj", + compactCf, + visibleFaceFaces + ); + } + + (void)mesh_.time().cpuTimeIncrement(); + + Info<< "\nCalculating view factors" << endl; + + scalarListIOList Fij + ( + IOobject + ( + "F", + mesh_.facesInstance(), + mesh_, + IOobject::NO_READ + ), + calculate + ( + visibleFaceFaces, + compactCf, + compactSf, + compactFineSf, + compactFineCf, + compactPoints, + compactPatchId + ) + ); + + const label totalPatches = mesh_.boundaryMesh().nNonProcessor(); + + // Matrix sum in j(Fij) for each i + // Note: if enclosure sum should = 1 + scalarSquareMatrix viewFactorPatch(totalPatches, Zero); + + forAll(visibleFaceFaces, startFacei) + { + const scalar magAi = mag(compactSf[startFacei]); + + const labelList& visibleSlots = visibleFaceFaces[startFacei]; + const label patchi = compactPatchId[startFacei]; + + forAll(visibleSlots, visSloti) + { + const label sloti = visibleSlots[visSloti]; + const label patchj = compactPatchId[sloti]; + + viewFactorPatch[patchi][patchj] += Fij[startFacei][visSloti]*magAi; + } + } + + reduce(viewFactorPatch, sumOp<scalarSquareMatrix>()); + + const scalarList patchArea = searchEngine.patchAreas(); + + + if (UPstream::master()) + { + Info<< "\nPatch view factor contributions:" << nl << endl; + + scalar vfSum = 0; + + const auto& patchIDs = searchEngine.patchIDs(); + const auto& patches = mesh_.boundaryMesh(); + + for (const label patchi : patchIDs) + { + Info<< " Patch " << patchi << ": " << patches[patchi].name() + << endl; + + scalar vfPatch = 0; + for (const label patchj: patchIDs) + { + scalar vf = viewFactorPatch[patchi][patchj]/patchArea[patchi]; + vfPatch += vf; + + Info<< " F" << patchi << patchj << ": " << vf << endl; + } + + Info<< " Sum: " << vfPatch << nl << endl; + + vfSum += vfPatch; + } + + Info<< "Sum(all patches) = " << vfSum << endl; + } + + // Write view factors matrix in list-list form + Info<< "\nWriting view factor matrix" << endl; + Fij.write(); + + if (writeViewFactors_) + { + Info<< "\nWriting view factor field" << endl; + + auto tviewFactorField = + volScalarField::New + ( + "viewFactorField", + mesh_, + dimensionedScalar(dimless, Zero) + ); + + auto& viewFactorField = tviewFactorField.ref(); + + searchEngine.interpolate(viewFactorField, Fij); + + viewFactorField.write(); + } + + + // Create globalFaceFaces needed to insert view factors + // in F to the global matrix Fmatrix + { + labelListIOList IOglobalFaceFaces + ( + IOobject + ( + "globalFaceFaces", + mesh_.facesInstance(), + mesh_, + IOobject::NO_READ + ), + visibleFaceFaces.size() + ); + + forAll(IOglobalFaceFaces, facei) + { + IOglobalFaceFaces[facei] = renumber + ( + searchEngine.compactToGlobal(), + visibleFaceFaces[facei] + ); + } + + IOglobalFaceFaces.write(); + } + + // Write parallel map + { + IOmapDistribute IOmapDist + ( + IOobject + ( + "mapDist", + mesh_.facesInstance(), + mesh_, + IOobject::NO_READ + ), + std::move(map) + ); + + IOmapDist.write(); + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.H b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.H new file mode 100644 index 0000000000000000000000000000000000000000..549c50978da3f15556a93d72b74903f79024eb84 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModel.H @@ -0,0 +1,185 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +Namespace + Foam::VF + +Description + A namespace for various \c viewFactor model implementations. + +Class + Foam::VF::viewFactorModel + +Description + A base class for \c viewFactor models. + +Usage + Minimal example in \c <constant>/viewFactorsDict: + \verbatim + // Mandatory entries + writeViewFactors <bool>; + + // Optional entries + writeRays <bool>; + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Reqd | Deflt + writeViewFactors | Flag to write the view factor field | bool | yes | - + writeRays | Flag to write the ray geometry | bool | no | false + \endtable + +SourceFiles + viewFactorModel.C + viewFactorModelNew.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_vf_viewFactorModel_H +#define Foam_vf_viewFactorModel_H + +#include "autoPtr.H" +#include "pointField.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward Declarations +class fvMesh; + +namespace VF +{ + +// Forward Declarations +class raySearchEngine; + +/*---------------------------------------------------------------------------*\ + Class viewFactorModel Declaration +\*---------------------------------------------------------------------------*/ + +class viewFactorModel +{ +protected: + + // Protected Data + + //- Reference to the mesh database + const fvMesh& mesh_; + + //- Run-time selectable ray search engine + autoPtr<raySearchEngine> searchEnginePtr_; + + //- Flag to write the view factor field + bool writeViewFactors_; + + //- Flag to write the ray geometry + bool writeRays_; + + + // Protected Member Functions + + //- Write ray geometry to file + static void writeRays + ( + const fileName& fName, + const pointField& compactCf, + const labelListList& visibleFaceFaces + ); + + //- Calculate the view factors using run-time selectable model + virtual scalarListList calculate + ( + const labelListList& visibleFaceFaces, + const pointField& compactCoarseCf, + const vectorField& compactCoarseSf, + const List<List<vector>>& compactFineSf, + const List<List<point>>& compactFineCf, + const DynamicList<List<point>>& compactPoints, + const DynamicList<label>& compactPatchId + ) const = 0; + + +public: + + //- Runtime type information + TypeName("viewFactorModel"); + + //- Selection table + declareRunTimeSelectionTable + ( + autoPtr, + viewFactorModel, + mesh, + ( + const fvMesh& mesh, + const dictionary& dict + ), + (mesh, dict) + ); + + //- Selector + static autoPtr<viewFactorModel> New + ( + const fvMesh& mesh, + const dictionary& dict + ); + + + // Generated Methods + + //- No copy construct + viewFactorModel(const viewFactorModel&) = delete; + + //- No copy assignment + void operator=(const viewFactorModel&) = delete; + + + //- Constructor + viewFactorModel(const fvMesh& mesh, const dictionary& dict); + + //- Destructor + virtual ~viewFactorModel(); + + + // Public Member Functions + + //- Calculate the view factors + virtual void calculate(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace VF +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModelNew.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModelNew.C new file mode 100644 index 0000000000000000000000000000000000000000..e87f7d459fd696e0a9a2371853e6ad05c902c4f2 --- /dev/null +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/viewFactorModel/viewFactorModel/viewFactorModelNew.C @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2023-2024 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "viewFactorModel.H" +#include "viewFactorHottel.H" +#include "fvMesh.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::VF::viewFactorModel> Foam::VF::viewFactorModel::New +( + const fvMesh& mesh, + const dictionary& dict +) +{ + // Intercept 2D cases + if (mesh.nSolutionD() == 2) + { + Info<< "Selecting " << typeName << ": " << viewFactorHottel::typeName + << " for 2D cases" << nl << endl; + return autoPtr<viewFactorModel>(new viewFactorHottel(mesh, dict)); + } + + + // 3D cases - use run-time selection + + const word modelType(dict.get<word>("viewFactorModel")); + + Info<< "Selecting " << typeName << ": " << modelType << endl; + + auto* ctorPtr = meshConstructorTable(modelType); + + if (!ctorPtr) + { + FatalIOErrorInLookup + ( + dict, + typeName, + modelType, + *meshConstructorTablePtr_ + ) << exit(FatalIOError); + } + + return autoPtr<viewFactorModel>(ctorPtr(mesh, dict)); +} + + +// ************************************************************************* //