File indexing completed on 2025-07-15 08:14:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0022 #include <stdexcept>
0023 #include <sstream>
0024 #include <string>
0025
0026
0027 #include <TGeoMatrix.h>
0028
0029
0030 namespace dd4hep {
0031
0032
0033
0034
0035
0036
0037 namespace detail { namespace tools {
0038
0039 std::string elementPath(const PlacementPath& nodes, bool reverse);
0040
0041 void elementPath(DetElement parent, DetElement elt, ElementPath& detectors);
0042
0043 void elementPath(DetElement elt, PlacementPath& nodes);
0044
0045 void elementPath(DetElement parent, DetElement element, PlacementPath& nodes);
0046
0047 bool findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path);
0048
0049
0050
0051 static void makePlacementPath(PlacementPath det_nodes, PlacementPath& all_nodes);
0052 }}
0053 }
0054
0055 using namespace dd4hep;
0056
0057
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
0069 bool detail::tools::findChild(PlacedVolume parent, PlacedVolume child, PlacementPath& path) {
0070 if ( parent.isValid() && child.isValid() ) {
0071
0072 if ( parent.ptr() == child.ptr() ) {
0073 path.emplace_back(child);
0074 return true;
0075 }
0076 TIter next(parent->GetVolume()->GetNodes());
0077
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
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
0100 static bool findChildByName(PlacedVolume parent, PlacedVolume child, detail::tools::PlacementPath& path) {
0101 if ( parent.isValid() && child.isValid() ) {
0102
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
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
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
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
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
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
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
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
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
0208 std::string detail::tools::elementPath(DetElement element) {
0209 ElementPath nodes;
0210 elementPath(element,nodes);
0211 return elementPath(nodes);
0212 }
0213
0214
0215 DetElement detail::tools::findElement(const Detector& description, const std::string& path) {
0216 return findDaughterElement(description.world(),path);
0217 }
0218
0219
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
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
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
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
0277 std::string detail::tools::placementPath(DetElement element) {
0278 PlacementPath path;
0279 placementPath(element,path);
0280 return placementPath(std::move(path));
0281 }
0282
0283
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
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
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
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
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
0333 Int_t length = strlen(path);
0334 if (!length) return 0;
0335 TString spath = path;
0336 TGeoVolume *vol;
0337
0338 Int_t ind1 = spath.Index("/");
0339 if (ind1<0) {
0340
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;
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
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
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
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
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 }