From 9d17d6a4d28a155c3384a3bf222b4cde0033ee9c Mon Sep 17 00:00:00 2001
From: Markus Frank <markus.frank@cern.ch>
Date: Mon, 17 Nov 2014 09:27:06 +0000
Subject: [PATCH] Check region definition conversion from compact

---
 DDCore/include/DD4hep/Objects.h               |   6 -
 .../include/DD4hep/objects/ObjectsInterna.h   |   1 -
 DDCore/include/XML/XMLDimension.h             |  18 ++
 DDCore/src/Objects.cpp                        |  22 --
 DDCore/src/XML/XMLDimension.cpp               |   6 +
 DDCore/src/plugins/Compact2Objects.cpp        |  56 +++--
 DDCore/src/plugins/LCDDConverter.cpp          |   4 +-
 DDCore/src/plugins/VolumeMgrTest.cpp          | 194 ++++++++++++++++++
 8 files changed, 263 insertions(+), 44 deletions(-)
 create mode 100644 DDCore/src/plugins/VolumeMgrTest.cpp

diff --git a/DDCore/include/DD4hep/Objects.h b/DDCore/include/DD4hep/Objects.h
index 82ead32b3..7ca2cc283 100644
--- a/DDCore/include/DD4hep/Objects.h
+++ b/DDCore/include/DD4hep/Objects.h
@@ -520,8 +520,6 @@ namespace DD4hep {
       Region& setStoreSecondaries(bool value);
       Region& setThreshold(double value);
       Region& setCut(double value);
-      Region& setLengthUnit(const std::string& unit);
-      Region& setEnergyUnit(const std::string& unit);
       /// Access references to user limits
       std::vector<std::string>& limits() const;
 
@@ -531,10 +529,6 @@ namespace DD4hep {
       double threshold() const;
       /// Access secondaries flag
       bool storeSecondaries() const;
-      /// Access the length unit
-      const std::string& lengthUnit() const;
-      /// Access the energy unit
-      const std::string& energyUnit() const;
     };
 
   } /* End namespace Geometry           */
