Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-21 09:29:04

0001 // This file is part of VecGeom and is distributed under the
0002 // conditions in the file LICENSE.txt in the top directory.
0003 // For the full list of authors see CONTRIBUTORS.txt and `git log`.
0004 
0005 /// \brief Class storing the global navigation index lookup table.
0006 /// \file management/NavIndexTable.h
0007 /// \author Andrei Gheata (andrei.gheata@cern.ch)
0008 
0009 #ifndef VECGEOM_MANAGEMENT_NAVINDEXTABLE_H_
0010 #define VECGEOM_MANAGEMENT_NAVINDEXTABLE_H_
0011 
0012 #include "VecGeom/management/GeoVisitor.h"
0013 #include "VecGeom/navigation/NavigationState.h"
0014 
0015 #include <new>
0016 
0017 namespace vecgeom {
0018 inline namespace VECGEOM_IMPL_NAMESPACE {
0019 
0020 class NavIndexTable;
0021 
0022 /// @brief Visitor class for creating the navigation table
0023 class BuildNavIndexVisitor : public GeoVisitorNavIndex {
0024 private:
0025   size_t fTableSize   = sizeof(NavIndex_t); ///< The table size
0026   NavIndex_t *fNavInd = nullptr;            ///< Array storing the navigation info related to a given state
0027   int fLimitDepth     = 0;                  ///< limit depth to scache the transformations, 0 means unlimited
0028   int fError          = 0;                  ///< error code
0029   NavIndex_t fCurrent = 1;                  ///< Current navigation index being filled.
0030   bool fDoCount       = true;               ///< First pass to compute the table size
0031   bool fValidate      = false;              ///< If set, this flag will force a thorough validation upon visiting
0032   std::vector<NavIndex_t> fSelectedVolumes; ///< Volumes selected to be compressed in scenes
0033   std::vector<int> fSceneId;                ///< Scene id's for selected volumes
0034 public:
0035   BuildNavIndexVisitor(int depth_limit, bool do_count)
0036       : GeoVisitorNavIndex(), fLimitDepth(depth_limit), fDoCount(do_count)
0037   {
0038     int ntot         = GeoManager::Instance().GetRegisteredVolumesCount();
0039     fSelectedVolumes = std::vector<NavIndex_t>(ntot, 0);
0040     fSceneId         = std::vector<int>(ntot, 0);
0041   }
0042   int GetError() const { return fError; }
0043   std::vector<NavIndex_t> &GetSelectedVolumes() { return fSelectedVolumes; }
0044   size_t GetTableSize() const { return fTableSize; }
0045   int GetSceneId(int ivol) const { return fSceneId[ivol]; }
0046   void SetSceneId(int ivol, int id) { fSceneId[ivol] = id; }
0047   bool IsSelected(int ivol) const { return fSelectedVolumes[ivol] > 0; }
0048   bool IsVisited(int ivol) const { return fSelectedVolumes[ivol] > 1; }
0049   void SetVisited(int ivol)
0050   {
0051     if (fSelectedVolumes[ivol] == 1) fSelectedVolumes[ivol] = 2;
0052   }
0053 
0054   void ResetVisited()
0055   {
0056     std::for_each(fSelectedVolumes.begin(), fSelectedVolumes.end(), [](NavIndex_t &i) {
0057       if (i > 1) i = 1;
0058     });
0059   }
0060 
0061   void SetSceneIndex(int ivol, NavIndex_t address) { fSelectedVolumes[ivol] = address; }
0062   NavIndex_t GetSceneIndex(int ivol)
0063   {
0064     auto scene_index = fSelectedVolumes[ivol];
0065     return (scene_index > 2) ? scene_index : 0;
0066   }
0067   void SetTable(NavIndex_t *table) { fNavInd = table; }
0068   void SetDoCount(bool flag) { fDoCount = flag; }
0069   void SetValidate(bool flag) { fValidate = flag; }
0070   std::vector<NavIndex_t> &SelectedVolumes() { return fSelectedVolumes; }
0071 
0072   /// @brief Visitor method applied for creating a single entru of the navigation table to use with indices
0073   /// @param state State currently visited
0074   /// @param level Current depth
0075   /// @param mother Mother navigation index
0076   /// @param dind Daugher index
0077   /// @param id Unique touchable id to be assigned
0078   /// @return Index of the record created for this state
0079   NavIndex_t apply(NavStatePath *state, int level, NavIndex_t mother, int dind, NavIndex_t &id);
0080 
0081   /// @brief Visitor method applied for creating a single entru of the navigation table to use with tuple states
0082   /// @param state State currently visited
0083   /// @param level Current depth
0084   /// @param mother Mother navigation index
0085   /// @param dind Daugher index
0086   /// @param id Unique touchable id to be assigned
0087   /// @param scene_id Current scene id
0088   /// @param new_scene_id New scene id
0089   /// @return Index of the record created for this state
0090   NavIndex_t apply_tuple(NavStatePath *state, int level, NavIndex_t mother, int dind, NavIndex_t &id, int scene_id,
0091                          int new_scene_id);
0092 
0093   /// @brief Run the optimal compression of touchables in logical scenes, constraining the maximum scene depth to
0094   ///        VECGEOM_NAVTUPLE_MAXDEPTH, and the minimum number of touchables per scene to NAVTUPLE_MINSCENE
0095   /// @param selected_volumes Container indexed with the logical volume id, returning the selection of scene volumes
0096   /// @param target_touchables Stop creating logical scenes if the target number is reached
0097   /// @param min_per_scene Minimum number of touchables of a logical volume that qualifying it to become a scene.
0098   void NodeReduction(int min_per_scene = 1000);
0099 };
0100 
0101 class NavIndexTable {
0102 private:
0103   NavIndex_t *fNavInd       = nullptr; ///< address of the table
0104   VPlacedVolume *fVolBuffer = nullptr; ///< placed volume buffer
0105   NavIndex_t fWorld         = 1;       ///< index for the world volume
0106   size_t fTableSize         = 0;       ///< table size in bytes
0107   size_t fDepthLimit        = 0;       ///< depth limnit to which transformations will be cached
0108 
0109   NavIndexTable(NavIndex_t *table, size_t table_size) : fNavInd(table), fTableSize(table_size) {}
0110 
0111 public:
0112   ~NavIndexTable() { CleanTable(); }
0113 
0114   /// @brief Returns the static instance of the navigation table
0115   /// @param nav_table Initialize with existing instance
0116   /// @param table_size Initialize with existing table size
0117   static NavIndexTable *Instance(NavIndex_t *nav_table = nullptr, size_t table_size = 0)
0118   {
0119     static NavIndexTable instance(nav_table, table_size);
0120     return &instance;
0121   }
0122 
0123   /// @brief Clean the current table
0124   void CleanTable()
0125   {
0126     delete[] fNavInd;
0127     fNavInd = nullptr;
0128   }
0129 
0130   /// @brief Returns the size in bytes of the table
0131   VECCORE_ATT_HOST_DEVICE
0132   VECGEOM_FORCE_INLINE
0133   size_t GetTableSize() const { return fTableSize; }
0134 
0135   /// @brief Returns the address of the table
0136   VECCORE_ATT_HOST_DEVICE
0137   VECGEOM_FORCE_INLINE
0138   NavIndex_t *GetTable() const { return fNavInd; }
0139 
0140   /// @brief Set the volume buffer
0141   VECCORE_ATT_HOST_DEVICE
0142   VECGEOM_FORCE_INLINE
0143   void SetVolumeBuffer(VPlacedVolume *buffer) { fVolBuffer = buffer; }
0144 
0145   /// @brief Get the navigation index of the world
0146   VECCORE_ATT_HOST_DEVICE
0147   VECGEOM_FORCE_INLINE
0148   NavIndex_t GetWorld() const { return fWorld; }
0149 
0150   /// @brief Allocate the table as a NavIndex_t array
0151   /// @param bytes Size to allocate
0152   /// @return Success flag
0153   bool AllocateTable(size_t bytes);
0154 
0155   /// @brief Create the navigation table starting from a top placed volume
0156   /// @param top Placed volume to start from
0157   /// @param maxdepth Maximum geometry depth
0158   /// @param depth_limit Depth limit to which to which transformations should be cached (0 = full)
0159   /// @param min_per_scene Minimum touchables to trigger scene creation for navigation tuple
0160   /// @return Success flag
0161   bool CreateTable(VPlacedVolume const *top, int maxdepth, int depth_limit, int min_per_scene = 1000);
0162 
0163   /// @brief Validate the navigation table.
0164   /// @param top Placed volume to start from
0165   /// @param maxdepth Maximum geometry depth
0166   /// @return Success flag
0167   bool Validate(VPlacedVolume const *top, int maxdepth) const;
0168 
0169   /// @brief Validate a single state against the built table
0170   /// @param state State to validate
0171   /// @param error Error code
0172   /// @return Corresponding navigation index for the deepest scene (0 = failure)
0173   NavIndex_t ValidateState(NavStatePath *state, int &error);
0174 
0175   /// @brief Recursive tree traversal keeping track of the state context and applying the injected
0176   /// visitor to create the navigation index table
0177   /// @tparam Visitor Visitor type
0178   /// @param currentvolume Placed volume currently visited
0179   /// @param visitor Visitor object
0180   /// @param state Current navigation state path
0181   /// @param id Unique touchable index (incremental)
0182   /// @param level Current depth in the tree
0183   /// @param mother Mother navigation index
0184   /// @param dind Child index
0185   template <typename Visitor>
0186   static int visitAllPlacedVolumesNavIndex(VPlacedVolume const *currentvolume, Visitor *visitor, NavStatePath *state,
0187                                            NavIndex_t &id, int level = 0, NavIndex_t mother = 0, int dind = 0)
0188   {
0189     if (currentvolume != NULL) {
0190       state->Push(currentvolume);
0191       NavIndex_t new_mother = visitor->apply(state, level, mother, dind, id);
0192       auto ierr             = visitor->GetError();
0193       if (ierr) return ierr;
0194       int size = currentvolume->GetDaughters().size();
0195       for (int i = 0; i < size; ++i) {
0196         ierr = visitAllPlacedVolumesNavIndex(currentvolume->GetDaughters().operator[](i), visitor, state, id, level + 1,
0197                                              new_mother, i);
0198         if (ierr) return ierr;
0199       }
0200       state->Pop();
0201     }
0202     return 0;
0203   }
0204 
0205   /// @brief Recursive tree traversal keeping track of the state context and applying the injected
0206   /// visitor to create the navigation tuple table
0207   /// @tparam Visitor Visitor type
0208   /// @param currentvolume Placed volume currently visited
0209   /// @param visitor Visitor object
0210   /// @param state Current navigation state path
0211   /// @param id Unique touchable index (incremental)
0212   /// @param scene_id Unique scene index (incremental)
0213   /// @param level Current depth in the tree
0214   /// @param mother Mother navigation index
0215   /// @param dind Child index
0216   /// @param new_scene Nodes have to be placed in a new scene
0217   template <typename Visitor>
0218   static int visitAllPlacedVolumesNavTuple(VPlacedVolume const *currentvolume, Visitor *visitor, NavStatePath *state,
0219                                            NavIndex_t &id, int &iscene, int scene_id, int level = 0,
0220                                            NavIndex_t mother = 0, int dind = 0, bool new_scene = false)
0221   {
0222     if (currentvolume != NULL) {
0223       auto lvol = currentvolume->GetLogicalVolume();
0224       int ivol  = lvol->id();
0225       state->Push(currentvolume);
0226       bool selected    = visitor->IsSelected(ivol);
0227       bool visited     = visitor->IsVisited(ivol);
0228       int new_scene_id = scene_id;
0229       // increment new scene id if this is an unvisited scene
0230       if (selected) {
0231         if (!visited) {
0232           new_scene_id = ++iscene;
0233           visitor->SetSceneId(ivol, new_scene_id);
0234         } else {
0235           new_scene_id = visitor->GetSceneId(ivol);
0236         }
0237       }
0238       NavIndex_t id_bak     = id;
0239       NavIndex_t new_mother = visitor->apply_tuple(state, level, mother, dind, id, scene_id, new_scene_id);
0240       auto ierr             = visitor->GetError();
0241       if (ierr) return ierr;
0242       if (!visited) {
0243         int size                  = currentvolume->GetDaughters().size();
0244         NavStatePath *scene_state = nullptr;
0245         if (selected) {
0246           scene_state = NavStatePath::MakeInstance(GeoManager::Instance().getMaxDepth());
0247           scene_state->Push(GeoManager::Instance().GetWorld());
0248           VECGEOM_ASSERT(visitor->IsVisited(ivol));
0249           id    = 1; // index 0 not used
0250           level = 0;
0251         }
0252         for (int i = 0; i < size; ++i) {
0253           ierr = visitAllPlacedVolumesNavTuple(currentvolume->GetDaughters().operator[](i), visitor,
0254                                                scene_state ? scene_state : state, id, iscene, new_scene_id, level + 1,
0255                                                new_mother, i, selected);
0256           if (ierr) return ierr;
0257         }
0258         if (selected) {
0259           NavStatePath::ReleaseInstance(scene_state);
0260           id = ++id_bak;
0261         }
0262       }
0263       state->Pop();
0264     }
0265     return 0;
0266   }
0267 };
0268 
0269 } // namespace VECGEOM_IMPL_NAMESPACE
0270 } // namespace vecgeom
0271 
0272 #endif