//========================================================================== // AIDA Detector description implementation //-------------------------------------------------------------------------- // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) // All rights reserved. // // For the licensing terms see $DD4hepINSTALL/LICENSE. // For the list of contributors see $DD4hepINSTALL/doc/CREDITS. // // Author : M.Frank // //========================================================================== // // DDCMS is a detector description convention developed by the CMS experiment. // //========================================================================== // Framework includes #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/DD4hepUnits.h" #include "DD4hep/GeoHandler.h" #include "DD4hep/Printout.h" #include "DD4hep/Plugins.h" #include "DD4hep/Path.h" #include "DD4hep/detail/SegmentationsInterna.h" #include "DD4hep/detail/DetectorInterna.h" #include "DD4hep/detail/ObjectsInterna.h" #include "XML/Utilities.h" #include "DDCMS/DDCMS.h" // Root/TGeo include files #include "TGeoManager.h" #include "TGeoMaterial.h" // C/C++ include files #include <climits> #include <iostream> #include <iomanip> #include <set> #include <map> using namespace std; using namespace dd4hep; using namespace dd4hep::cms; /// Namespace for the AIDA detector description toolkit namespace dd4hep { namespace { static UInt_t unique_mat_id = 0xAFFEFEED; class dddefinition; class include; class constantssection; class constant; class materialsection; class elementarymaterial; class compositematerial; class rotationsection; class rotation; class pospartsection; class pospart; class logicalpartsection; class logicalpart; class solidsection; class tubs; class polycone; class box; class algorithm; class vissection; class vis_apply; class vis; class debug; } /// Converter instances implemented in this compilation unit template <> void Converter<dddefinition>::operator()(xml_h element) const; template <> void Converter<debug>::operator()(xml_h element) const; template <> void Converter<constantssection>::operator()(xml_h element) const; template <> void Converter<constant>::operator()(xml_h element) const; template <> void Converter<vissection>::operator()(xml_h element) const; template <> void Converter<vis_apply>::operator()(xml_h element) const; template <> void Converter<vis>::operator()(xml_h element) const; template <> void Converter<materialsection>::operator()(xml_h element) const; template <> void Converter<elementarymaterial>::operator()(xml_h element) const; template <> void Converter<compositematerial>::operator()(xml_h element) const; template <> void Converter<rotationsection>::operator()(xml_h element) const; template <> void Converter<rotation>::operator()(xml_h element) const; template <> void Converter<logicalpartsection>::operator()(xml_h element) const; template <> void Converter<logicalpart>::operator()(xml_h element) const; template <> void Converter<pospartsection>::operator()(xml_h element) const; template <> void Converter<pospart>::operator()(xml_h element) const; template <> void Converter<solidsection>::operator()(xml_h element) const; template <> void Converter<polycone>::operator()(xml_h element) const; template <> void Converter<tubs>::operator()(xml_h element) const; template <> void Converter<box>::operator()(xml_h element) const; template <> void Converter<algorithm>::operator()(xml_h element) const; /// DD4hep specific template <> void Converter<include>::operator()(xml_h element) const; } /// Converter for <ConstantsSection/> tags template <> void Converter<constantssection>::operator()(xml_h element) const { ParsingContext* context = _param<ParsingContext>(); Namespace ns(context, element); xml_coll_t(element, _CMU(Constant)).for_each(Converter<constant>(description,context)); } /// Converter for <VisSection/> tags template <> void Converter<vissection>::operator()(xml_h element) const { ParsingContext* context = _param<ParsingContext>(); Namespace ns(context, element); xml_coll_t(element, _CMU(vis)).for_each(Converter<vis>(description,context)); } template <> void Converter<materialsection>::operator()(xml_h element) const { ParsingContext* context = _param<ParsingContext>(); Namespace ns(context, element); xml_coll_t(element, _CMU(ElementaryMaterial)).for_each(Converter<elementarymaterial>(description,context)); xml_coll_t(element, _CMU(CompositeMaterial)).for_each(Converter<compositematerial>(description,context)); } template <> void Converter<rotationsection>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>(), element); xml_coll_t(element, _CMU(Rotation)).for_each(Converter<rotation>(description,ns.context)); } template <> void Converter<pospartsection>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>(), element); xml_coll_t(element, _CMU(PosPart)).for_each(Converter<pospart>(description,ns.context)); } template <> void Converter<logicalpartsection>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>(), element); xml_coll_t(element, _CMU(LogicalPart)).for_each(Converter<logicalpart>(description,ns.context)); } template <> void Converter<solidsection>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>(), element); for(xml_coll_t solid(element, _U(star)); solid; ++solid) { string tag = solid.tag(); if ( tag == "Box" ) Converter<box>(description,ns.context)(solid); else if ( tag == "Polycone" ) Converter<polycone>(description,ns.context)(solid); else if ( tag == "Tubs" ) Converter<tubs>(description,ns.context)(solid); else printout(ERROR,"DDCMS","+++ Request to process unknown shape of type %s",tag.c_str()); } } /// Converter for <Constant/> tags template <> void Converter<constant>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t constant(element); xml_dim_t parent(constant.parent()); bool eval = parent.hasAttr(_U(eval)) ? parent.attr<bool>(_U(eval)) : false; string val = "";//ns.real_name(constant.attr<string>(_U(value))); string nam = ns.prepend(constant.nameStr()); string typ = eval ? "number" : "string"; if ( constant.hasAttr(_U(type)) ) typ = constant.typeStr(); if ( nam == "pixbarladderfull_CFStripY" ) { // debugging val = ns.real_name(constant.attr<string>(_U(value))); } else { val = ns.real_name(constant.attr<string>(_U(value))); } printout(ns.context->debug_constants ? ALWAYS : DEBUG, "DDCMS","+++ Add constant object: %s = %s [type:%s]", nam.c_str(), val.c_str(), typ.c_str()); Constant c(nam, val, typ); _toDictionary(nam, val, typ); description.addConstant(c); } /** Convert compact visualization attribute to Detector visualization attribute * * <vis name="SiVertexBarrelModuleVis" * alpha="1.0" r="1.0" g="0.75" b="0.76" * drawingStyle="wireframe" * showDaughters="false" * visible="true"/> */ template <> void Converter<vis>::operator()(xml_h e) const { Namespace ns(_param<ParsingContext>()); VisAttr attr(e.attr<string>(_U(name))); float red = e.hasAttr(_U(r)) ? e.attr<float>(_U(r)) : 1.0f; float green = e.hasAttr(_U(g)) ? e.attr<float>(_U(g)) : 1.0f; float blue = e.hasAttr(_U(b)) ? e.attr<float>(_U(b)) : 1.0f; printout(ns.context->debug_visattr ? ALWAYS : DEBUG, "Compact", "++ Converting VisAttr structure: %-16s. R=%.3f G=%.3f B=%.3f", attr.name(), red, green, blue); attr.setColor(red, green, blue); if (e.hasAttr(_U(alpha))) attr.setAlpha(e.attr<float>(_U(alpha))); if (e.hasAttr(_U(visible))) attr.setVisible(e.attr<bool>(_U(visible))); if (e.hasAttr(_U(lineStyle))) { string ls = e.attr<string>(_U(lineStyle)); if (ls == "unbroken") attr.setLineStyle(VisAttr::SOLID); else if (ls == "broken") attr.setLineStyle(VisAttr::DASHED); } else { attr.setLineStyle(VisAttr::SOLID); } if (e.hasAttr(_U(drawingStyle))) { string ds = e.attr<string>(_U(drawingStyle)); if (ds == "wireframe") attr.setDrawingStyle(VisAttr::WIREFRAME); else if (ds == "solid") attr.setDrawingStyle(VisAttr::SOLID); } else { attr.setDrawingStyle(VisAttr::SOLID); } if (e.hasAttr(_U(showDaughters))) attr.setShowDaughters(e.attr<bool>(_U(showDaughters))); else attr.setShowDaughters(true); description.addVisAttribute(attr); } /// Converter for <ElementaryMaterial/> tags template <> void Converter<elementarymaterial>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t xmat(element); string nam = ns.prepend(xmat.nameStr()); TGeoManager& mgr = description.manager(); TGeoMaterial* mat = mgr.GetMaterial(nam.c_str()); if ( 0 == mat ) { const char* matname = nam.c_str(); double density = xmat.density(); //double atomicWeight = xmat.attr<double>(_CMU(atomicWeight)); double atomicNumber = xmat.attr<double>(_CMU(atomicNumber)); TGeoElementTable* tab = mgr.GetElementTable(); TGeoMixture* mix = new TGeoMixture(nam.c_str(), 1, density); TGeoElement* elt = tab->FindElement(xmat.nameStr().c_str()); printout(ns.context->debug_materials ? ALWAYS : DEBUG, "DDCMS", "++ Converting material %-48s Density: %.3f.", ('"'+nam+'"').c_str(), density); if ( !elt ) { printout(WARNING,"DDCMS", "+++ Converter<ElementaryMaterial> No element present with name:%s [FAKE IT]", matname); int n = int(atomicNumber/2e0); if ( n < 2 ) n = 2; elt = new TGeoElement(xmat.nameStr().c_str(),"CMS element",n,atomicNumber); //return; } if ( elt->Z() == 0 ) { int n = int(atomicNumber/2e0); if ( n < 2 ) n = 2; elt = new TGeoElement((xmat.nameStr()+"-CMS").c_str(),"CMS element",n,atomicNumber); } mix->AddElement(elt, 1.0); mix->SetRadLen(0e0); /// Create medium from the material TGeoMedium* medium = mgr.GetMedium(matname); if (0 == medium) { --unique_mat_id; medium = new TGeoMedium(matname, unique_mat_id, mix); medium->SetTitle("material"); medium->SetUniqueID(unique_mat_id); } } } /// Converter for <CompositeMaterial/> tags template <> void Converter<compositematerial>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t xmat(element); string nam = ns.prepend(xmat.nameStr()); TGeoManager& mgr = description.manager(); TGeoMaterial* mat = mgr.GetMaterial(nam.c_str()); if ( 0 == mat ) { const char* matname = nam.c_str(); double density = xmat.density(); xml_coll_t composites(xmat,_CMU(MaterialFraction)); TGeoMixture* mix = new TGeoMixture(nam.c_str(), composites.size(), density); printout(ns.context->debug_materials ? ALWAYS : DEBUG, "DDCMS", "++ Converting material %-48s Density: %.3f.", ('"'+nam+'"').c_str(), density); for (composites.reset(); composites; ++composites) { xml_dim_t xfrac(composites); xml_dim_t xfrac_mat(xfrac.child(_CMU(rMaterial))); double fraction = xfrac.fraction(); string fracname = ns.real_name(xfrac_mat.nameStr()); TGeoMaterial* frac_mat = mgr.GetMaterial(fracname.c_str()); if ( frac_mat ) { mix->AddElement(frac_mat, fraction); continue; } printout(WARNING,"DDCMS","+++ Composite material \"%s\" not present!", fracname.c_str()); } mix->SetRadLen(0e0); /// Create medium from the material TGeoMedium* medium = mgr.GetMedium(matname); if (0 == medium) { --unique_mat_id; medium = new TGeoMedium(matname, unique_mat_id, mix); medium->SetTitle("material"); medium->SetUniqueID(unique_mat_id); } } } /// Converter for <Rotation/> tags template <> void Converter<rotation>::operator()(xml_h element) const { ParsingContext* ctx = _param<ParsingContext>(); Namespace ns(ctx); xml_dim_t xrot(element); string nam = ns.prepend(xrot.nameStr()); double thetaX = xrot.hasAttr(_CMU(thetaX)) ? xrot.attr<double>(_CMU(thetaX)) : 0e0; double phiX = xrot.hasAttr(_CMU(phiX)) ? xrot.attr<double>(_CMU(phiX)) : 0e0; double thetaY = xrot.hasAttr(_CMU(thetaY)) ? xrot.attr<double>(_CMU(thetaY)) : 0e0; double phiY = xrot.hasAttr(_CMU(phiY)) ? xrot.attr<double>(_CMU(phiY)) : 0e0; double thetaZ = xrot.hasAttr(_CMU(thetaZ)) ? xrot.attr<double>(_CMU(thetaZ)) : 0e0; double phiZ = xrot.hasAttr(_CMU(phiZ)) ? xrot.attr<double>(_CMU(phiZ)) : 0e0; Rotation3D rot = make_rotation3D(thetaX, phiX, thetaY, phiY, thetaZ, phiZ); ctx->rotations[nam] = rot; } /// Converter for <Rotation/> tags template <> void Converter<logicalpart>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); string sol_nam = xml_dim_t(e.child(_CMU(rSolid))).nameStr(); string mat_nam = xml_dim_t(e.child(_CMU(rMaterial))).nameStr(); Material material = description.material(ns.real_name(mat_nam)); Solid solid = ns.context->shapes[sol_nam]; Volume volume(ns.prepend(e.nameStr()), solid, material); printout(ns.context->debug_volumes ? ALWAYS : DEBUG, "DDCMS", "+++ Volume:%-24s Solid:%-24s [%-24s] Material:%s", volume.name(), solid.name(), solid.type(), material.name()); ns.context->volumes[volume.name()] = volume; } /// Converter for <Rotation/> tags template <> void Converter<pospart>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); int copy = e.attr<int>(_CMU(copyNumber)); string parent_nam = ns.real_name(xml_dim_t(e.child(_CMU(rParent))).nameStr()); string child_nam = ns.real_name(xml_dim_t(e.child(_CMU(rChild))).nameStr()); Volume parent = ns.context->volumes[parent_nam]; Volume child = ns.context->volumes[child_nam]; xml_dim_t translation(e.child(_CMU(Translation),false)); xml_dim_t rotation(e.child(_CMU(Rotation),false)); xml_dim_t refRotation(e.child(_CMU(rRotation),false)); Position pos; RotationZYX rot; printout(ns.context->debug_placements ? ALWAYS : DEBUG, "DDCMS", "+++ %s Parent: %-24s [%s] Child: %-32s [%s] copy:%d", e.tag().c_str(), parent_nam.c_str(), parent.isValid() ? "VALID" : "INVALID", child_nam.c_str(), child.isValid() ? "VALID" : "INVALID", copy); if ( translation.ptr() ) { double x = ns.attr<double>(translation,_U(x)); double y = ns.attr<double>(translation,_U(y)); double z = ns.attr<double>(translation,_U(z)); pos = Position(x,y,z); } if ( rotation.ptr() ) { double x = ns.attr<double>(rotation,_U(x)); double y = ns.attr<double>(rotation,_U(y)); double z = ns.attr<double>(rotation,_U(z)); rot = RotationZYX(z,y,x); } PlacedVolume pv; if ( child.isValid() ) { if ( !translation.ptr() && !rotation.ptr() ) pv = parent.placeVolume(child); else if ( translation.ptr() && !rotation.ptr() ) pv = parent.placeVolume(child,pos); else if ( !translation.ptr() && rotation.ptr() ) pv = parent.placeVolume(child,rot); else { Transform3D trafo(rot,pos); pv = parent.placeVolume(child,rot); } } if ( !pv.isValid() ) { printout(ERROR,"DDCMS","+++ Placement FAILED!"); } } /// Converter for <Polycone/> tags template <> void Converter<polycone>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); string nam = e.nameStr(); double startPhi = ns.attr<double>(e,_CMU(startPhi)); double deltaPhi = ns.attr<double>(e,_CMU(deltaPhi)); vector<double> z, rmin, rmax; for(xml_coll_t zplane(element, _CMU(ZSection)); zplane; ++zplane) { rmin.push_back(ns.attr<double>(zplane,_CMU(rMin))); rmax.push_back(ns.attr<double>(zplane,_CMU(rMax))); z.push_back(ns.attr<double>(zplane,_CMU(z))); } printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ Processing shape of type %s : %s",e.tag().c_str(), nam.c_str()); printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ startPhi=%10.3f [rad] deltaPhi=%10.3f [rad] %4ld z-planes", startPhi, deltaPhi, z.size()); Polycone pc(startPhi,deltaPhi,rmin,rmax,z); ns.context->shapes[nam] = pc.setName(nam); } /// Converter for <Tubs/> tags template <> void Converter<tubs>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); string nam = e.nameStr(); double dz = ns.attr<double>(e,_CMU(dz)); double rmin = ns.attr<double>(e,_CMU(rMin)); double rmax = ns.attr<double>(e,_CMU(rMax)); double startPhi = ns.attr<double>(e,_CMU(startPhi)); double deltaPhi = ns.attr<double>(e,_CMU(deltaPhi)); printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ Processing shape of type %s : %s",e.tag().c_str(), nam.c_str()); printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ dz=%10.3f [cm] rmin=%10.3f [cm] rmax=%10.3f [cm]" " startPhi=%10.3f [rad] deltaPhi=%10.3f [rad]", dz, rmin, rmax, startPhi, deltaPhi); Tube tube(rmin,rmax,dz,startPhi,deltaPhi); ns.context->shapes[nam] = tube.setName(nam); } /// Converter for <Box/> tags template <> void Converter<box>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); string nam = e.nameStr(); double dx = ns.attr<double>(e,_CMU(dx)); double dy = ns.attr<double>(e,_CMU(dy)); double dz = ns.attr<double>(e,_CMU(dz)); printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ Processing shape of type %s : %s",e.tag().c_str(), nam.c_str()); printout(ns.context->debug_shapes ? ALWAYS : DEBUG, "DDCMS", "+++ dx=%10.3f [cm] dy=%10.3f [cm] dz=%10.3f [cm]", dx, dy, dz); Box box(dx,dy,dz); ns.context->shapes[nam] = box.setName(nam); } /// DD4hep specific Converter for <Include/> tags template <> void Converter<include>::operator()(xml_h element) const { xml::DocumentHolder doc(xml::DocumentHandler().load(element, element.attr_value(_U(ref)))); xml_h node = doc.root(); Converter<dddefinition>(description,_param<ParsingContext>())(node); } /// Converter for <Algorithm/> tags template <> void Converter<algorithm>::operator()(xml_h element) const { Namespace ns(_param<ParsingContext>()); xml_dim_t e(element); string name = e.nameStr(); try { SensitiveDetector sd; Segmentation seg; string type = ns.real_name(e.nameStr()); // SensitiveDetector and Segmentation currently are undefined. Let's keep it like this // until we found something better..... DetElement det(PluginService::Create<NamedObject*>(type, &description, ns.context, &element, &sd)); if (det.isValid()) { // setChildTitles(make_pair(name, det)); if ( sd.isValid() ) { det->flag |= DetElement::Object::HAVE_SENSITIVE_DETECTOR; } if ( seg.isValid() ) { seg->sensitive = sd; seg->detector = det; } } #if 0 if (!det.isValid()) { PluginDebug dbg; PluginService::Create<NamedObject*>(type, &description, ns.context, &element, &sd); except("DDCMS","Failed to execute subdetector creation plugin. " + dbg.missingFactory(type)); } #endif ///description.addDetector(det); printout(ERROR, "DDCMS", "++ FAILED NOT ADDING SUBDETECTOR %s", name.c_str()); return; } catch (const exception& exc) { printout(ERROR, "DDCMS", "++ FAILED to convert subdetector: %s: %s", name.c_str(), exc.what()); terminate(); } catch (...) { printout(ERROR, "DDCMS", "++ FAILED to convert subdetector: %s: %s", name.c_str(), "UNKNONW Exception"); terminate(); } } template <> void Converter<debug>::operator()(xml_h dbg) const { Namespace ns(_param<ParsingContext>()); if ( dbg.hasChild(_CMU(debug_constants)) ) ns.context->debug_constants = true; if ( dbg.hasChild(_CMU(debug_materials)) ) ns.context->debug_materials = true; if ( dbg.hasChild(_CMU(debug_shapes)) ) ns.context->debug_shapes = true; if ( dbg.hasChild(_CMU(debug_volumes)) ) ns.context->debug_volumes = true; if ( dbg.hasChild(_CMU(debug_placements)) ) ns.context->debug_placements = true; if ( dbg.hasChild(_CMU(debug_namespaces)) ) ns.context->debug_namespaces = true; } template <> void Converter<vis_apply>::operator()(xml_h /* dddefinition */) const { struct VisPatcher: public detail::GeoScan { Detector& detector; VisPatcher(Detector& d) : detail::GeoScan(d.world()), detector(d) { } void patch() const { printout(INFO,"Detector","+++ Applying DD4hep visualization attributes...."); for (auto i = m_data->rbegin(); i != m_data->rend(); ++i) { for( const TGeoNode* n : (*i).second ) { Volume vol(n->GetVolume()); VisAttr vis = detector.visAttributes(vol.name()); printout(DEBUG,"Vis","+++ %s vis-attrs:%s",vol.name(), yes_no(vis.isValid())); vol.setVisAttributes(vis); } } } }; VisPatcher(description).patch(); } /// Converter for <DDDefinition/> tags template <> void Converter<dddefinition>::operator()(xml_h element) const { static int num_calls = 0; static ParsingContext ctxt; xml_elt_t dddef(element); string fname = xml::DocumentHandler::system_path(element); bool open_geometry = true; bool close_geometry = true; ++num_calls; Path path(fname); string ns = path.filename().substr(0,path.filename().rfind('.')); ctxt.namespaces.push_back(ns+'_'); xml_coll_t(dddef, _U(debug)).for_each(Converter<debug>(description,&ctxt)); // Here we define the order how XML elements are processed. // Be aware of dependencies. This can only defined once. // At the end it is a limitation of DOM.... printout(INFO,"DDCMS","+++ Processing the CMS detector description %s",fname.c_str()); xml_coll_t(dddef, _CMU(ConstantsSection)).for_each(Converter<constantssection>(description,&ctxt)); xml_coll_t(dddef, _CMU(VisSection)).for_each(Converter<vissection>(description,&ctxt)); xml_coll_t(dddef, _CMU(IncludeSection)).for_each(_CMU(Include), Converter<include>(description,&ctxt)); xml_coll_t(dddef, _CMU(RotationSection)).for_each(Converter<rotationsection>(description,&ctxt)); xml_coll_t(dddef, _CMU(MaterialSection)).for_each(Converter<materialsection>(description,&ctxt)); xml_coll_t(dddef, _CMU(SolidSection)).for_each(Converter<solidsection>(description,&ctxt)); xml_coll_t(dddef, _CMU(LogicalPartSection)).for_each(Converter<logicalpartsection>(description,&ctxt)); xml_coll_t(dddef, _CMU(PosPartSection)).for_each(Converter<pospartsection>(description,&ctxt)); /// Analyse algorithms to be called if ( !ctxt.geo_inited && dddef.hasChild(_CMU(Algorithm)) ) { ctxt.geo_inited = true; description.init(); } else if ( num_calls == 1 && open_geometry ) { ctxt.geo_inited = true; description.init(); } xml_coll_t(dddef, _CMU(Algorithm)).for_each(Converter<algorithm>(description,&ctxt)); /// This should be the end of all processing....close the geometry if ( --num_calls == 0 && close_geometry ) { Converter<vis_apply> cnv(description,&ctxt); cnv(dddef); description.endDocument(); } ctxt.namespaces.pop_back(); printout(INFO,"DDDefinition","+++ Finished processing %s",fname.c_str()); } static long load_dddefinition(Detector& description, xml_h element) { Converter<dddefinition>converter(description); converter(element); return 1; } // Now declare the factory entry for the plugin mechanism DECLARE_XML_DOC_READER(DDDefinition,load_dddefinition)