45 void Foam::VF::voxel::setTriangulation(
const fvMesh&
mesh)
47 Info<<
"\nCreating triangulated surface" <<
endl;
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: " 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)
122 if (isA<processorPolyPatch>(
pp))
125 for (
const label
pi : meshPts)
134 const auto& bndyPts =
pp.boundaryPoints();
136 for (
const label
pi : bndyPts)
138 ++vertHits[meshPts[
pi]];
149 void 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();
223 void 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),
302 void Foam::VF::voxel::writeBox
309 os.write(treeBoundBox(bb), lines);
313 void 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);
339 void 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]);
359 void 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)),
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;
501 writeVoxels(
"voxels.obj");
502 writeTriBoundBoxes(
"triBoundBoxes.obj");
509 void 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);
530 Foam::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());
569 void 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);
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];
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" List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const polyBoundaryMesh & pbm
void size(const label n)
Older name for setAddressableSize.
const label maxDynListLength(viewFactorDict.getOrDefault< label >("maxDynListLength", 1000000))
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
void compactPoints(labelList &pointMap=const_cast< labelList &>(labelList::null()))
Remove unused points and renumber faces in local visit order.
globalIndex globalNumbering_
Global numbering.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Ostream & endl(Ostream &os)
Add newline and flush stream.
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
static bool & parRun() noexcept
Test if this a parallel run.
HashSet< edge, Hash< edge > > edgeHashSet
A HashSet with edge for its key. Hashing (and ==) on an edge is symmetric.
std::vector< Triangle > triangles
This class describes the interaction of an object (often a face) and a point. It carries the info of ...
label k
Boltzmann constant.
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
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.
const fvMesh & mesh() const noexcept
Reference to the mesh.
dimensionedScalar neg(const dimensionedScalar &ds)
Macros for easy insertion into run-time selection tables.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
dimensionedScalar j1(const dimensionedScalar &ds)
virtual const pointField & points() const
Return raw points.
#define forAll(list, i)
Loop across all elements in list.
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
List< face > faceList
List of faces.
label size() const noexcept
The number of elements in table.
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
vectorField pointField
pointField is a vectorField.
const dimensionedScalar e
Elementary charge.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
voxel(const fvMesh &mesh, const dictionary &dict)
Constructor.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
virtual void shootRays(labelList &rayStartFaceOut, labelList &rayEndFaceOut) const
Shoot rays; returns lists of ray start and end faces.
constexpr scalar pi(M_PI)
Describes the interaction of a object and a (templated) point. It carries the info of a successful hi...
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
errorManip< error > abort(error &err)
int debug
Static debugging option.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
pointIndexHit hit(const point &origin, const vector &dir) const
vector point
Point is a vector.
label toGlobal(const label proci, const label i) const
From local to global on proci.
#define WarningInFunction
Report a warning using Foam::Warning.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
void Swap(DynamicList< T, SizeMinA > &a, DynamicList< T, SizeMinB > &b)
Exchange contents of lists - see DynamicList::swap().
const std::string patch
OpenFOAM patch number as a std::string.
triangle< point, const point & > triPointRef
A triangle using referred points.
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Field< vector > vectorField
Specialisation of Field<T> for vector.
Vector< label > labelVector
Vector of labels.
autoPtr< singleCellFvMesh > agglomMeshPtr_
Agglomerated mesh representation.
List< label > labelList
A List of labels.
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
dimensionedScalar j0(const dimensionedScalar &ds)
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
labelList patchIDs_
List of participating patch IDs.
PointHit< point > pointHit
A PointHit with a 3D point.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)