Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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     const char* matname = nam.c_str();
0594     double density = xmat.attr<double>(DD_CMU(density)) / (dd4hep::g / dd4hep::cm3);
0595     xml_coll_t composites(xmat, DD_CMU(MaterialFraction));
0596     TGeoMixture* mix = new TGeoMixture(nam.c_str(), composites.size(), density);
0597 
0598 #ifdef EDM_ML_DEBUG
0599 
0600     printout(ns.context()->debug_materials ? ALWAYS : DEBUG,
0601              "DD4CMS",
0602              "++ Converting material %-48s  Density: %8.3f [g/cm3] ROOT: %8.3f [g/cm3]",
0603              ('"' + nam + '"').c_str(),
0604              density,
0605              mix->GetDensity());
0606 
0607 #endif
0608 
0609     if (ns.context()->makePayload) {
0610       ns.context()->compMaterialsVec.emplace_back(std::make_pair(nam, density));
0611     }
0612     for (composites.reset(); composites; ++composites) {
0613       xml_dim_t xfrac(composites);
0614       xml_dim_t xfrac_mat(xfrac.child(DD_CMU(rMaterial)));
0615       double fraction = xfrac.fraction();
0616       string fracname = ns.realName(xfrac_mat.nameStr());
0617 
0618       if (ns.context()->makePayload) {
0619         ns.context()->compMaterialsRefs[nam].emplace_back(
0620             cms::DDParsingContext::CompositeMaterial(ns.prepend(fracname), fraction));
0621       }
0622       TGeoMaterial* frac_mat = mgr.GetMaterial(fracname.c_str());
0623       if (frac_mat == nullptr)  // Try to find it within this namespace
0624         frac_mat = mgr.GetMaterial(ns.prepend(fracname).c_str());
0625       if (frac_mat) {
0626         mix->AddElement(frac_mat, fraction);
0627         continue;
0628       }
0629 
0630       throw cms::Exception("DD4CMS") << "Composite material \"" + fracname + "\" or \"" + ns.prepend(fracname) +
0631                                             "\" not yet defined.";
0632     }
0633     mix->SetTemperature(ns.context()->description.stdConditions().temperature);
0634     mix->SetPressure(ns.context()->description.stdConditions().pressure);
0635     mix->SetRadLen(0e0);
0636     /// Create medium from the material
0637     TGeoMedium* medium = mgr.GetMedium(matname);
0638     if (nullptr == medium) {
0639       --unique_mat_id;
0640       medium = new TGeoMedium(matname, unique_mat_id, mix);
0641       medium->SetTitle("material");
0642       medium->SetUniqueID(unique_mat_id);
0643     }
0644   }
0645 }
0646 
0647 /// Converter for <Rotation/> tags
0648 template <>
0649 void Converter<DDLRotation>::operator()(xml_h element) const {
0650   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0651   cms::DDNamespace ns(context);
0652   xml_dim_t xrot(element);
0653   string nam = xrot.nameStr();
0654   double thetaX = xrot.hasAttr(DD_CMU(thetaX)) ? ns.attr<double>(xrot, DD_CMU(thetaX)) : 0e0;
0655   double phiX = xrot.hasAttr(DD_CMU(phiX)) ? ns.attr<double>(xrot, DD_CMU(phiX)) : 0e0;
0656   double thetaY = xrot.hasAttr(DD_CMU(thetaY)) ? ns.attr<double>(xrot, DD_CMU(thetaY)) : 0e0;
0657   double phiY = xrot.hasAttr(DD_CMU(phiY)) ? ns.attr<double>(xrot, DD_CMU(phiY)) : 0e0;
0658   double thetaZ = xrot.hasAttr(DD_CMU(thetaZ)) ? ns.attr<double>(xrot, DD_CMU(thetaZ)) : 0e0;
0659   double phiZ = xrot.hasAttr(DD_CMU(phiZ)) ? ns.attr<double>(xrot, DD_CMU(phiZ)) : 0e0;
0660   Rotation3D rot = makeRotation3D(thetaX, phiX, thetaY, phiY, thetaZ, phiZ);
0661 
0662 #ifdef EDM_ML_DEBUG
0663 
0664   printout(context->debug_rotations ? ALWAYS : DEBUG,
0665            "DD4CMS",
0666            "+++ Adding rotation: %-32s: (theta/phi)[rad] X: %6.3f %6.3f Y: %6.3f %6.3f Z: %6.3f %6.3f",
0667            ns.prepend(nam).c_str(),
0668            thetaX,
0669            phiX,
0670            thetaY,
0671            phiY,
0672            thetaZ,
0673            phiZ);
0674 
0675 #endif
0676 
0677   ns.addRotation(nam, rot);
0678 }
0679 
0680 /// Converter for <ReflectionRotation/> tags
0681 template <>
0682 void Converter<DDLReflectionRotation>::operator()(xml_h element) const {
0683   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0684   cms::DDNamespace ns(context);
0685   xml_dim_t xrot(element);
0686   string name = xrot.nameStr();
0687   double thetaX = xrot.hasAttr(DD_CMU(thetaX)) ? ns.attr<double>(xrot, DD_CMU(thetaX)) : 0e0;
0688   double phiX = xrot.hasAttr(DD_CMU(phiX)) ? ns.attr<double>(xrot, DD_CMU(phiX)) : 0e0;
0689   double thetaY = xrot.hasAttr(DD_CMU(thetaY)) ? ns.attr<double>(xrot, DD_CMU(thetaY)) : 0e0;
0690   double phiY = xrot.hasAttr(DD_CMU(phiY)) ? ns.attr<double>(xrot, DD_CMU(phiY)) : 0e0;
0691   double thetaZ = xrot.hasAttr(DD_CMU(thetaZ)) ? ns.attr<double>(xrot, DD_CMU(thetaZ)) : 0e0;
0692   double phiZ = xrot.hasAttr(DD_CMU(phiZ)) ? ns.attr<double>(xrot, DD_CMU(phiZ)) : 0e0;
0693 
0694 #ifdef EDM_ML_DEBUG
0695 
0696   printout(context->debug_rotations ? ALWAYS : DEBUG,
0697            "DD4CMS",
0698            "+++ Adding reflection rotation: %-32s: (theta/phi)[rad] X: %6.3f %6.3f Y: %6.3f %6.3f Z: %6.3f %6.3f",
0699            ns.prepend(name).c_str(),
0700            thetaX,
0701            phiX,
0702            thetaY,
0703            phiY,
0704            thetaZ,
0705            phiZ);
0706 
0707 #endif
0708 
0709   Rotation3D rot = makeRotReflect(thetaX, phiX, thetaY, phiY, thetaZ, phiZ);
0710   ns.addRotation(name, rot);
0711 }
0712 
0713 /// Converter for <RotationSequence/> tags
0714 template <>
0715 void Converter<DDLRotationSequence>::operator()(xml_h element) const {
0716   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0717   cms::DDNamespace ns(context);
0718   xml_dim_t xrot(element);
0719   string nam = xrot.nameStr();
0720   Rotation3D rot;
0721   xml_coll_t rotations(xrot, DD_CMU(RotationByAxis));
0722   for (rotations.reset(); rotations; ++rotations) {
0723     string axis = ns.attr<string>(rotations, DD_CMU(axis));
0724     double angle = ns.attr<double>(rotations, _U(angle));
0725     rot = makeRotation3D(rot, axis, angle);
0726 
0727 #ifdef EDM_ML_DEBUG
0728 
0729     printout(context->debug_rotations ? ALWAYS : DEBUG,
0730              "DD4CMS",
0731              "+   Adding rotation to: %-29s: (axis/angle)[rad] Axis: %s Angle: %6.3f",
0732              nam.c_str(),
0733              axis.c_str(),
0734              angle);
0735 
0736 #endif
0737   }
0738   double xx, xy, xz;
0739   double yx, yy, yz;
0740   double zx, zy, zz;
0741   rot.GetComponents(xx, xy, xz, yx, yy, yz, zx, zy, zz);
0742 
0743 #ifdef EDM_ML_DEBUG
0744 
0745   printout(context->debug_rotations ? ALWAYS : DEBUG,
0746            "DD4CMS",
0747            "+++ Adding rotation sequence: %-23s: %6.3f %6.3f %6.3f, %6.3f %6.3f %6.3f, %6.3f %6.3f %6.3f",
0748            ns.prepend(nam).c_str(),
0749            xx,
0750            xy,
0751            xz,
0752            yx,
0753            yy,
0754            yz,
0755            zx,
0756            zy,
0757            zz);
0758 
0759 #endif
0760 
0761   ns.addRotation(nam, rot);
0762 }
0763 
0764 /// Converter for <RotationByAxis/> tags
0765 template <>
0766 void Converter<DDLRotationByAxis>::operator()(xml_h element) const {
0767   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
0768   cms::DDNamespace ns(context);
0769   xml_dim_t xrot(element);
0770   xml_dim_t par(xrot.parent());
0771   if (xrot.hasAttr(_U(name))) {
0772     string nam = xrot.nameStr();
0773     string axis = ns.attr<string>(xrot, DD_CMU(axis));
0774     double angle = ns.attr<double>(xrot, _U(angle));
0775     Rotation3D rot;
0776     rot = makeRotation3D(rot, axis, angle);
0777 
0778 #ifdef EDM_ML_DEBUG
0779 
0780     printout(context->debug_rotations ? ALWAYS : DEBUG,
0781              "DD4CMS",
0782              "+++ Adding rotation: %-32s: (axis/angle)[rad] Axis: %s Angle: %6.3f",
0783              ns.prepend(nam).c_str(),
0784              axis.c_str(),
0785              angle);
0786 
0787 #endif
0788 
0789     ns.addRotation(nam, rot);
0790   }
0791 }
0792 
0793 /// Converter for <LogicalPart/> tags
0794 template <>
0795 void Converter<DDLLogicalPart>::operator()(xml_h element) const {
0796   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0797   xml_dim_t e(element);
0798   string sol = e.child(DD_CMU(rSolid)).attr<string>(_U(name));
0799   string mat = e.child(DD_CMU(rMaterial)).attr<string>(_U(name));
0800   string volName = ns.prepend(e.attr<string>(_U(name)));
0801   Solid solid = ns.solid(sol);
0802   Material material = ns.material(mat);
0803   if (ns.context()->assemblySolids.count(sol) == 1) {
0804     // To match the general paradigm, an assembly starts as a solid,
0805     // and then a logical part is made of the solid. However, the
0806     // solid is just a dummy whose names tags it as an assembly.
0807     ns.addAssembly(volName, false);
0808     return;
0809   }
0810 
0811 #ifdef EDM_ML_DEBUG
0812   Volume volume =
0813 #endif
0814 
0815       ns.addVolume(Volume(volName, solid, material));
0816 
0817 #ifdef EDM_ML_DEBUG
0818 
0819   printout(ns.context()->debug_volumes ? ALWAYS : DEBUG,
0820            "DD4CMS",
0821            "+++ %s Volume: %-24s [%s] Shape: %-32s [%s] Material: %-40s [%s]",
0822            e.tag().c_str(),
0823            volName.c_str(),
0824            volume.isValid() ? "VALID" : "INVALID",
0825            sol.c_str(),
0826            solid.isValid() ? "VALID" : "INVALID",
0827            mat.c_str(),
0828            material.isValid() ? "VALID" : "INVALID");
0829 
0830 #endif
0831 }
0832 
0833 /// Helper converter
0834 template <>
0835 void Converter<DDLTransform3D>::operator()(xml_h element) const {
0836   cms::DDNamespace ns(_param<cms::DDParsingContext>());
0837   Transform3D* tr = _option<Transform3D>();
0838   xml_dim_t e(element);
0839   xml_dim_t translation = e.child(DD_CMU(Translation), false);
0840   xml_dim_t rotation = e.child(DD_CMU(Rotation), false);
0841   xml_dim_t refRotation = e.child(DD_CMU(rRotation), false);
0842   xml_dim_t refReflectionRotation = e.child(DD_CMU(rReflectionRotation), false);
0843   Position pos;
0844   Rotation3D rot;
0845 
0846   if (translation.ptr()) {
0847     double x = ns.attr<double>(translation, _U(x));
0848     double y = ns.attr<double>(translation, _U(y));
0849     double z = ns.attr<double>(translation, _U(z));
0850     pos = Position(x, y, z);
0851   }
0852   if (rotation.ptr()) {
0853     double x = ns.attr<double>(rotation, _U(x));
0854     double y = ns.attr<double>(rotation, _U(y));
0855     double z = ns.attr<double>(rotation, _U(z));
0856     rot = RotationZYX(z, y, x);
0857   } else if (refRotation.ptr()) {
0858     string rotName = ns.prepend(refRotation.nameStr());
0859     rot = ns.rotation(rotName);
0860   } else if (refReflectionRotation.ptr()) {
0861     string rotName = ns.prepend(refReflectionRotation.nameStr());
0862     rot = ns.rotation(rotName);
0863   }
0864   *tr = Transform3D(rot, pos);
0865 }
0866 
0867 static void placeAssembly(Volume* parentPtr,
0868                           const string& parentName,
0869                           Volume* childPtr,
0870                           const string& childName,
0871                           int copy,
0872                           const Transform3D& transform,
0873                           cms::DDNamespace& ns) {
0874 #ifdef EDM_ML_DEBUG
0875 
0876   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0877            "DD4CMS",
0878            "+++ Parent vol: %-24s Child: %-32s, copy:%d",
0879            parentName.c_str(),
0880            childName.c_str(),
0881            copy);
0882 
0883 #endif
0884 
0885   TGeoShape* shape = (*childPtr)->GetShape();
0886   // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
0887   if (shape->IsA() == TGeoShapeAssembly::Class()) {
0888     TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
0889     if (std::fabs(as->GetDX()) < numeric_limits<double>::epsilon() &&
0890         std::fabs(as->GetDY()) < numeric_limits<double>::epsilon() &&
0891         std::fabs(as->GetDZ()) < numeric_limits<double>::epsilon()) {
0892       as->NeedsBBoxRecompute();
0893       as->ComputeBBox();
0894     }
0895   }
0896   if (ns.context()->validate) {
0897     TGeoNode* n;
0898     TString nam_id = TString::Format("%s_%d", (*childPtr)->GetName(), copy);
0899     n = static_cast<TGeoNode*>((*parentPtr)->GetNode(nam_id));
0900     if (n != nullptr) {
0901       printout(ERROR, "PlacedVolume", "++ Attempt to add already existing node %s", (const char*)nam_id);
0902       return;
0903     }
0904   }
0905 
0906   PlacedVolume pv;
0907   if ((*childPtr)->IsAssembly()) {
0908     pv = parentPtr->placeVolume(ns.assembly(childName), copy, transform);
0909   } else {
0910     pv = parentPtr->placeVolume(*childPtr, copy, transform);
0911   }
0912 
0913   if (!pv.isValid()) {
0914     printout(ERROR, "DD4CMS", "+++ Placement FAILED! Parent:%s Child:%s", parentName.c_str(), childName.c_str());
0915   }
0916 }
0917 
0918 /// Converter for <PosPart/> tags
0919 template <>
0920 void Converter<DDLPosPart>::operator()(xml_h element) const {
0921   cms::DDNamespace ns(_param<cms::DDParsingContext>());  //, element, true );
0922   xml_dim_t e(element);
0923   int copy = e.attr<int>(DD_CMU(copyNumber));
0924   string parentName = ns.prepend(ns.attr<string>(e.child(DD_CMU(rParent)), _U(name)));
0925   string childName = ns.prepend(ns.attr<string>(e.child(DD_CMU(rChild)), _U(name)));
0926   Transform3D transform;
0927   Converter<DDLTransform3D>(description, param, &transform)(element);
0928 
0929   Volume parent = ns.volume(parentName, false);
0930   Volume child = ns.volume(childName, false);
0931   Assembly parAsmb = ns.assembly(parentName, false);
0932   Assembly childAsmb = ns.assembly(childName, false);
0933 
0934 #ifdef EDM_ML_DEBUG
0935 
0936   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0937            "DD4CMS",
0938            "+++ %s Parent: %-24s [%s] Child: %-32s [%s] copy:%d",
0939            e.tag().c_str(),
0940            parentName.c_str(),
0941            parent.isValid() ? "VALID" : "INVALID",
0942            childName.c_str(),
0943            child.isValid() ? "VALID" : "INVALID",
0944            copy);
0945 
0946 #endif
0947 
0948   if (!parent.isValid() && !parAsmb.isValid() && strchr(parentName.c_str(), NAMESPACE_SEP) == nullptr) {
0949     parentName = ns.prepend(parentName);
0950     parAsmb = ns.assembly(parentName, false);
0951     if (!parAsmb.isValid())
0952       parent = ns.volume(parentName);
0953   }
0954 
0955   if (!child.isValid() && !childAsmb.isValid() && strchr(childName.c_str(), NAMESPACE_SEP) == nullptr) {
0956     childName = ns.prepend(childName);
0957     child = ns.volume(childName, false);
0958     childAsmb = ns.assembly(childName, false);
0959   }
0960   if (parAsmb.isValid() || childAsmb.isValid()) {
0961     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0962              "DD4CMS",
0963              "***** Placing assembly parent %s, child %s",
0964              parentName.c_str(),
0965              childName.c_str());
0966     Volume* parentPtr = parAsmb.isValid() ? &parAsmb : &parent;
0967     Volume* childPtr = childAsmb.isValid() ? &childAsmb : &child;
0968     placeAssembly(parentPtr, parentName, childPtr, childName, copy, transform, ns);
0969     return;
0970   }
0971 
0972 #ifdef EDM_ML_DEBUG
0973 
0974   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
0975            "DD4CMS",
0976            "+++ %s Parent: %-24s [%s] Child: %-32s [%s] copy:%d",
0977            e.tag().c_str(),
0978            parentName.c_str(),
0979            parent.isValid() ? "VALID" : "INVALID",
0980            childName.c_str(),
0981            child.isValid() ? "VALID" : "INVALID",
0982            copy);
0983 
0984 #endif
0985 
0986   PlacedVolume pv;
0987   if (child.isValid()) {
0988     // FIXME: workaround for Reflection rotation
0989     // copy from DDCore/src/Volumes.cpp to replace
0990     // static PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform)
0991     if (!parent) {
0992       except("dd4hep", "Volume: Attempt to assign daughters to an invalid physical parent volume.");
0993     }
0994     if (!child) {
0995       except("dd4hep", "Volume: Attempt to assign an invalid physical daughter volume.");
0996     }
0997     TGeoShape* shape = child->GetShape();
0998     // Need to fix the daughter's BBox of assemblies, if the BBox was not calculated....
0999     if (shape->IsA() == TGeoShapeAssembly::Class()) {
1000       TGeoShapeAssembly* as = (TGeoShapeAssembly*)shape;
1001       if (std::fabs(as->GetDX()) < numeric_limits<double>::epsilon() &&
1002           std::fabs(as->GetDY()) < numeric_limits<double>::epsilon() &&
1003           std::fabs(as->GetDZ()) < numeric_limits<double>::epsilon()) {
1004         as->NeedsBBoxRecompute();
1005         as->ComputeBBox();
1006       }
1007     }
1008     TGeoNode* n;
1009     TString nam_id = TString::Format("%s_%d", child->GetName(), copy);
1010     if (ns.context()->validate) {
1011       n = static_cast<TGeoNode*>(parent->GetNode(nam_id));
1012       if (n != nullptr) {
1013         printout(ERROR, "PlacedVolume", "++ Attempt to add already existing node %s", (const char*)nam_id);
1014       }
1015     }
1016 
1017     Rotation3D rot(transform.Rotation());
1018     Translation3D trans(transform.Translation());
1019     double x, y, z;
1020     trans.GetComponents(x, y, z);
1021     Position pos(x, y, z);
1022     parent->AddNode(child, copy, createPlacement(rot, pos));
1023 
1024     n = static_cast<TGeoNode*>(parent->GetNodes()->Last());
1025     assert(n->GetName() == nam_id);
1026     n->TGeoNode::SetUserExtension(new PlacedVolume::Object());
1027     pv = PlacedVolume(n);
1028   }
1029   if (!pv.isValid()) {
1030     printout(ERROR,
1031              "DD4CMS",
1032              "+++ Placement FAILED! Parent:%s Child:%s Valid:%s",
1033              parent.name(),
1034              childName.c_str(),
1035              yes_no(child.isValid()));
1036   }
1037 }
1038 
1039 /// Converter for <PartSelector/> tags
1040 template <>
1041 void Converter<PartSelector>::operator()(xml_h element) const {
1042   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1043   cms::DDParsingContext* const context = ns.context();
1044   dd4hep::SpecParRegistry& registry = *context->description.extension<dd4hep::SpecParRegistry>();
1045   xml_dim_t e(element);
1046   xml_dim_t specPar = e.parent();
1047   string specParName = specPar.attr<string>(_U(name));
1048   string path = e.attr<string>(DD_CMU(path));
1049 
1050 #ifdef EDM_ML_DEBUG
1051 
1052   printout(ns.context()->debug_specpars ? ALWAYS : DEBUG,
1053            "DD4CMS",
1054            "+++ PartSelector for %s path: %s",
1055            specParName.c_str(),
1056            path.c_str());
1057 
1058 #endif
1059 
1060   size_t pos = std::string::npos;
1061   if ((pos = path.find("//.*:")) != std::string::npos) {
1062     path.erase(pos + 2, 3);
1063   }
1064   registry.specpars[specParName].paths.emplace_back(std::move(path));
1065 }
1066 
1067 /// Converter for <Parameter/> tags
1068 template <>
1069 void Converter<Parameter>::operator()(xml_h element) const {
1070   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1071   cms::DDParsingContext* const context = ns.context();
1072   dd4hep::SpecParRegistry& registry = *context->description.extension<dd4hep::SpecParRegistry>();
1073   xml_dim_t e(element);
1074   xml_dim_t specPar = e.parent();
1075   xml_dim_t specParSect = specPar.parent();
1076   string specParName = specPar.attr<string>(_U(name));
1077   string name = e.nameStr();
1078   string value = e.attr<string>(DD_CMU(value));
1079   bool eval = specParSect.hasAttr(_U(eval)) ? specParSect.attr<bool>(_U(eval)) : false;
1080   eval = specPar.hasAttr(_U(eval)) ? specPar.attr<bool>(_U(eval)) : eval;
1081   eval = e.hasAttr(_U(eval)) ? e.attr<bool>(_U(eval)) : eval;
1082 
1083   string type = eval ? "number" : "string";
1084 
1085 #ifdef EDM_ML_DEBUG
1086 
1087   printout(ns.context()->debug_specpars ? ALWAYS : DEBUG,
1088            "DD4CMS",
1089            "+++ Parameter for %s: %s value %s is a %s",
1090            specParName.c_str(),
1091            name.c_str(),
1092            value.c_str(),
1093            type.c_str());
1094 
1095 #endif
1096 
1097   size_t idx = value.find('[');
1098   if (idx == string::npos && type == "number") {
1099     registry.specpars[specParName].numpars[name].emplace_back(dd4hep::_toDouble(value));
1100     return;
1101   }
1102   if (idx == string::npos || type == "string") {
1103     registry.specpars[specParName].spars[name].emplace_back(std::move(value));
1104     return;
1105   }
1106 
1107   while (idx != string::npos) {
1108     ++idx;
1109     size_t idp = value.find(':', idx);
1110     size_t idq = value.find(']', idx);
1111     if (idp == string::npos || idp > idq)
1112       value.insert(idx, ns.name());
1113     else if (idp != string::npos && idp < idq)
1114       value[idp] = NAMESPACE_SEP;
1115     idx = value.find('[', idx);
1116   }
1117 
1118   string rep;
1119   string& v = value;
1120   size_t idq;
1121   for (idx = v.find('[', 0); idx != string::npos; idx = v.find('[', idx + 1)) {
1122     idq = v.find(']', idx + 1);
1123     rep = v.substr(idx + 1, idq - idx - 1);
1124     auto r = ns.context()->description.constants().find(rep);
1125     if (r != ns.context()->description.constants().end()) {
1126       rep = "(" + r->second->type + ")";
1127       v.replace(idx, idq - idx + 1, rep);
1128     }
1129   }
1130   registry.specpars[specParName].numpars[name].emplace_back(dd4hep::_toDouble(value));
1131 }
1132 
1133 template <typename TYPE>
1134 static void convert_boolean(cms::DDParsingContext* context, xml_h element) {
1135   cms::DDNamespace ns(context);
1136   xml_dim_t e(element);
1137   string nam = e.nameStr();
1138   string solidName[2];
1139   Solid solids[2];
1140   Solid boolean;
1141   int cnt = 0;
1142   if (e.hasChild(DD_CMU(rSolid))) {
1143     for (xml_coll_t c(element, DD_CMU(rSolid)); cnt < 2 && c; ++c, ++cnt) {
1144       solidName[cnt] = c.attr<string>(_U(name));
1145       solids[cnt] = ns.solid(c.attr<string>(_U(name)));
1146     }
1147   } else {
1148     solidName[0] = e.attr<string>(DD_CMU(firstSolid));
1149     if ((solids[0] = ns.solid(e.attr<string>(DD_CMU(firstSolid)))).isValid())
1150       ++cnt;
1151     solidName[1] = e.attr<string>(DD_CMU(secondSolid));
1152     if ((solids[1] = ns.solid(e.attr<string>(DD_CMU(secondSolid)))).isValid())
1153       ++cnt;
1154   }
1155   if (cnt != 2) {
1156     except("DD4CMS", "+++ Failed to create boolean solid %s. Found only %d parts.", nam.c_str(), cnt);
1157   }
1158 
1159 #ifdef EDM_ML_DEBUG
1160 
1161   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1162            "DD4CMS",
1163            "+++ BooleanSolid: %s Left: %-32s Right: %-32s",
1164            nam.c_str(),
1165            ((solids[0].ptr() == nullptr) ? solidName[0].c_str() : solids[0]->GetName()),
1166            ((solids[1].ptr() == nullptr) ? solidName[1].c_str() : solids[1]->GetName()));
1167 
1168 #endif
1169 
1170   if (solids[0].isValid() && solids[1].isValid()) {
1171     Transform3D trafo;
1172     Converter<DDLTransform3D>(context->description, context, &trafo)(element);
1173     boolean = TYPE(solids[0], solids[1], trafo);
1174   } else {
1175     // Register it for later processing
1176     Transform3D trafo;
1177     Converter<DDLTransform3D>(context->description, context, &trafo)(element);
1178     ns.context()->unresolvedShapes.emplace(nam,
1179                                            DDParsingContext::BooleanShape<TYPE>(solidName[0], solidName[1], trafo));
1180     if (solids[0].isValid() == false) {
1181       printout(ERROR, "DD4CMS", "++ Solid not defined yet: %s", solidName[0].c_str());
1182     }
1183     if (solids[1].isValid() == false) {
1184       printout(ERROR, "DD4CMS", "++ Solid not defined yet: %s", solidName[1].c_str());
1185     }
1186     printout(ERROR, "DD4CMS", "++ Re-order XML files to prevent references to undefined solids");
1187   }
1188   if (!boolean.isValid()) {
1189     // Delay processing the shape
1190     ns.context()->shapes.emplace(nam, dd4hep::Solid(nullptr));
1191   } else
1192     ns.addSolid(nam, boolean);
1193 }
1194 
1195 /// Converter for <UnionSolid/> tags
1196 template <>
1197 void Converter<DDLUnionSolid>::operator()(xml_h element) const {
1198   convert_boolean<UnionSolid>(_param<cms::DDParsingContext>(), element);
1199 }
1200 
1201 /// Converter for <SubtractionSolid/> tags
1202 template <>
1203 void Converter<DDLSubtractionSolid>::operator()(xml_h element) const {
1204   convert_boolean<SubtractionSolid>(_param<cms::DDParsingContext>(), element);
1205 }
1206 
1207 /// Converter for <IntersectionSolid/> tags
1208 template <>
1209 void Converter<DDLIntersectionSolid>::operator()(xml_h element) const {
1210   convert_boolean<IntersectionSolid>(_param<cms::DDParsingContext>(), element);
1211 }
1212 
1213 /// Converter for <Polycone/> tags
1214 template <>
1215 void Converter<DDLPolycone>::operator()(xml_h element) const {
1216   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1217   xml_dim_t e(element);
1218   string nam = e.nameStr();
1219   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1220   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1221   vector<double> z, rmin, rmax, r;
1222 
1223   for (xml_coll_t rzpoint(element, DD_CMU(RZPoint)); rzpoint; ++rzpoint) {
1224     z.emplace_back(ns.attr<double>(rzpoint, _U(z)));
1225     r.emplace_back(ns.attr<double>(rzpoint, _U(r)));
1226   }
1227   if (z.empty()) {
1228     for (xml_coll_t zplane(element, DD_CMU(ZSection)); zplane; ++zplane) {
1229       rmin.emplace_back(ns.attr<double>(zplane, DD_CMU(rMin)));
1230       rmax.emplace_back(ns.attr<double>(zplane, DD_CMU(rMax)));
1231       z.emplace_back(ns.attr<double>(zplane, _U(z)));
1232     }
1233 
1234 #ifdef EDM_ML_DEBUG
1235 
1236     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1237              "DD4CMS",
1238              "+   Polycone: startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]  %4ld z-planes",
1239              startPhi,
1240              deltaPhi,
1241              z.size());
1242 
1243 #endif
1244 
1245     ns.addSolid(nam, Polycone(startPhi, deltaPhi, rmin, rmax, z));
1246   } else {
1247 #ifdef EDM_ML_DEBUG
1248 
1249     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1250              "DD4CMS",
1251              "+   Polycone: startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]  %4ld z-planes and %4ld radii",
1252              startPhi,
1253              deltaPhi,
1254              z.size(),
1255              r.size());
1256 
1257 #endif
1258 
1259     ns.addSolid(nam, Polycone(startPhi, deltaPhi, r, z));
1260   }
1261 }
1262 
1263 /// Converter for <ExtrudedPolygon/> tags
1264 template <>
1265 void Converter<DDLExtrudedPolygon>::operator()(xml_h element) const {
1266   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1267   xml_dim_t e(element);
1268   string nam = e.nameStr();
1269   vector<double> pt_x, pt_y, sec_x, sec_y, sec_z, sec_scale;
1270 
1271   for (xml_coll_t sec(element, DD_CMU(ZXYSection)); sec; ++sec) {
1272     sec_z.emplace_back(ns.attr<double>(sec, _U(z)));
1273     sec_x.emplace_back(ns.attr<double>(sec, _U(x)));
1274     sec_y.emplace_back(ns.attr<double>(sec, _U(y)));
1275     sec_scale.emplace_back(ns.attr<double>(sec, DD_CMU(scale), 1.0));
1276   }
1277   for (xml_coll_t pt(element, DD_CMU(XYPoint)); pt; ++pt) {
1278     pt_x.emplace_back(ns.attr<double>(pt, _U(x)));
1279     pt_y.emplace_back(ns.attr<double>(pt, _U(y)));
1280   }
1281 
1282 #ifdef EDM_ML_DEBUG
1283 
1284   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1285            "DD4CMS",
1286            "+   ExtrudedPolygon: %4ld points %4ld zxy sections",
1287            pt_x.size(),
1288            sec_z.size());
1289 
1290 #endif
1291 
1292   ns.addSolid(nam, ExtrudedPolygon(pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale));
1293 }
1294 
1295 /// Converter for <Polyhedra/> tags
1296 template <>
1297 void Converter<DDLPolyhedra>::operator()(xml_h element) const {
1298   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1299   xml_dim_t e(element);
1300   string nam = e.nameStr();
1301   double numSide = ns.attr<int>(e, DD_CMU(numSide));
1302   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1303   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1304   vector<double> z, rmin, rmax;
1305 
1306   for (xml_coll_t zplane(element, DD_CMU(RZPoint)); zplane; ++zplane) {
1307     rmin.emplace_back(0.0);
1308     rmax.emplace_back(ns.attr<double>(zplane, _U(r)));
1309     z.emplace_back(ns.attr<double>(zplane, _U(z)));
1310   }
1311   for (xml_coll_t zplane(element, DD_CMU(ZSection)); zplane; ++zplane) {
1312     rmin.emplace_back(ns.attr<double>(zplane, DD_CMU(rMin)));
1313     rmax.emplace_back(ns.attr<double>(zplane, DD_CMU(rMax)));
1314     z.emplace_back(ns.attr<double>(zplane, _U(z)));
1315   }
1316 
1317 #ifdef EDM_ML_DEBUG
1318 
1319   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1320            "DD4CMS",
1321            "+   Polyhedra:startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]  %4d sides %4ld z-planes",
1322            startPhi,
1323            deltaPhi,
1324            numSide,
1325            z.size());
1326 
1327 #endif
1328 
1329   ns.addSolid(nam, Polyhedra(numSide, startPhi, deltaPhi, z, rmin, rmax));
1330 }
1331 
1332 /// Converter for <Sphere/> tags
1333 template <>
1334 void Converter<DDLSphere>::operator()(xml_h element) const {
1335   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1336   xml_dim_t e(element);
1337   string nam = e.nameStr();
1338   double rinner = ns.attr<double>(e, DD_CMU(innerRadius));
1339   double router = ns.attr<double>(e, DD_CMU(outerRadius));
1340   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1341   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1342   double startTheta = ns.attr<double>(e, DD_CMU(startTheta));
1343   double deltaTheta = ns.attr<double>(e, DD_CMU(deltaTheta));
1344 
1345 #ifdef EDM_ML_DEBUG
1346 
1347   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1348            "DD4CMS",
1349            "+   Sphere:   r_inner=%8.3f [cm] r_outer=%8.3f [cm]"
1350            " startPhi=%8.3f [rad] deltaPhi=%8.3f startTheta=%8.3f delteTheta=%8.3f [rad]",
1351            rinner / dd4hep::cm,
1352            router / dd4hep::cm,
1353            startPhi,
1354            deltaPhi,
1355            startTheta,
1356            deltaTheta);
1357 
1358 #endif
1359 
1360   ns.addSolid(nam, Sphere(rinner, router, startTheta, deltaTheta, startPhi, deltaPhi));
1361 }
1362 
1363 /// Converter for <Torus/> tags
1364 template <>
1365 void Converter<DDLTorus>::operator()(xml_h element) const {
1366   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1367   xml_dim_t e(element);
1368   string nam = e.nameStr();
1369   double r = ns.attr<double>(e, DD_CMU(torusRadius));
1370   double rinner = ns.attr<double>(e, DD_CMU(innerRadius));
1371   double router = ns.attr<double>(e, DD_CMU(outerRadius));
1372   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1373   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1374 
1375 #ifdef EDM_ML_DEBUG
1376 
1377   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1378            "DD4CMS",
1379            "+   Torus:    r=%10.3f [cm] r_inner=%10.3f [cm] r_outer=%10.3f [cm]"
1380            " startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]",
1381            r / dd4hep::cm,
1382            rinner / dd4hep::cm,
1383            router / dd4hep::cm,
1384            startPhi,
1385            deltaPhi);
1386 
1387 #endif
1388 
1389   ns.addSolid(nam, Torus(r, rinner, router, startPhi, deltaPhi));
1390 }
1391 
1392 /// Converter for <Pseudotrap/> tags
1393 template <>
1394 void Converter<DDLPseudoTrap>::operator()(xml_h element) const {
1395   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1396   xml_dim_t e(element);
1397   string nam = e.nameStr();
1398   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1399   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1400   double dx2 = ns.attr<double>(e, DD_CMU(dx2));
1401   double dy2 = ns.attr<double>(e, DD_CMU(dy2));
1402   double dz = ns.attr<double>(e, _U(dz));
1403   double r = ns.attr<double>(e, _U(radius));
1404   bool atMinusZ = ns.attr<bool>(e, DD_CMU(atMinusZ));
1405 
1406 #ifdef EDM_ML_DEBUG
1407 
1408   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1409            "DD4CMS",
1410            "+   Pseudotrap:  dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2=%.3f dy2=%.3f radius:%.3f atMinusZ:%s",
1411            dz / dd4hep::cm,
1412            dx1 / dd4hep::cm,
1413            dy1 / dd4hep::cm,
1414            dx2 / dd4hep::cm,
1415            dy2 / dd4hep::cm,
1416            r / dd4hep::cm,
1417            yes_no(atMinusZ));
1418 
1419 #endif
1420 
1421   ns.addSolid(nam, PseudoTrap(dx1, dx2, dy1, dy2, dz, r, atMinusZ));
1422 }
1423 
1424 /// Converter for <Trapezoid/> tags
1425 template <>
1426 void Converter<DDLTrapezoid>::operator()(xml_h element) const {
1427   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1428   xml_dim_t e(element);
1429   string nam = e.nameStr();
1430   double dz = ns.attr<double>(e, _U(dz));
1431   double alp1 = ns.attr<double>(e, DD_CMU(alp1));
1432   double bl1 = ns.attr<double>(e, DD_CMU(bl1));
1433   double tl1 = ns.attr<double>(e, DD_CMU(tl1));
1434   double h1 = ns.attr<double>(e, DD_CMU(h1));
1435   double alp2 = ns.attr<double>(e, DD_CMU(alp2));
1436   double bl2 = ns.attr<double>(e, DD_CMU(bl2));
1437   double tl2 = ns.attr<double>(e, DD_CMU(tl2));
1438   double h2 = ns.attr<double>(e, DD_CMU(h2));
1439   double phi = ns.attr<double>(e, _U(phi), 0.0);
1440   double theta = ns.attr<double>(e, _U(theta), 0.0);
1441 
1442 #ifdef EDM_ML_DEBUG
1443 
1444   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1445            "DD4CMS",
1446            "+   Trapezoid:  dz=%10.3f [cm] alp1:%.3f bl1=%.3f tl1=%.3f alp2=%.3f bl2=%.3f tl2=%.3f h2=%.3f phi=%.3f "
1447            "theta=%.3f",
1448            dz / dd4hep::cm,
1449            alp1,
1450            bl1 / dd4hep::cm,
1451            tl1 / dd4hep::cm,
1452            h1 / dd4hep::cm,
1453            alp2,
1454            bl2 / dd4hep::cm,
1455            tl2 / dd4hep::cm,
1456            h2 / dd4hep::cm,
1457            phi,
1458            theta);
1459 
1460 #endif
1461 
1462   ns.addSolid(nam, Trap(dz, theta, phi, h1, bl1, tl1, alp1, h2, bl2, tl2, alp2));
1463 }
1464 
1465 /// Converter for <Trd1/> tags
1466 template <>
1467 void Converter<DDLTrd1>::operator()(xml_h element) const {
1468   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1469   xml_dim_t e(element);
1470   string nam = e.nameStr();
1471   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1472   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1473   double dx2 = ns.attr<double>(e, DD_CMU(dx2), 0.0);
1474   double dy2 = ns.attr<double>(e, DD_CMU(dy2), dy1);
1475   double dz = ns.attr<double>(e, DD_CMU(dz));
1476   if (dy1 == dy2) {
1477 #ifdef EDM_ML_DEBUG
1478 
1479     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1480              "DD4CMS",
1481              "+   Trd1:       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1482              dz / dd4hep::cm,
1483              dx1 / dd4hep::cm,
1484              dy1 / dd4hep::cm,
1485              dx2 / dd4hep::cm,
1486              dy2 / dd4hep::cm);
1487 
1488 #endif
1489 
1490     ns.addSolid(nam, Trd1(dx1, dx2, dy1, dz));
1491   } else {
1492 #ifdef EDM_ML_DEBUG
1493 
1494     printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1495              "DD4CMS",
1496              "+   Trd1(which is actually Trd2):       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1497              dz / dd4hep::cm,
1498              dx1 / dd4hep::cm,
1499              dy1 / dd4hep::cm,
1500              dx2 / dd4hep::cm,
1501              dy2 / dd4hep::cm);
1502 
1503 #endif
1504 
1505     ns.addSolid(nam, Trd2(dx1, dx2, dy1, dy2, dz));
1506   }
1507 }
1508 
1509 /// Converter for <Trd2/> tags
1510 template <>
1511 void Converter<DDLTrd2>::operator()(xml_h element) const {
1512   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1513   xml_dim_t e(element);
1514   string nam = e.nameStr();
1515   double dx1 = ns.attr<double>(e, DD_CMU(dx1));
1516   double dy1 = ns.attr<double>(e, DD_CMU(dy1));
1517   double dx2 = ns.attr<double>(e, DD_CMU(dx2), 0.0);
1518   double dy2 = ns.attr<double>(e, DD_CMU(dy2), dy1);
1519   double dz = ns.attr<double>(e, DD_CMU(dz));
1520 
1521 #ifdef EDM_ML_DEBUG
1522 
1523   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1524            "DD4CMS",
1525            "+   Trd1:       dz=%8.3f [cm] dx1:%.3f dy1:%.3f dx2:%.3f dy2:%.3f",
1526            dz / dd4hep::cm,
1527            dx1 / dd4hep::cm,
1528            dy1 / dd4hep::cm,
1529            dx2 / dd4hep::cm,
1530            dy2 / dd4hep::cm);
1531 
1532 #endif
1533 
1534   ns.addSolid(nam, Trd2(dx1, dx2, dy1, dy2, dz));
1535 }
1536 
1537 /// Converter for <Tubs/> tags
1538 template <>
1539 void Converter<DDLTubs>::operator()(xml_h element) const {
1540   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1541   xml_dim_t e(element);
1542   string nam = e.nameStr();
1543   double dz = ns.attr<double>(e, DD_CMU(dz));
1544   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1545   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1546   double startPhi = ns.attr<double>(e, DD_CMU(startPhi), 0.0);
1547   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi), 2 * M_PI);
1548 
1549 #ifdef EDM_ML_DEBUG
1550 
1551   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1552            "DD4CMS",
1553            "+   Tubs:     dz=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1554            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]",
1555            dz / dd4hep::cm,
1556            rmin / dd4hep::cm,
1557            rmax / dd4hep::cm,
1558            startPhi,
1559            deltaPhi);
1560 
1561 #endif
1562 
1563   ns.addSolid(nam, Tube(rmin, rmax, dz, startPhi, startPhi + deltaPhi));
1564 }
1565 
1566 /// Converter for <CutTubs/> tags
1567 template <>
1568 void Converter<DDLCutTubs>::operator()(xml_h element) const {
1569   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1570   xml_dim_t e(element);
1571   string nam = e.nameStr();
1572   double dz = ns.attr<double>(e, DD_CMU(dz));
1573   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1574   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1575   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1576   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1577   double lx = ns.attr<double>(e, DD_CMU(lx));
1578   double ly = ns.attr<double>(e, DD_CMU(ly));
1579   double lz = ns.attr<double>(e, DD_CMU(lz));
1580   double tx = ns.attr<double>(e, DD_CMU(tx));
1581   double ty = ns.attr<double>(e, DD_CMU(ty));
1582   double tz = ns.attr<double>(e, DD_CMU(tz));
1583 
1584 #ifdef EDM_ML_DEBUG
1585 
1586   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1587            "DD4CMS",
1588            "+   CutTube:  dz=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1589            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]...",
1590            dz / dd4hep::cm,
1591            rmin / dd4hep::cm,
1592            rmax / dd4hep::cm,
1593            startPhi,
1594            deltaPhi);
1595 
1596 #endif
1597 
1598   ns.addSolid(nam, CutTube(rmin, rmax, dz, startPhi, startPhi + deltaPhi, lx, ly, lz, tx, ty, tz));
1599 }
1600 
1601 /// Converter for <TruncTubs/> tags
1602 template <>
1603 void Converter<DDLTruncTubs>::operator()(xml_h element) const {
1604   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1605   xml_dim_t e(element);
1606   string nam = e.nameStr();
1607   double zhalf = ns.attr<double>(e, DD_CMU(zHalf));
1608   double rmin = ns.attr<double>(e, DD_CMU(rMin));
1609   double rmax = ns.attr<double>(e, DD_CMU(rMax));
1610   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1611   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1612   double cutAtStart = ns.attr<double>(e, DD_CMU(cutAtStart));
1613   double cutAtDelta = ns.attr<double>(e, DD_CMU(cutAtDelta));
1614   bool cutInside = ns.attr<bool>(e, DD_CMU(cutInside));
1615 
1616 #ifdef EDM_ML_DEBUG
1617 
1618   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1619            "DD4CMS",
1620            "+   TruncTube:zHalf=%8.3f [cm] rmin=%8.3f [cm] rmax=%8.3f [cm]"
1621            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad] atStart=%8.3f [cm] atDelta=%8.3f [cm] inside:%s",
1622            zhalf / dd4hep::cm,
1623            rmin / dd4hep::cm,
1624            rmax / dd4hep::cm,
1625            startPhi,
1626            deltaPhi,
1627            cutAtStart / dd4hep::cm,
1628            cutAtDelta / dd4hep::cm,
1629            yes_no(cutInside));
1630 
1631 #endif
1632 
1633   ns.addSolid(nam, TruncatedTube(zhalf, rmin, rmax, startPhi, deltaPhi, cutAtStart, cutAtDelta, cutInside));
1634 }
1635 
1636 /// Converter for <EllipticalTube/> tags
1637 template <>
1638 void Converter<DDLEllipticalTube>::operator()(xml_h element) const {
1639   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1640   xml_dim_t e(element);
1641   string nam = e.nameStr();
1642   double dx = ns.attr<double>(e, DD_CMU(xSemiAxis));
1643   double dy = ns.attr<double>(e, DD_CMU(ySemiAxis));
1644   double dz = ns.attr<double>(e, DD_CMU(zHeight));
1645 
1646 #ifdef EDM_ML_DEBUG
1647 
1648   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1649            "DD4CMS",
1650            "+   EllipticalTube xSemiAxis=%8.3f [cm] ySemiAxis=%8.3f [cm] zHeight=%8.3f [cm]",
1651            dx / dd4hep::cm,
1652            dy / dd4hep::cm,
1653            dz / dd4hep::cm);
1654 
1655 #endif
1656 
1657   ns.addSolid(nam, EllipticalTube(dx, dy, dz));
1658 }
1659 
1660 /// Converter for <Cone/> tags
1661 template <>
1662 void Converter<DDLCone>::operator()(xml_h element) const {
1663   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1664   xml_dim_t e(element);
1665   string nam = e.nameStr();
1666   double dz = ns.attr<double>(e, DD_CMU(dz));
1667   double rmin1 = ns.attr<double>(e, DD_CMU(rMin1));
1668   double rmin2 = ns.attr<double>(e, DD_CMU(rMin2));
1669   double rmax1 = ns.attr<double>(e, DD_CMU(rMax1));
1670   double rmax2 = ns.attr<double>(e, DD_CMU(rMax2));
1671   double startPhi = ns.attr<double>(e, DD_CMU(startPhi));
1672   double deltaPhi = ns.attr<double>(e, DD_CMU(deltaPhi));
1673   double phi2 = startPhi + deltaPhi;
1674 
1675 #ifdef EDM_ML_DEBUG
1676 
1677   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1678            "DD4CMS",
1679            "+   Cone:     dz=%8.3f [cm]"
1680            " rmin1=%8.3f [cm] rmax1=%8.3f [cm]"
1681            " rmin2=%8.3f [cm] rmax2=%8.3f [cm]"
1682            " startPhi=%8.3f [rad] deltaPhi=%8.3f [rad]",
1683            dz / dd4hep::cm,
1684            rmin1 / dd4hep::cm,
1685            rmax1 / dd4hep::cm,
1686            rmin2 / dd4hep::cm,
1687            rmax2 / dd4hep::cm,
1688            startPhi,
1689            deltaPhi);
1690 
1691 #endif
1692 
1693   ns.addSolid(nam, ConeSegment(dz, rmin1, rmax1, rmin2, rmax2, startPhi, phi2));
1694 }
1695 
1696 /// Converter for <Shapeless/> tags
1697 template <>
1698 void Converter<DDLShapeless>::operator()(xml_h element) const {
1699   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1700   xml_dim_t e(element);
1701   string nam = e.nameStr();
1702 
1703 #ifdef EDM_ML_DEBUG
1704 
1705   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1706            "DD4CMS",
1707            "+   Shapeless: THIS ONE CAN ONLY BE USED AT THE VOLUME LEVEL -> Shapeless: %s",
1708            nam.c_str());
1709 
1710 #endif
1711 
1712   ns.addSolid(nam, Box(1, 1, 1));
1713 }
1714 
1715 /// Converter for <Assembly/> tags
1716 template <>
1717 void Converter<DDLAssembly>::operator()(xml_h element) const {
1718   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1719   xml_dim_t e(element);
1720   string nam = e.nameStr();
1721 
1722 #ifdef EDM_ML_DEBUG
1723   printout(
1724       ns.context()->debug_shapes ? ALWAYS : DEBUG, "DD4CMS", "+   Assembly: Adding solid -> Assembly: %s", nam.c_str());
1725 #endif
1726 
1727   ns.addAssemblySolid(nam);
1728 }
1729 
1730 /// Converter for <Box/> tags
1731 template <>
1732 void Converter<DDLBox>::operator()(xml_h element) const {
1733   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1734   xml_dim_t e(element);
1735   string nam = e.nameStr();
1736   double dx = ns.attr<double>(e, DD_CMU(dx));
1737   double dy = ns.attr<double>(e, DD_CMU(dy));
1738   double dz = ns.attr<double>(e, DD_CMU(dz));
1739 
1740 #ifdef EDM_ML_DEBUG
1741 
1742   printout(ns.context()->debug_shapes ? ALWAYS : DEBUG,
1743            "DD4CMS",
1744            "+   Box:      dx=%10.3f [cm] dy=%10.3f [cm] dz=%10.3f [cm]",
1745            dx / dd4hep::cm,
1746            dy / dd4hep::cm,
1747            dz / dd4hep::cm);
1748 
1749 #endif
1750 
1751   ns.addSolid(nam, Box(dx, dy, dz));
1752 }
1753 
1754 /// DD4hep specific Converter for <Include/> tags: process only the constants
1755 template <>
1756 void Converter<include_load>::operator()(xml_h element) const {
1757   string fname = element.attr<string>(_U(ref));
1758   edm::FileInPath fp(fname);
1759   xml::Document doc;
1760   doc = xml::DocumentHandler().load(fp.fullPath());
1761 
1762 #ifdef EDM_ML_DEBUG
1763 
1764   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
1765            "DD4CMS",
1766            "+++ Processing the CMS detector description %s",
1767            fname.c_str());
1768 
1769 #endif
1770 
1771   _option<DDRegistry>()->includes.emplace_back(doc);
1772 }
1773 
1774 /// DD4hep specific Converter for <Include/> tags: process only the constants
1775 template <>
1776 void Converter<include_unload>::operator()(xml_h element) const {
1777   string fname = xml::DocumentHandler::system_path(element);
1778   xml::DocumentHolder(xml_elt_t(element).document()).assign(nullptr);
1779 
1780 #ifdef EDM_ML_DEBUG
1781 
1782   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
1783            "DD4CMS",
1784            "+++ Finished processing %s",
1785            fname.c_str());
1786 #endif
1787 }
1788 
1789 /// DD4hep specific Converter for <Include/> tags: process only the constants
1790 template <>
1791 void Converter<include_constants>::operator()(xml_h element) const {
1792   xml_coll_t(element, DD_CMU(ConstantsSection)).for_each(Converter<ConstantsSection>(description, param, optional));
1793 }
1794 
1795 namespace {
1796 
1797   //  The meaning of the axis index is the following:
1798   //    for all volumes having shapes like box, trd1, trd2, trap, gtra or para - 1,2,3 means X,Y,Z;
1799   //    for tube, tubs, cone, cons - 1 means Rxy, 2 means phi and 3 means Z;
1800   //    for pcon and pgon - 2 means phi and 3 means Z;
1801   //    for spheres 1 means R and 2 means phi.
1802 
1803   enum class DDAxes { x = 1, y = 2, z = 3, rho = 1, phi = 2, undefined };
1804   const std::map<std::string, DDAxes> axesmap{{"x", DDAxes::x},
1805                                               {"y", DDAxes::y},
1806                                               {"z", DDAxes::z},
1807                                               {"rho", DDAxes::rho},
1808                                               {"phi", DDAxes::phi},
1809                                               {"undefined", DDAxes::undefined}};
1810 }  // namespace
1811 
1812 /// Converter for <Division/> tags
1813 template <>
1814 void Converter<DDLDivision>::operator()(xml_h element) const {
1815   cms::DDNamespace ns(_param<cms::DDParsingContext>(), element);
1816   xml_dim_t e(element);
1817   string childName = e.nameStr();
1818   if (strchr(childName.c_str(), NAMESPACE_SEP) == nullptr)
1819     childName = ns.prepend(childName);
1820 
1821   string parentName = ns.attr<string>(e, DD_CMU(parent));
1822   if (strchr(parentName.c_str(), NAMESPACE_SEP) == nullptr)
1823     parentName = ns.prepend(parentName);
1824   string axis = ns.attr<string>(e, DD_CMU(axis));
1825 
1826   // If you divide a tube of 360 degrees the offset displaces
1827   // the starting angle, but you still fill the 360 degrees
1828   double offset = e.hasAttr(DD_CMU(offset)) ? ns.attr<double>(e, DD_CMU(offset)) : 0e0;
1829   double width = e.hasAttr(DD_CMU(width)) ? ns.attr<double>(e, DD_CMU(width)) : 0e0;
1830   int nReplicas = e.hasAttr(DD_CMU(nReplicas)) ? ns.attr<int>(e, DD_CMU(nReplicas)) : 0;
1831 
1832 #ifdef EDM_ML_DEBUG
1833 
1834   printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1835            "DD4CMS",
1836            "+++ Start executing Division of %s along %s (%d) with offset %6.3f and %6.3f to produce %s....",
1837            parentName.c_str(),
1838            axis.c_str(),
1839            axesmap.at(axis),
1840            offset,
1841            width,
1842            childName.c_str());
1843 
1844 #endif
1845 
1846   Volume parent = ns.volume(parentName);
1847 
1848   const TGeoShape* shape = parent.solid();
1849   TClass* cl = shape->IsA();
1850   if (cl == TGeoTubeSeg::Class()) {
1851     const TGeoTubeSeg* sh = (const TGeoTubeSeg*)shape;
1852     double widthInDeg = convertRadToDeg(width);
1853     double startInDeg = convertRadToDeg(offset);
1854     int numCopies = (int)((sh->GetPhi2() - sh->GetPhi1()) / widthInDeg);
1855 
1856 #ifdef EDM_ML_DEBUG
1857 
1858     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1859              "DD4CMS",
1860              "+++    ...divide %s along %s (%d) with offset %6.3f deg and %6.3f deg to produce %d copies",
1861              parent.solid().type(),
1862              axis.c_str(),
1863              axesmap.at(axis),
1864              startInDeg,
1865              widthInDeg,
1866              numCopies);
1867 
1868 #endif
1869 
1870     Volume child = parent.divide(childName, static_cast<int>(axesmap.at(axis)), numCopies, startInDeg, widthInDeg);
1871 
1872     ns.context()->volumes[childName] = child;
1873 
1874 #ifdef EDM_ML_DEBUG
1875 
1876     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1877              "DD4CMS",
1878              "+++ %s Parent: %-24s [%s] Child: %-32s [%s] is multivolume [%s]",
1879              e.tag().c_str(),
1880              parentName.c_str(),
1881              parent.isValid() ? "VALID" : "INVALID",
1882              child.name(),
1883              child.isValid() ? "VALID" : "INVALID",
1884              child->IsVolumeMulti() ? "YES" : "NO");
1885 #endif
1886 
1887   } else if (cl == TGeoTrd1::Class()) {
1888     double dy = static_cast<const TGeoTrd1*>(shape)->GetDy();
1889 
1890 #ifdef EDM_ML_DEBUG
1891 
1892     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1893              "DD4CMS",
1894              "+++    ...divide %s along %s (%d) with offset %6.3f cm and %6.3f cm to produce %d copies in %6.3f",
1895              parent.solid().type(),
1896              axis.c_str(),
1897              axesmap.at(axis),
1898              -dy + offset + width,
1899              width,
1900              nReplicas,
1901              dy);
1902 
1903 #endif
1904 
1905     Volume child = parent.divide(childName, static_cast<int>(axesmap.at(axis)), nReplicas, -dy + offset + width, width);
1906 
1907     ns.context()->volumes[childName] = child;
1908 
1909 #ifdef EDM_ML_DEBUG
1910 
1911     printout(ns.context()->debug_placements ? ALWAYS : DEBUG,
1912              "DD4CMS",
1913              "+++ %s Parent: %-24s [%s] Child: %-32s [%s] is multivolume [%s]",
1914              e.tag().c_str(),
1915              parentName.c_str(),
1916              parent.isValid() ? "VALID" : "INVALID",
1917              child.name(),
1918              child.isValid() ? "VALID" : "INVALID",
1919              child->IsVolumeMulti() ? "YES" : "NO");
1920 
1921 #endif
1922   } else {
1923     printout(ERROR, "DD4CMS", "++ FAILED Division of a %s is not implemented yet!", parent.solid().type());
1924   }
1925 }
1926 
1927 /// Converter for <Algorithm/> tags
1928 template <>
1929 void Converter<DDLAlgorithm>::operator()(xml_h element) const {
1930   cms::DDNamespace ns(_param<cms::DDParsingContext>());
1931   xml_dim_t e(element);
1932   string name = e.nameStr();
1933   size_t idx;
1934   string type = "DDCMS_" + ns.realName(name);
1935   while ((idx = type.find(NAMESPACE_SEP)) != string::npos)
1936     type[idx] = '_';
1937 
1938 #ifdef EDM_ML_DEBUG
1939 
1940   printout(
1941       ns.context()->debug_algorithms ? ALWAYS : DEBUG, "DD4CMS", "+++ Start executing algorithm %s....", type.c_str());
1942 
1943 #endif
1944 
1945   long ret = PluginService::Create<long>(type, &description, ns.context(), &element);
1946   if (ret == s_executed) {
1947 #ifdef EDM_ML_DEBUG
1948 
1949     printout(ns.context()->debug_algorithms ? ALWAYS : DEBUG,
1950 
1951              "DD4CMS",
1952              "+++ Executed algorithm: %08lX = %s",
1953              ret,
1954              name.c_str());
1955 
1956 #endif
1957     return;
1958   }
1959   printout(ERROR, "DD4CMS", "++ FAILED  NOT ADDING SUBDETECTOR %08lX = %s", ret, name.c_str());
1960 }
1961 
1962 template <class InputIt, class ForwardIt, class BinOp>
1963 void for_each_token(InputIt first, InputIt last, ForwardIt s_first, ForwardIt s_last, BinOp binary_op) {
1964   while (first != last) {
1965     const auto pos = std::find_first_of(first, last, s_first, s_last);
1966     binary_op(first, pos);
1967     if (pos == last)
1968       break;
1969     first = std::next(pos);
1970   }
1971 }
1972 
1973 namespace {
1974 
1975   std::vector<string> splitString(const string& str, const string& delims = ",") {
1976     std::vector<string> output;
1977 
1978     for_each_token(cbegin(str), cend(str), cbegin(delims), cend(delims), [&output](auto first, auto second) {
1979       if (first != second) {
1980         if (string(first, second).front() == '[' && string(first, second).back() == ']') {
1981           first++;
1982           second--;
1983         }
1984         output.emplace_back(string(first, second));
1985       }
1986     });
1987     return output;
1988   }
1989 
1990   std::vector<double> splitNumeric(const string& str, const string& delims = ",") {
1991     std::vector<double> output;
1992 
1993     for_each_token(cbegin(str), cend(str), cbegin(delims), cend(delims), [&output](auto first, auto second) {
1994       if (first != second) {
1995         if (string(first, second).front() == '[' && string(first, second).back() == ']') {
1996           first++;
1997           second--;
1998         }
1999         output.emplace_back(dd4hep::_toDouble(string(first, second)));
2000       }
2001     });
2002     return output;
2003   }
2004 }  // namespace
2005 
2006 /// Converter for <Vector/> tags
2007 /// FIXME: Check if(parent() == "Algorithm" || parent() == "SpecPar")
2008 template <>
2009 void Converter<DDLVector>::operator()(xml_h element) const {
2010   cms::DDNamespace ns(_param<cms::DDParsingContext>());
2011   cms::DDParsingContext* const context = ns.context();
2012   DDVectorsMap* registry = context->description.extension<DDVectorsMap>();
2013   xml_dim_t e(element);
2014   string name = ns.prepend(e.nameStr());
2015   string type = ns.attr<string>(e, _U(type));
2016   string nEntries = ns.attr<string>(e, DD_CMU(nEntries));
2017   string val = e.text();
2018   val.erase(remove_if(val.begin(), val.end(), [](unsigned char x) { return isspace(x); }), val.end());
2019 
2020 #ifdef EDM_ML_DEBUG
2021 
2022   printout(ns.context()->debug_constants ? ALWAYS : DEBUG,
2023            "DD4CMS",
2024            "+++ Vector<%s>:  %s[%s]: %s",
2025            type.c_str(),
2026            name.c_str(),
2027            nEntries.c_str(),
2028            val.c_str());
2029 
2030 #endif
2031 
2032   try {
2033     std::vector<double> results = splitNumeric(val);
2034     registry->insert(
2035         {name,
2036          results});  //tbb::concurrent_vector<double, tbb::cache_aligned_allocator<double>>(results.begin(), results.end())});
2037   } catch (const exception& e) {
2038 #ifdef EDM_ML_DEBUG
2039 
2040     printout(INFO,
2041              "DD4CMS",
2042              "++ Unresolved Vector<%s>:  %s[%s]: %s. Try to resolve later. [%s]",
2043              type.c_str(),
2044              name.c_str(),
2045              nEntries.c_str(),
2046              val.c_str(),
2047              e.what());
2048 
2049 #endif
2050 
2051     std::vector<string> results = splitString(val);
2052     context->unresolvedVectors.insert({name, results});
2053   }
2054 }
2055 
2056 template <>
2057 void Converter<debug>::operator()(xml_h dbg) const {
2058   cms::DDNamespace ns(_param<cms::DDParsingContext>());
2059   if (dbg.hasChild(DD_CMU(debug_constants)))
2060     ns.setContext()->debug_constants = true;
2061   if (dbg.hasChild(DD_CMU(debug_materials)))
2062     ns.setContext()->debug_materials = true;
2063   if (dbg.hasChild(DD_CMU(debug_rotations)))
2064     ns.setContext()->debug_rotations = true;
2065   if (dbg.hasChild(DD_CMU(debug_shapes)))
2066     ns.setContext()->debug_shapes = true;
2067   if (dbg.hasChild(DD_CMU(debug_volumes)))
2068     ns.setContext()->debug_volumes = true;
2069   if (dbg.hasChild(DD_CMU(debug_placements)))
2070     ns.setContext()->debug_placements = true;
2071   if (dbg.hasChild(DD_CMU(debug_namespaces)))
2072     ns.setContext()->debug_namespaces = true;
2073   if (dbg.hasChild(DD_CMU(debug_includes)))
2074     ns.setContext()->debug_includes = true;
2075   if (dbg.hasChild(DD_CMU(debug_algorithms)))
2076     ns.setContext()->debug_algorithms = true;
2077   if (dbg.hasChild(DD_CMU(debug_specpars)))
2078     ns.setContext()->debug_specpars = true;
2079 }
2080 
2081 template <>
2082 void Converter<DDRegistry>::operator()(xml_h /* element */) const {
2083   cms::DDParsingContext* context = _param<cms::DDParsingContext>();
2084   DDRegistry* res = _option<DDRegistry>();
2085   cms::DDNamespace ns(context);
2086   int count = 0;
2087 
2088 #ifdef EDM_ML_DEBUG
2089 
2090   printout(context->debug_constants ? ALWAYS : DEBUG,
2091            "DD4CMS",
2092            "+++ RESOLVING %ld unknown constants..... (out of %ld)",
2093            res->unresolvedConst.size(),
2094            res->originalConst.size());
2095 #endif
2096 
2097   while (!res->unresolvedConst.empty()) {
2098     for (auto& i : res->unresolvedConst) {
2099       const string& n = i.first;
2100       string rep;
2101       string& v = i.second;
2102       size_t idx, idq;
2103       for (idx = v.find('[', 0); idx != string::npos; idx = v.find('[', idx + 1)) {
2104         idq = v.find(']', idx + 1);
2105         rep = v.substr(idx + 1, idq - idx - 1);
2106         auto r = res->originalConst.find(rep);
2107         if (r != res->originalConst.end()) {
2108           rep = "(" + (*r).second + ")";
2109           v.replace(idx, idq - idx + 1, rep);
2110         }
2111       }
2112       if (v.find(']') == string::npos) {
2113         if (v.find("-+") != string::npos || v.find("+-") != string::npos) {
2114           while ((idx = v.find("-+")) != string::npos)
2115             v.replace(idx, 2, "-");
2116           while ((idx = v.find("+-")) != string::npos)
2117             v.replace(idx, 2, "-");
2118         }
2119 
2120 #ifdef EDM_ML_DEBUG
2121 
2122         printout(context->debug_constants ? ALWAYS : DEBUG,
2123                  "DD4CMS",
2124                  "+++ [%06ld] ----------  %-40s = %s",
2125                  res->unresolvedConst.size() - 1,
2126                  n.c_str(),
2127                  res->originalConst[n].c_str());
2128 
2129 #endif
2130 
2131         ns.addConstantNS(n, v, "number");
2132         res->unresolvedConst.erase(n);
2133         break;
2134       }
2135     }
2136     if (++count > 10000)
2137       break;
2138   }
2139   if (!res->unresolvedConst.empty()) {
2140     for (const auto& e : res->unresolvedConst)
2141       printout(ERROR, "DD4CMS", "+++ Unresolved constant: %-40s = %s.", e.first.c_str(), e.second.c_str());
2142     except("DD4CMS", "++ FAILED to resolve %ld constant entries:", res->unresolvedConst.size());
2143   }
2144   res->unresolvedConst.clear();
2145   res->originalConst.clear();
2146 }
2147 
2148 template <>
2149 void Converter<print_xml_doc>::operator()(xml_h element) const {
2150   string fname = xml::DocumentHandler::system_path(element);
2151 
2152 #ifdef EDM_ML_DEBUG
2153 
2154   printout(_param<cms::DDParsingContext>()->debug_includes ? ALWAYS : DEBUG,
2155            "DD4CMS",
2156            "+++ Processing data from: %s",
2157            fname.c_str());
2158 
2159 #endif
2160 }
2161 
2162 /// Converter for <DDDefinition/> tags
2163 static long load_dddefinition(Detector& det, xml_h element) {
2164   xml_elt_t dddef(element);
2165   if (dddef) {
2166     cms::DDParsingContext& context = *det.extension<DDParsingContext>();
2167     cms::DDNamespace ns(context);
2168     ns.addConstantNS("world_x", "101*m", "number");
2169     ns.addConstantNS("world_y", "101*m", "number");
2170     ns.addConstantNS("world_z", "450*m", "number");
2171     ns.addConstantNS("Air", "materials:Air", "string");
2172     ns.addConstantNS("Vacuum", "materials:Vacuum", "string");
2173 
2174     string fname = xml::DocumentHandler::system_path(element);
2175     bool open_geometry = dddef.hasChild(DD_CMU(open_geometry)) ? dddef.child(DD_CMU(open_geometry)) : true;
2176     bool close_geometry = dddef.hasChild(DD_CMU(close_geometry)) ? dddef.hasChild(DD_CMU(close_geometry)) : true;
2177 
2178     xml_coll_t(dddef, _U(debug)).for_each(Converter<debug>(det, &context));
2179 
2180     // Here we define the order how XML elements are processed.
2181     // Be aware of dependencies. This can only defined once.
2182     // At the end it is a limitation of DOM....
2183     printout(INFO, "DD4CMS", "+++ Processing the CMS detector description %s", fname.c_str());
2184 
2185     xml::Document doc;
2186     Converter<print_xml_doc> print_doc(det, &context);
2187     try {
2188       DDRegistry res;
2189       res.unresolvedConst.reserve(2000);
2190       res.originalConst.reserve(6000);
2191       print_doc((doc = dddef.document()).root());
2192       xml_coll_t(dddef, DD_CMU(ConstantsSection)).for_each(Converter<ConstantsSection>(det, &context, &res));
2193       xml_coll_t(dddef, DD_CMU(RotationSection)).for_each(Converter<RotationSection>(det, &context));
2194       xml_coll_t(dddef, DD_CMU(MaterialSection)).for_each(Converter<MaterialSection>(det, &context));
2195 
2196       xml_coll_t(dddef, DD_CMU(IncludeSection)).for_each(DD_CMU(Include), Converter<include_load>(det, &context, &res));
2197 
2198       for (xml::Document d : res.includes) {
2199         print_doc((doc = d).root());
2200         Converter<include_constants>(det, &context, &res)((doc = d).root());
2201       }
2202       // Before we continue, we have to resolve all constants NOW!
2203       Converter<DDRegistry>(det, &context, &res)(dddef);
2204       {
2205         DDVectorsMap* registry = context.description.extension<DDVectorsMap>();
2206 
2207         printout(context.debug_constants ? ALWAYS : DEBUG,
2208                  "DD4CMS",
2209                  "+++ RESOLVING %ld Vectors.....",
2210                  context.unresolvedVectors.size());
2211 
2212         while (!context.unresolvedVectors.empty()) {
2213           for (auto it = context.unresolvedVectors.begin(); it != context.unresolvedVectors.end();) {
2214             std::vector<double> result;
2215             for (const auto& i : it->second) {
2216               result.emplace_back(dd4hep::_toDouble(i));
2217             }
2218             registry->insert({it->first, result});
2219             // All components are resolved
2220             it = context.unresolvedVectors.erase(it);
2221           }
2222         }
2223       }
2224       // Now we can process the include files one by one.....
2225       for (xml::Document d : res.includes) {
2226         print_doc((doc = d).root());
2227         xml_coll_t(d.root(), DD_CMU(MaterialSection)).for_each(Converter<MaterialSection>(det, &context));
2228       }
2229       if (open_geometry) {
2230         det.init();
2231         ns.addVolume(det.worldVolume());
2232       }
2233       for (xml::Document d : res.includes) {
2234         print_doc((doc = d).root());
2235         xml_coll_t(d.root(), DD_CMU(RotationSection)).for_each(Converter<RotationSection>(det, &context));
2236       }
2237       for (xml::Document d : res.includes) {
2238         print_doc((doc = d).root());
2239         xml_coll_t(d.root(), DD_CMU(SolidSection)).for_each(Converter<SolidSection>(det, &context));
2240       }
2241       for (xml::Document d : res.includes) {
2242         print_doc((doc = d).root());
2243         xml_coll_t(d.root(), DD_CMU(LogicalPartSection)).for_each(Converter<LogicalPartSection>(det, &context));
2244       }
2245       for (xml::Document d : res.includes) {
2246         print_doc((doc = d).root());
2247         xml_coll_t(d.root(), DD_CMU(Algorithm)).for_each(Converter<DDLAlgorithm>(det, &context));
2248       }
2249       for (xml::Document d : res.includes) {
2250         print_doc((doc = d).root());
2251         xml_coll_t(d.root(), DD_CMU(PosPartSection)).for_each(Converter<PosPartSection>(det, &context));
2252       }
2253       for (xml::Document d : res.includes) {
2254         print_doc((doc = d).root());
2255         xml_coll_t(d.root(), DD_CMU(SpecParSection)).for_each(Converter<SpecParSection>(det, &context));
2256       }
2257 
2258       /// Unload all XML files after processing
2259       for (xml::Document d : res.includes)
2260         Converter<include_unload>(det, &context, &res)(d.root());
2261 
2262       print_doc((doc = dddef.document()).root());
2263       // Now process the actual geometry items
2264       xml_coll_t(dddef, DD_CMU(SolidSection)).for_each(Converter<SolidSection>(det, &context));
2265       {
2266         // Before we continue, we have to resolve all shapes NOW!
2267         // Note: This only happens in a legacy DB payloads where
2268         // boolean shapes can be defined before thier
2269         // component shapes
2270 
2271         while (!context.unresolvedShapes.empty()) {
2272           for (auto it = context.unresolvedShapes.begin(); it != context.unresolvedShapes.end();) {
2273             auto const& name = it->first;
2274             auto const& aname = std::visit([](auto&& arg) -> std::string { return arg.firstSolidName; }, it->second);
2275             auto const& bname = std::visit([](auto&& arg) -> std::string { return arg.secondSolidName; }, it->second);
2276 
2277             auto const& ait = context.shapes.find(aname);
2278             if (ait->second.isValid()) {
2279               auto const& bit = context.shapes.find(bname);
2280               if (bit->second.isValid()) {
2281                 dd4hep::Solid shape =
2282                     std::visit([&ait, &bit](auto&& arg) -> dd4hep::Solid { return arg.make(ait->second, bit->second); },
2283                                it->second);
2284                 context.shapes[name] = shape;
2285                 it = context.unresolvedShapes.erase(it);
2286               } else
2287                 ++it;
2288             } else
2289               ++it;
2290           }
2291         }
2292       }
2293       xml_coll_t(dddef, DD_CMU(LogicalPartSection)).for_each(Converter<LogicalPartSection>(det, &context));
2294       xml_coll_t(dddef, DD_CMU(Algorithm)).for_each(Converter<DDLAlgorithm>(det, &context));
2295       xml_coll_t(dddef, DD_CMU(PosPartSection)).for_each(Converter<PosPartSection>(det, &context));
2296       xml_coll_t(dddef, DD_CMU(SpecParSection)).for_each(Converter<SpecParSection>(det, &context));
2297     } catch (const exception& e) {
2298       printout(ERROR, "DD4CMS", "Exception while processing xml source:%s", doc.uri().c_str());
2299       printout(ERROR, "DD4CMS", "----> %s", e.what());
2300       throw;
2301     }
2302 
2303     /// This should be the end of all processing....close the geometry
2304     if (close_geometry) {
2305       Volume wv = det.worldVolume();
2306       Volume geomv = ns.volume("cms:OCMS", false);
2307       if (geomv.isValid())
2308         wv.placeVolume(geomv, 1);
2309       Volume mfv = ns.volume("cmsMagneticField:MAGF", false);
2310       if (mfv.isValid())
2311         wv.placeVolume(mfv, 1);
2312       Volume mfv1 = ns.volume("MagneticFieldVolumes:MAGF", false);
2313       if (mfv1.isValid())
2314         wv.placeVolume(mfv1, 1);
2315 
2316       // Can not deal with reflections without closed geometry
2317       det.manager().CloseGeometry("nv");
2318 
2319       det.endDocument();
2320     }
2321     printout(INFO, "DDDefinition", "+++ Finished processing %s", fname.c_str());
2322     return 1;
2323   }
2324   except("DDDefinition", "+++ FAILED to process unknown DOM tree [Invalid Handle]");
2325   return 0;
2326 }
2327 
2328 // Now declare the factory entry for the plugin mechanism
2329 DECLARE_XML_DOC_READER(DDDefinition, load_dddefinition)