Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:14:00

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