From 6abf73f3c2ee0074034937bff5cfdc663cd3f82d Mon Sep 17 00:00:00 2001
From: Markus Frank <markus.frank@cern.ch>
Date: Tue, 12 Jul 2016 14:52:43 +0000
Subject: [PATCH] Optimize G4 hits collections

---
 DDG4/include/DDG4/Geant4HitCollection.h | 46 ++++++++++++++++++++-----
 DDG4/include/DDG4/Geant4SensDetAction.h |  3 +-
 DDG4/plugins/Geant4SDActions.cpp        | 15 ++++----
 DDG4/src/Geant4HitCollection.cpp        | 13 ++++++-
 4 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/DDG4/include/DDG4/Geant4HitCollection.h b/DDG4/include/DDG4/Geant4HitCollection.h
index d65ef7766..f36d9a25c 100644
--- a/DDG4/include/DDG4/Geant4HitCollection.h
+++ b/DDG4/include/DDG4/Geant4HitCollection.h
@@ -198,13 +198,15 @@ namespace DD4hep {
      *  \version 1.0
      *  \ingroup DD4HEP_SIMULATION
      */
-    class Geant4HitCollection: public G4VHitsCollection {
+    class Geant4HitCollection : public G4VHitsCollection {
     public:
       /** Local type declarations  */
       /// Hit wrapper
       typedef std::vector<Geant4HitWrapper>    WrappedHits;
       /// Hit manipulator
       typedef Geant4HitWrapper::HitManipulator Manip;
+      /// Hit key map for fast random lookup
+      typedef std::map<VolumeID, size_t>  Keys;
 
       /// Generic class template to compare/select hits in Geant4HitCollection objects
       /**
@@ -223,6 +225,14 @@ namespace DD4hep {
         virtual void* operator()(const Geant4HitWrapper& w) const = 0;
       };
 
+      union CollectionFlags  {
+        unsigned long        value;
+        struct BitItems  {
+          unsigned           repeatedLookup:1;
+          unsigned           mappedLookup:1;
+        }                    bits;
+      };
+
     protected:
       /// The collection of hit pointers in the wrapped format
       WrappedHits                      m_hits;
@@ -232,20 +242,18 @@ namespace DD4hep {
       Manip*                           m_manipulator;
       /// Memorize for speedup the last searched hit
       size_t                           m_lastHit;
+      /// Hit key map for fast random lookup
+      Keys                             m_keys;
       /// Optimization flags
-      union CollectionFlags  {
-        unsigned long        value;
-        struct BitItems  {
-          unsigned           repeatedLookup:1;
-          unsigned           mappedLookup:1;
-        }                    bits;
-      }                                m_flags;
+      CollectionFlags                  m_flags;
       
     protected:
       /// Notification to increase the instance counter
       void newInstance();
       /// Find hit in a collection by comparison of attributes
       void* findHit(const Compare& cmp);
+      /// Find hit in a collection by comparison of the key
+      Geant4HitWrapper* findHitByKey(VolumeID key);
       /// Release all hits from the Geant4 container and pass ownership to the caller
       void releaseData(const ComponentCast& cast, std::vector<void*>* result);
       /// Release all hits from the Geant4 container. Ownership stays with the container
@@ -279,7 +287,7 @@ namespace DD4hep {
       {
         newInstance();
         m_hits.reserve(200);
-        m_flags.value = OPTIMIZE_REPEATEDLOOKUP;
+        m_flags.value = 0;//OPTIMIZE_REPEATEDLOOKUP;
       }
       /// Default destructor
       virtual ~Geant4HitCollection();
@@ -323,10 +331,29 @@ namespace DD4hep {
         m_lastHit = m_hits.size();
         m_hits.push_back(w);
       }
+      /// Add a new hit with a check, that the hit is of the same type
+      template <typename TYPE> void add(VolumeID key, TYPE* hit_pointer) {
+        m_lastHit = m_hits.size();
+        std::pair<Keys::iterator,bool> ret = m_keys.insert(std::make_pair(key,m_lastHit));
+        if ( ret.second )  {
+          Geant4HitWrapper w(m_manipulator->castHit(hit_pointer));
+          m_hits.push_back(w);
+          return;
+        }
+        throw std::runtime_error("Attempt to insert hit with same key to G4 hit-collection "+GetName());
+      }
       /// Find hits in a collection by comparison of attributes
       template <typename TYPE> TYPE* find(const Compare& cmp) {
         return (TYPE*) findHit(cmp);
       }
+      /// Find hits in a collection by comparison of key value
+      template <typename TYPE> TYPE* findByKey(VolumeID key) {
+        Keys::const_iterator i=m_keys.find(key);
+        if ( i == m_keys.end() ) return 0;
+        m_lastHit = (*i).second;
+        TYPE* obj = m_hits.at(m_lastHit);
+        return obj;
+      }
       /// Release all hits from the Geant4 container and pass ownership to the caller
       template <typename TYPE> std::vector<TYPE*> releaseHits() {
         std::vector<TYPE*> vec;
@@ -334,6 +361,7 @@ namespace DD4hep {
           releaseData(ComponentCast::instance<TYPE>(), (std::vector<void*>*) &vec);
         }
         m_lastHit = ULONG_MAX;
+        m_keys.clear();
         return vec;
       }
       /// Release all hits from the Geant4 container and pass ownership to the caller
diff --git a/DDG4/include/DDG4/Geant4SensDetAction.h b/DDG4/include/DDG4/Geant4SensDetAction.h
index 60b333071..0e6da962a 100644
--- a/DDG4/include/DDG4/Geant4SensDetAction.h
+++ b/DDG4/include/DDG4/Geant4SensDetAction.h
@@ -312,7 +312,8 @@ namespace DD4hep {
       /// The true sensitive type of the detector
       std::string m_sensitiveType;
       /// Create a new typed hit collection
-      template <typename TYPE> static Geant4HitCollection* _create(const std::string& det, const std::string& coll, Geant4Sensitive* sd) {
+      template <typename TYPE> static 
+      Geant4HitCollection* _create(const std::string& det, const std::string& coll, Geant4Sensitive* sd) {
         return new Geant4HitCollection(det, coll, sd, (TYPE*) 0);
       }
 
diff --git a/DDG4/plugins/Geant4SDActions.cpp b/DDG4/plugins/Geant4SDActions.cpp
index f06639fa9..00bbd71d4 100644
--- a/DDG4/plugins/Geant4SDActions.cpp
+++ b/DDG4/plugins/Geant4SDActions.cpp
@@ -107,7 +107,8 @@ namespace DD4hep {
       StepHandler h(step);
       HitContribution contrib = Hit::extractContribution(step);
       HitCollection*  coll    = collection(m_collectionID);
-      long long int cell;
+      VolumeID cell = 0;
+
       try {
         cell = cellID(step);
       } catch(std::runtime_error &e) {
@@ -128,14 +129,15 @@ namespace DD4hep {
         return true;
       }
 
-      Hit* hit = coll->find<Hit>(CellIDCompare<Hit>(cell));
+      //Hit* hit = coll->find<Hit>(CellIDCompare<Hit>(cell));
+      Hit* hit = coll->findByKey<Hit>(cell);
       if ( !hit ) {
         Geant4TouchableHandler handler(step);
         DDSegmentation::Vector3D pos = m_segmentation.position(cell);
         Position global = h.localToGlobal(pos);
         hit = new Hit(global);
         hit->cellID = cell;
-        coll->add(hit);
+        coll->add(cell, hit);
         printM2("%s> CREATE hit with deposit:%e MeV  Pos:%8.2f %8.2f %8.2f  %s  [%s]",
                 c_name(),contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str(),
                 coll->GetName().c_str());
@@ -245,7 +247,7 @@ namespace DD4hep {
       StepHandler h(step);
       HitContribution contrib = Hit::extractContribution(step,true);
       HitCollection*  coll    = collection(m_collectionID);
-      long long int cell;
+      VolumeID cell = 0;
       try {
         cell = cellID(step);
       } catch(std::runtime_error &e) {
@@ -266,14 +268,15 @@ namespace DD4hep {
         return true;
       }
 
-      Hit* hit = coll->find<Hit>(CellIDCompare<Hit>(cell));
+      //Hit* hit = coll->find<Hit>(CellIDCompare<Hit>(cell));
+      Hit* hit = coll->findByKey<Hit>(cell);
       if ( !hit ) {
         Geant4TouchableHandler handler(step);
         DDSegmentation::Vector3D pos = m_segmentation.position(cell);
         Position global = h.localToGlobal(pos);
         hit = new Hit(global);
         hit->cellID = cell;
-        coll->add(hit);
+        coll->add(cell, hit);
         printM2("CREATE hit with deposit:%e MeV  Pos:%8.2f %8.2f %8.2f  %s",
                 contrib.deposit,pos.X,pos.Y,pos.Z,handler.path().c_str());
         if ( 0 == hit->cellID )  { // for debugging only!
diff --git a/DDG4/src/Geant4HitCollection.cpp b/DDG4/src/Geant4HitCollection.cpp
index 8859627c7..a6f6988f6 100644
--- a/DDG4/src/Geant4HitCollection.cpp
+++ b/DDG4/src/Geant4HitCollection.cpp
@@ -81,6 +81,7 @@ Geant4HitCollection::Compare::~Compare()  {
 /// Default destructor
 Geant4HitCollection::~Geant4HitCollection() {
   m_hits.clear();
+  m_keys.clear();
   InstanceCount::decrement(this);
 }
 
@@ -103,6 +104,7 @@ void Geant4HitCollection::newInstance() {
 void Geant4HitCollection::clear()   {
   m_lastHit = ULONG_MAX;
   m_hits.clear();
+  m_keys.clear();
 }
 
 /// Find hit in a collection by comparison of attributes
@@ -121,6 +123,14 @@ void* Geant4HitCollection::findHit(const Compare& cmp)  {
   return p;
 }
 
+/// Find hit in a collection by comparison of the key
+Geant4HitWrapper* Geant4HitCollection::findHitByKey(VolumeID key)   {
+  Keys::const_iterator i=m_keys.find(key);
+  if ( i == m_keys.end() ) return 0;
+  m_lastHit = (*i).second;
+  return &m_hits.at(m_lastHit);
+}
+
 /// Release all hits from the Geant4 container and pass ownership to the caller
 void Geant4HitCollection::releaseData(const ComponentCast& cast, std::vector<void*>* result) {
   for (size_t j = 0, n = m_hits.size(); j < n; ++j) {
@@ -132,6 +142,7 @@ void Geant4HitCollection::releaseData(const ComponentCast& cast, std::vector<voi
       result->push_back(m->cast.apply_downCast(cast, w.release()));
   }
   m_lastHit = ULONG_MAX;
+  m_keys.clear();
 }
 
 /// Release all hits from the Geant4 container. Ownership stays with the container
@@ -153,6 +164,7 @@ void Geant4HitCollection::releaseHitsUnchecked(std::vector<void*>& result) {
     result.push_back(w.release());
   }
   m_lastHit = ULONG_MAX;
+  m_keys.clear();
 }
 
 /// Release all hits from the Geant4 container. Ownership stays with the container
@@ -161,5 +173,4 @@ void Geant4HitCollection::getHitsUnchecked(std::vector<void*>& result) {
     Geant4HitWrapper& w = m_hits.at(j);
     result.push_back(w.data());
   }
-  m_lastHit = ULONG_MAX;
 }
-- 
GitLab