diff --git a/DDG4/include/DDG4/Geant4HitCollection.h b/DDG4/include/DDG4/Geant4HitCollection.h
index 06d9dc07825d98972c98385600ceac545ff91be1..d65ef776659b2f30dd6715aed5c2ca8be86be5a9 100644
--- a/DDG4/include/DDG4/Geant4HitCollection.h
+++ b/DDG4/include/DDG4/Geant4HitCollection.h
@@ -23,6 +23,7 @@
// C/C++ include files
#include <vector>
#include <string>
+#include <climits>
#include <typeinfo>
#include <stdexcept>
@@ -174,6 +175,25 @@ namespace DD4hep {
* Polymorphism without an explicit type would only
* confuse most users.
*
+ * Note:
+ * This hit collection is optimized to search repeatedly the same cell using
+ *
+ * template <typename TYPE> TYPE* find(const Compare& cmp) const;
+ *
+ * by remembering the last search index.
+ * The collection uses this optimization if the corresponding flag
+ * OPTIMIZE_REPEATEDLOOKUP is set:
+ *
+ * setOptimize(OPTIMIZE_REPEATEDLOOKUP);
+ *
+ * The last search index is automatically set to last object insertion,
+ * if one happened between 2 search calls. For the typical use case,
+ * there always contributions to the same hit are added, this should
+ * reduce the lookup speed from O(n) to O(1).
+ * This obviously only helps, if contributions to the same cell come in
+ * sequence ie. from the same G4Track.
+ *
+ *
* \author M.Frank
* \version 1.0
* \ingroup DD4HEP_SIMULATION
@@ -205,38 +225,61 @@ namespace DD4hep {
protected:
/// The collection of hit pointers in the wrapped format
- WrappedHits m_hits;
+ WrappedHits m_hits;
/// Handle to the sensitive detector
- Geant4Sensitive* m_detector;
+ Geant4Sensitive* m_detector;
/// The type of the objects in this collection. Set by the constructor
- Manip* m_manipulator;
-
+ Manip* m_manipulator;
+ /// Memorize for speedup the last searched hit
+ size_t m_lastHit;
+ /// Optimization flags
+ union CollectionFlags {
+ unsigned long value;
+ struct BitItems {
+ unsigned repeatedLookup:1;
+ unsigned mappedLookup:1;
+ } bits;
+ } 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) const;
+ void* findHit(const Compare& cmp);
/// 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
void getData(const ComponentCast& cast, std::vector<void*>* result);
public:
+ enum {
+ OPTIMIZE_NONE = 0,
+ OPTIMIZE_REPEATEDLOOKUP = 1<<0,
+ OPTIMIZE_MAPPEDLOOKUP = 1<<1,
+ OPTIMIZE_LAST
+ } OptimizationFlags;
+
/// Initializing constructor (C++ version)
template <typename TYPE>
Geant4HitCollection(const std::string& det, const std::string& coll, Geant4Sensitive* sd)
: G4VHitsCollection(det, coll), m_detector(sd),
- m_manipulator(Geant4HitWrapper::manipulator<TYPE>()) {
+ m_manipulator(Geant4HitWrapper::manipulator<TYPE>()),
+ m_lastHit(ULONG_MAX)
+ {
newInstance();
m_hits.reserve(200);
+ m_flags.value = OPTIMIZE_REPEATEDLOOKUP;
}
/// Initializing constructor
template <typename TYPE>
Geant4HitCollection(const std::string& det, const std::string& coll, Geant4Sensitive* sd, const TYPE*)
: G4VHitsCollection(det, coll), m_detector(sd),
- m_manipulator(Geant4HitWrapper::manipulator<TYPE>()) {
+ m_manipulator(Geant4HitWrapper::manipulator<TYPE>()),
+ m_lastHit(ULONG_MAX)
+ {
newInstance();
m_hits.reserve(200);
+ m_flags.value = OPTIMIZE_REPEATEDLOOKUP;
}
/// Default destructor
virtual ~Geant4HitCollection();
@@ -246,6 +289,10 @@ namespace DD4hep {
const ComponentCast& vector_type() const;
/// Clear the collection (Deletes all valid references to real hits)
virtual void clear();
+ /// Set optimization flags
+ void setOptimize(int flag) {
+ m_flags.value |= flag;
+ }
/// Set the sensitive detector
void setSensitive(Geant4Sensitive* detector) {
m_detector = detector;
@@ -273,10 +320,11 @@ namespace DD4hep {
/// Add a new hit with a check, that the hit is of the same type
template <typename TYPE> void add(TYPE* hit_pointer) {
Geant4HitWrapper w(m_manipulator->castHit(hit_pointer));
+ m_lastHit = m_hits.size();
m_hits.push_back(w);
}
/// Find hits in a collection by comparison of attributes
- template <typename TYPE> TYPE* find(const Compare& cmp) const {
+ template <typename TYPE> TYPE* find(const Compare& cmp) {
return (TYPE*) findHit(cmp);
}
/// Release all hits from the Geant4 container and pass ownership to the caller
@@ -285,6 +333,7 @@ namespace DD4hep {
if (m_hits.size() != 0) {
releaseData(ComponentCast::instance<TYPE>(), (std::vector<void*>*) &vec);
}
+ m_lastHit = ULONG_MAX;
return vec;
}
/// Release all hits from the Geant4 container and pass ownership to the caller
diff --git a/DDG4/src/Geant4HitCollection.cpp b/DDG4/src/Geant4HitCollection.cpp
index aa9cfc5f897ca564d6f77d688501f7b6de1ec660..8859627c7a18c717c93f487969889849723a329b 100644
--- a/DDG4/src/Geant4HitCollection.cpp
+++ b/DDG4/src/Geant4HitCollection.cpp
@@ -101,15 +101,23 @@ void Geant4HitCollection::newInstance() {
/// Clear the collection (Deletes all valid references to real hits)
void Geant4HitCollection::clear() {
+ m_lastHit = ULONG_MAX;
m_hits.clear();
}
/// Find hit in a collection by comparison of attributes
-void* Geant4HitCollection::findHit(const Compare& cmp) const {
+void* Geant4HitCollection::findHit(const Compare& cmp) {
void* p = 0;
- for (WrappedHits::const_iterator i = m_hits.begin(); i != m_hits.end(); ++i)
- if ((p = cmp(*i)) != 0)
+ WrappedHits::const_iterator i = m_hits.begin();
+ if ( m_flags.bits.repeatedLookup && m_lastHit < m_hits.size() ) {
+ if ( (p = cmp(*(i+m_lastHit))) != 0 ) return p;
+ }
+ for (size_t cnt=0; i != m_hits.end(); ++i, ++cnt) {
+ if ((p = cmp(*i)) != 0) {
+ m_lastHit = cnt;
return p;
+ }
+ }
return p;
}
@@ -123,6 +131,7 @@ void Geant4HitCollection::releaseData(const ComponentCast& cast, std::vector<voi
else
result->push_back(m->cast.apply_downCast(cast, w.release()));
}
+ m_lastHit = ULONG_MAX;
}
/// Release all hits from the Geant4 container. Ownership stays with the container
@@ -143,6 +152,7 @@ void Geant4HitCollection::releaseHitsUnchecked(std::vector<void*>& result) {
Geant4HitWrapper& w = m_hits.at(j);
result.push_back(w.release());
}
+ m_lastHit = ULONG_MAX;
}
/// Release all hits from the Geant4 container. Ownership stays with the container
@@ -151,4 +161,5 @@ void Geant4HitCollection::getHitsUnchecked(std::vector<void*>& result) {
Geant4HitWrapper& w = m_hits.at(j);
result.push_back(w.data());
}
+ m_lastHit = ULONG_MAX;
}