Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /DD4hep/DDCore/src/plugins/Compact2Objects.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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