faceReflecting.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2018-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "faceReflecting.H"
30#include "cyclicAMIPolyPatch.H"
31#include "volFields.H"
32
33
34using namespace Foam::constant::mathematical;
35
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37
38namespace Foam
39{
41}
42
43// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44
46{
47
48 forAll(qreflective_, bandI)
49 {
50 qreflective_.set
51 (
52 bandI,
54 (
56 (
57 "qreflective_" + Foam::name(bandI) ,
58 mesh_.time().timeName(),
59 mesh_,
62 ),
63 mesh_,
65 )
66 );
67 }
68
69 label rayI = 0;
70 if (mesh_.nSolutionD() == 3)
71 {
72 nRay_ = 4*nPhi_*nTheta_;
73 refDiscAngles_.resize(nRay_);
74 const scalar deltaPhi = pi/(2.0*nPhi_);
75 const scalar deltaTheta = pi/nTheta_;
76
77 for (label n = 1; n <= nTheta_; n++)
78 {
79 for (label m = 1; m <= 4*nPhi_; m++)
80 {
81 const scalar thetai = (2*n - 1)*deltaTheta/2.0;
82 const scalar phii = (2*m - 1)*deltaPhi/2.0;
83
84 scalar sinTheta = Foam::sin(thetai);
85 scalar cosTheta = Foam::cos(thetai);
86 scalar sinPhi = Foam::sin(phii);
87 scalar cosPhi = Foam::cos(phii);
88 refDiscAngles_[rayI++] =
89 vector(sinTheta*sinPhi, sinTheta*cosPhi, cosTheta);
90
91 }
92 }
93
94 }
95 else if (mesh_.nSolutionD() == 2)
96 {
97 nRay_ = 4*nPhi_;
98 refDiscAngles_.resize(nRay_);
99 const scalar thetai = piByTwo;
100 //const scalar deltaTheta = pi;
101 const scalar deltaPhi = pi/(2.0*nPhi_);
102 for (label m = 1; m <= 4*nPhi_; m++)
103 {
104 const scalar phii = (2*m - 1)*deltaPhi/2.0;
105
106 scalar sinTheta = Foam::sin(thetai);
107 scalar cosTheta = Foam::cos(thetai);
108 scalar sinPhi = Foam::sin(phii);
109 scalar cosPhi = Foam::cos(phii);
110
111 refDiscAngles_[rayI++] =
112 vector(sinTheta*sinPhi, sinTheta*cosPhi, cosTheta);
113 }
114 }
115 else
116 {
118 << "The reflected rays are available in 2D or 3D "
119 << abort(FatalError);
120 }
121
122 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
123
124 const radiation::boundaryRadiationProperties& boundaryRadiation =
126
127 // global face index
128 globalIndex globalNumbering(mesh_.nFaces());
129
130
131 // Collect faces with t = 0, r = 0 and a > 0 to shoot rays
132 // and patches to construct the triSurface
133 DynamicList<point> dynCf;
135 DynamicList<label> dynFacesI;
136 forAll(patches, patchI)
137 {
138 const polyPatch& pp = patches[patchI];
139 const vectorField::subField cf = pp.faceCentres();
140
141 if (!pp.coupled() && !isA<cyclicAMIPolyPatch>(pp))
142 {
143 const tmp<scalarField> tt =
144 boundaryRadiation.transmissivity(patchI);
145
146 const tmp<scalarField> tr =
147 boundaryRadiation.specReflectivity(patchI);
148
149 const tmp<scalarField> ta =
150 boundaryRadiation.absorptivity(patchI);
151
152 const scalarField& t = tt();
153 const scalarField& r = tr();
154 const scalarField& a = ta();
155
156 const vectorField& n = pp.faceNormals();
157
158 forAll(pp, faceI)
159 {
160 //const vector nf(n[faceI]);
161 // Opaque, non-reflective, absortived faces to shoot
162 if
163 (
164 t[faceI] == 0
165 && r[faceI] == 0
166 && a[faceI] > 0
167 )
168 {
169 dynFacesI.append(faceI + pp.start());
170 dynCf.append(cf[faceI]);
171 dynNf.append(n[faceI]);
172 }
173
174 // relfective opaque patches to build reflective surface
175 // plus opaque non-reflective
176 if
177 (
178 (r[faceI] > 0 && t[faceI] == 0) ||
179 (t[faceI] == 0 && a[faceI] > 0 && r[faceI] == 0)
180 )
181 {
182 includePatches_.insert(patchI);
183 }
184 }
185 }
186 }
187
188 shootFacesIds_.reset(new labelList(dynFacesI));
189 Cfs_.reset(new pointField(dynCf));
190 Nfs_.reset(new vectorField(dynNf));
191
192 // * * * * * * * * * * * * * * *
193 // Create distributedTriSurfaceMesh
194 Random rndGen(653213);
195
196 // Determine mesh bounding boxes:
198 (
199 1,
201 (
202 boundBox(mesh_.points(), false)
203 ).extend(rndGen, 1e-3)
204 );
205
206 // Dummy bounds dictionary
208 dict.add("bounds", meshBb);
209 dict.add
210 (
211 "distributionType",
213 [
215 ]
216 );
217 dict.add("mergeDistance", SMALL);
218
219
221 (
222 mesh_.boundaryMesh(),
223 includePatches_,
224 mapTriToGlobal_
225 );
226
227 surfacesMesh_.reset
228 (
230 (
232 (
233 "reflectiveSurface.stl",
234 mesh_.time().constant(),
235 "triSurface",
236 mesh_.time(),
239 ),
241 dict
242 )
243 );
244
245 if (debug)
246 {
247 surfacesMesh_->searchableSurface::write();
248 }
249}
250
251
252void Foam::faceReflecting::calculate()
253{
254 const radiation::boundaryRadiationProperties& boundaryRadiation =
256
257 label nFaces = 0;
258
259 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
260
261 const fvBoundaryMesh& fvPatches = mesh_.boundary();
262
263 label nBands = spectralDistribution_.size();
264
265 // Collect reflected directions from reflecting surfaces on direct hit
266 // faces
267 const vector sunDir = directHitFaces_.direction();
268 const labelList& directHits = directHitFaces_.rayStartFaces();
269
270 globalIndex globalNumbering(mesh_.nFaces());
271
272 Map<label> refFacesDirIndex;
273 labelList refDisDirsIndex(nRay_, -1);
274
275 forAll(patches, patchI)
276 {
277 const polyPatch& pp = patches[patchI];
278
279 if (!pp.coupled() && !isA<cyclicAMIPolyPatch>(pp))
280 {
281 const tmp<scalarField> tr =
282 boundaryRadiation.specReflectivity(patchI);
283
284 const scalarField& r = tr();
285 const vectorField n(fvPatches[patchI].nf());
286
287 forAll(pp, faceI)
288 {
289 label globalID = faceI + pp.start();
290
291 if (r[faceI] > 0.0 && directHits.found(globalID))
292 {
293 vector refDir =
294 sunDir + 2.0*(-sunDir & n[faceI]) * n[faceI];
295
296 // Look for the discrete direction
297 scalar dev(-GREAT);
298 label rayIndex = -1;
299 forAll(refDiscAngles_, iDisc)
300 {
301 scalar dotProd = refDir & refDiscAngles_[iDisc];
302 if (dev < dotProd)
303 {
304 dev = dotProd;
305 rayIndex = iDisc;
306 }
307 }
308
309 if (rayIndex >= 0)
310 {
311 if (refDisDirsIndex[rayIndex] == -1)
312 {
313 refDisDirsIndex[rayIndex] = 1;
314 }
315 }
316
317 refFacesDirIndex.insert
318 (
319 globalNumbering.toGlobal(globalID),
320 rayIndex
321 );
322
323 nFaces++;
324 }
325 }
326 }
327 }
328
329 // Distribute ray indexes to all proc's
330 // Make sure all the processors have the same information
331
333 Pstream::mapCombineAllGather(refFacesDirIndex, minEqOp<label>());
334
335 scalar maxBounding = 5.0*mag(mesh_.bounds().max() - mesh_.bounds().min());
336
337 reduce(maxBounding, maxOp<scalar>());
338
339 // Shoot Rays
340 // From faces t = 0, r = 0 and a > 0 to all 'used' discrete reflected
341 // directions
342
344 DynamicField<point> end(start.size());
345 DynamicList<label> startIndex(start.size());
346 DynamicField<label> dirStartIndex(start.size());
347
348 label i = 0;
349 do
350 {
351 for (; i < Cfs_->size(); i++)
352 {
353 const point& fc = Cfs_()[i];
354
355 const vector nf = Nfs_()[i];
356
357 const label myFaceId = shootFacesIds_()[i];
358
359 forAll(refDisDirsIndex, dirIndex)
360 {
361 if (refDisDirsIndex[dirIndex] > -1)
362 {
363 if ((nf & refDiscAngles_[dirIndex]) > 0)
364 {
365 const vector direction = -refDiscAngles_[dirIndex];
366
367 start.append(fc + 0.001*direction);
368
369 startIndex.append(myFaceId);
370 dirStartIndex.append(dirIndex);
371
372 end.append(fc + maxBounding*direction);
373 }
374 }
375 }
376 }
377
378 }while (returnReduce(i < Cfs_->size(), orOp<bool>()));
379
380 List<pointIndexHit> hitInfo(startIndex.size());
381
382 surfacesMesh_->findLine(start, end, hitInfo);
383
384 // Query the local trigId on hit faces
385 labelList triangleIndex;
387 (
388 surfacesMesh_->localQueries
389 (
390 hitInfo,
391 triangleIndex
392 )
393 );
394 const mapDistribute& map = mapPtr();
395
398 forAll(patchr, patchi)
399 {
400 patchr.set
401 (
402 patchi,
403 new List<scalarField>(nBands)
404 );
405
406 patcha.set
407 (
408 patchi,
409 new List<scalarField>(nBands)
410 );
411 }
412
413 // Fill patchr
414 forAll(patchr, patchi)
415 {
416 const polyPatch& pp = patches[patchi];
417
418 if (!pp.coupled() && !isA<cyclicAMIPolyPatch>(pp))
419 {
420 for (label bandI = 0; bandI < nBands; bandI++)
421 {
422 patchr[patchi][bandI] =
423 boundaryRadiation.specReflectivity
424 (
425 patchi,
426 bandI,
427 new vectorField(patches[patchi].size(), sunDir)
428 );
429
430 patcha[patchi][bandI] =
431 boundaryRadiation.absorptivity
432 (
433 patchi,
434 bandI,
435 new vectorField(patches[patchi].size(), sunDir)
436 );
437 }
438 }
439 }
440
441 List<scalarField> r(nBands);
442 for (label bandI = 0; bandI < nBands; bandI++)
443 {
444 r[bandI].setSize(triangleIndex.size());
445 }
446 labelList refDirIndex(triangleIndex.size());
447 labelList refIndex(triangleIndex.size());
448 // triangleIndex includes hits on non-reflecting and reflecting faces
449 forAll(triangleIndex, i)
450 {
451 label trii = triangleIndex[i];
452 label facei = mapTriToGlobal_[trii];
453 label patchI = patches.whichPatch(facei);
454 const polyPatch& pp = patches[patchI];
455 label localFaceI = pp.whichFace(facei);
456
457 label globalFace = globalNumbering.toGlobal(Pstream::myProcNo(), facei);
458 if (refFacesDirIndex.found(globalFace))
459 {
460 refDirIndex[i] = refFacesDirIndex.find(globalFace)();
461 refIndex[i] = globalFace;
462 }
463 for (label bandI = 0; bandI < nBands; bandI++)
464 {
465 r[bandI][i] = patchr[patchI][bandI][localFaceI];
466 }
467 }
468 map.reverseDistribute(hitInfo.size(), refDirIndex);
469 map.reverseDistribute(hitInfo.size(), refIndex);
470 for (label bandI = 0; bandI < nBands; bandI++)
471 {
472 map.reverseDistribute(hitInfo.size(), r[bandI]);
473 }
474
475 for (label bandI = 0; bandI < nBands; bandI++)
476 {
478 qreflective_[bandI].boundaryFieldRef();
479 qrefBf = 0.0;
480 }
481
482 const vector qPrim(solarCalc_.directSolarRad()*solarCalc_.direction());
483
484 // Collect rays with a hit (hitting reflecting surfaces)
485 // and whose reflected direction are equal to the shot ray
486 forAll(hitInfo, rayI)
487 {
488 if (hitInfo[rayI].hit())
489 {
490 if
491 (
492 dirStartIndex[rayI] == refDirIndex[rayI]
493 && refFacesDirIndex.found(refIndex[rayI])
494 )
495 {
496 for (label bandI = 0; bandI < nBands; bandI++)
497 {
499 qreflective_[bandI].boundaryFieldRef();
500
501 label startFaceId = startIndex[rayI];
502 label startPatchI = patches.whichPatch(startFaceId);
503
504 const polyPatch& ppStart = patches[startPatchI];
505 label localStartFaceI = ppStart.whichFace(startFaceId);
506
507 scalar a = patcha[startPatchI][bandI][localStartFaceI];
508
509 const vectorField& nStart = ppStart.faceNormals();
510
511 vector rayIn = refDiscAngles_[dirStartIndex[rayI]];
512
513 rayIn /= mag(rayIn);
514
515 qrefBf[startPatchI][localStartFaceI] +=
516 (
517 (
518 mag(qPrim)
519 *r[bandI][rayI]
520 *spectralDistribution_[bandI]
521 *a
522 *rayIn
523 )
524 & nStart[localStartFaceI]
525 );
526 }
527 }
528 }
529 }
530
531 start.clear();
532 startIndex.clear();
533 end.clear();
534 dirStartIndex.clear();
535}
536
537
538// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
539
541(
542 const fvMesh& mesh,
543 const faceShading& directHiyFaces,
544 const solarCalculator& solar,
545 const scalarList& spectralDistribution,
546 const dictionary& dict
547)
548:
549 mesh_(mesh),
550 nTheta_(dict.subDict("reflecting").getOrDefault<label>("nTheta", 10)),
551 nPhi_(dict.subDict("reflecting").getOrDefault<label>("nPhi", 10)),
552 nRay_(0),
553 refDiscAngles_(0),
554 spectralDistribution_(spectralDistribution),
555 qreflective_(spectralDistribution_.size()),
556 directHitFaces_(directHiyFaces),
557 surfacesMesh_(),
558 shootFacesIds_(),
559 Cfs_(),
560 Nfs_(),
561 solarCalc_(solar),
562 includePatches_(),
563 mapTriToGlobal_()
564{
565 initialise(dict);
566}
567
568
569// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
570
572{
573 calculate();
574}
575
576
577// ************************************************************************* //
label n
Dynamically sized Field.
Definition: DynamicField.H:65
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
bool found(const Key &key) const
Return true if hashed entry is found in table.
Definition: HashTableI.H:100
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: HashTableI.H:114
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
A HashTable to objects of type <T> with a label key.
Definition: Map.H:60
virtual label triangulate()
Triangulate in-place, returning the number of triangles added.
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
static void listCombineAllGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
static void mapCombineAllGather(const List< commsStruct > &comms, Container &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: PtrList.H:73
void clear()
Clear the PtrList. Delete allocated entries and set size to zero.
Definition: PtrListI.H:97
Random number generator.
Definition: Random.H:60
SubField is a Field obtained as a section of another Field, without its own allocation....
Definition: SubField.H:62
const word & constant() const
Return constant name.
Definition: TimePathsI.H:96
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:780
bool found(const T &val, label pos=0) const
True if the value if found in the list.
Definition: UListI.H:265
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:64
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:640
IOoject and searching on distributed triSurface. All processor hold (possibly overlapping) part of th...
static const Enum< distributionType > distributionTypeNames_
Calculates the reflecting faces from specular surfaces. It only takes into account the first reflecti...
void correct()
Correct reflected flux.
faceShading uses the transmissivity value in the boundaryRadiationProperties in order to evaluate whi...
Definition: faceShading.H:62
Foam::fvBoundaryMesh.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:290
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Class containing processor-to-processor mapping information.
void reverseDistribute(const label constructSize, List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
label nSolutionD() const
Return the number of valid solved-for dimensions in the mesh.
Definition: polyMesh.C:900
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:451
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:380
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:364
const vectorField::subField faceCentres() const
Return face centres.
Definition: polyPatch.C:321
label nFaces() const noexcept
Number of mesh faces.
int myProcNo() const noexcept
Return processor number.
tmp< scalarField > absorptivity(const label patchI, const label bandI=0, vectorField *incomingDirection=nullptr, scalarField *T=nullptr) const
Access boundary absorptivity on patch.
tmp< scalarField > specReflectivity(const label patchI, const label bandI=0, vectorField *incomingDirection=nullptr, scalarField *T=nullptr) const
Access boundary specular reflectivity on patch.
tmp< scalarField > transmissivity(const label patchI, const label bandI=0, vectorField *incomingDirection=nullptr, scalarField *T=nullptr) const
Access boundary transmissivity on patch.
A solar calculator model providing models for the solar direction and solar loads.
A class for managing temporary objects.
Definition: tmp.H:65
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:89
treeBoundBox extend(Random &rndGen, const scalar s) const
Return slightly wider bounding box.
Triangulated surface description with patch information.
Definition: triSurface.H:79
void initialise()
Initialise integral-scale box properties.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
Mathematical constants.
constexpr scalar pi(M_PI)
constexpr scalar piByTwo(0.5 *M_PI)
T cosPhi(const Vector< T > &a, const Vector< T > &b, const T &tolerance=SMALL)
Calculate angle between a and b in radians.
Definition: vectorTools.H:107
Namespace for OpenFOAM.
dimensionedSymmTensor dev(const dimensionedSymmTensor &dt)
dimensionedScalar tr(const dimensionedSphericalTensor &dt)
List< label > labelList
A List of labels.
Definition: List.H:66
dimensionedScalar pow3(const dimensionedScalar &ds)
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:53
dimensionedScalar sin(const dimensionedScalar &ds)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Field< vector > vectorField
Specialisation of Field<T> for vector.
uint8_t direction
Definition: direction.H:56
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
Vector< scalar > vector
Definition: vector.H:61
dimensionedScalar cos(const dimensionedScalar &ds)
const dimensionSet dimMass(1, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:51
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:158
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(rndGen, 1e-3))
dictionary dict
const triSurface localSurface
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
Random rndGen
Definition: createFields.H:23