File indexing completed on 2025-01-18 10:14:12
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef VECGEOM_VOLUMES_TESSELLATEDSTRUCT_H_
0010 #define VECGEOM_VOLUMES_TESSELLATEDSTRUCT_H_
0011
0012 #include "TessellatedCluster.h"
0013 #include "VecGeom/base/BitSet.h"
0014 #include "VecGeom/base/RNG.h"
0015 #include "VecGeom/base/Config.h"
0016 #include <vector>
0017
0018 #include "VecGeom/base/Stopwatch.h"
0019 #include "VecGeom/management/HybridManager2.h"
0020 #include "VecGeom/navigation/HybridNavigator2.h"
0021
0022 #ifdef VECGEOM_EMBREE
0023 #include "VecGeom/management/EmbreeManager.h"
0024 #include "VecGeom/navigation/EmbreeNavigator.h"
0025 #endif
0026
0027 #include "VecGeom/management/ABBoxManager.h"
0028
0029 namespace vecgeom {
0030
0031
0032
0033 inline namespace VECGEOM_IMPL_NAMESPACE {
0034
0035
0036
0037 #ifdef VECGEOM_EMBREE
0038 #define USEEMBREE 1
0039 #endif
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 template <size_t NVERT, typename T = double>
0053 class TessellatedStruct {
0054
0055 #ifndef VECGEOM_ENABLE_CUDA
0056 using Real_v = vecgeom::VectorBackend::Real_v;
0057 #else
0058 using Real_v = vecgeom::ScalarBackend::Real_v;
0059 #endif
0060 using Facet_t = Tile<NVERT, T>;
0061
0062
0063 template <typename U>
0064 using vector_t = vecgeom::Vector<U>;
0065
0066 using BVHStructure = HybridManager2::HybridBoxAccelerationStructure;
0067
0068 #ifdef USEEMBREE
0069 using BVHStructure2 = EmbreeManager::EmbreeAccelerationStructure;
0070 #else
0071 using BVHStructure2 = HybridManager2::HybridBoxAccelerationStructure;
0072 #endif
0073
0074
0075
0076
0077
0078
0079 struct GridCell {
0080 vector_t<int> fArray;
0081 bool fUsed = false;
0082
0083
0084 VECCORE_ATT_HOST_DEVICE
0085 GridCell()
0086 {
0087 }
0088 };
0089
0090
0091
0092
0093
0094
0095
0096
0097 struct GridHelper {
0098 int fNgrid = 0;
0099 int fNcells = 0;
0100 int fNcached = 0;
0101 GridCell **fGrid = nullptr;
0102 Vector3D<T> fMinExtent;
0103 Vector3D<T> fMaxExtent;
0104 Vector3D<T> fInvExtSize;
0105 vector_t<Vector3D<T>> fAllVert;
0106
0107
0108 GridHelper() {}
0109
0110
0111 ~GridHelper()
0112 {
0113 if (fGrid) {
0114 for (int i = 0; i < fNcells; ++i)
0115 delete fGrid[i];
0116 delete[] fGrid;
0117 }
0118 }
0119
0120
0121
0122 void CreateCells(int ngrid)
0123 {
0124 if (fNgrid) return;
0125 fNgrid = ngrid;
0126 fNcells = ngrid * ngrid * ngrid;
0127 fGrid = new GridCell *[fNcells];
0128 for (int i = 0; i < fNcells; ++i)
0129 fGrid[i] = new GridCell();
0130 }
0131
0132
0133 VECCORE_ATT_HOST_DEVICE
0134 VECGEOM_FORCE_INLINE
0135 void ClearCells()
0136 {
0137 for (int icell = 0; icell < fNcells; ++icell)
0138 fGrid[icell]->fArray.clear();
0139 }
0140
0141
0142
0143
0144
0145 VECCORE_ATT_HOST_DEVICE
0146 VECGEOM_FORCE_INLINE
0147 GridCell *GetCell(int ind[3]) { return fGrid[fNgrid * fNgrid * ind[0] + fNgrid * ind[1] + ind[2]]; }
0148
0149
0150
0151
0152
0153
0154 VECCORE_ATT_HOST_DEVICE
0155 VECGEOM_FORCE_INLINE
0156 GridCell *GetCell(Vector3D<T> const &point, int ind[3])
0157 {
0158 Vector3D<T> ratios = (point - fMinExtent) * fInvExtSize;
0159 for (int i = 0; i < 3; ++i) {
0160 ind[i] = ratios[i] * fNgrid;
0161 ind[i] = vecCore::math::Max(ind[i], 0);
0162 ind[i] = vecCore::math::Min(ind[i], fNgrid - 1);
0163 }
0164 return (GetCell(ind));
0165 }
0166 };
0167
0168 public:
0169 bool fSolidClosed = false;
0170 T fCubicVolume = 0;
0171 T fSurfaceArea = 0;
0172 GridHelper *fHelper = nullptr;
0173 Vector3D<T> fMinExtent;
0174 Vector3D<T> fMaxExtent;
0175 Vector3D<T> fInvExtSize;
0176 Vector3D<T> fTestDir;
0177 BVHStructure *fNavHelper = nullptr;
0178 BVHStructure2 *fNavHelper2 = nullptr;
0179
0180
0181
0182
0183 vector_t<int> fCluster;
0184 vector_t<int> fCandidates;
0185 vector_t<Vector3D<T>> fVertices;
0186 vector_t<Facet_t *> fFacets;
0187 vector_t<TessellatedCluster<NVERT, Real_v> *> fClusters;
0188 BitSet *fSelected = nullptr;
0189 int fNcldist[kVecSize + 1] = {0};
0190
0191 private:
0192
0193 void CreateABBoxes()
0194 {
0195 using Boxes_t = ABBoxManager::ABBoxContainer_t;
0196 using BoxCorner_t = ABBoxManager::ABBox_s;
0197 int nclusters = fClusters.size();
0198 BoxCorner_t *boxcorners = new BoxCorner_t[2 * nclusters];
0199 for (int i = 0; i < nclusters; ++i) {
0200 boxcorners[2 * i] = fClusters[i]->fMinExtent;
0201 boxcorners[2 * i + 1] = fClusters[i]->fMaxExtent;
0202 }
0203 Boxes_t boxes = &boxcorners[0];
0204 fNavHelper = HybridManager2::Instance().BuildStructure(boxes, nclusters);
0205 #ifdef USEEMBREE
0206 fNavHelper2 = EmbreeManager::Instance().BuildStructureFromBoundingBoxes(boxes, nclusters);
0207 #else
0208 fNavHelper2 = fNavHelper;
0209 #endif
0210 }
0211
0212 public:
0213
0214 VECCORE_ATT_HOST_DEVICE
0215 VECGEOM_FORCE_INLINE
0216 TessellatedStruct()
0217 {
0218 fMinExtent = InfinityLength<T>();
0219 fMaxExtent = -InfinityLength<T>();
0220 fHelper = new GridHelper();
0221 }
0222
0223
0224 VECCORE_ATT_HOST_DEVICE
0225 VECGEOM_FORCE_INLINE
0226 ~TessellatedStruct()
0227 {
0228 delete fHelper;
0229 if (fSelected) BitSet::ReleaseInstance(fSelected);
0230 }
0231
0232
0233
0234
0235
0236
0237 VECCORE_ATT_HOST_DEVICE
0238 VECGEOM_FORCE_INLINE
0239 void AddFacet(Facet_t *facet)
0240 {
0241 using vecCore::math::Max;
0242 using vecCore::math::Min;
0243
0244 fFacets.push_back(facet);
0245 int ind = fHelper->fAllVert.size();
0246
0247 for (size_t i = 0; i < NVERT; ++i) {
0248 fHelper->fAllVert.push_back(facet->fVertices[i]);
0249 facet->fIndices[i] = ind + i;
0250 fMinExtent[0] = Min(fMinExtent[0], facet->fVertices[i].x());
0251 fMinExtent[1] = Min(fMinExtent[1], facet->fVertices[i].y());
0252 fMinExtent[2] = Min(fMinExtent[2], facet->fVertices[i].z());
0253 fMaxExtent[0] = Max(fMaxExtent[0], facet->fVertices[i].x());
0254 fMaxExtent[1] = Max(fMaxExtent[1], facet->fVertices[i].y());
0255 fMaxExtent[2] = Max(fMaxExtent[2], facet->fVertices[i].z());
0256 }
0257 }
0258
0259
0260
0261
0262
0263
0264
0265 VECCORE_ATT_HOST_DEVICE
0266 VECGEOM_FORCE_INLINE
0267 int AddVertex(Vector3D<T> const &vertex)
0268 {
0269
0270 int ind[3];
0271 GridCell *cell = fHelper->GetCell(vertex, ind);
0272
0273 constexpr Precision tolerancesq = kTolerance * kTolerance;
0274 for (int ivert : cell->fArray) {
0275
0276 if ((fVertices[ivert] - vertex).Mag2() < tolerancesq) return ivert;
0277 }
0278
0279 int ivertnew = fVertices.size();
0280 fVertices.push_back(vertex);
0281
0282 cell->fArray.push_back(ivertnew);
0283 return ivertnew;
0284 }
0285
0286
0287
0288
0289
0290 VECCORE_ATT_HOST_DEVICE
0291 VECGEOM_FORCE_INLINE
0292 void Extent(Vector3D<T> &amin, Vector3D<T> &amax) const
0293 {
0294 amin = fMinExtent;
0295 amax = fMaxExtent;
0296 }
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 void Close()
0307 {
0308 int ind[3];
0309 fInvExtSize = fMaxExtent - fMinExtent;
0310 if (fInvExtSize[0] * fInvExtSize[1] * fInvExtSize[2] < kTolerance) {
0311 std::cout << "Tessellated structure is flat - not allowed\n";
0312 return;
0313 }
0314 fInvExtSize = 1. / fInvExtSize;
0315 fHelper->fMinExtent = fMinExtent;
0316 fHelper->fMaxExtent = fMaxExtent;
0317 fHelper->fInvExtSize = fInvExtSize;
0318
0319 int ngrid = 1 + size_t(vecCore::math::Pow<T>(T(fFacets.size()), 1. / 3.));
0320
0321
0322 fHelper->CreateCells(ngrid);
0323
0324
0325
0326
0327
0328
0329 for (auto facet : fFacets) {
0330 for (int ivert = 0; ivert < 3; ++ivert) {
0331 facet->fIndices[ivert] = AddVertex(facet->fVertices[ivert]);
0332 }
0333 }
0334
0335
0336
0337
0338
0339 fHelper->ClearCells();
0340 unsigned ifacet = 0;
0341 for (auto facet : fFacets) {
0342 fHelper->GetCell(facet->fCenter, ind)->fArray.push_back(ifacet);
0343
0344
0345
0346 ifacet++;
0347 }
0348
0349
0350
0351
0352
0353
0354
0355
0356 const int nfacets = fFacets.size();
0357 fSelected = BitSet::MakeInstance(nfacets);
0358 fSelected->ResetAllBits();
0359 fCandidates.clear();
0360 ifacet = 0;
0361 fCandidates.push_back(ifacet);
0362 fSelected->SetBitNumber(ifacet);
0363 TessellatedCluster<NVERT, Real_v> *cluster;
0364 while (fCandidates.size()) {
0365
0366 cluster = CreateCluster();
0367 if (!cluster) cluster = MakePartialCluster();
0368 fClusters.push_back(cluster);
0369
0370 if (!fCandidates.size()) {
0371 ifacet = fSelected->FirstNullBit();
0372 if (ifacet == fFacets.size()) break;
0373 fCandidates.push_back(ifacet);
0374 fSelected->SetBitNumber(ifacet);
0375 }
0376 }
0377
0378
0379
0380
0381
0382
0383 CreateABBoxes();
0384
0385
0386
0387 constexpr T tolerance(1.e-8);
0388 while (1) {
0389 RandomDirection(fTestDir);
0390
0391 for (auto facet : fFacets) {
0392 if (vecCore::math::Abs(facet->fNormal.Dot(fTestDir)) < tolerance) break;
0393 }
0394 break;
0395 }
0396 fSolidClosed = true;
0397 }
0398
0399
0400
0401 void RandomDirection(Vector3D<Precision> &direction)
0402 {
0403 Precision phi = RNG::Instance().uniform(0., 2. * kPi);
0404 Precision theta = std::acos(1. - 2. * RNG::Instance().uniform(0, 1));
0405 direction.x() = std::sin(theta) * std::cos(phi);
0406 direction.y() = std::sin(theta) * std::sin(phi);
0407 direction.z() = std::cos(theta);
0408 }
0409
0410
0411 void CreateDummyClusters()
0412 {
0413 TessellatedCluster<NVERT, Real_v> *tcl = nullptr;
0414 int i = 0;
0415 int j = 0;
0416 for (auto facet : fFacets) {
0417 i = i % kVecSize;
0418 if (i == 0) {
0419 if (tcl) fClusters.push_back(tcl);
0420 tcl = new TessellatedCluster<NVERT, Real_v>();
0421 }
0422 tcl->AddFacet(i++, facet, j++);
0423 }
0424
0425 for (; i < kVecSize; ++i)
0426 tcl->AddFacet(i, tcl->fFacets[0], tcl->fIfacets[0]);
0427 }
0428
0429
0430
0431 TessellatedCluster<NVERT, Real_v> *CreateCluster()
0432 {
0433
0434 unsigned nfacets = 0;
0435 assert(fCandidates.size() > 0);
0436 constexpr int rankmax = 3;
0437 int rank = 0;
0438 fCluster.clear();
0439 int ifacet = fCandidates[0];
0440 fCluster.push_back(ifacet);
0441 while (fCandidates.size() < kVecSize && rank < rankmax) {
0442 GatherNeighborCandidates(fCandidates[0], rank++);
0443 }
0444 if (fCandidates.size() < kVecSize) return nullptr;
0445 fCandidates.erase(fCandidates.begin());
0446
0447 int iref = 0;
0448 while (nfacets < kVecSize) {
0449 nfacets = AddCandidatesToCluster(4 >> iref++);
0450 }
0451
0452
0453 TessellatedCluster<NVERT, Real_v> *tcl = new TessellatedCluster<NVERT, Real_v>();
0454 int i = 0;
0455 for (auto ifct : fCluster) {
0456 Facet_t *facet = fFacets[ifct];
0457 tcl->AddFacet(i++, facet, ifct);
0458 }
0459 fNcldist[fCluster.size()]++;
0460 return tcl;
0461 }
0462
0463
0464
0465 TessellatedCluster<NVERT, Real_v> *MakePartialCluster()
0466 {
0467 for (auto ifacet : fCandidates) {
0468 fCluster.push_back(ifacet);
0469 }
0470 fNcldist[fCluster.size()]++;
0471 fCandidates.clear();
0472 while (fCluster.size() < kVecSize)
0473 fCluster.push_back(fCluster[0]);
0474
0475
0476 TessellatedCluster<NVERT, Real_v> *tcl = new TessellatedCluster<NVERT, Real_v>();
0477 int i = 0;
0478 for (auto ifacet : fCluster) {
0479 Facet_t *facet = fFacets[ifacet];
0480 tcl->AddFacet(i++, facet, ifacet);
0481 }
0482 return tcl;
0483 }
0484
0485
0486
0487
0488
0489
0490
0491 int AddCandidatesToCluster(int weightmin)
0492 {
0493
0494
0495 for (auto it = fCandidates.begin(); it != fCandidates.end() && fCluster.size() < kVecSize;) {
0496 int weight = NeighborToCluster(*it);
0497 if (weight >= weightmin) {
0498 fCluster.push_back(*it);
0499 it = fCandidates.erase(it);
0500 } else {
0501 ++it;
0502 }
0503 }
0504 return fCluster.size();
0505 }
0506
0507
0508
0509
0510
0511 int NeighborToCluster(int ifacet)
0512 {
0513 Facet_t *facet = fFacets[ifacet];
0514 int weight = 0;
0515 for (auto icand : fCluster) {
0516 Facet_t *other = fFacets[icand];
0517 weight += facet->IsNeighbor(*other);
0518 }
0519 return weight;
0520 }
0521
0522
0523
0524 VECCORE_ATT_HOST_DEVICE
0525 VECGEOM_FORCE_INLINE
0526 void AddCandidatesFromCell(int ind[3])
0527 {
0528 GridCell *cell = fHelper->GetCell(ind);
0529 if (cell->fUsed) return;
0530 for (auto neighbor : cell->fArray) {
0531 if (!fSelected->TestBitNumber(neighbor)) {
0532 fSelected->SetBitNumber(neighbor);
0533 fCandidates.push_back(neighbor);
0534 }
0535 }
0536 cell->fUsed = true;
0537 }
0538
0539
0540
0541
0542
0543
0544
0545 int GatherNeighborCandidates(int ifacet, int rank)
0546 {
0547 int ind0[3], ind[3];
0548 const Facet_t *facet = fFacets[ifacet];
0549 fHelper->GetCell(facet->fCenter, ind0);
0550 if (rank == 0) {
0551 AddCandidatesFromCell(ind0);
0552 return (fCandidates.size());
0553 }
0554
0555
0556 int limits[6];
0557 bool limited[6] = {false};
0558 for (int i = 0; i < 3; ++i) {
0559 limits[2 * i] = ind0[i] - rank;
0560 if (limits[2 * i] < 0) {
0561 limits[2 * i] = 0;
0562 limited[2 * i] = true;
0563 }
0564 limits[2 * i + 1] = ind0[i] + rank;
0565 if (limits[2 * i + 1] > fHelper->fNgrid - 1) {
0566 limits[2 * i + 1] = fHelper->fNgrid - 1;
0567 limited[2 * i + 1] = true;
0568 }
0569 }
0570
0571 for (int iax1 = 0; iax1 < 3; ++iax1) {
0572 int iax2 = (iax1 + 1) % 3;
0573 int iax3 = (iax1 + 2) % 3;
0574 for (int iside = 0; iside < 2; ++iside) {
0575 if (limited[2 * iax1 + iside]) continue;
0576 ind[iax1] = limits[2 * iax1 + iside];
0577 for (ind[iax2] = limits[2 * iax2]; ind[iax2] <= limits[2 * iax2 + 1]; ind[iax2]++) {
0578 for (ind[iax3] = limits[2 * iax3]; ind[iax3] <= limits[2 * iax3 + 1]; ind[iax3]++) {
0579 AddCandidatesFromCell(ind);
0580 }
0581 }
0582 }
0583 }
0584 return (fCandidates.size());
0585 }
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595 VECCORE_ATT_HOST_DEVICE
0596 bool AddTriangularFacet(Vector3D<T> const &vt0, Vector3D<T> const &vt1, Vector3D<T> const &vt2, bool absolute = true)
0597 {
0598 assert(NVERT == 3);
0599 Facet_t *facet = new Facet_t;
0600 bool added = false;
0601 if (absolute)
0602 added = facet->SetVertices(vt0, vt1, vt2);
0603 else
0604 added = facet->SetVertices(vt0, vt0 + vt1, vt0 + vt1 + vt2);
0605 if (!added) {
0606 delete facet;
0607 return false;
0608 }
0609 AddFacet(facet);
0610 return true;
0611 }
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623 VECCORE_ATT_HOST_DEVICE
0624 bool AddQuadrilateralFacet(Vector3D<T> const &vt0, Vector3D<T> const &vt1, Vector3D<T> const &vt2,
0625 Vector3D<T> const &vt3, bool absolute = true)
0626 {
0627
0628
0629
0630 assert(NVERT <= 4);
0631 Facet_t *facet = new Facet_t;
0632 if (NVERT == 3) {
0633 if (absolute) {
0634 if (!facet->SetVertices(vt0, vt1, vt2)) {
0635 delete facet;
0636 return false;
0637 }
0638 } else {
0639 if (!facet->SetVertices(vt0, vt0 + vt1, vt0 + vt1 + vt2)) {
0640 delete facet;
0641 return false;
0642 }
0643 }
0644 AddFacet(facet);
0645 facet = new Facet_t;
0646 if (absolute) {
0647 if (!facet->SetVertices(vt0, vt2, vt3)) {
0648 delete facet;
0649 return false;
0650 }
0651 } else {
0652 if (!facet->SetVertices(vt0, vt0 + vt2, vt0 + vt2 + vt3)) {
0653 delete facet;
0654 return false;
0655 }
0656 }
0657 AddFacet(facet);
0658 return true;
0659 } else if (NVERT == 4) {
0660
0661 if (absolute) {
0662 if (!facet->SetVertices(vt0, vt1, vt2, vt3)) {
0663 delete facet;
0664 return false;
0665 }
0666 } else {
0667 if (!facet->SetVertices(vt0, vt0 + vt1, vt0 + vt1 + vt2, vt0 + vt1 + vt2 + vt3)) {
0668 delete facet;
0669 return false;
0670 }
0671 }
0672 AddFacet(facet);
0673 return true;
0674 }
0675 return false;
0676 }
0677
0678 };
0679 }
0680 }
0681
0682 #endif