Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-25 08:26:49

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   if( element.isValid() )  {
0160     if( !parent.isValid() ) {
0161       parent = element.world();
0162     }
0163     for( DetElement par = element; par.isValid(); par = par.parent() )  {
0164       PlacedVolume pv = par.placement();
0165       if ( pv.isValid() )  {
0166         det_nodes.emplace_back(pv);
0167       }
0168       if ( par.ptr() == parent.ptr() ) return;
0169     }
0170     throw std::runtime_error(("The detector element "+std::string(parent.name())+" is no parent of ")+element.name());
0171   }
0172   throw std::runtime_error("Cannot access element path [Invalid DetElement]");
0173 }
0174 
0175 /// Collect detector elements placements to the top detector element (world) [fast, but may have holes!]
0176 void detail::tools::elementPath(DetElement element, PlacementPath& det_nodes) {
0177   for(DetElement par = element; par.isValid(); par = par.parent())  {
0178     PlacedVolume pv = par.placement();
0179     if ( pv.isValid() )  {
0180       det_nodes.emplace_back(pv);
0181     }
0182   }
0183 }
0184 
0185 /// Assemble the path of the PlacedVolume selection
0186 std::string detail::tools::elementPath(const PlacementPath& nodes, bool reverse)   {
0187   std::string path = "";
0188   if ( reverse )  {
0189     for(auto i=nodes.rbegin(); i != nodes.rend(); ++i)
0190       path += "/" + std::string((*i).name());
0191   }
0192   else  {
0193     for(auto i=begin(nodes); i != end(nodes); ++i)
0194       path += "/" + std::string((*i)->GetName());
0195   }
0196   return path;
0197 }
0198 
0199 /// Assemble the path of the PlacedVolume selection
0200 std::string detail::tools::elementPath(const ElementPath& nodes, bool reverse)  {
0201   std::string path = "";
0202   if ( reverse )  {
0203     for(ElementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0204       path += "/" + std::string((*i)->GetName());
0205   }
0206   else  {
0207     for(ElementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
0208       path += "/" + std::string((*i)->GetName());
0209   }
0210   return path;
0211 }
0212 
0213 /// Assemble the path of a particular detector element
0214 std::string detail::tools::elementPath(DetElement element)  {
0215   ElementPath nodes;
0216   elementPath(element,nodes);
0217   return elementPath(nodes);
0218 }
0219 
0220 /// Find DetElement as child of the top level volume by its absolute path
0221 DetElement detail::tools::findElement(const Detector& description, const std::string& path)   {
0222   return findDaughterElement(description.world(),path);
0223 }
0224 
0225 /// Find DetElement as child of a parent by its relative or absolute path
0226 DetElement detail::tools::findDaughterElement(DetElement parent, const std::string& subpath)  {
0227   if ( parent.isValid() )   {
0228     size_t idx = subpath.find('/',1);
0229     if ( subpath[0] == '/' )   {
0230       DetElement top = topElement(parent);
0231       if ( idx == std::string::npos ) return top;
0232       return findDaughterElement(top,subpath.substr(idx+1));
0233     }
0234     if ( idx == std::string::npos )
0235       return parent.child(subpath);
0236     std::string name = subpath.substr(0,idx);
0237     DetElement node = parent.child(name);
0238     if ( node.isValid() )   {
0239       return findDaughterElement(node,subpath.substr(idx+1));
0240     }
0241     throw std::runtime_error("dd4hep: DetElement "+parent.path()+" has no child named:"+name+" [No such child]");
0242   }
0243   throw std::runtime_error("dd4hep: Cannot determine child with path "+subpath+" from invalid parent [invalid handle]");
0244 }
0245 
0246 /// Determine top level element (=world) for any element walking up the detector element tree
0247 DetElement detail::tools::topElement(DetElement child)   {
0248   if ( child.isValid() )   {
0249     if ( child.parent().isValid() )
0250       return topElement(child.parent());
0251     return child;
0252   }
0253   throw std::runtime_error("dd4hep: DetElement cannot determine top parent (world) [invalid handle]");
0254 }
0255 
0256 static void detail::tools::makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes)   {
0257   for (size_t i = 0, n = det_nodes.size(); n > 0 && i < n-1; ++i)   {
0258     if (!findChildByName(det_nodes[i + 1], det_nodes[i], all_nodes))   {
0259       throw std::runtime_error("dd4hep: DetElement cannot determine placement path of "
0260                                + std::string(det_nodes[i].name()) + " [internal error]");
0261     }
0262   }
0263   if ( det_nodes.size() > 0 )   {
0264     all_nodes.emplace_back(det_nodes.back());
0265   }
0266 }
0267 
0268 /// Collect detector elements placements to the top detector element (world) [no holes!]
0269 void detail::tools::placementPath(DetElement element, PlacementPath& all_nodes)   {
0270   PlacementPath det_nodes;
0271   elementPath(element,det_nodes);
0272   makePlacementPath(std::move(det_nodes), all_nodes);
0273 }
0274 
0275 /// Collect detector elements placements to the parent detector element [no holes!]
0276 void detail::tools::placementPath(DetElement parent, DetElement element, PlacementPath& all_nodes)   {
0277   PlacementPath det_nodes;
0278   elementPath(parent,element,det_nodes);
0279   makePlacementPath(std::move(det_nodes), all_nodes);
0280 }
0281 
0282 /// Assemble the path of the PlacedVolume selection
0283 std::string detail::tools::placementPath(DetElement element)  {
0284   PlacementPath path;
0285   placementPath(element,path);
0286   return placementPath(std::move(path));
0287 }
0288 
0289 /// Assemble the path of the PlacedVolume selection
0290 std::string detail::tools::placementPath(const PlacementPath& nodes, bool reverse)  {
0291   std::string path = "";
0292   if ( reverse )  {
0293     for(PlacementPath::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0294       path += "/" + std::string((*i)->GetName());
0295   }
0296   else  {
0297     for(PlacementPath::const_iterator i=nodes.begin();i!=nodes.end();++i)
0298       path += "/" + std::string((*i)->GetName());
0299   }
0300   return path;
0301 }
0302 
0303 /// Assemble the path of the PlacedVolume selection
0304 std::string detail::tools::placementPath(const std::vector<const TGeoNode*>& nodes, bool reverse)   {
0305   std::string path = "";
0306   if ( reverse )  {
0307     for(std::vector<const TGeoNode*>::const_reverse_iterator i=nodes.rbegin();i!=nodes.rend();++i)
0308       path += "/" + std::string((*i)->GetName());
0309     return path;
0310   }
0311   for( const auto* n : nodes )
0312     path += "/" + std::string(n->GetName());
0313   return path;
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   if ( !mat ) mat = new TGeoHMatrix(*gGeoIdentity);
0319   placementTrafo(nodes,inverse,*mat);
0320 }
0321 
0322 /// Update cached matrix to transform to positions to an upper level Placement
0323 void detail::tools::placementTrafo(const PlacementPath& nodes, bool inverse, TGeoHMatrix& mat) {
0324   mat = *gGeoIdentity;
0325   if (nodes.size() > 0) {
0326     for (size_t i = 0, n=nodes.size(); n>0 && i < n-1; ++i)  {
0327       const PlacedVolume& p = nodes[i];
0328       mat.MultiplyLeft(p->GetMatrix());
0329     }
0330     if ( inverse ) mat = mat.Inverse();
0331   }
0332 }
0333 
0334 /// Find a given node in the hierarchy starting from the top node (absolute placement!)
0335 PlacedVolume detail::tools::findNode(PlacedVolume top_place, const std::string& place)   {
0336   TGeoNode* top = top_place.ptr();
0337   const char* path = place.c_str();
0338   // Check if a geometry path is valid without changing the state of the navigator.
0339   Int_t length = strlen(path);
0340   if (!length) return 0;
0341   TString spath = path;
0342   TGeoVolume *vol;
0343   // Check first occurance of a '/'
0344   Int_t ind1 = spath.Index("/");
0345   if (ind1<0) {
0346     // No '/' so we check directly the path against the name of the top
0347     if ( strcmp(path,top->GetName()) ) return 0;
0348     return top;
0349   }
0350   Int_t ind2 = ind1;
0351   Bool_t end = kFALSE;
0352   if (ind1>0) ind1 = -1;   // no trailing '/'
0353   else ind2 = spath.Index("/", ind1+1);
0354 
0355   if (ind2<0) ind2 = length;
0356   TString name(spath(ind1+1, ind2-ind1-1));
0357   if ( name == top->GetName() ) {
0358     if (ind2>=length-1) return top;
0359     ind1 = ind2;
0360   }
0361   else  {
0362     return 0;
0363   }
0364   TGeoNode *node = top;
0365   // Deeper than just top level
0366   while (!end) {
0367     ind2 = spath.Index("/", ind1+1);
0368     if (ind2<0) {
0369       ind2 = length;
0370       end  = kTRUE;
0371     }
0372     vol = node->GetVolume();
0373     name = spath(ind1+1, ind2-ind1-1);
0374     node = vol->GetNode(name.Data());
0375     if (!node)
0376       return 0;
0377     else if (ind2>=length-1)
0378       return node;
0379     ind1 = ind2;
0380   }
0381   return node;
0382 }
0383 
0384 /// Convert VolumeID to string
0385 std::string detail::tools::toString(const PlacedVolume::VolIDs& ids)   {
0386   std::stringstream log;
0387   for( const auto& v : ids )
0388     log << v.first << "=" << v.second << "; ";
0389   return log.str();
0390 }
0391 
0392 /// Convert VolumeID to string
0393 std::string detail::tools::toString(const IDDescriptor& dsc, const PlacedVolume::VolIDs& ids, VolumeID code)   {
0394   std::stringstream log;
0395   for( const auto& id : ids )  {
0396     const BitFieldElement* f = dsc.field(id.first);
0397     VolumeID value = f->value(code);
0398     log << id.first << "=" << id.second << "," << value << " [" << f->offset() << "," << f->width() << "] ";
0399   }
0400   return log.str();
0401 }
0402 
0403 /// Extract all the path elements from a path
0404 std::vector<std::string> detail::tools::pathElements(const std::string& path)   {
0405   std::vector<std::string> result;
0406   if ( !path.empty() )  {
0407     std::string tmp = path[0]=='/' ? path.substr(1) : path;
0408     for(size_t idx=tmp.find('/'); idx != std::string::npos; idx=tmp.find('/'))  {
0409       std::string val = tmp.substr(0,idx);
0410       result.emplace_back(val);
0411       tmp = tmp.length()>idx ? tmp.substr(idx+1) : std::string();
0412     }
0413     if ( !tmp.empty() )  {
0414       result.emplace_back(tmp);
0415     }
0416   }
0417   return result;
0418 }