Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:05:29

0001 #include "DetectorDescription/DDCMS/interface/DDFilteredView.h"
0002 #include "DetectorDescription/DDCMS/interface/DDCompactView.h"
0003 #include "DetectorDescription/DDCMS/interface/DDDetector.h"
0004 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0005 #include "DD4hep/Detector.h"
0006 #include "DD4hep/Shapes.h"
0007 #include <TGeoBBox.h>
0008 #include <TGeoBoolNode.h>
0009 #include <charconv>
0010 
0011 using namespace cms;
0012 using namespace edm;
0013 using namespace std;
0014 using namespace cms::dd;
0015 using namespace dd4hep::dd;
0016 
0017 dd4hep::Solid DDSolid::solidA() const {
0018   if (dd4hep::isA<dd4hep::SubtractionSolid>(solid_) or dd4hep::isA<dd4hep::UnionSolid>(solid_) or
0019       dd4hep::isA<dd4hep::IntersectionSolid>(solid_)) {
0020     const TGeoCompositeShape* sh = (const TGeoCompositeShape*)solid_.ptr();
0021     const TGeoBoolNode* boolean = sh->GetBoolNode();
0022     TGeoShape* solidA = boolean->GetLeftShape();
0023     return dd4hep::Solid(solidA);
0024   }
0025   return solid_;
0026 }
0027 
0028 dd4hep::Solid DDSolid::solidB() const {
0029   if (dd4hep::isA<dd4hep::SubtractionSolid>(solid_) or dd4hep::isA<dd4hep::UnionSolid>(solid_) or
0030       dd4hep::isA<dd4hep::IntersectionSolid>(solid_)) {
0031     const TGeoCompositeShape* sh = static_cast<const TGeoCompositeShape*>(solid_.ptr());
0032     const TGeoBoolNode* boolean = sh->GetBoolNode();
0033     TGeoShape* solidB = boolean->GetRightShape();
0034     return dd4hep::Solid(solidB);
0035   }
0036   return solid_;
0037 }
0038 
0039 const std::vector<double> DDSolid::parameters() const { return solid().dimensions(); }
0040 
0041 DDFilteredView::DDFilteredView(const DDDetector* det, const Volume volume) : registry_(&det->specpars()) {
0042   it_.emplace_back(Iterator(volume));
0043 }
0044 
0045 DDFilteredView::DDFilteredView(const DDCompactView& cpv, const cms::DDFilter& filter) : registry_(&cpv.specpars()) {
0046   it_.emplace_back(Iterator(cpv.detector()->worldVolume()));
0047   registry_->filter(refs_, filter.attribute(), filter.value());
0048   mergedSpecifics(refs_);
0049   LogVerbatim("Geometry").log([&](auto& log) {
0050     log << "Filtered by an attribute " << filter.attribute() << "==" << filter.value()
0051         << " DD SpecPar Registry size: " << refs_.size() << "\n";
0052     for (const auto& t : refs_) {
0053       log << "\nSpecPar " << std::string(t.first.data(), t.first.size()) << "\nRegExps { ";
0054       for (const auto& ki : t.second->paths)
0055         log << ki << " ";
0056       log << "};\n ";
0057       for (const auto& kl : t.second->spars) {
0058         log << kl.first << " = ";
0059         for (const auto& kil : kl.second) {
0060           log << kil << " ";
0061         }
0062         log << "\n ";
0063       }
0064     }
0065   });
0066 }
0067 
0068 const PlacedVolume DDFilteredView::volume() const {
0069   assert(node_);
0070   return PlacedVolume(node_);
0071 }
0072 
0073 //
0074 // This should be used for debug purpose only
0075 //
0076 const std::string DDFilteredView::path() const {
0077   if (it_.empty()) {
0078     return std::string();
0079   }
0080   TString fullPath;
0081   it_.back().GetPath(fullPath);
0082   return std::string(fullPath.Data());
0083 }
0084 
0085 //
0086 // The vector is filled from bottom up:
0087 // result[0] contains the current node copy number
0088 //
0089 const std::vector<int> DDFilteredView::copyNos() const {
0090   std::vector<int> result;
0091 
0092   if (not it_.empty()) {
0093     for (int i = it_.back().GetLevel(); i > 0; --i) {
0094       result.emplace_back(it_.back().GetNode(i)->GetNumber());
0095     }
0096   }
0097 
0098   return result;
0099 }
0100 
0101 const Double_t* DDFilteredView::trans() const { return it_.back().GetCurrentMatrix()->GetTranslation(); }
0102 
0103 const Translation DDFilteredView::translation() const {
0104   const Double_t* translation = it_.back().GetCurrentMatrix()->GetTranslation();
0105   assert(translation);
0106   return Translation(translation[0], translation[1], translation[2]);
0107 }
0108 
0109 const Translation DDFilteredView::translation(const std::vector<Node*>& nodes) const {
0110   const TGeoMatrix* current = it_.back().GetCurrentMatrix();
0111   TGeoHMatrix matrix(*current);
0112   for (const auto& n : nodes) {
0113     matrix.Multiply(n->GetMatrix());
0114   }
0115   const Double_t* translation = matrix.GetTranslation();
0116   assert(translation);
0117   return Translation(translation[0], translation[1], translation[2]);
0118 }
0119 
0120 const Double_t* DDFilteredView::rot() const { return it_.back().GetCurrentMatrix()->GetRotationMatrix(); }
0121 
0122 const RotationMatrix DDFilteredView::rotation() const {
0123   const Double_t* rotation = it_.back().GetCurrentMatrix()->GetRotationMatrix();
0124   if (rotation == nullptr) {
0125     LogError("DDFilteredView") << "Current node has no valid rotation matrix.";
0126     return RotationMatrix();
0127   }
0128 
0129   RotationMatrix rotMatrix;
0130   rotMatrix.SetComponents(rotation[0],
0131                           rotation[1],
0132                           rotation[2],
0133                           rotation[3],
0134                           rotation[4],
0135                           rotation[5],
0136                           rotation[6],
0137                           rotation[7],
0138                           rotation[8]);
0139   return rotMatrix;
0140 }
0141 
0142 void DDFilteredView::rot(dd4hep::Rotation3D& matrixOut) const {
0143   const Double_t* rotation = it_.back().GetCurrentMatrix()->GetRotationMatrix();
0144   if (rotation == nullptr) {
0145     LogError("DDFilteredView") << "Current node has no valid rotation matrix.";
0146     return;
0147   }
0148   matrixOut.SetComponents(rotation[0],
0149                           rotation[1],
0150                           rotation[2],
0151                           rotation[3],
0152                           rotation[4],
0153                           rotation[5],
0154                           rotation[6],
0155                           rotation[7],
0156                           rotation[8]);
0157 }
0158 
0159 void DDFilteredView::mergedSpecifics(DDSpecParRefs const& specPars) {
0160   currentSpecPar_ = nullptr;
0161   if (!filters_.empty()) {
0162     filters_.clear();
0163     filters_.shrink_to_fit();
0164   }
0165 
0166   for (const auto& section : specPars) {
0167     for (const auto& partSelector : section.second->paths) {
0168       auto const& firstPartName = front(partSelector);
0169       auto const& filterMatch = find_if(begin(filters_), end(filters_), [&](auto const& it) {
0170         auto const& key =
0171             find_if(begin(it->skeys), end(it->skeys), [&](auto const& partName) { return firstPartName == partName; });
0172         if (key != end(it->skeys)) {
0173           currentFilter_ = it.get();
0174           return true;
0175         }
0176         return false;
0177       });
0178       if (filterMatch == end(filters_)) {
0179         filters_.emplace_back(make_unique<Filter>());
0180         filters_.back()->hasNamespace.emplace_back(dd4hep::dd::hasNamespace(firstPartName));
0181         if (dd4hep::dd::isRegex(firstPartName)) {
0182           filters_.back()->isRegex.emplace_back(true);
0183           filters_.back()->index.emplace_back(filters_.back()->keys.size());
0184           filters_.back()->keys.emplace_back(std::regex(std::begin(firstPartName), std::end(firstPartName)));
0185         } else {
0186           filters_.back()->isRegex.emplace_back(false);
0187           filters_.back()->index.emplace_back(filters_.back()->skeys.size());
0188         }
0189         filters_.back()->skeys.emplace_back(firstPartName);
0190         filters_.back()->up = nullptr;
0191         filters_.back()->next = nullptr;
0192         filters_.back()->spec = section.second;
0193         // initialize current filter if it's empty
0194         if (currentFilter_ == nullptr) {
0195           currentFilter_ = filters_.back().get();
0196         }
0197       }
0198       // all next levels
0199       vector<string_view> toks = split(partSelector, "/");
0200       for (size_t pos = 1; pos < toks.size(); ++pos) {
0201         if (currentFilter_->next != nullptr) {
0202           currentFilter_ = currentFilter_->next.get();
0203           auto const& key = find_if(begin(currentFilter_->skeys), end(currentFilter_->skeys), [&](auto const& p) {
0204             return toks.front() == p;
0205           });
0206           if (key == end(currentFilter_->skeys)) {
0207             currentFilter_->hasNamespace.emplace_back(dd4hep::dd::hasNamespace(toks[pos]));
0208             if (dd4hep::dd::isRegex(toks[pos])) {
0209               currentFilter_->isRegex.emplace_back(true);
0210               currentFilter_->index.emplace_back(currentFilter_->keys.size());
0211               currentFilter_->keys.emplace_back(std::regex(std::begin(toks[pos]), std::end(toks[pos])));
0212             } else {
0213               currentFilter_->isRegex.emplace_back(false);
0214               currentFilter_->index.emplace_back(currentFilter_->skeys.size());
0215             }
0216             currentFilter_->skeys.emplace_back(toks[pos]);
0217           }
0218         } else {
0219           auto nextLevelFilter = std::make_unique<Filter>();
0220           bool isRegex = dd4hep::dd::isRegex(toks[pos]);
0221           nextLevelFilter->isRegex.emplace_back(isRegex);
0222           nextLevelFilter->hasNamespace.emplace_back(dd4hep::dd::hasNamespace(toks[pos]));
0223           if (isRegex) {
0224             nextLevelFilter->index.emplace_back(filters_.back()->keys.size());
0225             nextLevelFilter->keys.emplace_back(std::regex(toks[pos].begin(), toks[pos].end()));
0226           } else {
0227             nextLevelFilter->index.emplace_back(filters_.back()->skeys.size());
0228           }
0229           nextLevelFilter->skeys.emplace_back(toks[pos]);
0230           nextLevelFilter->next = nullptr;
0231           nextLevelFilter->up = currentFilter_;
0232           nextLevelFilter->spec = section.second;
0233 
0234           currentFilter_->next = std::move(nextLevelFilter);
0235         }
0236       }
0237     }
0238   }
0239 }
0240 
0241 void print(const Filter* filter) {
0242   edm::LogVerbatim("Geometry").log([&](auto& log) {
0243     for (const auto& it : filter->skeys) {
0244       log << it << ", ";
0245     }
0246   });
0247 }
0248 
0249 void DDFilteredView::printFilter() const {
0250   for (const auto& f : filters_) {
0251     edm::LogVerbatim("Geometry").log([&](auto& log) {
0252       log << "\nFilter: ";
0253       for (const auto& it : f->skeys) {
0254         log << it << ", ";
0255       }
0256       if (f->next) {
0257         log << "\nNext: ";
0258         print(&*f->next);
0259       }
0260       if (f->up) {
0261         log << "Up: ";
0262         print(f->up);
0263       }
0264     });
0265   }
0266 }
0267 
0268 bool DDFilteredView::firstChild() {
0269   currentSpecPar_ = nullptr;
0270 
0271   if (it_.empty()) {
0272     LogVerbatim("DDFilteredView") << "Iterator vector has zero size.";
0273     return false;
0274   }
0275   it_.back().SetType(0);
0276   Node* node = nullptr;
0277   while ((node = it_.back().Next())) {
0278     if (accept(noNamespace(node->GetVolume()->GetName()))) {
0279       node_ = node;
0280       startLevel_ = it_.back().GetLevel();
0281       return true;
0282     }
0283   }
0284   LogVerbatim("DDFilteredView") << "Search for first child failed.";
0285   return false;
0286 }
0287 
0288 bool DDFilteredView::nextChild() {
0289   currentSpecPar_ = nullptr;
0290 
0291   if (it_.empty()) {
0292     LogVerbatim("DDFilteredView") << "Iterator vector has zero size.";
0293     return false;
0294   }
0295   it_.back().SetType(0);
0296   Node* node = nullptr;
0297   while ((node = it_.back().Next())) {
0298     if (it_.back().GetLevel() <= startLevel_) {
0299       return false;
0300     }
0301     if (accept(noNamespace(node->GetVolume()->GetName()))) {
0302       node_ = node;
0303       return true;
0304     }
0305   }
0306   LogVerbatim("DDFilteredView") << "Search for first child failed.";
0307   return false;
0308 }
0309 
0310 int DDFilteredView::nodeCopyNo(const std::string_view copyNo) const {
0311   int result;
0312   if (auto [p, ec] = std::from_chars(copyNo.data(), copyNo.data() + copyNo.size(), result); ec == std::errc()) {
0313     return result;
0314   }
0315   return -1;
0316 }
0317 
0318 std::vector<std::pair<std::string, int>> DDFilteredView::toNodeNames(const std::string& path) {
0319   std::vector<std::pair<std::string, int>> result;
0320   std::vector<string_view> names = split(path, "/");
0321   for (auto it : names) {
0322     auto name = noNamespace(it);
0323     int copyNo = -1;
0324     auto lpos = name.find_first_of('[');
0325     if (lpos != std::string::npos) {
0326       auto rpos = name.find_last_of(']');
0327       if (rpos != std::string::npos) {
0328         copyNo = nodeCopyNo(name.substr(lpos + 1, rpos - 1));
0329       }
0330       name.remove_suffix(name.size() - lpos);
0331     }
0332     result.emplace_back(std::string(name.data(), name.size()), copyNo);
0333   }
0334 
0335   return result;
0336 }
0337 
0338 bool DDFilteredView::match(const std::string& path, const std::vector<std::pair<std::string, int>>& names) const {
0339   std::vector<std::pair<std::string_view, int>> toks;
0340   std::vector<string_view> pnames = split(path, "/");
0341   for (const auto& i : pnames) {
0342     auto name = noNamespace(i);
0343     auto lpos = name.find_first_of('_');
0344     if (lpos != std::string::npos) {
0345       int copyNo = nodeCopyNo(name.substr(lpos + 1));
0346       toks.emplace_back(name.substr(0, lpos), copyNo);
0347     }
0348   }
0349   if (toks.size() != names.size()) {
0350     return false;
0351   }
0352 
0353   for (unsigned int i = 0; i < names.size(); i++) {
0354     if (names[i].first != toks[i].first) {
0355       return false;
0356     } else {
0357       if (names[i].second != -1 and names[i].second != toks[i].second) {
0358         return false;
0359       }
0360     }
0361   }
0362   return true;
0363 }
0364 
0365 std::vector<std::vector<Node*>> DDFilteredView::children(const std::string& selectPath) {
0366   currentSpecPar_ = nullptr;
0367 
0368   std::vector<std::vector<Node*>> paths;
0369   if (it_.empty()) {
0370     LogVerbatim("DDFilteredView") << "Iterator vector has zero size.";
0371     return paths;
0372   }
0373   if (node_ == nullptr) {
0374     throw cms::Exception("DDFilteredView") << "Can't get children of a null node. Please, call firstChild().";
0375   }
0376   it_.back().SetType(0);
0377   std::vector<std::pair<std::string, int>> names = toNodeNames(selectPath);
0378   auto rit = names.rbegin();
0379   Node* node = it_.back().Next();
0380   while (node != nullptr) {
0381     if (node->GetVolume()->GetName() == rit->first) {
0382       std::string pathToNode = path();
0383       std::string::size_type n = pathToNode.find(node_->GetName());
0384       std::string pathFromParent = pathToNode.substr(n);
0385 
0386       if (match(pathFromParent, names)) {
0387         std::vector<Node*> result;
0388         LogVerbatim("Geometry") << "Match found: " << pathFromParent;
0389         for (int i = startLevel_; i < it_.back().GetLevel(); i++) {
0390           result.emplace_back(it_.back().GetNode(i));
0391         }
0392         result.emplace_back(node);
0393         paths.emplace_back(result);
0394       }
0395     }
0396     node = it_.back().Next();
0397   }
0398   return paths;
0399 }
0400 
0401 bool DDFilteredView::firstSibling() {
0402   currentSpecPar_ = nullptr;
0403 
0404   assert(node_);
0405   if (it_.empty() or currentFilter_ == nullptr)
0406     return false;
0407   Node* node = nullptr;
0408   if (next(0) == false)
0409     return false;
0410   node = node_;
0411   it_.emplace_back(Iterator(it_.back()));
0412   it_.back().SetType(1);
0413   if (currentFilter_ != nullptr and currentFilter_->next != nullptr)
0414     currentFilter_ = currentFilter_->next.get();
0415   else
0416     return false;
0417   do {
0418     if (dd4hep::dd::accepted(currentFilter_, noNamespace(node->GetVolume()->GetName()))) {
0419       node_ = node;
0420       return true;
0421     }
0422   } while ((node = it_.back().Next()));
0423 
0424   return false;
0425 }
0426 
0427 bool DDFilteredView::nextSibling() {
0428   currentSpecPar_ = nullptr;
0429 
0430   assert(node_);
0431   if (it_.empty() or currentFilter_ == nullptr)
0432     return false;
0433   if (it_.back().GetType() == 0)
0434     return firstSibling();
0435   else {
0436     up();
0437     it_.back().SetType(1);
0438     Node* node = node_;
0439     do {
0440       if (dd4hep::dd::accepted(currentFilter_, noNamespace(node->GetVolume()->GetName()))) {
0441         node_ = node;
0442         return true;
0443       }
0444     } while ((node = it_.back().Next()));
0445 
0446     return false;
0447   }
0448 }
0449 
0450 bool DDFilteredView::sibling() {
0451   currentSpecPar_ = nullptr;
0452 
0453   if (it_.empty() or currentFilter_ == nullptr)
0454     return false;
0455   it_.back().SetType(1);
0456   Node* node = nullptr;
0457   while ((node = it_.back().Next())) {
0458     if (dd4hep::dd::accepted(currentFilter_, noNamespace(node->GetVolume()->GetName()))) {
0459       node_ = node;
0460       return true;
0461     }
0462   }
0463   return false;
0464 }
0465 
0466 bool DDFilteredView::checkChild() {
0467   currentSpecPar_ = nullptr;
0468 
0469   if (it_.empty() or currentFilter_ == nullptr)
0470     return false;
0471   it_.back().SetType(1);
0472   Node* node = nullptr;
0473   while ((node = it_.back().Next())) {
0474     if (dd4hep::dd::accepted(currentFilter_, noNamespace(node->GetVolume()->GetName()))) {
0475       return true;
0476     }
0477   }
0478   return false;
0479 }
0480 
0481 bool DDFilteredView::parent() {
0482   currentSpecPar_ = nullptr;
0483   if (it_.empty() or currentFilter_ == nullptr)
0484     return false;
0485   up();
0486   it_.back().SetType(0);
0487 
0488   return true;
0489 }
0490 
0491 bool DDFilteredView::next(int type) {
0492   currentSpecPar_ = nullptr;
0493 
0494   if (it_.empty())
0495     return false;
0496   it_.back().SetType(type);
0497   Node* node = nullptr;
0498   if ((node = it_.back().Next())) {
0499     node_ = node;
0500     return true;
0501   } else
0502     return false;
0503 }
0504 
0505 void DDFilteredView::down() {
0506   currentSpecPar_ = nullptr;
0507 
0508   if (it_.empty() or currentFilter_ == nullptr)
0509     return;
0510   it_.emplace_back(Iterator(it_.back()));
0511   next(0);
0512   if (currentFilter_->next)
0513     currentFilter_ = currentFilter_->next.get();
0514 }
0515 
0516 void DDFilteredView::up() {
0517   currentSpecPar_ = nullptr;
0518 
0519   if (it_.size() > 1 and currentFilter_ != nullptr) {
0520     it_.pop_back();
0521     it_.back().SetType(0);
0522     if (currentFilter_->up)
0523       currentFilter_ = currentFilter_->up;
0524   }
0525 }
0526 
0527 bool DDFilteredView::accept(std::string_view name) {
0528   for (const auto& it : filters_) {
0529     currentFilter_ = it.get();
0530     if (dd4hep::dd::accepted(currentFilter_, name))
0531       return true;
0532   }
0533   return false;
0534 }
0535 
0536 const std::vector<double> DDFilteredView::parameters() const {
0537   assert(node_);
0538   Volume currVol = node_->GetVolume();
0539   // Boolean shapes are a special case
0540   if (currVol->GetShape()->IsA() == TGeoCompositeShape::Class() and
0541       not dd4hep::isA<dd4hep::PseudoTrap>(currVol.solid())) {
0542     const TGeoCompositeShape* shape = static_cast<const TGeoCompositeShape*>(currVol->GetShape());
0543     const TGeoBoolNode* boolean = shape->GetBoolNode();
0544     while (boolean->GetLeftShape()->IsA() == TGeoCompositeShape::Class()) {
0545       boolean = static_cast<const TGeoCompositeShape*>(boolean->GetLeftShape())->GetBoolNode();
0546     }
0547     if (boolean->GetLeftShape()->IsA() == TGeoBBox::Class()) {
0548       const TGeoBBox* box = static_cast<const TGeoBBox*>(boolean->GetLeftShape());
0549       return {box->GetDX(), box->GetDY(), box->GetDZ()};
0550     } else if (boolean->GetLeftShape()->IsA() == TGeoPcon::Class()) {
0551       const TGeoPcon* pcon = static_cast<const TGeoPcon*>(boolean->GetLeftShape());
0552       double param[4];
0553       pcon->GetBoundingCylinder(param);
0554       return {param[0], param[1], param[2], param[3]};
0555     } else {
0556       throw cms::Exception("DDFilteredView") << "Unknown boolean solid component";
0557     }
0558   } else
0559     return currVol.solid().dimensions();
0560 }
0561 
0562 const cms::DDSolidShape DDFilteredView::shape() const {
0563   assert(node_);
0564   if ((volume().volume())->IsAssembly()) {
0565     return (cms::DDSolidShape::ddbox);  // Needs to be box to match DDFilteredView::solid()
0566   }
0567   return cms::dd::value(cms::DDSolidShapeMap, std::string(node_->GetVolume()->GetShape()->GetTitle()));
0568 }
0569 
0570 LegacySolidShape DDFilteredView::legacyShape(const cms::DDSolidShape shape) const {
0571   return cms::dd::value(cms::LegacySolidShapeMap, shape);
0572 }
0573 
0574 template <>
0575 std::string_view DDFilteredView::get<string_view>(const string& key) {
0576   std::string_view result;
0577 
0578   currentSpecPar_ = find(key);
0579   if (currentSpecPar_ != nullptr) {
0580     result = currentSpecPar_->strValue(key);
0581   }
0582   return result;
0583 }
0584 
0585 template <>
0586 double DDFilteredView::get<double>(const string& key) {
0587   double result(0.0);
0588 
0589   currentSpecPar_ = find(key);
0590   if (currentSpecPar_ != nullptr) {
0591     result = getNextValue(key);
0592   }
0593 
0594   return result;
0595 }
0596 
0597 template <>
0598 std::vector<double> DDFilteredView::get<std::vector<double>>(const string& name, const string& key) const {
0599   if (registry_->hasSpecPar(name))
0600     return registry_->specPar(name)->value<std::vector<double>>(key);
0601   else
0602     return std::vector<double>();
0603 }
0604 
0605 template <>
0606 std::vector<int> DDFilteredView::get<std::vector<int>>(const string& name, const string& key) const {
0607   if (registry_->hasSpecPar(name))
0608     return registry_->specPar(name)->value<std::vector<int>>(key);
0609   else
0610     return std::vector<int>();
0611 }
0612 
0613 template <>
0614 std::vector<std::string> DDFilteredView::get<std::vector<std::string>>(const string& name, const string& key) const {
0615   if (registry_->hasSpecPar(name))
0616     return registry_->specPar(name)->value<std::vector<std::string>>(key);
0617   else
0618     return std::vector<std::string>();
0619 }
0620 
0621 std::vector<double> DDFilteredView::get(const string& name, const string& key) const {
0622   std::vector<std::string> stringVector = get<std::vector<std::string>>(name, key);
0623   std::vector<double> doubleVector(stringVector.size());
0624   std::transform(stringVector.begin(), stringVector.end(), doubleVector.begin(), [](const std::string& val) {
0625     return std::stod(val);
0626   });
0627   return doubleVector;
0628 }
0629 
0630 std::string_view DDFilteredView::getString(const std::string& key) const {
0631   assert(currentFilter_);
0632   assert(currentFilter_->spec);
0633   return currentFilter_->spec->strValue(key);
0634 }
0635 
0636 DDFilteredView::nav_type DDFilteredView::navPos() const {
0637   nav_type pos;
0638 
0639   if (not it_.empty()) {
0640     int level = it_.back().GetLevel();
0641     for (int i = 1; i <= level; ++i)
0642       pos.emplace_back(it_.back().GetIndex(i));
0643   }
0644 
0645   return pos;
0646 }
0647 
0648 const int DDFilteredView::level() const {
0649   int level(0);
0650   if (not it_.empty()) {
0651     level = it_.back().GetLevel();
0652   }
0653   return level;
0654 }
0655 
0656 bool DDFilteredView::goTo(const nav_type& newpos) {
0657   bool result(false);
0658   currentSpecPar_ = nullptr;
0659 
0660   // save the current position
0661   it_.emplace_back(Iterator(it_.back().GetTopVolume()));
0662   Node* node = nullptr;
0663 
0664   // try to navigate down to the newpos
0665   for (auto const& i : newpos) {
0666     it_.back().SetType(0);
0667     node = it_.back().Next();
0668     for (int j = 1; j <= i; j++) {
0669       it_.back().SetType(1);
0670       node = it_.back().Next();
0671     }
0672   }
0673   if (node != nullptr) {
0674     node_ = node;
0675     result = true;
0676   } else {
0677     it_.pop_back();
0678   }
0679 
0680   return result;
0681 }
0682 
0683 const std::vector<const Node*> DDFilteredView::geoHistory() const {
0684   std::vector<const Node*> result;
0685   if (not it_.empty()) {
0686     int level = it_.back().GetLevel();
0687     for (int nit = level; nit > 0; --nit) {
0688       result.emplace_back(it_.back().GetNode(nit));
0689     }
0690   }
0691 
0692   return result;
0693 }
0694 
0695 const ExpandedNodes& DDFilteredView::history() {
0696   assert(registry_);
0697   nodes_.tags.clear();
0698   nodes_.offsets.clear();
0699   nodes_.copyNos.clear();
0700 
0701   int level = it_.back().GetLevel();
0702   for (int nit = level; nit > 0; --nit) {
0703     for (auto const& i : registry_->specpars) {
0704       auto k = find_if(begin(i.second.paths), end(i.second.paths), [&](auto const& j) {
0705         return (isMatch(noNamespace(it_.back().GetNode(nit)->GetVolume()->GetName()), front(j))) and
0706                (i.second.hasValue("CopyNoTag") or i.second.hasValue("CopyNoOffset"));
0707       });
0708       if (k != end(i.second.paths)) {
0709         nodes_.tags.emplace_back(i.second.dblValue("CopyNoTag"));
0710         nodes_.offsets.emplace_back(i.second.dblValue("CopyNoOffset"));
0711         nodes_.copyNos.emplace_back(it_.back().GetNode(nit)->GetNumber());
0712       }
0713     }
0714   }
0715 
0716   return nodes_;
0717 }
0718 
0719 const DDSpecPar* DDFilteredView::find(const std::string& key) const {
0720   DDSpecParRefs specParRefs;
0721   filter(specParRefs, key);
0722 
0723   for (auto const& specPar : specParRefs) {
0724     auto pos = find_if(begin(specPar.second->paths), end(specPar.second->paths), [&](auto const& partSelector) {
0725       return matchPath(partSelector);
0726     });
0727     if (pos != end(specPar.second->paths)) {
0728       return specPar.second;
0729     }
0730   }
0731 
0732   return nullptr;
0733 }
0734 
0735 void DDFilteredView::filter(DDSpecParRefs& refs, const std::string& key) const {
0736   for (auto const& it : registry_->specpars) {
0737     if (it.second.hasValue(key) || (it.second.spars.find(key) != end(it.second.spars))) {
0738       refs.emplace_back(it.first, &it.second);
0739     }
0740   }
0741 }
0742 
0743 // First name in a path
0744 std::string_view DDFilteredView::front(const std::string_view path) const {
0745   auto const& lpos = path.find_first_not_of('/');
0746   if (lpos != path.npos) {
0747     auto rpos = path.find_first_of('/', lpos);
0748     if (rpos == path.npos) {
0749       rpos = path.size();
0750     }
0751     return path.substr(lpos, rpos - lpos);
0752   }
0753 
0754   // throw cms::Exception("Filtered View") << "Path must start with '//'  " << path;
0755   return path;
0756 }
0757 
0758 // Last name in a path
0759 std::string_view DDFilteredView::back(const std::string_view path) const {
0760   if (auto const& lpos = path.rfind('/') != path.npos) {
0761     return path.substr(lpos, path.size());
0762   }
0763 
0764   // throw cms::Exception("Filtered View") << "Path must start with '//'  " << path;
0765   return path;
0766 }
0767 
0768 // Current Iterator level Node name
0769 std::string_view DDFilteredView::nodeNameAt(int level) const {
0770   assert(!it_.empty());
0771   assert(it_.back().GetLevel() >= level);
0772   return it_.back().GetNode(level)->GetVolume()->GetName();
0773 }
0774 
0775 // Current Iterator level Node copy number
0776 const int DDFilteredView::nodeCopyNoAt(int level) const {
0777   assert(!it_.empty());
0778   assert(it_.back().GetLevel() >= level);
0779   return it_.back().GetNode(level)->GetNumber();
0780 }
0781 
0782 // Compare if name matches a selection pattern that
0783 // may or may not be defined as a regular expression
0784 bool DDFilteredView::compareEqualName(const std::string_view selection, const std::string_view name) const {
0785   return (!(dd4hep::dd::isRegex(selection))
0786               ? dd4hep::dd::compareEqual(name, selection)
0787               : regex_match(name.begin(), name.end(), regex(selection.begin(), selection.end())));
0788 }
0789 
0790 // Check if both name and it's selection pattern
0791 // contain a namespace and
0792 // remove it if one of them does not
0793 std::tuple<std::string_view, std::string_view> DDFilteredView::alignNamespaces(std::string_view selection,
0794                                                                                std::string_view name) const {
0795   auto pos = selection.find(':');
0796   if (pos == selection.npos) {
0797     name = noNamespace(name);
0798   } else {
0799     if (name.find(':') == name.npos) {
0800       selection.remove_prefix(pos + 1);
0801     }
0802   }
0803   return std::make_tuple(selection, name);
0804 }
0805 
0806 // If a name has an XML-style copy number, e.g. Name[1]
0807 // and compare it to an integer
0808 bool DDFilteredView::compareEqualCopyNumber(const std::string_view name, int copy) const {
0809   auto pos = name.rfind('[');
0810   if (pos != name.npos) {
0811     if (std::stoi(std::string(name.substr(pos + 1, name.rfind(']')))) == copy) {
0812       return true;
0813     }
0814   }
0815 
0816   return false;
0817 }
0818 
0819 bool DDFilteredView::matchPath(const std::string_view path) const {
0820   assert(!it_.empty());
0821   int level = it_.back().GetLevel();
0822 
0823   auto to = path.size();
0824   auto from = path.rfind('/');
0825   bool result = false;
0826   for (int it = level; from - 1 <= to and it > 0; --it) {
0827     std::string_view name = nodeNameAt(it);
0828     std::string_view refname{&path[from + 1], to - from - 1};
0829     to = from;
0830     from = path.substr(0, to).rfind('/');
0831 
0832     std::tie(refname, name) = alignNamespaces(refname, name);
0833 
0834     auto pos = refname.rfind('[');
0835     if (pos != refname.npos) {
0836       if (!compareEqualCopyNumber(refname, nodeCopyNoAt(it))) {
0837         result = false;
0838         break;
0839       } else {
0840         refname.remove_suffix(refname.size() - pos);
0841       }
0842     }
0843     if (!compareEqualName(refname, name)) {
0844       result = false;
0845       break;
0846     } else {
0847       result = true;
0848     }
0849   }
0850   return result;
0851 }
0852 
0853 double DDFilteredView::getNextValue(const std::string& key) const {
0854   double result(0.0);
0855 
0856   if (currentSpecPar_ != nullptr) {
0857     auto const& nitem = currentSpecPar_->numpars.find(key);
0858     if (nitem != end(currentSpecPar_->numpars)) {
0859       result = nitem->second[0];
0860     }
0861   }
0862 
0863   return result;
0864 }
0865 
0866 std::string_view DDFilteredView::name() const {
0867   return (node_ == nullptr ? std::string_view() : (dd4hep::dd::noNamespace(volume().volume().name())));
0868 }
0869 
0870 std::string_view DDFilteredView::fullName() const {
0871   return (node_ == nullptr ? std::string_view() : (volume().volume().name()));
0872 }
0873 
0874 dd4hep::Solid DDFilteredView::solid() const {
0875   if ((volume().volume())->IsAssembly()) {
0876     std::string solName(name());
0877     // Valid solid is needed, use a dummy box
0878     return (dd4hep::Box(solName, 1., 1., 1.));
0879   }
0880   return (volume().volume().solid());
0881 }
0882 
0883 unsigned short DDFilteredView::copyNum() const { return (volume().copyNumber()); }
0884 
0885 std::string_view DDFilteredView::materialName() const { return (volume().material().name()); }
0886 
0887 std::ostream& operator<<(std::ostream& os, const std::vector<const cms::Node*>& hst) {
0888   for (auto nd = hst.rbegin(); nd != hst.rend(); ++nd)
0889     os << "/" << (*nd)->GetName();
0890   return os;
0891 }