Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 09:27:31

0001 //===-- kernel/BoxImplementation.h ----------------------------------*- C++ -*-===//
0002 //===--------------------------------------------------------------------------===//
0003 /// @file BoxImplementation.h
0004 /// @author Johannes de Fine Licht (johannes.definelicht@cern.ch), Sandro Wenzel (sandro.wenzel@cern.ch)
0005 
0006 /// History notes:
0007 /// 2013 - 2014: original development (abstracted kernels); Johannes and Sandro
0008 /// Oct 2015: revision + moving to new backend structure (Sandro Wenzel)
0009 
0010 #ifndef VECGEOM_VOLUMES_KERNEL_BOXIMPLEMENTATION_H_
0011 #define VECGEOM_VOLUMES_KERNEL_BOXIMPLEMENTATION_H_
0012 
0013 #include "VecGeom/base/Vector3D.h"
0014 #include "VecGeom/volumes/BoxStruct.h"
0015 #include "VecGeom/volumes/kernel/GenericKernels.h"
0016 #include <VecCore/VecCore>
0017 
0018 #include <cstdio>
0019 
0020 namespace vecgeom {
0021 
0022 VECGEOM_DEVICE_FORWARD_DECLARE(struct BoxImplementation;);
0023 VECGEOM_DEVICE_DECLARE_CONV(struct, BoxImplementation);
0024 
0025 inline namespace VECGEOM_IMPL_NAMESPACE {
0026 
0027 class PlacedBox;
0028 template <typename T>
0029 struct BoxStruct;
0030 class UnplacedBox;
0031 
0032 struct BoxImplementation {
0033 
0034   using PlacedShape_t    = PlacedBox;
0035   using UnplacedStruct_t = BoxStruct<Precision>;
0036   using UnplacedVolume_t = UnplacedBox;
0037 
0038   template <typename Real_v>
0039   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Vector3D<Real_v> HalfSize(const UnplacedStruct_t &box)
0040   {
0041     return Vector3D<Real_v>(box.fDimensions[0], box.fDimensions[1], box.fDimensions[2]);
0042   }
0043 
0044   template <typename Real_v, typename Bool_v>
0045   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Contains(UnplacedStruct_t const &box,
0046                                                                     Vector3D<Real_v> const &point, Bool_v &inside)
0047   {
0048     // in analogy to other shapes, surface points are considered inside
0049     inside = (point.Abs() - HalfSize<Real_v>(box)).Max() < Real_v(kTolerance);
0050   }
0051 
0052   template <typename Real_v, typename Inside_v>
0053   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Inside(UnplacedStruct_t const &box,
0054                                                                   Vector3D<Real_v> const &point, Inside_v &inside)
0055   {
0056     Real_v dist = (point.Abs() - HalfSize<Real_v>(box)).Max();
0057 
0058     inside = vecCore::Blend(dist < Real_v(0.0), Inside_v(kInside), Inside_v(kOutside));
0059     vecCore__MaskedAssignFunc(inside, Abs(dist) < Real_v(kHalfTolerance), Inside_v(kSurface));
0060   }
0061 
0062   template <typename Real_v, bool ForInside>
0063   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void GenericKernelForContainsAndInside(
0064       Vector3D<Real_v> const &halfsize, Vector3D<Real_v> const &point, vecCore::Mask<Real_v> &completelyinside,
0065       vecCore::Mask<Real_v> &completelyoutside)
0066   {
0067     Real_v dist = (point.Abs() - halfsize).Max();
0068 
0069     if (ForInside) completelyinside = dist < Real_v(-kHalfTolerance);
0070 
0071     completelyoutside = dist > Real_v(kHalfTolerance);
0072   }
0073 
0074   template <typename Real_v>
0075   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToIn(UnplacedStruct_t const &box,
0076                                                                         Vector3D<Real_v> const &point,
0077                                                                         Vector3D<Real_v> const &direction,
0078                                                                         Real_v const & /* stepMax */, Real_v &distance)
0079   {
0080     const Vector3D<Real_v> invDir(Real_v(1.0) / NonZero(direction[0]), Real_v(1.0) / NonZero(direction[1]),
0081                                   Real_v(1.0) / NonZero(direction[2]));
0082 
0083     const Vector3D<Real_v> signDir(Sign(direction[0]), Sign(direction[1]), Sign(direction[2]));
0084 
0085     const Vector3D<Real_v> tempIn  = -signDir * box.fDimensions - point;
0086     const Vector3D<Real_v> tempOut = signDir * box.fDimensions - point;
0087 
0088     // add a check for point on exit surface
0089     const Real_v absOrthogOut = Abs((signDir * tempOut).Min());
0090 
0091     const Real_v distOut = (tempOut * invDir).Min();
0092 
0093     // distIn calculation
0094     distance = (tempIn * invDir).Max();
0095 
0096     vecCore__MaskedAssignFunc(
0097         distance, distance >= distOut || distOut <= Real_v(kHalfTolerance) || absOrthogOut <= Real_v(kHalfTolerance),
0098         InfinityLength<Real_v>());
0099   }
0100 
0101   template <typename Real_v>
0102   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToOut(UnplacedStruct_t const &box,
0103                                                                          Vector3D<Real_v> const &point,
0104                                                                          Vector3D<Real_v> const &direction,
0105                                                                          Real_v const & /* stepMax */, Real_v &distance)
0106   {
0107     distance = Real_v(-1.0);
0108 
0109     // Quick check: if the point is outside the box plus tolerance, return early
0110     if ((point.Abs() - HalfSize<Real_v>(box)).Max() > Real_v(kTolerance)) return;
0111 
0112     // Compute reciprocal direction, with fallback for zero
0113     const Vector3D<Real_v> invDir(Real_v(1.0) / NonZero(direction[0]), Real_v(1.0) / NonZero(direction[1]),
0114                                   Real_v(1.0) / NonZero(direction[2]));
0115     // Sign of each direction component
0116     const Vector3D<Real_v> signDir(Sign(direction[0]), Sign(direction[1]), Sign(direction[2]));
0117 
0118     // Compute distance to the exit surface along each axis
0119     const Vector3D<Real_v> tempOut = signDir * box.fDimensions - point;
0120 
0121     // Skip near-parallel directions (avoid div by small invDir)
0122     auto skip = direction.Abs() * box.fDimensions < Vector3D<Real_v>(kTolerance);
0123     // auto skip = invDir.Abs() > InvdirNearParallel(box.fDimensions);
0124 
0125     // Compute final distance using min of unskipped axes
0126     distance = (tempOut * invDir).MinSkip(skip);
0127   }
0128 
0129   template <typename Real_v>
0130   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToIn(UnplacedStruct_t const &box,
0131                                                                       Vector3D<Real_v> const &point, Real_v &safety)
0132   {
0133     safety = (point.Abs() - HalfSize<Real_v>(box)).Max();
0134   }
0135 
0136   template <typename Real_v>
0137   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToOut(UnplacedStruct_t const &box,
0138                                                                        Vector3D<Real_v> const &point, Real_v &safety)
0139   {
0140     safety = (HalfSize<Real_v>(box) - point.Abs()).Min();
0141   }
0142 
0143   template <typename Real_v>
0144   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Vector3D<Real_v> NormalKernel(
0145       UnplacedStruct_t const &box, Vector3D<Real_v> const &point, typename vecCore::Mask_v<Real_v> &valid)
0146   {
0147     // Computes the normal on a surface and returns it as a unit vector
0148     //   In case a point is further than kHalfTolerance from a surface, set valid=false
0149     //   Must return a valid vector. (even if the point is not on the surface.)
0150     //
0151     //   On an edge or corner, provide an average normal of all facets within tolerance
0152 
0153     const Vector3D<Real_v> safety((point.Abs() - HalfSize<Real_v>(box)).Abs());
0154     const Real_v safmin = safety.Min();
0155     valid               = safmin < kHalfTolerance;
0156 
0157     Vector3D<Real_v> normal(0.);
0158     vecCore__MaskedAssignFunc(normal[0], safety[0] - safmin < kHalfTolerance, Sign(point[0]));
0159     vecCore__MaskedAssignFunc(normal[1], safety[1] - safmin < kHalfTolerance, Sign(point[1]));
0160     vecCore__MaskedAssignFunc(normal[2], safety[2] - safmin < kHalfTolerance, Sign(point[2]));
0161     if (normal.Mag2() > 1.0) normal.Normalize();
0162 
0163     return normal;
0164   }
0165 
0166   // an algorithm to test for intersection ( could be faster than DistanceToIn )
0167   // actually this also calculated the distance at the same time ( in tmin )
0168   // template <class Backend>
0169   VECCORE_ATT_HOST_DEVICE
0170   VECGEOM_FORCE_INLINE
0171   static bool Intersect(Vector3D<Precision> const *corners, Vector3D<Precision> const &point,
0172                         Vector3D<Precision> const &ray, Precision /* t0 */, Precision /* t1 */)
0173   {
0174     // intersection algorithm 1 ( Amy Williams )
0175     Precision tmin, tmax, tymin, tymax, tzmin, tzmax;
0176 
0177     // IF THERE IS A STEPMAX; COULD ALSO CHECK SAFETIES
0178     Precision inverserayx = 1. / ray[0];
0179     Precision inverserayy = 1. / ray[1];
0180 
0181     // TODO: we should promote this to handle multiple boxes
0182     int sign[3];
0183     sign[0] = inverserayx < 0;
0184     sign[1] = inverserayy < 0;
0185 
0186     tmin  = (corners[sign[0]].x() - point.x()) * inverserayx;
0187     tmax  = (corners[1 - sign[0]].x() - point.x()) * inverserayx;
0188     tymin = (corners[sign[1]].y() - point.y()) * inverserayy;
0189     tymax = (corners[1 - sign[1]].y() - point.y()) * inverserayy;
0190 
0191     if ((tmin > tymax) || (tymin > tmax)) return false;
0192 
0193     Precision inverserayz = 1. / ray.z();
0194     sign[2]               = inverserayz < 0;
0195 
0196     if (tymin > tmin) tmin = tymin;
0197     if (tymax < tmax) tmax = tymax;
0198 
0199     tzmin = (corners[sign[2]].z() - point.z()) * inverserayz;
0200     tzmax = (corners[1 - sign[2]].z() - point.z()) * inverserayz;
0201 
0202     if ((tmin > tzmax) || (tzmin > tmax)) return false;
0203     // if ((tzmin > tmin)) tmin = tzmin;
0204     // if (tzmax < tmax) tmax   = tzmax;
0205     // return ((tmin < t1) && (tmax > t0));
0206     // std::cerr << "tmin " << tmin << " tmax " << tmax << "\n";
0207     return true;
0208   }
0209 
0210   // an algorithm to test for intersection ( could be faster than DistanceToIn )
0211   // actually this also calculated the distance at the same time ( in tmin )
0212   template <int signx, int signy, int signz>
0213   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE
0214       //__attribute__((noinline))
0215       static Precision
0216       IntersectCached(Vector3D<Precision> const *corners, Vector3D<Precision> const &point,
0217                       Vector3D<Precision> const &inverseray, Precision t0, Precision t1)
0218   {
0219     // intersection algorithm 1 ( Amy Williams )
0220 
0221     // NOTE THE FASTEST VERSION IS STILL THE ORIGINAL IMPLEMENTATION
0222 
0223     Precision tmin, tmax, tymin, tymax, tzmin, tzmax;
0224 
0225     // TODO: we should promote this to handle multiple boxes
0226     // observation: we always compute sign and 1-sign; so we could do the assignment
0227     // to tmin and tmax in a masked assignment thereafter
0228     tmin  = (corners[signx].x() - point.x()) * inverseray.x();
0229     tmax  = (corners[1 - signx].x() - point.x()) * inverseray.x();
0230     tymin = (corners[signy].y() - point.y()) * inverseray.y();
0231     tymax = (corners[1 - signy].y() - point.y()) * inverseray.y();
0232     if ((tmin > tymax) || (tymin > tmax)) return InfinityLength<Precision>();
0233 
0234     if (tymin > tmin) tmin = tymin;
0235     if (tymax < tmax) tmax = tymax;
0236 
0237     tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0238     tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0239 
0240     if ((tmin > tzmax) || (tzmin > tmax)) return InfinityLength<Precision>(); // false
0241     if ((tzmin > tmin)) tmin = tzmin;
0242     if (tzmax < tmax) tmax = tzmax;
0243 
0244     if (!((tmin < t1) && (tmax > t0))) return InfinityLength<Precision>();
0245     return tmin;
0246   }
0247 
0248   // an algorithm to test for intersection ( could be faster than DistanceToIn )
0249   // actually this also calculated the distance at the same time ( in tmin )
0250   template <typename Real_v, int signx, int signy, int signz>
0251   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v IntersectCachedKernel(
0252       Vector3D<Real_v> const *corners, Vector3D<Precision> const &point, Vector3D<Precision> const &inverseray,
0253       Precision t0, Precision t1)
0254   {
0255 
0256     using Bool_v = vecCore::Mask_v<Real_v>;
0257 
0258     Real_v tmin  = (corners[signx].x() - point.x()) * inverseray.x();
0259     Real_v tmax  = (corners[1 - signx].x() - point.x()) * inverseray.x();
0260     Real_v tymin = (corners[signy].y() - point.y()) * inverseray.y();
0261     Real_v tymax = (corners[1 - signy].y() - point.y()) * inverseray.y();
0262 
0263     // do we need this condition ?
0264     Bool_v done = (tmin > tymax) || (tymin > tmax);
0265     if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0266     // if((tmin > tymax) || (tymin > tmax))
0267     //     return vecgeom::kInfLength;
0268 
0269     // Not sure if this has to be maskedassignments
0270     tmin = Max(tmin, tymin);
0271     tmax = Min(tmax, tymax);
0272 
0273     Real_v tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0274     Real_v tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0275 
0276     done |= (tmin > tzmax) || (tzmin > tmax);
0277     // if((tmin > tzmax) || (tzmin > tmax))
0278     //     return vecgeom::kInfLength; // false
0279     if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0280 
0281     // not sure if this has to be maskedassignments
0282     tmin = Max(tmin, tzmin);
0283     tmax = Min(tmax, tzmax);
0284 
0285     done |= !((tmin < t1) && (tmax > t0));
0286     // if( ! ((tmin < t1) && (tmax > t0)) )
0287     //     return vecgeom::kInfLength;
0288     vecCore__MaskedAssignFunc(tmin, done, InfinityLength<Real_v>());
0289     return tmin;
0290   }
0291 
0292   // an algorithm to test for intersection ( could be faster than DistanceToIn )
0293   // actually this also calculated the distance at the same time ( in tmin )
0294   template <typename Real_v, typename basep>
0295   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v IntersectCachedKernel2(Vector3D<Real_v> const *corners,
0296                                                                                     Vector3D<basep> const &point,
0297                                                                                     Vector3D<basep> const &inverseray,
0298                                                                                     int signx, int signy, int signz,
0299                                                                                     basep t0, basep t1)
0300   {
0301 
0302     using Bool_v = vecCore::Mask_v<Real_v>;
0303 
0304     Real_v tmin  = (corners[signx].x() - Real_v(point.x())) * inverseray.x();
0305     Real_v tymax = (corners[1 - signy].y() - Real_v(point.y())) * inverseray.y();
0306     Bool_v done  = tmin > tymax;
0307     if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0308 
0309     Real_v tmax  = (corners[1 - signx].x() - Real_v(point.x())) * inverseray.x();
0310     Real_v tymin = (corners[signy].y() - Real_v(point.y())) * inverseray.y();
0311 
0312     // do we need this condition ?
0313     done |= (tymin > tmax);
0314     if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0315 
0316     // if((tmin > tymax) || (tymin > tmax))
0317     //     return vecgeom::kInfLength;
0318 
0319     // Not sure if this has to be maskedassignments
0320     tmin = Max(tmin, tymin);
0321     tmax = Min(tmax, tymax);
0322 
0323     Real_v tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0324     Real_v tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0325 
0326     done |= (Real_v(tmin) > Real_v(tzmax)) || (Real_v(tzmin) > Real_v(tmax));
0327     // if((tmin > tzmax) || (tzmin > tmax))
0328     //     return vecgeom::kInfLength; // false
0329     if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0330 
0331     // not sure if this has to be maskedassignments
0332     tmin = Max(tmin, tzmin);
0333     tmax = Min(tmax, tzmax);
0334 
0335     done |= !((tmin <= Real_v(t1 + kTolerance)) && (tmax > Real_v(t0 - kTolerance)));
0336     // if( ! ((tmin < t1) && (tmax > t0)) )
0337     //     return vecgeom::kInfLength;
0338     vecCore__MaskedAssignFunc(tmin, done, InfinityLength<Real_v>());
0339     return tmin;
0340   }
0341 
0342   // an algorithm to test for intersection against many boxes but just one ray;
0343   // in this case, the inverse ray is cached outside and directly given here as input
0344   // we could then further specialize this function to the direction of the ray
0345   // because also the sign[] variables and hence the branches are predefined
0346 
0347   // one could do: template <class Backend, int sign0, int sign1, int sign2>
0348   template <typename Real_v>
0349   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Precision IntersectMultiple(Vector3D<Real_v> const lowercorners,
0350                                                                                   Vector3D<Real_v> const uppercorners,
0351                                                                                   Vector3D<Precision> const &point,
0352                                                                                   Vector3D<Precision> const &inverseray,
0353                                                                                   Precision t0, Precision t1)
0354   {
0355     // intersection algorithm 1 ( Amy Williams )
0356 
0357     typedef Real_v Float_t;
0358 
0359     Float_t tmin, tmax, tymin, tymax, tzmin, tzmax;
0360     // IF THERE IS A STEPMAX; COULD ALSO CHECK SAFETIES
0361 
0362     // TODO: we should promote this to handle multiple boxes
0363     // we might need to have an Index type
0364 
0365     // int sign[3];
0366     Float_t sign[3]; // this also exists
0367     sign[0] = inverseray.x() < 0;
0368     sign[1] = inverseray.y() < 0;
0369 
0370     // observation: we always compute sign and 1-sign; so we could do the assignment
0371     // to tmin and tmax in a masked assignment thereafter
0372 
0373     // tmin =  (corners[(int)sign[0]].x()   -point.x())*inverserayx;
0374     // tmax =  (corners[(int)(1-sign[0])].x() -point.x())*inverserayx;
0375     // tymin = (corners[(int)(sign[1])].y()   -point.y())*inverserayy;
0376     // tymax = (corners[(int)(1-sign[1])].y() -point.y())*inverserayy;
0377 
0378     Precision x0 = (lowercorners.x() - point.x()) * inverseray.x();
0379     Precision x1 = (uppercorners.x() - point.x()) * inverseray.x();
0380     Precision y0 = (lowercorners.y() - point.y()) * inverseray.y();
0381     Precision y1 = (uppercorners.y() - point.y()) * inverseray.y();
0382     // could we do this using multiplications?
0383     //    tmin =   !sign[0] ?  x0 : x1;
0384     //    tmax =   sign[0] ? x0 : x1;
0385     //    tymin =  !sign[1] ?  y0 : y1;
0386     //    tymax =  sign[1] ? y0 : y1;
0387 
0388     // could completely get rid of this ? because the sign is determined by the outside ray
0389 
0390     tmin  = (1 - sign[0]) * x0 + sign[0] * x1;
0391     tmax  = sign[0] * x0 + (1 - sign[0]) * x1;
0392     tymin = (1 - sign[1]) * y0 + sign[1] * y1;
0393     tymax = sign[1] * y0 + (1 - sign[1]) * y1;
0394 
0395     // tmax =  (corners[(int)(1-sign[0])].x() -point.x())*inverserayx;
0396     // tymin = (corners[(int)(sign[1])].y()   -point.y())*inverserayy;
0397     // tymax = (corners[(int)(1-sign[1])].y() -point.y())*inverserayy;
0398 
0399     if ((tmin > tymax) || (tymin > tmax)) return InfinityLength<Precision>();
0400 
0401     //  Precision inverserayz = 1./ray.z();
0402     sign[2] = inverseray.z() < 0;
0403 
0404     if (tymin > tmin) tmin = tymin;
0405     if (tymax < tmax) tmax = tymax;
0406 
0407     //
0408     // tzmin = (lowercorners[(int) sign[2]].z()   -point.z())*inverseray.z();
0409     // tzmax = (uppercorners[(int)(1-sign[2])].z() -point.z())*inverseray.z();
0410 
0411     if ((tmin > tzmax) || (tzmin > tmax)) return InfinityLength<Precision>(); // false
0412     if ((tzmin > tmin)) tmin = tzmin;
0413     if (tzmax < tmax) tmax = tzmax;
0414 
0415     if (!((tmin < t1) && (tmax > t0))) return InfinityLength<Precision>();
0416     // std::cerr << "tmin " << tmin << " tmax " << tmax << "\n";
0417     // return true;
0418     return tmin;
0419   }
0420 }; // End struct BoxImplementation
0421 
0422 struct ABBoxImplementation {
0423 
0424   // a contains kernel to be used with aligned bounding boxes
0425   // scalar and vector modes (aka backend) for boxes but only single points
0426   // should be useful to test one point against many bounding boxes
0427   // TODO: check if this can be unified with the normal generic box kernel
0428   template <typename Real_v, typename Bool_v = typename vecCore::Mask_v<Real_v>>
0429   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void ABBoxContainsKernel(Vector3D<Real_v> const &lowercorner,
0430                                                                                Vector3D<Real_v> const &uppercorner,
0431                                                                                Vector3D<Precision> const &point,
0432                                                                                Bool_v &inside)
0433   {
0434 
0435     inside = lowercorner.x() < Real_v(point.x());
0436     inside &= uppercorner.x() > Real_v(point.x());
0437     if (vecCore::MaskEmpty(inside)) return;
0438 
0439     inside &= lowercorner.y() < Real_v(point.y());
0440     inside &= uppercorner.y() > Real_v(point.y());
0441     if (vecCore::MaskEmpty(inside)) return;
0442 
0443     inside &= lowercorner.z() < Real_v(point.z());
0444     inside &= uppercorner.z() > Real_v(point.z());
0445   }
0446 
0447   // playing with a kernel that can do multi-box - single particle; multi-box -- multi-particle, single-box --
0448   // multi-particle
0449   template <typename T1, typename T2, typename Bool_v>
0450   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void ABBoxContainsKernelGeneric(Vector3D<T1> const &lowercorner,
0451                                                                                       Vector3D<T1> const &uppercorner,
0452                                                                                       Vector3D<T2> const &point,
0453                                                                                       Bool_v &inside)
0454   {
0455     inside = lowercorner.x() < T1(point.x());
0456     inside &= uppercorner.x() > T1(point.x());
0457     if (vecCore::MaskEmpty(inside)) return;
0458 
0459     inside &= lowercorner.y() < T1(point.y());
0460     inside &= uppercorner.y() > T1(point.y());
0461     if (vecCore::MaskEmpty(inside)) return;
0462 
0463     inside &= lowercorner.z() < T1(point.z());
0464     inside &= uppercorner.z() > T1(point.z());
0465   }
0466 
0467   // safety square for Bounding boxes
0468   // generic kernel treating one track and one or multiple boxes
0469   // in case a point is inside a box a squared value
0470   // is returned but given an overall negative sign
0471   template <typename Real_v, typename Real_s = typename vecCore::TypeTraits<Real_v>::ScalarType>
0472   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v ABBoxSafetySqr(Vector3D<Real_v> const &lowercorner,
0473                                                                             Vector3D<Real_v> const &uppercorner,
0474                                                                             Vector3D<Real_s> const &point)
0475   {
0476 
0477     using Vector3D_v = Vector3D<Real_v>;
0478     using Bool_v     = vecCore::Mask_v<Real_v>;
0479 
0480     const Vector3D_v kHalf(Real_v(static_cast<Real_s>(0.5)));
0481     const Vector3D_v origin((uppercorner + lowercorner) * kHalf);
0482     const Vector3D_v delta((uppercorner - lowercorner) * kHalf);
0483     // promote scalar point to vector point
0484     const Vector3D_v promotedpoint(Real_v(point.x()), Real_v(point.y()), Real_v(point.z()));
0485 
0486     // it would be nicer to have a standalone Abs function taking Vector3D as input
0487     const Vector3D_v safety = ((promotedpoint - origin).Abs()) - delta;
0488     const Bool_v outsidex   = safety.x() > Real_s(0.);
0489     const Bool_v outsidey   = safety.y() > Real_s(0.);
0490     const Bool_v outsidez   = safety.z() > Real_s(0.);
0491 
0492     Real_v runningsafetysqr(0.);                  // safety squared from outside
0493     Real_v runningmax(-InfinityLength<Real_v>()); // relevant for safety when we are inside
0494 
0495     // loop over dimensions manually unrolled
0496     // treat x dim
0497     {
0498       // this will be much simplified with operator notation
0499       Real_v tmp(0.);
0500       vecCore__MaskedAssignFunc(tmp, outsidex, safety.x() * safety.x());
0501       runningsafetysqr += tmp;
0502       runningmax = Max(runningmax, safety.x());
0503     }
0504 
0505     // treat y dim
0506     {
0507       Real_v tmp(0.);
0508       vecCore__MaskedAssignFunc(tmp, outsidey, safety.y() * safety.y());
0509       runningsafetysqr += tmp;
0510       runningmax = Max(runningmax, safety.y());
0511     }
0512 
0513     // treat z dim
0514     {
0515       Real_v tmp(0.);
0516       vecCore__MaskedAssignFunc(tmp, outsidez, safety.z() * safety.z());
0517       runningsafetysqr += tmp;
0518       runningmax = Max(runningmax, safety.z());
0519     }
0520 
0521     Bool_v inside = !(outsidex || outsidey || outsidez);
0522     if (!vecCore::MaskEmpty(inside)) vecCore__MaskedAssignFunc(runningsafetysqr, inside, -runningmax * runningmax);
0523     return runningsafetysqr;
0524   }
0525 
0526   // safety square for Bounding boxes, returning the squared range for any point in the box
0527   // generic kernel treating one track and one or multiple boxes
0528   // in case a point is inside a box a squared value
0529   // is returned but given an overall negative sign
0530   template <typename Real_v, typename Real_s = typename vecCore::TypeTraits<Real_v>::ScalarType>
0531   VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static Real_v ABBoxSafetyRangeSqr(Vector3D<Real_v> const &lowercorner,
0532                                                                                  Vector3D<Real_v> const &uppercorner,
0533                                                                                  Vector3D<Real_s> const &point,
0534                                                                                  Real_v &safetymaxsqr)
0535   {
0536 
0537     using Vector3D_v = Vector3D<Real_v>;
0538     using Bool_v     = vecCore::Mask_v<Real_v>;
0539 
0540     const Vector3D_v kHalf(Real_v(static_cast<Real_s>(0.5)));
0541     const Vector3D_v origin((uppercorner + lowercorner) * kHalf);
0542     const Vector3D_v delta((uppercorner - lowercorner) * kHalf);
0543     // promote scalar point to vector point
0544     const Vector3D_v promotedpoint(Real_v(point.x()), Real_v(point.y()), Real_v(point.z()));
0545 
0546     // it would be nicer to have a standalone Abs function taking Vector3D as input
0547     const Vector3D_v safety  = ((promotedpoint - origin).Abs()) - delta;
0548     const Vector3D_v safetyp = ((promotedpoint - origin).Abs()) + delta;
0549     const Bool_v outsidex    = safety.x() > Real_s(0.);
0550     const Bool_v outsidey    = safety.y() > Real_s(0.);
0551     const Bool_v outsidez    = safety.z() > Real_s(0.);
0552 
0553     Real_v runningsafetysqr(0.);                  // safety squared from outside
0554     safetymaxsqr = safetyp.Mag2();                // safetymax squared from outside
0555     Real_v runningmax(-InfinityLength<Real_v>()); // relevant for safety when we are inside
0556 
0557     // loop over dimensions manually unrolled
0558     // treat x dim
0559     {
0560       // this will be much simplified with operator notation
0561       Real_v tmp(0.);
0562       vecCore__MaskedAssignFunc(tmp, outsidex, safety.x() * safety.x());
0563       runningsafetysqr += tmp;
0564       runningmax = Max(runningmax, safety.x());
0565       //      vecCore__MaskedAssignFunc(tmp, outsidex, safetyp.x() * safetyp.x());
0566       //      safetymaxsqr += tmp;
0567     }
0568 
0569     // treat y dim
0570     {
0571       Real_v tmp(0.);
0572       vecCore__MaskedAssignFunc(tmp, outsidey, safety.y() * safety.y());
0573       runningsafetysqr += tmp;
0574       runningmax = Max(runningmax, safety.y());
0575       //      vecCore__MaskedAssignFunc(tmp, outsidey, safetyp.y() * safetyp.y());
0576       //      safetymaxsqr += tmp;
0577     }
0578 
0579     // treat z dim
0580     {
0581       Real_v tmp(0.);
0582       vecCore__MaskedAssignFunc(tmp, outsidez, safety.z() * safety.z());
0583       runningsafetysqr += tmp;
0584       runningmax = Max(runningmax, safety.z());
0585       //      vecCore__MaskedAssignFunc(tmp, outsidez, safetyp.z() * safetyp.z());
0586       //      safetymaxsqr += tmp;
0587     }
0588 
0589     Bool_v inside = !(outsidex || outsidey || outsidez);
0590     if (!vecCore::MaskEmpty(inside)) vecCore__MaskedAssignFunc(runningsafetysqr, inside, -runningmax * runningmax);
0591     return runningsafetysqr;
0592   }
0593 
0594 }; // end aligned bounding box struct
0595 } // namespace VECGEOM_IMPL_NAMESPACE
0596 } // namespace vecgeom
0597 
0598 #endif // VECGEOM_VOLUMES_KERNEL_BOXIMPLEMENTATION_H_