Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-05 08:16:12

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 //
0014 // Main conversion operations for the compact notation.
0015 // - Create elements, materials, etc.
0016 // - Calls detector construction factories.
0017 //
0018 //==========================================================================
0019 //
0020 // Framework includes
0021 #include <DD4hep/DetFactoryHelper.h>
0022 #include <DD4hep/DetectorTools.h>
0023 #include <DD4hep/MatrixHelpers.h>
0024 #include <DD4hep/PropertyTable.h>
0025 #include <DD4hep/OpticalSurfaces.h>
0026 #include <DD4hep/OpticalSurfaceManager.h>
0027 #include <DD4hep/IDDescriptor.h>
0028 #include <DD4hep/DD4hepUnits.h>
0029 #include <DD4hep/FieldTypes.h>
0030 #include <DD4hep/Printout.h>
0031 #include <DD4hep/Factories.h>
0032 #include <DD4hep/Path.h>
0033 #include <DD4hep/Plugins.h>
0034 #include <DD4hep/detail/SegmentationsInterna.h>
0035 #include <DD4hep/detail/DetectorInterna.h>
0036 #include <DD4hep/detail/ObjectsInterna.h>
0037 
0038 #include <XML/DocumentHandler.h>
0039 #include <XML/Utilities.h>
0040 
0041 // Root/TGeo include files
0042 #include <TGeoManager.h>
0043 #include <TGeoMaterial.h>
0044 #include <TGeoPhysicalConstants.h>
0045 #include <TGDMLMatrix.h>
0046 #include <TMath.h>
0047 
0048 // C/C++ include files
0049 #include <filesystem>
0050 #include <iostream>
0051 #include <climits>
0052 #include <set>
0053 
0054 using namespace dd4hep;
0055 
0056 /// Namespace for the AIDA detector description toolkit
0057 namespace dd4hep {
0058 
0059   class Debug;
0060   class World;
0061   class Isotope;
0062   class Plugin;
0063   class Compact;
0064   class Includes;
0065   class IncludeFile;
0066   class Property;
0067   class XMLFile;
0068   class JsonFile;
0069   class PropertyConstant;
0070   class Parallelworld_Volume;
0071   class DetElementInclude;
0072   class STD_Conditions;
0073   
0074   /// Converter instances implemented in this compilation unit
0075   template <> void Converter<Debug>::operator()(xml_h element) const;
0076   template <> void Converter<World>::operator()(xml_h element) const;
0077   template <> void Converter<Plugin>::operator()(xml_h element) const;
0078   template <> void Converter<Constant>::operator()(xml_h element) const;
0079   template <> void Converter<Material>::operator()(xml_h element) const;
0080   template <> void Converter<Atom>::operator()(xml_h element) const;
0081   template <> void Converter<Isotope>::operator()(xml_h element) const;
0082   template <> void Converter<VisAttr>::operator()(xml_h element) const;
0083   template <> void Converter<Region>::operator()(xml_h element) const;
0084   template <> void Converter<Readout>::operator()(xml_h element) const;
0085   template <> void Converter<Segmentation>::operator()(xml_h element) const;
0086   template <> void Converter<LimitSet>::operator()(xml_h element) const;
0087   template <> void Converter<Property>::operator()(xml_h element) const;
0088   template <> void Converter<CartesianField>::operator()(xml_h element) const;
0089   template <> void Converter<SensitiveDetector>::operator()(xml_h element) const;
0090   template <> void Converter<OpticalSurface>::operator()(xml_h element) const;
0091   template <> void Converter<PropertyTable>::operator()(xml_h element) const;
0092   template <> void Converter<PropertyConstant>::operator()(xml_h element) const;
0093   template <> void Converter<DetElement>::operator()(xml_h element) const;
0094   template <> void Converter<STD_Conditions>::operator()(xml_h element) const;
0095   template <> void Converter<IncludeFile>::operator()(xml_h element) const;
0096   template <> void Converter<JsonFile>::operator()(xml_h element) const;
0097   template <> void Converter<XMLFile>::operator()(xml_h element) const;
0098   template <> void Converter<Header>::operator()(xml_h element) const;
0099   template <> void Converter<DetElementInclude>::operator()(xml_h element) const;
0100   template <> void Converter<Parallelworld_Volume>::operator()(xml_h element) const;
0101   template <> void Converter<Compact>::operator()(xml_h element) const;
0102 }
0103 
0104 namespace {
0105   static UInt_t unique_mat_id = 0xAFFEFEED;
0106   void throw_print(const std::string& msg) {
0107     printout(ERROR, "Compact", msg.c_str());
0108     throw std::runtime_error(msg);
0109   }
0110   class DebugOptions  {
0111   public:
0112     bool readout      = false;
0113     bool regions      = false;
0114     bool limits       = false;
0115     bool visattr      = false;
0116     bool isotopes     = false;
0117     bool elements     = false;
0118     bool materials    = false;
0119     bool segmentation = false;
0120     bool constants    = false;
0121     bool includes     = false;
0122     bool matrix       = false;
0123     bool surface      = false;
0124     bool detelements  = false;
0125     bool include_guard= true;
0126   } s_debug;
0127 }
0128 
0129 static Ref_t create_ConstantField(Detector& description, xml_h e) {
0130   CartesianField obj;
0131   xml_comp_t    field(e), strength(e.child(_U(strength)));
0132   xml_dim_t     solid = field.child(_U(shape), false);
0133   std::string   type  = e.attr<std::string>(_U(field));
0134   ConstantField* ptr  = new ConstantField();
0135 
0136   ptr->field_type = ::toupper(type[0]) == 'E' ? CartesianField::ELECTRIC : CartesianField::MAGNETIC;
0137   ptr->direction.SetX(strength.x());
0138   ptr->direction.SetY(strength.y());
0139   ptr->direction.SetZ(strength.z());
0140   ptr->flag = 0;
0141   if ( solid )  { // Shape is not mandatory
0142     std::string    solid_type = solid.typeStr();
0143     xml_dim_t      _pos = solid.child(_U(position), false);
0144     xml_dim_t      _rot = solid.child(_U(rotation), false);
0145     RotationZYX     rot;
0146     Position        pos;
0147     ptr->volume = xml::createShape(description, solid_type, solid);
0148     ptr->flag |= ConstantField::FIELD_LOCAL;
0149     if( _pos )  {
0150       ptr->flag |= ConstantField::FIELD_TRANSLATED;
0151       pos.SetXYZ(_pos.x(), _pos.y(), _pos.z());
0152     }
0153     if( _rot )  {
0154       ptr->flag |= ConstantField::FIELD_ROTATED;
0155       rot.SetComponents(_rot.z(), _rot.y(), _rot.x());
0156     }
0157     auto tr = Transform3D(rot, pos);
0158     ptr->inverse_pos = tr.Inverse();
0159   }
0160   obj.assign(ptr, field.nameStr(), field.typeStr());
0161   return obj;
0162 }
0163 DECLARE_XMLELEMENT(ConstantField,create_ConstantField)
0164 
0165 static Ref_t create_SolenoidField(Detector& description, xml_h e) {
0166   xml_comp_t c(e);
0167   bool has_inner_radius = c.hasAttr(_U(inner_radius));
0168   bool has_outer_radius = c.hasAttr(_U(outer_radius));
0169 
0170   if (!has_inner_radius && !has_outer_radius) {
0171     throw_print("Compact2Objects[ERROR]: For a solenoidal field at least one of the "
0172                 " xml attributes inner_radius of outer_radius MUST be set.");
0173   }
0174   CartesianField obj;
0175   SolenoidField* ptr = new SolenoidField();
0176   //
0177   // This logic is a bit weird, but has its origin in the compact syntax:
0178   // If no "inner_radius" is given, the "outer_radius" IS the "inner_radius"
0179   // and the "outer_radius" is given by one side of the world volume's box
0180   //
0181   if (has_inner_radius && has_outer_radius) {
0182     ptr->innerRadius = c.attr<double>(_U(inner_radius));
0183     ptr->outerRadius = c.attr<double>(_U(outer_radius));
0184   }
0185   else if (has_inner_radius) {
0186     Box box = description.worldVolume().solid();
0187     ptr->innerRadius = c.attr<double>(_U(inner_radius));
0188     ptr->outerRadius = box.x();
0189   }
0190   else if (has_outer_radius) {
0191     Box box = description.worldVolume().solid();
0192     ptr->innerRadius = c.attr<double>(_U(outer_radius));
0193     ptr->outerRadius = box.x();
0194   }
0195   if (c.hasAttr(_U(inner_field)))
0196     ptr->innerField = c.attr<double>(_U(inner_field));
0197   if (c.hasAttr(_U(outer_field)))
0198     ptr->outerField = c.attr<double>(_U(outer_field));
0199   if (c.hasAttr(_U(zmax)))
0200     ptr->maxZ = c.attr<double>(_U(zmax));
0201   else
0202     ptr->maxZ = description.constant<double>("world_side");
0203   if (c.hasAttr(_U(zmin)))
0204     ptr->minZ = c.attr<double>(_U(zmin));
0205   else
0206     ptr->minZ = -ptr->maxZ;
0207   ptr->field_type = CartesianField::MAGNETIC;
0208   obj.assign(ptr, c.nameStr(), c.typeStr());
0209   return obj;
0210 }
0211 DECLARE_XMLELEMENT(SolenoidMagnet,create_SolenoidField)
0212 // This is the plugin required for slic: note the different name
0213 DECLARE_XMLELEMENT(solenoid,create_SolenoidField)
0214 
0215 static Ref_t create_DipoleField(Detector& /* description */, xml_h e) {
0216   xml_comp_t c(e);
0217   CartesianField obj;
0218   DipoleField*   ptr   = new DipoleField();
0219   double         lunit = c.hasAttr(_U(lunit)) ? c.attr<double>(_U(lunit)) : 1.0;
0220   double         funit = c.hasAttr(_U(funit)) ? c.attr<double>(_U(funit)) : 1.0;
0221   double         val, mult = funit;
0222 
0223   if (c.hasAttr(_U(zmin)))
0224     ptr->zmin = _multiply<double>(c.attr<std::string>(_U(zmin)), lunit);
0225   if (c.hasAttr(_U(zmax)))
0226     ptr->zmax = _multiply<double>(c.attr<std::string>(_U(zmax)), lunit);
0227   if (c.hasAttr(_U(rmax)))
0228     ptr->rmax = _multiply<double>(c.attr<std::string>(_U(rmax)), lunit);
0229   for (xml_coll_t coll(c, _U(dipole_coeff)); coll; ++coll, mult /= lunit) {
0230     xml_dim_t coeff = coll;
0231     if ( coeff.hasAttr(_U(value)) )
0232       val = coll.attr<double>(_U(value)) * mult;
0233     else if ( coeff.hasAttr(_U(coefficient)) )
0234       val = coeff.coefficient() * mult;
0235     else
0236       val = _multiply<double>(coll.text(), mult);
0237     ptr->coefficents.emplace_back(val);
0238   }
0239   ptr->field_type = CartesianField::MAGNETIC;
0240   obj.assign(ptr, c.nameStr(), c.typeStr());
0241   return obj;
0242 }
0243 DECLARE_XMLELEMENT(DipoleMagnet,create_DipoleField)
0244 
0245 static Ref_t create_MultipoleField(Detector& description, xml_h e) {
0246   xml_dim_t c(e), child;
0247   CartesianField  obj;
0248   MultipoleField* ptr = new MultipoleField();
0249   double          lunit = c.hasAttr(_U(lunit)) ? c.attr<double>(_U(lunit)) : 1.0;
0250   double          funit = c.hasAttr(_U(funit)) ? c.attr<double>(_U(funit)) : 1.0;
0251   double          val, mult = funit, bz = 0.0;
0252   RotationZYX     rot;
0253   Position        pos;
0254 
0255   if (c.hasAttr(_U(Z))) bz = c.Z() * funit;
0256   if ((child = c.child(_U(position), false))) {   // Position is not mandatory!
0257     pos.SetXYZ(child.x(), child.y(), child.z());
0258   }
0259   if ((child = c.child(_U(rotation), false))) {   // Rotation is not mandatory
0260     rot.SetComponents(child.z(), child.y(), child.x());
0261   }
0262   if ((child = c.child(_U(shape), false))) {      // Shape is not mandatory
0263     std::string type = child.typeStr();
0264     ptr->volume = xml::createShape(description, type, child);
0265   }
0266   ptr->B_z = bz;
0267   ptr->transform = Transform3D(rot,pos);
0268   for (xml_coll_t coll(c, _U(coefficient)); coll; ++coll, mult /= lunit) {
0269     xml_dim_t coeff = coll;
0270     if ( coll.hasAttr(_U(value)) )
0271       val = coll.attr<double>(_U(value)) * mult;
0272     else
0273       val = coeff.coefficient(0.0) * mult;
0274     ptr->coefficents.emplace_back(val);
0275     val = coeff.skew(0.0) * mult;
0276     ptr->skews.emplace_back(val);
0277   }
0278   ptr->field_type = CartesianField::MAGNETIC;
0279   obj.assign(ptr, c.nameStr(), c.typeStr());
0280   return obj;
0281 }
0282 DECLARE_XMLELEMENT(MultipoleMagnet,create_MultipoleField)
0283 
0284 static long load_Compact(Detector& description, xml_h element) {
0285   Converter<Compact>converter(description);
0286   converter(element);
0287   return 1;
0288 }
0289 DECLARE_XML_DOC_READER(lccdd,load_Compact)
0290 DECLARE_XML_DOC_READER(compact,load_Compact)
0291 
0292 // We create out own type to avoid a class over the extension types
0293 // attached to the Detector as a set of std::string is common.
0294 class ProcessedFilesSet: public std::set<std::string> {};
0295 
0296 /// Check whether a XML file was already processed
0297 bool check_process_file(Detector& description, std::string filename) {
0298 
0299   // In order to have a global compact that is kept across plugin invocations
0300   // we add it as an extension to the the detector description.
0301   auto already_processed = description.extension<ProcessedFilesSet>( false );
0302   if ( !already_processed ) {
0303     already_processed = new ProcessedFilesSet( );
0304     description.addExtension<ProcessedFilesSet>(already_processed );
0305   }
0306   std::string npath = dd4hep::Path{filename}.normalize();
0307   if (already_processed->find(npath) != already_processed->end() ) {
0308     printout(INFO, "Compact","++ Already processed xml document %s.", npath.c_str());
0309     return true;
0310   }
0311   already_processed->insert(npath);
0312   return false;
0313 }
0314 
0315 /** Convert parser debug flags.
0316  */
0317 template <> void Converter<Debug>::operator()(xml_h e) const {
0318   for (xml_coll_t coll(e, _U(type)); coll; ++coll) {
0319     int    val = coll.attr<int>(_U(value));
0320     std::string nam = coll.attr<std::string>(_U(name));
0321     if      ( nam.substr(0,6) == "isotop" ) s_debug.isotopes     = (0 != val);
0322     else if ( nam.substr(0,6) == "elemen" ) s_debug.elements     = (0 != val);
0323     else if ( nam.substr(0,6) == "materi" ) s_debug.materials    = (0 != val);
0324     else if ( nam.substr(0,6) == "visatt" ) s_debug.visattr      = (0 != val);
0325     else if ( nam.substr(0,6) == "region" ) s_debug.regions      = (0 != val);
0326     else if ( nam.substr(0,6) == "readou" ) s_debug.readout      = (0 != val);
0327     else if ( nam.substr(0,6) == "limits" ) s_debug.limits       = (0 != val);
0328     else if ( nam.substr(0,6) == "segmen" ) s_debug.segmentation = (0 != val);
0329     else if ( nam.substr(0,6) == "consta" ) s_debug.constants    = (0 != val);
0330     else if ( nam.substr(0,6) == "define" ) s_debug.constants    = (0 != val);
0331     else if ( nam.substr(0,6) == "includ" ) s_debug.includes     = (0 != val);
0332     else if ( nam.substr(0,6) == "matrix" ) s_debug.matrix       = (0 != val);
0333     else if ( nam.substr(0,6) == "surfac" ) s_debug.surface      = (0 != val);
0334     else if ( nam.substr(0,6) == "incgua" ) s_debug.include_guard= (0 != val);
0335     else if ( nam.substr(0,6) == "detele" ) s_debug.detelements  = (0 != val);
0336   }
0337 }
0338   
0339 /** Convert/execute plugin objects from the xml (plugins)
0340  *
0341  *
0342  */
0343 template <> void Converter<Plugin>::operator()(xml_h e) const {
0344   xml_comp_t  plugin(e);
0345   std::string name = plugin.nameStr();
0346   std::string type = "default";
0347 
0348   if ( xml_attr_t typ_attr = e.attr_nothrow(_U(type)) )   {
0349     type = e.attr<std::string>(typ_attr);
0350   }
0351   if ( type == "default" )  {
0352     std::vector<char*> argv;
0353     std::vector<std::string> arguments;
0354     for (xml_coll_t coll(e, _U(arg)); coll; ++coll) {
0355       std::string val = coll.attr<std::string>(_U(value));
0356       arguments.emplace_back(val);
0357     }
0358     for (xml_coll_t coll(e, _U(argument)); coll; ++coll) {
0359       std::string val = coll.attr<std::string>(_U(value));
0360       arguments.emplace_back(val);
0361     }
0362     for(std::vector<std::string>::iterator i=arguments.begin(); i!=arguments.end(); ++i)
0363       argv.emplace_back(&((*i)[0]));
0364     description.apply(name.c_str(),int(argv.size()), argv.empty() ? nullptr : &argv[0]);
0365     return;
0366   }
0367   // Call a custom plugin taking the xml element as an argument
0368   long result = PluginService::Create<long>(name, &description, &e);
0369   if (0 == result) {
0370     PluginDebug dbg;
0371     result = PluginService::Create<long>(name, &description, &e);
0372     if ( 0 == result )  {
0373       except("Compact","++ Failed to locate plugin %s - no factory: %s",
0374              name.c_str(), dbg.missingFactory(name).c_str());
0375     }
0376   }
0377   result = *(long*) result;
0378   if (result != 1) {
0379     except("Compact","++ Failed to execute plugin %s", name.c_str());
0380   }
0381 }
0382 
0383 /** Convert compact constant objects (defines)
0384  *
0385  *
0386  */
0387 template <> void Converter<Constant>::operator()(xml_h e) const {
0388   if ( e.tag() != "include" )   {
0389     xml_ref_t constant(e);
0390     std::string nam = constant.attr<std::string>(_U(name));
0391     std::string val = constant.attr<std::string>(_U(value));
0392     std::string typ = constant.hasAttr(_U(type)) ? constant.attr<std::string>(_U(type)) : "number";
0393     Constant c(nam, val, typ);
0394     _toDictionary(nam, val, typ);
0395     description.addConstant(c);
0396     if ( s_debug.constants )   {
0397       printout(ALWAYS, "Compact",
0398                "++ Converting constant %-16s = %-32s [%s]", nam.c_str(), val.c_str(), typ.c_str());
0399     }
0400     return;
0401   }
0402   xml::DocumentHolder doc(xml::DocumentHandler().load(e, e.attr_value(_U(ref))));
0403   if ( s_debug.includes )   {
0404     printout(ALWAYS, "Compact","++ Processing xml document %s.",doc.uri().c_str()); 
0405   }
0406   xml_h root = doc.root();
0407   xml_coll_t(root, _U(define)).for_each(_U(constant), Converter<Constant>(description));
0408   xml_coll_t(root, _U(constant)).for_each(Converter<Constant>(description));
0409 }
0410 
0411 /** Convert compact constant objects (defines)
0412  *
0413  *
0414  */
0415 template <> void Converter<Header>::operator()(xml_h e) const {
0416   xml_comp_t c(e);
0417   Header h = description.header();
0418   if( !h.isValid() )  {
0419     h = Header(e.attr<std::string>(_U(name)), e.attr<std::string>(_U(title), "Undefined"));
0420     h.setUrl(e.attr<std::string>(_U(url), "Undefined"));
0421     h.setAuthor(e.attr<std::string>(_U(author), "Undefined"));
0422     h.setStatus(e.attr<std::string>(_U(status), "development"));
0423     h.setVersion(e.attr<std::string>(_U(version), "Undefined"));
0424     h.setComment(e.hasChild(_U(comment)) ? e.child(_U(comment)).text() : "No Comment");
0425     description.setHeader(h);
0426     return;
0427   }
0428   printout(INFO, "Compact", "++ Overwriting/updating Header structure is dangerous. Try to avoid this.");
0429   printout(INFO, "Compact", "++     Header definition in: %s", xml::DocumentHandler::system_path(e).c_str());
0430   if( e.hasAttr(_U(comment)) ) h.setComment(e.attr<std::string>(_U(comment)).c_str());
0431   if( e.hasAttr(_U(version)) ) h.setVersion(e.attr<std::string>(_U(version)).c_str());
0432   if( e.hasAttr(_U(author)) ) h.setAuthor(e.attr<std::string>(_U(author)).c_str());
0433   if( e.hasAttr(_U(status)) ) h.setStatus(e.attr<std::string>(_U(status)).c_str());
0434   if( e.hasAttr(_U(title)) ) h.setTitle(e.attr<std::string>(_U(title)).c_str());
0435   if( e.hasAttr(_U(name)) ) h.setName(e.attr<std::string>(_U(name)).c_str());
0436   if( e.hasAttr(_U(url)) ) h.setUrl(e.attr<std::string>(_U(url)).c_str());
0437 }
0438 
0439 /** Convert compact material/element description objects
0440  *
0441  *  Materials:
0442  *  <material name="Air">
0443  *    <D type="density" unit="g/cm3" value="0.0012"/>
0444  *    <fraction n="0.754" ref="N"/>
0445  *    <fraction n="0.234" ref="O"/>
0446  *    <fraction n="0.012" ref="Ar"/>
0447  *  </material>
0448  *
0449  *  Elements:
0450  *  <element Z="29" formula="Cu" name="Cu" >
0451  *    <atom type="A" unit="g/mol" value="63.5456" />
0452  *  </element>
0453  *
0454  */
0455 template <> void Converter<Material>::operator()(xml_h e) const {
0456   xml_ref_t         x_mat(e);
0457   TGeoManager&      mgr     = description.manager();
0458   xml_tag_t         mname   = x_mat.name();
0459   const char*       matname = mname.c_str();
0460   TGeoElementTable* table   = mgr.GetElementTable();
0461   TGeoMaterial*     mat     = mgr.GetMaterial(matname);
0462   TGeoMixture*      mix     = dynamic_cast<TGeoMixture*>(mat);
0463   xml_coll_t        fractions (x_mat, _U(fraction));
0464   xml_coll_t        composites(x_mat, _U(composite));
0465 
0466   if (0 == mat) {
0467     TGeoMaterial* comp_mat;
0468     TGeoElement*  comp_elt;
0469     xml_h  density     = x_mat.child(_U(D), false);
0470     double dens_val    = density.ptr() ? density.attr<double>(_U(value)) : 0.0;
0471     double dens_unit   = 1.0;
0472 
0473     if ( !density.ptr() ) {
0474       throw_print("Compact2Objects[ERROR]: material without density tag ( <D  unit=\"g/cm3\" value=\"..\"/> ) provided: "
0475                   + std::string( matname ) ) ;
0476     }
0477     if ( density.hasAttr(_U(unit)) )   {
0478       dens_unit = density.attr<double>(_U(unit))/xml::_toDouble(_Unicode(gram/cm3));
0479     }
0480     if ( dens_unit != 1.0 )  {
0481       dens_val *= dens_unit;
0482       printout(s_debug.materials ? ALWAYS : DEBUG, "Compact","Density unit: %.3f [%s] raw: %.3f normalized: %.3f ",
0483                dens_unit, density.attr<std::string>(_U(unit)).c_str(), dens_val, (dens_val*dens_unit));
0484     }
0485     mat = mix = new TGeoMixture(matname, composites.size(), dens_val);
0486     std::size_t         ifrac = 0;
0487     std::vector<double> composite_fractions;
0488     double              composite_fractions_total = 0.0;
0489     for (composites.reset(); composites; ++composites)   {
0490       std::string nam      = composites.attr<std::string>(_U(ref));
0491       double      fraction = composites.attr<double>(_U(n));
0492       if (0 != (comp_mat = mgr.GetMaterial(nam.c_str())))
0493         fraction *= comp_mat->GetA();
0494       else if (0 != (comp_elt = table->FindElement(nam.c_str())))
0495         fraction *= comp_elt->A();
0496       else
0497         except("Compact2Objects","Converting material: %s Element missing: %s",mname.c_str(),nam.c_str());
0498       composite_fractions_total += fraction;
0499       composite_fractions.emplace_back(fraction);
0500     }
0501     for (composites.reset(), ifrac=0; composites; ++composites, ++ifrac) {
0502       std::string nam      = composites.attr<std::string>(_U(ref));
0503       double      fraction = composite_fractions[ifrac]/composite_fractions_total;
0504       if (0 != (comp_mat = mgr.GetMaterial(nam.c_str())))
0505         mix->AddElement(comp_mat, fraction);
0506       else if (0 != (comp_elt = table->FindElement(nam.c_str())))
0507         mix->AddElement(comp_elt, fraction);
0508     }
0509     for (fractions.reset(); fractions; ++fractions) {
0510       std::string nam      = fractions.attr<std::string>(_U(ref));
0511       double      fraction = fractions.attr<double>(_U(n));
0512       if (0 != (comp_mat = mgr.GetMaterial(nam.c_str())))
0513         mix->AddElement(comp_mat, fraction);
0514       else if (0 != (comp_elt = table->FindElement(nam.c_str())))
0515         mix->AddElement(comp_elt, fraction);
0516       else
0517         throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " Element missing: " + nam);
0518     }
0519     xml_h  temperature = x_mat.child(_U(T), false);
0520     double temp_val    = description.stdConditions().temperature;
0521     if ( temperature.ptr() )   {
0522       double temp_unit = _toDouble("kelvin");
0523       if ( temperature.hasAttr(_U(unit)) )
0524         temp_unit = temperature.attr<double>(_U(unit));
0525       temp_val = temperature.attr<double>(_U(value)) * temp_unit;
0526     }
0527     xml_h  pressure     = x_mat.child(_U(P), false);
0528     double pressure_val = description.stdConditions().pressure;
0529     if ( pressure.ptr() )   {
0530       double pressure_unit = _toDouble("pascal");
0531       if ( pressure.hasAttr(_U(unit)) )
0532         pressure_unit = pressure.attr<double>(_U(unit));
0533       pressure_val = pressure.attr<double>(_U(value)) * pressure_unit;
0534     }
0535 #if 0
0536     printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0537              "++ ROOT raw temperature and pressure: %.3g %.3g",
0538              mat->GetTemperature(),mat->GetPressure());
0539 #endif
0540     mat->SetTemperature(temp_val);
0541     mat->SetPressure(pressure_val);
0542     printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0543              "++ Converting material %-16s  Density: %9.7g  Temperature:%9.7g [K] Pressure:%9.7g [hPa].",
0544              matname, dens_val, temp_val/dd4hep::kelvin, pressure_val/dd4hep::pascal/100.0);
0545 
0546     mix->SetRadLen(0e0);
0547     mix->ComputeDerivedQuantities();
0548     ///
0549     /// In case there were material properties specified: convert them here
0550     for(xml_coll_t properties(x_mat, _U(constant)); properties; ++properties) {
0551       xml_elt_t p = properties;
0552       if ( p.hasAttr(_U(ref)) )   {
0553         bool        err = kFALSE;
0554         std::string ref = p.attr<std::string>(_U(ref));
0555         mgr.GetProperty(ref.c_str(), &err); /// Check existence
0556         if ( err == kFALSE )  {
0557           std::string prop_nam = p.attr<std::string>(_U(name));
0558           mat->AddConstProperty(prop_nam.c_str(), ref.c_str());
0559           printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0560                    "++            material %-16s  add constant property: %s  ->  %s.",
0561                    mat->GetName(), prop_nam.c_str(), ref.c_str());
0562           continue;
0563         }
0564         // ERROR
0565         throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " ConstProperty missing in TGeoManager: " + ref);
0566       }
0567       else if ( p.hasAttr(_U(value)) )   {
0568         std::stringstream str;
0569         std::string       ref, prop_nam = p.attr<std::string>(_U(name));
0570         str << prop_nam << "_" << (void*)mat;
0571         ref = str.str();
0572         mgr.AddProperty(ref.c_str(), p.attr<double>(_U(value))); /// Check existence
0573         mat->AddConstProperty(prop_nam.c_str(), ref.c_str());
0574         printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0575                  "++            material %-16s  add constant property: %s  ->  %s.",
0576                  mat->GetName(), prop_nam.c_str(), ref.c_str());
0577       }
0578       else if ( p.hasAttr(_U(option)) )   {
0579         std::string prop_nam = p.attr<std::string>(_U(name));
0580         std::string prop_typ = p.attr<std::string>(_U(option));
0581         mat->AddConstProperty(prop_nam.c_str(), prop_typ.c_str());
0582         printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0583                  "++            material %-16s  add constant property: %s  ->  %s.",
0584                  mat->GetName(), prop_nam.c_str(), prop_typ.c_str());
0585       }
0586     }
0587     /// In case there were material properties specified: convert them here
0588     for(xml_coll_t properties(x_mat, _U(property)); properties; ++properties) {
0589       xml_elt_t p = properties;
0590       if ( p.hasAttr(_U(ref)) )   {
0591         std::string  ref     = p.attr<std::string>(_U(ref));
0592         TGDMLMatrix* gdmlMat = mgr.GetGDMLMatrix(ref.c_str());
0593         if ( gdmlMat )  {
0594           std::string prop_nam = p.attr<std::string>(_U(name));
0595           mat->AddProperty(prop_nam.c_str(), ref.c_str());
0596           printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0597                    "++            material %-16s  add property: %s  ->  %s.",
0598                    mat->GetName(), prop_nam.c_str(), ref.c_str());
0599           continue;
0600         }
0601         // ERROR
0602         throw_print("Compact2Objects[ERROR]: Converting material:" + mname + " Property missing: " + ref);
0603       }
0604     }
0605   }
0606   TGeoMedium* medium = mgr.GetMedium(matname);
0607   if (0 == medium) {
0608     --unique_mat_id;
0609     medium = new TGeoMedium(matname, unique_mat_id, mat);
0610     medium->SetTitle("material");
0611     medium->SetUniqueID(unique_mat_id);
0612   }
0613   // TGeo has no notion of a material "formula"
0614   // Hence, treat the formula the same way as the material itself
0615   if (x_mat.hasAttr(_U(formula))) {
0616     std::string form = x_mat.attr<std::string>(_U(formula));
0617     if (form != matname) {
0618       medium = mgr.GetMedium(form.c_str());
0619       if (0 == medium) {
0620         --unique_mat_id;
0621         medium = new TGeoMedium(form.c_str(), unique_mat_id, mat);
0622         medium->SetTitle("material");
0623         medium->SetUniqueID(unique_mat_id);
0624       }
0625     }
0626   }
0627 }
0628 
0629 /** Convert compact isotope objects
0630  *
0631  *   <isotope name="C12" Z="2" N="12"/>
0632  *     <atom unit="g/mole" value="12"/>
0633  *   </isotope>
0634  */
0635 template <> void Converter<Isotope>::operator()(xml_h e) const {
0636   xml_dim_t isotope(e);
0637   TGeoManager&      mgr = description.manager();
0638   std::string       nam = isotope.nameStr();
0639   TGeoElementTable* tab = mgr.GetElementTable();
0640   TGeoIsotope*      iso = tab->FindIsotope(nam.c_str());
0641 
0642   // Create the isotope object in the event it is not yet present from the XML data
0643   if ( !iso )   {
0644     xml_ref_t   atom(isotope.child(_U(atom)));
0645     std::string unit  = atom.attr<std::string>(_U(unit));
0646     double      value = atom.attr<double>(_U(value));
0647     double      a     = value * _multiply<double>(unit,"mol/g");
0648     int         n     = isotope.attr<int>(_U(N));
0649     int         z     = isotope.attr<int>(_U(Z));
0650     iso = new TGeoIsotope(nam.c_str(), z, n, a);
0651     printout(s_debug.isotopes ? ALWAYS : DEBUG, "Compact",
0652              "++ Converting isotope  %-16s  Z:%3d N:%3d A:%8.4f [g/mol]",
0653              iso->GetName(), iso->GetZ(), iso->GetN(), iso->GetA());
0654   }
0655   else  {
0656     printout(s_debug.isotopes ? WARNING : DEBUG, "Compact",
0657              "++ Isotope %-16s  Z:%3d N:%3d A:%8.4f [g/mol] ALREADY defined. [Ignore definition]",
0658              iso->GetName(), iso->GetZ(), iso->GetN(), iso->GetA());
0659   }
0660 }
0661 
0662 /** Convert compact atom objects (periodic elements)
0663  *
0664  *   <element Z="4" formula="Be" name="Be" >
0665  *     <atom type="A" unit="g/mol" value="9.01218" />
0666  *   </element>
0667  *   or
0668  *   <element name="C">
0669  *     <fraction n="0.9893" ref="C12"/>
0670  *     <fraction n="0.0107" ref="C13"/>
0671  *   </element>
0672  * 
0673  *   Please note: 
0674  *   Elements may consist of a mixture of isotopes!
0675  */
0676 template <> void Converter<Atom>::operator()(xml_h e) const {
0677   xml_ref_t         elem(e);
0678   xml_tag_t         name = elem.name();
0679   TGeoManager&      mgr  = description.manager();
0680   TGeoElementTable* tab  = mgr.GetElementTable();
0681   TGeoElement*      elt  = tab->FindElement(name.c_str());
0682   if ( !elt ) {
0683     if ( elem.hasChild(_U(atom)) )  {
0684       xml_ref_t   atom(elem.child(_U(atom)));
0685       std::string formula = elem.attr<std::string>(_U(formula));
0686       double      value   = atom.attr<double>(_U(value));
0687       std::string unit    = atom.attr<std::string>(_U(unit));
0688       int         z       = elem.attr<int>(_U(Z));
0689       double      a       = value*_multiply<double>(unit,"mol/g");
0690       printout(s_debug.elements ? ALWAYS : DEBUG, "Compact",
0691                "++ Converting element  %-16s  [%-3s] Z:%3d A:%8.4f [g/mol]",
0692                name.c_str(), formula.c_str(), z, a);
0693       tab->AddElement(name.c_str(), formula.c_str(), z, a);
0694     }
0695     else  {
0696       int num_isotopes = 0;
0697       std::string formula = elem.hasAttr(_U(formula)) ? elem.attr<std::string>(_U(formula)) : name.str();
0698       for( xml_coll_t i(elem,_U(fraction)); i; ++i)
0699         ++num_isotopes;
0700       elt = new TGeoElement(name.c_str(), formula.c_str(), num_isotopes);
0701       tab->AddElement(elt);
0702       for( xml_coll_t i(elem,_U(fraction)); i; ++i)  {
0703         double       frac = i.attr<double>(_U(n));
0704         std::string  ref  = i.attr<std::string>(_U(ref));
0705         TGeoIsotope* iso  = tab->FindIsotope(ref.c_str());
0706         if ( !iso )  {
0707           except("Compact","Element %s cannot be constructed. Isotope '%s' (fraction: %.3f) missing!",
0708                  name.c_str(), ref.c_str(), frac);
0709         }
0710         printout(s_debug.elements ? ALWAYS : DEBUG, "Compact",
0711                  "++ Converting element  %-16s  Add isotope: %-16s fraction:%.4f.",
0712                  name.c_str(), ref.c_str(), frac);
0713         elt->AddIsotope(iso, frac);
0714       }
0715       printout(s_debug.elements ? ALWAYS : DEBUG, "Compact",
0716                "++ Converted  element  %-16s  [%-3s] Z:%3d A:%8.4f [g/mol] with %d isotopes.",
0717                name.c_str(), formula.c_str(), elt->Z(), elt->A(), num_isotopes);
0718     }
0719     elt = tab->FindElement(name.c_str());
0720     if (!elt) {
0721       throw_print("Failed to properly insert the Element:"+name+" into the element table!");
0722     }
0723   }
0724   else  {
0725     printout(s_debug.elements ? WARNING : DEBUG, "Compact",
0726              "++ Element %-16s  Z:%3d N:%3d A:%8.4f [g/mol] ALREADY defined. [Ignore definition]",
0727              elt->GetName(), elt->Z(), elt->N(), elt->A());
0728   }
0729 }
0730 
0731 /** Convert compact isotope objects
0732  *
0733  *   <std_conditions type="STP or NTP"> // type optional
0734  *     <item name="temperature" unit="kelvin" value="273.15"/>
0735  *     <item name="pressure"    unit="kPa" value="100"/>
0736  *   </std_conditions>
0737  */
0738 template <> void Converter<STD_Conditions>::operator()(xml_h e) const {
0739   xml_dim_t cond(e);
0740   // Create the isotope object in the event it is not yet present from the XML data
0741   if ( cond.ptr() )   {
0742     if ( cond.hasAttr(_U(type)) )   {
0743       description.setStdConditions(cond.typeStr());
0744     }
0745     xml_h  temperature = cond.child(_U(T), false);
0746     double temp_val    = description.stdConditions().temperature;
0747     if ( temperature.ptr() )   {
0748       double temp_unit = _toDouble("kelvin");
0749       if ( temperature.hasAttr(_U(unit)) )
0750         temp_unit = temperature.attr<double>(_U(unit));
0751       temp_val = temperature.attr<double>(_U(value)) * temp_unit;
0752     }
0753     xml_h  pressure     = cond.child(_U(P), false);
0754     double pressure_val = description.stdConditions().pressure;
0755     if ( pressure.ptr() )   {
0756       double pressure_unit = _toDouble("pascal");
0757       if ( pressure.hasAttr(_U(unit)) )
0758         pressure_unit = pressure.attr<double>(_U(unit));
0759       pressure_val = pressure.attr<double>(_U(value)) * pressure_unit;
0760     }
0761     description.setStdConditions(temp_val, pressure_val);
0762     printout(s_debug.materials ? ALWAYS : DEBUG, "Compact",
0763              "+++ Material standard conditions: Temperature: %.3f Kelvin Pressure: %.3f hPa",
0764              temp_val/_toDouble("kelvin"), pressure_val/_toDouble("hPa"));
0765   }
0766 }
0767 
0768 /** Convert compact optical surface objects (defines)
0769  *
0770  *
0771  */
0772 template <> void Converter<OpticalSurface>::operator()(xml_h element) const {
0773   xml_elt_t    e = element;
0774   TGeoManager& mgr = description.manager();
0775   std::string  sname = e.attr<std::string>(_U(name));
0776   std::string  ref, pname;
0777   
0778   // Defaults from Geant4
0779   OpticalSurface::EModel  model  = OpticalSurface::Model::kMglisur;
0780   OpticalSurface::EFinish finish = OpticalSurface::Finish::kFpolished;
0781   OpticalSurface::EType   type   = OpticalSurface::Type::kTdielectric_metal;
0782   Double_t value = 1.0;
0783   if ( e.hasAttr(_U(type))   ) type   = OpticalSurface::stringToType(e.attr<std::string>(_U(type)));
0784   if ( e.hasAttr(_U(model))  ) model  = OpticalSurface::stringToModel(e.attr<std::string>(_U(model)));
0785   if ( e.hasAttr(_U(finish)) ) finish = OpticalSurface::stringToFinish(e.attr<std::string>(_U(finish)));
0786   if ( e.hasAttr(_U(value))  ) value  = e.attr<double>(_U(value));
0787   OpticalSurface surf(description, sname, model, finish, type, value);
0788   if ( s_debug.surface )    {
0789     printout(ALWAYS,"Compact","+++ Reading optical surface %s Typ:%d model:%d finish:%d value: %.3f",
0790              sname.c_str(), int(type), int(model), int(finish), value);
0791   }
0792   for (xml_coll_t props(e, _U(property)); props; ++props)  {
0793     pname = props.attr<std::string>(_U(name));
0794     if ( props.hasAttr(_U(ref)) )  {
0795       bool err = kFALSE;
0796       ref = props.attr<std::string>(_U(ref));
0797       mgr.GetProperty(ref.c_str(), &err); /// Check existence
0798       surf->AddProperty(pname.c_str(), ref.c_str());
0799       if ( s_debug.surface )  {
0800         printout(ALWAYS,"Compact","+++ \t\t Property:  %s  -> %s", pname.c_str(), ref.c_str());
0801       }
0802       continue;
0803     }
0804     std::size_t         cols = props.attr<long>(_U(coldim));
0805     xml_attr_t          opt  = props.attr_nothrow(_U(option));
0806     std::stringstream   str(props.attr<std::string>(_U(values))), str_nam;
0807     std::string         val;
0808     std::vector<double> values;
0809     while ( !str.eof() )   {
0810       val = "";
0811       str >> val;
0812       if ( val.empty() && !str.good() ) break;
0813       values.emplace_back(_toDouble(val));
0814     }
0815     /// Create table and register table
0816     TGDMLMatrix* table = new TGDMLMatrix("",values.size()/cols, cols);
0817     if ( opt )   {
0818       std::string tit = e.attr<std::string>(opt);
0819       str_nam << tit << "|";
0820     }
0821     str_nam << pname << "__" << (void*)table;
0822     table->SetName(str_nam.str().c_str());
0823     table->SetTitle(pname.c_str());
0824     for (std::size_t i=0, n=values.size(); i<n; ++i)
0825       table->Set(i/cols, i%cols, values[i]);
0826     surf->AddProperty(pname.c_str(), table->GetName());
0827     description.manager().AddGDMLMatrix(table);
0828   }
0829 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,31,1)
0830   //
0831   // In case there were constant surface properties specified: convert them here
0832   for(xml_coll_t properties(e, _U(constant)); properties; ++properties) {
0833     xml_elt_t p = properties;
0834     pname = p.attr<std::string>(_U(name));
0835     if ( p.hasAttr(_U(ref)) )   {
0836       bool err = kFALSE;
0837       ref = p.attr<std::string>(_U(ref));
0838       mgr.GetProperty(ref.c_str(), &err); /// Check existence
0839       if ( err == kFALSE )  {
0840         surf->AddConstProperty(pname.c_str(), ref.c_str());
0841         printout(s_debug.surface ? ALWAYS : DEBUG, "Compact",
0842                  "++            surface  %-16s  add constant property: %s  ->  %s.",
0843                  surf->GetName(), pname.c_str(), ref.c_str());
0844         continue;
0845       }
0846       // ERROR
0847       throw_print("Compact2Objects[ERROR]: Converting surface: " + sname +
0848                   " ConstProperty missing in TGeoManager: " + ref);
0849     }
0850     else if ( p.hasAttr(_U(value)) )   {
0851       std::stringstream str;
0852       str << pname << "_" << (void*)surf.ptr();
0853       ref = str.str();
0854       mgr.AddProperty(ref.c_str(), p.attr<double>(_U(value))); /// Check existence
0855       surf->AddConstProperty(pname.c_str(), ref.c_str());
0856       printout(s_debug.surface ? ALWAYS : DEBUG, "Compact",
0857                "++            surface  %-16s  add constant property: %s  ->  %s.",
0858                surf->GetName(), pname.c_str(), ref.c_str());
0859     }
0860     else if ( p.hasAttr(_U(option)) )   {
0861       std::string ptyp = p.attr<std::string>(_U(option));
0862       surf->AddConstProperty(pname.c_str(), ptyp.c_str());
0863       printout(s_debug.surface ? ALWAYS : DEBUG, "Compact",
0864                "++            surface  %-16s  add constant property: %s  ->  %s.",
0865                surf->GetName(), pname.c_str(), ptyp.c_str());
0866     }
0867   }
0868 #endif
0869 }
0870 
0871 /** Convert compact constant property (Material properties stored in TGeoManager)
0872  *
0873  *  <constant name="RINDEX" value="8.123"/>
0874  *
0875  */
0876 template <> void Converter<PropertyConstant>::operator()(xml_h e) const    {
0877   double      value = e.attr<double>(_U(value));
0878   std::string name  = e.attr<std::string>(_U(name));
0879   description.manager().AddProperty(name.c_str(), value);
0880   if ( s_debug.matrix )    {
0881     printout(ALWAYS,"Compact","+++ Reading property %s : %f",name.c_str(), value);
0882   }
0883 #if 0
0884   xml_attr_t opt = e.attr_nothrow(_U(title));
0885   if ( opt )    {
0886     std::string  val = e.attr<std::string>(opt);
0887     TNamed* nam = description.manager().GetProperty(name.c_str());
0888     if ( !nam )   {
0889       except("Compact","Failed to access just added manager property: %s",name.c_str());
0890     }
0891     nam->SetTitle(val.c_str());
0892   }
0893 #endif
0894 }
0895 
0896 /** Convert compact property table objects (defines)
0897  *
0898  *  <matrix coldim="2" name="RINDEX0xf5972d0" values="1.5e-06 1.0013 1. ...."/>
0899  *
0900  */
0901 template <> void Converter<PropertyTable>::operator()(xml_h e) const {
0902   std::vector<double> vals;
0903   std::size_t         cols = e.attr<unsigned long>(_U(coldim));
0904   std::stringstream   str(e.attr<std::string>(_U(values)));
0905 
0906   if ( s_debug.matrix )    {
0907     printout(ALWAYS,"Compact","+++ Reading property table %s with %d columns.",
0908              e.attr<std::string>(_U(name)).c_str(), cols);
0909   }
0910   vals.reserve(1024);
0911   while ( !str.eof() )   {
0912     std::string item;
0913     str >> item;
0914     if ( item.empty() && !str.good() ) break;
0915     vals.emplace_back(_toDouble(item));
0916     if ( s_debug.matrix )    {
0917       std::cout << " state:" << (str.good() ? "OK " : "BAD") << " '" << item << "'";
0918       if ( 0 == (vals.size()%cols) ) std::cout << std::endl;
0919     }
0920   }
0921   if ( s_debug.matrix )    {
0922     std::cout << std::endl;
0923   }
0924   /// Create table and register table
0925   xml_attr_t    opt = e.attr_nothrow(_U(option));
0926   PropertyTable tab(description,
0927                     e.attr<std::string>(_U(name)),
0928                     opt ? e.attr<std::string>(opt).c_str() : "",
0929                     vals.size()/cols, cols);
0930   for( std::size_t i=0, n=vals.size(); i < n; ++i )
0931     tab->Set(i/cols, i%cols, vals[i]);
0932   //if ( s_debug.matrix ) tab->Print();
0933 }
0934 
0935 /** Convert compact visualization attribute to Detector visualization attribute.
0936  *
0937  *  <vis name="SiVertexBarrelModuleVis"
0938  *       alpha="1.0" r="1.0" g="0.75" b="0.76"
0939  *       drawingStyle="wireframe"
0940  *       showDaughters="false"
0941  *       visible="true"/>
0942  *
0943  *  Optionally inherit an already defined VisAttr and override other properties.
0944  *
0945  *  <vis name="SiVertexEndcapModuleVis"
0946  *       ref="SiVertexBarrelModuleVis"
0947  *       alpha="0.5"/>
0948  */
0949 template <> void Converter<VisAttr>::operator()(xml_h e) const {
0950   VisAttr attr(e.attr<std::string>(_U(name)));
0951   float alpha = 1.0;
0952   float red   = 1.0;
0953   float green = 1.0;
0954   float blue  = 1.0;
0955   bool use_ref = false;
0956   if(e.hasAttr(_U(ref))) {
0957     use_ref = true;
0958     auto refName = e.attr<std::string>(_U(ref));
0959     const auto refAttr = description.visAttributes(refName);
0960     if(!refAttr.isValid() )  {
0961       except("Compact","+++ Reference VisAttr %s does not exist", refName.c_str());
0962     }
0963     // Just copying things manually.
0964     // I think a handle's copy constructor/assignment would reuse the underlying pointer... maybe?
0965     refAttr.argb(alpha,red,green,blue);
0966     attr.setColor(alpha,red,green,blue);
0967     attr.setDrawingStyle( refAttr.drawingStyle());
0968     attr.setLineStyle( refAttr.lineStyle());
0969     attr.setShowDaughters(refAttr.showDaughters());
0970     attr.setVisible(refAttr.visible());
0971   }
0972   xml_dim_t dim(e);
0973   alpha = dim.alpha(alpha);
0974   red   = dim.r(red  );
0975   green = dim.g(green);
0976   blue  = dim.b(blue );
0977 
0978   printout(s_debug.visattr ? ALWAYS : DEBUG, "Compact",
0979            "++ Converting VisAttr  structure: %-16s. Alpha=%.2f R=%.3f G=%.3f B=%.3f",
0980            attr.name(), alpha, red, green, blue);
0981   attr.setColor(alpha, red, green, blue);
0982   if (e.hasAttr(_U(visible)))
0983     attr.setVisible(e.attr<bool>(_U(visible)));
0984   if (e.hasAttr(_U(lineStyle))) {
0985     std::string ls = e.attr<std::string>(_U(lineStyle));
0986     if (ls == "unbroken")
0987       attr.setLineStyle(VisAttr::SOLID);
0988     else if (ls == "broken")
0989       attr.setLineStyle(VisAttr::DASHED);
0990   }
0991   else {
0992     if (!use_ref)
0993       attr.setLineStyle(VisAttr::SOLID);
0994   }
0995   if (e.hasAttr(_U(drawingStyle))) {
0996     std::string ds = e.attr<std::string>(_U(drawingStyle));
0997     if (ds == "wireframe")
0998       attr.setDrawingStyle(VisAttr::WIREFRAME);
0999     else if (ds == "solid")
1000       attr.setDrawingStyle(VisAttr::SOLID);
1001   }
1002   else {
1003     if (!use_ref)
1004       attr.setDrawingStyle(VisAttr::SOLID);
1005   }
1006   if (e.hasAttr(_U(showDaughters)))
1007     attr.setShowDaughters(e.attr<bool>(_U(showDaughters)));
1008   else {
1009     if (!use_ref)
1010       attr.setShowDaughters(true);
1011   }
1012   description.addVisAttribute(attr);
1013 }
1014 
1015 /** Specialized converter for compact region objects.
1016  *
1017  */
1018 template <> void Converter<Region>::operator()(xml_h elt) const {
1019   xml_dim_t       e = elt;
1020   Region          region(e.nameStr());
1021   auto&           limits       = region.limits();
1022   xml_attr_t      cut          = elt.attr_nothrow(_U(cut));
1023   xml_attr_t      threshold    = elt.attr_nothrow(_U(threshold));
1024   xml_attr_t store_secondaries = elt.attr_nothrow(_U(store_secondaries));
1025   double ene = e.eunit(1.0), len = e.lunit(1.0);
1026 
1027   printout(s_debug.regions ? ALWAYS : DEBUG, "Compact",
1028            "++ Converting region   structure: %s.",region.name());
1029   if ( cut )  {
1030     region.setCut(elt.attr<double>(cut)*len);
1031   }
1032   if ( threshold )  {
1033     region.setThreshold(elt.attr<double>(threshold)*ene);
1034   }
1035   if ( store_secondaries )  {
1036     region.setStoreSecondaries(elt.attr<bool>(store_secondaries));
1037   }
1038   for (xml_coll_t user_limits(e, _U(limitsetref)); user_limits; ++user_limits)
1039     limits.emplace_back(user_limits.attr<std::string>(_U(name)));
1040   description.addRegion(region);
1041 }
1042 
1043 
1044 /** Specialized converter for compact readout objects.
1045  *
1046  * <readout name="HcalBarrelHits">
1047  *   <segmentation type="RegularNgonCartesianGridXY" gridSizeX="3.0*cm" gridSizeY="3.0*cm" />
1048  *   <id>system:6,barrel:3,module:4,layer:8,slice:5,x:32:-16,y:-16</id>
1049  * </readout>
1050  */
1051 template <> void Converter<Segmentation>::operator()(xml_h seg) const {
1052   std::string type = seg.attr<std::string>(_U(type));
1053   std::string name = seg.hasAttr(_U(name)) ? seg.attr<std::string>(_U(name)) : std::string();
1054   std::pair<Segmentation,IDDescriptor>* opt = _option<std::pair<Segmentation,IDDescriptor> >();
1055 
1056   const BitFieldCoder* bitfield = &opt->second->decoder;
1057   Segmentation segment(type, name, bitfield);
1058   if ( segment.isValid() ) {
1059     const DDSegmentation::Parameters& pars = segment.parameters();
1060     printout(s_debug.segmentation ? ALWAYS : DEBUG, "Compact",
1061              "++ Converting segmentation structure: %s of type %s.",name.c_str(),type.c_str());
1062     for(const auto p : pars )  {
1063       xml::Strng_t pNam(p->name());
1064       if ( seg.hasAttr(pNam) ) {
1065         std::string pType = p->type();
1066         if ( pType.compare("int") == 0 ) {
1067           typedef DDSegmentation::TypedSegmentationParameter<int> ParInt;
1068           static_cast<ParInt*>(p)->setTypedValue(seg.attr<int>(pNam));
1069         } else if ( pType.compare("float") == 0 ) {
1070           typedef DDSegmentation::TypedSegmentationParameter<float> ParFloat;
1071           static_cast<ParFloat*>(p)->setTypedValue(seg.attr<float>(pNam));
1072         } else if ( pType.compare("doublevec") == 0 ) {
1073           std::vector<double> valueVector;
1074           std::string par = seg.attr<std::string>(pNam);
1075           printout(s_debug.segmentation ? ALWAYS : DEBUG, "Compact",
1076                    "++ Converting this std::string structure: %s.",par.c_str());
1077           std::vector<std::string> elts = DDSegmentation::splitString(par);
1078           for (const std::string& spar : elts )  {
1079             if ( spar.empty() ) continue;
1080             valueVector.emplace_back(_toDouble(spar));
1081           }
1082           typedef DDSegmentation::TypedSegmentationParameter< std::vector<double> > ParDouVec;
1083           static_cast<ParDouVec*>(p)->setTypedValue(valueVector);
1084         } else if ( pType.compare("double" ) == 0) {
1085           typedef DDSegmentation::TypedSegmentationParameter<double>ParDouble;
1086           static_cast<ParDouble*>(p)->setTypedValue(seg.attr<double>(pNam));
1087         } else {
1088           p->setValue(seg.attr<std::string>(pNam));
1089         }
1090       } else if (not p->isOptional()) {
1091         throw_print("FAILED to create segmentation: " + type +
1092                     ". Missing mandatory parameter: " + p->name() + "!");
1093       }
1094     }
1095     long key_min = 0, key_max = 0;
1096     DDSegmentation::Segmentation* base = segment->segmentation;
1097     for(xml_coll_t sub(seg,_U(segmentation)); sub; ++sub)   {
1098       std::pair<Segmentation,IDDescriptor> sub_object(Segmentation(),opt->second);
1099       Converter<Segmentation> sub_conv(description,param,&sub_object);
1100       sub_conv(sub);
1101       if ( sub_object.first.isValid() )  {
1102         Segmentation sub_seg = sub_object.first;
1103         xml_dim_t x_seg(sub);
1104         if ( sub.hasAttr(_U(key_value)) ) {
1105           key_min = key_max = x_seg.key_value();
1106         }
1107         else if ( sub.hasAttr(_U(key_min)) && sub.hasAttr(_U(key_max)) )  {
1108           key_min = x_seg.key_min();
1109           key_max = x_seg.key_max();
1110         }
1111         else  {
1112           std::stringstream tree;
1113           xml::dump_tree(sub,tree);
1114           throw_print("Nested segmentations: Invalid key specification:"+tree.str());
1115         }
1116         printout(s_debug.segmentation ? ALWAYS : DEBUG,"Compact",
1117                  "++ Segmentation [%s/%s]: Add sub-segmentation %s [%s]",
1118                  name.c_str(), type.c_str(), 
1119                  sub_seg->segmentation->name().c_str(),
1120                  sub_seg->segmentation->type().c_str());
1121         base->addSubsegmentation(key_min, key_max, sub_seg->segmentation);
1122         sub_seg->segmentation = 0;
1123         delete sub_seg.ptr();
1124       }
1125     }
1126   }
1127   opt->first = segment;
1128 }
1129 
1130 /** Specialized converter for compact readout objects.
1131  *
1132  * <readout name="HcalBarrelHits">
1133  *   <segmentation type="RegularNgonCartesianGridXY" gridSizeX="3.0*cm" gridSizeY="3.0*cm" />
1134  *   <id>system:6,barrel:3,module:4,layer:8,slice:5,x:32:-16,y:-16</id>
1135  * </readout>
1136  */
1137 template <> void Converter<Readout>::operator()(xml_h e) const {
1138   xml_h seg = e.child(_U(segmentation), false);
1139   xml_h id  = e.child(_U(id));
1140   std::string name = e.attr<std::string>(_U(name));
1141   std::pair<Segmentation,IDDescriptor> opt;
1142   Readout ro(name);
1143   
1144   if (id) {
1145     //  <id>system:6,barrel:3,module:4,layer:8,slice:5,x:32:-16,y:-16</id>
1146     opt.second = IDDescriptor(name,id.text());
1147     description.addIDSpecification(opt.second);
1148   }
1149   if (seg) {   // Segmentation is not mandatory!
1150     Converter<Segmentation>(description,param,&opt)(seg);
1151     opt.first->setName(name);
1152   }
1153   /// The next 2 if-clauses are a bit tricky, because they are not commutativ.
1154   /// The segmentation MUST be set first - THEN the ID descriptor, since it will
1155   /// update the segmentation.
1156   if ( opt.first.isValid() )   {
1157     ro.setSegmentation(opt.first);
1158   }
1159   if ( opt.second.isValid() )  {
1160     ro.setIDDescriptor(opt.second);
1161   }
1162   
1163   printout(s_debug.readout ? ALWAYS : DEBUG,
1164            "Compact", "++ Converting readout  structure: %-16s. %s%s",
1165            ro.name(), id ? "ID: " : "", id ? id.text().c_str() : "");
1166   
1167   for(xml_coll_t colls(e,_U(hits_collections)); colls; ++colls)   {
1168     std::string hits_key;
1169     if ( colls.hasAttr(_U(key)) ) hits_key = colls.attr<std::string>(_U(key));
1170     for(xml_coll_t coll(colls,_U(hits_collection)); coll; ++coll)   {
1171       xml_dim_t c(coll);
1172       std::string coll_name = c.nameStr();
1173       std::string coll_key  = hits_key;
1174       long   key_min = 0, key_max = 0;
1175 
1176       if ( c.hasAttr(_U(key)) )   {
1177         coll_key = c.attr<std::string>(_U(key));
1178       }
1179       if ( c.hasAttr(_U(key_value)) )   {
1180         key_max = key_min = c.key_value();
1181       }
1182       else if ( c.hasAttr(_U(key_min)) && c.hasAttr(_U(key_max)) )  {
1183         key_min = c.key_min();
1184         key_max = c.key_max();
1185       }
1186       else   {
1187         std::stringstream tree;
1188         xml::dump_tree(e,tree);
1189         throw_print("Readout: Invalid specification for multiple hit collections."+tree.str());
1190       }
1191       printout(s_debug.readout ? ALWAYS : DEBUG,"Compact",
1192                "++ Readout[%s]: Add hit collection %s [%s]  %d-%d",
1193                ro.name(), coll_name.c_str(), coll_key.c_str(), key_min, key_max);
1194       HitCollection hits(coll_name, coll_key, key_min, key_max);
1195       ro->hits.emplace_back(hits);
1196     }
1197   }
1198   description.addReadout(ro);
1199 }
1200 
1201 static long load_readout(Detector& description, xml_h element) {
1202   Converter<Readout> converter(description);
1203   converter(element);
1204   return 1;
1205 }
1206 DECLARE_XML_DOC_READER(readout,load_readout)
1207 
1208 
1209 /** Specialized converter for compact LimitSet objects.
1210  *
1211  *      <limitset name="....">
1212  *        <limit name="step_length_max" particles="*" value="5.0" unit="mm" />
1213  *  ... </limitset>
1214  */
1215 template <> void Converter<LimitSet>::operator()(xml_h e) const {
1216   Limit limit;
1217   LimitSet ls(e.attr<std::string>(_U(name)));
1218   printout(s_debug.limits ? ALWAYS : DEBUG, "Compact",
1219            "++ Converting LimitSet structure: %s.",ls.name());
1220   for (xml_coll_t c(e, _U(limit)); c; ++c) {
1221     limit.name      = c.attr<std::string>(_U(name));
1222     limit.particles = c.attr<std::string>(_U(particles));
1223     limit.content   = c.attr<std::string>(_U(value));
1224     limit.unit      = c.attr<std::string>(_U(unit));
1225     limit.value     = _multiply<double>(limit.content, limit.unit);
1226     ls.addLimit(limit);
1227     printout(s_debug.limits ? ALWAYS : DEBUG, "Compact",
1228              "++ %s: add %-6s: [%s] = %s [%s] = %f",
1229              ls.name(), limit.name.c_str(), limit.particles.c_str(),
1230              limit.content.c_str(), limit.unit.c_str(), limit.value);
1231   }
1232   limit.name      = "cut";
1233   for (xml_coll_t c(e, _U(cut)); c; ++c) {
1234     limit.particles = c.attr<std::string>(_U(particles));
1235     limit.content   = c.attr<std::string>(_U(value));
1236     limit.unit      = c.attr<std::string>(_U(unit));
1237     limit.value     = _multiply<double>(limit.content, limit.unit);
1238     ls.addCut(limit);
1239     printout(s_debug.limits ? ALWAYS : DEBUG, "Compact",
1240              "++ %s: add %-6s: [%s] = %s [%s] = %f",
1241              ls.name(), limit.name.c_str(), limit.particles.c_str(),
1242              limit.content.c_str(), limit.unit.c_str(), limit.value);
1243   }
1244   description.addLimitSet(ls);
1245 }
1246 
1247 /** Specialized converter for generic Detector properties
1248  *
1249  *      <properties>
1250  *        <attributes name="key" type="" .... />
1251  *  ... </properties>
1252  */
1253 template <> void Converter<Property>::operator()(xml_h e) const {
1254   std::string name = e.attr<std::string>(_U(name));
1255   Detector::Properties& prp  = description.properties();
1256   if ( name.empty() )
1257     throw_print("Failed to convert properties. No name given!");
1258 
1259   std::vector<xml_attr_t> a = e.attributes();
1260   if ( prp.find(name) == prp.end() )
1261     prp.emplace(name, Detector::PropertyValues());
1262 
1263   for (xml_attr_t i : a )
1264     prp[name].emplace(xml_tag_t(e.attr_name(i)).str(),e.attr<std::string>(i));
1265 }
1266 
1267 /** Specialized converter for electric and magnetic fields
1268  *
1269  *  Uses internally a plugin to allow flexible field descriptions.
1270  *
1271  *     <field type="ConstantField" name="Myfield" field="electric">
1272  *       <strength x="0" y="0" z="5"/>
1273  *     </field>
1274  */
1275 template <> void Converter<CartesianField>::operator()(xml_h e) const {
1276   std::string msg  = "updated";
1277   std::string name = e.attr<std::string>(_U(name));
1278   std::string type = e.attr<std::string>(_U(type));
1279   CartesianField field = description.field(name);
1280   if ( !field.isValid() ) {
1281     // The field is not present: We create it and add it to Detector
1282     field = Ref_t(PluginService::Create<NamedObject*>(type, &description, &e));
1283     if ( !field.isValid() ) {
1284       PluginDebug dbg;
1285       PluginService::Create<NamedObject*>(type, &description, &e);
1286       throw_print("Failed to create field object of type "+type + ". "+dbg.missingFactory(type));
1287     }
1288     description.addField(field);
1289     msg = "created";
1290   }
1291   type = field.type();
1292   // Now update the field structure with the generic part ie. set its properties
1293   CartesianField::Properties& prp = field.properties();
1294   for ( xml_coll_t c(e, _U(properties)); c; ++c ) {
1295     std::string props_name = c.attr<std::string>(_U(name));
1296     std::vector<xml_attr_t>a = c.attributes();
1297     if ( prp.find(props_name) == prp.end() ) {
1298       prp.emplace(props_name, Detector::PropertyValues());
1299     }
1300     for ( xml_attr_t i : a )
1301       prp[props_name].emplace(xml_tag_t(c.attr_name(i)).str(), c.attr<std::string>(i));
1302 
1303     if (c.hasAttr(_U(global)) && c.attr<bool>(_U(global))) {
1304       description.field().properties() = prp;
1305     }
1306   }
1307   printout(INFO, "Compact", "++ Converted field: Successfully %s field %s [%s]", msg.c_str(), name.c_str(), type.c_str());
1308 }
1309 
1310 /** Update sensitive detectors from group tags.
1311  *
1312  *  Handle xml sections of the type:
1313  *  <sd name="MuonBarrel"
1314  *      type="Geant4Calorimeter"
1315  *      ecut="100.0*MeV"
1316  *      verbose="true"
1317  *      hit_aggregation="position"
1318  *      limits="limit-set-reference"
1319  *      region="region-name-reference">
1320  *  </sd>
1321  *
1322  */
1323 template <> void Converter<SensitiveDetector>::operator()(xml_h element) const {
1324   std::string name = element.attr<std::string>(_U(name));
1325   try {
1326     SensitiveDetector sd = description.sensitiveDetector(name);
1327     xml_attr_t type = element.attr_nothrow(_U(type));
1328     if ( type )  {
1329       sd.setType(element.attr<std::string>(type));
1330     }
1331     xml_attr_t verbose = element.attr_nothrow(_U(verbose));
1332     if ( verbose ) {
1333       sd.setVerbose(element.attr<bool>(verbose));
1334     }
1335     xml_attr_t combine = element.attr_nothrow(_U(combine_hits));
1336     if ( combine ) {
1337       sd.setCombineHits(element.attr<bool>(combine));
1338     }
1339     xml_attr_t limits = element.attr_nothrow(_U(limits));
1340     if ( limits ) {
1341       std::string l = element.attr<std::string>(limits);
1342       LimitSet ls = description.limitSet(l);
1343       if (!ls.isValid()) {
1344         throw_print("Converter<SensitiveDetector>: Request for non-existing limitset:" + l);
1345       }
1346       sd.setLimitSet(ls);
1347     }
1348     xml_attr_t region = element.attr_nothrow(_U(region));
1349     if ( region ) {
1350       std::string r = element.attr<std::string>(region);
1351       Region reg = description.region(r);
1352       if (!reg.isValid()) {
1353         throw_print("Converter<SensitiveDetector>: Request for non-existing region:" + r);
1354       }
1355       sd.setRegion(reg);
1356     }
1357     xml_attr_t hits = element.attr_nothrow(_U(hits_collection));
1358     if (hits) {
1359       sd.setHitsCollection(element.attr<std::string>(hits));
1360     }
1361     xml_attr_t ecut = element.attr_nothrow(_U(ecut));
1362     xml_attr_t eunit = element.attr_nothrow(_U(eunit));
1363     if (ecut && eunit) {
1364       double value = _multiply<double>(_toString(ecut), _toString(eunit));
1365       sd.setEnergyCutoff(value);
1366     }
1367     else if (ecut) {   // If no unit is given , we assume the correct Geant4 unit is used!
1368       sd.setEnergyCutoff(element.attr<double>(ecut));
1369     }
1370     printout(DEBUG, "Compact", "SensitiveDetector-update: %-18s %-24s Hits:%-24s Cutoff:%7.3f", sd.name(),
1371              (" [" + sd.type() + "]").c_str(), sd.hitsCollection().c_str(), sd.energyCutoff());
1372     xml_attr_t sequence = element.attr_nothrow(_U(sequence));
1373     if (sequence) {
1374     }
1375   }
1376   catch (const std::exception& e) {
1377     printout(ERROR, "Compact", "++ FAILED    to convert sensitive detector: %s: %s", name.c_str(), e.what());
1378   }
1379   catch (...) {
1380     printout(ERROR, "Compact", "++ FAILED    to convert sensitive detector: %s: %s", name.c_str(), "UNKNONW Exception");
1381   }
1382 }
1383 
1384 static void setChildTitles(const std::pair<std::string, DetElement>& e) {
1385   DetElement parent = e.second.parent();
1386   const DetElement::Children& children = e.second.children();
1387   if (::strlen(e.second->GetTitle()) == 0) {
1388     e.second->SetTitle(parent.isValid() ? parent.type().c_str() : e.first.c_str());
1389   }
1390   for_each(children.begin(), children.end(), setChildTitles);
1391 }
1392 
1393 template <> void Converter<DetElement>::operator()(xml_h element) const {
1394   static const char* req_dets = ::getenv("REQUIRED_DETECTORS");
1395   static const char* req_typs = ::getenv("REQUIRED_DETECTOR_TYPES");
1396   static const char* ign_dets = ::getenv("IGNORED_DETECTORS");
1397   static const char* ign_typs = ::getenv("IGNORED_DETECTOR_TYPES");
1398   std::string type = element.attr<std::string>(_U(type));
1399   std::string name = element.attr<std::string>(_U(name));
1400   std::string name_match = ":" + name + ":";
1401   std::string type_match = ":" + type + ":";
1402 
1403   if (req_dets && !strstr(req_dets, name_match.c_str()))
1404     return;
1405   if (req_typs && !strstr(req_typs, type_match.c_str()))
1406     return;
1407   if (ign_dets && strstr(ign_dets, name_match.c_str()))
1408     return;
1409   if (ign_typs && strstr(ign_typs, type_match.c_str()))
1410     return;
1411   xml_attr_t attr_ignore = element.attr_nothrow(_U(ignore));
1412   if ( attr_ignore )   {
1413     bool ignore_det = element.attr<bool>(_U(ignore));
1414     if ( ignore_det )  {
1415       printout(INFO, "Compact",
1416                "+++ Do not build subdetector:%s [ignore flag set]",
1417                name.c_str());
1418       return;
1419     }
1420   }
1421   try {
1422     std::string par_name;
1423     xml_attr_t attr_par = element.attr_nothrow(_U(parent));
1424     xml_elt_t  elt_par(0);
1425     if (attr_par)
1426       par_name = element.attr<std::string>(attr_par);
1427     else if ( (elt_par=element.child(_U(parent),false)) )
1428       par_name = elt_par.attr<std::string>(_U(name));
1429     if ( !par_name.empty() ) {
1430       // We have here a nested detector. If the mother volume is not yet registered
1431       // it must be done here, so that the detector constructor gets the correct answer from
1432       // the call to Detector::pickMotherVolume(DetElement).
1433       if ( par_name[0] == '$' ) par_name = xml::getEnviron(par_name);
1434       DetElement parent = description.detector(par_name);
1435       if ( !parent.isValid() )  {
1436         except("Compact","Failed to access valid parent detector of %s",name.c_str());
1437       }
1438       description.declareParent(name, parent);
1439     }
1440     if( s_debug.detelements )  {
1441       printout(ALWAYS, "Compact","++ Building DetElement %s of type: %s. Parent: %s",
1442                name.c_str(), type.c_str(), par_name.c_str());
1443     }
1444     
1445     xml_attr_t attr_ro  = element.attr_nothrow(_U(readout));
1446     SensitiveDetector sd;
1447     Segmentation seg;
1448     if ( attr_ro )   {
1449       Readout ro = description.readout(element.attr<std::string>(attr_ro));
1450       if (!ro.isValid()) {
1451         except("Compact","No Readout structure present for detector:" + name);
1452       }
1453       seg = ro.segmentation();
1454       sd = SensitiveDetector(name, "sensitive");
1455       sd.setHitsCollection(ro.name());
1456       sd.setReadout(ro);
1457       description.addSensitiveDetector(sd);
1458     }
1459     Ref_t sens = sd;
1460     DetElement det(Ref_t(PluginService::Create<NamedObject*>(type, &description, &element, &sens)));
1461     if (det.isValid()) {
1462       setChildTitles(std::make_pair(name, det));
1463       if ( sd.isValid() )  {
1464         det->flag |= DetElement::Object::HAVE_SENSITIVE_DETECTOR;
1465       }
1466       if ( seg.isValid() )  {
1467         seg->sensitive = sd;
1468         seg->detector  = det;
1469       }
1470     }
1471     printout(det.isValid() ? INFO : ERROR, "Compact", "%s subdetector:%s of type %s %s",
1472              (det.isValid() ? "++ Converted" : "FAILED    "), name.c_str(), type.c_str(),
1473              (sd.isValid() ? ("[" + sd.type() + "]").c_str() : ""));
1474 
1475     if (!det.isValid())  {
1476       PluginDebug dbg;
1477       PluginService::Create<NamedObject*>(type, &description, &element, &sens);
1478       except("Compact","Failed to execute subdetector creation plugin. %s", dbg.missingFactory(type).c_str());
1479     }
1480     description.addDetector(det);
1481     description.surfaceManager().registerSurfaces(det);
1482     return;
1483   }
1484   catch (const std::exception& e)  {
1485     printout(ERROR, "Compact", "++ FAILED    to convert subdetector: %s: %s", name.c_str(), e.what());
1486     std::terminate();
1487   }
1488   catch (...)  {
1489     printout(ERROR, "Compact", "++ FAILED    to convert subdetector: %s: %s", name.c_str(), "UNKNONW Exception");
1490     std::terminate();
1491   }
1492 }
1493 
1494 /// Read material entries from a seperate file in one of the include sections of the geometry
1495 template <> void Converter<IncludeFile>::operator()(xml_h element) const   {
1496   xml::DocumentHolder doc(xml::DocumentHandler().load(element, element.attr_value(_U(ref))));
1497   if ( s_debug.include_guard) {
1498     // Include guard, we check whether this file was already processed
1499     if (check_process_file(description, doc.uri()))
1500       return;
1501   }
1502   xml_h root = doc.root();
1503   if ( s_debug.includes )   {
1504     printout(ALWAYS, "Compact","++ Processing xml document %s.",doc.uri().c_str());
1505   }
1506   if ( root.tag() == "materials" || root.tag() == "elements" )   {
1507     xml_coll_t(root, _U(isotope)).for_each(Converter<Isotope>(this->description,0,0));
1508     xml_coll_t(root, _U(element)).for_each(Converter<Atom>(this->description));
1509     xml_coll_t(root, _U(material)).for_each(Converter<Material>(this->description));
1510     return;
1511   }
1512   this->description.fromXML(doc.uri(), this->description.buildType());
1513 }
1514 
1515 /// Read material entries from a seperate file in one of the include sections of the geometry
1516 template <> void Converter<JsonFile>::operator()(xml_h element) const {
1517   std::string base = xml::DocumentHandler::system_directory(element);
1518   std::string file = element.attr<std::string>(_U(ref));
1519   std::vector<char*>  argv{&file[0], &base[0]};
1520   description.apply("DD4hep_JsonProcessor",int(argv.size()), &argv[0]);
1521 }
1522 
1523 /// Read alignment entries from a seperate file in one of the include sections of the geometry
1524 template <> void Converter<XMLFile>::operator()(xml_h element) const {
1525   PrintLevel  level = s_debug.includes ? ALWAYS : DEBUG;
1526   std::string fname = element.attr<std::string>(_U(ref));
1527   std::size_t idx   = fname.find("://");
1528   std::error_code ec;
1529 
1530   if ( idx == std::string::npos && std::filesystem::exists(fname, ec) )  {
1531     // Regular file without protocol specification
1532     printout(level, "Compact","++ Processing xml document %s.", fname.c_str());
1533     this->description.fromXML(fname, this->description.buildType());
1534   }
1535   else if ( idx == std::string::npos )  {
1536     // File relative to location of xml tag (protocol specification not possible)
1537     std::string location = xml::DocumentHandler::system_path(element, fname);
1538     printout(level, "Compact","++ Processing xml document %s.", location.c_str());
1539     this->description.fromXML(location, this->description.buildType());
1540   }
1541   else if ( idx > 0 )   {
1542     // File with protocol specification: must trust the location and the parser capabilities
1543     printout(level, "Compact","++ Processing xml document %s.", fname.c_str());
1544     this->description.fromXML(fname, this->description.buildType());
1545   }
1546   else  {
1547     // Are there any other possibilities ?
1548     printout(level, "Compact","++ Processing xml document %s.", fname.c_str());
1549     this->description.fromXML(fname, this->description.buildType());
1550   }
1551 }
1552 
1553 /// Read material entries from a seperate file in one of the include sections of the geometry
1554 template <> void Converter<World>::operator()(xml_h element) const {
1555   xml_elt_t  x_world(element);
1556   xml_comp_t x_shape = x_world.child(_U(shape), false);
1557   xml_attr_t att = x_world.getAttr(_U(material));
1558   Material   mat = att ? description.material(x_world.attr<std::string>(att)) : description.air();
1559   Volume     world_vol;
1560 
1561   /// Create the shape and the corresponding volume
1562   if ( x_shape )   {
1563     Solid sol(x_shape.createShape());
1564     world_vol = Volume("world_volume", sol, mat);
1565     printout(INFO, "Compact", "++ Created successfully world volume '%s'. shape: %s material:%s.",
1566              world_vol.name(), sol.type(), mat.name());
1567     description.manager().SetTopVolume(world_vol.ptr());
1568   }
1569   else   {
1570     world_vol = description.worldVolume();
1571     if ( !world_vol && att )   {
1572       /// If we require a user configured world, but no shape is given, define the standard box.
1573       /// Implicitly assumes that the box dimensions are given in the standard way.
1574       Box sol("world_x", "world_y", "world_z");
1575       world_vol = Volume("world_volume", sol, mat);
1576       printout(INFO, "Compact", "++ Created world volume '%s' as %s (%.2f, %.2f %.2f [cm]) material:%s.",
1577                world_vol.name(), sol.type(),
1578                sol.x()/dd4hep::cm, sol.y()/dd4hep::cm, sol.z()/dd4hep::cm,
1579                mat.name());
1580       description.manager().SetTopVolume(world_vol.ptr());
1581     }
1582     else if ( !world_vol )  {
1583       except("Compact", "++ Logical error: "
1584              "You cannot configure the world volume before it is created and not giving creation instructions.");
1585     }
1586   }
1587   // Delegate further configuration o0f the world volume to the xml utilities:
1588   if ( world_vol.isValid() )   {
1589     xml::configVolume(description, x_world, world_vol, false, true);
1590     auto vis = world_vol.visAttributes();
1591     if ( !vis.isValid() )  {
1592       vis = description.visAttributes("WorldVis");
1593       world_vol.setVisAttributes(vis);
1594     }
1595   }
1596 }
1597 
1598 /// Read material entries from a seperate file in one of the include sections of the geometry
1599 template <> void Converter<Parallelworld_Volume>::operator()(xml_h element) const {
1600   xml_det_t    parallel(element);
1601   xml_comp_t   shape  = parallel.child(_U(shape));
1602   xml_dim_t    pos    = element.child(_U(position),false);
1603   xml_dim_t    rot    = element.child(_U(rotation),false);
1604   std::string  name   = element.attr<std::string>(_U(name));
1605   std::string  path   = element.attr<std::string>(_U(anchor));
1606   bool         conn   = element.attr<bool>(_U(connected),false);
1607   DetElement   anchor(detail::tools::findElement(description, path));
1608   Position     position = pos ? Position(pos.x(), pos.y(), pos.z())    : Position();
1609   RotationZYX  rotation = rot ? RotationZYX(rot.z(), rot.y(), rot.x()) : RotationZYX();
1610 
1611   Material mat = parallel.hasAttr(_U(material))
1612     ? description.material(parallel.attr<std::string>(_U(material)))
1613     : description.air();
1614   VisAttr vis = parallel.hasAttr(_U(vis))
1615     ? description.invisible()
1616     : description.visAttributes(parallel.visStr());
1617 
1618   if ( !anchor.isValid() )   {
1619     except("Parallelworld_Volume",
1620            "++ FAILED    Cannot identify the anchor of the tracking volume: '%s'",
1621            path.c_str());
1622   }
1623 
1624   /// Create the shape and the corresponding volume
1625   Transform3D  tr_volume(detail::matrix::_transform(anchor.nominal().worldTransformation().Inverse()));
1626   Solid        sol(shape.createShape());
1627   Volume       vol(name, sol, mat);
1628   Volume       par = conn ? description.worldVolume() : description.parallelWorldVolume();
1629   PlacedVolume pv;
1630 
1631   /// In case the volume is connected, we may use visualization
1632   vol.setVisAttributes(vis);
1633   /// Need to inhibit that this artifical volume gets translated to Geant4 (connected only)!
1634   vol.setFlagBit(Volume::VETO_SIMU);
1635   
1636   /// Now place the volume in the anchor frame
1637   Transform3D trafo = tr_volume * Transform3D(rotation,position); // Is this the correct order ?
1638   pv = par.placeVolume(vol, trafo);
1639   if ( !pv.isValid() )   {
1640     except("Parallelworld_Volume",
1641            "++ FAILED    to place the tracking volume inside the anchor '%s'",path.c_str());
1642   }
1643   if ( name == "tracking_volume" )   {
1644     description.setTrackingVolume(vol);
1645   }
1646   printout(INFO, "Compact", "++ Converted successfully parallelworld_volume %s. anchor: %s vis:%s.",
1647            vol.name(), anchor.path().c_str(), vis.name());
1648 }
1649 
1650 /// Process include statements in various sub-tags of compact
1651 template <> void Converter<DetElementInclude>::operator()(xml_h element) const {
1652   std::string type = element.hasAttr(_U(type)) ? element.attr<std::string>(_U(type)) : std::string("xml");
1653   if ( type == "xml" )  {
1654     xml::DocumentHolder doc(xml::DocumentHandler().load(element, element.attr_value(_U(ref))));
1655     if ( s_debug.include_guard ) {
1656       // Include guard, we check whether this file was already processed
1657       if (check_process_file(description, doc.uri()))
1658         return;
1659     }
1660     if ( s_debug.includes )   {
1661       printout(ALWAYS, "Compact","++ Processing xml document %s.",doc.uri().c_str());
1662     }
1663     xml_h node = doc.root();
1664     std::string tag = node.tag();
1665     if ( tag == "lccdd" )
1666       Converter<Compact>(this->description)(node);
1667     else if ( tag == "define" )
1668       xml_coll_t(node, _U(constant)).for_each(Converter<Constant>(this->description));
1669     else if ( tag == "readout" )
1670       Converter<Readout>(this->description)(node);
1671     else if ( tag == "readouts" )
1672       xml_coll_t(node, _U(readout)).for_each(Converter<Readout>(this->description));
1673     else if ( tag == "region" )
1674       Converter<Region>(this->description)(node);
1675     else if ( tag == "regions" )
1676       xml_coll_t(node, _U(region)).for_each(Converter<Region>(this->description));
1677     else if ( tag == "limits" || tag == "limitsets" )
1678       xml_coll_t(node, _U(limitset)).for_each(Converter<LimitSet>(this->description));
1679     else if ( tag == "display" )
1680       xml_coll_t(node,_U(vis)).for_each(Converter<VisAttr>(this->description));
1681     else if ( tag == "detector" )
1682       Converter<DetElement>(this->description)(node);
1683     else if ( tag == "detectors" )
1684       xml_coll_t(node,_U(detector)).for_each(Converter<DetElement>(this->description));
1685   }
1686   else if ( type == "json" )  {
1687     Converter<JsonFile>(this->description)(element);
1688   }
1689   else if ( type == "gdml" )  {
1690     Converter<IncludeFile>(this->description)(element);
1691   }
1692   else if ( type == "include" )  {
1693     Converter<IncludeFile>(this->description)(element);
1694   }
1695   else if ( type == "xml-extended" )  {
1696     Converter<XMLFile>(this->description)(element);
1697   }
1698   else  {
1699     except("Compact","++ FAILED    Invalid file type:%s. This cannot be processed!",type.c_str());
1700   }
1701 }
1702 
1703 /// Main compact conversion entry point
1704 template <> void Converter<Compact>::operator()(xml_h element) const {
1705   static int num_calls = 0;
1706   std::string close_option;
1707   char text[32];
1708 
1709   ++num_calls;
1710   xml_elt_t compact(element);
1711   bool steer_geometry = compact.hasChild(_U(geometry));
1712   bool open_geometry  = true;
1713   bool close_document = true;
1714   bool close_geometry = true;
1715   bool build_reflections = false;
1716   xml_dim_t world = element.child(_U(world), false);
1717 
1718 
1719   if (element.hasChild(_U(debug)))
1720     (Converter<Debug>(description))(xml_h(compact.child(_U(debug))));
1721 
1722   if ( steer_geometry )   {
1723     xml_elt_t steer = compact.child(_U(geometry));
1724     if ( steer.hasAttr(_U(open))  )
1725       open_geometry  = steer.attr<bool>(_U(open));
1726     if ( steer.hasAttr(_U(close)) )
1727       close_document = steer.attr<bool>(_U(close));
1728     if ( steer.hasAttr(_U(reflect)) )
1729       build_reflections = steer.attr<bool>(_U(reflect));
1730     if ( steer.hasAttr(_U(option))  )
1731       close_option = steer.attr<std::string>(_U(option));
1732 
1733     for (xml_coll_t clr(steer, _U(clear)); clr; ++clr) {
1734       std::string nam = clr.hasAttr(_U(name)) ? clr.attr<std::string>(_U(name)) : std::string();
1735       if ( nam.substr(0,6) == "elemen" )   {
1736         TGeoElementTable*        table = description.manager().GetElementTable();
1737         table->TGeoElementTable::~TGeoElementTable();
1738         new(table) TGeoElementTable();
1739         // This will initialize the table without filling:
1740         table->AddElement("VACUUM","VACUUM"   ,0,   0, 0.0);
1741         printout(INFO,"Compact",
1742                  "++ Cleared default ROOT TGeoElementTable contents. "
1743                  "Must now be filled from XML!");
1744       }
1745     }
1746   }
1747 
1748   if ( s_debug.materials || s_debug.elements )   {
1749     printout(INFO,"Compact","+++ UNIT System:");
1750     printout(INFO,"Compact","+++ Density:    %8.3g  Units:%8.3g",
1751              xml::_toDouble(_Unicode(gram/cm3)), dd4hep::gram/dd4hep::cm3);
1752     printout(INFO,"Compact","+++ GeV:        %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(GeV)),dd4hep::GeV);
1753     printout(INFO,"Compact","+++ sec:        %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(second)),dd4hep::second);
1754     printout(INFO,"Compact","+++ nanosecond: %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(nanosecond)),dd4hep::nanosecond);
1755     printout(INFO,"Compact","+++ kilo:       %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(kilogram)),dd4hep::kilogram);
1756     printout(INFO,"Compact","+++ kilo:       %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(joule*s*s/(m*m))),
1757              dd4hep::joule*dd4hep::s*dd4hep::s/(dd4hep::meter*dd4hep::meter));
1758     printout(INFO,"Compact","+++ meter:      %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(meter)),dd4hep::meter);
1759     printout(INFO,"Compact","+++ ampere:     %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(ampere)),dd4hep::ampere);
1760     printout(INFO,"Compact","+++ degree:     %8.3g  Units:%8.3g",xml::_toDouble(_Unicode(degree)),dd4hep::degree);
1761   }
1762   
1763   xml_coll_t(compact, _U(define)).for_each(_U(include),    Converter<DetElementInclude>(description));
1764   xml_coll_t(compact, _U(define)).for_each(_U(constant),   Converter<Constant>(description));
1765   xml_coll_t(compact, _U(std_conditions)).for_each(        Converter<STD_Conditions>(description));
1766   xml_coll_t(compact, _U(includes)).for_each(_U(gdmlFile), Converter<IncludeFile>(description));
1767   xml_coll_t(compact, _U(includes)).for_each(_U(file),     Converter<IncludeFile>(description));
1768 
1769   if (element.hasChild(_U(info)))
1770     (Converter<Header>(description))(xml_h(compact.child(_U(info))));
1771 
1772   /// These two must be parsed early, because they are needed by the detector constructors
1773   xml_coll_t(compact, _U(properties)).for_each(_U(attributes), Converter<Property>(description));
1774   xml_coll_t(compact, _U(properties)).for_each(_U(constant), Converter<PropertyConstant>(description));
1775   xml_coll_t(compact, _U(properties)).for_each(_U(matrix),   Converter<PropertyTable>(description));
1776   xml_coll_t(compact, _U(properties)).for_each(_U(plugin),   Converter<Plugin> (description));
1777   xml_coll_t(compact, _U(surfaces)).for_each(_U(opticalsurface), Converter<OpticalSurface>(description));
1778 
1779   xml_coll_t(compact, _U(materials)).for_each(_U(element),  Converter<Atom>(description));
1780   xml_coll_t(compact, _U(materials)).for_each(_U(material), Converter<Material>(description));
1781   xml_coll_t(compact, _U(materials)).for_each(_U(plugin),   Converter<Plugin> (description));
1782 
1783   printout(DEBUG, "Compact", "++ Converting visualization attributes...");
1784   xml_coll_t(compact, _U(display)).for_each(_U(include),    Converter<DetElementInclude>(description));
1785   xml_coll_t(compact, _U(display)).for_each(_U(vis),        Converter<VisAttr>(description));
1786 
1787   printout(DEBUG, "Compact", "++ Converting limitset structures...");
1788   xml_coll_t(compact, _U(limits)).for_each(_U(include),     Converter<DetElementInclude>(description));
1789   xml_coll_t(compact, _U(limits)).for_each(_U(limitset),    Converter<LimitSet>(description));
1790 
1791   printout(DEBUG, "Compact", "++ Converting region   structures...");
1792   xml_coll_t(compact, _U(regions)).for_each(_U(include),    Converter<DetElementInclude>(description));
1793   xml_coll_t(compact, _U(regions)).for_each(_U(region),     Converter<Region>(description));
1794   
1795   if ( world )  {
1796     (Converter<World>(description))(world);
1797   }
1798   if ( open_geometry ) description.init();
1799   printout(DEBUG, "Compact", "++ Converting readout  structures...");
1800   xml_coll_t(compact, _U(readouts)).for_each(_U(include), Converter<DetElementInclude>(description));
1801   xml_coll_t(compact, _U(readouts)).for_each(_U(readout), Converter<Readout>(description));
1802 
1803   printout(DEBUG, "Compact", "++ Converting included files with subdetector structures...");
1804   xml_coll_t(compact, _U(detectors)).for_each(_U(include), Converter<DetElementInclude>(description));
1805   printout(DEBUG, "Compact", "++ Converting detector structures...");
1806   xml_coll_t(compact, _U(detectors)).for_each(_U(detector), Converter<DetElement>(description));
1807   xml_coll_t(compact, _U(include)).for_each(Converter<DetElementInclude>(this->description));
1808 
1809   xml_coll_t(compact, _U(includes)).for_each(_U(xml), Converter<XMLFile>(description));
1810   xml_coll_t(compact, _U(fields)).for_each(_U(field), Converter<CartesianField>(description));
1811   xml_coll_t(compact, _U(sensitive_detectors)).for_each(_U(sd), Converter<SensitiveDetector>(description));
1812   xml_coll_t(compact, _U(parallelworld_volume)).for_each(Converter<Parallelworld_Volume>(description));
1813 
1814   if ( --num_calls == 0 && close_document )  {
1815     ::snprintf(text, sizeof(text), "%u", xml_h(element).checksum(0));
1816     description.addConstant(Constant("compact_checksum", text));
1817     if( close_geometry ) close_option += "close";
1818     description.endDocument(close_option.c_str());
1819   }
1820   if ( build_reflections )   {
1821     ReflectionBuilder rb(description);
1822     rb.execute();
1823   }
1824   /// Load plugin and process them as indicated
1825   xml_coll_t(compact, _U(plugins)).for_each(_U(plugin),  Converter<Plugin>  (description));
1826   xml_coll_t(compact, _U(plugins)).for_each(_U(include), Converter<XMLFile> (description));
1827   xml_coll_t(compact, _U(plugins)).for_each(_U(xml),     Converter<XMLFile> (description));
1828 }
1829 
1830 #ifdef _WIN32
1831 template Converter<Plugin>;
1832 template Converter<Constant>;
1833 template Converter<Material>;
1834 template Converter<Atom>;
1835 template Converter<VisAttr>;
1836 template Converter<Region>;
1837 template Converter<Readout>;
1838 template Converter<Segmentation>;
1839 template Converter<LimitSet>;
1840 template Converter<Property>;
1841 template Converter<CartesianField>;
1842 template Converter<SensitiveDetector>;
1843 template Converter<DetElement>;
1844 template Converter<GdmlFile>;
1845 template Converter<XMLFile>;
1846 template Converter<Header>;
1847 template Converter<DetElementInclude>;
1848 template Converter<Compact>;
1849 
1850 #endif