From d96f515f44a306afa72f4ac5f09aaee7b6791442 Mon Sep 17 00:00:00 2001
From: Markus Frank <markus.frank@cern.ch>
Date: Thu, 8 Aug 2013 16:18:20 +0000
Subject: [PATCH] Add Geant4VolumeManager to resolve volume ids of sensitive
 volumes.

---
 DDG4/include/DDG4/Geant4GeometryInfo.h      |  98 +++++++
 DDG4/include/DDG4/Geant4Mapping.h           | 100 +++----
 DDG4/include/DDG4/Geant4SensitiveDetector.h |   3 +
 DDG4/include/DDG4/Geant4StepHandler.h       |  30 +-
 DDG4/include/DDG4/Geant4VolumeManager.h     |  97 +++++++
 DDG4/src/Geant4Converter.cpp                | 307 ++++++++++++--------
 DDG4/src/Geant4DetectorConstruction.cpp     |   5 +-
 DDG4/src/Geant4GeometryInfo.cpp             |  21 ++
 DDG4/src/Geant4Mapping.cpp                  |  36 ++-
 DDG4/src/Geant4SensitiveDetector.cpp        |   7 +-
 DDG4/src/Geant4VolumeManager.cpp            | 245 ++++++++++++++++
 11 files changed, 739 insertions(+), 210 deletions(-)
 create mode 100644 DDG4/include/DDG4/Geant4GeometryInfo.h
 create mode 100644 DDG4/include/DDG4/Geant4VolumeManager.h
 create mode 100644 DDG4/src/Geant4GeometryInfo.cpp
 create mode 100644 DDG4/src/Geant4VolumeManager.cpp

diff --git a/DDG4/include/DDG4/Geant4GeometryInfo.h b/DDG4/include/DDG4/Geant4GeometryInfo.h
new file mode 100644
index 000000000..01f248497
--- /dev/null
+++ b/DDG4/include/DDG4/Geant4GeometryInfo.h
@@ -0,0 +1,98 @@
+// $Id: Geant4Geometryinfo.h 513 2013-04-05 14:31:53Z gaede $
+//====================================================================
+//  AIDA Detector description implementation
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+#ifndef DD4HEP_DDG4_GEANT4GEOMETRYINFO_H
+#define DD4HEP_DDG4_GEANT4GEOMETRYINFO_H
+
+// Framework include files
+#include "DD4hep/GeoHandler.h"
+#include "DDG4/Geant4Primitives.h"
+
+// C/C++ include files
+#include <map>
+#include <vector>
+
+// Forward declarations (TGeo)
+class TGeoElement;
+class TGeoMedium;
+class TGeoVolume;
+class TGeoShape;
+class TGeoNode;
+// Forward declarations (Geant4)
+class G4Element;
+class G4Material;
+class G4VSolid;
+class G4LogicalVolume;
+class G4Region;
+class G4UserLimits;
+class G4VisAttributes;
+class G4VPhysicalVolume;
+class G4AssemblyVolume;
+
+/*
+ *   DD4hep namespace declaration
+ */
+namespace DD4hep {
+
+  /*
+   *   Simulation namespace declaration
+   */
+  namespace Simulation   {
+
+    // Forward declarations
+    class Geant4Mapping;
+    class Geant4SensitiveDetector;
+    
+    struct Geant4GeometryInfo : public TNamed, public Geometry::GeoHandlerTypes::GeometryInfo   {
+    public:
+      typedef std::vector<const G4VPhysicalVolume*>                      PlacementPath;
+      typedef std::vector<std::pair<size_t,const TGeoNode*> >            AssemblyChildren;
+      typedef std::map<const TGeoElement*,     G4Element*>               ElementMap;
+      typedef std::map<const TGeoMedium*,      G4Material*>              MaterialMap;
+      typedef std::map<const TNamed*,          G4UserLimits*>            LimitMap;
+      typedef std::map<const TGeoNode*,        G4VPhysicalVolume*>       PlacementMap;
+      typedef std::map<const G4AssemblyVolume*,AssemblyChildren>         AssemblyChildMap;
+      typedef std::map<const TNamed*,          G4Region*>                RegionMap;
+      typedef std::map<const TNamed*,          Geant4SensitiveDetector*> SensDetMap;
+      typedef std::map<const TGeoVolume*,      G4LogicalVolume*>         VolumeMap;
+      typedef std::map<const TGeoShape*,       G4VSolid*>                SolidMap;
+      typedef std::map<const TNamed*,          G4VisAttributes*>         VisMap;
+      typedef std::map<PlacementPath,          VolumeID>                 PathMap;
+
+      typedef Geometry::GeoHandlerTypes::SensitiveVolumes                SensitiveVolumes;
+      typedef Geometry::GeoHandlerTypes::RegionVolumes                   RegionVolumes;
+      typedef Geometry::GeoHandlerTypes::LimitVolumes                    LimitVolumes;
+
+      ElementMap              g4Elements;
+      MaterialMap             g4Materials;
+      SolidMap                g4Solids;
+      VolumeMap               g4Volumes;
+      PlacementMap            g4Placements;
+      AssemblyChildMap        g4AssemblyChildren;
+      RegionMap               g4Regions;
+      VisMap                  g4Vis;
+      LimitMap                g4Limits;
+      SensDetMap              g4SensDets;
+      PathMap                 g4Paths;
+
+      SensitiveVolumes        sensitives;
+      RegionVolumes           regions;
+      LimitVolumes            limits;
+      bool                    valid;
+    private:
+      friend class Geant4Mapping;
+      /// Default constructor
+      Geant4GeometryInfo();
+      /// Default destructor
+      virtual ~Geant4GeometryInfo();
+    };
+
+  }    // End namespace Simulation
+}      // End namespace DD4hep
+
+#endif // DD4HEP_DDG4_GEANT4GEOMETRYINFO_H
diff --git a/DDG4/include/DDG4/Geant4Mapping.h b/DDG4/include/DDG4/Geant4Mapping.h
index 0b996b0d0..060b31d10 100644
--- a/DDG4/include/DDG4/Geant4Mapping.h
+++ b/DDG4/include/DDG4/Geant4Mapping.h
@@ -10,32 +10,10 @@
 #define DD4HEP_GEANT4MAPPING_H
 
 // Framework include files
-#include "DD4hep/GeoHandler.h"
 #include "DD4hep/LCDD.h"
