Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:17:05

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <DD4hep/Detector.h>
0016 #include <DD4hep/Printout.h>
0017 #include <DD4hep/MatrixHelpers.h>
0018 #include <DD4hep/detail/Handle.inl>
0019 #include <DD4hep/detail/ObjectsInterna.h>
0020 #include <DD4hep/detail/DetectorInterna.h>
0021 #include <DD4hep/detail/VolumeManagerInterna.h>
0022 
0023 // C/C++ includes
0024 #include <set>
0025 #include <cmath>
0026 #include <sstream>
0027 #include <iomanip>
0028 
0029 using namespace dd4hep;
0030 using namespace dd4hep::detail;
0031 
0032 DD4HEP_INSTANTIATE_HANDLE_NAMED(VolumeManagerObject);
0033 
0034 /// Namespace for the AIDA detector description toolkit
0035 namespace dd4hep {
0036 
0037   /// Namespace for implementation details of the AIDA detector description toolkit
0038   namespace detail {
0039 
0040     /// Helper class to populate the volume manager
0041     /**
0042      *  \author  M.Frank
0043      *  \version 1.0
0044      */
0045     class VolumeManager_Populator {
0046       typedef std::vector<TGeoNode*>        Chain;
0047       typedef PlacedVolume::VolIDs          VolIDs;
0048       typedef std::pair<VolumeID, VolumeID> Encoding;
0049       /// Reference to the Detector instance
0050       const Detector&    m_detDesc;
0051       /// Reference to the volume manager to be populated
0052       VolumeManager      m_volManager;
0053       /// Set of already added entries
0054       std::set<VolumeID> m_entries;
0055       /// Debug flag
0056       bool               m_debug    = false;
0057       /// Node counter
0058       std::size_t        m_numNodes = 0;
0059 
0060     public:
0061       /// Default constructor
0062       VolumeManager_Populator(const Detector& description, VolumeManager vm)
0063         : m_detDesc(description), m_volManager(vm)
0064       {
0065         m_debug = (0 != ::getenv("DD4HEP_VOLMGR_DEBUG"));
0066       }
0067 
0068       /// Access node count
0069       size_t numNodes()  const  {   return m_numNodes;  }
0070 
0071       /// Populate the Volume manager
0072       void populate(DetElement e) {
0073         //const char* typ = 0;//::getenv("VOLMGR_NEW");
0074         SensitiveDetector parent_sd;
0075         if ( e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR )  {
0076           parent_sd = m_detDesc.sensitiveDetector(e.name());
0077         }
0078         //printout(INFO, "VolumeManager", "++ Executing %s plugin manager version",typ ? "***NEW***" : "***OLD***");
0079         for (const auto& i : e.children() )  {
0080           DetElement de = i.second;
0081           PlacedVolume pv = de.placement();
0082           if (pv.isValid()) {
0083             Chain chain;
0084             Encoding coding(0, 0);
0085             SensitiveDetector sd = parent_sd;
0086             m_entries.clear();
0087             scanPhysicalVolume(de, de, pv, coding, sd, chain);
0088             continue;
0089           }
0090           printout(WARNING, "VolumeManager", "++ Detector element %s of type %s has no placement.", 
0091                    de.name(), de.type().c_str());
0092         }
0093       }
0094       /// Scan a single physical volume and look for sensitive elements below
0095       size_t scanPhysicalVolume(DetElement& parent, DetElement e, PlacedVolume pv, 
0096                                 Encoding parent_encoding,
0097                                 SensitiveDetector& sd, Chain& chain)
0098       {
0099         TGeoNode* node = pv.ptr();
0100         size_t count = 0;
0101         if (node) {
0102           Volume vol = pv.volume();
0103           const VolIDs& pv_ids   = pv.volIDs();
0104           Encoding vol_encoding  = parent_encoding;
0105           bool     is_sensitive  = vol.isSensitive();
0106           bool     have_encoding = pv_ids.empty();
0107           bool     compound      = e.type() == "compound";
0108 
0109           if ( compound )  {
0110             sd = SensitiveDetector(0);
0111             vol_encoding = Encoding();
0112           }
0113           else if ( !sd.isValid() )  {
0114             if ( is_sensitive )
0115               sd = vol.sensitiveDetector();
0116             else if ( (parent->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0117               sd = m_detDesc.sensitiveDetector(parent.name());
0118             else if ( (e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0119               sd = m_detDesc.sensitiveDetector(e.name());
0120           }
0121           chain.emplace_back(node);
0122           if ( sd.isValid() && !pv_ids.empty() )   {
0123             Readout ro = sd.readout();
0124             if ( ro.isValid() )   {
0125               vol_encoding = update_encoding(ro.idSpec(), pv_ids, parent_encoding);
0126               have_encoding = true;
0127             }
0128             else {
0129               printout(WARNING, "VolumeManager",
0130                        "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
0131                        parent.name(), pv.volume().name(), sd.ptr());
0132             }
0133           }
0134           for (int idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
0135             TGeoNode* daughter = node->GetDaughter(idau);
0136             PlacedVolume placement(daughter);
0137             if ( placement.data() ) {
0138               PlacedVolume pv_dau(daughter);
0139               DetElement   de_dau;
0140               /// Check if this particular volume is the placement of one of the
0141               /// children of this detector element. If the daughter placement is also
0142               /// a detector child, then we must reset the node chain.
0143               for( const auto& de : e.children() )  {
0144                 if ( de.second.placement().ptr() == daughter )  {
0145                   de_dau = de.second;
0146                   break;
0147                 }
0148               }
0149               if ( de_dau.isValid() ) {
0150                 Chain dau_chain;
0151                 count += scanPhysicalVolume(parent, de_dau, pv_dau, vol_encoding, sd, dau_chain);
0152               }
0153               else {
0154                 count += scanPhysicalVolume(parent, e, pv_dau, vol_encoding, sd, chain);
0155               }
0156             }
0157             else  {
0158               except("VolumeManager",
0159                      "Invalid not instrumented placement:"+std::string(daughter->GetName())+
0160                      " [Internal error -- bad detector constructor]");
0161             }
0162             if ( compound )  {
0163               sd = SensitiveDetector(0);
0164             }
0165           }
0166           if ( sd.isValid() )   {
0167             if ( !have_encoding && !compound )   {
0168               printout(ERROR, "VolumeManager","Element %s: Missing SD encoding. Volume manager won't work!",
0169                        e.path().c_str());
0170             }
0171             if ( is_sensitive || count > 0 )  {
0172               /// Distinguish logically the two following cases for our understanding....
0173               /// Though the treatment is identical
0174               if ( node == e.placement().ptr() )  {
0175                 // These here are placement nodes, which at the same time are DetElement placements
0176                 // 1) We recuperate volumes from lower levels by reusing the subdetector
0177                 //    This only works if there is exactly one sensitive detector per subdetector!
0178                 // 2) DetElements in the upper hierarchy of the sensitive also get al volume id,
0179                 //    and the volume is registered. (to be discussed)
0180                 //
0181                 // I hate this, but I could not talk Frank out of this!  M.F.
0182                 //
0183                 e.object<DetElement::Object>().volumeID = vol_encoding.first;
0184               }
0185               else  {
0186                 // These here are placement nodes, which are no DetElement placement
0187                 // used e.g. to model a very fine grained sensitive volume structure
0188                 // without always having DetElements.
0189               }
0190               add_entry(sd, parent, e, node, vol_encoding, chain);
0191               ++count;
0192               if ( m_debug )  {
0193                 IDDescriptor id(sd.readout().idSpec());
0194                 printout(INFO,"VolumeManager","Parent: %-44s id:%016llx Encoding: %s",
0195                          parent.path().c_str(), parent.volumeID(), id.str(parent_encoding.first,parent_encoding.second).c_str());
0196                 printout(INFO,"VolumeManager","Element:%-44s id:%016llx Encoding: %s",
0197                          e.path().c_str(), e.volumeID(), id.str(vol_encoding.first,vol_encoding.second).c_str());
0198                 printout(INFO, "VolumeManager", "%s SD:%s VolIDs:%s id:%016llx mask:%016llx",
0199                          node == e.placement().ptr() ? "DETELEMENT PLACEMENT" : "VOLUME PLACEMENT    ",
0200                          sd.name(), pv_ids.str().c_str(), vol_encoding.first, vol_encoding.second);
0201               }
0202             }
0203           }
0204           chain.pop_back();
0205         }
0206         return count;
0207       }
0208 
0209       /// Compute the encoding for a set of VolIDs within a readout descriptor
0210       static Encoding update_encoding(const IDDescriptor iddesc, const VolIDs& ids, const Encoding& initial)  {
0211         VolumeID volume_id = initial.first, mask = initial.second;
0212         for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
0213           const auto& id = (*i);
0214           const BitFieldElement* f = iddesc.field(id.first);
0215           VolumeID msk = f->mask();
0216           int      off = f->offset();
0217           VolumeID val = id.second;    // Necessary to extend volume IDs > 32 bit
0218           volume_id   |= ((f->value(val << off) << off)&msk);
0219           mask        |= msk;
0220         }
0221         return std::make_pair(volume_id, mask);
0222       }
0223       /// Compute the encoding for a set of VolIDs within a readout descriptor
0224       static Encoding encoding(const IDDescriptor iddesc, const VolIDs& ids)  {
0225         VolumeID volume_id = 0, mask = 0;
0226         for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
0227           const auto& id = (*i);
0228           const BitFieldElement* f = iddesc.field(id.first);
0229           VolumeID msk = f->mask();
0230           int      off = f->offset();
0231           VolumeID val = id.second;    // Necessary to extend volume IDs > 32 bit
0232           volume_id |= ((f->value(val << off) << off)&msk);
0233           mask      |= msk;
0234         }
0235         return std::make_pair(volume_id, mask);
0236       }
0237 
0238       void add_entry(SensitiveDetector sd, DetElement parent, DetElement e, 
0239                      const TGeoNode* n, const Encoding& code, Chain& nodes) 
0240       {
0241         if ( sd.isValid() )   {
0242           if (m_entries.find(code.first) == m_entries.end()) {
0243             Readout       ro           = sd.readout();
0244             std::string   sd_name      = sd.name();
0245             DetElement    sub_detector = m_detDesc.detector(sd_name);
0246             VolumeManager section      = m_volManager.addSubdetector(sub_detector, ro);
0247 
0248             //m_debug = true;
0249             // This is the block, we effectively have to save for each physical volume with a VolID
0250             VolumeManagerContext* context = nodes.empty()
0251               ? new VolumeManagerContext
0252               : new detail::VolumeManagerContextExtension;
0253             context->identifier = code.first;
0254             context->mask       = code.second;
0255             context->element    = e;
0256             context->flag       = nodes.empty() ? 0 : 1;
0257             if ( context->flag )  {
0258               detail::VolumeManagerContextExtension* ext = (detail::VolumeManagerContextExtension*)context;
0259               ext->placement  = PlacedVolume(n);
0260               for (std::size_t i = nodes.size(); i > 1; --i) {   // Omit the placement of the parent DetElement
0261                 TGeoMatrix* m = nodes[i-1]->GetMatrix();
0262                 ext->toElement.MultiplyLeft(m);
0263               }
0264             }
0265             if ( !section.adoptPlacement(context) || m_debug )  {
0266               print_node(sd, parent, e, n, code, nodes);
0267             }
0268             m_entries.insert(code.first);
0269             ++m_numNodes;
0270             //if ( (m_numNodes%1000) == 0 )   {
0271             //  printout(INFO, "VolumeManager","++ Added %ld volume entries.",m_numNodes);
0272             //}
0273           }
0274         }
0275       }
0276 
0277       void print_node(SensitiveDetector sd, DetElement parent, DetElement e,
0278                       const TGeoNode* n, const Encoding& code, const Chain& nodes) const
0279       {
0280         PlacedVolume pv = n;
0281         Readout      ro = sd.readout();
0282         bool sensitive = pv.volume().isSensitive();
0283 
0284         //if ( !sensitive ) return;
0285         std::stringstream log;
0286         log << m_entries.size() << ": Detector: " << e.path()
0287             << " id:" << volumeID(code.first)
0288             << " Nodes(" << int(nodes.size()) << "):" << ro.idSpec().str(code.first,code.second);
0289         printout(m_debug ? INFO : DEBUG,"VolumeManager",log.str().c_str());
0290         //for(const auto& i : nodes )
0291         //  log << i->GetName() << "/";
0292 
0293         log.str("");
0294         log << m_entries.size() << ": " << parent.name()
0295             << " ro:" << ro.name() << " pv:" << n->GetName()
0296             << " Sensitive:" << yes_no(sensitive);
0297         printout(m_debug ? INFO : DEBUG, "VolumeManager", log.str().c_str());
0298       }
0299     };
0300   }       /* End namespace detail                */
0301 }         /* End namespace dd4hep                */
0302 
0303 /// Default destructor
0304 VolumeManagerContext::~VolumeManagerContext() {
0305   if ( 0 == flag ) return;
0306 }
0307 
0308 /// Acces the sensitive volume placement
0309 PlacedVolume VolumeManagerContext::elementPlacement()  const   {
0310   return element.placement();
0311 }
0312 
0313 /// Acces the sensitive volume placement
0314 PlacedVolume VolumeManagerContext::volumePlacement()  const   {
0315   if ( 0 == flag )
0316     return element.placement();
0317   const detail::VolumeManagerContextExtension* ext = (const detail::VolumeManagerContextExtension*)this;
0318   return ext->placement;
0319 }
0320 
0321 /// Access the transformation to the closest detector element
0322 const TGeoHMatrix& VolumeManagerContext::toElement()  const   {
0323   static TGeoHMatrix identity;
0324   if ( 0 == flag ) return identity;
0325   const detail::VolumeManagerContextExtension* ext = (const detail::VolumeManagerContextExtension*)this;
0326   return ext->toElement;
0327 }
0328 
0329 /// Transform local coordinates to the DetElement coordinates
0330 Position VolumeManagerContext::localToElement(const double local[3])  const   {
0331   double elt[3];
0332   toElement().LocalToMaster(local, elt);
0333   return { elt[0], elt[1], elt[2] };
0334 }
0335 
0336 /// Transform local coordinates to the DetElement coordinates
0337 Position VolumeManagerContext::localToElement(const Position& local)  const   {
0338   double loc[3];
0339   local.GetCoordinates(loc);
0340   return localToElement(loc);
0341 }
0342 
0343 /// Transform local coordinates to the world coordinates
0344 Position VolumeManagerContext::localToWorld(const double local[3])  const   {
0345   double elt[3];
0346   toElement().LocalToMaster(local, elt);
0347   return element.nominal().localToWorld(elt);
0348 }
0349 
0350 /// Transform local coordinates to the world coordinates
0351 Position VolumeManagerContext::localToWorld(const Position& local)  const   {
0352   double l[3];
0353   local.GetCoordinates(l);
0354   return localToWorld(l);
0355 }
0356 
0357 /// Transform world coordinates to the DetElement coordinates
0358 Position VolumeManagerContext::worldToElement(const double world[3])  const    {
0359   return element.nominal().worldToLocal(world);
0360 }
0361 
0362 /// Transform world coordinates to the DetElement coordinates
0363 Position VolumeManagerContext::worldToElement(const Position& world)  const    {
0364   return element.nominal().worldToLocal(world);
0365 }
0366 
0367 /// Transform world coordinates to the DetElement coordinates
0368 void VolumeManagerContext::worldToElement(const double world[3], double elt[3])  const    {
0369   element.nominal().worldToLocal(world, elt);
0370 }
0371 
0372 /// Transform world coordinates to the local coordinates
0373 Position VolumeManagerContext::worldToLocal(const double world[3])  const    {
0374   double elt[3], local[3];
0375   worldToElement(world, elt);
0376   toElement().MasterToLocal(elt, local);
0377   return { local[0], local[1], local[2] };
0378 }
0379 
0380 /// Transform world coordinates to the local coordinates
0381 Position VolumeManagerContext::worldToLocal(const Position& world)  const    {
0382   double global[3];
0383   world.GetCoordinates(global);
0384   return worldToLocal(global);
0385 }
0386 
0387 /// Transform world coordinates to the DetElement coordinates
0388 void VolumeManagerContext::worldToLocal(const double world[3], double local[3])  const    {
0389   double elt[3];
0390   worldToElement(world, elt);
0391   toElement().MasterToLocal(elt, local);
0392 }
0393 
0394 /// Initializing constructor to create a new object
0395 VolumeManager::VolumeManager(const Detector& description, const std::string& nam, DetElement elt, Readout ro, int flags) {
0396   printout(INFO, "VolumeManager", " - populating volume ids - be patient ..."  );
0397   std::size_t node_count = 0;
0398   Object* obj_ptr = new Object();
0399   assign(obj_ptr, nam, "VolumeManager");
0400   if (elt.isValid()) {
0401     detail::VolumeManager_Populator p(description, *this);
0402     obj_ptr->detector = elt;
0403     obj_ptr->id    = ro.isValid() ? ro.idSpec() : IDDescriptor();
0404     obj_ptr->top   = obj_ptr;
0405     obj_ptr->flags = flags;
0406     p.populate(elt);
0407     node_count = p.numNodes();
0408   }
0409   printout(INFO, "VolumeManager", " - populating volume ids - done. %ld nodes.",node_count);
0410 }
0411 
0412 /// Initializing constructor to create a new object
0413 VolumeManager::VolumeManager(DetElement sub_detector, Readout ro)  {
0414   Object* obj_ptr = new Object();
0415   obj_ptr->detector = sub_detector;
0416   obj_ptr->id = ro.isValid() ? ro.idSpec() : IDDescriptor();
0417   assign(obj_ptr, sub_detector.name(), "VolumeManager");
0418 }
0419 
0420 VolumeManager VolumeManager::getVolumeManager(const Detector& description) {
0421   if( not description.volumeManager().isValid() ) {
0422     description.apply("DD4hepVolumeManager", 0, 0);
0423   }
0424   return description.volumeManager();
0425 }
0426 
0427 /// Add a new Volume manager section according to a new subdetector
0428 VolumeManager VolumeManager::addSubdetector(DetElement det, Readout ro) {
0429   if (isValid()) {
0430     Object& o = _data();
0431     if (!det.isValid()) {
0432       throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: Only valid subdetectors "
0433                                "are allowed. [Invalid DetElement]");
0434     }
0435     auto i = o.subdetectors.find(det);
0436     if (i == o.subdetectors.end()) {
0437       std::string det_name = det.name();
0438       // First check all pre-conditions
0439       if (!ro.isValid()) {
0440         throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: Only subdetectors with a "
0441                                  "valid readout descriptor are allowed. [Invalid DetElement:" + det_name + "]");
0442       }
0443       PlacedVolume pv = det.placement();
0444       if (!pv.isValid()) {
0445         throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: Only subdetectors with a "
0446                                  "valid placement are allowed. [Invalid DetElement:" + det_name + "]");
0447       }
0448       auto vit = pv.volIDs().find("system");
0449       if (vit == pv.volIDs().end()) {
0450         throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: Only subdetectors with "
0451                                  "valid placement VolIDs are allowed. [Invalid DetElement:" + det_name + "]");
0452       }
0453 
0454       i = o.subdetectors.emplace(det, VolumeManager(det,ro)).first;
0455       const auto& id = (*vit);
0456       VolumeManager mgr = (*i).second;
0457       const BitFieldElement* field = ro.idSpec().field(id.first);
0458       if (!field) {
0459         throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: IdDescriptor of " + 
0460                                  std::string(det.name()) + " has no field " + id.first);
0461       }
0462       Object& mo = mgr._data();
0463       mo.top     = o.top;
0464       mo.flags   = o.flags;
0465       mo.system  = field;
0466       mo.sysID   = id.second;
0467       mo.detMask = mo.sysID;
0468       o.managers[mo.sysID] = mgr;
0469       det.callAtUpdate(DetElement::PLACEMENT_CHANGED|DetElement::PLACEMENT_DETECTOR,
0470                        &mo,&Object::update);
0471     }
0472     return (*i).second;
0473   }
0474   throw std::runtime_error("dd4hep: VolumeManager::addSubdetector: "
0475                            "Failed to add subdetector section. [Invalid Manager Handle]");
0476 }
0477 
0478 /// Access the volume manager by cell id
0479 VolumeManager VolumeManager::subdetector(VolumeID id) const {
0480   if (isValid()) {
0481     const Object& o = _data();
0482     /// Need to perform a linear search, because the "system" tag width may vary between subdetectors
0483     for (const auto& j : o.subdetectors )  {
0484       const Object& mo = j.second._data();
0485       VolumeID      sys_id = mo.system->value(id << mo.system->offset());
0486       if ( sys_id == mo.sysID )
0487         return j.second;
0488     }
0489     throw std::runtime_error("dd4hep: VolumeManager::subdetector(VolID): "
0490                              "Attempt to access unknown subdetector section.");
0491   }
0492   throw std::runtime_error("dd4hep: VolumeManager::subdetector(VolID): "
0493                            "Cannot assign ID descriptor [Invalid Manager Handle]");
0494 }
0495 
0496 /// Access the top level detector element
0497 DetElement VolumeManager::detector() const {
0498   if (isValid()) {
0499     return _data().detector;
0500   }
0501   throw std::runtime_error("dd4hep: VolumeManager::detector: Cannot access DetElement [Invalid Handle]");
0502 }
0503 
0504 /// Access IDDescription structure
0505 IDDescriptor VolumeManager::idSpec() const {
0506   return _data().id;
0507 }
0508 
0509 /// Register physical volume with the manager (normally: section manager)
0510 bool VolumeManager::adoptPlacement(VolumeID sys_id, VolumeManagerContext* context) {
0511   std::stringstream err;
0512   Object&  o      = _data();
0513   VolumeID vid    = context->identifier;
0514   VolumeID mask   = context->mask;
0515   PlacedVolume pv = context->elementPlacement();
0516   auto i = o.volumes.find(vid);
0517 
0518   if ( (vid&mask) != vid ) {
0519     err << "Bad context mask:" << (void*)mask
0520         << " id:" << (void*)vid
0521         << " pv:" << pv.name()
0522         << " Sensitive:" << yes_no(pv.volume().isSensitive())
0523         << std::endl;
0524     goto Fail;
0525   }
0526 
0527   if ( i == o.volumes.end()) {
0528     o.volumes[vid] = context;
0529     o.detMask |= mask;
0530     err << "Inserted new volume:" << std::setw(6) << std::left << o.volumes.size()
0531         << " Ptr:"  << (void*) pv.ptr()
0532         << " ["     << pv.name() << "]"
0533         << " id:"   << std::setw(16) << std::hex << std::right << std::setfill('0') << vid  << std::dec << std::setfill(' ')
0534         << " mask:" << std::setw(16) << std::hex << std::right << std::setfill('0') << mask << std::dec << std::setfill(' ')
0535         << " Det:"  << std::setw(4)  << std::hex << std::right << std::setfill('0') << context->element.volumeID()
0536         << " / "    << std::setw(4)  << sys_id   << std::dec   << std::setfill(' ') << ": " << context->element.path();
0537     printout(VERBOSE, "VolumeManager", err.str().c_str());
0538     //printout(ALWAYS, "VolumeManager", err.str().c_str());
0539     return true;
0540   }
0541   err << "+++ Attempt to register duplicate"
0542       << " id:"   << std::setw(16) << std::hex << std::right << std::setfill('0') << vid  << std::dec << std::setfill(' ')
0543       << " mask:" << std::setw(16) << std::hex << std::right << std::setfill('0') << mask << std::dec << std::setfill(' ')
0544       << " to detector " << o.detector.name()
0545       << " ptr:" << (void*) pv.ptr()
0546       << " Name:" << pv.name()
0547       << " Sensitive:" << yes_no(pv.volume().isSensitive())
0548       << std::endl;
0549   printout(ERROR, "VolumeManager", "%s", err.str().c_str());
0550   err.str("");
0551   context = (*i).second;
0552   //pv = context->placement;
0553   err << " !!!!!               +++ Clashing"
0554       << " id:"   << std::setw(16) << std::hex << std::right << std::setfill('0') << vid  << std::dec << std::setfill(' ')
0555       << " mask:" << std::setw(16) << std::hex << std::right << std::setfill('0') << mask << std::dec << std::setfill(' ')
0556       << " to detector " << o.detector.name()
0557       << " ptr:" << (void*) pv.ptr()
0558       << " Name:" << pv.name()
0559       << " Sensitive:" << yes_no(pv.volume().isSensitive())
0560       << std::endl;
0561  Fail:
0562   printout(ERROR, "VolumeManager", "%s", err.str().c_str());
0563   // throw std::runtime_error(err.str());
0564   return false;
0565 }
0566 
0567 /// Register physical volume with the manager (normally: section manager)
0568 bool VolumeManager::adoptPlacement(VolumeManagerContext* context) {
0569   std::stringstream err;
0570   if ( isValid() ) {
0571     Object& o = _data();
0572     if ( context )   {
0573       if ( (o.flags & ONE) == ONE ) {
0574         VolumeManager top(o.top);
0575         return top.adoptPlacement(context);
0576       }
0577       if ( (o.flags & TREE) == TREE ) {
0578         bool isTop = ptr() == o.top;
0579         if ( !isTop ) {
0580           VolumeID sys_id = o.system->value(context->identifier);
0581           if ( sys_id == o.sysID ) {
0582             return adoptPlacement(sys_id, context);
0583           }
0584           VolumeManager top(o.top);
0585           return top.adoptPlacement(context);
0586         }
0587         for( auto& j : o.managers )  {
0588           Object& mgr = j.second._data();
0589           VolumeID sid = mgr.system->value(context->identifier);
0590           if ( j.first == sid ) {
0591             return j.second.adoptPlacement(sid, context);
0592           }
0593         }
0594       }
0595       return false;
0596     }
0597     except("VolumeManager","dd4hep: Failed to add new physical volume to detector: %s "
0598            "[Invalid Context]", o.detector.name());
0599   }
0600   except("VolumeManager","dd4hep: Failed to add new physical volume [Invalid Manager Handle]");
0601   return false;
0602 }
0603 
0604 /// Lookup the context, which belongs to a registered physical volume.
0605 VolumeManagerContext* VolumeManager::lookupContext(VolumeID volume_id) const {
0606   if (isValid()) {
0607     VolumeManagerContext* c = 0;
0608     const Object& o = _data();
0609     bool is_top = o.top == ptr();
0610     bool one_tree = (o.flags & ONE) == ONE;
0611     if ( !is_top && one_tree ) {
0612       return VolumeManager(o.top).lookupContext(volume_id);
0613     }
0614     VolumeID id = volume_id;
0615     /// First look in our own volume cache if the entry is found.
0616     c = o.search(id);
0617     if (c)
0618       return c;
0619     /// Second: look in the subdetector volume cache if the entry is found.
0620     if (!one_tree) {
0621       for (const auto& j : o.subdetectors )  {
0622         if ((c = j.second._data().search(id)) != 0)
0623           return c;
0624       }
0625     }
0626     except("VolumeManager","lookupContext: Failed to search Volume context %016llX [Unknown identifier]", (void*)volume_id);
0627   }
0628   except("VolumeManager","lookupContext: Failed to search Volume context [Invalid Manager Handle]");
0629   return 0;
0630 }
0631 
0632 /// Lookup a physical (placed) volume identified by its 64 bit hit ID
0633 PlacedVolume VolumeManager::lookupDetElementPlacement(VolumeID volume_id) const {
0634   VolumeManagerContext* c = lookupContext(volume_id); // Throws exception if not found!
0635   return c->elementPlacement();
0636 }
0637 
0638 /// Lookup a physical (placed) volume identified by its 64 bit hit ID
0639 PlacedVolume VolumeManager::lookupVolumePlacement(VolumeID volume_id) const {
0640   VolumeManagerContext* c = lookupContext(volume_id); // Throws exception if not found!
0641   return c->volumePlacement();
0642 }
0643 
0644 /// Lookup a top level subdetector detector element according to a contained 64 bit hit ID
0645 DetElement VolumeManager::lookupDetector(VolumeID volume_id) const {
0646   if (isValid()) {
0647     const Object& o = _data();
0648     VolumeID      sys_id = 0;
0649     if ( o.system )   {
0650       sys_id = o.system->value(volume_id);
0651     }
0652     else  {
0653       for (const auto& j : o.subdetectors )  {
0654         if ( j.second->system )  {
0655           VolumeID vid = volume_id&j.second->system->mask();
0656           if ( (volume_id&j.second->sysID) == vid )  {
0657             sys_id = j.second->sysID;
0658             break;
0659           }
0660         }
0661       }
0662     }
0663     VolumeID det_id = (volume_id&sys_id);
0664     VolumeManagerContext* c = lookupContext(det_id); // Throws exception if not found!
0665     return c->element;
0666   }
0667   except("VolumeManager","lookupContext: Failed to search Volume context [Invalid Manager Handle]");
0668   return DetElement();
0669 }
0670 
0671 /// Lookup the closest subdetector detector element in the hierarchy according to a contained 64 bit hit ID
0672 DetElement VolumeManager::lookupDetElement(VolumeID volume_id) const {
0673   VolumeManagerContext* c = lookupContext(volume_id); // Throws exception if not found!
0674   return c->element;
0675 }
0676 
0677 /// Access the transformation of a physical volume to the world coordinate system
0678 const TGeoMatrix&
0679 VolumeManager::worldTransformation(const ConditionsMap& mapping,
0680                                    VolumeID volume_id) const
0681 {
0682   VolumeManagerContext* c = lookupContext(volume_id); // Throws exception if not found!
0683   Alignment a = mapping.get(c->element,align::Keys::alignmentKey);
0684   return a.worldTransformation();
0685 }
0686 
0687 /// Enable printouts for debugging
0688 std::ostream& dd4hep::operator<<(std::ostream& os, const VolumeManager& mgr) {
0689   const VolumeManager::Object& o = *mgr.data<VolumeManager::Object>();
0690   VolumeManager::Object* top = dynamic_cast<VolumeManager::Object*>(o.top);
0691   bool isTop = top == &o;
0692   //bool hasTop = (o.flags & VolumeManager::ONE) == VolumeManager::ONE;
0693   //bool isSdet = (o.flags & VolumeManager::TREE) == VolumeManager::TREE && top != &o;
0694   std::string prefix(isTop ? "" : "++  ");
0695   os << prefix << (isTop ? "TOP Level " : "Secondary ") << "Volume manager:" 
0696      << &o << " " << o.detector.name() << " IDD:"
0697      << o.id.toString() << " SysID:" << (void*) o.sysID << " " 
0698      << o.managers.size() << " subsections " << o.volumes.size()
0699      << " placements ";
0700   if (!(o.managers.empty() && o.volumes.empty()))
0701     os << std::endl;
0702   for ( const auto& i : o.volumes ) {
0703     const VolumeManagerContext* c = i.second;
0704     os << prefix
0705        << "Element:" << std::setw(32) << std::left << c->element.path()
0706       //<< " pv:"     << std::setw(32) << std::left << c->placement().name()
0707        << " id:"     << std::setw(18) << std::left << (void*) c->identifier
0708        << " mask:"   << std::setw(18) << std::left << (void*) c->mask
0709        << std::endl;
0710   }
0711   for( const auto& i : o.managers )
0712     os << prefix << i.second << std::endl;
0713   return os;
0714 }
0715 
0716 /// Default destructor
0717 VolumeManagerObject::~VolumeManagerObject() {
0718   /// Cleanup volume tree
0719   destroyObjects(volumes);
0720   /// Cleanup dependent managers
0721   destroyHandles(managers);
0722   managers.clear();
0723   subdetectors.clear();
0724 }
0725 
0726 /// Update callback when alignment has changed (called only for subdetectors....)
0727 void VolumeManagerObject::update(unsigned long tags, DetElement& det, void* param)   {
0728   if ( DetElement::CONDITIONS_CHANGED == (tags&DetElement::CONDITIONS_CHANGED) )
0729     printout(DEBUG,"VolumeManager","+++ Conditions update %s param:%p",det.path().c_str(),param);
0730   if ( DetElement::PLACEMENT_CHANGED == (tags&DetElement::PLACEMENT_CHANGED) )
0731     printout(DEBUG,"VolumeManager","+++ Alignment update %s param:%p",det.path().c_str(),param);
0732   
0733   for(const auto& i : volumes )
0734     printout(DEBUG,"VolumeManager","+++ Alignment update %s",i.second->elementPlacement().name());
0735 }
0736 
0737 /// Search the locally cached volumes for a matching ID
0738 VolumeManagerContext* VolumeManagerObject::search(const VolumeID& vol_id) const {
0739   auto i = volumes.find(vol_id&detMask);
0740   return (i == volumes.end()) ? 0 : (*i).second;
0741 }
0742