File indexing completed on 2026-09-22 09:10:20
0001
0002
0003
0004 #ifndef VECGEOM_VOLUMES_KERNEL_TUBEIMPLEMENTATION_H_
0005 #define VECGEOM_VOLUMES_KERNEL_TUBEIMPLEMENTATION_H_
0006
0007 #include "VecGeom/base/Vector3D.h"
0008 #include "VecGeom/volumes/kernel/GenericKernels.h"
0009 #include "VecGeom/volumes/kernel/shapetypes/TubeTypes.h"
0010 #include "VecGeom/volumes/TubeStruct.h"
0011 #include "VecGeom/volumes/Wedge.h"
0012 #include <cstdio>
0013
0014 #define TUBE_SAFETY_OLD
0015
0016
0017 namespace vecgeom {
0018
0019 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE(struct, TubeImplementation, typename);
0020
0021 inline namespace VECGEOM_IMPL_NAMESPACE {
0022
0023 namespace TubeUtilities {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 template <typename Real_v, typename ShapeType, typename UnplacedVolumeType, bool onSurfaceT, bool includeSurface = true>
0059 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PointInCyclicalSector(UnplacedVolumeType const &volume,
0060 Real_v const &x, Real_v const &y,
0061 typename vecCore::Mask_v<Real_v> &ret)
0062 {
0063 using namespace ::vecgeom::TubeTypes;
0064
0065
0066
0067 Real_v startx(volume.fAlongPhi1x);
0068 Real_v starty(volume.fAlongPhi1y);
0069
0070 Real_v endx(volume.fAlongPhi2x);
0071 Real_v endy(volume.fAlongPhi2y);
0072
0073 bool smallerthanpi;
0074
0075 if (SectorType<ShapeType>::value == kUnknownAngle)
0076 smallerthanpi = volume.fDphi <= M_PI;
0077 else
0078 smallerthanpi = SectorType<ShapeType>::value == kOnePi || SectorType<ShapeType>::value == kSmallerThanPi;
0079
0080 Real_v startCheck = (-x * starty + y * startx);
0081 Real_v endCheck = (-endx * y + endy * x);
0082
0083 if (onSurfaceT) {
0084
0085 ret = (Abs(startCheck) <= kHalfTolerance) || (Abs(endCheck) <= kHalfTolerance);
0086 } else {
0087 if (smallerthanpi) {
0088 if (includeSurface)
0089 ret = (startCheck >= -kHalfTolerance) & (endCheck >= -kHalfTolerance);
0090 else
0091 ret = (startCheck >= kHalfTolerance) & (endCheck >= kHalfTolerance);
0092 } else {
0093 if (includeSurface)
0094 ret = (startCheck >= -kHalfTolerance) || (endCheck >= -kHalfTolerance);
0095 else
0096 ret = (startCheck >= kHalfTolerance) || (endCheck >= kHalfTolerance);
0097 }
0098 }
0099 }
0100
0101 template <typename Real_v, typename UnplacedStruct_t, typename TubeType, bool LargestSolution, bool insectorCheck>
0102 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void CircleTrajectoryIntersection(
0103 Real_v const &b, Real_v const &c, UnplacedStruct_t const &tube, Vector3D<Real_v> const &pos,
0104 Vector3D<Real_v> const &dir, Real_v &dist, typename vecCore::Mask_v<Real_v> &ok)
0105 {
0106 using namespace ::vecgeom::TubeTypes;
0107
0108 using Bool_v = vecCore::Mask_v<Real_v>;
0109
0110 Real_v delta = b * b - c;
0111 ok = delta > Real_v(0.);
0112 if (LargestSolution) ok |= delta == Real_v(0.);
0113
0114 vecCore::MaskedAssign(delta, !ok, Real_v(0.));
0115 delta = Sqrt(delta);
0116 if (!LargestSolution) delta = -delta;
0117
0118 dist = -b + delta;
0119
0120
0121
0122
0123 ok &= dist >= -2 * kTolerance;
0124 if (vecCore::EarlyReturnAllowed() && vecCore::MaskEmpty(ok)) return;
0125
0126 if (insectorCheck) {
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144 Real_v hitz = pos.z() + dist * dir.z();
0145 ok &= (Abs(hitz) <= tube.fZ);
0146 if (vecCore::EarlyReturnAllowed() && vecCore::MaskEmpty(ok)) return;
0147
0148 if (checkPhiTreatment<TubeType>(tube)) {
0149 Bool_v insector(false);
0150 Real_v hitx = pos.x() + dist * dir.x();
0151 Real_v hity = pos.y() + dist * dir.y();
0152 PointInCyclicalSector<Real_v, TubeType, UnplacedStruct_t, false, true>(tube, hitx, hity, insector);
0153
0154
0155 ok &= insector;
0156 }
0157 }
0158 }
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 template <typename Real_v>
0192 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Real_v PerpDist2D(Real_v const &px, Real_v const &py, Real_v const &vx,
0193 Real_v const &vy)
0194 {
0195 return px * vy - py * vx;
0196 }
0197
0198
0199
0200
0201 template <typename Real_v, typename UnplacedStruct_t, typename TubeType, bool inside>
0202 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PhiPlaneSafety(UnplacedStruct_t const &tube,
0203 Vector3D<Real_v> const &pos, Real_v &safety)
0204 {
0205 using namespace ::vecgeom::TubeTypes;
0206
0207 if ((SectorType<TubeType>::value == kUnknownAngle && tube.fDphi > M_PI) ||
0208 (SectorType<TubeType>::value == kBiggerThanPi)) {
0209 safety = Sqrt(pos.x() * pos.x() + pos.y() * pos.y());
0210 } else {
0211 safety = kInfLength;
0212 }
0213
0214 Real_v phi1 = PerpDist2D<Real_v>(pos.x(), pos.y(), Real_v(tube.fAlongPhi1x), Real_v(tube.fAlongPhi1y));
0215 if (inside) phi1 *= -1;
0216
0217 if (SectorType<TubeType>::value == kOnePi) {
0218 auto absphi1 = Abs(phi1);
0219 vecCore::MaskedAssign(safety, absphi1 > kHalfTolerance, absphi1);
0220 return;
0221 }
0222
0223
0224 vecCore::MaskedAssign(safety,
0225 phi1 > -kHalfTolerance &&
0226 phi1 < safety,
0227 phi1);
0228
0229 Real_v phi2 = PerpDist2D<Real_v>(pos.x(), pos.y(), Real_v(tube.fAlongPhi2x), Real_v(tube.fAlongPhi2y));
0230 if (!inside) phi2 *= -1;
0231
0232
0233 vecCore::MaskedAssign(safety,
0234 phi2 > -kHalfTolerance &&
0235 phi2 < safety,
0236 phi2);
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254 template <typename Real_v, typename UnplacedStruct_t, typename TubeType, bool PositiveDirectionOfPhiVector,
0255 bool insectorCheck>
0256 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void PhiPlaneTrajectoryIntersection(
0257 Precision alongX, Precision alongY, Precision normalX, Precision normalY, UnplacedStruct_t const &tube,
0258 Vector3D<Real_v> const &pos, Vector3D<Real_v> const &dir, Real_v &dist, typename vecCore::Mask_v<Real_v> &ok)
0259 {
0260
0261 dist = kInfLength;
0262
0263
0264
0265
0266 Real_v dirDotNorm = dir.x() * normalX + dir.y() * normalY;
0267 if (insectorCheck)
0268 ok = (dirDotNorm > Real_v(0.));
0269 else
0270 ok = (dirDotNorm < Real_v(0.));
0271
0272
0273
0274 Real_v dirDotXY = (dir.y() * alongX - dir.x() * alongY);
0275 dist = (alongY * pos.x() - alongX * pos.y()) / NonZero(dirDotXY);
0276
0277 ok &= (dist * Abs(dirDotNorm)) > -kHalfTolerance;
0278
0279
0280 if (insectorCheck) {
0281 Real_v hitx = pos.x() + dist * dir.x();
0282 Real_v hity = pos.y() + dist * dir.y();
0283 Real_v hitz = pos.z() + dist * dir.z();
0284 Real_v r2 = hitx * hitx + hity * hity;
0285 ok &= Abs(hitz) <= tube.fTolOz && (r2 >= tube.fTolOrmin2) && (r2 <= tube.fTolOrmax2);
0286
0287
0288
0289
0290 if (PositiveDirectionOfPhiVector) {
0291 ok = ok && (hitx * alongX + hity * alongY) > Real_v(0.);
0292 }
0293 } else {
0294 if (PositiveDirectionOfPhiVector) {
0295 Real_v hitx = pos.x() + dist * dir.x();
0296 Real_v hity = pos.y() + dist * dir.y();
0297 ok = ok && (hitx * alongX + hity * alongY) >= Real_v(0.);
0298 }
0299 }
0300 }
0301
0302 template <typename Real_v, typename UnplacedStruct_t, bool ForInnerSurface>
0303 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE typename vecCore::Mask_v<Real_v> IsOnTubeSurface(
0304 UnplacedStruct_t const &tube, Vector3D<Real_v> const &point)
0305 {
0306 const Real_v rho = point.Perp2();
0307 if (ForInnerSurface) {
0308 return (rho >= tube.fTolOrmin2) && (rho <= tube.fTolIrmin2) && (Abs(point.z()) < (tube.fZ + kTolerance));
0309 } else {
0310 return (rho >= tube.fTolIrmax2) && (rho <= tube.fTolOrmax2) && (Abs(point.z()) < (tube.fZ + kTolerance));
0311 }
0312 }
0313
0314 template <typename Real_v, bool ForInnerSurface>
0315 VECCORE_ATT_HOST_DEVICE Vector3D<Real_v> GetNormal(Vector3D<Real_v> const &point)
0316 {
0317 Vector3D<Real_v> norm(0., 0., 0.);
0318 if (ForInnerSurface) {
0319 norm.Set(-point.x(), -point.y(), 0.);
0320 } else {
0321 norm.Set(point.x(), point.y(), 0.);
0322 }
0323 return norm;
0324 }
0325
0326 template <typename Real_v, typename UnplacedStruct_t, bool ForInnerSurface>
0327 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE typename vecCore::Mask_v<Real_v> IsMovingInsideTubeSurface(
0328 UnplacedStruct_t const &tube, Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction)
0329 {
0330 return IsOnTubeSurface<Real_v, UnplacedStruct_t, ForInnerSurface>(tube, point) &&
0331 (direction.Dot(GetNormal<Real_v, ForInnerSurface>(point)) < -0.5 * int(!ForInnerSurface) * kTolerance);
0332 }
0333
0334 }
0335
0336 template <typename T>
0337 class SPlacedTube;
0338 template <typename T>
0339 class SUnplacedTube;
0340 template <typename tubeTypeT>
0341 struct TubeImplementation {
0342
0343 using UnplacedStruct_t = ::vecgeom::TubeStruct<Precision>;
0344 using UnplacedVolume_t = SUnplacedTube<tubeTypeT>;
0345 using PlacedShape_t = SPlacedTube<UnplacedVolume_t>;
0346
0347
0348 template <typename Real_v, bool ForInside>
0349 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void GenericKernelForContainsAndInside(
0350 UnplacedStruct_t const &tube, Vector3D<Real_v> const &point, typename vecCore::Mask_v<Real_v> &completelyinside,
0351 typename vecCore::Mask_v<Real_v> &completelyoutside)
0352 {
0353 using namespace ::vecgeom::TubeTypes;
0354 using Bool_v = vecCore::Mask_v<Real_v>;
0355
0356
0357 Real_v absz = Abs(point[2]);
0358 completelyoutside = absz > MakePlusTolerant<true>(tube.fZ);
0359 if (ForInside) {
0360 completelyinside = absz < MakeMinusTolerant<true>(tube.fZ);
0361 }
0362 if (vecCore::EarlyReturnAllowed()) {
0363 if (vecCore::MaskFull(completelyoutside)) {
0364 return;
0365 }
0366 }
0367
0368
0369 Real_v r2 = point.x() * point.x() + point.y() * point.y();
0370
0371
0372 completelyoutside |= r2 > MakePlusTolerantSquare<true>(tube.fRmax);
0373 if (ForInside) {
0374 completelyinside &= r2 < MakeMinusTolerantSquare<true>(tube.fRmax);
0375 }
0376 if (vecCore::EarlyReturnAllowed()) {
0377 if (vecCore::MaskFull(completelyoutside)) {
0378 return;
0379 }
0380 }
0381
0382
0383 if (checkRminTreatment<tubeTypeT>(tube)) {
0384 completelyoutside |= r2 <= MakeMinusTolerantSquare<true>(tube.fRmin);
0385 if (ForInside) {
0386 completelyinside &= r2 > MakePlusTolerantSquare<true>(tube.fRmin);
0387 }
0388 if (vecCore::EarlyReturnAllowed()) {
0389 if (vecCore::MaskFull(completelyoutside)) {
0390 return;
0391 }
0392 }
0393 }
0394
0395 if (checkPhiTreatment<tubeTypeT>(tube)) {
0396 Bool_v completelyoutsidephi(false);
0397 Bool_v completelyinsidephi(false);
0398 tube.fPhiWedge.GenericKernelForContainsAndInside<Real_v, true>(point, completelyinsidephi, completelyoutsidephi);
0399
0400 completelyoutside |= completelyoutsidephi;
0401 if (ForInside) completelyinside &= completelyinsidephi;
0402 }
0403 }
0404
0405 template <typename Real_v>
0406 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Contains(UnplacedStruct_t const &tube,
0407 Vector3D<Real_v> const &point,
0408 typename vecCore::Mask_v<Real_v> &contains)
0409 {
0410 using Bool_v = vecCore::Mask_v<Real_v>;
0411 Bool_v unused, outside;
0412 GenericKernelForContainsAndInside<Real_v, false>(tube, point, unused, outside);
0413 contains = !outside;
0414 }
0415
0416 template <typename Real_v, typename Inside_t>
0417 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Inside(UnplacedStruct_t const &tube,
0418 Vector3D<Real_v> const &point, Inside_t &inside)
0419 {
0420 using Bool_v = vecCore::Mask_v<Real_v>;
0421 using InsideBool_v = vecCore::Mask_v<Inside_t>;
0422 Bool_v completelyinside, completelyoutside;
0423 GenericKernelForContainsAndInside<Real_v, true>(tube, point, completelyinside, completelyoutside);
0424 inside = EInside::kSurface;
0425 vecCore::MaskedAssign(inside, (InsideBool_v)completelyoutside, Inside_t(EInside::kOutside));
0426 vecCore::MaskedAssign(inside, (InsideBool_v)completelyinside, Inside_t(EInside::kInside));
0427 }
0428
0429 template <typename Real_v>
0430 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToIn(UnplacedStruct_t const &tube,
0431 Vector3D<Real_v> const &pointt,
0432 Vector3D<Real_v> const &dir,
0433 Real_v const &stepMax, Real_v &distance)
0434 {
0435 Vector3D<Real_v> point = pointt;
0436 Real_v ptDist = point.Mag();
0437 Real_v distToMove(0.);
0438 using Bool_v = vecCore::Mask_v<Real_v>;
0439 Precision order = 100.;
0440 Bool_v cond = (ptDist > order * tube.fMaxVal);
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452 vecCore__MaskedAssignFunc(distToMove, cond, (ptDist - Real_v(order * tube.fMaxVal)));
0453 vecCore__MaskedAssignFunc(point, cond, point + distToMove * dir);
0454 DistanceToInKernel<Real_v>(tube, point, dir, stepMax, distance);
0455 distance += distToMove;
0456 }
0457
0458 template <typename Real_v>
0459 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToInKernel(UnplacedStruct_t const &tube,
0460 Vector3D<Real_v> const &point,
0461 Vector3D<Real_v> const &dir,
0462 Real_v const &stepMax, Real_v &distance)
0463 {
0464 (void)stepMax;
0465 using namespace TubeUtilities;
0466 using namespace ::vecgeom::TubeTypes;
0467
0468 using Bool_v = vecCore::Mask_v<Real_v>;
0469
0470 Bool_v done(false);
0471
0472
0473 distance = kInfLength;
0474
0475
0476 Real_v distz = Abs(point.z()) - tube.fZ;
0477 done |= distz > kHalfTolerance && point.z() * dir.z() >= 0;
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487 Real_v rsq = point.x() * point.x() + point.y() * point.y();
0488 Real_v rdotn = point.x() * dir.x() + point.y() * dir.y();
0489 done |= rsq > tube.fTolIrmax2 && rdotn >= 0;
0490 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0491
0492
0493
0494 vecCore__MaskedAssignFunc(distance, !done, Real_v(-1.0));
0495
0496
0497 Bool_v inside = distz < -kHalfTolerance;
0498
0499 inside &= rsq < tube.fTolIrmax2;
0500 if (checkRminTreatment<tubeTypeT>(tube)) {
0501 inside &= rsq > tube.fTolIrmin2;
0502 }
0503 if (checkPhiTreatment<tubeTypeT>(tube) && !vecCore::MaskEmpty(inside)) {
0504 Bool_v insector;
0505 PointInCyclicalSector<Real_v, tubeTypeT, UnplacedStruct_t, false, false>(tube, point.x(), point.y(), insector);
0506 inside &= insector;
0507
0508
0509 }
0510 done |= inside;
0511 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0512
0513
0514
0515 vecCore::MaskedAssign(distance, !done, Real_v(kInfLength));
0516
0517 distz /= NonZeroAbs(dir.z());
0518
0519
0520 Real_v hitx = point.x() + distz * dir.x();
0521 Real_v hity = point.y() + distz * dir.y();
0522 Real_v r2 = hitx * hitx + hity * hity;
0523 Bool_v okz = distz > -kHalfTolerance && (point.z() * dir.z() < 0);
0524
0525 okz &= (r2 <= tube.fRmax2);
0526 if (checkRminTreatment<tubeTypeT>(tube)) {
0527 okz &= (tube.fRmin2 <= r2);
0528 }
0529 if (checkPhiTreatment<tubeTypeT>(tube) && !vecCore::MaskEmpty(okz)) {
0530 Bool_v insector;
0531 PointInCyclicalSector<Real_v, tubeTypeT, UnplacedStruct_t, false>(tube, hitx, hity, insector);
0532 okz &= insector;
0533
0534
0535 }
0536 vecCore::MaskedAssign(distance, !done && okz, distz);
0537 done |= okz;
0538
0539
0540 Bool_v isOnSurface = IsOnTubeSurface<Real_v, UnplacedStruct_t, false>(tube, point);
0541 Bool_v movingInsideR = dir.Dot(GetNormal<Real_v, false>(point)) < -0.5 * kTolerance;
0542 done |= isOnSurface && !movingInsideR;
0543 vecCore::MaskedAssign(distance, isOnSurface && !movingInsideR, kInfLength);
0544 if (vecCore::MaskFull(done)) return;
0545
0546 Bool_v isOnSurfaceAndMovingInside = isOnSurface && movingInsideR;
0547 if (checkRminTreatment<tubeTypeT>(tube)) {
0548
0549 isOnSurfaceAndMovingInside |= IsMovingInsideTubeSurface<Real_v, UnplacedStruct_t, true>(tube, point, dir);
0550 }
0551
0552 if (!checkPhiTreatment<tubeTypeT>(tube)) {
0553 vecCore__MaskedAssignFunc(distance, !done && isOnSurfaceAndMovingInside, Real_v(0.));
0554 done |= isOnSurfaceAndMovingInside;
0555 if (vecCore::MaskFull(done)) return;
0556 } else {
0557 Bool_v insector(false);
0558 PointInCyclicalSector<Real_v, tubeTypeT, UnplacedStruct_t, false>(tube, point.x(), point.y(), insector);
0559 vecCore__MaskedAssignFunc(distance, !done && insector && isOnSurfaceAndMovingInside, Real_v(0.));
0560 done |= (insector && isOnSurfaceAndMovingInside);
0561 if (vecCore::MaskFull(done)) return;
0562 }
0563
0564
0565
0566
0567
0568
0569
0570 Real_v invnsq = Real_v(1.) / NonZero(Real_v(1.) - dir.z() * dir.z());
0571 Real_v b = invnsq * rdotn;
0572
0573
0574
0575
0576
0577
0578
0579 Real_v crmax = invnsq * (rsq - tube.fRmax2);
0580 Real_v dist_rmax;
0581 Bool_v ok_rmax(false);
0582 CircleTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, false, true>(b, crmax, tube, point, dir,
0583 dist_rmax, ok_rmax);
0584 ok_rmax &= dist_rmax < distance;
0585 vecCore::MaskedAssign(distance, !done && ok_rmax, dist_rmax);
0586 done |= ok_rmax;
0587 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0588
0589
0590
0591
0592
0593
0594
0595 Real_v dist_rmin(-kInfLength);
0596 Bool_v ok_rmin(false);
0597 if (checkRminTreatment<tubeTypeT>(tube)) {
0598
0599
0600
0601
0602
0603
0604
0605 Real_v crmin = invnsq * (rsq - tube.fRmin2);
0606 CircleTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, true, true>(b, crmin, tube, point, dir,
0607 dist_rmin, ok_rmin);
0608 ok_rmin &= dist_rmin < distance;
0609 vecCore::MaskedAssign(distance, !done && ok_rmin, dist_rmin);
0610
0611
0612 }
0613
0614
0615
0616
0617 if (checkPhiTreatment<tubeTypeT>(tube)) {
0618
0619 Real_v dist_phi;
0620 Bool_v ok_phi;
0621 auto const &w = tube.fPhiWedge;
0622 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, SectorType<tubeTypeT>::value != kOnePi, true>(
0623 tube.fAlongPhi1x, tube.fAlongPhi1y, w.GetNormal1().x(), w.GetNormal1().y(), tube, point, dir, dist_phi,
0624 ok_phi);
0625 ok_phi &= dist_phi < distance;
0626 vecCore::MaskedAssign(distance, !done && ok_phi, dist_phi);
0627 done |= ok_phi;
0628
0629
0630
0631
0632
0633
0634
0635
0636 if (SectorType<tubeTypeT>::value != kOnePi) {
0637 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, true, true>(
0638 tube.fAlongPhi2x, tube.fAlongPhi2y, w.GetNormal2().x(), w.GetNormal2().y(), tube, point, dir, dist_phi,
0639 ok_phi);
0640 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0641 }
0642 }
0643 }
0644
0645 template <typename Real_v>
0646 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToOut(UnplacedStruct_t const &tube,
0647 Vector3D<Real_v> const &point,
0648 Vector3D<Real_v> const &dir,
0649 Real_v const &stepMax, Real_v &distance)
0650 {
0651 (void)stepMax;
0652 using namespace ::vecgeom::TubeTypes;
0653 using namespace TubeUtilities;
0654
0655 using Bool_v = vecCore::Mask_v<Real_v>;
0656
0657 distance = Real_v(-1.);
0658 Bool_v done(false);
0659
0660
0661
0662
0663
0664 Real_v distz = tube.fZ - Abs(point.z());
0665 done |= distz < -kHalfTolerance;
0666 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0667
0668 Real_v rsq = point.x() * point.x() + point.y() * point.y();
0669 Real_v rdotn = dir.x() * point.x() + dir.y() * point.y();
0670 Real_v crmax = rsq - tube.fRmax2;
0671 Real_v crmin = rsq;
0672
0673
0674 done |= crmax > Real_v(2.0 * kTolerance * tube.fRmax);
0675 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0676
0677 if (checkRminTreatment<tubeTypeT>(tube)) {
0678
0679
0680 crmin -= tube.fRmin2;
0681 done |= crmin < Real_v(-2.0 * kTolerance * tube.fRmin);
0682 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0683 }
0684
0685
0686 if (checkPhiTreatment<tubeTypeT>(tube)) {
0687 Bool_v completelyoutsidephi(false);
0688 Bool_v completelyinsidephi(false);
0689 tube.fPhiWedge.GenericKernelForContainsAndInside<Real_v, true>(point, completelyinsidephi, completelyoutsidephi);
0690
0691 done |= completelyoutsidephi;
0692 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(done)) return;
0693 }
0694
0695
0696 vecCore::MaskedAssign(distance, !done, Real_v(kInfLength));
0697
0698 Real_v invdirz = Real_v(1.) / NonZero(dir.z());
0699 distz = (Sign(dir.z()) * tube.fZ - point.z()) * invdirz;
0700 vecCore__MaskedAssignFunc(distz, dir.z() < 0, (-tube.fZ - point.z()) * invdirz);
0701 vecCore::MaskedAssign(distance, !done && Abs(invdirz) < InvdirNearParallel(tube.fRmax) && distz < distance, distz);
0702
0703
0704
0705
0706
0707
0708 Real_v invnsq = Real_v(1.) / NonZero(Real_v(1.) - dir.z() * dir.z());
0709 Real_v b = invnsq * rdotn;
0710
0711
0712
0713 bool checkTube = invnsq < tube.fZ * tube.fZ * kInvTolerance * kInvTolerance;
0714
0715
0716
0717
0718
0719 if (checkTube && checkRminTreatment<tubeTypeT>(tube)) {
0720 Real_v dist_rmin(kInfLength);
0721 Bool_v ok_rmin(false);
0722 Bool_v isOnSurface = IsOnTubeSurface<Real_v, UnplacedStruct_t, true>(tube, point);
0723 if (vecCore::MaskFull(isOnSurface)) {
0724 ok_rmin = dir.Dot(GetNormal<Real_v, true>(point)) > 0.5 * kTolerance;
0725 dist_rmin = 0.;
0726 } else {
0727 crmin *= invnsq;
0728 CircleTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, false, false>(b, crmin, tube, point, dir,
0729 dist_rmin, ok_rmin);
0730 }
0731 vecCore::MaskedAssign(distance, ok_rmin && dist_rmin < distance, dist_rmin);
0732 }
0733
0734
0735
0736
0737
0738 Real_v dist_rmax(kInfLength);
0739 Bool_v ok_rmax(false);
0740 if (checkTube) {
0741 crmax *= invnsq;
0742 CircleTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, true, false>(b, crmax, tube, point, dir,
0743 dist_rmax, ok_rmax);
0744 vecCore::MaskedAssign(distance, ok_rmax && dist_rmax < distance, dist_rmax);
0745 }
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758 if (checkPhiTreatment<tubeTypeT>(tube)) {
0759 Real_v dist_phi(kInfLength);
0760 Bool_v ok_phi(false);
0761
0762 auto const &w = tube.fPhiWedge;
0763 if (SectorType<tubeTypeT>::value == kSmallerThanPi) {
0764
0765 Precision normal1X = w.GetNormal1().x();
0766 Precision normal1Y = w.GetNormal1().y();
0767 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, false, false>(
0768 tube.fAlongPhi1x, tube.fAlongPhi1y, normal1X, normal1Y, tube, point, dir, dist_phi, ok_phi);
0769 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0770
0771 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, false, false>(
0772 tube.fAlongPhi2x, tube.fAlongPhi2y, w.GetNormal2().x(), w.GetNormal2().y(), tube, point, dir, dist_phi,
0773 ok_phi);
0774 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0775 } else if (SectorType<tubeTypeT>::value == kOnePi) {
0776 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, false, false>(
0777 tube.fAlongPhi2x, tube.fAlongPhi2y, w.GetNormal2().x(), w.GetNormal2().y(), tube, point, dir, dist_phi,
0778 ok_phi);
0779 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0780 } else {
0781
0782
0783 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, true, false>(
0784 tube.fAlongPhi1x, tube.fAlongPhi1y, w.GetNormal1().x(), w.GetNormal1().y(), tube, point, dir, dist_phi,
0785 ok_phi);
0786 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0787
0788 PhiPlaneTrajectoryIntersection<Real_v, UnplacedStruct_t, tubeTypeT, true, false>(
0789 tube.fAlongPhi2x, tube.fAlongPhi2y, w.GetNormal2().x(), w.GetNormal2().y(), tube, point, dir, dist_phi,
0790 ok_phi);
0791 vecCore::MaskedAssign(distance, ok_phi && dist_phi < distance, dist_phi);
0792 }
0793 }
0794 return;
0795 }
0796
0797
0798
0799 template <typename Real_v>
0800 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyAssign(Real_v safety, Real_v &positiveSafety,
0801 Real_v &negativeSafety)
0802 {
0803 vecCore::MaskedAssign(positiveSafety, safety >= Real_v(0.) && safety < positiveSafety, safety);
0804 vecCore::MaskedAssign(negativeSafety, safety <= Real_v(0.) && safety > negativeSafety, safety);
0805 }
0806
0807
0808
0809
0810
0811
0812 template <typename Real_v>
0813 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyKernel(UnplacedStruct_t const &tube,
0814 Vector3D<Real_v> const &point, Real_v &safePos,
0815 Real_v &safeNeg)
0816 {
0817
0818
0819 using namespace ::vecgeom::TubeTypes;
0820 using namespace TubeUtilities;
0821
0822 safePos = kInfLength;
0823 safeNeg = -safePos;
0824
0825 Real_v safez = Abs(point.z()) - tube.fZ;
0826 SafetyAssign(safez, safePos, safeNeg);
0827
0828 Real_v r = Sqrt(point.x() * point.x() + point.y() * point.y());
0829 Real_v safermax = r - tube.fRmax;
0830 SafetyAssign(safermax, safePos, safeNeg);
0831
0832 if (checkRminTreatment<tubeTypeT>(tube)) {
0833 Real_v safermin = tube.fRmin - r;
0834 SafetyAssign(safermin, safePos, safeNeg);
0835 }
0836
0837 if (checkPhiTreatment<tubeTypeT>(tube)) {
0838 Real_v safephi;
0839 PhiPlaneSafety<Real_v, UnplacedStruct_t, tubeTypeT, false>(tube, point, safephi);
0840 SafetyAssign(safephi, safePos, safeNeg);
0841 }
0842 }
0843
0844 template <typename Real_v>
0845 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToIn(UnplacedStruct_t const &tube,
0846 Vector3D<Real_v> const &point, Real_v &safety)
0847 {
0848
0849 #ifdef TUBE_SAFETY_OLD
0850 SafetyToInOld(tube, point, safety);
0851 #else
0852 Real_v safetyInsidePoint, safetyOutsidePoint;
0853 SafetyKernel(tube, point, safetyOutsidePoint, safetyInsidePoint);
0854
0855
0856
0857
0858 safety = vecCore::Blend(safetyOutsidePoint == InfinityLength<Real_v>(), safetyInsidePoint, safetyOutsidePoint);
0859 #endif
0860 }
0861
0862 template <typename Real_v>
0863 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToOut(UnplacedStruct_t const &tube,
0864 Vector3D<Real_v> const &point, Real_v &safety)
0865 {
0866 #ifdef TUBE_SAFETY_OLD
0867 SafetyToOutOld(tube, point, safety);
0868 #else
0869 Real_v safetyInsidePoint, safetyOutsidePoint;
0870 SafetyKernel<Real_v>(tube, point, safetyOutsidePoint, safetyInsidePoint);
0871
0872
0873
0874
0875 safety = -vecCore::Blend(safetyOutsidePoint == InfinityLength<Real_v>(), safetyInsidePoint, safetyOutsidePoint);
0876 #endif
0877 }
0878
0879 template <typename Real_v>
0880 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToInOld(UnplacedStruct_t const &tube,
0881 Vector3D<Real_v> const &point, Real_v &safety)
0882 {
0883 using namespace ::vecgeom::TubeTypes;
0884 using namespace TubeUtilities;
0885
0886 using Bool_v = vecCore::Mask_v<Real_v>;
0887
0888 safety = Abs(point.z()) - tube.fZ;
0889
0890 Real_v r = Sqrt(point.x() * point.x() + point.y() * point.y());
0891 Real_v safermax = r - tube.fRmax;
0892 vecCore::MaskedAssign(safety, safermax > safety, safermax);
0893
0894 if (checkRminTreatment<tubeTypeT>(tube)) {
0895 Real_v safermin = tube.fRmin - r;
0896 vecCore::MaskedAssign(safety, safermin > safety, safermin);
0897 }
0898
0899 if (checkPhiTreatment<tubeTypeT>(tube)) {
0900 Bool_v insector;
0901 PointInCyclicalSector<Real_v, tubeTypeT, UnplacedStruct_t, false, false>(tube, point.x(), point.y(), insector);
0902 if (vecCore::EarlyReturnAllowed() && vecCore::MaskFull(insector)) return;
0903
0904 Real_v safephi;
0905 PhiPlaneSafety<Real_v, UnplacedStruct_t, tubeTypeT, false>(tube, point, safephi);
0906 vecCore::MaskedAssign(safety, !insector && safephi < kInfLength && safephi > safety, safephi);
0907 }
0908 }
0909
0910 template <typename Real_v>
0911 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToOutOld(UnplacedStruct_t const &tube,
0912 Vector3D<Real_v> const &point, Real_v &safety)
0913 {
0914 using namespace ::vecgeom::TubeTypes;
0915 using namespace TubeUtilities;
0916
0917 safety = tube.fZ - Abs(point.z());
0918 Real_v r = Sqrt(point.x() * point.x() + point.y() * point.y());
0919 Real_v safermax = tube.fRmax - r;
0920 vecCore::MaskedAssign(safety, safermax < safety, safermax);
0921
0922 if (checkRminTreatment<tubeTypeT>(tube)) {
0923 Real_v safermin = r - tube.fRmin;
0924 vecCore::MaskedAssign(safety, safermin < safety, safermin);
0925 }
0926
0927 if (checkPhiTreatment<tubeTypeT>(tube)) {
0928
0929 Real_v safephi = tube.fPhiWedge.SafetyToOut<Real_v>(point);
0930 vecCore::MaskedAssign(safety, safephi < safety, safephi);
0931 }
0932 }
0933
0934 template <typename Real_v>
0935 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Vector3D<Real_v> ApproxSurfaceNormalKernel(
0936 UnplacedStruct_t const &unplaced, Vector3D<Real_v> const &point)
0937 {
0938
0939 Vector3D<Real_v> norm(0., 0., 0.);
0940 Real_v radius = point.Perp();
0941 Real_v distRMax = vecCore::math::Abs(radius - unplaced.fRmax);
0942 Real_v distRMin = kInfLength;
0943 vecCore__MaskedAssignFunc(distRMax, distRMax < Real_v(0.), InfinityLength<Real_v>());
0944 if (unplaced.fRmin) {
0945 distRMin = Abs(unplaced.fRmin - radius);
0946 vecCore__MaskedAssignFunc(distRMin, distRMin < Real_v(0.), InfinityLength<Real_v>());
0947 }
0948 Real_v distMin = Min(distRMin, distRMax);
0949
0950 Real_v distPhi1 = kInfLength, distPhi2 = kInfLength;
0951 if (unplaced.fDphi != vecgeom::kTwoPi) {
0952 distPhi1 = point.x() * unplaced.fPhiWedge.GetNormal1().x() + point.y() * unplaced.fPhiWedge.GetNormal1().y();
0953 distPhi2 = point.x() * unplaced.fPhiWedge.GetNormal2().x() + point.y() * unplaced.fPhiWedge.GetNormal2().y();
0954
0955 vecCore__MaskedAssignFunc(distPhi1, distPhi1 < Real_v(0.), InfinityLength<Real_v>());
0956 vecCore__MaskedAssignFunc(distPhi2, distPhi2 < Real_v(0.), InfinityLength<Real_v>());
0957 distMin = Min(distMin, Min(distPhi1, distPhi2));
0958 }
0959
0960 Real_v distZ = kInfLength;
0961 vecCore__MaskedAssignFunc(distZ, point.z() < Real_v(0.), vecCore::math::Abs(point.z() + unplaced.fZ));
0962 vecCore__MaskedAssignFunc(distZ, point.z() >= Real_v(0.), vecCore::math::Abs(point.z() - unplaced.fZ));
0963 distMin = Min(distMin, distZ);
0964
0965 if (unplaced.fDphi) {
0966 Vector3D<Real_v> normal1 = unplaced.fPhiWedge.GetNormal1();
0967 Vector3D<Real_v> normal2 = unplaced.fPhiWedge.GetNormal2();
0968 vecCore__MaskedAssignFunc(norm, distMin == distPhi1, -normal1);
0969 vecCore__MaskedAssignFunc(norm, distMin == distPhi2, -normal2);
0970 }
0971
0972 vecCore__MaskedAssignFunc(norm, (distMin == distZ) && (point.z() < Real_v(0.)), Vector3D<Real_v>(0., 0., -1.));
0973 vecCore__MaskedAssignFunc(norm, (distMin == distZ) && (point.z() >= Real_v(0.)), Vector3D<Real_v>(0., 0., 1.));
0974
0975 if (vecCore::math::Abs(point.z()) < (unplaced.fZ + kTolerance)) {
0976 Vector3D<Real_v> temp = point;
0977 temp.z() = Real_v(0.);
0978 vecCore__MaskedAssignFunc(norm, distMin == distRMax, temp.Unit());
0979 if (unplaced.fRmin) vecCore__MaskedAssignFunc(norm, distMin == distRMin, -temp.Unit());
0980 }
0981
0982 return norm;
0983 }
0984
0985 template <typename Real_v, typename Bool_v>
0986 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void NormalKernel(UnplacedStruct_t const &unplaced,
0987 Vector3D<Real_v> const &point,
0988 Vector3D<Real_v> &norm, Bool_v &valid)
0989 {
0990
0991 valid = Bool_v(false);
0992 Bool_v isPointInside(false), isPointOutside(false);
0993 GenericKernelForContainsAndInside<Real_v, true>(unplaced, point, isPointInside, isPointOutside);
0994 if (isPointInside || isPointOutside) {
0995 norm = ApproxSurfaceNormalKernel<Real_v>(unplaced, point);
0996 return;
0997 }
0998
0999 int nosurface = 0;
1000
1001 Precision x2y2 = Sqrt(point.x() * point.x() + point.y() * point.y());
1002 bool inZ = ((point.z() < unplaced.fZ + kTolerance) && (point.z() > -unplaced.fZ - kTolerance));
1003 bool inR = ((x2y2 >= unplaced.fRmin - kTolerance) && (x2y2 <= unplaced.fRmax + kTolerance));
1004
1005
1006 if (inR && (Abs(point.z() - unplaced.fZ) <= kTolerance)) {
1007 norm.Set(0., 0., 1.);
1008 nosurface++;
1009 }
1010 if (inR && (Abs(point.z() + unplaced.fZ) <= kTolerance)) {
1011 if (nosurface > 0) {
1012
1013 norm[2] += Real_v(-1.);
1014 } else {
1015 norm.Set(0., 0., -1.);
1016 }
1017 nosurface++;
1018 }
1019 if (unplaced.fRmin > 0.) {
1020 if (inZ && (Abs(x2y2 - unplaced.fRmin) <= kTolerance)) {
1021 Precision invx2y2 = 1. / x2y2;
1022 if (nosurface == 0) {
1023 norm[0] = -point[0] * invx2y2;
1024 norm[1] = -point[1] * invx2y2;
1025 norm[2] = Real_v(0.);
1026 } else {
1027 norm[0] += -point[0] * invx2y2;
1028 norm[1] += -point[1] * invx2y2;
1029 }
1030 nosurface++;
1031 }
1032 }
1033 if (inZ && (Abs(x2y2 - unplaced.fRmax) <= kTolerance)) {
1034 Precision invx2y2 = 1. / x2y2;
1035 if (nosurface > 0) {
1036 norm[0] += point[0] * invx2y2;
1037 norm[1] += point[1] * invx2y2;
1038 } else {
1039 norm[0] = point[0] * invx2y2;
1040 norm[1] = point[1] * invx2y2;
1041 norm[2] = Real_v(0.);
1042 }
1043 nosurface++;
1044 }
1045
1046
1047 if (unplaced.fDphi < vecgeom::kTwoPi) {
1048 if (inR && unplaced.fPhiWedge.IsOnSurface1(point)) {
1049 if (nosurface == 0)
1050 norm = -unplaced.fPhiWedge.GetNormal1();
1051 else
1052 norm += -unplaced.fPhiWedge.GetNormal1();
1053 nosurface++;
1054 }
1055 if (inR && unplaced.fPhiWedge.IsOnSurface2(point)) {
1056 if (nosurface == 0)
1057 norm = -unplaced.fPhiWedge.GetNormal2();
1058 else
1059 norm += -unplaced.fPhiWedge.GetNormal2();
1060 nosurface++;
1061 }
1062 }
1063 if (nosurface > 1) norm = norm / std::sqrt(1. * nosurface);
1064 valid = nosurface != 0;
1065 }
1066
1067 };
1068
1069 }
1070 }
1071
1072 #endif