Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:16:58

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 #define DETECTORTOOLS_CPP
0016 #include <DD4hep/DetectorTools.h>
0017 #include <DD4hep/Printout.h>
0018 #include <DD4hep/Detector.h>
0019 #include <DD4hep/detail/DetectorInterna.h>
0020 
0021 // C/C++ include files
0022 #include <stdexcept>
0023 #include <memory>
0024 
0025 // ROOT include files
0026 #include <TGeoMatrix.h>
0027 
0028 /// Namespace for the AIDA detector description toolkit
0029 namespace dd4hep {
0030 
0031   /// Helper namespace used to answer detector element specific questons
0032   /**
0033    * @author  M.Frank
0034    * @version 1.0
0035    */
0036   namespace detail { namespace tools  {
0037       /// Assemble the path of the PlacedVolume selection
0038       std::string elementPath(const PlacementPath& nodes, bool reverse);
0039       /// Collect detector elements to any parent detector element
0040       void elementPath(DetElement parent, DetElement elt, ElementPath& detectors);
0041       /// Collect detector elements placements to the top detector element (world) [fast, but may have holes!]
0042       void elementPath(DetElement elt, PlacementPath& nodes);
0043       /// Collect detector elements placements to the parent detector element [no holes!]
0044       void elementPath(DetElement parent, DetElement element, PlacementPath& nodes);
0045       /// Find Child of PlacedVolume and assemble on the fly the path of PlacedVolumes
0046       bool findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path);
0047 
0048 
0049       // Internal helper
0050       static void makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes);
0051     }}
0052 }
0053 
0054 using namespace dd4hep;
0055 
0056 /// Find path between the child element and the parent element
0057 bool detail::tools::isParentElement(DetElement parent, DetElement child)   {
0058   if ( parent.isValid() && child.isValid() )  {
0059     if ( parent.ptr() == child.ptr() ) return true;
0060     for(DetElement par=child; par.isValid(); par=par.parent())  {
0061       if ( par.ptr() == parent.ptr() ) return true;
0062     }
0063   }
0064   throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
0065 }
0066 
0067 /// Find Child of PlacedVolume and assemble on the fly the path of PlacedVolumes
0068 bool detail::tools::findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path) {
0069   if ( parent.isValid() && child.isValid() ) {
0070     // Check self
0071     if ( parent.ptr() == child.ptr() ) {
0072       path.emplace_back(child);
0073       return true;
0074     }
0075     TIter next(parent->GetVolume()->GetNodes());
0076     // Now check next layer children
0077     for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
0078       if ( daughter == child.ptr() ) {
0079         path.emplace_back(daughter);
0080         return true;
0081       }
0082     }
0083     next.Reset();
0084     // Finally crawl down the tree
0085     for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
0086       PlacementPath sub_path;
0087       bool res = findChild(daughter, child, sub_path);
0088       if (res) {
0089         path.insert(path.end(), sub_path.begin(), sub_path.end());
0090         path.emplace_back(daughter);
0091         return res;
0092       }
0093     }
0094   }
0095   return false;
0096 }
0097 
0098 /// Find Child of PlacedVolume and assemble on the fly the path of PlacedVolumes
0099 static bool findChildByName(PlacedVolume parent, PlacedVolume child, detail::tools::PlacementPath& path) {
0100   if ( parent.isValid() && child.isValid() ) {
0101     // Check self
0102     if ( 0 == ::strcmp(parent.ptr()->GetName(),child.ptr()->GetName()) ) {
0103       path.emplace_back(child);
0104       return true;
0105     }
0106     TIter next(parent->GetVolume()->GetNodes());
0107     // Now check next layer children
0108     for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
0109       if ( 0 == ::strcmp(daughter->GetName(),child.ptr()->GetName()) ) {
0110         path.emplace_back(daughter);
0111         return true;
0112       }
0113     }
0114     next.Reset();
0115     // Finally crawl down the tree
0116     for (TGeoNode *daughter = (TGeoNode*) next(); daughter; daughter = (TGeoNode*) next()) {
0117       detail::tools::PlacementPath sub_path;
0118       bool res = findChildByName(daughter, child, sub_path);
0119       if (res) {
0120         path.insert(path.end(), sub_path.begin(), sub_path.end());
0121         path.emplace_back(daughter);
0122         return res;
0123       }
0124     }
0125   }
0126   return false;
0127 }
0128 
0129 /// Collect detector elements to the top detector element (world)
0130 void detail::tools::elementPath(DetElement element, ElementPath& detectors) {
0131   for(DetElement par = element; par.isValid(); par = par.parent())
0132     detectors.emplace_back(par);
0133 }
0134 
0135 /// Collect detector elements to any parent detector element
0136 void detail::tools::elementPath(DetElement parent, DetElement child, ElementPath& detectors)  {
0137   detectors.clear();
0138   if ( parent.isValid() && child.isValid() )  {
0139     if ( parent.ptr() == child.ptr() )  {
0140       detectors.emplace_back(child);
0141       return;
0142     }
0143     ElementPath elements;
0144     for(DetElement par = child; par.isValid(); par = par.parent())  {
0145       elements.emplace_back(par);
0146       if ( par.ptr() == parent.ptr() )  {
0147         detectors = elements;
0148         return;
0149       }
0150     }
0151     throw std::runtime_error(std::string("The detector element ")+parent.name()+std::string(" is no parent of ")+child.name());
0152   }
0153   throw std::runtime_error("Search for parent detector element with invalid handles not allowed.");
0154 }
0155 
0156 /// Collect detector elements placements to the top detector element (world) [fast, but may have holes!]
0157 void detail::tools::elementPath(DetElement parent, DetElement element, PlacementPath& det_nodes) {
0158   for(DetElement par = element; par.isValid(); par = par.parent())  {
0159     PlacedVolume pv = par.placement();
0160     if ( pv.isValid() )  {
0161       det_nodes.emplace_back(pv);
0162     }
0163     if ( par.ptr() == parent.ptr() ) return;
0164   }
0165   throw std::runtime_error(std::string("The detector element ")+parent.name()+std::string(" is no parent of ")+element.name());
0166 }
0167 
0168 /// Collect detector elements placements to the top detector element (world) [fast, but may have holes!]
0169 void detail::tools::elementPath(DetElement element, PlacementPath& det_nodes) {
0170   for(DetElement par = element; par.isValid(); par = par.parent())  {
0171     PlacedVolume pv = par.placement();
0172     if ( pv.isValid() )  {
0173       det_nodes.emplace_back(pv);
0174     }
0175   }
0176 }
0177 
0178 /// Assemble the path of the PlacedVolume selection
0179 std::string detail::tools::elementPath(const PlacementPath& nodes, bool reverse)   {
0180   std::string path = "";
0181   if ( reverse )  {
0182     for(auto i=nodes.rbegin(); i != nodes.rend(); ++i)
0183       path += "/" + std::string((*i).name());
0184   }
0185   else  {
0186     for(auto i=begin(nodes); i != end(nodes); ++i)
0187       path += "/" + std::string((*i)->GetName());
0188   }
0189   return path;
0190 }
0191 
0192 /// Assemble the path of the PlacedVolume selection
0193 std::string detail::tools::elementPath(const ElementPath& nodes, bool reverse)  {
0194   std::string path = "";
0195   if ( reverse )  {
0196     for(ElementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0197       path += "/" + std::string((*i)->GetName());
0198   }
0199   else  {
0200     for(ElementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
0201       path += "/" + std::string((*i)->GetName());
0202   }
0203   return path;
0204 }
0205 
0206 /// Assemble the path of a particular detector element
0207 std::string detail::tools::elementPath(DetElement element)  {
0208   ElementPath nodes;
0209   elementPath(element,nodes);
0210   return elementPath(nodes);
0211 }
0212 
0213 /// Find DetElement as child of the top level volume by its absolute path
0214 DetElement detail::tools::findElement(const Detector& description, const std::string& path)   {
0215   return findDaughterElement(description.world(),path);
0216 }
0217 
0218 /// Find DetElement as child of a parent by its relative or absolute path
0219 DetElement detail::tools::findDaughterElement(DetElement parent, const std::string& subpath)  {
0220   if ( parent.isValid() )   {
0221     size_t idx = subpath.find('/',1);
0222     if ( subpath[0] == '/' )   {
0223       DetElement top = topElement(parent);
0224       if ( idx == std::string::npos ) return top;
0225       return findDaughterElement(top,subpath.substr(idx+1));
0226     }
0227     if ( idx == std::string::npos )
0228       return parent.child(subpath);
0229     std::string name = subpath.substr(0,idx);
0230     DetElement node = parent.child(name);
0231     if ( node.isValid() )   {
0232       return findDaughterElement(node,subpath.substr(idx+1));
0233     }
0234     throw std::runtime_error("dd4hep: DetElement "+parent.path()+" has no child named:"+name+" [No such child]");
0235   }
0236   throw std::runtime_error("dd4hep: Cannot determine child with path "+subpath+" from invalid parent [invalid handle]");
0237 }
0238 
0239 /// Determine top level element (=world) for any element walking up the detector element tree
0240 DetElement detail::tools::topElement(DetElement child)   {
0241   if ( child.isValid() )   {
0242     if ( child.parent().isValid() )
0243       return topElement(child.parent());
0244     return child;
0245   }
0246   throw std::runtime_error("dd4hep: DetElement cannot determine top parent (world) [invalid handle]");
0247 }
0248 
0249 static void detail::tools::makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes)   {
0250   for (size_t i = 0, n = det_nodes.size(); n > 0 && i < n-1; ++i)   {
0251     if (!findChildByName(det_nodes[i + 1], det_nodes[i], all_nodes))   {
0252       throw std::runtime_error("dd4hep: DetElement cannot determine placement path of "
0253                                + std::string(det_nodes[i].name()) + " [internal error]");
0254     }
0255   }
0256   if ( det_nodes.size() > 0 )   {
0257     all_nodes.emplace_back(det_nodes.back());
0258   }
0259 }
0260 
0261 /// Collect detector elements placements to the top detector element (world) [no holes!]
0262 void detail::tools::placementPath(DetElement element, PlacementPath& all_nodes)   {
0263   PlacementPath det_nodes;
0264   elementPath(element,det_nodes);
0265   makePlacementPath(std::move(det_nodes), all_nodes);
0266 }
0267 
0268 /// Collect detector elements placements to the parent detector element [no holes!]
0269 void detail::tools::placementPath(DetElement parent, DetElement element, PlacementPath& all_nodes)   {
0270   PlacementPath det_nodes;
0271   elementPath(parent,element,det_nodes);
0272   makePlacementPath(std::move(det_nodes), all_nodes);
0273 }
0274 
0275 /// Assemble the path of the PlacedVolume selection
0276 std::string detail::tools::placementPath(DetElement element)  {
0277   PlacementPath path;
0278   placementPath(element,path);
0279   return placementPath(std::move(path));
0280 }
0281 
0282 /// Assemble the path of the PlacedVolume selection
0283 std::string detail::tools::placementPath(const PlacementPath& nodes, bool reverse)  {
0284   std::string path = "";
0285   if ( reverse )  {
0286     for(PlacementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0287       path += "/" + std::string((*i)->GetName());
0288   }
0289   else  {
0290     for(PlacementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
0291       path += "/" + std::string((*i)->GetName());
0292   }
0293   return path;
0294 }
0295 
0296 /// Assemble the path of the PlacedVolume selection
0297 std::string detail::tools::placementPath(const std::vector<const TGeoNode*>& nodes, bool reverse)   {
0298   std::string path = "";
0299   if ( reverse )  {
0300     for(std::vector<const TGeoNode*>::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0301       path += "/" + std::string((*i)->GetName());
0302     return path;
0303   }
0304   for( const auto* n : nodes )
0305     path += "/" + std::string(n->GetName());
0306   return path;
0307 }
0308 
0309 /// Update cached matrix to transform to positions to an upper level Placement
0310 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix*& mat) {
0311   if ( !mat ) mat = new TGeoHMatrix(*gGeoIdentity);
0312   placementTrafo(nodes,inverse,*mat);
0313 }
0314 
0315 /// Update cached matrix to transform to positions to an upper level Placement
0316 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix& mat) {
0317   mat = *gGeoIdentity;
0318   if (nodes.size() > 0) {
0319     for (size_t i = 0, n=nodes.size(); n>0 && i < n-1; ++i)  {
0320       const PlacedVolume& p = nodes[i];
0321       mat.MultiplyLeft(p->GetMatrix());
0322     }
0323     if ( inverse ) mat = mat.Inverse();
0324   }
0325 }
0326 
0327 /// Find a given node in the hierarchy starting from the top node (absolute placement!)
0328 PlacedVolume detail::tools::findNode(PlacedVolume top_place, const std::string& place)   {
0329   TGeoNode* top = top_place.ptr();
0330   const char* path = place.c_str();
0331   // Check if a geometry path is valid without changing the state of the navigator.
0332   Int_t length = strlen(path);
0333   if (!length) return 0;
0334   TString spath = path;
0335   TGeoVolume *vol;
0336   // Check first occurance of a '/'
0337   Int_t ind1 = spath.Index("/");
0338   if (ind1<0) {
0339     // No '/' so we check directly the path against the name of the top
0340     if ( strcmp(path,top->GetName()) ) return 0;
0341     return top;
0342   }
0343   Int_t ind2 = ind1;
0344   Bool_t end = kFALSE;
0345   if (ind1>0) ind1 = -1;   // no trailing '/'
0346   else ind2 = spath.Index("/", ind1+1);
0347 
0348   if (ind2<0) ind2 = length;
0349   TString name(spath(ind1+1, ind2-ind1-1));
0350   if ( name == top->GetName() ) {
0351     if (ind2>=length-1) return top;
0352     ind1 = ind2;
0353   }
0354   else  {
0355     return 0;
0356   }
0357   TGeoNode *node = top;
0358   // Deeper than just top level
0359   while (!end) {
0360     ind2 = spath.Index("/", ind1+1);
0361     if (ind2<0) {
0362       ind2 = length;
0363       end  = kTRUE;
0364     }
0365     vol = node->GetVolume();
0366     name = spath(ind1+1, ind2-ind1-1);
0367     node = vol->GetNode(name.Data());
0368     if (!node)
0369       return 0;
0370     else if (ind2>=length-1)
0371       return node;
0372     ind1 = ind2;
0373   }
0374   return node;
0375 }
0376 
0377 /// Convert VolumeID to string
0378 std::string detail::tools::toString(const PlacedVolume::VolIDs& ids)   {
0379   std::stringstream log;
0380   for( const auto& v : ids )
0381     log << v.first << "=" << v.second << "; ";
0382   return log.str();
0383 }
0384 
0385 /// Convert VolumeID to string
0386 std::string detail::tools::toString(const IDDescriptor& dsc, const PlacedVolume::VolIDs& ids, VolumeID code)   {
0387   std::stringstream log;
0388   for( const auto& id : ids )  {
0389     const BitFieldElement* f = dsc.field(id.first);
0390     VolumeID value = f->value(code);
0391     log << id.first << "=" << id.second << "," << value << " [" << f->offset() << "," << f->width() << "] ";
0392   }
0393   return log.str();
0394 }
0395 
0396 /// Extract all the path elements from a path
0397 std::vector<std::string> detail::tools::pathElements(const std::string& path)   {
0398   std::vector<std::string> result;
0399   if ( !path.empty() )  {
0400     std::string tmp = path[0]=='/' ? path.substr(1) : path;
0401     for(size_t idx=tmp.find('/'); idx != std::string::npos; idx=tmp.find('/'))  {
0402       std::string val = tmp.substr(0,idx);
0403       result.emplace_back(val);
0404       tmp = tmp.length()>idx ? tmp.substr(idx+1) : std::string();
0405     }
0406     if ( !tmp.empty() )  {
0407       result.emplace_back(tmp);
0408     }
0409   }
0410   return result;
0411 }