File indexing completed on 2026-10-27 09:51:31
0001
0002
0003
0004
0005 #ifndef VECGEOM_VOLUMES_KERNEL_POLYHEDRONIMPLEMENTATION_H_
0006 #define VECGEOM_VOLUMES_KERNEL_POLYHEDRONIMPLEMENTATION_H_
0007
0008 #include <cstdio>
0009
0010 #include "VecGeom/base/Vector3D.h"
0011 #include "VecGeom/volumes/kernel/GenericKernels.h"
0012 #include "VecGeom/volumes/kernel/TubeImplementation.h"
0013 #include "VecGeom/volumes/Quadrilaterals.h"
0014 #include "VecGeom/volumes/PolyhedronStruct.h"
0015 #include "VecGeom/volumes/SurfaceHitView.h"
0016
0017 namespace vecgeom {
0018
0019
0020
0021 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_2v(struct, PolyhedronImplementation, Polyhedron::EInnerRadii,
0022 Polyhedron::EInnerRadii::kGeneric, Polyhedron::EPhiCutout,
0023 Polyhedron::EPhiCutout::kGeneric);
0024
0025 inline namespace VECGEOM_IMPL_NAMESPACE {
0026
0027 class PlacedPolyhedron;
0028 class UnplacedPolyhedron;
0029
0030 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0031 struct PolyhedronImplementation {
0032
0033 using PlacedShape_t = PlacedPolyhedron;
0034 using UnplacedStruct_t = PolyhedronStruct<Precision>;
0035 using UnplacedVolume_t = UnplacedPolyhedron;
0036
0037
0038 enum class ExitSurface { kNone, kInner, kPhi, kOuter, kZMin, kZMax };
0039
0040
0041 struct ExitHit {
0042 ExitSurface surface{ExitSurface::kNone};
0043 int face{-1};
0044 };
0045
0046
0047
0048
0049
0050
0051
0052 template <typename Real_v>
0053 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static int FindZSegment(UnplacedStruct_t const &unplaced,
0054 Real_v const &pointZ);
0055
0056
0057
0058
0059
0060 template <typename Real_v>
0061 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static int FindPhiSegment(UnplacedStruct_t const &unplaced,
0062 Vector3D<Real_v> const &point);
0063
0064
0065
0066
0067
0068
0069
0070 template <typename Real_v>
0071 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v DistanceToInZSegment(UnplacedStruct_t const &unplaced,
0072 int segmentIndex,
0073 Vector3D<Real_v> const &point,
0074 Vector3D<Real_v> const &direction);
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 template <typename Real_v>
0086 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v DistanceToOutZSegment(
0087 UnplacedStruct_t const &unplaced, int segmentIndex, Precision zMin, Precision zMax, Vector3D<Real_v> const &point,
0088 Vector3D<Real_v> const &direction, ExitHit *hit = nullptr);
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 VECCORE_ATT_HOST_DEVICE
0101 VECGEOM_FORCE_INLINE
0102 static Precision SafetyToZSegmentSquared(UnplacedStruct_t const &unplaced, int segmentIndex, int &phiIndex,
0103 Vector3D<Precision> const &point, bool pt_inside, int &iSurf);
0104
0105
0106
0107
0108
0109
0110
0111
0112 template <bool pointInsideT>
0113 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static bool DistanceToEndcaps(UnplacedStruct_t const &unplaced,
0114 bool goingRight,
0115 Vector3D<Precision> const &point,
0116 Vector3D<Precision> const &direction,
0117 Precision &distance);
0118
0119
0120
0121
0122
0123
0124 template <typename Real_v>
0125 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SetExitHit(UnplacedStruct_t const &unplaced,
0126 int segmentIndex, ExitHit const &hit,
0127 SurfaceHitView<Real_v> *hitInfo);
0128
0129
0130
0131
0132
0133
0134 VECCORE_ATT_HOST_DEVICE
0135 VECGEOM_FORCE_INLINE
0136 static void SafetyToEndcapsSquared(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point,
0137 Precision &distance, int &iz);
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 VECCORE_ATT_HOST_DEVICE
0148 VECGEOM_FORCE_INLINE
0149 static Precision SafetyToFiniteFacesSquared(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point,
0150 int phiIndex, bool pointInside);
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 VECCORE_ATT_HOST_DEVICE
0166 VECGEOM_FORCE_INLINE
0167 static Precision SafetyToRZOutlineSquared(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point,
0168 Precision normSign, bool &wrongSide);
0169
0170
0171
0172
0173
0174
0175 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static bool InPhiCutoutWedge(ZSegment const &segment,
0176 bool largePhiCutout,
0177 Vector3D<Precision> const &point);
0178
0179
0180 VECCORE_ATT_HOST_DEVICE
0181 VECGEOM_FORCE_INLINE
0182 static Inside_t InsideSegBorder(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point, int zIndex);
0183
0184
0185 VECCORE_ATT_HOST_DEVICE
0186 VECGEOM_FORCE_INLINE
0187 static bool NormalKernel(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point,
0188 Vector3D<Precision> &normal);
0189
0190
0191 template <typename Real_v>
0192 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void UnplacedContains(UnplacedStruct_t const &unplaced,
0193 Vector3D<Real_v> const &point,
0194 bool &inside);
0195
0196
0197 template <typename Real_v>
0198 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Contains(UnplacedStruct_t const &unplaced,
0199 Vector3D<Real_v> const &point, bool &inside);
0200
0201
0202 template <typename Real_v>
0203 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Inside(UnplacedStruct_t const &unplaced,
0204 Vector3D<Real_v> const &point, Inside_t &inside);
0205
0206
0207 template <typename Real_v>
0208 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToIn(UnplacedStruct_t const &unplaced,
0209 Vector3D<Real_v> const &point,
0210 Vector3D<Real_v> const &direction,
0211 Real_v const &stepMax, Real_v &distance);
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 template <typename Real_v>
0223 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToOut(UnplacedStruct_t const &unplaced,
0224 Vector3D<Real_v> const &point,
0225 Vector3D<Real_v> const &direction,
0226 Real_v const &stepMax, Real_v &distance,
0227 SurfaceHitView<Real_v> *hitInfo = nullptr);
0228
0229
0230 template <typename Real_v, bool RecordHitInfo>
0231 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToOutImpl(UnplacedStruct_t const &unplaced,
0232 Vector3D<Real_v> const &point,
0233 Vector3D<Real_v> const &direction,
0234 Real_v const &stepMax, Real_v &distance,
0235 SurfaceHitView<Real_v> *hitInfo);
0236
0237
0238
0239
0240
0241 template <typename Real_v>
0242 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToIn(UnplacedStruct_t const &unplaced,
0243 Vector3D<Real_v> const &point, Real_v &safety);
0244
0245
0246
0247
0248 template <typename Real_v>
0249 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToOut(UnplacedStruct_t const &unplaced,
0250 Vector3D<Real_v> const &point, Real_v &safety);
0251
0252 };
0253
0254 namespace {
0255
0256
0257
0258
0259
0260
0261
0262
0263 template <Polyhedron::EInnerRadii innerRadiiT>
0264 struct HasInnerRadiiTraits {
0265
0266 typedef TubeImplementation<TubeTypes::UniversalTube> TubeKernels;
0267 };
0268
0269 template <>
0270 struct HasInnerRadiiTraits<Polyhedron::EInnerRadii::kFalse> {
0271
0272 typedef TubeImplementation<TubeTypes::UniversalTube> TubeKernels;
0273 };
0274
0275
0276
0277
0278 template <Polyhedron::EInnerRadii innerRadiiT>
0279 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool TreatInner(bool hasInnerRadius)
0280 {
0281 return hasInnerRadius;
0282 }
0283
0284
0285 template <>
0286 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool TreatInner<Polyhedron::EInnerRadii::kFalse>(bool )
0287 {
0288 return false;
0289 }
0290
0291
0292
0293
0294 template <Polyhedron::EPhiCutout phiCutoutT>
0295 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool TreatPhi(bool )
0296 {
0297 return true;
0298 }
0299
0300
0301 template <>
0302 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool TreatPhi<Polyhedron::EPhiCutout::kFalse>(bool )
0303 {
0304 return false;
0305 }
0306
0307
0308 template <>
0309 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool TreatPhi<Polyhedron::EPhiCutout::kGeneric>(bool hasPhiCutout)
0310 {
0311 return hasPhiCutout;
0312 }
0313
0314
0315
0316
0317 template <Polyhedron::EPhiCutout phiCutoutT>
0318 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool LargePhiCutout(bool largePhiCutout)
0319 {
0320 return largePhiCutout;
0321 }
0322
0323
0324 template <>
0325 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool LargePhiCutout<Polyhedron::EPhiCutout::kTrue>(bool )
0326 {
0327 return false;
0328 }
0329
0330
0331 template <>
0332 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool LargePhiCutout<Polyhedron::EPhiCutout::kLarge>(
0333 bool )
0334 {
0335 return true;
0336 }
0337
0338 }
0339
0340 namespace {
0341
0342
0343
0344
0345
0346
0347 template <typename Real_v>
0348 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE int FindZSegmentKernel(Real_v const &pointZ, Precision const *begin,
0349 size_t size);
0350 template <>
0351 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE int FindZSegmentKernel<Precision>(Precision const &pointZ,
0352 Precision const *begin, size_t size)
0353 {
0354 int index = size - 1;
0355 Precision const *end = begin + index;
0356
0357
0358 while (begin <= end && pointZ < *end + kTolerance) {
0359 --index;
0360 --end;
0361 }
0362 if ((size_t(index + 2) < size) && (pointZ > *(end + 1) - kTolerance)) return (index + 1);
0363 return index;
0364 }
0365 }
0366
0367 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0368 template <typename Real_v>
0369 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE int PolyhedronImplementation<innerRadiiT, phiCutoutT>::FindZSegment(
0370 UnplacedStruct_t const &unplaced, Real_v const &pointZ)
0371 {
0372 return FindZSegmentKernel<Real_v>(pointZ, &unplaced.fZPlanes[0], unplaced.fZPlanes.size());
0373 }
0374
0375 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0376 template <typename Real_v>
0377 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE int PolyhedronImplementation<innerRadiiT, phiCutoutT>::FindPhiSegment(
0378 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point)
0379 {
0380
0381
0382
0383
0384
0385
0386
0387 int index = -1;
0388 SOA3D<Precision> const &phiSections = unplaced.fPhiSections;
0389 Real_v projectionFirst, projectionSecond;
0390 projectionFirst = point[0] * phiSections.x(0) + point[1] * phiSections.y(0) + point[2] * phiSections.z(0);
0391 for (int i = 1, iMax = unplaced.fSideCount + 1; i < iMax; ++i) {
0392 projectionSecond = point[0] * phiSections.x(i) + point[1] * phiSections.y(i) + point[2] * phiSections.z(i);
0393 if (projectionFirst > -kTolerance && projectionSecond < kTolerance) {
0394 index = i - 1;
0395 break;
0396 }
0397 projectionFirst = projectionSecond;
0398 }
0399
0400 return index;
0401 }
0402
0403 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0404 template <typename Real_v>
0405 VECCORE_ATT_HOST_DEVICE Real_v PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToInZSegment(
0406 UnplacedStruct_t const &unplaced, int segmentIndex, Vector3D<Real_v> const &point,
0407 Vector3D<Real_v> const &direction)
0408 {
0409
0410 Real_v distance;
0411 bool done = false;
0412
0413 ZSegment const &segment = unplaced.fZSegments[segmentIndex];
0414
0415
0416
0417
0418 distance = segment.outer.DistanceToIn<Real_v, false>(point, direction);
0419 if (TreatInner<innerRadiiT>(segment.hasInnerRadius()) && distance < kTolerance) {
0420 for (int i = 0; i < segment.inner.size(); ++i) {
0421 auto const normal = segment.inner.GetNormal(i);
0422 if (Abs(point.Dot(normal) + segment.inner.GetDistance(i)) < kTolerance && direction.Dot(normal) < -kTolerance) {
0423 distance = InfinityLength<Real_v>();
0424 break;
0425 }
0426 }
0427 }
0428 done = distance < InfinityLength<Real_v>();
0429 if (done) return distance;
0430
0431
0432
0433 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
0434 if (!done) distance = segment.phi.DistanceToIn<Real_v, false>(point, direction);
0435 if (unplaced.fHasLargePhiCutout) {
0436
0437
0438 done |= distance < InfinityLength<Real_v>();
0439 if (done) return distance;
0440 }
0441 }
0442
0443
0444 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0445 Real_v distrmin = segment.inner.DistanceToIn<Real_v, true>(point, direction);
0446
0447
0448 if (distrmin < kTolerance) {
0449 for (int i = 0; i < segment.outer.size(); ++i) {
0450 auto const normal = segment.outer.GetNormal(i);
0451 if (Abs(point.Dot(normal) + segment.outer.GetDistance(i)) < kTolerance && direction.Dot(normal) > kTolerance) {
0452 distrmin = InfinityLength<Real_v>();
0453 break;
0454 }
0455 }
0456 }
0457 if (!done && distance > distrmin) distance = distrmin;
0458 }
0459
0460 return distance;
0461 }
0462
0463 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0464 template <typename Real_v>
0465 VECCORE_ATT_HOST_DEVICE Real_v PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToOutZSegment(
0466 UnplacedStruct_t const &unplaced, int segmentIndex, Precision zMin, Precision zMax, Vector3D<Real_v> const &point,
0467 Vector3D<Real_v> const &direction, ExitHit *hit)
0468 {
0469
0470 bool done = false;
0471 Real_v distance = InfinityLength<Real_v>();
0472
0473 ZSegment const &segment = unplaced.fZSegments[segmentIndex];
0474
0475
0476 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0477 int face = -1;
0478 distance = segment.inner.DistanceToIn<Real_v, false, true>(point, direction, &face);
0479 if (distance < kTolerance) {
0480 const int count = segment.inner.size();
0481 const int previous = face ? face - 1 : count - 1;
0482 const int next = face + 1 == count ? 0 : face + 1;
0483
0484
0485 const bool nearEdge =
0486 Abs(point.Dot(segment.inner.GetNormal(previous)) + segment.inner.GetDistance(previous)) < kTolerance ||
0487 Abs(point.Dot(segment.inner.GetNormal(next)) + segment.inner.GetDistance(next)) < kTolerance;
0488
0489
0490 for (int i = 0; nearEdge && i < count; ++i) {
0491 auto const normal = segment.inner.GetNormal(i);
0492 if (Abs(point.Dot(normal) + segment.inner.GetDistance(i)) < kTolerance && direction.Dot(normal) > kTolerance) {
0493 distance = InfinityLength<Real_v>();
0494 break;
0495 }
0496 }
0497 }
0498 if (hit && distance < InfinityLength<Real_v>()) *hit = {ExitSurface::kInner, face};
0499
0500 if (unplaced.fHasLargePhiCutout) {
0501 done = distance < InfinityLength<Real_v>();
0502 if (done) return distance;
0503 }
0504 }
0505
0506
0507
0508 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
0509 int face = -1;
0510 Real_v distphi = segment.phi.DistanceToIn<Real_v, true, true>(point, direction, hit ? &face : nullptr);
0511 if (distance > distphi) {
0512 distance = distphi;
0513 if (hit) *hit = {ExitSurface::kPhi, face};
0514 }
0515 }
0516
0517 done = distance > -kTolerance && distance < InfinityLength<Real_v>();
0518 if (done) return distance;
0519
0520
0521 int face = -1;
0522 Real_v distout = segment.outer.DistanceToOut<Real_v>(point, direction, zMin, zMax, hit ? &face : nullptr);
0523 if (!done) {
0524 distance = distout;
0525 if (hit && distout < InfinityLength<Real_v>()) *hit = {ExitSurface::kOuter, face};
0526 }
0527
0528 return distance;
0529 }
0530
0531 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0532 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Precision
0533 PolyhedronImplementation<innerRadiiT, phiCutoutT>::SafetyToZSegmentSquared(UnplacedStruct_t const &unplaced,
0534 int segmentIndex, int &phiIndex,
0535 Vector3D<Precision> const &point,
0536 bool pt_inside, int &iSurf)
0537 {
0538
0539 ZSegment const &segment = unplaced.fZSegments[segmentIndex];
0540 bool in_cutout = phiIndex < 0;
0541
0542 Precision safetySquared = InfinityLength<Precision>();
0543 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout) && segment.phi.size() == 2) {
0544
0545 if (pt_inside || in_cutout) {
0546
0547 iSurf = 0;
0548 safetySquared = segment.phi.ScalarDistanceSquared(0, point);
0549 Precision saf = segment.phi.ScalarDistanceSquared(1, point);
0550 if (saf < safetySquared) {
0551 safetySquared = saf;
0552 iSurf = 1;
0553 }
0554
0555
0556 if (in_cutout) {
0557 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0558 if (segment.inner.size() > 0) {
0559 Precision safetySquaredInner = segment.inner.ScalarDistanceSquared(0, point);
0560 if (safetySquaredInner < safetySquared) {
0561 iSurf = 2;
0562 phiIndex = 0;
0563 safetySquared = safetySquaredInner;
0564 }
0565 if (segment.inner.size() > 1) {
0566 safetySquaredInner = segment.inner.ScalarDistanceSquared(segment.inner.size() - 1, point);
0567 if (safetySquaredInner < safetySquared) {
0568 iSurf = 2;
0569 phiIndex = segment.inner.size() - 1;
0570 safetySquared = safetySquaredInner;
0571 }
0572 }
0573 }
0574 }
0575 return safetySquared;
0576 }
0577 }
0578 }
0579
0580 if (in_cutout && segmentIndex > 0 && segmentIndex < unplaced.fZSegments.size() - 1 &&
0581 unplaced.fZPlanes[segmentIndex] == unplaced.fZPlanes[segmentIndex + 1]) {
0582
0583
0584 Precision safetySquaredOuter = InfinityLength<Precision>();
0585 if (segment.outer.size() > 0) {
0586 safetySquaredOuter = segment.outer.ScalarDistanceSquared(0, point);
0587 if (safetySquaredOuter < safetySquared) {
0588 iSurf = 3;
0589 phiIndex = 0;
0590 safetySquared = safetySquaredOuter;
0591 }
0592 if (segment.outer.size() > 1) {
0593 safetySquaredOuter = segment.outer.ScalarDistanceSquared(segment.outer.size() - 1, point);
0594 if (safetySquaredOuter < safetySquared) {
0595 iSurf = 3;
0596 phiIndex = segment.outer.size() - 1;
0597 safetySquared = safetySquaredOuter;
0598 }
0599 }
0600 }
0601 Precision safetySquaredInner = InfinityLength<Precision>();
0602 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0603 if (segment.inner.size() > 0) {
0604 safetySquaredInner = segment.inner.ScalarDistanceSquared(0, point);
0605 if (safetySquaredInner < safetySquared) {
0606 iSurf = 2;
0607 phiIndex = 0;
0608 safetySquared = safetySquaredInner;
0609 }
0610 if (segment.inner.size() > 1) {
0611 safetySquaredInner = segment.inner.ScalarDistanceSquared(segment.inner.size() - 1, point);
0612 if (safetySquaredInner < safetySquared) {
0613 iSurf = 2;
0614 phiIndex = segment.inner.size() - 1;
0615 safetySquared = safetySquaredInner;
0616 }
0617 }
0618 }
0619 }
0620 return safetySquared;
0621 }
0622
0623
0624
0625 Precision safetySquaredOuter = InfinityLength<Precision>();
0626 if (segment.outer.size() > 0) safetySquaredOuter = segment.outer.ScalarDistanceSquared(phiIndex, point);
0627
0628
0629 Precision safetySquaredInner = InfinityLength<Precision>();
0630 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0631 if (segment.inner.size() > 0) safetySquaredInner = segment.inner.ScalarDistanceSquared(phiIndex, point);
0632 }
0633 if (safetySquaredInner < safetySquared) {
0634 iSurf = 2;
0635 safetySquared = safetySquaredInner;
0636 }
0637 if (safetySquaredOuter < safetySquared) {
0638 iSurf = 3;
0639 safetySquared = safetySquaredOuter;
0640 }
0641 return safetySquared;
0642 }
0643
0644 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0645 template <bool pointInsideT>
0646 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToEndcaps(
0647 UnplacedStruct_t const &unplaced, bool , Vector3D<Precision> const &point,
0648 Vector3D<Precision> const &direction, Precision &distance)
0649 {
0650
0651 ZSegment const *segment;
0652 Precision zPlane;
0653
0654
0655
0656
0657 if (pointInsideT)
0658 {
0659 if (direction[2] < 0) {
0660 segment = &unplaced.fZSegments[0];
0661 zPlane = unplaced.fZPlanes[0];
0662 } else {
0663 segment = &unplaced.fZSegments[unplaced.fZSegments.size() - 1];
0664 zPlane = unplaced.fZPlanes[unplaced.fZSegments.size()];
0665 }
0666 } else
0667 {
0668 if (direction[2] < 0) {
0669 segment = &unplaced.fZSegments[unplaced.fZSegments.size() - 1];
0670 zPlane = unplaced.fZPlanes[unplaced.fZSegments.size()];
0671 } else {
0672 segment = &unplaced.fZSegments[0];
0673 zPlane = unplaced.fZPlanes[0];
0674 }
0675 }
0676
0677 Precision distanceTest = (zPlane - point[2]) / NonZero(direction[2]);
0678
0679 if (distanceTest < -kTolerance || distanceTest >= distance) return false;
0680
0681 Vector3D<Precision> intersection = point + distanceTest * direction;
0682
0683 if (!segment->outer.Contains<Precision>(intersection)) return false;
0684 if (TreatInner<innerRadiiT>(segment->hasInnerRadius())) {
0685 if (segment->inner.Contains<Precision>(intersection)) return false;
0686 }
0687
0688 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
0689 if (InPhiCutoutWedge(*segment, unplaced.fHasLargePhiCutout, intersection)) {
0690 return false;
0691 }
0692 }
0693
0694 distance = distanceTest;
0695 return true;
0696 }
0697
0698 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0699 template <typename Real_v>
0700 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::SetExitHit(
0701 UnplacedStruct_t const &unplaced, int segmentIndex, ExitHit const &hit, SurfaceHitView<Real_v> *hitInfo)
0702 {
0703 bool leftBehind = false;
0704 Vector3D<Precision> normal;
0705
0706 if (hit.surface == ExitSurface::kZMin || hit.surface == ExitSurface::kZMax) {
0707 leftBehind = true;
0708 normal.Set(0., 0., hit.surface == ExitSurface::kZMin ? -1. : 1.);
0709 } else if (segmentIndex >= 0 && segmentIndex < unplaced.fZSegments.size() && hit.face >= 0) {
0710 ZSegment const &segment = unplaced.fZSegments[segmentIndex];
0711 if (hit.surface == ExitSurface::kOuter) {
0712 leftBehind = segment.outerSupports;
0713 normal = segment.outer.GetNormal(hit.face);
0714 } else if (hit.surface == ExitSurface::kPhi) {
0715 leftBehind = unplaced.fHasLargePhiCutout;
0716 normal = segment.phi.GetNormal(hit.face);
0717 } else if (hit.surface == ExitSurface::kInner) {
0718
0719 normal = -segment.inner.GetNormal(hit.face);
0720 }
0721 }
0722
0723 hitInfo->SetLeftBehind(leftBehind);
0724 if (hitInfo->WantsNormal() && normal.Mag2() > 0.) hitInfo->SetNormal(Vector3D<Real_v>(normal));
0725 }
0726
0727 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0728 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<
0729 innerRadiiT, phiCutoutT>::SafetyToEndcapsSquared(UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point,
0730 Precision &distanceSquared, int &iz)
0731 {
0732
0733
0734 Precision firstDistance = unplaced.fZPlanes[0] - point[2];
0735 Precision lastDistance = unplaced.fZPlanes[unplaced.fZSegments.size()] - point[2];
0736
0737
0738 bool isFirst = Abs(firstDistance) < Abs(lastDistance);
0739 iz = 0;
0740 ZSegment const &segment = isFirst ? unplaced.fZSegments[0] : unplaced.fZSegments[unplaced.fZSegments.size() - 1];
0741
0742 Precision distanceTest = isFirst ? firstDistance : lastDistance;
0743 Precision distanceTestSquared = distanceTest * distanceTest;
0744
0745 if (distanceTestSquared >= distanceSquared) return;
0746
0747
0748 Vector3D<Precision> intersection(point[0], point[1], point[2] + distanceTest);
0749 if (!segment.outer.Contains<Precision>(intersection)) return;
0750 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
0751 if (segment.inner.Contains<Precision>(intersection)) return;
0752 }
0753 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
0754 if (InPhiCutoutWedge(segment, unplaced.fHasLargePhiCutout, intersection)) {
0755 return;
0756 }
0757 }
0758
0759 iz = (isFirst) ? -1 : 1;
0760 distanceSquared = distanceTestSquared;
0761 }
0762
0763 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0764 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool PolyhedronImplementation<innerRadiiT, phiCutoutT>::InPhiCutoutWedge(
0765 ZSegment const &segment, bool largePhiCutout, Vector3D<Precision> const &point)
0766 {
0767 bool pointSeg0 = point.Dot(segment.phi.GetNormal(0)) + segment.phi.GetDistance(0) >= kTolerance;
0768 bool pointSeg1 = point.Dot(segment.phi.GetNormal(1)) + segment.phi.GetDistance(1) >= kTolerance;
0769
0770
0771 if (LargePhiCutout<phiCutoutT>(largePhiCutout)) {
0772 return pointSeg0 || pointSeg1;
0773 }
0774
0775 return pointSeg0 && pointSeg1;
0776 }
0777
0778 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0779 VECCORE_ATT_HOST_DEVICE Inside_t PolyhedronImplementation<innerRadiiT, phiCutoutT>::InsideSegBorder(
0780 UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point, int zIndex)
0781 {
0782
0783
0784
0785
0786 ZSegment const &segment = unplaced.fZSegments[zIndex];
0787
0788 int phiIndex = FindPhiSegment<Precision>(unplaced, point);
0789 if (phiIndex < 0) return EInside::kOutside;
0790
0791 Vector3D<Precision> const &vout = (segment.outer.size()) ? segment.outer.GetSideVectors()[0].GetNormals()[phiIndex]
0792 : segment.inner.GetSideVectors()[0].GetNormals()[phiIndex];
0793
0794
0795 Precision rdotvout = Abs<Precision>(point.Dot(vout));
0796
0797
0798 bool in1 = (rdotvout > unplaced.fRMin[zIndex] - kTolerance) && (rdotvout < unplaced.fRMax[zIndex] + kTolerance);
0799 bool in2 =
0800 (rdotvout > unplaced.fRMin[zIndex + 1] - kTolerance) && (rdotvout < unplaced.fRMax[zIndex + 1] + kTolerance);
0801 if (in1 && in2) {
0802 if ((rdotvout < unplaced.fRMin[zIndex] + kTolerance) || (rdotvout > unplaced.fRMax[zIndex] - kTolerance) ||
0803 (rdotvout < unplaced.fRMin[zIndex + 1] + kTolerance) || (rdotvout > unplaced.fRMax[zIndex + 1] - kTolerance))
0804 return EInside::kSurface;
0805
0806 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
0807 Inside_t insidePhi = unplaced.fPhiWedge.Inside<Precision>(point);
0808 return insidePhi;
0809 }
0810 return EInside::kInside;
0811 }
0812 if (!in1 && !in2) return EInside::kOutside;
0813 return EInside::kSurface;
0814 }
0815
0816 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0817 VECCORE_ATT_HOST_DEVICE bool PolyhedronImplementation<innerRadiiT, phiCutoutT>::NormalKernel(
0818 UnplacedStruct_t const &unplaced, Vector3D<Precision> const &point, Vector3D<Precision> &normal)
0819 {
0820
0821 Precision safety = InfinityLength<Precision>();
0822 const int zMax = unplaced.fZSegments.size();
0823 int zIndex = FindZSegment<Precision>(unplaced, point[2]);
0824 if (zIndex < 0) {
0825 normal = Vector3D<Precision>(0, 0, -1);
0826 return true;
0827 }
0828
0829 if (zIndex >= zMax) {
0830 normal = Vector3D<Precision>(0, 0, 1);
0831 return true;
0832 }
0833
0834 int iSeg = zIndex;
0835 Precision dz;
0836 int iSurf = -1;
0837 int iz = 0;
0838 int phiIndex = FindPhiSegment<Precision>(unplaced, point);
0839
0840 if (zMax == 1 && phiIndex >= 0 && !TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout) &&
0841 !TreatInner<innerRadiiT>(unplaced.fZSegments[0].hasInnerRadius()) && unplaced.fRMax[0] == unplaced.fRMax[1] &&
0842 point[2] >= unplaced.fZPlanes[0] && point[2] <= unplaced.fZPlanes[1]) {
0843 const auto &outer = unplaced.fZSegments[0].outer;
0844 const auto faceNormal = outer.GetNormal(phiIndex);
0845 const Precision planeDistance = point.Dot(faceNormal) + outer.GetDistance(phiIndex);
0846 const Vector3D<Precision> projection = point - planeDistance * faceNormal;
0847 const auto &sides = outer.GetSideVectors();
0848
0849 if (faceNormal.z() == 0. && projection.Dot(sides[1].GetNormal(phiIndex)) + sides[1].GetDistance(phiIndex) >= 0. &&
0850 projection.Dot(sides[3].GetNormal(phiIndex)) + sides[3].GetDistance(phiIndex) >= 0.) {
0851 safety = planeDistance * planeDistance;
0852 SafetyToEndcapsSquared(unplaced, point, safety, iz);
0853 normal = iz ? Vector3D<Precision>(0., 0., iz) : faceNormal;
0854 return true;
0855 }
0856 }
0857
0858
0859 for (int z = zIndex; z < zMax;) {
0860 int iSurfCrt = -1;
0861 Precision safetySeg = SafetyToZSegmentSquared(unplaced, z, phiIndex, point, true, iSurfCrt);
0862 if (safetySeg < safety) {
0863 safety = safetySeg;
0864 iSeg = z;
0865 iSurf = iSurfCrt;
0866 }
0867 ++z;
0868 dz = unplaced.fZPlanes[z] - point[2];
0869 if (dz * dz > safety) break;
0870 }
0871
0872 for (int z = zIndex - 1; z >= 0; --z) {
0873 int iSurfCrt = -1;
0874 Precision safetySeg = SafetyToZSegmentSquared(unplaced, z, phiIndex, point, true, iSurfCrt);
0875 if (safetySeg < safety) {
0876 safety = safetySeg;
0877 iSeg = z;
0878 iSurf = iSurfCrt;
0879 }
0880 dz = point[2] - unplaced.fZPlanes[z];
0881 if (dz * dz > safety) break;
0882 }
0883
0884
0885 SafetyToEndcapsSquared(unplaced, point, safety, iz);
0886 if (iz != 0) {
0887 normal = Vector3D<Precision>(0, 0, iz);
0888 return true;
0889 }
0890
0891
0892 ZSegment const &segment = unplaced.fZSegments[iSeg];
0893 if (iSurf >= 0 && iSurf < 2) {
0894 normal = segment.phi.GetNormal(iSurf);
0895 } else {
0896 if (iSurf == 2)
0897 normal = -1. * segment.inner.GetNormal(phiIndex);
0898 else
0899 normal = segment.outer.GetNormal(phiIndex);
0900 }
0901 return true;
0902 }
0903
0904 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0905 template <typename Real_v>
0906 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::UnplacedContains(
0907 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, bool &inside)
0908 {
0909 Contains(unplaced, point, inside);
0910 }
0911
0912 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0913 template <typename Real_v>
0914 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::Contains(
0915 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, bool &inside)
0916 {
0917 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
0918
0919
0920 {
0921 bool inBounds;
0922 HasInnerRadiiTraits<innerRadiiT>::TubeKernels::template Contains<>(
0923 unplaced.fBoundingTube,
0924 Vector3D<Precision>(localPoint[0], localPoint[1], localPoint[2] - unplaced.fBoundingTubeOffset), inBounds);
0925 if (!inBounds) {
0926 inside = false;
0927 return;
0928 }
0929 }
0930
0931
0932 int zIndex = FindZSegment<Precision>(unplaced, localPoint[2]);
0933 if (!(zIndex >= 0 && zIndex < unplaced.fZSegments.size())) {
0934 inside = false;
0935 return;
0936 }
0937
0938 ZSegment const &segment = unplaced.fZSegments[zIndex];
0939
0940
0941
0942
0943 if (unplaced.fSameZ[zIndex]) {
0944 int phiIndex = FindPhiSegment<Precision>(unplaced, localPoint);
0945 if (phiIndex < 0) {
0946 inside = false;
0947 return;
0948 }
0949 Vector3D<Precision> const &vout = (segment.outer.size()) ? segment.outer.GetSideVectors()[0].GetNormals()[phiIndex]
0950 : segment.inner.GetSideVectors()[0].GetNormals()[phiIndex];
0951 Precision rdotvout = Abs<Precision>(localPoint.Dot(vout));
0952 bool in1 = (rdotvout >= unplaced.fRMin[zIndex]) && (rdotvout <= unplaced.fRMax[zIndex]);
0953 bool in2 = (rdotvout >= unplaced.fRMin[zIndex + 1]) && (rdotvout <= unplaced.fRMax[zIndex + 1]);
0954 inside = (in1 | in2);
0955 return;
0956 }
0957
0958 if (!segment.outer.Contains<Precision>(localPoint)) {
0959 inside = false;
0960 return;
0961 }
0962
0963 if (TreatInner<innerRadiiT>(segment.hasInnerRadius()) && segment.inner.Contains<Precision>(localPoint)) {
0964 inside = false;
0965 return;
0966 }
0967
0968
0969
0970 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout) && !segment.phi.Contains<Precision>(localPoint)) {
0971 inside = false;
0972 return;
0973 }
0974
0975 inside = true;
0976 }
0977
0978 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
0979 template <typename Real_v>
0980 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::Inside(UnplacedStruct_t const &unplaced,
0981 Vector3D<Real_v> const &point,
0982 Inside_t &inside)
0983 {
0984 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
0985
0986 {
0987 bool inBounds;
0988
0989
0990
0991
0992 HasInnerRadiiTraits<innerRadiiT>::TubeKernels::template Contains<>(
0993 unplaced.fBoundingTube,
0994 Vector3D<Precision>(localPoint[0], localPoint[1], localPoint[2] - unplaced.fBoundingTubeOffset), inBounds);
0995 if (!inBounds) {
0996 inside = EInside::kOutside;
0997 return;
0998 }
0999 }
1000
1001
1002
1003
1004
1005 int zIndex = FindZSegment<Precision>(unplaced, localPoint[2]);
1006 if (zIndex < 0 || zIndex > (unplaced.fZSegments.size() - 1)) {
1007 inside = EInside::kOutside;
1008 return;
1009 }
1010
1011 ZSegment const &segment = unplaced.fZSegments[zIndex];
1012 if (unplaced.fSameZ[zIndex]) {
1013 inside = InsideSegBorder(unplaced, localPoint, zIndex);
1014 return;
1015 }
1016
1017 {
1018 Inside_t insideOuter = segment.outer.Inside<Precision, Inside_t>(localPoint);
1019 if (insideOuter != EInside::kInside) {
1020 inside = insideOuter;
1021 return;
1022 }
1023 }
1024
1025 if (TreatInner<innerRadiiT>(segment.hasInnerRadius())) {
1026 Inside_t insideInner = segment.inner.Inside<Precision, Inside_t>(localPoint);
1027 if (insideInner == EInside::kInside) {
1028 inside = EInside::kOutside;
1029 return;
1030 }
1031 if (insideInner == EInside::kSurface) {
1032 inside = EInside::kSurface;
1033 return;
1034 }
1035 }
1036
1037 if (TreatPhi<phiCutoutT>(unplaced.fHasPhiCutout)) {
1038 Inside_t insidePhi = segment.phi.Inside<Precision, Inside_t>(localPoint);
1039 if (insidePhi != EInside::kInside) {
1040 inside = insidePhi;
1041 return;
1042 }
1043 }
1044
1045
1046
1047 Precision dz = Abs(Abs(localPoint[2] - unplaced.fBoundingTubeOffset) -
1048 0.5 * (unplaced.fZPlanes[unplaced.fZSegments.size()] - unplaced.fZPlanes[0]));
1049 inside = dz < kTolerance ? EInside::kSurface : EInside::kInside;
1050 }
1051
1052 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1053 template <typename Real_v>
1054 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToIn(
1055 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction,
1056 Real_v const &stepMax, Real_v &distance)
1057 {
1058 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
1059 Vector3D<Precision> localDirection(direction[0], direction[1], direction[2]);
1060 Precision localStepMax = stepMax;
1061
1062 if ((localPoint[2] < unplaced.fZPlanes[0] + kTolerance) && localDirection[2] <= 0) {
1063 distance = InfinityLength<Real_v>();
1064 return;
1065 }
1066 if ((localPoint[2] > unplaced.fZPlanes[unplaced.fZSegments.size()] - kTolerance) && localDirection[2] >= 0) {
1067 distance = InfinityLength<Real_v>();
1068 return;
1069 }
1070
1071
1072
1073 Inside_t insideState;
1074 Inside(unplaced, localPoint, insideState);
1075 if (insideState == kInside) {
1076 distance = Real_v(-1.);
1077 return;
1078 }
1079
1080 bool inBounds;
1081 Precision tubeDistance = 0.;
1082 {
1083 Vector3D<Precision> boundsPoint(localPoint[0], localPoint[1], localPoint[2] - unplaced.fBoundingTubeOffset);
1084 HasInnerRadiiTraits<innerRadiiT>::TubeKernels::template Contains<>(unplaced.fBoundingTube, boundsPoint, inBounds);
1085
1086
1087
1088 if (!inBounds) {
1089
1090
1091 HasInnerRadiiTraits<innerRadiiT>::TubeKernels::template DistanceToIn<>(
1092 unplaced.fBoundingTube, boundsPoint, localDirection, localStepMax, tubeDistance);
1093 if (tubeDistance == InfinityLength<Precision>()) {
1094 distance = InfinityLength<Real_v>();
1095 return;
1096 }
1097 }
1098 }
1099
1100 int zIndex = FindZSegment<Precision>(unplaced, localPoint[2]);
1101 const int zMax = unplaced.fZSegments.size();
1102
1103
1104 zIndex = zIndex < 0 ? 0 : (zIndex >= zMax ? zMax - 1 : zIndex);
1105
1106 bool goingRight = localDirection[2] >= 0;
1107 constexpr Precision boundsTolerance = 1E-6;
1108 if (zMax > 2 && tubeDistance > boundsTolerance) {
1109
1110
1111 const Precision boundsZ = localPoint[2] + (tubeDistance - boundsTolerance) * localDirection[2];
1112 const int initialIndex = zIndex;
1113 if (goingRight) {
1114 while (zIndex + 1 < zMax && unplaced.fZPlanes[zIndex + 1] < boundsZ - kTolerance)
1115 ++zIndex;
1116 if (zIndex > initialIndex) --zIndex;
1117 } else {
1118 while (zIndex > 0 && unplaced.fZPlanes[zIndex] > boundsZ + kTolerance)
1119 --zIndex;
1120 if (zIndex < initialIndex) ++zIndex;
1121 }
1122 }
1123
1124 Precision result = InfinityLength<Precision>();
1125 if (goingRight) {
1126 for (int zSegCount = unplaced.fZSegments.size(); zIndex < zSegCount; ++zIndex) {
1127 result = DistanceToInZSegment<Precision>(unplaced, zIndex, localPoint, localDirection);
1128
1129
1130 if (result >= 0 && result < InfinityLength<Precision>()) break;
1131 }
1132 } else {
1133 for (; zIndex >= 0; --zIndex) {
1134 result = DistanceToInZSegment<Precision>(unplaced, zIndex, localPoint, localDirection);
1135
1136
1137 if (result >= 0 && result < InfinityLength<Precision>()) break;
1138 }
1139 }
1140
1141
1142
1143
1144 DistanceToEndcaps<false>(unplaced, goingRight, localPoint, localDirection, result);
1145 result = (result >= tubeDistance - boundsTolerance) ? result : vecgeom::InfinityLength<Precision>();
1146 distance = result;
1147 }
1148
1149 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1150 template <typename Real_v, bool RecordHitInfo>
1151 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToOutImpl(
1152 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction,
1153 Real_v const &stepMax, Real_v &distance, SurfaceHitView<Real_v> *hitInfo)
1154 {
1155 if constexpr (RecordHitInfo) hitInfo->Clear();
1156
1157
1158
1159 (void)stepMax;
1160 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
1161 Vector3D<Precision> localDirection(direction[0], direction[1], direction[2]);
1162
1163 const int zMax = unplaced.fZSegments.size();
1164 if ((localPoint[2] < unplaced.fZPlanes[0] - kTolerance) || (localPoint[2] > unplaced.fZPlanes[zMax] + kTolerance)) {
1165 distance = Real_v(-1.);
1166 return;
1167 }
1168
1169 Inside_t insideState;
1170 Inside(unplaced, localPoint, insideState);
1171 if (insideState == kOutside) {
1172 distance = Real_v(-1.);
1173 return;
1174 }
1175
1176 int zIndex = FindZSegment<Precision>(unplaced, localPoint[2]);
1177 zIndex = zIndex < 0 ? 0 : (zIndex >= zMax ? zMax - 1 : zIndex);
1178
1179 bool goingRight = localDirection[2] >= 0;
1180
1181 Precision result = InfinityLength<Precision>();
1182 ExitHit finalHit;
1183 int finalSegment = -1;
1184 if (goingRight) {
1185 for (; zIndex < zMax; ++zIndex) {
1186 ExitHit segmentHit;
1187 result =
1188 DistanceToOutZSegment<Precision>(unplaced, zIndex, unplaced.fZPlanes[zIndex], unplaced.fZPlanes[zIndex + 1],
1189 localPoint, localDirection, RecordHitInfo ? &segmentHit : nullptr);
1190 if (result >= 0 && result < InfinityLength<Precision>()) {
1191 if constexpr (RecordHitInfo) {
1192 finalHit = segmentHit;
1193 finalSegment = zIndex;
1194 }
1195 break;
1196 }
1197 if (unplaced.fZPlanes[zIndex] - localPoint[2] > result) break;
1198 }
1199 } else {
1200 for (; zIndex >= 0; --zIndex) {
1201 ExitHit segmentHit;
1202 result =
1203 DistanceToOutZSegment<Precision>(unplaced, zIndex, unplaced.fZPlanes[zIndex], unplaced.fZPlanes[zIndex + 1],
1204 localPoint, localDirection, RecordHitInfo ? &segmentHit : nullptr);
1205 if (result >= 0 && result < InfinityLength<Precision>()) {
1206 if constexpr (RecordHitInfo) {
1207 finalHit = segmentHit;
1208 finalSegment = zIndex;
1209 }
1210 break;
1211 }
1212 if (localPoint[2] - unplaced.fZPlanes[zIndex] > result) break;
1213 }
1214 }
1215
1216 if (Abs(localDirection[2]) > kTolerance) {
1217 bool const endcapHit = DistanceToEndcaps<true>(unplaced, goingRight, localPoint, localDirection, result);
1218 if constexpr (RecordHitInfo) {
1219 if (endcapHit) {
1220 finalHit.surface = localDirection[2] < 0. ? ExitSurface::kZMin : ExitSurface::kZMax;
1221 finalHit.face = -1;
1222 finalSegment = -1;
1223 }
1224 }
1225 }
1226
1227 if (result >= InfinityLength<Precision>()) result = 0.;
1228 distance = result;
1229 if constexpr (RecordHitInfo) {
1230 if (finalHit.surface != ExitSurface::kNone) SetExitHit(unplaced, finalSegment, finalHit, hitInfo);
1231 }
1232 }
1233
1234 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1235 template <typename Real_v>
1236 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::DistanceToOut(
1237 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction,
1238 Real_v const &stepMax, Real_v &distance, SurfaceHitView<Real_v> *hitInfo)
1239 {
1240 if (hitInfo)
1241 DistanceToOutImpl<Real_v, true>(unplaced, point, direction, stepMax, distance, hitInfo);
1242 else
1243 DistanceToOutImpl<Real_v, false>(unplaced, point, direction, stepMax, distance, nullptr);
1244 }
1245
1246 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1247 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Precision
1248 PolyhedronImplementation<innerRadiiT, phiCutoutT>::SafetyToRZOutlineSquared(UnplacedStruct_t const &unplaced,
1249 Vector3D<Precision> const &point,
1250 Precision normSign, bool &wrongSide)
1251 {
1252
1253
1254
1255 const int phiIndex = unplaced.fSideCount > 64 ? FindPhiSegment<Precision>(unplaced, point) : -1;
1256 Precision rzRadius = 0.;
1257 if (phiIndex >= 0) {
1258 const PhiMidTrig trig = unplaced.fPhiMid[phiIndex];
1259 rzRadius = Max(Precision(0.), point.x() * trig.cosMid + point.y() * trig.sinMid);
1260 } else {
1261 for (int i = 0; i < unplaced.fSideCount; ++i) {
1262 const PhiMidTrig trig = unplaced.fPhiMid[i];
1263 rzRadius = Max(rzRadius, point.x() * trig.cosMid + point.y() * trig.sinMid);
1264 }
1265 }
1266 const Precision z = point.z();
1267
1268
1269
1270
1271
1272
1273 const int numCorners = int(unplaced.fRZOutline.size());
1274
1275 Precision best = InfinityLength<Precision>();
1276
1277
1278
1279 bool contains = false;
1280 RZOutlineEntry entry0 = unplaced.fRZOutline[0];
1281 for (int k = 0; k < numCorners; ++k) {
1282 const int k1 = (k + 1 == numCorners) ? 0 : k + 1;
1283 const RZOutlineEntry entry1 = unplaced.fRZOutline[k1];
1284 const Precision r0 = entry0.r, z0 = entry0.z;
1285 const Precision r1 = entry1.r, z1 = entry1.z;
1286
1287 if ((z0 > z) != (z1 > z)) {
1288 const Precision rIntercept = r0 + (z - z0) / (z1 - z0) * (r1 - r0);
1289 if (rzRadius < rIntercept) contains = !contains;
1290 }
1291
1292
1293
1294
1295 const Precision zEdgeMin = Min(z0, z1), zEdgeMax = Max(z0, z1);
1296 Precision dzBound = Precision(0.);
1297 if (z < zEdgeMin) {
1298 dzBound = zEdgeMin - z;
1299 } else if (z > zEdgeMax) {
1300 dzBound = z - zEdgeMax;
1301 }
1302 if (dzBound * dzBound > best) {
1303 entry0 = entry1;
1304 continue;
1305 }
1306
1307 const Precision length = entry0.edgeLength;
1308
1309 if (length > Precision(0.) && (r0 > Precision(0.) || r1 > Precision(0.))) {
1310 const Precision rS = entry0.edgeRS, zS = entry0.edgeZS;
1311 const Precision rNorm = zS, zNorm = -rS;
1312 const Precision drp = rzRadius - r0, dzp = z - z0;
1313 const Precision norm = drp * rNorm + dzp * zNorm;
1314 if (normSign * norm > -Precision(0.5) * kTolerance) {
1315 const Precision q = drp * rS + dzp * zS;
1316 Precision distOut2 = Precision(0.);
1317 if (q < Precision(0.)) {
1318 distOut2 = q * q;
1319 } else if (q > length) {
1320 distOut2 = (q - length) * (q - length);
1321 }
1322 const Precision d2 = norm * norm + distOut2;
1323 if (d2 < best) best = d2;
1324 }
1325 }
1326 entry0 = entry1;
1327 }
1328
1329
1330
1331 wrongSide = ((normSign > Precision(0.)) ? contains : !contains) && best > kTolerance * kTolerance;
1332 return best;
1333 }
1334
1335 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1336 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Precision
1337 PolyhedronImplementation<innerRadiiT, phiCutoutT>::SafetyToFiniteFacesSquared(UnplacedStruct_t const &unplaced,
1338 Vector3D<Precision> const &point,
1339 int phiIndex, bool pointInside)
1340 {
1341
1342
1343
1344
1345 Precision result = InfinityLength<Precision>();
1346 const int nz = unplaced.fZSegments.size();
1347 const int start = Max(0, Min(nz - 1, FindZSegment(unplaced, point.z())));
1348
1349
1350 for (int iz = start; iz < nz; ++iz) {
1351
1352
1353 int segmentPhi = phiIndex, surface;
1354 result = Min(result, SafetyToZSegmentSquared(unplaced, iz, segmentPhi, point, pointInside, surface));
1355 const Precision dz = unplaced.fZPlanes[iz + 1] - point.z();
1356 if (dz * dz > result) break;
1357 }
1358 for (int iz = start - 1; iz >= 0; --iz) {
1359 int segmentPhi = phiIndex, surface;
1360 result = Min(result, SafetyToZSegmentSquared(unplaced, iz, segmentPhi, point, pointInside, surface));
1361 const Precision dz = point.z() - unplaced.fZPlanes[iz];
1362 if (dz * dz > result) break;
1363 }
1364 if (phiIndex >= 0) {
1365 int cap;
1366 SafetyToEndcapsSquared(unplaced, point, result, cap);
1367 }
1368 return result;
1369 }
1370
1371 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1372 template <typename Real_v>
1373 VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::SafetyToIn(
1374 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, Real_v &safety)
1375 {
1376 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
1377
1378
1379
1380
1381 const bool useOutline = unplaced.fPhiDelta <= Precision(unplaced.fSideCount) * kHalfPi;
1382 if (!unplaced.fHasPhiCutout && useOutline) {
1383 bool wrongSide;
1384 const Precision result = SafetyToRZOutlineSquared(unplaced, localPoint, Precision(1.), wrongSide);
1385 safety = wrongSide ? Real_v(-1.) : Sqrt(result);
1386 return;
1387 }
1388
1389 const int phiIndex = FindPhiSegment<Precision>(unplaced, localPoint);
1390 if (phiIndex >= 0) {
1391
1392
1393
1394
1395
1396 bool wrongSide;
1397 const Precision result = SafetyToRZOutlineSquared(unplaced, localPoint, Precision(1.), wrongSide);
1398 if (wrongSide || useOutline) {
1399 safety = wrongSide ? Real_v(-1.) : Sqrt(result);
1400 return;
1401 }
1402 }
1403
1404 safety = Sqrt(SafetyToFiniteFacesSquared(unplaced, localPoint, phiIndex, false));
1405 }
1406
1407 template <Polyhedron::EInnerRadii innerRadiiT, Polyhedron::EPhiCutout phiCutoutT>
1408 template <typename Real_v>
1409 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PolyhedronImplementation<innerRadiiT, phiCutoutT>::SafetyToOut(
1410 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point, Real_v &safety)
1411 {
1412 Vector3D<Precision> localPoint(point[0], point[1], point[2]);
1413
1414 const bool useOutline = unplaced.fPhiDelta <= Precision(unplaced.fSideCount) * kHalfPi;
1415 if (!unplaced.fHasPhiCutout) {
1416 bool wrongSide;
1417 Precision result = SafetyToRZOutlineSquared(unplaced, localPoint, Precision(-1.), wrongSide);
1418 if (!wrongSide && !useOutline)
1419 result = SafetyToFiniteFacesSquared(unplaced, localPoint, FindPhiSegment(unplaced, localPoint), true);
1420 safety = wrongSide ? Real_v(-1.) : Sqrt(result);
1421 return;
1422 }
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435 const Precision phiSafety = unplaced.fPhiWedge.SafetyToOut(localPoint);
1436 if (phiSafety < Precision(0.)) {
1437 safety = Real_v(-1.);
1438 return;
1439 }
1440 bool rzWrongSide;
1441 const Precision rzResult = SafetyToRZOutlineSquared(unplaced, localPoint, Precision(-1.), rzWrongSide);
1442 if (rzWrongSide) {
1443 safety = Real_v(-1.);
1444 return;
1445 }
1446 if (!useOutline) {
1447 const int phiIndex = FindPhiSegment<Precision>(unplaced, localPoint);
1448 if (phiIndex < 0) {
1449 safety = Real_v(-1.);
1450 return;
1451 }
1452 safety = Sqrt(SafetyToFiniteFacesSquared(unplaced, localPoint, phiIndex, true));
1453 return;
1454 }
1455 Precision phiSquared = phiSafety * phiSafety;
1456
1457
1458
1459 if (unplaced.fPhiDelta > kPi && localPoint.Dot(unplaced.fPhiWedge.GetAlong1()) < 0. &&
1460 localPoint.Dot(unplaced.fPhiWedge.GetAlong2()) < 0.)
1461 phiSquared = localPoint.Perp2();
1462 safety = Sqrt(Min(rzResult, phiSquared));
1463 }
1464
1465 }
1466 }
1467
1468 #endif