faceShading.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) 2015 OpenFOAM Foundation
9  Copyright (C) 2017-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "faceShading.H"
30 #include "fvMesh.H"
32 #include "cyclicAMIPolyPatch.H"
33 #include "volFields.H"
34 #include "surfaceFields.H"
36 #include "OBJstream.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(faceShading, 0);
43 }
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 void Foam::faceShading::calculate()
48 {
49  const auto& pbm = mesh_.boundaryMesh();
50 
51  const bitSet isOpaqueFace
52  (
53  selectOpaqueFaces
54  (
56  patchIDs_,
57  zoneIDs_
58  )
59  );
60 
61  // Find faces potentially hit by solar rays
62  // - correct normal
63  // - transmissivity 0
64  labelList hitFacesIds;
65  bitSet hitFacesFlips;
66  selectFaces
67  (
68  true, // use normal to do first filtering
69  isOpaqueFace,
70  patchIDs_,
71  zoneIDs_,
72 
73  hitFacesIds,
74  hitFacesFlips
75  );
76 
77  Info<< "Number of 'potential' direct hits : "
78  << returnReduce(hitFacesIds.size(), sumOp<label>()) << endl;
79 
80 
81  // * * * * * * * * * * * * * * *
82  // Create distributedTriSurfaceMesh
83  Random rndGen(653213);
84 
85  // Find potential obstructions. Include all faces that might potentially
86  // block (so ignore normal)
87  labelList blockingFacesIds;
88  bitSet blockingFacesFlips;
89  selectFaces
90  (
91  false, // use normal to do first filtering
92  isOpaqueFace,
93  patchIDs_,
94  zoneIDs_,
95 
96  blockingFacesIds,
97  blockingFacesFlips
98  );
99 
100  const triSurface localSurface = triangulate
101  (
102  blockingFacesIds,
103  blockingFacesFlips
104  );
105 
106  // Determine mesh bounding boxes:
107  List<treeBoundBox> meshBb
108  (
109  1,
110  treeBoundBox(mesh_.points()).extend(rndGen, 1e-3)
111  );
112 
113  // Dummy bounds dictionary
115  dict.add("bounds", meshBb);
116  dict.add
117  (
118  "distributionType",
120  [
122  ]
123  );
124  dict.add("mergeDistance", SMALL);
125 
126  distributedTriSurfaceMesh surfacesMesh
127  (
128  IOobject
129  (
130  "opaqueSurface.stl",
131  mesh_.time().constant(), // directory
132  "triSurface", // instance
133  mesh_.time(), // registry
136  ),
137  localSurface,
138  dict
139  );
140 
141  if (debug)
142  {
143  surfacesMesh.searchableSurface::write();
144  }
145 
146  const scalar maxBounding =
147  returnReduce(5.0*mesh_.bounds().mag(), maxOp<scalar>());
148 
149  // Calculate index of faces which have a direct hit (local)
150 
151  // Shoot Rays
152  // * * * * * * * * * * * * * * * *
153  {
154 
155  DynamicField<point> start(hitFacesIds.size());
156  DynamicField<point> end(start.size());
157  DynamicList<label> startIndex(start.size());
158 
159  const pointField& faceCentres = mesh_.faceCentres();
160 
161  const vector d(direction_*maxBounding);
162 
163  forAll(hitFacesIds, i)
164  {
165  const label facei = hitFacesIds[i];
166  const point& fc = faceCentres[facei];
167 
168  start.append(fc - 0.001*d);
169  startIndex.append(facei);
170  end.append(fc - d);
171  }
172 
173  List<pointIndexHit> hitInfo(startIndex.size());
174  surfacesMesh.findLine(start, end, hitInfo);
175 
176  // Collect the rays which has 'only one not wall' obstacle between
177  // start and end.
178  // If the ray hit itself get stored in dRayIs
179 
180  label nVisible = 0;
181  forAll(hitInfo, rayI)
182  {
183  if (!hitInfo[rayI].hit())
184  {
185  nVisible++;
186  }
187  }
188  rayStartFaces_.setSize(nVisible);
189  nVisible = 0;
190 
191  forAll(hitInfo, rayI)
192  {
193  if (!hitInfo[rayI].hit())
194  {
195  rayStartFaces_[nVisible++] = startIndex[rayI];
196  }
197  }
198 
199  // Plot all rays between visible faces.
200  if (debug)
201  {
202  writeRays
203  (
204  mesh_.time().path()/"allVisibleFaces.obj",
205  end,
206  start
207  );
208  }
209 
210  start.clear();
211  startIndex.clear();
212  end.clear();
213  }
214 
215  if (debug)
216  {
217  auto thitFaces = tmp<surfaceScalarField>::New
218  (
219  IOobject
220  (
221  "hitFaces",
222  mesh_.time().timeName(),
223  mesh_,
227  ),
228  mesh_,
230  );
231 
232  surfaceScalarField& hitFaces = thitFaces.ref();
233  surfaceScalarField::Boundary& hitFacesBf = hitFaces.boundaryFieldRef();
234 
235  hitFacesBf = 0.0;
236  for (const label facei : rayStartFaces_)
237  {
238  const label patchID = pbm.whichPatch(facei);
239  if (patchID == -1)
240  {
241  hitFaces[facei] = 1.0;
242  }
243  else
244  {
245  const polyPatch& pp = pbm[patchID];
246  hitFacesBf[patchID][facei - pp.start()] = 1.0;
247  }
248  }
249  hitFaces.write();
250  }
251 
252  Info<< "Total number of hit faces : "
253  << returnReduce(rayStartFaces_.size(), sumOp<label>()) << endl;
254 }
255 
256 
257 Foam::triSurface Foam::faceShading::triangulate
258 (
259  const labelUList& faceIDs,
260  const bitSet& flipMap
261 ) const
262 {
263  if (faceIDs.size() != flipMap.size())
264  {
265  FatalErrorInFunction << "Size problem :"
266  << "faceIDs:" << faceIDs.size()
267  << "flipMap:" << flipMap.size()
268  << exit(FatalError);
269  }
270 
271  const auto& points = mesh_.points();
272  const auto& faces = mesh_.faces();
273  const auto& bMesh = mesh_.boundaryMesh();
274  const auto& fzs = mesh_.faceZones();
275 
276  // Patching of surface:
277  // - non-processor patches
278  // - faceZones
279  // Note: check for faceZones on boundary? Who has priority?
280  geometricSurfacePatchList surfPatches(bMesh.nNonProcessor()+fzs.size());
281  labelList patchID(mesh_.nFaces(), -1);
282  {
283  label newPatchi = 0;
284  for (label patchi = 0; patchi < bMesh.nNonProcessor(); ++patchi)
285  {
286  const auto& pp = bMesh[patchi];
287 
288  surfPatches[newPatchi] = geometricSurfacePatch
289  (
290  pp.name(),
291  newPatchi,
292  pp.type()
293  );
294  SubList<label>
295  (
296  patchID,
297  pp.size(),
298  pp.start()
299  ) = newPatchi;
300 
301  newPatchi++;
302  }
303  for (const auto& fz : fzs)
304  {
305  surfPatches[newPatchi] = geometricSurfacePatch
306  (
307  fz.name(),
308  newPatchi,
309  fz.type()
310  );
311  UIndirectList<label>(patchID, fz) = newPatchi;
312 
313  newPatchi++;
314  }
315  }
316 
317 
318  // Storage for surfaceMesh. Size estimate.
319  DynamicList<labelledTri> triangles(2*faceIDs.size());
320 
321  // Work array
322  faceList triFaces;
323 
324  forAll(faceIDs, i)
325  {
326  const label facei = faceIDs[i];
327  const bool flip = flipMap[i];
328  const label patchi = patchID[facei];
329  const face& f = faces[facei];
330 
331  // Triangulate face
332  triFaces.setSize(f.nTriangles(points));
333  label nTri = 0;
334  f.triangles(points, nTri, triFaces);
335 
336  for (const face& f : triFaces)
337  {
338  if (!flip)
339  {
340  triangles.append(labelledTri(f[0], f[1], f[2], patchi));
341  }
342  else
343  {
344  triangles.append(labelledTri(f[0], f[2], f[1], patchi));
345  }
346  }
347  }
348 
349  triangles.shrink();
350 
351  // Create globally numbered tri surface
352  triSurface rawSurface(triangles, mesh_.points());
353 
354  // Create locally numbered tri surface
355  triSurface surface
356  (
357  rawSurface.localFaces(),
358  rawSurface.localPoints()
359  );
360 
361  // Add patch names to surface
362  surface.patches().transfer(surfPatches);
363 
364  return surface;
365 }
366 
367 
368 Foam::bitSet Foam::faceShading::selectOpaqueFaces
369 (
370  const radiation::boundaryRadiationProperties& boundaryRadiation,
371  const labelUList& patchIDs,
372  const labelUList& zoneIDs
373 ) const
374 {
375  const auto& pbm = mesh_.boundaryMesh();
376 
377  bitSet isOpaqueFace(mesh_.nFaces(), false);
378 
379  // Check selected patches
380  for (const label patchi : patchIDs)
381  {
382  const auto& pp = pbm[patchi];
383  tmp<scalarField> tt = boundaryRadiation.transmissivity(patchi);
384  const scalarField& t = tt.cref();
385 
386  forAll(t, i)
387  {
388  isOpaqueFace[i + pp.start()] = (t[i] == 0.0);
389  }
390  }
391 
392  // Check selected faceZones
393  const auto& fzs = mesh_.faceZones();
394 
395  for (const label zonei : zoneIDs)
396  {
397  const auto& fz = fzs[zonei];
398 
399  //- Note: slice mesh face centres preferentially
400  tmp<scalarField> tt = boundaryRadiation.zoneTransmissivity
401  (
402  zonei,
403  fz
404  );
405  const scalarField& t = tt.cref();
406 
407  forAll(t, i)
408  {
409  isOpaqueFace[fz[i]] = (t[i] == 0.0);
410  }
411  }
412 
413  return isOpaqueFace;
414 }
415 
416 
417 void Foam::faceShading::selectFaces
418 (
419  const bool useNormal,
420  const bitSet& isCandidateFace,
421  const labelUList& patchIDs,
422  const labelUList& zoneIDs,
423 
424  labelList& faceIDs,
425  bitSet& flipMap
426 ) const
427 {
428  const auto& pbm = mesh_.boundaryMesh();
429 
430  bitSet isSelected(mesh_.nFaces());
431  DynamicList<label> dynFaces(mesh_.nBoundaryFaces());
432  bitSet isFaceFlipped(mesh_.nFaces());
433 
434  // Add patches
435  for (const label patchi : patchIDs)
436  {
437  const auto& pp = pbm[patchi];
438  const vectorField& n = pp.faceNormals();
439 
440  forAll(n, i)
441  {
442  const label meshFacei = i + pp.start();
443  if
444  (
445  isCandidateFace[meshFacei]
446  && (
447  !useNormal
448  || ((direction_ & n[i]) > 0)
449  )
450  )
451  {
452  isSelected.set(meshFacei);
453  isFaceFlipped[meshFacei] = false;
454  dynFaces.append(meshFacei);
455  }
456  }
457  }
458 
459 
460  // Add faceZones
461  const auto& fzs = mesh_.faceZones();
462 
463  for (const label zonei : zoneIDs)
464  {
465  const auto& fz = fzs[zonei];
466  const primitiveFacePatch& pp = fz();
467  const vectorField& n = pp.faceNormals();
468 
469  forAll(n, i)
470  {
471  const label meshFacei = fz[i];
472 
473  if
474  (
475  !isSelected[meshFacei]
476  && isCandidateFace[meshFacei]
477  && (
478  !useNormal
479  || ((direction_ & n[i]) > 0)
480  )
481  )
482  {
483  isSelected.set(meshFacei);
484  dynFaces.append(meshFacei);
485  isFaceFlipped[meshFacei] = fz.flipMap()[i];
486  }
487  }
488  }
489  faceIDs = std::move(dynFaces);
490  flipMap = bitSet(isFaceFlipped, faceIDs);
491 }
492 
493 
494 void Foam::faceShading::writeRays
495 (
496  const fileName& fName,
497  const DynamicField<point>& endCf,
498  const pointField& myFc
499 )
500 {
501  OBJstream os(fName);
502 
503  Pout<< "Dumping rays to " << os.name() << endl;
504 
505  forAll(myFc, facei)
506  {
507  os.writeLine(myFc[facei], endCf[facei]);
508  }
509 }
511 
512 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
513 
514 Foam::faceShading::faceShading
515 (
516  const fvMesh& mesh,
517  const vector& dir
518 )
519 :
520  mesh_(mesh),
521  patchIDs_(nonCoupledPatches(mesh)),
522  zoneIDs_(0),
523  direction_(dir),
524  rayStartFaces_(0)
525 {
526  calculate();
527 }
528 
529 
530 Foam::faceShading::faceShading
531 (
532  const fvMesh& mesh,
533  const labelList& patchIDs,
534  const labelList& zoneIDs,
535  const vector& dir
536 )
537 :
538  mesh_(mesh),
539  patchIDs_(patchIDs),
540  zoneIDs_(zoneIDs),
541  direction_(dir),
542  rayStartFaces_(0)
543 {
544  calculate();
545 }
546 
547 
548 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
549 
551 {
552  const auto& pbm = mesh.boundaryMesh();
553 
554  DynamicList<label> ncPatches;
555  forAll(pbm, patchi)
556  {
557  const polyPatch& pp = pbm[patchi];
558  if (!pp.coupled() && !isA<cyclicAMIPolyPatch>(pp))
559  {
560  ncPatches.append(patchi);
561  }
562  }
563  return ncPatches;
564 }
565 
566 
568 {
569  calculate();
570 }
571 
572 
573 // ************************************************************************* //
static const Enum< distributionType > distributionTypeNames_
Foam::surfaceFields.
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const polyBoundaryMesh & pbm
dictionary dict
const triSurface localSurface
const labelIOList & zoneIDs
Definition: correctPhi.H:59
fileName path() const
Return path = rootPath/caseName. Same as TimePaths::path()
Definition: Time.H:503
void correct()
Recalculate rayStartFaces using direction vector.
Definition: faceShading.C:562
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition: OSstream.H:128
static const boundaryRadiationProperties & New(const fvMesh &mesh, Args &&... args)
Get existing or create a new MeshObject. Registered with typeName.
Definition: MeshObject.C:53
Random rndGen
Definition: createFields.H:23
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
distributedTriSurfaceMesh surfacesMesh(IOobject("wallSurface.stl", runTime.constant(), "triSurface", runTime, IOobject::NO_READ, IOobject::NO_WRITE), localSurface, dict)
std::vector< Triangle > triangles
GeometricBoundaryField< scalar, fvsPatchField, surfaceMesh > Boundary
Type of boundary fields.
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
const pointField & points
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
scalar mag() const
The magnitude/length of the bounding box diagonal.
Definition: boundBoxI.H:198
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
Vector< scalar > vector
Definition: vector.H:57
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
static labelList nonCoupledPatches(const polyMesh &mesh)
Helper: return all uncoupled patches.
Definition: faceShading.C:545
const wordList surface
Standard surface field types (scalar, vector, tensor, etc)
Ostream & writeLine(const point &p0, const point &p1)
Write line joining two points.
Definition: OBJstream.C:234
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:112
int debug
Static debugging option.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
OBJstream os(runTime.globalPath()/outputName)
List< geometricSurfacePatch > geometricSurfacePatchList
List of geometricSurfacePatch.
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
PrimitivePatch< List< face >, const pointField & > primitiveFacePatch
A PrimitivePatch with List storage for the faces, const reference for the point field.
const vectorField & faceCentres() const
vector point
Point is a vector.
Definition: point.H:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Nothing to be read.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Internal & ref(const bool updateAccessTime=true)
Same as internalFieldRef()
const boundBox & bounds() const noexcept
Return mesh bounding box.
Definition: polyMesh.H:616
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< label > labelList
A List of labels.
Definition: List.H:62
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Triangulated surface description with patch information.
Definition: triSurface.H:71
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Do not request registration (bool: false)
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127