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