From b4f263c2e73fed78dfbf91d9686101b97cd18e0a Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Wed, 3 Jul 2024 17:09:06 +0200
Subject: [PATCH] Cosmetic changes only

---
 .../include/DDG4/Geant4DetectorConstruction.h |   5 +-
 DDG4/include/DDG4/Geant4Kernel.h              |  19 ++-
 .../Geant4DetectorGeometryConstruction.cpp    |   6 +-
 .../Geant4DetectorSensitivesConstruction.cpp  |  38 ++----
 DDG4/plugins/Geant4SDActions.cpp              |  28 +++--
 DDG4/python/DDG4.py                           |   6 +
 DDG4/src/Geant4Converter.cpp                  |  10 +-
 DDG4/src/Geant4DetectorConstruction.cpp       |  66 +++++++----
 DDG4/src/Geant4Kernel.cpp                     |  22 +++-
 DDG4/src/Geant4VolumeManager.cpp              | 108 +++++++++---------
 .../DDG4_MySensDet/src/MyTrackerSDAction.cpp  |  32 ++++--
 11 files changed, 198 insertions(+), 142 deletions(-)

diff --git a/DDG4/include/DDG4/Geant4DetectorConstruction.h b/DDG4/include/DDG4/Geant4DetectorConstruction.h
index f63b7f937..9a227977a 100644
--- a/DDG4/include/DDG4/Geant4DetectorConstruction.h
+++ b/DDG4/include/DDG4/Geant4DetectorConstruction.h
@@ -73,7 +73,7 @@ namespace dd4hep {
       /// G4 User detector initializer
       G4VUserDetectorConstruction* detector  { nullptr };
       /// Initializing Constructor
-      Geant4DetectorConstructionContext(Detector& l,G4VUserDetectorConstruction* d)
+      Geant4DetectorConstructionContext(Detector& l, G4VUserDetectorConstruction* d)
         : description(l), world(0), geometry(0), detector(d)  { }
       /// Default destructor
       ~Geant4DetectorConstructionContext()             { }
@@ -111,6 +111,9 @@ namespace dd4hep {
       virtual void constructField(Geant4DetectorConstructionContext* ctxt);
       /// Sensitive detector construction callback. Called at "ConstructSDandField()"
       virtual void constructSensitives(Geant4DetectorConstructionContext* ctxt);
+      /// Create Geant4 sensitive detector object using the factory mechanism
+      virtual G4VSensitiveDetector* createSensitiveDetector(const std::string& type,
+                                                            const std::string& name);
     };
 
     /// Concrete basic implementation of the Geant4 detector construction sequencer.
diff --git a/DDG4/include/DDG4/Geant4Kernel.h b/DDG4/include/DDG4/Geant4Kernel.h
index 5a055c4d0..03bfeed8d 100644
--- a/DDG4/include/DDG4/Geant4Kernel.h
+++ b/DDG4/include/DDG4/Geant4Kernel.h
@@ -88,20 +88,20 @@ namespace dd4hep {
       /// Property: Name of the UI action. Must be member of the global actions
       std::string   m_uiName                   { };
       /// Property: Name of the G4 run manager factory to be used. Default: Geant4RunManager
-      std::string m_runManagerType;
+      std::string   m_runManagerType;
       /// Property: Name of the default factory to create G4VSensitiveDetector instances
-      std::string m_dfltSensitiveDetectorType;
+      std::string   m_dfltSensitiveDetectorType;
       /// Property: Names with specialized factories to create G4VSensitiveDetector instances
       std::map<std::string, std::string> m_sensitiveDetectorTypes;
       /// Property: Number of events to be executed in batch mode
-      long        m_numEvent = 10;
+      long          m_numEvent = 10;
       /// Property: Output level
-      int         m_outputLevel = 0;
+      int           m_outputLevel = 0;
 
       /// Master property: Number of execution threads in multi threaded mode.
-      int         m_numThreads = 0;
+      int           m_numThreads = 0;
       /// Master property: Instantiate the Geant4 scoring manager object
-      int         m_haveScoringMgr = false;
+      int           m_haveScoringMgr = false;
       
       /// Registered action callbacks on configure
       UserCallbacks m_actionConfigure  { };
@@ -205,6 +205,13 @@ namespace dd4hep {
       const std::map<std::string, std::string>& sensitiveDetectorTypes()  const   {
         return m_sensitiveDetectorTypes;
       }
+      /// Add new sensitive type to factory list
+      /** This is present mainly for debugging purposes and tests.
+       * Never necessary in real life!
+       * For all practical purpose the default type Geant4SensDet is sufficient.
+       *
+       */
+      void defineSensitiveDetectorType(const std::string& type, const std::string& factory);
       /// Access to geometry world
       G4VPhysicalVolume* world()  const;
       /// Set the geometry world
diff --git a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
index 8d79de9e5..2b9f37b5a 100644
--- a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
+++ b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp
@@ -194,7 +194,7 @@ void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstruction
 
 std::pair<std::string, dd4hep::PlacedVolume>
 Geant4DetectorGeometryConstruction::resolve_path(const char* vol_path)  const {
-  std::string       p   = vol_path;
+  std::string  p   = vol_path;
   Detector&    det = context()->kernel().detectorDescription();
   PlacedVolume top = det.world().placement();
   PlacedVolume pv  = detail::tools::findNode(top, p);
@@ -437,7 +437,7 @@ int Geant4DetectorGeometryConstruction::writeGDML(const char* output)  {
 
 void Geant4DetectorGeometryConstruction::printG4(const std::string& prefix, const G4VPhysicalVolume* g4pv)    const   {
   std::string path = prefix + "/";
-  printP2(  "+++  GEANT4 volume: %s", prefix.c_str());
+  printP2("+++  GEANT4 volume: %s", prefix.c_str());
   auto* g4v = g4pv->GetLogicalVolume();
   for(size_t i=0, n=g4v->GetNoDaughters(); i<n; ++i)    {
     auto* dau = g4v->GetDaughter(i);
@@ -480,5 +480,3 @@ void Geant4DetectorGeometryConstruction::installCommandMessenger()   {
   m_control->addCall("printMaterial", "Print Geant4 material properties [uses argument]",
                      Callback(this).make(&Geant4DetectorGeometryConstruction::printMaterial),1);
 }
-
-
diff --git a/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp
index f23dc4611..73d55c2aa 100644
--- a/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp
+++ b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp
@@ -86,36 +86,18 @@ void Geant4DetectorSensitivesConstruction::constructSensitives(Geant4DetectorCon
   const std::string&  dflt   = kernel.defaultSensitiveDetectorType();
   for( const auto& iv : p->sensitives )  {
     SensitiveDetector sd = iv.first;
-    std::string nam = sd.name();
-    auto iter = types.find(nam);
-    std::string typ = (iter != types.end()) ? (*iter).second : dflt;
-    G4VSensitiveDetector* g4sd = 
-      PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->description);
-    if (g4sd) {
-      print("Geant4SDConstruction", "+++ Subdetector: %-32s  type: %-16s factory: %s.",
-            nam.c_str(), sd.type().c_str(), typ.c_str());
-    }
-    else  {
-      PluginDebug dbg;
-      g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->description);
-      if ( !g4sd )  {
-        throw std::runtime_error("ConstructSDandField: FATAL Failed to "
-                                 "create Geant4 sensitive detector " + nam + 
-                                 " (" + sd.type() + ") of type " + typ + ".");
-      }
-      print("Geant4SDConstruction", "+++ Subdetector: %-32s  type: %-16s factory: %s.",
-            nam.c_str(), sd.type().c_str(), typ.c_str());
-    }
-    g4sd->Activate(true);
-    G4SDManager::GetSDMpointer()->AddNewDetector(g4sd);
-    for(const TGeoVolume* vol : iv.second )  {
+    std::string nam  = sd.name();
+    auto        iter = types.find(nam);
+    std::string typ  = (iter != types.end()) ? (*iter).second : dflt;
+    G4VSensitiveDetector* g4sd = this->createSensitiveDetector(typ, nam);
+    for( const TGeoVolume* vol : iv.second )  {
       G4LogicalVolume* g4v = p->g4Volumes[vol];
-      if ( !g4v )  {
-        throw std::runtime_error("ConstructSDandField: Failed to access G4LogicalVolume for SD "+
-                                 nam + " of type " + typ + ".");
+      if( !g4v )  {
+        except("ConstructSDandField: Failed to access G4LogicalVolume for SD %s of type %s.",
+               nam.c_str(), typ.c_str());
       }
-      ctxt->setSensitiveDetector(g4v,g4sd);
+      ctxt->setSensitiveDetector(g4v, g4sd);
     }
   }
-  print("Geant4SDConstruction", "+++ Handled %ld sensitive detectors.",p->sensitives.size());
+  print("+++ Handled %ld sensitive detectors.",p->sensitives.size());
 }
diff --git a/DDG4/plugins/Geant4SDActions.cpp b/DDG4/plugins/Geant4SDActions.cpp
index de9aba8e5..c3b734e55 100644
--- a/DDG4/plugins/Geant4SDActions.cpp
+++ b/DDG4/plugins/Geant4SDActions.cpp
@@ -296,7 +296,7 @@ namespace dd4hep {
       }
       Hit* hit = coll->findByKey<Hit>(cell);
       if ( !hit ) {
-	Geant4TouchableHandler   handler(h.touchable());
+        Geant4TouchableHandler   handler(h.touchable());
         DDSegmentation::Vector3D pos = m_segmentation.position(cell);
         Position global = h.localToGlobal(pos);
         hit = new Hit(global);
@@ -507,7 +507,7 @@ namespace dd4hep {
       }
       Hit* hit = coll->findByKey<Hit>(cell);
       if ( !hit ) {
-	Geant4TouchableHandler   handler(h.touchable());
+        Geant4TouchableHandler   handler(h.touchable());
         DDSegmentation::Vector3D pos = m_segmentation.position(cell);
         Position global = h.localToGlobal(pos);
         hit = new Hit(global);
@@ -577,13 +577,13 @@ namespace dd4hep {
       }
       void start(const G4Step* step, const G4StepPoint* point)   {
         pre.storePoint(step,point);
-	start_collecting(step->GetTrack());
-	firstSpotVolume = step->GetPreStepPoint()->GetTouchableHandle()->GetVolume();
+        start_collecting(step->GetTrack());
+        firstSpotVolume = step->GetPreStepPoint()->GetTouchableHandle()->GetVolume();
       }
       void start(const Geant4FastSimSpot* spot)   {
         pre.storePoint(spot);
-	start_collecting(spot->primary);
-	firstSpotVolume = spot->volume();
+        start_collecting(spot->primary);
+        firstSpotVolume = spot->volume();
       }
 
       /// Update energy and track information during hit info accumulation
@@ -604,11 +604,11 @@ namespace dd4hep {
       }
       void update(const Geant4StepHandler& h) {
         post.storePoint(h.step, h.post);
-	update_collected_hit(h.preTouchable(), h.avgPositionG4()); // Compute cellID
+        update_collected_hit(h.preTouchable(), h.avgPositionG4()); // Compute cellID
       }
       void update(const Geant4FastSimHandler& h)   {
         post.storePoint(h.spot);
-	update_collected_hit(h.touchable(), h.avgPositionG4());       // Compute cellID
+        update_collected_hit(h.touchable(), h.avgPositionG4());       // Compute cellID
       }
 
       /// Clear collected information and restart for new hit
@@ -620,7 +620,7 @@ namespace dd4hep {
         current = -1;
         combined = 0;
         cell = 0;
-	firstSpotVolume = nullptr;
+        firstSpotVolume = nullptr;
       }
 
       /// Helper function to decide if the hit has to be extracted and saved in the collection
@@ -653,10 +653,8 @@ namespace dd4hep {
       /// Method for generating hit(s) using the information of G4Step object.
       G4bool process(const G4Step* step, G4TouchableHistory* ) {
         Geant4StepHandler h(step);
-
-	// std::cout << " process called - pre pos: " << h.prePos() << " post pos " << h.postPos() 
-	// 	  << " edep: " << h.deposit() << std::endl ;
-
+        // std::cout << " process called - pre pos: " << h.prePos() << " post pos " << h.postPos() 
+        // 	  << " edep: " << h.deposit() << std::endl ;
         void *prePV = h.volume(h.pre), *postPV = h.volume(h.post);
 
         Geant4HitCollection* coll = sensitive->collection(0);
@@ -689,7 +687,7 @@ namespace dd4hep {
 
       /// Method for generating hit(s) using the information of fast simulation spot object.
       G4bool process(const Geant4FastSimSpot* spot, G4TouchableHistory* ) {
-	Geant4FastSimHandler h(spot);
+        Geant4FastSimHandler h(spot);
         G4VPhysicalVolume*   prePV = firstSpotVolume, *postPV = h.volume();
         Geant4HitCollection* coll  = sensitive->collection(0);
         /// If we are handling a new track, then store the content of the previous one.
@@ -716,7 +714,7 @@ namespace dd4hep {
         else if ( h.track->GetTrackStatus() == fStopAndKill ) {
           extractHit(coll);
         }
-	return true;
+        return true;
       }
 
       /// Post-event action callback
diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py
index 41007834e..b85a3711d 100644
--- a/DDG4/python/DDG4.py
+++ b/DDG4/python/DDG4.py
@@ -680,7 +680,10 @@ class Geant4:
     self.description.sensitiveDetector(str(name))
     # sd.setType('calorimeter')
     if typ is None:
+      type = 'calorimeter'
       typ = self.sensitive_types['calorimeter']
+    elif typ is not None and self.sensitive_types.get(typ):
+      typ = self.sensitive_types[typ]
     return self.setupDetector(name, typ, collections)
 
   def setupTracker(self, name, type=None, collections=None):  # noqa: A002
@@ -693,7 +696,10 @@ class Geant4:
     self.description.sensitiveDetector(str(name))
     # sd.setType('tracker')
     if typ is None:
+      type = 'tracker'
       typ = self.sensitive_types['tracker']
+    elif typ is not None and self.sensitive_types.get(typ):
+      typ = self.sensitive_types[typ]
     return self.setupDetector(name, typ, collections)
 
   def _private_setupField(self, field, stepper, equation, prt):
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index 8bfc8921b..3b8a6d5e5 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -34,6 +34,7 @@
 
 // ROOT includes
 #include <TClass.h>
+#include <TTimeStamp.h>
 #include <TGeoBoolNode.h>
 
 // Geant4 include files
@@ -1648,7 +1649,8 @@ void* Geant4Converter::printPlacement(const std::string& name, const TGeoNode* n
   printout(outputLevel, "G4Placement", str.str().c_str());
   printout(outputLevel, "G4Placement", printSolid(sol).c_str());
   str.str("");
-  str << "                  |" << " Ndau:" << vol->GetNoDaughters() << " physvols." << " Mat:" << vol->GetMaterial()->GetName()
+  str << "                  |" << " Ndau:" << vol->GetNoDaughters()
+      << " physvols." << " Mat:" << vol->GetMaterial()->GetName()
       << " Mother:" << (char*) (mot ? mot->GetName().c_str() : "---");
   printout(outputLevel, "G4Placement", str.str().c_str());
   str.str("");
@@ -1660,6 +1662,7 @@ void* Geant4Converter::printPlacement(const std::string& name, const TGeoNode* n
 /// Create geometry conversion
 Geant4Converter& Geant4Converter::create(DetElement top) {
   typedef std::map<const TGeoNode*, std::vector<TGeoNode*> > _DAU;
+  TTimeStamp start;
   _DAU daughters;
   Geant4GeometryInfo& geo = this->init();
   World wrld = top.world();
@@ -1710,6 +1713,9 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
   m_daughters = nullptr;
   geo.setWorld(top.placement().ptr());
   geo.valid = true;
-  printout(INFO, "Geant4Converter", "+++  Successfully converted geometry to Geant4.");
+  TTimeStamp stop;
+  printout(INFO, "Geant4Converter",
+           "+++  Successfully converted geometry to Geant4. [%7.3f seconds]",
+           stop.AsDouble()-start.AsDouble() );
   return *this;
 }
diff --git a/DDG4/src/Geant4DetectorConstruction.cpp b/DDG4/src/Geant4DetectorConstruction.cpp
index 2b0efa9ef..561c4a08e 100644
--- a/DDG4/src/Geant4DetectorConstruction.cpp
+++ b/DDG4/src/Geant4DetectorConstruction.cpp
@@ -12,6 +12,7 @@
 //==========================================================================
 
 // Framework include files
+#include <DD4hep/Plugins.h>
 #include <DD4hep/InstanceCount.h>
 #include <DDG4/Geant4Mapping.h>
 #include <DDG4/Geant4GeometryInfo.h>
@@ -23,7 +24,7 @@
 using namespace dd4hep::sim;
 
 /// Helper: Assign sensitive detector to logical volume
-void Geant4DetectorConstructionContext::setSensitiveDetector(G4LogicalVolume* vol, G4VSensitiveDetector* sd)   {
+void Geant4DetectorConstructionContext::setSensitiveDetector(G4LogicalVolume* vol, G4VSensitiveDetector* sd)  {
   //detector->SetSensitiveDetector(vol,sd);
   G4SDManager::GetSDMpointer()->AddNewDetector(sd);
   vol->SetSensitiveDetector(sd);
@@ -39,19 +40,44 @@ Geant4DetectorConstruction::Geant4DetectorConstruction(Geant4Context* ctxt, cons
 Geant4DetectorConstruction::~Geant4DetectorConstruction()  {
 }
 
+/// Create Geant4 sensitive detector object using the factory mechanism
+G4VSensitiveDetector*
+Geant4DetectorConstruction::createSensitiveDetector(const std::string& typ,
+                                                    const std::string& nam)  {
+  Detector& dsc = context()->detectorDescription();
+  G4VSensitiveDetector* g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &dsc);
+  if( g4sd )  {
+    print("+++ Subdetector: %-32s  type: %s.", nam.c_str(), typ.c_str());
+  }
+  else  {
+    PluginDebug dbg;
+    g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &dsc);
+    if ( !g4sd )  {
+      except("createSensitiveDetector: FATAL Failed to "
+             "create Geant4 sensitive detector %s of type %s.",
+             nam.c_str(), typ.c_str());
+    }
+    print("+++ Subdetector: %-32s  type: %s.", nam.c_str(), typ.c_str());
+  }
+  if ( g4sd )  {
+    g4sd->Activate(true);
+    G4SDManager::GetSDMpointer()->AddNewDetector(g4sd);
+  }
+  return g4sd;
+}
+
 /// Geometry construction callback. Called at "Construct()"
-void Geant4DetectorConstruction::constructGeo(Geant4DetectorConstructionContext* )   {
+void Geant4DetectorConstruction::constructGeo(Geant4DetectorConstructionContext* )  {
 }
 
 /// Electromagnetic field construction callback. Called at "ConstructSDandField()"
-void Geant4DetectorConstruction::constructField(Geant4DetectorConstructionContext* )   {
+void Geant4DetectorConstruction::constructField(Geant4DetectorConstructionContext* )  {
 }
 
 /// Sensitive detector construction callback. Called at "ConstructSDandField()"
-void Geant4DetectorConstruction::constructSensitives(Geant4DetectorConstructionContext* )   {
+void Geant4DetectorConstruction::constructSensitives(Geant4DetectorConstructionContext* )  {
 }
 
-
 /// Standard Constructor
 Geant4DetectorConstructionSequence::Geant4DetectorConstructionSequence(Geant4Context* ctxt, const std::string& nam)
   : Geant4Action(ctxt,nam)
@@ -61,19 +87,19 @@ Geant4DetectorConstructionSequence::Geant4DetectorConstructionSequence(Geant4Con
 }
 
 /// Default destructor
-Geant4DetectorConstructionSequence::~Geant4DetectorConstructionSequence()   {
+Geant4DetectorConstructionSequence::~Geant4DetectorConstructionSequence()  {
   m_actors(&Geant4DetectorConstruction::release);  
   InstanceCount::decrement(this);
 }
 
 /// Set or update client context
-void Geant4DetectorConstructionSequence::updateContext(Geant4Context* ctxt)   {
+void Geant4DetectorConstructionSequence::updateContext(Geant4Context* ctxt)  {
   m_context = ctxt;
   m_actors(&Geant4DetectorConstruction::updateContext,ctxt);  
 }
 
 /// Add an actor responding to all callbacks. Sequence takes ownership.
-void Geant4DetectorConstructionSequence::adopt(Geant4DetectorConstruction* action)   {
+void Geant4DetectorConstructionSequence::adopt(Geant4DetectorConstruction* action)  {
   if (action) {
     action->addRef();
     m_actors.add(action);
@@ -83,7 +109,7 @@ void Geant4DetectorConstructionSequence::adopt(Geant4DetectorConstruction* actio
 }
 
 /// Access an actor by name
-Geant4DetectorConstruction* Geant4DetectorConstructionSequence::get(const std::string& nam)  const   {
+Geant4DetectorConstruction* Geant4DetectorConstructionSequence::get(const std::string& nam)  const  {
   for(auto* i : m_actors)  {
     if ( i->name() == nam )  {
       return i;
@@ -94,23 +120,23 @@ Geant4DetectorConstruction* Geant4DetectorConstructionSequence::get(const std::s
 }
 
 /// Geometry construction callback. Called at "Construct()"
-void Geant4DetectorConstructionSequence::constructGeo(Geant4DetectorConstructionContext* ctxt)   {
+void Geant4DetectorConstructionSequence::constructGeo(Geant4DetectorConstructionContext* ctxt)  {
   m_actors(&Geant4DetectorConstruction::constructGeo, ctxt);  
 }
 
 /// Electromagnetic field construction callback. Called at "ConstructSDandField()"
-void Geant4DetectorConstructionSequence::constructField(Geant4DetectorConstructionContext* ctxt)   {
+void Geant4DetectorConstructionSequence::constructField(Geant4DetectorConstructionContext* ctxt)  {
   m_actors(&Geant4DetectorConstruction::constructField, ctxt);  
 }
 
 /// Sensitive detector construction callback. Called at "ConstructSDandField()"
-void Geant4DetectorConstructionSequence::constructSensitives(Geant4DetectorConstructionContext* ctxt)   {
+void Geant4DetectorConstructionSequence::constructSensitives(Geant4DetectorConstructionContext* ctxt)  {
   m_actors(&Geant4DetectorConstruction::constructSensitives, ctxt);  
 }
 
 /// Access to the converted regions
 const std::map<dd4hep::Region, G4Region*>&
-Geant4DetectorConstructionSequence::regions() const   {
+Geant4DetectorConstructionSequence::regions() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Regions;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::regions: Access not possible. Geometry is not yet converted!");
@@ -118,14 +144,14 @@ Geant4DetectorConstructionSequence::regions() const   {
 
 /// Access to the converted volumes
 const std::map<dd4hep::Volume, G4LogicalVolume*>&
-Geant4DetectorConstructionSequence::volumes() const   {
+Geant4DetectorConstructionSequence::volumes() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Volumes;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::volumes: Access not possible. Geometry is not yet converted!");
 }
 
 /// Access to the converted shapes
-const std::map<const TGeoShape*, G4VSolid*>& Geant4DetectorConstructionSequence::shapes() const   {
+const std::map<const TGeoShape*, G4VSolid*>& Geant4DetectorConstructionSequence::shapes() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Solids;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::shapes: Access not possible. Geometry is not yet converted!");
@@ -133,7 +159,7 @@ const std::map<const TGeoShape*, G4VSolid*>& Geant4DetectorConstructionSequence:
 
 /// Access to the converted limit sets
 const std::map<dd4hep::LimitSet, G4UserLimits*>&
-Geant4DetectorConstructionSequence::limits() const   {
+Geant4DetectorConstructionSequence::limits() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Limits;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::limits: Access not possible. Geometry is not yet converted!");
@@ -141,7 +167,7 @@ Geant4DetectorConstructionSequence::limits() const   {
 
 /// Access to the converted assemblies
 const std::map<dd4hep::PlacedVolume, Geant4AssemblyVolume*>&
-Geant4DetectorConstructionSequence::assemblies() const   {
+Geant4DetectorConstructionSequence::assemblies() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4AssemblyVolumes;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::assemblies: Access not possible. Geometry is not yet converted!");
@@ -149,21 +175,21 @@ Geant4DetectorConstructionSequence::assemblies() const   {
 
 /// Access to the converted placements
 const std::map<dd4hep::PlacedVolume, G4VPhysicalVolume*>&
-Geant4DetectorConstructionSequence::placements() const   {
+Geant4DetectorConstructionSequence::placements() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Placements;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::placements: Access not possible. Geometry is not yet converted!");
 }
 
 /// Access to the converted materials
-const Geant4GeometryMaps::MaterialMap& Geant4DetectorConstructionSequence::materials() const   {
+const Geant4GeometryMaps::MaterialMap& Geant4DetectorConstructionSequence::materials() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Materials;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::materials: Access not possible. Geometry is not yet converted!");
 }
 
 /// Access to the converted elements
-const Geant4GeometryMaps::ElementMap& Geant4DetectorConstructionSequence::elements() const   {
+const Geant4GeometryMaps::ElementMap& Geant4DetectorConstructionSequence::elements() const  {
   Geant4GeometryInfo* p = Geant4Mapping::instance().ptr();
   if ( p ) return p->g4Elements;
   throw std::runtime_error("+++ Geant4DetectorConstructionSequence::elements: Access not possible. Geometry is not yet converted!");
diff --git a/DDG4/src/Geant4Kernel.cpp b/DDG4/src/Geant4Kernel.cpp
index 00b004af8..dc85386dc 100644
--- a/DDG4/src/Geant4Kernel.cpp
+++ b/DDG4/src/Geant4Kernel.cpp
@@ -202,7 +202,7 @@ Geant4Kernel& Geant4Kernel::worker(unsigned long identifier, bool create_if)
       return *this;
     }
   }
-  else if ( create_if )  {
+  else if( create_if )  {
     return createWorker();
   }
   except("Geant4Kernel", "DDG4: The Kernel object 0x%p does not exists!",(void*)identifier);
@@ -216,16 +216,32 @@ int Geant4Kernel::numWorkers() const   {
 
 /// Access to geometry world
 G4VPhysicalVolume* Geant4Kernel::world()  const   {
-  if ( this != m_master ) return m_master->world();
+  if( this != m_master ) return m_master->world();
   return m_world;
 }
 
 /// Set the geometry world
 void Geant4Kernel::setWorld(G4VPhysicalVolume* volume)  {
-  if ( this == m_master ) m_world = volume;
+  if( this == m_master ) m_world = volume;
   else m_master->setWorld(volume);
 }
 
+/// Add new sensitive type to factory list
+void Geant4Kernel::defineSensitiveDetectorType(const std::string& type, const std::string& factory)  {
+  auto iter = m_sensitiveDetectorTypes.find(type);
+  if( iter == m_sensitiveDetectorTypes.end() )  {
+    printout(INFO,"Geant4Kernel","+++ Define sensitive type: %s -> %s", type.c_str(), factory.c_str());
+    m_sensitiveDetectorTypes.emplace(type, factory);
+    return;
+  }
+  else if( iter->first == type && iter->second == factory )  {
+    return;
+  }
+  except("Geant4Kernel",
+         "+++ The sensitive type %s is already defined and used %s. Cannot overwrite with %s",
+         type.c_str(), iter->second.c_str(), factory.c_str());
+}
+
 void Geant4Kernel::printProperties()  const  {
   printout(ALWAYS,"Geant4Kernel","OutputLevel:  %d", m_outputLevel);
   printout(ALWAYS,"Geant4Kernel","UI:           %s", m_uiName.c_str());
diff --git a/DDG4/src/Geant4VolumeManager.cpp b/DDG4/src/Geant4VolumeManager.cpp
index a2e1d2cb1..a24ee1e5e 100644
--- a/DDG4/src/Geant4VolumeManager.cpp
+++ b/DDG4/src/Geant4VolumeManager.cpp
@@ -28,22 +28,24 @@
 // C/C++ include files
 #include <sstream>
 
-using namespace dd4hep::sim::Geant4GeometryMaps;
 using namespace dd4hep::sim;
 using namespace dd4hep;
 
 #include <DDG4/Geant4AssemblyVolume.h>
-typedef std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > > VolIDDescriptor;
-namespace {
+using VolIDDescriptor = std::pair<VolumeID,std::vector<std::pair<const BitFieldElement*, VolumeID> > >;
+
+namespace  {
 
   /// Helper class to populate the Geant4 volume manager
   struct Populator {
+
     typedef std::vector<const TGeoNode*> Chain;
     typedef std::map<VolumeID,Geant4GeometryInfo::Geant4PlacementPath> Registries;
+
     /// Reference to the Detector instance
-    const Detector& m_detDesc;
+    const Detector&     m_detDesc;
     /// Set of already added entries
-    Registries m_entries;
+    Registries          m_entries;
     /// Reference to Geant4 translation information
     Geant4GeometryInfo& m_geo;
 
@@ -71,7 +73,7 @@ namespace {
                  "++ Detector element %s of type %s has no placement.", de.name(), de.type().c_str());
       }
       /// Needed to compute the cellID of parameterized volumes
-      for( const auto& pv : m_geo.g4Placements )   {
+      for( const auto& pv : m_geo.g4Placements )  {
         if ( pv.second->IsParameterised() )
           m_geo.g4Parameterised[pv.second] = pv.first;
         if ( pv.second->IsReplicated() )
@@ -110,12 +112,12 @@ namespace {
 
     void add_entry(SensitiveDetector sd, const TGeoNode* n, const PlacedVolume::VolIDs& ids, const Chain& nodes) {
       Chain control;
-      const TGeoNode* node;
-      Volume vol;
-      Geant4GeometryInfo::Geant4PlacementPath path;
-      Readout ro = sd.readout();
+      Volume       vol;
+      const TGeoNode* node = nullptr;
+      Readout      ro = sd.readout();
       IDDescriptor iddesc = ro.idSpec();
-      VolumeID code = iddesc.encode(ids);
+      VolumeID     code = iddesc.encode(ids);
+      Geant4GeometryInfo::Geant4PlacementPath path;
       Registries::const_iterator i = m_entries.find(code);
       PrintLevel print_level  = m_geo.printLevel;
       PrintLevel print_action = print_level;
@@ -125,17 +127,17 @@ namespace {
       printout(print_action,"Geant4VolumeManager","+++ Add path:%s vid:%016X",
                detail::tools::placementPath(nodes,false).c_str(),code);
 
-      if (i == m_entries.end()) {
+      if( i == m_entries.end() ) {
         path.reserve(nodes.size());
-        for (Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k) {
+        for( Chain::const_reverse_iterator k = nodes.rbegin(), kend=nodes.rend(); k != kend; ++k ) {
           node = *(k);
-          PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(node);
-          if (g4pit != m_geo.g4Placements.end()) {
-            G4VPhysicalVolume* phys = (*g4pit).second;
-            if ( phys->IsParameterised() )   {
+          auto g4pit = m_geo.g4Placements.find(node);
+          if( g4pit != m_geo.g4Placements.end() )  {
+            G4VPhysicalVolume* phys = g4pit->second;
+            if( phys->IsParameterised() )  {
               PlacedVolume pv(n);
               PlacedVolumeExtension* ext = pv.data();
-              if ( nullptr == ext->params->field )   {
+              if( nullptr == ext->params->field )  {
                 ext->params->field = iddesc.field(ext->volIDs.at(0).first);
               }
             }
@@ -146,12 +148,11 @@ namespace {
           }
           control.insert(control.begin(),node);
           vol = Volume(node->GetVolume());
-          VolumeImprintMap::const_iterator iVolImp = m_geo.g4VolumeImprints.find(vol);
-          if ( iVolImp != m_geo.g4VolumeImprints.end() )   {
-            const Imprints& imprints = (*iVolImp).second;
-            for(const auto& imp : imprints )   {
-              const VolumeChain& c = imp.first;
-              if ( c.size() <= control.size() && control == c )   {
+          auto iVolImp = m_geo.g4VolumeImprints.find(vol);
+          if ( iVolImp != m_geo.g4VolumeImprints.end() )  {
+            for(const auto& imp : iVolImp->second )  {
+              const auto& c = imp.first;
+              if ( c.size() <= control.size() && control == c )  {
                 path.emplace_back(imp.second);
                 printout(print_chain, "Geant4VolumeManager", "+++     Chain: Node OK: %s %s -> %s",
                          node->GetName(), detail::tools::placementPath(c,false).c_str(),
@@ -162,7 +163,7 @@ namespace {
             }
           }
         }
-        if ( control.empty() )   {
+        if ( control.empty() )  {
           printout(print_res, "Geant4VolumeManager", "+++     Volume  IDs:%s",
                    detail::tools::toString(ro.idSpec(),ids,code).c_str());
           path.erase(path.begin()+path.size()-1);
@@ -170,7 +171,7 @@ namespace {
                    (void*)code, Geant4GeometryInfo::placementPath(path).c_str());
           if ( m_geo.g4Paths.find(path) == m_geo.g4Paths.end() ) {
             Geant4GeometryInfo::PlacementFlags opt;
-            for(const auto* phys : path)   {
+            for(const auto* phys : path)  {
               opt.flags.path_has_parametrised = phys->IsParameterised() ? 1 : 0;
               opt.flags.path_has_replicated   = phys->IsReplicated()    ? 1 : 0;
             }
@@ -181,7 +182,7 @@ namespace {
             return;
           }
           /// This is a normal case for parametrized volumes and no error
-          if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) )   {
+          if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) )  {
             return;
           }
           printout(ERROR, "Geant4VolumeManager", "populate: Severe error: Duplicated Geant4 path!!!! %s %s",
@@ -194,7 +195,7 @@ namespace {
       }
       else  {
         /// This is a normal case for parametrized volumes and no error
-        if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) )   {
+        if ( !path.empty() && (path.front()->IsParameterised() || path.front()->IsReplicated()) )  {
           return;
         }
       }
@@ -216,7 +217,7 @@ namespace {
 
 /// Initializing constructor. The tree will automatically be built if possible
 Geant4VolumeManager::Geant4VolumeManager(const Detector& description, Geant4GeometryInfo* info)
-  : Handle<Geant4GeometryInfo>(info)   {
+  : Handle<Geant4GeometryInfo>(info)  {
   if (info && info->valid && info->g4Paths.empty()) {
     Populator p(description, *info);
     p.populate(description.world());
@@ -249,7 +250,7 @@ VolumeID Geant4VolumeManager::volumeID(const std::vector<const G4VPhysicalVolume
   if (!path.empty() && checkValidity()) {
     const auto& mapping = ptr()->g4Paths;
     auto i = mapping.find(path);
-    if ( i != mapping.end() )   {
+    if ( i != mapping.end() )  {
       return (*i).second.first;
     }
     if (!path[0])
@@ -267,25 +268,25 @@ VolumeID Geant4VolumeManager::volumeID(const std::vector<const G4VPhysicalVolume
 VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
   Geant4TouchableHandler handler(touchable);
   std::vector<const G4VPhysicalVolume*> path = handler.placementPath();
-  if (!path.empty() && checkValidity()) {
+  if( !path.empty() && checkValidity() )  {
     const auto& mapping = ptr()->g4Paths;
     auto i = mapping.find(path);
-    if ( i != mapping.end() )   {
+    if( i != mapping.end() )  {
       const auto& e = (*i).second;
       /// No parametrization or replication.
-      if ( e.flags == 0 )  {
+      if( e.flags == 0 )  {
         return e.volumeID;
       }
       VolumeID volid = e.volumeID;
       const auto& paramterised = ptr()->g4Parameterised;
       const auto& replicated   = ptr()->g4Replicated;
       /// This is incredibly slow .... but what can I do ? Need a better idea.
-      for ( std::size_t j=0; j < path.size(); ++j )   {
+      for( std::size_t j=0; j < path.size(); ++j )  {
         const auto* phys = path[j];
-        if ( phys->IsParameterised() )   {
+        if( phys->IsParameterised() )  {
           int copy_no = touchable->GetCopyNumber(j);
           const auto it = paramterised.find(phys);
-          if ( it != paramterised.end() )   {
+          if( it != paramterised.end() )  {
             //printout(INFO,"Geant4VolumeManager",
             //         "Copy number:   %ld  <--> %ld", copy_no, long(phys->GetCopyNo()));
             const auto* field = (*it).second.data()->params->field;
@@ -294,10 +295,10 @@ VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
           }
           except("Geant4VolumeManager","Error  Geant4VolumeManager::volumeID(const G4VTouchable* touchable)");
         }
-        else if ( phys->IsReplicated() )    {
+        else if( phys->IsReplicated() )   {
           int copy_no = touchable->GetCopyNumber(j);
           const auto it = replicated.find(phys);
-          if ( it != replicated.end() )   {
+          if( it != replicated.end() )  {
             const auto* field = (*it).second.data()->params->field;
             volid |= IDDescriptor::encode(field, copy_no);
             continue;
@@ -307,9 +308,9 @@ VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const {
       }
       return volid;
     }
-    if (!path[0])
+    if( !path[0] )
       return InvalidPath;
-    else if (!path[0]->GetLogicalVolume()->GetSensitiveDetector())
+    else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
       return Insensitive;
   }
   printout(INFO, "Geant4VolumeManager","+++   Bad volume Geant4 Path: %s",
@@ -323,20 +324,20 @@ void Geant4VolumeManager::volumeDescriptor(const std::vector<const G4VPhysicalVo
 {
   vol_desc.second.clear();
   vol_desc.first = NonExisting;
-  if ( !path.empty() && checkValidity() )  {
+  if( !path.empty() && checkValidity() )  {
     const auto& mapping = ptr()->g4Paths;
     auto i = mapping.find(path);
-    if (i != mapping.end()) {
+    if( i != mapping.end() ) {
       VolumeID vid = (*i).second.volumeID;
       G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
-      if ( lvol->GetSensitiveDetector() ) {
-        const G4VPhysicalVolume* node = path[0];
-        const PlacementMap& pm = ptr()->g4Placements;
-        for (PlacementMap::const_iterator ipm = pm.begin(); ipm != pm.end(); ++ipm) {
-          if ( (*ipm).second == node )  {
-            PlacedVolume pv = (*ipm).first;
-            SensitiveDetector sd = pv.volume().sensitiveDetector();
-            IDDescriptor dsc = sd.readout().idSpec();
+      if( lvol->GetSensitiveDetector() ) {
+        const auto* node = path[0];
+        const auto& pm = ptr()->g4Placements;
+        for( const auto& ipm : pm )  {
+          if ( ipm.second == node )  {
+            PlacedVolume      pv  = ipm.first;
+            SensitiveDetector sd  = pv.volume().sensitiveDetector();
+            IDDescriptor      dsc = sd.readout().idSpec();
             vol_desc.first = vid;
             dsc.decodeFields(vid, vol_desc.second);
             return;
@@ -346,9 +347,9 @@ void Geant4VolumeManager::volumeDescriptor(const std::vector<const G4VPhysicalVo
       vol_desc.first = Insensitive;
       return;
     }
-    if ( !path[0] )
+    if( !path[0] )
       vol_desc.first = InvalidPath;
-    else if ( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
+    else if( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
       vol_desc.first = Insensitive;
     else
       vol_desc.first = NonExisting;
@@ -357,7 +358,6 @@ void Geant4VolumeManager::volumeDescriptor(const std::vector<const G4VPhysicalVo
 
 /// Access fully decoded volume fields by Geant4 touchable object
 void Geant4VolumeManager::volumeDescriptor(const G4VTouchable* touchable,
-                                           VolIDDescriptor&    vol_desc) const {
+                                           VolIDDescriptor&    vol_desc)  const  {
   volumeDescriptor(placementPath(touchable), vol_desc);
 }
-
diff --git a/examples/DDG4_MySensDet/src/MyTrackerSDAction.cpp b/examples/DDG4_MySensDet/src/MyTrackerSDAction.cpp
index 1d98b8edc..476244e46 100644
--- a/examples/DDG4_MySensDet/src/MyTrackerSDAction.cpp
+++ b/examples/DDG4_MySensDet/src/MyTrackerSDAction.cpp
@@ -24,7 +24,8 @@ namespace SomeExperiment {
   public:
     typedef MyTrackerHit Hit;
     // If we need special data to personalize the action, be put it here
-    int mumDeposits = 0;
+    bool   haveCellID = true;
+    int    mumDeposits = 0;
     double integratedDeposit = 0;
   };
 }
@@ -48,7 +49,20 @@ namespace dd4hep {
      *
      * @}
      */
-
+    template <>
+    Geant4SensitiveAction<MyTrackerSD>::Geant4SensitiveAction(Geant4Context* ctxt,
+                                                              const std::string& nam,
+                                                              DetElement det,
+                                                              Detector& description_ref)
+      : Geant4Sensitive(ctxt,nam,det,description_ref), m_collectionName(), m_collectionID(0)
+    {
+      declareProperty("HaveCellID",     m_userData.haveCellID = true);
+      declareProperty("ReadoutName",    m_readoutName);
+      declareProperty("CollectionName", m_collectionName);
+      initialize();
+      InstanceCount::increment(this);
+    }
+    
     /// Define collections created by this sensitivie action object
     template <> void Geant4SensitiveAction<MyTrackerSD>::defineCollections()    {
       m_collectionID = declareReadoutFilteredCollection<MyTrackerSD::Hit>();
@@ -67,20 +81,20 @@ namespace dd4hep {
       double    tim       = h.track->GetGlobalTime();
       // Somehow extract here the physics you want
       MyTrackerSD::Hit* hit = 
-	new MyTrackerSD::Hit(h.trkID(), h.trkPdgID(), depo, tim, hit_len, pos, mom);
+        new MyTrackerSD::Hit(h.trkID(), h.trkPdgID(), depo, tim, hit_len, pos, mom);
       Geant4HitData::MonteCarloContrib contrib = Geant4HitData::extractContribution(step);
-      hit->cellID        = cellID(step);
+      hit->cellID        = this->m_userData.haveCellID ? cellID(step) : 0;
       hit->step_length   = hit_len;
       hit->prePos        = prePos;
       hit->postPos       = postPos;
       collection(m_collectionID)->add(hit);
       mark(h.track);
-      if ( 0 == hit->cellID )  {
+      if ( this->m_userData.haveCellID && 0 == hit->cellID )  {
         hit->cellID = volumeID(step);
         except("+++ Invalid CELL ID for hit!");
       }
       printP1("Hit with deposit:%f  Pos:%f %f %f ID=%016X",
-	      depo, pos.X(), pos.Y(), pos.Z(), (void*)hit->cellID);
+              depo, pos.X(), pos.Y(), pos.Z(), (void*)hit->cellID);
       Geant4TouchableHandler handler(step);
       print("    Geant4 path:%s", handler.path().c_str());
 
@@ -91,9 +105,9 @@ namespace dd4hep {
       /// Let's play with the Geant4TrackInformation
       /// See issue https://github.com/AIDASoft/DD4hep/issues/1073
       if ( nullptr == h.track->GetUserInformation() )   {
-	auto data = std::make_unique<ParticleUserData>();
-	data->absolute_momentum = h.track->GetMomentum().mag();
-	h.track->SetUserInformation(new Geant4ParticleInformation(std::move(data)));
+        auto data = std::make_unique<ParticleUserData>();
+        data->absolute_momentum = h.track->GetMomentum().mag();
+        h.track->SetUserInformation(new Geant4ParticleInformation(std::move(data)));
       }
       return true;
     }
-- 
GitLab