From c03310882642579ce735987e2dff01ec335f9ad0 Mon Sep 17 00:00:00 2001
From: Markus Frank <markus.frank@cern.ch>
Date: Fri, 8 May 2015 18:57:08 +0000
Subject: [PATCH] Allow to access detectors by type from lcdd

---
 DDCore/include/DD4hep/LCDD.h                  | 28 +++++++-
 .../include/DD4hep/objects/DetectorInterna.h  | 10 +--
 DDCore/src/LCDDImp.cpp                        | 66 +++++++++++++++++++
 DDCore/src/LCDDImp.h                          | 26 ++++++++
 DDCore/src/plugins/StandardPlugins.cpp        | 42 ++++++++++--
 DDDetectors/src/SubdetectorAssembly_geo.cpp   |  4 +-
 doc/release.notes                             |  9 +++
 7 files changed, 172 insertions(+), 13 deletions(-)

diff --git a/DDCore/include/DD4hep/LCDD.h b/DDCore/include/DD4hep/LCDD.h
index 261cf2252..59a261830 100644
--- a/DDCore/include/DD4hep/LCDD.h
+++ b/DDCore/include/DD4hep/LCDD.h
@@ -24,6 +24,7 @@
 
 // C/C++ include files
 #include <map>
+#include <vector>
 
 // Forward declarations
 class TGeoManager;
