diff --git a/DDCore/include/DD4hep/Factories.h b/DDCore/include/DD4hep/Factories.h index 12c6ae6b98d74975370ed9e7df097761c7697d6c..92116429056e921cef0134dd5535ae69bc08abed 100644 --- a/DDCore/include/DD4hep/Factories.h +++ b/DDCore/include/DD4hep/Factories.h @@ -284,7 +284,12 @@ namespace { // Call function of the type [void* (*func)(dd4hep::Detector& description, xml_h handle)] #define DECLARE_XML_SHAPE(name,func) DD4HEP_OPEN_PLUGIN(dd4hep,xml_element_##name) {\ - template <> Handle<TObject> XMLObjectFactory<xml_element_##name>::create(dd4hep::Detector& l,ns::xml_h e) {return func(l,e);} \ + template <> Handle<TObject> XMLObjectFactory<xml_element_##name>::create(dd4hep::Detector& l,ns::xml_h e) {return func(l,e);}\ + DD4HEP_PLUGINSVC_FACTORY(xml_element_##name,name,TObject*(dd4hep::Detector*,ns::xml_h*),__LINE__) } + +// Call function of the type [void* (*func)(dd4hep::Detector& description, xml_h handle)] +#define DECLARE_XML_VOLUME(name,func) DD4HEP_OPEN_PLUGIN(dd4hep,xml_element_##name) {\ + template <> Handle<TObject> XMLObjectFactory<xml_element_##name>::create(dd4hep::Detector& l,ns::xml_h e) {return func(l,e);}\ DD4HEP_PLUGINSVC_FACTORY(xml_element_##name,name,TObject*(dd4hep::Detector*,ns::xml_h*),__LINE__) } // Call function of the type [long (*func)(dd4hep::Detector& description, xml_h handle)] diff --git a/DDCore/include/DD4hep/Objects.h b/DDCore/include/DD4hep/Objects.h index 3b8e8ebbcffc5ff96b843348a6ba97046db38aac..3f80f71ee26c61bc33d348a1b7c49123a906cb6e 100644 --- a/DDCore/include/DD4hep/Objects.h +++ b/DDCore/include/DD4hep/Objects.h @@ -71,9 +71,12 @@ namespace dd4hep { class RegionObject; class LimitSetObject; - typedef ROOT::Math::XYZVector Position; - typedef ROOT::Math::XYZVector Direction; - typedef ROOT::Math::XYZVector XYZAngles; + typedef ROOT::Math::RhoZPhiVector PositionRhoZPhi; + typedef ROOT::Math::Polar3DVector PositionPolar; + typedef ROOT::Math::XYZVector Position; + typedef ROOT::Math::XYZVector Position; + typedef ROOT::Math::XYZVector Direction; + typedef ROOT::Math::XYZVector XYZAngles; template <class V> V RotateX(const V& v, double a) { return ROOT::Math::VectorUtil::RotateX(v, a); diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h index 91e02862d8209235630cf2311376f06b2f62e45a..b6affce1eb9eb3d1544a6e85869804b68f0b7aec 100644 --- a/DDCore/include/XML/UnicodeValues.h +++ b/DDCore/include/XML/UnicodeValues.h @@ -321,6 +321,7 @@ UNICODE (parallelworld_volume); UNICODE (param); UNICODE (parameter); UNICODE (parameters); +UNICODE (paramphysvol); UNICODE (params); UNICODE (parent); UNICODE (particles); diff --git a/DDCore/include/XML/Utilities.h b/DDCore/include/XML/Utilities.h index 8d92a4089d6001028173c95f5505c1559d9e1342..cc68e2c88a7388bc4c79256363ee9b4330a35a6c 100644 --- a/DDCore/include/XML/Utilities.h +++ b/DDCore/include/XML/Utilities.h @@ -50,8 +50,11 @@ namespace dd4hep { */ Transform3D createTransformation(xml::Element element); + /// Create a simple volume using the shape plugin mechanism from the attributes of the XML element + Volume createStdVolume(Detector& description, xml::Element element); + /// Create a volume using the plugin mechanism from the attributes of the XML element - Volume createVolume(Detector& description, xml::Element element); + Volume createVolume(Detector& description, const std::string& type, xml::Element element); /// Create a solid shape using the plugin mechanism from the attributes of the XML element diff --git a/DDCore/include/XML/VolumeBuilder.h b/DDCore/include/XML/VolumeBuilder.h index 63759cbd0b91e861230e971f264554fb915049c3..82a0a41d92ae1c96453e2f158345fd40332a1571 100644 --- a/DDCore/include/XML/VolumeBuilder.h +++ b/DDCore/include/XML/VolumeBuilder.h @@ -15,6 +15,7 @@ // Framework include files #include "XML/XMLElements.h" +#include "XML/XMLDetector.h" #include "DD4hep/Detector.h" // C/C++ include files @@ -136,14 +137,15 @@ namespace dd4hep { * \date 12/10/2018 */ class VolumeBuilder { - public: + public: typedef ::dd4hep::DetElement DetElement; + typedef ::dd4hep::xml::DetElement xml_det_h; typedef std::map<std::string,std::pair<Handle_t,Solid> > Shapes; typedef std::map<std::string,std::pair<Handle_t,Volume> > Volumes; typedef std::map<std::string,Material> Materials; typedef std::map<std::string,std::pair<Handle_t,Transform3D> > Transformations; Detector& description; - Handle_t x_det; + xml_det_h x_det; int id = -1; std::string name; DetElement detector; @@ -156,6 +158,13 @@ namespace dd4hep { std::set<std::string> shape_veto, vol_veto; bool debug = false; + protected: + /// Place single volumes + void _placeSingleVolume(DetElement de, Volume vol, Handle_t c); + /// Place parametrized volumes + void _placeParamVolumes(DetElement de, Volume vol, Handle_t c); + + public: /// Inhibit default constructor VolumeBuilder() = delete; /// Inhibit move constructor diff --git a/DDCore/src/XML/Utilities.cpp b/DDCore/src/XML/Utilities.cpp index 37a39ac10dbf1acf335c24a9a23a1c2cca03f9af..fe52c62a1981edd5787263bb0aee26d5f4bd1a69 100644 --- a/DDCore/src/XML/Utilities.cpp +++ b/DDCore/src/XML/Utilities.cpp @@ -37,7 +37,7 @@ Transform3D dd4hep::xml::createTransformation(xml::Element e) { if ( tag == "positionRPhiZ" ) { if ( flag == 1 ) result = position * result; else if ( flag == 2 ) result = (position * rotation) * result; - ROOT::Math::RhoZPhiVector pos(x_elt.r(0), x_elt.z(0), x_elt.phi(0)); + PositionRhoZPhi pos(x_elt.r(0), x_elt.z(0), x_elt.phi(0)); position = Transform3D(pos); rotation = Transform3D(); flag = 1; @@ -78,7 +78,7 @@ Solid dd4hep::xml::createShape(Detector& description, Solid solid = Solid(PluginService::Create<TObject*>(fac, &description, &solid_elt)); if ( !solid.isValid() ) { PluginDebug dbg; - PluginService::Create<TObject*>(shape_type, &description, &solid_elt); + PluginService::Create<TObject*>(fac, &description, &solid_elt); except("xml::createShape","Failed to create solid of type %s [%s]", shape_type.c_str(),dbg.missingFactory(shape_type).c_str()); } @@ -86,7 +86,7 @@ Solid dd4hep::xml::createShape(Detector& description, } /// Create a volume using the plugin mechanism from the attributes of the XML element -Volume dd4hep::xml::createVolume(Detector& description, xml::Element element) { +Volume dd4hep::xml::createStdVolume(Detector& description, xml::Element element) { xml_dim_t e(element); if ( e.hasAttr(_U(material)) ) { xml_dim_t x_s = e.child(_U(shape)); @@ -113,6 +113,30 @@ Volume dd4hep::xml::createVolume(Detector& description, xml::Element element) return Volume(); } +/// Create a volume using the plugin mechanism from the attributes of the XML element +Volume dd4hep::xml::createVolume(Detector& description, + const std::string& typ, + xml::Element element) { + if ( !typ.empty() ) { + xml_dim_t e(element); + string fac = typ + "__volume_constructor"; + xml::Handle_t elt = element; + TObject* obj = PluginService::Create<TObject*>(fac, &description, &elt); + Volume vol = Volume(dynamic_cast<TGeoVolume*>(obj)); + if ( !vol.isValid() ) { + PluginDebug dbg; + PluginService::Create<TObject*>(fac, &description, &elt); + except("xml::createShape","Failed to create volume of type %s [%s]", + typ.c_str(),dbg.missingFactory(typ).c_str()); + } + if ( e.hasAttr(_U(name)) ) vol->SetName(e.attr<string>(_U(name)).c_str()); + vol.setAttributes(description,e.regionStr(),e.limitsStr(),e.visStr()); + return vol; + } + except("xml::createVolume","Failed to create volume. No materiaWNo type specified!"); + return Volume(); +} + Volume dd4hep::xml::createPlacedEnvelope( dd4hep::Detector& description, dd4hep::xml::Handle_t e, dd4hep::DetElement sdet) diff --git a/DDCore/src/XML/VolumeBuilder.cpp b/DDCore/src/XML/VolumeBuilder.cpp index f7f354111f5b9211ed4cc7de94df5136cb6d95b0..3169d1860b90f103d5db9a33dbfd95fdcca13b42 100644 --- a/DDCore/src/XML/VolumeBuilder.cpp +++ b/DDCore/src/XML/VolumeBuilder.cpp @@ -33,12 +33,12 @@ VolumeBuilder::VolumeBuilder(Detector& dsc, xml_h x_parent, SensitiveDetector sd : description(dsc), x_det(x_parent), sensitive(sd) { if ( x_det ) { - xml_det_t c(x_det); - name = c.nameStr(); - id = c.id(); + name = x_det.nameStr(); + id = x_det.id(); detector = DetElement(name, id); } buildType = description.buildType(); + debug = true; } /// Collect a set of materials from the leafs of an xml tag @@ -153,6 +153,8 @@ Solid VolumeBuilder::makeShape(xml_h handle) { solid.setName(nam); shapes.insert(make_pair(nam,make_pair(handle,solid))); } + printout(debug ? ALWAYS : INFO, "VolumeBuilder", + "+++ Created shape of type: %s name: %s",type.c_str(), nam.c_str()); return solid; } @@ -211,6 +213,23 @@ size_t VolumeBuilder::buildVolumes(xml_h handle) { continue; } } + /// Check if the volume is implemented by a factory + if ( (attr=c.attr_nothrow(_U(type))) ) { + string typ = c.attr<string>(attr); + Volume vol = xml::createVolume(description, typ, c); + vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr()); + volumes.insert(make_pair(nam,make_pair(c,vol))); + /// Check if the volume is sensitive + if ( c.attr_nothrow(_U(sensitive)) ) { + vol.setSensitiveDetector(sensitive); + } + if ( debug ) { + printout(ALWAYS,"VolumeBuilder","+++ Building volume from XML: %s",nam.c_str()); + } + buildVolumes(c); + continue; + } + /// Check if the volume has a shape attribute --> shape reference if ( (attr=c.attr_nothrow(_U(shape))) ) { string ref = c.attr<string>(attr); @@ -249,107 +268,165 @@ size_t VolumeBuilder::buildVolumes(xml_h handle) { buildVolumes(c); continue; } - except("VolumeBuilder","+++ Failed to create volume %s. " + except("VolumeBuilder","+++ Failed to create volume %s - " "It is neither Volume nor assembly....", nam.c_str()); } return volumes.size()-len; } -/// Build all <physvol/> identifiers as PlaceVolume daughters. Ignores structure -VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle) { - for( xml_coll_t c(handle,_U(physvol)); c; ++c ) { - xml_attr_t attr = c.attr_nothrow(_U(logvol)); - if ( !attr ) { - attr = c.attr_nothrow(_U(volume)); - } - if ( !attr ) { - except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!"); +/// Place single volumes +void VolumeBuilder::_placeSingleVolume(DetElement parent, Volume vol, xml_h c) { + xml_attr_t attr = c.attr_nothrow(_U(logvol)); + if ( !attr ) { + attr = c.attr_nothrow(_U(volume)); + } + if ( !attr ) { + except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!"); + } + string nam = c.attr<string>(attr); + if ( vol_veto.find(nam) != vol_veto.end() ) { + return; + } + auto iv = volumes.find(nam); + if ( iv == volumes.end() ) { + except("VolumeBuilder", + "+++ Failed to locate volume %s [typo somewhere in the XML?]", + nam.c_str()); + } + PlacedVolume pv; + Volume daughter = (*iv).second.second; + attr = c.attr_nothrow(_U(transformation)); + if ( attr ) { + string tr_nam = c.attr<string>(attr); + auto it = transformations.find(tr_nam); + if ( it == transformations.end() ) { + except("VolumeBuilder", + "+++ Failed to locate name transformation %s " + "[typo somewhere in the XML?]", + nam.c_str()); } - string nam = c.attr<string>(attr); - if ( vol_veto.find(nam) == vol_veto.end() ) { - auto iv = volumes.find(nam); - if ( iv == volumes.end() ) { - except("VolumeBuilder","+++ Failed to locate volume %s. [typo somewhere in the XML?]", - nam.c_str()); - } - attr = c.attr_nothrow(_U(transformation)); - if ( attr ) { - string tr_nam = c.attr<string>(attr); - auto it = transformations.find(tr_nam); - if ( it == transformations.end() ) { - except("VolumeBuilder", - "+++ Failed to locate name transformation %s. " - "[typo somewhere in the XML?]", - nam.c_str()); - } - const Transform3D& tr = (*it).second.second; - vol.placeVolume((*iv).second.second, tr); - placeDaughters(vol, c); - } - else { - Transform3D tr = xml::createTransformation(c); - vol.placeVolume((*iv).second.second, tr); - placeDaughters(vol, c); - } + const Transform3D& tr = (*it).second.second; + pv = vol.placeVolume(daughter, tr); + } + else { + Transform3D tr = xml::createTransformation(c); + pv = vol.placeVolume(daughter, tr); + } + xml_attr_t attr_nam = c.attr_nothrow(_U(name)); + if ( attr_nam ) { + string phys_nam = c.attr<string>(attr_nam); + pv->SetName(phys_nam.c_str()); + } + attr = c.attr_nothrow(_U(element)); + if ( attr && !parent.isValid() ) { + except("VolumeBuilder", + "+++ Failed to set DetElement placement for volume %s [Invalid parent]", + nam.c_str()); + } + else if ( attr ) { + int parent_id = parent.id(); + string elt = c.attr<string>(attr); + attr = c.attr_nothrow(_U(id)); + if ( attr ) { + id = c.attr<int>(attr); + elt += c.attr<string>(attr); } + DetElement de(parent,elt,parent_id); + de.setPlacement(pv); + placeDaughters(de, daughter, c); + } + else { + placeDaughters(parent, daughter, c); } - return *this; } -/// Build all <physvol/> identifiers as PlaceVolume daughters. Also handles structure -VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle) -{ - for( xml_coll_t c(handle,_U(physvol)); c; ++c ) { - xml_attr_t attr = c.attr_nothrow(_U(logvol)); - if ( !attr ) { - attr = c.attr_nothrow(_U(volume)); +/// Place parametrized volumes +void VolumeBuilder::_placeParamVolumes(DetElement parent, Volume vol, xml_h c) { + xml_attr_t attr_tr, attr_elt, attr_nam; + xml_h x_phys = c.child(_U(physvol)); + xml_attr_t attr = x_phys.attr_nothrow(_U(logvol)); + if ( !attr ) { + attr = x_phys.attr_nothrow(_U(volume)); + } + if ( !attr ) { + except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!"); + } + string nam = x_phys.attr<string>(attr); + if ( vol_veto.find(nam) != vol_veto.end() ) { + return; + } + auto iv = volumes.find(nam); + if ( iv == volumes.end() ) { + except("VolumeBuilder", + "+++ Failed to locate volume %s [typo somewhere in the XML?]", + nam.c_str()); + } + attr_elt = c.attr_nothrow(_U(element)); + if ( attr_elt && !parent.isValid() ) { + except("VolumeBuilder", + "+++ Failed to set DetElement placement for volume %s [Invalid parent]", + nam.c_str()); + } + Volume daughter = (*iv).second.second; + attr_tr = c.attr_nothrow(_U(transformation)); + Transform3D tr; + if ( attr_tr ) { + string tr_nam = c.attr<string>(attr_tr); + auto it = transformations.find(tr_nam); + if ( it == transformations.end() ) { + except("VolumeBuilder", + "+++ Failed to locate name transformation %s " + "[typo somewhere in the XML?]", + nam.c_str()); } - if ( !attr ) { - except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!"); + tr = (*it).second.second; + } + else { + tr = xml::createTransformation(c); + } + Transform3D transformation(Position(0,0,0)); + int parent_id = -1; + string elt, phys_nam; + attr_nam = x_phys.attr_nothrow(_U(name)); + if ( attr_nam ) { + phys_nam = x_phys.attr<string>(_U(name))+"_%d"; + } + if ( attr_elt ) { + parent_id = parent.id(); + elt = c.attr<string>(attr_elt); + } + int number = c.attr<int>(_U(number)); + printout(debug ? ALWAYS : DEBUG,"VolumeBuilder","+++ Mother:%s place volume %s %d times.", + vol.name(), daughter.name(), number); + for(int i=0; i<number; ++i) { + PlacedVolume pv = vol.placeVolume(daughter, transformation); + if ( attr_nam ) { + //pv->SetName(_toString(i,phys_nam.c_str()).c_str()); } - string nam = c.attr<string>(attr); - if ( vol_veto.find(nam) == vol_veto.end() ) { - auto iv = volumes.find(nam); - if ( iv == volumes.end() ) { - except("VolumeBuilder", - "+++ Failed to locate volume %s. [typo somewhere in the XML?]", - nam.c_str()); - } - PlacedVolume pv; - attr = c.attr_nothrow(_U(transformation)); - if ( attr ) { - string tr_nam = c.attr<string>(attr); - auto it = transformations.find(tr_nam); - if ( it == transformations.end() ) { - except("VolumeBuilder", - "+++ Failed to locate name transformation %s. " - "[typo somewhere in the XML?]", - nam.c_str()); - } - const Transform3D& tr = (*it).second.second; - pv = vol.placeVolume((*iv).second.second, tr); - } - else { - Transform3D tr = xml::createTransformation(c); - pv = vol.placeVolume((*iv).second.second, tr); - } - if ( (attr=c.attr_nothrow(_U(element))) ) { - int parent_id = parent.id(); - string elt = c.attr<string>(attr); - attr = c.attr_nothrow(_U(id)); - if ( attr ) { - id = c.attr<int>(attr); - elt += c.attr<string>(attr); - } - DetElement de(parent,elt,parent_id); - de.setPlacement(pv); - placeDaughters(de, vol, c); - } - else { - placeDaughters(parent, vol, c); - } + if ( attr_elt ) { + DetElement de(parent,elt,parent_id); + de.setPlacement(pv); + //placeDaughters(de, daughter, c); } + else { + //placeDaughters(parent, daughter, c); + } + transformation *= tr; } +} + +/// Build all <physvol/> identifiers as PlaceVolume daughters. Ignores structure +VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle) { + DetElement null_de; + return placeDaughters(null_de, vol, handle); +} + +/// Build all <physvol/> identifiers as PlaceVolume daughters. Also handles structure +VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle) { + for( xml_coll_t c(handle,_U(physvol)); c; ++c ) + _placeSingleVolume(parent, vol, c); + for( xml_coll_t c(handle,_U(paramphysvol)); c; ++c ) + _placeParamVolumes(parent, vol, c); return *this; } diff --git a/DDDetectors/src/VolumeAssembly_geo.cpp b/DDDetectors/src/VolumeAssembly_geo.cpp index e430d7a79141dad43878436db46ca53c867763ac..f50f99625213dc1bb165c5565ec06352450429c4 100644 --- a/DDDetectors/src/VolumeAssembly_geo.cpp +++ b/DDDetectors/src/VolumeAssembly_geo.cpp @@ -34,22 +34,23 @@ static Ref_t create_element(Detector& description, xml_h e, SensitiveDetector se Volume assembly; xml::tools::VolumeBuilder builder(description, e, sens); - builder.debug = x_dbg != 0; - builder.buildShapes(x_det); - builder.buildShapes(x_env); - builder.buildVolumes(x_det); - builder.buildVolumes(x_env); + builder.debug = x_dbg != 0 || true; // Need to keep these alive as long as the volumebuilder lives - map<string, xml::DocumentHolder*> docs; + map<string, unique_ptr<xml::DocumentHolder> > docs; for( xml_coll_t c(x_det,_U(include)); c; ++c ) { string ref = c.attr<string>(_U(ref)); - docs[ref] = new xml::DocumentHolder(xml::DocumentHandler().load(e, c.attr_value(_U(ref)))); + docs[ref] = unique_ptr<xml::DocumentHolder>(new xml::DocumentHolder(xml::DocumentHandler().load(e, c.attr_value(_U(ref))))); xml_h vols = docs[ref]->root(); + printout(builder.debug ? ALWAYS : DEBUG, "VolumeAssembly","++ Processing xml document %s.", + docs[ref]->uri().c_str()); builder.buildShapes(vols); builder.buildVolumes(vols); } - for(auto& d : docs) delete d.second; + builder.buildShapes(x_det); + builder.buildShapes(x_env); + builder.buildVolumes(x_det); + builder.buildVolumes(x_env); // Now we build the envelope if ( !x_shp ) x_shp = x_env; @@ -67,6 +68,12 @@ static Ref_t create_element(Detector& description, xml_h e, SensitiveDetector se if ( x_env.hasAttr(_U(vis)) ) { assembly.setVisAttributes(description, x_env.visStr()); } + if ( x_env.hasAttr(_U(region)) ) { + assembly.setRegion(description, x_env.regionStr()); + } + if ( x_env.hasAttr(_U(limits)) ) { + assembly.setLimitSet(description, x_env.limitsStr()); + } if ( x_det.hasAttr(_U(sensitive)) ) { sens.setType(x_det.attr<string>(_U(sensitive))); } @@ -80,7 +87,8 @@ static Ref_t create_element(Detector& description, xml_h e, SensitiveDetector se x_tr = x_env.child(_U(transformation),false); builder.placeDetector(assembly, (x_pos || x_rot || x_tr) ? x_env : x_det); printout(builder.debug ? ALWAYS : DEBUG, "VolumeBuilder", - "+++ Created subdetector instance %s",builder.name.c_str()); + "+++ Created subdetector instance %s vis:", + builder.name.c_str(), x_det.visStr().c_str()); return builder.detector; } DECLARE_DETELEMENT(DD4hep_VolumeAssembly,create_element)