File indexing completed on 2025-03-13 09:29:31
0001
0002
0003
0004
0005
0006
0007 #ifndef VECGEOM_VOLUMES_TESSELLATEDCLUSTER_H_
0008 #define VECGEOM_VOLUMES_TESSELLATEDCLUSTER_H_
0009
0010 #include <VecCore/VecCore>
0011
0012 #include "VecGeom/base/AlignedBase.h"
0013 #include "VecGeom/base/Global.h"
0014 #include "VecGeom/base/Vector3D.h"
0015 #include "VecGeom/base/Vector.h"
0016 #include "VecGeom/volumes/kernel/GenericKernels.h"
0017 #include "Tile.h"
0018
0019 namespace vecgeom {
0020
0021 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_1v_1t(class, TessellatedCluster, size_t, typename);
0022
0023 inline namespace VECGEOM_IMPL_NAMESPACE {
0024
0025 constexpr size_t kVecSize = vecCore::VectorSize<vecgeom::VectorBackend::Real_v>();
0026
0027
0028
0029
0030
0031
0032 template <size_t NVERT, typename Real_v>
0033 class TessellatedCluster : public AlignedBase {
0034 public:
0035
0036 using T = typename vecCore::ScalarType<Real_v>::Type;
0037
0038 using Facet_t = Tile<NVERT, T>;
0039
0040 Vector3D<Real_v> fNormals;
0041 Real_v fDistances;
0042 Vector3D<Real_v> fSideVectors[NVERT];
0043 Vector3D<Real_v> fVertices[NVERT];
0044 size_t fIfacets[kVecSize] = {};
0045 Facet_t *fFacets[kVecSize] = {};
0046 Vector3D<T> fMinExtent;
0047 Vector3D<T> fMaxExtent;
0048 bool fConvex = false;
0049
0050
0051 VECCORE_ATT_HOST_DEVICE
0052 TessellatedCluster()
0053 {
0054 fMinExtent.Set(InfinityLength<T>());
0055 fMaxExtent.Set(-InfinityLength<T>());
0056 }
0057
0058
0059 VECGEOM_FORCE_INLINE
0060 VECCORE_ATT_HOST_DEVICE
0061 bool IsConvex() const { return fConvex; }
0062
0063
0064 VECGEOM_FORCE_INLINE
0065 VECCORE_ATT_HOST_DEVICE
0066 bool CalculateConvexity()
0067 {
0068 bool convex = true;
0069 for (size_t i = 0; i < kVecSize; ++i)
0070 convex &= fFacets[i]->fConvex;
0071 return convex;
0072 }
0073
0074
0075
0076
0077
0078 VECGEOM_FORCE_INLINE
0079 VECCORE_ATT_HOST_DEVICE
0080 void GetVertex(size_t ifacet, size_t ivert, Vector3D<T> &vertex) const
0081 {
0082 vertex[0] = vecCore::Get(fVertices[ivert].x(), ifacet);
0083 vertex[1] = vecCore::Get(fVertices[ivert].y(), ifacet);
0084 vertex[2] = vecCore::Get(fVertices[ivert].z(), ifacet);
0085 }
0086
0087
0088
0089
0090 VECGEOM_FORCE_INLINE
0091 VECCORE_ATT_HOST_DEVICE
0092 Facet_t *GetFacet(size_t ifacet) const { return fFacets[ifacet]; }
0093
0094
0095
0096
0097
0098
0099 VECGEOM_FORCE_INLINE
0100 VECCORE_ATT_HOST_DEVICE
0101 T ComputeSparsity(int &nblobs, int &nfacets)
0102 {
0103
0104 Vector3D<T> clcenter;
0105 for (unsigned ifacet = 0; ifacet < kVecSize; ++ifacet) {
0106 clcenter += fFacets[ifacet]->fCenter;
0107 }
0108 clcenter /= kVecSize;
0109
0110
0111 T maxsize = 0, lensq = 0, dmax = 0;
0112 for (unsigned ifacet = 0; ifacet < kVecSize; ++ifacet) {
0113 T facetsizesq = 0;
0114 for (int i = 0; i < 3; ++i) {
0115 lensq = (fFacets[ifacet]->fVertices[i] - fFacets[ifacet]->fVertices[(i + 1) % 3]).Mag2();
0116 if (lensq > facetsizesq) facetsizesq = lensq;
0117 }
0118 if (facetsizesq > maxsize) maxsize = facetsizesq;
0119 lensq = (fFacets[ifacet]->fCenter - clcenter).Mag2();
0120 if (lensq > dmax) dmax = lensq;
0121 }
0122 T dispersion = vecCore::math::Sqrt(dmax / maxsize);
0123
0124
0125 nfacets = 0;
0126 for (unsigned ifacet = 0; ifacet < kVecSize; ++ifacet) {
0127 bool duplicate = false;
0128 for (unsigned jfacet = ifacet + 1; jfacet < kVecSize; ++jfacet) {
0129 if (fFacets[jfacet] == fFacets[ifacet]) {
0130 duplicate = true;
0131 break;
0132 }
0133 }
0134 if (!duplicate) nfacets++;
0135 }
0136
0137
0138 nblobs = 0;
0139 int cluster[kVecSize];
0140 int ncl = 0;
0141 bool used[kVecSize] = {false};
0142 for (unsigned ifacet = 0; ifacet < kVecSize; ++ifacet) {
0143 ncl = 0;
0144 if (used[ifacet]) break;
0145 cluster[ncl++] = ifacet;
0146 used[ifacet] = true;
0147 nblobs++;
0148
0149 for (unsigned jfacet = ifacet + 1; jfacet < kVecSize; ++jfacet) {
0150 if (used[jfacet]) break;
0151
0152 int nneighbors = 0;
0153 for (int incl = 0; incl < ncl; ++incl) {
0154 nneighbors += fFacets[jfacet]->IsNeighbor(*fFacets[cluster[incl]]);
0155 }
0156 if (nneighbors > ncl) {
0157 cluster[ncl++] = jfacet;
0158 used[jfacet] = true;
0159 }
0160 }
0161 }
0162 return dispersion;
0163 }
0164
0165
0166
0167
0168
0169 VECCORE_ATT_HOST_DEVICE
0170 void AddFacet(size_t index, Facet_t *facet, size_t ifacet)
0171 {
0172
0173 assert(index < kVecSize);
0174 vecCore::Set(fNormals.x(), index, facet->fNormal.x());
0175 vecCore::Set(fNormals.y(), index, facet->fNormal.y());
0176 vecCore::Set(fNormals.z(), index, facet->fNormal.z());
0177
0178 vecCore::Set(fDistances, index, facet->fDistance);
0179
0180 for (size_t ivert = 0; ivert < NVERT; ++ivert) {
0181 Vector3D<T> c0 = facet->fVertices[ivert];
0182 if (c0.x() < fMinExtent[0]) fMinExtent[0] = c0.x();
0183 if (c0.y() < fMinExtent[1]) fMinExtent[1] = c0.y();
0184 if (c0.z() < fMinExtent[2]) fMinExtent[2] = c0.z();
0185 if (c0.x() > fMaxExtent[0]) fMaxExtent[0] = c0.x();
0186 if (c0.y() > fMaxExtent[1]) fMaxExtent[1] = c0.y();
0187 if (c0.z() > fMaxExtent[2]) fMaxExtent[2] = c0.z();
0188 Vector3D<T> c1 = facet->fVertices[(ivert + 1) % NVERT];
0189 Vector3D<T> sideVector = facet->fNormal.Cross(c1 - c0).Normalized();
0190 vecCore::Set(fSideVectors[ivert].x(), index, sideVector.x());
0191 vecCore::Set(fSideVectors[ivert].y(), index, sideVector.y());
0192 vecCore::Set(fSideVectors[ivert].z(), index, sideVector.z());
0193 vecCore::Set(fVertices[ivert].x(), index, c0.x());
0194 vecCore::Set(fVertices[ivert].y(), index, c0.y());
0195 vecCore::Set(fVertices[ivert].z(), index, c0.z());
0196 }
0197 fFacets[index] = facet;
0198 fIfacets[index] = ifacet;
0199 if (index == kVecSize - 1) CalculateConvexity();
0200 }
0201
0202
0203
0204
0205
0206 VECGEOM_FORCE_INLINE
0207 VECCORE_ATT_HOST_DEVICE
0208 bool Contains(Vector3D<T> point)
0209 {
0210 using Bool_v = vecCore::Mask<Real_v>;
0211
0212 Bool_v inside;
0213
0214 InsideCluster(point, inside);
0215 return (!vecCore::MaskEmpty(inside));
0216 }
0217
0218
0219
0220 VECGEOM_FORCE_INLINE
0221 VECCORE_ATT_HOST_DEVICE
0222 void InsideCluster(Vector3D<Real_v> const &point, typename vecCore::Mask<Real_v> &inside) const
0223 {
0224 using Bool_v = vecCore::Mask<Real_v>;
0225
0226 inside = Bool_v(true);
0227 for (size_t i = 0; i < NVERT; ++i) {
0228 Real_v saf = (point - fVertices[i]).Dot(fSideVectors[i]);
0229 inside &= saf > Real_v(-kTolerance);
0230 }
0231 }
0232
0233
0234
0235 VECGEOM_FORCE_INLINE
0236 VECCORE_ATT_HOST_DEVICE
0237 Real_v DistPlanes(Vector3D<Real_v> const &point) const { return (point.Dot(fNormals) + fDistances); }
0238
0239
0240
0241
0242
0243
0244
0245
0246 VECCORE_ATT_HOST_DEVICE
0247 void DistanceToCluster(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T &distanceToIn,
0248 T &distanceToOut, int &isurfToIn, int &isurfToOut) const
0249 {
0250 using Bool_v = vecCore::Mask<Real_v>;
0251
0252 distanceToIn = InfinityLength<T>();
0253 distanceToOut = InfinityLength<T>();
0254
0255
0256 isurfToIn = -1;
0257 isurfToOut = -1;
0258
0259
0260
0261 Real_v ndd = NonZero(direction.Dot(fNormals));
0262 Real_v saf = DistPlanes(point);
0263
0264 Bool_v validToIn = ndd < Real_v(0.) && saf > Real_v(-kTolerance);
0265 Bool_v validToOut = ndd > Real_v(0.) && saf < Real_v(kTolerance);
0266
0267 Real_v dist = -saf / ndd;
0268 Vector3D<Real_v> pointv = point + dist * direction;
0269
0270 Bool_v hit;
0271 InsideCluster(pointv, hit);
0272
0273 validToIn &= hit;
0274 validToOut &= hit;
0275
0276
0277 if (vecCore::EarlyReturnAllowed() && vecCore::MaskEmpty(validToIn || validToOut)) return;
0278
0279
0280
0281
0282 for (size_t i = 0; i < kVecSize; ++i) {
0283 if (vecCore::Get(validToIn, i)) {
0284 T dlane = vecCore::Get(dist, i);
0285 if (dlane < distanceToIn) {
0286 distanceToIn = dlane;
0287 isurfToIn = fIfacets[i];
0288 }
0289 } else {
0290 if (vecCore::Get(validToOut, i)) {
0291 T dlane = vecCore::Get(dist, i);
0292 if (dlane < distanceToOut) {
0293 distanceToOut = dlane;
0294 isurfToOut = fIfacets[i];
0295 }
0296 }
0297 }
0298 }
0299 }
0300
0301
0302
0303
0304
0305
0306 VECCORE_ATT_HOST_DEVICE
0307 void DistanceToIn(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T const & ,
0308 T &distance, int &isurf) const
0309 {
0310 using Bool_v = vecCore::Mask<Real_v>;
0311
0312 distance = InfinityLength<T>();
0313 Real_v dist = InfinityLength<Real_v>();
0314 isurf = -1;
0315
0316
0317 Real_v ndd = NonZero(direction.Dot(fNormals));
0318 Real_v saf = DistPlanes(point);
0319 Bool_v valid = ndd < Real_v(0.) && saf > Real_v(-kTolerance);
0320
0321
0322 vecCore__MaskedAssignFunc(dist, valid, -saf / ndd);
0323
0324
0325
0326 Vector3D<Real_v> pointv = point + dist * direction;
0327
0328 Bool_v hit;
0329 InsideCluster(pointv, hit);
0330 valid &= hit;
0331
0332 if (vecCore::EarlyReturnAllowed() && vecCore::MaskEmpty(valid)) return;
0333
0334 for (size_t i = 0; i < kVecSize; ++i) {
0335 if (vecCore::Get(valid, i) && (vecCore::Get(dist, i) < distance)) {
0336 distance = vecCore::Get(dist, i);
0337 isurf = fIfacets[i];
0338 }
0339 }
0340 }
0341
0342
0343
0344
0345
0346
0347
0348 VECCORE_ATT_HOST_DEVICE
0349 VECGEOM_FORCE_INLINE
0350 bool DistanceToInConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T &distance, T &limit) const
0351 {
0352 using Bool_v = vecCore::Mask<Real_v>;
0353
0354
0355 const Real_v proj = NonZero(direction.Dot(fNormals));
0356 const Bool_v moving_away = proj > Real_v(-kTolerance);
0357
0358 const Real_v pdist = DistPlanes(point);
0359 const Bool_v side_correct = pdist > Real_v(-kTolerance);
0360
0361 if (!vecCore::MaskEmpty(side_correct && moving_away)) return false;
0362
0363
0364 const Bool_v from_outside = side_correct && !moving_away;
0365
0366
0367 const Bool_v from_inside = !side_correct && moving_away;
0368
0369 Real_v dmin = -InfinityLength<Real_v>();
0370 Real_v dmax = InfinityLength<Real_v>();
0371
0372 const Real_v dist = -pdist / NonZero(proj);
0373 vecCore__MaskedAssignFunc(dmin, from_outside, dist);
0374 vecCore__MaskedAssignFunc(dmax, from_inside, dist);
0375 distance = vecCore::math::Max(distance, vecCore::ReduceMax(dmin));
0376 limit = vecCore::math::Min(limit, vecCore::ReduceMin(dmax));
0377
0378
0379
0380 return true;
0381 }
0382
0383
0384
0385
0386
0387
0388 VECCORE_ATT_HOST_DEVICE
0389 void DistanceToOut(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T const & ,
0390 T &distance, int &isurf) const
0391 {
0392 using Bool_v = vecCore::Mask<Real_v>;
0393
0394 distance = 0.;
0395 Real_v dist = InfinityLength<Real_v>();
0396 isurf = -1;
0397
0398
0399
0400
0401
0402
0403 Real_v ndd = NonZero(direction.Dot(fNormals));
0404
0405
0406 Real_v saf = DistPlanes(point);
0407
0408 Bool_v valid = ndd > Real_v(0.) && saf < Real_v(kTolerance);
0409
0410 if (vecCore::EarlyReturnAllowed() && vecCore::MaskEmpty(valid)) return;
0411
0412 vecCore__MaskedAssignFunc(dist, valid, -saf / ndd);
0413
0414
0415
0416 Vector3D<Real_v> pointv = point + dist * direction;
0417
0418 Bool_v hit;
0419 InsideCluster(pointv, hit);
0420 valid &= hit;
0421 if (vecCore::MaskEmpty(valid)) return;
0422
0423
0424 distance = InfinityLength<T>();
0425 for (size_t i = 0; i < kVecSize; ++i) {
0426 if (vecCore::Get(valid, i) && vecCore::Get(dist, i) < distance) {
0427 distance = vecCore::Get(dist, i);
0428 isurf = fIfacets[i];
0429 }
0430 }
0431 }
0432
0433
0434
0435
0436
0437
0438 VECCORE_ATT_HOST_DEVICE
0439 bool DistanceToOutConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T &distance) const
0440 {
0441 using Bool_v = vecCore::Mask<Real_v>;
0442
0443 distance = -kTolerance;
0444 Real_v dist = InfinityLength<Real_v>();
0445
0446
0447 Real_v saf = DistPlanes(point);
0448 Bool_v valid = saf < Real_v(kTolerance);
0449 if (vecCore::EarlyReturnAllowed() && !vecCore::MaskFull(valid)) return false;
0450
0451
0452
0453 Real_v ndd = NonZero(direction.Dot(fNormals));
0454 valid = ndd > Real_v(0.);
0455
0456 vecCore__MaskedAssignFunc(dist, valid, -saf / ndd);
0457 distance = vecCore::ReduceMin(dist);
0458 return true;
0459 }
0460
0461
0462
0463
0464
0465
0466 VECCORE_ATT_HOST_DEVICE
0467 bool DistanceToInOut(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, T &dtoin, T &dtoout) const
0468 {
0469 using Bool_v = vecCore::Mask<Real_v>;
0470 using vecCore::ReduceMax;
0471 using vecCore::ReduceMin;
0472 using vecCore::math::Max;
0473 using vecCore::math::Min;
0474
0475
0476 Real_v projdir_v = NonZero(direction.Dot(fNormals));
0477 Bool_v moving_away = projdir_v > Real_v(0.);
0478
0479 Real_v projdist_v = DistPlanes(point);
0480 Bool_v outside = projdist_v > Real_v(kTolerance);
0481
0482 if (!vecCore::MaskEmpty(outside && moving_away)) return false;
0483
0484 Bool_v from_inside = !outside && moving_away;
0485
0486 Bool_v from_outside = outside && !moving_away;
0487
0488 const Real_v dist_v = -projdist_v / NonZero(projdir_v);
0489 Real_v dtoin_v = -InfinityLength<Real_v>();
0490 Real_v dtoout_v = InfinityLength<Real_v>();
0491 vecCore__MaskedAssignFunc(dtoin_v, from_outside, dist_v);
0492 dtoin = Max(dtoin, ReduceMax(dtoin_v));
0493 vecCore__MaskedAssignFunc(dtoout_v, from_inside, dist_v);
0494 dtoout = Min(dtoout, ReduceMin(dtoout_v));
0495 return true;
0496 }
0497
0498
0499
0500
0501 template <bool ToIn>
0502 VECCORE_ATT_HOST_DEVICE
0503 T SafetySq(Vector3D<Real_v> const &point, int &isurf) const
0504 {
0505 using Bool_v = vecCore::Mask<Real_v>;
0506
0507 Real_v safetyv = DistPlanes(point);
0508 T distancesq = InfinityLength<T>();
0509
0510 Vector3D<Real_v> intersectionv = point - safetyv * fNormals;
0511 Bool_v withinBound;
0512 InsideCluster(intersectionv, withinBound);
0513 if (ToIn)
0514 withinBound &= safetyv > Real_v(-kTolerance);
0515 else
0516 withinBound &= safetyv < Real_v(kTolerance);
0517 safetyv *= safetyv;
0518
0519 isurf = -1;
0520 if (vecCore::MaskFull(withinBound)) {
0521
0522 for (size_t i = 0; i < kVecSize; ++i) {
0523 auto saflane = vecCore::Get(safetyv, i);
0524 if (saflane < distancesq) {
0525 distancesq = saflane;
0526 isurf = fIfacets[i];
0527 }
0528 }
0529 return distancesq;
0530 }
0531
0532 Vector3D<Real_v> safetyv_outbound = InfinityLength<Real_v>();
0533 for (size_t ivert = 0; ivert < NVERT; ++ivert) {
0534 safetyv_outbound[ivert] =
0535 DistanceToLineSegmentSquared2(fVertices[ivert], fVertices[(ivert + 1) % NVERT], point, !withinBound);
0536 }
0537 Real_v safety_outv = safetyv_outbound.Min();
0538 vecCore::MaskedAssign(safetyv, !withinBound, safety_outv);
0539
0540
0541 for (size_t i = 0; i < kVecSize; ++i) {
0542 auto saflane = vecCore::Get(safetyv, i);
0543 if (saflane < distancesq) {
0544 distancesq = saflane;
0545 isurf = fIfacets[i];
0546 }
0547 }
0548 return distancesq;
0549 }
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600 };
0601
0602 std::ostream &operator<<(std::ostream &os, TessellatedCluster<3, typename vecgeom::VectorBackend::Real_v> const &tcl);
0603 std::ostream &operator<<(std::ostream &os, TessellatedCluster<4, typename vecgeom::VectorBackend::Real_v> const &tcl);
0604
0605 }
0606 }
0607
0608 #endif