Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:26:22

0001 #pragma once
0002 
0003 #include "VecGeom/base/Cuda.h"
0004 #include "VecGeom/base/Global.h"
0005 #include "VecGeom/base/SOA3D.h"
0006 
0007 #include <algorithm>
0008 
0009 #ifdef VECGEOM_DISTANCE_DEBUG
0010 #include "VecGeom/volumes/utilities/ResultComparator.h"
0011 #endif
0012 
0013 #ifndef __clang__
0014 #pragma GCC diagnostic push
0015 // We ignore warnings of this type in this file.
0016 // The warning occurred due to potential overflow of memory address locations output[i]
0017 // where i is an unsigned long long in a loop. It can be safely ignored since such
0018 // memory locations do in fact not exist (~multiple petabyte in memory).
0019 #pragma GCC diagnostic ignored "-Waggressive-loop-optimizations"
0020 #endif // __clang__
0021 
0022 namespace vecgeom {
0023 
0024 // putting a forward declaration by hand
0025 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_1t_2v(class, CommonSpecializedVolImplHelper, typename, TranslationCode,
0026                                            translation::kGeneric, RotationCode, rotation::kGeneric);
0027 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_1t_2v(class, SIMDSpecializedVolImplHelper, class, TranslationCode,
0028                                            translation::kGeneric, RotationCode, rotation::kGeneric);
0029 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_1t_2v(class, LoopSpecializedVolImplHelper, class, TranslationCode,
0030                                            translation::kGeneric, RotationCode, rotation::kGeneric);
0031 
0032 inline namespace VECGEOM_IMPL_NAMESPACE {
0033 
0034 template <class Specialization, TranslationCode transC, RotationCode rotC>
0035 class CommonSpecializedVolImplHelper : public Specialization::PlacedShape_t {
0036 
0037   using PlacedShape_t    = typename Specialization::PlacedShape_t;
0038   using UnplacedVolume_t = typename Specialization::UnplacedVolume_t;
0039 
0040 public:
0041 #ifndef VECCORE_CUDA
0042   CommonSpecializedVolImplHelper(char const *const label, LogicalVolume const *const logical_volume,
0043                                  Transformation3D const *const transformation)
0044       : PlacedShape_t(label, logical_volume, transformation)
0045   {
0046   }
0047 
0048   CommonSpecializedVolImplHelper(char const *const label, LogicalVolume *const logical_volume,
0049                                  Transformation3D const *const transformation)
0050       : PlacedShape_t(label, logical_volume, transformation)
0051   {
0052   }
0053 
0054   CommonSpecializedVolImplHelper(LogicalVolume const *const logical_volume,
0055                                  Transformation3D const *const transformation)
0056       : CommonSpecializedVolImplHelper("", logical_volume, transformation)
0057   {
0058   }
0059 
0060   // this constructor mimics the constructor from the Unplaced solid
0061   // it ensures that placed volumes can be constructed just like ordinary Geant4/ROOT solids
0062   template <typename... ArgTypes>
0063   CommonSpecializedVolImplHelper(char const *const label, ArgTypes... params)
0064       : CommonSpecializedVolImplHelper(label, new LogicalVolume(new UnplacedVolume_t(params...)),
0065                                        &Transformation3D::kIdentity)
0066   {
0067   }
0068 
0069 #else // Compiling for CUDA
0070   VECCORE_ATT_DEVICE CommonSpecializedVolImplHelper(LogicalVolume const *const logical_volume,
0071                                                     Transformation3D const *const transformation, const unsigned int id,
0072                                                     const int copy_no, const int child_id)
0073       : PlacedShape_t(logical_volume, transformation, id, copy_no, child_id)
0074   {
0075   }
0076 #endif
0077   using PlacedShape_t::Contains;
0078   using PlacedShape_t::DistanceToIn;
0079   using PlacedShape_t::DistanceToOut;
0080   using PlacedShape_t::Inside;
0081   using PlacedShape_t::PlacedShape_t;
0082   using PlacedShape_t::SafetyToIn;
0083   using PlacedShape_t::SafetyToOut;
0084   using PlacedShape_t::UnplacedContains;
0085 
0086   virtual int MemorySize() const override { return sizeof(*this); }
0087 
0088   VECCORE_ATT_HOST_DEVICE
0089   virtual void PrintType() const override { Specialization::PrintType(); }
0090 
0091   virtual void PrintType(std::ostream &os) const override { Specialization::PrintType(os, transC, rotC); }
0092   virtual void PrintImplementationType(std::ostream &os) const override { Specialization::PrintImplementationType(os); }
0093   virtual void PrintUnplacedType(std::ostream &os) const override { Specialization::PrintUnplacedType(os); }
0094 
0095   int GetTransCode() const final { return transC; }
0096   int GetRotCode() const final { return rotC; }
0097 
0098   VECCORE_ATT_HOST_DEVICE
0099   virtual EnumInside Inside(Vector3D<Precision> const &point) const override
0100   {
0101     Inside_t output;
0102     Transformation3D const *tr = this->GetTransformation();
0103     Specialization::Inside(*this->GetUnplacedStruct(), tr->Transform<transC, rotC, Precision>(point), output);
0104     return (EnumInside)output;
0105   }
0106 
0107   VECCORE_ATT_HOST_DEVICE
0108   virtual bool Contains(Vector3D<Precision> const &point) const override
0109   {
0110     bool output(false);
0111     Transformation3D const *tr = this->GetTransformation();
0112     Vector3D<Precision> lp     = tr->Transform<transC, rotC, Precision>(point);
0113     Specialization::Contains(*this->GetUnplacedStruct(), lp, output);
0114     return output;
0115   }
0116 
0117   VECCORE_ATT_HOST_DEVICE
0118   virtual bool Contains(Vector3D<Precision> const &point, Vector3D<Precision> &localPoint) const override
0119   {
0120     bool output(false);
0121     Transformation3D const *tr = this->GetTransformation();
0122     localPoint                 = tr->Transform<transC, rotC, Precision>(point);
0123     Specialization::Contains(*this->GetUnplacedStruct(), localPoint, output);
0124 #ifdef VECGEOM_DISTANCE_DEBUG
0125     DistanceComparator::CompareUnplacedContains(this, output, localPoint);
0126 #endif
0127     return output;
0128   }
0129 
0130   VECCORE_ATT_HOST_DEVICE
0131   virtual Precision DistanceToIn(Vector3D<Precision> const &point, Vector3D<Precision> const &direction,
0132                                  const Precision stepMax = kInfLength) const override
0133   {
0134 #ifndef VECCORE_CUDA
0135     assert(direction.IsNormalized() && " direction not normalized in call to DistanceToIn ");
0136 #endif
0137     Precision output(kInfLength);
0138     Transformation3D const *tr = this->GetTransformation();
0139     Specialization::DistanceToIn(*this->GetUnplacedStruct(), tr->Transform<transC, rotC>(point),
0140                                  tr->TransformDirection<rotC>(direction), stepMax, output);
0141 #ifdef VECGEOM_DISTANCE_DEBUG
0142     DistanceComparator::CompareDistanceToIn(this, output, point, direction, stepMax);
0143 #endif
0144     return output;
0145   }
0146 
0147   VECCORE_ATT_HOST_DEVICE
0148   virtual Precision PlacedDistanceToOut(Vector3D<Precision> const &point, Vector3D<Precision> const &direction,
0149                                         const Precision stepMax = kInfLength) const override
0150   {
0151 #ifndef VECCORE_CUDA
0152     assert(direction.IsNormalized() && " direction not normalized in call to PlacedDistanceToOut ");
0153 #endif
0154     Transformation3D const *tr = this->GetTransformation();
0155     Precision output(-1.);
0156     Specialization::template DistanceToOut(*this->GetUnplacedStruct(), tr->Transform<transC, rotC>(point),
0157                                            tr->TransformDirection<rotC>(direction), stepMax, output);
0158 
0159 #ifdef VECGEOM_DISTANCE_DEBUG
0160     DistanceComparator::CompareDistanceToOut(this, output, this->GetTransformation()->Transform(point),
0161                                              this->GetTransformation()->TransformDirection(direction), stepMax);
0162 #endif
0163     return output;
0164   }
0165 
0166   VECCORE_ATT_HOST_DEVICE
0167   virtual Precision SafetyToIn(Vector3D<Precision> const &point) const override
0168   {
0169     Precision output(kInfLength);
0170     Transformation3D const *tr = this->GetTransformation();
0171     Specialization::SafetyToIn(*this->GetUnplacedStruct(), tr->Transform<transC, rotC>(point), output);
0172     return output;
0173   }
0174 
0175   virtual Real_v SafetyToInVec(Vector3D<Real_v> const &position) const override
0176   {
0177     Transformation3D const *tr = this->GetTransformation();
0178     return this->GetUnplacedVolume()->UnplacedVolume_t::SafetyToInVec(tr->Transform<transC, rotC>(position));
0179   }
0180 
0181 }; // End class CommonSpecializedVolImplHelper
0182 
0183 // needs to be in the specializations
0184 template <class Specialization, typename Real_v, int transC, int rotC>
0185 VECGEOM_FORCE_INLINE
0186 static void ContainsLoopKernel(typename Specialization::UnplacedStruct_t const &shapestruct,
0187                                Transformation3D const &trans, const size_t offset, const size_t size,
0188                                SOA3D<Precision> const &points, bool *const output)
0189 {
0190 
0191   using Bool_v = typename vecCore::Mask_v<Real_v>;
0192   for (decltype(points.size()) i(offset); i < size; i += vecCore::VectorSize<Real_v>()) {
0193     Vector3D<Real_v> point(vecCore::FromPtr<Real_v>(points.x() + i), vecCore::FromPtr<Real_v>(points.y() + i),
0194                            vecCore::FromPtr<Real_v>(points.z() + i));
0195     Bool_v result(false);
0196     Specialization::template Contains<Real_v>(shapestruct, trans.Transform<transC, rotC>(point), result);
0197     // vecCore::StoreMask(result, output);
0198     // StoreMask has problem -> see VECCORE-21
0199     for (size_t j = 0; j < vecCore::VectorSize<Real_v>(); ++j)
0200       output[i + j] = vecCore::MaskLaneAt(result, j);
0201   }
0202 }
0203 
0204 template <class Specialization, typename Real_v, int transC, int rotC>
0205 VECGEOM_FORCE_INLINE
0206 static void InsideLoopKernel(typename Specialization::UnplacedStruct_t const &shapestruct,
0207                              Transformation3D const &trans, const size_t offset, const size_t size,
0208                              SOA3D<Precision> const &points, Inside_t *const output)
0209 {
0210   using Index_t = vecCore::Index_v<Real_v>;
0211   for (decltype(points.size()) i(offset); i < size; i += vecCore::VectorSize<Real_v>()) {
0212     Vector3D<Real_v> point(vecCore::FromPtr<Real_v>(points.x() + i), vecCore::FromPtr<Real_v>(points.y() + i),
0213                            vecCore::FromPtr<Real_v>(points.z() + i));
0214     Index_t result;
0215     Specialization::template Inside<Real_v>(shapestruct, trans.Transform<transC, rotC>(point), result);
0216     // TODO: make a proper store here
0217     for (size_t j = 0; j < vecCore::VectorSize<Index_t>(); ++j)
0218       output[i + j] = vecCore::LaneAt<Index_t>(result, j);
0219   }
0220 }
0221 
0222 template <class Specialization, typename Real_v, int transC, int rotC>
0223 VECGEOM_FORCE_INLINE
0224 static void SafetyToInLoopKernel(typename Specialization::UnplacedStruct_t const &shapestruct,
0225                                  Transformation3D const &trans, const size_t offset, const size_t size,
0226                                  SOA3D<Precision> const &points, Precision *const output)
0227 {
0228 
0229   for (decltype(points.size()) i(offset); i < size; i += vecCore::VectorSize<Real_v>()) {
0230     Vector3D<Real_v> point(vecCore::FromPtr<Real_v>(points.x() + i), vecCore::FromPtr<Real_v>(points.y() + i),
0231                            vecCore::FromPtr<Real_v>(points.z() + i));
0232     Real_v result(kInfLength);
0233     Specialization::template SafetyToIn<Real_v>(shapestruct, trans.Transform<transC, rotC>(point), result);
0234     vecCore::Store(result, output + i);
0235   }
0236 }
0237 
0238 template <class Specialization, typename Real_v, int transC, int rotC>
0239 VECGEOM_FORCE_INLINE
0240 static void DistanceToInLoopKernel(typename Specialization::UnplacedStruct_t const &shapestruct,
0241                                    Transformation3D const &trans, const size_t offset, const size_t size,
0242                                    SOA3D<Precision> const &points, SOA3D<Precision> const &directions,
0243                                    Precision const *const stepMax, Precision *const output)
0244 {
0245 
0246   for (decltype(points.size()) i(offset); i < size; i += vecCore::VectorSize<Real_v>()) {
0247     Vector3D<Real_v> point(vecCore::FromPtr<Real_v>(points.x() + i), vecCore::FromPtr<Real_v>(points.y() + i),
0248                            vecCore::FromPtr<Real_v>(points.z() + i));
0249     Vector3D<Real_v> dir(vecCore::FromPtr<Real_v>(directions.x() + i), vecCore::FromPtr<Real_v>(directions.y() + i),
0250                          vecCore::FromPtr<Real_v>(directions.z() + i));
0251     Real_v step_max(vecCore::FromPtr<Real_v>(stepMax + i));
0252     Real_v result(kInfLength);
0253     Specialization::template DistanceToIn<Real_v>(shapestruct, trans.Transform<transC, rotC>(point),
0254                                                   trans.TransformDirection<rotC>(dir), step_max, result);
0255     vecCore::Store(result, output + i);
0256   }
0257 }
0258 
0259 template <class Specialization, int transC, int rotC>
0260 class SIMDSpecializedVolImplHelper : public CommonSpecializedVolImplHelper<Specialization, transC, rotC> {
0261   using CommonHelper_t = CommonSpecializedVolImplHelper<Specialization, transC, rotC>;
0262 
0263 public:
0264   using CommonHelper_t::CommonHelper_t;
0265   using CommonHelper_t::Contains;
0266   using CommonHelper_t::DistanceToIn;
0267   using CommonHelper_t::DistanceToOut;
0268   using CommonHelper_t::Inside;
0269   using CommonHelper_t::SafetyToIn;
0270   using CommonHelper_t::SafetyToOut;
0271   using CommonHelper_t::UnplacedContains;
0272 
0273   SIMDSpecializedVolImplHelper(VPlacedVolume const *other)
0274       : CommonHelper_t(other->GetName(), other->GetLogicalVolume(), other->GetTransformation())
0275   {
0276   }
0277 
0278   VECCORE_ATT_HOST_DEVICE
0279   virtual ~SIMDSpecializedVolImplHelper() {}
0280 
0281   virtual void SafetyToIn(SOA3D<Precision> const &points, Precision *const output) const override
0282   {
0283     const auto kS = vecCore::VectorSize<VectorBackend::Real_v>();
0284     auto offset   = points.size() - points.size() % kS;
0285     //   auto shape = ((UnplacedVolume_t *)this)->UnplacedVolume_t::GetUnplacedStruct();
0286     auto shape  = this->GetUnplacedStruct();
0287     auto transf = this->GetTransformation();
0288 
0289     // vector loop treatment
0290     SafetyToInLoopKernel<Specialization, VectorBackend::Real_v, transC, rotC>(*shape, *transf, 0, offset, points,
0291                                                                               output);
0292     // tail treatment
0293     SafetyToInLoopKernel<Specialization, ScalarBackend::Real_v, transC, rotC>(*shape, *transf, offset, points.size(),
0294                                                                               points, output);
0295   }
0296 
0297   virtual void DistanceToIn(SOA3D<Precision> const &points, SOA3D<Precision> const &directions,
0298                             Precision const *const stepMax, Precision *const output) const override
0299   {
0300     auto offset = points.size() - points.size() % vecCore::VectorSize<VectorBackend::Real_v>();
0301     auto shape  = this->GetUnplacedStruct();
0302     auto transf = this->GetTransformation();
0303     // vector loop treatment
0304     DistanceToInLoopKernel<Specialization, VectorBackend::Real_v, transC, rotC>(*shape, *transf, 0, offset, points,
0305                                                                                 directions, stepMax, output);
0306     // tail treatment
0307     DistanceToInLoopKernel<Specialization, ScalarBackend::Real_v, transC, rotC>(*shape, *transf, offset, points.size(),
0308                                                                                 points, directions, stepMax, output);
0309   }
0310 
0311   using UnplacedVolume_t = typename Specialization::UnplacedVolume_t;
0312 
0313   // the explicit SIMD interface
0314   virtual Real_v DistanceToInVec(Vector3D<Real_v> const &p, Vector3D<Real_v> const &d,
0315                                  Real_v const step_max) const override
0316   {
0317     Real_v output(kInfLength);
0318     Transformation3D const *tr = this->GetTransformation();
0319     auto unplacedstruct        = this->GetUnplacedStruct();
0320     Specialization::template DistanceToIn<Real_v>(*unplacedstruct, tr->Transform<transC, rotC>(p),
0321                                                   tr->TransformDirection<rotC>(d), step_max, output);
0322     return output;
0323   }
0324 
0325   virtual void Contains(SOA3D<Precision> const &points, bool *const output) const override
0326   {
0327     auto offset = points.size() - points.size() % vecCore::VectorSize<VectorBackend::Real_v>();
0328     auto shape  = this->GetUnplacedStruct();
0329     auto transf = this->GetTransformation();
0330     // vector loop treatment
0331     ContainsLoopKernel<Specialization, VectorBackend::Real_v, transC, rotC>(*shape, *transf, 0, offset, points, output);
0332     // tail treatment
0333     ContainsLoopKernel<Specialization, ScalarBackend::Real_v, transC, rotC>(*shape, *transf, offset, points.size(),
0334                                                                             points, output);
0335   }
0336 
0337   virtual void Inside(SOA3D<Precision> const &points, Inside_t *const output) const override
0338   {
0339     // I would be in favor of getting rid of this interface (unless someone asks for it)
0340     // Inside is only provided for Geant4 which currently does not have a basket interface
0341     // InsideTemplate(points, output);
0342     auto offset = points.size() - points.size() % vecCore::VectorSize<VectorBackend::Real_v>();
0343     auto shape  = this->GetUnplacedStruct();
0344     auto transf = this->GetTransformation();
0345     // vector loop treatment
0346     InsideLoopKernel<Specialization, VectorBackend::Real_v, transC, rotC>(*shape, *transf, 0, offset, points, output);
0347     // tail treatment
0348     InsideLoopKernel<Specialization, ScalarBackend::Real_v, transC, rotC>(*shape, *transf, offset, points.size(),
0349                                                                           points, output);
0350   }
0351 
0352 #ifdef VECGEOM_CUDA_INTERFACE
0353   using ThisClass_t = SIMDSpecializedVolImplHelper<Specialization, transC, rotC>;
0354   virtual size_t DeviceSizeOf() const override { return DevicePtr<CudaType_t<ThisClass_t>>::SizeOf(); }
0355 
0356   DevicePtr<cuda::VPlacedVolume> CopyToGpu(DevicePtr<cuda::LogicalVolume> const logical_volume,
0357                                            DevicePtr<cuda::Transformation3D> const transform,
0358                                            DevicePtr<cuda::VPlacedVolume> const in_gpu_ptr) const override
0359   {
0360     DevicePtr<CudaType_t<ThisClass_t>> gpu_ptr(in_gpu_ptr);
0361     gpu_ptr.Construct(logical_volume, transform, this->id(), this->GetCopyNo(), this->GetChildId());
0362     CudaAssertError();
0363     // Need to go via the void* because the regular c++ compilation
0364     // does not actually see the declaration for the cuda version
0365     // (and thus can not determine the inheritance).
0366     return DevicePtr<cuda::VPlacedVolume>((void *)gpu_ptr);
0367   }
0368 
0369   DevicePtr<cuda::VPlacedVolume> CopyToGpu(DevicePtr<cuda::LogicalVolume> const logical_volume,
0370                                            DevicePtr<cuda::Transformation3D> const transform) const override
0371   {
0372     DevicePtr<CudaType_t<ThisClass_t>> gpu_ptr;
0373     gpu_ptr.Allocate();
0374     return CopyToGpu(logical_volume, transform, DevicePtr<cuda::VPlacedVolume>((void *)gpu_ptr));
0375   }
0376 
0377   /**
0378    * Copy many instances of this class to the GPU.
0379    * \param host_volumes Host volumes to be copied. These should all be of the same type as the class that this function is called with.
0380    * \param logical_volumes GPU addresses of the logical volumes corresponding to the placed volumes.
0381    * \param transforms GPU addresses of the transformations corresponding to the placed volumes.
0382    * \param in_gpu_ptrs GPU addresses where the GPU instances of the host volumes should be placed.
0383    * \note This requires an explicit template instantiation of ConstructManyOnGpu<ThisClass_t>().
0384    * \see VECGEOM_DEVICE_INST_PLACED_VOLUME_IMPL and its multi-argument versions.
0385    */
0386   void CopyManyToGpu(std::vector<VPlacedVolume const *> const & host_volumes,
0387                      std::vector<DevicePtr<cuda::LogicalVolume>> const & logical_volumes,
0388                      std::vector<DevicePtr<cuda::Transformation3D>> const & transforms,
0389                      std::vector<DevicePtr<cuda::VPlacedVolume>> const & in_gpu_ptrs) const override
0390   {
0391     assert(host_volumes.size() == logical_volumes.size());
0392     assert(host_volumes.size() == transforms.size());
0393     assert(host_volumes.size() == in_gpu_ptrs.size());
0394 
0395     std::vector<decltype(std::declval<ThisClass_t>().id())> ids;
0396     std::vector<decltype(std::declval<ThisClass_t>().GetCopyNo())> copyNos;
0397     std::vector<decltype(std::declval<ThisClass_t>().GetChildId())> childIds;
0398     for (auto placedVol : host_volumes) {
0399       ids.push_back(placedVol->id());
0400       copyNos.push_back(placedVol->GetCopyNo());
0401       childIds.push_back(placedVol->GetChildId());
0402     }
0403 
0404     ConstructManyOnGpu<CudaType_t<ThisClass_t>>(in_gpu_ptrs.size(), in_gpu_ptrs.data(), logical_volumes.data(),
0405                                                 transforms.data(), ids.data(), copyNos.data(), childIds.data());
0406   }
0407 
0408 #endif // VECGEOM_CUDA_INTERFACE
0409 
0410 }; // end SIMD Helper
0411 
0412 template <class Specialization, int transC, int rotC>
0413 class LoopSpecializedVolImplHelper : public CommonSpecializedVolImplHelper<Specialization, transC, rotC> {
0414   using CommonHelper_t   = CommonSpecializedVolImplHelper<Specialization, transC, rotC>;
0415   using UnplacedVolume_t = typename Specialization::UnplacedVolume_t;
0416 
0417 public:
0418   using CommonHelper_t::CommonHelper_t;
0419   using CommonHelper_t::Contains;
0420   using CommonHelper_t::DistanceToIn;
0421   using CommonHelper_t::DistanceToOut;
0422   using CommonHelper_t::Inside;
0423   using CommonHelper_t::SafetyToIn;
0424   using CommonHelper_t::SafetyToOut;
0425   using CommonHelper_t::UnplacedContains;
0426 
0427   LoopSpecializedVolImplHelper(VPlacedVolume const *other)
0428       : CommonHelper_t(other->GetName(), other->GetLogicalVolume(), other->GetTransformation())
0429   {
0430   }
0431 
0432   virtual void SafetyToIn(SOA3D<Precision> const &points, Precision *const output) const override
0433   {
0434     auto shape  = this->GetUnplacedStruct();
0435     auto transf = this->GetTransformation();
0436     SafetyToInLoopKernel<Specialization, vecgeom::ScalarBackend::Real_v, transC, rotC>(*shape, *transf, 0,
0437                                                                                        points.size(), points, output);
0438   }
0439 
0440   virtual void Contains(SOA3D<Precision> const &points, bool *const output) const override
0441   {
0442     auto unplacedv = this->GetUnplacedStruct();
0443     auto transf    = this->GetTransformation();
0444     // vector loop treatment
0445     ContainsLoopKernel<Specialization, vecgeom::ScalarBackend::Real_v, transC, rotC>(*unplacedv, *transf, 0,
0446                                                                                      points.size(), points, output);
0447   }
0448 
0449   virtual void Inside(SOA3D<Precision> const &points, Inside_t *const output) const override
0450   {
0451     // I would be in favor of getting rid of this interface (unless someone asks for it)
0452     // Inside is only provided for Geant4 which currently does not have a basket interface
0453     // InsideTemplate(points, output);
0454     auto shape  = this->GetUnplacedStruct();
0455     auto transf = this->GetTransformation();
0456     InsideLoopKernel<Specialization, vecgeom::ScalarBackend::Real_v, transC, rotC>(*shape, *transf, 0, points.size(),
0457                                                                                    points, output);
0458   }
0459 
0460   virtual void DistanceToIn(SOA3D<Precision> const &points, SOA3D<Precision> const &directions,
0461                             Precision const *const stepMax, Precision *const output) const override
0462   {
0463     auto shape  = this->GetUnplacedStruct();
0464     auto transf = this->GetTransformation();
0465     DistanceToInLoopKernel<Specialization, vecgeom::ScalarBackend::Real_v, transC, rotC>(
0466         *shape, *transf, 0, points.size(), points, directions, stepMax, output);
0467   }
0468 
0469   // the explicit SIMD interface
0470   virtual Real_v DistanceToInVec(Vector3D<Real_v> const &p, Vector3D<Real_v> const &d,
0471                                  Real_v const step_max) const override
0472   {
0473     Real_v output(kInfLength);
0474     using vecCore::LaneAt;
0475     using Real_s = Precision;
0476     for (size_t i = 0; i < vecCore::VectorSize<Real_v>(); ++i) {
0477       Transformation3D const *tr = this->GetTransformation();
0478       const auto unplacedstruct  = this->GetUnplacedStruct();
0479       const Vector3D<Real_s> ps(LaneAt(p.x(), i), LaneAt(p.y(), i), LaneAt(p.z(), i)); // scalar vector
0480       const Vector3D<Real_s> ds(LaneAt(d.x(), i), LaneAt(d.y(), i), LaneAt(d.z(), i)); // scalar direction;
0481       Real_s tmp(-1.);
0482       Specialization::template DistanceToIn<Real_s>(*unplacedstruct, tr->Transform<transC, rotC>(ps),
0483                                                     tr->TransformDirection<rotC>(ds), LaneAt(step_max, i), tmp);
0484       vecCore::AssignLane(output, i, tmp);
0485     }
0486     return output;
0487   }
0488 
0489 #ifdef VECGEOM_CUDA_INTERFACE
0490   // QUESTION: CAN WE COMBINE THIS CODE WITH THE ONE FROM SIMDHelper and put it into CommonHelper?
0491   using ThisClass_t = LoopSpecializedVolImplHelper<Specialization, transC, rotC>;
0492 
0493   virtual size_t DeviceSizeOf() const override { return DevicePtr<CudaType_t<ThisClass_t>>::SizeOf(); }
0494 
0495   DevicePtr<cuda::VPlacedVolume> CopyToGpu(DevicePtr<cuda::LogicalVolume> const logical_volume,
0496                                            DevicePtr<cuda::Transformation3D> const transform,
0497                                            DevicePtr<cuda::VPlacedVolume> const in_gpu_ptr) const override
0498   {
0499     DevicePtr<CudaType_t<ThisClass_t>> gpu_ptr(in_gpu_ptr);
0500     gpu_ptr.Construct(logical_volume, transform, this->id(), this->GetCopyNo(), this->GetChildId());
0501     CudaAssertError();
0502     // Need to go via the void* because the regular c++ compilation
0503     // does not actually see the declaration for the cuda version
0504     // (and thus can not determine the inheritance).
0505     return DevicePtr<cuda::VPlacedVolume>((void *)gpu_ptr);
0506   }
0507 
0508   DevicePtr<cuda::VPlacedVolume> CopyToGpu(DevicePtr<cuda::LogicalVolume> const logical_volume,
0509                                            DevicePtr<cuda::Transformation3D> const transform) const override
0510   {
0511     DevicePtr<CudaType_t<ThisClass_t>> gpu_ptr;
0512     gpu_ptr.Allocate();
0513     return CopyToGpu(logical_volume, transform, DevicePtr<cuda::VPlacedVolume>((void *)gpu_ptr));
0514   }
0515 
0516   /**
0517    * Copy many instances of this class to the GPU.
0518    * \param host_volumes Host volumes to be copied. These should all be of the same type as the class that this function is called with.
0519    * \param logical_volumes GPU addresses of the logical volumes corresponding to the placed volumes.
0520    * \param transforms GPU addresses of the transformations corresponding to the placed volumes.
0521    * \param in_gpu_ptrs GPU addresses where the GPU instances of the host volumes should be placed.
0522    * \note This requires an explicit template instantiation of ConstructManyOnGpu<ThisClass_t>().
0523    * \see VECGEOM_DEVICE_INST_PLACED_VOLUME_IMPL
0524    */
0525   void CopyManyToGpu(std::vector<VPlacedVolume const *> const & host_volumes,
0526                      std::vector<DevicePtr<cuda::LogicalVolume>> const & logical_volumes,
0527                      std::vector<DevicePtr<cuda::Transformation3D>> const & transforms,
0528                      std::vector<DevicePtr<cuda::VPlacedVolume>> const & in_gpu_ptrs) const override
0529   {
0530     assert(host_volumes.size() == logical_volumes.size());
0531     assert(host_volumes.size() == transforms.size());
0532     assert(host_volumes.size() == in_gpu_ptrs.size());
0533 
0534     std::vector<decltype(std::declval<ThisClass_t>().id())> ids;
0535     std::vector<decltype(std::declval<ThisClass_t>().GetCopyNo())> copyNos;
0536     std::vector<decltype(std::declval<ThisClass_t>().GetChildId())> childIds;
0537     for (auto placedVol : host_volumes) {
0538       ids.push_back(placedVol->id());
0539       copyNos.push_back(placedVol->GetCopyNo());
0540       childIds.push_back(placedVol->GetChildId());
0541     }
0542 
0543     ConstructManyOnGpu<CudaType_t<ThisClass_t>>(in_gpu_ptrs.size(), in_gpu_ptrs.data(), logical_volumes.data(),
0544                                                 transforms.data(), ids.data(), copyNos.data(), childIds.data());
0545   }
0546 #endif // VECGEOM_CUDA_INTERFACE
0547 
0548 }; // end Loop Helper
0549 } // namespace VECGEOM_IMPL_NAMESPACE
0550 } // namespace vecgeom
0551 
0552 #ifndef __clang__
0553 #pragma GCC diagnostic pop
0554 #endif