-
-// C/C++ include files
-#include <set>
-#include <map>
-#include <vector>
-
-// Forward declarations
-class TGeoVolume;
-class TGeoElement;
-class TGeoShape;
-class TGeoMedium;
-class TGeoNode;
-
-class G4Element;
-class G4Material;
-class G4VSolid;
-class G4LogicalVolume;
-class G4PVPlacement;
-class G4Region;
-class G4Field;
-class G4FieldManager;
-class G4UserLimits;
-class G4VisAttributes;
-class G4VPhysicalVolume;
+#include "DD4hep/GeoHandler.h"
+#include "DDG4/Geant4GeometryInfo.h"
+#include "DDG4/Geant4VolumeManager.h"
 
 /*
  *   DD4hep namespace declaration
@@ -47,8 +25,6 @@ namespace DD4hep {
    */
   namespace Simulation   {
 
-    class Geant4SensitiveDetector;
-
     /** @class Geant4Mapping Geant4Mapping.h DDG4/Geant4Mapping.h
      * 
      * Geometry mapping from DD4hep to Geant 4.
@@ -67,60 +43,56 @@ namespace DD4hep {
       typedef Geometry::Material          Material;
       typedef Geometry::Region            Region;
 
-      typedef std::map<const TGeoElement*,G4Element*>               ElementMap;
-      typedef std::map<const TGeoMedium*, G4Material*>              MaterialMap;
-      typedef std::map<const TNamed*,     G4UserLimits*>            LimitMap;
-      typedef std::map<const TGeoNode*,   G4PVPlacement*>           PlacementMap;
-      typedef std::map<const TNamed*,     G4Region*>                RegionMap;
-      typedef std::map<const TNamed*,     Geant4SensitiveDetector*> SensDetMap;
-      typedef std::map<const TGeoVolume*, G4LogicalVolume*>         VolumeMap;
-      typedef std::map<const TGeoShape*,  G4VSolid*>                SolidMap;
-      typedef std::map<const TNamed*,     G4VisAttributes*>         VisMap;
-      struct G4GeometryInfo : public GeometryInfo {
-	ElementMap              g4Elements;
-	MaterialMap             g4Materials;
-	SolidMap                g4Solids;
-	VolumeMap               g4Volumes;
-	PlacementMap            g4Placements;
-	RegionMap               g4Regions;
-	VisMap                  g4Vis;
-	LimitMap                g4Limits;
-	SensDetMap              g4SensDets;
-
-	SensitiveVolumes   sensitives;
-	RegionVolumes      regions;
-	LimitVolumes       limits;
-      };
+      typedef Geant4GeometryInfo::PlacementPath      PlacementPath;
+      typedef Geant4GeometryInfo::AssemblyChildren   AssemblyChildren;
+      typedef Geant4GeometryInfo::ElementMap         ElementMap;
+      typedef Geant4GeometryInfo::MaterialMap        MaterialMap;
+      typedef Geant4GeometryInfo::LimitMap           LimitMap;
+      typedef Geant4GeometryInfo::PlacementMap       PlacementMap;
+      typedef Geant4GeometryInfo::AssemblyChildMap   AssemblyChildMap;
+      typedef Geant4GeometryInfo::RegionMap          RegionMap;
+      typedef Geant4GeometryInfo::SensDetMap         SensDetMap;
+      typedef Geant4GeometryInfo::VolumeMap          VolumeMap;
+      typedef Geant4GeometryInfo::SolidMap           SolidMap;
+      typedef Geant4GeometryInfo::VisMap             VisMap;
+      typedef Geant4GeometryInfo::PathMap            PathMap;
+
     protected:
-      LCDD&           m_lcdd;
-      G4GeometryInfo* m_dataPtr;
+      LCDD&               m_lcdd;
+      Geant4GeometryInfo* m_dataPtr;
 
       /// When resolving pointers, we must check for the validity of the data block
       void checkValidity() const;
     public:
-      /// Access to the data pointer
-      G4GeometryInfo& data() const { return *m_dataPtr; }
-      /// Release data and pass over the ownership
-      G4GeometryInfo* detach();
-      /// Set a new data block
-      void attach(G4GeometryInfo* data);
       /// Initializing Constructor
-      Geant4Mapping(LCDD& lcdd, G4GeometryInfo* data);
+      Geant4Mapping(LCDD& lcdd);
+
       /// Standard destructor
       virtual ~Geant4Mapping();
+
       /// Possibility to define a singleton instance
       static Geant4Mapping& instance();
 
       /// Accesor to the LCDD instance
       LCDD& lcdd() const {  return m_lcdd; }
 
-      /// Accessor to resolve G4 placements
-      G4PVPlacement* g4Placement(const TGeoNode* node)  const;
-      /// Accessor to resolve geometry placements
-      PlacedVolume placement(const G4VPhysicalVolume* node)  const;
+      /// Access to the data pointer
+      Geant4GeometryInfo& data() const { return *m_dataPtr; }
 
+      /// Create and attach new data block. Delete old data block if present.
+      Geant4GeometryInfo& init();
 
+      /// Release data and pass over the ownership
+      Geant4GeometryInfo* detach();
 
+      /// Set a new data block
+      void attach(Geant4GeometryInfo* data);
+
+      /// Access the volume manager
+      Geant4VolumeManager volumeManager() const;
+
+      /// Accessor to resolve geometry placements
+      PlacedVolume placement(const G4VPhysicalVolume* node)  const;
     };
   }    // End namespace Simulation
 }      // End namespace DD4hep
diff --git a/DDG4/include/DDG4/Geant4SensitiveDetector.h b/DDG4/include/DDG4/Geant4SensitiveDetector.h
index db8f41aa6..ef91e5dbb 100644
--- a/DDG4/include/DDG4/Geant4SensitiveDetector.h
+++ b/DDG4/include/DDG4/Geant4SensitiveDetector.h
@@ -115,6 +115,9 @@ namespace DD4hep {
       /// G4VSensitiveDetector interface: Method for generating hit(s) using the information of G4Step object.
       virtual G4bool ProcessHits(G4Step* step,G4TouchableHistory* history);
 
+      /// G4VSensitiveDetector interface: Method for generating hit(s) using the information of G4Step object.
+      virtual G4bool process(G4Step* step,G4TouchableHistory* history);
+
       /// G4VSensitiveDetector interface: Method invoked if the event was aborted.
       /** Hits collections created but not beibg set to G4HCofThisEvent 
        *  at the event should be deleted.
diff --git a/DDG4/include/DDG4/Geant4StepHandler.h b/DDG4/include/DDG4/Geant4StepHandler.h
index a7f821678..739ce4c55 100644
--- a/DDG4/include/DDG4/Geant4StepHandler.h
+++ b/DDG4/include/DDG4/Geant4StepHandler.h
@@ -79,33 +79,41 @@ namespace DD4hep {
       const G4VTouchable* postTouchable()  const {
 	return post->GetTouchable();
       }
-      const char* volName(G4StepPoint* p, const char* undefined="")  const {
+      const char* volName(const G4StepPoint* p, const char* undefined="")  const {
 	G4VPhysicalVolume* v = volume(p);
 	return v ? v->GetName().c_str() : undefined;
       }
-      G4VPhysicalVolume* volume(G4StepPoint* p)  const {
+      G4VPhysicalVolume* volume(const G4StepPoint* p)  const {
 	return p->GetTouchableHandle()->GetVolume();
       }
-      G4VPhysicalVolume* physvol(G4StepPoint* p)   const {
+      G4VPhysicalVolume* physvol(const G4StepPoint* p)   const {
 	return p->GetPhysicalVolume();
       }
-      G4LogicalVolume* logvol(G4StepPoint* p)   const {
+      G4LogicalVolume* logvol(const G4StepPoint* p)   const {
 	G4VPhysicalVolume* pv = physvol(p);
 	return pv ? pv->GetLogicalVolume() : 0;
       }
-      G4VSensitiveDetector* sd(G4StepPoint* p)  const {
+      G4VSensitiveDetector* sd(const G4StepPoint* p)  const {
 	G4LogicalVolume* lv = logvol(p);
 	return lv ? lv->GetSensitiveDetector() : 0;
       }
-      const char* sdName(G4StepPoint* p, const char* undefined="")  const {
+      const char* sdName(const G4StepPoint* p, const char* undefined="")  const {
 	G4VSensitiveDetector* s = sd(p);
 	return s ? s->GetName().c_str() : undefined;
       }
-
-      G4VPhysicalVolume* preVolume()  const  {	return volume(pre);       }
-      G4VSensitiveDetector* preSD()  const   {	return sd(pre);           }
-      G4VPhysicalVolume* postVolume()  const {	return volume(post);      }
-      G4VSensitiveDetector* postSD()  const  {	return sd(post);          }
+      bool isSensitive(const G4LogicalVolume* lv) const  {
+	return lv ? (0 != lv->GetSensitiveDetector()) : false;
+      }
+      bool isSensitive(const G4VPhysicalVolume* pv) const  {
+	return pv ? isSensitive(pv->GetLogicalVolume()) : false;
+      }
+      bool isSensitive(const G4StepPoint* point) const  {
+	return point ? isSensitive(volume(point)) : false;
+      }
+      G4VPhysicalVolume*    preVolume()   const  {	return volume(pre);       }
+      G4VSensitiveDetector* preSD()       const  {	return sd(pre);           }
+      G4VPhysicalVolume*    postVolume()  const  {	return volume(post);      }
+      G4VSensitiveDetector* postSD()      const  {	return sd(post);          }
     };
 
   }    // End namespace Simulation
diff --git a/DDG4/include/DDG4/Geant4VolumeManager.h b/DDG4/include/DDG4/Geant4VolumeManager.h
new file mode 100644
index 000000000..028288da6
--- /dev/null
+++ b/DDG4/include/DDG4/Geant4VolumeManager.h
@@ -0,0 +1,97 @@
+// $Id: Geant4VolumeManager.h 603 2013-06-13 21:15:14Z markus.frank $
+//====================================================================
+//  AIDA Detector description implementation
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+#ifndef DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H
+#define DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H
+
+// Framework include files
+#include "DD4hep/LCDD.h"
+#include "DD4hep/IDDescriptor.h"
+#include "DDG4/Geant4Primitives.h"
+#include "DDG4/Geant4GeometryInfo.h"
+
+// Geant4 forward declarations
+class G4VTouchable;
+
+/*
+ *   DD4hep namespace declaration
+ */
+namespace DD4hep {
+
+  /*
+   *   Simulation namespace declaration
+   */
+  namespace Simulation {
+
+    // Forward declarations
+    class Geant4VolumeManager;
+    class Geant4GeometryInfo;
+
+    /** @class Geant4VolumeManager Geant4VolumeManager.h DDG4/Geant4VolumeManager.h
+     *
+     * @author  M.Frank
+     * @version 1.0
+     */
+    struct Geant4VolumeManager : public Geometry::Handle<Geant4GeometryInfo>  {
+    public:
+      // Forward declarations
+      typedef Geometry::Handle<Geant4GeometryInfo>  Base;
+      typedef Geometry::PlacedVolume                PlacedVolume;
+      typedef Geometry::IDDescriptor                IDDescriptor;
+      typedef IDDescriptor::VolIDFields             VolIDFields;
+      typedef std::pair<VolumeID, VolIDFields>      VolIDDescriptor;
+      typedef Geant4GeometryInfo::PlacementPath     PlacementPath;
+      typedef Geant4GeometryInfo                    Object;
+
+    protected:
+      /// Optimization flag to shortcut object checks
+      mutable bool m_isValid;
+
+      /// Check the validity of the information before accessing it.
+      bool checkValidity() const;
+
+    public:
+      static const VolumeID InvalidPath = VolumeID(-1LL);
+      static const VolumeID Insensitive = VolumeID(-2LL);
+      static const VolumeID NonExisting = 0ULL;
+
+      /// Initializing constructor. The tree will automatically be built if possible
+      Geant4VolumeManager(Geometry::LCDD& lcdd, Geant4GeometryInfo* info);
+      /// Default constructor
+      Geant4VolumeManager() : Base(), m_isValid(false) {}
+      /// Constructor to be used when reading the already parsed object
+      Geant4VolumeManager(const Base& e) : Base(e), m_isValid(false) {}
+      /// Constructor to be used when reading the already parsed object
+      Geant4VolumeManager(const Geant4VolumeManager& e) : Base(e), m_isValid(false) {}
+      /// Constructor to be used when reading the already parsed object
+      template <typename Q> Geant4VolumeManager(const Geometry::Handle<Q>& e) : Base(e), m_isValid(false) {}
+
+      /// Helper: Generate placement path from touchable object
+      PlacementPath placementPath(const G4VTouchable* touchable, bool exception=true) const;
+
+      /// Accessor to resolve TGeo geometry placements from Geant4 placements
+      PlacedVolume placement(const G4VPhysicalVolume* node)  const;
+      /// Accessor to resolve Geant4 geometry placements from TGeo placements
+      G4VPhysicalVolume* placement(const TGeoNode* node)  const;
+      /// Accessor to resolve Geant4 geometry placements from TGeo placements
+      G4VPhysicalVolume* placement(const PlacedVolume& node)  const   
+      {  	return placement(node.ptr());      }
+      /// Access CELLID by placement path
+      VolumeID volumeID(const PlacementPath& path) const;
+      /// Access CELLID by Geant4 touchable object
+      VolumeID volumeID(const G4VTouchable* touchable) const;
+
+      /// Accessfully decoded volume fields  by placement path
+      void volumeDescriptor(const PlacementPath& path, VolIDDescriptor& volume_desc) const;
+      /// Access fully decoded volume fields by Geant4 touchable object
+      void volumeDescriptor(const G4VTouchable* touchable, VolIDDescriptor& volume_desc) const;
+    };
+
+  }    // End namespace Simulation
+}      // End namespace DD4hep
+#endif // DD4HEP_DDG4_GEANT4VOLUMEMANAGER_H
diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp
index 079d7c53e..85e08cf0d 100644
--- a/DDG4/src/Geant4Converter.cpp
+++ b/DDG4/src/Geant4Converter.cpp
@@ -44,7 +44,6 @@
 #include "G4Element.hh"
 #include "G4SDManager.hh"
 #include "G4Assembly.hh"
-#include "G4AssemblyVolume.hh"
 #include "G4Box.hh"
 #include "G4Trd.hh"
 #include "G4Tubs.hh"
@@ -72,6 +71,8 @@
 #include "G4ElectroMagneticField.hh"
 #include "G4FieldManager.hh"
 
+#include "G4ReflectionFactory.hh"
+
 #include <iostream>
 #include <iomanip>
 #include <sstream>
@@ -81,6 +82,112 @@ using namespace DD4hep::Geometry;
 using namespace DD4hep;
 using namespace std;
 
+#define private public
+#include "G4AssemblyVolume.hh"
+#undef private
+
+struct Geant4AssemblyVolume : public G4AssemblyVolume  {
+  Geant4AssemblyVolume() {}
+  size_t placeVolume(G4LogicalVolume* pPlacedVolume,
+		     G4Transform3D&   transformation)  {
+    size_t id = fTriplets.size();
+    this->AddPlacedVolume(pPlacedVolume,transformation);
+    return id;
+  }
+  void imprint( std::vector<G4VPhysicalVolume*>& nodes,
+		G4LogicalVolume*  pMotherLV,
+		G4Transform3D&    transformation,
+		G4int copyNumBase,
+		G4bool surfCheck );
+  
+};
+
+void Geant4AssemblyVolume::imprint( std::vector<G4VPhysicalVolume*>& nodes,
+                                    G4LogicalVolume*  pMotherLV,
+                                    G4Transform3D&    transformation,
+                                    G4int copyNumBase,
+                                    G4bool surfCheck )
+{
+  G4AssemblyVolume* pAssembly = this;
+  unsigned int  numberOfDaughters;  
+  if( copyNumBase == 0 )  {
+    numberOfDaughters = pMotherLV->GetNoDaughters();
+  }
+  else  {
+    numberOfDaughters = copyNumBase;
+  }
+  // We start from the first available index
+  numberOfDaughters++;
+  ImprintsCountPlus();
+  
+  std::vector<G4AssemblyTriplet> triplets = pAssembly->fTriplets;
+  for( unsigned int   i = 0; i < triplets.size(); i++ )  {
+    G4Transform3D Ta( *(triplets[i].GetRotation()),
+                      triplets[i].GetTranslation() );
+    if ( triplets[i].IsReflection() )  { Ta = Ta * G4ReflectZ3D(); }
+
+    G4Transform3D Tfinal = transformation * Ta;
+    
+    if ( triplets[i].GetVolume() )
+    {
+      // Generate the unique name for the next PV instance
+      // The name has format:
+      //
+      // av_WWW_impr_XXX_YYY_ZZZ
+      // where the fields mean:
+      // WWW - assembly volume instance number
+      // XXX - assembly volume imprint number
+      // YYY - the name of a log. volume we want to make a placement of
+      // ZZZ - the log. volume index inside the assembly volume
+      //
+      std::stringstream pvName;
+      pvName << "av_"
+             << GetAssemblyID()
+             << "_impr_"
+             << GetImprintsCount()
+             << "_"
+             << triplets[i].GetVolume()->GetName().c_str()
+             << "_pv_"
+             << i
+             << std::ends;
+
+      // Generate a new physical volume instance inside a mother
+      // (as we allow 3D transformation use G4ReflectionFactory to 
+      //  take into account eventual reflection)
+      //
+      G4PhysicalVolumesPair pvPlaced
+        = G4ReflectionFactory::Instance()->Place( Tfinal,
+                                                  pvName.str().c_str(),
+                                                  triplets[i].GetVolume(),
+                                                  pMotherLV,
+                                                  false,
+                                                  numberOfDaughters + i,
+                                                  surfCheck );
+
+      // Register the physical volume created by us so we can delete it later
+      //
+      fPVStore.push_back( pvPlaced.first );
+      nodes.push_back(pvPlaced.first);
+      if ( pvPlaced.second )  { // Supported by G4, but not by TGeo!
+	fPVStore.push_back( pvPlaced.second ); 
+	G4Exception("G4AssemblyVolume::MakeImprint(..)",
+		    "GeomVol0003", FatalException,
+		    "Fancy construct popping new mother from the stack!");
+      }
+    }
+    else if ( triplets[i].GetAssembly() )    {
+      // Place volumes in this assembly with composed transformation
+      G4Exception("G4AssemblyVolume::MakeImprint(..)",
+                  "GeomVol0003", FatalException,
+                  "Assemblies within assembliesare not supported.");
+    }
+    else    {
+      G4Exception("G4AssemblyVolume::MakeImprint(..)",
+                  "GeomVol0003", FatalException,
+                  "Triplet has no volume and no assembly");
+    }  
+  }  
+}    
 
 namespace {
   static TGeoNode* s_topPtr;
@@ -117,8 +224,9 @@ namespace {
 
 /// Initializing Constructor
 Geant4Converter::Geant4Converter( LCDD& lcdd ) 
-  : Geant4Mapping(lcdd,new G4GeometryInfo()), m_checkOverlaps(true)
+  : Geant4Mapping(lcdd), m_checkOverlaps(true)
 {
+  this->Geant4Mapping::init();
 }
 
 /// Standard destructor
@@ -343,7 +451,7 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape)
 
 /// Dump logical volume in GDML format to output stream
 void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume)   const   {
-  G4GeometryInfo& info = data();
+  Geant4GeometryInfo& info = data();
   G4LogicalVolume* vol = info.g4Volumes[volume];
   if ( !vol ) {
     const TGeoVolume*        v        = volume;
@@ -431,7 +539,7 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume
 
 /// Dump logical volume in GDML format to output stream
 void* Geant4Converter::collectVolume(const string& /* name */, const TGeoVolume* volume)   const   {
-  G4GeometryInfo& info = data();
+  Geant4GeometryInfo& info = data();
   const TGeoVolume* v = volume;
   Volume            _v  = Ref_t(v);
   Region            reg = _v.region();
@@ -446,128 +554,82 @@ void* Geant4Converter::collectVolume(const string& /* name */, const TGeoVolume*
 
 /// Dump volume placement in GDML format to output stream
 void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) const {
-  G4GeometryInfo& info = data();  
-  G4PVPlacement* g4    = info.g4Placements[node];
+  static Double_t identity_rot[] = { 1., 0., 0., 0., 1., 0., 0., 0., 1. };
+  Geant4GeometryInfo& info = data();  
+  PlacementMap::const_iterator g4it = info.g4Placements.find(node);
+  G4VPhysicalVolume* g4 = (g4it == info.g4Placements.end()) ? 0 : (*g4it).second;
   if ( !g4 )   {
     TGeoVolume*      mot_vol = node->GetMotherVolume();
     TGeoVolume*      vol     = node->GetVolume();
     TGeoMatrix*      trafo   = node->GetMatrix();
-    int              copy    = node->GetNumber();
-
-    //fg: this is not needed any more - the cellIDs are taken from the VolumIDs
-    //    set for the placed volumes ...
-    // // if the CellID0 volID is defined for the volume we 
-    // // use it to overwrite the copy number
-    // // this is then used in the sensitive detector to fill the CellID0
-    // // of the SimTrackerHits
-    // if ( dynamic_cast<const PlacedVolume::Object*>(node) ) {
-    //   PlacedVolume p = Ref_t(node);
-    //   const PlacedVolume::VolIDs& ids = p.volIDs();
-    //   //      copy = ids[ "CellID0" ] ;
-    //   PlacedVolume::VolIDs::const_iterator it = ids.find("CellID0") ;
-    //   if( it != ids.end() ) 
-    //  	copy = it->second ;
-    // }
-    //--------------------------------------------------------
-    G4LogicalVolume*  g4vol   = info.g4Volumes[vol];
-    G4LogicalVolume*  g4mot   = info.g4Volumes[mot_vol];
-    G4AssemblyVolume* ass_mot = (G4AssemblyVolume*)g4mot;
-    G4AssemblyVolume* ass_dau = (G4AssemblyVolume*)g4vol;
-    bool daughter_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class();
-    bool mother_is_assembly   = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false;
-    if ( trafo ) {
-      const Double_t*  trans = trafo->GetTranslation();
-      bool is_rot  = trafo->IsRotation();
-      if ( 0 == vol ) {
-	printout(FATAL,"Geant4Converter","++ Unknown G4 volume:%p %s of type %s vol:%s ptr:%s",
-		 node,node->GetName(),node->IsA()->GetName(),vol->IsA()->GetName(),vol);
-      }
-      else if ( is_rot )    {
-	const Double_t* rot = trafo->GetRotationMatrix();
-	MyTransform3D transform(rot[0],rot[1],rot[2],trans[0]*CM_2_MM,
-				rot[3],rot[4],rot[5],trans[1]*CM_2_MM,
-				rot[6],rot[7],rot[8],trans[2]*CM_2_MM);
-	CLHEP::HepRotation rotmat=transform.getRotation();
-	if ( mother_is_assembly )  {	  // Mother is an assembly:
-	  printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s "
-		   "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
-		   ass_mot,g4vol->GetName().c_str(),
-		   transform.dx(),transform.dy(),transform.dz(),
-		   rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi());
-	  ass_mot->AddPlacedVolume(g4vol,transform);
-	  return 0;
-	}
-	else if ( daughter_is_assembly )  {
-	  printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s "
-		   "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
-		   ass_dau,g4mot->GetName().c_str(),
-		   transform.dx(),transform.dy(),transform.dz(),
-		   rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi());
-	  ass_dau->MakeImprint(g4mot,transform,copy,m_checkOverlaps);
-	  return 0;
-	}
-	g4 = new G4PVPlacement(transform, // no rotation
-			       g4vol,     // its logical volume
-			       name,      // its name
-			       g4mot,     // its mother (logical) volume
-			       false,     // no boolean operations
-			       copy,      // its copy number
-			       m_checkOverlaps);
-      }
-      else {
-	G4ThreeVector pos(trans[0]*CM_2_MM,trans[1]*CM_2_MM,trans[2]*CM_2_MM);
-	if ( mother_is_assembly )  {	  // Mother is an assembly:
-	  ass_mot->AddPlacedVolume(g4vol,pos,0);
-	  printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s "
-		   "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
-		   ass_mot,g4vol->GetName().c_str(),
-		   pos.x(),pos.y(),pos.z(),0,0,0);
-	  return 0;
-	}
-	else if ( daughter_is_assembly )  {
-	  printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s "
-		   "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
-		   ass_dau,g4mot->GetName().c_str(),
-		   pos.x(),pos.y(),pos.z(),0,0,0);
-	  ass_dau->MakeImprint(g4mot,pos,0,copy,m_checkOverlaps);
-	  return 0;
-	}
-	g4 = new G4PVPlacement(0,         // no rotation
-			       pos,       // translation position
-			       g4vol,     // its logical volume
-			       name,      // its name
-			       g4mot,     // its mother (logical) volume
-			       false,     // no boolean operations
-			       copy,      // its copy number
-			       m_checkOverlaps);
-      }
-      data().g4Placements[node] = g4;
-    }
-    else if ( node == s_topPtr )  {
-      G4ThreeVector pos(0,0,0);
+    if ( !trafo ) {
+      printout(FATAL,"Geant4Converter","++ Attempt to handle placement without transformation:%p %s of type %s vol:%p",
+	       node,node->GetName(),node->IsA()->GetName(),vol);
+    }
+    else if ( 0 == vol ) {
+      printout(FATAL,"Geant4Converter","++ Unknown G4 volume:%p %s of type %s vol:%s ptr:%p",
+	       node,node->GetName(),node->IsA()->GetName(),vol->IsA()->GetName(),vol);
+    }
+    else  {
+      int                   copy    = node->GetNumber();
+      G4LogicalVolume*      g4vol   = info.g4Volumes[vol];
+      G4LogicalVolume*      g4mot   = info.g4Volumes[mot_vol];
+      Geant4AssemblyVolume* ass_mot = (Geant4AssemblyVolume*)g4mot;
+      Geant4AssemblyVolume* ass_dau = (Geant4AssemblyVolume*)g4vol;
+      const Double_t*       trans   = trafo->GetTranslation();
+      const Double_t*       rot     = trafo->IsRotation() ? trafo->GetRotationMatrix() : identity_rot;
+      bool daughter_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class();
+      bool mother_is_assembly   = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false;
+      MyTransform3D transform(rot[0],rot[1],rot[2],trans[0]*CM_2_MM,
+			      rot[3],rot[4],rot[5],trans[1]*CM_2_MM,
+			      rot[6],rot[7],rot[8],trans[2]*CM_2_MM);
+      CLHEP::HepRotation rotmat=transform.getRotation();
+
       if ( mother_is_assembly )  {	  // Mother is an assembly:
-	ass_mot->AddPlacedVolume(g4vol,pos,0);
+	printout(DEBUG,"Geant4Converter","++ Assembly: AddPlacedVolume: %16p dau:%s "
+		 "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
+		 ass_mot,g4vol ? g4vol->GetName().c_str() : "---",
+		 transform.dx(),transform.dy(),transform.dz(),
+		 rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi());
+	size_t id = ass_mot->placeVolume(g4vol,transform);
+	info.g4AssemblyChildren[ass_mot].push_back(make_pair(id,node));
 	return 0;
       }
       else if ( daughter_is_assembly )  {
-	ass_dau->MakeImprint(g4mot,pos,0,copy,m_checkOverlaps);
+	printout(DEBUG,"Geant4Converter","++ Assembly: makeImprint: %16p dau:%s "
+		 "Tr:x=%8.3f y=%8.3f z=%8.3f  Rot:phi=%7.3f theta=%7.3f psi=%7.3f\n",
+		 ass_dau,g4mot ? g4mot->GetName().c_str() : "---",
+		 transform.dx(),transform.dy(),transform.dz(),
+		 rotmat.getPhi(),rotmat.getTheta(),rotmat.getPsi());
+	std::vector<G4VPhysicalVolume*> phys_volumes;
+	AssemblyChildMap::iterator i = info.g4AssemblyChildren.find(ass_dau);
+	if ( i == info.g4AssemblyChildren.end() )  {
+	  printout(ERROR, "Geant4Converter", "++ Non-existing assembly [%p]",ass_dau);
+	}
+	const AssemblyChildren& v = (*i).second;
+	ass_dau->imprint(phys_volumes,g4mot,transform,copy,m_checkOverlaps);
+	if ( v.size() != phys_volumes.size() )   {
+	  printout(ERROR, "Geant4Converter", "++ Unexpected number of placements in assembly: %ld <> %ld.",
+		   v.size(), phys_volumes.size());
+	}
+	for(size_t j=0; j<v.size(); ++j)  {
+	  info.g4Placements[v[j].second] = phys_volumes[j];
+	}
 	return 0;
       }
-      g4 = new G4PVPlacement(0,         // no rotation
-			     pos,       // translation position
+      g4 = new G4PVPlacement(transform, // no rotation
 			     g4vol,     // its logical volume
 			     name,      // its name
 			     g4mot,     // its mother (logical) volume
 			     false,     // no boolean operations
 			     copy,      // its copy number
 			     m_checkOverlaps);
-      data().g4Placements[node] = g4;
-      printout(ERROR, "Geant4Converter", "++ Attempt to convert TOP Detector node failed.");
     }
+    info.g4Placements[node] = g4;
   }
   else {
-    printout(ERROR, "Geant4Converter", "++ Attempt to DOUBLE-place physical volume: %s No:%d",
-	     name.c_str(),node->GetNumber());
+   printout(ERROR, "Geant4Converter", "++ Attempt to DOUBLE-place physical volume: %s No:%d",
+	    name.c_str(),node->GetNumber());
   }
   return g4;
 }
@@ -643,7 +705,7 @@ void* Geant4Converter::handleLimitSet(const TNamed* limitset, const set<const TG
 
 /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s).
 void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const TGeoVolume*>& /* volumes */) const  {
-  G4GeometryInfo& info = data();
+  Geant4GeometryInfo& info = data();
   Geant4SensitiveDetector* g4 = info.g4SensDets[sens_det];
   if ( !g4 )   {
     SensitiveDetector sd = Ref_t(sens_det);
@@ -651,8 +713,14 @@ void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const T
 
     g4 = ROOT::Reflex::PluginService::Create<Geant4SensitiveDetector*>(type,name,&m_lcdd);
     if ( !g4 ) {
-      throw runtime_error("Geant4Converter<SensitiveDetector>: FATAL Failed to "
-			  "create Geant4 sensitive detector "+name+" of type "+type+".");
+      string tmp = type;
+      tmp[0] = ::toupper(tmp[0]);
+      type = "Geant4"+tmp;
+      g4 = ROOT::Reflex::PluginService::Create<Geant4SensitiveDetector*>(type,name,&m_lcdd);
+      if ( !g4 )  {
+	throw runtime_error("Geant4Converter<SensitiveDetector>: FATAL Failed to "
+			    "create Geant4 sensitive detector "+name+" of type "+type+".");
+      }
     }
     g4->Activate(true);
     g4->defineCollection(sd.hitsCollection());
@@ -664,7 +732,7 @@ void* Geant4Converter::handleSensitive(const TNamed* sens_det, const set<const T
 
 /// Convert the geometry visualisation attributes to the corresponding Geant4 object(s).
 void* Geant4Converter::handleVis(const string& /* name */, const TNamed* vis) const  {
-  G4GeometryInfo& info = data();
+  Geant4GeometryInfo& info = data();
   G4VisAttributes* g4 = info.g4Vis[vis];
   if ( !g4 )   {
     float   r=0, g=0, b=0;
@@ -732,7 +800,7 @@ void Geant4Converter::handleProperties(LCDD::Properties& prp)   const {
 
 /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s).
 void* Geant4Converter::printSensitive(const TNamed* sens_det, const set<const TGeoVolume*>& /* volumes */) const  {
-  G4GeometryInfo& info = data();
+  Geant4GeometryInfo& info = data();
   Geant4SensitiveDetector* g4 = info.g4SensDets[sens_det];
   ConstVolumeSet& volset = info.sensitives[sens_det];
   SensitiveDetector   sd = Ref_t(sens_det);
@@ -777,12 +845,12 @@ string printSolid(G4VSolid* sol) {
 
 /// Print G4 placement
 void* Geant4Converter::printPlacement(const string& name, const TGeoNode* node) const {
-  G4GeometryInfo& info = data();  
-  G4PVPlacement*    g4 = info.g4Placements[node];
-  G4LogicalVolume* vol = info.g4Volumes[node->GetVolume()];
-  G4LogicalVolume* mot = info.g4Volumes[node->GetMotherVolume()];
-  G4VSolid*        sol = vol->GetSolid();
-  G4ThreeVector     tr = g4->GetObjectTranslation();
+  Geant4GeometryInfo&  info = data();  
+  G4VPhysicalVolume* g4 = info.g4Placements[node];
+  G4LogicalVolume*  vol = info.g4Volumes[node->GetVolume()];
+  G4LogicalVolume*  mot = info.g4Volumes[node->GetMotherVolume()];
+  G4VSolid*         sol = vol->GetSolid();
+  G4ThreeVector      tr = g4->GetObjectTranslation();
   
   G4VSensitiveDetector* sd = vol->GetSensitiveDetector();
   if ( !sd ) return g4;
@@ -827,7 +895,7 @@ template <typename O, typename C, typename F> void handleRMap(const O* o, const
 
 /// Create geometry conversion
 Geant4Converter& Geant4Converter::create(DetElement top) {
-  G4GeometryInfo& geo = *(m_dataPtr=new G4GeometryInfo);
+  Geant4GeometryInfo& geo = this->init();
   m_data->clear();
   collect(top, geo);
   s_topPtr = top.placement().ptr();
@@ -861,5 +929,6 @@ Geant4Converter& Geant4Converter::create(DetElement top) {
 
   //handleMap(this, geo.sensitives, &Geant4Converter::printSensitive);
   //handleRMap(this, *m_data, &Geant4Converter::printPlacement);
+  geo.valid = true;
   return *this;
 }
diff --git a/DDG4/src/Geant4DetectorConstruction.cpp b/DDG4/src/Geant4DetectorConstruction.cpp
index f1478c882..b8945e666 100644
--- a/DDG4/src/Geant4DetectorConstruction.cpp
+++ b/DDG4/src/Geant4DetectorConstruction.cpp
@@ -26,9 +26,10 @@ G4VPhysicalVolume* DD4hep::Simulation::Geant4DetectorConstruction::Construct() {
   Geant4Mapping&  g4map = Geant4Mapping::instance();
   DetElement      world = m_lcdd.world();
   Geant4Converter conv(m_lcdd);
-  Geant4Converter::G4GeometryInfo* info = conv.create(world).detach();
+  Geant4GeometryInfo* info = conv.create(world).detach();
   g4map.attach(info);
-  m_world = g4map.g4Placement(top);
+  Geant4VolumeManager mgr = g4map.volumeManager();
+  m_world = mgr.placement(top);
   m_lcdd.apply("DD4hepVolumeManager",0,0);
   //Geant4HierarchyDump dmp(m_lcdd);
   //dmp.dump("",m_world);
diff --git a/DDG4/src/Geant4GeometryInfo.cpp b/DDG4/src/Geant4GeometryInfo.cpp
new file mode 100644
index 000000000..97d044c1e
--- /dev/null
+++ b/DDG4/src/Geant4GeometryInfo.cpp
@@ -0,0 +1,21 @@
+// $Id: Geant4Mapping.cpp 588 2013-06-03 11:41:35Z markus.frank $
+//====================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+
+#include "DDG4/Geant4GeometryInfo.h"
+using namespace DD4hep::Simulation;
+
+/// Default constructor
+Geant4GeometryInfo::Geant4GeometryInfo() 
+: TNamed("Geant4GeometryInfo","Geant4GeometryInfo"), valid(false)
+{
+}
+
+/// Default destructor
+Geant4GeometryInfo::~Geant4GeometryInfo()   {
+}
diff --git a/DDG4/src/Geant4Mapping.cpp b/DDG4/src/Geant4Mapping.cpp
index 2f2376c1b..18bfab246 100644
--- a/DDG4/src/Geant4Mapping.cpp
+++ b/DDG4/src/Geant4Mapping.cpp
@@ -7,6 +7,7 @@
 //
 //====================================================================
 
+#include "DD4hep/Printout.h"
 #include "DDG4/Geant4Mapping.h"
 #include "G4PVPlacement.hh"
 #include <stdexcept>
@@ -16,8 +17,7 @@ using namespace DD4hep::Geometry;
 using namespace std;
 
 /// Initializing Constructor
-Geant4Mapping::Geant4Mapping( LCDD& lcdd, G4GeometryInfo* data) 
-  : m_lcdd(lcdd), m_dataPtr(data)
+Geant4Mapping::Geant4Mapping(LCDD& lcdd) : m_lcdd(lcdd), m_dataPtr(0)
 {
 }
 
@@ -29,7 +29,7 @@ Geant4Mapping::~Geant4Mapping()  {
 
 /// Possibility to define a singleton instance
 Geant4Mapping& Geant4Mapping::instance()  {
-  static Geant4Mapping inst(LCDD::getInstance(),0);
+  static Geant4Mapping inst(LCDD::getInstance());
   return inst;
 }
 
@@ -39,25 +39,35 @@ void Geant4Mapping::checkValidity() const   {
   throw runtime_error("Geant4Mapping: Attempt to access an invalid data block!");
 }
 
+/// Create new data block. Delete old data block if present.
+Geant4GeometryInfo& Geant4Mapping::init()  {
+  Geant4GeometryInfo* p = detach();
+  if ( p ) delete p;
+  attach(new Geant4GeometryInfo());
+  return data();
+}
+
 /// Release data and pass over the ownership
-Geant4Mapping::G4GeometryInfo* Geant4Mapping::detach()   {
-  G4GeometryInfo* p = m_dataPtr;
+Geant4GeometryInfo* Geant4Mapping::detach()   {
+  Geant4GeometryInfo* p = m_dataPtr;
   m_dataPtr = 0;
   return p;
 }
 
 /// Set a new data block
-void Geant4Mapping::attach(G4GeometryInfo* data)   {
+void Geant4Mapping::attach(Geant4GeometryInfo* data)   {
   m_dataPtr = data;
 }
 
-/// Accessor to resolve G4 placements
-G4PVPlacement* Geant4Mapping::g4Placement(const TGeoNode* node)  const   {
-  checkValidity();
-  const PlacementMap& m = m_dataPtr->g4Placements;
-  PlacementMap::const_iterator i = m.find(node);
-  if ( i !=  m.end() ) return (*i).second;
-  return 0;
+/// Access the volume manager
+Geant4VolumeManager Geant4Mapping::volumeManager() const   {
+  if ( m_dataPtr )  {
+    if ( m_dataPtr->g4Paths.empty() )  {
+      return Geant4VolumeManager(m_lcdd,m_dataPtr);
+    }
+    return Geant4VolumeManager(Geometry::Handle<Geant4GeometryInfo>(m_dataPtr));
+  }
+  throw runtime_error(format("Geant4Mapping","Cannot create volume manager without Geant4 geometry info [Invalid-Info]"));
 }
 
 /// Accessor to resolve geometry placements
diff --git a/DDG4/src/Geant4SensitiveDetector.cpp b/DDG4/src/Geant4SensitiveDetector.cpp
index b1c408722..9132bb642 100644
--- a/DDG4/src/Geant4SensitiveDetector.cpp
+++ b/DDG4/src/Geant4SensitiveDetector.cpp
@@ -95,6 +95,11 @@ void Geant4SensitiveDetector::EndOfEvent(G4HCofThisEvent* /* HCE */) {
 
 /// Method for generating hit(s) using the information of G4Step object.
 G4bool Geant4SensitiveDetector::ProcessHits(G4Step* step,G4TouchableHistory* hist) {
+  return process(step,hist);
+}
+
+/// Method for generating hit(s) using the information of G4Step object.
+G4bool Geant4SensitiveDetector::process(G4Step* step,G4TouchableHistory* hist) {
   double ene_cut = m_sensitive.energyCutoff();
   if ( step->GetTotalEnergyDeposit() > ene_cut ) {
     if ( !Geant4Hit::isGeantino(step->GetTrack()) )   {
@@ -155,7 +160,7 @@ void Geant4SensitiveDetector::dumpStep(G4Step* st, G4TouchableHistory* /* histor
   const Places& places = cnv.data().g4Placements;
 
   for(Places::const_iterator i=places.begin(); i!=places.end();++i) {
-    const G4PVPlacement* pl = (*i).second;
+    const G4VPhysicalVolume* pl = (*i).second;
     const G4VPhysicalVolume* qv = pl;
     
     if ( qv == pv ) {
diff --git a/DDG4/src/Geant4VolumeManager.cpp b/DDG4/src/Geant4VolumeManager.cpp
new file mode 100644
index 000000000..57fdb518a
--- /dev/null
+++ b/DDG4/src/Geant4VolumeManager.cpp
@@ -0,0 +1,245 @@
+// $Id: Geant4VolumeManager.cpp 513 2013-04-05 14:31:53Z gaede $
+//====================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+
+// Framework include files
+#include "DD4hep/Printout.h"
+#include "DD4hep/Volumes.h"
+#include "DD4hep/Detector.h"
+#include "DDG4/Geant4VolumeManager.h"
+#include "DDG4/Geant4Mapping.h"
+
+// Geant4 include files
+#include "G4VTouchable.hh"
+#include "G4LogicalVolume.hh"
+#include "G4VPhysicalVolume.hh"
+
+using namespace DD4hep::Simulation;
+using namespace DD4hep::Geometry;
+using namespace DD4hep;
+using namespace std;
+
+typedef Geant4GeometryInfo::PathMap      PathMap;
+typedef Geant4GeometryInfo::PlacementMap PlacementMap;
+
+namespace {
+
+  struct Populator  {
+    typedef vector<const TGeoNode*>      Chain;
+    typedef DD4hep::Geometry::LCDD       LCDD;
+    typedef DD4hep::Geometry::Readout    Readout;
+    typedef DD4hep::Geometry::DetElement DetElement;
+
+    /// Reference to the LCDD instance
+    LCDD&               m_lcdd;
+    /// Set of already added entries
+    set<VolumeID>       m_entries;
+    /// Reference to Geant4 translation information
+    Geant4GeometryInfo& m_geo;
+
+    /// Default constructor
+    Populator(LCDD& lcdd, Geant4GeometryInfo& g) : m_lcdd(lcdd), m_geo(g) {
+    }
+
+    /// Populate the Volume manager
+    void populate(DetElement e)   {
+      const DetElement::Children& c = e.children();
+      for(DetElement::Children::const_iterator i=c.begin(); i!=c.end(); ++i)   {
+	DetElement   de = (*i).second;
+	PlacedVolume pv = de.placement();
+	if ( pv.isValid() )  {
+	  Chain                chain;
+	  SensitiveDetector    sd;
+	  PlacedVolume::VolIDs ids;
+	  m_entries.clear();
+	  scanPhysicalVolume(pv.ptr(), ids, sd, chain);
+	  continue;
+	}
+	printout(WARNING,"VolumeManager","++ Detector element %s of type %s has no placement.",
+		 de.name(),de.type().c_str());
+      }
+    }
+
+    /// Scan a single physical volume and look for sensitive elements below
+    void scanPhysicalVolume(const TGeoNode* node, PlacedVolume::VolIDs ids, SensitiveDetector& sd, Chain& chain)    {
+      PlacedVolume pv  = Ref_t(node);
+      Volume       vol = pv.volume();
+      PlacedVolume::VolIDs pv_ids = pv.volIDs();
+
+      chain.push_back(node);
+      ids.PlacedVolume::VolIDs::Base::insert(ids.end(),pv_ids.begin(),pv_ids.end());
+      if ( vol.isSensitive() )  {
+	sd = vol.sensitiveDetector();
+	if ( sd.readout().isValid() )  {
+	  add_entry(sd, node, ids, chain);
+	}
+	else  {
+	  printout(WARNING,"VolumeManager",
+		   "Strange constellation volume %s is sensitive, but has no readout! sd:%p",
+		   pv.volume().name(), sd.ptr());
+	}
+      }
+      for(Int_t idau=0, ndau=node->GetNdaughters(); idau<ndau; ++idau)  {
+	TGeoNode* daughter = node->GetDaughter(idau);
+	if ( dynamic_cast<const PlacedVolume::Object*>(daughter) ) {
+	  scanPhysicalVolume(daughter, ids, sd, chain);
+	}
+      }
+      chain.pop_back();
+    }
+
+    void add_entry(SensitiveDetector sd, const TGeoNode* n, const PlacedVolume::VolIDs& ids, const Chain& nodes)  {
+      Readout      ro      = sd.readout();
+      IDDescriptor iddesc  = ro.idSpec();
+      VolumeID     code    = iddesc.encode(ids);
+      if ( m_entries.find(code) == m_entries.end() )  {
+	PlacedVolume place = Ref_t(n);
+	Geant4Mapping::PlacementPath path;
+	path.reserve(nodes.size());
+	for(Chain::const_reverse_iterator i=nodes.rbegin(); i != nodes.rend(); ++i)   {
+	  const TGeoNode* n = *i;
+	  PlacementMap::const_iterator g4pit = m_geo.g4Placements.find(n);
+	  if ( g4pit != m_geo.g4Placements.end() )  {
+	    path.push_back((*g4pit).second);
+	  }
+	}
+	if ( m_geo.g4Paths.find(path) != m_geo.g4Paths.end() )  {
+	  cout <<  "Severe error: Duplicated Geant4 path!!!!" << endl;
+	}
+	m_geo.g4Paths[path] = code;
+	m_entries.insert(code);
+      }
+      else   {
+	cout <<  "Severe error: Duplicated Volume entry:" << (void*)code << endl;
+      }
+    }
+  };
+}
+
+/// Initializing constructor. The tree will automatically be built if possible
+Geant4VolumeManager::Geant4VolumeManager(LCDD& lcdd, Geant4GeometryInfo* info) 
+: Base(info), m_isValid(false)
+{
+  if ( info && info->valid && info->g4Paths.empty() )   {
+    Populator p(lcdd,*info);
+    p.populate(lcdd.world());
+    return;
+  }
+  throw runtime_error(format("Geant4VolumeManager","Attempt populate from invalid Geant4 geometry info [Invalid-Info]"));
+}
+
+/// Helper: Generate placement path from touchable object
+Geant4VolumeManager::PlacementPath 
+Geant4VolumeManager::placementPath(const G4VTouchable* touchable, bool exception) const   
+{
+  Geant4Mapping::PlacementPath path;
+  if ( touchable )   {
+    for(int i=0, n=touchable->GetHistoryDepth(); i<n; ++i)  {
+      G4VPhysicalVolume* pv = touchable->GetVolume(i);
+      path.push_back(pv);
+    }
+  }
+  else if ( exception )  {
+    throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 touchable [Invalid-Touchable]"));
+  }
+  return path;
+}
+
+/// Check the validity of the information before accessing it.
+bool Geant4VolumeManager::checkValidity() const   {
+  if ( m_isValid )  {
+    return true;
+  }
+  else if ( !isValid() )   {
+    throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 volume manager [Invalid-Handle]"));
+  }
+  else if ( !ptr()->valid )  {
+    throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 geometry info [Invalid-Info]"));
+  }
+  m_isValid = true;
+  return m_isValid;
+}
+
+/// Accessor to resolve G4 placements
+G4VPhysicalVolume* Geant4VolumeManager::placement(const TGeoNode* node)  const   {
+  if ( node && checkValidity() )  {
+    const PlacementMap& m = ptr()->g4Placements;
+    PlacementMap::const_iterator i = m.find(node);
+    if ( i !=  m.end() ) return (*i).second;
+    return 0;
+  }
+  throw runtime_error(format("Geant4VolumeManager","Attempt to use invalid Geant4 volume manager [Invalid-Handle]"));
+}
+
+/// Accessor to resolve geometry placements
+PlacedVolume Geant4VolumeManager::placement(const G4VPhysicalVolume* node)  const   {
+  if ( node && checkValidity() )  {
+    const PlacementMap& m = ptr()->g4Placements;
+    for(PlacementMap::const_iterator i = m.begin(); i != m.end(); ++i)   {
+      if ( (*i).second == node ) return PlacedVolume((*i).first);
+    }
+    return PlacedVolume(0);
+  }
+  throw runtime_error(format("Geant4VolumeManager","Attempt to lookup invalid TGeo placement [Null-Pointer]"));
+}
+
+/// Access CELLID by placement path
+VolumeID Geant4VolumeManager::volumeID(const PlacementPath& path) const    {
+  if ( !path.empty() && checkValidity() )  {
+    const PathMap& m = ptr()->g4Paths;
+    PathMap::const_iterator i=m.find(path);
+    if ( i != m.end() ) return (*i).second;
+    if ( !path[0] )
+      return InvalidPath;
+    else if ( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
+      return Insensitive;
+    return NonExisting;
+  }
+  return NonExisting;
+}
+
+/// Access CELLID by Geant4 touchable object
+VolumeID Geant4VolumeManager::volumeID(const G4VTouchable* touchable) const   {
+  return volumeID(placementPath(touchable));
+}
+
+/// Accessfully decoded volume fields  by placement path
+void Geant4VolumeManager::volumeDescriptor(const PlacementPath& path, VolIDDescriptor& vol_desc) const    {
+  vol_desc.second.clear();
+  vol_desc.first = NonExisting;
+  if ( !path.empty() && checkValidity() )  {
+    const PathMap& m = ptr()->g4Paths;
+    PathMap::const_iterator i=m.find(path);
+    if ( i != m.end() )   {
+      VolumeID vid = (*i).second;
+      G4LogicalVolume* lvol = path[0]->GetLogicalVolume();
+      if ( lvol->GetSensitiveDetector() )  {
+	PlacedVolume pv = placement(path[0]);
+	Geometry::SensitiveDetector sd  = pv.volume().sensitiveDetector();
+	Geometry::IDDescriptor      dsc = sd.readout().idSpec();
+	vol_desc.first = vid;
+	dsc.decodeFields(vid,vol_desc.second);
+	return;
+      }
+      vol_desc.first = Insensitive;
+      return;
+    }
+    if ( !path[0] )
+      vol_desc.first = InvalidPath;
+    else if ( !path[0]->GetLogicalVolume()->GetSensitiveDetector() )
+      vol_desc.first = Insensitive;
+    else
+      vol_desc.first = NonExisting;
+  }
+}
+
+/// Access fully decoded volume fields by Geant4 touchable object
+void Geant4VolumeManager::volumeDescriptor(const G4VTouchable* touchable, VolIDDescriptor& vol_desc) const    {
+  volumeDescriptor(placementPath(touchable),vol_desc);
+}
+
-- 
GitLab