diff --git a/DDCore/include/DD4hep/objects/ObjectsInterna.h b/DDCore/include/DD4hep/objects/ObjectsInterna.h
index c30d11515..28667566e 100644
--- a/DDCore/include/DD4hep/objects/ObjectsInterna.h
+++ b/DDCore/include/DD4hep/objects/ObjectsInterna.h
@@ -85,7 +85,6 @@ namespace DD4hep {
       double threshold;
       double cut;
       bool store_secondaries;
-      std::string lunit, eunit;
       std::vector<std::string> user_limits;
       /// Standard constructor
       RegionObject();
diff --git a/DDCore/include/XML/XMLDimension.h b/DDCore/include/XML/XMLDimension.h
index 3e93304eb..0390645d4 100644
--- a/DDCore/include/XML/XMLDimension.h
+++ b/DDCore/include/XML/XMLDimension.h
@@ -441,6 +441,24 @@ namespace DD4hep {
       /// Access attribute values: show_daughters
       bool show_daughters() const;
 
+      /// Access min/max parameters: cut
+      double cut() const;
+      /// Access min/max parameters: cut
+      double cut(double default_value) const;
+      /// Access min/max parameters: threshold
+      double threshold() const;
+      /// Access min/max parameters: threshold
+      double threshold(double default_value) const;
+      /// Access min/max parameters: eunit
+      double eunit() const;
+      /// Access min/max parameters: eunit
+      double eunit(double default_value) const;
+      /// Access min/max parameters: lunit
+      double lunit() const;
+      /// Access min/max parameters: lunit
+      double lunit(double default_value) const;
+      
+
       /// Access child element with tag "dimensions" as Dimension object
       Dimension dimensions(bool throw_if_not_present = true) const;
       /// Child access: position
diff --git a/DDCore/src/Objects.cpp b/DDCore/src/Objects.cpp
index 520632ba0..3e7bc4a1b 100644
--- a/DDCore/src/Objects.cpp
+++ b/DDCore/src/Objects.cpp
@@ -428,8 +428,6 @@ Region::Region(const string& name) {
   p->magic = magic_word();
   p->store_secondaries = false;
   p->threshold = 10.0;
-  p->lunit = "mm";
-  p->eunit = "MeV";
   p->cut = 10.0;
 }
 
@@ -448,16 +446,6 @@ Region& Region::setCut(double value) {
   return *this;
 }
 
-Region& Region::setLengthUnit(const string& unit) {
-  object<Object>().lunit = unit;
-  return *this;
-}
-
-Region& Region::setEnergyUnit(const string& unit) {
-  object<Object>().eunit = unit;
-  return *this;
-}
-
 /// Access references to user limits
 vector<string>& Region::limits() const {
   return object<Object>().user_limits;
@@ -478,16 +466,6 @@ bool Region::storeSecondaries() const {
   return object<Object>().store_secondaries;
 }
 
-/// Access the length unit
-const std::string& Region::lengthUnit() const {
-  return object<Object>().lunit;
-}
-
-/// Access the energy unit
-const std::string& Region::energyUnit() const {
-  return object<Object>().eunit;
-}
-
 #undef setAttr
 
 #if 0
diff --git a/DDCore/src/XML/XMLDimension.cpp b/DDCore/src/XML/XMLDimension.cpp
index ffa132d01..d9ed8f069 100644
--- a/DDCore/src/XML/XMLDimension.cpp
+++ b/DDCore/src/XML/XMLDimension.cpp
@@ -159,6 +159,12 @@ XML_ATTR_ACCESSOR(int, type)
 
 XML_ATTR_ACCESSOR(bool, visible)
 XML_ATTR_ACCESSOR(bool, show_daughters)
+
+XML_ATTR_ACCESSOR_DOUBLE(cut)
+XML_ATTR_ACCESSOR_DOUBLE(threshold)
+XML_ATTR_ACCESSOR_DOUBLE(lunit)
+XML_ATTR_ACCESSOR_DOUBLE(eunit)
+
 #if 0
 XML_ATTR_ACCESSOR(double,)
 XML_ATTR_ACCESSOR(double,)
diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index 8b99d8540..d37fe2adb 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -296,7 +296,7 @@ template <> void Converter<Material>::operator()(xml_h e) const {
     cout << "degree " << XML::_toDouble(_Unicode(degree)) << endl;
 #endif
     //throw 1;
-    printout(DEBUG, "Compact", "++ Creating material %s", matname);
+    printout(DEBUG, "Compact", "++ Converting material %s", matname);
     mat = mix = new TGeoMixture(matname, composites.size(), dens_val);
     mat->SetRadLen(radlen_val, intlen_val);
     size_t ifrac = 0;
@@ -310,7 +310,7 @@ template <> void Converter<Material>::operator()(xml_h e) const {
       else if (0 != (comp_elt = table->FindElement(nam.c_str())))
 	fraction *= comp_elt->A();
       else
-        throw_print("Compact2Objects[ERROR]: Creating material:" + mname + " Element missing: " + nam);
+        throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " Element missing: " + nam);
       composite_fractions_total += fraction;
       composite_fractions.push_back(fraction);
     }
@@ -330,7 +330,7 @@ template <> void Converter<Material>::operator()(xml_h e) const {
       else if (0 != (comp_elt = table->FindElement(nam.c_str())))
         mix->AddElement(comp_elt, fraction);
       else
-        throw_print("Compact2Objects[ERROR]: Creating material:" + mname + " Element missing: " + nam);
+        throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " Element missing: " + nam);
     }
     // Update estimated density if not provided.
     if ( has_density )   {
@@ -410,6 +410,8 @@ template <> void Converter<VisAttr>::operator()(xml_h e) const {
   float r = e.hasAttr(_U(r)) ? e.attr<float>(_U(r)) : 1.0f;
   float g = e.hasAttr(_U(g)) ? e.attr<float>(_U(g)) : 1.0f;
   float b = e.hasAttr(_U(b)) ? e.attr<float>(_U(b)) : 1.0f;
+
+  printout(DEBUG, "Compact", "++ Converting VisAttr  structure: %s.",attr.name());
   attr.setColor(r, g, b);
   if (e.hasAttr(_U(alpha)))
     attr.setAlpha(e.attr<float>(_U(alpha)));
@@ -476,16 +478,25 @@ template <> void Converter<AlignmentEntry>::operator()(xml_h e) const {
 /** Specialized converter for compact region objects.
  *
  */
-template <> void Converter<Region>::operator()(xml_h e) const {
-  Region region(e.attr<string>(_U(name)));
+template <> void Converter<Region>::operator()(xml_h elt) const {
+  xml_dim_t  e = elt;
+  Region     region(e.nameStr());
   vector<string>&limits = region.limits();
-  string ene = e.attr<string>(_U(eunit)), len = e.attr<string>(_U(lunit));
+  xml_attr_t cut = elt.attr_nothrow(_U(cut));
+  xml_attr_t threshold = elt.attr_nothrow(_U(threshold));
+  xml_attr_t store_secondaries = elt.attr_nothrow(_U(store_secondaries));
+  double ene = e.eunit(1.0), len = e.lunit(1.0);
 
-  region.setEnergyUnit(ene);
-  region.setLengthUnit(len);
-  region.setCut(_multiply<double>(e.attr<string>(_U(cut)), len));
-  region.setThreshold(_multiply<double>(e.attr<string>(_U(threshold)), ene));
-  region.setStoreSecondaries(e.attr<bool>(_U(store_secondaries)));
+  printout(DEBUG, "Compact", "++ Converting region   structure: %s.",region.name());
+  if ( cut )  {
+    region.setCut(elt.attr<double>(cut)*len);
+  }
+  if ( threshold )  {
+    region.setThreshold(elt.attr<double>(threshold)*ene);
+  }
+  if ( store_secondaries )  {
+    region.setStoreSecondaries(elt.attr<bool>(store_secondaries));
+  }
   for (xml_coll_t user_limits(e, _U(limitsetref)); user_limits; ++user_limits)
     limits.push_back(user_limits.attr<string>(_U(name)));
   lcdd.addRegion(region);
@@ -505,7 +516,7 @@ template <> void Converter<Readout>::operator()(xml_h e) const {
   Readout ro(name);
   Ref_t idSpec;
 
-  printout(DEBUG, "Compact", "++ Creating readout structure: %s.",ro.name());
+  printout(DEBUG, "Compact", "++ Converting readout  structure: %s.",ro.name());
   if (seg) {   // Segmentation is not mandatory!
     string type = seg.attr<string>(_U(type));
     Segmentation segment(type, name);
@@ -551,6 +562,7 @@ template <> void Converter<Readout>::operator()(xml_h e) const {
  */
 template <> void Converter<LimitSet>::operator()(xml_h e) const {
   LimitSet ls(e.attr<string>(_U(name)));
+  printout(DEBUG, "Compact", "++ Converting LimitSet structure: %s.",ls.name());
   for (xml_coll_t c(e, _U(limit)); c; ++c) {
     Limit limit;
     limit.particles = c.attr<string>(_U(particles));
@@ -722,6 +734,16 @@ template <> void Converter<DetElement>::operator()(xml_h element) const {
   string name = element.attr<string>(_U(name));
   string name_match = ":" + name + ":";
   string type_match = ":" + type + ":";
+
+  // Allow to define readout  structures in the local element
+  xml_coll_t(element, _U(readout)).for_each(Converter < Readout > (this->lcdd));
+  // Allow to define region   structures in the local element
+  xml_coll_t(element, _U(region)).for_each(Converter < Region > (this->lcdd));
+  // Allow to define limitset structures in the local element
+  xml_coll_t(element, _U(limitset)).for_each(Converter < LimitSet > (this->lcdd));
+  // Allow to define visualization definitions in the local element
+  xml_coll_t(element,_U(vis)).for_each(Converter < VisAttr > (this->lcdd));
+
   if (req_dets && !strstr(req_dets, name_match.c_str()))
     return;
   if (req_typs && !strstr(req_typs, type_match.c_str()))
@@ -800,6 +822,12 @@ template <> void Converter<DetElementInclude>::operator()(xml_h element) const {
     Converter < Compact > (this->lcdd)(node);
   else if ( tag == "define" )
     xml_coll_t(node, _U(constant)).for_each(Converter < Constant > (this->lcdd));
+  else if ( tag == "readouts" )
+    xml_coll_t(node, _U(readout)).for_each(Converter < Readout > (this->lcdd));
+  else if ( tag == "regions" )
+    xml_coll_t(node, _U(region)).for_each(Converter < Region > (this->lcdd));
+  else if ( tag == "limitsets" )
+    xml_coll_t(node, _U(limitset)).for_each(Converter < LimitSet > (this->lcdd));
   else if ( tag == "display" )
     xml_coll_t(node,_U(vis)).for_each(Converter < VisAttr > (this->lcdd));
   else if ( tag == "detector" )  
@@ -825,8 +853,10 @@ template <> void Converter<Compact>::operator()(xml_h element) const {
   xml_coll_t(compact, _U(limits)).for_each(_U(limitset), Converter < LimitSet > (lcdd));
   xml_coll_t(compact, _U(display)).for_each(_U(include), Converter < DetElementInclude > (lcdd));
   xml_coll_t(compact, _U(display)).for_each(_U(vis), Converter < VisAttr > (lcdd));
-  printout(DEBUG, "Compact", "++ Converting readout structures...");
+  printout(DEBUG, "Compact", "++ Converting readout  structures...");
   xml_coll_t(compact, _U(readouts)).for_each(_U(readout), Converter < Readout > (lcdd));
+  printout(DEBUG, "Compact", "++ Converting region   structures...");
+  xml_coll_t(compact, _U(regions)).for_each(_U(region), Converter < Region > (lcdd));
   printout(DEBUG, "Compact", "++ Converting included files with subdetector structures...");
   xml_coll_t(compact, _U(detectors)).for_each(_U(include), Converter < DetElementInclude > (lcdd));
   printout(DEBUG, "Compact", "++ Converting detector structures...");
diff --git a/DDCore/src/plugins/LCDDConverter.cpp b/DDCore/src/plugins/LCDDConverter.cpp
index f26f5f82e..e511dc7ce 100644
--- a/DDCore/src/plugins/LCDDConverter.cpp
+++ b/DDCore/src/plugins/LCDDConverter.cpp
@@ -780,8 +780,8 @@ xml_h LCDDConverter::handleRegion(const std::string& /* name */, Region region)
     geo.doc_regions.append(reg = xml_elt_t(geo.doc, _U(region)));
     reg.setAttr(_U(name), region.name());
     reg.setAttr(_U(cut), region.cut());
-    reg.setAttr(_U(eunit), region.energyUnit());
-    reg.setAttr(_U(lunit), region.lengthUnit());
+    reg.setAttr(_U(eunit), "GeV");  // TGeo has energy in GeV
+    reg.setAttr(_U(lunit), "cm");   // TGeo has lengths in cm
     reg.setAttr(_U(store_secondaries), region.storeSecondaries());
     geo.xmlRegions[region] = reg;
   }
diff --git a/DDCore/src/plugins/VolumeMgrTest.cpp b/DDCore/src/plugins/VolumeMgrTest.cpp
new file mode 100644
index 000000000..13701ecf0
--- /dev/null
+++ b/DDCore/src/plugins/VolumeMgrTest.cpp
@@ -0,0 +1,194 @@
+// $Id: TubeSegment_geo.cpp 633 2013-06-21 13:50:50Z markus.frank $
+//====================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------
+//
+//  Author     : M.Frank
+//
+//====================================================================
+
+// Framework include files
+#include "DD4hep/LCDD.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/Factories.h"
+#include "DD4hep/IDDescriptor.h"
+#include "DD4hep/VolumeManager.h"
+
+// C/C++ include files
+#include <stdexcept>
+#include <algorithm>
+
+using namespace std;
+using namespace DD4hep;
+using namespace DD4hep::Geometry;
+
+
+namespace  {
+  /** @class VolIDTest
+   *
+   *  Test the volume manager by scanning the sensitive 
+   *  volumes of one or several subdetectors.
+   *
+   *  @author  M.Frank
+   *  @version 1.0
+   */
+  struct VolIDTest  {
+    typedef vector<PlacedVolume::VolID> VolIDs;
+    /// Helper to scan volume ids
+    struct FND {
+      const string& test;
+      FND(const string& c) : test(c) {}
+      bool operator()(const VolIDs::value_type& c) const { return c.first == test; }
+    };
+    IDDescriptor  m_iddesc;
+    VolumeManager m_mgr;
+    DetElement    m_det;
+
+    /// Initializing constructor
+    VolIDTest(LCDD& lcdd, DetElement sdet, size_t depth);
+    /// Default destructor
+    virtual ~VolIDTest() {}
+    /// Check volume integrity
+    void checkVolume(DetElement e, PlacedVolume pv, const VolIDs& child_ids)  const;
+    /// Walk through tree of detector elements
+    void walk(DetElement de, VolIDs ids, size_t depth, size_t mx_depth)  const;
+    /// Walk through tree of volume placements
+    void walkVolume(DetElement e, PlacedVolume pv, VolIDs ids, size_t depth, size_t mx_depth)  const;
+
+    /// Action routine to execute the test
+    static long run(LCDD& lcdd,int argc,char** argv);
+  };
+}
+
+/// Initializing constructor
+VolIDTest::VolIDTest(LCDD& lcdd, DetElement sdet, size_t depth) : m_det(sdet) {
+  m_mgr    = lcdd.volumeManager();
+  if ( !m_det.isValid() )   {
+    stringstream err;
+    err << "The subdetector " << m_det.name() << " is not known to the geometry.";
+    printout(INFO,"VolIDTest",err.str().c_str());
+    throw runtime_error(err.str());
+  }
+  if ( !lcdd.sensitiveDetector(m_det.name()).isValid() )   {
+    stringstream err;
+    err << "The sensitive detector of subdetector " << m_det.name() 
+	<< " is not known to the geometry.";
+    printout(INFO,"VolIDTest",err.str().c_str());
+    throw runtime_error(err.str());
+  }
+  m_iddesc = lcdd.sensitiveDetector(m_det.name()).readout().idSpec();
+  walk(m_det,VolIDs(),0,depth);
+}
+
+/// Check volume integrity
+void VolIDTest::checkVolume(DetElement e, PlacedVolume pv, const VolIDs& child_ids)  const {
+  stringstream err, log;
+  VolumeID vid = m_iddesc.encode(child_ids);
+  VolumeID mask = 0xFFFFULL;
+  vid |= mask<<(31+16);
+  try {
+    DetElement det         = m_mgr.lookupDetector(vid);
+    DetElement det_elem    = m_mgr.lookupDetElement(vid);
+    PlacedVolume det_place = m_mgr.lookupPlacement(vid);
+    if ( pv.ptr() != det_place.ptr() )   {
+      err << "Wrong placement "
+	  << " got "        << det_place.name() << " (" << (void*)det_place.ptr() << ")"
+	  << " instead of " << pv.name()        << " (" << (void*)pv.ptr()        << ") "
+	  << " vid:" << (void*)vid;
+    }
+    else if ( det_elem.ptr() != e.ptr() )   {
+      err << "Wrong associated detector element vid="  << (void*)vid 
+	  << " got "        << det_elem.path() << " (" << (void*)det_elem.ptr() << ") "
+	  << " instead of " << e.path()        << " (" << (void*)e.ptr()        << ")"
+	  << " vid:" << (void*)vid;
+    }
+    else if ( det.ptr() != m_det.ptr() )   {
+      err << "Wrong associated detector "
+	  << " vid:" << (void*)vid;
+    }
+  }
+  catch(const exception& ex) {
+    err << "Lookup " << pv.name() << " id:" << (void*)vid << " path:" << e.path() << " error:" << ex.what();
+  }
+  const IDDescriptor::FieldMap& m = m_iddesc.fields();
+  log << "IDS(" << pv.name() << "): ";
+  for(size_t fi=0; fi<m.size(); ++fi)  {
+    IDDescriptor::Field fld = m_iddesc.field(fi);
+    if ( find_if(child_ids.begin(),child_ids.end(),FND(fld->name())) == child_ids.end() ) continue;
+    log << fld->name() << "=" << fld->value(vid) << "  ";
+  }
+  log << " vid:" << (void*)vid;
+  if ( !err.str().empty() )   {
+    printout(ERROR,m_det.name(),err.str()+" "+log.str());
+    throw runtime_error(err.str());
+  }
+  printout(INFO,m_det.name(),"OK: "+log.str());
+}
+
+/// Walk through tree of detector elements
+void VolIDTest::walkVolume(DetElement e, PlacedVolume pv, VolIDs ids, size_t depth, size_t mx_depth)  const   {
+  if ( depth <= mx_depth )  {
+    const TGeoNode* current = pv.ptr();
+    TObjArray*  nodes  = current->GetNodes();
+    int   num_children = nodes ? nodes->GetEntriesFast() : 0;
+    for(int i=0; i<num_children; ++i)   {
+      TGeoNode* node = (TGeoNode*)nodes->At(i);
+      PlacedVolume place(node);
+      VolIDs child_ids(ids);
+      stringstream err, log;
+
+      child_ids.insert(child_ids.end(),place.volIDs().begin(),place.volIDs().end());
+      bool is_sensitive = place.volume().isSensitive();
+      if ( is_sensitive )  {
+	checkVolume(e,place,child_ids);
+      }
+      walkVolume(e,place,child_ids,depth+1,mx_depth);
+    }
+  }
+}
+
+/// Walk through tree of volume placements
+void VolIDTest::walk(DetElement e, VolIDs ids, size_t depth, size_t mx_depth)  const   {
+  if ( depth <= mx_depth )  {
+    DetElement::Children::const_iterator i;
+    const DetElement::Children& children = e.children();  
+    PlacedVolume pv = e.placement();
+    VolIDs child_ids(ids);
+    bool is_sensitive = pv.volume().isSensitive();
+    child_ids.insert(child_ids.end(),pv.volIDs().begin(),pv.volIDs().end());
+    for (i=children.begin(); i!=children.end(); ++i)  {
+      walk((*i).second,child_ids,depth+1,mx_depth);
+    }
+    if ( !is_sensitive && children.empty() )  {
+      walkVolume(e,pv,child_ids,depth+1,mx_depth);
+    }
+    else if ( is_sensitive )  {
+      checkVolume(e, pv,child_ids);
+    }
+  }
+}
+
+/// Action routine to execute the test
+long VolIDTest::run(LCDD& lcdd,int argc,char** argv)    {
+  cout << "++ Processing plugin...CLICSid_VolMgrTest..." << endl;
+  for(int i=1; i<argc;++i)  {
+    string name = argv[i]+1;
+    if ( name == "all" || name == "All" || name == "ALL" )  {
+      const DetElement::Children& children = lcdd.world().children();  
+      for (DetElement::Children::const_iterator i=children.begin(); i!=children.end(); ++i)  {
+	DetElement sdet = (*i).second;
+	cout << "++ Processing subdetector: " << sdet.name() << endl;
+	VolIDTest test(lcdd,sdet,99);
+      }
+      return 1;
+    }
+    cout << "++ Processing subdetector: " << name << endl;
+    VolIDTest test(lcdd,lcdd.detector(name),99);
+  }
+  return 1;
+}
+
+namespace DD4hep {
+  using ::VolIDTest;
+}
+DECLARE_APPLY(CLICSiD_VolMgrTest,VolIDTest::run)
-- 
GitLab