Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:13:57

0001 /// \file BVHNavigator.h
0002 /// \author Guilherme Amadio
0003 
0004 #ifndef VECGEOM_NAVIGATION_BVHNAVIGATOR_H_
0005 #define VECGEOM_NAVIGATION_BVHNAVIGATOR_H_
0006 
0007 #include "VecGeom/management/BVHManager.h"
0008 #include "VecGeom/navigation/BVHSafetyEstimator.h"
0009 #include "VecGeom/navigation/VNavigator.h"
0010 #include "VecGeom/volumes/LogicalVolume.h"
0011 #include "VecGeom/volumes/PlacedVolume.h"
0012 
0013 namespace vecgeom {
0014 inline namespace VECGEOM_IMPL_NAMESPACE {
0015 
0016 /**
0017  * @brief Navigator class using the bounding volume hierarchy of each logical volume for acceleration.
0018  */
0019 
0020 template <bool MotherIsConvex = false>
0021 class BVHNavigator : public VNavigatorHelper<BVHNavigator<MotherIsConvex>, MotherIsConvex> {
0022 private:
0023   /** Constructor. Private since this is a singleton class accessed only via the @c Instance() static method. */
0024   VECCORE_ATT_DEVICE
0025   BVHNavigator() : VNavigatorHelper<BVHNavigator<MotherIsConvex>, MotherIsConvex>(BVHSafetyEstimator::Instance()) {}
0026 
0027 public:
0028   using SafetyEstimator_t = BVHSafetyEstimator;
0029   using Base              = VNavigatorHelper<BVHNavigator<MotherIsConvex>, MotherIsConvex>;
0030   using Base::CheckDaughterIntersections;
0031 
0032   static constexpr const char *gClassNameString = "BVHNavigator";
0033 
0034 #ifndef VECCORE_CUDA
0035   /** Returns the instance of this singleton class. */
0036   static VNavigator *Instance()
0037   {
0038     static BVHNavigator instance;
0039     return &instance;
0040   }
0041 #else
0042   // If used on device, this needs to be implemented in a .cu file rather than in this header
0043   // This hack is used also by NewSimpleNavigator, implemented in LogicalVolume.cpp
0044   // This is now implemented in BVHManager.cu
0045   VECCORE_ATT_DEVICE
0046   static VNavigator *Instance();
0047 #endif
0048 
0049   /**
0050    * Checks for intersections against child volumes of logical volume @p lvol, using the BVH
0051    * associated with it.
0052    * @param[in] lvol Logical volume being checked.
0053    * @param[in] localpoint Point in the local coordinates of the logical volume.
0054    * @param[in] localdir Direction in the local coordinates of the logical volume.
0055    * @param[in] in_state Incoming navigation state.
0056    * @param[in] out_state Outgoing navigation state (not used by this method).
0057    * @param[in] step Maximum step size. Volumes beyond this distance are ignored.
0058    * @param[out] hitcandidate
0059    * @returns Whether @p out_state has been modified or not. Always false for this method.
0060    */
0061   VECCORE_ATT_HOST_DEVICE
0062   bool CheckDaughterIntersections(LogicalVolume const *lvol, Vector3D<Precision> const &localpoint,
0063                                   Vector3D<Precision> const &localdir, NavigationState const *in_state,
0064                                   NavigationState * /* out_state */, Precision &step,
0065                                   VPlacedVolume const *&hitcandidate) const final
0066   {
0067     if (auto bvh = BVHManager::GetBVH(lvol)) {
0068       VPlacedVolume const *last = in_state ? in_state->GetLastExited() : nullptr;
0069       bvh->CheckDaughterIntersections(localpoint, localdir, step, last, hitcandidate);
0070     }
0071     return false; /* return value indicates whether out_state has been modified */
0072   }
0073 
0074   /// @brief Relocates the point on boundary after crossing.
0075   /// @param[in] pointafterboundary Propagated point on boundary, in the reference frame of in_state.Top().
0076   /// @param[in] in_state Mother volume being exited.
0077   /// @param[out] out_state State being exited, or daughter being entered.
0078   VECCORE_ATT_HOST_DEVICE
0079   void Relocate(Vector3D<Precision> const &pointafterboundary, NavigationState const &__restrict__ in_state,
0080                 NavigationState &__restrict__ out_state) const final
0081   {
0082     // this means that we are leaving the mother
0083     // alternatively we could use nextvolumeindex like before
0084     if (out_state.Top() == in_state.Top()) {
0085       RelocatePointFromPathForceDifferent(pointafterboundary, out_state);
0086     } else {
0087       // continue directly further down ( next volume should have been stored in out_state already )
0088       VPlacedVolume const *nextvol = out_state.Top();
0089       out_state.Pop();
0090       LocateGlobalPoint(nextvol, nextvol->GetTransformation()->Transform(pointafterboundary), out_state, false);
0091       return;
0092     }
0093   }
0094 
0095   /// @brief Locate a point starting from a volume
0096   /// @param[in] vol Current volume to start the search from
0097   /// @param[in] point Point in current volume frame
0098   /// @param[in] path Navigation state pointing to the mother of vol
0099   /// @param[in] top Should the top volume be checked
0100   /// @param[in] exclude Volume excluded from search
0101   /// @return Deepest placed volume containing the point
0102   VECCORE_ATT_HOST_DEVICE
0103   VPlacedVolume const *LocateGlobalPoint(VPlacedVolume const *vol, Vector3D<Precision> const &point,
0104                                          NavigationState &path, bool top, VPlacedVolume const *exclude = nullptr) const
0105   {
0106     if (top) {
0107       assert(vol != nullptr);
0108       if (!vol->UnplacedContains(point)) return nullptr;
0109     }
0110 
0111     path.Push(vol);
0112 
0113     Vector3D<Precision> currentpoint(point);
0114     Vector3D<Precision> daughterlocalpoint;
0115 
0116     for (auto v = vol; v->GetDaughters().size() > 0;) {
0117       auto bvh = vecgeom::BVHManager::GetBVH(v->GetLogicalVolume()->id());
0118 
0119       if (!bvh->LevelLocate(exclude, currentpoint, v, daughterlocalpoint)) break;
0120 
0121       currentpoint = daughterlocalpoint;
0122       path.Push(v);
0123       // Only exclude the placed volume once since we could enter it again via a
0124       // different volume history.
0125       exclude = nullptr;
0126     }
0127 
0128     return path.Top();
0129   }
0130 
0131   /// @brief Special version of locate point function that excludes searching a given volume
0132   /// (useful when we know that a particle must have traversed a boundary).
0133   /// @param vol Current volume to start the search from
0134   /// @param exclvol Volume to be excluded from search
0135   /// @param point Point in current volume frame
0136   /// @param path Navigation state pointing to the mother of vol
0137   /// @param top Should the top volume be checked
0138   /// @return Deepest placed volume containing the point
0139   VECCORE_ATT_HOST_DEVICE
0140   VPlacedVolume const *LocateGlobalPointExclVolume(VPlacedVolume const *vol, VPlacedVolume const *exclvol,
0141                                                    Vector3D<Precision> const &point, NavigationState &path,
0142                                                    bool top) const
0143   {
0144     VPlacedVolume const *candvolume = vol;
0145     Vector3D<Precision> currentpoint(point);
0146     if (top) {
0147       assert(vol != nullptr);
0148       candvolume = (vol->UnplacedContains(point)) ? vol : nullptr;
0149     }
0150     if (candvolume) {
0151       path.Push(candvolume);
0152       LogicalVolume const *lvol         = candvolume->GetLogicalVolume();
0153       Vector<Daughter> const *daughters = lvol->GetDaughtersp();
0154 
0155       bool godeeper = true;
0156       while (daughters->size() > 0 && godeeper) {
0157         // returns nextvolume; and transformedpoint; modified path
0158         Vector3D<Precision> transformedpoint;
0159         godeeper = BVHManager::GetBVH(lvol)->LevelLocate(exclvol, currentpoint, candvolume, transformedpoint);
0160         if (godeeper) {
0161           lvol         = candvolume->GetLogicalVolume();
0162           daughters    = lvol->GetDaughtersp();
0163           currentpoint = transformedpoint;
0164           path.Push(candvolume);
0165         }
0166       }
0167     }
0168     return candvolume;
0169   }
0170 
0171   /// @brief Relocation function called when exiting the current volume.
0172   /// @param[in] localpoint Point in current volume path coordinates
0173   /// @param path Path to volume being exited
0174   /// @return Location of point after exiting
0175   VECCORE_ATT_HOST_DEVICE
0176   VPlacedVolume const *RelocatePointFromPathForceDifferent(Vector3D<Precision> const &localpoint,
0177                                                            NavigationState &path) const
0178   {
0179     // idea: do the following:
0180     // ----- is localpoint still in current mother ? : then go down
0181     // if not: have to go up until we reach a volume that contains the
0182     // localpoint and then go down again (neglecting the volumes currently stored in the path)
0183     VPlacedVolume const *currentmother = path.Top();
0184     VPlacedVolume const *entryvol      = currentmother;
0185 
0186     if (currentmother != nullptr) {
0187       Vector3D<Precision> tmp = localpoint;
0188       while (currentmother) {
0189         if (currentmother == entryvol || currentmother->GetLogicalVolume()->GetUnplacedVolume()->IsAssembly() ||
0190             !currentmother->UnplacedContains(tmp)) {
0191           path.Pop();
0192           Vector3D<Precision> pointhigherup = currentmother->GetTransformation()->InverseTransform(tmp);
0193           tmp                               = pointhigherup;
0194           currentmother                     = path.Top();
0195         } else {
0196           break;
0197         }
0198       }
0199 
0200       if (currentmother) {
0201         path.Pop();
0202         return LocateGlobalPointExclVolume(currentmother, entryvol, tmp, path, false);
0203       }
0204     }
0205     return currentmother;
0206   }
0207 };
0208 } // namespace VECGEOM_IMPL_NAMESPACE
0209 } // namespace vecgeom
0210 
0211 #endif