Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-27 04:54:48

0001 #include "DD4hep/DetFactoryHelper.h"
0002 #include "DD4hep/DetectorHelper.h"
0003 #include "DD4hep/DD4hepUnits.h"
0004 #include "DD4hep/GeoHandler.h"
0005 #include "DD4hep/Printout.h"
0006 #include "DD4hep/Plugins.h"
0007 #include "DD4hep/detail/SegmentationsInterna.h"
0008 #include "DD4hep/detail/DetectorInterna.h"
0009 #include "DD4hep/detail/ObjectsInterna.h"
0010 #include "DD4hep/MatrixHelpers.h"
0011 
0012 #include "XML/Utilities.h"
0013 #include "FWCore/ParameterSet/interface/FileInPath.h"
0014 #include "FWCore/Utilities/interface/Exception.h"
0015 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0016 #include "DataFormats/Math/interface/CMSUnits.h"
0017 #include "DetectorDescription/DDCMS/interface/DDAlgoArguments.h"
0018 #include "DetectorDescription/DDCMS/interface/DDNamespace.h"
0019 #include "DetectorDescription/DDCMS/interface/DDParsingContext.h"
0020 #include "DetectorDescription/DDCMS/interface/DDDetector.h"
0021 
0022 #include "TGeoManager.h"
0023 #include "TGeoMaterial.h"
0024 
0025 #include <climits>
0026 #include <iostream>
0027 #include <iomanip>
0028 #include <map>
0029 #include <vector>
0030 #include <unordered_map>
0031 #include <utility>
0032 
0033 // #define EDM_ML_DEBUG 1
0034 
0035 using namespace std;
0036 using namespace dd4hep;
0037 using namespace cms;
0038 using namespace cms_units::operators;
0039 
0040 namespace dd4hep {
0041 
0042   namespace {
0043 
0044     atomic<UInt_t> unique_mat_id = 0xAFFEFEED;
0045 
0046     class include_constants;
0047     class include_load;
0048     class include_unload;
0049     class print_xml_doc;
0050 
0051     class ConstantsSection;
0052     class DDLConstant;
0053 
0054     struct DDRegistry {
0055       std::vector<xml::Document> includes;
0056       std::unordered_map<std::string, std::string> unresolvedConst;
0057       std::unordered_map<std::string, std::string> originalConst;
0058     };
0059 
0060     class MaterialSection;
0061     class DDLElementaryMaterial;
0062     class DDLCompositeMaterial;
0063 
0064     class RotationSection;
0065     class DDLRotation;
0066     class DDLReflectionRotation;
0067     class DDLRotationSequence;
0068     class DDLRotationByAxis;
0069     class DDLTransform3D;
0070 
0071     class PosPartSection;
0072     class DDLPosPart;
0073     class DDLDivision;
0074 
0075     class LogicalPartSection;
0076     class DDLLogicalPart;
0077 
0078     class SolidSection;
0079     class DDLExtrudedPolygon;
0080     class DDLShapeless;
0081     class DDLAssembly;
0082     class DDLTrapezoid;
0083     class DDLEllipticalTube;
0084     class DDLPseudoTrap;
0085     class DDLPolyhedra;
0086     class DDLPolycone;
0087     class DDLTorus;
0088     class DDLTrd1;
0089     class DDLTrd2;
0090     class DDLTruncTubs;
0091     class DDLCutTubs;
0092     class DDLTubs;
0093     class DDLBox;
0094     class DDLCone;
0095     class DDLSphere;
0096     class DDLUnionSolid;
0097     class DDLIntersectionSolid;
0098     class DDLSubtractionSolid;
0099 
0100     class DDLAlgorithm;
0101     class DDLVector;
0102 
0103     class SpecParSection;
0104     class DDLSpecPar;
0105     class PartSelector;
0106     class Parameter;
0107 
0108     class debug;
0109   }  // namespace
0110 
0111   TGeoCombiTrans* createPlacement(const Rotation3D& iRot, const Position& iTrans) {
0112     double elements[9];
0113     iRot.GetComponents(elements);
0114     TGeoRotation r;
0115     r.SetMatrix(elements);
0116 
0117     TGeoTranslation t(iTrans.x(), iTrans.y(), iTrans.z());
0118 
0119     return new TGeoCombiTrans(t, r);
0120   }
0121 
0122   /// Converter instances implemented in this compilation unit
0123   template <>
0124   void Converter<debug>::operator()(xml_h element) const;
0125   template <>
0126   void Converter<print_xml_doc>::operator()(xml_h element) const;
0127 
0128   /// Converter for <ConstantsSection/> tags
0129   template <>
0130   void Converter<ConstantsSection>::operator()(xml_h element) const;
0131   template <>
0132   void Converter<DDLConstant>::operator()(xml_h element) const;
0133   template <>
0134   void Converter<DDRegistry>::operator()(xml_h element) const;
0135 
0136   /// Converter for <MaterialSection/> tags
0137   template <>
0138   void Converter<MaterialSection>::operator()(xml_h element) const;
0139   template <>
0140   void Converter<DDLElementaryMaterial>::operator()(xml_h element) const;
0141   template <>
0142   void Converter<DDLCompositeMaterial>::operator()(xml_h element) const;
0143 
0144   /// Converter for <RotationSection/> tags
0145   template <>
0146   void Converter<RotationSection>::operator()(xml_h element) const;
0147   /// Converter for <DDLRotation/> tags
0148   template <>
0149   void Converter<DDLRotation>::operator()(xml_h element) const;
0150   /// Converter for <DDLReflectionRotation/> tags
0151   template <>
0152   void Converter<DDLReflectionRotation>::operator()(xml_h element) const;
0153   /// Converter for <DDLRotationSequence/> tags
0154   template <>
0155   void Converter<DDLRotationSequence>::operator()(xml_h element) const;
0156   /// Converter for <DDLRotationByAxis/> tags
0157   template <>
0158   void Converter<DDLRotationByAxis>::operator()(xml_h element) const;
0159   template <>
0160   void Converter<DDLTransform3D>::operator()(xml_h element) const;
0161 
0162   /// Generic converter for <LogicalPartSection/> tags
0163   template <>
0164   void Converter<LogicalPartSection>::operator()(xml_h element) const;
0165   template <>
0166   void Converter<DDLLogicalPart>::operator()(xml_h element) const;
0167 
0168   /// Generic converter for <PosPartSection/> tags
0169   template <>
0170   void Converter<PosPartSection>::operator()(xml_h element) const;
0171   /// Converter for <PosPart/> tags
0172   template <>
0173   void Converter<DDLPosPart>::operator()(xml_h element) const;
0174   /// Converter for <Division/> tags
0175   template <>
0176   void Converter<DDLDivision>::operator()(xml_h element) const;
0177 
0178   /// Generic converter for <SpecParSection/> tags
0179   template <>
0180   void Converter<SpecParSection>::operator()(xml_h element) const;
0181   template <>
0182   void Converter<DDLSpecPar>::operator()(xml_h element) const;
0183   template <>
0184   void Converter<PartSelector>::operator()(xml_h element) const;
0185   template <>
0186   void Converter<Parameter>::operator()(xml_h element) const;
0187 
0188   /// Generic converter for solids: <SolidSection/> tags
0189   template <>
0190   void Converter<SolidSection>::operator()(xml_h element) const;
0191   /// Converter for <UnionSolid/> tags
0192   template <>
0193   void Converter<DDLUnionSolid>::operator()(xml_h element) const;
0194   /// Converter for <SubtractionSolid/> tags
0195   template <>
0196   void Converter<DDLSubtractionSolid>::operator()(xml_h element) const;
0197   /// Converter for <IntersectionSolid/> tags
0198   template <>
0199   void Converter<DDLIntersectionSolid>::operator()(xml_h element) const;
0200   /// Converter for <PseudoTrap/> tags
0201   template <>
0202   void Converter<DDLPseudoTrap>::operator()(xml_h element) const;
0203   /// Converter for <ExtrudedPolygon/> tags
0204   template <>
0205   void Converter<DDLExtrudedPolygon>::operator()(xml_h element) const;
0206   /// Converter for <ShapelessSolid/> tags
0207   template <>
0208   void Converter<DDLShapeless>::operator()(xml_h element) const;
0209   /// Converter for <Assembly/> tags
0210   template <>
0211   void Converter<DDLAssembly>::operator()(xml_h element) const;
0212   /// Converter for <Trapezoid/> tags
0213   template <>
0214   void Converter<DDLTrapezoid>::operator()(xml_h element) const;
0215   /// Converter for <Polycone/> tags
0216   template <>
0217   void Converter<DDLPolycone>::operator()(xml_h element) const;
0218   /// Converter for <Polyhedra/> tags
0219   template <>
0220   void Converter<DDLPolyhedra>::operator()(xml_h element) const;
0221   /// Converter for <EllipticalTube/> tags
0222   template <>
0223   void Converter<DDLEllipticalTube>::operator()(xml_h element) const;
0224   /// Converter for <Torus/> tags
0225   template <>
0226   void Converter<DDLTorus>::operator()(xml_h element) const;
0227   /// Converter for <Tubs/> tags
0228   template <>
0229   void Converter<DDLTubs>::operator()(xml_h element) const;
0230   /// Converter for <CutTubs/> tags
0231   template <>
0232   void Converter<DDLCutTubs>::operator()(xml_h element) const;
0233   /// Converter for <TruncTubs/> tags
0234   template <>
0235   void Converter<DDLTruncTubs>::operator()(xml_h element) const;
0236   /// Converter for <Sphere/> tags
0237   template <>
0238   void Converter<DDLSphere>::operator()(xml_h element) const;
0239   /// Converter for <Trd1/> tags
0240   template <>
0241   void Converter<DDLTrd1>::operator()(xml_h element) const;
0242   /// Converter for <Trd2/> tags
0243   template <>
0244   void Converter<DDLTrd2>::operator()(xml_h element) const;
0245   /// Converter for <Cone/> tags
0246   template <>
0247   void Converter<DDLCone>::operator()(xml_h element) const;
0248   /// Converter for <DDLBox/> tags
0249   template <>
0250   void Converter<DDLBox>::operator()(xml_h element) const;
0251   /// Converter for <Algorithm/> tags
0252   template <>
0253   void Converter<DDLAlgorithm>::operator()(xml_h element) const;
0254   /// Converter for <Vector/> tags
0255   template <>
0256   void Converter<DDLVector>::operator()(xml_h element) const;
0257 
0258   /// DD4hep specific: Load include file
0259   template <>
0260   void Converter<include_load>::operator()(xml_h element) const;
0261   /// DD4hep specific: Unload include file
0262   template <>
0263   void Converter<include_unload>::operator()(xml_h element) const;
0264   /// DD4hep specific: Process constants objects
0265   template <>
0266   void Converter<include_constants>::operator()(xml_h element) const;
0267 }  // namespace dd4hep
0268 
0269 /// Converter for <ConstantsSection/> tags
0270 template <>
0271 void Converter<ConstantsSection>::operator()(xml_h element) const {
0272   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0273   cms::DDParsingContext* const context = ns.context();
0274   xml_coll_t(element, DD_CMU(Constant)).for_each(Converter<DDLConstant>(description, context, optional));
0275   xml_coll_t(element, DD_CMU(Vector)).for_each(Converter<DDLVector>(description, context, optional));
0276 }
0277 
0278 /// Converter for <MaterialSection/> tags
0279 template <>
0280 void Converter<MaterialSection>::operator()(xml_h element) const {
0281   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0282   xml_coll_t(element, DD_CMU(ElementaryMaterial))
0283       .for_each(Converter<DDLElementaryMaterial>(description, ns.context(), optional));
0284   xml_coll_t(element, DD_CMU(CompositeMaterial))
0285       .for_each(Converter<DDLCompositeMaterial>(description, ns.context(), optional));
0286 }
0287 
0288 template <>
0289 void Converter<RotationSection>::operator()(xml_h element) const {
0290   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0291   xml_coll_t(element, DD_CMU(Rotation)).for_each(Converter<DDLRotation>(description, ns.context(), optional));
0292   xml_coll_t(element, DD_CMU(ReflectionRotation))
0293       .for_each(Converter<DDLReflectionRotation>(description, ns.context(), optional));
0294   xml_coll_t(element, DD_CMU(RotationSequence))
0295       .for_each(Converter<DDLRotationSequence>(description, ns.context(), optional));
0296   xml_coll_t(element, DD_CMU(RotationByAxis))
0297       .for_each(Converter<DDLRotationByAxis>(description, ns.context(), optional));
0298 }
0299 
0300 template <>
0301 void Converter<PosPartSection>::operator()(xml_h element) const {
0302   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0303   xml_coll_t(element, DD_CMU(Division)).for_each(Converter<DDLDivision>(description, ns.context(), optional));
0304   xml_coll_t(element, DD_CMU(PosPart)).for_each(Converter<DDLPosPart>(description, ns.context(), optional));
0305   xml_coll_t(element, DD_CMU(Algorithm)).for_each(Converter<DDLAlgorithm>(description, ns.context(), optional));
0306 }
0307 
0308 template <>
0309 void Converter<SpecParSection>::operator()(xml_h element) const {
0310   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0311   xml_coll_t(element, DD_CMU(SpecPar)).for_each(Converter<DDLSpecPar>(description, ns.context(), optional));
0312 }
0313 
0314 template <>
0315 void Converter<DDLSpecPar>::operator()(xml_h element) const {
0316   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0317   xml_coll_t(element, DD_CMU(PartSelector)).for_each(Converter<PartSelector>(description, ns.context(), optional));
0318   xml_coll_t(element, DD_CMU(Parameter)).for_each(Converter<Parameter>(description, ns.context(), optional));
0319 }
0320 
0321 /// Generic converter for  <LogicalPartSection/> tags
0322 template <>
0323 void Converter<LogicalPartSection>::operator()(xml_h element) const {
0324   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0325   xml_coll_t(element, DD_CMU(LogicalPart)).for_each(Converter<DDLLogicalPart>(description, ns.context(), optional));
0326 }
0327 
0328 /// Generic converter for  <SolidSection/> tags
0329 template <>
0330 void Converter<SolidSection>::operator()(xml_h element) const {
0331   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
0332   for (xml_coll_t solid(element, _U(star)); solid; ++solid) {
0333     using cms::hash;
0334     switch (hash(solid.tag())) {
0335       case hash("Box"):
0336         Converter<DDLBox>(description, ns.context(), optional)(solid);
0337         break;
0338       case hash("Polycone"):
0339         Converter<DDLPolycone>(description, ns.context(), optional)(solid);
0340         break;
0341       case hash("Polyhedra"):
0342         Converter<DDLPolyhedra>(description, ns.context(), optional)(solid);
0343         break;
0344       case hash("Tubs"):
0345         Converter<DDLTubs>(description, ns.context(), optional)(solid);
0346         break;
0347       case hash("CutTubs"):
0348         Converter<DDLCutTubs>(description, ns.context(), optional)(solid);
0349         break;
0350       case hash("TruncTubs"):
0351         Converter<DDLTruncTubs>(description, ns.context(), optional)(solid);
0352         break;
0353       case hash("Tube"):
0354         Converter<DDLTubs>(description, ns.context(), optional)(solid);
0355         break;
0356       case hash("Trd1"):
0357         Converter<DDLTrd1>(description, ns.context(), optional)(solid);
0358         break;
0359       case hash("Trd2"):
0360         Converter<DDLTrd2>(description, ns.context(), optional)(solid);
0361         break;
0362       case hash("Cone"):
0363         Converter<DDLCone>(description, ns.context(), optional)(solid);
0364         break;
0365       case hash("Sphere"):
0366         Converter<DDLSphere>(description, ns.context(), optional)(solid);
0367         break;
0368       case hash("EllipticalTube"):
0369         Converter<DDLEllipticalTube>(description, ns.context(), optional)(solid);
0370         break;
0371       case hash("Torus"):
0372         Converter<DDLTorus>(description, ns.context(), optional)(solid);
0373         break;
0374       case hash("PseudoTrap"):
0375         Converter<DDLPseudoTrap>(description, ns.context(), optional)(solid);
0376         break;
0377       case hash("ExtrudedPolygon"):
0378         Converter<DDLExtrudedPolygon>(description, ns.context(), optional)(solid);
0379         break;
0380       case hash("Trapezoid"):
0381         Converter<DDLTrapezoid>(description, ns.context(), optional)(solid);
0382         break;
0383       case hash("UnionSolid"):
0384         Converter<DDLUnionSolid>(description, ns.context(), optional)(solid);
0385         break;
0386       case hash("SubtractionSolid"):
0387         Converter<DDLSubtractionSolid>(description, ns.context(), optional)(solid);
0388         break;
0389       case hash("IntersectionSolid"):
0390         Converter<DDLIntersectionSolid>(description, ns.context(), optional)(solid);
0391         break;
0392       case hash("ShapelessSolid"):
0393         Converter<DDLShapeless>(description, ns.context(), optional)(solid);
0394         break;
0395       case hash("Assembly"):
0396         Converter<DDLAssembly>(description, ns.context(), optional)(solid);
0397         break;
0398       default:
0399         throw std::runtime_error("Request to process unknown shape '" + xml_dim_t(solid).nameStr() + "' [" +
0400                                  solid.tag() + "]");
0401         break;
0402     }
0403   }
0404 }
0405 
0406 /// Converter for <Constant/> tags
0407 template <>
0408 void Converter<DDLConstant>::operator()(xml_h element) const {
0409   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0410   DDRegistry* res = _option<DDRegistry>();
0411   xml_dim_t constant = element;
0412   xml_dim_t par = constant.parent();
0413   bool eval = par.hasAttr(_U(eval)) ? par.attr<bool>(_U(eval)) : true;
0414   string val = constant.valueStr();
0415   string nam = constant.nameStr();
0416   string real = ns.prepend(nam);
0417   string typ = eval ? "number" : "string";
0418   size_t idx = val.find('[');
0419 
0420   if (constant.hasAttr(_U(type)))
0421     typ = constant.typeStr();
0422 
0423   if (idx == string::npos || typ == "string") {
0424     try {
0425       ns.addConstant(nam, val, typ);
0426       res->originalConst[real] = val;
0427     } catch (const exception& e) {
0428 #ifdef EDM_ML_DEBUG
0429 
0430       printout(INFO,
0431                "DD4CMS",
0432                "++ Unresolved constant: %s = %s [%s]. Try to resolve later. [%s]",
0433                real.c_str(),
0434                val.c_str(),
0435                typ.c_str(),
0436                e.what());
0437 #endif
0438     }
0439     return;
0440   }
0441   // Setup the resolution mechanism in Converter<resolve>
0442   while (idx != string::npos) {
0443     ++idx;
0444     size_t idp = val.find(':', idx);
0445     size_t idq = val.find(']', idx);
0446     if (idp == string::npos || idp > idq)
0447       val.insert(idx, ns.name());
0448     else if (idp != string::npos && idp < idq)
0449       val[idp] = NAMESPACE_SEP;
0450     idx = val.find('[', idx);
0451   }
0452 
0453 #ifdef EDM_ML_DEBUG
0454 
0455   printout(
0456       ns.context()->debug_constants ? ALWAYS : DEBUG, "Constant", "Unresolved: %s -> %s", real.c_str(), val.c_str());
0457 
0458 #endif
0459 
0460   res->originalConst[real] = val;
0461   res->unresolvedConst[real] = val;
0462 }
0463 
0464 /// Converter for <DDLElementaryMaterial/> tags
0465 template <>
0466 void Converter<DDLElementaryMaterial>::operator()(xml_h element) const {
0467   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0468   xml_dim_t xmat(element);
0469   const string xmatName(xmat.nameStr());
0470   string nam = ns.prepend(xmatName);
0471   TGeoManager& mgr = description.manager();
0472   TGeoMaterial* mat = mgr.GetMaterial(nam.c_str());
0473   if (nullptr == mat) {
0474     const char* matname = nam.c_str();
0475     double density = xmat.attr<double>(DD_CMU(density)) / (dd4hep::g / dd4hep::cm3);
0476     int atomicNumber = xmat.attr<int>(DD_CMU(atomicNumber));
0477     double atomicWeight = xmat.attr<double>(DD_CMU(atomicWeight)) / (dd4hep::g / dd4hep::mole);
0478     TGeoElementTable* tab = mgr.GetElementTable();
0479     int nElem = tab->GetNelements();
0480 
0481 #ifdef EDM_ML_DEBUG
0482 
0483     printout(ns.context()->debug_materials ? ALWAYS : DEBUG, "DD4CMS", "+++ Element table size = %d", nElem);
0484 
0485 #endif
0486 
0487     if (nElem <= 1) {  // Restore the element table DD4hep destroyed.
0488       tab->TGeoElementTable::~TGeoElementTable();
0489       new (tab) TGeoElementTable();
0490       tab->BuildDefaultElements();
0491     }
0492     TGeoMixture* mix = new TGeoMixture(nam.c_str(), 1, density);
0493     const char* const matNameNoNS = xmatName.c_str();
0494     TGeoElement* elt = tab->FindElement(matNameNoNS);
0495 
0496 #ifdef EDM_ML_DEBUG
0497 
0498     printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0499              "DD4CMS",
0500              "+++ Searching for material %-48s  elt_ptr = %ld",
0501              matNameNoNS,
0502              elt);
0503 
0504     printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0505              "DD4CMS",
0506              "+++ Converting material %-48s  Atomic weight %8.3f   [g/mol], Atomic number %u, Density: %8.3f [g/cm3] "
0507              "ROOT: %8.3f [g/cm3]",
0508              ('"' + nam + '"').c_str(),
0509              atomicWeight,
0510              atomicNumber,
0511              density,
0512              mix->GetDensity());
0513 
0514 #endif
0515 
0516     bool newMatDef = false;
0517 
0518     if (elt) {
0519       // A is Mass of a mole in Geant4 units for atoms with atomic shell
0520 
0521 #ifdef EDM_ML_DEBUG
0522 
0523       printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0524                "DD4CMS",
0525                "    ROOT definition of %-50s Atomic weight %g, Atomic number %u, Number of nucleons %u",
0526                elt->GetName(),
0527                elt->A(),
0528                elt->Z(),
0529                elt->N());
0530       printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0531                "DD4CMS",
0532                "+++ Compared to XML values: Atomic weight %g, Atomic number %u",
0533                atomicWeight,
0534                atomicNumber);
0535 #endif
0536 
0537       static constexpr double const weightTolerance = 1.0e-6;
0538       if (atomicNumber != elt->Z() ||
0539           (std::abs(atomicWeight - elt->A()) > (weightTolerance * (atomicWeight + elt->A()))))
0540         newMatDef = true;
0541     }
0542 
0543     if (!elt || newMatDef) {
0544       if (newMatDef) {
0545 #ifdef EDM_ML_DEBUG
0546 
0547         printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0548                  "DD4CMS Warning",
0549                  "+++ Converter<ElementaryMaterial> Different definition of a default element with name:%s [CREATE NEW "
0550                  "MATERIAL]",
0551                  matname);
0552 
0553 #endif
0554 
0555       } else {
0556 #ifdef EDM_ML_DEBUG
0557 
0558         printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0559                  "DD4CMS Warning",
0560                  "+++ Converter<ElementaryMaterial> No default element present with name:%s  [CREATE NEW MATERIAL]",
0561                  matname);
0562 
0563 #endif
0564       }
0565       elt = new TGeoElement(matNameNoNS, matNameNoNS, atomicNumber, atomicWeight);
0566     }
0567 
0568     mix->AddElement(elt, 1.0);
0569     mix->SetTemperature(ns.context()->description.stdConditions().temperature);
0570     mix->SetPressure(ns.context()->description.stdConditions().pressure);
0571 
0572     /// Create medium from the material
0573     TGeoMedium* medium = mgr.GetMedium(matname);
0574     if (nullptr == medium) {
0575       --unique_mat_id;
0576       medium = new TGeoMedium(matname, unique_mat_id, mix);
0577       medium->SetTitle("material");
0578       medium->SetUniqueID(unique_mat_id);
0579     }
0580   }
0581 }
0582 
0583 /// Converter for <DDLCompositeMaterial/> tags
0584 template <>
0585 void Converter<DDLCompositeMaterial>::operator()(xml_h element) const {
0586   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0587   xml_dim_t xmat(element);
0588   string nam = ns.prepend(xmat.nameStr());
0589 
0590   TGeoManager& mgr = description.manager();
0591   TGeoMaterial* mat = mgr.GetMaterial(nam.c_str());
0592   if (nullptr == mat) {
0593     double density = xmat.attr<double>(DD_CMU(density)) / (dd4hep::g / dd4hep::cm3);
0594     xml_coll_t composites(xmat, DD_CMU(MaterialFraction));
0595     TGeoMixture* mix = new TGeoMixture(nam.c_str(), composites.size(), density);
0596 
0597 #ifdef EDM_ML_DEBUG
0598 
0599     printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0600              "DD4CMS",
0601              "++ Converting material %-48s  Density: %8.3f [g/cm3] ROOT: %8.3f [g/cm3]",
0602              ('"' + nam + '"').c_str(),
0603              density,
0604              mix->GetDensity());
0605 
0606 #endif
0607 
0608     if (ns.context()->makePayload) {
0609       ns.context()->compMaterialsVec.emplace_back(std::make_pair(nam, density));
0610     }
0611     for (composites.reset(); composites; ++composites) {
0612       xml_dim_t xfrac(composites);
0613       xml_dim_t xfrac_mat(xfrac.child(DD_CMU(rMaterial)));
0614       double fraction = xfrac.fraction();
0615       string fracname = ns.realName(xfrac_mat.nameStr());
0616 
0617       if (ns.context()->makePayload) {
0618         ns.context()->compMaterialsRefs[nam].emplace_back(
0619             cms::DDParsingContext::CompositeMaterial(ns.prepend(fracname), fraction));
0620       }
0621       TGeoMaterial* frac_mat = mgr.GetMaterial(fracname.c_str());
0622       if (frac_mat == nullptr)  // Try to find it within this namespace
0623         frac_mat = mgr.GetMaterial(ns.prepend(fracname).c_str());
0624       if (frac_mat) {
0625         mix->AddElement(frac_mat, fraction);
0626         continue;
0627       }
0628 
0629       throw cms::Exception("DD4CMS") << "Composite material \"" + fracname + "\" or \"" + ns.prepend(fracname) +
0630                                             "\" not yet defined.";
0631     }
0632     mix->SetTemperature(ns.context()->description.stdConditions().temperature);
0633     mix->SetPressure(ns.context()->description.stdConditions().pressure);
0634     mix->SetRadLen(0e0);
0635     /// Create medium from the material
0636     TGeoMedium* medium = mgr.GetMedium(nam.c_str());
0637     if (nullptr == medium) {
0638       --unique_mat_id;
0639       medium = new TGeoMedium(nam.c_str(), unique_mat_id, mix);
0640       medium->SetTitle("material");
0641       medium->SetUniqueID(unique_mat_id);
0642     }
0643   }
0644 }
0645 
0646 /// Converter for <Rotation/> tags
0647 template <>
0648 void Converter<DDLRotation>::operator()(xml_h element) const {
0649   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0650   cms::DDNamespace ns(context);
0651   xml_dim_t xrot(element);
0652   string nam = xrot.nameStr();
0653   double thetaX = xrot.hasAttr(DD_CMU(thetaX)) ? ns.attr<double>(xrot, DD_CMU(thetaX)) : 0e0;
0654   double phiX = xrot.hasAttr(DD_CMU(phiX)) ? ns.attr<double>(xrot, DD_CMU(phiX)) : 0e0;
0655   double thetaY = xrot.hasAttr(DD_CMU(thetaY)) ? ns.attr<double>(xrot, DD_CMU(thetaY)) : 0e0;
0656   double phiY = xrot.hasAttr(DD_CMU(phiY)) ? ns.attr<double>(xrot, DD_CMU(phiY)) : 0e0;
0657   double thetaZ = xrot.hasAttr(DD_CMU(thetaZ)) ? ns.attr<double>(xrot, DD_CMU(thetaZ)) : 0e0;
0658   double phiZ = xrot.hasAttr(DD_CMU(phiZ)) ? ns.attr<double>(xrot, DD_CMU(phiZ)) : 0e0;
0659   Rotation3D rot = makeRotation3D(thetaX, phiX, thetaY, phiY, thetaZ, phiZ);
0660 
0661 #ifdef EDM_ML_DEBUG
0662 
0663   printout(context->debug_rotations ? ALWAYS : DEBUG,
0664            "DD4CMS",
0665            "+++ Adding rotation: %-32s: (theta/phi)[rad] X: %6.3f %6.3f Y: %6.3f %6.3f Z: %6.3f %6.3f",
0666            ns.prepend(nam).c_str(),
0667            thetaX,
0668            phiX,
0669            thetaY,
0670            phiY,
0671            thetaZ,
0672            phiZ);
0673 
0674 #endif
0675 
0676   ns.addRotation(nam, rot);
0677 }
0678 
0679 /// Converter for <ReflectionRotation/> tags
0680 template <>
0681 void Converter<DDLReflectionRotation>::operator()(xml_h element) const {
0682   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0683   cms::DDNamespace ns(context);
0684   xml_dim_t xrot(element);
0685   string name = xrot.nameStr();
0686   double thetaX = xrot.hasAttr(DD_CMU(thetaX)) ? ns.attr<double>(xrot, DD_CMU(thetaX)) : 0e0;
0687   double phiX = xrot.hasAttr(DD_CMU(phiX)) ? ns.attr<double>(xrot, DD_CMU(phiX)) : 0e0;
0688   double thetaY = xrot.hasAttr(DD_CMU(thetaY)) ? ns.attr<double>(xrot, DD_CMU(thetaY)) : 0e0;
0689   double phiY = xrot.hasAttr(DD_CMU(phiY)) ? ns.attr<double>(xrot, DD_CMU(phiY)) : 0e0;
0690   double thetaZ = xrot.hasAttr(DD_CMU(thetaZ)) ? ns.attr<double>(xrot, DD_CMU(thetaZ)) : 0e0;
0691   double phiZ = xrot.hasAttr(DD_CMU(phiZ)) ? ns.attr<double>(xrot, DD_CMU(phiZ)) : 0e0;
0692 
0693 #ifdef EDM_ML_DEBUG
0694 
0695   printout(context->debug_rotations ? ALWAYS : DEBUG,
0696            "DD4CMS",
0697            "+++ Adding reflection rotation: %-32s: (theta/phi)[rad] X: %6.3f %6.3f Y: %6.3f %6.3f Z: %6.3f %6.3f",
0698            ns.prepend(name).c_str(),
0699            thetaX,
0700            phiX,
0701            thetaY,
0702            phiY,
0703            thetaZ,
0704            phiZ);
0705 
0706 #endif
0707 
0708   Rotation3D rot = makeRotReflect(thetaX, phiX, thetaY, phiY, thetaZ, phiZ);
0709   ns.addRotation(name, rot);
0710 }
0711 
0712 /// Converter for <RotationSequence/> tags
0713 template <>
0714 void Converter<DDLRotationSequence>::operator()(xml_h element) const {
0715   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0716   cms::DDNamespace ns(context);
0717   xml_dim_t xrot(element);
0718   string nam = xrot.nameStr();
0719   Rotation3D rot;
0720   xml_coll_t rotations(xrot, DD_CMU(RotationByAxis));
0721   for (rotations.reset(); rotations; ++rotations) {
0722     string axis = ns.attr<string>(rotations, DD_CMU(axis));
0723     double angle = ns.attr<double>(rotations, _U(angle));
0724     rot = makeRotation3D(rot, axis, angle);
0725 
0726 #ifdef EDM_ML_DEBUG
0727 
0728     printout(context->debug_rotations ? ALWAYS : DEBUG,
0729              "DD4CMS",
0730              "+   Adding rotation to: %-29s: (axis/angle)[rad] Axis: %s Angle: %6.3f",
0731              nam.c_str(),
0732              axis.c_str(),
0733              angle);
0734 
0735 #endif
0736   }
0737   double xx, xy, xz;
0738   double yx, yy, yz;
0739   double zx, zy, zz;
0740   rot.GetComponents(xx, xy, xz, yx, yy, yz, zx, zy, zz);
0741 
0742 #ifdef EDM_ML_DEBUG
0743 
0744   printout(context->debug_rotations ? ALWAYS : DEBUG,
0745            "DD4CMS",
0746            "+++ Adding rotation sequence: %-23s: %6.3f %6.3f %6.3f, %6.3f %6.3f %6.3f, %6.3f %6.3f %6.3f",
0747            ns.prepend(nam).c_str(),
0748            xx,
0749            xy,
0750            xz,
0751            yx,
0752            yy,
0753            yz,
0754            zx,
0755            zy,
0756            zz);
0757 
0758 #endif
0759 
0760   ns.addRotation(nam, rot);
0761 }
0762 
0763 /// Converter for <RotationByAxis/> tags
0764 template <>
0765 void Converter<DDLRotationByAxis>::operator()(xml_h element) const {
0766   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0767   cms::DDNamespace ns(context);
0768   xml_dim_t xrot(element);
0769   xml_dim_t par(xrot.parent());
0770   if (xrot.hasAttr(_U(name))) {
0771     string nam = xrot.nameStr();
0772     string axis = ns.attr<string>(xrot, DD_CMU(axis));
0773     double angle = ns.attr<double>(xrot, _U(angle));
0774     Rotation3D rot;
0775     rot = makeRotation3D(rot, axis, angle);
0776 
0777 #ifdef EDM_ML_DEBUG
0778 
0779     printout(context->debug_rotations ? ALWAYS : DEBUG,
0780              "DD4CMS",
0781              "+++ Adding rotation: %-32s: (axis/angle)[rad] Axis: %s Angle: %6.3f",
0782              ns.prepend(nam).c_str(),
0783              axis.c_str(),
0784              angle);
0785 
0786 #endif
0787 
0788     ns.addRotation(nam, rot);
0789   }
0790 }
0791 
0792 /// Converter for <LogicalPart/> tags
0793 template <>
0794 void Converter<DDLLogicalPart>::operator()(xml_h element) const {
0795   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0796   xml_dim_t e(element);
0797   string sol = e.child(DD_CMU(rSolid)).attr<string>(_U(name));
0798   string mat = e.child(DD_CMU(rMaterial)).attr<string>(_U(name));
0799   string volName = ns.prepend(e.attr<string>(_U(name)));
0800   Solid solid = ns.solid(sol);
0801   Material material = ns.material(mat);
0802   if (ns.context()->assemblySolids.count(sol) == 1) {
0803     // To match the general paradigm, an assembly starts as a solid,
0804     // and then a logical part is made of the solid. However, the
0805     // solid is just a dummy whose names tags it as an assembly.
0806     ns.addAssembly(volName, false);
0807     return;
0808   }
0809 
0810 #ifdef EDM_ML_DEBUG
0811   Volume volume =
0812 #endif
0813 
0814       ns.addVolume(Volume(volName, solid, material));
0815 
0816 #ifdef EDM_ML_DEBUG
0817 
0818   printout(ns.context()->debug_volumes ? ALWAYS : DEBUG,
0819            "DD4CMS",
0820            "+++ %s Volume: %-24s [%s] Shape: %-32s [%s] Material: %-40s [%s]",
0821            e.tag().c_str(),
0822            volName.c_str(),
0823            volume.isValid() ? "VALID" : "INVALID",
0824            sol.c_str(),
0825            solid.isValid() ? "VALID" : "INVALID",
0826            mat.c_str(),
0827            material.isValid() ? "VALID" : "INVALID");
0828 
0829 #endif
0830 }
0831 
0832 /// Helper converter
0833 template <>
0834 void Converter<DDLTransform3D>::operator()(xml_h element) const {
0835   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0836   Transform3D* tr = _option<Transform3D>();
0837   xml_dim_t e(element);
0838   xml_dim_t translation = e.child(DD_CMU(Translation), false);
0839   xml_dim_t rotation = e.child(DD_CMU(Rotation), false);
0840   xml_dim_t refRotation = e.child(DD_CMU(rRotation), false);
0841   xml_dim_t refReflectionRotation = e.child(DD_CMU(rReflectionRotation), false);
0842   Position pos;
0843   Rotation3D rot;
0844 
0845   if (translation.ptr()) {
0846     double x = ns.attr<double>(translation, _U(x));
0847     double y = ns.attr<double>(translation, _U(y));
0848     double z = ns.attr<double>(translation, _U(z));
0849     pos = Position(x, y, z);
0850   }
0851   if (rotation.ptr()) {
0852     double x = ns.attr<double>(rotation, _U(x));
0853     double y = ns.attr<double>(rotation, _U(y));
0854     double z = ns.attr<double>(rotation, _U(z));
0855     rot = RotationZYX(z, y, x);
0856   } else if (refRotation.ptr()) {
0857     string rotName = ns.prepend(refRotation.nameStr());
0858     rot = ns.rotation(rotName);
0859   } else if (refReflectionRotation.ptr()) {
0860     string rotName = ns.prepend(refReflectionRotation.nameStr());
0861     rot = ns.rotation(rotName);
0862   }
0863   *tr = Transform3D(rot, pos);
0864 }
0865 
0866 static void placeAssembly(Volume* parentPtr,
0867                           const string& parentName,
0868                           Volume* childPtr,
0869                           const string& childName,
0870                           int copy,
0871                           const Transform3D& transform,
0872                           cms::DDNamespace& ns) {
0873 #ifdef EDM_ML_DEBUG
0874 
0875   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0876            "DD4CMS",
0877            "+++ Parent vol: %-24s Child: %-32s, copy:%d",
0878            parentName.c_str(),
0879            childName.c_str(),
0880            copy);
0881 
0882 #endif
0883 
0884   TGeoShape* shape = (*childPtr)->GetShape();
0885   // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
0886   if (shape->IsA() == TGeoShapeAssembly::Class()) {
0887     TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
0888     if (std::fabs(as->GetDX()) < numeric_limits<double>::epsilon() &&
0889         std::fabs(as->GetDY()) < numeric_limits<double>::epsilon() &&
0890         std::fabs(as->GetDZ()) < numeric_limits<double>::epsilon()) {
0891       as->NeedsBBoxRecompute();
0892       as->ComputeBBox();
0893     }
0894   }
0895   if (ns.context()->validate) {
0896     TGeoNode* n;
0897     TString nam_id = TString::Format("%s_%d", (*childPtr)->GetName(), copy);
0898     n = static_cast<TGeoNode*>((*parentPtr)->GetNode(nam_id));
0899     if (n != nullptr) {
0900       printout(ERROR, "PlacedVolume", "++ Attempt to add already existing node %s", (const char*)nam_id);
0901       return;
0902     }
0903   }
0904 
0905   PlacedVolume pv;
0906   if ((*childPtr)->IsAssembly()) {
0907     pv = parentPtr->placeVolume(ns.assembly(childName), copy, transform);
0908   } else {
0909     pv = parentPtr->placeVolume(*childPtr, copy, transform);
0910   }
0911 
0912   if (!pv.isValid()) {
0913     printout(ERROR, "DD4CMS", "+++ Placement FAILED! Parent:%s Child:%s", parentName.c_str(), childName.c_str());
0914   }
0915 }
0916 
0917 /// Converter for <PosPart/> tags
0918 template <>
0919 void Converter<DDLPosPart>::operator()(xml_h element) const {
0920   cms::DDNamespace ns(_param<cms::DDParsingContext>());  //, element, true );
0921   xml_dim_t e(element);
0922   int copy = e.attr<int>(DD_CMU(copyNumber));
0923   string parentName = ns.prepend(ns.attr<string>(e.child(DD_CMU(rParent)), _U(name)));
0924   string childName = ns.prepend(ns.attr<string>(e.child(DD_CMU(rChild)), _U(name)));
0925   Transform3D transform;
0926   Converter<DDLTransform3D>(description, param, &transform)(element);
0927 
0928   Volume parent = ns.volume(parentName, false);
0929   Volume child = ns.volume(childName, false);
0930   Assembly parAsmb = ns.assembly(parentName, false);
0931   Assembly childAsmb = ns.assembly(childName, false);
0932 
0933 #ifdef EDM_ML_DEBUG
0934 
0935   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0936            "DD4CMS",
0937            "+++ %s Parent: %-24s [%s] Child: %-32s [%s] copy:%d",
0938            e.tag().c_str(),
0939            parentName.c_str(),
0940            parent.isValid() ? "VALID" : "INVALID",
0941            childName.c_str(),
0942            child.isValid() ? "VALID" : "INVALID",
0943            copy);
0944 
0945 #endif
0946 
0947   if (!parent.isValid() && !parAsmb.isValid() && strchr(parentName.c_str(), NAMESPACE_SEP) == nullptr) {
0948     parentName = ns.prepend(parentName);
0949     parAsmb = ns.assembly(parentName, false);
0950     if (!parAsmb.isValid())
0951       parent = ns.volume(parentName);
0952   }
0953 
0954   if (!child.isValid() && !childAsmb.isValid() && strchr(childName.c_str(), NAMESPACE_SEP) == nullptr) {
0955     childName = ns.prepend(childName);
0956     child = ns.volume(childName, false);
0957     childAsmb = ns.assembly(childName, false);
0958   }
0959   if (parAsmb.isValid() || childAsmb.isValid()) {
0960     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0961              "DD4CMS",
0962              "***** Placing assembly parent %s, child %s",
0963              parentName.c_str(),
0964              childName.c_str());
0965     Volume* parentPtr = parAsmb.isValid() ? &parAsmb : &parent;
0966     Volume* childPtr = childAsmb.isValid() ? &childAsmb : &child;
0967     placeAssembly(parentPtr, parentName, childPtr, childName, copy, transform, ns);
0968     return;
0969   }
0970 
0971 #ifdef EDM_ML_DEBUG
0972 
0973   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0974            "DD4CMS",
0975            "+++ %s Parent: %-24s [%s] Child: %-32s [%s] copy:%d",
0976            e.tag().c_str(),
0977            parentName.c_str(),
0978            parent.isValid() ? "VALID" : "INVALID",
0979            childName.c_str(),
0980            child.isValid() ? "VALID" : "INVALID",
0981            copy);
0982 
0983 #endif
0984 
0985   PlacedVolume pv;
0986   if (child.isValid()) {
0987     // FIXME: workaround for Reflection rotation
0988     // copy from DDCore/src/Volumes.cpp to replace
0989     // static PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform)
0990     if (!parent) {
0991       except("dd4hep", "Volume: Attempt to assign daughters to an invalid physical parent volume.");
0992     }
0993     if (!child) {
0994       except("dd4hep", "Volume: Attempt to assign an invalid physical daughter volume.");
0995     }
0996     TGeoShape* shape = child->GetShape();
0997     // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
0998     if (shape->IsA() == TGeoShapeAssembly::Class()) {
0999       TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
1000       if (std::fabs(as->GetDX()) < numeric_limits<double>::epsilon() &&
1001           std::fabs(as->GetDY()) < numeric_limits<double>::epsilon() &&
1002           std::fabs(as->GetDZ()) < numeric_limits<double>::epsilon()) {
1003         as->NeedsBBoxRecompute();
1004         as->ComputeBBox();
1005       }
1006     }
1007     TGeoNode* n;
1008     TString nam_id = TString::Format("%s_%d", child->GetName(), copy);
1009     if (ns.context()->validate) {
1010       n = static_cast<TGeoNode*>(parent->GetNode(nam_id));
1011       if (n != nullptr) {
1012         printout(ERROR, "PlacedVolume", "++ Attempt to add already existing node %s", (const char*)nam_id);
1013       }
1014     }
1015 
1016     Rotation3D rot(transform.Rotation());
1017     Translation3D trans(transform.Translation());
1018     double x, y, z;
1019     trans.GetComponents(x, y, z);
1020     Position pos(x, y, z);
1021     parent->AddNode(child, copy, createPlacement(rot, pos));
1022 
1023     n = static_cast<TGeoNode*>(parent->GetNodes()->Last());
1024     assert(n->GetName() == nam_id);
1025     n->TGeoNode::SetUserExtension(new PlacedVolume::Object());
1026     pv = PlacedVolume(n);
1027   }
1028   if (!pv.isValid()) {
1029     printout(ERROR,
1030              "DD4CMS",
1031              "+++ Placement FAILED! Parent:%s Child:%s Valid:%s",
1032              parent.name(),
1033              childName.c_str(),
1034              yes_no(child.isValid()));
1035   }
1036 }
1037 
1038 /// Converter for <PartSelector/> tags
1039 template <>
1040 void Converter<PartSelector>::operator()(xml_h element) const {
1041   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1042   cms::DDParsingContext* const context = ns.context();
1043   dd4hep::SpecParRegistry& registry = *context->description.extension<dd4hep::SpecParRegistry>();
1044   xml_dim_t e(element);
1045   xml_dim_t specPar = e.parent();
1046   string specParName = specPar.attr<string>(_U(name));
1047   string path = e.attr<string>(DD_CMU(path));
1048 
1049 #ifdef EDM_ML_DEBUG
1050 
1051   printout(ns.context()->debug_specpars ? ALWAYS : DEBUG,
1052            "DD4CMS",
1053            "+++ PartSelector for %s path: %s",
1054            specParName.c_str(),
1055            path.c_str());
1056 
1057 #endif
1058 
1059   size_t pos = std::string::npos;
1060   if ((pos = path.find("//.*:")) != std::string::npos) {
1061     path.erase(pos + 2, 3);
1062   }
1063   registry.specpars[specParName].paths.emplace_back(std::move(path));
1064 }
1065 
1066 /// Converter for <Parameter/> tags
1067 template <>
1068 void Converter<Parameter>::operator()(xml_h element) const {
1069   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1070   cms::DDParsingContext* const context = ns.context();
1071   dd4hep::SpecParRegistry& registry = *context->description.extension<dd4hep::SpecParRegistry>();
1072   xml_dim_t e(element);
1073   xml_dim_t specPar = e.parent();
1074   xml_dim_t specParSect = specPar.parent();
1075   string specParName = specPar.attr<string>(_U(name));
1076   string name = e.nameStr();
1077   string value = e.attr<string>(DD_CMU(value));
1078   bool eval = specParSect.hasAttr(_U(eval)) ? specParSect.attr<bool>(_U(eval)) : false;
1079   eval = specPar.hasAttr(_U(eval)) ? specPar.attr<bool>(_U(eval)) : eval;
1080   eval = e.hasAttr(_U(eval)) ? e.attr<bool>(_U(eval)) : eval;
1081 
1082   string type = eval ? "number" : "string";
1083 
1084 #ifdef EDM_ML_DEBUG
1085 
1086   printout(ns.context()->debug_specpars ? ALWAYS : DEBUG,
1087            "DD4CMS",
1088            "+++ Parameter for %s: %s value %s is a %s",
1089            specParName.c_str(),
1090            name.c_str(),
1091            value.c_str(),
1092            type.c_str());
1093 
1094 #endif
1095 
1096   size_t idx = value.find('[');
1097   if (idx == string::npos && type == "number") {
1098     registry.specpars[specParName].numpars[name].emplace_back(dd4hep::_toDouble(value));
1099     return;
1100   }
1101   if (idx == string::npos || type == "string") {
1102     registry.specpars[specParName].spars[name].emplace_back(std::move(value));
1103     return;
1104   }
1105 
1106   while (idx != string::npos) {
1107     ++idx;
1108     size_t idp = value.find(':', idx);
1109     size_t idq = value.find(']', idx);
1110     if (idp == string::npos || idp > idq)
1111       value.insert(idx, ns.name());
1112     else if (idp != string::npos && idp < idq)
1113       value[idp] = NAMESPACE_SEP;
1114     idx = value.find('[', idx);
1115   }
1116 
1117   string rep;
1118   string& v = value;
1119   size_t idq;
1120   for (idx = v.find('[', 0); idx != string::npos; idx = v.find('[', idx + 1)) {
1121     idq = v.find(']', idx + 1);
1122     rep = v.substr(idx + 1, idq - idx - 1);
1123     auto r = ns.context()->description.constants().find(rep);
1124     if (r != ns.context()->description.constants().end()) {
1125       rep = "(" + r->second->type + ")";
1126       v.replace(idx, idq - idx + 1, rep);
1127     }
1128   }
1129   registry.specpars[specParName].numpars[name].emplace_back(dd4hep::_toDouble(value));
1130 }
1131 
1132 template <typename TYPE>
1133 static void convert_boolean(cms::DDParsingContext* context, xml_h element) {
1134   cms::DDNamespace ns(context);
1135   xml_dim_t e(element);
1136   string nam = e.nameStr();
1137   string solidName[2];
1138   Solid solids[2];
1139   Solid boolean;
1140   int cnt = 0;
1141   if (e.hasChild(DD_CMU(rSolid))) {
1142     for (xml_coll_t c(element, DD_CMU(rSolid)); cnt < 2 && c; ++c, ++cnt) {
1143       solidName[cnt] = c.attr<string>(_U(name));
1144       solids[cnt] = ns.solid(c.attr<string>(_U(name)));
1145     }
1146   } else {
1147     solidName[0] = e.attr<string>(DD_CMU(firstSolid));
1148     if ((solids[0] = ns.solid(e.attr<string>(DD_CMU(firstSolid)))).isValid())
1149       ++cnt;
1150     solidName[1] = e.attr<string>(DD_CMU(secondSolid));
1151     if ((solids[1] = ns.solid(e.attr<string>(DD_CMU(secondSolid)))).isValid())
1152       ++cnt;
1153   }
1154   if (cnt != 2) {
1155     except("DD4CMS", "+++ Failed to create boolean solid %s. Found only %d parts.", nam.c_str(), cnt);
1156   }
1157 
1158 #ifdef EDM_ML_DEBUG
1159 
1160   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1161            "DD4CMS",
1162            "+++ BooleanSolid: %s Left: %-32s Right: %-32s",
1163            nam.c_str(),
1164            ((solids[0].ptr() == nullptr) ? solidName[0].c_str() : solids[0]->GetName()),
1165            ((solids[1].ptr() == nullptr) ? solidName[1].c_str() : solids[1]->GetName()));
1166 
1167 #endif
1168 
1169   if (solids[0].isValid() && solids[1].isValid()) {
1170     Transform3D trafo;
1171     Converter<DDLTransform3D>(context->description, context, &trafo)(element);
1172     boolean = TYPE(solids[0], solids[1], trafo);
1173   } else {
1174     // Register it for later processing
1175     Transform3D trafo;
1176     Converter<DDLTransform3D>(context->description, context, &trafo)(element);
1177     ns.context()->unresolvedShapes.emplace(nam,
1178                                            DDParsingContext::BooleanShape<TYPE>(solidName[0], solidName[1], trafo));
1179     if (solids[0].isValid() == false) {
1180       printout(ERROR, "DD4CMS", "++ Solid not defined yet: %s", solidName[0].c_str());
1181     }
1182     if (solids[1].isValid() == false) {
1183       printout(ERROR, "DD4CMS", "++ Solid not defined yet: %s", solidName[1].c_str());
1184     }
1185     printout(ERROR, "DD4CMS", "++ Re-order XML files to prevent references to undefined solids");
1186   }
1187   if (!boolean.isValid()) {
1188     // Delay processing the shape
1189     ns.context()->shapes.emplace(nam, dd4hep::Solid(nullptr));
1190   } else
1191     ns.addSolid(nam, boolean);
1192 }
1193 
1194 /// Converter for <UnionSolid/> tags
1195 template <>
1196 void Converter<DDLUnionSolid>::operator()(xml_h element) const {
1197   convert_boolean<UnionSolid>(_param<cms::DDParsingContext>(), element);
1198 }
1199 
1200 /// Converter for <SubtractionSolid/> tags
1201 template <>
1202 void Converter<DDLSubtractionSolid>::operator()(xml_h element) const {
1203   convert_boolean<SubtractionSolid>(_param<cms::DDParsingContext>(), element);
1204 }
1205 
1206 /// Converter for <IntersectionSolid/> tags
1207 template <>
1208 void Converter<DDLIntersectionSolid>::operator()(xml_h element) const {
1209   convert_boolean<IntersectionSolid>(_param<cms::DDParsingContext>(), element);
1210 }
1211 
1212 /// Converter for <Polycone/> tags
1213 template <>
1214 void Converter<DDLPolycone>::operator()(xml_h element) const {
1215   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1216   xml_dim_t e(element);
1217   string nam = e.nameStr();
1218   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1219   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1220   vector<double> z, rmin, rmax, r;
1221 
1222   for (xml_coll_t rzpoint(element, DD_CMU(RZPoint)); rzpoint; ++rzpoint) {
1223     z.emplace_back(ns.attr<double>(rzpoint, _U(z)));
1224     r.emplace_back(ns.attr<double>(rzpoint, _U(r)));
1225   }
1226   if (z.empty()) {
1227     for (xml_coll_t zplane(element, DD_CMU(ZSection)); zplane; ++zplane) {
1228       rmin.emplace_back(ns.attr<double>(zplane, DD_CMU(rMin)));
1229       rmax.emplace_back(ns.attr<double>(zplane, DD_CMU(rMax)));
1230       z.emplace_back(ns.attr<double>(zplane, _U(z)));
1231     }
1232 
1233 #ifdef EDM_ML_DEBUG
1234 
1235     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1236              "DD4CMS",
1237              "+   Polycone: startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]  %4ld z-planes",
1238              startPhi,
1239              deltaPhi,
1240              z.size());
1241 
1242 #endif
1243 
1244     ns.addSolid(nam, Polycone(startPhi, deltaPhi, rmin, rmax, z));
1245   } else {
1246 #ifdef EDM_ML_DEBUG
1247 
1248     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1249              "DD4CMS",
1250              "+   Polycone: startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]  %4ld z-planes and %4ld radii",
1251              startPhi,
1252              deltaPhi,
1253              z.size(),
1254              r.size());
1255 
1256 #endif
1257 
1258     ns.addSolid(nam, Polycone(startPhi, deltaPhi, r, z));
1259   }
1260 }
1261 
1262 /// Converter for <ExtrudedPolygon/> tags
1263 template <>
1264 void Converter<DDLExtrudedPolygon>::operator()(xml_h element) const {
1265   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1266   xml_dim_t e(element);
1267   string nam = e.nameStr();
1268   vector<double> pt_x, pt_y, sec_x, sec_y, sec_z, sec_scale;
1269 
1270   for (xml_coll_t sec(element, DD_CMU(ZXYSection)); sec; ++sec) {
1271     sec_z.emplace_back(ns.attr<double>(sec, _U(z)));
1272     sec_x.emplace_back(ns.attr<double>(sec, _U(x)));
1273     sec_y.emplace_back(ns.attr<double>(sec, _U(y)));
1274     sec_scale.emplace_back(ns.attr<double>(sec, DD_CMU(scale), 1.0));
1275   }
1276   for (xml_coll_t pt(element, DD_CMU(XYPoint)); pt; ++pt) {
1277     pt_x.emplace_back(ns.attr<double>(pt, _U(x)));
1278     pt_y.emplace_back(ns.attr<double>(pt, _U(y)));
1279   }
1280 
1281 #ifdef EDM_ML_DEBUG
1282 
1283   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1284            "DD4CMS",
1285            "+   ExtrudedPolygon: %4ld points %4ld zxy sections",
1286            pt_x.size(),
1287            sec_z.size());
1288 
1289 #endif
1290 
1291   ns.addSolid(nam, ExtrudedPolygon(pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale));
1292 }
1293 
1294 /// Converter for <Polyhedra/> tags
1295 template <>
1296 void Converter<DDLPolyhedra>::operator()(xml_h element) const {
1297   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1298   xml_dim_t e(element);
1299   string nam = e.nameStr();
1300   double numSide = ns.attr<int>(e, DD_CMU(numSide));
1301   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1302   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1303   vector<double> z, rmin, rmax;
1304 
1305   for (xml_coll_t zplane(element, DD_CMU(RZPoint)); zplane; ++zplane) {
1306     rmin.emplace_back(0.0);
1307     rmax.emplace_back(ns.attr<double>(zplane, _U(r)));
1308     z.emplace_back(ns.attr<double>(zplane, _U(z)));
1309   }
1310   for (xml_coll_t zplane(element, DD_CMU(ZSection)); zplane; ++zplane) {
1311     rmin.emplace_back(ns.attr<double>(zplane, DD_CMU(rMin)));
1312     rmax.emplace_back(ns.attr<double>(zplane, DD_CMU(rMax)));
1313     z.emplace_back(ns.attr<double>(zplane, _U(z)));
1314   }
1315 
1316 #ifdef EDM_ML_DEBUG
1317 
1318   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1319            "DD4CMS",
1320            "+   Polyhedra:startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]  %4d sides %4ld z-planes",
1321            startPhi,
1322            deltaPhi,
1323            numSide,
1324            z.size());
1325 
1326 #endif
1327 
1328   ns.addSolid(nam, Polyhedra(numSide, startPhi, deltaPhi, z, rmin, rmax));
1329 }
1330 
1331 /// Converter for <Sphere/> tags
1332 template <>
1333 void Converter<DDLSphere>::operator()(xml_h element) const {
1334   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1335   xml_dim_t e(element);
1336   string nam = e.nameStr();
1337   double rinner = ns.attr<double>(e, DD_CMU(innerRadius));
1338   double router = ns.attr<double>(e, DD_CMU(outerRadius));
1339   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1340   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1341   double startTheta = ns.attr<double>(e, DD_CMU(startTheta));
1342   double deltaTheta = ns.attr<double>(e, DD_CMU(deltaTheta));
1343 
1344 #ifdef EDM_ML_DEBUG
1345 
1346   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1347            "DD4CMS",
1348            "+   Sphere:   r_inner=%8.3f [cm] r_outer=%8.3f [cm]"
1349            " startPhi=%8.3f [rad] deltaPhi=%8.3f startTheta=%8.3f delteTheta=%8.3f [rad]",
1350            rinner / dd4hep::cm,
1351            router / dd4hep::cm,
1352            startPhi,
1353            deltaPhi,
1354            startTheta,
1355            deltaTheta);
1356 
1357 #endif
1358 
1359   ns.addSolid(nam, Sphere(rinner, router, startTheta, deltaTheta, startPhi, deltaPhi));
1360 }
1361 
1362 /// Converter for <Torus/> tags
1363 template <>
1364 void Converter<DDLTorus>::operator()(xml_h element) const {
1365   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1366   xml_dim_t e(element);
1367   string nam = e.nameStr();
1368   double r = ns.attr<double>(e, DD_CMU(torusRadius));
1369   double rinner = ns.attr<double>(e, DD_CMU(innerRadius));
1370   double router = ns.attr<double>(e, DD_CMU(outerRadius));
1371   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1372   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1373 
1374 #ifdef EDM_ML_DEBUG
1375 
1376   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1377            "DD4CMS",
1378            "+   Torus:    r=%10.3f [cm] r_inner=%10.3f [cm] r_outer=%10.3f [cm]"
1379            " startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]",
1380            r / dd4hep::cm,
1381            rinner / dd4hep::cm,
1382            router / dd4hep::cm,
1383            startPhi,
1384            deltaPhi);
1385 
1386 #endif
1387 
1388   ns.addSolid(nam, Torus(r, rinner, router, startPhi, deltaPhi));
1389 }
1390 
1391 /// Converter for <Pseudotrap/> tags
1392 template <>
1393 void Converter<DDLPseudoTrap>::operator()(xml_h element) const {
1394   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1395   xml_dim_t e(element);
1396   string nam = e.nameStr();
1397   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1398   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1399   double dx2 = ns.attr<double>(e, DD_CMU(dx2));
1400   double dy2 = ns.attr<double>(e, DD_CMU(dy2));
1401   double dz = ns.attr<double>(e, _U(dz));
1402   double r = ns.attr<double>(e, _U(radius));
1403   bool atMinusZ = ns.attr<bool>(e, DD_CMU(atMinusZ));
1404 
1405 #ifdef EDM_ML_DEBUG
1406 
1407   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1408            "DD4CMS",
1409            "+   Pseudotrap:  dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2=%.3f dy2=%.3f radius:%.3f atMinusZ:%s",
1410            dz / dd4hep::cm,
1411            dx1 / dd4hep::cm,
1412            dy1 / dd4hep::cm,
1413            dx2 / dd4hep::cm,
1414            dy2 / dd4hep::cm,
1415            r / dd4hep::cm,
1416            yes_no(atMinusZ));
1417 
1418 #endif
1419 
1420   ns.addSolid(nam, PseudoTrap(dx1, dx2, dy1, dy2, dz, r, atMinusZ));
1421 }
1422 
1423 /// Converter for <Trapezoid/> tags
1424 template <>
1425 void Converter<DDLTrapezoid>::operator()(xml_h element) const {
1426   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1427   xml_dim_t e(element);
1428   string nam = e.nameStr();
1429   double dz = ns.attr<double>(e, _U(dz));
1430   double alp1 = ns.attr<double>(e, DD_CMU(alp1));
1431   double bl1 = ns.attr<double>(e, DD_CMU(bl1));
1432   double tl1 = ns.attr<double>(e, DD_CMU(tl1));
1433   double h1 = ns.attr<double>(e, DD_CMU(h1));
1434   double alp2 = ns.attr<double>(e, DD_CMU(alp2));
1435   double bl2 = ns.attr<double>(e, DD_CMU(bl2));
1436   double tl2 = ns.attr<double>(e, DD_CMU(tl2));
1437   double h2 = ns.attr<double>(e, DD_CMU(h2));
1438   double phi = ns.attr<double>(e, _U(phi), 0.0);
1439   double theta = ns.attr<double>(e, _U(theta), 0.0);
1440 
1441 #ifdef EDM_ML_DEBUG
1442 
1443   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1444            "DD4CMS",
1445            "+   Trapezoid:  dz=%10.3f [cm] alp1:%.3f bl1=%.3f tl1=%.3f alp2=%.3f bl2=%.3f tl2=%.3f h2=%.3f phi=%.3f "
1446            "theta=%.3f",
1447            dz / dd4hep::cm,
1448            alp1,
1449            bl1 / dd4hep::cm,
1450            tl1 / dd4hep::cm,
1451            h1 / dd4hep::cm,
1452            alp2,
1453            bl2 / dd4hep::cm,
1454            tl2 / dd4hep::cm,
1455            h2 / dd4hep::cm,
1456            phi,
1457            theta);
1458 
1459 #endif
1460 
1461   ns.addSolid(nam, Trap(dz, theta, phi, h1, bl1, tl1, alp1, h2, bl2, tl2, alp2));
1462 }
1463 
1464 /// Converter for <Trd1/> tags
1465 template <>
1466 void Converter<DDLTrd1>::operator()(xml_h element) const {
1467   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1468   xml_dim_t e(element);
1469   string nam = e.nameStr();
1470   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1471   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1472   double dx2 = ns.attr<double>(e, DD_CMU(dx2), 0.0);
1473   double dy2 = ns.attr<double>(e, DD_CMU(dy2), dy1);
1474   double dz = ns.attr<double>(e, DD_CMU(dz));
1475   if (dy1 == dy2) {
1476 #ifdef EDM_ML_DEBUG
1477 
1478     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1479              "DD4CMS",
1480              "+   Trd1:       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1481              dz / dd4hep::cm,
1482              dx1 / dd4hep::cm,
1483              dy1 / dd4hep::cm,
1484              dx2 / dd4hep::cm,
1485              dy2 / dd4hep::cm);
1486 
1487 #endif
1488 
1489     ns.addSolid(nam, Trd1(dx1, dx2, dy1, dz));
1490   } else {
1491 #ifdef EDM_ML_DEBUG
1492 
1493     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1494              "DD4CMS",
1495              "+   Trd1(which is actually Trd2):       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1496              dz / dd4hep::cm,
1497              dx1 / dd4hep::cm,
1498              dy1 / dd4hep::cm,
1499              dx2 / dd4hep::cm,
1500              dy2 / dd4hep::cm);
1501 
1502 #endif
1503 
1504     ns.addSolid(nam, Trd2(dx1, dx2, dy1, dy2, dz));
1505   }
1506 }
1507 
1508 /// Converter for <Trd2/> tags
1509 template <>
1510 void Converter<DDLTrd2>::operator()(xml_h element) const {
1511   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1512   xml_dim_t e(element);
1513   string nam = e.nameStr();
1514   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1515   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1516   double dx2 = ns.attr<double>(e, DD_CMU(dx2), 0.0);
1517   double dy2 = ns.attr<double>(e, DD_CMU(dy2), dy1);
1518   double dz = ns.attr<double>(e, DD_CMU(dz));
1519 
1520 #ifdef EDM_ML_DEBUG
1521 
1522   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1523            "DD4CMS",
1524            "+   Trd1:       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1525            dz / dd4hep::cm,
1526            dx1 / dd4hep::cm,
1527            dy1 / dd4hep::cm,
1528            dx2 / dd4hep::cm,
1529            dy2 / dd4hep::cm);
1530 
1531 #endif
1532 
1533   ns.addSolid(nam, Trd2(dx1, dx2, dy1, dy2, dz));
1534 }
1535 
1536 /// Converter for <Tubs/> tags
1537 template <>
1538 void Converter<DDLTubs>::operator()(xml_h element) const {
1539   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1540   xml_dim_t e(element);
1541   string nam = e.nameStr();
1542   double dz = ns.attr<double>(e, DD_CMU(dz));
1543   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1544   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1545   double startPhi = ns.attr<double>(e, DD_CMU(startPhi), 0.0);
1546   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi), 2 * M_PI);
1547 
1548 #ifdef EDM_ML_DEBUG
1549 
1550   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1551            "DD4CMS",
1552            "+   Tubs:     dz=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1553            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]",
1554            dz / dd4hep::cm,
1555            rmin / dd4hep::cm,
1556            rmax / dd4hep::cm,
1557            startPhi,
1558            deltaPhi);
1559 
1560 #endif
1561 
1562   ns.addSolid(nam, Tube(rmin, rmax, dz, startPhi, startPhi + deltaPhi));
1563 }
1564 
1565 /// Converter for <CutTubs/> tags
1566 template <>
1567 void Converter<DDLCutTubs>::operator()(xml_h element) const {
1568   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1569   xml_dim_t e(element);
1570   string nam = e.nameStr();
1571   double dz = ns.attr<double>(e, DD_CMU(dz));
1572   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1573   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1574   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1575   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1576   double lx = ns.attr<double>(e, DD_CMU(lx));
1577   double ly = ns.attr<double>(e, DD_CMU(ly));
1578   double lz = ns.attr<double>(e, DD_CMU(lz));
1579   double tx = ns.attr<double>(e, DD_CMU(tx));
1580   double ty = ns.attr<double>(e, DD_CMU(ty));
1581   double tz = ns.attr<double>(e, DD_CMU(tz));
1582 
1583 #ifdef EDM_ML_DEBUG
1584 
1585   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1586            "DD4CMS",
1587            "+   CutTube:  dz=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1588            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]...",
1589            dz / dd4hep::cm,
1590            rmin / dd4hep::cm,
1591            rmax / dd4hep::cm,
1592            startPhi,
1593            deltaPhi);
1594 
1595 #endif
1596 
1597   ns.addSolid(nam, CutTube(rmin, rmax, dz, startPhi, startPhi + deltaPhi, lx, ly, lz, tx, ty, tz));
1598 }
1599 
1600 /// Converter for <TruncTubs/> tags
1601 template <>
1602 void Converter<DDLTruncTubs>::operator()(xml_h element) const {
1603   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1604   xml_dim_t e(element);
1605   string nam = e.nameStr();
1606   double zhalf = ns.attr<double>(e, DD_CMU(zHalf));
1607   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1608   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1609   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1610   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1611   double cutAtStart = ns.attr<double>(e, DD_CMU(cutAtStart));
1612   double cutAtDelta = ns.attr<double>(e, DD_CMU(cutAtDelta));
1613   bool cutInside = ns.attr<bool>(e, DD_CMU(cutInside));
1614 
1615 #ifdef EDM_ML_DEBUG
1616 
1617   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1618            "DD4CMS",
1619            "+   TruncTube:zHalf=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1620            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad] atStart=%8.3f [cm] atDelta=%8.3f [cm] inside:%s",
1621            zhalf / dd4hep::cm,
1622            rmin / dd4hep::cm,
1623            rmax / dd4hep::cm,
1624            startPhi,
1625            deltaPhi,
1626            cutAtStart / dd4hep::cm,
1627            cutAtDelta / dd4hep::cm,
1628            yes_no(cutInside));
1629 
1630 #endif
1631 
1632   ns.addSolid(nam, TruncatedTube(zhalf, rmin, rmax, startPhi, deltaPhi, cutAtStart, cutAtDelta, cutInside));
1633 }
1634 
1635 /// Converter for <EllipticalTube/> tags
1636 template <>
1637 void Converter<DDLEllipticalTube>::operator()(xml_h element) const {
1638   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1639   xml_dim_t e(element);
1640   string nam = e.nameStr();
1641   double dx = ns.attr<double>(e, DD_CMU(xSemiAxis));
1642   double dy = ns.attr<double>(e, DD_CMU(ySemiAxis));
1643   double dz = ns.attr<double>(e, DD_CMU(zHeight));
1644 
1645 #ifdef EDM_ML_DEBUG
1646 
1647   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1648            "DD4CMS",
1649            "+   EllipticalTube xSemiAxis=%8.3f [cm] ySemiAxis=%8.3f [cm] zHeight=%8.3f [cm]",
1650            dx / dd4hep::cm,
1651            dy / dd4hep::cm,
1652            dz / dd4hep::cm);
1653 
1654 #endif
1655 
1656   ns.addSolid(nam, EllipticalTube(dx, dy, dz));
1657 }
1658 
1659 /// Converter for <Cone/> tags
1660 template <>
1661 void Converter<DDLCone>::operator()(xml_h element) const {
1662   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1663   xml_dim_t e(element);
1664   string nam = e.nameStr();
1665   double dz = ns.attr<double>(e, DD_CMU(dz));
1666   double rmin1 = ns.attr<double>(e, DD_CMU(rMin1));
1667   double rmin2 = ns.attr<double>(e, DD_CMU(rMin2));
1668   double rmax1 = ns.attr<double>(e, DD_CMU(rMax1));
1669   double rmax2 = ns.attr<double>(e, DD_CMU(rMax2));
1670   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1671   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1672   double phi2 = startPhi + deltaPhi;
1673 
1674 #ifdef EDM_ML_DEBUG
1675 
1676   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1677            "DD4CMS",
1678            "+   Cone:     dz=%8.3f [cm]"
1679            " rmin1=%8.3f [cm] rmax1=%8.3f [cm]"
1680            " rmin2=%8.3f [cm] rmax2=%8.3f [cm]"
1681            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]",
1682            dz / dd4hep::cm,
1683            rmin1 / dd4hep::cm,
1684            rmax1 / dd4hep::cm,
1685            rmin2 / dd4hep::cm,
1686            rmax2 / dd4hep::cm,
1687            startPhi,
1688            deltaPhi);
1689 
1690 #endif
1691 
1692   ns.addSolid(nam, ConeSegment(dz, rmin1, rmax1, rmin2, rmax2, startPhi, phi2));
1693 }
1694 
1695 /// Converter for <Shapeless/> tags
1696 template <>
1697 void Converter<DDLShapeless>::operator()(xml_h element) const {
1698   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1699   xml_dim_t e(element);
1700   string nam = e.nameStr();
1701 
1702 #ifdef EDM_ML_DEBUG
1703 
1704   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1705            "DD4CMS",
1706            "+   Shapeless: THIS ONE CAN ONLY BE USED AT THE VOLUME LEVEL -> Shapeless: %s",
1707            nam.c_str());
1708 
1709 #endif
1710 
1711   ns.addSolid(nam, Box(1, 1, 1));
1712 }
1713 
1714 /// Converter for <Assembly/> tags
1715 template <>
1716 void Converter<DDLAssembly>::operator()(xml_h element) const {
1717   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1718   xml_dim_t e(element);
1719   string nam = e.nameStr();
1720 
1721 #ifdef EDM_ML_DEBUG
1722   printout(
1723       ns.context()->debug_shapes ? ALWAYS : DEBUG, "DD4CMS", "+   Assembly: Adding solid -> Assembly: %s", nam.c_str());
1724 #endif
1725 
1726   ns.addAssemblySolid(nam);
1727 }
1728 
1729 /// Converter for <Box/> tags
1730 template <>
1731 void Converter<DDLBox>::operator()(xml_h element) const {
1732   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1733   xml_dim_t e(element);
1734   string nam = e.nameStr();
1735   double dx = ns.attr<double>(e, DD_CMU(dx));
1736   double dy = ns.attr<double>(e, DD_CMU(dy));
1737   double dz = ns.attr<double>(e, DD_CMU(dz));
1738 
1739 #ifdef EDM_ML_DEBUG
1740 
1741   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1742            "DD4CMS",
1743            "+   Box:      dx=%10.3f [cm] dy=%10.3f [cm] dz=%10.3f [cm]",
1744            dx / dd4hep::cm,
1745            dy / dd4hep::cm,
1746            dz / dd4hep::cm);
1747 
1748 #endif
1749 
1750   ns.addSolid(nam, Box(dx, dy, dz));
1751 }
1752 
1753 /// DD4hep specific Converter for <Include/> tags: process only the constants
1754 template <>
1755 void Converter<include_load>::operator()(xml_h element) const {
1756   string fname = element.attr<string>(_U(ref));
1757   edm::FileInPath fp(fname);
1758   xml::Document doc;
1759   doc = xml::DocumentHandler().load(fp.fullPath());
1760 
1761 #ifdef EDM_ML_DEBUG
1762 
1763   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
1764            "DD4CMS",
1765            "+++ Processing the CMS detector description %s",
1766            fname.c_str());
1767 
1768 #endif
1769 
1770   _option<DDRegistry>()->includes.emplace_back(doc);
1771 }
1772 
1773 /// DD4hep specific Converter for <Include/> tags: process only the constants
1774 template <>
1775 void Converter<include_unload>::operator()(xml_h element) const {
1776   string fname = xml::DocumentHandler::system_path(element);
1777   xml::DocumentHolder(xml_elt_t(element).document()).assign(nullptr);
1778 
1779 #ifdef EDM_ML_DEBUG
1780 
1781   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
1782            "DD4CMS",
1783            "+++ Finished processing %s",
1784            fname.c_str());
1785 #endif
1786 }
1787 
1788 /// DD4hep specific Converter for <Include/> tags: process only the constants
1789 template <>
1790 void Converter<include_constants>::operator()(xml_h element) const {
1791   xml_coll_t(element, DD_CMU(ConstantsSection)).for_each(Converter<ConstantsSection>(description, param, optional));
1792 }
1793 
1794 namespace {
1795 
1796   //  The meaning of the axis index is the following:
1797   //    for all volumes having shapes like box, trd1, trd2, trap, gtra or para - 1,2,3 means X,Y,Z;
1798   //    for tube, tubs, cone, cons - 1 means Rxy, 2 means phi and 3 means Z;
1799   //    for pcon and pgon - 2 means phi and 3 means Z;
1800   //    for spheres 1 means R and 2 means phi.
1801 
1802   enum class DDAxes { x = 1, y = 2, z = 3, rho = 1, phi = 2, undefined };
1803   const std::map<std::string, DDAxes> axesmap{{"x", DDAxes::x},
1804                                               {"y", DDAxes::y},
1805                                               {"z", DDAxes::z},
1806                                               {"rho", DDAxes::rho},
1807                                               {"phi", DDAxes::phi},
1808                                               {"undefined", DDAxes::undefined}};
1809 }  // namespace
1810 
1811 /// Converter for <Division/> tags
1812 template <>
1813 void Converter<DDLDivision>::operator()(xml_h element) const {
1814   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
1815   xml_dim_t e(element);
1816   string childName = e.nameStr();
1817   if (strchr(childName.c_str(), NAMESPACE_SEP) == nullptr)
1818     childName = ns.prepend(childName);
1819 
1820   string parentName = ns.attr<string>(e, DD_CMU(parent));
1821   if (strchr(parentName.c_str(), NAMESPACE_SEP) == nullptr)
1822     parentName = ns.prepend(parentName);
1823   string axis = ns.attr<string>(e, DD_CMU(axis));
1824 
1825   // If you divide a tube of 360 degrees the offset displaces
1826   // the starting angle, but you still fill the 360 degrees
1827   double offset = e.hasAttr(DD_CMU(offset)) ? ns.attr<double>(e, DD_CMU(offset)) : 0e0;
1828   double width = e.hasAttr(DD_CMU(width)) ? ns.attr<double>(e, DD_CMU(width)) : 0e0;
1829   int nReplicas = e.hasAttr(DD_CMU(nReplicas)) ? ns.attr<int>(e, DD_CMU(nReplicas)) : 0;
1830 
1831 #ifdef EDM_ML_DEBUG
1832 
1833   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1834            "DD4CMS",
1835            "+++ Start executing Division of %s along %s (%d) with offset %6.3f and %6.3f to produce %s....",
1836            parentName.c_str(),
1837            axis.c_str(),
1838            axesmap.at(axis),
1839            offset,
1840            width,
1841            childName.c_str());
1842 
1843 #endif
1844 
1845   Volume parent = ns.volume(parentName);
1846 
1847   const TGeoShape* shape = parent.solid();
1848   TClass* cl = shape->IsA();
1849   if (cl == TGeoTubeSeg::Class()) {
1850     const TGeoTubeSeg* sh = (const TGeoTubeSeg*)shape;
1851     double widthInDeg = convertRadToDeg(width);
1852     double startInDeg = convertRadToDeg(offset);
1853     int numCopies = (int)((sh->GetPhi2() - sh->GetPhi1()) / widthInDeg);
1854 
1855 #ifdef EDM_ML_DEBUG
1856 
1857     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1858              "DD4CMS",
1859              "+++    ...divide %s along %s (%d) with offset %6.3f deg and %6.3f deg to produce %d copies",
1860              parent.solid().type(),
1861              axis.c_str(),
1862              axesmap.at(axis),
1863              startInDeg,
1864              widthInDeg,
1865              numCopies);
1866 
1867 #endif
1868 
1869     Volume child = parent.divide(childName, static_cast<int>(axesmap.at(axis)), numCopies, startInDeg, widthInDeg);
1870 
1871     ns.context()->volumes[childName] = child;
1872 
1873 #ifdef EDM_ML_DEBUG
1874 
1875     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1876              "DD4CMS",
1877              "+++ %s Parent: %-24s [%s] Child: %-32s [%s] is multivolume [%s]",
1878              e.tag().c_str(),
1879              parentName.c_str(),
1880              parent.isValid() ? "VALID" : "INVALID",
1881              child.name(),
1882              child.isValid() ? "VALID" : "INVALID",
1883              child->IsVolumeMulti() ? "YES" : "NO");
1884 #endif
1885 
1886   } else if (cl == TGeoTrd1::Class()) {
1887     double dy = static_cast<const TGeoTrd1*>(shape)->GetDy();
1888 
1889 #ifdef EDM_ML_DEBUG
1890 
1891     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1892              "DD4CMS",
1893              "+++    ...divide %s along %s (%d) with offset %6.3f cm and %6.3f cm to produce %d copies in %6.3f",
1894              parent.solid().type(),
1895              axis.c_str(),
1896              axesmap.at(axis),
1897              -dy + offset + width,
1898              width,
1899              nReplicas,
1900              dy);
1901 
1902 #endif
1903 
1904     Volume child = parent.divide(childName, static_cast<int>(axesmap.at(axis)), nReplicas, -dy + offset + width, width);
1905 
1906     ns.context()->volumes[childName] = child;
1907 
1908 #ifdef EDM_ML_DEBUG
1909 
1910     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1911              "DD4CMS",
1912              "+++ %s Parent: %-24s [%s] Child: %-32s [%s] is multivolume [%s]",
1913              e.tag().c_str(),
1914              parentName.c_str(),
1915              parent.isValid() ? "VALID" : "INVALID",
1916              child.name(),
1917              child.isValid() ? "VALID" : "INVALID",
1918              child->IsVolumeMulti() ? "YES" : "NO");
1919 
1920 #endif
1921   } else {
1922     printout(ERROR, "DD4CMS", "++ FAILED Division of a %s is not implemented yet!", parent.solid().type());
1923   }
1924 }
1925 
1926 /// Converter for <Algorithm/> tags
1927 template <>
1928 void Converter<DDLAlgorithm>::operator()(xml_h element) const {
1929   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1930   xml_dim_t e(element);
1931   string name = e.nameStr();
1932   size_t idx;
1933   string type = "DDCMS_" + ns.realName(name);
1934   while ((idx = type.find(NAMESPACE_SEP)) != string::npos)
1935     type[idx] = '_';
1936 
1937 #ifdef EDM_ML_DEBUG
1938 
1939   printout(
1940       ns.context()->debug_algorithms ? ALWAYS : DEBUG, "DD4CMS", "+++ Start executing algorithm %s....", type.c_str());
1941 
1942 #endif
1943 
1944   long ret = PluginService::Create<long>(type, &description, ns.context(), &element);
1945   if (ret == s_executed) {
1946 #ifdef EDM_ML_DEBUG
1947 
1948     printout(ns.context()->debug_algorithms ? ALWAYS : DEBUG,
1949 
1950              "DD4CMS",
1951              "+++ Executed algorithm: %08lX = %s",
1952              ret,
1953              name.c_str());
1954 
1955 #endif
1956     return;
1957   }
1958   printout(ERROR, "DD4CMS", "++ FAILED  NOT ADDING SUBDETECTOR %08lX = %s", ret, name.c_str());
1959 }
1960 
1961 template <class InputIt, class ForwardIt, class BinOp>
1962 void for_each_token(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last, BinOp binary_op) {
1963   while (first != last) {
1964     const auto pos = std::find_first_of(first, last, s_first, s_last);
1965     binary_op(first, pos);
1966     if (pos == last)
1967       break;
1968     first = std::next(pos);
1969   }
1970 }
1971 
1972 namespace {
1973 
1974   std::vector<string> splitString(const string& str, const string& delims = ",") {
1975     std::vector<string> output;
1976 
1977     for_each_token(cbegin(str), cend(str), cbegin(delims), cend(delims), [&output](auto first, auto second) {
1978       if (first != second) {
1979         if (string(first, second).front() == '[' && string(first, second).back() == ']') {
1980           first++;
1981           second--;
1982         }
1983         output.emplace_back(string(first, second));
1984       }
1985     });
1986     return output;
1987   }
1988 
1989   std::vector<double> splitNumeric(const string& str, const string& delims = ",") {
1990     std::vector<double> output;
1991 
1992     for_each_token(cbegin(str), cend(str), cbegin(delims), cend(delims), [&output](auto first, auto second) {
1993       if (first != second) {
1994         if (string(first, second).front() == '[' && string(first, second).back() == ']') {
1995           first++;
1996           second--;
1997         }
1998         output.emplace_back(dd4hep::_toDouble(string(first, second)));
1999       }
2000     });
2001     return output;
2002   }
2003 }  // namespace
2004 
2005 /// Converter for <Vector/> tags
2006 /// FIXME: Check if(parent() == "Algorithm" || parent() == "SpecPar")
2007 template <>
2008 void Converter<DDLVector>::operator()(xml_h element) const {
2009   cms::DDNamespace ns(_param<cms::DDParsingContext>());
2010   cms::DDParsingContext* const context = ns.context();
2011   DDVectorsMap* registry = context->description.extension<DDVectorsMap>();
2012   xml_dim_t e(element);
2013   string name = ns.prepend(e.nameStr());
2014   string type = ns.attr<string>(e, _U(type));
2015   string nEntries = ns.attr<string>(e, DD_CMU(nEntries));
2016   string val = e.text();
2017   val.erase(remove_if(val.begin(), val.end(), [](unsigned char x) { return isspace(x); }), val.end());
2018 
2019 #ifdef EDM_ML_DEBUG
2020 
2021   printout(ns.context()->debug_constants ? ALWAYS : DEBUG,
2022            "DD4CMS",
2023            "+++ Vector<%s>:  %s[%s]: %s",
2024            type.c_str(),
2025            name.c_str(),
2026            nEntries.c_str(),
2027            val.c_str());
2028 
2029 #endif
2030 
2031   try {
2032     std::vector<double> results = splitNumeric(val);
2033     registry->insert(
2034         {name,
2035          results});  //tbb::concurrent_vector<double, tbb::cache_aligned_allocator<double>>(results.begin(), results.end())});
2036   } catch (const exception& e) {
2037 #ifdef EDM_ML_DEBUG
2038 
2039     printout(INFO,
2040              "DD4CMS",
2041              "++ Unresolved Vector<%s>:  %s[%s]: %s. Try to resolve later. [%s]",
2042              type.c_str(),
2043              name.c_str(),
2044              nEntries.c_str(),
2045              val.c_str(),
2046              e.what());
2047 
2048 #endif
2049 
2050     std::vector<string> results = splitString(val);
2051     context->unresolvedVectors.insert({name, results});
2052   }
2053 }
2054 
2055 template <>
2056 void Converter<debug>::operator()(xml_h dbg) const {
2057   cms::DDNamespace ns(_param<cms::DDParsingContext>());
2058   if (dbg.hasChild(DD_CMU(debug_constants)))
2059     ns.setContext()->debug_constants = true;
2060   if (dbg.hasChild(DD_CMU(debug_materials)))
2061     ns.setContext()->debug_materials = true;
2062   if (dbg.hasChild(DD_CMU(debug_rotations)))
2063     ns.setContext()->debug_rotations = true;
2064   if (dbg.hasChild(DD_CMU(debug_shapes)))
2065     ns.setContext()->debug_shapes = true;
2066   if (dbg.hasChild(DD_CMU(debug_volumes)))
2067     ns.setContext()->debug_volumes = true;
2068   if (dbg.hasChild(DD_CMU(debug_placements)))
2069     ns.setContext()->debug_placements = true;
2070   if (dbg.hasChild(DD_CMU(debug_namespaces)))
2071     ns.setContext()->debug_namespaces = true;
2072   if (dbg.hasChild(DD_CMU(debug_includes)))
2073     ns.setContext()->debug_includes = true;
2074   if (dbg.hasChild(DD_CMU(debug_algorithms)))
2075     ns.setContext()->debug_algorithms = true;
2076   if (dbg.hasChild(DD_CMU(debug_specpars)))
2077     ns.setContext()->debug_specpars = true;
2078 }
2079 
2080 template <>
2081 void Converter<DDRegistry>::operator()(xml_h /* element */) const {
2082   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
2083   DDRegistry* res = _option<DDRegistry>();
2084   cms::DDNamespace ns(context);
2085   int count = 0;
2086 
2087 #ifdef EDM_ML_DEBUG
2088 
2089   printout(context->debug_constants ? ALWAYS : DEBUG,
2090            "DD4CMS",
2091            "+++ RESOLVING %ld unknown constants..... (out of %ld)",
2092            res->unresolvedConst.size(),
2093            res->originalConst.size());
2094 #endif
2095 
2096   while (!res->unresolvedConst.empty()) {
2097     for (auto& i : res->unresolvedConst) {
2098       const string& n = i.first;
2099       string rep;
2100       string& v = i.second;
2101       size_t idx, idq;
2102       for (idx = v.find('[', 0); idx != string::npos; idx = v.find('[', idx + 1)) {
2103         idq = v.find(']', idx + 1);
2104         rep = v.substr(idx + 1, idq - idx - 1);
2105         auto r = res->originalConst.find(rep);
2106         if (r != res->originalConst.end()) {
2107           rep = "(" + (*r).second + ")";
2108           v.replace(idx, idq - idx + 1, rep);
2109         }
2110       }
2111       if (v.find(']') == string::npos) {
2112         if (v.find("-+") != string::npos || v.find("+-") != string::npos) {
2113           while ((idx = v.find("-+")) != string::npos)
2114             v.replace(idx, 2, "-");
2115           while ((idx = v.find("+-")) != string::npos)
2116             v.replace(idx, 2, "-");
2117         }
2118 
2119 #ifdef EDM_ML_DEBUG
2120 
2121         printout(context->debug_constants ? ALWAYS : DEBUG,
2122                  "DD4CMS",
2123                  "+++ [%06ld] ----------  %-40s = %s",
2124                  res->unresolvedConst.size() - 1,
2125                  n.c_str(),
2126                  res->originalConst[n].c_str());
2127 
2128 #endif
2129 
2130         ns.addConstantNS(n, v, "number");
2131         res->unresolvedConst.erase(n);
2132         break;
2133       }
2134     }
2135     if (++count > 10000)
2136       break;
2137   }
2138   if (!res->unresolvedConst.empty()) {
2139     for (const auto& e : res->unresolvedConst)
2140       printout(ERROR, "DD4CMS", "+++ Unresolved constant: %-40s = %s.", e.first.c_str(), e.second.c_str());
2141     except("DD4CMS", "++ FAILED to resolve %ld constant entries:", res->unresolvedConst.size());
2142   }
2143   res->unresolvedConst.clear();
2144   res->originalConst.clear();
2145 }
2146 
2147 template <>
2148 void Converter<print_xml_doc>::operator()(xml_h element) const {
2149   string fname = xml::DocumentHandler::system_path(element);
2150 
2151 #ifdef EDM_ML_DEBUG
2152 
2153   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
2154            "DD4CMS",
2155            "+++ Processing data from: %s",
2156            fname.c_str());
2157 
2158 #endif
2159 }
2160 
2161 /// Converter for <DDDefinition/> tags
2162 static long load_dddefinition(Detector& det, xml_h element) {
2163   xml_elt_t dddef(element);
2164   if (dddef) {
2165     cms::DDParsingContext& context = *det.extension<DDParsingContext>();
2166     cms::DDNamespace ns(context);
2167     ns.addConstantNS("world_x", "101*m", "number");
2168     ns.addConstantNS("world_y", "101*m", "number");
2169     ns.addConstantNS("world_z", "450*m", "number");
2170     ns.addConstantNS("Air", "materials:Air", "string");
2171     ns.addConstantNS("Vacuum", "materials:Vacuum", "string");
2172 
2173     string fname = xml::DocumentHandler::system_path(element);
2174     bool open_geometry = dddef.hasChild(DD_CMU(open_geometry)) ? dddef.child(DD_CMU(open_geometry)) : true;
2175     bool close_geometry = dddef.hasChild(DD_CMU(close_geometry)) ? dddef.hasChild(DD_CMU(close_geometry)) : true;
2176 
2177     xml_coll_t(dddef, _U(debug)).for_each(Converter<debug>(det, &context));
2178 
2179     // Here we define the order how XML elements are processed.
2180     // Be aware of dependencies. This can only defined once.
2181     // At the end it is a limitation of DOM....
2182     printout(INFO, "DD4CMS", "+++ Processing the CMS detector description %s", fname.c_str());
2183 
2184     xml::Document doc;
2185     Converter<print_xml_doc> print_doc(det, &context);
2186     try {
2187       DDRegistry res;
2188       res.unresolvedConst.reserve(2000);
2189       res.originalConst.reserve(6000);
2190       print_doc((doc = dddef.document()).root());
2191       xml_coll_t(dddef, DD_CMU(ConstantsSection)).for_each(Converter<ConstantsSection>(det, &context, &res));
2192       xml_coll_t(dddef, DD_CMU(RotationSection)).for_each(Converter<RotationSection>(det, &context));
2193       xml_coll_t(dddef, DD_CMU(MaterialSection)).for_each(Converter<MaterialSection>(det, &context));
2194 
2195       xml_coll_t(dddef, DD_CMU(IncludeSection)).for_each(DD_CMU(Include), Converter<include_load>(det, &context, &res));
2196 
2197       for (xml::Document d : res.includes) {
2198         print_doc((doc = d).root());
2199         Converter<include_constants>(det, &context, &res)((doc = d).root());
2200       }
2201       // Before we continue, we have to resolve all constants NOW!
2202       Converter<DDRegistry>(det, &context, &res)(dddef);
2203       {
2204         DDVectorsMap* registry = context.description.extension<DDVectorsMap>();
2205 
2206         printout(context.debug_constants ? ALWAYS : DEBUG,
2207                  "DD4CMS",
2208                  "+++ RESOLVING %ld Vectors.....",
2209                  context.unresolvedVectors.size());
2210 
2211         while (!context.unresolvedVectors.empty()) {
2212           for (auto it = context.unresolvedVectors.begin(); it != context.unresolvedVectors.end();) {
2213             std::vector<double> result;
2214             for (const auto& i : it->second) {
2215               result.emplace_back(dd4hep::_toDouble(i));
2216             }
2217             registry->insert({it->first, result});
2218             // All components are resolved
2219             it = context.unresolvedVectors.erase(it);
2220           }
2221         }
2222       }
2223       // Now we can process the include files one by one.....
2224       for (xml::Document d : res.includes) {
2225         print_doc((doc = d).root());
2226         xml_coll_t(d.root(), DD_CMU(MaterialSection)).for_each(Converter<MaterialSection>(det, &context));
2227       }
2228       if (open_geometry) {
2229         det.init();
2230         ns.addVolume(det.worldVolume());
2231       }
2232       for (xml::Document d : res.includes) {
2233         print_doc((doc = d).root());
2234         xml_coll_t(d.root(), DD_CMU(RotationSection)).for_each(Converter<RotationSection>(det, &context));
2235       }
2236       for (xml::Document d : res.includes) {
2237         print_doc((doc = d).root());
2238         xml_coll_t(d.root(), DD_CMU(SolidSection)).for_each(Converter<SolidSection>(det, &context));
2239       }
2240       for (xml::Document d : res.includes) {
2241         print_doc((doc = d).root());
2242         xml_coll_t(d.root(), DD_CMU(LogicalPartSection)).for_each(Converter<LogicalPartSection>(det, &context));
2243       }
2244       for (xml::Document d : res.includes) {
2245         print_doc((doc = d).root());
2246         xml_coll_t(d.root(), DD_CMU(Algorithm)).for_each(Converter<DDLAlgorithm>(det, &context));
2247       }
2248       for (xml::Document d : res.includes) {
2249         print_doc((doc = d).root());
2250         xml_coll_t(d.root(), DD_CMU(PosPartSection)).for_each(Converter<PosPartSection>(det, &context));
2251       }
2252       for (xml::Document d : res.includes) {
2253         print_doc((doc = d).root());
2254         xml_coll_t(d.root(), DD_CMU(SpecParSection)).for_each(Converter<SpecParSection>(det, &context));
2255       }
2256 
2257       /// Unload all XML files after processing
2258       for (xml::Document d : res.includes)
2259         Converter<include_unload>(det, &context, &res)(d.root());
2260 
2261       print_doc((doc = dddef.document()).root());
2262       // Now process the actual geometry items
2263       xml_coll_t(dddef, DD_CMU(SolidSection)).for_each(Converter<SolidSection>(det, &context));
2264       {
2265         // Before we continue, we have to resolve all shapes NOW!
2266         // Note: This only happens in a legacy DB payloads where
2267         // boolean shapes can be defined before thier
2268         // component shapes
2269 
2270         while (!context.unresolvedShapes.empty()) {
2271           for (auto it = context.unresolvedShapes.begin(); it != context.unresolvedShapes.end();) {
2272             auto const& name = it->first;
2273             auto const& aname = std::visit([](auto&& arg) -> std::string { return arg.firstSolidName; }, it->second);
2274             auto const& bname = std::visit([](auto&& arg) -> std::string { return arg.secondSolidName; }, it->second);
2275 
2276             auto const& ait = context.shapes.find(aname);
2277             if (ait->second.isValid()) {
2278               auto const& bit = context.shapes.find(bname);
2279               if (bit->second.isValid()) {
2280                 dd4hep::Solid shape =
2281                     std::visit([&ait, &bit](auto&& arg) -> dd4hep::Solid { return arg.make(ait->second, bit->second); },
2282                                it->second);
2283                 context.shapes[name] = shape;
2284                 it = context.unresolvedShapes.erase(it);
2285               } else
2286                 ++it;
2287             } else
2288               ++it;
2289           }
2290         }
2291       }
2292       xml_coll_t(dddef, DD_CMU(LogicalPartSection)).for_each(Converter<LogicalPartSection>(det, &context));
2293       xml_coll_t(dddef, DD_CMU(Algorithm)).for_each(Converter<DDLAlgorithm>(det, &context));
2294       xml_coll_t(dddef, DD_CMU(PosPartSection)).for_each(Converter<PosPartSection>(det, &context));
2295       xml_coll_t(dddef, DD_CMU(SpecParSection)).for_each(Converter<SpecParSection>(det, &context));
2296     } catch (const exception& e) {
2297       printout(ERROR, "DD4CMS", "Exception while processing xml source:%s", doc.uri().c_str());
2298       printout(ERROR, "DD4CMS", "----> %s", e.what());
2299       throw;
2300     }
2301 
2302     /// This should be the end of all processing....close the geometry
2303     if (close_geometry) {
2304       Volume wv = det.worldVolume();
2305       Volume geomv = ns.volume("cms:OCMS", false);
2306       if (geomv.isValid())
2307         wv.placeVolume(geomv, 1);
2308       Volume mfv = ns.volume("cmsMagneticField:MAGF", false);
2309       if (mfv.isValid())
2310         wv.placeVolume(mfv, 1);
2311       Volume mfv1 = ns.volume("MagneticFieldVolumes:MAGF", false);
2312       if (mfv1.isValid())
2313         wv.placeVolume(mfv1, 1);
2314 
2315       // Can not deal with reflections without closed geometry
2316       det.manager().CloseGeometry("nv");
2317 
2318       det.endDocument();
2319     }
2320     printout(INFO, "DDDefinition", "+++ Finished processing %s", fname.c_str());
2321     return 1;
2322   }
2323   except("DDDefinition", "+++ FAILED to process unknown DOM tree [Invalid Handle]");
2324   return 0;
2325 }
2326 
2327 // Now declare the factory entry for the plugin mechanism
2328 DECLARE_XML_DOC_READER(DDDefinition, load_dddefinition)