45void Foam::VF::voxel::setTriangulation(
const fvMesh&
mesh)
47 Info<<
"\nCreating triangulated surface" <<
endl;
51 DynamicList<label> globalFaces(
mesh.nBoundaryFaces());
54 const auto&
pbm =
mesh.boundaryMesh();
59 const polyPatch&
patch =
pbm[patchi];
62 for (
const face&
f : patch)
66 f.triangles(
points, nTri, triFaces);
68 const label globalFacei =
71 for (
const face&
f : triFaces)
74 globalFaces.push_back(globalFacei);
79 triToGlobalFace_.transfer(globalFaces);
81 Info<<
" Total number of triangles: "
87 surface_.compactPoints();
99 if (
mesh.nSolutionD() == 3)
101 const auto&
pbm =
mesh.boundaryMesh();
106 const polyPatch&
patch =
pbm[patchI];
107 for (
const face&
f : patch)
109 for (
const label fpi :
f)
116 for (
const auto&
pp :
pbm)
125 for (
const label
pi : meshPts)
134 const auto& bndyPts =
pp.boundaryPoints();
136 for (
const label
pi : bndyPts)
138 ++vertHits[meshPts[
pi]];
149void Foam::VF::voxel::setCoarseTriangulation(
const fvMesh&
mesh)
151 Info<<
"\nCreating triangulated surface" <<
endl;
159 DynamicList<label> globalFaces(
mesh.nBoundaryFaces());
164 const label nVertMin =
mesh.nSolutionD() == 3 ? 2 : 0;
169 const auto&
pbm =
mesh.boundaryMesh();
171 for (
const label patchi : patchIDs_)
173 const polyPatch&
patch =
pbm[patchi];
176 for (
const face&
f : patch)
178 DynamicList<label> faceVerts;
179 for (
const label fpi :
f)
181 if (vertHits[fpi] > nVertMin)
183 faceVerts.push_back(fpi);
187 if (faceVerts.size() < 3)
194 const face reducedFace(faceVerts);
196 reducedFace.triangles(
points, nTri, triFaces);
198 const label globalFacei =
201 for (
const face&
f : triFaces)
203 triangles.push_back(labelledTri(
f[0],
f[1],
f[2], patchi));
204 globalFaces.push_back(globalFacei);
209 triToGlobalFace_.transfer(globalFaces);
211 Info<<
" Total number of triangles: "
213 <<
"\n Number of invalid (removed) triangles: "
219 surface_.compactPoints();
223void Foam::VF::voxel::broadcast()
226 const globalIndex globalFaceIdx(globalIndex::gatherOnly{}, surface_.size());
227 const globalIndex globalPointIdx
229 globalIndex::gatherOnly{},
230 surface_.points().size()
233 List<labelledTri> globalSurfaceTris(globalFaceIdx.gather(surface_));
234 pointField globalSurfacePoints(globalPointIdx.gather(surface_.points()));
235 List<label> globalTriToGlobalFace(globalFaceIdx.gather(triToGlobalFace_));
238 for (
const label proci : globalPointIdx.allProcs())
240 const label offset = globalPointIdx.localStart(proci);
247 : globalSurfaceTris.slice(globalFaceIdx.range(proci))
260 std::move(globalSurfaceTris),
261 std::move(globalSurfacePoints)
266 triToGlobalFace_ = std::move(globalTriToGlobalFace);
282 const auto& ind = surface_[trii];
283 const auto&
pts = surface_.points();
289 static scalar tolerance = 1
e-6;
294 globalPosition(origin),
302void Foam::VF::voxel::writeBox
309 os.write(treeBoundBox(bb), lines);
313void Foam::VF::voxel::writeVoxels(
const word& fName)
const
318 Info<<
"Writing voxels to " <<
os.name() <<
endl;
321 const bool lines =
true;
322 for (label i = 0; i < nijk_[0]; ++i)
324 for (label j = 0; j < nijk_[1]; ++j)
326 for (label
k = 0;
k < nijk_[2]; ++
k)
328 bb.min() = voxelMin(i, j,
k);
329 bb.max() = voxelMax(i, j,
k);
330 writeBox(
os, lines, bb);
339void Foam::VF::voxel::writeTriBoundBoxes(
const word& fName)
const
344 Info<<
"Writing triangle boundBoxes to " <<
os.name() <<
endl;
346 const bool lines =
true;
347 for (
const auto& voxeli : objects_)
349 for (
const label trii : voxeli)
351 writeBox(
os, lines, objectBbs_[trii]);
359void Foam::VF::voxel::writeHitObjects
372 voxelBb.min() = voxelMin(ijk[0], ijk[1], ijk[2]);
373 voxelBb.max() = voxelMax(ijk[0], ijk[1], ijk[2]);
375 writeBox(
os,
true, voxelBb);
377 for (
const auto& trii : objects_[voxeli])
379 writeBox(
os,
true, objectBbs_[trii]);
381 const auto& ind = surface_[trii];
382 const auto&
pts = surface_.points();
384 os.write(tri,
false);
395 const scalar minDistance
410 writeHitObjects(voxeli, origin, dir);
417 for (
const auto& trii : objects_[voxeli])
422 pointHit pi = rayTriIntersect(trii, origin, dir);
428 pi.distance() > minDistance
429 &&
pi.distance() < closestHit.distance()
452 nRayPerFace_(
dict.
get<label>(
"nRayPerFace")),
453 nTriPerVoxelMax_(
dict.getOrDefault<label>(
"nTriPerVoxelMax", 50)),
454 depthMax_(
dict.getOrDefault<label>(
"depthMax", 5)),
460 setCoarseTriangulation(*agglomMeshPtr_);
464 setTriangulation(
mesh);
469 objectBbs_.resize_nocopy(surface_.size());
471 bb0_.add(surface_.points());
473 span0_ = bb0_.span();
476 scalar maxDx = span0_.x();
477 scalar maxDy = span0_.y();
478 scalar maxDz = span0_.z();
480 const label refDn = 8;
481 scalar maxDim =
max(maxDx,
max(maxDy, maxDz));
490 objects_.resize_nocopy(nVoxel());
495 voxelise(objects_, trii, depth);
497 Info<<
"\nCreated voxel mesh: " << nijk_ <<
endl;
499 if ((debug > 3) && UPstream::master())
501 writeVoxels(
"voxels.obj");
502 writeTriBoundBoxes(
"triBoundBoxes.obj");
509void Foam::VF::voxel::refineObjects
511 List<DynamicList<label>>& objects,
517 if (debug > 2)
Pout<<
"Refining voxels: n=" << nijk_ <<
endl;
519 List<DynamicList<label>> objectsNew(objects.size()*8);
521 for (label trii = 0; trii <= triMax; ++trii)
523 addBbToVoxels(objectBbs_[trii], trii, objectsNew);
526 objects.transfer(objectsNew);
530Foam::label Foam::VF::voxel::addBbToVoxels
534 List<DynamicList<label>>& objects
539 const point minbb(localPosition(bb.min()));
540 const label i0 =
max(0, floor(minbb.x()/dxyz_[0]));
541 const label
j0 =
max(0, floor(minbb.y()/dxyz_[1]));
542 const label k0 =
max(0, floor(minbb.z()/dxyz_[2]));
544 const point maxbb(localPosition(bb.max()));
545 const label i1 =
min(nijk_[0], ceil(maxbb.x()/dxyz_[0]));
546 const label
j1 =
min(nijk_[1], ceil(maxbb.y()/dxyz_[1]));
547 const label k1 =
min(nijk_[2], ceil(maxbb.z()/dxyz_[2]));
551 for (label ii = i0; ii < i1; ++ii)
553 for (label jj =
j0; jj <
j1; ++jj)
555 for (label kk = k0; kk < k1; ++kk)
557 const label voxeli = this->voxeli(ii, jj, kk);
559 objects[voxeli].push_back(trii);
560 nTriMax =
max(nTriMax, objects[voxeli].size());
569void Foam::VF::voxel::voxelise
571 List<DynamicList<label>>& objects,
578 Pout<<
"voxelise - start at tri=" << trii0
579 <<
" depth=" << depth
583 const auto&
points = surface_.points();
585 for (label trii = trii0; trii < surface_.size(); ++trii)
588 boundBox bb(
points, surface_[trii]);
590 objectBbs_[trii] = bb;
592 const label nVoxelMax = addBbToVoxels(bb, trii, objects);
595 if (nVoxelMax > nTriPerVoxelMax_ && depth < depthMax_)
597 refineObjects(objects, trii);
598 voxelise(objects, trii + 1, depth + 1);
611 if (tri0 > surface_.size()-1)
614 <<
"Index tri0 out of bounds: " << tri0
615 <<
". Surface size: " << surface_.size()
619 return hit(surface_.faceCentres()[tri0], direction0);
625 const point& origin0,
632 const point origin(localPosition(origin0));
637 <<
"Point located outside voxel mesh"
638 <<
" - possible coarsening problem?"
642 if (
magSqr(direction0) < ROOTVSMALL)
645 <<
"Supplied direction has zero size"
660 ijk[d] = floor(origin[d]/dxyz_[d]);
661 step[d] = sign0(dir[d]);
664 tDelta[d] =
mag(dxyz_[d]/dir[d]);
666 scalar voxelMax = (1 + ijk[d] -
neg(dir[d]))*dxyz_[d];
667 tMax[d] = (voxelMax - origin[d])/dir[d];
673 Info<<
"surfBb:" << boundBox(surface_.points())
675 <<
" origin" << origin0
676 <<
" voxel_origin:" << origin
680 <<
" tDelta:" << tDelta
685 auto traverse = [&](
const label i)
688 if (outOfBounds(ijk, i))
return false;
689 tMax[i] += tDelta[i];
696 const label voxeli = this->voxeli(ijk);
701 <<
" voxeli:" << voxeli
703 <<
" objs:" << objects_[voxeli].size()
707 hitInfo = hitObject(voxeli, origin, dir, tMax);
716 if (tMax[0] < tMax[1] && tMax[0] < tMax[2])
718 if (!traverse(0))
break;
720 else if (tMax[1] < tMax[2])
722 if (!traverse(1))
break;
726 if (!traverse(2))
break;
741 (void)mesh_.time().cpuTimeIncrement();
746 const label nTotalRays = myFc.
size()*nRayPerFace_;
750 <<
"Dynamic list needs more capacity to support " << nRayPerFace_
751 <<
" rays per face (" << nTotalRays <<
"). "
756 DynamicList<label> rayStartFace(nTotalRays);
757 DynamicList<label> rayEndFace(rayStartFace.size());
759 DynamicList<label> endFacei(nTotalRays);
760 DynamicList<label> startFacei(nTotalRays);
762 const pointField hemi(createHemiPoints(nRayPerFace_));
766 const scalar nDiv = 10;
767 const label nStep = floor(myFc.size()/nDiv);
770 for (label stepi=0; stepi<nDiv; ++stepi)
772 const label step0 = stepi*nStep;
773 const label step1 = stepi == nDiv - 1 ? myFc.size() : (stepi+1)*nStep;
775 for (label i = step0; i < step1; ++i)
781 localFaceHits.clear();
783 const point& origin = myFc[i];
786 const coordSystem::cartesian cs = createCoordSystem(origin, dir);
790 for (
const auto&
p :
pts)
796 label hitFacei = triToGlobalFace_[hitInfo.index()];
798 if (localFaceHits.insert(hitFacei))
800 endFacei.push_back(hitFacei);
801 startFacei.push_back(i);
811 const label globalStepi =
returnReduce(stepi, minOp<label>()) + 1;
813 Info<<
" " << globalStepi/nDiv*100 <<
"% complete" <<
endl;
828 globalNumbering_.toGlobal(startFacei)
831 forAll(globalStartFaceIDs, rayi)
833 label start = globalStartFaceIDs[rayi];
834 label
end = endFacei[rayi];
836 const label endProci = globalNumbering_.whichProcID(end);
838 if (start > end)
Swap(start, end);
840 if (uniqueRays.insert(edge(start, end)))
845 remoteStartFace[endProci].push_back(start);
846 remoteEndFace[endProci].push_back(end);
858 UOPstream str(domain, pBufs);
859 str << remoteStartFace[domain]
860 << remoteEndFace[domain];
864 pBufs.finishedSends();
871 UIPstream is(domain, pBufs);
872 is >> remoteStartFace[domain]
873 >> remoteEndFace[domain];
875 forAll(remoteStartFace[domain], i)
877 const label start = remoteStartFace[domain][i];
878 const label
end = remoteEndFace[domain][i];
879 uniqueRays.insert(edge(start, end));
885 for (
const edge&
e : uniqueRays)
887 const label start =
e.first();
888 const label
end =
e.second();
890 bool sameFace = start ==
end;
892 if (globalNumbering_.isLocal(start))
895 const label localStart = globalNumbering_.toLocal(start);
897 rayStartFace.append(localStart);
898 rayEndFace.append(end);
901 if (!sameFace && globalNumbering_.isLocal(end))
905 const label localEnd = globalNumbering_.toLocal(end);
907 rayStartFace.append(localEnd);
908 rayEndFace.append(start);
920 label start = startFacei[rayi];
921 label
end = endFacei[rayi];
923 if (start > end)
Swap(start, end);
925 if (uniqueRays.insert(edge(start, end)))
927 rayStartFace.append(start);
928 rayEndFace.append(end);
933 rayStartFace.append(end);
934 rayEndFace.append(start);
940 rayStartFaceOut.transfer(rayStartFace);
941 rayEndFaceOut.transfer(rayEndFace);
943 Info<<
" Time taken: " << mesh_.time().cpuTimeIncrement() <<
" s"
constexpr scalar pi(M_PI)
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
void size(const label n)
Older name for setAddressableSize.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
@ nonBlocking
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
@ broadcast
broadcast [MPI]
static bool & parRun() noexcept
Test if this a parallel run.
Base class for ray search engines.
globalIndex globalNumbering_
Global numbering.
const fvMesh & mesh() const noexcept
Reference to the mesh.
labelList patchIDs_
List of participating patch IDs.
Ray search engine based on discretising space into uniform voxels.
pointIndexHit hit(const point &origin, const vector &dir) const
voxel(const fvMesh &mesh, const dictionary &dict)
Constructor.
virtual void shootRays(labelList &rayStartFaceOut, labelList &rayEndFaceOut) const
Shoot rays; returns lists of ray start and end faces.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
OBJstream os(runTime.globalPath()/outputName)
#define WarningInFunction
Report a warning using Foam::Warning.
bool broadcast(Type *values, int count, MPI_Datatype datatype, const int communicator, const int root=0)
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
A namespace for various viewFactor model implementations.
const std::string patch
OpenFOAM patch number as a std::string.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
PointHit< point > pointHit
A PointHit with a 3D point.
HashSet< edge, Hash< edge > > edgeHashSet
A HashSet with edge for its key. Hashing (and ==) on an edge is symmetric.
List< label > labelList
A List of labels.
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Vector< label > labelVector
Vector of labels.
dimensionedScalar j1(const dimensionedScalar &ds)
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
void Swap(DynamicList< T, SizeMinA > &a, DynamicList< T, SizeMinB > &b)
Exchange contents of lists - see DynamicList::swap().
Ostream & endl(Ostream &os)
Add newline and flush stream.
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
errorManip< error > abort(error &err)
Field< vector > vectorField
Specialisation of Field<T> for vector.
vector point
Point is a vector.
dimensionedScalar neg(const dimensionedScalar &ds)
static constexpr const zero Zero
Global zero (0).
triangle< point, const point & > triPointRef
A triangle using referred points.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dimensionedScalar j0(const dimensionedScalar &ds)
std::vector< Triangle > triangles
const label maxDynListLength(viewFactorDict.getOrDefault< label >("maxDynListLength", 1000000))
#define forAll(list, i)
Loop across all elements in list.