diff --git a/DDCore/include/DD4hep/Detector.h b/DDCore/include/DD4hep/Detector.h index 3bb048d64f3ed104edd4ea6198b96ff717ce4f59..c3b82901f7f9372e7c48168fc58d05066bf53258 100644 --- a/DDCore/include/DD4hep/Detector.h +++ b/DDCore/include/DD4hep/Detector.h @@ -113,8 +113,12 @@ namespace dd4hep { /// Return handle to the world volume containing everything virtual Volume worldVolume() const = 0; + /// Return handle to the parallel world volume + virtual Volume parallelWorldVolume() const = 0; /// Return handle to the volume containing the tracking devices virtual Volume trackingVolume() const = 0; + /// Set the tracking volume of the detector + virtual void setTrackingVolume(Volume vol) = 0; /// Return handle to the VolumeManager virtual VolumeManager volumeManager() const = 0; diff --git a/DDCore/include/DD4hep/DetectorData.h b/DDCore/include/DD4hep/DetectorData.h index 79958894334d3556016bf93a07983cfb7d3eaad1..37f36deccb7f4c62b74d12165ca4de913112de8d 100644 --- a/DDCore/include/DD4hep/DetectorData.h +++ b/DDCore/include/DD4hep/DetectorData.h @@ -115,6 +115,7 @@ namespace dd4hep { DetElement m_world; DetElement m_trackers; Volume m_worldVol; + Volume m_parallelWorldVol; Volume m_trackingVol; Material m_materialAir; @@ -169,6 +170,8 @@ namespace dd4hep { /// Return handle to the world volume containing everything dd4hep::Volume worldVolume() const { return m_worldVol; } /// Return handle to the world volume containing the volume with the tracking devices + dd4hep::Volume parallelWorldVolume() const { return m_parallelWorldVol; } + /// Return handle to the world volume containing the volume with the tracking devices dd4hep::Volume trackingVolume() const { return m_trackingVol; } /// Return handle to the VolumeManager dd4hep::VolumeManager volumeManager() const { return m_volManager; } diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h index 5ee29611d9a59dcd42bd308c425a45868a7423ae..e13a9ad5a6b0bceb0ba18994ca54828651bdb633 100644 --- a/DDCore/include/XML/UnicodeValues.h +++ b/DDCore/include/XML/UnicodeValues.h @@ -39,6 +39,7 @@ UNICODE (alpha1); UNICODE (alpha2); UNICODE (alpha3); UNICODE (alpha4); +UNICODE (anchor); UNICODE (arb8); UNICODE (arg); UNICODE (argument); @@ -80,6 +81,7 @@ UNICODE (component); UNICODE (composite); UNICODE (cone); UNICODE (config); +UNICODE (connected); UNICODE (cons); UNICODE (constant); UNICODE (crossing_angle); @@ -294,6 +296,7 @@ UNICODE (padPitch); UNICODE (pads); UNICODE (para); UNICODE (paraboloid); +UNICODE (parallelworld_volume); UNICODE (param); UNICODE (parameter); UNICODE (params); diff --git a/DDCore/src/DetectorData.cpp b/DDCore/src/DetectorData.cpp index e71534cd8d2b9f6f13d59cbf05225c39224ccaae..bea31ce3f207fa2656fca6193ae5d0ab365242ac 100644 --- a/DDCore/src/DetectorData.cpp +++ b/DDCore/src/DetectorData.cpp @@ -209,6 +209,7 @@ void DetectorData::destroyData(bool destroy_mgr) { m_properties.clear(); m_trackers.clear(); m_trackingVol.clear(); + m_parallelWorldVol.clear(); m_worldVol.clear(); m_invisibleVis.clear(); m_materialVacuum.clear(); @@ -242,6 +243,7 @@ void DetectorData::clearData() { m_trackers.clear(); m_worldVol.clear(); m_trackingVol.clear(); + m_parallelWorldVol.clear(); m_invisibleVis.clear(); m_materialVacuum.clear(); m_materialAir.clear(); @@ -254,29 +256,30 @@ void DetectorData::clearData() { void DetectorData::adoptData(DetectorData& source, bool clr) { m_inhibitConstants = source.m_inhibitConstants; m_extensions.move(source.m_extensions); - m_manager = source.m_manager; - m_readouts = source.m_readouts; - m_idDict = source.m_idDict; - m_limits = source.m_limits; - m_regions = source.m_regions; - m_detectors = source.m_detectors; - m_sensitive = source.m_sensitive; - m_display = source.m_display; - m_fields = source.m_fields; - m_define = source.m_define; + m_manager = source.m_manager; + m_readouts = source.m_readouts; + m_idDict = source.m_idDict; + m_limits = source.m_limits; + m_regions = source.m_regions; + m_detectors = source.m_detectors; + m_sensitive = source.m_sensitive; + m_display = source.m_display; + m_fields = source.m_fields; + m_define = source.m_define; - m_motherVolumes = source.m_motherVolumes; - m_world = source.m_world; - m_trackers = source.m_trackers; - m_worldVol = source.m_worldVol; - m_trackingVol = source.m_trackingVol; - m_materialAir = source.m_materialAir; - m_materialVacuum = source.m_materialVacuum; - m_invisibleVis = source.m_invisibleVis; - m_field = source.m_field; - m_header = source.m_header; - m_properties = source.m_properties; + m_motherVolumes = source.m_motherVolumes; + m_world = source.m_world; + m_trackers = source.m_trackers; + m_worldVol = source.m_worldVol; + m_trackingVol = source.m_trackingVol; + m_parallelWorldVol = source.m_parallelWorldVol; + m_materialAir = source.m_materialAir; + m_materialVacuum = source.m_materialVacuum; + m_invisibleVis = source.m_invisibleVis; + m_field = source.m_field; + m_header = source.m_header; + m_properties = source.m_properties; //m_extensions = source.m_extensions; - m_volManager = source.m_volManager; + m_volManager = source.m_volManager; if ( clr ) source.clearData(); } diff --git a/DDCore/src/DetectorImp.cpp b/DDCore/src/DetectorImp.cpp index c828ab6a3c0d6b5a915f6ea6633a4f45d43d404f..053534ecf6b140dec711457cac3861182dc03d56 100644 --- a/DDCore/src/DetectorImp.cpp +++ b/DDCore/src/DetectorImp.cpp @@ -510,6 +510,8 @@ void DetectorImp::init() { TGeoManager* mgr = m_manager; Constant air_const = getRefChild(m_define, "Air", false); Constant vac_const = getRefChild(m_define, "Vacuum", false); + + /// Construct the top level world element Box worldSolid("world_x", "world_y", "world_z"); printout(INFO,"Detector"," *********** created World volume with size : %7.0f %7.0f %7.0f", worldSolid->GetDX(), worldSolid->GetDY(), worldSolid->GetDZ()); @@ -519,7 +521,7 @@ void DetectorImp::init() { Volume world_vol("world_volume", worldSolid, m_materialAir); m_world = DetElement(new WorldObject(*this,"world")); m_worldVol = world_vol; - // Set the world volume to invisible. + /// Set the world volume to invisible. VisAttr worldVis("WorldVis"); worldVis.setAlpha(1.0); worldVis.setVisible(false); @@ -533,19 +535,17 @@ void DetectorImp::init() { m_worldVol->SetVisContainers(kTRUE); add(worldVis); -#if 0 - Tube trackingSolid(0.,"tracking_region_radius","2*tracking_region_zmax",2*M_PI); - Volume tracking("tracking_volume",trackingSolid, m_materialAir); - m_trackers = TopDetElement("tracking"); - m_trackingVol = tracking; - m_trackers.setPlacement(m_worldVol.placeVolume(tracking)); - m_world.add(m_trackers); -#endif - + /// Set the top level volume to the TGeomanager m_detectors.append(m_world); m_manager->SetTopVolume(m_worldVol.ptr()); m_world.setPlacement(mgr->GetTopNode()); + /// Construct the parallel world + Box parallelWorldSolid("world_x", "world_y", "world_z"); + parallelWorldSolid->SetName("parallel_world_solid"); + m_parallelWorldVol = Volume("parallel_world_volume", worldSolid, m_materialAir); + + /// Construct the field envelope m_field = OverlayedField("global"); m_state = LOADING; } diff --git a/DDCore/src/DetectorImp.h b/DDCore/src/DetectorImp.h index 9796ca621cafa2dd71c41ccb06f7f96e6d0e800d..af5fb999afbf909e16d6f657456cffb6b89e0587 100644 --- a/DDCore/src/DetectorImp.h +++ b/DDCore/src/DetectorImp.h @@ -148,9 +148,17 @@ namespace dd4hep { return m_worldVol; } /// Return handle to the world volume containing the volume with the tracking devices + virtual Volume parallelWorldVolume() const override { + return m_parallelWorldVol; + } + /// Return handle to the world volume containing the volume with the tracking devices virtual Volume trackingVolume() const override { return m_trackingVol; } + /// Set the tracking volume of the detector + virtual void setTrackingVolume(Volume vol) override { + m_trackingVol = vol; + } /// Return handle to the VolumeManager virtual VolumeManager volumeManager() const override { return m_volManager; diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp index 2bfce5d79526dd7d0c969681f4749e6773a550f4..070874018e9d5bdd01d7923f5abb5bd9187ba6a5 100644 --- a/DDCore/src/plugins/Compact2Objects.cpp +++ b/DDCore/src/plugins/Compact2Objects.cpp @@ -14,6 +14,7 @@ // Framework includes #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/DetectorTools.h" +#include "DD4hep/MatrixHelpers.h" #include "DD4hep/IDDescriptor.h" #include "DD4hep/DD4hepUnits.h" #include "DD4hep/FieldTypes.h" @@ -51,7 +52,7 @@ namespace dd4hep { class Property; class XMLFile; class JsonFile; - class TrackingVolume; + class Parallelworld_Volume; class DetElementInclude; /// Converter instances implemented in this compilation unit @@ -75,7 +76,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<Parallelworld_Volume>::operator()(xml_h element) const; template <> void Converter<Compact>::operator()(xml_h element) const; } @@ -1063,57 +1064,56 @@ template <> void Converter<XMLFile>::operator()(xml_h element) const { } /// 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)); +template <> void Converter<Parallelworld_Volume>::operator()(xml_h element) const { + xml_det_t parallel(element); + xml_dim_t shape = parallel.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)); + xml_dim_t rot = element.child(_U(rotation),false); + string name = element.attr<string>(_U(name)); + string path = element.attr<string>(_U(anchor)); + bool conn = element.attr<bool>(_U(connected),false); + DetElement anchor(detail::tools::findElement(description, path)); RotationZYX rotation; Position position; - if ( !mother.isValid() ) - except("TrackingVolume", - "++ FAILED Cannot identify the mother of the tracking volume: '%s'", + if ( !anchor.isValid() ) + except("Parallelworld_Volume", + "++ FAILED Cannot identify the anchor 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()); + /// Create the shape and the corresponding volume + Transform3D tr_volume(detail::matrix::_transform(&anchor.nominal().worldTransformation().Inverse())); Solid sol(xml_comp_t(shape).createShape()); - Volume vol("TrackingVolume", sol, mat); - Volume par(mother.placement().volume()); + Material mat(description.vacuum()); + Volume vol(name, sol, mat); + Volume par = conn ? description.worldVolume() : description.parallelWorldVolume(); PlacedVolume pv; - if ( !par.isValid() ) - except("TrackingVolume", - "++ FAILED Cannot identify the volume of parent: '%s'", - mother.path().c_str()); - 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); + if ( parallel.hasAttr(_U(material)) ) + mat = description.material(parallel.attr<string>(_U(material))); - /// 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); + /// In case the volume is connected, we may use visualization + vol.setVisAttributes(parallel.visStr().empty() + ? description.invisible() + : description.visAttributes(parallel.visStr())); + /// Need to inhibit that this artifical volume gets translated to Geant4 (connected only)! + vol.setFlagBit(Volume::VETO_SIMU); + + /// Now place the volume in the anchor frame + Transform3D trafo = tr_volume * Transform3D(rotation,position); // Is this the correct order ? + pv = par.placeVolume(vol, trafo); if ( !pv.isValid() ) { - except("TrackingVolume", - "++ FAILED to place the tracking volume inside the mother '%s'",path.c_str()); + except("Parallelworld_Volume", + "++ FAILED to place the tracking volume inside the anchor '%s'",path.c_str()); } + if ( name == "tracking_volume" ) { + } + printout(INFO, "Compact", "++ Converted successfully parallelworld_volume %s. anchor: %s vis:%s.", + name.c_str(), anchor.path().c_str(), parallel.visStr().c_str()); } /// Read material entries from a seperate file in one of the include sections of the geometry @@ -1214,10 +1214,8 @@ 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)); + xml_coll_t(compact, _U(parallelworld_volume)).for_each(Converter<Parallelworld_Volume>(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/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp index 5550f71104f63ca10861835d7ff80116cbe841b7..21a414341783ff8a404f97afd220df88c9d03817 100644 --- a/DDG4/src/Geant4Converter.cpp +++ b/DDG4/src/Geant4Converter.cpp @@ -869,15 +869,23 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& if (ls.isValid()) { const LimitSet::Set& cts = ls.cuts(); for (const auto& c : cts ) { - int pid; + int pid = 0; if ( c.particles == "*" ) pid = -1; else if ( c.particles == "e-" ) pid = idxG4ElectronCut; else if ( c.particles == "e+" ) pid = idxG4PositronCut; + else if ( c.particles == "e[+-]" ) pid = -idxG4PositronCut-idxG4ElectronCut; + else if ( c.particles == "e[-+]" ) pid = -idxG4PositronCut-idxG4ElectronCut; 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); + if ( pid == -(idxG4PositronCut+idxG4ElectronCut) ) { + cuts->SetProductionCut(c.value*CLHEP::mm/units::mm, idxG4PositronCut); + cuts->SetProductionCut(c.value*CLHEP::mm/units::mm, idxG4ElectronCut); + } + else { + 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); } diff --git a/examples/ClientTests/CMakeLists.txt b/examples/ClientTests/CMakeLists.txt index f2daf3dc5ededb6a0f4bdbaa9c22044c9df75c6f..d5e22f8b5ec139ef04e30ad418a2b3568ece55d0 100644 --- a/examples/ClientTests/CMakeLists.txt +++ b/examples/ClientTests/CMakeLists.txt @@ -243,7 +243,7 @@ if (DD4HEP_USE_GEANT4) 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_PASS "Placement tracking_volume_1 not converted \\[Veto'ed for simulation\\]" REGEX_FAIL "Exception;EXCEPTION;ERROR;Error" ) # # Geant4 full simulation checks of simple detectors diff --git a/examples/ClientTests/compact/TrackingRegion.xml b/examples/ClientTests/compact/TrackingRegion.xml index 24ca0b9d45911459f3220c071313bf71ed826ff7..19b7c297cde51c93e5b29cb87c81519cf210984c 100644 --- a/examples/ClientTests/compact/TrackingRegion.xml +++ b/examples/ClientTests/compact/TrackingRegion.xml @@ -28,7 +28,7 @@ <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="VisibleBlue" r="0.0" g="0.0" b="1.0" showDaughters="true" 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> @@ -45,8 +45,12 @@ </region> </regions> - <tracking_volume mother="/world" vis="VisibleBlue"> - <material name="Air"/> + <!-- + If the volume should be connected to the world: connected="true" + else if the wolume is part of the parallelworld: connected="false" + The wolume is always connected to the top level! + --> + <parallelworld_volume name="tracking_volume" anchor="/world" material="Air" connected="true" vis="VisibleBlue"> <shape type="BooleanShape" operation="Subtraction"> <shape type="BooleanShape" operation="Subtraction"> <shape type="BooleanShape" operation="Subtraction" > @@ -60,9 +64,9 @@ <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> + <position x="0*cm" y="50*cm" z="0*cm"/> + <rotation x="pi/2.0" y="0" z="0"/> + </parallelworld_volume> <detectors> <detector id="1" name="SiliconBlock" type="DD4hep_BoxSegment" readout="SiliconHits" vis="VisibleGreen" sensitive="true" region="SiRegion" limits="SiRegionLimitSet">