@@ -64,7 +65,8 @@ namespace DD4hep {
     class LCDD {
     public:
       /// Type definition of a map of named handles
-      typedef std::map<std::string, Handle<NamedObject> > HandleMap;
+      typedef Handle<NamedObject> NamedHandle;
+      typedef std::map<std::string, NamedHandle > HandleMap;
       typedef std::map<std::string, std::string> PropertyValues;
       typedef std::map<std::string, PropertyValues> Properties;
 
@@ -132,6 +134,30 @@ namespace DD4hep {
       /// Accessor to the map of ID specifications
       virtual const HandleMap& idSpecifications() const = 0;
 
+      #ifndef __MAKECINT__
+      /** Access to predefined caches of subdetectors according to the sensitive type */
+      /// Access a set of subdetectors according to the sensitive type.
+      /**
+	 Please note:
+	 - The sensitive type of a detector is set in the 'detector constructor'.
+	 - Not sensitive detector structures have the name 'passive'
+	 - Compounds (ie. nested detectors) are of type 'compound'
+       */
+      virtual const std::vector<DetElement>& detectors(const std::string& type) = 0;
+
+      /// Access a set of subdetectors according to several sensitive types.
+      virtual std::vector<DetElement> detectors(const std::string& type1,
+						const std::string& type2,
+						const std::string& type3="",
+						const std::string& type4="",
+						const std::string& type5="" ) = 0;
+
+      /// Access the availible detector types
+      virtual std::vector<std::string> detectorTypes() const = 0;
+      #endif
+
+      /** Miscaneleous accessors to the detexctor description  */
+
       /// Register new mother volume using the detector name.
       /** Volumes must be registered/declared PRIOR to be picked up!
        *  The method throws an exception if another volume was already declared for this subdetector
diff --git a/DDCore/include/DD4hep/objects/DetectorInterna.h b/DDCore/include/DD4hep/objects/DetectorInterna.h
index 1864c073b..4e38457f7 100644
--- a/DDCore/include/DD4hep/objects/DetectorInterna.h
+++ b/DDCore/include/DD4hep/objects/DetectorInterna.h
@@ -67,11 +67,13 @@ namespace DD4hep {
      */
     class DetElementObject: public NamedObject, public ObjectExtensions {
     public:
-      typedef DetElement::destruct_t destruct_t;
-      typedef DetElement::copy_t copy_t;
+      // Type definitions.
+      // The full namespace declaration is required by cint....
+      typedef /* DD4hep::Geometry:: */  DetElement::destruct_t destruct_t;
+      typedef /* DD4hep::Geometry:: */  DetElement::copy_t copy_t;
 
-      typedef DetElement::Children Children;
-      typedef DetElement::Extensions Extensions;
+      typedef /* DD4hep::Geometry:: */  DetElement::Children Children;
+      typedef /* DD4hep::Geometry:: */  DetElement::Extensions Extensions;
       typedef std::pair<Callback,unsigned long> UpdateCall;
       typedef std::vector<UpdateCall> UpdateCallbacks;
 
diff --git a/DDCore/src/LCDDImp.cpp b/DDCore/src/LCDDImp.cpp
index 4209ff40c..7a0382e40 100644
--- a/DDCore/src/LCDDImp.cpp
+++ b/DDCore/src/LCDDImp.cpp
@@ -245,6 +245,71 @@ Material LCDDImp::material(const string& name) const {
   throw runtime_error("Cannot find a material the reference name:" + name);
 }
 
+/// Internal helper to map detector types once the geometry is closed
+void LCDDImp::mapDetectorTypes()  {
+  for(HandleMap::const_iterator i=m_detectors.begin(); i!=m_detectors.end(); ++i)   {
+    DetElement det((*i).second);
+    if ( det.parent().isValid() )  { // Exclude 'world'
+      HandleMap::const_iterator j=m_sensitive.find(det.name());
+      if ( j != m_sensitive.end() )  {
+	SensitiveDetector sd((*j).second);
+	m_detectorTypes[sd.type()].push_back(det);
+      }
+      else if ( det.type() == "compound" )  {
+	m_detectorTypes[det.type()].push_back(det);      
+      }
+      else  {
+	m_detectorTypes["passive"].push_back(det);      
+      }
+    }
+  }
+}
+
+/// Access the availible detector types
+vector<string> LCDDImp::detectorTypes() const  {
+  if ( m_manager->IsClosed() ) {
+    vector<string> v;
+    for(DetectorTypeMap::const_iterator i=m_detectorTypes.begin(); i!=m_detectorTypes.end(); ++i)  
+      v.push_back((*i).first);
+    return v;
+  }
+  throw runtime_error("detectorTypes: Call only available once the geometry is closed!");
+}
+
+/// Access a set of subdetectors according to the sensitive type.
+const vector<DetElement>& LCDDImp::detectors(const string& type)  {
+  if ( m_manager->IsClosed() ) {
+    DetectorTypeMap::const_iterator i=m_detectorTypes.find(type);
+    if ( i != m_detectorTypes.end() ) return (*i).second;
+    throw runtime_error("detectors("+type+"): Detectors of this type do not exist in the current setup!");
+  }
+  throw runtime_error("detectors("+type+"): Detectors can only selected by type once the geometry is closed!");
+}
+
+/// Access a set of subdetectors according to several sensitive types.
+vector<DetElement> LCDDImp::detectors(const string& type1,
+				      const string& type2,
+				      const string& type3,
+				      const string& type4,
+				      const string& type5 )  {
+  if ( m_manager->IsClosed() ) {
+    vector<DetElement> v;
+    DetectorTypeMap::const_iterator i, end=m_detectorTypes.end();
+    if ( !type1.empty() && (i=m_detectorTypes.find(type1)) != end )
+      v.insert(v.end(),(*i).second.begin(),(*i).second.end());
+    if ( !type2.empty() && (i=m_detectorTypes.find(type2)) != end )
+      v.insert(v.end(),(*i).second.begin(),(*i).second.end());
+    if ( !type3.empty() && (i=m_detectorTypes.find(type3)) != end )
+      v.insert(v.end(),(*i).second.begin(),(*i).second.end());
+    if ( !type4.empty() && (i=m_detectorTypes.find(type4)) != end )
+      v.insert(v.end(),(*i).second.begin(),(*i).second.end());
+    if ( !type5.empty() && (i=m_detectorTypes.find(type5)) != end ) 
+      v.insert(v.end(),(*i).second.begin(),(*i).second.end());
+    return v;
+  }
+  throw runtime_error("detectors("+type1+","+type2+",...): Detectors can only selected by type once the geometry is closed!");
+}
+
 Handle<TObject> LCDDImp::getRefChild(const HandleMap& e, const string& name, bool do_throw) const {
   HandleMap::const_iterator i = e.find(name);
   if (i != e.end()) {
@@ -344,6 +409,7 @@ void LCDDImp::endDocument() {
     mgr->CloseGeometry();
     ShapePatcher patcher(m_volManager, m_world);
     patcher.patchShapes();
+    mapDetectorTypes();
   }
 }
 
diff --git a/DDCore/src/LCDDImp.h b/DDCore/src/LCDDImp.h
index 538d249d9..6b682347c 100644
--- a/DDCore/src/LCDDImp.h
+++ b/DDCore/src/LCDDImp.h
@@ -32,6 +32,11 @@ namespace DD4hep {
      * @version 1.0
      */
     class LCDDImp: public LCDD, public LCDDData, public LCDDLoad  {
+    protected:
+      /// Cached map with detector types:
+      typedef std::map<std::string, std::vector<DetElement> > DetectorTypeMap;
+      DetectorTypeMap m_detectorTypes;
+
     private:
       /// Disable copy constructor
       LCDDImp(const LCDDImp&);
@@ -39,6 +44,8 @@ namespace DD4hep {
       /// Disable assignment operator
       LCDDImp& operator=(const LCDDImp&);
 
+      /// Internal helper to map detector types once the geometry is closed
+      void mapDetectorTypes();
     public:
 
       /// Local method (no interface): Load volume manager.
@@ -238,6 +245,25 @@ namespace DD4hep {
         return m_idDict;
       }
 
+      /// Access a set of subdetectors according to the sensitive type.
+      /**
+	 Please note:
+	 - The sensitive type of a detector is set in the 'detector constructor'.
+	 - Not sensitive detector structures have the name 'passive'
+	 - Compounds (ie. nested detectors) are of type 'compound'
+       */
+      virtual const std::vector<DetElement>& detectors(const std::string& type);
+
+      /// Access a set of subdetectors according to several sensitive types.
+      virtual std::vector<DetElement> detectors(const std::string& type1,
+						const std::string& type2,
+						const std::string& type3="",
+						const std::string& type4="",
+						const std::string& type5="" );
+
+      /// Access the availible detector types
+      virtual std::vector<std::string> detectorTypes() const;
+
 #define __R  return *this
       /// Add a new constant to the detector description
       virtual LCDD& add(Constant x) {
diff --git a/DDCore/src/plugins/StandardPlugins.cpp b/DDCore/src/plugins/StandardPlugins.cpp
index 0c9ec8d65..06c6a2553 100644
--- a/DDCore/src/plugins/StandardPlugins.cpp
+++ b/DDCore/src/plugins/StandardPlugins.cpp
@@ -199,14 +199,27 @@ DECLARE_APPLY(DD4hepVolumeDump,dump_volume_tree)
  *  @version 1.0
  *  @date    01/04/2014
  */
-static long dump_detelement_tree(LCDD& lcdd, int argc, char** argv) {
+template <int flag> long dump_detelement_tree(LCDD& lcdd, int argc, char** argv) {
   struct Actor {
     static long dump(DetElement de,int level, bool sensitive_only) {
       const DetElement::Children& c = de.children();
       if ( !sensitive_only || 0 != de.volumeID() )  {
+	int value = flag;
 	char fmt[64];
-	::sprintf(fmt,"%03d %%-%ds %%s #Dau:%%d VolID:%%p",level+1,2*level+1);
-	printout(INFO,"+++",fmt,"",de.placementPath().c_str(),int(c.size()),(void*)de.volumeID());
+	switch(value)  {
+	case 0:
+	  ::sprintf(fmt,"%03d %%-%ds %%s #Dau:%%d VolID:%%p",level+1,2*level+1);
+	  printout(INFO,"+++",fmt,"",de.path().c_str(),int(c.size()),(void*)de.volumeID());
+	  break;
+	case 1:
+	  ::sprintf(fmt,"%03d %%-%ds Detector: %%s #Dau:%%d VolID:%%p",level+1,2*level+1);
+	  printout(INFO,"+++",fmt,"",de.path().c_str(),int(c.size()),(void*)de.volumeID());
+	  ::sprintf(fmt,"%03d %%-%ds Placement: %%s",level+1,2*level+3);
+	  printout(INFO,"+++",fmt,"",de.placementPath().c_str());
+	  break;
+	default:
+	  break;
+	}
       }
       for (DetElement::Children::const_iterator i = c.begin(); i != c.end(); ++i)
 	dump((*i).second,level+1,sensitive_only);
@@ -219,7 +232,8 @@ static long dump_detelement_tree(LCDD& lcdd, int argc, char** argv) {
   }
   return Actor::dump(lcdd.world(),0,sensitive_only);
 }
-DECLARE_APPLY(DD4hepDetectorDump,dump_detelement_tree)
+DECLARE_APPLY(DD4hepDetectorDump,dump_detelement_tree<0>)
+DECLARE_APPLY(DD4hepDetectorVolumeDump,dump_detelement_tree<1>)
 
 /** Basic entry point to print out the volume hierarchy
  *
@@ -266,9 +280,27 @@ static long exec_SimpleGDMLWriter(LCDD& lcdd, int argc, char** argv) {
   }
   return 1;
 }
-
 DECLARE_APPLY(DD4hepSimpleGDMLWriter,exec_SimpleGDMLWriter)
 
+/** Basic entry point to print out detector type map
+ *
+ *  @author  M.Frank
+ *  @version 1.0
+ *  @date    01/04/2014
+ */
+static long detectortype_cache(LCDD& lcdd, int , char** ) {
+  vector<string> v = lcdd.detectorTypes();
+  printout(INFO,"DetectorTypes","Detector type dump:  %ld types:",long(v.size()));
+  for(vector<string>::const_iterator i=v.begin(); i!=v.end(); ++i)   {
+    const vector<DetElement>& vv=lcdd.detectors(*i);
+    printout(INFO,"DetectorTypes","\t --> %ld %s detectors:",long(vv.size()),(*i).c_str());
+    for(vector<DetElement>::const_iterator j=vv.begin(); j!=vv.end(); ++j)
+      printout(INFO,"DetectorTypes","\t\t %-16s --> %s  [%s]",(*i).c_str(),(*j).name(),(*j).type().c_str());
+  }
+  return 1;
+}
+DECLARE_APPLY(DD4hepDetectorTypes,detectortype_cache)
+
 #include "DD4hep/SurfaceInstaller.h"
 typedef SurfaceInstaller TestSurfacesPlugin;
 DECLARE_SURFACE_INSTALLER(TestSurfaces,TestSurfacesPlugin)
diff --git a/DDDetectors/src/SubdetectorAssembly_geo.cpp b/DDDetectors/src/SubdetectorAssembly_geo.cpp
index 7d8edcd6b..a459a9ecf 100644
--- a/DDDetectors/src/SubdetectorAssembly_geo.cpp
+++ b/DDDetectors/src/SubdetectorAssembly_geo.cpp
@@ -25,6 +25,7 @@ static Ref_t create_element(LCDD& lcdd, xml_h e, Ref_t)  {
   Position    pos;
   RotationZYX rot;
 
+  sdet.setType("compound");
   usePos = x_det.hasChild(_U(position));
   useRot = x_det.hasChild(_U(rotation));
   if( usePos ) {
@@ -34,7 +35,6 @@ static Ref_t create_element(LCDD& lcdd, xml_h e, Ref_t)  {
     rot = RotationZYX(x_det.rotation().x(), x_det.rotation().y(), x_det.rotation().z());
   }
 
-
   if ( x_det.hasChild(_U(shape)) )  {
     xml_comp_t x_shape = x_det.child(_U(shape));
     string     type  = x_shape.typeStr();
@@ -42,8 +42,6 @@ static Ref_t create_element(LCDD& lcdd, xml_h e, Ref_t)  {
     Material   mat   = lcdd.material(x_shape.materialStr());
     printout(DEBUG,det_name,"+++ Creating detector assembly with shape of type:%s",type.c_str());
     vol = Volume(det_name,solid,mat);
-
-
   }
   else  {
     printout(DEBUG,det_name,"+++ Creating detector assembly without shape");
diff --git a/doc/release.notes b/doc/release.notes
index 2456a06d9..0ceb8da0f 100644
--- a/doc/release.notes
+++ b/doc/release.notes
@@ -4,6 +4,15 @@ DD4hep  ----  Release Notes
 =================================
 
 
+2015/05/09 Markus Frank
+-----------------------
+  - Allow to access detectors by type from lcdd.
+	 - The sensitive type of a detector is set in the 'detector constructor'.
+	 - Not sensitive detector structures have the name 'passive'
+	 - Compounds (ie. nested detectors) are of type 'compound'
+  - Dump detector types using plugin:
+         geoPluginRun -plugin DD4hepDetectorTypes -input <compact-file>
+
 2015/03/12 Markus Frank
 -----------------------
   - Add support for ellipsoids in gdml/lcdd and geant4 conversion.
-- 
GitLab