diff --git a/DDCore/include/DD4hep/Objects.h b/DDCore/include/DD4hep/Objects.h index 5f207d2c7cdb3a61c3866db18764c6a12069f13b..3b8e8ebbcffc5ff96b843348a6ba97046db38aac 100644 --- a/DDCore/include/DD4hep/Objects.h +++ b/DDCore/include/DD4hep/Objects.h @@ -389,11 +389,19 @@ namespace dd4hep { /// Handle class describing a set of limits as they are used for simulation /** + * The class manages the production cuts and the limits for a given simulation region. + * Currently known clients of this objects are simulation programs. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_CORE */ class LimitSet: public Handle<LimitSetObject> { + public: + /// Iterator definitions + typedef std::set<Limit> Set; + typedef std::set<Limit>::iterator iterator; + typedef std::set<Limit>::const_iterator const_iterator; public: /// Constructor to be used when reading the already parsed DOM tree LimitSet() = default; @@ -413,6 +421,10 @@ namespace dd4hep { bool addLimit(const Limit& limit); /// Accessor to limits container const std::set<Limit>& limits() const; + /// Add new limit. Returns true if the new limit was added, false if it already existed. + bool addCut(const Limit& limit); + /// Accessor to limits container + const std::set<Limit>& cuts() const; }; /// Handle class describing a region as used in simulation @@ -438,9 +450,15 @@ namespace dd4hep { /// Assignment operator Region& operator=(const Region& c) = default; + /// Set flag to store secondaries Region& setStoreSecondaries(bool value); + /// Set threshold in MeV Region& setThreshold(double value); + /// Set default production cut Region& setCut(double value); + /// Set particle type specific cut (Geant4 accepts e+, e-, gamma, and proton) + Region& setCut(double value, const std::string& particle); + /// Access references to user limits std::vector<std::string>& limits() const; diff --git a/DDCore/include/DD4hep/Shapes.h b/DDCore/include/DD4hep/Shapes.h index ad60565b5a2e5033be3dd0ebe2d3e48dd79225b3..4d7860a010eff6fdcd897387bb64dbeee6c71331 100644 --- a/DDCore/include/DD4hep/Shapes.h +++ b/DDCore/include/DD4hep/Shapes.h @@ -777,7 +777,7 @@ namespace dd4hep { */ class ExtrudedPolygon : public Solid_type<TGeoXtru> { protected: - /// Helper function to create the polyhedron + /// Helper function to create the polygon void make(const std::vector<double> & pt_x, const std::vector<double> & pt_y, const std::vector<double> & sec_z, diff --git a/DDCore/include/DD4hep/Volumes.h b/DDCore/include/DD4hep/Volumes.h index b42a221ccee38ec1dcd287340a9e6fa6f8155519..6f730b9faab51b0cf331da4fb14838b0d27bb97f 100644 --- a/DDCore/include/DD4hep/Volumes.h +++ b/DDCore/include/DD4hep/Volumes.h @@ -104,9 +104,9 @@ namespace dd4hep { std::string str() const; }; /// Magic word to detect memory corruptions - unsigned long magic; + unsigned long magic = 0; /// Reference count on object (used to implement Grab/Release) - long refCount; + long refCount = 0; /// ID container VolIDs volIDs; /// Default constructor @@ -201,9 +201,13 @@ namespace dd4hep { class VolumeExtension : public TGeoExtension { public: /// Magic word to detect memory corruptions - unsigned long magic; + unsigned long magic = 0; /// Reference count on object (used to implement Grab/Release) - long refCount; + long refCount = 0; + /// + int referenced = 0; + /// Bit field to determine the usage. Bit 0...15 reserverd for system usage. 16...31 user space. + int flags = 0; /// Region reference Region region; /// Limit sets used for simulation @@ -212,8 +216,7 @@ namespace dd4hep { VisAttr vis; /// Reference to the sensitive detector Handle<NamedObject> sens_det; - - int referenced; + /// Default constructor VolumeExtension(); /// Default destructor @@ -249,7 +252,12 @@ namespace dd4hep { class Volume: public Handle<TGeoVolume> { public: typedef VolumeExtension Object; - + /// Flag bit numbers for special volume treatments + enum { + VETO_SIMU = 1, + VETO_RECO = 2, + VETO_DISPLAY = 3 + }; public: /// Default constructor Volume() = default; @@ -299,6 +307,11 @@ namespace dd4hep { /// Place rotated daughter volume. The position is automatically the identity position PlacedVolume placeVolume(const Volume& vol, int copy_no, const Rotation3D& rot) const; + /// Set user flags in bit-field + void setFlagBit(unsigned int bit); + /// Test the user flag bit + bool testFlagBit(unsigned int bit) const; + /// Attach attributes to the volume const Volume& setAttributes(const Detector& description, const std::string& region, const std::string& limits, const std::string& vis) const; diff --git a/DDCore/include/DD4hep/detail/ObjectsInterna.h b/DDCore/include/DD4hep/detail/ObjectsInterna.h index c0f98d6e3ce3eaeab8f1380ef954c475b7f24923..6e48f0b46fae3f26d7322bac779b2c33568e9ca3 100644 --- a/DDCore/include/DD4hep/detail/ObjectsInterna.h +++ b/DDCore/include/DD4hep/detail/ObjectsInterna.h @@ -88,10 +88,13 @@ namespace dd4hep { class VisAttrObject: public NamedObject { public: unsigned long magic; - TColor* col; - int color; - float alpha; - unsigned char drawingStyle, lineStyle, showDaughters, visible; + TColor* col = 0; + int color = 0; + float alpha = 0; + unsigned char drawingStyle = VisAttr::SOLID; + unsigned char lineStyle = VisAttr::SOLID; + unsigned char showDaughters = true; + unsigned char visible = true; /// Standard constructor VisAttrObject(); /// Default destructor @@ -108,11 +111,12 @@ namespace dd4hep { class RegionObject: public NamedObject { public: unsigned long magic; - double threshold; - double cut; - bool store_secondaries; - bool use_default_cut; - bool was_threshold_set; + double threshold = 10.0; + double cut = 10.0; + bool store_secondaries = false; + bool use_default_cut = true; + bool was_threshold_set = false; + /// References to user limits std::vector<std::string> user_limits; /// Standard constructor RegionObject(); @@ -127,7 +131,16 @@ namespace dd4hep { * \version 1.0 * \ingroup DD4HEP_CORE */ - class LimitSetObject: public NamedObject, public std::set<Limit> { + class LimitSetObject: public NamedObject { + public: + /// Iterator definitions + typedef std::set<Limit>::iterator iterator; + typedef std::set<Limit>::const_iterator const_iterator; + public: + /// Particle specific limits + std::set<Limit> limits; + /// Particle specific production cuts + std::set<Limit> cuts; public: /// Standard constructor LimitSetObject(); diff --git a/DDCore/include/Parsers/detail/Dimension.h b/DDCore/include/Parsers/detail/Dimension.h index 6a6e87522e48c996f8f7a01ea60a35e60d55aa2a..07166bbda7a4f1d8e28209d6b4b3dc25216cfc88 100644 --- a/DDCore/include/Parsers/detail/Dimension.h +++ b/DDCore/include/Parsers/detail/Dimension.h @@ -419,6 +419,11 @@ namespace dd4hep { /// Access attribute values: coefficient double coefficient(double default_value) const; + /// Access attribute values: scale + double scale() const; + /// Access attribute values: scale + double scale(double default_value) const; + /// Access attribute values: skew double skew() const; /// Access attribute values: skew diff --git a/DDCore/include/Parsers/detail/Dimension.imp b/DDCore/include/Parsers/detail/Dimension.imp index ec1932619dfa668d4601a82b8989da7b374c5dc4..1380c248caa926a6eeaf02deca018c2f73095064 100644 --- a/DDCore/include/Parsers/detail/Dimension.imp +++ b/DDCore/include/Parsers/detail/Dimension.imp @@ -120,6 +120,7 @@ XML_ATTR_ACCESSOR(double, phi_size_max) XML_ATTR_ACCESSOR(double, r_size) XML_ATTR_ACCESSOR_DOUBLE(skew) +XML_ATTR_ACCESSOR_DOUBLE(scale) XML_ATTR_ACCESSOR_DOUBLE(coefficient) XML_ATTR_ACCESSOR(double, gap) diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h index 70aac776ef997d89657e6481eb6151d6bad45fa9..5ee29611d9a59dcd42bd308c425a45868a7423ae 100644 --- a/DDCore/include/XML/UnicodeValues.h +++ b/DDCore/include/XML/UnicodeValues.h @@ -132,7 +132,7 @@ UNICODE (eval); UNICODE (f); UNICODE (F); -UNICODE(false); +UNICODE (false); UNICODE (field); UNICODE (fields); UNICODE (field_name); @@ -232,6 +232,9 @@ UNICODE (lineStyle); UNICODE (local); UNICODE (logvol); UNICODE (lunit); +UNICODE (lx); +UNICODE (ly); +UNICODE (lz); UNICODE (m); UNICODE (M); @@ -301,6 +304,7 @@ UNICODE (phi); UNICODE (phi0); UNICODE (phi0_offset); UNICODE (phi1); +UNICODE (phi2); UNICODE (phi_tilt); UNICODE (phiBins); UNICODE (phi_size_max); @@ -308,6 +312,7 @@ UNICODE (physvol); UNICODE (physvolid); UNICODE (pivot); UNICODE (pivot_point); +UNICODE (plane); UNICODE (plugin); UNICODE (plugins); UNICODE (point); @@ -365,10 +370,12 @@ UNICODE (rtor); UNICODE (s); UNICODE (S); +UNICODE (scale); UNICODE (scintillator); UNICODE (sd); UNICODE (sdref); UNICODE (second); +UNICODE (section); UNICODE (segmentation); UNICODE (sensitive); UNICODE (sensitive_detector); @@ -380,7 +387,7 @@ UNICODE (shape); UNICODE (show_daughters); UNICODE (showDaughters); UNICODE (size); -UNICODE(signed); +UNICODE (signed); UNICODE (skew); UNICODE (slice); UNICODE (slices); @@ -415,8 +422,6 @@ UNICODE (thetaBins); UNICODE (thickness); UNICODE (threshold); UNICODE (title); -UNICODE (tube); -UNICODE (tubes); UNICODE (torus); UNICODE (tracker); UNICODE (tracking_cylinder); @@ -424,8 +429,13 @@ UNICODE (tracking_volume); UNICODE (trap); UNICODE (trd); UNICODE (true); +UNICODE (tube); +UNICODE (tubes); UNICODE (tubs); UNICODE (type); +UNICODE (tx); +UNICODE (ty); +UNICODE (tz); UNICODE (u); UNICODE (U); diff --git a/DDCore/src/Objects.cpp b/DDCore/src/Objects.cpp index 96ea6377ddbed065eea72b19ee9ad7365aeca094..286962b2ab07745b71cd04d8cfa491a8a3ed3a58 100644 --- a/DDCore/src/Objects.cpp +++ b/DDCore/src/Objects.cpp @@ -384,10 +384,10 @@ bool Limit::operator==(const Limit& c) const { /// operator less bool Limit::operator<(const Limit& c) const { - if (value < c.value) - return true; if (name < c.name) return true; + if (value < c.value) + return true; if (particles < c.particles) return true; return false; @@ -409,14 +409,25 @@ LimitSet::LimitSet(const string& nam) { /// Add new limit. Returns true if the new limit was added, false if it already existed. bool LimitSet::addLimit(const Limit& limit) { - pair<Object::iterator, bool> ret = data<Object>()->insert(limit); + pair<Object::iterator, bool> ret = data<Object>()->limits.insert(limit); return ret.second; } /// Accessor to limits container const set<Limit>& LimitSet::limits() const { const Object* o = data<Object>(); - return *o; + return o->limits; +} + +/// Add new limit. Returns true if the new limit was added, false if it already existed. +bool LimitSet::addCut(const Limit& cut_obj) { + pair<Object::iterator, bool> ret = data<Object>()->cuts.insert(cut_obj); + return ret.second; +} + +/// Accessor to limits container +const std::set<Limit>& LimitSet::cuts() const { + return data<Object>()->cuts; } /// Constructor to be used when creating a new DOM tree diff --git a/DDCore/src/ObjectsInterna.cpp b/DDCore/src/ObjectsInterna.cpp index 6f82b1c00b5e45a821ebe4150f585043f127cf98..373c9a27429a721645adf9ca18459cf712da59f7 100644 --- a/DDCore/src/ObjectsInterna.cpp +++ b/DDCore/src/ObjectsInterna.cpp @@ -24,9 +24,7 @@ using namespace dd4hep::detail; DD4HEP_INSTANTIATE_HANDLE_NAMED(VisAttrObject); /// Standard constructor -VisAttrObject::VisAttrObject() - : magic(magic_word()), col(0), color(0), alpha(0), - drawingStyle(VisAttr::SOLID), lineStyle(VisAttr::SOLID), showDaughters(true), visible(true) { +VisAttrObject::VisAttrObject() : magic(magic_word()) { InstanceCount::increment(this); } @@ -70,10 +68,7 @@ ConstantObject::~ConstantObject() { DD4HEP_INSTANTIATE_HANDLE_NAMED(RegionObject); /// Standard constructor -RegionObject::RegionObject() - : magic(magic_word()), threshold(10.0), cut(10.0), store_secondaries(false), - use_default_cut(true), was_threshold_set(false) -{ +RegionObject::RegionObject() : magic(magic_word()) { InstanceCount::increment(this); } diff --git a/DDCore/src/Volumes.cpp b/DDCore/src/Volumes.cpp index 440614206e7fdc6ea9b792e2d565ea9d7370d678..b2655ef812ecc06b93de35d981635421dfd91485 100644 --- a/DDCore/src/Volumes.cpp +++ b/DDCore/src/Volumes.cpp @@ -334,7 +334,8 @@ PlacedVolume::Processor::~Processor() { /// Default constructor PlacedVolumeExtension::PlacedVolumeExtension() - : TGeoExtension(), magic(0), refCount(0), volIDs() { + : TGeoExtension(), volIDs() +{ magic = magic_word(); INCREMENT_COUNTER; } @@ -457,7 +458,7 @@ ClassImp(VolumeExtension) /// Default constructor VolumeExtension::VolumeExtension() -: TGeoExtension(), magic(0), refCount(0), region(), limits(), vis(), sens_det(), referenced(0) { +: TGeoExtension(), region(), limits(), vis(), sens_det() { INCREMENT_COUNTER; } @@ -537,7 +538,25 @@ Volume& Volume::import() { except("dd4hep","Volume: Attempt to import invalid Volume handle."); return *this; } - + +/// Set user flags in bit-field +void Volume::setFlagBit(unsigned int bit) { + if ( bit <= 31 ) { + data()->flags |= 1<<bit; + return; + } + except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit); +} + +/// Test the user flag bit +bool Volume::testFlagBit(unsigned int bit) const { + if ( bit <= 31 ) { + return (data()->flags & 1<<bit) != 0; + } + except("Volume","+++ Volume flag bit outsize range [0...31]: %d",bit); + return false; // Anyhow never called. Only to satisfy the compiler. +} + static PlacedVolume _addNode(TGeoVolume* par, TGeoVolume* daughter, int id, TGeoMatrix* transform) { TGeoVolume* parent = par; if ( !parent ) { diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp index 391849e7ca184b05d72ad3bdf83c1f81f16941c3..b9303ecd09748bb37d049afea21673b1c89beb61 100644 --- a/DDCore/src/plugins/Compact2Objects.cpp +++ b/DDCore/src/plugins/Compact2Objects.cpp @@ -13,6 +13,7 @@ // Framework includes #include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/DetectorTools.h" #include "DD4hep/IDDescriptor.h" #include "DD4hep/DD4hepUnits.h" #include "DD4hep/FieldTypes.h" @@ -50,6 +51,7 @@ namespace dd4hep { class Property; class XMLFile; class JsonFile; + class TrackingVolume; class DetElementInclude; /// Converter instances implemented in this compilation unit @@ -73,6 +75,7 @@ namespace dd4hep { template <> void Converter<XMLFile>::operator()(xml_h element) const; template <> void Converter<Header>::operator()(xml_h element) const; template <> void Converter<DetElementInclude>::operator()(xml_h element) const; + template <> void Converter<TrackingVolume>::operator()(xml_h element) const; template <> void Converter<Compact>::operator()(xml_h element) const; } @@ -784,18 +787,26 @@ template <> void Converter<Readout>::operator()(xml_h e) const { * ... </limitset> */ template <> void Converter<LimitSet>::operator()(xml_h e) const { + Limit limit; LimitSet ls(e.attr<string>(_U(name))); printout(s_debug_limits ? ALWAYS : DEBUG, "Compact", "++ Converting LimitSet structure: %s.",ls.name()); for (xml_coll_t c(e, _U(limit)); c; ++c) { - Limit limit; + limit.name = c.attr<string>(_U(name)); limit.particles = c.attr<string>(_U(particles)); - limit.name = c.attr<string>(_U(name)); - limit.content = c.attr<string>(_U(value)); - limit.unit = c.attr<string>(_U(unit)); - limit.value = _multiply<double>(limit.content, limit.unit); + limit.content = c.attr<string>(_U(value)); + limit.unit = c.attr<string>(_U(unit)); + limit.value = _multiply<double>(limit.content, limit.unit); ls.addLimit(limit); } + limit.name = "cut"; + for (xml_coll_t c(e, _U(cut)); c; ++c) { + limit.particles = c.attr<string>(_U(particles)); + limit.content = c.attr<string>(_U(value)); + limit.unit = c.attr<string>(_U(unit)); + limit.value = _multiply<double>(limit.content, limit.unit); + ls.addCut(limit); + } description.addLimitSet(ls); } @@ -1051,6 +1062,55 @@ template <> void Converter<XMLFile>::operator()(xml_h element) const { this->description.fromXML(element.attr<string>(_U(ref))); } +/// Read material entries from a seperate file in one of the include sections of the geometry +template <> void Converter<TrackingVolume>::operator()(xml_h element) const { + xml_det_t trackers(element); + xml_dim_t shape = trackers.child(_U(shape)); + xml_dim_t pos = element.child(_U(position),false); + xml_dim_t rot = element.child(_U(position),false); + string path = element.attr<string>(_U(mother)); + DetElement mother(detail::tools::findElement(description, path)); + RotationZYX rotation; + Position position; + + if ( !mother.isValid() ) + except("TrackingVolume", + "+++ Cannot identify the mother of the tracking volume: '%s'",path.c_str()); + if ( pos ) + position = Position(pos.x(), pos.y(), pos.z()); + if ( rot ) + rotation = RotationZYX(rot.z(), rot.y(), rot.x()); + + Material mat(description.vacuum()); + Solid sol(xml_comp_t(shape).createShape()); + Volume vol("TrackingVolume", sol, mat); + Volume par(mother.placement().volume()); + PlacedVolume pv; + + if ( !trackers.materialStr().empty() ) + mat = description.material(trackers.materialStr()); + if ( trackers.visStr().empty() ) + vol.setVisAttributes(description.invisible()); + else + vol.setVisAttributes(description,trackers.visStr()); + /// Need to inhibit that this atrifical volume gets translated to Geant4! + vol.setFlagBit(Volume::VETO_SIMU); + + /// Now place the volume in the mother frame + if ( pos && rot ) + pv = par.placeVolume(vol, Transform3D(rotation, position)); + else if ( pos ) + pv = par.placeVolume(vol, pos); + else if ( rot ) + pv = par.placeVolume(vol, rot); + else + pv = par.placeVolume(vol); + if ( !pv.isValid() ) { + except("TrackingVolume", + "++ Failed to place the tracking volume inside the mother '%s'",path.c_str()); + } +} + /// Read material entries from a seperate file in one of the include sections of the geometry template <> void Converter<DetElementInclude>::operator()(xml_h element) const { string type = element.hasAttr(_U(type)) ? element.attr<string>(_U(type)) : string("xml"); @@ -1135,6 +1195,7 @@ template <> void Converter<Compact>::operator()(xml_h element) const { xml_coll_t(compact, _U(limits)).for_each(_U(limitset), Converter<LimitSet>(description)); xml_coll_t(compact, _U(display)).for_each(_U(include), Converter<DetElementInclude>(description)); xml_coll_t(compact, _U(display)).for_each(_U(vis), Converter<VisAttr>(description)); + printout(DEBUG, "Compact", "++ Converting readout structures..."); xml_coll_t(compact, _U(readouts)).for_each(_U(readout), Converter<Readout>(description)); printout(DEBUG, "Compact", "++ Converting region structures..."); @@ -1148,6 +1209,10 @@ template <> void Converter<Compact>::operator()(xml_h element) const { xml_coll_t(compact, _U(includes)).for_each(_U(xml), Converter<XMLFile>(description)); xml_coll_t(compact, _U(fields)).for_each(_U(field), Converter<CartesianField>(description)); xml_coll_t(compact, _U(sensitive_detectors)).for_each(_U(sd), Converter<SensitiveDetector>(description)); + + if (element.hasChild(_U(tracking_volume))) { + (Converter<TrackingVolume>(description))(xml_h(compact.child(_U(tracking_volume)))); + } ::snprintf(text, sizeof(text), "%u", xml_h(element).checksum(0)); description.addConstant(Constant("compact_checksum", text)); if ( --num_calls == 0 && close_geometry ) { diff --git a/DDCore/src/plugins/ShapePlugins.cpp b/DDCore/src/plugins/ShapePlugins.cpp index d32be9c6f88348bc194947da49299a2e94e1fa67..d0cf5daa01f3ffd76bc9d372900b032b3efa9d7c 100644 --- a/DDCore/src/plugins/ShapePlugins.cpp +++ b/DDCore/src/plugins/ShapePlugins.cpp @@ -71,6 +71,20 @@ static Handle<TObject> create_Tube(Detector&, xml_h element) { } DECLARE_XML_SHAPE(Tube__shape_constructor,create_Tube) +static Handle<TObject> create_CutTube(Detector&, xml_h element) { + xml_dim_t e(element); + return CutTube(e.rmin(0.0),e.rmax(),e.dz(), + e.attr<double>(_U(phi1)), + e.attr<double>(_U(phi2)), + e.attr<double>(_U(lx)), + e.attr<double>(_U(ly)), + e.attr<double>(_U(lz)), + e.attr<double>(_U(tx)), + e.attr<double>(_U(ty)), + e.attr<double>(_U(tz))); +} +DECLARE_XML_SHAPE(CutTube__shape_constructor,create_CutTube) + static Handle<TObject> create_EllipticalTube(Detector&, xml_h element) { xml_dim_t e(element); return EllipticalTube(e.a(),e.b(),e.dz()); @@ -92,6 +106,12 @@ static Handle<TObject> create_Trap(Detector&, xml_h element) { } DECLARE_XML_SHAPE(Trap__shape_constructor,create_Trap) +static Handle<TObject> create_PseudoTrap(Detector&, xml_h element) { + xml_dim_t e(element); + return PseudoTrap(e.x1(),e.x2(),e.y1(),e.y2(),e.z(),e.radius(),e.attr<double>(xml_tag_t("minusZ"))); +} +DECLARE_XML_SHAPE(PseudoTrap__shape_constructor,create_PseudoTrap) + static Handle<TObject> create_Trapezoid(Detector&, xml_h element) { xml_dim_t e(element); return Trapezoid(e.x1(),e.x2(),e.y1(),e.y2(),e.z(0.0)); @@ -128,6 +148,38 @@ static Handle<TObject> create_PolyhedraRegular(Detector&, xml_h element) { } DECLARE_XML_SHAPE(PolyhedraRegular__shape_constructor,create_PolyhedraRegular) +static Handle<TObject> create_Polyhedra(Detector&, xml_h element) { + xml_dim_t e(element); + std::vector<double> z, rmin, rmax; + for ( xml_coll_t c(e,_U(plane)); c; ++c ) { + xml_comp_t plane(c); + rmin.push_back(plane.rmin()); + rmax.push_back(plane.rmax()); + z.push_back(plane.z()); + } + return Polyhedra(e.numsides(),e.startphi(),e.deltaphi(),z,rmin,rmax); +} +DECLARE_XML_SHAPE(Polyhedra__shape_constructor,create_Polyhedra) + +static Handle<TObject> create_ExtrudedPolygon(Detector&, xml_h element) { + xml_dim_t e(element); + std::vector<double> pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale; + for ( xml_coll_t sec(element, _U(section)); sec; ++sec ) { + xml_dim_t section(sec); + sec_z.push_back(section.attr<double>(_U(z))); + sec_x.push_back(section.attr<double>(_U(x))); + sec_y.push_back(section.attr<double>(_U(y))); + sec_scale.push_back(section.attr<double>(_U(scale),1.0)); + } + for ( xml_coll_t pt(element, _U(point)); pt; ++pt ) { + xml_dim_t point(pt); + pt_x.push_back(point.attr<double>(_U(x))); + pt_y.push_back(point.attr<double>(_U(y))); + } + return ExtrudedPolygon(pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale); +} +DECLARE_XML_SHAPE(ExtrudedPolygon__shape_constructor,create_ExtrudedPolygon) + static Handle<TObject> create_EightPointSolid(Detector&, xml_h element) { xml_dim_t e(element); double v[8][2]; diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py index 2d6f38007276e996385a3ddc76589370a05883b5..aeedfff1c51beeebf7a86d6e041252b601a6701f 100644 --- a/DDG4/python/DDG4.py +++ b/DDG4/python/DDG4.py @@ -340,8 +340,19 @@ class Geant4: self.sensitive_types['escape_counter'] = 'Geant4EscapeCounter' + """ + Access the worker kernel object. + + \author M.Frank + """ def kernel(self): return self._kernel.worker() + + """ + Access the master kernel object. + + \author M.Frank + """ def master(self): return self._kernel diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp index 4184994264a28d490ef29e12b026d538606cd51c..5550f71104f63ca10861835d7ff80116cbe841b7 100644 --- a/DDG4/src/Geant4Converter.cpp +++ b/DDG4/src/Geant4Converter.cpp @@ -610,14 +610,18 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape) c /// Dump logical volume in GDML format to output stream void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume) const { Geant4GeometryInfo& info = data(); + PrintLevel lvl = debugVolumes ? ALWAYS : outputLevel; Geant4GeometryMaps::VolumeMap::const_iterator volIt = info.g4Volumes.find(volume); - if (volIt == info.g4Volumes.end() ) { - PrintLevel lvl = debugVolumes ? ALWAYS : outputLevel; + Volume _v(volume); + if ( _v.testFlagBit(Volume::VETO_SIMU) ) { + printout(lvl, "Geant4Converter", "++ Volume %s not converted [Veto'ed for simulation]",volume->GetName()); + return 0; + } + else if (volIt == info.g4Volumes.end() ) { const TGeoVolume* v = volume; - Volume _v(v); - string n = v->GetName(); + string n = v->GetName(); TGeoMedium* med = v->GetMedium(); - TGeoShape* sh = v->GetShape(); + TGeoShape* sh = v->GetShape(); G4VSolid* solid = (G4VSolid*) handleSolid(sh->GetName(), sh); G4Material* medium = 0; bool assembly = sh->IsA() == TGeoShapeAssembly::Class() || v->IsA() == TGeoVolumeAssembly::Class(); @@ -700,14 +704,19 @@ void* Geant4Converter::collectVolume(const string& /* name */, const TGeoVolume* /// Dump volume placement in GDML format to output stream void* Geant4Converter::handleAssembly(const string& name, const TGeoNode* node) const { TGeoVolume* mot_vol = node->GetVolume(); + PrintLevel lvl = debugVolumes ? ALWAYS : outputLevel; if ( mot_vol->IsA() != TGeoVolumeAssembly::Class() ) { return 0; } + Volume _v(mot_vol); + if ( _v.testFlagBit(Volume::VETO_SIMU) ) { + printout(lvl, "Geant4Converter", "++ AssemblyNode %s not converted [Veto'ed for simulation]",node->GetName()); + return 0; + } Geant4GeometryInfo& info = data(); Geant4AssemblyVolume* g4 = info.g4AssemblyVolumes[node]; if ( !g4 ) { - PrintLevel lvl = debugVolumes ? ALWAYS : outputLevel; g4 = new Geant4AssemblyVolume(); for(Int_t i=0; i < mot_vol->GetNdaughters(); ++i) { TGeoNode* d = mot_vol->GetNode(i); @@ -750,11 +759,17 @@ void* Geant4Converter::handleAssembly(const string& name, const TGeoNode* node) /// Dump volume placement in GDML format to output stream void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) const { Geant4GeometryInfo& info = data(); + PrintLevel lvl = debugPlacements ? ALWAYS : outputLevel; Geant4GeometryMaps::PlacementMap::const_iterator g4it = info.g4Placements.find(node); G4VPhysicalVolume* g4 = (g4it == info.g4Placements.end()) ? 0 : (*g4it).second; + TGeoVolume* vol = node->GetVolume(); + Volume _v(vol); + if ( _v.testFlagBit(Volume::VETO_SIMU) ) { + printout(lvl, "Geant4Converter", "++ Placement %s not converted [Veto'ed for simulation]",node->GetName()); + return 0; + } if (!g4) { TGeoVolume* mot_vol = node->GetMotherVolume(); - TGeoVolume* vol = node->GetVolume(); TGeoMatrix* tr = node->GetMatrix(); if (!tr) { except("Geant4Converter", "++ Attempt to handle placement without transformation:%p %s of type %s vol:%p", node, @@ -765,7 +780,6 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) node->IsA()->GetName(), vol); } else { - PrintLevel lvl = debugPlacements ? ALWAYS : outputLevel; int copy = node->GetNumber(); bool node_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class(); bool mother_is_assembly = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false; @@ -828,17 +842,12 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& PrintLevel lvl = debugRegions ? ALWAYS : outputLevel; Region r = region; g4 = new G4Region(r.name()); - // set production cut - if( not r.useDefaultCut() ) { - G4ProductionCuts* cuts = new G4ProductionCuts(); - cuts->SetProductionCut(r.cut()*CLHEP::mm/units::mm); - g4->SetProductionCuts(cuts); - } // create region info with storeSecondaries flag if( not r.wasThresholdSet() and r.storeSecondaries() ) { throw runtime_error("G4Region: StoreSecondaries is True, but no explicit threshold set:"); } + printout(lvl, "Geant4Converter", "++ Setting up region: %s", r.name()); G4UserRegionInformation* info = new G4UserRegionInformation(); info->region = r; info->threshold = r.threshold()*CLHEP::MeV/units::MeV; @@ -847,23 +856,50 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& printout(lvl, "Geant4Converter", "++ Converted region settings of:%s.", r.name()); vector < string > &limits = r.limits(); + G4ProductionCuts* cuts = 0; + // set production cut + if( not r.useDefaultCut() ) { + cuts = new G4ProductionCuts(); + cuts->SetProductionCut(r.cut()*CLHEP::mm/units::mm); + printout(lvl, "Geant4Converter", "++ %s: Using default cut: %f [mm]", + r.name(), r.cut()*CLHEP::mm/units::mm); + } for (const auto& nam : limits ) { LimitSet ls = m_detDesc.limitSet(nam); if (ls.isValid()) { + const LimitSet::Set& cts = ls.cuts(); + for (const auto& c : cts ) { + int pid; + if ( c.particles == "*" ) pid = -1; + else if ( c.particles == "e-" ) pid = idxG4ElectronCut; + else if ( c.particles == "e+" ) pid = idxG4PositronCut; + else if ( c.particles == "gamma" ) pid = idxG4GammaCut; + else if ( c.particles == "proton" ) pid = idxG4ProtonCut; + else throw runtime_error("G4Region: Invalid production cut particle-type:" + c.particles); + if ( !cuts ) cuts = new G4ProductionCuts(); + cuts->SetProductionCut(c.value*CLHEP::mm/units::mm, pid); + printout(lvl, "Geant4Converter", "++ %s: Set cut [%s/%d] = %f [mm]", + r.name(), c.particles.c_str(), pid, c.value*CLHEP::mm/units::mm); + } bool found = false; const auto& lm = data().g4Limits; for (const auto& j : lm ) { if (nam == j.first->GetName()) { g4->SetUserLimits(j.second); + printout(lvl, "Geant4Converter", "++ %s: Set limits %s to region type %s", + r.name(), nam.c_str(), j.second->GetType().c_str()); found = true; break; } } - if (found) + if ( found ) { continue; + } } throw runtime_error("G4Region: Failed to resolve user limitset:" + nam); } + /// Assign cuts to region if they were created + if ( cuts ) g4->SetProductionCuts(cuts); data().g4Regions[region] = g4; } return g4; @@ -873,26 +909,34 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& void* Geant4Converter::handleLimitSet(LimitSet limitset, const set<const TGeoVolume*>& /* volumes */) const { G4UserLimits* g4 = data().g4Limits[limitset]; if (!g4) { - g4 = new Geant4UserLimits(limitset); - /* - LimitSet ls = limitset; - g4 = new G4UserLimits(limitset); - const set<Limit>& limits = ls.limits(); - for (const auto& l : limits) { - if (l.name == "step_length_max") - g4->SetMaxAllowedStep(l.value*CLHEP::mm/units::mm); - else if (l.name == "track_length_max") - g4->SetUserMaxTrackLength(l.value*CLHEP::mm/units::mm); - else if (l.name == "time_max") - g4->SetUserMaxTime(l.value*CLHEP::ns/units::ns); - else if (l.name == "ekin_min") - g4->SetUserMinEkine(l.value*CLHEP::MeV/units::MeV); - else if (l.name == "range_min") - g4->SetUserMinRange(l.value); - else - throw runtime_error("Unknown Geant4 user limit: " + l.toString()); + struct LimitPrint { + const LimitSet& ls; + LimitPrint(const LimitSet& lset) : ls(lset) {} + const LimitPrint& operator()(const std::string& pref, const Geant4UserLimits::Handler& h) const { + if ( !h.particleLimits.empty() ) { + printout(ALWAYS,"Geant4Converter", + "+++ LimitSet: Limit %s.%s applied for particles:",ls.name(), pref.c_str()); + for(const auto& p : h.particleLimits) + printout(ALWAYS,"Geant4Converter","+++ LimitSet: Particle type: %-18s PDG: %-6d : %f", + p.first->GetParticleName().c_str(), p.first->GetPDGEncoding(), p.second); + } + else { + printout(ALWAYS,"Geant4Converter", + "+++ LimitSet: Limit %s.%s NOT APPLIED.",ls.name(), pref.c_str()); + } + return *this; + } + }; + Geant4UserLimits* limits = new Geant4UserLimits(limitset); + g4 = limits; + if ( debugRegions ) { + LimitPrint print(limitset); + print("maxTime", limits->maxTime) + ("minEKine", limits->minEKine) + ("minRange", limits->minRange) + ("maxStepLength", limits->maxStepLength) + ("maxTrackLength",limits->maxTrackLength); } - */ data().g4Limits[limitset] = g4; } return g4; diff --git a/DDG4/src/Geant4Plugins.cpp b/DDG4/src/Geant4Plugins.cpp index b22db7d03bb65397cf5ed97719fdc27fbfe6bc1b..dc7e399bfabfa027b4161807565b29320f96b62b 100644 --- a/DDG4/src/Geant4Plugins.cpp +++ b/DDG4/src/Geant4Plugins.cpp @@ -17,7 +17,6 @@ #include "DDG4/Geant4SensDetAction.h" #include "DDG4/Geant4PhysicsList.h" #include "DDG4/Geant4InputAction.h" -#include "DDG4/Geant4Converter.h" // Geant4 include files #include "G4VSensitiveDetector.hh" diff --git a/DDG4/src/Geant4UIMessenger.cpp b/DDG4/src/Geant4UIMessenger.cpp index bc2e8e65218687092ea9bd53c6989fa35f2fc583..69aecc24056c0c128c22b752f5602b553e7227d8 100644 --- a/DDG4/src/Geant4UIMessenger.cpp +++ b/DDG4/src/Geant4UIMessenger.cpp @@ -48,7 +48,7 @@ namespace { Geant4UIMessenger::Geant4UIMessenger(const string& name, const string& path) : G4UImessenger(), m_directory(0), m_properties(0), m_name(name), m_path(path) { m_directory = new G4UIdirectory(path.c_str()); - printout(INFO, "Geant4UIMessenger", "+++ %s> Install Geant4 control directory:%s", name.c_str(), path.c_str()); + printout(INFO, "Geant4UI", "+++ %s> Install Geant4 control directory:%s", name.c_str(), path.c_str()); m_directory->SetGuidance(("Control hierarchy for Geant4 action:" + name).c_str()); } @@ -81,7 +81,7 @@ G4String Geant4UIMessenger::GetCurrentValue(G4UIcommand * c) { const string& n = (*i).second; return (*m_properties)[n].str(); } - printout(INFO, "Geant4UIMessenger", + printout(INFO, "Geant4UI", "+++ %s> Failed to access property value.", m_name.c_str()); return ""; } @@ -95,23 +95,23 @@ void Geant4UIMessenger::SetNewValue(G4UIcommand *c, G4String v) { if (!v.empty()) { Property& p = (*m_properties)[n]; p.str(v); - printout(INFO, "Geant4UIMessenger", + printout(INFO, "Geant4UI", "+++ %s> Setting property value %s = %s native:%s.", m_name.c_str(), n.c_str(), v.c_str(), p.str().c_str()); } else { string value = (*m_properties)[n].str(); - printout(INFO, "Geant4UIMessenger", "+++ %s> Unchanged property value %s = %s.", + printout(INFO, "Geant4UI", "+++ %s> Unchanged property value %s = %s.", m_name.c_str(), n.c_str(), value.c_str()); } } catch(const exception& e) { - printout(INFO, "Geant4UIMessenger", "+++ %s> Exception: Failed to change property %s = '%s'.", + printout(INFO, "Geant4UI", "+++ %s> Exception: Failed to change property %s = '%s'.", m_name.c_str(), n.c_str(), v.c_str()); - printout(INFO, "Geant4UIMessenger", "+++ %s> Exception: %s", m_name.c_str(), e.what()); + printout(INFO, "Geant4UI", "+++ %s> Exception: %s", m_name.c_str(), e.what()); } catch(...) { - printout(INFO, "Geant4UIMessenger", "+++ %s> UNKNOWN Exception: Failed to change property %s = '%s'.", + printout(INFO, "Geant4UI", "+++ %s> UNKNOWN Exception: Failed to change property %s = '%s'.", m_name.c_str(), n.c_str(), v.c_str()); } return; @@ -123,16 +123,16 @@ void Geant4UIMessenger::SetNewValue(G4UIcommand *c, G4String v) { (*j).second.execute(0); } catch(const exception& e) { - printout(INFO, "Geant4UIMessenger", "+++ %s> Exception: Failed to exec action '%s' [%s].", + printout(INFO, "Geant4UI", "+++ %s> Exception: Failed to exec action '%s' [%s].", m_name.c_str(), c->GetCommandName().c_str(), c->GetCommandPath().c_str()); - printout(INFO, "Geant4UIMessenger", "+++ %s> Exception: %s",e.what()); + printout(INFO, "Geant4UI", "+++ %s> Exception: %s",e.what()); } catch(...) { - printout(INFO, "Geant4UIMessenger", "+++ %s> UNKNOWN Exception: Failed to exec action '%s' [%s].", + printout(INFO, "Geant4UI", "+++ %s> UNKNOWN Exception: Failed to exec action '%s' [%s].", m_name.c_str(), c->GetCommandName().c_str(), c->GetCommandPath().c_str()); } return; } } - printout(INFO, "Geant4UIMessenger", "+++ %s> Unknown command callback!", m_name.c_str()); + printout(INFO, "Geant4UI", "+++ %s> Unknown command callback!", m_name.c_str()); } diff --git a/examples/CLICSiD/scripts/CLICSid.py b/examples/CLICSiD/scripts/CLICSid.py index dc6c2abf12b5d4ed8b943fec2aa26833ab2abb95..a2c3573cdabacccbb19c4064d122f801712b0efb 100644 --- a/examples/CLICSiD/scripts/CLICSid.py +++ b/examples/CLICSiD/scripts/CLICSid.py @@ -69,7 +69,8 @@ class CLICSid: seq,act = self.geant4.setupCalorimeter('LumiCal') seq,act = self.geant4.setupCalorimeter('BeamCal') return self - + + # Test the configuration def test_config(self, have_geo=True): self.kernel.configure() if have_geo: diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt index 6d229804101ffbbb96f9ca85a0ee82ebe226bd2e..d2d37f6abb45bc0032c47c6f65650f475b0a72a7 100644 --- a/examples/ClientTests/CMakeLists.txt +++ b/examples/ClientTests/CMakeLists.txt @@ -214,6 +214,38 @@ endforeach() # if (DD4HEP_USE_GEANT4) # + # Geant4 test if production cuts are processed + dd4hep_add_test_reg( ClientTests_MiniTel_prod_cuts + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/MiniTelRegions.py batch + REQUIRES DDG4 Geant4 + REGEX_PASS "minitel_region_1: Set cut \\[gamma/0\\] = 5.000" + REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) + # + # Geant4 test if production cuts are processed + dd4hep_add_test_reg( ClientTests_MiniTel_limitset + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/MiniTelRegions.py batch + REQUIRES DDG4 Geant4 + REGEX_PASS "LimitSet: Particle type: mu- PDG: 13 : 3.000000" + REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) + # + # Test of an example user analysis creating an N-tuple instead of an output file with events + dd4hep_add_test_reg( ClientTests_sim_UserAnalysis + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/MiniTelEnergyDeposits.py batch + REQUIRES DDG4 Geant4 + REGEX_PASS "Entries : 200 " + REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) + # + # Test of an example user analysis creating an N-tuple instead of an output file with events + dd4hep_add_test_reg( ClientTests_sim_TrackinRegion + COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" + EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/TrackingRegion.py batch + REQUIRES DDG4 Geant4 + REGEX_PASS "Placement TrackingVolume_1 not converted \\[Veto'ed for simulation\\]" + REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) + # # Geant4 full simulation checks of simple detectors foreach(script Assemblies LheD_tracker MiniTel NestedDetectors ) dd4hep_add_test_reg( ClientTests_sim_${script} @@ -223,6 +255,7 @@ if (DD4HEP_USE_GEANT4) REGEX_PASS NONE REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) endforeach(script) + # # Geant4 full simulation checks of multi-collection/segmentation detectors foreach(script MultiCollections MultiSegmentations MultiSegmentCollections ) dd4hep_add_test_reg( ClientTests_sim_${script} @@ -234,11 +267,4 @@ if (DD4HEP_USE_GEANT4) REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) endforeach(script) - dd4hep_add_test_reg( ClientTests_sim_UserAnalysis - COMMAND "${CMAKE_INSTALL_PREFIX}/bin/run_test_ClientTests.sh" - EXEC_ARGS python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/MiniTelEnergyDeposits.py batch - REQUIRES DDG4 Geant4 - REGEX_PASS "Entries : 200 " - REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) - endif(DD4HEP_USE_GEANT4) diff --git a/examples/ClientTests/compact/Assemblies.xml b/examples/ClientTests/compact/Assemblies.xml index 2b299a5220184b89840f2fa01622895d33dfa8ad..f8e27000f01ccd8d3122a10ef40c639110ec757e 100644 --- a/examples/ClientTests/compact/Assemblies.xml +++ b/examples/ClientTests/compact/Assemblies.xml @@ -37,11 +37,14 @@ <limit name="step_length_max" particles="*" value="5.0" unit="mm" /> </limitset> <limitset name="VXD_RegionLimitSet"> - <limit name="step_length_max" particles="*" value="5.0" unit="mm" /> + <limit name="step_length_max" particles="*" value="5.0" unit="mm" /> <limit name="track_length_max" particles="*" value="5.0" unit="mm" /> - <limit name="time_max" particles="*" value="5.0" unit="ns" /> - <limit name="ekin_min" particles="*" value="0.01" unit="MeV" /> - <limit name="range_min" particles="*" value="5.0" unit="mm" /> + <limit name="time_max" particles="*" value="5.0" unit="ns" /> + <limit name="ekin_min" particles="*" value="0.01" unit="MeV" /> + <limit name="range_min" particles="*" value="5.0" unit="mm" /> + <cut particles="e+" value="2.0" unit="mm" /> + <cut particles="e-" value="2.0" unit="mm" /> + <cut particles="gamma" value="5.0" unit="mm" /> </limitset> </limits> <regions> diff --git a/examples/ClientTests/compact/MiniTel.xml b/examples/ClientTests/compact/MiniTel.xml index 3ad9944f32138fb60a420bbbeacedf55edb198ae..889945c642d6c3d2997bce8de1a00728055afd1b 100644 --- a/examples/ClientTests/compact/MiniTel.xml +++ b/examples/ClientTests/compact/MiniTel.xml @@ -38,21 +38,21 @@ <detectors> - <detector name="MyLHCBdetector1" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="1" sensitive="true" readout="MyLHCBdetector1Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector1" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="1" sensitive="true" readout="MyLHCBdetector1Hits" limits="minitel_limits_1" region="minitel_region_1"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="0*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> </detector> - <detector name="MyLHCBdetector2" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="2" sensitive="true" readout="MyLHCBdetector2Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector2" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="2" sensitive="true" readout="MyLHCBdetector2Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="10*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> </detector> - <detector name="MyLHCBdetector3" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="3" sensitive="true" readout="MyLHCBdetector3Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector3" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="3" sensitive="true" readout="MyLHCBdetector3Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="20*mm" y="0*cm" x="0*cm" /> @@ -60,7 +60,7 @@ </detector> - <detector name="MyLHCBdetector4" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="4" sensitive="true" readout="MyLHCBdetector4Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector4" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="4" sensitive="true" readout="MyLHCBdetector4Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm"/> <position z="30*mm" y="0*cm" x="0*cm" /> @@ -68,7 +68,7 @@ </detector> - <detector name="MyLHCBdetector5" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="5" sensitive="true" readout="MyLHCBdetector5Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector5" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="5" sensitive="true" readout="MyLHCBdetector5Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm"/> <position z="40*mm" y="0*cm" x="0*cm" /> @@ -76,7 +76,7 @@ </detector> - <detector name="MyLHCBdetector6" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="6" sensitive="true" readout="MyLHCBdetector6Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector6" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="6" sensitive="true" readout="MyLHCBdetector6Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="50*mm" y="0*cm" x="0*cm" /> @@ -84,7 +84,7 @@ </detector> - <detector name="MyLHCBdetector7" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="7" sensitive="true" readout="MyLHCBdetector7Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector7" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="7" sensitive="true" readout="MyLHCBdetector7Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="60*mm" y="0*cm" x="0*cm" /> @@ -92,31 +92,41 @@ </detector> - <detector name="MyLHCBdetector8" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="8" sensitive="true" readout="MyLHCBdetector8Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector8" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="8" sensitive="true" readout="MyLHCBdetector8Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="70*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> </detector> - <detector name="MyLHCBdetector9" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="9" sensitive="true" readout="MyLHCBdetector9Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector9" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="9" sensitive="true" readout="MyLHCBdetector9Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="80*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> </detector> - <detector name="MyLHCBdetector10" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="10" sensitive="true" readout="MyLHCBdetector10Hits" limits="minitel_limits"> + <detector name="MyLHCBdetector10" type="MiniTelPixel" material="Silicon" vis="DetVis" id ="10" sensitive="true" readout="MyLHCBdetector10Hits" limits="minitel_limits" region="minitel_region"> <dimensions z="1*mm" y="10*cm" x="10*cm" /> <position z="90*mm" y="0*cm" x="0*cm" /> <module name="pixel" type="MiniTelPixel" material="Silicon" x="6*mm" y="6*mm" z="1*mm" vis="ModVis" alpha="-2.*radian" beta="-2.*radian" gamma="-0.*radian" /> </detector> - - </detectors> <limits> + <limitset name="minitel_limits_1"> + <limit name="step_length_max" particles="e[+-]" value="1.0" unit="mm" /> + <limit name="step_length_max" particles="mu[+-]" value="3.0" unit="mm" /> + <limit name="step_length_max" particles="*" value="5.0" unit="mm" /> + <limit name="track_length_max" particles="*" value="5.0" unit="mm" /> + <limit name="time_max" particles="*" value="5.0" unit="ns" /> + <limit name="ekin_min" particles="*" value="0.01" unit="MeV" /> + <limit name="range_min" particles="*" value="5.0" unit="mm" /> + <cut particles="e+" value="2.0" unit="mm" /> + <cut particles="e-" value="2.0" unit="mm" /> + <cut particles="gamma" value="5.0" unit="mm" /> + </limitset> <limitset name="minitel_limits"> <limit name="step_length_max" particles="e[+-]" value="1.0" unit="mm" /> <limit name="step_length_max" particles="mu[+-]" value="3.0" unit="mm" /> @@ -124,6 +134,15 @@ </limitset> </limits> + <regions> + <region name="minitel_region_1" eunit="MeV" lunit="mm" cut="0.001" threshold="0.001"> + <limitsetref name="minitel_limits_1"/> + </region> + <region name="minitel_region" eunit="MeV" lunit="mm" cut="0.001" threshold="0.001"> + <limitsetref name="minitel_limits"/> + </region> + </regions> + <readouts> <readout name="MyLHCBdetector1Hits"> <segmentation type="CartesianGridXY" grid_size_x="6*mm" grid_size_y="6*mm" /> diff --git a/examples/ClientTests/compact/TrackingRegion.xml b/examples/ClientTests/compact/TrackingRegion.xml new file mode 100644 index 0000000000000000000000000000000000000000..24ca0b9d45911459f3220c071313bf71ed826ff7 --- /dev/null +++ b/examples/ClientTests/compact/TrackingRegion.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd"> + + <info name="SiliconBlock" + title="Test with 2 simple silicon boxes" + author="Markus Frank" + url="http://www.cern.ch/lhcb" + status="development" + version="$Id: compact.xml 513 2013-04-05 14:31:53Z gaede $"> + <comment>Alignment test with 2 simple boxes</comment> + </info> + + <includes> + <gdmlFile ref="${DD4hepINSTALL}/DDDetectors/compact/elements.xml"/> + <gdmlFile ref="${DD4hepINSTALL}/DDDetectors/compact/materials.xml"/> + </includes> + + <define> + <constant name="world_size" value="30*m"/> + <constant name="world_x" value="world_size"/> + <constant name="world_y" value="world_size"/> + <constant name="world_z" value="world_size"/> + </define> + + <display> + <vis name="Invisible" showDaughters="false" visible="false"/> + <vis name="InvisibleWithChildren" showDaughters="true" visible="false"/> + <vis name="VisibleRed" r="1.0" g="0.0" b="0.0" showDaughters="true" visible="true"/> + <vis name="VisibleBlue" r="0.0" g="0.0" b="1.0" showDaughters="false" visible="true"/> + <vis name="VisibleGreen" alpha="1.0" r="0.0" g="1.0" b="0.0" showDaughters="true" visible="true" drawingStyle="solid" lineStyle="solid"/> + </display> + + <limits> + <limitset name="SiRegionLimitSet"> + <limit name="step_length_max" particles="*" value="5.0" unit="mm" /> + <limit name="track_length_max" particles="*" value="1.0" unit="mm" /> + </limitset> + </limits> + + <regions> + <region name="SiRegion" eunit="MeV" lunit="mm" cut="0.001" threshold="0.001"> + <limitsetref name="SiRegionLimitSet"/> + </region> + </regions> + + <tracking_volume mother="/world" vis="VisibleBlue"> + <material name="Air"/> + <shape type="BooleanShape" operation="Subtraction"> + <shape type="BooleanShape" operation="Subtraction"> + <shape type="BooleanShape" operation="Subtraction" > + <shape type="Tube" rmin="0*cm" rmax="100*cm" dz="100*cm"/> + <shape type="Cone" rmin2="0*cm" rmax2="60*cm" rmin1="0*cm" rmax1="30*cm" z="40*cm"/> + <position x="0*cm" y="0*cm" z="65*cm"/> + </shape> + <shape type="Cone" rmin1="0*cm" rmax1="60*cm" rmin2="0*cm" rmax2="30*cm" z="40*cm"/> + <position x="0" y="0" z="-65*cm"/> + </shape> + <shape type="Cone" rmin2="0*cm" rmax2="55*cm" rmin1="0*cm" rmax1="55*cm" z="30*cm"/> + <position x="0" y="0" z="0*cm"/> + </shape> + <position x="0" y="0" z="0"/> + <rotation x="0" y="0" z="0"/> + </tracking_volume> + + <detectors> + <detector id="1" name="SiliconBlock" type="DD4hep_BoxSegment" readout="SiliconHits" vis="VisibleGreen" sensitive="true" region="SiRegion" limits="SiRegionLimitSet"> + <material name="Silicon"/> + <sensitive type="tracker"/> + <box x="20*cm" y="20*cm" z="20*cm"/> + <position x="0" y="0" z="0"/> + <rotation x="0" y="0" z="0"/> + </detector> + </detectors> + + <readouts> + <readout name="SiliconHits"> + <id>system:8</id> + </readout> + </readouts> + + <fields> + <field name="GlobalSolenoid" type="solenoid" + inner_field="5.0*tesla" + outer_field="-1.5*tesla" + zmax="2*m" + outer_radius="3*m"> + </field> + </fields> + +</lccdd> diff --git a/examples/ClientTests/scripts/DDG4TestSetup.py b/examples/ClientTests/scripts/DDG4TestSetup.py new file mode 100644 index 0000000000000000000000000000000000000000..c6d32120b0bb82841f98c38b10e2bc5f46248b50 --- /dev/null +++ b/examples/ClientTests/scripts/DDG4TestSetup.py @@ -0,0 +1,83 @@ +import os, sys, time, logging, DDG4 +from DDG4 import OutputLevel as Output +from g4Units import * + +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) + +""" + + dd4hep example setup using the python configuration + + \author M.Frank + \version 1.0 + +""" +class Setup: + def __init__(self, geometry_file): + self.kernel = DDG4.Kernel() + self.kernel.setOutputLevel('Geant4Converter',Output.DEBUG) + self.kernel.setOutputLevel('Gun',Output.INFO) + self.kernel.loadGeometry(geometry_file) + + self.geant4 = DDG4.Geant4(self.kernel) + self.geant4.printDetectors() + self.geant4.setupCshUI() + + def configure(self): + # Configure field + self.field = self.geant4.setupTrackingField(prt=True) + return self + + def defineOutput(self,output): + # Configure I/O + evt_root = self.geant4.setupROOTOutput('RootOutput',output,mc_truth=True) + return evt_root + + def setupGun(self, name="Gun",particle='pi-',energy=100*GeV,multiplicity=1): + # Setup particle gun + self.geant4.setupGun(name,particle=particle,energy=energy,multiplicity=multiplicity) + return self + + def setupGenerator(self): + # And handle the simulation particles. + part = DDG4.GeneratorAction(self.kernel,"Geant4ParticleHandler/ParticleHandler") + self.kernel.generatorAction().adopt(part) + part.SaveProcesses = ['conv','Decay'] + part.MinimalKineticEnergy = 1*MeV + part.OutputLevel = 5 # generator_output_level + part.enableUI() + return self + + def setupPhysics(self): + # Now build the physics list: + self.phys = self.kernel.physicsList() + self.phys.extends = 'QGSP_BERT' + self.phys.enableUI() + return self + + def run(self): + # and run + self.geant4.execute() + return self + + # Stop the entire excercise + def terminate(self): + self.kernel.terminate() + logging.info('+++++ All Done....\n\nTEST_PASSED') + sys.exit(0) + + # Test the configuration + def test_config(self, have_geo=True): + self.kernel.configure() + if have_geo: + self.kernel.initialize() + + # Test runner + def test_run(self, have_geo=True, have_physics=False): + self.test_config(have_geo) + if have_geo: + self.kernel.UI = '' + self.kernel.NumEvents = 0 + self.kernel.run() + self.terminate() + diff --git a/examples/ClientTests/scripts/MiniTel.py b/examples/ClientTests/scripts/MiniTel.py index 3d457ba9e5bd04277b16c637c8637b7e84be1d85..ab2a1b33684523692170b04c1b33dfcfbe558265 100644 --- a/examples/ClientTests/scripts/MiniTel.py +++ b/examples/ClientTests/scripts/MiniTel.py @@ -1,7 +1,4 @@ -import os, sys, time, DDG4 -from DDG4 import OutputLevel as Output -from SystemOfUnits import * -# +import os, sys # """ @@ -12,51 +9,18 @@ from SystemOfUnits import * """ def run(): - kernel = DDG4.Kernel() - install_dir = os.environ['DD4hepINSTALL'] - kernel.setOutputLevel('Geant4Converter',Output.DEBUG) - kernel.setOutputLevel('Gun',Output.INFO) - kernel.loadGeometry("file:"+install_dir+"/examples/ClientTests/compact/MiniTel.xml") + from MiniTelSetup import Setup as MiniTel + m = MiniTel() - geant4 = DDG4.Geant4(kernel) - geant4.printDetectors() - geant4.setupCshUI() if len(sys.argv) >= 2 and sys.argv[1] =="batch": - kernel.UI = '' - - # Configure field - field = geant4.setupTrackingField(prt=True) - # Configure I/O - evt_root = geant4.setupROOTOutput('RootOutput','MiniTel_'+time.strftime('%Y-%m-%d_%H-%M'),mc_truth=True) - # Setup particle gun - geant4.setupGun("Gun",particle='pi-',energy=100*GeV,multiplicity=1) - # Now the calorimeters - seq,act = geant4.setupTracker('MyLHCBdetector1') - seq,act = geant4.setupTracker('MyLHCBdetector2') - seq,act = geant4.setupTracker('MyLHCBdetector3') - seq,act = geant4.setupTracker('MyLHCBdetector4') - act.OutputLevel = 4 - seq,act = geant4.setupTracker('MyLHCBdetector5') - seq,act = geant4.setupTracker('MyLHCBdetector6') - seq,act = geant4.setupTracker('MyLHCBdetector7') - seq,act = geant4.setupTracker('MyLHCBdetector8') - seq,act = geant4.setupTracker('MyLHCBdetector9') - seq,act = geant4.setupTracker('MyLHCBdetector10') - - # And handle the simulation particles. - part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") - kernel.generatorAction().adopt(part) - part.SaveProcesses = ['conv','Decay'] - part.MinimalKineticEnergy = 1*MeV - part.OutputLevel = 5 # generator_output_level - part.enableUI() - - # Now build the physics list: - phys = kernel.physicsList() - phys.extends = 'QGSP_BERT' - phys.enableUI() - # and run - geant4.execute() + m.kernel.UI = '' + + m.configure() + m.defineOutput() + m.setupGun() + m.setupGenerator() + m.setupPhysics() + m.run() if __name__ == "__main__": run() diff --git a/examples/ClientTests/scripts/MiniTelEnergyDeposits.py b/examples/ClientTests/scripts/MiniTelEnergyDeposits.py index 3a6c40d3b25204c65998a26eb9b0eadf6df3a1ef..936257f14ade2b0286bc4719496ffe1b1d9334b6 100644 --- a/examples/ClientTests/scripts/MiniTelEnergyDeposits.py +++ b/examples/ClientTests/scripts/MiniTelEnergyDeposits.py @@ -1,6 +1,4 @@ -import os, sys, time, DDG4 -from DDG4 import OutputLevel as Output -from SystemOfUnits import * +import sys, time, DDG4, MiniTelSetup # # """ @@ -12,56 +10,22 @@ from SystemOfUnits import * """ def run(): - kernel = DDG4.Kernel() - install_dir = os.environ['DD4hepINSTALL'] - kernel.setOutputLevel('Geant4Converter',Output.DEBUG) - kernel.setOutputLevel('Gun',Output.INFO) - kernel.loadGeometry("file:"+install_dir+"/examples/ClientTests/compact/MiniTel.xml") - - geant4 = DDG4.Geant4(kernel) - geant4.printDetectors() - geant4.setupCshUI() + m = MiniTelSetup.Setup() if len(sys.argv) >= 2 and sys.argv[1] =="batch": - kernel.NumEvents = 200 - kernel.UI = '' - - # Configure field - field = geant4.setupTrackingField(prt=True) - # Setup particle gun - geant4.setupGun("Gun",particle='pi-',energy=100*GeV,multiplicity=1) - # Now the calorimeters - seq,act = geant4.setupTracker('MyLHCBdetector1') - seq,act = geant4.setupTracker('MyLHCBdetector2') - seq,act = geant4.setupTracker('MyLHCBdetector3') - seq,act = geant4.setupTracker('MyLHCBdetector4') - act.OutputLevel = 4 - seq,act = geant4.setupTracker('MyLHCBdetector5') - seq,act = geant4.setupTracker('MyLHCBdetector6') - seq,act = geant4.setupTracker('MyLHCBdetector7') - seq,act = geant4.setupTracker('MyLHCBdetector8') - seq,act = geant4.setupTracker('MyLHCBdetector9') - seq,act = geant4.setupTracker('MyLHCBdetector10') - - # And handle the simulation particles. - part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") - kernel.generatorAction().adopt(part) - part.SaveProcesses = ['conv','Decay'] - part.MinimalKineticEnergy = 1*MeV - part.OutputLevel = 5 # generator_output_level - part.enableUI() - + m.kernel.NumEvents = 200 + m.kernel.UI = '' + m.configure() + m.setupGun() + m.setupGenerator() + # This is the actual test: hit_tuple = DDG4.EventAction(kernel,'HitTupleAction/MiniTelTuple',True) hit_tuple.OutputFile = 'MiniTel_EnergyDeposits_'+time.strftime('%Y-%m-%d_%H-%M')+'.root' hit_tuple.Collections = ['*'] - kernel.eventAction().add(hit_tuple) - - - # Now build the physics list: - phys = kernel.physicsList() - phys.extends = 'QGSP_BERT' - phys.enableUI() - # and run - geant4.execute() + m.kernel.eventAction().add(hit_tuple) + # Setup physics + m.setupPhysics() + # ... and run + m.geant4.execute() if __name__ == "__main__": run() diff --git a/examples/ClientTests/scripts/MiniTelRegions.py b/examples/ClientTests/scripts/MiniTelRegions.py new file mode 100644 index 0000000000000000000000000000000000000000..d9857a2d573c6181bfd0b50dec8b7400d1858c4f --- /dev/null +++ b/examples/ClientTests/scripts/MiniTelRegions.py @@ -0,0 +1,16 @@ +""" + Subtest using CLICSid showing how to setup the Geant4 physics list + + @author M.Frank + @version 1.0 + +""" +if __name__ == "__main__": + from MiniTelSetup import Setup as MiniTel + m = MiniTel() + m.configure() + logging.info("# Configure G4 geometry setup") + seq,act = m.geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo") + act.DebugRegions = True + m.test_config(True) + m.terminate() diff --git a/examples/ClientTests/scripts/MiniTelSetup.py b/examples/ClientTests/scripts/MiniTelSetup.py new file mode 100644 index 0000000000000000000000000000000000000000..192fc0390aea040b1ef33fc6339ee6f82b4f6eee --- /dev/null +++ b/examples/ClientTests/scripts/MiniTelSetup.py @@ -0,0 +1,32 @@ +import os, time, DDG4TestSetup +""" + + dd4hep example setup using the python configuration + + \author M.Frank + \version 1.0 + +""" +class Setup(DDG4TestSetup.Setup): + def __init__(self): + install_dir = os.environ['DD4hepINSTALL'] + DDG4TestSetup.Setup.__init__(self, "file:"+install_dir+"/examples/ClientTests/compact/MiniTel.xml") + + def configure(self): + DDG4TestSetup.Setup.configure(self) + # Now the calorimeters + seq,act = self.geant4.setupTracker('MyLHCBdetector1') + seq,act = self.geant4.setupTracker('MyLHCBdetector2') + seq,act = self.geant4.setupTracker('MyLHCBdetector3') + seq,act = self.geant4.setupTracker('MyLHCBdetector4') + act.OutputLevel = 4 + seq,act = self.geant4.setupTracker('MyLHCBdetector5') + seq,act = self.geant4.setupTracker('MyLHCBdetector6') + seq,act = self.geant4.setupTracker('MyLHCBdetector7') + seq,act = self.geant4.setupTracker('MyLHCBdetector8') + seq,act = self.geant4.setupTracker('MyLHCBdetector9') + seq,act = self.geant4.setupTracker('MyLHCBdetector10') + return self + + def defineOutput(self,output='MiniTel_'+time.strftime('%Y-%m-%d_%H-%M')): + return DDG4TestSetup.Setup.configure(self,output) diff --git a/examples/ClientTests/scripts/TrackingRegion.py b/examples/ClientTests/scripts/TrackingRegion.py new file mode 100644 index 0000000000000000000000000000000000000000..4ef8ed79a47846ef57fca1dfc84a9af67bcc5a6e --- /dev/null +++ b/examples/ClientTests/scripts/TrackingRegion.py @@ -0,0 +1,31 @@ +# +# +import os, sys, time, DDG4 +# +""" + + dd4hep simulation example setup using the python configuration + + @author M.Frank + @version 1.0 + +""" +def run(): + kernel = DDG4.Kernel() + install_dir = os.environ['DD4hepINSTALL'] + kernel.loadGeometry("file:"+install_dir+"/examples/ClientTests/compact/TrackingRegion.xml") + geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerCombineAction') + # Configure field + ##field = geant4.setupTrackingField(prt=True) + # Configure G4 geometry setup + seq,act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo") + act.DebugVolumes = True + act.DebugPlacements = True + geant4.setupTracker('SiliconBlock') + kernel.configure() + kernel.initialize() + kernel.terminate() + sys.exit(0) + +if __name__ == "__main__": + run() diff --git a/examples/DDG4/src/HitTupleAction.cpp b/examples/DDG4/src/HitTupleAction.cpp index f690f2784b9f8c02b45f5daf2d1aacc796533398..f9257b17a2fec851e42b22e41ae4c086287d6e61 100644 --- a/examples/DDG4/src/HitTupleAction.cpp +++ b/examples/DDG4/src/HitTupleAction.cpp @@ -126,7 +126,6 @@ void myanalysis::HitTupleAction::beginRun(const G4Run* /* run */) { void myanalysis::HitTupleAction::endRun(const G4Run* /* run */) { if ( m_outFile ) { if ( m_outTree ) { - m_outTree->Write(); m_outTree->Print(); } m_outFile->Write();