Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:14:42

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