From 173619f456b24cb6ffa7819671d21924e790ccfb Mon Sep 17 00:00:00 2001 From: Victor Schwan <162138084+Victor-Schwan@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:21:01 +0200 Subject: [PATCH 001/133] ILD_l5_v11: fix a barrel layer ID (#378) * 2nd SIT barrel layer ID corrected; error stemed from outcommenting previous 2nd layer * removed commented layer to avoid any potential issue in the future --- ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml b/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml index 1d5142850..8f1df743f 100644 --- a/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml +++ b/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml @@ -120,13 +120,8 @@ adapted by DJeans to fit into ILD model at FCCee - - From e7cc12336bdfa00e92d24335f2173943fe98d7f9 Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Mon, 5 Aug 2024 08:58:08 +0200 Subject: [PATCH 002/133] copy TrackerBarrel_o1_v06 --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 detector/tracker/TrackerBarrel_o1_v06_geo.cpp diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp new file mode 100644 index 000000000..92b82cf00 --- /dev/null +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -0,0 +1,327 @@ +// Silicon Tracker Barrel implementation for the CLIC detector +//==================================================================== +//-------------------------------------------------------------------- +// +// Author : N. Nikiforou (forked from SiTrackerBarrel_geo.cpp +// +// Comment: Here each slice of the module has the same transversal +// dimensions (x,y). Suitable for Surfaces. +// +// Comment: You have to use +#include +#include "UTIL/LCTrackerConf.h" +#include + +using namespace std; + +using dd4hep::Assembly; +using dd4hep::BUILD_ENVELOPE; +using dd4hep::Box; +using dd4hep::DetElement; +using dd4hep::Detector; +using dd4hep::ERROR; +using dd4hep::Material; +using dd4hep::PlacedVolume; +using dd4hep::Position; +using dd4hep::Ref_t; +using dd4hep::RotationZYX; +using dd4hep::SensitiveDetector; +using dd4hep::Transform3D; +using dd4hep::Tube; +using dd4hep::Volume; +using dd4hep::_toString; +using dd4hep::rec::NeighbourSurfacesData; +using dd4hep::rec::ZPlanarData; + + +static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { + typedef vector Placements; + xml_det_t x_det = e; + Material air = theDetector.air(); + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + DetElement sdet (det_name,det_id); + // Assembly assembly (det_name); + map volumes; + map sensitives; + PlacedVolume pv; + + + // for encoding + std::string cellIDEncoding = sens.readout().idSpec().fieldDescription(); + UTIL::BitField64 encoder( cellIDEncoding ); + encoder.reset(); + encoder[lcio::LCTrackerCellID::subdet()] = det_id; + encoder[lcio::LCTrackerCellID::side()] = lcio::ILDDetID::barrel; + + + // --- create an envelope volume and position it into the world --------------------- + + Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; + dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; + + if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; + + //----------------------------------------------------------------------------------- + ZPlanarData* zPlanarData = new ZPlanarData() ; + NeighbourSurfacesData* neighbourSurfacesData = new NeighbourSurfacesData() ; + + sens.setType("tracker"); + + //NOTE modules are what is defined in compact. Later we call a "module" as a "sensor". + for(xml_coll_t mi(x_det,_U(module)); mi; ++mi) { + xml_comp_t x_mod = mi; + xml_comp_t m_env = x_mod.child(_U(module_envelope)); + string m_nam = x_mod.nameStr(); + + + if ( volumes.find(m_nam) != volumes.end() ) { + printout(ERROR,"TrackerBarrel","Logics error in building modules."); + throw runtime_error("Logic error in building modules."); + } + + double module_thickness = 0; + for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { + dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); + xml_h includes = doc.root(); + xml_det_t incl_stack = includes; + for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci) { + xml_comp_t x_comp = ci; + module_thickness = module_thickness + x_comp.thickness(); + } + } + + Volume m_vol(m_nam,Box(m_env.width()/2.,m_env.length()/2.,module_thickness/2.),air); + volumes[m_nam] = m_vol; + m_vol.setVisAttributes(theDetector.visAttributes(x_mod.visStr())); + + + int ncomponents = 0; + + //First component on top of the list is the innermost one. + double position_z= -module_thickness/2.; + for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) { + dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref)))); + xml_h includes = doc.root(); + xml_det_t incl_stack = includes; + for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci, ++ncomponents) { + xml_comp_t x_comp = ci; + string c_nam = _toString(ncomponents, "component%d"); + Box c_box(m_env.width() / 2.0, m_env.length() / 2.0, x_comp.thickness() / 2.0); + Volume c_vol(c_nam, c_box, theDetector.material(x_comp.materialStr())); + + + pv = m_vol.placeVolume(c_vol, Position(0, 0, position_z + x_comp.thickness() / 2.0)); + + c_vol.setRegion(theDetector, x_comp.regionStr()); + c_vol.setLimitSet(theDetector, x_comp.limitsStr()); + c_vol.setVisAttributes(theDetector, x_comp.visStr()); + if (x_comp.isSensitive()) { + // pv.addPhysVolID("wafer",wafer_number++); + c_vol.setSensitiveDetector(sens); + sensitives[m_nam].push_back(pv); + } + + position_z += x_comp.thickness(); + } + } + } + for(xml_coll_t li(x_det,_U(layer)); li; ++li) { + xml_comp_t x_layer = li; + xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); + xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element. + int lay_id = x_layer.id(); + // int type = x_layer.type(); + string m_nam = x_layer.moduleStr(); + string lay_nam = _toString(x_layer.id(),"layer%d"); + Assembly lay_vol (lay_nam); // Create the layer envelope volume. + double phi0 = x_layout.phi0(); // Starting phi of first sensor. + double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a sensor. + double rc = x_layout.rc(); // Radius of the sensor center. + int nphi = x_layout.nphi(); // Number of sensors in phi. + double rphi_dr = x_layout.dr(); // The delta radius of every other sensor. + + double phi_incr = (M_PI * 2) / nphi; // Phi increment for one sensor. + double phic = phi0; // Phi of the sensor center. + double z0 = z_layout.z0(); // Z position of first sensor in phi. + double nz = z_layout.nz(); // Number of sensors to place in z. + double z_dr = z_layout.dr(); // Radial displacement parameter, of every other sensor. + Volume m_env = volumes[m_nam]; + DetElement lay_elt(sdet,_toString(x_layer.id(),"layer%d"),lay_id); + Placements& waferVols = sensitives[m_nam]; + + // Z increment for sensor placement along Z axis. + // Adjust for z0 at center of sensor rather than + // the end of cylindrical envelope. + double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; + // Starting z for sensor placement along Z axis. + double sensor_z = -z0; + int module_idx =0; + + + ZPlanarData::LayerLayout thisLayer ; + + + // Loop over the number of sensors in phi. + for (int ii = 0; ii < nphi; ii++) { + double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of sensor position. + double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of sensor position. + double x = rc * std::cos(phic); // Basic x sensor position. + double y = rc * std::sin(phic); // Basic y sensor position. + + // Loop over the number of sensors in z. + //Create stave FIXME disable for now + string module_name = _toString(module_idx,"module%d"); + // DetElement module_elt(lay_elt,module_name,module_idx); + int sensor_idx = 0; + + for (int j = 0; j < nz; j++) { + string sensor_name = _toString(sensor_idx,"sensor%d"); + + /////////////////// + + //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > + + //encoding + + encoder[lcio::LCTrackerCellID::layer()] = lay_id; + encoder[lcio::LCTrackerCellID::module()] = module_idx; + encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; + + const dd4hep::CellID cellID = encoder.lowWord(); // 32 bits + + //compute neighbours + + int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) + int n_neighbours_sensor = 1; + + int newmodule=0, newsensor=0; + + for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules + for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors + + if (imodule==0 && isensor==0) continue; // cellID we started with + newmodule = module_idx + imodule; + newsensor = sensor_idx + isensor; + + //compute special case at the boundary + //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2) + + if (newmodule < 0) newmodule = nphi + newmodule; + if (newmodule >= nphi) newmodule = newmodule - nphi; + + if (newsensor < 0 || newsensor >= nz) continue; //out of the stave + + //encoding + encoder[lcio::LCTrackerCellID::module()] = newmodule; + encoder[lcio::LCTrackerCellID::sensor()] = newsensor; + + neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); + + } + } + + /////////////////// + + + //FIXME + sensor_name = module_name + sensor_name; + + DetElement sens_elt(lay_elt,sensor_name,sensor_idx); + // Module PhysicalVolume. + Transform3D tr(RotationZYX(0,((M_PI/2)-phic-phi_tilt),-M_PI/2),Position(x,y,sensor_z)); + + //FIXME + pv = lay_vol.placeVolume(m_env,tr); + pv.addPhysVolID(_U(module), module_idx); + pv.addPhysVolID(_U(sensor), sensor_idx); + sens_elt.setPlacement(pv); + for(size_t ic=0; icGetMatrix()->GetTranslation(); + double half_module_thickness = mod_shape->GetDZ(); + double half_silicon_thickness = comp_shape->GetDZ(); + + double sensitive_z_position = trans[2]; + + double inner_thickness = half_module_thickness - sensitive_z_position; + + thisLayer.distanceSupport = rc ; + + thisLayer.offsetSupport = 0; + thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; + thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); + thisLayer.widthSupport = 2*mod_shape->GetDX(); + + thisLayer.distanceSensitive = rc+sensitive_z_position; + thisLayer.offsetSensitive = 0. ; + thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z + //Changed by Thorben Quast (same applies to zHalfSupport) + //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module + thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); + thisLayer.widthSensitive = 2*comp_shape->GetDX(); + thisLayer.ladderNumber = (int) nphi ; + thisLayer.phi0 = phic; + } + + } + + + /// Increase counters etc. + sensor_idx++; + // Adjust the x and y coordinates of the sensor. + x += dx; + y += dy; + // Flip sign of x and y adjustments. + dx *= -1; + dy *= -1; + // Add z increment to get next z placement pos. + sensor_z += z_incr; + } + module_idx++; + phic += phi_incr; // Increment the phi placement of sensor. + rc += rphi_dr; // Increment the center radius according to dr parameter. + rphi_dr *= -1; // Flip sign of dr parameter. + sensor_z = -z0; // Reset the Z placement parameter for sensor. + } + // Create the PhysicalVolume for the layer. + pv = envelope.placeVolume(lay_vol); // Place layer in mother + pv.addPhysVolID("layer", lay_id); // Set the layer ID. + lay_elt.setAttributes(theDetector,lay_vol,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr()); + lay_elt.setPlacement(pv); + + zPlanarData->layers.push_back( thisLayer ) ; + + } + sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); + sdet.addExtension< ZPlanarData >( zPlanarData ) ; + sdet.addExtension< NeighbourSurfacesData >( neighbourSurfacesData ) ; + + //envelope.setVisAttributes(theDetector.invisible()); + /*pv = theDetector.pickMotherVolume(sdet).placeVolume(assembly); + pv.addPhysVolID("system", det_id); // Set the subdetector system ID. + pv.addPhysVolID("barrel", 0); // Flag this as a barrel subdetector. + sdet.setPlacement(pv);*/ + return sdet; +} + +DECLARE_DETELEMENT(TrackerBarrel_o1_v06, create_detector) From e55d30ecf9bfad1a548fe883c09cbdc391176216 Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Thu, 8 Aug 2024 16:10:22 +0200 Subject: [PATCH 003/133] copy CLD_o2_v06 to CLD_o2_v07 --- .../BeamInstrumentation_o3_v02_fitShield.xml | 26 + .../compact/CLD_o2_v07/Beampipe_o4_v05.xml | 158 ++++ FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml | 439 +++++++++ .../CLD_o2_v07/ECalBarrel_o2_v01_03.xml | 66 ++ .../CLD_o2_v07/ECalEndcap_o2_v01_03.xml | 57 ++ .../CLD_o2_v07/HCalBarrel_o1_v01_01.xml | 58 ++ .../CLD_o2_v07/HCalEndcap_o1_v01_01.xml | 131 +++ .../InnerTrackerBarrelModuleDown.xml | 25 + .../CLD_o2_v07/InnerTrackerBarrelModuleUp.xml | 25 + .../CLD_o2_v07/InnerTracker_o2_v07.xml | 582 ++++++++++++ .../compact/CLD_o2_v07/LumiCal_o3_v02_04.xml | 188 ++++ .../OuterTrackerBarrelModuleDown.xml | 27 + .../CLD_o2_v07/OuterTrackerBarrelModuleUp.xml | 27 + .../CLD_o2_v07/OuterTracker_o2_v07.xml | 226 +++++ .../compact/CLD_o2_v07/Solenoid_o1_v01_02.xml | 54 ++ .../CLD_o2_v07/TrackerDiskModuleIn.xml | 27 + .../CLD_o2_v07/TrackerDiskModuleOut.xml | 27 + .../CLD_o2_v07/Vertex_o4_v07_smallBP.xml | 225 +++++ .../CLD_o2_v07/YokeBarrel_o1_v01_02.xml | 68 ++ .../CLD_o2_v07/YokeEndcap_o1_v01_02.xml | 67 ++ FCCee/CLD/compact/CLD_o2_v07/elements.xml | 884 ++++++++++++++++++ FCCee/CLD/compact/CLD_o2_v07/materials.xml | 230 +++++ 22 files changed, 3617 insertions(+) create mode 100644 FCCee/CLD/compact/CLD_o2_v07/BeamInstrumentation_o3_v02_fitShield.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/Beampipe_o4_v05.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/ECalBarrel_o2_v01_03.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/ECalEndcap_o2_v01_03.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/HCalBarrel_o1_v01_01.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/HCalEndcap_o1_v01_01.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleDown.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleUp.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleDown.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleUp.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/Solenoid_o1_v01_02.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleIn.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleOut.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/Vertex_o4_v07_smallBP.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/YokeBarrel_o1_v01_02.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/YokeEndcap_o1_v01_02.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/elements.xml create mode 100644 FCCee/CLD/compact/CLD_o2_v07/materials.xml diff --git a/FCCee/CLD/compact/CLD_o2_v07/BeamInstrumentation_o3_v02_fitShield.xml b/FCCee/CLD/compact/CLD_o2_v07/BeamInstrumentation_o3_v02_fitShield.xml new file mode 100644 index 000000000..dba09d325 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/BeamInstrumentation_o3_v02_fitShield.xml @@ -0,0 +1,26 @@ + + + + Beampipe Instrumentation + + + + + + +
+ + + + + + + + +
+ +
+ + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/Beampipe_o4_v05.xml b/FCCee/CLD/compact/CLD_o2_v07/Beampipe_o4_v05.xml new file mode 100644 index 000000000..5610b7225 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/Beampipe_o4_v05.xml @@ -0,0 +1,158 @@ + + + + A beampipe for FCCee detector based on CLD + + + + + + + + + + + + + + + + + + + + + Part of beampipe made of AlBeMet162 and Paraffin flow + + + + + + + +
+
+
+
+ + + + + + + + + + + + Golden foil in the inner part of the Be beampipe + +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + + + + +Synch Radiation mask inside the beam-pipe, at z = 2.1 m + + + +
+ +
+ +
+ + + +Full Cone Tungsten Shield + + + + Beampipe Shield (APS: WHAT????? +18 cm (??plus??) as solenoid is now closer to IP) +
+ + + + +Asymmetric Tungsten Shield no Rotation + + + + +
+ + was 370. Add 0.1*mm so that rmax1 is larger than rmin1 +
+ + one degree less, to fit lumical window +
+ +
+ + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml new file mode 100644 index 000000000..853cd02d4 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml @@ -0,0 +1,439 @@ + + + + The compact format for the FCCee Detector design + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + suggested naming convention: + + main parameters: + + DET_inner_radius : inner radius of tube like envelope ( inscribed cylinder ) + DET_outer_radius : outer radius of tube like envelope ( circumscribed cylinder ) + DET_half_length : half length along z axis + DET_min_z : smallest absolute value on z-axis + DET_max_z : largest absolute value on z-axis + DET_inner_symmetry : number of sides on the inside ( 0 for tube ) + DET_outer_symmetry : number of sides on the inside ( 0 for tube ) + DET_inner_phi0 : optional rotation of the inner polygon ( in r-phi plane ) + DET_outer_phi0 : optional rotation of the outer polygon ( in r-phi plane ) + + additional parameters for cutting away volumes/shapes use one of the above with a number + appended and/or an extra specifiaction such as cone ( for a cut away cone ) + + DET_inner_radius_1 + DET_outer_radius_2 + DET_cone_min_z + DET_cone_max_z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/ECalBarrel_o2_v01_03.xml b/FCCee/CLD/compact/CLD_o2_v07/ECalBarrel_o2_v01_03.xml new file mode 100644 index 000000000..abe72e0fa --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/ECalBarrel_o2_v01_03.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + + + + + + + + + + + + + + + EM Calorimeter Barrel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/ECalEndcap_o2_v01_03.xml b/FCCee/CLD/compact/CLD_o2_v07/ECalEndcap_o2_v01_03.xml new file mode 100644 index 000000000..dd84c505f --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/ECalEndcap_o2_v01_03.xml @@ -0,0 +1,57 @@ + + + + + + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + + + + + + Electromagnetic Calorimeter Endcap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/HCalBarrel_o1_v01_01.xml b/FCCee/CLD/compact/CLD_o2_v07/HCalBarrel_o1_v01_01.xml new file mode 100644 index 000000000..d0ade5fc2 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/HCalBarrel_o1_v01_01.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + + + + Hadron Calorimeter Barrel + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/HCalEndcap_o1_v01_01.xml b/FCCee/CLD/compact/CLD_o2_v07/HCalEndcap_o1_v01_01.xml new file mode 100644 index 000000000..ef70e41e8 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/HCalEndcap_o1_v01_01.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HCalEndcap Assembly + + + + + + + + + + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + + + + + + Hadronic Calorimeter Endcap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hadronic Calorimeter Endcap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleDown.xml b/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleDown.xml new file mode 100644 index 000000000..12d5d7485 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleDown.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleUp.xml b/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleUp.xml new file mode 100644 index 000000000..a81418293 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/InnerTrackerBarrelModuleUp.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml new file mode 100644 index 000000000..8406b1115 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tracking detectors + + + + + + + + + + + + + Inner Tracker Assembly + + + + + + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + + + + + + + + Silicon Inner Tracker Barrel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Silicon Inner Tracker Endcaps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3.5959*cm = X0 for Carbon fibre + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + The next section is the cable for the vertex + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml new file mode 100644 index 000000000..cbc708e20 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml @@ -0,0 +1,188 @@ + + + + + + + + + + system:8,barrel:3,layer:8,slice:8,r:32:-16,phi:-16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleDown.xml b/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleDown.xml new file mode 100644 index 000000000..8c0303810 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleDown.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleUp.xml b/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleUp.xml new file mode 100644 index 000000000..12a1efe2e --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/OuterTrackerBarrelModuleUp.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml new file mode 100644 index 000000000..fb8e27d9b --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Tracking detectors + + + + + Outer Tracker Assembly + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + + + + + + + + + Silicon Outer Tracker Barrel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Silicon Outer Tracker Endcaps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/Solenoid_o1_v01_02.xml b/FCCee/CLD/compact/CLD_o2_v07/Solenoid_o1_v01_02.xml new file mode 100644 index 000000000..634f3cab3 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/Solenoid_o1_v01_02.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + Solenoid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleIn.xml b/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleIn.xml new file mode 100644 index 000000000..12a1efe2e --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleIn.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleOut.xml b/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleOut.xml new file mode 100644 index 000000000..8c0303810 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/TrackerDiskModuleOut.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/Vertex_o4_v07_smallBP.xml b/FCCee/CLD/compact/CLD_o2_v07/Vertex_o4_v07_smallBP.xml new file mode 100644 index 000000000..8082039f9 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/Vertex_o4_v07_smallBP.xml @@ -0,0 +1,225 @@ + + + + + Tracking detectors + + + + + + + + + + + Vertex Assembly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vertex Detector Endcaps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/YokeBarrel_o1_v01_02.xml b/FCCee/CLD/compact/CLD_o2_v07/YokeBarrel_o1_v01_02.xml new file mode 100644 index 000000000..5d4e62d73 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/YokeBarrel_o1_v01_02.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + system:5,side:2,layer:9,module:8,stave:4,submodule:4,x:32:-16,y:-16 + + + + + + + + Yoke Calorimeter Barrel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/YokeEndcap_o1_v01_02.xml b/FCCee/CLD/compact/CLD_o2_v07/YokeEndcap_o1_v01_02.xml new file mode 100644 index 000000000..e4503843b --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/YokeEndcap_o1_v01_02.xml @@ -0,0 +1,67 @@ + + + + + + + system:5,side:2,module:8,stave:4,layer:9,submodule:4,x:32:-16,y:-16 + + + + + + + + + + + + + + Encap Yoke + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/elements.xml b/FCCee/CLD/compact/CLD_o2_v07/elements.xml new file mode 100644 index 000000000..8358bac36 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/elements.xml @@ -0,0 +1,884 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/CLD/compact/CLD_o2_v07/materials.xml b/FCCee/CLD/compact/CLD_o2_v07/materials.xml new file mode 100644 index 000000000..acdb4a66a --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/materials.xml @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + From 9adea87a73b7814dcc694ae1b96f95834680bb9c Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Thu, 8 Aug 2024 16:22:21 +0200 Subject: [PATCH 004/133] update version --- .../CLD_o2_v07/{CLD_o2_v06.xml => CLD_o2_v07.xml} | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) rename FCCee/CLD/compact/CLD_o2_v07/{CLD_o2_v06.xml => CLD_o2_v07.xml} (98%) diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml similarity index 98% rename from FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml rename to FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml index 853cd02d4..3f30e801d 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v06.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml @@ -2,12 +2,12 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd"> - + version="7"> The compact format for the FCCee Detector design @@ -297,8 +297,6 @@ - - From 0db37600f87a3e034263358aade395e5c48a706b Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Thu, 8 Aug 2024 16:22:50 +0200 Subject: [PATCH 005/133] Use new TrackerBarrel --- FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml | 2 ++ .../{InnerTracker_o2_v07.xml => InnerTracker_o2_v08.xml} | 2 +- .../{OuterTracker_o2_v07.xml => OuterTracker_o2_v08.xml} | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) rename FCCee/CLD/compact/CLD_o2_v07/{InnerTracker_o2_v07.xml => InnerTracker_o2_v08.xml} (99%) rename FCCee/CLD/compact/CLD_o2_v07/{OuterTracker_o2_v07.xml => OuterTracker_o2_v08.xml} (99%) diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml index 3f30e801d..10954f514 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml @@ -297,6 +297,8 @@ + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml similarity index 99% rename from FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml rename to FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml index 8406b1115..e31978c98 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml @@ -80,7 +80,7 @@ - + diff --git a/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v08.xml similarity index 99% rename from FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml rename to FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v08.xml index fb8e27d9b..073799501 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/OuterTracker_o2_v08.xml @@ -57,7 +57,7 @@ - + From c8a5694609d00cbbac8e70447cc176f3c0f6e69a Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Fri, 9 Aug 2024 13:29:43 +0200 Subject: [PATCH 006/133] TrackerBarrel_o1_v06 remove using namespace std --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp index 92b82cf00..e09c79836 100644 --- a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -21,8 +21,6 @@ #include "UTIL/LCTrackerConf.h" #include -using namespace std; - using dd4hep::Assembly; using dd4hep::BUILD_ENVELOPE; using dd4hep::Box; @@ -44,15 +42,15 @@ using dd4hep::rec::ZPlanarData; static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { - typedef vector Placements; + typedef std::vector Placements; xml_det_t x_det = e; Material air = theDetector.air(); int det_id = x_det.id(); - string det_name = x_det.nameStr(); + std::string det_name = x_det.nameStr(); DetElement sdet (det_name,det_id); // Assembly assembly (det_name); - map volumes; - map sensitives; + std::map volumes; + std::map sensitives; PlacedVolume pv; @@ -81,12 +79,12 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s for(xml_coll_t mi(x_det,_U(module)); mi; ++mi) { xml_comp_t x_mod = mi; xml_comp_t m_env = x_mod.child(_U(module_envelope)); - string m_nam = x_mod.nameStr(); + std::string m_nam = x_mod.nameStr(); if ( volumes.find(m_nam) != volumes.end() ) { printout(ERROR,"TrackerBarrel","Logics error in building modules."); - throw runtime_error("Logic error in building modules."); + throw std::runtime_error("Logic error in building modules."); } double module_thickness = 0; @@ -115,7 +113,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s xml_det_t incl_stack = includes; for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci, ++ncomponents) { xml_comp_t x_comp = ci; - string c_nam = _toString(ncomponents, "component%d"); + std::string c_nam = _toString(ncomponents, "component%d"); Box c_box(m_env.width() / 2.0, m_env.length() / 2.0, x_comp.thickness() / 2.0); Volume c_vol(c_nam, c_box, theDetector.material(x_comp.materialStr())); @@ -141,8 +139,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element. int lay_id = x_layer.id(); // int type = x_layer.type(); - string m_nam = x_layer.moduleStr(); - string lay_nam = _toString(x_layer.id(),"layer%d"); + std::string m_nam = x_layer.moduleStr(); + std::string lay_nam = _toString(x_layer.id(),"layer%d"); Assembly lay_vol (lay_nam); // Create the layer envelope volume. double phi0 = x_layout.phi0(); // Starting phi of first sensor. double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a sensor. @@ -180,12 +178,12 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s // Loop over the number of sensors in z. //Create stave FIXME disable for now - string module_name = _toString(module_idx,"module%d"); + std::string module_name = _toString(module_idx,"module%d"); // DetElement module_elt(lay_elt,module_name,module_idx); int sensor_idx = 0; for (int j = 0; j < nz; j++) { - string sensor_name = _toString(sensor_idx,"sensor%d"); + std::string sensor_name = _toString(sensor_idx,"sensor%d"); /////////////////// From 1281fc673c27b04916df4321613059aa0f1ed5ea Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Fri, 9 Aug 2024 14:12:26 +0200 Subject: [PATCH 007/133] move NeighbourSurfacesData population into a function --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 80 ++++++++++--------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp index e09c79836..7df9479fc 100644 --- a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -40,6 +40,40 @@ using dd4hep::_toString; using dd4hep::rec::NeighbourSurfacesData; using dd4hep::rec::ZPlanarData; +void populateNeighbourData(NeighbourSurfacesData* neighbourSurfacesData, UTIL::BitField64& encoder, int module_idx, int sensor_idx, int nphi, int nz) { + const dd4hep::CellID cellID = encoder.lowWord(); // 32 bits + + //compute neighbours + int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) + int n_neighbours_sensor = 1; + + int newmodule=0, newsensor=0; + + for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules + for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors + + if (imodule==0 && isensor==0) continue; // cellID we started with + newmodule = module_idx + imodule; + newsensor = sensor_idx + isensor; + + //compute special case at the boundary + //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2) + + if (newmodule < 0) newmodule = nphi + newmodule; + if (newmodule >= nphi) newmodule = newmodule - nphi; + + if (newsensor < 0 || newsensor >= nz) continue; //out of the stave + + //encoding + encoder[lcio::LCTrackerCellID::module()] = newmodule; + encoder[lcio::LCTrackerCellID::sensor()] = newsensor; + + neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); + + } + } + +} static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef std::vector Placements; @@ -185,50 +219,20 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s for (int j = 0; j < nz; j++) { std::string sensor_name = _toString(sensor_idx,"sensor%d"); - /////////////////// - - //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > - - //encoding - - encoder[lcio::LCTrackerCellID::layer()] = lay_id; - encoder[lcio::LCTrackerCellID::module()] = module_idx; - encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; - - const dd4hep::CellID cellID = encoder.lowWord(); // 32 bits - - //compute neighbours - - int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this) - int n_neighbours_sensor = 1; - - int newmodule=0, newsensor=0; + /////////////////// - for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules - for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors - - if (imodule==0 && isensor==0) continue; // cellID we started with - newmodule = module_idx + imodule; - newsensor = sensor_idx + isensor; + //get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces > - //compute special case at the boundary - //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2) - - if (newmodule < 0) newmodule = nphi + newmodule; - if (newmodule >= nphi) newmodule = newmodule - nphi; + //encoding - if (newsensor < 0 || newsensor >= nz) continue; //out of the stave + encoder[lcio::LCTrackerCellID::layer()] = lay_id; + encoder[lcio::LCTrackerCellID::module()] = module_idx; + encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; - //encoding - encoder[lcio::LCTrackerCellID::module()] = newmodule; - encoder[lcio::LCTrackerCellID::sensor()] = newsensor; - - neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord()); + populateNeighbourData(neighbourSurfacesData, encoder, module_idx, sensor_idx, nphi, nz); - } - } - /////////////////// + /////////////////// //FIXME From acbbcd380b5a4e47356dea7eeae0f4d35c82e3a9 Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Fri, 9 Aug 2024 15:02:16 +0200 Subject: [PATCH 008/133] Move LayerLayout population out of the sensor loop --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 67 +++++++++---------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp index 7df9479fc..341aa8704 100644 --- a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -201,7 +201,36 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s ZPlanarData::LayerLayout thisLayer ; - + /// GET GEAR INFORMATION + /// NOTE WORKS ONLY FOR ONE WAFER + Box mod_shape(m_env.solid()), comp_shape(waferVols[0].volume().solid()); + + const double* trans = waferVols[0]->GetMatrix()->GetTranslation(); + double half_module_thickness = mod_shape->GetDZ(); + double half_silicon_thickness = comp_shape->GetDZ(); + + double sensitive_z_position = trans[2]; + + double inner_thickness = half_module_thickness - sensitive_z_position; + + thisLayer.distanceSupport = rc ; + + thisLayer.offsetSupport = 0; + thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; + thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); + thisLayer.widthSupport = 2*mod_shape->GetDX(); + + thisLayer.distanceSensitive = rc+sensitive_z_position; + thisLayer.offsetSensitive = 0. ; + thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z + //Changed by Thorben Quast (same applies to zHalfSupport) + //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module + thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); + thisLayer.widthSensitive = 2*comp_shape->GetDX(); + thisLayer.ladderNumber = nphi; + thisLayer.phi0 = phic; + zPlanarData->layers.push_back(thisLayer); + // Loop over the number of sensors in phi. for (int ii = 0; ii < nphi; ii++) { @@ -252,39 +281,6 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s PlacedVolume wafer_pv = waferVols[ic]; DetElement comp_elt(sens_elt,wafer_pv.volume().name(),sensor_idx); comp_elt.setPlacement(wafer_pv); - - ///GET GEAR INFORMATION FROM FIRST "MODULE" IN Z AND phi - ///NOTE WORKS ONLY FOR ONE WAFER - if (ii==0 && j==0 && ic==0){ - - Box mod_shape(m_env.solid()), comp_shape(wafer_pv.volume().solid()); - - const double* trans = comp_elt.placement()->GetMatrix()->GetTranslation(); - double half_module_thickness = mod_shape->GetDZ(); - double half_silicon_thickness = comp_shape->GetDZ(); - - double sensitive_z_position = trans[2]; - - double inner_thickness = half_module_thickness - sensitive_z_position; - - thisLayer.distanceSupport = rc ; - - thisLayer.offsetSupport = 0; - thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; - thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); - thisLayer.widthSupport = 2*mod_shape->GetDX(); - - thisLayer.distanceSensitive = rc+sensitive_z_position; - thisLayer.offsetSensitive = 0. ; - thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z - //Changed by Thorben Quast (same applies to zHalfSupport) - //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module - thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); - thisLayer.widthSensitive = 2*comp_shape->GetDX(); - thisLayer.ladderNumber = (int) nphi ; - thisLayer.phi0 = phic; - } - } @@ -310,9 +306,6 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s pv.addPhysVolID("layer", lay_id); // Set the layer ID. lay_elt.setAttributes(theDetector,lay_vol,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr()); lay_elt.setPlacement(pv); - - zPlanarData->layers.push_back( thisLayer ) ; - } sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); sdet.addExtension< ZPlanarData >( zPlanarData ) ; From 86199ad3bdbbb68f99eafaaeaa5f267636300b2a Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Mon, 12 Aug 2024 10:41:58 +0200 Subject: [PATCH 009/133] refactor LayerLayout population into function --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp index 341aa8704..8051d0f53 100644 --- a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -75,6 +75,41 @@ void populateNeighbourData(NeighbourSurfacesData* neighbourSurfacesData, UTIL::B } +ZPlanarData::LayerLayout buildLayerLayout(double radius, int staves, double phi0, double z0, Volume module, PlacedVolume sensor) { + ZPlanarData::LayerLayout thisLayer ; + /// GET GEAR INFORMATION + /// NOTE WORKS ONLY FOR ONE WAFER + /// FIXME: does not take phi_dr and z_dr into account. + Box mod_shape(module.solid()), comp_shape(sensor.volume().solid()); + + const double* trans = sensor->GetMatrix()->GetTranslation(); + double half_module_thickness = mod_shape->GetDZ(); + double half_silicon_thickness = comp_shape->GetDZ(); + + double sensitive_z_position = trans[2]; + + double inner_thickness = half_module_thickness - sensitive_z_position; + + thisLayer.distanceSupport = radius; + + thisLayer.offsetSupport = 0; + thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; + thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); + thisLayer.widthSupport = 2*mod_shape->GetDX(); + + thisLayer.distanceSensitive = radius + sensitive_z_position; + thisLayer.offsetSensitive = 0. ; + thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z + //Changed by Thorben Quast (same applies to zHalfSupport) + //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module + thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); + thisLayer.widthSensitive = 2*comp_shape->GetDX(); + thisLayer.ladderNumber = staves; + thisLayer.phi0 = phi0; + + return thisLayer; +} + static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { typedef std::vector Placements; xml_det_t x_det = e; @@ -200,35 +235,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s int module_idx =0; - ZPlanarData::LayerLayout thisLayer ; - /// GET GEAR INFORMATION - /// NOTE WORKS ONLY FOR ONE WAFER - Box mod_shape(m_env.solid()), comp_shape(waferVols[0].volume().solid()); - - const double* trans = waferVols[0]->GetMatrix()->GetTranslation(); - double half_module_thickness = mod_shape->GetDZ(); - double half_silicon_thickness = comp_shape->GetDZ(); - - double sensitive_z_position = trans[2]; - - double inner_thickness = half_module_thickness - sensitive_z_position; - - thisLayer.distanceSupport = rc ; - - thisLayer.offsetSupport = 0; - thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness; - thisLayer.zHalfSupport = z0 + mod_shape->GetDY(); - thisLayer.widthSupport = 2*mod_shape->GetDX(); - - thisLayer.distanceSensitive = rc+sensitive_z_position; - thisLayer.offsetSensitive = 0. ; - thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z - //Changed by Thorben Quast (same applies to zHalfSupport) - //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module - thisLayer.zHalfSensitive = z0 + comp_shape->GetDY(); - thisLayer.widthSensitive = 2*comp_shape->GetDX(); - thisLayer.ladderNumber = nphi; - thisLayer.phi0 = phic; + ZPlanarData::LayerLayout thisLayer = buildLayerLayout(rc, nphi, phi0, z0, m_env, waferVols[0]); zPlanarData->layers.push_back(thisLayer); From 6135d1f03f7e060a1292ef977d53ae42c6930828 Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Wed, 14 Aug 2024 09:34:25 +0200 Subject: [PATCH 010/133] TrackerBarrel_o1_v06 add assembly stave --- detector/tracker/TrackerBarrel_o1_v06_geo.cpp | 129 +++++++++--------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp index 8051d0f53..9ba5c30f0 100644 --- a/detector/tracker/TrackerBarrel_o1_v06_geo.cpp +++ b/detector/tracker/TrackerBarrel_o1_v06_geo.cpp @@ -31,7 +31,9 @@ using dd4hep::Material; using dd4hep::PlacedVolume; using dd4hep::Position; using dd4hep::Ref_t; -using dd4hep::RotationZYX; +using dd4hep::Rotation3D; +using dd4hep::RotationX; +using dd4hep::RotationZ; using dd4hep::SensitiveDetector; using dd4hep::Transform3D; using dd4hep::Tube; @@ -144,6 +146,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s sens.setType("tracker"); + // TODO: refactor module creation code into a function... //NOTE modules are what is defined in compact. Later we call a "module" as a "sensor". for(xml_coll_t mi(x_det,_U(module)); mi; ++mi) { xml_comp_t x_mod = mi; @@ -218,42 +221,70 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s double rphi_dr = x_layout.dr(); // The delta radius of every other sensor. double phi_incr = (M_PI * 2) / nphi; // Phi increment for one sensor. - double phic = phi0; // Phi of the sensor center. double z0 = z_layout.z0(); // Z position of first sensor in phi. double nz = z_layout.nz(); // Number of sensors to place in z. double z_dr = z_layout.dr(); // Radial displacement parameter, of every other sensor. - Volume m_env = volumes[m_nam]; + Volume sensorVol = volumes[m_nam]; DetElement lay_elt(sdet,_toString(x_layer.id(),"layer%d"),lay_id); Placements& waferVols = sensitives[m_nam]; - + + ZPlanarData::LayerLayout thisLayer = buildLayerLayout(rc, nphi, phi0, z0, sensorVol, waferVols[0]); + zPlanarData->layers.push_back(thisLayer); + + Assembly stave("stave"); // Z increment for sensor placement along Z axis. // Adjust for z0 at center of sensor rather than // the end of cylindrical envelope. - double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; - // Starting z for sensor placement along Z axis. - double sensor_z = -z0; - int module_idx =0; - - - ZPlanarData::LayerLayout thisLayer = buildLayerLayout(rc, nphi, phi0, z0, m_env, waferVols[0]); - zPlanarData->layers.push_back(thisLayer); + DetElement staveElementTemplate("staveElementTemplate", 0); + double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; + for (int i = 0; i < nz; i++) + { + // sensor/module still lives in a world where: + // x: width, y: length, z: thickness + // we construct the stave in the same way, + // i.e. the modules are placed along y from z0 to -z0 + // and dr is applied along z + double y = z0 - i * z_incr; + double z = i % 2 == 0 ? 0 : z_dr; + Position pos(0., y, z); + auto sensorPv = stave.placeVolume(sensorVol, pos); + sensorPv.addPhysVolID("sensor", i); + std::string sensorName = _toString(i, "sensor%d"); + DetElement sensorElement(sensorName, i); + staveElementTemplate.add(sensorElement); + sensorElement.setPlacement(sensorPv); + + // also add a DetElement for the sensitive component + for (const PlacedVolume& wafer_pv : waferVols) { + DetElement comp_elt(sensorElement, wafer_pv.volume().name(), i); + comp_elt.setPlacement(wafer_pv); + } + } - - // Loop over the number of sensors in phi. - for (int ii = 0; ii < nphi; ii++) { - double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of sensor position. - double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of sensor position. - double x = rc * std::cos(phic); // Basic x sensor position. - double y = rc * std::sin(phic); // Basic y sensor position. - - // Loop over the number of sensors in z. - //Create stave FIXME disable for now - std::string module_name = _toString(module_idx,"module%d"); - // DetElement module_elt(lay_elt,module_name,module_idx); - int sensor_idx = 0; - - for (int j = 0; j < nz; j++) { - std::string sensor_name = _toString(sensor_idx,"sensor%d"); + // Loop over the number of staves in phi. + for (int i = 0; i < nphi; i++) + { + double dr = i % 2 == 0 ? 0 : rphi_dr; + double r = rc + dr; + double phi = phi0 + i * phi_incr; + double x = r * std::cos(phi); // Basic x stave position. + double y = r * std::sin(phi); // Basic y stave position. + + // module: stave + std::string moduleName = _toString(i, "module%d"); + // stave has x: width, y: length, z: thickness (pointing outwards) + // rotate -pi/2 around x to align length with z + // rotate -p/2 * phi around z to point outwards again + Rotation3D rotation = RotationZ(-M_PI/2 + phi + phi_tilt) * RotationX(-M_PI/2); + Transform3D transform(rotation, Position(x, y, 0.)); + auto stavePv = lay_vol.placeVolume(stave, transform); + stavePv.addPhysVolID("module", i); + DetElement staveElement = staveElementTemplate.clone(moduleName, i); + staveElement.setPlacement(stavePv); + lay_elt.add(staveElement); + + for (int j = 0; j < nz; j++) + { /////////////////// @@ -262,51 +293,15 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s //encoding encoder[lcio::LCTrackerCellID::layer()] = lay_id; - encoder[lcio::LCTrackerCellID::module()] = module_idx; - encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx; + encoder[lcio::LCTrackerCellID::module()] = i; + encoder[lcio::LCTrackerCellID::sensor()] = j; - populateNeighbourData(neighbourSurfacesData, encoder, module_idx, sensor_idx, nphi, nz); + populateNeighbourData(neighbourSurfacesData, encoder, i, j, nphi, nz); /////////////////// - - //FIXME - sensor_name = module_name + sensor_name; - - DetElement sens_elt(lay_elt,sensor_name,sensor_idx); - // Module PhysicalVolume. - Transform3D tr(RotationZYX(0,((M_PI/2)-phic-phi_tilt),-M_PI/2),Position(x,y,sensor_z)); - - //FIXME - pv = lay_vol.placeVolume(m_env,tr); - pv.addPhysVolID(_U(module), module_idx); - pv.addPhysVolID(_U(sensor), sensor_idx); - sens_elt.setPlacement(pv); - for(size_t ic=0; ic Date: Thu, 22 Aug 2024 16:08:18 +0200 Subject: [PATCH 011/133] add tracking volume --- FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml index 10954f514..c45519d6e 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml @@ -254,6 +254,22 @@ + + + + + + + + + + + From 0e922ed9d3d28123728a4b9bc30b6b7852225ccf Mon Sep 17 00:00:00 2001 From: Leonhard Reichenbach Date: Mon, 19 Aug 2024 09:03:03 +0200 Subject: [PATCH 012/133] update README --- FCCee/CLD/compact/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/FCCee/CLD/compact/README.md b/FCCee/CLD/compact/README.md index bcd254a15..c53c2223e 100644 --- a/FCCee/CLD/compact/README.md +++ b/FCCee/CLD/compact/README.md @@ -39,6 +39,13 @@ CLD_o2_v06 This model is based on `CLD_o2_v05` with the following changes: LumiCal outer radius from 112 mm to 115 mm, remove unused nose shield parameters, place LumiCal at 1074*mm along the beam-axis, instead of at 1074*mm in Z, moves LumiCal by 100*micron. +CLD_o2_v07 +---------- + +This model is based on `CLD_o2_v06` with the following changes: reduced loading time by adding stave assemblies in the tracker barrel. +Additionally, a non-cylindrical (polycone) tracking volume was added that excludes the LumiCal. To profit from this feature the `Geant4TVUserParticleHandler` +needs to be used in `ddsim`. The definitions for the cylindrical volume were kept to be backwards compatible to the `Geant4TCUserParticleHandler`. + CLD_o3_v01 ---------- From f8b5a1592b6d6e2ccf62aa861fb3ca3f74f0ed89 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Thu, 4 Jul 2024 19:40:29 +0200 Subject: [PATCH 013/133] addExtensionsToHCalAllegro --- .../HCalEndcaps_ThreeParts_TileCal.xml | 31 +- .../HCalThreePartsEndcap_o1_v01_geo.cpp | 896 +++++++++--------- .../calorimeter/HCalTileBarrel_o1_v01_geo.cpp | 92 +- 3 files changed, 535 insertions(+), 484 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml index c5cbe72a7..cc1e2190f 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml @@ -44,20 +44,23 @@ - - system:4,type:2,layer:5,row:9,eta:11,phi:10 + + system:4,type:2,layer:5,row:9,theta:11,phi:10 - - - system:4,type:2,layer:4,eta:11,phi:10 + + + system:4,type:2,layer:5,theta:11,phi:10 - - - system:4,type:2,layer:5,row:9,eta:10,phi:10 + + system:4,type:2,layer:5,row:9,theta:0,phi:10 + + @@ -70,7 +73,7 @@ @@ -78,17 +81,17 @@ diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp index 34544c2e2..1baccf00c 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp @@ -1,467 +1,487 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" +#include // todo: remove gaudi logging and properly capture output #define endmsg std::endl #define lLog std::cout namespace MSG { -const std::string DEBUG = " Debug: "; -const std::string INFO = " Info: "; +const std::string ERROR = "createHCalThrePartsEndcap ERROR "; +const std::string DEBUG = "createHCalThrePartsEndcap DEBUG "; +const std::string INFO = "createHCalThrePartsEndcap INFO "; } using dd4hep::Volume; using dd4hep::DetElement; using dd4hep::xml::Dimension; using dd4hep::PlacedVolume; +using xml_comp_t = dd4hep::xml::Component; +using xml_det_t = dd4hep::xml::DetElement; +using xml_h = dd4hep::xml::Handle_t; namespace det { -void buildEC(dd4hep::Detector& aLcdd, dd4hep::SensitiveDetector& aSensDet, dd4hep::Volume& aEnvelope, - dd4hep::DetElement& aHCal, xml_det_t aXmlElement, int sign) { - - dd4hep::SensitiveDetector sensDet = aSensDet; - Dimension sensDetType = aXmlElement.child(_Unicode(sensitive)); - sensDet.setType(sensDetType.typeStr()); - - Dimension dimensions(aXmlElement.child(_Unicode(dimensions))); - xml_comp_t xEndPlate = aXmlElement.child(_Unicode(end_plate)); - double dZEndPlate = xEndPlate.thickness() / 2.; - xml_comp_t xFacePlate = aXmlElement.child(_Unicode(face_plate)); - double dRhoFacePlate = xFacePlate.thickness() / 2.; - xml_comp_t xSpace = aXmlElement.child(_Unicode(plate_space)); // to avoid overlaps - double space = xSpace.thickness(); - xml_comp_t xSteelSupport = aXmlElement.child(_Unicode(steel_support)); - double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; - lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; - - double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; - double sensitiveBarrel2Rmin = dimensions.rmin2() + 2 * dRhoFacePlate + space; - double sensitiveBarrel3Rmin = dimensions.rmin() + 2 * dRhoFacePlate + space; - - // Offset in z is given as distance from 0 to the middle of the Calorimeter volume - double extBarrelOffset1 = dimensions.offset(); - double extBarrelOffset2 = dimensions.z_offset(); - double extBarrelOffset3 = dimensions.v_offset(); - - // Hard-coded assumption that we have two different sequences for the modules - std::vector sequences = {aXmlElement.child(_Unicode(sequence_a)), aXmlElement.child(_Unicode(sequence_b))}; - // NOTE: This assumes that both have the same dimensions! - Dimension sequenceDimensions(sequences[1].dimensions()); - double dzSequence = sequenceDimensions.dz(); - lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; - - // calculate the number of modules fitting in Z - unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); - unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); - unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); - - unsigned int numSequencesR1 = 0; - unsigned int numSequencesR2 = 0; - unsigned int numSequencesR3 = 0; - double moduleDepth1 = 0.; - double moduleDepth2 = 0.; - double moduleDepth3 = 0.; - std::vector layerDepths1 = std::vector(); - std::vector layerDepths2 = std::vector(); - std::vector layerDepths3 = std::vector(); - - // get all 'layer' children of the 'layers' tag - std::vector Layers; - for (xml_coll_t xCompColl(aXmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; - ++xCompColl) { - Layers.push_back(xCompColl); - } - - for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { - xml_comp_t layer = *it; - Dimension layerDimension(layer.dimensions()); - numSequencesR1 += layerDimension.nmodules(); - numSequencesR2 += layerDimension.nModules(); - numSequencesR3 += layerDimension.nPads(); - for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++) { - moduleDepth1 += layerDimension.dr(); - layerDepths1.push_back(layerDimension.dr()); - } - for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++) { - moduleDepth2 += layerDimension.dr(); - layerDepths2.push_back(layerDimension.dr()); - } - for (int nLayer = 0; nLayer < layerDimension.nPads(); nLayer++) { - moduleDepth3 += layerDimension.dr(); - layerDepths3.push_back(layerDimension.dr()); +static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4hep::SensitiveDetector sensDet){ + xml_det_t xmlDet = xmlElement; + std::string detName = xmlDet.nameStr(); + + // Make DetElement + dd4hep::DetElement caloDetElem(detName, xmlDet.id()); + + // Make volume that envelopes the whole barrel; set material to air + Dimension dimensions(xmlDet.dimensions()); + + dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); + dd4hep::Tube negative1(dimensions.rmin(), dimensions.rmax1(), (dimensions.offset() - dimensions.width())); + dd4hep::Tube negative2(dimensions.rmin(), dimensions.rmin1(), (dimensions.z_offset() - dimensions.dz())); + dd4hep::Tube negative3(dimensions.rmin(), dimensions.rmin2(), (dimensions.v_offset() - dimensions.z_length())); + + dd4hep::SubtractionSolid envelopeShapeTmp1(envelope, negative1); + dd4hep::SubtractionSolid envelopeShapeTmp2(envelopeShapeTmp1, negative2); + dd4hep::SubtractionSolid envelopeShape(envelopeShapeTmp2, negative3); + + Volume envelopeVolume(detName + "_volume", envelopeShape, lcdd.air()); + envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); + + // Set sensitive detector type + Dimension sensDetType = xmlElement.child(_Unicode(sensitive)); + sensDet.setType(sensDetType.typeStr()); + + // Dimension dimensions(xmlElement.child(_Unicode(dimensions))); + xml_comp_t xEndPlate = xmlElement.child(_Unicode(end_plate)); + double dZEndPlate = xEndPlate.thickness() / 2.; + xml_comp_t xFacePlate = xmlElement.child(_Unicode(face_plate)); + double dRhoFacePlate = xFacePlate.thickness() / 2.; + xml_comp_t xSpace = xmlElement.child(_Unicode(plate_space)); // to avoid overlaps + double space = xSpace.thickness(); + xml_comp_t xSteelSupport = xmlElement.child(_Unicode(steel_support)); + double dSteelSupport = xSteelSupport.thickness(); + lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; + lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; + + // Calculate sensitive barrel dimensions + double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; + double sensitiveBarrel2Rmin = dimensions.rmin2() + 2 * dRhoFacePlate + space; + double sensitiveBarrel3Rmin = dimensions.rmin() + 2 * dRhoFacePlate + space; + + // Offset in z is given as distance from 0 to the middle of the Calorimeter volume + double extBarrelOffset1 = dimensions.offset(); + double extBarrelOffset2 = dimensions.z_offset(); + double extBarrelOffset3 = dimensions.v_offset(); + + // Hard-coded assumption that we have two different sequences for the modules + std::vector sequences = {xmlElement.child(_Unicode(sequence_a)), xmlElement.child(_Unicode(sequence_b))}; + // NOTE: This assumes that both have the same dimensions! + Dimension sequenceDimensions(sequences[1].dimensions()); + double dzSequence = sequenceDimensions.dz(); + lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + + // calculate the number of modules fitting in Z + unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); + + unsigned int numSequencesR1 = 0; + unsigned int numSequencesR2 = 0; + unsigned int numSequencesR3 = 0; + double moduleDepth1 = 0.; + double moduleDepth2 = 0.; + double moduleDepth3 = 0.; + + // MM: using layers and Layers is not very fortunate + std::vector layerDepths1 = std::vector(); + std::vector layerDepths2 = std::vector(); + std::vector layerDepths3 = std::vector(); + + // get all 'layer' children of the 'layers' tag + std::vector Layers; + for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ + Layers.push_back(xCompColl); } - } - - lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numSequencesR1 - << " , which end up to a full module depth in rho of " << moduleDepth1 << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << layerDepths1.size() << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numSequencesR2 - << " , which end up to a full module depth in rho of " << moduleDepth2 << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << layerDepths2.size() << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numSequencesR3 - << " , which end up to a full module depth in rho of " << moduleDepth3 << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << layerDepths3.size() << endmsg; - - lLog << MSG::INFO << "constructing first part EC: with offset " << extBarrelOffset1 << ": "<< numSequencesZ1 - << " rings in Z, " << numSequencesR1 << " layers in Rho, " << numSequencesR1 * numSequencesZ1 - << " tiles" << endmsg; - - lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << ": " << numSequencesZ2 - << " rings in Z, " << numSequencesR2 << " layers in Rho, " - << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; - - lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << ": " << numSequencesZ3 - << " rings in Z, " << numSequencesR3 << " layers in Rho, " - << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; - - lLog << MSG::INFO << "number of channels: " - << (numSequencesR1 * numSequencesZ1) + (numSequencesR2 * numSequencesZ2) + (numSequencesR3 * numSequencesZ3) - << endmsg; - - // Calculate correction along z based on the module size (can only have natural number of modules) - double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; - lLog << MSG::INFO - << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 - << endmsg; - double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; - lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 - << endmsg; - lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 - << endmsg; - lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 - << endmsg; - - double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; - lLog << MSG::INFO << "dz third part EC:" << dzDetector2 * 2 - << endmsg; - - // Add structural support made of steel inside of HCal - DetElement facePlate1(aHCal, "FacePlate_" + std::to_string(1 * sign), 0); - dd4hep::Tube facePlateShape1(dimensions.rmin1(), (sensitiveBarrel1Rmin - space), - (dzDetector1 - 2 * dZEndPlate - space)); - Volume facePlateVol1("facePlateVol1", facePlateShape1, aLcdd.material(xFacePlate.materialStr())); - facePlateVol1.setVisAttributes(aLcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace1(0, 0, sign * extBarrelOffset1); - - // Faceplate for 2nd part of extended Barrel - DetElement facePlate2(aHCal, "FacePlate_" + std::to_string(2 * sign), 0); - dd4hep::Tube facePlateShape2(dimensions.rmin2(), (sensitiveBarrel2Rmin - space), - dzDetector2); - Volume facePlateVol2("facePlateVol2", facePlateShape2, aLcdd.material(xFacePlate.materialStr())); - facePlateVol2.setVisAttributes(aLcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace2(0, 0, sign * extBarrelOffset2); - - // Faceplate for 3rd part of extended Barrel - DetElement facePlate3(aHCal, "FacePlate_" + std::to_string(3 * sign), 0); - dd4hep::Tube facePlateShape3(dimensions.rmin(), (sensitiveBarrel3Rmin - space), - (dzDetector3 - 2 * dZEndPlate - space)); - Volume facePlateVol3("facePlateVol3", facePlateShape3, aLcdd.material(xFacePlate.materialStr())); - facePlateVol3.setVisAttributes(aLcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace3(0, 0, sign * extBarrelOffset3); - - PlacedVolume placedFacePlate1 = aEnvelope.placeVolume(facePlateVol1, offsetFace1); - facePlate1.setPlacement(placedFacePlate1); - PlacedVolume placedFacePlate2 = aEnvelope.placeVolume(facePlateVol2, offsetFace2); - facePlate2.setPlacement(placedFacePlate2); - PlacedVolume placedFacePlate3 = aEnvelope.placeVolume(facePlateVol3, offsetFace3); - facePlate3.setPlacement(placedFacePlate3); - - // Add structural support made of steel at both ends of extHCal - dd4hep::Tube endPlateShape1(dimensions.rmin1(), (dimensions.rmax1() - dSteelSupport), dZEndPlate); - Volume endPlateVol1("endPlateVol1", endPlateShape1, aLcdd.material(xEndPlate.materialStr())); - endPlateVol1.setVisAttributes(aLcdd, xEndPlate.visStr()); - dd4hep::Tube endPlateShape3(dimensions.rmin(), (dimensions.rmax() - dSteelSupport), dZEndPlate); - Volume endPlateVol3("endPlateVol3", endPlateShape3, aLcdd.material(xEndPlate.materialStr())); - endPlateVol3.setVisAttributes(aLcdd, xEndPlate.visStr()); - - // Endplates placed for the extended Barrels in front and in the back to the central Barrel - DetElement endPlatePos(aHCal, "endPlate_" + std::to_string(1 * sign), 0); - dd4hep::Position posOffset(0, 0, sign * (extBarrelOffset3 + dzDetector3 - dZEndPlate)); - PlacedVolume placedEndPlatePos = aEnvelope.placeVolume(endPlateVol3, posOffset); - endPlatePos.setPlacement(placedEndPlatePos); - - DetElement endPlateNeg(aHCal, "endPlate_" + std::to_string(2 * sign), 0); - dd4hep::Position negOffset(0, 0, sign * (extBarrelOffset1 - dzDetector1 + dZEndPlate)); - PlacedVolume placedEndPlateNeg = aEnvelope.placeVolume(endPlateVol1, negOffset); - endPlateNeg.setPlacement(placedEndPlateNeg); - - std::vector layers; - layers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - std::vector > seqInLayers; - seqInLayers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - std::vector tilesPerLayer; - tilesPerLayer.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - - // loop over R ("layers") - double layerR = 0.; - for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel1Rmin + layerR; - double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); - layerR += layerDepths1.at(idxLayer); - - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; - - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, aLcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); - Volume layerVolume("HCalECLayerVol1", layerShape, aLcdd.air()); - - layerVolume.setVisAttributes(aLcdd.invisible()); - unsigned int idxSubMod = 0; - - dd4hep::Position moduleOffset1 (0,0,sign * extBarrelOffset1); - - dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset1); - unsigned int type1 = 0; - if (sign<0) { - type1 = 3; - } - placedLayerVolume.addPhysVolID("type", type1); // First module type=0,3 in front of second +/- - placedLayerVolume.addPhysVolID("layer", idxLayer); - layers.push_back(placedLayerVolume); - - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; - ++xCompColl, ++idxSubMod) { - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_"+ xComp.materialStr() - , tileShape, - aLcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(aLcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()) { - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); + for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it){ + xml_comp_t layer = *it; + Dimension layerDimension(layer.dimensions()); + numSequencesR1 += layerDimension.nmodules(); + numSequencesR2 += layerDimension.nModules(); + numSequencesR3 += layerDimension.nPads(); + + for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++){ + moduleDepth1 += layerDimension.dr(); + layerDepths1.push_back(layerDimension.dr()); + } + for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++){ + moduleDepth2 += layerDimension.dr(); + layerDepths2.push_back(layerDimension.dr()); + } + for (int nLayer = 0; nLayer < layerDimension.nPads(); nLayer++){ + moduleDepth3 += layerDimension.dr(); + layerDepths3.push_back(layerDimension.dr()); + } } - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector1 + 0.5 * dzSequence; //2*dZEndPlate + space + 0.5 * dzSequence; - - for (uint numSeq=0; numSeq < numSequencesZ1; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; + lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numSequencesR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numSequencesR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numSequencesR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; + + lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numSequencesR1 << " layers in Rho, " << numSequencesR1 * numSequencesZ1 << " tiles" << endmsg; + lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numSequencesR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; + + lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numSequencesR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; + + lLog << MSG::INFO << "number of channels: " << (numSequencesR1 * numSequencesZ1) + (numSequencesR2 * numSequencesZ2) + (numSequencesR3 * numSequencesZ3) << endmsg; + + // Calculate correction along z based on the module size (can only have natural number of modules) + double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; + double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; + double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; + + lLog << MSG::INFO << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 << endmsg; + lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 << endmsg; + lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 << endmsg; + lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 << endmsg; + + lLog << MSG::INFO << "dz third part EC:" << dzDetector2 * 2 << endmsg; + + + for (int iSign = 0; iSign < 2; iSign++){ + int sign; + if(iSign == 0){ + sign = +1; + lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; + } + else{ + sign = -1; + lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; + } + // Add structural support made of steel inside of HCal + DetElement facePlate1(caloDetElem, "FacePlate_" + std::to_string(1 * sign), 0); + dd4hep::Tube facePlateShape1(dimensions.rmin1(), (sensitiveBarrel1Rmin - space), (dzDetector1 - 2 * dZEndPlate - space)); + Volume facePlateVol1("facePlateVol1", facePlateShape1, lcdd.material(xFacePlate.materialStr())); + facePlateVol1.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace1(0, 0, sign * extBarrelOffset1); + + // Faceplate for 2nd part of extended Barrel + DetElement facePlate2(caloDetElem, "FacePlate_" + std::to_string(2 * sign), 0); + dd4hep::Tube facePlateShape2(dimensions.rmin2(), (sensitiveBarrel2Rmin - space), + dzDetector2); + Volume facePlateVol2("facePlateVol2", facePlateShape2, lcdd.material(xFacePlate.materialStr())); + facePlateVol2.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace2(0, 0, sign * extBarrelOffset2); + + // Faceplate for 3rd part of extended Barrel + DetElement facePlate3(caloDetElem, "FacePlate_" + std::to_string(3 * sign), 0); + dd4hep::Tube facePlateShape3(dimensions.rmin(), (sensitiveBarrel3Rmin - space), + (dzDetector3 - 2 * dZEndPlate - space)); + Volume facePlateVol3("facePlateVol3", facePlateShape3, lcdd.material(xFacePlate.materialStr())); + facePlateVol3.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace3(0, 0, sign * extBarrelOffset3); + + PlacedVolume placedFacePlate1 = envelopeVolume.placeVolume(facePlateVol1, offsetFace1); + facePlate1.setPlacement(placedFacePlate1); + PlacedVolume placedFacePlate2 = envelopeVolume.placeVolume(facePlateVol2, offsetFace2); + facePlate2.setPlacement(placedFacePlate2); + PlacedVolume placedFacePlate3 = envelopeVolume.placeVolume(facePlateVol3, offsetFace3); + facePlate3.setPlacement(placedFacePlate3); + + // Add structural support made of steel at both ends of extHCal + dd4hep::Tube endPlateShape1(dimensions.rmin1(), (dimensions.rmax1() - dSteelSupport), dZEndPlate); + Volume endPlateVol1("endPlateVol1", endPlateShape1, lcdd.material(xEndPlate.materialStr())); + endPlateVol1.setVisAttributes(lcdd, xEndPlate.visStr()); + dd4hep::Tube endPlateShape3(dimensions.rmin(), (dimensions.rmax() - dSteelSupport), dZEndPlate); + Volume endPlateVol3("endPlateVol3", endPlateShape3, lcdd.material(xEndPlate.materialStr())); + endPlateVol3.setVisAttributes(lcdd, xEndPlate.visStr()); + + // Endplates placed for the extended Barrels in front and in the back to the central Barrel + DetElement endPlatePos(caloDetElem, "endPlate_" + std::to_string(1 * sign), 0); + dd4hep::Position posOffset(0, 0, sign * (extBarrelOffset3 + dzDetector3 - dZEndPlate)); + PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol3, posOffset); + endPlatePos.setPlacement(placedEndPlatePos); + + DetElement endPlateNeg(caloDetElem, "endPlate_" + std::to_string(2 * sign), 0); + dd4hep::Position negOffset(0, 0, sign * (extBarrelOffset1 - dzDetector1 + dZEndPlate)); + PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol1, negOffset); + endPlateNeg.setPlacement(placedEndPlateNeg); + + std::vector layers; + layers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector > seqInLayers; + seqInLayers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector tilesPerLayer; + tilesPerLayer.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + + // loop over R ("layers") + double layerR = 0.; + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel1Rmin + layerR; + double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); + layerR += layerDepths1.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); + Volume layerVolume("HCalECLayerVol1", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + dd4hep::Position moduleOffset1 (0,0,sign * extBarrelOffset1); + + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset1); + unsigned int type1 = 0; + if (sign<0){ + type1 = 3; + } + placedLayerVolume.addPhysVolID("type", type1); // First module type=0,3 in front of second +/- + placedLayerVolume.addPhysVolID("layer", idxLayer); + + layers.push_back(placedLayerVolume); + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_"+ xComp.materialStr(), tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector1 + 0.5 * dzSequence; //2*dZEndPlate + space + 0.5 * dzSequence; + + for (uint numSeq=0; numSeq < numSequencesZ1; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + } // layers loop + + + layerR = 0.; + // Placement of subWedges in Wedge, 2nd part + for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel2Rmin + layerR; + double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); + layerR += layerDepths2.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); + Volume layerVolume("HCalECLayerVol2", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_", tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } // close first Z loop + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector2 + 0.5 * dzSequence; //(dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ2; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + + dd4hep::Position moduleOffset2 (0, 0, sign * extBarrelOffset2); + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset2); + unsigned int type2 = 1; + if (sign<0){ + type2 = 4; + } + placedLayerVolume.addPhysVolID("type", type2); // Second module type=1,4 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + idxLayer); + layers.push_back(placedLayerVolume); + } + + layerR = 0.; + // Placement of subWedges in Wedge, 3th part + for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel3Rmin + layerR; + double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); + layerR += layerDepths3.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); + Volume layerVolume("HCalECLayerVol3", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_" , tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector3 + 0.5 * dzSequence; //2*dZEndPlate + space + (dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ3; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + + dd4hep::Position moduleOffset3 (0, 0, sign * extBarrelOffset3); + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset3); + unsigned int type3 = 2; + if (sign<0){ + type3 = 5; + } + placedLayerVolume.addPhysVolID("type", type3); // Second module type=2,5 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + layerDepths2.size() + idxLayer); + layers.push_back(placedLayerVolume); + } // end loop placement of subwedges + + // Placement of DetElements + lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; + lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; + + // Place det elements wihtin each other to recover volume positions later via cellID + for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++){ + DetElement layerDet(caloDetElem, dd4hep::xml::_toString(sign*(iLayer+1), "layer%d"), sign*(iLayer+1)); + layerDet.setPlacement(layers[iLayer]); + + for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ + DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), sign*(iSeq+1)); + seqDet.setPlacement(seqInLayers[iLayer][iSeq]); + + DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), sign*(iSeq+1)); + tileDet.setPlacement(tilesPerLayer[iLayer]); + } + } + } // for signs loop + + // Place envelope volume + Volume motherVol = lcdd.pickMotherVolume(caloDetElem); + + PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); + placedHCal.addPhysVolID("system", xmlDet.id()); + caloDetElem.setPlacement(placedHCal); + + + // Create caloData object + auto caloData = new dd4hep::rec::LayeredCalorimeterData; + caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::EndcapLayout; + caloDetElem.addExtension(caloData); + + caloData->extent[0] = sensitiveBarrel3Rmin; + caloData->extent[1] = sensitiveBarrel3Rmin + moduleDepth3; // + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = dzDetector1 + dzDetector2 + dzDetector3; + + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths1.at(idxLayer); + + caloLayer.distance = sensitiveBarrel1Rmin; // should this be always the radius of the first layer as it is now? + caloLayer.sensitive_thickness = difference_bet_r1r2; // not really sure what is this variable + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); } - seqInLayers.push_back(seqs); - } - - layerR = 0.; - // Placement of subWedges in Wedge, 2nd part - for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel2Rmin + layerR; - double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); - layerR += layerDepths2.at(idxLayer); + for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths2.at(idxLayer); - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; + caloLayer.distance = sensitiveBarrel2Rmin; + caloLayer.sensitive_thickness = difference_bet_r1r2; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, aLcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); - Volume layerVolume("HCalECLayerVol2", layerShape, aLcdd.air()); - - layerVolume.setVisAttributes(aLcdd.invisible()); - unsigned int idxSubMod = 0; - - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; - ++xCompColl, ++idxSubMod) { - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_" - , tileShape, - aLcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(aLcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()) { - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); + caloData->layers.push_back(caloLayer); } - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector2 + 0.5 * dzSequence; //(dzSequence * 0.5); + for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths3.at(idxLayer); - for (uint numSeq=0; numSeq < numSequencesZ2; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; - } - seqInLayers.push_back(seqs); + caloLayer.distance = sensitiveBarrel3Rmin; + caloLayer.sensitive_thickness = difference_bet_r1r2; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; - dd4hep::Position moduleOffset2 (0, 0, sign * extBarrelOffset2); - dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset2); - unsigned int type2 = 1; - if (sign<0) { - type2 = 4; - } - placedLayerVolume.addPhysVolID("type", type2); // Second module type=1,4 behind the first +/- - placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + idxLayer); - layers.push_back(placedLayerVolume); - } - - layerR = 0.; - // Placement of subWedges in Wedge, 3th part - for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel3Rmin + layerR; - double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); - layerR += layerDepths3.at(idxLayer); - - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; - - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, aLcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); - Volume layerVolume("HCalECLayerVol3", layerShape, aLcdd.air()); - - layerVolume.setVisAttributes(aLcdd.invisible()); - unsigned int idxSubMod = 0; - - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; - ++xCompColl, ++idxSubMod) { - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_" - , tileShape, - aLcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(aLcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()) { - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); + caloData->layers.push_back(caloLayer); } - - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector3 + 0.5 * dzSequence; //2*dZEndPlate + space + (dzSequence * 0.5); - - for (uint numSeq=0; numSeq < numSequencesZ3; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; - } - seqInLayers.push_back(seqs); - - dd4hep::Position moduleOffset3 (0, 0, sign * extBarrelOffset3); - dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset3); - unsigned int type3 = 2; - if (sign<0) { - type3 = 5; - } - placedLayerVolume.addPhysVolID("type", type3); // Second module type=2,5 behind the first +/- - placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + layerDepths2.size() + idxLayer); - layers.push_back(placedLayerVolume); - } - - // Placement of DetElements - lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; - lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; - - for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++) { - DetElement layerDet(aHCal, dd4hep::xml::_toString(sign*(iLayer+1), "layer%d"), sign*(iLayer+1)); - layerDet.setPlacement(layers[iLayer]); - - for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ - DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), sign*(iSeq+1)); - seqDet.setPlacement(seqInLayers[iLayer][iSeq]); - - DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), sign*(iSeq+1)); - tileDet.setPlacement(tilesPerLayer[iLayer]); - } - } - -} - -static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4hep::SensitiveDetector sensDet) { - - - xml_det_t xmlDet = xmlElement; - std::string detName = xmlDet.nameStr(); - - // Make DetElement - dd4hep::DetElement hCalEC(detName, xmlDet.id()); - - // Make volume that envelopes the whole barrel; set material to air - Dimension dimensions(xmlDet.dimensions()); - - dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); - dd4hep::Tube negative1(dimensions.rmin(), dimensions.rmax1(), (dimensions.offset() - dimensions.width())); - dd4hep::Tube negative2(dimensions.rmin(), dimensions.rmin1(), (dimensions.z_offset() - dimensions.dz())); - dd4hep::Tube negative3(dimensions.rmin(), dimensions.rmin2(), (dimensions.v_offset() - dimensions.z_length())); - dd4hep::SubtractionSolid envelopeShapeTmp1(envelope, negative1); - dd4hep::SubtractionSolid envelopeShapeTmp2(envelopeShapeTmp1, negative2); - dd4hep::SubtractionSolid envelopeShape(envelopeShapeTmp2, negative3); - - Volume envelopeVolume(detName + "_volume", envelopeShape, lcdd.air()); - envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); - - lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) - << endmsg; - buildEC(lcdd, sensDet, envelopeVolume, hCalEC, xmlElement, 1); - lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) - << endmsg; - buildEC(lcdd, sensDet, envelopeVolume, hCalEC, xmlElement, -1); - - // Place envelope volume - Volume motherVol = lcdd.pickMotherVolume(hCalEC); - - PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); - placedHCal.addPhysVolID("system", xmlDet.id()); - hCalEC.setPlacement(placedHCal); - - return hCalEC; -} -} // namespace hcal - + return caloDetElem; +} +}// namespace det DECLARE_DETELEMENT(CaloThreePartsEndcap_o1_v01, det::createHCalEC) diff --git a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp index 89be7154d..2084146b8 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp @@ -1,6 +1,7 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" +#include using dd4hep::Volume; using dd4hep::DetElement; @@ -12,11 +13,11 @@ using dd4hep::PlacedVolume; #define endmsg std::endl #define lLog std::cout namespace MSG { -const std::string DEBUG = " Debug: "; -const std::string INFO = " Info: "; +const std::string ERROR = "createHCalTileBarrel ERROR "; +const std::string DEBUG = "createHCalTileBarrel DEBUG "; +const std::string INFO = "createHCalTileBarrel INFO "; } - namespace det { static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep::SensitiveDetector sensDet) { @@ -40,7 +41,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep xml_comp_t xSteelSupport = xmlDet.child(_Unicode(steel_support)); double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness: " << dSteelSupport << " [cm]" << endmsg; + lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport << endmsg; lLog << MSG::DEBUG << "steel support material: " << xSteelSupport.materialStr() << endmsg; double sensitiveBarrelRmin = xDimensions.rmin() + xFacePlate.thickness() + space; @@ -50,17 +51,15 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // NOTE: This assumes that both have the same dimensions! Dimension sequenceDimensions(sequences[1].dimensions()); double dzSequence = sequenceDimensions.dz(); - lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + lLog << MSG::DEBUG << "sequence thickness (cm) " << dzSequence << endmsg; - // calculate the number of modules fitting in Z + // calculate the number of sequences fitting in Z unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); - // get all 'layer' children of the 'layers' tag std::vector Layers; - for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; - ++xCompColl) { - Layers.push_back(xCompColl); + for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl) { + Layers.push_back(xCompColl); } unsigned int numSequencesR = 0; double moduleDepth = 0.; @@ -74,21 +73,23 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep layerDepths.push_back(layerDimension.dr()); } } - lLog << MSG::DEBUG << "retrieved number of layers: " << numSequencesR - << " , which end up to a full module depth in rho of " << moduleDepth << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers: " << layerDepths.size() << endmsg; + lLog << MSG::DEBUG << "retrieved number of radial layers: " << numSequencesR + << " , which end up to a full module depth in rho of " << moduleDepth << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of radial layers: " << layerDepths.size() << endmsg; - lLog << MSG::INFO << "constructing: " << numSequencesZ << " rings in Z, " << numSequencesR - << " layers in Rho, " << numSequencesR * numSequencesZ << " tiles" << endmsg; + lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numSequencesR + << " radial layers, in total " << numSequencesR * numSequencesZ << " tiles" << endmsg; // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; - lLog << MSG::DEBUG << "dzDetector: " << dzDetector << endmsg; - lLog << MSG::INFO << "correction of dz (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; + lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector << endmsg; + lLog << MSG::INFO << "correction of dz in cm (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; double rminSupport = sensitiveBarrelRmin + moduleDepth; double rmaxSupport = sensitiveBarrelRmin + moduleDepth + dSteelSupport; + double sensitiveBarrelRmax = sensitiveBarrelRmin + moduleDepth; + ////////////////////// detector building ////////////////////// @@ -102,10 +103,11 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // top level det element representing whole hcal barrel - DetElement hCal(xmlDet.nameStr(), xmlDet.id()); + DetElement caloDetElem(xmlDet.nameStr(), xmlDet.id()); /// envelope shape dd4hep::Tube envelopeShape(xDimensions.rmin(), xDimensions.rmax(), xDimensions.dz()); + Volume envelopeVolume("HCalEnvelopeVolume", envelopeShape, lcdd.air()); envelopeVolume.setVisAttributes(lcdd, xDimensions.visStr()); @@ -114,7 +116,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep Volume facePlateVol("HCalFacePlateVol", facePlateShape, lcdd.material(xFacePlate.materialStr())); facePlateVol.setVisAttributes(lcdd, xFacePlate.visStr()); PlacedVolume placedFacePlate = envelopeVolume.placeVolume(facePlateVol); - DetElement facePlate_det(hCal, "HCalFacePlate", 0); + DetElement facePlate_det(caloDetElem, "HCalFacePlate", 0); facePlate_det.setPlacement(placedFacePlate); // Add structural support made of steel at both ends of HCal @@ -122,22 +124,21 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep Volume endPlateVol("HCalEndPlateVol", endPlateShape, lcdd.material(xEndPlate.materialStr())); endPlateVol.setVisAttributes(lcdd, xEndPlate.visStr()); - DetElement endPlatePos(hCal, "HCalEndPlatePos", 0); + DetElement endPlatePos(caloDetElem, "HCalEndPlatePos", 0); dd4hep::Position posOffset(0, 0, dzDetector - (dZEndPlate / 2)); PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol, posOffset); endPlatePos.setPlacement(placedEndPlatePos); - DetElement endPlateNeg(hCal, "HCalEndPlateNeg", 1); + DetElement endPlateNeg(caloDetElem, "HCalEndPlateNeg", 1); dd4hep::Position negOffset(0, 0, -dzDetector + (dZEndPlate / 2)); PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol, negOffset); endPlateNeg.setPlacement(placedEndPlateNeg); dd4hep::Tube supportShape(rminSupport, rmaxSupport, (dzDetector - dZEndPlate - space)); - Volume steelSupportVolume("HCalSteelSupportVol", supportShape, - lcdd.material(xSteelSupport.materialStr())); + Volume steelSupportVolume("HCalSteelSupportVol", supportShape, lcdd.material(xSteelSupport.materialStr())); steelSupportVolume.setVisAttributes(lcdd.invisible()); PlacedVolume placedSupport = envelopeVolume.placeVolume(steelSupportVolume); - DetElement support(hCal, "HCalSteelSupport", 0); + DetElement support(caloDetElem, "HCalSteelSupport", 0); support.setPlacement(placedSupport); // double sensitiveBarrelDz = dzDetector - dZEndPlate; @@ -158,7 +159,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + lLog << MSG::INFO << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector - dZEndPlate - space ); @@ -176,7 +177,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep double tileZOffset = - 0.5* dzSequence; // first Z loop (tiles that make up a sequence) for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; - ++xCompColl, ++idxSubMod) { + ++xCompColl, ++idxSubMod) { xml_comp_t xComp = xCompColl; dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); @@ -210,7 +211,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // Place det elements wihtin each other to recover volume positions later via cellID for (uint iLayer = 0; iLayer < numSequencesR; iLayer++) { - DetElement layerDet(hCal, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); + DetElement layerDet(caloDetElem, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); layerDet.setPlacement(layers[iLayer]); for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ @@ -223,12 +224,39 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep } // Place envelope (or barrel) volume - Volume motherVol = lcdd.pickMotherVolume(hCal); + Volume motherVol = lcdd.pickMotherVolume(caloDetElem); motherVol.setVisAttributes(lcdd.invisible()); - PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); - placedHCal.addPhysVolID("system", hCal.id()); - hCal.setPlacement(placedHCal); - return hCal; + PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVolume); + envelopePhysVol.addPhysVolID("system", xmlDet.id()); + caloDetElem.setPlacement(envelopePhysVol); + + + // Create caloData object + auto caloData = new dd4hep::rec::LayeredCalorimeterData; + caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; + caloDetElem.addExtension(caloData); + + caloData->extent[0] = sensitiveBarrelRmin; + caloData->extent[1] = sensitiveBarrelRmax; // or r_max ? + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = dzDetector; + + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + for (unsigned int idxLayer = 0; idxLayer < layerDepths.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths.at(idxLayer); + + caloLayer.distance = sensitiveBarrelRmin; // should this be always the radius of the first layer as it is now? + caloLayer.sensitive_thickness = difference_bet_r1r2; // not really sure what is this variable + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); + } + + + return caloDetElem; + } } // namespace hcal From acff9945ee964d78a339ad7065af466f064e3c42 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Thu, 11 Jul 2024 16:26:30 +0200 Subject: [PATCH 014/133] implemented suggestions from discussion --- .../HCalThreePartsEndcap_o1_v01_geo.cpp | 17 +++++++++++++---- .../calorimeter/HCalTileBarrel_o1_v01_geo.cpp | 17 ++++++++--------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp index 1baccf00c..e447069f4 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp @@ -92,6 +92,10 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h std::vector layerDepths2 = std::vector(); std::vector layerDepths3 = std::vector(); + std::vector layerInnerRadii1 = std::vector(); + std::vector layerInnerRadii2 = std::vector(); + std::vector layerInnerRadii3 = std::vector(); + // get all 'layer' children of the 'layers' tag std::vector Layers; for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ @@ -216,6 +220,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h double rminLayer = sensitiveBarrel1Rmin + layerR; double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); layerR += layerDepths1.at(idxLayer); + layerInnerRadii1.push_back(rminLayer); //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = (idxLayer+1) % 2; @@ -285,6 +290,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h double rminLayer = sensitiveBarrel2Rmin + layerR; double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); layerR += layerDepths2.at(idxLayer); + layerInnerRadii2.push_back(rminLayer); //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = (idxLayer+1) % 2; @@ -351,6 +357,8 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h double rminLayer = sensitiveBarrel3Rmin + layerR; double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); layerR += layerDepths3.at(idxLayer); + layerInnerRadii3.push_back(rminLayer); + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = (idxLayer+1) % 2; @@ -449,11 +457,12 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths1.at(idxLayer); - caloLayer.distance = sensitiveBarrel1Rmin; // should this be always the radius of the first layer as it is now? - caloLayer.sensitive_thickness = difference_bet_r1r2; // not really sure what is this variable + caloLayer.distance = layerInnerRadii1.at(idxLayer); // radius of the current layer + caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; @@ -463,7 +472,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths2.at(idxLayer); - caloLayer.distance = sensitiveBarrel2Rmin; + caloLayer.distance = layerInnerRadii2.at(idxLayer); caloLayer.sensitive_thickness = difference_bet_r1r2; caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; @@ -474,7 +483,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths3.at(idxLayer); - caloLayer.distance = sensitiveBarrel3Rmin; + caloLayer.distance = layerInnerRadii3.at(idxLayer); caloLayer.sensitive_thickness = difference_bet_r1r2; caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; diff --git a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp index 2084146b8..98573707a 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp @@ -41,7 +41,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep xml_comp_t xSteelSupport = xmlDet.child(_Unicode(steel_support)); double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport << endmsg; + lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport / dd4hep::cm << endmsg; lLog << MSG::DEBUG << "steel support material: " << xSteelSupport.materialStr() << endmsg; double sensitiveBarrelRmin = xDimensions.rmin() + xFacePlate.thickness() + space; @@ -51,7 +51,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // NOTE: This assumes that both have the same dimensions! Dimension sequenceDimensions(sequences[1].dimensions()); double dzSequence = sequenceDimensions.dz(); - lLog << MSG::DEBUG << "sequence thickness (cm) " << dzSequence << endmsg; + lLog << MSG::DEBUG << "sequence thickness (cm) " << dzSequence / dd4hep::cm << endmsg; // calculate the number of sequences fitting in Z unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); @@ -64,6 +64,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep unsigned int numSequencesR = 0; double moduleDepth = 0.; std::vector layerDepths = std::vector(); + std::vector layerInnerRadii = std::vector(); for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { xml_comp_t layer = *it; Dimension layerDimension(layer.dimensions()); @@ -82,7 +83,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; - lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector << endmsg; + lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector / dd4hep::cm << endmsg; lLog << MSG::INFO << "correction of dz in cm (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; double rminSupport = sensitiveBarrelRmin + moduleDepth; @@ -152,15 +153,13 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep double rminLayer = sensitiveBarrelRmin + layerR; double rmaxLayer = sensitiveBarrelRmin + layerR + layerDepths.at(idxLayer); layerR += layerDepths.at(idxLayer); + layerInnerRadii.push_back(rminLayer); //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = idxLayer % 2; dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); - - lLog << MSG::INFO << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - + Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector - dZEndPlate - space ); Volume layerVolume("HCalLayerVol", layerShape, lcdd.air()); @@ -246,8 +245,8 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep for (unsigned int idxLayer = 0; idxLayer < layerDepths.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths.at(idxLayer); - caloLayer.distance = sensitiveBarrelRmin; // should this be always the radius of the first layer as it is now? - caloLayer.sensitive_thickness = difference_bet_r1r2; // not really sure what is this variable + caloLayer.distance = layerInnerRadii.at(idxLayer); // radius of the current layer + caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; From 43b7380e6543114acd3700dfbc4b3190d769813c Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Wed, 31 Jul 2024 17:30:17 +0200 Subject: [PATCH 015/133] implement comments and improve code readibility --- .../HCalEndcaps_ThreeParts_TileCal.xml | 10 ++-- .../HCalThreePartsEndcap_o1_v01_geo.cpp | 49 ++++++++++--------- .../calorimeter/HCalTileBarrel_o1_v01_geo.cpp | 22 ++++++--- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml index cc1e2190f..971b613a2 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml @@ -57,8 +57,8 @@ - @@ -74,7 +74,7 @@ @@ -82,7 +82,7 @@ @@ -90,7 +90,7 @@ diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp index e447069f4..05d428801 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp @@ -27,7 +27,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h // Make DetElement dd4hep::DetElement caloDetElem(detName, xmlDet.id()); - // Make volume that envelopes the whole barrel; set material to air + // Make volume that envelopes the whole endcap; set material to air Dimension dimensions(xmlDet.dimensions()); dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); @@ -46,7 +46,6 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h Dimension sensDetType = xmlElement.child(_Unicode(sensitive)); sensDet.setType(sensDetType.typeStr()); - // Dimension dimensions(xmlElement.child(_Unicode(dimensions))); xml_comp_t xEndPlate = xmlElement.child(_Unicode(end_plate)); double dZEndPlate = xEndPlate.thickness() / 2.; xml_comp_t xFacePlate = xmlElement.child(_Unicode(face_plate)); @@ -70,9 +69,19 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h // Hard-coded assumption that we have two different sequences for the modules std::vector sequences = {xmlElement.child(_Unicode(sequence_a)), xmlElement.child(_Unicode(sequence_b))}; - // NOTE: This assumes that both have the same dimensions! - Dimension sequenceDimensions(sequences[1].dimensions()); - double dzSequence = sequenceDimensions.dz(); + // Check if both sequences are present + if (!sequences[0] || !sequences[1]) { + lLog << MSG::ERROR << "The two sequences sequence_a and sequence_b must be present in the xml file." << endmsg; + throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); + } + // Check if both sequences have the same dimensions + Dimension dimensionsA(sequences[0].dimensions()); + Dimension dimensionsB(sequences[1].dimensions()); + if (dimensionsA.dz() != dimensionsB.dz()) { + lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); + } + double dzSequence = dimensionsB.dz(); lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; // calculate the number of modules fitting in Z @@ -87,7 +96,6 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h double moduleDepth2 = 0.; double moduleDepth3 = 0.; - // MM: using layers and Layers is not very fortunate std::vector layerDepths1 = std::vector(); std::vector layerDepths2 = std::vector(); std::vector layerDepths3 = std::vector(); @@ -96,24 +104,19 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h std::vector layerInnerRadii2 = std::vector(); std::vector layerInnerRadii3 = std::vector(); - // get all 'layer' children of the 'layers' tag - std::vector Layers; + // iterating over XML elements to retrieve all child elements of 'layers' for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ - Layers.push_back(xCompColl); - } - - for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it){ - xml_comp_t layer = *it; - Dimension layerDimension(layer.dimensions()); + xml_comp_t currentLayer = xCompColl; + Dimension layerDimension(currentLayer.dimensions()); numSequencesR1 += layerDimension.nmodules(); - numSequencesR2 += layerDimension.nModules(); + numSequencesR2 += layerDimension.nsegments(); numSequencesR3 += layerDimension.nPads(); for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++){ moduleDepth1 += layerDimension.dr(); layerDepths1.push_back(layerDimension.dr()); } - for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++){ + for (int nLayer = 0; nLayer < layerDimension.nsegments(); nLayer++){ moduleDepth2 += layerDimension.dr(); layerDepths2.push_back(layerDimension.dr()); } @@ -147,15 +150,15 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h lLog << MSG::INFO << "dz third part EC:" << dzDetector2 * 2 << endmsg; - for (int iSign = 0; iSign < 2; iSign++){ + for (int iSign = -1; iSign < 2; iSign+=2){ int sign; - if(iSign == 0){ - sign = +1; - lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; + if(iSign < 0){ + sign = -1; + lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; } else{ - sign = -1; - lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; + sign = +1; + lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; } // Add structural support made of steel inside of HCal DetElement facePlate1(caloDetElem, "FacePlate_" + std::to_string(1 * sign), 0); @@ -441,7 +444,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h Volume motherVol = lcdd.pickMotherVolume(caloDetElem); PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); - placedHCal.addPhysVolID("system", xmlDet.id()); + placedHCal.addPhysVolID("system", caloDetElem.id()); caloDetElem.setPlacement(placedHCal); diff --git a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp index 98573707a..2a8815251 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp @@ -48,10 +48,20 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // Hard-coded assumption that we have two different sequences for the modules std::vector sequences = {xmlDet.child(_Unicode(sequence_a)), xmlDet.child(_Unicode(sequence_b))}; - // NOTE: This assumes that both have the same dimensions! - Dimension sequenceDimensions(sequences[1].dimensions()); - double dzSequence = sequenceDimensions.dz(); - lLog << MSG::DEBUG << "sequence thickness (cm) " << dzSequence / dd4hep::cm << endmsg; + // Check if both sequences are present + if (!sequences[0] || !sequences[1]) { + lLog << MSG::ERROR << "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file." << endmsg; + throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); + } + // Check if both sequences have the same dimensions + Dimension dimensionsA(sequences[0].dimensions()); + Dimension dimensionsB(sequences[1].dimensions()); + if (dimensionsA.dz() != dimensionsB.dz()) { + lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); + } + double dzSequence = dimensionsB.dz(); + lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; // calculate the number of sequences fitting in Z unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); @@ -226,7 +236,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep Volume motherVol = lcdd.pickMotherVolume(caloDetElem); motherVol.setVisAttributes(lcdd.invisible()); PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVolume); - envelopePhysVol.addPhysVolID("system", xmlDet.id()); + envelopePhysVol.addPhysVolID("system", caloDetElem.id()); caloDetElem.setPlacement(envelopePhysVol); @@ -236,7 +246,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep caloDetElem.addExtension(caloData); caloData->extent[0] = sensitiveBarrelRmin; - caloData->extent[1] = sensitiveBarrelRmax; // or r_max ? + caloData->extent[1] = sensitiveBarrelRmax; caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 caloData->extent[3] = dzDetector; From 9fe397e6262162cc096904ac4c8579b940664a9f Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Fri, 2 Aug 2024 20:46:43 +0200 Subject: [PATCH 016/133] fix failing test and remove unused phi segmentation --- .../ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml | 6 +++--- .../ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml | 6 +++--- FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml | 5 ----- .../ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml | 4 ---- detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp | 6 +++--- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml index c5cbe72a7..5531d85db 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml @@ -71,7 +71,7 @@ @@ -79,7 +79,7 @@ @@ -87,7 +87,7 @@ diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml index c5cbe72a7..5531d85db 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml @@ -71,7 +71,7 @@ @@ -79,7 +79,7 @@ @@ -87,7 +87,7 @@ diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml index 714fffbe1..0c051c39b 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml @@ -52,11 +52,6 @@ system:4,layer:5,theta:9,phi:10 - - - - system:4,layer:5,row:9,theta:0,phi:10 - diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml index 971b613a2..b63d439bd 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml @@ -51,10 +51,6 @@ system:4,type:2,layer:5,theta:11,phi:10 - - - system:4,type:2,layer:5,row:9,theta:0,phi:10 - - - system:4,type:2,layer:5,row:9,theta:11,phi:10 + + system:4,type:3,layer:6,row:11,theta:11,phi:10 - - system:4,type:2,layer:5,theta:11,phi:10 + + system:4,type:3,layer:6,theta:11,phi:10 diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp index 416570235..88af1f401 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp @@ -89,9 +89,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); - unsigned int numSequencesR1 = 0; - unsigned int numSequencesR2 = 0; - unsigned int numSequencesR3 = 0; + unsigned int numLayersR1 = 0; + unsigned int numLayersR2 = 0; + unsigned int numLayersR3 = 0; double moduleDepth1 = 0.; double moduleDepth2 = 0.; double moduleDepth3 = 0.; @@ -108,9 +108,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ xml_comp_t currentLayer = xCompColl; Dimension layerDimension(currentLayer.dimensions()); - numSequencesR1 += layerDimension.nmodules(); - numSequencesR2 += layerDimension.nsegments(); - numSequencesR3 += layerDimension.nPads(); + numLayersR1 += layerDimension.nmodules(); + numLayersR2 += layerDimension.nsegments(); + numLayersR3 += layerDimension.nPads(); for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++){ moduleDepth1 += layerDimension.dr(); @@ -126,16 +126,16 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h } } - lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numSequencesR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numSequencesR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numSequencesR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numLayersR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numLayersR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numLayersR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; - lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numSequencesR1 << " layers in Rho, " << numSequencesR1 * numSequencesZ1 << " tiles" << endmsg; - lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numSequencesR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; + lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numLayersR1 << " layers in Rho, " << numLayersR1 * numSequencesZ1 << " tiles" << endmsg; + lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numLayersR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; - lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numSequencesR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; + lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numLayersR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; - lLog << MSG::INFO << "number of channels: " << (numSequencesR1 * numSequencesZ1) + (numSequencesR2 * numSequencesZ2) + (numSequencesR3 * numSequencesZ3) << endmsg; + lLog << MSG::INFO << "number of channels: " << (numLayersR1 * numSequencesZ1) + (numLayersR2 * numSequencesZ2) + (numLayersR3 * numSequencesZ3) << endmsg; // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; @@ -147,7 +147,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 << endmsg; lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 << endmsg; - lLog << MSG::INFO << "dz third part EC:" << dzDetector2 * 2 << endmsg; + lLog << MSG::INFO << "dz third part EC:" << dzDetector3 * 2 << endmsg; for (int iSign = -1; iSign < 2; iSign+=2){ @@ -232,7 +232,7 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, lcdd.air()); lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); Volume layerVolume("HCalECLayerVol1", layerShape, lcdd.air()); @@ -474,7 +474,6 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths2.at(idxLayer); - caloLayer.distance = layerInnerRadii2.at(idxLayer); caloLayer.sensitive_thickness = difference_bet_r1r2; caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; @@ -485,7 +484,6 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { const double difference_bet_r1r2 = layerDepths3.at(idxLayer); - caloLayer.distance = layerInnerRadii3.at(idxLayer); caloLayer.sensitive_thickness = difference_bet_r1r2; caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; diff --git a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp index 2a8815251..c6f359dd3 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp @@ -71,25 +71,25 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl) { Layers.push_back(xCompColl); } - unsigned int numSequencesR = 0; + unsigned int numLayersR = 0; double moduleDepth = 0.; std::vector layerDepths = std::vector(); std::vector layerInnerRadii = std::vector(); for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { xml_comp_t layer = *it; Dimension layerDimension(layer.dimensions()); - numSequencesR += layerDimension.nModules(); + numLayersR += layerDimension.nModules(); for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++) { moduleDepth += layerDimension.dr(); layerDepths.push_back(layerDimension.dr()); } } - lLog << MSG::DEBUG << "retrieved number of radial layers: " << numSequencesR + lLog << MSG::DEBUG << "retrieved number of radial layers: " << numLayersR << " , which end up to a full module depth in rho of " << moduleDepth << " cm" << endmsg; lLog << MSG::DEBUG << "retrieved number of radial layers: " << layerDepths.size() << endmsg; - lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numSequencesR - << " radial layers, in total " << numSequencesR * numSequencesZ << " tiles" << endmsg; + lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numLayersR + << " radial layers, in total " << numLayersR * numSequencesZ << " tiles" << endmsg; // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; @@ -219,7 +219,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep } // Place det elements wihtin each other to recover volume positions later via cellID - for (uint iLayer = 0; iLayer < numSequencesR; iLayer++) { + for (uint iLayer = 0; iLayer < numLayersR; iLayer++) { DetElement layerDet(caloDetElem, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); layerDet.setPlacement(layers[iLayer]); From 4650a4bb6e7206d845cfaab2bac7410026a2a7e3 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Wed, 7 Aug 2024 17:31:59 +0200 Subject: [PATCH 018/133] keep ALLEGRO v03 xml file unchanged --- .../FCCee_HCalEndcaps_ThreeParts_TileCal.xml | 6 +- .../HCalEndcaps_ThreeParts_TileCal.xml | 6 +- .../compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 2 +- .../HCalEndcaps_ThreeParts_TileCal.xml | 33 +- .../HCalEndcaps_ThreeParts_TileCal_v02.xml | 140 +++ .../HCalThreePartsEndcap_o1_v01_geo.cpp | 910 +++++++++--------- .../HCalThreePartsEndcap_o1_v02_geo.cpp | 497 ++++++++++ 7 files changed, 1101 insertions(+), 493 deletions(-) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v02.xml create mode 100644 detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml index 5531d85db..c5cbe72a7 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v01/FCCee_HCalEndcaps_ThreeParts_TileCal.xml @@ -71,7 +71,7 @@ @@ -79,7 +79,7 @@ @@ -87,7 +87,7 @@ diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml index 5531d85db..c5cbe72a7 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v02/HCalEndcaps_ThreeParts_TileCal.xml @@ -71,7 +71,7 @@ @@ -79,7 +79,7 @@ @@ -87,7 +87,7 @@ diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index 7606b7f23..190b83188 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -45,7 +45,7 @@ - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml index 45069ec3b..c5cbe72a7 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml @@ -44,19 +44,20 @@ - - system:4,type:3,layer:6,row:11,theta:11,phi:10 + + system:4,type:2,layer:5,row:9,eta:11,phi:10 - - - system:4,type:3,layer:6,theta:11,phi:10 + + + system:4,type:2,layer:4,eta:11,phi:10 + + + + + system:4,type:2,layer:5,row:9,eta:10,phi:10 - - @@ -69,25 +70,25 @@ diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v02.xml new file mode 100644 index 000000000..06fa8d510 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v02.xml @@ -0,0 +1,140 @@ + + + + HCal layout based on ATLAS HCal, with realistic longitudinal segmentation and steel support + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,type:3,layer:6,row:11,theta:11,phi:10 + + + + system:4,type:3,layer:6,theta:11,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp index 88af1f401..34544c2e2 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v01_geo.cpp @@ -1,497 +1,467 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" -#include // todo: remove gaudi logging and properly capture output #define endmsg std::endl #define lLog std::cout namespace MSG { -const std::string ERROR = "createHCalThrePartsEndcap ERROR "; -const std::string DEBUG = "createHCalThrePartsEndcap DEBUG "; -const std::string INFO = "createHCalThrePartsEndcap INFO "; +const std::string DEBUG = " Debug: "; +const std::string INFO = " Info: "; } using dd4hep::Volume; using dd4hep::DetElement; using dd4hep::xml::Dimension; using dd4hep::PlacedVolume; -using xml_comp_t = dd4hep::xml::Component; -using xml_det_t = dd4hep::xml::DetElement; -using xml_h = dd4hep::xml::Handle_t; namespace det { -static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4hep::SensitiveDetector sensDet){ - xml_det_t xmlDet = xmlElement; - std::string detName = xmlDet.nameStr(); - - // Make DetElement - dd4hep::DetElement caloDetElem(detName, xmlDet.id()); - - // Make volume that envelopes the whole endcap; set material to air - Dimension dimensions(xmlDet.dimensions()); - - dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); - dd4hep::Tube negative1(dimensions.rmin(), dimensions.rmax1(), (dimensions.offset() - dimensions.width())); - dd4hep::Tube negative2(dimensions.rmin(), dimensions.rmin1(), (dimensions.z_offset() - dimensions.dz())); - dd4hep::Tube negative3(dimensions.rmin(), dimensions.rmin2(), (dimensions.v_offset() - dimensions.z_length())); - - dd4hep::SubtractionSolid envelopeShapeTmp1(envelope, negative1); - dd4hep::SubtractionSolid envelopeShapeTmp2(envelopeShapeTmp1, negative2); - dd4hep::SubtractionSolid envelopeShape(envelopeShapeTmp2, negative3); - - Volume envelopeVolume(detName + "_volume", envelopeShape, lcdd.air()); - envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); - - // Set sensitive detector type - Dimension sensDetType = xmlElement.child(_Unicode(sensitive)); - sensDet.setType(sensDetType.typeStr()); - - xml_comp_t xEndPlate = xmlElement.child(_Unicode(end_plate)); - double dZEndPlate = xEndPlate.thickness() / 2.; - xml_comp_t xFacePlate = xmlElement.child(_Unicode(face_plate)); - double dRhoFacePlate = xFacePlate.thickness() / 2.; - xml_comp_t xSpace = xmlElement.child(_Unicode(plate_space)); // to avoid overlaps - double space = xSpace.thickness(); - xml_comp_t xSteelSupport = xmlElement.child(_Unicode(steel_support)); - double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; - lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; - - // Calculate sensitive barrel dimensions - double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; - double sensitiveBarrel2Rmin = dimensions.rmin2() + 2 * dRhoFacePlate + space; - double sensitiveBarrel3Rmin = dimensions.rmin() + 2 * dRhoFacePlate + space; - - // Offset in z is given as distance from 0 to the middle of the Calorimeter volume - double extBarrelOffset1 = dimensions.offset(); - double extBarrelOffset2 = dimensions.z_offset(); - double extBarrelOffset3 = dimensions.v_offset(); - - // Hard-coded assumption that we have two different sequences for the modules - std::vector sequences = {xmlElement.child(_Unicode(sequence_a)), xmlElement.child(_Unicode(sequence_b))}; - // Check if both sequences are present - if (!sequences[0] || !sequences[1]) { - lLog << MSG::ERROR << "The two sequences sequence_a and sequence_b must be present in the xml file." << endmsg; - throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); +void buildEC(dd4hep::Detector& aLcdd, dd4hep::SensitiveDetector& aSensDet, dd4hep::Volume& aEnvelope, + dd4hep::DetElement& aHCal, xml_det_t aXmlElement, int sign) { + + dd4hep::SensitiveDetector sensDet = aSensDet; + Dimension sensDetType = aXmlElement.child(_Unicode(sensitive)); + sensDet.setType(sensDetType.typeStr()); + + Dimension dimensions(aXmlElement.child(_Unicode(dimensions))); + xml_comp_t xEndPlate = aXmlElement.child(_Unicode(end_plate)); + double dZEndPlate = xEndPlate.thickness() / 2.; + xml_comp_t xFacePlate = aXmlElement.child(_Unicode(face_plate)); + double dRhoFacePlate = xFacePlate.thickness() / 2.; + xml_comp_t xSpace = aXmlElement.child(_Unicode(plate_space)); // to avoid overlaps + double space = xSpace.thickness(); + xml_comp_t xSteelSupport = aXmlElement.child(_Unicode(steel_support)); + double dSteelSupport = xSteelSupport.thickness(); + lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; + lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; + + double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; + double sensitiveBarrel2Rmin = dimensions.rmin2() + 2 * dRhoFacePlate + space; + double sensitiveBarrel3Rmin = dimensions.rmin() + 2 * dRhoFacePlate + space; + + // Offset in z is given as distance from 0 to the middle of the Calorimeter volume + double extBarrelOffset1 = dimensions.offset(); + double extBarrelOffset2 = dimensions.z_offset(); + double extBarrelOffset3 = dimensions.v_offset(); + + // Hard-coded assumption that we have two different sequences for the modules + std::vector sequences = {aXmlElement.child(_Unicode(sequence_a)), aXmlElement.child(_Unicode(sequence_b))}; + // NOTE: This assumes that both have the same dimensions! + Dimension sequenceDimensions(sequences[1].dimensions()); + double dzSequence = sequenceDimensions.dz(); + lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + + // calculate the number of modules fitting in Z + unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); + + unsigned int numSequencesR1 = 0; + unsigned int numSequencesR2 = 0; + unsigned int numSequencesR3 = 0; + double moduleDepth1 = 0.; + double moduleDepth2 = 0.; + double moduleDepth3 = 0.; + std::vector layerDepths1 = std::vector(); + std::vector layerDepths2 = std::vector(); + std::vector layerDepths3 = std::vector(); + + // get all 'layer' children of the 'layers' tag + std::vector Layers; + for (xml_coll_t xCompColl(aXmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; + ++xCompColl) { + Layers.push_back(xCompColl); + } + + for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { + xml_comp_t layer = *it; + Dimension layerDimension(layer.dimensions()); + numSequencesR1 += layerDimension.nmodules(); + numSequencesR2 += layerDimension.nModules(); + numSequencesR3 += layerDimension.nPads(); + for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++) { + moduleDepth1 += layerDimension.dr(); + layerDepths1.push_back(layerDimension.dr()); } - // Check if both sequences have the same dimensions - Dimension dimensionsA(sequences[0].dimensions()); - Dimension dimensionsB(sequences[1].dimensions()); - if (dimensionsA.dz() != dimensionsB.dz()) { - lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; - throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); + for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++) { + moduleDepth2 += layerDimension.dr(); + layerDepths2.push_back(layerDimension.dr()); } - double dzSequence = dimensionsB.dz(); - lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; - - // calculate the number of modules fitting in Z - unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); - unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); - unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); - - unsigned int numLayersR1 = 0; - unsigned int numLayersR2 = 0; - unsigned int numLayersR3 = 0; - double moduleDepth1 = 0.; - double moduleDepth2 = 0.; - double moduleDepth3 = 0.; - - std::vector layerDepths1 = std::vector(); - std::vector layerDepths2 = std::vector(); - std::vector layerDepths3 = std::vector(); - - std::vector layerInnerRadii1 = std::vector(); - std::vector layerInnerRadii2 = std::vector(); - std::vector layerInnerRadii3 = std::vector(); - - // iterating over XML elements to retrieve all child elements of 'layers' - for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ - xml_comp_t currentLayer = xCompColl; - Dimension layerDimension(currentLayer.dimensions()); - numLayersR1 += layerDimension.nmodules(); - numLayersR2 += layerDimension.nsegments(); - numLayersR3 += layerDimension.nPads(); - - for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++){ - moduleDepth1 += layerDimension.dr(); - layerDepths1.push_back(layerDimension.dr()); - } - for (int nLayer = 0; nLayer < layerDimension.nsegments(); nLayer++){ - moduleDepth2 += layerDimension.dr(); - layerDepths2.push_back(layerDimension.dr()); - } - for (int nLayer = 0; nLayer < layerDimension.nPads(); nLayer++){ - moduleDepth3 += layerDimension.dr(); - layerDepths3.push_back(layerDimension.dr()); - } + for (int nLayer = 0; nLayer < layerDimension.nPads(); nLayer++) { + moduleDepth3 += layerDimension.dr(); + layerDepths3.push_back(layerDimension.dr()); } - - lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numLayersR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numLayersR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numLayersR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; - - lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numLayersR1 << " layers in Rho, " << numLayersR1 * numSequencesZ1 << " tiles" << endmsg; - lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numLayersR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; - - lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numLayersR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; - - lLog << MSG::INFO << "number of channels: " << (numLayersR1 * numSequencesZ1) + (numLayersR2 * numSequencesZ2) + (numLayersR3 * numSequencesZ3) << endmsg; - - // Calculate correction along z based on the module size (can only have natural number of modules) - double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; - double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; - double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; - - lLog << MSG::INFO << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 << endmsg; - lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 << endmsg; - lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 << endmsg; - lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 << endmsg; - - lLog << MSG::INFO << "dz third part EC:" << dzDetector3 * 2 << endmsg; - - - for (int iSign = -1; iSign < 2; iSign+=2){ - int sign; - if(iSign < 0){ - sign = -1; - lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; - } - else{ - sign = +1; - lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; - } - // Add structural support made of steel inside of HCal - DetElement facePlate1(caloDetElem, "FacePlate_" + std::to_string(1 * sign), 0); - dd4hep::Tube facePlateShape1(dimensions.rmin1(), (sensitiveBarrel1Rmin - space), (dzDetector1 - 2 * dZEndPlate - space)); - Volume facePlateVol1("facePlateVol1", facePlateShape1, lcdd.material(xFacePlate.materialStr())); - facePlateVol1.setVisAttributes(lcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace1(0, 0, sign * extBarrelOffset1); - - // Faceplate for 2nd part of extended Barrel - DetElement facePlate2(caloDetElem, "FacePlate_" + std::to_string(2 * sign), 0); - dd4hep::Tube facePlateShape2(dimensions.rmin2(), (sensitiveBarrel2Rmin - space), - dzDetector2); - Volume facePlateVol2("facePlateVol2", facePlateShape2, lcdd.material(xFacePlate.materialStr())); - facePlateVol2.setVisAttributes(lcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace2(0, 0, sign * extBarrelOffset2); - - // Faceplate for 3rd part of extended Barrel - DetElement facePlate3(caloDetElem, "FacePlate_" + std::to_string(3 * sign), 0); - dd4hep::Tube facePlateShape3(dimensions.rmin(), (sensitiveBarrel3Rmin - space), - (dzDetector3 - 2 * dZEndPlate - space)); - Volume facePlateVol3("facePlateVol3", facePlateShape3, lcdd.material(xFacePlate.materialStr())); - facePlateVol3.setVisAttributes(lcdd, xFacePlate.visStr()); - dd4hep::Position offsetFace3(0, 0, sign * extBarrelOffset3); - - PlacedVolume placedFacePlate1 = envelopeVolume.placeVolume(facePlateVol1, offsetFace1); - facePlate1.setPlacement(placedFacePlate1); - PlacedVolume placedFacePlate2 = envelopeVolume.placeVolume(facePlateVol2, offsetFace2); - facePlate2.setPlacement(placedFacePlate2); - PlacedVolume placedFacePlate3 = envelopeVolume.placeVolume(facePlateVol3, offsetFace3); - facePlate3.setPlacement(placedFacePlate3); - - // Add structural support made of steel at both ends of extHCal - dd4hep::Tube endPlateShape1(dimensions.rmin1(), (dimensions.rmax1() - dSteelSupport), dZEndPlate); - Volume endPlateVol1("endPlateVol1", endPlateShape1, lcdd.material(xEndPlate.materialStr())); - endPlateVol1.setVisAttributes(lcdd, xEndPlate.visStr()); - dd4hep::Tube endPlateShape3(dimensions.rmin(), (dimensions.rmax() - dSteelSupport), dZEndPlate); - Volume endPlateVol3("endPlateVol3", endPlateShape3, lcdd.material(xEndPlate.materialStr())); - endPlateVol3.setVisAttributes(lcdd, xEndPlate.visStr()); - - // Endplates placed for the extended Barrels in front and in the back to the central Barrel - DetElement endPlatePos(caloDetElem, "endPlate_" + std::to_string(1 * sign), 0); - dd4hep::Position posOffset(0, 0, sign * (extBarrelOffset3 + dzDetector3 - dZEndPlate)); - PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol3, posOffset); - endPlatePos.setPlacement(placedEndPlatePos); - - DetElement endPlateNeg(caloDetElem, "endPlate_" + std::to_string(2 * sign), 0); - dd4hep::Position negOffset(0, 0, sign * (extBarrelOffset1 - dzDetector1 + dZEndPlate)); - PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol1, negOffset); - endPlateNeg.setPlacement(placedEndPlateNeg); - - std::vector layers; - layers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - std::vector > seqInLayers; - seqInLayers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - std::vector tilesPerLayer; - tilesPerLayer.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); - - // loop over R ("layers") - double layerR = 0.; - for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer){ - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel1Rmin + layerR; - double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); - layerR += layerDepths1.at(idxLayer); - layerInnerRadii1.push_back(rminLayer); - - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; - - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, lcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); - Volume layerVolume("HCalECLayerVol1", layerShape, lcdd.air()); - - layerVolume.setVisAttributes(lcdd.invisible()); - unsigned int idxSubMod = 0; - - dd4hep::Position moduleOffset1 (0,0,sign * extBarrelOffset1); - - dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset1); - unsigned int type1 = 0; - if (sign<0){ - type1 = 3; - } - placedLayerVolume.addPhysVolID("type", type1); // First module type=0,3 in front of second +/- - placedLayerVolume.addPhysVolID("layer", idxLayer); - - layers.push_back(placedLayerVolume); + } + + lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numSequencesR1 + << " , which end up to a full module depth in rho of " << moduleDepth1 << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << layerDepths1.size() << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numSequencesR2 + << " , which end up to a full module depth in rho of " << moduleDepth2 << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << layerDepths2.size() << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numSequencesR3 + << " , which end up to a full module depth in rho of " << moduleDepth3 << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << layerDepths3.size() << endmsg; + + lLog << MSG::INFO << "constructing first part EC: with offset " << extBarrelOffset1 << ": "<< numSequencesZ1 + << " rings in Z, " << numSequencesR1 << " layers in Rho, " << numSequencesR1 * numSequencesZ1 + << " tiles" << endmsg; + + lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << ": " << numSequencesZ2 + << " rings in Z, " << numSequencesR2 << " layers in Rho, " + << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; + + lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << ": " << numSequencesZ3 + << " rings in Z, " << numSequencesR3 << " layers in Rho, " + << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; + + lLog << MSG::INFO << "number of channels: " + << (numSequencesR1 * numSequencesZ1) + (numSequencesR2 * numSequencesZ2) + (numSequencesR3 * numSequencesZ3) + << endmsg; + + // Calculate correction along z based on the module size (can only have natural number of modules) + double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; + lLog << MSG::INFO + << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 + << endmsg; + double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; + lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 + << endmsg; + lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 + << endmsg; + lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 + << endmsg; + + double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; + lLog << MSG::INFO << "dz third part EC:" << dzDetector2 * 2 + << endmsg; + + // Add structural support made of steel inside of HCal + DetElement facePlate1(aHCal, "FacePlate_" + std::to_string(1 * sign), 0); + dd4hep::Tube facePlateShape1(dimensions.rmin1(), (sensitiveBarrel1Rmin - space), + (dzDetector1 - 2 * dZEndPlate - space)); + Volume facePlateVol1("facePlateVol1", facePlateShape1, aLcdd.material(xFacePlate.materialStr())); + facePlateVol1.setVisAttributes(aLcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace1(0, 0, sign * extBarrelOffset1); + + // Faceplate for 2nd part of extended Barrel + DetElement facePlate2(aHCal, "FacePlate_" + std::to_string(2 * sign), 0); + dd4hep::Tube facePlateShape2(dimensions.rmin2(), (sensitiveBarrel2Rmin - space), + dzDetector2); + Volume facePlateVol2("facePlateVol2", facePlateShape2, aLcdd.material(xFacePlate.materialStr())); + facePlateVol2.setVisAttributes(aLcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace2(0, 0, sign * extBarrelOffset2); + + // Faceplate for 3rd part of extended Barrel + DetElement facePlate3(aHCal, "FacePlate_" + std::to_string(3 * sign), 0); + dd4hep::Tube facePlateShape3(dimensions.rmin(), (sensitiveBarrel3Rmin - space), + (dzDetector3 - 2 * dZEndPlate - space)); + Volume facePlateVol3("facePlateVol3", facePlateShape3, aLcdd.material(xFacePlate.materialStr())); + facePlateVol3.setVisAttributes(aLcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace3(0, 0, sign * extBarrelOffset3); + + PlacedVolume placedFacePlate1 = aEnvelope.placeVolume(facePlateVol1, offsetFace1); + facePlate1.setPlacement(placedFacePlate1); + PlacedVolume placedFacePlate2 = aEnvelope.placeVolume(facePlateVol2, offsetFace2); + facePlate2.setPlacement(placedFacePlate2); + PlacedVolume placedFacePlate3 = aEnvelope.placeVolume(facePlateVol3, offsetFace3); + facePlate3.setPlacement(placedFacePlate3); + + // Add structural support made of steel at both ends of extHCal + dd4hep::Tube endPlateShape1(dimensions.rmin1(), (dimensions.rmax1() - dSteelSupport), dZEndPlate); + Volume endPlateVol1("endPlateVol1", endPlateShape1, aLcdd.material(xEndPlate.materialStr())); + endPlateVol1.setVisAttributes(aLcdd, xEndPlate.visStr()); + dd4hep::Tube endPlateShape3(dimensions.rmin(), (dimensions.rmax() - dSteelSupport), dZEndPlate); + Volume endPlateVol3("endPlateVol3", endPlateShape3, aLcdd.material(xEndPlate.materialStr())); + endPlateVol3.setVisAttributes(aLcdd, xEndPlate.visStr()); + + // Endplates placed for the extended Barrels in front and in the back to the central Barrel + DetElement endPlatePos(aHCal, "endPlate_" + std::to_string(1 * sign), 0); + dd4hep::Position posOffset(0, 0, sign * (extBarrelOffset3 + dzDetector3 - dZEndPlate)); + PlacedVolume placedEndPlatePos = aEnvelope.placeVolume(endPlateVol3, posOffset); + endPlatePos.setPlacement(placedEndPlatePos); + + DetElement endPlateNeg(aHCal, "endPlate_" + std::to_string(2 * sign), 0); + dd4hep::Position negOffset(0, 0, sign * (extBarrelOffset1 - dzDetector1 + dZEndPlate)); + PlacedVolume placedEndPlateNeg = aEnvelope.placeVolume(endPlateVol1, negOffset); + endPlateNeg.setPlacement(placedEndPlateNeg); + + std::vector layers; + layers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector > seqInLayers; + seqInLayers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector tilesPerLayer; + tilesPerLayer.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + + // loop over R ("layers") + double layerR = 0.; + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel1Rmin + layerR; + double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); + layerR += layerDepths1.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, aLcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); + Volume layerVolume("HCalECLayerVol1", layerShape, aLcdd.air()); + + + layerVolume.setVisAttributes(aLcdd.invisible()); + unsigned int idxSubMod = 0; + + dd4hep::Position moduleOffset1 (0,0,sign * extBarrelOffset1); + + dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset1); + unsigned int type1 = 0; + if (sign<0) { + type1 = 3; + } + placedLayerVolume.addPhysVolID("type", type1); // First module type=0,3 in front of second +/- + placedLayerVolume.addPhysVolID("layer", idxLayer); + layers.push_back(placedLayerVolume); - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_"+ xComp.materialStr(), tileShape, lcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(lcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()){ - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); - } - - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector1 + 0.5 * dzSequence; //2*dZEndPlate + space + 0.5 * dzSequence; - - for (uint numSeq=0; numSeq < numSequencesZ1; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; - } - seqInLayers.push_back(seqs); - } // layers loop - - - layerR = 0.; - // Placement of subWedges in Wedge, 2nd part - for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer){ - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel2Rmin + layerR; - double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); - layerR += layerDepths2.at(idxLayer); - layerInnerRadii2.push_back(rminLayer); - - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; - - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, lcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); - Volume layerVolume("HCalECLayerVol2", layerShape, lcdd.air()); - - layerVolume.setVisAttributes(lcdd.invisible()); - unsigned int idxSubMod = 0; - - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_", tileShape, lcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(lcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()){ - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); - } // close first Z loop - - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector2 + 0.5 * dzSequence; //(dzSequence * 0.5); - - for (uint numSeq=0; numSeq < numSequencesZ2; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; - } - seqInLayers.push_back(seqs); - - dd4hep::Position moduleOffset2 (0, 0, sign * extBarrelOffset2); - dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset2); - unsigned int type2 = 1; - if (sign<0){ - type2 = 4; - } - placedLayerVolume.addPhysVolID("type", type2); // Second module type=1,4 behind the first +/- - placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + idxLayer); - layers.push_back(placedLayerVolume); - } - - layerR = 0.; - // Placement of subWedges in Wedge, 3th part - for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer){ - // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) - double rminLayer = sensitiveBarrel3Rmin + layerR; - double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); - layerR += layerDepths3.at(idxLayer); - layerInnerRadii3.push_back(rminLayer); - - - //alternate: even layers consist of tile sequence b, odd layer of tile sequence a - unsigned int sequenceIdx = (idxLayer+1) % 2; - - dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, lcdd.air()); - - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - - dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); - Volume layerVolume("HCalECLayerVol3", layerShape, lcdd.air()); - - layerVolume.setVisAttributes(lcdd.invisible()); - unsigned int idxSubMod = 0; - - double tileZOffset = - 0.5* dzSequence; - - // first Z loop (tiles that make up a sequence) - for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ - xml_comp_t xComp = xCompColl; - dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); - - Volume tileVol("HCalECTileVol_" , tileShape, lcdd.material(xComp.materialStr())); - tileVol.setVisAttributes(lcdd, xComp.visStr()); - - dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); - dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); - - if (xComp.isSensitive()){ - tileVol.setSensitiveDetector(sensDet); - tilesPerLayer.push_back(placedTileVol); - } - tileZOffset += xComp.thickness(); - } - - // second z loop (place sequences in layer) - std::vector seqs; - double zOffset = - dzDetector3 + 0.5 * dzSequence; //2*dZEndPlate + space + (dzSequence * 0.5); - - for (uint numSeq=0; numSeq < numSequencesZ3; numSeq++){ - dd4hep::Position tileSequencePosition(0, 0, zOffset); - dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); - placedTileSequenceVolume.addPhysVolID("row", numSeq); - seqs.push_back(placedTileSequenceVolume); - zOffset += dzSequence; - } - seqInLayers.push_back(seqs); - - dd4hep::Position moduleOffset3 (0, 0, sign * extBarrelOffset3); - dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset3); - unsigned int type3 = 2; - if (sign<0){ - type3 = 5; - } - placedLayerVolume.addPhysVolID("type", type3); // Second module type=2,5 behind the first +/- - placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + layerDepths2.size() + idxLayer); - layers.push_back(placedLayerVolume); - } // end loop placement of subwedges - - // Placement of DetElements - lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; - lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; - - // Place det elements wihtin each other to recover volume positions later via cellID - for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++){ - DetElement layerDet(caloDetElem, dd4hep::xml::_toString(sign*(iLayer+1), "layer%d"), sign*(iLayer+1)); - layerDet.setPlacement(layers[iLayer]); - - for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ - DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), sign*(iSeq+1)); - seqDet.setPlacement(seqInLayers[iLayer][iSeq]); - - DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), sign*(iSeq+1)); - tileDet.setPlacement(tilesPerLayer[iLayer]); - } - } - } // for signs loop - - // Place envelope volume - Volume motherVol = lcdd.pickMotherVolume(caloDetElem); - - PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); - placedHCal.addPhysVolID("system", caloDetElem.id()); - caloDetElem.setPlacement(placedHCal); - - - // Create caloData object - auto caloData = new dd4hep::rec::LayeredCalorimeterData; - caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::EndcapLayout; - caloDetElem.addExtension(caloData); - - caloData->extent[0] = sensitiveBarrel3Rmin; - caloData->extent[1] = sensitiveBarrel3Rmin + moduleDepth3; // - caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 - caloData->extent[3] = dzDetector1 + dzDetector2 + dzDetector3; - - dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; - - // IMPORTANT: the information below is used to calculate the cell position in CellPositionsHCalPhiThetaSegTool in k4RecCalorimeter - // if the definition distance or sensitive_thickness is modified, one also needs to modify CellPositionsHCalPhiThetaSegTool - for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { - const double difference_bet_r1r2 = layerDepths1.at(idxLayer); - caloLayer.distance = layerInnerRadii1.at(idxLayer); // radius of the current layer - caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer - caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; - caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; - - caloData->layers.push_back(caloLayer); + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; + ++xCompColl, ++idxSubMod) { + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_"+ xComp.materialStr() + , tileShape, + aLcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(aLcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()) { + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector1 + 0.5 * dzSequence; //2*dZEndPlate + space + 0.5 * dzSequence; + + for (uint numSeq=0; numSeq < numSequencesZ1; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; } + seqInLayers.push_back(seqs); + } + + + layerR = 0.; + // Placement of subWedges in Wedge, 2nd part + for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel2Rmin + layerR; + double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); + layerR += layerDepths2.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, aLcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; - for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { - const double difference_bet_r1r2 = layerDepths2.at(idxLayer); - caloLayer.distance = layerInnerRadii2.at(idxLayer); - caloLayer.sensitive_thickness = difference_bet_r1r2; - caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; - caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; - caloData->layers.push_back(caloLayer); + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); + Volume layerVolume("HCalECLayerVol2", layerShape, aLcdd.air()); + + layerVolume.setVisAttributes(aLcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; + ++xCompColl, ++idxSubMod) { + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_" + , tileShape, + aLcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(aLcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()) { + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); } - for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { - const double difference_bet_r1r2 = layerDepths3.at(idxLayer); - caloLayer.distance = layerInnerRadii3.at(idxLayer); - caloLayer.sensitive_thickness = difference_bet_r1r2; - caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; - caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector2 + 0.5 * dzSequence; //(dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ2; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); - caloData->layers.push_back(caloLayer); + dd4hep::Position moduleOffset2 (0, 0, sign * extBarrelOffset2); + dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset2); + unsigned int type2 = 1; + if (sign<0) { + type2 = 4; } - return caloDetElem; -} -}// namespace det + placedLayerVolume.addPhysVolID("type", type2); // Second module type=1,4 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + idxLayer); + layers.push_back(placedLayerVolume); + } + + layerR = 0.; + // Placement of subWedges in Wedge, 3th part + for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel3Rmin + layerR; + double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); + layerR += layerDepths3.at(idxLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, aLcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); + Volume layerVolume("HCalECLayerVol3", layerShape, aLcdd.air()); + + layerVolume.setVisAttributes(aLcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; + ++xCompColl, ++idxSubMod) { + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_" + , tileShape, + aLcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(aLcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()) { + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector3 + 0.5 * dzSequence; //2*dZEndPlate + space + (dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ3; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + + dd4hep::Position moduleOffset3 (0, 0, sign * extBarrelOffset3); + dd4hep::PlacedVolume placedLayerVolume = aEnvelope.placeVolume(layerVolume, moduleOffset3); + unsigned int type3 = 2; + if (sign<0) { + type3 = 5; + } + placedLayerVolume.addPhysVolID("type", type3); // Second module type=2,5 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + layerDepths2.size() + idxLayer); + layers.push_back(placedLayerVolume); + } + + // Placement of DetElements + lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; + lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; + + for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++) { + DetElement layerDet(aHCal, dd4hep::xml::_toString(sign*(iLayer+1), "layer%d"), sign*(iLayer+1)); + layerDet.setPlacement(layers[iLayer]); + + for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ + DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), sign*(iSeq+1)); + seqDet.setPlacement(seqInLayers[iLayer][iSeq]); + + DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), sign*(iSeq+1)); + tileDet.setPlacement(tilesPerLayer[iLayer]); + } + } + +} + +static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4hep::SensitiveDetector sensDet) { + + + xml_det_t xmlDet = xmlElement; + std::string detName = xmlDet.nameStr(); + + // Make DetElement + dd4hep::DetElement hCalEC(detName, xmlDet.id()); + + // Make volume that envelopes the whole barrel; set material to air + Dimension dimensions(xmlDet.dimensions()); + + dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); + dd4hep::Tube negative1(dimensions.rmin(), dimensions.rmax1(), (dimensions.offset() - dimensions.width())); + dd4hep::Tube negative2(dimensions.rmin(), dimensions.rmin1(), (dimensions.z_offset() - dimensions.dz())); + dd4hep::Tube negative3(dimensions.rmin(), dimensions.rmin2(), (dimensions.v_offset() - dimensions.z_length())); + dd4hep::SubtractionSolid envelopeShapeTmp1(envelope, negative1); + dd4hep::SubtractionSolid envelopeShapeTmp2(envelopeShapeTmp1, negative2); + dd4hep::SubtractionSolid envelopeShape(envelopeShapeTmp2, negative3); + + Volume envelopeVolume(detName + "_volume", envelopeShape, lcdd.air()); + envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); + + lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) + << endmsg; + buildEC(lcdd, sensDet, envelopeVolume, hCalEC, xmlElement, 1); + lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) + << endmsg; + buildEC(lcdd, sensDet, envelopeVolume, hCalEC, xmlElement, -1); + + // Place envelope volume + Volume motherVol = lcdd.pickMotherVolume(hCalEC); + + PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); + placedHCal.addPhysVolID("system", xmlDet.id()); + hCalEC.setPlacement(placedHCal); + + return hCalEC; +} +} // namespace hcal + DECLARE_DETELEMENT(CaloThreePartsEndcap_o1_v01, det::createHCalEC) diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp new file mode 100644 index 000000000..da2ec6af9 --- /dev/null +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp @@ -0,0 +1,497 @@ +// DD4hep +#include "DD4hep/DetFactoryHelper.h" +#include + +// todo: remove gaudi logging and properly capture output +#define endmsg std::endl +#define lLog std::cout +namespace MSG { +const std::string ERROR = "createHCalThrePartsEndcap ERROR "; +const std::string DEBUG = "createHCalThrePartsEndcap DEBUG "; +const std::string INFO = "createHCalThrePartsEndcap INFO "; +} + +using dd4hep::Volume; +using dd4hep::DetElement; +using dd4hep::xml::Dimension; +using dd4hep::PlacedVolume; +using xml_comp_t = dd4hep::xml::Component; +using xml_det_t = dd4hep::xml::DetElement; +using xml_h = dd4hep::xml::Handle_t; + +namespace det { +static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4hep::SensitiveDetector sensDet){ + xml_det_t xmlDet = xmlElement; + std::string detName = xmlDet.nameStr(); + + // Make DetElement + dd4hep::DetElement caloDetElem(detName, xmlDet.id()); + + // Make volume that envelopes the whole endcap; set material to air + Dimension dimensions(xmlDet.dimensions()); + + dd4hep::Tube envelope(dimensions.rmin(), dimensions.rmax1(), (dimensions.v_offset() + dimensions.z_length())); + dd4hep::Tube negative1(dimensions.rmin(), dimensions.rmax1(), (dimensions.offset() - dimensions.width())); + dd4hep::Tube negative2(dimensions.rmin(), dimensions.rmin1(), (dimensions.z_offset() - dimensions.dz())); + dd4hep::Tube negative3(dimensions.rmin(), dimensions.rmin2(), (dimensions.v_offset() - dimensions.z_length())); + + dd4hep::SubtractionSolid envelopeShapeTmp1(envelope, negative1); + dd4hep::SubtractionSolid envelopeShapeTmp2(envelopeShapeTmp1, negative2); + dd4hep::SubtractionSolid envelopeShape(envelopeShapeTmp2, negative3); + + Volume envelopeVolume(detName + "_volume", envelopeShape, lcdd.air()); + envelopeVolume.setVisAttributes(lcdd, dimensions.visStr()); + + // Set sensitive detector type + Dimension sensDetType = xmlElement.child(_Unicode(sensitive)); + sensDet.setType(sensDetType.typeStr()); + + xml_comp_t xEndPlate = xmlElement.child(_Unicode(end_plate)); + double dZEndPlate = xEndPlate.thickness() / 2.; + xml_comp_t xFacePlate = xmlElement.child(_Unicode(face_plate)); + double dRhoFacePlate = xFacePlate.thickness() / 2.; + xml_comp_t xSpace = xmlElement.child(_Unicode(plate_space)); // to avoid overlaps + double space = xSpace.thickness(); + xml_comp_t xSteelSupport = xmlElement.child(_Unicode(steel_support)); + double dSteelSupport = xSteelSupport.thickness(); + lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; + lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; + + // Calculate sensitive barrel dimensions + double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; + double sensitiveBarrel2Rmin = dimensions.rmin2() + 2 * dRhoFacePlate + space; + double sensitiveBarrel3Rmin = dimensions.rmin() + 2 * dRhoFacePlate + space; + + // Offset in z is given as distance from 0 to the middle of the Calorimeter volume + double extBarrelOffset1 = dimensions.offset(); + double extBarrelOffset2 = dimensions.z_offset(); + double extBarrelOffset3 = dimensions.v_offset(); + + // Hard-coded assumption that we have two different sequences for the modules + std::vector sequences = {xmlElement.child(_Unicode(sequence_a)), xmlElement.child(_Unicode(sequence_b))}; + // Check if both sequences are present + if (!sequences[0] || !sequences[1]) { + lLog << MSG::ERROR << "The two sequences sequence_a and sequence_b must be present in the xml file." << endmsg; + throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); + } + // Check if both sequences have the same dimensions + Dimension dimensionsA(sequences[0].dimensions()); + Dimension dimensionsB(sequences[1].dimensions()); + if (dimensionsA.dz() != dimensionsB.dz()) { + lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); + } + double dzSequence = dimensionsB.dz(); + lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + + // calculate the number of modules fitting in Z + unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ2 = static_cast((2 * dimensions.dz() - 2 * dZEndPlate - space) / dzSequence); + unsigned int numSequencesZ3 = static_cast((2 * dimensions.z_length() - 2 * dZEndPlate - space) / dzSequence); + + unsigned int numLayersR1 = 0; + unsigned int numLayersR2 = 0; + unsigned int numLayersR3 = 0; + double moduleDepth1 = 0.; + double moduleDepth2 = 0.; + double moduleDepth3 = 0.; + + std::vector layerDepths1 = std::vector(); + std::vector layerDepths2 = std::vector(); + std::vector layerDepths3 = std::vector(); + + std::vector layerInnerRadii1 = std::vector(); + std::vector layerInnerRadii2 = std::vector(); + std::vector layerInnerRadii3 = std::vector(); + + // iterating over XML elements to retrieve all child elements of 'layers' + for (xml_coll_t xCompColl(xmlElement.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl){ + xml_comp_t currentLayer = xCompColl; + Dimension layerDimension(currentLayer.dimensions()); + numLayersR1 += layerDimension.nmodules(); + numLayersR2 += layerDimension.nsegments(); + numLayersR3 += layerDimension.nPads(); + + for (int nLayer = 0; nLayer < layerDimension.nmodules(); nLayer++){ + moduleDepth1 += layerDimension.dr(); + layerDepths1.push_back(layerDimension.dr()); + } + for (int nLayer = 0; nLayer < layerDimension.nsegments(); nLayer++){ + moduleDepth2 += layerDimension.dr(); + layerDepths2.push_back(layerDimension.dr()); + } + for (int nLayer = 0; nLayer < layerDimension.nPads(); nLayer++){ + moduleDepth3 += layerDimension.dr(); + layerDepths3.push_back(layerDimension.dr()); + } + } + + lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numLayersR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numLayersR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numLayersR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; + + lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numLayersR1 << " layers in Rho, " << numLayersR1 * numSequencesZ1 << " tiles" << endmsg; + lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numLayersR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; + + lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numLayersR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; + + lLog << MSG::INFO << "number of channels: " << (numLayersR1 * numSequencesZ1) + (numLayersR2 * numSequencesZ2) + (numLayersR3 * numSequencesZ3) << endmsg; + + // Calculate correction along z based on the module size (can only have natural number of modules) + double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; + double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; + double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; + + lLog << MSG::INFO << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 << endmsg; + lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 << endmsg; + lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 << endmsg; + lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 << endmsg; + + lLog << MSG::INFO << "dz third part EC:" << dzDetector3 * 2 << endmsg; + + + for (int iSign = -1; iSign < 2; iSign+=2){ + int sign; + if(iSign < 0){ + sign = -1; + lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; + } + else{ + sign = +1; + lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; + } + // Add structural support made of steel inside of HCal + DetElement facePlate1(caloDetElem, "FacePlate_" + std::to_string(1 * sign), 0); + dd4hep::Tube facePlateShape1(dimensions.rmin1(), (sensitiveBarrel1Rmin - space), (dzDetector1 - 2 * dZEndPlate - space)); + Volume facePlateVol1("facePlateVol1", facePlateShape1, lcdd.material(xFacePlate.materialStr())); + facePlateVol1.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace1(0, 0, sign * extBarrelOffset1); + + // Faceplate for 2nd part of extended Barrel + DetElement facePlate2(caloDetElem, "FacePlate_" + std::to_string(2 * sign), 0); + dd4hep::Tube facePlateShape2(dimensions.rmin2(), (sensitiveBarrel2Rmin - space), + dzDetector2); + Volume facePlateVol2("facePlateVol2", facePlateShape2, lcdd.material(xFacePlate.materialStr())); + facePlateVol2.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace2(0, 0, sign * extBarrelOffset2); + + // Faceplate for 3rd part of extended Barrel + DetElement facePlate3(caloDetElem, "FacePlate_" + std::to_string(3 * sign), 0); + dd4hep::Tube facePlateShape3(dimensions.rmin(), (sensitiveBarrel3Rmin - space), + (dzDetector3 - 2 * dZEndPlate - space)); + Volume facePlateVol3("facePlateVol3", facePlateShape3, lcdd.material(xFacePlate.materialStr())); + facePlateVol3.setVisAttributes(lcdd, xFacePlate.visStr()); + dd4hep::Position offsetFace3(0, 0, sign * extBarrelOffset3); + + PlacedVolume placedFacePlate1 = envelopeVolume.placeVolume(facePlateVol1, offsetFace1); + facePlate1.setPlacement(placedFacePlate1); + PlacedVolume placedFacePlate2 = envelopeVolume.placeVolume(facePlateVol2, offsetFace2); + facePlate2.setPlacement(placedFacePlate2); + PlacedVolume placedFacePlate3 = envelopeVolume.placeVolume(facePlateVol3, offsetFace3); + facePlate3.setPlacement(placedFacePlate3); + + // Add structural support made of steel at both ends of extHCal + dd4hep::Tube endPlateShape1(dimensions.rmin1(), (dimensions.rmax1() - dSteelSupport), dZEndPlate); + Volume endPlateVol1("endPlateVol1", endPlateShape1, lcdd.material(xEndPlate.materialStr())); + endPlateVol1.setVisAttributes(lcdd, xEndPlate.visStr()); + dd4hep::Tube endPlateShape3(dimensions.rmin(), (dimensions.rmax() - dSteelSupport), dZEndPlate); + Volume endPlateVol3("endPlateVol3", endPlateShape3, lcdd.material(xEndPlate.materialStr())); + endPlateVol3.setVisAttributes(lcdd, xEndPlate.visStr()); + + // Endplates placed for the extended Barrels in front and in the back to the central Barrel + DetElement endPlatePos(caloDetElem, "endPlate_" + std::to_string(1 * sign), 0); + dd4hep::Position posOffset(0, 0, sign * (extBarrelOffset3 + dzDetector3 - dZEndPlate)); + PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol3, posOffset); + endPlatePos.setPlacement(placedEndPlatePos); + + DetElement endPlateNeg(caloDetElem, "endPlate_" + std::to_string(2 * sign), 0); + dd4hep::Position negOffset(0, 0, sign * (extBarrelOffset1 - dzDetector1 + dZEndPlate)); + PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol1, negOffset); + endPlateNeg.setPlacement(placedEndPlateNeg); + + std::vector layers; + layers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector > seqInLayers; + seqInLayers.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + std::vector tilesPerLayer; + tilesPerLayer.reserve(layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); + + // loop over R ("layers") + double layerR = 0.; + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel1Rmin + layerR; + double rmaxLayer = sensitiveBarrel1Rmin + layerR + layerDepths1.at(idxLayer); + layerR += layerDepths1.at(idxLayer); + layerInnerRadii1.push_back(rminLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); + Volume layerVolume("HCalECLayerVol1", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + dd4hep::Position moduleOffset1 (0,0,sign * extBarrelOffset1); + + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset1); + unsigned int type1 = 0; + if (sign<0){ + type1 = 3; + } + placedLayerVolume.addPhysVolID("type", type1); // First module type=0,3 in front of second +/- + placedLayerVolume.addPhysVolID("layer", idxLayer); + + layers.push_back(placedLayerVolume); + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_"+ xComp.materialStr(), tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector1 + 0.5 * dzSequence; //2*dZEndPlate + space + 0.5 * dzSequence; + + for (uint numSeq=0; numSeq < numSequencesZ1; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + } // layers loop + + + layerR = 0.; + // Placement of subWedges in Wedge, 2nd part + for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel2Rmin + layerR; + double rmaxLayer = sensitiveBarrel2Rmin + layerR + layerDepths2.at(idxLayer); + layerR += layerDepths2.at(idxLayer); + layerInnerRadii2.push_back(rminLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); + Volume layerVolume("HCalECLayerVol2", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_", tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } // close first Z loop + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector2 + 0.5 * dzSequence; //(dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ2; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + + dd4hep::Position moduleOffset2 (0, 0, sign * extBarrelOffset2); + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset2); + unsigned int type2 = 1; + if (sign<0){ + type2 = 4; + } + placedLayerVolume.addPhysVolID("type", type2); // Second module type=1,4 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + idxLayer); + layers.push_back(placedLayerVolume); + } + + layerR = 0.; + // Placement of subWedges in Wedge, 3th part + for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer){ + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrel3Rmin + layerR; + double rmaxLayer = sensitiveBarrel3Rmin + layerR + layerDepths3.at(idxLayer); + layerR += layerDepths3.at(idxLayer); + layerInnerRadii3.push_back(rminLayer); + + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = (idxLayer+1) % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); + Volume layerVolume("HCalECLayerVol3", layerShape, lcdd.air()); + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + double tileZOffset = - 0.5* dzSequence; + + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; ++xCompColl, ++idxSubMod){ + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalECTileVol_" , tileShape, lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()){ + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector seqs; + double zOffset = - dzDetector3 + 0.5 * dzSequence; //2*dZEndPlate + space + (dzSequence * 0.5); + + for (uint numSeq=0; numSeq < numSequencesZ3; numSeq++){ + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + seqs.push_back(placedTileSequenceVolume); + zOffset += dzSequence; + } + seqInLayers.push_back(seqs); + + dd4hep::Position moduleOffset3 (0, 0, sign * extBarrelOffset3); + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume, moduleOffset3); + unsigned int type3 = 2; + if (sign<0){ + type3 = 5; + } + placedLayerVolume.addPhysVolID("type", type3); // Second module type=2,5 behind the first +/- + placedLayerVolume.addPhysVolID("layer", layerDepths1.size() + layerDepths2.size() + idxLayer); + layers.push_back(placedLayerVolume); + } // end loop placement of subwedges + + // Placement of DetElements + lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; + lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; + + // Place det elements wihtin each other to recover volume positions later via cellID + for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++){ + DetElement layerDet(caloDetElem, dd4hep::xml::_toString(sign*(iLayer+1), "layer%d"), sign*(iLayer+1)); + layerDet.setPlacement(layers[iLayer]); + + for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ + DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), sign*(iSeq+1)); + seqDet.setPlacement(seqInLayers[iLayer][iSeq]); + + DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), sign*(iSeq+1)); + tileDet.setPlacement(tilesPerLayer[iLayer]); + } + } + } // for signs loop + + // Place envelope volume + Volume motherVol = lcdd.pickMotherVolume(caloDetElem); + + PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); + placedHCal.addPhysVolID("system", caloDetElem.id()); + caloDetElem.setPlacement(placedHCal); + + + // Create caloData object + auto caloData = new dd4hep::rec::LayeredCalorimeterData; + caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::EndcapLayout; + caloDetElem.addExtension(caloData); + + caloData->extent[0] = sensitiveBarrel3Rmin; + caloData->extent[1] = sensitiveBarrel3Rmin + moduleDepth3; // + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = dzDetector1 + dzDetector2 + dzDetector3; + + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + // IMPORTANT: the information below is used to calculate the cell position in CellPositionsHCalPhiThetaSegTool in k4RecCalorimeter + // if the definition distance or sensitive_thickness is modified, one also needs to modify CellPositionsHCalPhiThetaSegTool + for (unsigned int idxLayer = 0; idxLayer < layerDepths1.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths1.at(idxLayer); + caloLayer.distance = layerInnerRadii1.at(idxLayer); // radius of the current layer + caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); + } + + for (unsigned int idxLayer = 0; idxLayer < layerDepths2.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths2.at(idxLayer); + caloLayer.distance = layerInnerRadii2.at(idxLayer); + caloLayer.sensitive_thickness = difference_bet_r1r2; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); + } + + for (unsigned int idxLayer = 0; idxLayer < layerDepths3.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths3.at(idxLayer); + caloLayer.distance = layerInnerRadii3.at(idxLayer); + caloLayer.sensitive_thickness = difference_bet_r1r2; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); + } + return caloDetElem; +} +}// namespace det +DECLARE_DETELEMENT(CaloThreePartsEndcap_o1_v02, det::createHCalEC) From d705b1b9e1b16d1a15de7f2951e5adfd31719dd2 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Thu, 8 Aug 2024 15:13:12 +0200 Subject: [PATCH 019/133] adding version nr also for the barrel xml --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal.xml | 5 + .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml | 128 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml index 0c051c39b..714fffbe1 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml @@ -52,6 +52,11 @@ system:4,layer:5,theta:9,phi:10 + + + + system:4,layer:5,row:9,theta:0,phi:10 + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml new file mode 100644 index 000000000..0c051c39b --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml @@ -0,0 +1,128 @@ + + + + The first FCCee HCal layout based on ATLAS HCal, not optimised yet + 1. Nov 2022, J. Faltova: update material and radial segmentation for FCCee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,layer:5,row:9,theta:9,phi:10 + + + + system:4,layer:5,theta:9,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a07d7a6745f8eb0f64dfecef381f5d9c3457ee3f Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Thu, 8 Aug 2024 17:11:06 +0200 Subject: [PATCH 020/133] update hcal xml files to v02 --- FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index 190b83188..2e0343104 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -44,9 +44,9 @@ - + - + From 102813e7bb1f9d79dd066860789b966f1b33f60f Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Sat, 10 Aug 2024 12:02:11 +0200 Subject: [PATCH 021/133] add back ECalEndcaps_Turbine --- FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index 2e0343104..7f2b2fb3f 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -45,7 +45,7 @@ - + From c9535c8baae3ea0439d1045c4fcc2ef5b0362689 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Tue, 13 Aug 2024 13:16:45 +0200 Subject: [PATCH 022/133] remove unused hcal v01 xml files --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal.xml | 133 ----------------- .../HCalEndcaps_ThreeParts_TileCal.xml | 141 ------------------ 2 files changed, 274 deletions(-) delete mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml delete mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml deleted file mode 100644 index 714fffbe1..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal.xml +++ /dev/null @@ -1,133 +0,0 @@ - - - - The first FCCee HCal layout based on ATLAS HCal, not optimised yet - 1. Nov 2022, J. Faltova: update material and radial segmentation for FCCee - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - system:4,layer:5,row:9,theta:9,phi:10 - - - - system:4,layer:5,theta:9,phi:10 - - - - - system:4,layer:5,row:9,theta:0,phi:10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml deleted file mode 100644 index c5cbe72a7..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - HCal layout based on ATLAS HCal, with realistic longitudinal segmentation and steel support - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - system:4,type:2,layer:5,row:9,eta:11,phi:10 - - - - system:4,type:2,layer:4,eta:11,phi:10 - - - - - system:4,type:2,layer:5,row:9,eta:10,phi:10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 18d66e50d838007279023b4e96808d1502d2d3f8 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Tue, 13 Aug 2024 13:50:41 +0200 Subject: [PATCH 023/133] update READMEs --- FCCee/ALLEGRO/compact/README.md | 3 +++ detector/calorimeter/README.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/FCCee/ALLEGRO/compact/README.md b/FCCee/ALLEGRO/compact/README.md index 6225008c8..b30399a46 100644 --- a/FCCee/ALLEGRO/compact/README.md +++ b/FCCee/ALLEGRO/compact/README.md @@ -10,3 +10,6 @@ ALLEGRO_o1_v03: with respect to v02 it features an ECal barrel with 11 layers an The vertex detector and drift chamber are now taken directly from IDEA_o1_v03, this effectively updates both the vertex detector (which was taken from an old CLD version) and the drift chamber (which was corresponding to IDEA_o1_v02/DriftChamber_o1_v01.xml). The z-extent of the drift chamber is now unchanged w.r.t. the IDEA detector (2 m) since it requires optimization anyway. Magnetic fields (solenoid + MDI) have been added. Added "turbine-style" endcap ecal, and invoke this in the top-level xml (replacing the coneCyro geometry). +Added HCalBarrel_TileCal_v02.xml where unused readout BarHCal_Readout_phi is removed. +Added HCalEndcaps_ThreeParts_TileCal_v02.xml, which was migrated to the theta-phi segmentation; unused readout *Readout_phi was removed; +fixed radial dimensions, so the outer radius of all three cylinders is the same; moved to use updated geometry CaloThreePartsEndcap_o1_v02. diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index ddb6a0b1b..ddcafd117 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -34,6 +34,7 @@ This sub-detector makes calorimeter barrel. It is used in ALLEGRO detector conce ### o1_v01 Original version taken from [FCCDetectors](https://github.com/HEP-FCC/FCCDetectors/blob/70a989a6fc333610e3b1b979c3596da9c41543d8/Detector/DetFCChhHCalTile/src/HCalBarrel_geo.cpp). +In August 2024, added extension (LayeredCalorimeterData) to store radial layer radii and dimensions; made small updates of the code to improve readibility, while the functionality remains the same. ## HCalThreePartsEndcap This sub-detector makes calorimeter endcaps. Each endcap is made up by three cylindrical pieces with different thickness and inner radius, but same outer radius. It is used in ALLEGRO detector concept. @@ -41,6 +42,8 @@ This sub-detector makes calorimeter endcaps. Each endcap is made up by three cyl ### o1_v01 Original version taken from [FCCDetectors](https://github.com/HEP-FCC/FCCDetectors/blob/70a989a6fc333610e3b1b979c3596da9c41543d8/Detector/DetFCCeeHCalTile/src/HCalThreePartsEndcap_geo.cpp#L4). +### o1_v02 +Changes wrt o1_v01: Added extension (LayeredCalorimeterData) to store radial layer radii and dimensions. To make this work, the whole code had to be rewritten, but its functionality remains the same. ## dual-readout From 3e7117c9da91853291acd991c5b80b49fae3f40b Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Tue, 13 Aug 2024 23:31:28 +0200 Subject: [PATCH 024/133] add HCalTileBarrel_o1_v02_geo.cpp --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml | 2 +- FCCee/ALLEGRO/compact/README.md | 5 +- .../calorimeter/HCalTileBarrel_o1_v01_geo.cpp | 117 +++----- .../calorimeter/HCalTileBarrel_o1_v02_geo.cpp | 272 ++++++++++++++++++ detector/calorimeter/README.md | 6 +- 5 files changed, 319 insertions(+), 83 deletions(-) create mode 100644 detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml index 0c051c39b..cd012cdf4 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml @@ -55,7 +55,7 @@ - + diff --git a/FCCee/ALLEGRO/compact/README.md b/FCCee/ALLEGRO/compact/README.md index b30399a46..9da75a3de 100644 --- a/FCCee/ALLEGRO/compact/README.md +++ b/FCCee/ALLEGRO/compact/README.md @@ -10,6 +10,5 @@ ALLEGRO_o1_v03: with respect to v02 it features an ECal barrel with 11 layers an The vertex detector and drift chamber are now taken directly from IDEA_o1_v03, this effectively updates both the vertex detector (which was taken from an old CLD version) and the drift chamber (which was corresponding to IDEA_o1_v02/DriftChamber_o1_v01.xml). The z-extent of the drift chamber is now unchanged w.r.t. the IDEA detector (2 m) since it requires optimization anyway. Magnetic fields (solenoid + MDI) have been added. Added "turbine-style" endcap ecal, and invoke this in the top-level xml (replacing the coneCyro geometry). -Added HCalBarrel_TileCal_v02.xml where unused readout BarHCal_Readout_phi is removed. -Added HCalEndcaps_ThreeParts_TileCal_v02.xml, which was migrated to the theta-phi segmentation; unused readout *Readout_phi was removed; -fixed radial dimensions, so the outer radius of all three cylinders is the same; moved to use updated geometry CaloThreePartsEndcap_o1_v02. +Added HCalBarrel_TileCal_v02.xml which uses HCalTileBarrel_o1_v02_geo.cpp and removed unused readout BarHCal_Readout_phi. +Added HCalEndcaps_ThreeParts_TileCal_v02.xml which uses HCalThreePartsEndcap_o1_v02_geo.cpp. Additionally, wrt v02 the readout was migrated to the theta-phi segmentation; unused readout *Readout_phi was removed; radial dimensions of layers were modified, so the outer radius of all three cylinders is the same. diff --git a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp index c6f359dd3..89be7154d 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v01_geo.cpp @@ -1,7 +1,6 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" -#include using dd4hep::Volume; using dd4hep::DetElement; @@ -13,11 +12,11 @@ using dd4hep::PlacedVolume; #define endmsg std::endl #define lLog std::cout namespace MSG { -const std::string ERROR = "createHCalTileBarrel ERROR "; -const std::string DEBUG = "createHCalTileBarrel DEBUG "; -const std::string INFO = "createHCalTileBarrel INFO "; +const std::string DEBUG = " Debug: "; +const std::string INFO = " Info: "; } + namespace det { static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep::SensitiveDetector sensDet) { @@ -41,66 +40,55 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep xml_comp_t xSteelSupport = xmlDet.child(_Unicode(steel_support)); double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport / dd4hep::cm << endmsg; + lLog << MSG::DEBUG << "steel support thickness: " << dSteelSupport << " [cm]" << endmsg; lLog << MSG::DEBUG << "steel support material: " << xSteelSupport.materialStr() << endmsg; double sensitiveBarrelRmin = xDimensions.rmin() + xFacePlate.thickness() + space; // Hard-coded assumption that we have two different sequences for the modules std::vector sequences = {xmlDet.child(_Unicode(sequence_a)), xmlDet.child(_Unicode(sequence_b))}; - // Check if both sequences are present - if (!sequences[0] || !sequences[1]) { - lLog << MSG::ERROR << "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file." << endmsg; - throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); - } - // Check if both sequences have the same dimensions - Dimension dimensionsA(sequences[0].dimensions()); - Dimension dimensionsB(sequences[1].dimensions()); - if (dimensionsA.dz() != dimensionsB.dz()) { - lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; - throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); - } - double dzSequence = dimensionsB.dz(); + // NOTE: This assumes that both have the same dimensions! + Dimension sequenceDimensions(sequences[1].dimensions()); + double dzSequence = sequenceDimensions.dz(); lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; - // calculate the number of sequences fitting in Z + // calculate the number of modules fitting in Z unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); + // get all 'layer' children of the 'layers' tag std::vector Layers; - for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl) { - Layers.push_back(xCompColl); + for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; + ++xCompColl) { + Layers.push_back(xCompColl); } - unsigned int numLayersR = 0; + unsigned int numSequencesR = 0; double moduleDepth = 0.; std::vector layerDepths = std::vector(); - std::vector layerInnerRadii = std::vector(); for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { xml_comp_t layer = *it; Dimension layerDimension(layer.dimensions()); - numLayersR += layerDimension.nModules(); + numSequencesR += layerDimension.nModules(); for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++) { moduleDepth += layerDimension.dr(); layerDepths.push_back(layerDimension.dr()); } } - lLog << MSG::DEBUG << "retrieved number of radial layers: " << numLayersR - << " , which end up to a full module depth in rho of " << moduleDepth << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of radial layers: " << layerDepths.size() << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers: " << numSequencesR + << " , which end up to a full module depth in rho of " << moduleDepth << endmsg; + lLog << MSG::DEBUG << "retrieved number of layers: " << layerDepths.size() << endmsg; - lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numLayersR - << " radial layers, in total " << numLayersR * numSequencesZ << " tiles" << endmsg; + lLog << MSG::INFO << "constructing: " << numSequencesZ << " rings in Z, " << numSequencesR + << " layers in Rho, " << numSequencesR * numSequencesZ << " tiles" << endmsg; // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; - lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector / dd4hep::cm << endmsg; - lLog << MSG::INFO << "correction of dz in cm (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; + lLog << MSG::DEBUG << "dzDetector: " << dzDetector << endmsg; + lLog << MSG::INFO << "correction of dz (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; double rminSupport = sensitiveBarrelRmin + moduleDepth; double rmaxSupport = sensitiveBarrelRmin + moduleDepth + dSteelSupport; - double sensitiveBarrelRmax = sensitiveBarrelRmin + moduleDepth; - ////////////////////// detector building ////////////////////// @@ -114,11 +102,10 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep // top level det element representing whole hcal barrel - DetElement caloDetElem(xmlDet.nameStr(), xmlDet.id()); + DetElement hCal(xmlDet.nameStr(), xmlDet.id()); /// envelope shape dd4hep::Tube envelopeShape(xDimensions.rmin(), xDimensions.rmax(), xDimensions.dz()); - Volume envelopeVolume("HCalEnvelopeVolume", envelopeShape, lcdd.air()); envelopeVolume.setVisAttributes(lcdd, xDimensions.visStr()); @@ -127,7 +114,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep Volume facePlateVol("HCalFacePlateVol", facePlateShape, lcdd.material(xFacePlate.materialStr())); facePlateVol.setVisAttributes(lcdd, xFacePlate.visStr()); PlacedVolume placedFacePlate = envelopeVolume.placeVolume(facePlateVol); - DetElement facePlate_det(caloDetElem, "HCalFacePlate", 0); + DetElement facePlate_det(hCal, "HCalFacePlate", 0); facePlate_det.setPlacement(placedFacePlate); // Add structural support made of steel at both ends of HCal @@ -135,21 +122,22 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep Volume endPlateVol("HCalEndPlateVol", endPlateShape, lcdd.material(xEndPlate.materialStr())); endPlateVol.setVisAttributes(lcdd, xEndPlate.visStr()); - DetElement endPlatePos(caloDetElem, "HCalEndPlatePos", 0); + DetElement endPlatePos(hCal, "HCalEndPlatePos", 0); dd4hep::Position posOffset(0, 0, dzDetector - (dZEndPlate / 2)); PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol, posOffset); endPlatePos.setPlacement(placedEndPlatePos); - DetElement endPlateNeg(caloDetElem, "HCalEndPlateNeg", 1); + DetElement endPlateNeg(hCal, "HCalEndPlateNeg", 1); dd4hep::Position negOffset(0, 0, -dzDetector + (dZEndPlate / 2)); PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol, negOffset); endPlateNeg.setPlacement(placedEndPlateNeg); dd4hep::Tube supportShape(rminSupport, rmaxSupport, (dzDetector - dZEndPlate - space)); - Volume steelSupportVolume("HCalSteelSupportVol", supportShape, lcdd.material(xSteelSupport.materialStr())); + Volume steelSupportVolume("HCalSteelSupportVol", supportShape, + lcdd.material(xSteelSupport.materialStr())); steelSupportVolume.setVisAttributes(lcdd.invisible()); PlacedVolume placedSupport = envelopeVolume.placeVolume(steelSupportVolume); - DetElement support(caloDetElem, "HCalSteelSupport", 0); + DetElement support(hCal, "HCalSteelSupport", 0); support.setPlacement(placedSupport); // double sensitiveBarrelDz = dzDetector - dZEndPlate; @@ -163,13 +151,15 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep double rminLayer = sensitiveBarrelRmin + layerR; double rmaxLayer = sensitiveBarrelRmin + layerR + layerDepths.at(idxLayer); layerR += layerDepths.at(idxLayer); - layerInnerRadii.push_back(rminLayer); //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = idxLayer % 2; dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); - Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); + Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); + + lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector - dZEndPlate - space ); Volume layerVolume("HCalLayerVol", layerShape, lcdd.air()); @@ -186,7 +176,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep double tileZOffset = - 0.5* dzSequence; // first Z loop (tiles that make up a sequence) for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; - ++xCompColl, ++idxSubMod) { + ++xCompColl, ++idxSubMod) { xml_comp_t xComp = xCompColl; dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); @@ -219,8 +209,8 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep } // Place det elements wihtin each other to recover volume positions later via cellID - for (uint iLayer = 0; iLayer < numLayersR; iLayer++) { - DetElement layerDet(caloDetElem, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); + for (uint iLayer = 0; iLayer < numSequencesR; iLayer++) { + DetElement layerDet(hCal, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); layerDet.setPlacement(layers[iLayer]); for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ @@ -233,39 +223,12 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep } // Place envelope (or barrel) volume - Volume motherVol = lcdd.pickMotherVolume(caloDetElem); + Volume motherVol = lcdd.pickMotherVolume(hCal); motherVol.setVisAttributes(lcdd.invisible()); - PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVolume); - envelopePhysVol.addPhysVolID("system", caloDetElem.id()); - caloDetElem.setPlacement(envelopePhysVol); - - - // Create caloData object - auto caloData = new dd4hep::rec::LayeredCalorimeterData; - caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; - caloDetElem.addExtension(caloData); - - caloData->extent[0] = sensitiveBarrelRmin; - caloData->extent[1] = sensitiveBarrelRmax; - caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 - caloData->extent[3] = dzDetector; - - dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; - - for (unsigned int idxLayer = 0; idxLayer < layerDepths.size(); ++idxLayer) { - const double difference_bet_r1r2 = layerDepths.at(idxLayer); - - caloLayer.distance = layerInnerRadii.at(idxLayer); // radius of the current layer - caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer - caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; - caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; - - caloData->layers.push_back(caloLayer); - } - - - return caloDetElem; - + PlacedVolume placedHCal = motherVol.placeVolume(envelopeVolume); + placedHCal.addPhysVolID("system", hCal.id()); + hCal.setPlacement(placedHCal); + return hCal; } } // namespace hcal diff --git a/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp new file mode 100644 index 000000000..4e1796c94 --- /dev/null +++ b/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp @@ -0,0 +1,272 @@ +// DD4hep +#include "DD4hep/DetFactoryHelper.h" + +#include + +using dd4hep::Volume; +using dd4hep::DetElement; +using dd4hep::xml::Dimension; +using dd4hep::PlacedVolume; + + +// todo: remove gaudi logging and properly capture output +#define endmsg std::endl +#define lLog std::cout +namespace MSG { +const std::string ERROR = "createHCalTileBarrel ERROR "; +const std::string DEBUG = "createHCalTileBarrel DEBUG "; +const std::string INFO = "createHCalTileBarrel INFO "; +} + +namespace det { + +static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep::SensitiveDetector sensDet) { + + /////////////////// config parsing /////////////////////////////////// + + // Make volume that envelopes the whole barrel; set material to air + Dimension xDimensions(xmlDet.dimensions()); + + + // sensitive detector type read from xml (for example "SimpleCalorimeterSD") + Dimension xSensitive = xmlDet.child(_U(sensitive)); + sensDet.setType(xSensitive.typeStr()); + + + xml_comp_t xEndPlate = xmlDet.child(_Unicode(end_plate)); + double dZEndPlate = xEndPlate.thickness(); + xml_comp_t xFacePlate = xmlDet.child(_Unicode(face_plate)); + xml_comp_t xSpace = xmlDet.child(_Unicode(plate_space)); // to avoid overlaps + double space = xSpace.thickness(); + xml_comp_t xSteelSupport = xmlDet.child(_Unicode(steel_support)); + double dSteelSupport = xSteelSupport.thickness(); + + lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport / dd4hep::cm << endmsg; + lLog << MSG::DEBUG << "steel support material: " << xSteelSupport.materialStr() << endmsg; + + double sensitiveBarrelRmin = xDimensions.rmin() + xFacePlate.thickness() + space; + + // Hard-coded assumption that we have two different sequences for the modules + std::vector sequences = {xmlDet.child(_Unicode(sequence_a)), xmlDet.child(_Unicode(sequence_b))}; + // Check if both sequences are present + if (!sequences[0] || !sequences[1]) { + lLog << MSG::ERROR << "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file." << endmsg; + throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); + } + // Check if both sequences have the same dimensions + Dimension dimensionsA(sequences[0].dimensions()); + Dimension dimensionsB(sequences[1].dimensions()); + if (dimensionsA.dz() != dimensionsB.dz()) { + lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); + } + double dzSequence = dimensionsB.dz(); + lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + + // calculate the number of sequences fitting in Z + unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); + + // get all 'layer' children of the 'layers' tag + std::vector Layers; + for (xml_coll_t xCompColl(xmlDet.child(_Unicode(layers)), _Unicode(layer)); xCompColl; ++xCompColl) { + Layers.push_back(xCompColl); + } + unsigned int numLayersR = 0; + double moduleDepth = 0.; + std::vector layerDepths = std::vector(); + std::vector layerInnerRadii = std::vector(); + for (std::vector::iterator it = Layers.begin(); it != Layers.end(); ++it) { + xml_comp_t layer = *it; + Dimension layerDimension(layer.dimensions()); + numLayersR += layerDimension.nModules(); + for (int nLayer = 0; nLayer < layerDimension.nModules(); nLayer++) { + moduleDepth += layerDimension.dr(); + layerDepths.push_back(layerDimension.dr()); + } + } + lLog << MSG::DEBUG << "retrieved number of radial layers: " << numLayersR + << " , which end up to a full module depth in rho of " << moduleDepth << " cm" << endmsg; + lLog << MSG::DEBUG << "retrieved number of radial layers: " << layerDepths.size() << endmsg; + + lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numLayersR + << " radial layers, in total " << numLayersR * numSequencesZ << " tiles" << endmsg; + + // Calculate correction along z based on the module size (can only have natural number of modules) + double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; + lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector / dd4hep::cm << endmsg; + lLog << MSG::INFO << "correction of dz in cm (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; + + double rminSupport = sensitiveBarrelRmin + moduleDepth; + double rmaxSupport = sensitiveBarrelRmin + moduleDepth + dSteelSupport; + + double sensitiveBarrelRmax = sensitiveBarrelRmin + moduleDepth; + + + ////////////////////// detector building ////////////////////// + + + std::vector layers; + layers.reserve(layerDepths.size()); + std::vector > seqInLayers; + seqInLayers.reserve(layerDepths.size()); + std::vector tilesPerLayer; + tilesPerLayer.reserve(layerDepths.size()); + + + // top level det element representing whole hcal barrel + DetElement caloDetElem(xmlDet.nameStr(), xmlDet.id()); + + /// envelope shape + dd4hep::Tube envelopeShape(xDimensions.rmin(), xDimensions.rmax(), xDimensions.dz()); + + Volume envelopeVolume("HCalEnvelopeVolume", envelopeShape, lcdd.air()); + envelopeVolume.setVisAttributes(lcdd, xDimensions.visStr()); + + // Add structural support made of steel inside of HCal + dd4hep::Tube facePlateShape(xDimensions.rmin(), sensitiveBarrelRmin, (dzDetector - dZEndPlate - space)); + Volume facePlateVol("HCalFacePlateVol", facePlateShape, lcdd.material(xFacePlate.materialStr())); + facePlateVol.setVisAttributes(lcdd, xFacePlate.visStr()); + PlacedVolume placedFacePlate = envelopeVolume.placeVolume(facePlateVol); + DetElement facePlate_det(caloDetElem, "HCalFacePlate", 0); + facePlate_det.setPlacement(placedFacePlate); + + // Add structural support made of steel at both ends of HCal + dd4hep::Tube endPlateShape(xDimensions.rmin(), (xDimensions.rmax() - dSteelSupport), dZEndPlate / 2); + Volume endPlateVol("HCalEndPlateVol", endPlateShape, lcdd.material(xEndPlate.materialStr())); + endPlateVol.setVisAttributes(lcdd, xEndPlate.visStr()); + + DetElement endPlatePos(caloDetElem, "HCalEndPlatePos", 0); + dd4hep::Position posOffset(0, 0, dzDetector - (dZEndPlate / 2)); + PlacedVolume placedEndPlatePos = envelopeVolume.placeVolume(endPlateVol, posOffset); + endPlatePos.setPlacement(placedEndPlatePos); + + DetElement endPlateNeg(caloDetElem, "HCalEndPlateNeg", 1); + dd4hep::Position negOffset(0, 0, -dzDetector + (dZEndPlate / 2)); + PlacedVolume placedEndPlateNeg = envelopeVolume.placeVolume(endPlateVol, negOffset); + endPlateNeg.setPlacement(placedEndPlateNeg); + + dd4hep::Tube supportShape(rminSupport, rmaxSupport, (dzDetector - dZEndPlate - space)); + Volume steelSupportVolume("HCalSteelSupportVol", supportShape, lcdd.material(xSteelSupport.materialStr())); + steelSupportVolume.setVisAttributes(lcdd.invisible()); + PlacedVolume placedSupport = envelopeVolume.placeVolume(steelSupportVolume); + DetElement support(caloDetElem, "HCalSteelSupport", 0); + support.setPlacement(placedSupport); + + // double sensitiveBarrelDz = dzDetector - dZEndPlate; + + // loop over R ("layers") + double layerR = 0.; + for (unsigned int idxLayer = 0; idxLayer < layerDepths.size(); ++idxLayer) { + std::string layerName = "HCalLayer" + std::to_string(idxLayer); + + // in Module rmin = 0 for first wedge, changed radius to the full radius starting at (0,0,0) + double rminLayer = sensitiveBarrelRmin + layerR; + double rmaxLayer = sensitiveBarrelRmin + layerR + layerDepths.at(idxLayer); + layerR += layerDepths.at(idxLayer); + layerInnerRadii.push_back(rminLayer); + + //alternate: even layers consist of tile sequence b, odd layer of tile sequence a + unsigned int sequenceIdx = idxLayer % 2; + + dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); + Volume tileSequenceVolume("HCalTileSequenceVol", tileSequenceShape, lcdd.air()); + + dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector - dZEndPlate - space ); + Volume layerVolume("HCalLayerVol", layerShape, lcdd.air()); + + + layerVolume.setVisAttributes(lcdd.invisible()); + unsigned int idxSubMod = 0; + + + dd4hep::PlacedVolume placedLayerVolume = envelopeVolume.placeVolume(layerVolume); + placedLayerVolume.addPhysVolID("layer", idxLayer); + layers.push_back(placedLayerVolume); + + double tileZOffset = - 0.5* dzSequence; + // first Z loop (tiles that make up a sequence) + for (xml_coll_t xCompColl(sequences[sequenceIdx], _Unicode(module_component)); xCompColl; + ++xCompColl, ++idxSubMod) { + xml_comp_t xComp = xCompColl; + dd4hep::Tube tileShape(rminLayer, rmaxLayer, 0.5 * xComp.thickness()); + + Volume tileVol("HCalTileVol_"+xComp.nameStr(), tileShape, + lcdd.material(xComp.materialStr())); + tileVol.setVisAttributes(lcdd, xComp.visStr()); + + dd4hep::Position tileOffset(0, 0, tileZOffset + 0.5 * xComp.thickness() ); + dd4hep::PlacedVolume placedTileVol = tileSequenceVolume.placeVolume(tileVol, tileOffset); + + if (xComp.isSensitive()) { + tileVol.setSensitiveDetector(sensDet); + tilesPerLayer.push_back(placedTileVol); + } + tileZOffset += xComp.thickness(); + } + + // second z loop (place sequences in layer) + std::vector sq_vector; + + for (uint numSeq=0; numSeq < numSequencesZ; numSeq++){ + double zOffset = - dzDetector + (2 * numSeq + 1) * (dzSequence * 0.5); + dd4hep::Position tileSequencePosition(0, 0, zOffset); + dd4hep::PlacedVolume placedTileSequenceVolume = layerVolume.placeVolume(tileSequenceVolume, tileSequencePosition); + placedTileSequenceVolume.addPhysVolID("row", numSeq); + sq_vector.push_back(placedTileSequenceVolume); + } + seqInLayers.push_back(sq_vector); + + } + + // Place det elements wihtin each other to recover volume positions later via cellID + for (uint iLayer = 0; iLayer < numLayersR; iLayer++) { + DetElement layerDet(caloDetElem, dd4hep::xml::_toString(iLayer, "layer%d"), iLayer); + layerDet.setPlacement(layers[iLayer]); + + for (uint iSeq = 0; iSeq < seqInLayers[iLayer].size(); iSeq++){ + DetElement seqDet(layerDet, dd4hep::xml::_toString(iSeq, "seq%d"), iSeq); + seqDet.setPlacement(seqInLayers[iLayer][iSeq]); + + DetElement tileDet(seqDet, dd4hep::xml::_toString(iSeq, "tile%d"), iSeq); + tileDet.setPlacement(tilesPerLayer[iLayer]); + } + } + + // Place envelope (or barrel) volume + Volume motherVol = lcdd.pickMotherVolume(caloDetElem); + motherVol.setVisAttributes(lcdd.invisible()); + PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVolume); + envelopePhysVol.addPhysVolID("system", caloDetElem.id()); + caloDetElem.setPlacement(envelopePhysVol); + + + // Create caloData object + auto caloData = new dd4hep::rec::LayeredCalorimeterData; + caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; + caloDetElem.addExtension(caloData); + + caloData->extent[0] = sensitiveBarrelRmin; + caloData->extent[1] = sensitiveBarrelRmax; + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = dzDetector; + + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + for (unsigned int idxLayer = 0; idxLayer < layerDepths.size(); ++idxLayer) { + const double difference_bet_r1r2 = layerDepths.at(idxLayer); + + caloLayer.distance = layerInnerRadii.at(idxLayer); // radius of the current layer + caloLayer.sensitive_thickness = difference_bet_r1r2; // radial dimension of the current layer + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2.0; + + caloData->layers.push_back(caloLayer); + } + + + return caloDetElem; + +} +} // namespace hcal + +DECLARE_DETELEMENT(HCalTileBarrel_o1_v02, det::createHCal) diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index ddcafd117..ce9c3b869 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -34,7 +34,9 @@ This sub-detector makes calorimeter barrel. It is used in ALLEGRO detector conce ### o1_v01 Original version taken from [FCCDetectors](https://github.com/HEP-FCC/FCCDetectors/blob/70a989a6fc333610e3b1b979c3596da9c41543d8/Detector/DetFCChhHCalTile/src/HCalBarrel_geo.cpp). -In August 2024, added extension (LayeredCalorimeterData) to store radial layer radii and dimensions; made small updates of the code to improve readibility, while the functionality remains the same. + +### o1_v02 +Changes wrt o1_v01: Added extension (LayeredCalorimeterData) to store radial layer radii and dimensions. Added several checks for the geometry building and made small changes in the code to improve readibility. ## HCalThreePartsEndcap This sub-detector makes calorimeter endcaps. Each endcap is made up by three cylindrical pieces with different thickness and inner radius, but same outer radius. It is used in ALLEGRO detector concept. @@ -43,7 +45,7 @@ This sub-detector makes calorimeter endcaps. Each endcap is made up by three cyl Original version taken from [FCCDetectors](https://github.com/HEP-FCC/FCCDetectors/blob/70a989a6fc333610e3b1b979c3596da9c41543d8/Detector/DetFCCeeHCalTile/src/HCalThreePartsEndcap_geo.cpp#L4). ### o1_v02 -Changes wrt o1_v01: Added extension (LayeredCalorimeterData) to store radial layer radii and dimensions. To make this work, the whole code had to be rewritten, but its functionality remains the same. +Changes wrt o1_v01: Added extension (LayeredCalorimeterData) to store radial layer radii and dimensions. To make this work, the whole code had to be reshuffled, but the way how the geometry and individual volumes are built remains the same as in o1_v01. ## dual-readout From 585378a9cbb5223c28596568d977098e1e9fb4f9 Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Tue, 27 Aug 2024 16:20:07 +0200 Subject: [PATCH 025/133] CLD_o2_v07: start with new lumical to fix overlaps --- .../compact/CLD_o2_v07/LumiCal_o3_v02_05.xml | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml new file mode 100644 index 000000000..cbc708e20 --- /dev/null +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml @@ -0,0 +1,188 @@ + + + + + + + + + + system:8,barrel:3,layer:8,slice:8,r:32:-16,phi:-16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 213fde1c66a34c8fbf4e8898f451d6e9971d001c Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Tue, 27 Aug 2024 16:18:13 +0200 Subject: [PATCH 026/133] CLD_o2_v07: fix overlaps in the LumiCal itself Add a lumical_max_z_prime parameter to get the actual end place of the lumical add 7 micron meter to the envelopes. Fix the location and rotation to use the max_z_prime values --- FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml | 6 +++-- .../compact/CLD_o2_v07/LumiCal_o3_v02_05.xml | 22 +++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml index c45519d6e..f63eed8bb 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml @@ -198,12 +198,14 @@ + + + - @@ -309,7 +311,7 @@ - + diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml index cbc708e20..0340746aa 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml @@ -24,14 +24,14 @@ - + - + @@ -67,14 +67,14 @@ - + - + @@ -109,14 +109,14 @@ - + - + @@ -150,16 +150,16 @@ - + - + - + - + @@ -173,7 +173,7 @@ + inner_z = "LumiCal_max_z+0.009*mm"/> From 5869debb94fb9793789d3fea4abd90168d230f4a Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Tue, 27 Aug 2024 16:23:52 +0200 Subject: [PATCH 027/133] CLD_o2_v07: remove old lumical xml --- .../compact/CLD_o2_v07/LumiCal_o3_v02_04.xml | 188 ------------------ 1 file changed, 188 deletions(-) delete mode 100644 FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml deleted file mode 100644 index cbc708e20..000000000 --- a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_04.xml +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - system:8,barrel:3,layer:8,slice:8,r:32:-16,phi:-16 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 7480cfde05667bc425532b5204449d27fc372ac5 Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Wed, 28 Aug 2024 13:59:36 +0200 Subject: [PATCH 028/133] CLD_o2_v07: InnerTracker: fix envelope overlap between lumical and innertracker --- FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml index e31978c98..1b7a8fa30 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/InnerTracker_o2_v08.xml @@ -39,10 +39,14 @@ + + + + From efe5c02b9cfc59b7d451d6fe4db15c7f094cb83c Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Wed, 28 Aug 2024 14:09:35 +0200 Subject: [PATCH 029/133] Tests: move CLD test to latest model --- FCCee/CLD/compact/README.md | 1 + test/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/FCCee/CLD/compact/README.md b/FCCee/CLD/compact/README.md index c53c2223e..9477865e3 100644 --- a/FCCee/CLD/compact/README.md +++ b/FCCee/CLD/compact/README.md @@ -45,6 +45,7 @@ CLD_o2_v07 This model is based on `CLD_o2_v06` with the following changes: reduced loading time by adding stave assemblies in the tracker barrel. Additionally, a non-cylindrical (polycone) tracking volume was added that excludes the LumiCal. To profit from this feature the `Geant4TVUserParticleHandler` needs to be used in `ddsim`. The definitions for the cylindrical volume were kept to be backwards compatible to the `Geant4TCUserParticleHandler`. +Overlaps related to the LumiCal were fixed that were present in the v06 model CLD_o3_v01 ---------- diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5ba8150b8..a7592f011 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -69,7 +69,7 @@ ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/CLD/compact/FCCee_o1_v05/FCCee_o1_v05.xml --runType=batch -G -N=1 --outputFile=testFCCee_o1_v05.slcio ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) -SET( det_name "CLD_o2_v06" ) +SET( det_name "CLD_o2_v07" ) ADD_TEST( t_test_${det_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/CLD/compact/${det_name}/${det_name}.xml --runType=batch -G -N=1 --outputFile=test${det_name}.slcio ) SET_TESTS_PROPERTIES( t_test_${det_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) From 7f49ac942e45c820c175c21a41de49ae4360ea75 Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Thu, 29 Aug 2024 09:47:25 +0200 Subject: [PATCH 030/133] CLD_o2_v07: account for lumical positioning with difference between primed and unprimed --- FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml | 3 +- .../compact/CLD_o2_v07/LumiCal_o3_v02_05.xml | 29 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml index f63eed8bb..ec7c9bc21 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/CLD_o2_v07.xml @@ -225,7 +225,8 @@ - + + diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml index 0340746aa..3c3f7bf64 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml @@ -24,14 +24,14 @@ - + - + @@ -42,7 +42,7 @@ - + - + @@ -85,7 +85,7 @@ - + - + @@ -127,7 +127,7 @@ - + - + - + - + @@ -172,8 +172,7 @@ + inner_z = "LumiCal_max_z - LumiCal_shield_dz_prime + LumiCal_shield_dz"/> From 53ae8d9c0a25a67880b6378150c59700e14ca0c0 Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Fri, 30 Aug 2024 16:36:54 +0200 Subject: [PATCH 031/133] Fields: correct type to field_type, changed variable name in DD4hep, type still exists as part of handle --- detector/other/FieldMapBrBz.cpp | 1 + detector/other/FieldMapXYZ.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/detector/other/FieldMapBrBz.cpp b/detector/other/FieldMapBrBz.cpp index e14b92519..0978959a9 100644 --- a/detector/other/FieldMapBrBz.cpp +++ b/detector/other/FieldMapBrBz.cpp @@ -38,6 +38,7 @@ namespace { } FieldMapBrBz::FieldMapBrBz() { + field_type = CartesianField::MAGNETIC; type = CartesianField::MAGNETIC; } //ctor diff --git a/detector/other/FieldMapXYZ.cpp b/detector/other/FieldMapXYZ.cpp index 8857cff18..e9e7c2309 100644 --- a/detector/other/FieldMapXYZ.cpp +++ b/detector/other/FieldMapXYZ.cpp @@ -40,6 +40,7 @@ namespace { } FieldMapXYZ::FieldMapXYZ() { + field_type = CartesianField::MAGNETIC; type = CartesianField::MAGNETIC; } //ctor From a3b130311a6929ef7a053e9dbe1cc2a9a4c9f668 Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Fri, 30 Aug 2024 16:38:47 +0200 Subject: [PATCH 032/133] Tests: move one test to something with fieldmaps --- test/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a7592f011..91c3febaa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,9 +15,9 @@ ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../ILD/compact/ILD_l5_v02/ILD_l5_v02.xml --runType=batch -G -N=1 --outputFile=testILD_l5_v02.slcio ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) -SET( test_name "test_ILD_s5_v02" ) +SET( test_name "test_ILD_s5_v08" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" - ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../ILD/compact/ILD_s5_v02/ILD_s5_v02.xml --runType=batch -G -N=1 --outputFile=testILD_s5_v02.slcio ) + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../ILD/compact/ILD_s5_v08/ILD_s5_v08.xml --runType=batch -G -N=1 --outputFile=testILD_s5_v08.slcio ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) SET( test_name "test_ILD_l5_v09" ) From be633b899b72a6d40d855e3400b554401e8d645f Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:18:48 +0200 Subject: [PATCH 033/133] Do not link against podio and EDM4hep dictionaries (#386) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08c8bf3d3..a484b4291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ target_include_directories(${PackageName} PRIVATE ${PROJECT_SOURCE_DIR}/detect target_include_directories(${PackageName}G4 PRIVATE ${PROJECT_SOURCE_DIR}/detector/calorimeter/dual-readout/include ) target_link_libraries(${PackageName} DD4hep::DDCore DD4hep::DDRec DD4hep::DDParsers ROOT::Core detectorSegmentations) -target_link_libraries(${PackageName}G4 DD4hep::DDCore DD4hep::DDRec DD4hep::DDParsers DD4hep::DDG4 ROOT::Core EDM4HEP::edm4hep EDM4HEP::edm4hepDict podio::podio podio::podioDict podio::podioRootIO ${Geant4_LIBRARIES}) +target_link_libraries(${PackageName}G4 DD4hep::DDCore DD4hep::DDRec DD4hep::DDParsers DD4hep::DDG4 ROOT::Core podio::podioRootIO EDM4HEP::edm4hep ${Geant4_LIBRARIES}) if(K4GEO_USE_LCIO) target_link_libraries(${PackageName} LCIO::lcio) From b464a1fb0b954d689f44760f607e3925ba78021f Mon Sep 17 00:00:00 2001 From: jmcarcell Date: Fri, 6 Sep 2024 22:14:05 +0200 Subject: [PATCH 034/133] Add a Key4hepConfig file --- cmake/Key4hepConfig.cmake | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 cmake/Key4hepConfig.cmake diff --git a/cmake/Key4hepConfig.cmake b/cmake/Key4hepConfig.cmake new file mode 100644 index 000000000..1309ed9f8 --- /dev/null +++ b/cmake/Key4hepConfig.cmake @@ -0,0 +1,84 @@ +macro(key4hep_set_compiler_flags) + if (DEFINED KEY4HEP_SET_COMPILER_FLAGS AND NOT KEY4HEP_SET_COMPILER_FLAGS) + return() + endif() + + set(COMPILER_FLAGS "-fPIC -Wall -Wextra -Wpedantic -Wshadow -Wdeprecated") + + if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") + set(COMPILER_FLAGS "${COMPILER_FLAGS} -Winconsistent-missing-override -Wheader-hygiene -fcolor-diagnostics") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color=always") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS}") + +endmacro() + +macro(key4hep_set_build_type) + + # For ccmake and cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "None" "Debug" "Release" "MinSizeRel" "RelWithDebInfo") + + if(NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo + CACHE STRING "Choose the type of build, options are: None, Release, MinSizeRel, Debug, RelWithDebInfo (default)" + FORCE + ) + else() + set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" + CACHE STRING "Choose the type of build, options are: None, Release, MinSizeRel, Debug, RelWithDebInfo (default)" + FORCE + ) + endif() + endif() +endmacro() + +macro(key4hep_set_cxx_standard_and_extensions) + set(CMAKE_CXX_STANDARD 20 CACHE STRING "") + + if(NOT CMAKE_CXX_STANDARD MATCHES "20|23") + message(FATAL_ERROR "Unsupported C++ standard: ${CMAKE_CXX_STANDARD}, supported values are 20 and 23") + endif() + + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + +endmacro() + +macro(key4hep_set_rpath) + # When building, don't use the install RPATH already (but later on when installing) + set(CMAKE_SKIP_BUILD_RPATH FALSE) # don't skip the full RPATH for the build tree + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # use always the build RPATH for the build tree + set(CMAKE_MACOSX_RPATH TRUE) # use RPATH for MacOSX + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # point to directories outside the build tree to the install RPATH + + # Check whether to add RPATH to the installation (the build tree always has the RPATH enabled) + if(APPLE) + set(CMAKE_INSTALL_NAME_DIR "@rpath") + set(CMAKE_INSTALL_RPATH "@loader_path/../lib") # self relative LIBDIR + # the RPATH to be used when installing, but only if it's not a system directory + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "@loader_path/../lib") + endif() + elseif(DEFINED KEY4HEP_SET_RPATH AND NOT KEY4HEP_SET_RPATH) + set(CMAKE_SKIP_INSTALL_RPATH TRUE) # skip the full RPATH for the install tree + else() + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") # install LIBDIR + # the RPATH to be used when installing, but only if it's not a system directory + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") + endif() + endif() +endmacro() + +################################################### + +key4hep_set_compiler_flags() +key4hep_set_build_type() +key4hep_set_cxx_standard_and_extensions() +key4hep_set_rpath() From b80c7c8b0020941755f747919f61f5209be9059a Mon Sep 17 00:00:00 2001 From: jmcarcell Date: Mon, 9 Sep 2024 21:57:23 +0200 Subject: [PATCH 035/133] Update Key4hepConfig.cmake with fixes from https://github.com/key4hep/key4hep-dev-utils/pull/7 --- cmake/Key4hepConfig.cmake | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/Key4hepConfig.cmake b/cmake/Key4hepConfig.cmake index 1309ed9f8..6dd524abe 100644 --- a/cmake/Key4hepConfig.cmake +++ b/cmake/Key4hepConfig.cmake @@ -1,7 +1,8 @@ +# Do not edit this file, it will be overwritten! +# The template file can be found in +# https://github.com/key4hep/key4hep-dev-utils/blob/main/defaults/cmake/Key4hepConfig.cmake + macro(key4hep_set_compiler_flags) - if (DEFINED KEY4HEP_SET_COMPILER_FLAGS AND NOT KEY4HEP_SET_COMPILER_FLAGS) - return() - endif() set(COMPILER_FLAGS "-fPIC -Wall -Wextra -Wpedantic -Wshadow -Wdeprecated") @@ -11,7 +12,10 @@ macro(key4hep_set_compiler_flags) set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color=always") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS}") + if (DEFINED KEY4HEP_SET_COMPILER_FLAGS AND NOT KEY4HEP_SET_COMPILER_FLAGS) + else() + set(CMAKE_CXX_FLAGS "${COMPILER_FLAGS} ${CMAKE_CXX_FLAGS}") + endif() endmacro() From 9e9c87f54addd5149616c5ad1e6974dac2b2ca60 Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:45:51 +0200 Subject: [PATCH 036/133] Use the Key4hepConfig flag to set the standard, compiler flags (#387) --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a484b4291..35697ba60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +include(cmake/Key4hepConfig.cmake) + include(GNUInstallDirs) set(CMAKE_INSTALL_LIBDIR lib) set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) @@ -43,10 +45,6 @@ option(INSTALL_BEAMPIPE_STL_FILES "Download CAD files for building the detailed find_package(DD4hep REQUIRED COMPONENTS DDRec DDG4 DDParsers) -# dd4hep_set_compiler_flags() expects DD4hep_SET_RPATH to be set to ON -# otherwise it will not set the rpath when installing -set(DD4HEP_SET_RPATH ON) -dd4hep_set_compiler_flags() find_package ( ROOT REQUIRED COMPONENTS Geom GenVector) message ( STATUS "ROOT_VERSION: ${ROOT_VERSION}" ) From 76b676e7677b463ea60e1b53e0a4a897a52cff2f Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Thu, 12 Sep 2024 11:19:20 +0200 Subject: [PATCH 037/133] CLD_o2_v07: LumiCalBackShield: change envelope to an assembly instead of algobal union of intersections... No overlaps detected and the finding points on surface does not complain any more --- .../compact/CLD_o2_v07/LumiCal_o3_v02_05.xml | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml index 3c3f7bf64..ccb19b7bc 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml @@ -146,21 +146,16 @@ - - - - - - - - + + + + + - - - - - - + + + + From baa438aafc2d8387108014207c28209f69344c4e Mon Sep 17 00:00:00 2001 From: Andre Sailer Date: Thu, 12 Sep 2024 11:29:00 +0200 Subject: [PATCH 038/133] CLD_o2_v07: LumiCal: replace all envelopes with assemblies at least the lumical specific overlap check with /geometry/test/resolution 300000 is much faster now as well??? --- .../compact/CLD_o2_v07/LumiCal_o3_v02_05.xml | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml index ccb19b7bc..54c8af2f4 100644 --- a/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml +++ b/FCCee/CLD/compact/CLD_o2_v07/LumiCal_o3_v02_05.xml @@ -21,17 +21,13 @@ - - - - + + - - - + @@ -64,17 +60,13 @@ - - - - + + - - - + @@ -106,17 +98,13 @@ - - - - + + - - - + From 5a426489a7e362fec7b322769a49b34743085c29 Mon Sep 17 00:00:00 2001 From: Daniel Jeans Date: Mon, 16 Sep 2024 16:51:21 +0900 Subject: [PATCH 039/133] ILD models: apply Tracker_limits to the volume inside of beampipe and MDI (#388) * apply Tracker_limits to the volume inside of beampipe and related MDI elements --------- Co-authored-by: JEANS Daniel Thomelin Dietrich --- ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml b/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml index 6cfc55ff9..217e2e575 100644 --- a/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml +++ b/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml @@ -3,7 +3,7 @@ - + @@ -151,7 +151,7 @@ - + @@ -183,7 +183,7 @@ - + From 8a7c23281446e8c9f2d99fa8ed5dbd0219e94ed2 Mon Sep 17 00:00:00 2001 From: varnes <150390087+varnes@users.noreply.github.com> Date: Wed, 18 Sep 2024 00:21:25 -0700 Subject: [PATCH 040/133] Fix printout issues in turbine endcap geometry; also add v02 of the geometry (#379) * Fix bug in cell y position for -z endcap * Add v02 of turbine endcal ecal * Fix up some printouts * Fix printouts * Fix printouts * Fix printouts * Resolve conflicts * update for v2 geometry * Fix printouts * Fix printouts * Update to be compatible with v2 segmentation * Fix printout * comment include of DRC in IDEA o1 v3 * IDEA with DRC dedicated test added * fix IDEA with DRC test * apply other SD action to DRC * update IDEA README * still not working... * replace absolute path by cmake variables in ctest * fix test_IDEA_o1_v03 by removing DRC steering file * IDEA+DRC test is now working * Fix a few compiler warnings (#374) * [FCCeeMDI] Use absolute path to import CAD files * ILD_l5_v11: fix a barrel layer ID (#378) * 2nd SIT barrel layer ID corrected; error stemed from outcommenting previous 2nd layer * removed commented layer to avoid any potential issue in the future * copy TrackerBarrel_o1_v06 * copy CLD_o2_v06 to CLD_o2_v07 * update version * Use new TrackerBarrel * TrackerBarrel_o1_v06 remove using namespace std * move NeighbourSurfacesData population into a function * Move LayerLayout population out of the sensor loop * refactor LayerLayout population into function * TrackerBarrel_o1_v06 add assembly stave * add tracking volume * update README * addExtensionsToHCalAllegro * implemented suggestions from discussion * implement comments and improve code readibility * fix failing test and remove unused phi segmentation * fix endcap bitfields and improve readibility * keep ALLEGRO v03 xml file unchanged * adding version nr also for the barrel xml * update hcal xml files to v02 * add back ECalEndcaps_Turbine * remove unused hcal v01 xml files * update READMEs * add HCalTileBarrel_o1_v02_geo.cpp * CLD_o2_v07: start with new lumical to fix overlaps * CLD_o2_v07: fix overlaps in the LumiCal itself Add a lumical_max_z_prime parameter to get the actual end place of the lumical add 7 micron meter to the envelopes. Fix the location and rotation to use the max_z_prime values * CLD_o2_v07: remove old lumical xml * CLD_o2_v07: InnerTracker: fix envelope overlap between lumical and innertracker * Tests: move CLD test to latest model * CLD_o2_v07: account for lumical positioning with difference between primed and unprimed * Fields: correct type to field_type, changed variable name in DD4hep, type still exists as part of handle * Tests: move one test to something with fieldmaps * Do not link against podio and EDM4hep dictionaries (#386) * Add a Key4hepConfig file * Update Key4hepConfig.cmake with fixes from https://github.com/key4hep/key4hep-dev-utils/pull/7 * Use the Key4hepConfig flag to set the standard, compiler flags (#387) * CLD_o2_v07: LumiCalBackShield: change envelope to an assembly instead of algobal union of intersections... No overlaps detected and the finding points on surface does not complain any more * CLD_o2_v07: LumiCal: replace all envelopes with assemblies at least the lumical specific overlap check with /geometry/test/resolution 300000 is much faster now as well??? * ILD models: apply Tracker_limits to the volume inside of beampipe and MDI (#388) * apply Tracker_limits to the volume inside of beampipe and related MDI elements --------- Co-authored-by: JEANS Daniel Thomelin Dietrich * Remove unused variable, and add information about o1_v02 to the README file * Initialize all variables * Initialize all variables --------- Co-authored-by: Erich Varnes Co-authored-by: Brieuc Francois Co-authored-by: Alvaro Tolosa Delgado Co-authored-by: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Co-authored-by: BrieucF Co-authored-by: Victor Schwan <162138084+Victor-Schwan@users.noreply.github.com> Co-authored-by: Leonhard Reichenbach Co-authored-by: michaela mlynarikova Co-authored-by: Andre Sailer Co-authored-by: jmcarcell Co-authored-by: Daniel Jeans Co-authored-by: JEANS Daniel Thomelin Dietrich --- .../ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml | 8 +- .../ECalEndcaps_Turbine_calibration.xml | 8 +- .../ECalEndcap_Turbine_o1_v01_geo.cpp | 66 +- .../ECalEndcap_Turbine_o1_v02_geo.cpp | 671 ++++++++++++++++++ detector/calorimeter/README.md | 5 +- .../FCCSWEndcapTurbine_k4geo.h | 4 +- .../src/FCCSWEndcapTurbine_k4geo.cpp | 73 +- 7 files changed, 787 insertions(+), 48 deletions(-) create mode 100644 detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml index 547053962..ac5b7f2ef 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml @@ -43,6 +43,11 @@ + + + + + @@ -51,6 +56,7 @@ + @@ -108,7 +114,7 @@ - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml index 3d07d3671..1df7dd3af 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml @@ -35,6 +35,11 @@ + + + + + @@ -43,6 +48,7 @@ + @@ -100,7 +106,7 @@ - + diff --git a/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp b/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp index 51d79a656..4a4c43822 100644 --- a/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp +++ b/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp @@ -1,4 +1,5 @@ #include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" #include "TMatrixT.h" // todo: remove gaudi logging and properly capture output @@ -83,18 +84,18 @@ namespace det { float BladeAngle = genericBladeElem.attr(_Unicode(angle)); bool decreaseAnglePerWheel = genericBladeElem.attr(_Unicode(decreaseAnglePerWheel)); - lLog << MSG::DEBUG << "Making wheel with inner, outer radii " << ri << ", " << ro << std:: endl; - lLog << MSG::DEBUG << "Blade angle is " << BladeAngle << "; decrease angle per wheel? " << decreaseAnglePerWheel << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Making wheel with inner, outer radii %f, %f", ri, ro); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Blade angle is %f; decrease angle per wheel? ", BladeAngle, decreaseAnglePerWheel); dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); double grmin = dim.rmin1(); - lLog << MSG::DEBUG << "delZ is " << delZ << endmsg; + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "delZ is %f", delZ); if (decreaseAnglePerWheel) { float tubeFracCovered = delZ/(2*grmin*TMath::Tan(BladeAngle)); BladeAngle = TMath::ATan(delZ/(2*ri*tubeFracCovered)); } if (TMath::Abs(TMath::Tan(BladeAngle)) < delZ/(2.*ri)) { - lLog << MSG::ERROR << "The requested blade angle is too small for the given delZ and ri values. Please adjust to at least " << TMath::ATan(delZ/(2.*ri))*180./TMath::Pi() << " degrees!" << endmsg; + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v01", "The requested blade angle is too small for the given delZ and ri values. Please adjust to at least %f degrees!", TMath::ATan(delZ/(2.*ri))*180./TMath::Pi() ); return; } @@ -106,7 +107,7 @@ namespace det { float CladdingThick = claddingElem.attr(_Unicode(thickness)); float AbsThickMin = absBladeElem.attr(_Unicode(thickness))-(GlueThick+CladdingThick); if (AbsThickMin < 0.) { - lLog << MSG::ERROR << "Error: requested absorber thickness is negative after accounting for glue and cladding thickness" << endmsg; + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v01", "Error: requested absorber thickness is negative after accounting for glue and cladding thickness"); } float ElectrodeThick = electrodeBladeElem.attr(_Unicode(thickness)); float LArgapi = nobleLiquidElem.attr(_Unicode(gap)); @@ -127,7 +128,7 @@ namespace det { bool scaleBladeThickness = absBladeElem.attr(_Unicode(scaleThickness)); float bladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor)); - lLog << MSG::DEBUG << "nUnitCells: " << nUnitCells << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "nUnitCells: %d", nUnitCells); float AbsThicki = AbsThickMin; // make volumes for the noble liquid, electrode, and absorber blades @@ -148,7 +149,7 @@ namespace det { double leftoverS = (circ - nUnitCells*delrPhiNoGap); double delrPhiGapOnly = leftoverS/(2*nUnitCells); LArgapi = delrPhiGapOnly*TMath::Sin(BladeAngle); - lLog << MSG::DEBUG << "LArGap at inner radius is " << LArgapi << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "LArGap at inner radius is %f", LArgapi); // now find gap at outer radius circ = 2*TMath::Pi()*ro; @@ -193,7 +194,7 @@ namespace det { } else if (allNonActiveNotSensitive) { numNonActiveLayers = 1; } else { - lLog << MSG::ERROR << "Some non-active layers are sensitive and others are not -- this is likely a misconfiguration"; + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v01", "Some non-active layers are sensitive and others are not -- this is likely a misconfiguration"); } float delrNonActive = (ro-ri)/numNonActiveLayers; @@ -201,14 +202,14 @@ namespace det { for (unsigned iLayer = 0; iLayer < numNonActiveLayers; iLayer++) { float roLayer = riLayer + delrNonActive; - lLog << MSG::INFO << "Making layer in inner, outer radii " << riLayer << " " << roLayer << endmsg; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Making layer with inner, outer radii %f, %f", riLayer, roLayer); if (scaleBladeThickness) { AbsThicko = AbsThicki + bladeThicknessScaleFactor*((roLayer/riLayer)-1.)*AbsThicki; } else { AbsThicko = AbsThicki; } - lLog << MSG::DEBUG << "Inner and outer absorber thicknesses " << AbsThicki << " " << AbsThicko << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Inner and outer absorber thicknesses %f, %f ", AbsThicki, AbsThicko); dd4hep::Solid claddingLayer = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, roLayer, riLayer, BladeAngle, delZ ); dd4hep::Solid glueLayer = buildOneBlade(AbsThicki+GlueThick, AbsThicko+GlueThick, xRange, roLayer, riLayer, BladeAngle, delZ ); @@ -264,8 +265,8 @@ namespace det { leftoverS = (circ - nUnitCells*delrPhiNoGap); delrPhiGapOnly = leftoverS/(2*nUnitCells); LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); - lLog << MSG::DEBUG << "Outer LAr gap is " << LArgapo << endmsg ; - lLog << MSG::INFO << "Inner and outer thicknesses of noble liquid volume " << ElectrodeThick+LArgapi*2 << " " << ElectrodeThick+LArgapo*2 << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Outer LAr gap is %f", LArgapo) ; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Inner and outer thicknesses of noble liquid volume %f, %f", ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2); dd4hep::Solid electrodeBladeAndGapLayer = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange, roLayer, riLayer, BladeAngle, delZ); @@ -289,12 +290,12 @@ namespace det { LArgapi = LArgapo; AbsThicki = AbsThicko; } - lLog << MSG::INFO << "ECal endcap materials: nobleLiquid: " << nobleLiquidElem.materialStr() << " absorber: " << absBladeElem.materialStr() << " electrode: " << electrodeBladeElem.materialStr() << endmsg; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECal endcap materials: nobleLiquid: %s absorber %s electrode %s", nobleLiquidElem.materialStr().c_str(), absBladeElem.materialStr().c_str(), electrodeBladeElem.materialStr().c_str() ); int nUnitCellsToDraw = nUnitCells; // nUnitCellsToDraw = 2; - lLog << MSG::INFO << "Number of unit cells "<< nUnitCells << endmsg; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Number of unit cells %d", nUnitCells); // place all components of the absorber blade inside passive volume @@ -310,7 +311,7 @@ namespace det { dd4hep::PlacedVolume absBladeVol_pv = glueLayerVols[iLayer].placeVolume(absBladeLayerVol, posLayer); absBladeVol_pv.addPhysVolID("subtype", 0); // 0 = absorber, 1 = glue, 2 = cladding - lLog << MSG::DEBUG << "Blade layer, rho is " << iLayer << " " << absBladeVol_pv.position().Rho() << " " << roLayer/2. << endmsg; + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01_geo", "Blade layer, rho is %d, %f, %f", iLayer, absBladeVol_pv.position().Rho(), roLayer/2.); absBladeVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); riLayer = roLayer; @@ -387,10 +388,9 @@ namespace det { double zminLayer = getZmin(riLayer, BladeAngle, delZ); dd4hep::Position posLayer(0,0,(zminLayer-zminri+roLayer-ro)/2.); - std::cout << "for active, riLayer, ri, roLayer, ro = " << riLayer << " " << ri << " " << roLayer << " " << ro << std::endl; dd4hep::PlacedVolume LArVol_pv(activeVol.placeVolume(LArTotalLayerVol, posLayer)); - lLog << MSG::DEBUG << "LAr layer: " << iLayer << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "LAr layer: %d", iLayer ); LArVol_pv.addPhysVolID("layer", iWheel*ECalEndcapNumCalibLayers+iLayer); riLayer = roLayer; @@ -404,7 +404,7 @@ namespace det { float phi = (iUnitCell-nUnitCellsToDraw/2)*2*TMath::Pi()/nUnitCells; float delPhi = 2*TMath::Pi()/nUnitCells; - lLog << MSG::DEBUG << "Placing blade, ro, ri = " << ro << " " << ri << endmsg; + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Placing blade, ro, ri = %f %f", ro, ri); TGeoRotation tgr; tgr.RotateZ(BladeAngle*180/TMath::Pi()); tgr.RotateX(-phi*180/TMath::Pi()); @@ -466,7 +466,7 @@ namespace det { - lLog << MSG::DEBUG << "LArTotalLayerVols.size = " << LArTotalLayerVols.size() << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "LArTotalLayerVols.size = %d", LArTotalLayerVols.size()); } @@ -510,17 +510,17 @@ namespace det { dd4hep::Tube bathOuterShape(bathRmin, bathRmax, bathDelZ); // make it 4 volumes + 5th for detector envelope dd4hep::Tube bathAndServicesOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), caloDim.dz()); // make it 4 volumes + 5th for detector envelope - lLog << MSG::INFO << "Cryostat front thickness is " << cryoDim.rmin2() << endmsg; + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat front thickness is %f", cryoDim.rmin2() ); if (cryoThicknessFront > 0) { // 1. Create cryostat dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); dd4hep::Tube cryoBackShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); - lLog << MSG::INFO << "ECAL endcap cryostat: front: rmin (cm) = " << cryoDim.rmin1() << " rmax (cm) = " << cryoDim.rmin2() << " dz (cm) = " << cryoDim.dz() << endmsg; - lLog << MSG::INFO << "ECAL encdap cryostat: back: rmin (cm) = " << cryoDim.rmax1() << " rmax (cm) = " << cryoDim.rmax2() << " dz (cm) = " << cryoDim.dz() << endmsg; - lLog << MSG::INFO << "ECAL endcap cryostat: side: rmin (cm) = " << cryoDim.rmin2() << " rmax (cm) = " << cryoDim.rmax1() << " dz (cm) = " << cryoDim.dz() - caloDim.dz() << endmsg; - lLog << MSG::INFO << "Cryostat is made out of " << cryostat.materialStr() << endmsg; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECAL endcap cryostat: front: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f ", cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECAL encdap cryostat: back: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECAL endcap cryostat: side: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz() - caloDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat is made out of %s", cryostat.materialStr().c_str() ); dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); @@ -533,19 +533,19 @@ namespace det { cryoFrontVol.setSensitiveDetector(aSensDet); cryoFrontPhysVol.addPhysVolID("cryo", 1); cryoFrontPhysVol.addPhysVolID("type", sidetype+1); - lLog << MSG::INFO << "Cryostat front volume set as sensitive" << endmsg; + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat front volume set as sensitive"); } if (cryoBackSensitive) { cryoBackVol.setSensitiveDetector(aSensDet); cryoBackPhysVol.addPhysVolID("cryo", 1); cryoBackPhysVol.addPhysVolID("type", sidetype+2); - lLog << MSG::INFO << "Cryostat back volume set as sensitive" << endmsg; + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat back volume set as sensitive" ); } if (cryoSideSensitive) { cryoSideVol.setSensitiveDetector(aSensDet); cryoSidePhysVol.addPhysVolID("cryo", 1); cryoSidePhysVol.addPhysVolID("type", sidetype+3); - lLog << MSG::INFO << "Cryostat front volume set as sensitive" << endmsg; + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat front volume set as sensitive"); } dd4hep::DetElement cryoFrontDetElem(caloDetElem, "cryo_front", 0); cryoFrontDetElem.setPlacement(cryoFrontPhysVol); @@ -558,9 +558,7 @@ namespace det { // 2. Create noble liquid bath std::string nobleLiquidMaterial = nobleLiquid.materialStr(); dd4hep::Volume bathVol(nobleLiquidMaterial + "_bath", bathOuterShape, aLcdd.material(nobleLiquidMaterial)); - lLog << MSG::INFO << "ECAL endcap bath: material = " << nobleLiquidMaterial << " rmin (cm) = " << bathRmin - << " rmax (cm) = " << bathRmax << " dz (cm) = " << caloDim.dz() << " thickness in front of ECal (cm) = " << caloDim.rmin() - cryoDim.rmin2() - << " thickness behind ECal (cm) = " << cryoDim.rmax1() - caloDim.rmax() << endmsg; + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECAL endcap bath: material = %s rmin (cm) = %f rmax (cm) = %f, dz (cm) = %f, thickness in front of ECal (cm) = %f, thickness behind ECal (cm) = %f", nobleLiquidMaterial.c_str(), bathRmin, bathRmax, caloDim.dz(), caloDim.rmin() - cryoDim.rmin2(), cryoDim.rmax1() - caloDim.rmax()); dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); // 3. Create detector structure @@ -569,7 +567,7 @@ namespace det { dd4hep::xml::DetElement supportTubeElem = calo.child(_Unicode(supportTube)); unsigned nWheels = supportTubeElem.attr(_Unicode(nWheels)); - lLog << MSG::INFO << "Will build " << nWheels << " wheels" << endmsg; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Will build %d wheels", nWheels); double rmin = bathRmin; double rmax = bathRmax; float radiusRatio = pow(rmax/rmin, 1./nWheels); @@ -604,7 +602,7 @@ namespace det { dd4hep::PlacedVolume bathPhysVol = aEnvelope.placeVolume(bathVol); bathDetElem.setPlacement(bathPhysVol); - lLog << MSG::DEBUG << "Total number of modules: " << iModule << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Total number of modules: %d", iModule); return; } @@ -634,11 +632,9 @@ createECalEndcapTurbine(dd4hep::Detector& aLcdd, dd4hep::xml::Handle_t aXmlEleme // dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); // dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); - lLog << MSG::DEBUG << "Placing dector on the positive side: (cm) " << dim.z_offset() << " with min, max radii " << dim.rmin1() << " " << dim.rmax1() << endmsg; + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Placing detector on the positive side: (cm) %f with min, max radii %f %f",dim.z_offset(), dim.rmin1(), dim.rmax1() ); unsigned iModule = 0; buildOneSide_Turbine(aLcdd, aSensDet, envelopeVol, aXmlElement, iModule); - // lLog << MSG::DEBUG << "Placing dector on the negative side: (cm) " << -dim.z_offset() << " with min, max radii " << dim.rmin1() << " " << dim.rmax() << endmsg; - // buildOneSide_Turbine(aLcdd, aSensDet, envelopeNegativeVol, aXmlElement, -1, iModule); dd4hep::Assembly endcapsAssembly("ECalEndcaps_turbine"); diff --git a/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp b/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp new file mode 100644 index 000000000..a8fcafdc5 --- /dev/null +++ b/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp @@ -0,0 +1,671 @@ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "TMatrixT.h" + +// todo: remove gaudi logging and properly capture output +#define endmsg std::endl +#define lLog std::cout +namespace MSG { + const std::string ERROR = " Error: "; + const std::string DEBUG = " Debug: "; + const std::string INFO = " Info: "; +} + +namespace det { + + namespace ECalEndcap_Turbine_o1_v02 { + unsigned ECalEndCapElementCounter = 0; + + unsigned ECalEndcapNumCalibLayers; + + double tForArcLength(double s, double bladeangle, double delZ, double r) { + + // some intermediate constants + double zpos = delZ/2.; + double zp = zpos/TMath::Tan(bladeangle); + double b = zp/(TMath::Sqrt(r*r-zp*zp)); + double c = (TMath::Tan(s/r) +b)/(1.-b*TMath::Tan(s/r)); + double d = c*c*r*r/(1+c*c); + return (TMath::Sqrt(d)-zp)*TMath::Sin(bladeangle); + + // try approximating the arclength as dx. Less accurate, but that + // approximation is used in calculating the LAr gap, so maybe this + // will make it more consistent? + //return s*TMath::Sin(bladeangle); + + } + + // return position of the inner edge of a blade + double getZmin(double r, double bladeangle, double delZ) { + // r: distance from the beamline + // bladeangle: angle of turbine blades wrt xy plane, in radians + // delZ: z extent of the blades + return TMath::Sqrt(r*r - ((delZ/2)/TMath::Tan(bladeangle))*((delZ/2)/TMath::Tan(bladeangle))); + } + + dd4hep::Solid buildOneBlade(double thickness_inner, + double thickness_outer, + double width, + double ro, double ri, + double bladeangle, + double delZ) + { + + dd4hep::Solid shapeBeforeSubtraction; + + // set max and min extent of the blade (along the z axis in the body frame) + double zmax = ro; + double zmin = getZmin(ri, bladeangle, delZ); + + dd4hep::Trd2 tmp1(thickness_inner/2., thickness_outer/2., width/2., width/2., (zmax-zmin)/2. ); + shapeBeforeSubtraction = tmp1; + + dd4hep::Tube allowedTube(ri, ro, delZ); + + return dd4hep::IntersectionSolid (shapeBeforeSubtraction, allowedTube, dd4hep::Transform3D(dd4hep::RotationZYX( 0, TMath::Pi()/2.-bladeangle, TMath::Pi()/2.),dd4hep::Position(0,0, -(zmin+zmax)/2.))); + + } + + void buildWheel(dd4hep::Detector& aLcdd, + dd4hep::SensitiveDetector& aSensDet, + dd4hep::Volume& aEnvelope, + dd4hep::xml::Handle_t& aXmlElement, + dd4hep::DetElement& bathDetElem, + float ri, float ro, float delZ, + unsigned iWheel) { + + + dd4hep::xml::DetElement calorimeterElem = aXmlElement.child(_Unicode(calorimeter)); + dd4hep::xml::DetElement genericBladeElem = calorimeterElem.child(_Unicode(turbineBlade)); + dd4hep::xml::DetElement absBladeElem = genericBladeElem.child(_Unicode(absorberBlade)); + dd4hep::xml::DetElement claddingElem = genericBladeElem.child(_Unicode(cladding)); + dd4hep::xml::DetElement glueElem = genericBladeElem.child(_Unicode(glue)); + dd4hep::xml::DetElement electrodeBladeElem = genericBladeElem.child(_Unicode(electrodeBlade)); + dd4hep::xml::DetElement nobleLiquidElem = genericBladeElem.child(_Unicode(nobleLiquidGap)); + + float BladeAngle = 0.0, AbsThickMin = 0.0, BladeThicknessScaleFactor=0.0; + // hardcode for three wheels + if (iWheel == 0) { + BladeAngle = genericBladeElem.attr(_Unicode(angle1)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness1)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor1)); + } + if (iWheel == 1) { + BladeAngle = genericBladeElem.attr(_Unicode(angle2)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness2)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor2)); + } + if (iWheel == 2) { + BladeAngle = genericBladeElem.attr(_Unicode(angle3)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness3)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor3)); + } + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Making wheel with inner, outer radii %f, %f", ri, ro); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Blade angle is %f ", BladeAngle); + dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "delZ is %f", delZ); + + if (TMath::Abs(TMath::Tan(BladeAngle)) < delZ/(2.*ri)) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v02", "The requested blade angle is too small for the given delZ and ri values. Please adjust to at least %f degrees!", TMath::ATan(delZ/(2.*ri))*180./TMath::Pi() ); + return; + } + + Float_t xRange = delZ/(TMath::Sin(BladeAngle)); + + double delrPhiNoGap; + + float GlueThick = glueElem.attr(_Unicode(thickness)); + float CladdingThick = claddingElem.attr(_Unicode(thickness)); + + AbsThickMin = AbsThickMin-(GlueThick+CladdingThick); + if (AbsThickMin < 0.) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v02", "Error: requested absorber thickness is negative after accounting for glue and cladding thickness"); + } + float ElectrodeThick = electrodeBladeElem.attr(_Unicode(thickness)); + float LArgapi = nobleLiquidElem.attr(_Unicode(gap)); + + bool sameNUnitCells = genericBladeElem.attr(_Unicode(sameNUnitCells)); + char* nUnitCellsStrArr = (char*)genericBladeElem.attr(_Unicode(nUnitCells)).c_str(); + char* nUnitCellsCStr = strtok(nUnitCellsStrArr, " "); + int nUnitCells = -1; + if (!sameNUnitCells) { + for (unsigned i = 0; i < iWheel; i++) { + nUnitCellsCStr = strtok(NULL, " "); + } + std::string nUnitCellsStr = nUnitCellsCStr; + nUnitCells = std::stoi(nUnitCellsStr); + } + int nUnitCellsLeastCommonMultiple = genericBladeElem.attr(_Unicode(nUnitCellsLeastCommonMultiple)); + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "nUnitCells: %d", nUnitCells); + + float AbsThicki = AbsThickMin; + // make volumes for the noble liquid, electrode, and absorber blades + float AbsThicko; + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((ro/ri)-1.)*AbsThicki; + + // Calculate gap thickness at inner layer + double circ = 2*TMath::Pi()*ri; + double x2 =(AbsThickMin+(GlueThick+CladdingThick)+ElectrodeThick)/TMath::Sin(BladeAngle); + double y2 = TMath::Sqrt(ri*ri-x2*x2); + double rPhi1 = ri*TMath::Pi()/2.; + double rPhi2 = ri*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + double leftoverS = (circ - nUnitCells*delrPhiNoGap); + double delrPhiGapOnly = leftoverS/(2*nUnitCells); + LArgapi = delrPhiGapOnly*TMath::Sin(BladeAngle); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "LArGap at inner radius is %f", LArgapi); + + // now find gap at outer radius + circ = 2*TMath::Pi()*ro; + x2 = (AbsThicko+GlueThick+CladdingThick+ElectrodeThick)/TMath::Sin(BladeAngle); + y2 = TMath::Sqrt(ro*ro-x2*x2); + rPhi1 = ro*TMath::Pi()/2.; + rPhi2 = ro*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + leftoverS = (circ - nUnitCells*delrPhiNoGap); + delrPhiGapOnly = leftoverS/(2*nUnitCells); + float LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); + // LArgapo *= 2.; + + dd4hep::Solid absBlade; + float riLayer = ri; + + std::vector claddingLayerVols; + std::vector glueLayerVols; + std::vector absBladeLayerVols; + std::vector LArTotalLayerVols; + std::vector electrodeBladeLayerVols; + + + dd4hep::Solid passiveShape = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, ro, ri, BladeAngle, delZ ); + dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); + + dd4hep::Solid activeShape = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange, ro, ri, BladeAngle, delZ); + dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); + + unsigned numNonActiveLayers = 1; + // check that either all non-active volumes are set to sensitive (for + // sampling fraction calculations) or none are (for normal running) + bool allNonActiveSensitive = ( claddingElem.isSensitive() && + glueElem.isSensitive() && + absBladeElem.isSensitive() && + electrodeBladeElem.isSensitive() ); + bool allNonActiveNotSensitive = ( !claddingElem.isSensitive() && + !glueElem.isSensitive() && + !absBladeElem.isSensitive() && + !electrodeBladeElem.isSensitive() ); + if (allNonActiveSensitive) { + numNonActiveLayers = ECalEndcapNumCalibLayers; + } else if (allNonActiveNotSensitive) { + numNonActiveLayers = 1; + } else { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v02", "Some non-active layers are sensitive and others are not -- this is likely a misconfiguration"); + } + + float delrNonActive = (ro-ri)/numNonActiveLayers; + float delrActive = (ro-ri)/ECalEndcapNumCalibLayers; + + for (unsigned iLayer = 0; iLayer < numNonActiveLayers; iLayer++) { + float roLayer = riLayer + delrNonActive; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Making layer with inner, outer radii %f, %f", riLayer, roLayer); + + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((roLayer/riLayer)-1.)*AbsThicki; + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Inner and outer absorber thicknesses %f, %f ", AbsThicki, AbsThicko); + dd4hep::Solid claddingLayer = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, roLayer, riLayer, BladeAngle, delZ ); + + dd4hep::Solid glueLayer = buildOneBlade(AbsThicki+GlueThick, AbsThicko+GlueThick, xRange, roLayer, riLayer, BladeAngle, delZ ); + + // dd4hep::SubtractionSolid claddingLayer(absGlueCladdingLayer, absGlueLayer); + dd4hep::Solid absBladeLayer = buildOneBlade(AbsThicki, AbsThicko, xRange, roLayer, riLayer, BladeAngle, delZ ); + + // dd4hep::SubtractionSolid glueLayer(absGlueLayer, absBladeLayer); + dd4hep::Volume claddingLayerVol("claddingLayer", claddingLayer, aLcdd.material(claddingElem.materialStr())); + if (claddingElem.isSensitive()) { + claddingLayerVol.setSensitiveDetector(aSensDet); + } + claddingLayerVols.push_back(claddingLayerVol); + + dd4hep::Volume glueLayerVol("glueLayer", glueLayer, aLcdd.material(glueElem.materialStr())); + if (glueElem.isSensitive()) { + glueLayerVol.setSensitiveDetector(aSensDet); + } + glueLayerVols.push_back(glueLayerVol); + + dd4hep::Volume absBladeLayerVol("absBladeLayer", absBladeLayer, aLcdd.material(absBladeElem.materialStr())); + if (absBladeElem.isSensitive()) { + absBladeLayerVol.setSensitiveDetector(aSensDet); + } + absBladeLayerVols.push_back(absBladeLayerVol); + + riLayer = roLayer; + AbsThicki = AbsThicko; + } + + riLayer = ri; + + AbsThicki = AbsThickMin; + + for (unsigned iLayer = 0; iLayer < ECalEndcapNumCalibLayers; iLayer++) { + + float roLayer = riLayer + delrActive; + + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((roLayer/riLayer)-1.)*AbsThicki; + + // now find gap at outer layer + circ = 2*TMath::Pi()*roLayer; + x2 = (AbsThicko+GlueThick+CladdingThick+ElectrodeThick)/TMath::Sin(BladeAngle); + y2 = TMath::Sqrt(roLayer*roLayer-x2*x2); + rPhi1 = roLayer*TMath::Pi()/2.; + rPhi2 = roLayer*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + leftoverS = (circ - nUnitCells*delrPhiNoGap); + delrPhiGapOnly = leftoverS/(2*nUnitCells); + LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Outer LAr gap is %f", LArgapo) ; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Inner and outer thicknesses of noble liquid volume %f, %f", ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2); + + dd4hep::Solid electrodeBladeAndGapLayer = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange, roLayer, riLayer, BladeAngle, delZ); + + dd4hep::Solid electrodeBladeLayer = buildOneBlade(ElectrodeThick, ElectrodeThick, xRange, roLayer, riLayer, BladeAngle, delZ); + + dd4hep::Volume electrodeBladeLayerVol("electrodeBladeLayer", electrodeBladeLayer, aLcdd.material(electrodeBladeElem.materialStr())); + if (electrodeBladeElem.isSensitive()) { + electrodeBladeLayerVol.setSensitiveDetector(aSensDet); + } + electrodeBladeLayerVols.push_back(electrodeBladeLayerVol); + + // dd4hep::SubtractionSolid LArShapeTotalLayer(electrodeBladeAndGapLayer, electrodeBladeLayer); + dd4hep::Volume LArTotalLayerVol("LArTotalLayerVol", electrodeBladeAndGapLayer, aLcdd.material(nobleLiquidElem.materialStr())); + + if ( nobleLiquidElem.isSensitive() ) { + LArTotalLayerVol.setSensitiveDetector(aSensDet); + } + LArTotalLayerVols.push_back(LArTotalLayerVol); + + riLayer = roLayer; + LArgapi = LArgapo; + AbsThicki = AbsThicko; + } + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECal endcap materials: nobleLiquid: %s absorber %s electrode %s", nobleLiquidElem.materialStr().c_str(), absBladeElem.materialStr().c_str(), electrodeBladeElem.materialStr().c_str() ); + + int nUnitCellsToDraw = nUnitCells; + // nUnitCellsToDraw = 2; + + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Number of unit cells %d", nUnitCells); + + // place all components of the absorber blade inside passive volume + + unsigned iLayer = 0; + + riLayer = ri; + + for (auto absBladeLayerVol: absBladeLayerVols) { + + float roLayer = riLayer+delrNonActive; + + dd4hep::Position posLayer(0,0,(riLayer-ri+roLayer-ro)/2.); + dd4hep::PlacedVolume absBladeVol_pv = glueLayerVols[iLayer].placeVolume(absBladeLayerVol, posLayer); + + absBladeVol_pv.addPhysVolID("subtype", 0); // 0 = absorber, 1 = glue, 2 = cladding + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Blade layer, rho is %d, %f, %f", iLayer, absBladeVol_pv.position().Rho(), roLayer/2.); + absBladeVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); + + riLayer = roLayer; + iLayer++; + } + + riLayer = ri; + iLayer =0; + + for (auto glueLayerVol: glueLayerVols) { + + float roLayer = riLayer+delrNonActive; + + dd4hep::Position posLayer(0,0,(riLayer-ri+roLayer-ro)/2.); + dd4hep::PlacedVolume glueVol_pv = claddingLayerVols[iLayer].placeVolume(glueLayerVol, posLayer); + + + glueVol_pv.addPhysVolID("subtype", 1); // 0 = absorber, 1 = glue, 2 = cladding + glueVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); + + // dd4hep::DetElement glueDetElem(passiveDetElem, "glue_",ECalEndCapElementCounter++); + // glueDetElem.setPlacement(glueVol_pv); + + riLayer = roLayer; + iLayer++; + } + + riLayer = ri; + iLayer =0; + + double zminri = getZmin(ri, BladeAngle, delZ); + + for (auto claddingLayerVol: claddingLayerVols) { + + float roLayer = riLayer+delrNonActive; + + double zminLayer = getZmin(riLayer, BladeAngle, delZ); + + dd4hep::Position posLayer(0,0,(zminLayer-zminri+roLayer-ro)/2.); + dd4hep::PlacedVolume claddingVol_pv = passiveVol.placeVolume(claddingLayerVol, posLayer); + + claddingVol_pv.addPhysVolID("subtype", 2); // 0 = absorber, 1 = glue, 2 = cladding + claddingVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); + + // dd4hep::DetElement claddingDetElem(passiveDetElem, "cladding_", ECalEndCapElementCounter++); + // claddingDetElem.setPlacement(claddingVol_pv); + + riLayer = roLayer; + iLayer++; + } + + + riLayer = ri; + iLayer = 0; + + for (auto electrodeBladeLayerVol: electrodeBladeLayerVols) { + + float roLayer = riLayer+delrActive; + + dd4hep::PlacedVolume electrodeBladeVol_pv = LArTotalLayerVols[iLayer].placeVolume(electrodeBladeLayerVol); + electrodeBladeVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); + + riLayer = roLayer; + iLayer++; + } + + riLayer = ri; + iLayer = 0; + + for (auto LArTotalLayerVol: LArTotalLayerVols) { + + float roLayer = riLayer+delrActive; + + double zminLayer = getZmin(riLayer, BladeAngle, delZ); + + dd4hep::Position posLayer(0,0,(zminLayer-zminri+roLayer-ro)/2.); + + dd4hep::PlacedVolume LArVol_pv(activeVol.placeVolume(LArTotalLayerVol, posLayer)); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "LAr layer: %d", iLayer ); + LArVol_pv.addPhysVolID("layer", iWheel*ECalEndcapNumCalibLayers+iLayer); + + riLayer = roLayer; + iLayer++; + } + + for (int iUnitCell = 0; iUnitCell < nUnitCellsToDraw; iUnitCell++) { + + int modIndex = iUnitCell-nUnitCellsToDraw/2; + if (modIndex < 0) modIndex += nUnitCells; + float phi = (iUnitCell-nUnitCellsToDraw/2)*2*TMath::Pi()/nUnitCells; + float delPhi = 2*TMath::Pi()/nUnitCells; + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Placing blade, ro, ri = %f %f", ro, ri); + + TGeoRotation tgr; + tgr.RotateZ(BladeAngle*180/TMath::Pi()); + tgr.RotateX(-phi*180/TMath::Pi()); + tgr.RotateY(90); + + const Double_t *rotMatPtr; + + rotMatPtr = tgr.GetRotationMatrix(); + TMatrixT rotMat(3,3, rotMatPtr); + dd4hep::Rotation3D r3d; + r3d.SetComponents(rotMat(0,0), rotMat(0,1), rotMat(0,2), + rotMat(1,0), rotMat(1,1), rotMat(1,2), + rotMat(2,0), rotMat(2,1), rotMat(2,2)); + + tgr.Clear(); + tgr.RotateZ(BladeAngle*180/TMath::Pi()); + tgr.RotateX(-(phi+delPhi/2.)*180/TMath::Pi()); + tgr.RotateY(90); + + rotMatPtr = tgr.GetRotationMatrix(); + TMatrixT rotMat2(3,3, rotMatPtr); + dd4hep::Rotation3D r3d2; + r3d2.SetComponents(rotMat2(0,0), rotMat2(0,1), rotMat2(0,2), + rotMat2(1,0), rotMat2(1,1), rotMat2(1,2), + rotMat2(2,0), rotMat2(2,1), rotMat2(2,2)); + + riLayer = ri; + + float xCell = ((ro+zminri)/2.)*TMath::Cos(phi); + float yCell = ((ro+zminri)/2.)*TMath::Sin(phi); //ri*TMath::Sin(phi)/6.; + float zCell = 0.; + + dd4hep::Transform3D comCell(r3d, dd4hep::Translation3D(xCell,yCell,zCell)); + + // place passive volume in LAr bath + dd4hep::PlacedVolume passivePhysVol = aEnvelope.placeVolume(passiveVol, comCell); + passivePhysVol.addPhysVolID("module", modIndex*nUnitCellsLeastCommonMultiple/nUnitCells); + passivePhysVol.addPhysVolID("wheel", iWheel); + passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout + dd4hep::DetElement passiveDetElem(bathDetElem, "passive_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); + passiveDetElem.setPlacement(passivePhysVol); + + // place active volume in LAr bath + + xCell = ((ro+zminri)/2.)*TMath::Cos(phi+delPhi/2.); + yCell = ((ro+zminri)/2.)*TMath::Sin(phi+delPhi/2.); //ri*TMath::Sin(phi)/6.; + zCell = 0.; + dd4hep::Transform3D comCell2(r3d2, dd4hep::Translation3D(xCell,yCell,zCell)); + dd4hep::PlacedVolume activePhysVol = aEnvelope.placeVolume(activeVol, comCell2); + activePhysVol.addPhysVolID("module", modIndex*nUnitCellsLeastCommonMultiple/nUnitCells); + activePhysVol.addPhysVolID("wheel", iWheel); + activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout + + dd4hep::DetElement activeDetElem(bathDetElem, "active_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); + activeDetElem.setPlacement(activePhysVol); + + riLayer = ri; + iLayer =0; + + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "LArTotalLayerVols.size = %d", LArTotalLayerVols.size()); + + } + + return; + + } + + void buildOneSide_Turbine(dd4hep::Detector& aLcdd, dd4hep::SensitiveDetector& aSensDet, + dd4hep::Volume& aEnvelope, dd4hep::xml::Handle_t& aXmlElement, + unsigned& iModule) { + + dd4hep::xml::DetElement calo = aXmlElement.child(_Unicode(calorimeter)); + dd4hep::xml::Dimension caloDim(calo.dimensions()); + + + dd4hep::xml::DetElement blade = calo.child(_Unicode(turbineBlade)); + dd4hep::xml::DetElement nobleLiquid = blade.child(_Unicode(nobleLiquidGap)); + + dd4hep::xml::DetElement xmlDetElem = aXmlElement; + std::string nameDet = xmlDetElem.nameStr(); + dd4hep::DetElement caloDetElem(nameDet, xmlDetElem.id()); + + dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); + + //build cryostat + // Retrieve cryostat data + dd4hep::xml::DetElement cryostat = calo.child(_Unicode(cryostat)); + dd4hep::xml::Dimension cryoDim(cryostat.dimensions()); + double cryoThicknessFront = cryoDim.rmin2() - cryoDim.rmin1(); + + dd4hep::xml::DetElement cryoFront = cryostat.child(_Unicode(front)); + dd4hep::xml::DetElement cryoBack = cryostat.child(_Unicode(back)); + dd4hep::xml::DetElement cryoSide = cryostat.child(_Unicode(side)); + bool cryoFrontSensitive = cryoFront.isSensitive(); + bool cryoBackSensitive = cryoBack.isSensitive(); + bool cryoSideSensitive = cryoSide.isSensitive(); + + double bathRmin = caloDim.rmin(); // - margin for inclination + double bathRmax = caloDim.rmax(); // + margin for inclination + double bathDelZ = caloDim.dz(); + dd4hep::Tube bathOuterShape(bathRmin, bathRmax, bathDelZ); // make it 4 volumes + 5th for detector envelope + dd4hep::Tube bathAndServicesOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), caloDim.dz()); // make it 4 volumes + 5th for detector envelope + + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat front thickness is %f", cryoDim.rmin2() ); + + if (cryoThicknessFront > 0) { + // 1. Create cryostat + dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::Tube cryoBackShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); + dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap cryostat: front: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f ", cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL encdap cryostat: back: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap cryostat: side: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz() - caloDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat is made out of %s", cryostat.materialStr().c_str() ); + + dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoSideVol(cryostat.nameStr()+"_side", cryoSideShape, aLcdd.material(cryostat.materialStr())); + dd4hep::PlacedVolume cryoFrontPhysVol = aEnvelope.placeVolume(cryoFrontVol); + dd4hep::PlacedVolume cryoBackPhysVol = aEnvelope.placeVolume(cryoBackVol); + dd4hep::PlacedVolume cryoSidePhysVol = aEnvelope.placeVolume(cryoSideVol); + unsigned sidetype = 0x4; // probably not needed anymore... + if (cryoFrontSensitive) { + cryoFrontVol.setSensitiveDetector(aSensDet); + cryoFrontPhysVol.addPhysVolID("cryo", 1); + cryoFrontPhysVol.addPhysVolID("type", sidetype+1); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat front volume set as sensitive"); + } + if (cryoBackSensitive) { + cryoBackVol.setSensitiveDetector(aSensDet); + cryoBackPhysVol.addPhysVolID("cryo", 1); + cryoBackPhysVol.addPhysVolID("type", sidetype+2); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat back volume set as sensitive" ); + } + if (cryoSideSensitive) { + cryoSideVol.setSensitiveDetector(aSensDet); + cryoSidePhysVol.addPhysVolID("cryo", 1); + cryoSidePhysVol.addPhysVolID("type", sidetype+3); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat side volume set as sensitive" ); + } + dd4hep::DetElement cryoFrontDetElem(caloDetElem, "cryo_front", 0); + cryoFrontDetElem.setPlacement(cryoFrontPhysVol); + dd4hep::DetElement cryoBackDetElem(caloDetElem, "cryo_back", 0); + cryoBackDetElem.setPlacement(cryoBackPhysVol); + dd4hep::DetElement cryoSideDetElem(caloDetElem, "cryo_side", 0); + cryoSideDetElem.setPlacement(cryoSidePhysVol); + } + + // 2. Create noble liquid bath + std::string nobleLiquidMaterial = nobleLiquid.materialStr(); + dd4hep::Volume bathVol(nobleLiquidMaterial + "_bath", bathOuterShape, aLcdd.material(nobleLiquidMaterial)); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap bath: material = %s rmin (cm) = %f rmax (cm) = %f, dz (cm) = %f, thickness in front of ECal (cm) = %f, thickness behind ECal (cm) = %f", nobleLiquidMaterial.c_str(), bathRmin, bathRmax, caloDim.dz(), caloDim.rmin() - cryoDim.rmin2(), cryoDim.rmax1() - caloDim.rmax()); + dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); + + // 3. Create detector structure + double length = dim.dz() * 2.; + double zOffsetEnvelope = -length / 2.; + + dd4hep::xml::DetElement supportTubeElem = calo.child(_Unicode(supportTube)); + unsigned nWheels = supportTubeElem.attr(_Unicode(nWheels)); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Will build %d wheels", nWheels); + double rmin = bathRmin; + double rmax = bathRmax; + float radiusRatio = pow(rmax/rmin, 1./nWheels); + double ro = rmin*radiusRatio; + double ri = rmin; + + float supportTubeThickness=supportTubeElem.thickness(); + unsigned iSupportTube = 0; + + for (unsigned iWheel = 0; iWheel < nWheels; iWheel++) { + + dd4hep::Tube supportTube(ro, ro+supportTubeThickness, bathDelZ ); + + dd4hep::Volume supportTubeVol("supportTube", supportTube, aLcdd.material(supportTubeElem.materialStr())); + if (supportTubeElem.isSensitive()) { + supportTubeVol.setSensitiveDetector(aSensDet); + } + dd4hep::PlacedVolume supportTube_pv = bathVol.placeVolume(supportTubeVol, dd4hep::Position(0,0,zOffsetEnvelope + dim.dz() )); + supportTube_pv.addPhysVolID("cryo", 1); + // supportTube_pv.addPhysVolID("side",sign); + supportTube_pv.addPhysVolID("wheel", iWheel); + dd4hep::DetElement supportTubeDetElem(bathDetElem, "supportTube_"+std::to_string(iWheel), 0); + supportTubeDetElem.setPlacement(supportTube_pv); + + + buildWheel(aLcdd, aSensDet, bathVol, aXmlElement, bathDetElem, ri+supportTubeThickness, ro, bathDelZ*2, iWheel); + ri = ro; + ro *= radiusRatio; + if (ro > rmax) ro = rmax; + iSupportTube++; + } + + + dd4hep::PlacedVolume bathPhysVol = aEnvelope.placeVolume(bathVol); + bathDetElem.setPlacement(bathPhysVol); + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Total number of modules: %d", iModule); + + + return; + } + + + + static dd4hep::Ref_t + createECalEndcapTurbine(dd4hep::Detector& aLcdd, dd4hep::xml::Handle_t aXmlElement, dd4hep::SensitiveDetector aSensDet) { + + dd4hep::xml::DetElement xmlDetElem = aXmlElement; + std::string nameDet = xmlDetElem.nameStr(); + int idDet = xmlDetElem.id(); + dd4hep::xml::Dimension dim(xmlDetElem.dimensions()); + dd4hep::DetElement caloDetElem(nameDet, idDet); + dd4hep::xml::Dimension sdType = xmlDetElem.child(_U(sensitive)); + aSensDet.setType(sdType.typeStr()); + + ECalEndcapNumCalibLayers = aLcdd.constant("ECalEndcapNumCalibLayers"); + + + // Create air envelope for one endcap (will be copied to make both endcaps) + dd4hep::Tube endcapShape( dim.rmin1(), dim.rmax1(), dim.dz()); + + dd4hep::Volume envelopeVol(nameDet + "_vol", endcapShape, aLcdd.material("Air")); + + + // dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); + // dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Placing detector on the positive side: (cm) %f with min, max radii %f %f",dim.z_offset(), dim.rmin1(), dim.rmax1() ); + + unsigned iModule = 0; + buildOneSide_Turbine(aLcdd, aSensDet, envelopeVol, aXmlElement, iModule); + + dd4hep::Assembly endcapsAssembly("ECalEndcaps_turbine"); + + // Place the envelope + dd4hep::Transform3D envelopePositiveVolume_tr(dd4hep::RotationZYX( 0 ,0,0), dd4hep::Translation3D(0, 0, dim.z_offset())); + dd4hep::PlacedVolume envelopePositivePhysVol = endcapsAssembly.placeVolume(envelopeVol, envelopePositiveVolume_tr); + envelopePositivePhysVol.addPhysVolID("side", 1); + + dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); + caloPositiveDetElem.setPlacement(envelopePositivePhysVol); + + // make another placement for the negative z endcap + dd4hep::Transform3D envelopeNegativeVolume_tr(dd4hep::RotationZYX( 0 ,0,180*dd4hep::deg), dd4hep::Translation3D(0, 0, -dim.z_offset())); + dd4hep::PlacedVolume envelopeNegativePhysVol = + endcapsAssembly.placeVolume(envelopeVol, envelopeNegativeVolume_tr); + envelopeNegativePhysVol.addPhysVolID("side", -1); + + dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); + caloNegativeDetElem.setPlacement(envelopeNegativePhysVol); + + dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); + dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(endcapsAssembly); + caloDetElem.setPlacement(envelopePhysVol); + envelopePhysVol.addPhysVolID("system", idDet); + return caloDetElem; + } + } +} // namespace det + +DECLARE_DETELEMENT(ECalEndcap_Turbine_o1_v02, det::ECalEndcap_Turbine_o1_v02::createECalEndcapTurbine) diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index ce9c3b869..1306a0a87 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -26,9 +26,12 @@ Original version taken from [FCCDetectors](https://github.com/HEP-FCC/FCCDetecto Sub-detector for the ecal endcaps, with the absorbers and readout boards arranged in a "turbine-like" geometry. -### 01_v01 +### o1_v01 Initial implementation. A custom segmentation that creates readout cells and constant radius and z is also included (FCCSWEndcapTurbine_k4geo). +### o1_v02 +Changes wrt o1_v01: Added flexibility to configure the wheels individual (to allow for example the possibiliity of having different blade angles in each). This is still a work in progress, so o1_v01 should be used for integrated tests. + ## HCalTileBarrel This sub-detector makes calorimeter barrel. It is used in ALLEGRO detector concept. diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h index b4abef119..3b1d93bb6 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h @@ -129,7 +129,9 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { protected: /// turbine blade angle - double m_bladeAngle; + std::vector m_bladeAngle; + /// least common multiple of number of unit cells + int m_nUnitCellsLeastCommonMultiple; /// the number of bins in phi int m_phiBins; /// the coordinate offset in phi diff --git a/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp b/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp index c25d00625..a3cf00b35 100644 --- a/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp @@ -21,15 +21,41 @@ namespace DDSegmentation { registerIdentifier("identifier_side", "Cell ID identifier for side", m_sideID, "side"); dd4hep::Detector* dd4hepgeo = &(dd4hep::Detector::getInstance()); + m_bladeAngle.clear(); + + try { + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle1")); + std::cout << "Blade angle 1 is " << m_bladeAngle[0] << std::endl; + } + catch(...) { + std::cout << "Blade angle 1 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle2")); + std::cout << "Blade angle 2 is " << m_bladeAngle[1] << std::endl; + } + catch(...) { + std::cout << "Blade angle 2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } try { - m_bladeAngle = dd4hepgeo->constant("BladeAngle"); - std::cout << "Blade angle is " << m_bladeAngle << std::endl; + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle3")); + std::cout << "Blade angle 3 is " << m_bladeAngle[2] << std::endl; } catch(...) { - std::cout << "Blade angle not found in detector metadata, exiting..." << std::endl; + std::cout << "Blade angle 3 not found in detector metadata, exiting..." << std::endl; exit(1); } + try { + m_nUnitCellsLeastCommonMultiple = dd4hepgeo->constant("nUnitCellsLeastCommonMultiple"); + } + catch(...) { + std::cout << "nUnitCellsLeastCommonMultiple not found in detector metadata, exiting..." << std::endl; + exit(1); + } + } FCCSWEndcapTurbine_k4geo::FCCSWEndcapTurbine_k4geo(const BitFieldCoder* decoder) : Segmentation(decoder) { @@ -49,15 +75,40 @@ namespace DDSegmentation { registerIdentifier("identifier_wheel", "Cell ID identifier for wheel", m_wheelID, "wheel"); registerIdentifier("identifier_module", "Cell ID identifier for module", m_moduleID, "module"); dd4hep::Detector* dd4hepgeo = &(dd4hep::Detector::getInstance()); + + m_bladeAngle.clear(); + try { - m_bladeAngle = dd4hepgeo->constant("BladeAngle"); - std::cout << "Blade angle is " << m_bladeAngle << std::endl; + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle1")); + std::cout << "Blade angle 1 is " << m_bladeAngle[0] << std::endl; } catch(...) { - std::cout << "Blade angle not found in detector metadata, exiting..." << std::endl; + std::cout << "Blade angle 1 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle2")); + std::cout << "Blade angle 2 is " << m_bladeAngle[1] << std::endl; + } + catch(...) { + std::cout << "Blade angle 2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle3")); + std::cout << "Blade angle 3 is " << m_bladeAngle[2] << std::endl; + } + catch(...) { + std::cout << "Blade angle 3 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_nUnitCellsLeastCommonMultiple = dd4hepgeo->constant("nUnitCellsLeastCommonMultiple"); + } + catch(...) { + std::cout << "nUnitCellsLeastCommonMultiple not found in detector metadata, exiting..." << std::endl; exit(1); } - } @@ -90,12 +141,16 @@ CellID FCCSWEndcapTurbine_k4geo::cellID(const Vector3D& /* localPosition */, con double FCCSWEndcapTurbine_k4geo::phi(const CellID& cID) const { CellID iModule = _decoder->get(cID, m_moduleID); - double phiCent = twopi*(iModule+0.5)/78336; + CellID iWheel = _decoder->get(cID, m_wheelID); + + double phiCent = twopi*(iModule+0.5)/m_nUnitCellsLeastCommonMultiple; double rhoLoc = rho(cID); double zLoc = TMath::Abs(z(cID))-m_offsetZ - 45; // hard-code midpoint in z for now - double zCotBladeAngle = zLoc/TMath::Tan(m_bladeAngle); + + double zCotBladeAngle = zLoc/TMath::Tan(m_bladeAngle[iWheel]); + double x = zCotBladeAngle; double y = TMath::Sqrt(rhoLoc*rhoLoc - x*x); // rotate about z axis by phiCent From 72c9480c116cd80dab6d7eb96c8a3abf955bd152 Mon Sep 17 00:00:00 2001 From: Armin Ilg Date: Thu, 19 Sep 2024 17:45:16 +0200 Subject: [PATCH 041/133] IDEA vertex and silicon wrapper for IDEA_o1_v03 (#363) * Leaving ZPlanarTracker as it is but instead make a new VertexBarrel_o1_v01_geo module * Added ability to have flex and support consisting of multiple components, ability to tilt whole modules. * First implementation of IDEA end-cap and adaption of barrel * Version of Barrel with correct sensitive surfaces (use teveDisplay to show them) * Improved structure of barrel detectors (layer - ladder+sensors) * Progress: The surface arrows are now displayed in the endcap, but the volumes not yet * Whole barrel is properly visible in teveDisplay, but don't mange to make good assembly structure * Also endcap shows all volumes in teveDisplay, but bad hierarchy * Endcap and barrel now run through ddsim overlap checker (overlaps still there) * IDEA Vertex working with ddsim, some overlaps still to be understood * Not working teveDisplay, endcap digitisation not working probably therefore * Fixed endcap, all surfaces visible in teveDisplay, managed to run ddsim and fccRec_e4h with vertex digitisation, but no vertices reco'd yet, bad hierarchy again * Non-working version, the sensitive volumes are wrong, no idea why, use the previous commit * Bad hierarchy, but otherwise working * Found way to remove mother volumes in sensitive and passives. Now all overlaps in Endcap gone * Removing unneeded lines * Recomputing bounding boxes, hasn't fixed the problem yet * Adding IDEA as FCCee_IDEA_o1_v01, not final yet, need to make sure that latest beam pipe and other files are used. There's also still an overlap between the CAD-imported vertex support and the vertex barrel * Adding again deleted file * Reverting changes to VertexBarrel_o1_v01_geo.cpp * Adding scripts * Addressing comments from MR, adding some tests for DDCAD files * Add DDCAD test * Adding test * Renamed constructor files * Changing naming convention to Vertex inner barrel, vertex outer barrel and vertex disks, adding working DDCAD import of vertex inner barrel support (using material budget estimation from FCCSW not working yet though, need to use g4MaterialScan). Adding example on how I install k4geo locally (install.sh) * SingleShape_geo not needed for DDCAD import, instead using DD4hep_TestShape_Creator from DD4hep * Changing CAD shape name * Adding all plotting scripts * Renaming constructor files, adding in latest changes * Add README file for the vertex detector constructors, remove HOM absorber * Make scripts working with command line input argument for xml file * Change folder structure as sugested by Brieuc * Fixed some paths * Testing test... * Increasing timeout for IDEA test * Fixing test * Using .obj file for Vertex inner barrel support instead of .stl, running now without Geant4 exceptions * Adding back hierarchy of vertex detector elements, visualisation does not work in teveDisplay (for the whole vertex) or in geoDisplay (for the disks), but is working when using scripts/build_view.sh * Add missing periphery components to outer barrel * Fix simulate script * ATLASPix3 modules were 90 degrees rotated, now fixed. Furthermore wrong distance between individual chips fixed * Removing unnecessary line * Test is working now for the key4hep nightly release, decreasing large timeout again * Reducing hierarchy by one level in the endcaps, so that it's visible in geoDisplay. Apparently three levels of hierarchy of assemblies is the limit, otherwise geoDisplay will not show the volumes. It is not working in teveDisplay however * Small script fixes * Moving IDEA scripts to FCCee/scripts as they are generally usable * Fixing paths using a /afs/cern.ch/user/a/afehr/lcgeo global variable * Cannot use environmental variable before it's defined * Found another way to get the correct paths for the scripts, using /cvmfs/sw-nightlies.hsf.org/key4hep/releases/2023-07-22/x86_64-centos7-gcc12.2.0-opt/k4geo/1c08affe597cf3b1c10c4e81cdbc95ab9e4a4d23=develop-q7e4mj/share/k4geo/compact for the DDCAD import in Vertex_IDEA_o1_v01.xml, should work once merged and added to the key4hep nightly * Deleting utils inside of IDEA folder * Addressing last comments from Andre * Adding suggested change to dd4hep2root * Addressing comments by Andre, still need to copy beam pipe from CLD * Using same beampipe as in CLD_o2_v05 * Renaming beampipe to match with CLD beampipe (identical at the moment, change name when they differ) * Fixing test and have correct name for beampipe also in main xml file. The test will only run once the IDEA folder is in the nightly Key4hep software stack * Moved volume creation within main part of program, so that correct volume names can be assigned. Furthermore changed DetElements in barrel constructor so that they can be properly accessed in k4RecTracker * Added functionality to have end of stave structures in vertex barrel. This is applied in the IDEA vertex detector. Other than this, also the width of the sensor support in the vertex barrel was corrected to be only 4.4 mm wide (instead of 8.8) * Added end-of-stave structures or proxies as well for the outer barrel, only end-cap missing * Making proxy end-of-stave structure smaller to not have overlaps * Unified description of readout and support structures, now called components. Multiple components can be added per stave and the name will be used to name the corresponding assembly. Furthermore fixed the sensitive/periphery regions in VTXIB layers 2 and 3 to be correct * Fixing volIDs in barrel, adding end-of-stave structures in barrel and end-cap. * Correcting material in beam pipe * Fixing test and for the moment comment out the vertex inner barrel support as it will fail the test, since the CAD file cannot be found. After the IDEA detector is in a nightly release, then the CAD file will be found and we can include these lines in the xml again * Changing to IDEA_o1_v02 * Add back vertex inner barrel support, other minor changes * Adding first version of Si wrapper * Add PC * Thanks to changes in FCCSW and DD4hep, now plotstyle.py from FCCSW can be imported directly and the DDCAD file can be imported in the same way as .xml files * Use VTXOB_r_max from dimensions in vertex detector. Not done yet for z max * Changing L3 of vertex inner barrel, and added possibility to have every second stave offset in r * Surfaces finally working, had to decrease the hierarchy of DetElements * Making detector constructors more efficient (more intermediate assemblies) and finalisation of first Si wrapper layout * Removing one level of DetElements, as otherwise the surfaces are not correctly added by Surfacemanager * Made the hole in Si wrapper barrel larger, not compatible with numbers from https://fcc-ee-detector-full-sim.docs.cern.ch/IDEA/ * Improving description of IDEA vertex disks, they should now match the design quite well. It includes rotation of disks of the two sides relative to each other and the correct staggering of staves in the disks * Updating VertexSupport to have origin at the IP and to have already a correct rotation * Correctly renaming VertexSupport * Removing overlaps in Si wrapper and vertex, filling holes in Si wrapper coverage with shorter tile and fixing the subdetector assembly of the Si wrapper * scripts/save_detector_to_root.sh can be provided with a second argument to define the output file name * Fixing change coming from wrong git rebase * Adding default values to offset in vertexBarrel end_z structures * Making Si Disk go to larger radii, as otherwise a large area is not covered by the barrel. Will need to investigate to instead make the barrel longer or put the disk closer to the IP * Fix some overlap * Put mistakingly deleted files back * Revert some stupid git mistake * Fixing some other git mistakes * Remove whitespace change * Remove whitespace change * Adding default dz value for endOfStave structure * Getting rid of one overlap, there is still one hidden somewhere in the Si wrapper * Trying to pass test without the DDCAD vertex support * Adding vertex support again as this is not the culprit * Reducing vertex clearance from IP further so that Vertex disks are fully in envelope * Adding module functionality to ZPlanarTracker_geo * Removing unnecessary includes in vertex constructors and fix VertexBarrel constructor problem * Increasing timeout for IDEA test * Small changes to fix visualisation * Merging inner and outer vertex barrel into one constructor to enable simper usage of CLD Reconstruction. Since the sensors have different pitches, the segmentation is removed. Need to find a solution to add different segmentations for different layers in the same detector * Adding first version of curved vertex * Revert "Merging inner and outer vertex barrel into one constructor to enable simper usage of CLD Reconstruction. Since the sensors have different pitches, the segmentation is removed. Need to find a solution to add different segmentations for different layers in the same detector" This reverts commit 96b28244490bd027c964eaad0b25a2188884c0f3. * Changing description * Separating inner vertex and outer vertex into two different files, so that inner vertex can more simply be replaced by curved vertex concept * Adding CLD with IDEA vertex * Removing assembly that is put into world and instead place the envelope (volume) there. Leave assemblies in detector constructors as they are * Adding LiquidNDecane to list, to ignore beam pipe material budget * Adding some way to reduce overlaps, but the curved structures require a very high artificial separation in r not to be detected as overlaps. Remaining overlap is between the envelopes and between the inner barrel envelope and beam pipe * Fix disk envelope * Changes to CLDwithIDEAvertex * Getting rid of overlap between endcap and outer barrel envelopes * Commenting out CAD volume for the moment * Fixing detID * Fixed all overlaps except for between disk environment and first disk. This is difficult to fix since the inner barrel is inserted inside the disks and is inside the space for the first disk, but no actual collision. Dont know yet how to fix * Fix to avoid overlaps * Temp fix for overlaps * Actually working version of CLD with IDEA vertex * Working configuration, fixing orientation of sensitive volumes in vertex inner barrel * Adding install.sh file * IDEA vertex detector outer barrel uses as well Cylindrical constructor, adding support for having multiple wafers/staves in z, have vertex inner and outer barrel in same constructor in order to have same detector ID (needed by iLCSoft), replacing some assemblies by volumes in Cylindrical constructor * Working! * Use same readout names as for CLD * My CLD with IDEA vertex * Making curved vertex asymmetric in layer 3 and 4, removing some longerons, and changing gap to 1.25 mm * Adding ability to have asymmetrical designs for the vertex detector, by using side=+1 or -1, to use a second wafer or stave with a different number of modules * Adding metal layer to curved vertex, fix module id issue by removing pixel segmentation, ... * VertexCylindrical now working with mother volume option (for Silicon wrapper), doing some final checks * Fix extrusion of longerons with mother volume * Fixed flex overlaps * Got rid of ALL overlaps in inner vertex (normal and ultra-light) and outer vertex. Need to include new inner vertex conical support * Removed all overlaps in both detectors. Added the inner vertex tube. Commented out the inner vertex support and the cooling cones as they produce overlaps (with themselves and with the vertex). * Fixed mother volume usage in silicon wrapper * All overlaps gone, also in Silicon Wrapper. Silicon Wrapper performant enough, very quick to build geometry and also easily viewable when exported to root file. Using one very long sensor in the silicon wrapper barrel and large sensors in the disks to reduce number of sensitive surfaces, which was taking very long. Everything else is with the same amount of detail however. Silicon wrapper geometry still the same as presented in Annecy Jan 2024 * Moving to v03 of IDEA, no overlaps found! * Updating my CLD_IDEAvertex * New branch with only IDEA_o1_v03 * Removing changes to v02 * Fixing v02 * Fixing v02, finally * Not working version, investigating * Add bounding boxes to assemblies - fixing bad reconstruction when using iLCSoft track reco * Removing old (non-curved) vertex barrel constructor. * Renaming VertexCylindrical to VertexBarrel and increase version of vertex constructors to o1_v02 * Updating README * Adding curved vertex sensitive surfaces (see DD4hep MR as well) * Final changes to have sensitive VolCylinder surface positioned correctly and having the origin vector pointing outwards * Addressing comments and update ALLEGRO, move some visibilities into the subdetector xml files * Fixing some final things for the PR * Fixing wrong VertexEndcap file * And also o1_v01 endcap file * WIP towards an updated silicon wrapper, with a more realistic geometry. Started with barrel * Adding Silicon Wrapper for ALLEGRO, reverting lumical vis change, formatting, correcting readout for vertex and silicon wrapper in ALLEGRO, adding drift chamber readout ID in ALLEGRO, using built-in pi * Removing mistakingly added drift chamber readout ID * Now have a rough version of how the SiWr updated barrel could look like. Added functionality to define layers without sensors (used for complex support structures), adjusted vertex accordingly * Properties of to-be-added global disk support proxies. Will need feature from SiliconWrapper branch to do this * Start adding disk proxy volumes * Finally made vertex disk supports running correctly (they had a wrongly defined mother volume). DDCAD files look fine in display, but need DD4hep material budget estimation for them (doesn't work with FCCSW estimation) * Renaming VertexBarrel_detailed * Comment out DDCAD files * Rotating inner vertex tube, making insensitive regions in phi for curved vertex * Changed inner vertex tube to use just 200 um of carbon fiber and have a continuous tube for the ultra-light vertex (afte discussions with Fabrizio) * Going full detail for the curved vertex, adding feature to name sensor components * Use as default the classic vertex * Removing again CLDIDEAvertex * For the moment remove updated silicon wrapper * Adding Rohacell to ALLEGRO, no overlaps in vertex/silicon wrapper * Update tests, also change to new vertex and silicon wrapper there * Remove .stl files, add them later in the same way as MDI files * Fixing silicon wrapper path... * Update utils/material_plots.py Co-authored-by: Andre Sailer --------- Co-authored-by: Armin Fehr Co-authored-by: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Co-authored-by: Armin Ilg Co-authored-by: Andre Sailer --- .../compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 5 +- .../compact/ALLEGRO_o1_v03/DectDimensions.xml | 105 +- .../ALLEGRO_o1_v03/SiliconWrapper_o1_v03.xml | 1 + .../VertexComplete_IDEA_o1_v03.xml | 1 + .../ALLEGRO_o1_v03/Vertex_IDEA_o1_v01.xml | 1 - .../compact/ALLEGRO_o1_v03/materials.xml | 7 +- .../DectDimensions_IDEA_o1_v03.xml | 175 +- .../IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml | 8 +- .../IDEA_o1_v03/SiliconWrapper_o1_v03.xml | 838 +++++++ .../VertexComplete_IDEA_o1_v03.xml | 1972 +++++++++++++++++ .../IDEA_o1_v03/Vertex_IDEA_o1_v01.xml | 726 ------ ...erials_o1_v02.xml => materials_o1_v03.xml} | 32 +- FCCee/IDEA/compact/README.md | 3 + detector/tracker/README.md | 10 +- .../VertexBarrel_detailed_o1_v01_geo.cpp | 2 +- .../VertexBarrel_detailed_o1_v02_geo.cpp | 544 +++++ .../VertexEndcap_detailed_o1_v01_geo.cpp | 2 +- .../VertexEndcap_detailed_o1_v02_geo.cpp | 426 ++++ scripts/save_detector_to_root.sh | 3 +- test/compact/DCH_standalone_o1_v02.xml | 2 +- test/compact/IDEA_withDRC_o1_v03.xml | 6 +- utils/material_plots.py | 10 +- utils/material_plots_2D.py | 3 +- 23 files changed, 3985 insertions(+), 897 deletions(-) create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/SiliconWrapper_o1_v03.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/VertexComplete_IDEA_o1_v03.xml delete mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/Vertex_IDEA_o1_v01.xml create mode 100644 FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml create mode 100644 FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml delete mode 100644 FCCee/IDEA/compact/IDEA_o1_v03/Vertex_IDEA_o1_v01.xml rename FCCee/IDEA/compact/IDEA_o1_v03/{materials_o1_v02.xml => materials_o1_v03.xml} (94%) create mode 100644 detector/tracker/VertexBarrel_detailed_o1_v02_geo.cpp create mode 100644 detector/tracker/VertexEndcap_detailed_o1_v02_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index 7f2b2fb3f..fc2ca3b09 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -41,8 +41,9 @@ - - + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/DectDimensions.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/DectDimensions.xml index d100e0a0f..82f00d088 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/DectDimensions.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/DectDimensions.xml @@ -18,36 +18,38 @@ - - - - - + - - - - - - - + + + + + + + + + + + + + - - + + - - - - - - - - - - - + + + + + + + + + + + @@ -79,14 +81,29 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -96,6 +113,16 @@ + + + + + + + + + + @@ -213,18 +240,16 @@ - - + - - + + - - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/SiliconWrapper_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/SiliconWrapper_o1_v03.xml new file mode 120000 index 000000000..70972fa9c --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/SiliconWrapper_o1_v03.xml @@ -0,0 +1 @@ +../../../IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/VertexComplete_IDEA_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/VertexComplete_IDEA_o1_v03.xml new file mode 120000 index 000000000..b0bf97dfa --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/VertexComplete_IDEA_o1_v03.xml @@ -0,0 +1 @@ +../../../IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/Vertex_IDEA_o1_v01.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/Vertex_IDEA_o1_v01.xml deleted file mode 120000 index cfab0871b..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/Vertex_IDEA_o1_v01.xml +++ /dev/null @@ -1 +0,0 @@ -../../../IDEA/compact/IDEA_o1_v03/Vertex_IDEA_o1_v01.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/materials.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/materials.xml index 338606639..4b0956cc5 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/materials.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/materials.xml @@ -236,6 +236,11 @@ + + + + + @@ -243,7 +248,7 @@ - + diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml index e662f7a58..3a6e0fd32 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml @@ -18,47 +18,46 @@ - - - - - - + + - - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + - - - - - - + + - - + + + + + + + - + @@ -83,21 +82,36 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + @@ -105,6 +119,16 @@ + + + + + + + + + + @@ -220,47 +244,34 @@ - - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -269,9 +280,7 @@ - - @@ -281,7 +290,9 @@ - + + + diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml index 949c55eb7..213071c79 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml @@ -7,7 +7,7 @@ @@ -20,7 +20,7 @@ - + @@ -46,13 +46,13 @@ - + - + diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml new file mode 100644 index 000000000..f55707337 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml @@ -0,0 +1,838 @@ + + + + + A Silicon Wrapper layer for the FCC-ee IDEA detector concept with timing to enable excellent PID together with drift chamber. + + Silicon wrapper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + + ${GlobalTrackerReadoutID} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Silicon wrapper disks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml new file mode 100644 index 000000000..a82899dff --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml @@ -0,0 +1,1972 @@ + + + + + A Vertex Detector for the FCC-ee IDEA detector concept, based on the engineered design by Fabrizio Palla and Filippo Bosi (INFN Pisa), implemented in DD4hep by Armin Ilg (UZH) + + Vertex inner barrel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vertex Assembly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vertex Detector Disks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Vertex_IDEA_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Vertex_IDEA_o1_v01.xml deleted file mode 100644 index c38d19da7..000000000 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Vertex_IDEA_o1_v01.xml +++ /dev/null @@ -1,726 +0,0 @@ - - - - - A Vertex Detector for the FCC-ee IDEA detector concept, based on the engineered design by Fabrizio Palla and Filippo Bosi (INFN Pisa) - - Vertex detector - - - - - - - - - - - - - Vertex Assembly - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${GlobalTrackerReadoutID} - - - ${GlobalTrackerReadoutID_OB} - - - ${GlobalTrackerReadoutID_Disk} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Vertex Detector Disks - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v02.xml b/FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v03.xml similarity index 94% rename from FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v02.xml rename to FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v03.xml index 189bc202e..c7f888533 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v02.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/materials_o1_v03.xml @@ -131,26 +131,11 @@ - - - - + + + - - - - - - - - - - - - - - @@ -185,7 +170,7 @@ - + @@ -272,15 +257,6 @@ - - - - - - - - - diff --git a/FCCee/IDEA/compact/README.md b/FCCee/IDEA/compact/README.md index fed6cf941..95f958f11 100644 --- a/FCCee/IDEA/compact/README.md +++ b/FCCee/IDEA/compact/README.md @@ -20,3 +20,6 @@ v02). NB: production threshold and step limit physics have to be tuned for the d July 2024: Added a detailed version of the muon system. The monolithic fiber dual-readout calorimeter (o1, v01) is added to the directory, but commented in the main file IDEA_o1_v03.xml for the sake of speed. Please remove the comments to include this calorimeter in the full IDEA detector. + +August 2024: Added an updated vertex detector (also with the ultra-light inner vertex option) and a more light-weight +implementation of the silicon wrapper. \ No newline at end of file diff --git a/detector/tracker/README.md b/detector/tracker/README.md index d2e213cfe..e95f83e0d 100644 --- a/detector/tracker/README.md +++ b/detector/tracker/README.md @@ -1,10 +1,16 @@ # Vertex detectors -## VertexBarrel_detailed and VertexDisks_detailed description +## VertexBarrel_detailed and VertexEndcap_detailed description + +### o1_v01 These two detector constructors were derived from ZPlanarTracker.cpp and from VertexEndcap_o1_v06.cpp and adapted to fit the needs of the [IDEA vertex detector engineering design](https://indico.cern.ch/event/1202105/timetable/#242-mechanical-integration-of). Both the barrel and the disks are made up of staves, that can feature an arbitrary number of cuboid layers to describe the support, readout and sensor structures. The sensors can be described by individual sensitive and insensitive pieces to form large, complex structures such as quad modules, that have an insensitive periphery. -More details can be found in the talks at the [FCC week 2023](https://indico.cern.ch/event/1202105/timetable/#356-idea-vertex-detector-in-ke) with an update the the [MDI meeting of the 10th of July 2023](https://indico.cern.ch/event/1292318/#5-vxd-implementation-in-full-s). Once public, the constructor and the resulting IDEA vertex detector are described in the MDI note for the mid-term review. +More details can be found in the talks at the [FCC week 2023](https://indico.cern.ch/event/1202105/timetable/#356-idea-vertex-detector-in-ke) with an update the the [MDI meeting of the 10th of July 2023](https://indico.cern.ch/event/1292318/#5-vxd-implementation-in-full-s). The constructor and the resulting IDEA vertex detector are described in the MDI note for the mid-term review (not public). + +### o1_v02 +These versions for the vertex barrel and disks fix previous issues with overlaps and enable to define in the xml file mother volumes to speed up the simulation by having less volumes per node in the volume hierarchy (especially relevant for the large-area silicon wrapper that also uses these constructors). +o1_v02 of the barrel also enables the use of curved support and sensor volumes needed to describe the ultra-light vertex detector proposed in the 2024 [FCC Physics Workshop](https://indico.cern.ch/event/1307378/timetable/?view=standard#84-vertex-detector-and-silicon) and [FCC Week](https://indico.cern.ch/event/1298458/timetable/#15-optimization-of-si-tracking). # Trackers diff --git a/detector/tracker/VertexBarrel_detailed_o1_v01_geo.cpp b/detector/tracker/VertexBarrel_detailed_o1_v01_geo.cpp index 801c854c2..04f4d24b6 100644 --- a/detector/tracker/VertexBarrel_detailed_o1_v01_geo.cpp +++ b/detector/tracker/VertexBarrel_detailed_o1_v01_geo.cpp @@ -375,4 +375,4 @@ static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector se return sdet; } -DECLARE_DETELEMENT(VertexBarrel_detailed_o1_v01,create_element) +DECLARE_DETELEMENT(VertexBarrel_detailed_o1_v01,create_element) \ No newline at end of file diff --git a/detector/tracker/VertexBarrel_detailed_o1_v02_geo.cpp b/detector/tracker/VertexBarrel_detailed_o1_v02_geo.cpp new file mode 100644 index 000000000..691e9736a --- /dev/null +++ b/detector/tracker/VertexBarrel_detailed_o1_v02_geo.cpp @@ -0,0 +1,544 @@ +// $Id: $ +//==================================================================== +// Based on ZPlanarTracker module from F. Gaede + +// Tracking detector to describe the FCC-ee IDEA vertex detector barrel. +// The vertex detector is assembled of stave structures which feature +// support and readout (flex) elements. Each stave features multiple +// individual modules, that consist of sensitive and insensitive +// sensor elements. From o1_v02 it is possible to define curved +// sensor and support elements. +//-------------------------------------------------------------------- +// +// Author : Armin Ilg +// +//==================================================================== +#include "DD4hep/DetFactoryHelper.h" +#include "XML/Utilities.h" +#include "XMLHandlerDB.h" +#include +#include "DDRec/Surface.h" + +using namespace std; + +using dd4hep::Assembly; +using dd4hep::Box; +using dd4hep::Tube; +using dd4hep::BUILD_ENVELOPE; +using dd4hep::DetElement; +using dd4hep::Detector; +using dd4hep::Material; +using dd4hep::PlacedVolume; +using dd4hep::Position; +using dd4hep::Ref_t; +using dd4hep::RotationZYX; +using dd4hep::SensitiveDetector; +using dd4hep::Transform3D; +using dd4hep::Translation3D; +using dd4hep::Volume; +using dd4hep::getAttrOrDefault; +using dd4hep::_toString; + +using dd4hep::rec::volSurfaceList; +using dd4hep::rec::Vector3D; +using dd4hep::rec::VolPlane; +using dd4hep::rec::VolCylinder; +using dd4hep::rec::SurfaceType; + +static Ref_t create_element(Detector& theDetector, xml_h e, SensitiveDetector sens) { + + xml_det_t x_det = e; + int m_id=0; + std::string det_name = x_det.nameStr(); + + DetElement sdet( det_name, x_det.id() ) ; + PlacedVolume pv; + + Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; + dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; + + if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; + + envelope.setVisAttributes(theDetector, x_det.visStr()); + sens.setType("tracker"); + + // Struct to support multiple readout or support layers (both using this struct) + struct componentsStruct{ + string name; + double r; + double offset; + double length; + double z_offset; + vector thicknesses; + vector offsets; + vector z_offsets; + vector rs; + vector phis; + vector volumes; + vector isCurved; + }; + + // Struct to support end-of-stave structures + struct endOfStaveStruct{ + string name; + double r; + double offset; + double z_offset; + vector thicknesses; + vector lengths; + vector dzs; + vector offsets; + vector z_offsets; + vector rs; + vector volumes; + vector side; + vector isCurved; + }; + + // Struct for sensors + struct sensorsStruct{ + string name; + double r; + double offset; + double thickness; + Material material; + vector sensitives; + vector xmin; + vector xmax; + vector ymin; + vector ymax; + vector phi_offsets; + vector names; + vector isCurved; + double width; + double length; + vector volumes; + }; + + // --- Module information struct --- + struct stave_information{ + string name; + double motherVolThickness; + double motherVolWidth; + + vector components_vec; + vector endOfStaves_vec; + vector sensorsVec; + + double stave_dr; + double stave_r; + double stave_length; + string staveVis; + }; + list stave_information_list; + + // --- Collect stave(s) information + for(xml_coll_t mi(x_det,_U(stave)); mi; ++mi, ++m_id) { + xml_comp_t x_stave = mi; + + stave_information m; + m.name = x_stave.nameStr(); + m.staveVis = x_stave.visStr(); + m.stave_length = x_stave.length(); + + m.stave_dr = x_stave.dr(0); // Offset for every second module in r + m.stave_r = x_stave.r(0); // Radius of stave + + m.motherVolThickness = getAttrOrDefault(x_stave, _Unicode(motherVolThickness), double(0.0)); + m.motherVolWidth = getAttrOrDefault(x_stave, _Unicode(motherVolWidth), double(0.0)); + + // Components + xml_coll_t c_components(x_stave,_U(components)); + for(c_components.reset(); c_components; ++c_components){ + componentsStruct components; + components.name = xml_comp_t(c_components).nameStr(); + components.r = xml_comp_t(c_components).r(0); + components.length = xml_comp_t(c_components).length(); + components.offset = xml_comp_t(c_components).offset(0); + components.z_offset = xml_comp_t(c_components).z_offset(0); + + + xml_coll_t c_component(c_components,_U(component)); + int iComponent = 0; + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + components.thicknesses.push_back(component.thickness()); + components.offsets.push_back(component.offset(0)); + components.z_offsets.push_back(component.z_offset(0)); + components.rs.push_back(component.r(0)); + components.phis.push_back(component.phi(0)); // Rotation of component around its own axis, not applicable for curved components + + bool isCurved = getAttrOrDefault(component, _Unicode(isCurved), bool(false)); + components.isCurved.push_back(isCurved); + Volume ele_vol; + + if(isCurved){ + double rmin = m.stave_r + components.r+components.rs.back(); + double half_width = component.width()/(2.*M_PI*rmin)*(2.0*M_PI)/2.; + double phi_offset = getAttrOrDefault(component, _Unicode(phi_offset), double(0.0)); + Tube ele_box = Tube(rmin, rmin+components.thicknesses.back(), components.length, -half_width + phi_offset, half_width + phi_offset); + ele_vol = Volume(components.name + _toString(iComponent, "_%d"), ele_box, theDetector.material(component.materialStr())); + } + else{ + Box ele_box = Box(component.thickness()/2., component.width()/2., components.length); + ele_vol = Volume(components.name + _toString(iComponent, "_%d"), ele_box, theDetector.material(component.materialStr())); + } + ele_vol.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), component.visStr()); + components.volumes.push_back(ele_vol); + + iComponent++; + } + m.components_vec.push_back(components); + } + + // End of stave structures + xml_coll_t c_endOfStave(x_stave,_U(end_z)); + for(c_endOfStave.reset(); c_endOfStave; ++c_endOfStave){ + endOfStaveStruct endOfStave; + endOfStave.offset = xml_comp_t(c_endOfStave).offset(0); + endOfStave.z_offset = xml_comp_t(c_endOfStave).z_offset(0); + endOfStave.r = xml_comp_t(c_endOfStave).r(0); + endOfStave.name = xml_comp_t(c_endOfStave).nameStr(); + + xml_coll_t c_component = xml_coll_t(c_endOfStave,_U(component)); + int iEndOfStave = 0; + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + endOfStave.thicknesses.push_back(component.thickness()); + endOfStave.dzs.push_back(component.dz(0)); + endOfStave.offsets.push_back(component.offset(0)); + endOfStave.z_offsets.push_back(component.z_offset(0)); + endOfStave.lengths.push_back(component.length()); + endOfStave.rs.push_back(component.r(0)); + + int side = getAttrOrDefault(component, _Unicode(side), int(0)); + + endOfStave.side.push_back(side); // 0 for both sides (default), +1 for +z side, -1 for -z side + bool isCurved = getAttrOrDefault(component, _Unicode(isCurved), bool(false)); + endOfStave.isCurved.push_back(isCurved); + Volume ele_vol; + + if(isCurved){ + double rmin = m.stave_r + endOfStave.r+endOfStave.rs.back(); + double half_width = component.width()/(2.*M_PI*rmin)*(2.0*M_PI)/2.; + double phi_offset = getAttrOrDefault(component, _Unicode(phi_offset), double(0.0)); + Tube ele_box = Tube(rmin, rmin+endOfStave.thicknesses.back(), component.length()/2., -half_width + phi_offset, half_width + phi_offset); + ele_vol = Volume(endOfStave.name + _toString(iEndOfStave, "_%d"), ele_box, theDetector.material(component.materialStr())); + } + else{ + Box ele_box = Box(component.thickness()/2., component.width()/2., component.length()/2.); + ele_vol = Volume(endOfStave.name + _toString(iEndOfStave, "_%d"), ele_box, theDetector.material(component.materialStr())); + } + ele_vol.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), component.visStr()); + + endOfStave.volumes.push_back(ele_vol); + iEndOfStave++; + } + m.endOfStaves_vec.push_back(endOfStave); + } + + // Sensor + xml_coll_t c_sensor(x_stave,_U(sensor)); + for(c_sensor.reset(); c_sensor; ++c_sensor){ + sensorsStruct sensor; + + sensor.r = xml_comp_t(c_sensor).r(0); + sensor.offset = xml_comp_t(c_sensor).offset(0); + sensor.thickness = xml_comp_t(c_sensor).thickness(); + sensor.material = theDetector.material(xml_comp_t(c_sensor).materialStr()); + sensor.name = xml_comp_t(c_sensor).nameStr(); + + xml_coll_t c_component = xml_coll_t(c_sensor,_U(component)); + int iSensor = 0; + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + sensor.sensitives.push_back(component.isSensitive()); + sensor.xmin.push_back(component.xmin()); + sensor.xmax.push_back(component.xmax()); + sensor.ymin.push_back(component.ymin()); + sensor.ymax.push_back(component.ymax()); + sensor.names.push_back(component.nameStr("sensor")); + + sensor.phi_offsets.push_back(getAttrOrDefault(component, _Unicode(phi_offset), double(0.0)) ); + + bool isCurved = getAttrOrDefault(component, _Unicode(isCurved), bool(false)); + sensor.isCurved.push_back(isCurved); + + // Already create volumes for all sensor components as this is independent of number of sensors per layer + Volume ele_vol; + if(isCurved){ + double rmin = m.stave_r + sensor.r; + double half_width = abs(component.xmax()-component.xmin())/rmin/2.; + double phi_offset = getAttrOrDefault(component, _Unicode(phi_offset), double(0.0)); + Tube ele_box = Tube(rmin, rmin + sensor.thickness, abs(component.ymax()-component.ymin())/2., -half_width+phi_offset, half_width+phi_offset); + ele_vol = Volume(sensor.names.back() + _toString(iSensor, "_%d"), ele_box, sensor.material); + } + else{ + Box ele_box = Box(sensor.thickness/2., abs(component.xmax()-component.xmin())/2., abs(component.ymax()-component.ymin())/2.); + ele_vol = Volume(sensor.names.back() + _toString(iSensor, "_%d"), ele_box, sensor.material); + } + + if(sensor.sensitives.back()) + ele_vol.setSensitiveDetector(sens); + ele_vol.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), component.visStr()); + sensor.volumes.push_back(ele_vol); + + iSensor++; + } + sensor.width = *max_element(sensor.xmax.begin(), sensor.xmax.end()) - *min_element(sensor.xmin.begin(), sensor.xmin.end()); + sensor.length = *max_element(sensor.ymax.begin(), sensor.ymax.end()) - *min_element(sensor.ymin.begin(), sensor.ymin.end()); + cout << det_name << ": Module: " << sensor.name << ", sensor width: " << to_string(sensor.width) << ", sensor length: " << to_string(sensor.length) << endl; + m.sensorsVec.push_back(sensor); + } + + stave_information_list.push_back(m); + cout << "Read stave information of stave " << m.name << endl; + } + + int iModule_tot = 0; + + //========= loop over layer elements in xml ====================================== + + cout << "Building " << det_name << " barrel detector " << det_name << "..." << endl; + for(xml_coll_t c(e, _U(layer) ); c; ++c) { + + xml_comp_t x_layer( c ); + + // child elements: ladder, sensitive and periphery + + int layer_id = x_layer.id(); + int side = getAttrOrDefault(x_layer, _Unicode(side), 0); // Use side=1 or -1 to use two staves/wafers with the same layer id + + double dr = x_layer.dr(0); // Spacing in r for every second stave. + double layer_offset = x_layer.offset(0); + double z_offset = x_layer.z_offset(0); + + string nameStr = x_layer.nameStr(); + int nmodules = x_layer.nmodules(); + double step = x_layer.step(0); // Spacing of modules + + + // Use the correct stave + auto m = *find_if(stave_information_list.cbegin(), stave_information_list.cend(), [&nameStr] (const stave_information& stave) { + return stave.name == nameStr; + }); + + + double motherVolThickness = getAttrOrDefault(x_layer, _Unicode(motherVolThickness), double(5.0)); + double motherVolLength = getAttrOrDefault(x_layer, _Unicode(motherVolLength), double(m.stave_length)); + double motherVolOffset = getAttrOrDefault(x_layer, _Unicode(motherVolOffset), double(0.0)); // In case wafer/stave is asymmetric + + std::string layer_name = det_name+_toString(layer_id,"_layer%d")+_toString(side,"_side%d"); + double motherVolRmin = getAttrOrDefault(x_layer, _Unicode(motherVolRmin), double(x_layer.r())); + Tube whole_layer_tube = Tube(motherVolRmin, motherVolRmin+motherVolThickness, motherVolLength/2.); + + Volume whole_layer_volume = Volume(layer_name, whole_layer_tube, theDetector.material("Air")); + whole_layer_volume.setVisAttributes(theDetector, x_layer.visStr()); + pv = envelope.placeVolume(whole_layer_volume, Position(0., 0., z_offset)); + pv.addPhysVolID("layer", layer_id); + + DetElement layerDE( sdet , _toString(layer_id,"layer_%d")+_toString(side,"_side%d"), x_det.id() ); + layerDE.setPlacement( pv ) ; + + int nLadders = x_layer.attr( _Unicode(nLadders) ) ; + double dphi = 2.*M_PI / double(nLadders); + double phi0 = x_layer.phi0(0); + + //--------- loop over ladders --------------------------- + for(int iStave=0; iStave0.0 && m.motherVolWidth>0.0){ + + r = layer_r + m.motherVolThickness/2.; + x_pos = r*cos(phi) - r_offset_component*sin(phi); + y_pos = r*sin(phi) + r_offset_component*cos(phi); + Box whole_stave_box = Box(m.motherVolThickness/2., m.motherVolWidth/2., m.stave_length/2.); + whole_stave_volume_v = Volume(stave_name, whole_stave_box, theDetector.material("Air")); + whole_stave_volume_v.setVisAttributes(theDetector, m.staveVis); + whole_stave_volume_placed = whole_layer_volume.placeVolume(whole_stave_volume_v, Transform3D(rot,Position(x_pos, y_pos, z_pos))); + } + else{ + //// Use just assembly to avoid overlap between stave volume and other volumes + whole_stave_volume_a = Assembly(stave_name); + whole_stave_volume_placed = whole_layer_volume.placeVolume(whole_stave_volume_a, Transform3D(rot,stave_pos)); + } + + // Place components + for(auto& component : m.components_vec){ + Assembly component_assembly(stave_name + "_" + component.name); + if(m.motherVolThickness>0.0 && m.motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(component_assembly, Position(-m.motherVolThickness/2., 0., 0.)); + else + pv = whole_stave_volume_a.placeVolume(component_assembly); + + for(int i=0; iGetShape()->ComputeBBox(); + } + + // Place end of stave structures + for(auto& endOfStave : m.endOfStaves_vec){ + Assembly endOfStave_assembly(stave_name + "_" + endOfStave.name); + if(m.motherVolThickness>0.0 && m.motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(endOfStave_assembly, Position(-m.motherVolThickness/2., 0., 0.)); + else + pv = whole_stave_volume_a.placeVolume(endOfStave_assembly); + + for(int i=0; i endOfStave_sides = {1,-1}; + if(endOfStave.side[i] != 0) + endOfStave_sides = {endOfStave.side[i]}; + for(auto& endOfStave_side : endOfStave_sides){ // Place it on both sides of the stave + if(endOfStave.isCurved[i]){ + double r_component_curved = 0.0; // endOfStave.r + endOfStave.rs[i] + endOfStave.thicknesses[i]/2; // Correct for the fact that a tube element's origin is offset compared to the origin of a box + r_offset_component = endOfStave.offset + endOfStave.offsets[i]; + x_pos = r_component_curved*cos(phi) - r_offset_component*sin(phi); + y_pos = r_component_curved*sin(phi) + r_offset_component*cos(phi); + z_pos = m.stave_length/2.+endOfStave.lengths[i]/2.+endOfStave.dzs[i] + endOfStave.z_offset + endOfStave.z_offsets[i]; + Position pos = Position(x_pos, y_pos, z_pos*endOfStave_side+motherVolOffset); + endOfStave_assembly.placeVolume(endOfStave.volumes[i], Transform3D(rot,stave_pos).Inverse()*Transform3D(rot,pos)); + } + else{ + x_pos = endOfStave.r + endOfStave.rs[i] + endOfStave.thicknesses[i]/2.; + y_pos = endOfStave.offset + endOfStave.offsets[i]; + z_pos = m.stave_length/2.+endOfStave.lengths[i]/2.+endOfStave.dzs[i] + endOfStave.z_offset + endOfStave.z_offsets[i]; + Position pos(x_pos, y_pos, z_pos*endOfStave_side+motherVolOffset); + endOfStave_assembly.placeVolume(endOfStave.volumes[i], pos); + } + } + } + endOfStave_assembly->GetShape()->ComputeBBox(); + } + + // Place sensor + for(auto& sensor : m.sensorsVec){ + for(int iModule=0; iModule0.0 && m.motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(module_assembly, Position(-m.motherVolThickness/2., 0., 0.)); + else + pv = whole_stave_volume_a.placeVolume(module_assembly); + pv.addPhysVolID("module", iModule_tot); + + DetElement moduleDE(layerDE,module_name,x_det.id()); + moduleDE.setPlacement(pv); + + + // Place all sensor parts + int iSensitive = 0; + for(int i=0; ipush_back(surf); + iSensitive++; + } + } + else{ // not curved + x_pos = 0.0; + y_pos = sensor.xmin[i]+abs(sensor.xmax[i]-sensor.xmin[i])/2.; + z_pos = sensor.ymin[i]+abs(sensor.ymax[i]-sensor.ymin[i])/2.; + Position pos2(x_pos, y_pos, z_pos); + pv = module_assembly.placeVolume(sensor.volumes[i], pos+pos2); + + if(sensor.sensitives[i]) { // Define as sensitive and add sensitive surface + string sensor_name = module_name + _toString(iSensitive,"_sensor%d"); + pv.addPhysVolID("sensor", iSensitive); + DetElement sensorDE(moduleDE,sensor_name,x_det.id()); + sensorDE.setPlacement(pv); + + Vector3D u( 0. , 1. , 0. ) ; + Vector3D v( 0. , 0. , 1. ) ; + Vector3D n( 1. , 0. , 0. ) ; + VolPlane surf( sensor.volumes[i] , dd4hep::rec::SurfaceType::Sensitive , sensor.thickness/2. , sensor.thickness/2. , u,v,n ); + volSurfaceList(sensorDE)->push_back(surf); + iSensitive++; + } + } + } + iModule_tot++; + module_assembly->GetShape()->ComputeBBox(); + } + } + + if(m.motherVolThickness>0.0 && m.motherVolWidth>0.0){} + else{ + whole_stave_volume_a->GetShape()->ComputeBBox(); + } + } + } + + pv.addPhysVolID( "system", x_det.id() ).addPhysVolID("side",0 ) ; + + sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); + + return sdet; +} + +DECLARE_DETELEMENT(VertexBarrel_detailed_o1_v02,create_element) \ No newline at end of file diff --git a/detector/tracker/VertexEndcap_detailed_o1_v01_geo.cpp b/detector/tracker/VertexEndcap_detailed_o1_v01_geo.cpp index 8d423703f..cccd79233 100644 --- a/detector/tracker/VertexEndcap_detailed_o1_v01_geo.cpp +++ b/detector/tracker/VertexEndcap_detailed_o1_v01_geo.cpp @@ -366,4 +366,4 @@ static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector s return sdet; } -DECLARE_DETELEMENT(VertexDisks_detailed_o1_v01,create_detector) +DECLARE_DETELEMENT(VertexDisks_detailed_o1_v01,create_detector) \ No newline at end of file diff --git a/detector/tracker/VertexEndcap_detailed_o1_v02_geo.cpp b/detector/tracker/VertexEndcap_detailed_o1_v02_geo.cpp new file mode 100644 index 000000000..204d08f8c --- /dev/null +++ b/detector/tracker/VertexEndcap_detailed_o1_v02_geo.cpp @@ -0,0 +1,426 @@ +//==================================================================== +// Vertex Detector implementation for the FCC-ee IDEA detector +//-------------------------------------------------------------------- +// +// Based on VertexEndcap_o2_v06_geo.cpp from M. Petric, which was +// originaly forked form SiTrackerEndcap2 by M. Frank +// +// Author : A. Ilg +// +// This code allows to build a tracker/vertex endcap made out of staves +// as it is used in the IDEA vertex detector design by F. Palla and +// F. Bosi as of mid-2023. +// The staves are arranged in petals, and can feature any number of modules. +// The modules can be built by smaller rectangular structures to represent +// both sensitive and insensitive (periphery) parts so that e.g Quad +// modules can be bult. When using this detector constructor, in addition, +// the DD4hep_GenericSurfaceInstallerPlugin plugin needs to be instantiated +// in the xml compact file to define the sensitive surfaces. +//==================================================================== + +#include "DD4hep/DetFactoryHelper.h" +#include "XML/Utilities.h" +#include "DD4hep/Printout.h" + +using namespace std; + +using dd4hep::Assembly; +using dd4hep::BUILD_ENVELOPE; +using dd4hep::DetElement; +using dd4hep::Detector; +using dd4hep::Material; +using dd4hep::PlacedVolume; +using dd4hep::Position; +using dd4hep::Ref_t; +using dd4hep::RotationZYX; +using dd4hep::SensitiveDetector; +using dd4hep::Transform3D; +using dd4hep::Translation3D; +using dd4hep::Volume; +using dd4hep::_toString; +using dd4hep::getAttrOrDefault; +using dd4hep::Box; +using dd4hep::Tube; + +static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens) { + xml_det_t x_det = e; + string det_name = x_det.nameStr(); + bool reflect = x_det.reflect(false); + DetElement sdet (det_name,x_det.id()); + int m_id=0; + PlacedVolume pv; + + // --- create an envelope volume and position it into the world --------------------- + + Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, e , sdet ) ; + dd4hep::xml::setDetectorTypeFlag( e, sdet ) ; + + if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; + + envelope.setVisAttributes(theDetector, x_det.visStr()); + sens.setType("tracker"); + + // Struct to support multiple readout or support layers (both using this struct) + struct componentsStruct{ + string name; + double z_offset; + double offset; + vector thicknesses; + vector widths; + vector offsets; + vector z_offsets; + vector materials; + vector viss; + }; + + // Struct to support end-of-stave structures + struct endOfStaveStruct{ + string name; + double z_offset; + double offset; + vector thicknesses; + vector lengths; + vector offsets; + vector z_offsets; + vector dxs; // Distance of end-of-stave structure to stave itself + vector xs; // Indicating whether end of stave struct should be place on pos x side (if x>0) or on neg x side (if x<0). Didn't work with using nsides + vector volumes; + }; + + // --- Module information struct --- + struct module_information{ + string name; + + vector components_vec; + vector endOfStaves; + double sensor_z_offset; + double sensor_offset; + double sensor_thickness; + vector sensor_sensitives; + vector sensor_xmin; + vector sensor_xmax; + vector sensor_ymin; + vector sensor_ymax; + vector sensor_names; + double sensor_width; + double sensor_length; + vector sensor_volumes; + Material sensor_material; + }; + list module_information_list; + + // --- Collect module(s) information + for(xml_coll_t mi(x_det,_U(module)); mi; ++mi, ++m_id) { + xml_comp_t x_mod = mi; + + module_information m; + m.name = x_mod.nameStr(); + + // Components + xml_coll_t c_components(x_mod,_U(components)); + for(c_components.reset(); c_components; ++c_components){ + componentsStruct components; + components.name = xml_comp_t(c_components).nameStr(); + components.z_offset = xml_comp_t(c_components).z_offset(0); + components.offset = xml_comp_t(c_components).offset(0); + xml_coll_t c_component(c_components,_U(component)); + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + components.thicknesses.push_back(component.thickness()); + components.widths.push_back(component.width()); + components.offsets.push_back(component.offset(0)); + components.z_offsets.push_back(component.z_offset(0)); + components.materials.push_back(theDetector.material(component.materialStr())); + components.viss.push_back(component.visStr()); + } + m.components_vec.push_back(components); + } + + // End of stave structures + xml_coll_t c_endOfStave(x_mod,_U(end_z)); + int iEndOfStave = 0; + for(c_endOfStave.reset(); c_endOfStave; ++c_endOfStave,++iEndOfStave){ + endOfStaveStruct endOfStave; + endOfStave.z_offset = xml_comp_t(c_endOfStave).z_offset(0); + endOfStave.offset = xml_comp_t(c_endOfStave).offset(0); + endOfStave.name = xml_comp_t(c_endOfStave).nameStr(); + xml_coll_t c_component = xml_coll_t(c_endOfStave,_U(component)); + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + endOfStave.thicknesses.push_back(component.thickness()); + endOfStave.lengths.push_back(component.length()); + endOfStave.offsets.push_back(component.offset(0)); + endOfStave.z_offsets.push_back(component.z_offset(0)); + endOfStave.dxs.push_back(component.dx()); + endOfStave.xs.push_back(component.x()); + + Box ele_box = Box(component.width()/2., component.length()/2., component.thickness()/2.); + Volume ele_vol = Volume( endOfStave.name + _toString(iEndOfStave, "_%d"), ele_box, theDetector.material(component.materialStr())); + ele_vol.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), component.visStr()); + + endOfStave.volumes.push_back(ele_vol); + } + m.endOfStaves.push_back(endOfStave); + } + + // Sensor + xml_coll_t c_sensor(x_mod,_U(sensor)); + m.sensor_z_offset = xml_comp_t(c_sensor).z_offset(0); + m.sensor_offset = xml_comp_t(c_sensor).offset(0); + m.sensor_thickness = xml_comp_t(c_sensor).thickness(); + m.sensor_material = theDetector.material(xml_comp_t(c_sensor).materialStr()); + xml_coll_t c_component = xml_coll_t(c_sensor,_U(component)); + + int iSensor = 0; + for(c_component.reset(); c_component; ++c_component){ + xml_comp_t component = c_component; + m.sensor_sensitives.push_back(component.isSensitive()); + m.sensor_xmin.push_back(component.xmin()); + m.sensor_xmax.push_back(component.xmax()); + m.sensor_ymin.push_back(component.ymin()); + m.sensor_ymax.push_back(component.ymax()); + m.sensor_names.push_back(component.nameStr("sensor")); + + Box ele_box = Box( abs(component.xmax()-component.xmin())/2., abs(component.ymax()-component.ymin())/2., m.sensor_thickness/2.); + Volume ele_vol = Volume( m.sensor_names.back() + _toString(iSensor, "_%d"), ele_box, m.sensor_material); + ele_vol.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), component.visStr()); + + if(m.sensor_sensitives.back()) + ele_vol.setSensitiveDetector(sens); + m.sensor_volumes.push_back(ele_vol); + iSensor++; + } + m.sensor_width = *max_element(m.sensor_xmax.begin(), m.sensor_xmax.end()) - *min_element(m.sensor_xmin.begin(), m.sensor_xmin.end()); + m.sensor_length = *max_element(m.sensor_ymax.begin(), m.sensor_ymax.end()) - *min_element(m.sensor_ymin.begin(), m.sensor_ymin.end()); + cout << det_name << "Module: " << m.name << ", sensor width: " << to_string(m.sensor_width) << ", sensor length: " << to_string(m.sensor_length) << endl; + module_information_list.push_back(m); + } + + vector sides = {1}; + if(reflect){sides.push_back(-1);} + + for(auto & side : sides){ + string side_name = det_name + _toString(side,"_side%d"); + + Assembly side_assembly(side_name); + pv = envelope.placeVolume(side_assembly); + pv.addPhysVolID("side", side); + + for(xml_coll_t li(x_det,_U(layer)); li; ++li) { + xml_comp_t x_layer(li); + int layer_id = x_layer.id(); + double rmin = x_layer.rmin(); + double rmax = x_layer.rmax(); + double dr = x_layer.dr(0); + double z = x_layer.z(); + double layer_dz = x_layer.dz(0); + int nPetals = x_layer.nphi(); + double phi0_layer = x_layer.phi0(0); + double reflect_rot = x_layer.attr(_Unicode(reflect_rot),0.0); + + string disk_name = side_name + _toString(layer_id,"_layer%d"); + + // Either use assembly or volume, depending on whether motherVolThickness is given + PlacedVolume whole_disk_volume_placed; + Volume whole_disk_volume_v; + Assembly whole_disk_volume_a; + double disk_motherVolThickness = getAttrOrDefault(x_layer, _Unicode(motherVolThickness), double(0.0)); + if(disk_motherVolThickness>0.0){ + Tube whole_disk_tube = Tube(rmin, rmax, disk_motherVolThickness/2.); + whole_disk_volume_v = Volume(disk_name, whole_disk_tube, theDetector.material("Air")); + whole_disk_volume_v.setVisAttributes(theDetector, x_layer.visStr()); + whole_disk_volume_placed = side_assembly.placeVolume(whole_disk_volume_v, Position(0.0, 0.0, side*(z+disk_motherVolThickness/2.))); + } + else{ + //// Use just assembly to avoid overlap between disk volume and other volumes + whole_disk_volume_a = Assembly(disk_name); + whole_disk_volume_placed = side_assembly.placeVolume(whole_disk_volume_a, Position(0.0, 0.0, side*z)); + } + + + whole_disk_volume_placed.addPhysVolID("layer", layer_id); + + DetElement diskDE( sdet , disk_name, layer_id); + diskDE.setPlacement( whole_disk_volume_placed ); + + int iModule_tot = 0; + for(int iPetal=0; iPetal0.) + pv = whole_disk_volume_v.placeVolume(petal_assembly); + else + pv = whole_disk_volume_a.placeVolume(petal_assembly); + + int iStave = 0; + for(xml_coll_t ri(x_layer,_U(stave)); ri; ++ri,++iStave) { + xml_comp_t x_stave = ri; + + int nmodules = x_stave.nmodules(); + double r_stave = x_stave.r(); + double z_offset = x_stave.z_offset(0); + double stave_dz = x_stave.dz(0); + double step = x_stave.step(); // Spacing of modules + string moduleStr = x_stave.moduleStr(); + double phi0_stave = x_stave.phi0(0); + double stave_offset = x_stave.offset(0); // Offset of stave in r-phi + double phi = 2*M_PI/nPetals*iPetal + phi0_layer + phi0_stave + (side == -1 ? reflect_rot : 0.0); + + // Use the correct module + auto m = *find_if(module_information_list.cbegin(), module_information_list.cend(), [&moduleStr] (const module_information& module) { + return module.name == moduleStr; + }); + + + + // Place all components + RotationZYX rot( phi , 0, 0 ); + double stave_length = nmodules*m.sensor_length + (nmodules-1)*step; + double r = rmin + m.sensor_width/2.0 + r_stave + ((iPetal%2 == 0) ? 0.0 : dr); + + double x_pos = r*cos(phi) - stave_offset*sin(phi); + double y_pos = r*sin(phi) + stave_offset*cos(phi); + double z_pos = z_alternate_petal + z_offset; + if(side == -1){z_pos = -z_pos;} + Position stave_pos = Position(x_pos, y_pos, z_pos); + + string stave_name = petal_name + _toString(iStave,"_stave%d"); + + PlacedVolume whole_stave_volume_placed; + Volume whole_stave_volume_v; + Assembly whole_stave_volume_a; + double stave_motherVolThickness = getAttrOrDefault(x_stave, _Unicode(motherVolThickness), double(0.0)); + double stave_motherVolWidth = getAttrOrDefault(x_stave, _Unicode(motherVolWidth), double(0.0)); + if(stave_motherVolThickness>0.0 && stave_motherVolWidth>0.0){ + Box whole_stave_box = Box(stave_motherVolWidth/2., stave_length/2., stave_motherVolThickness/2.); + whole_stave_volume_v = Volume(stave_name, whole_stave_box, theDetector.material("Air")); + whole_stave_volume_v.setVisAttributes(theDetector, x_stave.visStr()); + whole_stave_volume_placed = petal_assembly.placeVolume(whole_stave_volume_v, Transform3D(rot,stave_pos)); + } + else{ + //// Use just assembly to avoid overlap between stave volume and other volumes + whole_stave_volume_a = Assembly(stave_name); + whole_stave_volume_placed = petal_assembly.placeVolume(whole_stave_volume_a, Transform3D(rot,stave_pos)); + } + + // Place components + for(auto& component : m.components_vec){ + Assembly component_assembly(stave_name + "_" + component.name); + + if(stave_motherVolThickness>0.0 && stave_motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(component_assembly); + else + pv = whole_stave_volume_a.placeVolume(component_assembly); + + for(int i=0; iGetShape()->ComputeBBox(); + } + + // Place end of stave structures + int iEndOfStave = 0; + for(auto& endOfStave : m.endOfStaves){ + Assembly endOfStave_assembly(stave_name + "_" + endOfStave.name + _toString(iEndOfStave,"_%d")); + + if(stave_motherVolThickness>0.0 && stave_motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(endOfStave_assembly); + else + pv = whole_stave_volume_a.placeVolume(endOfStave_assembly); + + for(int i=0; i0 ? stave_length/2.+endOfStave.lengths[i]/2.+endOfStave.dxs[i] : -(stave_length/2.+endOfStave.lengths[i]/2.+endOfStave.dxs[i]); + z_pos = endOfStave.z_offset + endOfStave.z_offsets[i] + endOfStave.thicknesses[i]/2.; + + if(side == -1){z_pos = -z_pos;} + Position pos(x_pos, y_pos, z_pos); + + pv = endOfStave_assembly.placeVolume(endOfStave.volumes[i], pos); + iEndOfStave++; + } + endOfStave_assembly->GetShape()->ComputeBBox(); + } + + // Place sensor + for(int iModule=0; iModule0.0 && stave_motherVolWidth>0.0) + pv = whole_stave_volume_v.placeVolume(module_assembly); + else + pv = whole_stave_volume_a.placeVolume(module_assembly); + + pv.addPhysVolID("module", iModule_tot); + DetElement moduleDE(diskDE,module_name,x_det.id()); + moduleDE.setPlacement(pv); + + int iSensitive = 0; + for(int i=0; iGetShape()->ComputeBBox(); + } + if(stave_motherVolThickness>0.0 && stave_motherVolWidth>0.0){} + else{ + whole_stave_volume_a->GetShape()->ComputeBBox(); + } + } + petal_assembly->GetShape()->ComputeBBox(); + } + if(disk_motherVolThickness>0.0){} + else{ + whole_disk_volume_a->GetShape()->ComputeBBox(); + } + } + side_assembly->GetShape()->ComputeBBox(); + } + + cout << "Built disks detector:" << det_name << endl; + sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); + pv.addPhysVolID("system", x_det.id()); + + return sdet; +} + +DECLARE_DETELEMENT(VertexEndcap_detailed_o1_v02,create_detector) \ No newline at end of file diff --git a/scripts/save_detector_to_root.sh b/scripts/save_detector_to_root.sh index e4307a51e..553a134f9 100644 --- a/scripts/save_detector_to_root.sh +++ b/scripts/save_detector_to_root.sh @@ -5,11 +5,12 @@ script_folder="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" # Get the location of this script, to execute correctly other commands xml=$1 # Give xml detector file as input argument! +outputName="${2:-detector}" # Name of output file, saved as $outputName_dd4hep2root.root echo "Running on xml file $xml" if [[ -n "$xml" ]]; then # test to see if not empty - python ${script_folder}/../utils/dd4hep2root.py -c ${xml} -o detector_dd4hep2root.root + python ${script_folder}/../utils/dd4hep2root.py -c ${xml} -o ${outputName}_dd4hep2root.root else echo "argument error, please provide an xml file as input argument!" fi \ No newline at end of file diff --git a/test/compact/DCH_standalone_o1_v02.xml b/test/compact/DCH_standalone_o1_v02.xml index 93a3ec357..c8564735e 100644 --- a/test/compact/DCH_standalone_o1_v02.xml +++ b/test/compact/DCH_standalone_o1_v02.xml @@ -14,7 +14,7 @@ - + diff --git a/test/compact/IDEA_withDRC_o1_v03.xml b/test/compact/IDEA_withDRC_o1_v03.xml index 22ab501bb..6f5e94dfc 100644 --- a/test/compact/IDEA_withDRC_o1_v03.xml +++ b/test/compact/IDEA_withDRC_o1_v03.xml @@ -20,7 +20,7 @@ - + @@ -43,13 +43,13 @@ - + - + diff --git a/utils/material_plots.py b/utils/material_plots.py index bc3e91abe..561ca60f7 100644 --- a/utils/material_plots.py +++ b/utils/material_plots.py @@ -2,9 +2,9 @@ import argparse import sys,os -print(os.path.dirname(os.path.abspath(__file__)) + "/../../FCCSW/Examples/scripts") -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../FCCSW/Examples/scripts") # FCC Style from https://github.com/HEP-FCC/FCCSW/blob/master/Examples/scripts/plotstyle.py +sys.path.append(os.path.expandvars("$FCCSW") + "/Examples/scripts") from plotstyle import FCCStyle + import ROOT def main(): @@ -38,6 +38,8 @@ def main(): if material == "Tungsten": continue if material == "Copper": continue if material == "beam": continue + if material in ["LiquidNDecane", "AlBeMet162", "Gold"]: + continue if material not in histDict.keys(): histDict[material] = { "x0": ROOT.TH1F("", "", (int)((args.angleMax-args.angleMin) / args.angleBinning), args.angleMin, args.angleMax), @@ -91,6 +93,8 @@ def main(): match material: case "CarbonFiber": fillcolor = FCCStyle.fillcolors[0] + case "CarbonFoam": + fillcolor = FCCStyle.fillcolors[0] case "CarbonFleece": fillcolor = ROOT.kBlack case "Rohacell": @@ -105,6 +109,8 @@ def main(): fillcolor = FCCStyle.fillcolors[6] case "Water": fillcolor = FCCStyle.fillcolors[5] + case "PCB": + fillcolor = ROOT.kGreen histDict_ordered[material][plot].SetLineColor(linecolor) histDict_ordered[material][plot].SetFillColor(fillcolor) diff --git a/utils/material_plots_2D.py b/utils/material_plots_2D.py index d050857b5..65babb228 100644 --- a/utils/material_plots_2D.py +++ b/utils/material_plots_2D.py @@ -3,8 +3,7 @@ import math import sys,os -print(os.path.dirname(os.path.abspath(__file__)) + "/../../FCCSW/Examples/scripts") -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../../FCCSW/Examples/scripts") # FCC Style from https://github.com/HEP-FCC/FCCSW/blob/master/Examples/scripts/plotstyle.py +sys.path.append(os.path.expandvars("$FCCSW") + "/Examples/scripts") from plotstyle import FCCStyle import ROOT From d7cddc076cd75c16dbf7b4b57705f1e143e2603c Mon Sep 17 00:00:00 2001 From: jmcarcell Date: Tue, 24 Sep 2024 18:51:29 +0200 Subject: [PATCH 042/133] Update Key4hepConfig.cmake with https://github.com/key4hep/key4hep-dev-utils/pull/9 --- cmake/Key4hepConfig.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Key4hepConfig.cmake b/cmake/Key4hepConfig.cmake index 6dd524abe..7579de142 100644 --- a/cmake/Key4hepConfig.cmake +++ b/cmake/Key4hepConfig.cmake @@ -9,7 +9,7 @@ macro(key4hep_set_compiler_flags) if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") set(COMPILER_FLAGS "${COMPILER_FLAGS} -Winconsistent-missing-override -Wheader-hygiene -fcolor-diagnostics") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color=always") + set(COMPILER_FLAGS "${COMPILER_FLAGS} -fdiagnostics-color=always -Wno-dangling-reference") endif() if (DEFINED KEY4HEP_SET_COMPILER_FLAGS AND NOT KEY4HEP_SET_COMPILER_FLAGS) From f626aa888d907a87e37dc9e09de9335d2e9be604 Mon Sep 17 00:00:00 2001 From: "armin.ilg" Date: Tue, 24 Sep 2024 14:20:10 +0200 Subject: [PATCH 043/133] Removed repeated definition in silicon wrapper XML, improved printout in vertex detector constructors, changed paths of .stl filesin vertex (still commented out due to overlaps) --- .../IDEA_o1_v03/SiliconWrapper_o1_v03.xml | 71 ++++++++----------- .../VertexComplete_IDEA_o1_v03.xml | 6 +- .../VertexBarrel_detailed_o1_v02_geo.cpp | 11 ++- .../VertexEndcap_detailed_o1_v02_geo.cpp | 10 ++- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml index f55707337..c04307f43 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml @@ -68,6 +68,19 @@ + + + + + + + + + + + + + @@ -75,25 +88,29 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -118,14 +135,6 @@ - - - - - - - - @@ -164,12 +173,6 @@ - - - + @@ -819,14 +816,6 @@ - - - - - - - - diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml index a82899dff..c524c7adb 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml @@ -1735,7 +1735,7 @@ " +print(" -->", file=file) for k in sorted( params ): v = params[ k ] if v: - print >>file, "" + print("", file=file) else: cur.execute("select name, default_value from parameters where name=\"" + k + "\";") for row in cur.fetchall() : v = row[1] - print >>file, "" - + print("", file=file) diff --git a/example/guineapig_to_lcio.py b/example/guineapig_to_lcio.py index 7b43e48e3..47e3308b6 100755 --- a/example/guineapig_to_lcio.py +++ b/example/guineapig_to_lcio.py @@ -23,7 +23,7 @@ #================================================ if len( sys.argv ) < 2: - print " usage: python guineapig_to_lcio.py eepair_guineapig.pair " + print(" usage: python guineapig_to_lcio.py eepair_guineapig.pair ") sys.exit(0) #================================================= From d904a01dede89b6e0c26445e6c3b8fc9ecd90359 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Thu, 26 Sep 2024 20:20:54 +0200 Subject: [PATCH 050/133] [format] Run ruff on all python files to comply with rules --- .../CaloTB_EPT_AHCAL/TBModel2015_steering.py | 21 +- CaloTB/run_sim/ddsim_steering_00.py | 14 +- .../writeAllILDCompactDescriptions.py | 225 +++-- ILD/doc/latex/ILD_envelopeDict.py | 9 +- ILD/doc/latex/documentEnvelopes.py | 910 +++++++++++------- ILD/doc/latex/extractParameters.py | 123 ++- ILD/scripts/dumpModelParameters.py | 97 +- .../tests/options/phiEtaSegmentation.py | 57 +- example/SteeringFile_IDEA_o1_v03.py | 304 +++--- example/arcfullsim.py | 91 +- example/guineapig_to_lcio.py | 87 +- example/lcio_particle_gun.py | 117 ++- example/steeringFile.py | 35 +- utils/dd4hep2root.py | 27 +- utils/material_plots.py | 139 ++- utils/material_plots_2D.py | 111 ++- utils/material_scan.py | 15 +- utils/material_scan_2D.py | 17 +- 18 files changed, 1403 insertions(+), 996 deletions(-) diff --git a/CaloTB/CaloTB_EPT_AHCAL/TBModel2015_steering.py b/CaloTB/CaloTB_EPT_AHCAL/TBModel2015_steering.py index b547c31e3..a90bfc930 100644 --- a/CaloTB/CaloTB_EPT_AHCAL/TBModel2015_steering.py +++ b/CaloTB/CaloTB_EPT_AHCAL/TBModel2015_steering.py @@ -6,33 +6,38 @@ SIM.compactFile = "../../DD4HEP/compact/TBModel2015.xml" SIM.runType = "batch" SIM.macroFile = "vis.mac" -#SIM.inputFiles = "mcparticles.slcio" +# SIM.inputFiles = "mcparticles.slcio" SIM.outputFile = "DD4hep_mu-_8GeV_QGSP_BERT_10k.slcio" SIM.numberOfEvents = 10000 SIM.skipNEvents = 0 SIM.physicsList = "QGSP_BERT" SIM.dumpSteeringFile = "TBModel2015_dump.xml" -SIM.enableDetailedShowerMode=True +SIM.enableDetailedShowerMode = True SIM.random.seed = "0123456789" -SIM.field.eps_min = 1*mm -SIM.part.minimalKineticEnergy = 1*MeV +SIM.field.eps_min = 1 * mm +SIM.part.minimalKineticEnergy = 1 * MeV SIM.action.calo = "Geant4ScintillatorCalorimeterAction" ## set the particle.tbl file to add extra particles to DDsim (B-Baryons) ## use the power of python to get the file from DD4hep wherever it is import os -if os.path.exists( os.path.join( os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") ): - SIM.physics.pdgfile = os.path.join( os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") + +if os.path.exists( + os.path.join(os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") +): + SIM.physics.pdgfile = os.path.join( + os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl" + ) SIM.enableGun = True SIM.gun.particle = "mu-" -SIM.gun.energy = 8*GeV +SIM.gun.energy = 8 * GeV SIM.gun.position = "0, 0, -1000" SIM.gun.direction = "0,0,1" -#SIM.gun.isotrop +# SIM.gun.isotrop SIM.gun.multiplicity = 1 diff --git a/CaloTB/run_sim/ddsim_steering_00.py b/CaloTB/run_sim/ddsim_steering_00.py index 4d02f47d6..0a93d03e2 100644 --- a/CaloTB/run_sim/ddsim_steering_00.py +++ b/CaloTB/run_sim/ddsim_steering_00.py @@ -12,19 +12,19 @@ SIM.compactFile = "../compact/MainTestBeamSetup.xml" SIM.dumpSteeringFile = "dumpSteering00.xml" -SIM.field.eps_min = 1*mm +SIM.field.eps_min = 1 * mm -SIM.part.minimalKineticEnergy = 1*MeV +SIM.part.minimalKineticEnergy = 1 * MeV SIM.physicsList = "QGSP_BERT" - -SIM.enableDetailedShowerMode=True + +SIM.enableDetailedShowerMode = True SIM.enableGun = True -SIM.gun.energy = 10*GeV +SIM.gun.energy = 10 * GeV SIM.gun.particle = "pi+" -#SIM.gun.multiplicity +# SIM.gun.multiplicity SIM.gun.position = "0,0,-1000" -#SIM.gun.isotrop +# SIM.gun.isotrop SIM.gun.direction = "0,0,1" diff --git a/ILD/compact/ILD_common_v02/writeAllILDCompactDescriptions.py b/ILD/compact/ILD_common_v02/writeAllILDCompactDescriptions.py index ed170a418..d6ab99de4 100644 --- a/ILD/compact/ILD_common_v02/writeAllILDCompactDescriptions.py +++ b/ILD/compact/ILD_common_v02/writeAllILDCompactDescriptions.py @@ -1,40 +1,41 @@ -def writeTopCompactXml( outfile, version, name, Large, Option, SolenoidMap, AntiDID, FwdFields ): - +def writeTopCompactXml(outfile, version, name, Large, Option, SolenoidMap, AntiDID, FwdFields): # defaults for option 0, 1 # si ecal - ecal_sl1=4 - ecal_sl2=10 + ecal_sl1 = 4 + ecal_sl2 = 10 # ahcal - hcal_sl=3 - if Option==2 or Option==4: # SDHCAL - hcal_sl=1 - elif Option==3 or Option==4: # ScECAL - ecal_sl1=3 - ecal_sl2=11 - elif Option>1: - print( 'ERROR: do not know about Option', Option) + hcal_sl = 3 + if Option == 2 or Option == 4: # SDHCAL + hcal_sl = 1 + elif Option == 3 or Option == 4: # ScECAL + ecal_sl1 = 3 + ecal_sl2 = 11 + elif Option > 1: + print("ERROR: do not know about Option", Option) return - if FwdFields!=250 and FwdFields!=500 and FwdFields!=1000 and FwdFields!=0: - print( 'ERROR: do not know about FwdFields at energy', FwdFields) + if FwdFields != 250 and FwdFields != 500 and FwdFields != 1000 and FwdFields != 0: + print("ERROR: do not know about FwdFields at energy", FwdFields) return outfile.write('\n') - outfile.write(' \n' + ) + outfile.write(' \n') - outfile.write(' ILD simulation models used for detector optimisation \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write(' version="v' + version + '">\n') + outfile.write(" ILD simulation models used for detector optimisation \n") + outfile.write(" \n") + outfile.write(" \n") outfile.write(' \n') outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write(" \n") + outfile.write(" \n") if Large: outfile.write(' \n') else: @@ -52,23 +53,35 @@ def writeTopCompactXml( outfile, version, name, Large, Option, SolenoidMap, Anti outfile.write(' \n') outfile.write(' \n') outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write(" \n") + outfile.write( + ' \n' + ) + outfile.write( + ' \n' + ) + outfile.write(" \n") + outfile.write( + ' \n' + ) + outfile.write(" \n") + outfile.write(" \n") outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write( + ' \n' + ) + outfile.write(" \n") outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write( + ' \n' + ) + outfile.write(" \n") outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') - outfile.write(' \n') + outfile.write( + ' \n' + ) + outfile.write(" \n") + outfile.write(" \n") outfile.write(' \n') outfile.write(' \n') outfile.write(' \n') @@ -80,7 +93,7 @@ def writeTopCompactXml( outfile, version, name, Large, Option, SolenoidMap, Anti outfile.write(' \n') outfile.write(' \n') outfile.write(' \n') - + if Large: outfile.write(' \n') else: @@ -94,10 +107,10 @@ def writeTopCompactXml( outfile, version, name, Large, Option, SolenoidMap, Anti outfile.write(' \n') outfile.write(' \n') outfile.write(' \n') - outfile.write(' \n') + outfile.write(" \n") outfile.write(' \n') outfile.write(' \n') - outfile.write(' \n') + outfile.write(" \n") if SolenoidMap: if Large: @@ -113,89 +126,103 @@ def writeTopCompactXml( outfile, version, name, Large, Option, SolenoidMap, Anti else: outfile.write(' \n') - if FwdFields>0: - outfile.write(' \n') + if FwdFields > 0: + outfile.write( + ' \n' + ) + + outfile.write("\n") + - outfile.write('\n') +# ----------------------------------------------------- -#----------------------------------------------------- def getVersionParameters(version): - vparams={} - if version==2: - vparams['SolenoidMap']=False - vparams['AntiDID']=False - vparams['FwdFields']=0 - elif version==3: - vparams['SolenoidMap']=True - vparams['AntiDID']=False - vparams['FwdFields']=250 - elif version==4: - vparams['SolenoidMap']=True - vparams['AntiDID']=False - vparams['FwdFields']=500 - elif version==5: - vparams['SolenoidMap']=True - vparams['AntiDID']=True - vparams['FwdFields']=250 - elif version==6: - vparams['SolenoidMap']=True - vparams['AntiDID']=True - vparams['FwdFields']=500 - elif version==7: - vparams['SolenoidMap']=True - vparams['AntiDID']=False - vparams['FwdFields']=1000 - elif version==8: - vparams['SolenoidMap']=True - vparams['AntiDID']=True - vparams['FwdFields']=1000 + vparams = {} + if version == 2: + vparams["SolenoidMap"] = False + vparams["AntiDID"] = False + vparams["FwdFields"] = 0 + elif version == 3: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = False + vparams["FwdFields"] = 250 + elif version == 4: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = False + vparams["FwdFields"] = 500 + elif version == 5: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = True + vparams["FwdFields"] = 250 + elif version == 6: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = True + vparams["FwdFields"] = 500 + elif version == 7: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = False + vparams["FwdFields"] = 1000 + elif version == 8: + vparams["SolenoidMap"] = True + vparams["AntiDID"] = True + vparams["FwdFields"] = 1000 else: - print( 'ERROR: unknown version requested:',version,'!!') + print("ERROR: unknown version requested:", version, "!!") return vparams - if version<10: - vparams['vString']='0'+str(version) + if version < 10: + vparams["vString"] = "0" + str(version) else: - vparams['vString']=str(version) + vparams["vString"] = str(version) return vparams -#----------------------------------------------------- +# ----------------------------------------------------- import os -prename='ILD' # for the real thing +prename = "ILD" # for the real thing # prename='test' # for testing -topdir='../' -mainoutdirname=prename+'_sl5_v02' -mainoutdir=topdir+mainoutdirname +topdir = "../" +mainoutdirname = prename + "_sl5_v02" +mainoutdir = topdir + mainoutdirname if not os.path.exists(mainoutdir): os.makedirs(mainoutdir) for version in range(2, 9): - vparams=getVersionParameters(version) + vparams = getVersionParameters(version) for Large in (True, False): - for Option in range(0,5): - - modelname=prename+'_' + for Option in range(0, 5): + modelname = prename + "_" if Large: - modelname=modelname+'l' + modelname = modelname + "l" else: - modelname=modelname+'s' - modelname=modelname+'5_' - - if Option>0: - modelname=modelname+'o'+str(Option)+'_' - - modelname=modelname+'v'+vparams['vString'] - - outfile=open(mainoutdir+'/'+modelname+'.xml','w') - writeTopCompactXml( outfile, version=vparams['vString'], name=modelname, Large=Large, Option=Option, SolenoidMap=vparams['SolenoidMap'], AntiDID=vparams['AntiDID'], FwdFields=vparams['FwdFields'] ) + modelname = modelname + "s" + modelname = modelname + "5_" + + if Option > 0: + modelname = modelname + "o" + str(Option) + "_" + + modelname = modelname + "v" + vparams["vString"] + + outfile = open(mainoutdir + "/" + modelname + ".xml", "w") + writeTopCompactXml( + outfile, + version=vparams["vString"], + name=modelname, + Large=Large, + Option=Option, + SolenoidMap=vparams["SolenoidMap"], + AntiDID=vparams["AntiDID"], + FwdFields=vparams["FwdFields"], + ) outfile.close() - - if not os.path.exists( topdir+modelname ): - os.symlink( mainoutdirname, topdir+modelname ) + + if not os.path.exists(topdir + modelname): + os.symlink(mainoutdirname, topdir + modelname) diff --git a/ILD/doc/latex/ILD_envelopeDict.py b/ILD/doc/latex/ILD_envelopeDict.py index 3bbefa5fc..38ee735c9 100644 --- a/ILD/doc/latex/ILD_envelopeDict.py +++ b/ILD/doc/latex/ILD_envelopeDict.py @@ -1,7 +1,8 @@ -""" - python dictionary with parameters extracted from: /data/ilcsoft/HEAD/lcgeo/HEAD/ILD/compact/ILD_o1_v05/ILD_o1_v05.xml -""" -values={} +""" +python dictionary with parameters extracted from: /data/ilcsoft/HEAD/lcgeo/HEAD/ILD/compact/ILD_o1_v05/ILD_o1_v05.xml +""" + +values = {} values["VXD_inner_radius"] = 16.0 values["VXD_outer_radius"] = 60.0 values["VXD_half_length"] = 177.6 diff --git a/ILD/doc/latex/documentEnvelopes.py b/ILD/doc/latex/documentEnvelopes.py index 1774787c9..3ce8edf7f 100644 --- a/ILD/doc/latex/documentEnvelopes.py +++ b/ILD/doc/latex/documentEnvelopes.py @@ -1,517 +1,679 @@ """ - Create Latex documents with drawings and tables - documenting envelope parameters +Create Latex documents with drawings and tables +documenting envelope parameters - @author F.Gaede, CERN/DESY - @version 1.0 +@author F.Gaede, CERN/DESY +@version 1.0 """ + import sys import copy import cStringIO - # --- define the envelope parameters for every subdetector ----- -envDict={} -envDict['VXD'] = [ 'VXD_inner_radius', 'VXD_outer_radius', - 'VXD_half_length', 'VXD_cone_min_z', 'VXD_cone_max_z', 'VXD_inner_radius_1' ] - -envDict['SIT'] = [ 'SIT_inner_radius', 'SIT_outer_radius', - 'SIT_half_length', 'SIT_outer_radius_1', 'SIT_half_length_1' ] - -envDict['TPC'] = [ 'TPC_inner_radius', 'TPC_outer_radius', 'TPC_half_length' ] - -envDict['FTD'] = [ 'FTD_inner_radius', 'FTD_outer_radius', 'FTD_half_length', - 'FTD_outer_radius_1', 'FTD_outer_radius_2', - 'FTD_min_z_0', 'FTD_min_z_1', 'FTD_min_z_2', 'FTD_cone_min_z', 'FTD_cone_radius' ] - -envDict['SET'] = [ 'SET_inner_radius', 'SET_outer_radius', 'SET_half_length' ] - - -envDict['Ecal'] = [ 'Ecal_Hcal_symmetry', 'Ecal_inner_radius', 'Ecal_outer_radius', 'Ecal_half_length', 'Ecal_symmetry' ] - -envDict['EcalEndcap'] = [ 'EcalEndcap_inner_radius', 'EcalEndcap_outer_radius', 'EcalEndcap_min_z', 'EcalEndcap_max_z' ] - -envDict['EcalEndcapRing'] = [ 'EcalEndcapRing_inner_radius', 'EcalEndcapRing_outer_radius', 'EcalEndcapRing_min_z', 'EcalEndcapRing_max_z' ] - -envDict['Hcal'] = [ 'Hcal_inner_radius', 'Hcal_outer_radius', 'Hcal_half_length', 'Hcal_inner_symmetry' ] - -envDict['HcalEndcap'] = [ 'EcalEndcap_symmetry', 'HcalEndcap_inner_radius', 'HcalEndcap_outer_radius', 'HcalEndcap_min_z', 'HcalEndcap_max_z' ] - -envDict['HcalEndcapRing'] = [ 'HcalEndcapRing_inner_radius', 'HcalEndcapRing_outer_radius', 'HcalEndcapRing_min_z', 'HcalEndcapRing_max_z', 'HcalEndcapRing_symmetry' ] - -envDict['Coil'] = [ 'Coil_inner_radius', 'Coil_outer_radius', 'Coil_half_length'] - -envDict['Yoke'] = [ 'Yoke_inner_radius', 'Yoke_outer_radius', 'Yoke_half_length', 'Yoke_symmetry' ] - -envDict['YokeEndcap'] = [ 'YokeEndcap_inner_radius', 'YokeEndcap_outer_radius', 'YokeEndcap_min_z', 'YokeEndcap_max_z', 'YokeEndcap_symmetry' ] - -envDict['YokeEndcapPlug'] = [ 'YokeEndcapPlug_inner_radius', 'YokeEndcapPlug_outer_radius', 'YokeEndcapPlug_min_z', 'YokeEndcapPlug_max_z', 'YokeEndcapPlug_symmetry' ] - -envDict['BeamCal'] = [ 'BeamCal_inner_radius', 'BeamCal_outer_radius', 'BeamCal_min_z', 'BeamCal_max_z', 'BeamCal_thickness', 'BeamCal_tubeIncoming_radius' ] - -envDict['LumiCal'] = [ 'LumiCal_inner_radius', 'LumiCal_outer_radius', 'LumiCal_min_z', 'LumiCal_max_z', 'LumiCal_thickness' ] - -envDict['LHCal'] = [ 'LHCal_inner_radius', 'LHCal_outer_radius', 'LHCal_min_z', 'LHCal_max_z', 'LHCal_thickness' ] - - -#----- define the envelope shape points in rz ------------ +envDict = {} +envDict["VXD"] = [ + "VXD_inner_radius", + "VXD_outer_radius", + "VXD_half_length", + "VXD_cone_min_z", + "VXD_cone_max_z", + "VXD_inner_radius_1", +] + +envDict["SIT"] = [ + "SIT_inner_radius", + "SIT_outer_radius", + "SIT_half_length", + "SIT_outer_radius_1", + "SIT_half_length_1", +] + +envDict["TPC"] = ["TPC_inner_radius", "TPC_outer_radius", "TPC_half_length"] + +envDict["FTD"] = [ + "FTD_inner_radius", + "FTD_outer_radius", + "FTD_half_length", + "FTD_outer_radius_1", + "FTD_outer_radius_2", + "FTD_min_z_0", + "FTD_min_z_1", + "FTD_min_z_2", + "FTD_cone_min_z", + "FTD_cone_radius", +] + +envDict["SET"] = ["SET_inner_radius", "SET_outer_radius", "SET_half_length"] + + +envDict["Ecal"] = [ + "Ecal_Hcal_symmetry", + "Ecal_inner_radius", + "Ecal_outer_radius", + "Ecal_half_length", + "Ecal_symmetry", +] + +envDict["EcalEndcap"] = [ + "EcalEndcap_inner_radius", + "EcalEndcap_outer_radius", + "EcalEndcap_min_z", + "EcalEndcap_max_z", +] + +envDict["EcalEndcapRing"] = [ + "EcalEndcapRing_inner_radius", + "EcalEndcapRing_outer_radius", + "EcalEndcapRing_min_z", + "EcalEndcapRing_max_z", +] + +envDict["Hcal"] = [ + "Hcal_inner_radius", + "Hcal_outer_radius", + "Hcal_half_length", + "Hcal_inner_symmetry", +] + +envDict["HcalEndcap"] = [ + "EcalEndcap_symmetry", + "HcalEndcap_inner_radius", + "HcalEndcap_outer_radius", + "HcalEndcap_min_z", + "HcalEndcap_max_z", +] + +envDict["HcalEndcapRing"] = [ + "HcalEndcapRing_inner_radius", + "HcalEndcapRing_outer_radius", + "HcalEndcapRing_min_z", + "HcalEndcapRing_max_z", + "HcalEndcapRing_symmetry", +] + +envDict["Coil"] = ["Coil_inner_radius", "Coil_outer_radius", "Coil_half_length"] + +envDict["Yoke"] = ["Yoke_inner_radius", "Yoke_outer_radius", "Yoke_half_length", "Yoke_symmetry"] + +envDict["YokeEndcap"] = [ + "YokeEndcap_inner_radius", + "YokeEndcap_outer_radius", + "YokeEndcap_min_z", + "YokeEndcap_max_z", + "YokeEndcap_symmetry", +] + +envDict["YokeEndcapPlug"] = [ + "YokeEndcapPlug_inner_radius", + "YokeEndcapPlug_outer_radius", + "YokeEndcapPlug_min_z", + "YokeEndcapPlug_max_z", + "YokeEndcapPlug_symmetry", +] + +envDict["BeamCal"] = [ + "BeamCal_inner_radius", + "BeamCal_outer_radius", + "BeamCal_min_z", + "BeamCal_max_z", + "BeamCal_thickness", + "BeamCal_tubeIncoming_radius", +] + +envDict["LumiCal"] = [ + "LumiCal_inner_radius", + "LumiCal_outer_radius", + "LumiCal_min_z", + "LumiCal_max_z", + "LumiCal_thickness", +] + +envDict["LHCal"] = [ + "LHCal_inner_radius", + "LHCal_outer_radius", + "LHCal_min_z", + "LHCal_max_z", + "LHCal_thickness", +] + + +# ----- define the envelope shape points in rz ------------ envRZDict = {} -envRZDict['VXD'] = [ ( '0' , 'VXD_inner_radius' ) , - ( '0' , 'VXD_outer_radius' ) , - ( 'VXD_half_length', 'VXD_outer_radius' ) , - ( 'VXD_half_length', 'VXD_inner_radius_1') , - ( 'VXD_cone_max_z' , 'VXD_inner_radius_1') , - ( 'VXD_cone_min_z' , 'VXD_inner_radius' ) , - ( '0' , 'VXD_inner_radius' ) ] - -envRZDict['SIT'] = [ ( '0' , 'SIT_inner_radius' ) , - ( '0' , 'SIT_outer_radius' ) , - ( 'SIT_half_length' , 'SIT_outer_radius' ) , - ( 'SIT_half_length' , 'SIT_outer_radius_1' ) , - ( 'SIT_half_length_1', 'SIT_outer_radius_1' ) , - ( 'SIT_half_length_1', 'SIT_inner_radius' ) , - ( '0' , 'SIT_inner_radius' ) ] - -envRZDict['FTD'] = [ ( 'FTD_min_z_0' , 'FTD_inner_radius' ) , - ( 'FTD_min_z_0' , 'FTD_outer_radius_1' ) , - ( 'FTD_min_z_1' , 'FTD_outer_radius_1' ) , - ( 'FTD_min_z_1' , 'FTD_outer_radius_2' ) , - ( 'FTD_min_z_2' , 'FTD_outer_radius_2' ) , - ( 'FTD_min_z_2' , 'FTD_outer_radius' ) , - ( 'FTD_half_length', 'FTD_outer_radius' ) , - ( 'FTD_half_length', 'FTD_cone_radius' ) , - ( 'FTD_cone_min_z', 'FTD_inner_radius' ) , - ( 'FTD_min_z_0' , 'FTD_inner_radius' ) ] - -envRZDict['SET'] = [ ( '0' , 'SET_inner_radius' ) , - ( '0' , 'SET_outer_radius' ) , - ( 'SET_half_length', 'SET_outer_radius' ) , - ( 'SET_half_length', 'SET_inner_radius' ) , - ( '0' , 'SET_inner_radius' ) ] - -envRZDict['TPC'] = [ ( '0' , 'TPC_inner_radius' ) , - ( '0' , 'TPC_outer_radius' ) , - ( 'TPC_half_length', 'TPC_outer_radius' ) , - ( 'TPC_half_length', 'TPC_inner_radius' ) , - ( '0' , 'TPC_inner_radius' ) ] - -envRZDict['Ecal'] = [ ( '0' , 'Ecal_inner_radius' ) , - ( '0' , 'Ecal_outer_radius' ) , - ( 'Ecal_half_length', 'Ecal_outer_radius' ) , - ( 'Ecal_half_length', 'Ecal_inner_radius' ) , - ( '0' , 'Ecal_inner_radius' ) ] - -envRZDict['EcalEndcap'] = [ ( 'EcalEndcap_min_z' , 'EcalEndcap_inner_radius' ) , - ( 'EcalEndcap_min_z' , 'EcalEndcap_outer_radius' ) , - ( 'EcalEndcap_max_z' , 'EcalEndcap_outer_radius' ) , - ( 'EcalEndcap_max_z' , 'EcalEndcap_inner_radius' ) , - ( 'EcalEndcap_min_z' , 'EcalEndcap_inner_radius' ) ] - -envRZDict['EcalEndcapRing'] = [ ( 'EcalEndcapRing_min_z' , 'EcalEndcapRing_inner_radius' ) , - ( 'EcalEndcapRing_min_z' , 'EcalEndcapRing_outer_radius' ) , - ( 'EcalEndcapRing_max_z' , 'EcalEndcapRing_outer_radius' ) , - ( 'EcalEndcapRing_max_z' , 'EcalEndcapRing_inner_radius' ) , - ( 'EcalEndcapRing_min_z' , 'EcalEndcapRing_inner_radius' ) ] - -envRZDict['Hcal'] = [ ( '0' , 'Hcal_inner_radius' ) , - ( '0' , 'Hcal_outer_radius' ) , - ( 'Hcal_half_length', 'Hcal_outer_radius' ) , - ( 'Hcal_half_length', 'Hcal_inner_radius' ) , - ( '0' , 'Hcal_inner_radius' ) ] - - -envRZDict['HcalEndcap'] = [ ( 'HcalEndcap_min_z' , 'HcalEndcap_inner_radius' ) , - ( 'HcalEndcap_min_z' , 'HcalEndcap_outer_radius' ) , - ( 'HcalEndcap_max_z' , 'HcalEndcap_outer_radius' ) , - ( 'HcalEndcap_max_z' , 'HcalEndcap_inner_radius' ) , - ( 'HcalEndcap_min_z' , 'HcalEndcap_inner_radius' ) ] - -envRZDict['HcalEndcapRing'] = [ ( 'HcalEndcapRing_min_z' , 'HcalEndcapRing_inner_radius' ) , - ( 'HcalEndcapRing_min_z' , 'HcalEndcapRing_outer_radius' ) , - ( 'HcalEndcapRing_max_z' , 'HcalEndcapRing_outer_radius' ) , - ( 'HcalEndcapRing_max_z' , 'HcalEndcapRing_inner_radius' ) , - ( 'HcalEndcapRing_min_z' , 'HcalEndcapRing_inner_radius' ) ] - - -envRZDict['Yoke'] = [ ( '0' , 'Yoke_inner_radius' ) , - ( '0' , 'Yoke_outer_radius' ) , - ( 'Yoke_half_length', 'Yoke_outer_radius' ) , - ( 'Yoke_half_length', 'Yoke_inner_radius' ) , - ( '0' , 'Yoke_inner_radius' ) ] - - -envRZDict['YokeEndcap'] = [ ( 'YokeEndcap_min_z' , 'YokeEndcap_inner_radius' ) , - ( 'YokeEndcap_min_z' , 'YokeEndcap_outer_radius' ) , - ( 'YokeEndcap_max_z' , 'YokeEndcap_outer_radius' ) , - ( 'YokeEndcap_max_z' , 'YokeEndcap_inner_radius' ) , - ( 'YokeEndcap_min_z' , 'YokeEndcap_inner_radius' ) ] - -envRZDict['YokeEndcapPlug'] = [ ( 'YokeEndcapPlug_min_z' , 'YokeEndcapPlug_inner_radius' ) , - ( 'YokeEndcapPlug_min_z' , 'YokeEndcapPlug_outer_radius' ) , - ( 'YokeEndcapPlug_max_z' , 'YokeEndcapPlug_outer_radius' ) , - ( 'YokeEndcapPlug_max_z' , 'YokeEndcapPlug_inner_radius' ) , - ( 'YokeEndcapPlug_min_z' , 'YokeEndcapPlug_inner_radius' ) ] - -envRZDict['Coil'] = [ ( '0' , 'Coil_inner_radius' ) , - ( '0' , 'Coil_outer_radius' ) , - ( 'Coil_half_length', 'Coil_outer_radius' ) , - ( 'Coil_half_length', 'Coil_inner_radius' ) , - ( '0' , 'Coil_inner_radius' ) ] - - -envRZDict['BeamCal'] = [ ( 'BeamCal_min_z' , 'BeamCal_inner_radius' ) , - ( 'BeamCal_min_z' , 'BeamCal_outer_radius' ) , - ( 'BeamCal_max_z' , 'BeamCal_outer_radius' ) , - ( 'BeamCal_max_z' , 'BeamCal_inner_radius' ) , - ( 'BeamCal_min_z' , 'BeamCal_inner_radius' ) ] - -envRZDict['LumiCal'] = [ ( 'LumiCal_min_z' , 'LumiCal_inner_radius' ) , - ( 'LumiCal_min_z' , 'LumiCal_outer_radius' ) , - ( 'LumiCal_max_z' , 'LumiCal_outer_radius' ) , - ( 'LumiCal_max_z' , 'LumiCal_inner_radius' ) , - ( 'LumiCal_min_z' , 'LumiCal_inner_radius' ) ] - -envRZDict['LHCal'] = [ ( 'LHCal_min_z' , 'LHCal_inner_radius' ) , - ( 'LHCal_min_z' , 'LHCal_outer_radius' ) , - ( 'LHCal_max_z' , 'LHCal_outer_radius' ) , - ( 'LHCal_max_z' , 'LHCal_inner_radius' ) , - ( 'LHCal_min_z' , 'LHCal_inner_radius' ) ] - - - -#----------------------------------------------- +envRZDict["VXD"] = [ + ("0", "VXD_inner_radius"), + ("0", "VXD_outer_radius"), + ("VXD_half_length", "VXD_outer_radius"), + ("VXD_half_length", "VXD_inner_radius_1"), + ("VXD_cone_max_z", "VXD_inner_radius_1"), + ("VXD_cone_min_z", "VXD_inner_radius"), + ("0", "VXD_inner_radius"), +] + +envRZDict["SIT"] = [ + ("0", "SIT_inner_radius"), + ("0", "SIT_outer_radius"), + ("SIT_half_length", "SIT_outer_radius"), + ("SIT_half_length", "SIT_outer_radius_1"), + ("SIT_half_length_1", "SIT_outer_radius_1"), + ("SIT_half_length_1", "SIT_inner_radius"), + ("0", "SIT_inner_radius"), +] + +envRZDict["FTD"] = [ + ("FTD_min_z_0", "FTD_inner_radius"), + ("FTD_min_z_0", "FTD_outer_radius_1"), + ("FTD_min_z_1", "FTD_outer_radius_1"), + ("FTD_min_z_1", "FTD_outer_radius_2"), + ("FTD_min_z_2", "FTD_outer_radius_2"), + ("FTD_min_z_2", "FTD_outer_radius"), + ("FTD_half_length", "FTD_outer_radius"), + ("FTD_half_length", "FTD_cone_radius"), + ("FTD_cone_min_z", "FTD_inner_radius"), + ("FTD_min_z_0", "FTD_inner_radius"), +] + +envRZDict["SET"] = [ + ("0", "SET_inner_radius"), + ("0", "SET_outer_radius"), + ("SET_half_length", "SET_outer_radius"), + ("SET_half_length", "SET_inner_radius"), + ("0", "SET_inner_radius"), +] + +envRZDict["TPC"] = [ + ("0", "TPC_inner_radius"), + ("0", "TPC_outer_radius"), + ("TPC_half_length", "TPC_outer_radius"), + ("TPC_half_length", "TPC_inner_radius"), + ("0", "TPC_inner_radius"), +] + +envRZDict["Ecal"] = [ + ("0", "Ecal_inner_radius"), + ("0", "Ecal_outer_radius"), + ("Ecal_half_length", "Ecal_outer_radius"), + ("Ecal_half_length", "Ecal_inner_radius"), + ("0", "Ecal_inner_radius"), +] + +envRZDict["EcalEndcap"] = [ + ("EcalEndcap_min_z", "EcalEndcap_inner_radius"), + ("EcalEndcap_min_z", "EcalEndcap_outer_radius"), + ("EcalEndcap_max_z", "EcalEndcap_outer_radius"), + ("EcalEndcap_max_z", "EcalEndcap_inner_radius"), + ("EcalEndcap_min_z", "EcalEndcap_inner_radius"), +] + +envRZDict["EcalEndcapRing"] = [ + ("EcalEndcapRing_min_z", "EcalEndcapRing_inner_radius"), + ("EcalEndcapRing_min_z", "EcalEndcapRing_outer_radius"), + ("EcalEndcapRing_max_z", "EcalEndcapRing_outer_radius"), + ("EcalEndcapRing_max_z", "EcalEndcapRing_inner_radius"), + ("EcalEndcapRing_min_z", "EcalEndcapRing_inner_radius"), +] + +envRZDict["Hcal"] = [ + ("0", "Hcal_inner_radius"), + ("0", "Hcal_outer_radius"), + ("Hcal_half_length", "Hcal_outer_radius"), + ("Hcal_half_length", "Hcal_inner_radius"), + ("0", "Hcal_inner_radius"), +] + + +envRZDict["HcalEndcap"] = [ + ("HcalEndcap_min_z", "HcalEndcap_inner_radius"), + ("HcalEndcap_min_z", "HcalEndcap_outer_radius"), + ("HcalEndcap_max_z", "HcalEndcap_outer_radius"), + ("HcalEndcap_max_z", "HcalEndcap_inner_radius"), + ("HcalEndcap_min_z", "HcalEndcap_inner_radius"), +] + +envRZDict["HcalEndcapRing"] = [ + ("HcalEndcapRing_min_z", "HcalEndcapRing_inner_radius"), + ("HcalEndcapRing_min_z", "HcalEndcapRing_outer_radius"), + ("HcalEndcapRing_max_z", "HcalEndcapRing_outer_radius"), + ("HcalEndcapRing_max_z", "HcalEndcapRing_inner_radius"), + ("HcalEndcapRing_min_z", "HcalEndcapRing_inner_radius"), +] + + +envRZDict["Yoke"] = [ + ("0", "Yoke_inner_radius"), + ("0", "Yoke_outer_radius"), + ("Yoke_half_length", "Yoke_outer_radius"), + ("Yoke_half_length", "Yoke_inner_radius"), + ("0", "Yoke_inner_radius"), +] + + +envRZDict["YokeEndcap"] = [ + ("YokeEndcap_min_z", "YokeEndcap_inner_radius"), + ("YokeEndcap_min_z", "YokeEndcap_outer_radius"), + ("YokeEndcap_max_z", "YokeEndcap_outer_radius"), + ("YokeEndcap_max_z", "YokeEndcap_inner_radius"), + ("YokeEndcap_min_z", "YokeEndcap_inner_radius"), +] + +envRZDict["YokeEndcapPlug"] = [ + ("YokeEndcapPlug_min_z", "YokeEndcapPlug_inner_radius"), + ("YokeEndcapPlug_min_z", "YokeEndcapPlug_outer_radius"), + ("YokeEndcapPlug_max_z", "YokeEndcapPlug_outer_radius"), + ("YokeEndcapPlug_max_z", "YokeEndcapPlug_inner_radius"), + ("YokeEndcapPlug_min_z", "YokeEndcapPlug_inner_radius"), +] + +envRZDict["Coil"] = [ + ("0", "Coil_inner_radius"), + ("0", "Coil_outer_radius"), + ("Coil_half_length", "Coil_outer_radius"), + ("Coil_half_length", "Coil_inner_radius"), + ("0", "Coil_inner_radius"), +] + + +envRZDict["BeamCal"] = [ + ("BeamCal_min_z", "BeamCal_inner_radius"), + ("BeamCal_min_z", "BeamCal_outer_radius"), + ("BeamCal_max_z", "BeamCal_outer_radius"), + ("BeamCal_max_z", "BeamCal_inner_radius"), + ("BeamCal_min_z", "BeamCal_inner_radius"), +] + +envRZDict["LumiCal"] = [ + ("LumiCal_min_z", "LumiCal_inner_radius"), + ("LumiCal_min_z", "LumiCal_outer_radius"), + ("LumiCal_max_z", "LumiCal_outer_radius"), + ("LumiCal_max_z", "LumiCal_inner_radius"), + ("LumiCal_min_z", "LumiCal_inner_radius"), +] + +envRZDict["LHCal"] = [ + ("LHCal_min_z", "LHCal_inner_radius"), + ("LHCal_min_z", "LHCal_outer_radius"), + ("LHCal_max_z", "LHCal_outer_radius"), + ("LHCal_max_z", "LHCal_inner_radius"), + ("LHCal_min_z", "LHCal_inner_radius"), +] + + +# ----------------------------------------------- try: - dictFile = sys.argv[1] + dictFile = sys.argv[1] except IndexError: - print( " usage: python documentEnvelopes.py pyDict.py ") - print( " pyDict.py : python file with a data dictionary (created with extractParameters)") - print() - sys.exit(1) + print(" usage: python documentEnvelopes.py pyDict.py ") + print(" pyDict.py : python file with a data dictionary (created with extractParameters)") + print() + sys.exit(1) + +# ------ read dictionary 'values' from file +execfile(dictFile) +values["0"] = 0 -#------ read dictionary 'values' from file -execfile( dictFile ) -values['0'] = 0 -#----------------------------------------------- +# ----------------------------------------------- def run(): + writeTexFile("VXD", "_rz_envelope", getRZEnvCmds, 20) + writeTexFile("SIT", "_rz_envelope", getRZEnvCmds, 20) + writeTexFile("FTD", "_rz_envelope", getRZEnvCmds, 20) + writeTexFile("TPC", "_rz_envelope", getRZEnvCmds, 20) + writeTexFile("SET", "_rz_envelope", getRZEnvCmds, 20) - writeTexFile( 'VXD', '_rz_envelope' , getRZEnvCmds, 20 ) - writeTexFile( 'SIT', '_rz_envelope' , getRZEnvCmds, 20 ) - writeTexFile( 'FTD', '_rz_envelope' , getRZEnvCmds, 20 ) - writeTexFile( 'TPC', '_rz_envelope' , getRZEnvCmds, 20 ) - writeTexFile( 'SET', '_rz_envelope' , getRZEnvCmds, 20 ) + writeTexFile("ILD", "_rz_quadrant", getILDRZQuadrantCmds, 20) - writeTexFile( 'ILD', '_rz_quadrant' , getILDRZQuadrantCmds, 20 ) + writeILDEnvTable("ILD_enevelope_table.tex") - writeILDEnvTable('ILD_enevelope_table.tex' ) -#----------------------------------------------- -def writeILDEnvTable( file ): - fn = './ILD_envelopeTable.tex' - of = open( fn , 'w' ) +# ----------------------------------------------- +def writeILDEnvTable(file): + fn = "./ILD_envelopeTable.tex" + of = open(fn, "w") cmds = [] - cmds.extend( getDocHeaderCmds( 'article', ['multirow'] )) - - dets = ['VXD','FTD','SIT','TPC','SET', 'Ecal', 'EcalEndcap', 'EcalEndcapRing', - 'Hcal', 'HcalEndcap', 'HcalEndcapRing', 'Coil', 'Yoke', 'YokeEndcap', 'YokeEndcapPlug', 'BeamCal', 'LHCal', 'LumiCal' ] - - - cmds.extend( getEnvelopeTableCmds( dets , '\\large{Envelope parameters for ILD\_o1\_v05}' ) ) - - cmds.extend( getDocFooterCmds() ) + cmds.extend(getDocHeaderCmds("article", ["multirow"])) + + dets = [ + "VXD", + "FTD", + "SIT", + "TPC", + "SET", + "Ecal", + "EcalEndcap", + "EcalEndcapRing", + "Hcal", + "HcalEndcap", + "HcalEndcapRing", + "Coil", + "Yoke", + "YokeEndcap", + "YokeEndcapPlug", + "BeamCal", + "LHCal", + "LumiCal", + ] + + cmds.extend(getEnvelopeTableCmds(dets, "\\large{Envelope parameters for ILD\_o1\_v05}")) + + cmds.extend(getDocFooterCmds()) for cmd in cmds: - print(cmd , file=of) + print(cmd, file=of) of.close() -#----------------------------------------------- -def getEnvelopeTableCmds( dets , title ): + + +# ----------------------------------------------- +def getEnvelopeTableCmds(dets, title): cmds = [] - cmds.append( '\\begin{tabular}{|l | c | c | c | l r |}' ) - cmds.append( '\\hline' ) + cmds.append("\\begin{tabular}{|l | c | c | c | l r |}") + cmds.append("\\hline") - if( len( title )): - cmds.append( '\\multicolumn{6}{|c|}{} \\\\' ) - cmds.append( '\\multicolumn{6}{|c|}{' + title + '} \\\\' ) - cmds.append( '\\multicolumn{6}{|c|}{} \\\\' ) - cmds.append( '\\hline' ) + if len(title): + cmds.append("\\multicolumn{6}{|c|}{} \\\\") + cmds.append("\\multicolumn{6}{|c|}{" + title + "} \\\\") + cmds.append("\\multicolumn{6}{|c|}{} \\\\") + cmds.append("\\hline") - cmds.append( ' detector & inner radius & outer radius & half length & \multicolumn{2}{c|}{additional parameters} \\\\' ) - cmds.append( ' & & & min z, max z & & \\\\' ) - cmds.append( '\\hline' ) + cmds.append( + " detector & inner radius & outer radius & half length & \multicolumn{2}{c|}{additional parameters} \\\\" + ) + cmds.append(" & & & min z, max z & & \\\\") + cmds.append("\\hline") for d in dets: - cmds.extend( getTableLinesCmds( d ) ) + cmds.extend(getTableLinesCmds(d)) - cmds.append( '\\end{tabular}' ) + cmds.append("\\end{tabular}") return cmds -#----------------------------------------------- + +# ----------------------------------------------- def getTableLinesCmds(det): - cmds=[] - params = copy.deepcopy( envDict[ det ] ) + cmds = [] + params = copy.deepcopy(envDict[det]) - ri = det+'_inner_radius' - ro = det+'_outer_radius' - hl = det+'_half_length' - zs = det+'_min_z' - ze = det+'_max_z' + ri = det + "_inner_radius" + ro = det + "_outer_radius" + hl = det + "_half_length" + zs = det + "_min_z" + ze = det + "_max_z" - line = det + ' & ' + line = det + " & " - if( ri in params): - line += ( ("%.1f"%values[ ri ] ) + ' & ' ) - params.remove( ri ) + if ri in params: + line += ("%.1f" % values[ri]) + " & " + params.remove(ri) else: - line += ' - & ' + line += " - & " - if( ro in params): - line += ( ("%.1f"% values[ ro ] ) + ' & ' ) - params.remove( ro ) + if ro in params: + line += ("%.1f" % values[ro]) + " & " + params.remove(ro) else: - line += ' - & ' + line += " - & " - if( hl in params): - line += ( ("%.1f"% values[ hl ] ) + ' & ' ) - params.remove( hl ) + if hl in params: + line += ("%.1f" % values[hl]) + " & " + params.remove(hl) else: - line += ( ("%.1f"% values[ zs ] ) + ', ' + ("%.1f"% values[ ze ] ) + ' & ' ) - params.remove( zs ) - params.remove( ze ) - - #--- first extra parameter - if any - if len( params)>0: + line += ("%.1f" % values[zs]) + ", " + ("%.1f" % values[ze]) + " & " + params.remove(zs) + params.remove(ze) + + # --- first extra parameter - if any + if len(params) > 0: p = params[0] - line += '\\small{\\verb#'+ p + '#} & ' + ("%.1f"% values[ p ] ) - params.remove( p ) + line += "\\small{\\verb#" + p + "#} & " + ("%.1f" % values[p]) + params.remove(p) else: - line += ' & ' + line += " & " - line += ' \\\\ ' - cmds.append( line ) + line += " \\\\ " + cmds.append(line) - #--- other extra parameters - if any - need extra line + # --- other extra parameters - if any - need extra line - while( len( params)>0 ): - line = ' & & & & ' + while len(params) > 0: + line = " & & & & " p = params[0] - line += '\\small{\\verb#'+ p + '#} & ' + ("%.1f"% values[ p ] ) - params.remove( p ) - line += ' \\\\ ' - cmds.append( line ) - - cmds.append( '\\hline' ) + line += "\\small{\\verb#" + p + "#} & " + ("%.1f" % values[p]) + params.remove(p) + line += " \\\\ " + cmds.append(line) + + cmds.append("\\hline") return cmds -#----------------------------------------------- + + +# ----------------------------------------------- def getILDRZQuadrantCmds(det, width): - cmds = [] - cmds.extend( getColorCmds() ) + cmds.extend(getColorCmds()) + + cmds.append("\\begin{tikzpicture}") - cmds.append( '\\begin{tikzpicture}' ) - scale = 0.01 - #--------------------------------------------------- - - - cmds.append( lineOStr('[fill=VXDcol]', getEnvPoints('VXD',scale) ) ) - cmds.append( lineOStr('[fill=SITcol]', getEnvPoints('SIT',scale) ) ) - cmds.append( lineOStr('[fill=FTDcol]', getEnvPoints('FTD',scale) ) ) - cmds.append( lineOStr('[fill=TPCcol]', getEnvPoints('TPC',scale) ) ) - cmds.append( lineOStr('[fill=ECALcol]', getEnvPoints('Ecal',scale) ) ) - cmds.append( lineOStr('[fill=ECALcol]', getEnvPoints('EcalEndcap',scale) ) ) - cmds.append( lineOStr('[fill=ECALcol]', getEnvPoints('EcalEndcapRing',scale) ) ) - cmds.append( lineOStr('[fill=HCALcol]', getEnvPoints('Hcal',scale) ) ) - cmds.append( lineOStr('[fill=HCALcol]', getEnvPoints('HcalEndcap',scale) ) ) - cmds.append( lineOStr('[fill=HCALcol]', getEnvPoints('HcalEndcapRing',scale) ) ) - cmds.append( lineOStr('[fill=YOKEcol]', getEnvPoints('Yoke',scale) ) ) - cmds.append( lineOStr('[fill=YOKEcol]', getEnvPoints('YokeEndcap',scale) ) ) - cmds.append( lineOStr('[fill=YOKEcol]', getEnvPoints('YokeEndcapPlug',scale) ) ) - cmds.append( lineOStr('[fill=COILcol]', getEnvPoints('Coil',scale) ) ) - cmds.append( lineOStr('[fill=SITcol]', getEnvPoints('BeamCal',scale) ) ) - cmds.append( lineOStr('[fill=SITcol]', getEnvPoints('LumiCal',scale) ) ) - cmds.append( lineOStr('[fill=SITcol]', getEnvPoints('LHCal',scale) ) ) - - - cmds.append( '\\end{tikzpicture}' ) + # --------------------------------------------------- + + cmds.append(lineOStr("[fill=VXDcol]", getEnvPoints("VXD", scale))) + cmds.append(lineOStr("[fill=SITcol]", getEnvPoints("SIT", scale))) + cmds.append(lineOStr("[fill=FTDcol]", getEnvPoints("FTD", scale))) + cmds.append(lineOStr("[fill=TPCcol]", getEnvPoints("TPC", scale))) + cmds.append(lineOStr("[fill=ECALcol]", getEnvPoints("Ecal", scale))) + cmds.append(lineOStr("[fill=ECALcol]", getEnvPoints("EcalEndcap", scale))) + cmds.append(lineOStr("[fill=ECALcol]", getEnvPoints("EcalEndcapRing", scale))) + cmds.append(lineOStr("[fill=HCALcol]", getEnvPoints("Hcal", scale))) + cmds.append(lineOStr("[fill=HCALcol]", getEnvPoints("HcalEndcap", scale))) + cmds.append(lineOStr("[fill=HCALcol]", getEnvPoints("HcalEndcapRing", scale))) + cmds.append(lineOStr("[fill=YOKEcol]", getEnvPoints("Yoke", scale))) + cmds.append(lineOStr("[fill=YOKEcol]", getEnvPoints("YokeEndcap", scale))) + cmds.append(lineOStr("[fill=YOKEcol]", getEnvPoints("YokeEndcapPlug", scale))) + cmds.append(lineOStr("[fill=COILcol]", getEnvPoints("Coil", scale))) + cmds.append(lineOStr("[fill=SITcol]", getEnvPoints("BeamCal", scale))) + cmds.append(lineOStr("[fill=SITcol]", getEnvPoints("LumiCal", scale))) + cmds.append(lineOStr("[fill=SITcol]", getEnvPoints("LHCal", scale))) + + cmds.append("\\end{tikzpicture}") return cmds -#----------------------------------------------- -def getEnvPoints(det,scale): + +# ----------------------------------------------- +def getEnvPoints(det, scale): points = [] env = envRZDict[det] for ep in env: - p = (scale * values[ ep[0] ], scale * values[ ep[1] ] ) - print( det, ' point: ' , p) - points.append( p ) + p = (scale * values[ep[0]], scale * values[ep[1]]) + print(det, " point: ", p) + points.append(p) return points -#----------------------------------------------- -def writeTexFile( det, fileExt, method, width ): - fn = './figs/' + det + fileExt + '.tex' +# ----------------------------------------------- +def writeTexFile(det, fileExt, method, width): + fn = "./figs/" + det + fileExt + ".tex" - of = open( fn , 'w' ) + of = open(fn, "w") cmds = [] - cmds.extend( getDocHeaderCmds( 'standalone', ['tikz','graphicx'] ) ) + cmds.extend(getDocHeaderCmds("standalone", ["tikz", "graphicx"])) - cmds.extend( method( det , width ) ) + cmds.extend(method(det, width)) - cmds.extend( getDocFooterCmds() ) + cmds.extend(getDocFooterCmds()) for cmd in cmds: - print(cmd , file=of) + print(cmd, file=of) of.close() -#----------------------------------------------- -def lineStr( tl, opt="" ): - +# ----------------------------------------------- +def lineStr(tl, opt=""): o = cStringIO.StringIO() - - print('\draw ', opt, file=o) - - i=0 + + print("\draw ", opt, file=o) + + i = 0 for t in tl: - if( i>0 ): - print(' -- ', file=o) - print('(', t[0] ,',', t[1],') ', file=o) + if i > 0: + print(" -- ", file=o) + print("(", t[0], ",", t[1], ") ", file=o) i += 1 - print(';', file=o) + print(";", file=o) str = o.getvalue() o.close() return str -#----------------------------------------------- -def lineOStr( opt, tl ): - return lineStr( tl, opt ) -#----------------------------------------------- +# ----------------------------------------------- + -def getDocHeaderCmds( docClass , packages): +def lineOStr(opt, tl): + return lineStr(tl, opt) + + +# ----------------------------------------------- + + +def getDocHeaderCmds(docClass, packages): cmds = [] - - cmds.append( '\\documentclass[a4]{'+ docClass+'}' ) - if( docClass == 'standalone'): - cmds.append( '\\standaloneconfig{border=20pt}' ) + + cmds.append("\\documentclass[a4]{" + docClass + "}") + if docClass == "standalone": + cmds.append("\\standaloneconfig{border=20pt}") for p in packages: - cmds.append( '\\usepackage{'+p+'}' ) + cmds.append("\\usepackage{" + p + "}") - cmds.append( '\\usepackage[a4paper,top=3cm, bottom=2.5cm, left=1cm, right=2cm ]{geometry}' ) + cmds.append("\\usepackage[a4paper,top=3cm, bottom=2.5cm, left=1cm, right=2cm ]{geometry}") - cmds.append( '\\begin{document}' ) + cmds.append("\\begin{document}") return cmds -#----------------------------------------------- + + +# ----------------------------------------------- def getColorCmds(): cmds = [] - cmds.append( '\\definecolor{VXDcol}{RGB}{255,255,255}') - cmds.append( '\\definecolor{SITcol}{RGB}{221,221,221}') - cmds.append( '\\definecolor{SETcol}{RGB}{221,221,221}') - cmds.append( '\\definecolor{TPCcol}{RGB}{245,243,0}') - cmds.append( '\\definecolor{ECALcol}{RGB}{123,243,0}') - cmds.append( '\\definecolor{HCALcol}{RGB}{196,194,49}') - cmds.append( '\\definecolor{YOKEcol}{RGB}{24,194,196}') - cmds.append( '\\definecolor{COILcol}{RGB}{73,73,221}') - cmds.append( '\\definecolor{FTDcol}{RGB}{101,28,147}') - cmds.append( '\\definecolor{FCALcol}{RGB}{171,170,171}') + cmds.append("\\definecolor{VXDcol}{RGB}{255,255,255}") + cmds.append("\\definecolor{SITcol}{RGB}{221,221,221}") + cmds.append("\\definecolor{SETcol}{RGB}{221,221,221}") + cmds.append("\\definecolor{TPCcol}{RGB}{245,243,0}") + cmds.append("\\definecolor{ECALcol}{RGB}{123,243,0}") + cmds.append("\\definecolor{HCALcol}{RGB}{196,194,49}") + cmds.append("\\definecolor{YOKEcol}{RGB}{24,194,196}") + cmds.append("\\definecolor{COILcol}{RGB}{73,73,221}") + cmds.append("\\definecolor{FTDcol}{RGB}{101,28,147}") + cmds.append("\\definecolor{FCALcol}{RGB}{171,170,171}") return cmds + def getDocFooterCmds(): cmds = [] - cmds.append( '\\end{document}' ) + cmds.append("\\end{document}") return cmds -#----------------------------------------------- -def fixstr( aStr ): + + +# ----------------------------------------------- +def fixstr(aStr): l = len(aStr) - s = '' - for i in range(0,l+2): - s = s + ' ' + s = "" + for i in range(0, l + 2): + s = s + " " s = s + aStr return s -#----------------------------------------------- -def getRZEnvCmds( det, width ): +# ----------------------------------------------- + +def getRZEnvCmds(det, width): cmds = [] - envPoints = envRZDict[ det ] + envPoints = envRZDict[det] vals = values - - cmds.append( '\\begin{tikzpicture}' ) + cmds.append("\\begin{tikzpicture}") xmaxOrg = -1e99 # ---- compute the scale such that ymax == width for ep in envPoints: - if( vals[ ep[0] ] > xmaxOrg): - xmaxOrg = vals[ ep[0] ] + if vals[ep[0]] > xmaxOrg: + xmaxOrg = vals[ep[0]] scale = width / xmaxOrg - #--------------------------------------------------- + # --------------------------------------------------- points = [] - xvals = [] - yvals = [] - xmax,ymax= -1.e99, -1e99 + xvals = [] + yvals = [] + xmax, ymax = -1.0e99, -1e99 for ep in envPoints: + p = (scale * vals[ep[0]], scale * vals[ep[1]]) + points.append(p) - p = (scale * vals[ ep[0] ], scale * vals[ ep[1] ] ) - points.append( p ) - - x,y = p - if( x> xmax ): + x, y = p + if x > xmax: xmax = x - if( y> ymax ): + if y > ymax: ymax = y if ep[0] not in xvals: - xvals.append( ep[0] ) - p0 = ( scale * vals[ ep[0] ], 0 ) - cmds.append( lineOStr('[dashed]', [ p , p0 ] ) ) - cmds.append( '\\node [rotate=-90] at (' + str( p0[0] ) +','+ str( p0[1] ) - + ') {{\\verb#' + fixstr( ep[0] ) + '#}};' ) + xvals.append(ep[0]) + p0 = (scale * vals[ep[0]], 0) + cmds.append(lineOStr("[dashed]", [p, p0])) + cmds.append( + "\\node [rotate=-90] at (" + + str(p0[0]) + + "," + + str(p0[1]) + + ") {{\\verb#" + + fixstr(ep[0]) + + "#}};" + ) if ep[1] not in yvals: - yvals.append( ep[1] ) - p1 = ( 0, scale * vals[ ep[1] ] ) - cmds.append( lineOStr('[dashed]', [ p , p1 ] ) ) - cmds.append( '\\node [left] at (' + str(p1[0]) +','+str( p1[1] ) + ') {{\\verb#' - + str( ep[1] ) + '#}};' ) - - cmds.append( lineOStr('[ultra thick]', points ) ) - - cmds.append( lineOStr('[<->,thick]' , ( (0 , 1.25 * ymax ), (0,0), (1.25 * xmax ,0) ) ) ) + yvals.append(ep[1]) + p1 = (0, scale * vals[ep[1]]) + cmds.append(lineOStr("[dashed]", [p, p1])) + cmds.append( + "\\node [left] at (" + + str(p1[0]) + + "," + + str(p1[1]) + + ") {{\\verb#" + + str(ep[1]) + + "#}};" + ) + cmds.append(lineOStr("[ultra thick]", points)) - cmds.append( '\\end{tikzpicture}' ) + cmds.append(lineOStr("[<->,thick]", ((0, 1.25 * ymax), (0, 0), (1.25 * xmax, 0)))) + cmds.append("\\end{tikzpicture}") return cmds -#----------------------------------------------- +# ----------------------------------------------- -#----------------------------------------------- +# ----------------------------------------------- if __name__ == "__main__": - run() -#----------------------------------------------- + run() +# ----------------------------------------------- diff --git a/ILD/doc/latex/extractParameters.py b/ILD/doc/latex/extractParameters.py index cc637bb29..bb9d29d70 100644 --- a/ILD/doc/latex/extractParameters.py +++ b/ILD/doc/latex/extractParameters.py @@ -10,102 +10,97 @@ @version 1.0 """ -#----------------------------------------------- +# ----------------------------------------------- -#------------------------------------------------ +# ------------------------------------------------ # read the compact xml file from the command line # try: - compactFile = sys.argv[1] - paramFile = sys.argv[2] - dictFile = sys.argv[3] + compactFile = sys.argv[1] + paramFile = sys.argv[2] + dictFile = sys.argv[3] except IndexError: - print( " usage: python extractParameters.py compact.xml param_names.txt pyDict.py") - print() - sys.exit(1) + print(" usage: python extractParameters.py compact.xml param_names.txt pyDict.py") + print() + sys.exit(1) -#----------------------------------------------- +# ----------------------------------------------- import os, time, DDG4 from DDG4 import OutputLevel as Output from SystemOfUnits import * -#----------------------------------------------- +# ----------------------------------------------- + def run(): + kernel = DDG4.Kernel() - kernel = DDG4.Kernel() + try: + install_dir = os.environ["DD4hepINSTALL"] - try: - install_dir = os.environ['DD4hepINSTALL'] + except KeyError: + print(" please set the environment variable DD4hepINSTALL ") + print(" to your DD4hep installation path ! ") + exit(1) - except (KeyError): - print( " please set the environment variable DD4hepINSTALL ") - print( " to your DD4hep installation path ! ") - exit(1) + kernel.loadGeometry("file:" + compactFile) + lcdd = kernel.detectorDescription() + DDG4.importConstants(lcdd) - kernel.loadGeometry("file:"+ compactFile ) - lcdd = kernel.detectorDescription() - DDG4.importConstants( lcdd ) + # -------- - #-------- + inf = open(paramFile, "r") + outf = open(dictFile, "w") - inf = open( paramFile , 'r' ) - outf = open( dictFile , 'w' ) + names = readNames(inf) - names = readNames( inf ) - - writeDictionary( names, outf ) - - inf.close() - outf.close() + writeDictionary(names, outf) + inf.close() + outf.close() -#----------------------------------------------- -def readNames( inf ): - - """ - read ascii file with parameter names - """ - names = [] - - for line in inf: - cols = line.split() - for n in cols: - names.append( n ) - - return names -#----------------------------------------------- +# ----------------------------------------------- -def writeDictionary( names, of ): - - of.write( '""" \n' ) - of.write( ' python dictionary with parameters extracted from: ' + compactFile + '\n' ) - of.write( '""" '+ '\n') - of.write( 'values={}'+ '\n') - - for n in names: - of.write( 'values["'+n+'"] = ' + str( getattr( DDG4, n ) ) + '\n') - -#----------------------------------------------- +def readNames(inf): + """ + read ascii file with parameter names + """ + names = [] + for line in inf: + cols = line.split() + for n in cols: + names.append(n) -def printEnvelopeParameters( det ): - - print( " ========== ", det , " ================== ") - for p in dict[ det ]: - print( " ", p , getattr( DDG4, p )) + return names -#----------------------------------------------- +# ----------------------------------------------- -if __name__ == "__main__": - run() +def writeDictionary(names, of): + of.write('""" \n') + of.write(" python dictionary with parameters extracted from: " + compactFile + "\n") + of.write('""" ' + "\n") + of.write("values={}" + "\n") + + for n in names: + of.write('values["' + n + '"] = ' + str(getattr(DDG4, n)) + "\n") + +# ----------------------------------------------- - +def printEnvelopeParameters(det): + print(" ========== ", det, " ================== ") + for p in dict[det]: + print(" ", p, getattr(DDG4, p)) + +# ----------------------------------------------- + +if __name__ == "__main__": + run() diff --git a/ILD/scripts/dumpModelParameters.py b/ILD/scripts/dumpModelParameters.py index b5e63ff4c..06a748b16 100644 --- a/ILD/scripts/dumpModelParameters.py +++ b/ILD/scripts/dumpModelParameters.py @@ -3,85 +3,88 @@ import sys import time -#--- Mokka DB parameters --------------- -host="pollin1.in2p3.fr" # your host, usually localhost -user="consult" # your username -passwd="consult" # your password -dbName="models03" # name of the data base -#--------------------------------------- - -if len( sys.argv ) != 2: - print( " usage: python dumpModelParameters.py MODEL_NAME ") +# --- Mokka DB parameters --------------- +host = "pollin1.in2p3.fr" # your host, usually localhost +user = "consult" # your username +passwd = "consult" # your password +dbName = "models03" # name of the data base +# --------------------------------------- + +if len(sys.argv) != 2: + print(" usage: python dumpModelParameters.py MODEL_NAME ") sys.exit(0) -model = sys.argv[1] +model = sys.argv[1] -#model="ILD_o1_v05" +# model="ILD_o1_v05" -#----------------------------------------------------------------------- -db = MySQLdb.connect(host, user, passwd, dbName ) -#----------------------------------------------------------------------- +# ----------------------------------------------------------------------- +db = MySQLdb.connect(host, user, passwd, dbName) +# ----------------------------------------------------------------------- -outfile = "model_parameters_"+model+".xml" +outfile = "model_parameters_" + model + ".xml" -file = open( outfile , 'w' ) +file = open(outfile, "w") -#----------------------------------------------------------------------- +# ----------------------------------------------------------------------- # create a Cursor object cur = db.cursor() -#--- param dict: -params = {} +# --- param dict: +params = {} -#----- select all global parameters +# ----- select all global parameters cur.execute("select * from parameters ;") -#--- overwrite values in the dict: -for row in cur.fetchall() : - params[ row[0] ] = row[2] +# --- overwrite values in the dict: +for row in cur.fetchall(): + params[row[0]] = row[2] -# --- now select all sharing parameters for the model -cur.execute("select sub_detector.driver, sharing.parameter, sharing.driver_default_value from ingredients,sub_detector,sharing where (ingredients.model=\""+model+"\" and ingredients.sub_detector=sub_detector.name and sharing.driver=sub_detector.driver) ;") -#cur.execute("select sub_detector.driver, sharing.parameter, sharing.driver_default_value from ingredients,sub_detector,sharing where (ingredients.model=\""+model+"\" and ingredients.sub_detector=sub_detector.name and sharing.driver=sub_detector.driver and sharing.driver_default_value IS NOT NULL) ;") - +# --- now select all sharing parameters for the model +cur.execute( + 'select sub_detector.driver, sharing.parameter, sharing.driver_default_value from ingredients,sub_detector,sharing where (ingredients.model="' + + model + + '" and ingredients.sub_detector=sub_detector.name and sharing.driver=sub_detector.driver) ;' +) +# cur.execute("select sub_detector.driver, sharing.parameter, sharing.driver_default_value from ingredients,sub_detector,sharing where (ingredients.model=\""+model+"\" and ingredients.sub_detector=sub_detector.name and sharing.driver=sub_detector.driver and sharing.driver_default_value IS NOT NULL) ;") # --- safe params in dict -for row in cur.fetchall() : - #print row[1], " " , row[2] - params[ row[1] ] = row[2] +for row in cur.fetchall(): + # print row[1], " " , row[2] + params[row[1]] = row[2] -#----- now select all model specific parameters -cur.execute("select * from model_parameters where model=\""+model+"\" ;") +# ----- now select all model specific parameters +cur.execute('select * from model_parameters where model="' + model + '" ;') -#--- overwrite values in the dict: -for row in cur.fetchall() : - #print row[1], " " , row[2] - params[ row[1] ] = row[2] +# --- overwrite values in the dict: +for row in cur.fetchall(): + # print row[1], " " , row[2] + params[row[1]] = row[2] -#dump params to xml file +# dump params to xml file print("", file=file) -for k in sorted( params ): - v = params[ k ] - if v: - print("", file=file) - else: - cur.execute("select name, default_value from parameters where name=\"" + k + "\";") - for row in cur.fetchall() : - v = row[1] - print("", file=file) +for k in sorted(params): + v = params[k] + if v: + print('', file=file) + else: + cur.execute('select name, default_value from parameters where name="' + k + '";') + for row in cur.fetchall(): + v = row[1] + print('', file=file) diff --git a/detectorSegmentations/tests/options/phiEtaSegmentation.py b/detectorSegmentations/tests/options/phiEtaSegmentation.py index 9c00267ed..9c8102a53 100644 --- a/detectorSegmentations/tests/options/phiEtaSegmentation.py +++ b/detectorSegmentations/tests/options/phiEtaSegmentation.py @@ -4,52 +4,65 @@ from Configurables import MomentumRangeParticleGun from GaudiKernel import PhysicalConstants as constants + guntool = MomentumRangeParticleGun() -guntool.ThetaMin = 0 -guntool.ThetaMax = 2 * constants.pi +guntool.ThetaMin = 0 +guntool.ThetaMax = 2 * constants.pi guntool.PdgCodes = [11] guntool.MomentumMin = 500 guntool.MomentumMax = 1000 from Configurables import FlatSmearVertex + vertexsmeartool = FlatSmearVertex() -vertexsmeartool.xVertexMin = -25. -vertexsmeartool.xVertexMax = 25. -vertexsmeartool.yVertexMin = -25. -vertexsmeartool.yVertexMax = 25. -vertexsmeartool.zVertexMin = -25. -vertexsmeartool.zVertexMax = 25. +vertexsmeartool.xVertexMin = -25.0 +vertexsmeartool.xVertexMax = 25.0 +vertexsmeartool.yVertexMin = -25.0 +vertexsmeartool.yVertexMax = 25.0 +vertexsmeartool.zVertexMin = -25.0 +vertexsmeartool.zVertexMax = 25.0 from Configurables import GenAlg + gen = GenAlg() -gen.SignalProvider=guntool -gen.VertexSmearingTool=vertexsmeartool +gen.SignalProvider = guntool +gen.VertexSmearingTool = vertexsmeartool gen.hepmc.Path = "hepmc" from Configurables import HepMCToEDMConverter + hepmc_converter = HepMCToEDMConverter("Converter") -hepmc_converter.hepmc.Path="hepmc" -hepmc_converter.genparticles.Path="allGenParticles" -hepmc_converter.genvertices.Path="allGenVertices" +hepmc_converter.hepmc.Path = "hepmc" +hepmc_converter.genparticles.Path = "allGenParticles" +hepmc_converter.genvertices.Path = "allGenVertices" from Configurables import GeoSvc -geoservice = GeoSvc("GeoSvc", detectors=['file:Test/TestGeometry/data/Barrel_testCaloSD_phieta.xml']) + +geoservice = GeoSvc( + "GeoSvc", detectors=["file:Test/TestGeometry/data/Barrel_testCaloSD_phieta.xml"] +) from Configurables import SimG4Svc + geantservice = SimG4Svc("SimG4Svc") from Configurables import SimG4Alg, SimG4SaveCalHits, InspectHitsCollectionsTool -inspecttool = InspectHitsCollectionsTool("inspect", readoutNames=["ECalHits"], OutputLevel = DEBUG) -savecaltool = SimG4SaveCalHits("saveECalHits", readoutNames = ["ECalHits"], OutputLevel = DEBUG) + +inspecttool = InspectHitsCollectionsTool("inspect", readoutNames=["ECalHits"], OutputLevel=DEBUG) +savecaltool = SimG4SaveCalHits("saveECalHits", readoutNames=["ECalHits"], OutputLevel=DEBUG) savecaltool.positionedCaloHits.Path = "positionedCaloHits" savecaltool.caloHits.Path = "caloHits" -geantsim = SimG4Alg("SimG4Alg", outputs= ["SimG4SaveCalHits/saveECalHits","InspectHitsCollectionsTool/inspect"]) +geantsim = SimG4Alg( + "SimG4Alg", outputs=["SimG4SaveCalHits/saveECalHits", "InspectHitsCollectionsTool/inspect"] +) from Configurables import FCCDataSvc, PodioOutput + podiosvc = FCCDataSvc("EventDataSvc") out = PodioOutput("out", filename="test_phiEtaSegmentation.root") out.outputCommands = ["keep *"] -ApplicationMgr(EvtSel='NONE', - EvtMax=10, - TopAlg=[gen, hepmc_converter, geantsim, out], - ExtSvc = [podiosvc, geoservice, geantservice], - ) +ApplicationMgr( + EvtSel="NONE", + EvtMax=10, + TopAlg=[gen, hepmc_converter, geantsim, out], + ExtSvc=[podiosvc, geoservice, geantservice], +) diff --git a/example/SteeringFile_IDEA_o1_v03.py b/example/SteeringFile_IDEA_o1_v03.py index f9adeb07e..102085aa5 100644 --- a/example/SteeringFile_IDEA_o1_v03.py +++ b/example/SteeringFile_IDEA_o1_v03.py @@ -1,9 +1,10 @@ from DDSim.DD4hepSimulation import DD4hepSimulation from g4units import mm, GeV, MeV + SIM = DD4hepSimulation() ## The compact XML file, or multiple compact files, if the last one is the closer. -SIM.compactFile = ['../FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml'] +SIM.compactFile = ["../FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml"] ## Lorentz boost for the crossing angle, in radian! SIM.crossingAngleBoost = 0.0 SIM.enableDetailedShowerMode = False @@ -42,32 +43,32 @@ ################################################################################ ## Helper holding sensitive detector and other actions. -## +## ## The default tracker and calorimeter sensitive actions can be set with -## +## ## >>> SIM = DD4hepSimulation() ## >>> SIM.action.tracker=('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) ## >>> SIM.action.calo = "Geant4CalorimeterAction" -## +## ## The default sensitive actions for calorimeters and trackers are applied based on the sensitive type. ## The list of sensitive types can be changed with -## +## ## >>> SIM = DD4hepSimulation() ## >>> SIM.action.trackerSDTypes = ['tracker', 'myTrackerSensType'] ## >>> SIM.calor.calorimeterSDTypes = ['calorimeter', 'myCaloSensType'] -## +## ## For specific subdetectors specific sensitive detectors can be set based on patterns in the name of the subdetector. -## +## ## >>> SIM = DD4hepSimulation() ## >>> SIM.action.mapActions['tpc'] = "TPCSDAction" -## +## ## and additional parameters for the sensitive detectors can be set when the map is given a tuple -## +## ## >>> SIM = DD4hepSimulation() ## >>> SIM.action.mapActions['ecal'] =( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) -## +## ## Additional actions can be set as well with the following syntax variations: -## +## ## >>> SIM = DD4hepSimulation() ## # single action by name only: ## >>> SIM.action.run = "Geant4TestRunAction" @@ -79,7 +80,7 @@ ## >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } ## # multiple actions by list of dict of name and parameter dict: ## >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] -## +## ## On the command line or in python, these actions can be specified as JSON strings: ## $ ddsim --action.stack '{ "name": "Geant4TestStackAction", "parameter": { "Property_int": 10 } }' ## or @@ -92,48 +93,51 @@ ## } ## } ## ''' -## -## +## +## ################################################################################ -## set the default calorimeter action +## set the default calorimeter action SIM.action.calo = "Geant4ScintillatorCalorimeterAction" ## List of patterns matching sensitive detectors of type Calorimeter. -SIM.action.calorimeterSDTypes = ['calorimeter', 'DRcaloSiPMSD'] +SIM.action.calorimeterSDTypes = ["calorimeter", "DRcaloSiPMSD"] -## set the default event action +## set the default event action SIM.action.event = [] ## Create a map of patterns and actions to be applied to sensitive detectors. -## +## ## Example: if the name of the detector matches 'tpc' the TPCSDAction is used. -## +## ## SIM.action.mapActions['tpc'] = "TPCSDAction" -## -SIM.action.mapActions = {'DRcalo': 'DRCaloSDAction'} +## +SIM.action.mapActions = {"DRcalo": "DRCaloSDAction"} -## set the default run action +## set the default run action SIM.action.run = [] -## set the default stack action +## set the default stack action SIM.action.stack = [] -## set the default step action +## set the default step action SIM.action.step = [] -## set the default track action +## set the default track action SIM.action.track = [] -## set the default tracker action -SIM.action.tracker = ('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) +## set the default tracker action +SIM.action.tracker = ( + "Geant4TrackerWeightedAction", + {"HitPositionCombination": 2, "CollectSingleDeposits": False}, +) ## List of patterns matching sensitive detectors of type Tracker. -SIM.action.trackerSDTypes = ['tracker'] +SIM.action.trackerSDTypes = ["tracker"] ################################################################################ -## Configuration for the magnetic field (stepper) +## Configuration for the magnetic field (stepper) ################################################################################ SIM.field.delta_chord = 0.25 SIM.field.delta_intersection = 0.001 @@ -148,37 +152,41 @@ ################################################################################ ## Configuration for sensitive detector filters -## +## ## Set the default filter for 'tracker' ## >>> SIM.filter.tracker = "edep1kev" ## Use no filter for 'calorimeter' by default ## >>> SIM.filter.calo = "" -## +## ## Assign a filter to a sensitive detector via pattern matching ## >>> SIM.filter.mapDetFilter['FTD'] = "edep1kev" -## +## ## Or more than one filter: ## >>> SIM.filter.mapDetFilter['FTD'] = ["edep1kev", "geantino"] -## +## ## Don't use the default filter or anything else: ## >>> SIM.filter.mapDetFilter['TPC'] = None ## or "" or [] -## +## ## Create a custom filter. The dictionary is used to instantiate the filter later on ## >>> SIM.filter.filters['edep3kev'] = dict(name="EnergyDepositMinimumCut/3keV", parameter={"Cut": 3.0*keV} ) -## -## +## +## ################################################################################ -## +## ## default filter for calorimeter sensitive detectors; ## this is applied if no other filter is used for a calorimeter -## +## SIM.filter.calo = "edep0" -## list of filter objects: map between name and parameter dictionary -SIM.filter.filters = {'geantino': {'name': 'GeantinoRejectFilter/GeantinoRejector', 'parameter': {}}, 'edep1kev': {'name': 'EnergyDepositMinimumCut', 'parameter': {'Cut': 0.001}}, 'edep0': {'name': 'EnergyDepositMinimumCut/Cut0', 'parameter': {'Cut': 0.0}}} +## list of filter objects: map between name and parameter dictionary +SIM.filter.filters = { + "geantino": {"name": "GeantinoRejectFilter/GeantinoRejector", "parameter": {}}, + "edep1kev": {"name": "EnergyDepositMinimumCut", "parameter": {"Cut": 0.001}}, + "edep0": {"name": "EnergyDepositMinimumCut/Cut0", "parameter": {"Cut": 0.0}}, +} -## a map between patterns and filter objects, using patterns to attach filters to sensitive detector +## a map between patterns and filter objects, using patterns to attach filters to sensitive detector SIM.filter.mapDetFilter = {} ## default filter for tracking sensitive detectors; this is applied if no other filter is used for a tracker @@ -186,7 +194,7 @@ ################################################################################ -## Configuration for the Detector Construction. +## Configuration for the Detector Construction. ################################################################################ SIM.geometry.dumpGDML = "" SIM.geometry.dumpHierarchy = 0 @@ -223,38 +231,38 @@ ################################################################################ -## Configuration for the GuineaPig InputFiles +## Configuration for the GuineaPig InputFiles ################################################################################ ## Set the number of pair particles to simulate per event. ## Only used if inputFile ends with ".pairs" ## If "-1" all particles will be simulated in a single event -## +## SIM.guineapig.particlesPerEvent = "-1" ################################################################################ -## Configuration for the DDG4 ParticleGun +## Configuration for the DDG4 ParticleGun ################################################################################ -## direction of the particle gun, 3 vector -SIM.gun.direction = (1., 1., 1.) +## direction of the particle gun, 3 vector +SIM.gun.direction = (1.0, 1.0, 1.0) ## choose the distribution of the random direction for theta -## +## ## Options for random distributions: -## +## ## 'uniform' is the default distribution, flat in theta ## 'cos(theta)' is flat in cos(theta) ## 'eta', or 'pseudorapidity' is flat in pseudorapity ## 'ffbar' is distributed according to 1+cos^2(theta) -## +## ## Setting a distribution will set isotrop = True -## +## SIM.gun.distribution = None ## Total energy (including mass) for the particle gun. -## +## ## If not None, it will overwrite the setting of momentumMin and momentumMax SIM.gun.energy = None @@ -265,10 +273,10 @@ SIM.gun.etaMin = None ## isotropic distribution for the particle gun -## +## ## use the options phiMin, phiMax, thetaMin, and thetaMax to limit the range of randomly distributed directions ## if one of these options is not None the random distribution will be set to True and cannot be turned off! -## +## SIM.gun.isotrop = False ## Maximal momentum when using distribution (default = 0.0) @@ -285,7 +293,7 @@ ## Minimal azimuthal angle for random distribution SIM.gun.phiMin = None -## position of the particle gun, 3 vector +## position of the particle gun, 3 vector SIM.gun.position = (0.0, 0.0, 0.0) ## Maximal polar angle for random distribution @@ -296,7 +304,7 @@ ################################################################################ -## Configuration for the hepmc3 InputFiles +## Configuration for the hepmc3 InputFiles ################################################################################ ## Set the name of the attribute contraining color flow information index 0. @@ -306,28 +314,28 @@ SIM.hepmc3.Flow2 = "flow2" ## Set to false if the input should be opened with the hepmc2 ascii reader. -## +## ## If ``True`` a '.hepmc' file will be opened with the HEPMC3 Reader Factory. -## +## ## Defaults to true if DD4hep was build with HEPMC3 support. -## +## SIM.hepmc3.useHepMC3 = True ################################################################################ -## Configuration for Input Files. +## Configuration for Input Files. ################################################################################ ## Set one or more functions to configure input steps. -## +## ## The functions must take a ``DD4hepSimulation`` object as their only argument and return the created generatorAction ## ``gen`` (for example). -## +## ## For example one can add this to the ddsim steering file: -## +## ## def exampleUserPlugin(dd4hepSimulation): ## '''Example code for user created plugin. -## +## ## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed ## :return: GeneratorAction ## ''' @@ -340,27 +348,27 @@ ## gen.Parameters = {'DataFilePath': '/path/to/files/data'} ## gen.enableUI() ## return gen -## +## ## SIM.inputConfig.userInputPlugin = exampleUserPlugin -## +## ## Repeat function definition and assignment to add multiple input steps -## -## +## +## SIM.inputConfig.userInputPlugin = [] ################################################################################ -## Configuration for the generator-level InputFiles +## Configuration for the generator-level InputFiles ################################################################################ ## Set the name of the collection containing the MCParticle input. ## Default is "MCParticle". -## +## SIM.lcio.mcParticleCollectionName = "MCParticle" ################################################################################ -## Configuration for the LCIO output file settings +## Configuration for the LCIO output file settings ################################################################################ ## The event number offset to write in slcio output file. E.g setting it to 42 will start counting events from 42 instead of 0 @@ -374,7 +382,7 @@ ################################################################################ -## Configuration for the output levels of DDG4 components +## Configuration for the output levels of DDG4 components ################################################################################ ## Output level for geometry. @@ -394,7 +402,7 @@ ################################################################################ -## Configuration for Output Files. +## Configuration for Output Files. ################################################################################ ## Use the DD4HEP output plugin regardless of outputfilename. @@ -407,14 +415,14 @@ SIM.outputConfig.forceLCIO = False ## Set a function to configure the outputFile. -## +## ## The function must take a ``DD4hepSimulation`` object as its only argument and return ``None``. -## +## ## For example one can add this to the ddsim steering file: -## +## ## def exampleUserPlugin(dd4hepSimulation): ## '''Example code for user created plugin. -## +## ## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed ## :return: None ## ''' @@ -430,15 +438,19 @@ ## evt_root.enableUI() ## Kernel().eventAction().add(evt_root) ## return None -## +## ## SIM.outputConfig.userOutputPlugin = exampleUserPlugin ## # arbitrary options can be created and set via the steering file or command line ## SIM.outputConfig.myExtension = '.csv' -## +## + def Geant4Output2EDM4hep_DRC_plugin(dd4hepSimulation): from DDG4 import EventAction, Kernel - evt_root = EventAction(Kernel(), 'Geant4Output2EDM4hep_DRC/' + dd4hepSimulation.outputFile, True) + + evt_root = EventAction( + Kernel(), "Geant4Output2EDM4hep_DRC/" + dd4hepSimulation.outputFile, True + ) evt_root.Control = True output = dd4hepSimulation.outputFile evt_root.Output = output @@ -446,34 +458,35 @@ def Geant4Output2EDM4hep_DRC_plugin(dd4hepSimulation): Kernel().eventAction().add(evt_root) return None + SIM.outputConfig.userOutputPlugin = Geant4Output2EDM4hep_DRC_plugin ################################################################################ -## Configuration for the Particle Handler/ MCTruth treatment +## Configuration for the Particle Handler/ MCTruth treatment ################################################################################ ## Enable lots of printout on simulated hits and MC-truth information SIM.part.enableDetailedHitsAndParticleInfo = False -## Keep all created particles +## Keep all created particles SIM.part.keepAllParticles = False ## Minimal distance between particle vertex and endpoint of parent after ## which the vertexIsNotEndpointOfParent flag is set -## +## SIM.part.minDistToParentVertex = 2.2e-14 ## MinimalKineticEnergy to store particles created in the tracking region SIM.part.minimalKineticEnergy = 1.0 -## Printout at End of Tracking +## Printout at End of Tracking SIM.part.printEndTracking = False -## Printout at Start of Tracking +## Printout at Start of Tracking SIM.part.printStartTracking = False ## List of processes to save, on command line give as whitespace separated string in quotation marks -SIM.part.saveProcesses = ['Decay'] +SIM.part.saveProcesses = ["Decay"] ## Optionally enable an extended Particle Handler SIM.part.userParticleHandler = "Geant4TCUserParticleHandler" @@ -481,13 +494,13 @@ def Geant4Output2EDM4hep_DRC_plugin(dd4hepSimulation): ################################################################################ ## Configuration for the PhysicsList and Monte Carlo particle selection. -## +## ## To load arbitrary plugins, add a function to be executed. -## +## ## The function must take the DDG4.Kernel() object as the only argument. -## +## ## For example, add a function definition and the call to a steering file:: -## +## ## def setupCerenkov(kernel): ## from DDG4 import PhysicsList ## seq = kernel.physicsList() @@ -504,106 +517,149 @@ def Geant4Output2EDM4hep_DRC_plugin(dd4hepSimulation): ## ph.enableUI() ## seq.adopt(ph) ## return None -## +## ## SIM.physics.setupUserPhysics(setupCerenkov) -## +## ## # End of example -## +## ################################################################################ ## Set of Generator Statuses that are used to mark unstable particles that should decay inside of Geant4. -## +## SIM.physics.alternativeDecayStatuses = set() ## If true, add decay processes for all particles. -## +## ## Only enable when creating a physics list not based on an existing Geant4 list! -## +## SIM.physics.decays = False ## The name of the Geant4 Physics list. SIM.physics.list = "FTFP_BERT" ## location of particle.tbl file containing extra particles and their lifetime information -## +## ## For example in $DD4HEP/examples/DDG4/examples/particle.tbl -## +## SIM.physics.pdgfile = None ## The global geant4 rangecut for secondary production -## +## ## Default is 0.7 mm as is the case in geant4 10 -## +## ## To disable this plugin and be absolutely sure to use the Geant4 default range cut use "None" -## +## ## Set printlevel to DEBUG to see a printout of all range cuts, ## but this only works if range cut is not "None" -## +## SIM.physics.rangecut = 0.7 ## Set of PDG IDs that will not be passed from the input record to Geant4. -## +## ## Quarks, gluons and W's Z's etc should not be treated by Geant4 -## -SIM.physics.rejectPDGs = {1, 2, 3, 4, 5, 6, 3201, 3203, 4101, 4103, 21, 23, 24, 5401, 25, 2203, 5403, 3101, 3103, 4403, 2101, 5301, 2103, 5303, 4301, 1103, 4303, 5201, 5203, 3303, 4201, 4203, 5101, 5103, 5503} +## +SIM.physics.rejectPDGs = { + 1, + 2, + 3, + 4, + 5, + 6, + 3201, + 3203, + 4101, + 4103, + 21, + 23, + 24, + 5401, + 25, + 2203, + 5403, + 3101, + 3103, + 4403, + 2101, + 5301, + 2103, + 5303, + 4301, + 1103, + 4303, + 5201, + 5203, + 3303, + 4201, + 4203, + 5101, + 5103, + 5503, +} ## Set of PDG IDs for particles that should not be passed to Geant4 if their properTime is 0. -## +## ## The properTime of 0 indicates a documentation to add FSR to a lepton for example. -## +## SIM.physics.zeroTimePDGs = {17, 11, 13, 15} def setupOpticalPhysics(kernel): from DDG4 import PhysicsList + seq = kernel.physicsList() - cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys') + cerenkov = PhysicsList(kernel, "Geant4CerenkovPhysics/CerenkovPhys") cerenkov.TrackSecondariesFirst = True cerenkov.VerboseLevel = 1 cerenkov.enableUI() seq.adopt(cerenkov) - scint = PhysicsList(kernel, 'Geant4ScintillationPhysics/ScintillationPhys') + scint = PhysicsList(kernel, "Geant4ScintillationPhysics/ScintillationPhys") scint.VerboseLevel = 1 scint.TrackSecondariesFirst = True scint.BoundaryInvokeSD = True scint.enableUI() seq.adopt(scint) - - opt = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys') - opt.addParticleConstructor('G4OpticalPhoton') + + opt = PhysicsList(kernel, "Geant4OpticalPhotonPhysics/OpticalGammaPhys") + opt.addParticleConstructor("G4OpticalPhoton") opt.VerboseLevel = 1 opt.BoundaryInvokeSD = True opt.enableUI() seq.adopt(opt) return None + + SIM.physics.setupUserPhysics(setupOpticalPhysics) + def setupDRCFastSim(kernel): from DDG4 import DetectorConstruction, Geant4, PhysicsList + geant4 = Geant4(kernel) seq = geant4.detectorConstruction() # Create a model for fast simulation - model = DetectorConstruction(kernel, str("Geant4DRCFiberModel/ShowerModel") ) + model = DetectorConstruction(kernel, str("Geant4DRCFiberModel/ShowerModel")) # Mandatory model parameters - model.RegionName = 'FastSimOpFiberRegion' + model.RegionName = "FastSimOpFiberRegion" model.Enable = True - model.ApplicableParticles = ['opticalphoton'] + model.ApplicableParticles = ["opticalphoton"] model.enableUI() seq.adopt(model) # Now build the physics list: phys = kernel.physicsList() - ph = PhysicsList(kernel, str('Geant4FastPhysics/FastPhysicsList')) - ph.EnabledParticles = ['opticalphoton'] + ph = PhysicsList(kernel, str("Geant4FastPhysics/FastPhysicsList")) + ph.EnabledParticles = ["opticalphoton"] ph.BeVerbose = True ph.enableUI() phys.adopt(ph) phys.dump() + + SIM.physics.setupUserPhysics(setupDRCFastSim) ################################################################################ -## Properties for the random number generator +## Properties for the random number generator ################################################################################ ## If True, calculate random seed for each event basedon eventID and runID @@ -618,21 +674,21 @@ def setupDRCFastSim(kernel): ################################################################################ ## Configuration for setting commands to run during different phases. -## +## ## In this section, one can configure commands that should be run during the different phases of the Geant4 execution. -## +## ## 1. Configuration ## 2. Initialization ## 3. Pre Run ## 4. Post Run ## 5. Terminate / Finalization -## +## ## For example, one can add -## +## ## >>> SIM.ui.commandsConfigure = ['/physics_lists/em/SyncRadiation true'] -## +## ## Further details should be taken from the Geant4 documentation. -## +## ################################################################################ ## List of UI commands to run during the 'Configure' phase. diff --git a/example/arcfullsim.py b/example/arcfullsim.py index 41cbabe12..e47f420f0 100755 --- a/example/arcfullsim.py +++ b/example/arcfullsim.py @@ -2,10 +2,11 @@ Test of ARC detector The lines 27-95 setup the simulation using DD4hep The lines 99-127 run the simulation and produce some plots -An exception is thrown in case the simulation failed or the output file is too small. - Last modification 2023-Jun-23 - Author: Alvaro Tolosa-Delgado +An exception is thrown in case the simulation failed or the output file is too small. + Last modification 2023-Jun-23 + Author: Alvaro Tolosa-Delgado """ + from __future__ import absolute_import, unicode_literals import logging import sys @@ -20,14 +21,14 @@ format="%(name)-16s %(levelname)s %(message)s", level=logging.INFO, stream=sys.stdout, - ) + ) logger = logging.getLogger("DDSim") SIM = DD4hepSimulation() # Default is enable visualization of tracks SIM.runType = "qt" - SIM.macroFile ='vis.mac' + SIM.macroFile = "vis.mac" # Ensure that Cerenkov and optical physics are always loaded def setupCerenkov(kernel): @@ -58,7 +59,7 @@ def setupCerenkov(kernel): SIM.filter.filters["opticalphotons"] = dict( name="ParticleSelectFilter/OpticalPhotonSelector", parameter={"particle": "opticalphoton"}, - ) + ) SIM.filter.mapDetFilter["ARCBARREL"] = "opticalphotons" SIM.filter.mapDetFilter["ARCENDCAP"] = "opticalphotons" @@ -74,15 +75,14 @@ def setupCerenkov(kernel): SIM.enableGun = True SIM.gun.energy = "50*GeV" SIM.gun.particle = "pi+" - #SIM.gun.thetaMin = "30*deg" - #SIM.gun.thetaMax = "150*deg" - #SIM.gun.phiMin = "0*deg" - #SIM.gun.phiMax = "240.1*deg" + # SIM.gun.thetaMin = "30*deg" + # SIM.gun.thetaMax = "150*deg" + # SIM.gun.phiMin = "0*deg" + # SIM.gun.phiMax = "240.1*deg" SIM.gun.distribution = "uniform" SIM.gun.multiplicity = 1 SIM.gun.position = "0 0 0*cm" - # Default compact file SIM.compactFile = "./compact/arc_full_v0.xml" @@ -90,7 +90,7 @@ def setupCerenkov(kernel): SIM.outputFile = "arcsim.root" if hasattr(SIM, "outputConfig") and hasattr(SIM.outputConfig, "forceDD4HEP"): SIM.outputConfig.forceDD4HEP = True # use DD4hep root format, not EDM4HEP - #SIM.outputFile = "arcsim_edm4hep.root" + # SIM.outputFile = "arcsim_edm4hep.root" # Override with user options SIM.parseOptions() @@ -98,32 +98,56 @@ def setupCerenkov(kernel): # Run the simulation try: SIM.run() - if os.path.getsize( SIM.outputFile ) < 1000000 : + if os.path.getsize(SIM.outputFile) < 1000000: raise RuntimeError("Output file not found or size less than 1MB") # Create some images outImagePrefix = "arcsim_" ROOT.gROOT.SetBatch(1) rootfile = ROOT.TFile(SIM.outputFile) - if not "edm4hep" in SIM.outputFile : + if not "edm4hep" in SIM.outputFile: EVENT = rootfile.Get("EVENT") - EVENT.Draw("ArcCollection.position.Z():ArcCollection.position.phi()","((ArcCollection.cellID>>5)&0x7)==0") - ROOT.gPad.SaveAs( outImagePrefix + "barrel_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.Y():ArcCollection.position.X()","((ArcCollection.cellID>>5)&0x7)==1") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZpos_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.Y():ArcCollection.position.X()","((ArcCollection.cellID>>5)&0x7)==2") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZneg_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.Y():ArcCollection.position.X()","((ArcCollection.cellID>>5)&0x7)==2&&ArcCollection.position.Y()>0&&ArcCollection.position.X()>0") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZneg_" + SIM.gun.particle + "zoom.png") - else : + EVENT.Draw( + "ArcCollection.position.Z():ArcCollection.position.phi()", + "((ArcCollection.cellID>>5)&0x7)==0", + ) + ROOT.gPad.SaveAs(outImagePrefix + "barrel_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.Y():ArcCollection.position.X()", + "((ArcCollection.cellID>>5)&0x7)==1", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZpos_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.Y():ArcCollection.position.X()", + "((ArcCollection.cellID>>5)&0x7)==2", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZneg_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.Y():ArcCollection.position.X()", + "((ArcCollection.cellID>>5)&0x7)==2&&ArcCollection.position.Y()>0&&ArcCollection.position.X()>0", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZneg_" + SIM.gun.particle + "zoom.png") + else: EVENT = rootfile.Get("events") - EVENT.Draw("ArcCollection.position.z:atan(ArcCollection.position.y/ArcCollection.position.x)","((ArcCollection.cellID>>5)&0x7)==0&& ArcCollection.position.x>0") - ROOT.gPad.SaveAs( outImagePrefix + "barrel_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.y:ArcCollection.position.x","((ArcCollection.cellID>>5)&0x7)==1") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZpos_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.y:ArcCollection.position.x","((ArcCollection.cellID>>5)&0x7)==2") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZneg_" + SIM.gun.particle + ".png") - EVENT.Draw("ArcCollection.position.y:ArcCollection.position.x","((ArcCollection.cellID>>5)&0x7)==2&& ArcCollection.position.x>0&& ArcCollection.position.y>0") - ROOT.gPad.SaveAs( outImagePrefix + "endcapZneg_" + SIM.gun.particle + "zoom.png") + EVENT.Draw( + "ArcCollection.position.z:atan(ArcCollection.position.y/ArcCollection.position.x)", + "((ArcCollection.cellID>>5)&0x7)==0&& ArcCollection.position.x>0", + ) + ROOT.gPad.SaveAs(outImagePrefix + "barrel_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.y:ArcCollection.position.x", + "((ArcCollection.cellID>>5)&0x7)==1", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZpos_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.y:ArcCollection.position.x", + "((ArcCollection.cellID>>5)&0x7)==2", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZneg_" + SIM.gun.particle + ".png") + EVENT.Draw( + "ArcCollection.position.y:ArcCollection.position.x", + "((ArcCollection.cellID>>5)&0x7)==2&& ArcCollection.position.x>0&& ArcCollection.position.y>0", + ) + ROOT.gPad.SaveAs(outImagePrefix + "endcapZneg_" + SIM.gun.particle + "zoom.png") rootfile.Close() @@ -133,4 +157,7 @@ def setupCerenkov(kernel): logger.fatal("TEST: failed") if "global name" in str(e): globalToSet = str(e).split("'")[1] - logger.fatal("Unknown global variable, please add\nglobal %s\nto your steeringFile" % globalToSet) + logger.fatal( + "Unknown global variable, please add\nglobal %s\nto your steeringFile" + % globalToSet + ) diff --git a/example/guineapig_to_lcio.py b/example/guineapig_to_lcio.py index 47e3308b6..e2ee1b96b 100755 --- a/example/guineapig_to_lcio.py +++ b/example/guineapig_to_lcio.py @@ -2,7 +2,7 @@ ####################################################### # # simple script to read guineapig pair background files -# and convert them to LCIO files +# and convert them to LCIO files # # @author F.Gaede, DESY # @date 18/01/2017 @@ -20,93 +20,86 @@ from pyLCIO import UTIL, EVENT, IMPL, IO, IOIMPL - -#================================================ -if len( sys.argv ) < 2: +# ================================================ +if len(sys.argv) < 2: print(" usage: python guineapig_to_lcio.py eepair_guineapig.pair ") sys.exit(0) -#================================================= +# ================================================= infile = sys.argv[1] outfile = infile + ".slcio" -wrt = IOIMPL.LCFactory.getInstance().createLCWriter( ) -wrt.open( outfile , EVENT.LCIO.WRITE_NEW ) -col = IMPL.LCCollectionVec( EVENT.LCIO.MCPARTICLE ) +wrt = IOIMPL.LCFactory.getInstance().createLCWriter() +wrt.open(outfile, EVENT.LCIO.WRITE_NEW) +col = IMPL.LCCollectionVec(EVENT.LCIO.MCPARTICLE) -evt = IMPL.LCEventImpl() -evt.setEventNumber( 0 ) +evt = IMPL.LCEventImpl() +evt.setEventNumber(0) -evt.addCollection( col , "MCParticle" ) +evt.addCollection(col, "MCParticle") -# --- +# --- -f = open( infile , 'r' ) +f = open(infile, "r") for lin in f: - d = lin.split() -# print d + # print d - energy = float( d[0] ) - betaX = float( d[1] ) - betaY = float( d[2] ) - betaZ = float( d[3] ) - posX = float( d[4] ) - posY = float( d[5] ) - posZ = float( d[6] ) + energy = float(d[0]) + betaX = float(d[1]) + betaY = float(d[2]) + betaZ = float(d[3]) + posX = float(d[4]) + posY = float(d[5]) + posZ = float(d[6]) -# ---- + # ---- pdg = 11 - charge = -1. + charge = -1.0 if energy < 0: pdg = -11 - energy = - energy - charge = 1. + energy = -energy + charge = 1.0 -#--- + # --- px = betaX * energy py = betaY * energy pz = betaZ * energy - momentum = array('f',[ px, py, pz ] ) + momentum = array("f", [px, py, pz]) - nm2mm = 1e-6 + nm2mm = 1e-6 vtxx = nm2mm * posX vtxy = nm2mm * posY vtxz = nm2mm * posZ - vertex = array('d',[vtxx, vtxy, vtxz ] ) - - - -#--------------- create MCParticle ------------------- - - mcp = IMPL.MCParticleImpl() + vertex = array("d", [vtxx, vtxy, vtxz]) - mcp.setGeneratorStatus(1) + # --------------- create MCParticle ------------------- - mcp.setMass( 0.0005109989461 ) - - mcp.setPDG( pdg ) + mcp = IMPL.MCParticleImpl() - mcp.setMomentum( momentum ) - mcp.setVertex( vertex ) - mcp.setCharge( charge ) + mcp.setGeneratorStatus(1) + mcp.setMass(0.0005109989461) -#------------------------------------------------------- + mcp.setPDG(pdg) + mcp.setMomentum(momentum) + mcp.setVertex(vertex) + mcp.setCharge(charge) - col.addElement( mcp ) + # ------------------------------------------------------- + col.addElement(mcp) -wrt.writeEvent( evt ) -wrt.close() +wrt.writeEvent(evt) +wrt.close() diff --git a/example/lcio_particle_gun.py b/example/lcio_particle_gun.py index b72a5c27f..2a9b47970 100644 --- a/example/lcio_particle_gun.py +++ b/example/lcio_particle_gun.py @@ -16,105 +16,98 @@ # --- LCIO dependencies --- from pyLCIO import UTIL, EVENT, IMPL, IO, IOIMPL -#---- number of events per momentum bin ----- +# ---- number of events per momentum bin ----- nevt = 1000 outfile = "mcparticles.slcio" -#-------------------------------------------- +# -------------------------------------------- -wrt = IOIMPL.LCFactory.getInstance().createLCWriter( ) +wrt = IOIMPL.LCFactory.getInstance().createLCWriter() -wrt.open( outfile , EVENT.LCIO.WRITE_NEW ) +wrt.open(outfile, EVENT.LCIO.WRITE_NEW) -print( " opened outfile: " , outfile ) +print(" opened outfile: ", outfile) random.seed() -#========== particle properties =================== +# ========== particle properties =================== -#momenta = [ 1. , 3., 5., 10., 15., 25., 50., 100. ] -momenta = [ 5. ] +# momenta = [ 1. , 3., 5., 10., 15., 25., 50., 100. ] +momenta = [5.0] -genstat = 1 +genstat = 1 pdg = -13 -charge = +1. -#pdg = 211 -mass = 0.105658 -theta = 85./180. * math.pi -#theta = 20./180. * math.pi +charge = +1.0 +# pdg = 211 +mass = 0.105658 +theta = 85.0 / 180.0 * math.pi +# theta = 20./180. * math.pi -decayLen = 1.e32 -#================================================= +decayLen = 1.0e32 +# ================================================= # write a RunHeader -run = IMPL.LCRunHeaderImpl() -run.setRunNumber( 0 ) -run.parameters().setValue("Generator","${lcgeo}_DIR/examples/lcio_particle_gun.py") -run.parameters().setValue("PDG", pdg ) -run.parameters().setValue("Charge", charge ) -run.parameters().setValue("Mass", mass ) -wrt.writeRunHeader( run ) -#================================================ +run = IMPL.LCRunHeaderImpl() +run.setRunNumber(0) +run.parameters().setValue("Generator", "${lcgeo}_DIR/examples/lcio_particle_gun.py") +run.parameters().setValue("PDG", pdg) +run.parameters().setValue("Charge", charge) +run.parameters().setValue("Mass", mass) +wrt.writeRunHeader(run) +# ================================================ for p in momenta: - - for j in range( 0, nevt ): + for j in range(0, nevt): + col = IMPL.LCCollectionVec(EVENT.LCIO.MCPARTICLE) + evt = IMPL.LCEventImpl() - col = IMPL.LCCollectionVec( EVENT.LCIO.MCPARTICLE ) - evt = IMPL.LCEventImpl() + evt.setEventNumber(j) - evt.setEventNumber( j ) + evt.addCollection(col, "MCParticle") - evt.addCollection( col , "MCParticle" ) + phi = random.random() * math.pi * 2.0 - phi = random.random() * math.pi * 2. - - energy = math.sqrt( mass*mass + p * p ) - - px = p * math.cos( phi ) * math.sin( theta ) - py = p * math.sin( phi ) * math.sin( theta ) - pz = p * math.cos( theta ) + energy = math.sqrt(mass * mass + p * p) - momentum = array('f',[ px, py, pz ] ) + px = p * math.cos(phi) * math.sin(theta) + py = p * math.sin(phi) * math.sin(theta) + pz = p * math.cos(theta) - epx = decayLen * math.cos( phi ) * math.sin( theta ) - epy = decayLen * math.sin( phi ) * math.sin( theta ) - epz = decayLen * math.cos( theta ) + momentum = array("f", [px, py, pz]) - endpoint = array('d',[ epx, epy, epz ] ) - + epx = decayLen * math.cos(phi) * math.sin(theta) + epy = decayLen * math.sin(phi) * math.sin(theta) + epz = decayLen * math.cos(theta) -#--------------- create MCParticle ------------------- - - mcp = IMPL.MCParticleImpl() + endpoint = array("d", [epx, epy, epz]) - mcp.setGeneratorStatus( genstat ) - mcp.setMass( mass ) - mcp.setPDG( pdg ) - mcp.setMomentum( momentum ) - mcp.setCharge( charge ) + # --------------- create MCParticle ------------------- - if( decayLen < 1.e9 ) : # arbitrary ... - mcp.setEndpoint( endpoint ) + mcp = IMPL.MCParticleImpl() + mcp.setGeneratorStatus(genstat) + mcp.setMass(mass) + mcp.setPDG(pdg) + mcp.setMomentum(momentum) + mcp.setCharge(charge) -#------------------------------------------------------- + if decayLen < 1.0e9: # arbitrary ... + mcp.setEndpoint(endpoint) - + # ------------------------------------------------------- -#------------------------------------------------------- + # ------------------------------------------------------- + col.addElement(mcp) - col.addElement( mcp ) + wrt.writeEvent(evt) - wrt.writeEvent( evt ) - -wrt.close() +wrt.close() # @@ -138,10 +131,10 @@ # double VHEP3; // z vertex position in mm # double VHEP4; // production time in mm/c # -# inputFile >> ISTHEP >> IDHEP +# inputFile >> ISTHEP >> IDHEP # >> JMOHEP1 >> JMOHEP2 # >> JDAHEP1 >> JDAHEP2 -# >> PHEP1 >> PHEP2 >> PHEP3 +# >> PHEP1 >> PHEP2 >> PHEP3 # >> PHEP4 >> PHEP5 # >> VHEP1 >> VHEP2 >> VHEP3 # >> VHEP4; diff --git a/example/steeringFile.py b/example/steeringFile.py index 47530cfed..773c0f7a1 100644 --- a/example/steeringFile.py +++ b/example/steeringFile.py @@ -6,40 +6,47 @@ SIM.runType = "batch" SIM.numberOfEvents = 2 -SIM.field.eps_min = .001*mm +SIM.field.eps_min = 0.001 * mm SIM.gun.multiplicity = 1 -SIM.gun.energy = 40*GeV +SIM.gun.energy = 40 * GeV SIM.gun.direction = (1.0, 1.0, 1.0) SIM.enableGun = True -SIM.part.minimalKineticEnergy = 1*MeV +SIM.part.minimalKineticEnergy = 1 * MeV -SIM.action.mapActions['tpc'] = "TPCSDAction" +SIM.action.mapActions["tpc"] = "TPCSDAction" ## if there is a user provided SDAction which needs additional parameters these can be passed as a dictionary -SIM.action.mapActions['ecal'] = ( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) +SIM.action.mapActions["ecal"] = ("CaloPreShowerSDAction", {"FirstLayerNumber": 1}) ## add filter to sensitive detectors: # Either assign dict -SIM.filter.mapDetFilter = {"VXD": "edep1kev"} ## default filter +SIM.filter.mapDetFilter = {"VXD": "edep1kev"} ## default filter # or use bracket operator -SIM.filter.mapDetFilter['VXD'] = "edep1kev" ## default filter -SIM.filter.mapDetFilter['FTD'] = ["edep3kev","geantino"] ## custom filter +SIM.filter.mapDetFilter["VXD"] = "edep1kev" ## default filter +SIM.filter.mapDetFilter["FTD"] = ["edep3kev", "geantino"] ## custom filter -#create your own filter with a dict containing name and parameter -SIM.filter.filters['edep3kev'] = dict(name="EnergyDepositMinimumCut/3keV", parameter={"Cut": 3.0*keV} ) +# create your own filter with a dict containing name and parameter +SIM.filter.filters["edep3kev"] = dict( + name="EnergyDepositMinimumCut/3keV", parameter={"Cut": 3.0 * keV} +) -#chose the physicslist and range cut +# chose the physicslist and range cut SIM.physics.list = "FTFP_BERT" -SIM.physics.rangecut = 1*mm +SIM.physics.rangecut = 1 * mm ## set the particle.tbl file to add extra particles to DDsim (B-Baryons) ## use the power of python to get the file from DD4hep wherever it is import os -if os.path.exists( os.path.join( os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") ): - SIM.physics.pdgfile = os.path.join( os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") + +if os.path.exists( + os.path.join(os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl") +): + SIM.physics.pdgfile = os.path.join( + os.environ.get("DD4hepINSTALL"), "examples/DDG4/examples/particle.tbl" + ) ## Add parameters to the run header ## This will store the Parameter "MyNewParameter" in the runHeader of the slcio file diff --git a/utils/dd4hep2root.py b/utils/dd4hep2root.py index a251d8484..63bc7edba 100755 --- a/utils/dd4hep2root.py +++ b/utils/dd4hep2root.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -### Script to generate ROOT file with detector geometry from detector xml file, +### Script to generate ROOT file with detector geometry from detector xml file, ### from https://fccsw.web.cern.ch/fccsw/tutorials/static/python/dd4hep2root -### usage described in FCC software tutorial: +### usage described in FCC software tutorial: ### https://hep-fcc.github.io/fcc-tutorials/master/full-detector-simulations/Visualization/Visualization.html#detector-geometry import sys @@ -10,23 +10,26 @@ def main(): - parser = argparse.ArgumentParser(description='Convert detector') - parser.add_argument('-c', '--compact', help='Compact file location(s)', - required=True, type=str, nargs='+') - parser.add_argument('-o', '--out', help='Converted file path', - default='detector.root', type=str) + parser = argparse.ArgumentParser(description="Convert detector") + parser.add_argument( + "-c", "--compact", help="Compact file location(s)", required=True, type=str, nargs="+" + ) + parser.add_argument( + "-o", "--out", help="Converted file path", default="detector.root", type=str + ) args = parser.parse_args() - + convert(args.compact, args.out) + def convert(compact_files, out_path): - print('INFO: Converting following compact file(s):') + print("INFO: Converting following compact file(s):") for cfile in compact_files: - print(' ' + cfile) + print(" " + cfile) import ROOT - ROOT.gSystem.Load('libDDCore') + ROOT.gSystem.Load("libDDCore") description = ROOT.dd4hep.Detector.getInstance() for cfile in compact_files: description.fromXML(cfile) @@ -36,5 +39,5 @@ def convert(compact_files, out_path): ROOT.gGeoManager.Export(out_path) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/utils/material_plots.py b/utils/material_plots.py index 580746d22..f95ba5780 100644 --- a/utils/material_plots.py +++ b/utils/material_plots.py @@ -1,22 +1,54 @@ from __future__ import print_function import argparse -import sys,os +import sys, os + sys.path.append(os.path.expandvars("$FCCSW") + "/Examples/scripts") from plotstyle import FCCStyle import ROOT + def main(): - parser = argparse.ArgumentParser(description='Material Plotter') - parser.add_argument('--fname', "-f", dest='fname', type=str, help="name of file to read") - parser.add_argument('--angleMin', dest='angleMin', default=-6, type=float, help="minimum eta/theta/cosTheta") - parser.add_argument('--angleMax', dest='angleMax', default=6, type=float, help="maximum eta/theta/cosTheta") - parser.add_argument('--angleDef', dest='angleDef', default="eta", type=str, help="angle definition to use: eta, theta, cosTheta or thetaRad, default: eta") - parser.add_argument('--angleBinning', "-b", dest='angleBinning', default=0.05, type=float, help="eta/theta/cosTheta/thetaRad bin width") - parser.add_argument('--x0max', "-x", dest='x0max', default=0.0, type=float, help="Max of x0") - parser.add_argument('--removeMatsSubstrings', dest='removeMatsSubstrings', nargs='+', default=[], help="Substrings to be removed from materials strings (e.g. '66D' for reduced density materials)") - parser.add_argument('--ignoreMats', "-i", dest='ignoreMats', nargs='+', default=[], help="List of materials that should be ignored") + parser = argparse.ArgumentParser(description="Material Plotter") + parser.add_argument("--fname", "-f", dest="fname", type=str, help="name of file to read") + parser.add_argument( + "--angleMin", dest="angleMin", default=-6, type=float, help="minimum eta/theta/cosTheta" + ) + parser.add_argument( + "--angleMax", dest="angleMax", default=6, type=float, help="maximum eta/theta/cosTheta" + ) + parser.add_argument( + "--angleDef", + dest="angleDef", + default="eta", + type=str, + help="angle definition to use: eta, theta, cosTheta or thetaRad, default: eta", + ) + parser.add_argument( + "--angleBinning", + "-b", + dest="angleBinning", + default=0.05, + type=float, + help="eta/theta/cosTheta/thetaRad bin width", + ) + parser.add_argument("--x0max", "-x", dest="x0max", default=0.0, type=float, help="Max of x0") + parser.add_argument( + "--removeMatsSubstrings", + dest="removeMatsSubstrings", + nargs="+", + default=[], + help="Substrings to be removed from materials strings (e.g. '66D' for reduced density materials)", + ) + parser.add_argument( + "--ignoreMats", + "-i", + dest="ignoreMats", + nargs="+", + default=[], + help="List of materials that should be ignored", + ) args = parser.parse_args() f = ROOT.TFile.Open(args.fname, "read") @@ -34,7 +66,7 @@ def main(): # Removing substrings from materials for substring in args.removeMatsSubstrings: - material = material.replace(substring,"") + material = material.replace(substring, "") # Ignore certain materials if specified if material in args.ignoreMats: @@ -42,31 +74,58 @@ def main(): if material not in histDict.keys(): histDict[material] = { - "x0": ROOT.TH1F("", "", (int)((args.angleMax-args.angleMin) / args.angleBinning), args.angleMin, args.angleMax), - "lambda": ROOT.TH1F("", "", (int)((args.angleMax-args.angleMin) / args.angleBinning), args.angleMin, args.angleMax), - "depth": ROOT.TH1F("", "", (int)((args.angleMax-args.angleMin) / args.angleBinning), args.angleMin, args.angleMax) + "x0": ROOT.TH1F( + "", + "", + (int)((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + ), + "lambda": ROOT.TH1F( + "", + "", + (int)((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + ), + "depth": ROOT.TH1F( + "", + "", + (int)((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + ), } hs = histDict[material] - hs["x0"].SetBinContent(angleBinning+1, hs["x0"].GetBinContent(angleBinning+1) + entry.nX0.at(i)*100.0) - hs["lambda"].SetBinContent(angleBinning+1, hs["lambda"].GetBinContent(angleBinning+1) + entry.nLambda.at(i)) - hs["depth"].SetBinContent(angleBinning+1, hs["depth"].GetBinContent(angleBinning+1) + entry.matDepth.at(i)) + hs["x0"].SetBinContent( + angleBinning + 1, + hs["x0"].GetBinContent(angleBinning + 1) + entry.nX0.at(i) * 100.0, + ) + hs["lambda"].SetBinContent( + angleBinning + 1, + hs["lambda"].GetBinContent(angleBinning + 1) + entry.nLambda.at(i), + ) + hs["depth"].SetBinContent( + angleBinning + 1, + hs["depth"].GetBinContent(angleBinning + 1) + entry.matDepth.at(i), + ) axis_titles = ["Material budget x/X_{0} [%] ", "Number of #lambda", "Material depth [cm]"] # This loop does the drawing, sets the style and saves the pdf files for plot, title in zip(["x0", "lambda", "depth"], axis_titles): - if args.angleDef=="eta": - xtitle="#eta" - legend = ROOT.TLegend(.2, .6, .5, .94) - elif args.angleDef=="theta": - xtitle="#theta" - legend = ROOT.TLegend(.5, .6, .8, .94) - elif args.angleDef=="thetaRad": - xtitle="#theta [rad]" - legend = ROOT.TLegend(.5, .6, .8, .94) - elif args.angleDef=="cosTheta": - xtitle="cos(#theta)" - legend = ROOT.TLegend(.2, .6, .5, .94) + if args.angleDef == "eta": + xtitle = "#eta" + legend = ROOT.TLegend(0.2, 0.6, 0.5, 0.94) + elif args.angleDef == "theta": + xtitle = "#theta" + legend = ROOT.TLegend(0.5, 0.6, 0.8, 0.94) + elif args.angleDef == "thetaRad": + xtitle = "#theta [rad]" + legend = ROOT.TLegend(0.5, 0.6, 0.8, 0.94) + elif args.angleDef == "cosTheta": + xtitle = "cos(#theta)" + legend = ROOT.TLegend(0.2, 0.6, 0.5, 0.94) legend.SetLineColor(0) ths = ROOT.THStack() @@ -75,7 +134,16 @@ def main(): reorder = False histDict_ordered = {} if reorder: - order = ["Silicon", "CarbonFiber", "CarbonFleece", "Rohacell", "Aluminum", "GlueEcobond45", "Kapton", "Water"] + order = [ + "Silicon", + "CarbonFiber", + "CarbonFleece", + "Rohacell", + "Aluminum", + "GlueEcobond45", + "Kapton", + "Water", + ] ordered_list = sorted(histDict.items(), key=lambda pair: order.index(pair[0])) for key, value in ordered_list: @@ -87,7 +155,7 @@ def main(): # Make the plots for i, material in enumerate(histDict_ordered.keys()): linecolor = 1 - fillcolor = FCCStyle.fillcolors[i if i<7 else 0] + fillcolor = FCCStyle.fillcolors[i if i < 7 else 0] # If you want to map a material to a specific color, do that here match material: @@ -100,15 +168,15 @@ def main(): case "Rohacell": fillcolor = FCCStyle.fillcolors[4] case "Silicon": - fillcolor = FCCStyle.fillcolors[2] + fillcolor = FCCStyle.fillcolors[2] case "Aluminum": fillcolor = FCCStyle.fillcolors[1] case "Kapton": fillcolor = FCCStyle.fillcolors[3] case "GlueEcobond45": - fillcolor = FCCStyle.fillcolors[6] + fillcolor = FCCStyle.fillcolors[6] case "Water": - fillcolor = FCCStyle.fillcolors[5] + fillcolor = FCCStyle.fillcolors[5] case "PCB": fillcolor = ROOT.kGreen @@ -129,7 +197,7 @@ def main(): legend.SetTextSize(0.04) legend.Draw() - if args.x0max != 0.0 and plot=="x0": + if args.x0max != 0.0 and plot == "x0": ths.SetMaximum(args.x0max) ths.GetXaxis().SetRangeUser(args.angleMin, args.angleMax) @@ -137,6 +205,7 @@ def main(): cv.Print(plot + ".png") cv.SaveAs(plot + ".root") + if __name__ == "__main__": FCCStyle.initialize() main() diff --git a/utils/material_plots_2D.py b/utils/material_plots_2D.py index d87e549f5..d67758cf0 100644 --- a/utils/material_plots_2D.py +++ b/utils/material_plots_2D.py @@ -2,22 +2,49 @@ import argparse import math -import sys,os +import sys, os + sys.path.append(os.path.expandvars("$FCCSW") + "/Examples/scripts") from plotstyle import FCCStyle import ROOT def main(): - parser = argparse.ArgumentParser(description='Material Plotter') - parser.add_argument('--fname', "-f", dest='fname', type=str, help="name of file to read") - parser.add_argument('--angleMin', dest='angleMin', default=6, type=float, help="minimum eta/theta/cosTheta") - parser.add_argument('--angleMax', dest='angleMax', default=6, type=float, help="maximum eta/theta/cosTheta") - parser.add_argument('--angleDef', dest='angleDef', default="eta", type=str, help="angle definition to use: eta, theta or cosTheta, default: eta") - parser.add_argument('--angleBinning', "-b", dest='angleBinning', default=0.05, type=float, help="eta/theta/cosTheta bin width") - parser.add_argument('--nPhiBins', dest='nPhiBins', default=100, type=int, help="number of bins in phi") - parser.add_argument('--x0max', "-x", dest='x0max', default=0.0, type=float, help="Max of x0") - parser.add_argument('--ignoreMats', "-i", dest='ignoreMats', nargs='+', default=[], help="List of materials that should be ignored") + parser = argparse.ArgumentParser(description="Material Plotter") + parser.add_argument("--fname", "-f", dest="fname", type=str, help="name of file to read") + parser.add_argument( + "--angleMin", dest="angleMin", default=6, type=float, help="minimum eta/theta/cosTheta" + ) + parser.add_argument( + "--angleMax", dest="angleMax", default=6, type=float, help="maximum eta/theta/cosTheta" + ) + parser.add_argument( + "--angleDef", + dest="angleDef", + default="eta", + type=str, + help="angle definition to use: eta, theta or cosTheta, default: eta", + ) + parser.add_argument( + "--angleBinning", + "-b", + dest="angleBinning", + default=0.05, + type=float, + help="eta/theta/cosTheta bin width", + ) + parser.add_argument( + "--nPhiBins", dest="nPhiBins", default=100, type=int, help="number of bins in phi" + ) + parser.add_argument("--x0max", "-x", dest="x0max", default=0.0, type=float, help="Max of x0") + parser.add_argument( + "--ignoreMats", + "-i", + dest="ignoreMats", + nargs="+", + default=[], + help="List of materials that should be ignored", + ) args = parser.parse_args() ROOT.gStyle.SetNumberContours(100) @@ -28,9 +55,36 @@ def main(): ROOT.gROOT.SetBatch(1) - h_x0 = ROOT.TH2F("h_x0","h_x0", int((args.angleMax-args.angleMin)/args.angleBinning),args.angleMin,args.angleMax,args.nPhiBins,-math.pi,math.pi) - h_lambda = ROOT.TH2F("h_lambda","h_lambda", int((args.angleMax-args.angleMin)/args.angleBinning),args.angleMin,args.angleMax,args.nPhiBins,-math.pi,math.pi) - h_depth = ROOT.TH2F("h_depth","h_depth", int((args.angleMax-args.angleMin)/args.angleBinning),args.angleMin,args.angleMax,args.nPhiBins,-math.pi,math.pi) + h_x0 = ROOT.TH2F( + "h_x0", + "h_x0", + int((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + args.nPhiBins, + -math.pi, + math.pi, + ) + h_lambda = ROOT.TH2F( + "h_lambda", + "h_lambda", + int((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + args.nPhiBins, + -math.pi, + math.pi, + ) + h_depth = ROOT.TH2F( + "h_depth", + "h_depth", + int((args.angleMax - args.angleMin) / args.angleBinning), + args.angleMin, + args.angleMax, + args.nPhiBins, + -math.pi, + math.pi, + ) for angleBinning, entry in enumerate(tree): nMat = entry.nMaterials @@ -41,35 +95,35 @@ def main(): if entry.material.at(i) in args.ignoreMats: continue - entry_x0 += entry.nX0.at(i)*100.0 - entry_lambda += entry.nLambda.at(i) - entry_depth += entry.matDepth.at(i) + entry_x0 += entry.nX0.at(i) * 100.0 + entry_lambda += entry.nLambda.at(i) + entry_depth += entry.matDepth.at(i) - h_x0.Fill(tree.angle,tree.phi,entry_x0) - h_lambda.Fill(tree.angle,tree.phi,entry_lambda) - h_depth.Fill(tree.angle,tree.phi,entry_depth) + h_x0.Fill(tree.angle, tree.phi, entry_x0) + h_lambda.Fill(tree.angle, tree.phi, entry_lambda) + h_depth.Fill(tree.angle, tree.phi, entry_depth) - # go through the + # go through the plots = ["x0", "lambda", "depth"] histograms = [h_x0, h_lambda, h_depth] axis_titles = ["Material budget x/X_{0} [%]", "Number of #lambda", "Material depth [cm]"] for i in range(len(plots)): - cv = ROOT.TCanvas("","",800,600) + cv = ROOT.TCanvas("", "", 800, 600) cv.SetRightMargin(0.18) histograms[i].Draw("COLZ") - if args.angleDef=="eta": - title="#eta" - elif args.angleDef=="theta": - title="#theta [#circ]" - elif args.angleDef=="cosTheta": - title="cos(#theta)" + if args.angleDef == "eta": + title = "#eta" + elif args.angleDef == "theta": + title = "#theta [#circ]" + elif args.angleDef == "cosTheta": + title = "cos(#theta)" histograms[i].GetXaxis().SetTitle(title) histograms[i].GetYaxis().SetTitle("#phi") histograms[i].GetZaxis().SetTitle(axis_titles[i]) - if args.x0max != 0.0 and plots[i]=="x0": + if args.x0max != 0.0 and plots[i] == "x0": histograms[i].SetMaximum(args.x0max) histograms[i].GetXaxis().SetRangeUser(args.angleMin, args.angleMax) @@ -79,6 +133,7 @@ def main(): cv.Print(plots[i] + ".png") cv.SaveAs(plots[i] + ".root") + if __name__ == "__main__": FCCStyle.initialize() main() diff --git a/utils/material_scan.py b/utils/material_scan.py index 25ea63563..cf33f6e92 100644 --- a/utils/material_scan.py +++ b/utils/material_scan.py @@ -2,22 +2,23 @@ from Gaudi.Configuration import * from Configurables import ApplicationMgr -ApplicationMgr().EvtSel = 'None' + +ApplicationMgr().EvtSel = "None" ApplicationMgr().EvtMax = 1 ApplicationMgr().OutputLevel = INFO # DD4hep geometry service from Configurables import GeoSvc + ## parse the given xml file geoservice = GeoSvc("GeoSvc") -geoservice.detectors = [ - 'IDEA_o1_v02.xml' - ] -geoservice.OutputLevel = INFO +geoservice.detectors = ["IDEA_o1_v02.xml"] +geoservice.OutputLevel = INFO ApplicationMgr().ExtSvc += [geoservice] # Using material scan from k4SimGeant4: https://github.com/HEP-FCC/k4SimGeant4/tree/main/Detector/DetComponents/src from Configurables import MaterialScan_genericAngle + # Material scan is done from the interaction point to the end of world volume. # In order to use other end boundary, please provide the name of a thin, e.g. cylindrical volume. # For instance adding envelopeName="BoundaryPostCalorimetry" will perform the scan only till the end of calorimetry. @@ -28,7 +29,5 @@ materialservice.angleMin = -3.0 materialservice.angleMax = 3.0 materialservice.nPhiTrials = 100 -materialservice.angleDef = "eta" # eta or cosTheta or theta or thetaRad +materialservice.angleDef = "eta" # eta or cosTheta or theta or thetaRad ApplicationMgr().ExtSvc += [materialservice] - - diff --git a/utils/material_scan_2D.py b/utils/material_scan_2D.py index 041a786ee..ab6ee21eb 100644 --- a/utils/material_scan_2D.py +++ b/utils/material_scan_2D.py @@ -2,22 +2,23 @@ from Gaudi.Configuration import * from Configurables import ApplicationMgr -ApplicationMgr().EvtSel = 'None' + +ApplicationMgr().EvtSel = "None" ApplicationMgr().EvtMax = 1 ApplicationMgr().OutputLevel = INFO # DD4hep geometry service from Configurables import GeoSvc + ## parse the given xml file geoservice = GeoSvc("GeoSvc") -geoservice.detectors = [ - 'IDEA_o1_v02.xml' - ] -geoservice.OutputLevel = INFO +geoservice.detectors = ["IDEA_o1_v02.xml"] +geoservice.OutputLevel = INFO ApplicationMgr().ExtSvc += [geoservice] # Using material scan from k4SimGeant4: https://github.com/HEP-FCC/k4SimGeant4/tree/main/Detector/DetComponents/src from Configurables import MaterialScan_2D_genericAngle + # Material scan is done from the interaction point to the end of world volume. # In order to use other end boundary, please provide the name of a thin, e.g. cylindrical volume. # For instance adding envelopeName="BoundaryPostCalorimetry" will perform the scan only till the end of calorimetry. @@ -25,12 +26,10 @@ materialservice = MaterialScan_2D_genericAngle("GeoDump") materialservice.filename = "out_material_scan.root" -materialservice.angleDef = 'eta' # eta, theta, cosTheta or thetaRad +materialservice.angleDef = "eta" # eta, theta, cosTheta or thetaRad materialservice.angleBinning = 0.05 materialservice.angleMax = 3.0 materialservice.angleMin = -3.0 -materialservice.nPhi = 100 # number of bins in phi +materialservice.nPhi = 100 # number of bins in phi ApplicationMgr().ExtSvc += [materialservice] - - From 766f11ea51aa45a6fc5d1aa755b025720366e1cb Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Tue, 24 Sep 2024 18:16:17 +0200 Subject: [PATCH 051/133] Generalizing the muonSystem builder variable names --- .../IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml | 3 + .../compact/IDEA_o1_v03/Preshower_o1_v01.xml | 69 +++++++++++++++++++ .../muonSystem/muonSystemMuRWELL_o1_v01.cpp | 22 +++--- 3 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml index 213071c79..adafde035 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml @@ -60,6 +60,9 @@ + + + diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml new file mode 100644 index 000000000..0ed00127d --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -0,0 +1,69 @@ + + + + + It depends on the factory: muonSystemMuRWELL_o1_v01 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:5,type:2,layer:4,chamber:15,slice:1,y:-10,z:-10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp index 2f4321433..2a9fc70c8 100644 --- a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp +++ b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp @@ -135,7 +135,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::PolyhedraRegular BarrelEnvWithoutLastLayer(numSides, radius, barrelRMax, barrelLength); dd4hep::PolyhedraRegular BarrelLastLayerEnv(numSides, (barrelRMax - 2 * detectorVolumeThickness), barrelRMax, barreltotalLength); - std::string barrelName = dd4hep::xml::_toString(0, "MS-Barrel%d"); + std::string barrelName = name + "-Barrel" + std::to_string(0); dd4hep::Position barrelUnionPos(0.0 , 0.0, 0.0); dd4hep::Rotation3D barrelUnionRot(dd4hep::RotationY(0.0 * dd4hep::degree)); @@ -147,7 +147,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Position barrelTrans(0., 0., 0.); dd4hep::PlacedVolume barrelPhys = detectorVolume.placeVolume(BarrelVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), barrelTrans)); barrelPhys.addPhysVolID("type", 0); - dd4hep::DetElement BarrelDE(detElement, "MSBarrelDE" , 0); + dd4hep::DetElement BarrelDE(detElement, name +"-BarrelDE" , 0); BarrelDE.setPlacement(barrelPhys); BarrelVolume.setVisAttributes(lcdd.visAttributes("no_vis")); @@ -166,7 +166,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, } dd4hep::PolyhedraRegular BarrelDetectorLayer(numSides, barrelLayerRMin, barrelLayerRMax, barrelLayerLength); - std::string barrelDetectorName = dd4hep::xml::_toString(numBarrelLayer +1, "MS-BarrelDetectorLayer%d"); + std::string barrelDetectorName = name + "-BarrelDetectorLayer" + std::to_string(numBarrelLayer + 1); dd4hep::Volume BarrelDetectorLayerVolume(barrelDetectorName, BarrelDetectorLayer, mat); // sideLength and sideLength2 are the lengths of the parallel sides of the trapezoid. @@ -524,7 +524,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Position detectorLayerTrans(0., 0., 0.); dd4hep::PlacedVolume detectorLayerPhys = BarrelVolume.placeVolume(BarrelDetectorLayerVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), detectorLayerTrans)); detectorLayerPhys.addPhysVolID("layer", numBarrelLayer+1); - dd4hep::DetElement BarrelDetectorLayerDE(BarrelDE, "MSBarrel_DetectorLayerDE_" + std::to_string(numBarrelLayer+1), numBarrelLayer+1); + dd4hep::DetElement BarrelDetectorLayerDE(BarrelDE, name + "-Barrel_DetectorLayerDE_" + std::to_string(numBarrelLayer+1), numBarrelLayer+1); BarrelDetectorLayerDE.setPlacement(detectorLayerPhys); BarrelDetectorLayerVolume.setVisAttributes(lcdd.visAttributes("no_vis")); @@ -539,7 +539,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double barrelRadiatorLayerRMid = (barrelRadiatorLayerRMin + barrelRadiatorLayerRMax)/2.0; dd4hep::PolyhedraRegular BarrelRadiatorLayer(numSides, barrelRadiatorLayerRMin, barrelRadiatorLayerRMax, barrelLength); - std::string barrelRadiatorEnvName = dd4hep::xml::_toString(numBarrelRadiatorLayer +1, "MS-BarrelRadiatorLayer%d"); + std::string barrelRadiatorEnvName = name + "-BarrelRadiatorLayer" + std::to_string(numBarrelRadiatorLayer + 1); dd4hep::Volume BarrelRadiatorLayerVolume(barrelRadiatorEnvName , BarrelRadiatorLayer, mat); double barrelRadiatorSideLength = 2 * (barrelRadiatorLayerRMid - barrelRadiatorThickness/2.0)* std::tan(shapeAngle_radians); @@ -548,7 +548,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int side = 0; side < numSides; ++side) { int sideID = (numBarrelRadiatorLayer + 1) * 100 + (side +1); // to differentiated with the same side in different layers. dd4hep::Trapezoid barrelRadiatorEnvelope(barrelLength/2.0, barrelLength/2.0, barrelRadiatorSideLength/2.0, barrelRadiatorSideLength2/2.0, barrelRadiatorThickness/2.0); - std::string barrelRadiatorEnvelopeName = dd4hep::xml::_toString(sideID, "MSBarrelRadiatorSide%d"); + std::string barrelRadiatorEnvelopeName = name + "-BarrelRadiatorSide" + std::to_string(sideID); dd4hep::Volume barrelRadiatorEnvVol(barrelRadiatorEnvelopeName, barrelRadiatorEnvelope, mat); double angle_degrees = shapeAngle * side; // Calculate the angle for each side @@ -589,7 +589,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Position radiatorLayerTrans(0., 0., 0.); dd4hep::PlacedVolume radiatorLayerPhys = BarrelVolume.placeVolume(BarrelRadiatorLayerVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), radiatorLayerTrans)); - dd4hep::DetElement BarrelRadiatorLayerDE(BarrelDE, "MSBarrel_RadiatorLayerDE_" + std::to_string(numBarrelRadiatorLayer+1), numBarrelRadiatorLayer+1); + dd4hep::DetElement BarrelRadiatorLayerDE(BarrelDE, name + "-Barrel_RadiatorLayerDE_" + std::to_string(numBarrelRadiatorLayer+1), numBarrelRadiatorLayer+1); BarrelRadiatorLayerDE.setPlacement(radiatorLayerPhys); BarrelRadiatorLayerVolume.setVisAttributes(lcdd.visAttributes("no_vis")); @@ -609,12 +609,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, if (endcapType == 0) { continue; // Skip the iteration when endcapType is 0 } - EndcapName = dd4hep::xml::_toString(endcapType, "MS-Endcap%d"); + EndcapName = name + "-Endcap" + std::to_string(endcapType); endcapVolume = dd4hep::Volume(EndcapName, EndcapEnv, mat); endcapTrans = dd4hep::Position(0., 0., endcapType * endcapOffset); endcapPhys = detectorVolume.placeVolume(endcapVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), endcapTrans)); endcapPhys.addPhysVolID("type", endcapType); - EndcapDE = dd4hep::DetElement(detElement, "MSEndcapDE_" + std::to_string(endcapType) , endcapType); + EndcapDE = dd4hep::DetElement(detElement, name + "EndcapDE_" + std::to_string(endcapType) , endcapType); EndcapDE.setPlacement(endcapPhys); endcapVolume.setVisAttributes(lcdd.visAttributes("no_vis")); @@ -629,7 +629,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::PolyhedraRegular endcapDetectorEnvelope(numSides, endcapDetectorLayerInnerRadius, endcapDetectorLayerOuterRadius, 2 * detectorVolumeThickness); endcapLayerZOffset = - EndcaptotalLength/2.0 + detectorVolumeThickness + numEndcapLayer * (2 * detectorVolumeThickness) + numEndcapLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer - endcapDetectorEnvelopeName = dd4hep::xml::_toString(numEndcapLayer+1, "MS-EndcapDetectorLayer%d"); + endcapDetectorEnvelopeName = name + "-EndcapDetectorLayer" + std::to_string(numEndcapLayer + 1); endcapDetectorEnvZPos = endcapLayerZOffset; @@ -886,7 +886,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double endcapRadiatorLayerZOffset = - EndcaptotalLength/2.0 + (endcapRadiatorThickness/2.0) + (numEndcapRadiatorLayer +1) * (2 * detectorVolumeThickness) + numEndcapRadiatorLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer dd4hep::PolyhedraRegular endcapRadiatorEnvelope(numSides, endcapRadiatorLayerInnerRadius, endcapRadiatorLayerOuterRadius, endcapRadiatorThickness); - std::string endcapRadiatorEnvelopeName = dd4hep::xml::_toString(numEndcapRadiatorLayer+1, "MS-EndcapRadiatorLayer%d"); + std::string endcapRadiatorEnvelopeName = name + "-EndcapRadiatorLayer" + std::to_string(numEndcapRadiatorLayer + 1); dd4hep::Volume endcapRadiatorEnvVol(endcapRadiatorEnvelopeName, endcapRadiatorEnvelope, mat); double endcapRadiatorEnvXPos = 0.0 ; From 6272aea2761e0f497cf1ae44fea06dada05af833 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Wed, 25 Sep 2024 15:42:15 +0200 Subject: [PATCH 052/133] Adopting the muonSystem buider to pre-shower case --- .../muonSystem/muonSystemMuRWELL_o1_v01.cpp | 113 ++++++++++++++---- 1 file changed, 91 insertions(+), 22 deletions(-) diff --git a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp index 2a9fc70c8..2014fb3f0 100644 --- a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp +++ b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp @@ -79,10 +79,17 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double shapeAngle_radians = M_PI / numSides; // Isn't it a half angle!! double angle_clearance = 0.0; // 0.02 works good but needs the detector volume thick to be more than 60 mm. // it's less than 1 degree, we use the clearnce to avoid overlapping + double sideLengthEstimate = 2 * (radius) * std::tan(shapeAngle_radians); + double chamberAngle_rad = std::atan(dimensions.x()/dimensions.y()); double rectangleThickness = (2 * dimensions.y()) * std::sin(chamberAngle_rad) + (2 * dimensions.x()) * std::cos(chamberAngle_rad) + 1.2 * clearance; - double rectangleAngle_rad = std::atan(rectangleThickness/dimensions.z()); - double detectorVolumeThickness = (2 * dimensions.z()) * std::sin(rectangleAngle_rad) + rectangleThickness * std::cos(rectangleAngle_rad); + double rectangleAngle_rad = std::atan(rectangleThickness/dimensions.z()); + double detectorVolumeThickness; + if (sideLengthEstimate <= (2 * dimensions.y()) && numBarrelDetectorLayers == 1){ // putting this condtition to minimize the volume thickness in case of there is only one chamber per side(espicially for circular shape detector) + detectorVolumeThickness = rectangleThickness; + } else { + detectorVolumeThickness = (2 * dimensions.z()) * std::sin(rectangleAngle_rad) + rectangleThickness * std::cos(rectangleAngle_rad); + } double endcapDetectorSideLength = (2 * (endcapDetectorLayerInnerRadius) * std::tan(shapeAngle_radians)) + 42.0; // shouldn't be hardcoded, but // the offset of 42.0 cm to avoid the overalp with the rectangles @@ -178,6 +185,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double sideEnvZ = (barrelLayerLength / 2.0); double remainderZ = std::fmod((barrelLayerLength - 2 * clearance), (2 * dimensions.z() - overlapZ)) / (2 * dimensions.z()) - (2 * clearance / dimensions.z()); + // ------- Dividing every layer into # of sides = # of polyhedron sides ----------- for (int side = 0; side < numSides; ++side) { int sideID = (numBarrelLayer + 1) * 100 + (side +1); // to differentiated with the same side in different layers. @@ -230,7 +238,6 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int rectangle = 0; rectangle < (numRectangles + 1); ++rectangle) { - double rectangleEnvX = detectorVolumeThickness/4.5; // dividing by 4.5 gets the best thickness for the recatngle to avoid any overlap ~ in our case the uRWELL the best rectangle thickness is 26.667 mm which is 120/4.5. double rectangleEnvY; if (side % 2 == 0) { rectangleEnvY = sideLength / 2.0; // + clearance; @@ -239,6 +246,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, } double rectangleEnvZ = dimensions.z() + clearance/2.0; double rectangleRemainderEnvZ = (remainderZ * dimensions.z()) + clearance/4.0; // this is the last rectangle in the side, and it is smaller than the usual one, with larger rotation angle. so it need to be shorter in length to avoid overlap. + double rectangleEnvX; + if (rectangleEnvY <= dimensions.y()){ + rectangleEnvX = dimensions.x(); // in case if there is only one chamber inside the rectangle. + } else { + rectangleEnvX = detectorVolumeThickness/4.5; // dividing by 4.5 gets the best thickness for the recatngle to avoid any overlap ~ in our case the uRWELL the best rectangle thickness is 26.667 mm which is 120/4.5. + } dd4hep::Box rectangleEnvelope(rectangleEnvX, rectangleEnvY, rectangleEnvZ); std::string rectangleEnvelopeName = dd4hep::xml::_toString(rectangle, "rectangleEnvelope%d"); @@ -285,7 +298,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, // ------------------------ start to build the chamber envelopes ------------------- - int numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + int numChambersInRectangle; + if (rectangleEnvY <= dimensions.y()){ + numChambersInRectangle = 0; // number of the chambers in each rectangle + }else { + numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + } for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { @@ -295,8 +313,13 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Box envelope(dimensions.x(), dimensions.y(), remainderZ * dimensions.z()); dd4hep::Volume envVolume(BarrelChamberName, envelope, lcdd.material(dimensions.materialStr())); - - double rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + + double rectangleRemainderY; + if (numChambersInRectangle == 0){ + rectangleRemainderY = std::abs(std::fmod((2 * rectangleEnvY - clearance), (2 * dimensions.y() - clearance))) / (2 * dimensions.y()); + }else { + rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + } dd4hep::Box rectangleRemainderYEnvelope(dimensions.x(), rectangleRemainderY * dimensions.y(), remainderZ * dimensions.z()); dd4hep::Volume rectangleRemainderYEnvVolume(BarrelChamberName + "rectangleRemainderY", rectangleRemainderYEnvelope, lcdd.material(dimensions.materialStr())); @@ -304,10 +327,17 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double envYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + dimensions.y() + clearance/20.0 ; // found that the positioning of the chambers inside the rectangle had an overlap with the mother volume ~ 45 um. double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20.0; - double zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); - dd4hep::RotationZ chamberRotation(zRotation); - - double rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + double zRotation; + double rectangleRemainderZRotation; + if (numChambersInRectangle == 0){ + zRotation = 0.0; + rectangleRemainderZRotation = 0.0; + } else { + zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); + rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + } + + dd4hep::RotationZ chamberRotation(zRotation); dd4hep::RotationZ rectangleRemainderRotationZ(rectangleRemainderZRotation); auto Slices = xmlElement.children(_Unicode(slice)); @@ -409,7 +439,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, // ------------------------ start to build the chamber envelopes ------------------- - int numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + int numChambersInRectangle; + if (rectangleEnvY <= dimensions.y()){ + numChambersInRectangle = 0; // number of the chambers in each rectangle, in that case it will create just 1 chamber. + }else { + numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + } for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { @@ -420,7 +455,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Box envelope(dimensions.x(), dimensions.y(), dimensions.z()); dd4hep::Volume envVolume(BarrelChamberName, envelope, lcdd.material(dimensions.materialStr())); - double rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + double rectangleRemainderY; + if (numChambersInRectangle == 0){ + rectangleRemainderY = std::abs(std::fmod((2 * rectangleEnvY - clearance), (2 * dimensions.y() - clearance))) / (2 * dimensions.y()); + }else { + rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + } dd4hep::Box rectangleRemainderYEnvelope(dimensions.x(), rectangleRemainderY * dimensions.y(), dimensions.z()); dd4hep::Volume rectangleRemainderYEnvVolume(BarrelChamberName + "rectangleRemainderY", rectangleRemainderYEnvelope, lcdd.material(dimensions.materialStr())); @@ -428,10 +468,17 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double envYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + dimensions.y() + clearance/20.0 ; // found that the positioning of the chambers inside the rectangle had an overlap with the mother volume ~ 45 um. double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20.0; - double zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); - dd4hep::RotationZ chamberRotation(zRotation); + double zRotation; + double rectangleRemainderZRotation; + if (numChambersInRectangle == 0){ + zRotation = 0.0; + rectangleRemainderZRotation = 0.0; + } else { + zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); + rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + } - double rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + dd4hep::RotationZ chamberRotation(zRotation); dd4hep::RotationZ rectangleRemainderRotationZ(rectangleRemainderZRotation); auto Slices = xmlElement.children(_Unicode(slice)); @@ -712,7 +759,6 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int rectangle = 0; rectangle < (numRectangles + 1); ++rectangle) { - double rectangleEnvX = endcapDetectorEnvZ/4.5; // dividing by 4.5 gets the best thickness for the recatngle to avoid any overlap ~ in our case the uRWELL the thickness is 26.667 mm which is 120/4.5. double rectangleEnvY = (endcapDetectorLayerOuterRadius - rectangle * (2 * dimensions.y() - overlapY)) * std::tan(shapeAngle_radians) ; // without multiplying by 2 .. because it is the half length // it should be dimensions.x() instead of z, but in the endcap its perpendicular to usual dimension set double rectangleEnvZ; if (rectangle == numRectangles) { @@ -720,6 +766,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, } else { rectangleEnvZ = dimensions.z() + clearance/2.0; } + double rectangleEnvX; + if (rectangleEnvY <= dimensions.y()){ + rectangleEnvX = dimensions.x(); // in case if there is only one chamber inside the rectangle. + } else { + rectangleEnvX = detectorVolumeThickness/4.5; // dividing by 4.5 gets the best thickness for the recatngle to avoid any overlap ~ in our case the uRWELL the best rectangle thickness is 26.667 mm which is 120/4.5. + } dd4hep::Box rectangleEnvelope(rectangleEnvX, rectangleEnvY, rectangleEnvZ); std::string rectangleEnvelopeName; @@ -750,7 +802,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, // ------------------------ start to build the chamber envelopes ------------------- - int numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + int numChambersInRectangle; + if (rectangleEnvY <= dimensions.y()){ + numChambersInRectangle = 0; // number of the chambers in each rectangle + }else { + numChambersInRectangle = 2 * rectangleEnvY / (2 * dimensions.y() - overlapY); // number of the chambers in each rectangle + } for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { @@ -767,7 +824,12 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, dd4hep::Volume envVolume(EndcapChamberName, envelope, lcdd.material(dimensions.materialStr())); - double rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + double rectangleRemainderY; + if (numChambersInRectangle == 0){ + rectangleRemainderY = std::abs(std::fmod((2 * rectangleEnvY - clearance), (2 * dimensions.y() - clearance))) / (2 * dimensions.y()); + }else { + rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + } dd4hep::Box rectangleRemainderYEnvelope; if (rectangle == numRectangles) { @@ -780,11 +842,18 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double envYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + dimensions.y() + 0.005 ; // found that the positioning of the chambers inside the rectangle had an overlap with the mother volume ~ 45 um. double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + 0.005; - - double zRotation = std::atan(dimensions.x() / (dimensions.z() - (2 * overlapZ))); - dd4hep::RotationZ chamberRotation(zRotation); - double rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.z() - (2 * overlapZ))); // Y and Z are reversed in local remainder + double zRotation; + double rectangleRemainderZRotation; + if (numChambersInRectangle == 0){ + zRotation = 0.0; + rectangleRemainderZRotation = 0.0; + } else { + zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); + rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + } + + dd4hep::RotationZ chamberRotation(zRotation); dd4hep::RotationZ rectangleRemainderRotationZ(rectangleRemainderZRotation); auto Slices = xmlElement.children(_Unicode(slice)); From a53d06b8c6dbf56c4dabe69f68e6961b7557994f Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Wed, 25 Sep 2024 15:47:09 +0200 Subject: [PATCH 053/133] Updating IDEA Pre-shower compact file --- FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml index 0ed00127d..0efaaa043 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -3,7 +3,7 @@ @@ -66,4 +66,4 @@ - \ No newline at end of file + From d163003580f58ecb3fef5cf09933a7dae2b0e8f0 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Thu, 26 Sep 2024 13:37:52 +0200 Subject: [PATCH 054/133] Fixing preshower compact file --- FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml index 0efaaa043..633a86142 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -3,7 +3,7 @@ From 35ea89029a2d403ff793f8dafdf8ab4df21ff615 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Fri, 27 Sep 2024 18:52:47 +0200 Subject: [PATCH 055/133] Removing hardcoded clearance values --- detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp index 2014fb3f0..55f734fa6 100644 --- a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp +++ b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp @@ -86,14 +86,14 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double rectangleAngle_rad = std::atan(rectangleThickness/dimensions.z()); double detectorVolumeThickness; if (sideLengthEstimate <= (2 * dimensions.y()) && numBarrelDetectorLayers == 1){ // putting this condtition to minimize the volume thickness in case of there is only one chamber per side(espicially for circular shape detector) - detectorVolumeThickness = rectangleThickness; + detectorVolumeThickness = rectangleThickness + 2 * clearance; } else { detectorVolumeThickness = (2 * dimensions.z()) * std::sin(rectangleAngle_rad) + rectangleThickness * std::cos(rectangleAngle_rad); } - double endcapDetectorSideLength = (2 * (endcapDetectorLayerInnerRadius) * std::tan(shapeAngle_radians)) + 42.0; // shouldn't be hardcoded, but // the offset of 42.0 cm to avoid the overalp with the rectangles + double endcapDetectorSideLength = (2 * (endcapDetectorLayerInnerRadius + 2 * dimensions.y()) * std::tan(shapeAngle_radians)) + 2 * clearance; + double endcapDetectorSideTrapLength = (2 * (endcapDetectorLayerOuterRadius) * std::tan(shapeAngle_radians)) + 2 * clearance; - double endcapDetectorSideTrapLength = (2 * (endcapDetectorLayerOuterRadius - 2 * dimensions.z()) * std::tan(shapeAngle_radians)) + 42.0; // the offset of 42.0 cm to avoid the overalp with the rectangles double endcapDetectorSideTrapYLength = endcapDetectorLayerOuterRadius - 2 * dimensions.z() - endcapDetectorLayerInnerRadius; double endcapDetectorSideBoxLength = 2 * (endcapDetectorLayerOuterRadius) * std::tan(shapeAngle_radians); double endcapDetectorSideBoxYLength = 2 * dimensions.z(); From 6fed79e2035dbb4e468345a408a5f44fab1fdf03 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Mon, 30 Sep 2024 03:47:55 +0200 Subject: [PATCH 056/133] Solving pre-shower overlap problems --- .../DectDimensions_IDEA_o1_v03.xml | 16 +++-- .../compact/IDEA_o1_v03/Preshower_o1_v01.xml | 14 ++-- .../muonSystem/muonSystemMuRWELL_o1_v01.cpp | 66 +++++++++++-------- 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml index 3a6e0fd32..31878b65e 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml @@ -56,6 +56,7 @@ + @@ -205,6 +206,16 @@ + + + + + + + + + + @@ -220,9 +231,7 @@ - - @@ -230,10 +239,7 @@ - - - diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml index 633a86142..9505f04c8 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -3,7 +3,7 @@ @@ -29,8 +29,6 @@ - - @@ -42,14 +40,14 @@ - + - - - + + + @@ -66,4 +64,4 @@ - + \ No newline at end of file diff --git a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp index 55f734fa6..abf64a9c9 100644 --- a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp +++ b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp @@ -85,10 +85,13 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double rectangleThickness = (2 * dimensions.y()) * std::sin(chamberAngle_rad) + (2 * dimensions.x()) * std::cos(chamberAngle_rad) + 1.2 * clearance; double rectangleAngle_rad = std::atan(rectangleThickness/dimensions.z()); double detectorVolumeThickness; + double endcapDetectorEnvZ; // endcap detetcor layer thickness if (sideLengthEstimate <= (2 * dimensions.y()) && numBarrelDetectorLayers == 1){ // putting this condtition to minimize the volume thickness in case of there is only one chamber per side(espicially for circular shape detector) - detectorVolumeThickness = rectangleThickness + 2 * clearance; + detectorVolumeThickness = rectangleThickness * 1.33; // multiplying by 1.33 fit the best thickness avoiding overlaps with smaller volumes insides (rectangles). + endcapDetectorEnvZ = 2 * detectorVolumeThickness; } else { detectorVolumeThickness = (2 * dimensions.z()) * std::sin(rectangleAngle_rad) + rectangleThickness * std::cos(rectangleAngle_rad); + endcapDetectorEnvZ = detectorVolumeThickness; } double endcapDetectorSideLength = (2 * (endcapDetectorLayerInnerRadius + 2 * dimensions.y()) * std::tan(shapeAngle_radians)) + 2 * clearance; @@ -107,11 +110,9 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double endcapRemainderZ = std::fmod((endcapDetectorYLength - 2 * clearance), (2 * dimensions.z() - overlapZ)) / (2 * dimensions.z()) - (2 * clearance / dimensions.z()); - double endcapDetectorEnvZ = detectorVolumeThickness; // layer thickness - double barrelRMax = radius + numBarrelDetectorLayers * (2 * detectorVolumeThickness) + numBarrelRadiators * barrelRadiatorThickness; double barreltotalLength = barrelLength + (numEndcapDetectorLayers * 2) * (2 * detectorVolumeThickness) + (numEndcapRadiators * 2) * endcapRadiatorThickness; // This condition to make the last barrel layer encloses all the endcap layers inside it. - double EndcaptotalLength = numEndcapDetectorLayers * (2 * detectorVolumeThickness) + numEndcapRadiators * endcapRadiatorThickness; + double EndcaptotalLength = numEndcapDetectorLayers * (2 * endcapDetectorEnvZ) + numEndcapRadiators * endcapRadiatorThickness; double endcapOffset = endcapZOffset + EndcaptotalLength/2.0; int barrelIdCounter = 1; @@ -673,9 +674,9 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, std::string endcapDetectorEnvelopeName; double endcapDetectorEnvZPos; - dd4hep::PolyhedraRegular endcapDetectorEnvelope(numSides, endcapDetectorLayerInnerRadius, endcapDetectorLayerOuterRadius, 2 * detectorVolumeThickness); + dd4hep::PolyhedraRegular endcapDetectorEnvelope(numSides, endcapDetectorLayerInnerRadius, endcapDetectorLayerOuterRadius, 2 * endcapDetectorEnvZ); - endcapLayerZOffset = - EndcaptotalLength/2.0 + detectorVolumeThickness + numEndcapLayer * (2 * detectorVolumeThickness) + numEndcapLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer + endcapLayerZOffset = - EndcaptotalLength/2.0 + endcapDetectorEnvZ + numEndcapLayer * (2 * endcapDetectorEnvZ) + numEndcapLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer endcapDetectorEnvelopeName = name + "-EndcapDetectorLayer" + std::to_string(numEndcapLayer + 1); endcapDetectorEnvZPos = endcapLayerZOffset; @@ -698,8 +699,8 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int side = 0; side < numSides; ++side) { int sideID = (numEndcapLayer + 1) * 100 + (side +1); // to differentiated with the same side in different layers. - dd4hep::Trapezoid endcapDetectorSideTrap(endcapDetectorEnvZ/2.0, endcapDetectorEnvZ/2.0, endcapDetectorSideLength/2.0, endcapDetectorSideTrapLength/2.0, endcapDetectorSideTrapYLength/2.0); - dd4hep::Box endcapDetectorSideBox(endcapDetectorEnvZ/2.0, endcapDetectorSideBoxLength/2.0, endcapDetectorSideBoxYLength/2.0); + dd4hep::Trapezoid endcapDetectorSideTrap(detectorVolumeThickness/2.0, detectorVolumeThickness/2.0, endcapDetectorSideLength/2.0, endcapDetectorSideTrapLength/2.0, endcapDetectorSideTrapYLength/2.0); + dd4hep::Box endcapDetectorSideBox(detectorVolumeThickness/2.0, endcapDetectorSideBoxLength/2.0, endcapDetectorSideBoxYLength/2.0); double boxOffsetZ = endcapDetectorYLength/2.0; @@ -727,31 +728,44 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, double endcapDetectorSideEnvXPos = endcapDetectorXOffset ; double endcapDetectorSideEnvYPos = endcapDetectorYOffset ; - double endcapDetectorSideEnvZPos = - endcapDetectorEnvZ/2.0 ; - double endcapDetectorSideEnvZPos2 = endcapDetectorEnvZ/2.0; - - // --------- here I start to divide the two z-positions // by odd and even numbers + double endcapDetectorSideEnvZPos; + double endcapDetectorSideEnvZPos2; dd4hep::Position endcapDetectorSideEnvTrans; dd4hep::PlacedVolume endcapDetectorSideEnvPhys; dd4hep::DetElement endcapDetectorSideEnvDE; - if (side % 2 == 0) { + if (sideLengthEstimate <= (2 * dimensions.y())){ // in case of small side's length, put the sides in 4 differnet positions, to avoid overlaps between different sides, and the probability increases for small sides + endcapDetectorSideEnvZPos = -endcapDetectorEnvZ/4.0; + endcapDetectorSideEnvZPos2 = -endcapDetectorEnvZ * 3.0/4.0; + double endcapDetectorSideEnvZPos3 = endcapDetectorEnvZ/4.0; + double endcapDetectorSideEnvZPos4 = endcapDetectorEnvZ * 3.0/4.0; + + if (side % 4 == 0) { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos); + } else if (side % 4 == 1) { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos2); + } else if (side % 4 == 2) { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos3); + } else { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos4); + } - endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos); - endcapDetectorSideEnvPhys = endcapDetectorEnvVol.placeVolume(endcapDetectorSideEnvVol, dd4hep::Transform3D(endcapDetectorRotation * dd4hep::RotationY(90.0 * dd4hep::degree) , endcapDetectorSideEnvTrans)); - endcapDetectorSideEnvDE = dd4hep::DetElement(endcapDetectorEnvelopeDE, endcapDetectorSideEnvName + "DE", sideID); - endcapDetectorSideEnvDE.setPlacement(endcapDetectorSideEnvPhys); - endcapDetectorSideEnvVol.setVisAttributes(lcdd, xmlDet.visStr()); + } else { // else, put the sides in 2 differnet positions. + endcapDetectorSideEnvZPos = -endcapDetectorEnvZ/2.0; + endcapDetectorSideEnvZPos2 = endcapDetectorEnvZ/2.0; - } else { + if (side % 2 == 0) { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos); + } else { + endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos2); + } + } - endcapDetectorSideEnvTrans = dd4hep::Position(endcapDetectorSideEnvXPos, endcapDetectorSideEnvYPos, endcapDetectorSideEnvZPos2); - endcapDetectorSideEnvPhys = endcapDetectorEnvVol.placeVolume(endcapDetectorSideEnvVol, dd4hep::Transform3D(endcapDetectorRotation * dd4hep::RotationY(90.0 * dd4hep::degree) , endcapDetectorSideEnvTrans)); - endcapDetectorSideEnvDE = dd4hep::DetElement(endcapDetectorEnvelopeDE, endcapDetectorSideEnvName + "DE", sideID); - endcapDetectorSideEnvDE.setPlacement(endcapDetectorSideEnvPhys); - endcapDetectorSideEnvVol.setVisAttributes(lcdd, xmlDet.visStr()); - } + endcapDetectorSideEnvPhys = endcapDetectorEnvVol.placeVolume(endcapDetectorSideEnvVol, dd4hep::Transform3D(endcapDetectorRotation * dd4hep::RotationY(90.0 * dd4hep::degree) , endcapDetectorSideEnvTrans)); + endcapDetectorSideEnvDE = dd4hep::DetElement(endcapDetectorEnvelopeDE, endcapDetectorSideEnvName + "DE", sideID); + endcapDetectorSideEnvDE.setPlacement(endcapDetectorSideEnvPhys); + endcapDetectorSideEnvVol.setVisAttributes(lcdd, xmlDet.visStr()); // ----- dividing the trapezoid envelope to smaller pieces (rectangles) @@ -952,7 +966,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int numEndcapRadiatorLayer = 0; numEndcapRadiatorLayer < numEndcapRadiators; ++numEndcapRadiatorLayer){ - double endcapRadiatorLayerZOffset = - EndcaptotalLength/2.0 + (endcapRadiatorThickness/2.0) + (numEndcapRadiatorLayer +1) * (2 * detectorVolumeThickness) + numEndcapRadiatorLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer + double endcapRadiatorLayerZOffset = - EndcaptotalLength/2.0 + (endcapRadiatorThickness/2.0) + (numEndcapRadiatorLayer +1) * (2 * endcapDetectorEnvZ) + numEndcapRadiatorLayer * endcapRadiatorThickness; // Automation of inner Z-Offset of different layers, taking into account that every detector layer is followed by a yoke(radiator) layer dd4hep::PolyhedraRegular endcapRadiatorEnvelope(numSides, endcapRadiatorLayerInnerRadius, endcapRadiatorLayerOuterRadius, endcapRadiatorThickness); std::string endcapRadiatorEnvelopeName = name + "-EndcapRadiatorLayer" + std::to_string(numEndcapRadiatorLayer + 1); From 3c58659d1a782d877e87118ba3cb4465019c9fcf Mon Sep 17 00:00:00 2001 From: Mahmoud Ali Date: Mon, 30 Sep 2024 03:51:21 +0200 Subject: [PATCH 057/133] Update IDEA_o1_v03.xml Co-authored-by: Brieuc Francois --- FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml index adafde035..2cdcd42f1 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml @@ -60,7 +60,7 @@ - + From 78c0123c6d0824a61aaf1bd36244323686ccf9c8 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Mon, 30 Sep 2024 17:09:00 +0200 Subject: [PATCH 058/133] Updating IDEA Readme to add pre-shower --- FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml | 3 ++- FCCee/IDEA/compact/README.md | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml index 31878b65e..4ff22e24d 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml @@ -215,7 +215,8 @@ - + + diff --git a/FCCee/IDEA/compact/README.md b/FCCee/IDEA/compact/README.md index 95f958f11..e5ebd2add 100644 --- a/FCCee/IDEA/compact/README.md +++ b/FCCee/IDEA/compact/README.md @@ -22,4 +22,6 @@ July 2024: Added a detailed version of the muon system. The monolithic fiber dual-readout calorimeter (o1, v01) is added to the directory, but commented in the main file IDEA_o1_v03.xml for the sake of speed. Please remove the comments to include this calorimeter in the full IDEA detector. August 2024: Added an updated vertex detector (also with the ultra-light inner vertex option) and a more light-weight -implementation of the silicon wrapper. \ No newline at end of file +implementation of the silicon wrapper. + +September 2024: Added detailed version of the pre-shower, based on muon system builder. From d8b0cd34615bf862f67dcb0656af27abe573c57b Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Tue, 1 Oct 2024 02:18:39 +0200 Subject: [PATCH 059/133] fixing pre-shower warning message --- .../compact/IDEA_o1_v03/Preshower_o1_v01.xml | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml index 9505f04c8..4d0cf6fb6 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -13,22 +13,22 @@ - - - - - - - - - + + + + + + + + + - - + + - - - + + + @@ -41,26 +41,26 @@ - + - + - - - - - - - - - - + + + + + + + + + + From 871e8930fd93bd4018a2bba8ce688cdc24a4fd3c Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Tue, 1 Oct 2024 11:37:47 +0200 Subject: [PATCH 060/133] updating pre-shower xml --- FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml index 4d0cf6fb6..434c2d4ce 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/Preshower_o1_v01.xml @@ -11,7 +11,7 @@ - + @@ -64,4 +64,4 @@ - \ No newline at end of file + From 50380ee937041d0ec22ef5f0e05069c0f9b88107 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Tue, 1 Oct 2024 20:47:36 +0200 Subject: [PATCH 061/133] Make tree structure visible in README (#394) --- FCCee/MDI/compact/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FCCee/MDI/compact/README.md b/FCCee/MDI/compact/README.md index 13222dae2..5b92a453a 100644 --- a/FCCee/MDI/compact/README.md +++ b/FCCee/MDI/compact/README.md @@ -9,6 +9,7 @@ aciarma - 08/07/24 -- Beampipe_CADimport_o1_v02.xml : import CAD models for engineered beam pipe (by F. Fransesini/INFN-LNF) These .stl files are hosted [here](https://fccsw.web.cern.ch/fccsw/filesForSimDigiReco/MDI/MDI_o1_v01/). The CMake option `INSTALL_BEAMPIPE_STL_FILES=ON` downloads these STL. +``` -- stl_files/Pipe_240430 ├── AlBeMet162_30042024.stl : central and elliptoconical chambers, with cooling manifolds ├── Copper_pipe_28092023.stl : low impedance beam pipe separation region @@ -17,3 +18,4 @@ The CMake option `INSTALL_BEAMPIPE_STL_FILES=ON` downloads these STL. ├── Tungsten_mask_02102023.stl : SR masks 2.1m upstream └── Water_30042024.stl : cooling for elliptoconical chambers -- BeamInstrumentation_o1_v01.xml : compensating and screening solenoids +``` From 0a4177c6efe8e9b4ce4663412b7dfabebd2c890f Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Wed, 2 Oct 2024 03:11:33 +0200 Subject: [PATCH 062/133] Moving muon-system backwards to avoid overlap with DR-Calo --- .../DectDimensions_IDEA_o1_v03.xml | 8 +++--- .../muonSystem/muonSystemMuRWELL_o1_v01.cpp | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml index 4ff22e24d..a21fa462e 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml @@ -234,12 +234,12 @@ - - + + - + - + diff --git a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp index abf64a9c9..dc9957749 100644 --- a/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp +++ b/detector/muonSystem/muonSystemMuRWELL_o1_v01.cpp @@ -309,24 +309,27 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { std::stringstream barrelNameStream; - barrelNameStream << "MuRWELL_Barrel_" << barrelIdCounter++; - std::string BarrelChamberName = barrelNameStream.str(); + barrelNameStream << "-MuRWELL_Barrel_" << barrelIdCounter++; + std::string BarrelChamberName = name + barrelNameStream.str(); dd4hep::Box envelope(dimensions.x(), dimensions.y(), remainderZ * dimensions.z()); dd4hep::Volume envVolume(BarrelChamberName, envelope, lcdd.material(dimensions.materialStr())); double rectangleRemainderY; + double rectangleRemainderREnvYPos; if (numChambersInRectangle == 0){ rectangleRemainderY = std::abs(std::fmod((2 * rectangleEnvY - clearance), (2 * dimensions.y() - clearance))) / (2 * dimensions.y()); + rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20; }else { rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + 1.5 * clearance; } dd4hep::Box rectangleRemainderYEnvelope(dimensions.x(), rectangleRemainderY * dimensions.y(), remainderZ * dimensions.z()); dd4hep::Volume rectangleRemainderYEnvVolume(BarrelChamberName + "rectangleRemainderY", rectangleRemainderYEnvelope, lcdd.material(dimensions.materialStr())); double envYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + dimensions.y() + clearance/20.0 ; // found that the positioning of the chambers inside the rectangle had an overlap with the mother volume ~ 45 um. - double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20.0; + //double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + 1.5 * clearance; double zRotation; double rectangleRemainderZRotation; @@ -335,7 +338,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, rectangleRemainderZRotation = 0.0; } else { zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); - rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - overlapY * 1.5)); // Y and Z are reversed in local remainder } dd4hep::RotationZ chamberRotation(zRotation); @@ -450,24 +453,27 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { std::stringstream barrelNameStream; - barrelNameStream << "MuRWELL_Barrel_" << barrelIdCounter++; - std::string BarrelChamberName = barrelNameStream.str(); + barrelNameStream << "-MuRWELL_Barrel_" << barrelIdCounter++; + std::string BarrelChamberName = name + barrelNameStream.str(); dd4hep::Box envelope(dimensions.x(), dimensions.y(), dimensions.z()); dd4hep::Volume envVolume(BarrelChamberName, envelope, lcdd.material(dimensions.materialStr())); double rectangleRemainderY; + double rectangleRemainderREnvYPos; if (numChambersInRectangle == 0){ rectangleRemainderY = std::abs(std::fmod((2 * rectangleEnvY - clearance), (2 * dimensions.y() - clearance))) / (2 * dimensions.y()); + rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20; }else { rectangleRemainderY = std::fmod(2 * (rectangleEnvY - clearance), (2 * dimensions.y() - overlapY)) / (2 * dimensions.y()); + rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + 1.5 * clearance; } dd4hep::Box rectangleRemainderYEnvelope(dimensions.x(), rectangleRemainderY * dimensions.y(), dimensions.z()); dd4hep::Volume rectangleRemainderYEnvVolume(BarrelChamberName + "rectangleRemainderY", rectangleRemainderYEnvelope, lcdd.material(dimensions.materialStr())); double envYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + dimensions.y() + clearance/20.0 ; // found that the positioning of the chambers inside the rectangle had an overlap with the mother volume ~ 45 um. - double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + clearance/20.0; + //double rectangleRemainderREnvYPos = (chamberIndex * 2 * dimensions.y()) - (overlapY * chamberIndex) + dimensions.y_offset() - rectangleEnvY + rectangleRemainderY * dimensions.y() + 1.5 * clearance; double zRotation; double rectangleRemainderZRotation; @@ -476,7 +482,7 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, rectangleRemainderZRotation = 0.0; } else { zRotation = std::atan(dimensions.x() / (dimensions.y() - (2 * overlapY))); - rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - (2 * overlapY))); // Y and Z are reversed in local remainder + rectangleRemainderZRotation = std::atan(dimensions.x() / (rectangleRemainderY * dimensions.y() - overlapY * 1.5)); // Y and Z are reversed in local remainder } dd4hep::RotationZ chamberRotation(zRotation); @@ -826,8 +832,8 @@ static dd4hep::Ref_t createmuonSystemMuRWELL_o1_v01(dd4hep::Detector& lcdd, for (int chamberIndex = 0; chamberIndex < (numChambersInRectangle + 1); chamberIndex++) { std::stringstream endcapNameStream; - endcapNameStream << "MuRWELL_Endcap_" << endcapIdCounter++; - std::string EndcapChamberName = endcapNameStream.str(); + endcapNameStream << "-MuRWELL_Endcap_" << endcapIdCounter++; + std::string EndcapChamberName = name + endcapNameStream.str(); dd4hep::Box envelope; if (rectangle == numRectangles) { From a162fbc05fc6c451956ab43b81d6a1d0c4f07638 Mon Sep 17 00:00:00 2001 From: mahmoudali2 Date: Wed, 2 Oct 2024 10:47:57 +0200 Subject: [PATCH 063/133] Fixing overlap issues among IDEA sub-detectors --- .../IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml index a21fa462e..7a72d28eb 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DectDimensions_IDEA_o1_v03.xml @@ -116,7 +116,7 @@ - + @@ -132,8 +132,8 @@ - - + + @@ -209,12 +209,12 @@ - - + + - + - + From e0fa2262ed8da91369abd728c8354dc76ab0e1c5 Mon Sep 17 00:00:00 2001 From: michaela mlynarikova Date: Tue, 24 Sep 2024 14:05:30 +0200 Subject: [PATCH 064/133] fix printout messages --- .../HCalThreePartsEndcap_o1_v02_geo.cpp | 66 +++++++++---------- .../calorimeter/HCalTileBarrel_o1_v02_geo.cpp | 38 ++++------- 2 files changed, 45 insertions(+), 59 deletions(-) diff --git a/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp b/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp index da2ec6af9..30235a955 100644 --- a/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp +++ b/detector/calorimeter/HCalThreePartsEndcap_o1_v02_geo.cpp @@ -1,15 +1,7 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" #include - -// todo: remove gaudi logging and properly capture output -#define endmsg std::endl -#define lLog std::cout -namespace MSG { -const std::string ERROR = "createHCalThrePartsEndcap ERROR "; -const std::string DEBUG = "createHCalThrePartsEndcap DEBUG "; -const std::string INFO = "createHCalThrePartsEndcap INFO "; -} +#include "DD4hep/Printout.h" using dd4hep::Volume; using dd4hep::DetElement; @@ -54,8 +46,8 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h double space = xSpace.thickness(); xml_comp_t xSteelSupport = xmlElement.child(_Unicode(steel_support)); double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness " << dSteelSupport << endmsg; - lLog << MSG::DEBUG << "steel support material " << xSteelSupport.materialStr() << endmsg; + + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "steel support thickness (cm): %.2f", dSteelSupport); // Calculate sensitive barrel dimensions double sensitiveBarrel1Rmin = dimensions.rmin1() + 2 * dRhoFacePlate + space; @@ -71,18 +63,18 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h std::vector sequences = {xmlElement.child(_Unicode(sequence_a)), xmlElement.child(_Unicode(sequence_b))}; // Check if both sequences are present if (!sequences[0] || !sequences[1]) { - lLog << MSG::ERROR << "The two sequences sequence_a and sequence_b must be present in the xml file." << endmsg; + dd4hep::printout(dd4hep::ERROR, "HCalThreePartsEndcap_o1_v02", "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file."); throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); } // Check if both sequences have the same dimensions Dimension dimensionsA(sequences[0].dimensions()); Dimension dimensionsB(sequences[1].dimensions()); if (dimensionsA.dz() != dimensionsB.dz()) { - lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + dd4hep::printout(dd4hep::ERROR, "HCalThreePartsEndcap_o1_v02", "The dimensions of sequence_a and sequence_b do not match."); throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); } double dzSequence = dimensionsB.dz(); - lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "sequence thickness %.2f", dzSequence); // calculate the number of modules fitting in Z unsigned int numSequencesZ1 = static_cast((2 * dimensions.width() - 2 * dZEndPlate - space) / dzSequence); @@ -126,39 +118,38 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h } } - lLog << MSG::DEBUG << "retrieved number of layers in first Endcap part: " << numLayersR1 << " , which end up to a full module depth in rho of " << moduleDepth1 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in second Endcap part: " << numLayersR2 << " , which end up to a full module depth in rho of " << moduleDepth2 << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of layers in third Endcap part: " << numLayersR3 << " , which end up to a full module depth in rho of " << moduleDepth3 << " cm" << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "retrieved number of layers in first Endcap part: %d , which end up to a full module depth in rho of %.2f cm", numLayersR1, moduleDepth1); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "retrieved number of layers in second Endcap part: %d , which end up to a full module depth in rho of %.2f cm", numLayersR2, moduleDepth2); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "retrieved number of layers in third Endcap part: %d , which end up to a full module depth in rho of %.2f cm", numLayersR3, moduleDepth3); - lLog << MSG::INFO << "constructing first part EC: with z offset " << extBarrelOffset1 << " cm: "<< numSequencesZ1 << " sequences in Z, " << numLayersR1 << " layers in Rho, " << numLayersR1 * numSequencesZ1 << " tiles" << endmsg; - lLog << MSG::INFO << "constructing second part EC: with offset " << extBarrelOffset2 << " cm: " << numSequencesZ2 << " sequences in Z, " << numLayersR2 << " layers in Rho, " << layerDepths2.size() * numSequencesZ2 << " tiles" << endmsg; + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "constructing first part EC: with z offset %.2f cm: %d sequences in Z, %d radial layers, %d tiles", extBarrelOffset1, numSequencesZ1, numLayersR1, numSequencesZ1*numLayersR1); + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "constructing second part EC: with z offset %.2f cm: %d sequences in Z, %d radial layers, %d tiles", extBarrelOffset2, numSequencesZ2, numLayersR2, numSequencesZ2*numLayersR2); + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "constructing third part EC: with z offset %.2f cm: %d sequences in Z, %d radial layers, %d tiles", extBarrelOffset3, numSequencesZ3, numLayersR3, numSequencesZ3*numLayersR3); - lLog << MSG::INFO << "constructing third part EC: with offset " << extBarrelOffset3 << " cm: " << numSequencesZ3 << " sequences in Z, " << numLayersR3 << " layers in Rho, " << layerDepths3.size() * numSequencesZ3 << " tiles" << endmsg; - - lLog << MSG::INFO << "number of channels: " << (numLayersR1 * numSequencesZ1) + (numLayersR2 * numSequencesZ2) + (numLayersR3 * numSequencesZ3) << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "number of sequences in the whole Endcap ", numLayersR1*numSequencesZ1 + numLayersR2*numSequencesZ2 + numLayersR3*numSequencesZ3); // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector1 = (numSequencesZ1 * dzSequence) / 2 + 2 * dZEndPlate + space; double dzDetector2 = (numSequencesZ2 * dzSequence) / 2; double dzDetector3 = (numSequencesZ3 * dzSequence) / 2 + 2 * dZEndPlate + space; - lLog << MSG::INFO << "correction of dz (negative = size reduced) first part EC :" << dzDetector1*2 - dimensions.width()*2 << endmsg; - lLog << MSG::INFO << "dz second part EC:" << dzDetector2 * 2 << endmsg; - lLog << MSG::INFO << "width second part EC:" << dimensions.dz() * 2 << endmsg; - lLog << MSG::INFO << "correction of dz (negative = size reduced) second part EB:" << dzDetector2*2 - dimensions.dz()*2 << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "correction of dz (negative = size reduced) first part EC: %.2f", dzDetector1*2 - dimensions.width()*2); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "dz second part EC: %.2f", dzDetector2 * 2); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "width second part EC: %.2f", dimensions.dz() * 2); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "correction of dz (negative = size reduced) second part EB: %.2f", dzDetector2*2 - dimensions.dz()*2); - lLog << MSG::INFO << "dz third part EC:" << dzDetector3 * 2 << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "dz third part EC: %.2f", dzDetector3 * 2); for (int iSign = -1; iSign < 2; iSign+=2){ int sign; if(iSign < 0){ sign = -1; - lLog << MSG::DEBUG << "Placing detector on the negative side: (cm) " << -(dimensions.offset() + dimensions.dz()) << endmsg; + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "Placing detector on the negative side: (cm) %.2f", -(dimensions.offset() + dimensions.dz())); } else{ sign = +1; - lLog << MSG::DEBUG << "Placing detector on the positive side: (cm) " << (dimensions.offset() + dimensions.dz()) << endmsg; + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "Placing detector on the positive side: (cm) %.2f", (dimensions.offset() + dimensions.dz())); } // Add structural support made of steel inside of HCal DetElement facePlate1(caloDetElem, "FacePlate_" + std::to_string(1 * sign), 0); @@ -231,7 +222,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); Volume tileSequenceVolume("HCalECTileSequenceVol1", tileSequenceShape, lcdd.air()); - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + if(iSign < 0){ + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "first part: layer %d (cm): %.2f - %.2f", idxLayer, rminLayer, rmaxLayer); + } dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector1 ); Volume layerVolume("HCalECLayerVol1", layerShape, lcdd.air()); @@ -301,7 +294,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); Volume tileSequenceVolume("HCalECTileSequenceVol2", tileSequenceShape, lcdd.air()); - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + if(iSign < 0){ + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "second part: layer %d (cm): %.2f - %.2f", idxLayer, rminLayer, rmaxLayer); + } dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector2); Volume layerVolume("HCalECLayerVol2", layerShape, lcdd.air()); @@ -369,7 +364,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h dd4hep::Tube tileSequenceShape(rminLayer, rmaxLayer, 0.5*dzSequence); Volume tileSequenceVolume("HCalECTileSequenceVol3", tileSequenceShape, lcdd.air()); - lLog << MSG::DEBUG << "layer radii: " << rminLayer << " - " << rmaxLayer << " [cm]" << endmsg; + if(iSign < 0){ + dd4hep::printout(dd4hep::INFO, "HCalThreePartsEndcap_o1_v02", "third part: layer %d (cm): %.2f - %.2f", idxLayer, rminLayer, rmaxLayer); + } dd4hep::Tube layerShape(rminLayer, rmaxLayer, dzDetector3); Volume layerVolume("HCalECLayerVol3", layerShape, lcdd.air()); @@ -422,8 +419,9 @@ static dd4hep::Ref_t createHCalEC(dd4hep::Detector& lcdd, xml_h xmlElement, dd4h } // end loop placement of subwedges // Placement of DetElements - lLog << MSG::DEBUG << "Layers in r : " << layers.size() << std::endl; - lLog << MSG::DEBUG << "Tiles in layers :" << tilesPerLayer.size() << std::endl; + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "Layers in r : %d", layers.size()); + dd4hep::printout(dd4hep::DEBUG, "HCalThreePartsEndcap_o1_v02", "Tiles in layers : %d", tilesPerLayer.size()); + // Place det elements wihtin each other to recover volume positions later via cellID for (uint iLayer = 0; iLayer < (layerDepths1.size()+layerDepths2.size()+layerDepths3.size()); iLayer++){ diff --git a/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp b/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp index 4e1796c94..aaf6c9c4d 100644 --- a/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp +++ b/detector/calorimeter/HCalTileBarrel_o1_v02_geo.cpp @@ -1,23 +1,13 @@ // DD4hep #include "DD4hep/DetFactoryHelper.h" - #include +#include "DD4hep/Printout.h" using dd4hep::Volume; using dd4hep::DetElement; using dd4hep::xml::Dimension; using dd4hep::PlacedVolume; - -// todo: remove gaudi logging and properly capture output -#define endmsg std::endl -#define lLog std::cout -namespace MSG { -const std::string ERROR = "createHCalTileBarrel ERROR "; -const std::string DEBUG = "createHCalTileBarrel DEBUG "; -const std::string INFO = "createHCalTileBarrel INFO "; -} - namespace det { static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep::SensitiveDetector sensDet) { @@ -41,8 +31,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep xml_comp_t xSteelSupport = xmlDet.child(_Unicode(steel_support)); double dSteelSupport = xSteelSupport.thickness(); - lLog << MSG::DEBUG << "steel support thickness (cm): " << dSteelSupport / dd4hep::cm << endmsg; - lLog << MSG::DEBUG << "steel support material: " << xSteelSupport.materialStr() << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalTileBarrel_o1_v02", "steel support thickness (cm): %.2f", dSteelSupport); double sensitiveBarrelRmin = xDimensions.rmin() + xFacePlate.thickness() + space; @@ -50,18 +39,18 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep std::vector sequences = {xmlDet.child(_Unicode(sequence_a)), xmlDet.child(_Unicode(sequence_b))}; // Check if both sequences are present if (!sequences[0] || !sequences[1]) { - lLog << MSG::ERROR << "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file." << endmsg; + dd4hep::printout(dd4hep::ERROR, "HCalTileBarrel_o1_v02", "The two sequences 'sequence_a' and 'sequence_b' must be present in the xml file."); throw std::runtime_error("Missing sequence_a or sequence_b in the xml file."); } // Check if both sequences have the same dimensions Dimension dimensionsA(sequences[0].dimensions()); Dimension dimensionsB(sequences[1].dimensions()); if (dimensionsA.dz() != dimensionsB.dz()) { - lLog << MSG::ERROR << "The dimensions of sequence_a and sequence_b do not match." << endmsg; + dd4hep::printout(dd4hep::ERROR, "HCalTileBarrel_o1_v02", "The dimensions of sequence_a and sequence_b do not match."); throw std::runtime_error("The dimensions of the sequence_a and sequence_b do not match."); } double dzSequence = dimensionsB.dz(); - lLog << MSG::DEBUG << "sequence thickness " << dzSequence << endmsg; + dd4hep::printout(dd4hep::DEBUG, "HCalTileBarrel_o1_v02", "sequence thickness %.2f", dzSequence); // calculate the number of sequences fitting in Z unsigned int numSequencesZ = static_cast((2 * xDimensions.dz() - 2 * dZEndPlate - 2 * space) / dzSequence); @@ -84,17 +73,15 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep layerDepths.push_back(layerDimension.dr()); } } - lLog << MSG::DEBUG << "retrieved number of radial layers: " << numLayersR - << " , which end up to a full module depth in rho of " << moduleDepth << " cm" << endmsg; - lLog << MSG::DEBUG << "retrieved number of radial layers: " << layerDepths.size() << endmsg; - - lLog << MSG::INFO << "constructing: " << numSequencesZ << " sequences in Z, " << numLayersR - << " radial layers, in total " << numLayersR * numSequencesZ << " tiles" << endmsg; - // Calculate correction along z based on the module size (can only have natural number of modules) double dzDetector = (numSequencesZ * dzSequence) / 2 + dZEndPlate + space; - lLog << MSG::DEBUG << "dzDetector (cm): " << dzDetector / dd4hep::cm << endmsg; - lLog << MSG::INFO << "correction of dz in cm (negative = size reduced):" << dzDetector - xDimensions.dz() << endmsg; + + dd4hep::printout(dd4hep::INFO, "HCalTileBarrel_o1_v02", "dzDetector (cm): %.2f", dzDetector); + dd4hep::printout(dd4hep::DEBUG, "HCalTileBarrel_o1_v02", "correction of dz in cm (negative = size reduced): %.2f", dzDetector - xDimensions.dz()); + + dd4hep::printout(dd4hep::DEBUG, "HCalTileBarrel_o1_v02", "retrieved number of radial layers: %d , which end up to a full module depth in rho of %.2f cm", numLayersR, moduleDepth); + dd4hep::printout(dd4hep::DEBUG, "HCalTileBarrel_o1_v02", "retrieved number of radial layers: %d", layerDepths.size()); + dd4hep::printout(dd4hep::INFO, "HCalTileBarrel_o1_v02", "constructing: %d sequences in Z, %d radial layers, in total %d tiles", numSequencesZ, numLayersR, numLayersR * numSequencesZ); double rminSupport = sensitiveBarrelRmin + moduleDepth; double rmaxSupport = sensitiveBarrelRmin + moduleDepth + dSteelSupport; @@ -164,6 +151,7 @@ static dd4hep::Ref_t createHCal(dd4hep::Detector& lcdd, xml_det_t xmlDet, dd4hep double rmaxLayer = sensitiveBarrelRmin + layerR + layerDepths.at(idxLayer); layerR += layerDepths.at(idxLayer); layerInnerRadii.push_back(rminLayer); + dd4hep::printout(dd4hep::INFO, "HCalTileBarrel_o1_v02", "layer %d (cm): %.2f - %.2f", idxLayer, rminLayer, rmaxLayer); //alternate: even layers consist of tile sequence b, odd layer of tile sequence a unsigned int sequenceIdx = idxLayer % 2; From 118a19f771818f1eb20d3dc7573c832303092e9e Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:15:27 +0200 Subject: [PATCH 065/133] Release Notes for v00-21-00 --- doc/ReleaseNotes.md | 196 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md index 94ec37b5d..f2c8af276 100644 --- a/doc/ReleaseNotes.md +++ b/doc/ReleaseNotes.md @@ -1,3 +1,199 @@ +# v00-21-00 + +* 2024-10-02 mahmoudali2 ([PR#401](https://github.com/key4hep/k4geo/pull/401)) + - IDEA_o1_v03: Moving IDEA muon system starting point in both barrel (rmin) and endcap (z-offset) 30 mm, backwards to avoid overlapping with Dual readout calorimeter. + - The change including also updating chamber names to distinguish between muon chambers and pre shower chamber, since they are using the same uURWELL chamber. + - Change dimensions of solenoid/endplate and move the pre-shower to avoid overlaps with dual readout calorimeter + +* 2024-10-02 michaela mlynarikova ([PR#395](https://github.com/key4hep/k4geo/pull/395)) + - fix printout messages in HCal Tile barrel and Endcap three parts detector builder + +* 2024-10-01 tmadlener ([PR#398](https://github.com/key4hep/k4geo/pull/398)) + - Switch the `pre-commit` action to run in a Key4hep environment + - Add `ruff` formatting to `pre-commit` + - Fix a few python2 style `print` statements + - Fix format of all python files + +* 2024-10-01 mahmoudali2 ([PR#397](https://github.com/key4hep/k4geo/pull/397)) + - Generalizing the muon system builder to adopt pre-shower description, the changes include: + - Making the variable names more general, not specific only for muon system. + - Changing the detector side's volume thicknesses in case there is only one chambers row in the side (like the pre-shower case), and it's in general it is the case for any -almost- circular shape for the detector. + - Disallowing the overlap rotation in case of single chamber side. + - Overall, the changes make the builder more general to adopt different cases with different structures (polyhedron & cylinder of chambers). + +* 2024-10-01 Thomas Madlener ([PR#394](https://github.com/key4hep/k4geo/pull/394)) + - Improve readability of README for FCCee MDI + +* 2024-09-25 armin.ilg ([PR#396](https://github.com/key4hep/k4geo/pull/396)) + - No more warnings in silicon wrapper + - Improvements in vertex builder printouts + - Adding all materials of beam pipe also to material_plots_2D.py, as without having the beam pipe enabled, the vertex material budget estimation will fail. + - Changed paths to .stl files in vertex to use https://fccsw.web.cern.ch/fccsw/filesForSimDigiReco/IDEA/IDEA_o1_v03/STL_FILES/ (still commented out due to overlaps) + +* 2024-09-19 Armin Fehr ([PR#363](https://github.com/key4hep/k4geo/pull/363)) + - Update of IDEA vertex, with the ability to use the ultra-light vertex concept in-situ. + - No overlaps in all of vertex and silicon wrapper (not including the DDCAD imported vertex support and cooling cones yet), more performant silicon wrapper (only silicon wrapper barrel sensors are simplified) + +* 2024-09-18 Erich Varnes ([PR#379](https://github.com/key4hep/k4geo/pull/379)) + * ECalEndcap_Turbine_o1_v01_geo: Fix issues with printout (to allow verbosity to be controlled from run script). + * Add ECalEndcap_Turbine_o1_v02_geo of the "turbine" endcap geometry: which allows for more flexibility than v01 (for example, one can set different blade angles for the three wheels in v02). As v02 is still a work in progress, the default xml points to v01. + +* 2024-09-16 JEANS Daniel Thomelin Dietrich ([PR#388](https://github.com/key4hep/k4geo/pull/388)) + - For ILD models only: apply the same step limits as defined for the tracker ("Tracker_limits", currently 5mm) inside the beampipe volume and MDI region. This is important for tracking of low momentum particles (eg beamstrahlung pairs) especially in non-uniform fields. Should have no noticeable effect in other situations. + +* 2024-09-12 Andre Sailer ([PR#391](https://github.com/key4hep/k4geo/pull/391)) + - CLD_o2_v07: change LumiCal envelopes from boolean of boolean to assembly, fixes #306, speeds up overlap check (of LumiCal only) with /geometry/test/resolution 300000 down to 13s instead of 3m10s + +* 2024-09-10 jmcarcell ([PR#387](https://github.com/key4hep/k4geo/pull/387)) + - Use the Key4hepConfig flag to set the standard, compiler flags and rpath magic. + +* 2024-09-03 jmcarcell ([PR#386](https://github.com/key4hep/k4geo/pull/386)) + - Do not link against podio and EDM4hep dictionaries. Introduced in https://github.com/key4hep/k4geo/pull/346, I think it's never necessary to link to the dictionaries. + +* 2024-09-02 Andre Sailer ([PR#385](https://github.com/key4hep/k4geo/pull/385)) + - FieldMapXYZ, FieldMapBrBz: adapt to variable rename from DD4hep, fix "OverlayedField ERROR add: Attempt to add an unknown field type.", fixes #384 + +* 2024-08-29 Andre Sailer ([PR#383](https://github.com/key4hep/k4geo/pull/383)) + - CLD_o2_v07: fix overlaps related to the LumiCal, slight correction in the position of the envelopes and passive material. Fixes #376 + +* 2024-08-28 Leonhard Reichenbach ([PR#369](https://github.com/key4hep/k4geo/pull/369)) + - Added TrackerBarrel_o1_v06 using a stave assembly instead of directly placing the sensors into the layers + - Added CLD_o2_v07 using the new TrackerBarrel_o1_v06 + +* 2024-08-28 michaela mlynarikova ([PR#350](https://github.com/key4hep/k4geo/pull/350)) + - added new HCalEndcaps_ThreeParts_TileCal_v02.xml: migrated to use FCCSWGridPhiTheta_k4geo; fixed radial dimensions, so the outer radius of all three parts is the same; renamed nModules to nsegments for number of layers in the second cylinder; uses geometry CaloThreePartsEndcap_o1_v02 + + - added new HCalBarrel_TileCal_v02.xml which uses geometry HCalTileBarrel_o1_v01 + + - updated ALLEGRO_o1_v03.xml to include HCalBarrel_TileCal_v02.xml and HCalEndcaps_ThreeParts_TileCal_v02.xml + + - added new HCalThreePartsEndcap_o1_v02_geo.cpp: added extension to store the radii of each radial layer as well as dimensions of cells. These will be used by the CellPositionsHCalPhiThetaSegTool to calculate the radii of each layer. Improved code readability and variables naming + + - updated HCalTileBarrel_o1_v01_geo.cpp: added extension to store the radii of each radial layer as well as dimensions of cells. These will be used by the CellPositionsHCalPhiThetaSegTool to calculate the radii of each layer. Improved code readability and variables naming + +* 2024-08-22 Victor Schwan ([PR#378](https://github.com/key4hep/k4geo/pull/378)) + - 2nd SIT barrel layer ID was corrected for `ILD_l5_v11`; the error stemmed from out-commenting 2nd out of 3 layers without adjusting hard-coded layer IDs + +* 2024-08-20 BrieucF ([PR#372](https://github.com/key4hep/k4geo/pull/372)) + - [FCCeeMDI] Use absolute path to import CAD files + +* 2024-08-09 jmcarcell ([PR#374](https://github.com/key4hep/k4geo/pull/374)) + - Fix a few compiler warnings + +* 2024-08-09 Erich Varnes ([PR#373](https://github.com/key4hep/k4geo/pull/373)) + FCCSWEndcapTurbine_k4geo segmentation: Correct the y position for cells in the endcap on the -z side of the detector (a minus sign is needed since this detector is a mirrored copy of the +z side). + +* 2024-08-09 jmcarcell ([PR#368](https://github.com/key4hep/k4geo/pull/368)) + - Clean up includes + +* 2024-08-09 Alvaro Tolosa Delgado ([PR#365](https://github.com/key4hep/k4geo/pull/365)) + - IDEA_o1_v03: Dual Readout Calorimeter (DRC) is not loaded by default + - Added Test for IDEA with DRC + +* 2024-08-09 jmcarcell ([PR#353](https://github.com/key4hep/k4geo/pull/353)) + - muonSystemMuRWELL_o1_v01.cpp: Use + std::to_string to append to a string, instead of adding an integer to a string (introduced in https://github.com/key4hep/k4geo/pull/322). Adding a string and an integer cuts the string by as many characters as the value of the integer. + +* 2024-08-08 BrieucF ([PR#371](https://github.com/key4hep/k4geo/pull/371)) + - Put the stl files for CAD beampipe, downloaded with cmake, at the right place + +* 2024-08-06 Alvaro Tolosa Delgado ([PR#359](https://github.com/key4hep/k4geo/pull/359)) + - New CMake option `INSTALL_BEAMPIPE_STL_FILES` can be used to download the STL (CAD model) beam pipe files from the web EOS + +* 2024-08-06 Sungwon Kim ([PR#346](https://github.com/key4hep/k4geo/pull/346)) + - Add DRC geometry construction code under `detector/calorimeter/dual-readout` directory + - Add .xml compact files under `FCCee/IDEA/compact/IDEA_o1_v03` directory + - Add custom SD action, output file, fast simulation (boosting optical photon transportation) for Monolithic fiber DRC under `plugin` directory + - Fixed CMakeLists to compile all above + +* 2024-07-30 Leonhard Reichenbach ([PR#362](https://github.com/key4hep/k4geo/pull/362)) + - TrackerEndcap_o2_v06_geo: Fixed endcap radius calculation for the event display (CED), and only the event display, fixes #355 + +* 2024-07-30 jmcarcell ([PR#360](https://github.com/key4hep/k4geo/pull/360)) + - Add aliases for the detectorCommon and detectorSegmentations libraries + +* 2024-07-22 Giovanni Marchiori ([PR#357](https://github.com/key4hep/k4geo/pull/357)) + - [ALLEGRO_o1_v03 ECAL barrel] Get number of modules passed to readout from constant defined before in xml + +* 2024-07-22 Erich Varnes ([PR#347](https://github.com/key4hep/k4geo/pull/347)) + - Added a new driver, `ECalEndcap_Turbine_o1_v01`, to build a Noble Liquid ECAL endcap with inclined blades (aka turbine geometry) + - Added a new segmentation (`FCCSWEndcapTurbine_k4geo`) for the Noble Liquid ECAL endcap turbine geometry + - Replaced the ALLEGRO_o1_v03 ECAL endcap made of disks perpendicular to the z axis by the turbine geometry built with `ECalEndcap_Turbine_o1_v01` + +* 2024-07-19 aciarma ([PR#344](https://github.com/key4hep/k4geo/pull/344)) + - added `k4geo/FCCee/MDI` folder + - put the shape based beampipe in `MDI_o1_v00` + - prepared `k4geo/FCCee/MDI/compact/MDI_o1_v01/` which will contain the CAD beampipe + - modified the main compact files of `ALLEGRO_o1_v03` and `IDEA_o1_v03` to include the centralized beampipe and prepare them for the CAD ones + - removed `HOMAbsorbers.xml` from ALLEGRO_o1_v03 since they are not needed with the low impedance beam pipe. + +* 2024-07-16 jmcarcell ([PR#354](https://github.com/key4hep/k4geo/pull/354)) + - Rename the lcgeoTests folder to test + +* 2024-07-08 mahmoudali2 ([PR#322](https://github.com/key4hep/k4geo/pull/322)) + - Define the first draft of the detailed muon system, which depend on mosaics of 50 * 50 cm^2 mRWELL chambers. + - Define a suitable XML for the new detailed version. + - Describe µRWELL materials. + - Add the parameters of the muon system into the full IDEA implementation. + +* 2024-07-04 Giovanni Marchiori ([PR#349](https://github.com/key4hep/k4geo/pull/349)) + - fix detector type in ALLEGRO v03 ECAL calibration scripts + +* 2024-07-04 jmcarcell ([PR#348](https://github.com/key4hep/k4geo/pull/348)) + - CMake: fix printout for missing header file, by printing the actual missing file + +* 2024-06-28 tmadlener ([PR#343](https://github.com/key4hep/k4geo/pull/343)) + - Make the TPC have detector ID 4 and use a consistent cellID for all tracking detectors in `ILD_l5_v11` in order to make tracking code run again + +* 2024-06-19 jmcarcell ([PR#342](https://github.com/key4hep/k4geo/pull/342)) + - Remove a warning by deleting an unused string + +* 2024-06-12 jmcarcell ([PR#340](https://github.com/key4hep/k4geo/pull/340)) + - Remove a CentOS7 workflow using the CLIC nightlies + +* 2024-06-10 Frank Gaede ([PR#333](https://github.com/key4hep/k4geo/pull/333)) + - fix CED event display for CLIC like detectors using TrackerEndcap_o2_v0x_geo + - fix nPetals in ZDiskPetalsData (for CEDViewer) to use nmodules (e.g. 48 ) rather than nrings + - store the number of rings in `ZDiskPetalsData::sensorsPerPetal` + +* 2024-06-06 BrieucF ([PR#339](https://github.com/key4hep/k4geo/pull/339)) + - [FCCee-ALLEGRO_o1_v03] Vertex detector and drift chamber updated to the last IDEA version + - [FCCee-ALLEGRO_o1_v03] Added solenoidal and MDI magnetic fields + - [FCCee-ALLEGRO_o1_v03] Removed ALLEGRO_o1_v03_ecalonly.xml and ALLEGRO_o1_v03_trackeronly.xml to ease maintenance (they can be obtained by commenting out sub-detectors) + +* 2024-05-30 BrieucF ([PR#335](https://github.com/key4hep/k4geo/pull/335)) + - Fix for the IDEA_o1_v03 solenoid position + +* 2024-05-15 Alvaro Tolosa Delgado ([PR#330](https://github.com/key4hep/k4geo/pull/330)) + - Implementation of IDEA drift chamber, o1_v02. It is based on an original description. The code was redesign to be light. Standalone overlap ctest added. + +* 2024-05-06 Zhibo WU ([PR#334](https://github.com/key4hep/k4geo/pull/334)) + - xtalk_neighbors_moduleThetaMergedSegmentation.cpp: change the loop variable itField from int to size_t, in order to remove a compilation warning. + +* 2024-04-18 Zhibo WU ([PR#331](https://github.com/key4hep/k4geo/pull/331)) + - Add new functions related to the crosstalk neighbour finding for ALLEGRO ECAL barrel cells. + +* 2024-04-16 Giovanni Marchiori ([PR#332](https://github.com/key4hep/k4geo/pull/332)) + - New version of ALLEGRO detector o1_v03 with ecal barrel with 11 layers with cell corners projective along phi. No changes to the other sub detectors. + +* 2024-03-24 BrieucF ([PR#326](https://github.com/key4hep/k4geo/pull/326)) + - CLD_o2_v06: add new detector model + +* 2024-03-21 Brieuc Francois ([PR#329](https://github.com/key4hep/k4geo/pull/329)) + - Add a description of CLD_o4_v05 in the FCCee README + +* 2024-03-21 BrieucF ([PR#327](https://github.com/key4hep/k4geo/pull/327)) + - Add a solenoid and magnetic fields for IDEA. The solenoid has the right material budget (0.75 X0) and spacial extent but its internals should be revised by ultra-thin solenoid designers. + - Add the endplate lead absorbers for IDEA + +* 2024-03-06 Anna Zaborowska ([PR#328](https://github.com/key4hep/k4geo/pull/328)) + - Make LCIO an optional dependency. If LCIO is not found, some detectors (trackers) will not be built. + +* 2024-02-25 jmcarcell ([PR#324](https://github.com/key4hep/k4geo/pull/324)) + - Remove the old key4hep build workflow since there is a newer one that builds for all the supported OSes + +* 2024-02-25 jmcarcell ([PR#302](https://github.com/key4hep/k4geo/pull/302)) + - Clean up unused variables + # v00-20-00 * 2024-02-22 BrieucF ([PR#323](https://github.com/key4hep/k4geo/pull/323)) From 2a8573aead54464496f736040252fcbcdfddcbbc Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:15:28 +0200 Subject: [PATCH 066/133] Updating version to v00-21-00 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35697ba60..7832f679a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(${PackageName}) # project version SET( ${PackageName}_VERSION_MAJOR 0 ) -SET( ${PackageName}_VERSION_MINOR 20 ) +SET( ${PackageName}_VERSION_MINOR 21 ) SET( ${PackageName}_VERSION_PATCH 0 ) SET( ${PackageName}_VERSION "${${PackageName}_VERSION_MAJOR}.${${PackageName}_VERSION_MINOR}" ) From 2ca85013ad3a5cb02e18407a936ddec66ea83fdb Mon Sep 17 00:00:00 2001 From: BrieucF Date: Fri, 11 Oct 2024 12:40:39 +0200 Subject: [PATCH 067/133] [IDEA] Lower drift chamber verbosity --- FCCee/IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml b/FCCee/IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml index b7f781561..309d98af8 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml @@ -84,7 +84,7 @@ region="DCH_region" limits="DCH_limits" buildLayers="True" - printExcelTable="True" + printExcelTable="False" > Date: Thu, 17 Oct 2024 18:16:05 +0900 Subject: [PATCH 068/133] experimental ILD models for FCCee (#390) * remove duplicated definitions; some moving of definitions between files * new model for FCCee: ILD_FCCee_v01 * small fix * fix overlaps in inner tracker of ILD_l5_v11 * remove local copies of files: link directly to source (in CLD, MID directories) * add in forgotten definition of inner TPC radius (due to previous moving around of defs) * move ILD model for FCCee (ILD_FCCee_v01) to the FCCee directory * added in some missing definitions (due to earlier re-organisation) * change to ILD-specific visualisation colours to avoid clashes when linking to xml descriptions from other detectors (eg RedVis -> ILD_RedVis) * ILD_FCCee_v02 model added with CLD InnerTracker and correspondingly shrunk TPC * moved ILD_FCCee_v02 into FCCee folder * changes to READMEs * minor fixups in ILD_FCCee_v01.xml * subdetector configs from common MDI and CLD where possible * minor README fixes * no files with same name. use same file (linked) for identical definitions between v01, v02 models. * add tests for ILC_FCCee_v01 and ILC_FCCee_v02 models * moved and combined individual README files * edit README to suggest not using ILD_l5_v11 * revert correction to material (G4_Au): to be implemented separately * adjust GlobalTrackerReadoutID to match other ILD trackers * add comment about ILDDetID_TPC * Revert "adjust GlobalTrackerReadoutID to match other ILD trackers" This reverts commit 46539095d4d7c88a3eb28289a2375b9cd010c5d2. (adjustment of CellID encoding) * add comment re cellID * link rather than copy identical file * move common ILD_FCCee definitions to common directory * remove hanging link * add EcalEndcapRing * add experimental label * Update ILD/compact/README.md Co-authored-by: Thomas Madlener --------- Co-authored-by: Victor Schwan Co-authored-by: Thomas Madlener --- .../compact/ILD_FCCee_v01/ILD_FCCee_v01.xml | 177 ++++++ .../ILD_FCCee_v01/ILD_FCCee_v01_defs.xml | 8 + .../InnerTrackerILD_o1_v02_00.xml | 544 ++++++++++++++++++ .../ILD_FCCee_v01/top_defs_ILD_FCCee_v01.xml | 12 + .../compact/ILD_FCCee_v02/ILD_FCCee_v02.xml | 176 ++++++ .../ILD_FCCee_v02/ILD_FCCee_v02_defs.xml | 6 + .../ILD_FCCee_v02/top_defs_ILD_FCCee_v02.xml | 12 + .../ILD_common_FCCee/FCCdefs_common.xml | 109 ++++ .../ILD_common_FCCee/SEcal06_siw_ECRing.xml | 83 +++ .../compact/ILD_common_FCCee/basic_defs.xml | 44 ++ .../ILD_common_FCCee/envelope_defs.xml | 97 ++++ FCCee/ILD_FCCee/compact/ILD_common_v02 | 1 + FCCee/ILD_FCCee/compact/README.md | 33 ++ ILD/compact/ILD_common_v02/BeamCal08.xml | 22 +- .../ILD_common_v02/Beampipe_o1_v01_01.xml | 9 +- .../ILD_common_v02/EcalBarrelFace_v00.xml | 2 +- .../ILD_common_v02/EcalEndcapFace_v00.xml | 2 +- .../ILD_common_v02/Hcal_Barrel_SD_v01.xml | 34 +- .../ILD_common_v02/Hcal_Barrel_SD_v02.xml | 34 +- .../ILD_common_v02/Hcal_EndcapRing_SD_v01.xml | 34 +- .../ILD_common_v02/Hcal_Endcaps_SD_v01.xml | 34 +- .../ILD_common_v02/Hcal_Endcaps_SD_v02.xml | 34 +- .../Hcal_Endcaps_SD_v02_SMALL.xml | 34 +- ILD/compact/ILD_common_v02/LHCal.xml | 10 +- ILD/compact/ILD_common_v02/LHCal01.xml | 14 +- ILD/compact/ILD_common_v02/LumiCal.xml | 14 +- .../ILD_common_v02/SEcal05_siw_Barrel.xml | 92 +-- .../ILD_common_v02/SEcal05_siw_ECRing.xml | 92 +-- .../ILD_common_v02/SEcal05_siw_Endcaps.xml | 92 +-- .../ILD_common_v02/SEcal06_hybrid_Barrel.xml | 68 +-- .../ILD_common_v02/SEcal06_hybrid_Endcaps.xml | 68 +-- .../ILD_common_v02/SHcalSc04_Barrel_v01.xml | 14 +- .../ILD_common_v02/SHcalSc04_Barrel_v04.xml | 16 +- .../ILD_common_v02/SHcalSc04_EndcapRing.xml | 12 +- .../SHcalSc04_EndcapRing_v01.xml | 16 +- .../SHcalSc04_Endcaps_LARGE.xml | 10 +- .../SHcalSc04_Endcaps_SMALL.xml | 10 +- .../SHcalSc04_Endcaps_v01_LARGE.xml | 14 +- .../SHcalSc04_Endcaps_v01_SMALL.xml | 14 +- ILD/compact/ILD_common_v02/SServices00.xml | 2 +- ILD/compact/ILD_common_v02/SServices01.xml | 2 +- ILD/compact/ILD_common_v02/Yoke05_Barrel.xml | 12 +- ILD/compact/ILD_common_v02/Yoke05_Endcaps.xml | 10 +- ILD/compact/ILD_common_v02/Yoke06_Endcaps.xml | 10 +- ILD/compact/ILD_common_v02/display.xml | 68 ++- .../ftd_simple_staggered_02.xml | 2 +- ILD/compact/ILD_common_v02/hcal_defs.xml | 18 - .../ILD_common_v02/top_defs_ILD_l5_v02.xml | 1 + .../ILD_common_v02/top_defs_ILD_s5_v02.xml | 1 + .../ILD_common_v02/top_defs_common_v02.xml | 1 - ILD/compact/ILD_common_v02/tpc10_01.xml | 2 +- ILD/compact/ILD_common_v02/vxd07.xml | 2 +- .../ILD_l2_v02/top_defs_ILD_l2_v02.xml | 1 + .../ILD_l4_v02/top_defs_ILD_l4_v02.xml | 3 +- .../ILD_l5_v10/top_defs_ILD_l5_v10.xml | 3 +- .../ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml | 2 +- .../ILD_l5_v11/top_defs_ILD_l5_v11.xml | 3 +- .../ILD_l6_v02/top_defs_ILD_l6_v02.xml | 1 + .../ILD_s1_v02/top_defs_ILD_s1_v02.xml | 1 + .../ILD_s2_v02/top_defs_ILD_s2_v02.xml | 1 + .../ILD_s4_v02/top_defs_ILD_s4_v02.xml | 1 + .../ILD_s6_v02/top_defs_ILD_s6_v02.xml | 1 + ILD/compact/README.md | 12 +- test/CMakeLists.txt | 10 + 64 files changed, 1792 insertions(+), 475 deletions(-) create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01_defs.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v01/InnerTrackerILD_o1_v02_00.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v01/top_defs_ILD_FCCee_v01.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02_defs.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_FCCee_v02/top_defs_ILD_FCCee_v02.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_common_FCCee/FCCdefs_common.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_common_FCCee/SEcal06_siw_ECRing.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_common_FCCee/basic_defs.xml create mode 100644 FCCee/ILD_FCCee/compact/ILD_common_FCCee/envelope_defs.xml create mode 120000 FCCee/ILD_FCCee/compact/ILD_common_v02 create mode 100644 FCCee/ILD_FCCee/compact/README.md diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml new file mode 100644 index 000000000..0c159e67b --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml @@ -0,0 +1,177 @@ + + + experimental ILD simulation model for FCCee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01_defs.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01_defs.xml new file mode 100644 index 000000000..e0444bacd --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01_defs.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/InnerTrackerILD_o1_v02_00.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/InnerTrackerILD_o1_v02_00.xml new file mode 100644 index 000000000..bd8121151 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/InnerTrackerILD_o1_v02_00.xml @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tracking detectors + + + + + + + + + + + + + + + + + Inner Tracker Assembly + + + + + + + + + + + + + + + + + + + + + ${GlobalTrackerReadoutID} + + + ${GlobalTrackerReadoutID} + + + + + + + + + + Silicon Inner Tracker Barrel + + + + + + + + + + + + + + + + + + + + + + + + + Silicon Inner Tracker Endcaps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3.5959*cm = X0 for Carbon fibre + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + The next section is the cable for the vertex + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/top_defs_ILD_FCCee_v01.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/top_defs_ILD_FCCee_v01.xml new file mode 100644 index 000000000..c21e861a1 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/top_defs_ILD_FCCee_v01.xml @@ -0,0 +1,12 @@ + + + +all hardcoded overall dimensions which differ between large and small models + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml new file mode 100644 index 000000000..7c3cf258e --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml @@ -0,0 +1,176 @@ + + + experimental ILD simulation model for FCCee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02_defs.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02_defs.xml new file mode 100644 index 000000000..f6d289f93 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02_defs.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/top_defs_ILD_FCCee_v02.xml b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/top_defs_ILD_FCCee_v02.xml new file mode 100644 index 000000000..255446701 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/top_defs_ILD_FCCee_v02.xml @@ -0,0 +1,12 @@ + + + +all hardcoded overall dimensions which differ between large and small models + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_common_FCCee/FCCdefs_common.xml b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/FCCdefs_common.xml new file mode 100644 index 000000000..f1685c739 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/FCCdefs_common.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_common_FCCee/SEcal06_siw_ECRing.xml b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/SEcal06_siw_ECRing.xml new file mode 100644 index 000000000..58ccb80df --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/SEcal06_siw_ECRing.xml @@ -0,0 +1,83 @@ + + + + + EM Calorimeter Endcap plugs for FCCee, has phi symmetry unlike at ILC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:5,module:3,stave:4,tower:3,layer:6,x:32:-16,y:-16 + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_common_FCCee/basic_defs.xml b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/basic_defs.xml new file mode 100644 index 000000000..917010c7e --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/basic_defs.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_common_FCCee/envelope_defs.xml b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/envelope_defs.xml new file mode 100644 index 000000000..af833077d --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_common_FCCee/envelope_defs.xml @@ -0,0 +1,97 @@ + + + + + + suggested naming convention: + + main parameters: + + DET_inner_radius : inner radius of tube like envelope ( inscribed cylinder ) + DET_outer_radius : outer radius of tube like envelope ( inscribed cylinder ) + DET_half_length : half length along z axis + DET_min_z : smallest absolute value on z-axis + DET_max_z : largest absolute value on z-axis + DET_inner_symmetry : number of sides on the inside ( 0 for tube ) + DET_outer_symmetry : number of sides on the inside ( 0 for tube ) + DET_inner_phi0 : optional rotation of the inner polygon ( in r-phi plane ) + DET_outer_phi0 : optional rotation of the outer polygon ( in r-phi plane ) + + additional parameters for cutting away volumes/shapes use one of the above with a number + appended and/or an extra specifiaction such as cone ( for a cut away cone ) + + DET_inner_radius_1 + DET_outer_radius_2 + DET_cone_min_z + DET_cone_max_z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ILD_FCCee/compact/ILD_common_v02 b/FCCee/ILD_FCCee/compact/ILD_common_v02 new file mode 120000 index 000000000..da51bb822 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/ILD_common_v02 @@ -0,0 +1 @@ +../../../ILD/compact/ILD_common_v02 \ No newline at end of file diff --git a/FCCee/ILD_FCCee/compact/README.md b/FCCee/ILD_FCCee/compact/README.md new file mode 100644 index 000000000..4e71fd7b8 --- /dev/null +++ b/FCCee/ILD_FCCee/compact/README.md @@ -0,0 +1,33 @@ +ILD models under FCCee/ILD_FCCee + +These are based on the ILC-specific models located under ILD/compact + +########################## +# ILD_FCCee_v01 +# +# D.Jeans, V.Schwan, Sep 2024 +########################## + +- experimental version of ILD for FCCee +- based on ILD_l5_v02 +- vertex detector and lumiCal copied from CLD_o2_v07 +- inner silicon tracker adapted from CLD_o2_v07 +- TPC inner radius slightly larger than ILD_l5_v02 model (329 -> 365 mm) to keep 150 mrad cone clear for MDI +- MDI taken from FCCee common MDI design +- ECal ring removed +- other subdetectors same as ILD_l5_v02 + +########################## +# ILD_FCCee_v02 +# +# V.Schwan, D.Jeans, Sep 2024 +########################## + +- experimental version of ILD for FCCee +- based on ILD_l5_v02 +- vertex detector, inner silicon tracker, lumiCal copied from CLD_o2_v07 +- TPC inner radius enlarged compared to ILD_l5_v02 model (329 -> 701 mm) to keep 5 mm safety distance from the outer radius of the inner tracker (696 mm) +- MDI taken from FCCee common MDI design +- ECal ring removed +- other subdetectors same as ILD_l5_v02 + diff --git a/ILD/compact/ILD_common_v02/BeamCal08.xml b/ILD/compact/ILD_common_v02/BeamCal08.xml index 9563e85c0..60b5d63c6 100644 --- a/ILD/compact/ILD_common_v02/BeamCal08.xml +++ b/ILD/compact/ILD_common_v02/BeamCal08.xml @@ -5,7 +5,7 @@ - @@ -97,20 +97,20 @@ - + - - - - + + + + - - - - - + + + + + diff --git a/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml b/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml index 217e2e575..c5048af59 100644 --- a/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml +++ b/ILD/compact/ILD_common_v02/Beampipe_o1_v01_01.xml @@ -1,6 +1,13 @@ - + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/EcalBarrelFace_v00.xml b/ILD/compact/ILD_common_v02/EcalBarrelFace_v00.xml index 99524c9b4..bc4a54957 100644 --- a/ILD/compact/ILD_common_v02/EcalBarrelFace_v00.xml +++ b/ILD/compact/ILD_common_v02/EcalBarrelFace_v00.xml @@ -1,4 +1,4 @@ - + Surfaces at the face of the Ecal Barrel diff --git a/ILD/compact/ILD_common_v02/EcalEndcapFace_v00.xml b/ILD/compact/ILD_common_v02/EcalEndcapFace_v00.xml index f70a6ad44..a9d7a2c26 100644 --- a/ILD/compact/ILD_common_v02/EcalEndcapFace_v00.xml +++ b/ILD/compact/ILD_common_v02/EcalEndcapFace_v00.xml @@ -1,4 +1,4 @@ - + Surfaces at the face of the Ecal Endcap diff --git a/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v01.xml b/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v01.xml index bfee3f1b9..d8a864ab1 100644 --- a/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v01.xml +++ b/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v01.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter Barrel @@ -14,25 +14,25 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v02.xml b/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v02.xml index 057aa4813..af7f1d9e3 100644 --- a/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v02.xml +++ b/ILD/compact/ILD_common_v02/Hcal_Barrel_SD_v02.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter Barrel @@ -14,25 +14,25 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/Hcal_EndcapRing_SD_v01.xml b/ILD/compact/ILD_common_v02/Hcal_EndcapRing_SD_v01.xml index ee89545a0..465ae9823 100644 --- a/ILD/compact/ILD_common_v02/Hcal_EndcapRing_SD_v01.xml +++ b/ILD/compact/ILD_common_v02/Hcal_EndcapRing_SD_v01.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter EndcapRing @@ -23,24 +23,24 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v01.xml b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v01.xml index 3b77b0fa6..b69218bff 100644 --- a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v01.xml +++ b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v01.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter Endcap @@ -19,25 +19,25 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02.xml b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02.xml index 8e245aa2b..78c6c422c 100644 --- a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02.xml +++ b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Endcap @@ -18,7 +18,7 @@ - + @@ -33,21 +33,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02_SMALL.xml b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02_SMALL.xml index 9c07b0837..e1f98f049 100644 --- a/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02_SMALL.xml +++ b/ILD/compact/ILD_common_v02/Hcal_Endcaps_SD_v02_SMALL.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Endcap @@ -18,7 +18,7 @@ - + @@ -32,21 +32,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/LHCal.xml b/ILD/compact/ILD_common_v02/LHCal.xml index 0577c1a4e..99caa932a 100644 --- a/ILD/compact/ILD_common_v02/LHCal.xml +++ b/ILD/compact/ILD_common_v02/LHCal.xml @@ -2,7 +2,7 @@ LHCal parameters for ILD --> - @@ -35,11 +35,11 @@ /> - - + + - - + + diff --git a/ILD/compact/ILD_common_v02/LHCal01.xml b/ILD/compact/ILD_common_v02/LHCal01.xml index 078cae14c..c4d257d8d 100644 --- a/ILD/compact/ILD_common_v02/LHCal01.xml +++ b/ILD/compact/ILD_common_v02/LHCal01.xml @@ -3,7 +3,7 @@ --> - @@ -32,12 +32,12 @@ /> - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/LumiCal.xml b/ILD/compact/ILD_common_v02/LumiCal.xml index db288e4c0..42fbaad1b 100644 --- a/ILD/compact/ILD_common_v02/LumiCal.xml +++ b/ILD/compact/ILD_common_v02/LumiCal.xml @@ -5,7 +5,7 @@ - @@ -61,12 +61,12 @@ r_gap = "Lcal_tile_gap" /> - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/SEcal05_siw_Barrel.xml b/ILD/compact/ILD_common_v02/SEcal05_siw_Barrel.xml index 1661c9884..6c6443fdf 100644 --- a/ILD/compact/ILD_common_v02/SEcal05_siw_Barrel.xml +++ b/ILD/compact/ILD_common_v02/SEcal05_siw_Barrel.xml @@ -1,7 +1,7 @@ - + EM Calorimeter Barrel @@ -15,56 +15,56 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/SEcal05_siw_ECRing.xml b/ILD/compact/ILD_common_v02/SEcal05_siw_ECRing.xml index a4b960610..3aca70fb0 100644 --- a/ILD/compact/ILD_common_v02/SEcal05_siw_ECRing.xml +++ b/ILD/compact/ILD_common_v02/SEcal05_siw_ECRing.xml @@ -1,7 +1,7 @@ - + EM Calorimeter Endcaps @@ -22,53 +22,53 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/SEcal05_siw_Endcaps.xml b/ILD/compact/ILD_common_v02/SEcal05_siw_Endcaps.xml index 75556c83b..423a1a56e 100644 --- a/ILD/compact/ILD_common_v02/SEcal05_siw_Endcaps.xml +++ b/ILD/compact/ILD_common_v02/SEcal05_siw_Endcaps.xml @@ -1,7 +1,7 @@ - + EM Calorimeter Endcaps @@ -21,54 +21,54 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/SEcal06_hybrid_Barrel.xml b/ILD/compact/ILD_common_v02/SEcal06_hybrid_Barrel.xml index 084f7ea99..457246d86 100644 --- a/ILD/compact/ILD_common_v02/SEcal06_hybrid_Barrel.xml +++ b/ILD/compact/ILD_common_v02/SEcal06_hybrid_Barrel.xml @@ -7,7 +7,7 @@ - EM Calorimeter Barrel @@ -22,46 +22,46 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/SEcal06_hybrid_Endcaps.xml b/ILD/compact/ILD_common_v02/SEcal06_hybrid_Endcaps.xml index c0760b162..9747acbc1 100644 --- a/ILD/compact/ILD_common_v02/SEcal06_hybrid_Endcaps.xml +++ b/ILD/compact/ILD_common_v02/SEcal06_hybrid_Endcaps.xml @@ -5,7 +5,7 @@ - EM Calorimeter Endcaps @@ -26,45 +26,45 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v01.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v01.xml index de0471ba0..5752ae0df 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v01.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v01.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Barrel @@ -16,15 +16,15 @@ - + - - - - - + + + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v04.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v04.xml index fb79b33d4..5d1fd3e59 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v04.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Barrel_v04.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Barrel @@ -16,18 +16,18 @@ - + - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing.xml b/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing.xml index 74d18b867..453f4c291 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter EndcapRing @@ -23,17 +23,17 @@ - + - + - - - + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing_v01.xml b/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing_v01.xml index 299a0d427..f369579db 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing_v01.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_EndcapRing_v01.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter EndcapRing @@ -23,17 +23,17 @@ - + - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_LARGE.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_LARGE.xml index 57a6d813e..05541e999 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_LARGE.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_LARGE.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Endcap @@ -42,11 +42,11 @@ - + - - - + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_SMALL.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_SMALL.xml index f8c937cad..85c57a502 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_SMALL.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_SMALL.xml @@ -2,7 +2,7 @@ - + Hadron Calorimeter Endcap @@ -41,11 +41,11 @@ - + - - - + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_LARGE.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_LARGE.xml index 2c1a15293..5679e7a1d 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_LARGE.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_LARGE.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter Endcap @@ -42,12 +42,12 @@ - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_SMALL.xml b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_SMALL.xml index 001451c01..1391dd7b0 100644 --- a/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_SMALL.xml +++ b/ILD/compact/ILD_common_v02/SHcalSc04_Endcaps_v01_SMALL.xml @@ -1,7 +1,7 @@ - + Hadron Calorimeter Endcap @@ -40,12 +40,12 @@ - - - - - - + + + + + + diff --git a/ILD/compact/ILD_common_v02/SServices00.xml b/ILD/compact/ILD_common_v02/SServices00.xml index d34161c48..2f2a7fa1d 100644 --- a/ILD/compact/ILD_common_v02/SServices00.xml +++ b/ILD/compact/ILD_common_v02/SServices00.xml @@ -4,7 +4,7 @@ - + diff --git a/ILD/compact/ILD_common_v02/SServices01.xml b/ILD/compact/ILD_common_v02/SServices01.xml index 932a106b0..38e3544d5 100644 --- a/ILD/compact/ILD_common_v02/SServices01.xml +++ b/ILD/compact/ILD_common_v02/SServices01.xml @@ -5,7 +5,7 @@ - + diff --git a/ILD/compact/ILD_common_v02/Yoke05_Barrel.xml b/ILD/compact/ILD_common_v02/Yoke05_Barrel.xml index 00c8d2642..193091704 100644 --- a/ILD/compact/ILD_common_v02/Yoke05_Barrel.xml +++ b/ILD/compact/ILD_common_v02/Yoke05_Barrel.xml @@ -1,7 +1,7 @@ - + - - - - - + + + + + diff --git a/ILD/compact/ILD_common_v02/Yoke05_Endcaps.xml b/ILD/compact/ILD_common_v02/Yoke05_Endcaps.xml index 6115d54d8..f575ffb02 100644 --- a/ILD/compact/ILD_common_v02/Yoke05_Endcaps.xml +++ b/ILD/compact/ILD_common_v02/Yoke05_Endcaps.xml @@ -1,7 +1,7 @@ - + @@ -26,10 +26,10 @@ - - - - + + + + diff --git a/ILD/compact/ILD_common_v02/Yoke06_Endcaps.xml b/ILD/compact/ILD_common_v02/Yoke06_Endcaps.xml index e704a3577..0857dcb7a 100644 --- a/ILD/compact/ILD_common_v02/Yoke06_Endcaps.xml +++ b/ILD/compact/ILD_common_v02/Yoke06_Endcaps.xml @@ -1,7 +1,7 @@ - + @@ -34,10 +34,10 @@ - - - - + + + + diff --git a/ILD/compact/ILD_common_v02/display.xml b/ILD/compact/ILD_common_v02/display.xml index edce85779..e96c56df3 100644 --- a/ILD/compact/ILD_common_v02/display.xml +++ b/ILD/compact/ILD_common_v02/display.xml @@ -1,41 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILD/compact/ILD_common_v02/ftd_simple_staggered_02.xml b/ILD/compact/ILD_common_v02/ftd_simple_staggered_02.xml index 5290ca829..9b2e9efb9 100644 --- a/ILD/compact/ILD_common_v02/ftd_simple_staggered_02.xml +++ b/ILD/compact/ILD_common_v02/ftd_simple_staggered_02.xml @@ -7,7 +7,7 @@ - + diff --git a/ILD/compact/ILD_common_v02/hcal_defs.xml b/ILD/compact/ILD_common_v02/hcal_defs.xml index d54e67902..736f2649b 100644 --- a/ILD/compact/ILD_common_v02/hcal_defs.xml +++ b/ILD/compact/ILD_common_v02/hcal_defs.xml @@ -19,11 +19,6 @@ - @@ -65,21 +60,8 @@ - - - - - - - - - - - - - diff --git a/ILD/compact/ILD_common_v02/top_defs_ILD_l5_v02.xml b/ILD/compact/ILD_common_v02/top_defs_ILD_l5_v02.xml index e670b598d..61684ef22 100644 --- a/ILD/compact/ILD_common_v02/top_defs_ILD_l5_v02.xml +++ b/ILD/compact/ILD_common_v02/top_defs_ILD_l5_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_common_v02/top_defs_ILD_s5_v02.xml b/ILD/compact/ILD_common_v02/top_defs_ILD_s5_v02.xml index a5b044905..5144058d3 100644 --- a/ILD/compact/ILD_common_v02/top_defs_ILD_s5_v02.xml +++ b/ILD/compact/ILD_common_v02/top_defs_ILD_s5_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_common_v02/top_defs_common_v02.xml b/ILD/compact/ILD_common_v02/top_defs_common_v02.xml index 6a3145588..b377376fb 100644 --- a/ILD/compact/ILD_common_v02/top_defs_common_v02.xml +++ b/ILD/compact/ILD_common_v02/top_defs_common_v02.xml @@ -38,7 +38,6 @@ - diff --git a/ILD/compact/ILD_common_v02/tpc10_01.xml b/ILD/compact/ILD_common_v02/tpc10_01.xml index eb46b3b73..d27607b75 100644 --- a/ILD/compact/ILD_common_v02/tpc10_01.xml +++ b/ILD/compact/ILD_common_v02/tpc10_01.xml @@ -6,7 +6,7 @@ - + diff --git a/ILD/compact/ILD_common_v02/vxd07.xml b/ILD/compact/ILD_common_v02/vxd07.xml index ad32df1c8..8be4e2f24 100644 --- a/ILD/compact/ILD_common_v02/vxd07.xml +++ b/ILD/compact/ILD_common_v02/vxd07.xml @@ -5,7 +5,7 @@ - + diff --git a/ILD/compact/ILD_l2_v02/top_defs_ILD_l2_v02.xml b/ILD/compact/ILD_l2_v02/top_defs_ILD_l2_v02.xml index e670b598d..61684ef22 100644 --- a/ILD/compact/ILD_l2_v02/top_defs_ILD_l2_v02.xml +++ b/ILD/compact/ILD_l2_v02/top_defs_ILD_l2_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_l4_v02/top_defs_ILD_l4_v02.xml b/ILD/compact/ILD_l4_v02/top_defs_ILD_l4_v02.xml index e670b598d..d95419012 100644 --- a/ILD/compact/ILD_l4_v02/top_defs_ILD_l4_v02.xml +++ b/ILD/compact/ILD_l4_v02/top_defs_ILD_l4_v02.xml @@ -1,10 +1,11 @@ -all hardcoded overall dimensions which differ between large and small models +all hardcoded overall dimensions specific to this model (ie which differ between models) + diff --git a/ILD/compact/ILD_l5_v10/top_defs_ILD_l5_v10.xml b/ILD/compact/ILD_l5_v10/top_defs_ILD_l5_v10.xml index e670b598d..130f776a3 100644 --- a/ILD/compact/ILD_l5_v10/top_defs_ILD_l5_v10.xml +++ b/ILD/compact/ILD_l5_v10/top_defs_ILD_l5_v10.xml @@ -1,10 +1,11 @@ -all hardcoded overall dimensions which differ between large and small models +hardcoded overall dimensions specific to this model ILD_l5_v10 (ie not common to all/many models) + diff --git a/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml b/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml index 8f1df743f..78b6d384c 100644 --- a/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml +++ b/ILD/compact/ILD_l5_v11/InnerTrackerILD_o1_v01_00.xml @@ -122,7 +122,7 @@ adapted by DJeans to fit into ILD model at FCCee - + diff --git a/ILD/compact/ILD_l5_v11/top_defs_ILD_l5_v11.xml b/ILD/compact/ILD_l5_v11/top_defs_ILD_l5_v11.xml index f5996bdea..7bb940e21 100644 --- a/ILD/compact/ILD_l5_v11/top_defs_ILD_l5_v11.xml +++ b/ILD/compact/ILD_l5_v11/top_defs_ILD_l5_v11.xml @@ -1,9 +1,10 @@ -all hardcoded overall dimensions which differ between large and small models +hardcoded overall dimensions specific to this model ILD_l5_v11 (ie not common to all/many models) + diff --git a/ILD/compact/ILD_l6_v02/top_defs_ILD_l6_v02.xml b/ILD/compact/ILD_l6_v02/top_defs_ILD_l6_v02.xml index e670b598d..61684ef22 100644 --- a/ILD/compact/ILD_l6_v02/top_defs_ILD_l6_v02.xml +++ b/ILD/compact/ILD_l6_v02/top_defs_ILD_l6_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_s1_v02/top_defs_ILD_s1_v02.xml b/ILD/compact/ILD_s1_v02/top_defs_ILD_s1_v02.xml index a5b044905..5144058d3 100644 --- a/ILD/compact/ILD_s1_v02/top_defs_ILD_s1_v02.xml +++ b/ILD/compact/ILD_s1_v02/top_defs_ILD_s1_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_s2_v02/top_defs_ILD_s2_v02.xml b/ILD/compact/ILD_s2_v02/top_defs_ILD_s2_v02.xml index a5b044905..5144058d3 100644 --- a/ILD/compact/ILD_s2_v02/top_defs_ILD_s2_v02.xml +++ b/ILD/compact/ILD_s2_v02/top_defs_ILD_s2_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_s4_v02/top_defs_ILD_s4_v02.xml b/ILD/compact/ILD_s4_v02/top_defs_ILD_s4_v02.xml index a5b044905..5144058d3 100644 --- a/ILD/compact/ILD_s4_v02/top_defs_ILD_s4_v02.xml +++ b/ILD/compact/ILD_s4_v02/top_defs_ILD_s4_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/ILD_s6_v02/top_defs_ILD_s6_v02.xml b/ILD/compact/ILD_s6_v02/top_defs_ILD_s6_v02.xml index a5b044905..5144058d3 100644 --- a/ILD/compact/ILD_s6_v02/top_defs_ILD_s6_v02.xml +++ b/ILD/compact/ILD_s6_v02/top_defs_ILD_s6_v02.xml @@ -5,6 +5,7 @@ all hardcoded overall dimensions which differ between large and small models + diff --git a/ILD/compact/README.md b/ILD/compact/README.md index c1c1dac47..d7df9e1e2 100644 --- a/ILD/compact/README.md +++ b/ILD/compact/README.md @@ -5,6 +5,7 @@ The following ILD detector models are available in lcgeo ( current production mo + | Model | Description | Hcal | Ecal | geometry | Status | | ------------- | ---------------------------|--------|---------|----------|-------------------| | ILD_l5_v02 | large simulation model | hybrid | hybrid | Tesla | validated | @@ -40,9 +41,18 @@ The following ILD detector models are available in lcgeo ( current production mo ## Details +### ILD_FCCee_v01 +ILD model for the FCCee with large TPC. +This model definition can be found under [FCCee/ILD_FCCee/compact/ILD_FCCee_v01](../../FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml) + +### ILD_FCCee_v02 +ILD model for the FCCee with the CLD InnerTracker and a correspondingly shrunk TPC. +This model definition can be found under [FCCee/ILD_FCCee/compact/ILD_FCCee_v02](../../FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml) + ### ILD_l5_v11 -same detector geometry as ILD_l5_v02 model, but with FCCee MDI and CLD-inspired silicon inner tracker & VTX in place of original ILD's VTX, SIT, FTD. +TEST DEVELOPMENT model: same detector geometry as ILD_l5_v02 model, but with FCCee MDI and CLD-inspired silicon inner tracker & VTX in place of original ILD's VTX, SIT, FTD. BeamCal, LHCAL removed. +**We recommend that you use an ILD model under FCCee/ILD_FCCee/ instead. Model ILD_FCCee_v01 is rather similar to ILD_l5_v11.** ### ILD_l5_v10 same detector geometry as ILD_l5_v02 model, but with CLD-inspired silicon inner tracker/VTX in place of original VTX, SIT, FTD diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 91c3febaa..0b0203867 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,16 @@ ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../ILD/compact/ILD_l5_v11/ILD_l5_v11.xml --runType=batch -G -N=1 --outputFile=testILD_l5_v11.slcio ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) +SET( test_name "test_ILD_FCCee_v01" ) +ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml --runType=batch -G -N=1 --outputFile=testILD_FCCee_v01.slcio ) +SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) + +SET( test_name "test_ILD_FCCee_v02" ) +ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml --runType=batch -G -N=1 --outputFile=testILD_FCCee_v02.slcio ) +SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) + #-------------------------------------------------- # tests for SiD SET( test_name "test_SiD_o2_v03" ) From 60243ef547ddb21bff38e280637738ebf8f01abe Mon Sep 17 00:00:00 2001 From: tmadlener Date: Wed, 9 Oct 2024 17:37:52 +0200 Subject: [PATCH 069/133] Fix the CI badge and add a zenodo badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 35ea2bd61..63ae75b57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # lcgeo (Lepton Collider Geometry) -[![Build](https://github.com/iLCSoft/lcgeo/actions/workflows/linux.yml/badge.svg)](https://github.com/iLCSoft/lcgeo/actions/workflows/linux.yml) +[![DOI](https://zenodo.org/badge/60772160.svg)](https://doi.org/10.5281/zenodo.596333) +[![Key4hep build](https://github.com/key4hep/k4geo/actions/workflows/key4hep-build.yaml/badge.svg)](https://github.com/key4hep/k4geo/actions/workflows/key4hep-build.yaml) [![Coverity Scan Build Status](https://scan.coverity.com/projects/12359/badge.svg)](https://scan.coverity.com/projects/ilcsoft-lcgeo) Implementation of Lepton Collider detector models in DD4hep. From 1f414da263a8b7c15f3dcbbc2ea278d5a84a6e8b Mon Sep 17 00:00:00 2001 From: Victor Schwan <162138084+Victor-Schwan@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:10:09 +0200 Subject: [PATCH 070/133] Configurability for material plots (#392) * format material_(plots/scan)_2D.py * refactorization, parseArgs added to material_scan_2D.py, thetaRad as angleDef option added to material_plots_2D.py * outsource creation of 2D hists to function * fix x0max user interface Co-authored-by: Thomas Madlener * Fix inputFile arg parsing * Remove leftover conflict markers * Complete switch back to x0max * Remove stray conflict marker remnants * bug fix and switch to os.smth to ease searching for usage * make create_histogram function more reusable --------- Co-authored-by: Thomas Madlener --- utils/material_plots_2D.py | 107 +++++++++++++++++++++---------------- utils/material_scan_2D.py | 51 ++++++++++++++++-- 2 files changed, 108 insertions(+), 50 deletions(-) diff --git a/utils/material_plots_2D.py b/utils/material_plots_2D.py index d67758cf0..e6ed7e3de 100644 --- a/utils/material_plots_2D.py +++ b/utils/material_plots_2D.py @@ -1,17 +1,47 @@ +""" +This script must be called with python: 'python material_scan_2D.py --{argument} {value}'. +The output files are saved in data/{outputDir}/name.suffix. +If no outputDir is specified, it will be data/plots/name.suffix. +""" + from __future__ import print_function + import argparse import math - -import sys, os +import os +import sys +from pathlib import Path sys.path.append(os.path.expandvars("$FCCSW") + "/Examples/scripts") from plotstyle import FCCStyle import ROOT +def create_histogram( + name_and_title: str, + angle_min: float, + angle_max: float, + angle_binning: float, + n_phi_bins: int, +) -> ROOT.TH2F: + num_bins = int((angle_max - angle_min) / angle_binning) + return ROOT.TH2F( + name_and_title, + name_and_title, + num_bins, + angle_min, + angle_max, + n_phi_bins, + -math.pi, + math.pi, + ) + + def main(): parser = argparse.ArgumentParser(description="Material Plotter") - parser.add_argument("--fname", "-f", dest="fname", type=str, help="name of file to read") + parser.add_argument( + "--inputFile", "--fname", "-f", type=str, help="relative path to the input file" + ) parser.add_argument( "--angleMin", dest="angleMin", default=6, type=float, help="minimum eta/theta/cosTheta" ) @@ -20,23 +50,27 @@ def main(): ) parser.add_argument( "--angleDef", - dest="angleDef", default="eta", + choices=["eta", "theta", "cosTheta", "thetaRad"], type=str, - help="angle definition to use: eta, theta or cosTheta, default: eta", + help="Angle definition to use: eta, theta, thetaRad or cosTheta; default: eta", ) parser.add_argument( "--angleBinning", "-b", - dest="angleBinning", default=0.05, type=float, - help="eta/theta/cosTheta bin width", + help="Eta/theta/cosTheta bin width", ) + parser.add_argument("--nPhiBins", default=100, type=int, help="Number of bins in phi") + parser.add_argument("--x0max", "-x", default=0.0, type=float, help="Max of x0") parser.add_argument( - "--nPhiBins", dest="nPhiBins", default=100, type=int, help="number of bins in phi" + "--outputDir", + "-o", + type=str, + default="plots", + help="Directory to store output files in", ) - parser.add_argument("--x0max", "-x", dest="x0max", default=0.0, type=float, help="Max of x0") parser.add_argument( "--ignoreMats", "-i", @@ -45,45 +79,25 @@ def main(): default=[], help="List of materials that should be ignored", ) + args = parser.parse_args() + output_dir = Path("data") / args.outputDir + output_dir.mkdir(parents=True, exist_ok=True) # Create the directory if it doesn't exist + ROOT.gStyle.SetNumberContours(100) - f = ROOT.TFile.Open(args.fname, "read") + f = ROOT.TFile.Open(os.fspath(Path(args.inputFile).with_suffix(".root")), "read") tree = f.Get("materials") - histDict = {} ROOT.gROOT.SetBatch(1) - h_x0 = ROOT.TH2F( - "h_x0", - "h_x0", - int((args.angleMax - args.angleMin) / args.angleBinning), - args.angleMin, - args.angleMax, - args.nPhiBins, - -math.pi, - math.pi, + h_x0 = create_histogram("h_x0", args.angleMin, args.angleMax, args.angleBinning, args.nPhiBins) + h_lambda = create_histogram( + "h_lambda", args.angleMin, args.angleMax, args.angleBinning, args.nPhiBins ) - h_lambda = ROOT.TH2F( - "h_lambda", - "h_lambda", - int((args.angleMax - args.angleMin) / args.angleBinning), - args.angleMin, - args.angleMax, - args.nPhiBins, - -math.pi, - math.pi, - ) - h_depth = ROOT.TH2F( - "h_depth", - "h_depth", - int((args.angleMax - args.angleMin) / args.angleBinning), - args.angleMin, - args.angleMax, - args.nPhiBins, - -math.pi, - math.pi, + h_depth = create_histogram( + "h_depth", args.angleMin, args.angleMax, args.angleBinning, args.nPhiBins ) for angleBinning, entry in enumerate(tree): @@ -103,11 +117,11 @@ def main(): h_lambda.Fill(tree.angle, tree.phi, entry_lambda) h_depth.Fill(tree.angle, tree.phi, entry_depth) - # go through the + # go through the plots plots = ["x0", "lambda", "depth"] histograms = [h_x0, h_lambda, h_depth] axis_titles = ["Material budget x/X_{0} [%]", "Number of #lambda", "Material depth [cm]"] - for i in range(len(plots)): + for i, plot in enumerate(plots): cv = ROOT.TCanvas("", "", 800, 600) cv.SetRightMargin(0.18) histograms[i].Draw("COLZ") @@ -116,6 +130,8 @@ def main(): title = "#eta" elif args.angleDef == "theta": title = "#theta [#circ]" + elif args.angleDef == "thetaRad": + title = "#theta [rad]" elif args.angleDef == "cosTheta": title = "cos(#theta)" histograms[i].GetXaxis().SetTitle(title) @@ -123,15 +139,16 @@ def main(): histograms[i].GetZaxis().SetTitle(axis_titles[i]) - if args.x0max != 0.0 and plots[i] == "x0": + if args.x0max != 0.0 and plot == "x0": histograms[i].SetMaximum(args.x0max) histograms[i].GetXaxis().SetRangeUser(args.angleMin, args.angleMax) ROOT.gStyle.SetPadRightMargin(0.5) - cv.Print(plots[i] + ".pdf") - cv.Print(plots[i] + ".png") - cv.SaveAs(plots[i] + ".root") + output_path = output_dir / plot + cv.Print(os.fspath(output_path.with_suffix(".pdf"))) + cv.Print(os.fspath(output_path.with_suffix(".png"))) + cv.SaveAs(os.fspath(output_path.with_suffix(".root"))) if __name__ == "__main__": diff --git a/utils/material_scan_2D.py b/utils/material_scan_2D.py index ab6ee21eb..c59a9b757 100644 --- a/utils/material_scan_2D.py +++ b/utils/material_scan_2D.py @@ -1,7 +1,15 @@ -import os -from Gaudi.Configuration import * +""" +This script must be called with k4run: 'k4run material_scan_2D.py --{argument} {value}'. +The output files are saved in 'data/{outputDir}/{outputFileBase}.root'. +If no outputDir is specified, it will be 'data/{outputFileBase}.root'. +""" + +from os import environ, fspath +from pathlib import Path from Configurables import ApplicationMgr +from Gaudi.Configuration import * +from k4FWCore.parseArgs import parser ApplicationMgr().EvtSel = "None" ApplicationMgr().EvtMax = 1 @@ -10,9 +18,42 @@ # DD4hep geometry service from Configurables import GeoSvc +parser.add_argument( + "--compactFile", + help="Compact detector file to use", + type=str, + default=fspath( + Path(environ["k4geo_DIR"]) / "ILD" / "compact" / "ILD_sl5_v02" / "ILD_l5_v02.xml" + ), +) +parser.add_argument( + "--outputFileBase", + help="Base name of all the produced output files", + default="out_material_scan", +) +parser.add_argument( + "--angleDef", + help="angle definition to use: eta, theta, cosTheta or thetaRad, default: eta", + choices=["eta", "theta", "cosTheta", "thetaRad"], + default="eta", +) +parser.add_argument( + "--outputDir", + "-o", + type=str, + default="", + help="Directory to store the output file in", +) + +reco_args = parser.parse_known_args()[0] +compact_file = reco_args.compactFile +angle_def = reco_args.angleDef +output_dir = "data" / Path(reco_args.outputDir) +output_dir.mkdir(parents=True, exist_ok=True) # Create the directory if it doesn't exist + ## parse the given xml file geoservice = GeoSvc("GeoSvc") -geoservice.detectors = ["IDEA_o1_v02.xml"] +geoservice.detectors = [compact_file] geoservice.OutputLevel = INFO ApplicationMgr().ExtSvc += [geoservice] @@ -24,9 +65,9 @@ # For instance adding envelopeName="BoundaryPostCalorimetry" will perform the scan only till the end of calorimetry. # BoundaryPostCalorimetry is defined in Detector/DetFCChhECalInclined/compact/envelopePreCalo.xml materialservice = MaterialScan_2D_genericAngle("GeoDump") -materialservice.filename = "out_material_scan.root" +materialservice.filename = fspath(output_dir / Path(reco_args.outputFileBase).with_suffix(".root")) -materialservice.angleDef = "eta" # eta, theta, cosTheta or thetaRad +materialservice.angleDef = angle_def # eta, theta, cosTheta or thetaRad materialservice.angleBinning = 0.05 materialservice.angleMax = 3.0 materialservice.angleMin = -3.0 From 1558cdb73e364ff7554cda66888f454ea8f4cb15 Mon Sep 17 00:00:00 2001 From: Daniel Jeans Date: Fri, 25 Oct 2024 18:44:03 +0900 Subject: [PATCH 071/133] Fix some material definitions for ILD models (#404) * fix definition of G4_Au * adjust some material definitions to remove warnings (sum of fractions != 1.0) * add comment * adjust RPCGas definition (from G. Grenier) * adjust density of RPC gas --- ILD/compact/ILD_common_v02/materials.xml | 71 +++++++++++++++++------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/ILD/compact/ILD_common_v02/materials.xml b/ILD/compact/ILD_common_v02/materials.xml index 792f49a0f..726cdde45 100644 --- a/ILD/compact/ILD_common_v02/materials.xml +++ b/ILD/compact/ILD_common_v02/materials.xml @@ -434,6 +434,7 @@ + @@ -471,19 +472,45 @@ - materials for the SemiDigital Hadronic calorimeter - - - - - - - - + + materials for the SemiDigital Hadronic calorimeter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -509,22 +536,26 @@ + + + + + + + - - - - + + - - - - - - + + + + + From 3e94e497e9eb54f8c4d32d4fd238a096c9b3790e Mon Sep 17 00:00:00 2001 From: Giovanni Marchiori Date: Mon, 4 Nov 2024 14:52:42 +0100 Subject: [PATCH 072/133] make material in 1st layer of ECAL absorber configurable. Set by default to G10 rather than LAr. Also add more comments and fix some whitespaces --- .../ECalBarrel_thetamodulemerged.xml | 8 +- ...alBarrel_thetamodulemerged_calibration.xml | 8 +- .../ECalBarrel_thetamodulemerged_upstream.xml | 8 +- ...leLiquid_InclinedTrapezoids_o1_v03_geo.cpp | 390 +++++++++++------- 4 files changed, 242 insertions(+), 172 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml index 5b7dc11fa..1bf3b73e3 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml @@ -126,11 +126,11 @@ - - + + - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml index c8c79f253..a6101643e 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml @@ -118,11 +118,11 @@ - - + + - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml index b4e05e073..6e79b4aba 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml @@ -118,11 +118,11 @@ - - + + - - + + diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp index 288b8c158..51a3a133e 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp @@ -74,7 +74,6 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } lLog << MSG::DEBUG << "Total electrode length from calorimeter xml description (cm): " << layersTotalHeight/dd4hep::cm << endmsg; - // The following code checks if the xml geometry file contains a constant defining // the number of layers the barrel. In that case, it makes the program abort // if the number of planes in the xml is different from the one calculated from @@ -109,7 +108,8 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::xml::DetElement passiveInnerMax = passive.child(_Unicode(innerMax)); dd4hep::xml::DetElement passiveOuter = passive.child(_Unicode(outer)); dd4hep::xml::DetElement passiveGlue = passive.child(_Unicode(glue)); - std::string passiveInnerMaterial = passiveInner.materialStr(); + std::string passiveInnerMaterial = passiveInnerMax.materialStr(); + std::string passiveInnerMaterialFirstLayer = passiveInner.materialStr(); std::string passiveOuterMaterial = passiveOuter.materialStr(); std::string passiveGlueMaterial = passiveGlue.materialStr(); double passiveInnerThicknessMin = passiveInner.thickness(); @@ -119,6 +119,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, double passiveThickness = passiveInnerThicknessMin + passiveOuterThickness + passiveGlueThickness; // inclination angle double angle = passive.rotation().angle(); + // Retrieve info about bath dd4hep::xml::DetElement bath = aXmlElement.child(_Unicode(bath)); dd4hep::xml::Dimension bathDim(bath.dimensions()); @@ -134,17 +135,17 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); lLog << MSG::INFO - << "ECAL cryostat: front: rmin (cm) = " << cryoDim.rmin1()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + << "ECAL cryostat: front: rmin (cm) = " << cryoDim.rmin1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL cryostat: back: rmin (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax2()/dd4hep::cm - << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + << "ECAL cryostat: back: rmin (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL cryostat: side: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " dz (cm) = " << (cryoDim.dz() - caloDim.dz())/dd4hep::cm << endmsg; + << "ECAL cryostat: side: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << (cryoDim.dz() - caloDim.dz())/dd4hep::cm << endmsg; dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoSideVol(cryostat.nameStr()+"_side", cryoSideShape, aLcdd.material(cryostat.materialStr())); @@ -179,13 +180,13 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Tube servicesFrontShape(cryoDim.rmin2(), bathRmin, caloDim.dz()); dd4hep::Tube servicesBackShape(bathRmax, cryoDim.rmax1(), caloDim.dz()); lLog << MSG::INFO - << "ECAL services: front: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " rmax (cm) = " << bathRmin/dd4hep::cm/dd4hep::cm - << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + << "ECAL services: front: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << bathRmin/dd4hep::cm/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL services: back: rmin (cm) = " << bathRmax/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + << "ECAL services: back: rmin (cm) = " << bathRmax/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; dd4hep::Volume servicesFrontVol("services_front", servicesFrontShape, aLcdd.material(activeMaterial)); dd4hep::Volume servicesBackVol("services_back", servicesBackShape, aLcdd.material(activeMaterial)); dd4hep::PlacedVolume servicesFrontPhysVol = envelopeVol.placeVolume(servicesFrontVol); @@ -226,14 +227,16 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // 3. Create the calorimeter by placing the passive material, trapezoid active layers, readout and again trapezoid // active layers in the bath. - // sensitive detector for the layers + // sensitive detector for the layers (and, if desired to study energy deposited in absorbers or up/downstream, in services and cryo) dd4hep::SensitiveDetector sd = aSensDet; dd4hep::xml::Dimension sdType = xmlDetElem.child(_U(sensitive)); sd.setType(sdType.typeStr()); - // 3.a. Create the passive planes, readout in between of 2 passive planes and the remaining space fill with active + // 3.a. Create the passive planes, readout in between of 2 passive planes and the remaining space filled with active // material + // Start by first calculating geometry parameters and printing out info + ////////////////////////////// // PASSIVE PLANES ////////////////////////////// @@ -241,14 +244,18 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // passive volumes consist of inner part and two outer, joined by glue lLog << MSG::INFO << "Passive elements:" << endmsg; lLog << MSG::INFO << " material in inner part of absorber (except 1st layer) = " << passiveInnerMaterial << endmsg; - lLog << MSG::INFO << " material in inner part of absorber (1st layer) = " << activeMaterial << endmsg; + lLog << MSG::INFO << " material in inner part of absorber (1st layer) = " << passiveInnerMaterialFirstLayer << endmsg; lLog << MSG::INFO << " material in outer part of absorber = " << passiveOuterMaterial << endmsg; - lLog << MSG::INFO << " material in between = " << passiveGlueMaterial << endmsg; - lLog << MSG::INFO << " thickness of inner part at inner radius (cm) = " << passiveInnerThicknessMin/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of inner part at outer radius (cm) = " << passiveInnerThicknessMax/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of outer part (cm) = " << passiveOuterThickness/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of middle part (cm) = " << passiveGlueThickness/dd4hep::cm << endmsg; - lLog << MSG::INFO << " total thickness of absorber (cm) = " << passiveThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " material in middle part between inner and outer = " << passiveGlueMaterial << endmsg; + lLog << MSG::INFO << " thickness of inner part at inner radius (cm) = " << passiveInnerThicknessMin/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of inner part at outer radius (cm) = " << passiveInnerThicknessMax/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of outer part (cm) = " << passiveOuterThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of middle part (cm) = " << passiveGlueThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " total thickness of absorber at inner radius (cm) = " << passiveThickness/dd4hep::cm << endmsg; + + ////////////////////////////// + // ELECTRODES + ////////////////////////////// lLog << MSG::INFO << "Electrodes:" << endmsg; lLog << MSG::INFO << " rotation angle (radians) = " << angle << " , (degrees) = " << angle*57.295780 << endmsg; @@ -285,6 +292,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // Andre, Alvaro, assert replaced by exception throw std::runtime_error("Incorrect number of planes (ECalBarrelNumPlanes) in calorimeter xml description!"); } + // Readout is in the middle between two passive planes double offsetPassivePhi = caloDim.offset() + dPhi / 2.; double offsetReadoutPhi = caloDim.offset() + 0; @@ -292,8 +300,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::INFO << " thickness of readout planes (cm) = " << readoutThickness/dd4hep::cm << endmsg; lLog << MSG::INFO << " number of layers = " << numLayers << endmsg; - - // electrode length, given inclination angle and min/max radius of the active calorimeter volume + // Electrode length, given inclination angle and min/max radius of the active calorimeter volume double planeLength = -Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2)); double runningHeight = 0.; @@ -308,13 +315,14 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::INFO << " layer " << iLay << " (cm) = " << rMin/dd4hep::cm << " - " << rMax/dd4hep::cm << endmsg; } - // check that electrode length is consistent with calorimeter radial extent + // Check that electrode length is consistent with calorimeter radial extent // and inclination angle to within 0.5 mm if (fabs(planeLength - layersTotalHeight) > 0.05*dd4hep::cm) { lLog << MSG::ERROR << " the sum of the electrode lengths per layer in the calorimeter xml file is not consistent with the length calculated from the calorimeter radial extent and the inclination angle" << endmsg; throw std::runtime_error("Incorrect length of electrode layers in calorimeter xml description!"); } - // calculate the thickness of the passive material in each layer + + // Calculate the thickness of the passive material in each layer // it's not constant in case of trapezoidal absorbers (passiveInnerThicknessMax != passiveInnerThicknessMin) // the code calculates the (max) passive thickness per layer i.e. at Rout of layer // rescaling by runningHeight / Ltot @@ -331,17 +339,67 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::DEBUG << " layer " << numLayers << " = " << passiveInnerThicknessLayer[numLayers] << " cm" << endmsg; - // calculate the angle of the passive elements if trapezoidal absorbers are used (Max != Min) + // Calculate the angle of the passive elements if trapezoidal absorbers are used (Max != Min) // if parallel absorbers are used then passiveAngle = 0 and cosPassiveAngle = 1 double passiveAngle = atan2((passiveInnerThicknessMax - passiveInnerThicknessMin) / 2., planeLength); double cosPassiveAngle = cos(passiveAngle); double rotatedOuterThickness = passiveOuterThickness / cosPassiveAngle; double rotatedGlueThickness = passiveGlueThickness / cosPassiveAngle; - // distance from the center of the electrode to the center of the 1st layer, in the electrode direction + // Distance from the center of the electrode to the center of the 1st layer, in the electrode direction double layerFirstOffset = -planeLength / 2. + layerHeight[0] / 2.; - // in the first calo layer we use a different material (LAr instead of Pb) for the inner passive material + ////////////////////////////// + // ACTIVE ELEMENTS + ////////////////////////////// + + // The active (LAr/LKr) elements are constructed subtracting from their + // envelope the readout and passive elements. + // This requires some calculations + + // Thickness of active layers at inner radius and outer ( = distance between passive plane and readout plane) + // at inner radius: distance projected at plane perpendicular to readout plane + double activeInThickness = Rmin * sin(dPhi / 2.) * cos(angle); + activeInThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // at outer radius: distance projected at plane perpendicular to readout plane + double activeOutThickness = (Rmin + planeLength) * sin(dPhi / 2.) * cos(angle); + // make correction for outer readius caused by inclination angle + // first calculate intersection of readout plane and plane parallel to shifted passive plane + double xIntersect = (Rmin * (tan(angle) - cos(dPhi / 2.) * tan(angle + dPhi / 2.)) - planeLength * sin(dPhi / 2.)) / + (tan(angle) - tan(angle + dPhi / 2.)); + double yIntersect = tan(angle) * xIntersect + Rmin * (sin(dPhi / 2.) - tan(angle)) + planeLength * sin(dPhi / 2.); + // distance from inner radius to intersection + double correction = + planeLength - sqrt(pow(xIntersect - Rmin * cos(dPhi / 2), 2) + pow(yIntersect - Rmin * sin(dPhi / 2), 2)); + // correction to the active thickness + activeOutThickness += 2. * correction * sin(dPhi / 4.); + activeOutThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // print the active layer dimensions + double activeInThicknessAfterSubtraction = + 2. * activeInThickness - readoutThickness - 2. * activePassiveOverlap * passiveThickness; + double activeOutThicknessAfterSubtraction = + 2. * activeOutThickness - readoutThickness - 2. * activePassiveOverlap * + (passiveThickness + passiveInnerThicknessMax - passiveInnerThicknessMin); // correct thickness for trapezoid + lLog << MSG::INFO << "Active elements:" << endmsg; + lLog << MSG::INFO << " material = " << activeMaterial << endmsg; + lLog << MSG::INFO << " thickness at inner radius (cm) = " << activeInThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness at outer radius (cm) = " << activeOutThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness relative increase from inner to outer radius = " + << (activeOutThicknessAfterSubtraction - activeInThicknessAfterSubtraction) * 100 / + activeInThicknessAfterSubtraction + << " %." << endmsg; + lLog << MSG::INFO + << " active passive initial overlap (before subtraction) (cm) = " << passiveThickness/dd4hep::cm * activePassiveOverlap + << " = " << activePassiveOverlap * 100 << " %" << endmsg; + + + // Now create the volumes + + ////////////////////////////// + // PASSIVE ELEMENTS + ////////////////////////////// + + // in the first calo layer we might use a different material (LAr instead of Pb) for the inner passive material // to sample more uniformly for the upstream correction. So we need to split the volume into // passiveInnerShapeFirstLayer (for first layer) and passiveInnerShape (for other layers) // passiveInner elements' lengths along electrode are length of layer0 and suf of lengths of other layers @@ -359,20 +417,76 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Box passiveGlueShape(passiveGlueThickness / 4., caloDim.dz(), planeLength / 2. / cosPassiveAngle); dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); dd4hep::Volume passiveInnerVol(passiveInnerMaterial + "_passive", passiveInnerShape, - aLcdd.material(passiveInnerMaterial)); - dd4hep::Volume passiveInnerVolFirstLayer(activeMaterial + "_passive", passiveInnerShapeFirstLayer, - aLcdd.material(activeMaterial)); + aLcdd.material(passiveInnerMaterial)); + dd4hep::Volume passiveInnerVolFirstLayer(passiveInnerMaterialFirstLayer + "_passive", passiveInnerShapeFirstLayer, + aLcdd.material(passiveInnerMaterialFirstLayer)); dd4hep::Volume passiveOuterVol(passiveOuterMaterial + "_passive", passiveOuterShape, - aLcdd.material(passiveOuterMaterial)); + aLcdd.material(passiveOuterMaterial)); dd4hep::Volume passiveGlueVol(passiveGlueMaterial + "_passive", passiveGlueShape, - aLcdd.material(passiveGlueMaterial)); + aLcdd.material(passiveGlueMaterial)); + + // translate and rotate the elements of the module appropriately + // the Pb absorber does not need to be rotated, but the glue and + // the outer absorbers have to, in case of trapezoidal absorbers. + // The glue and steel absorbers also have to be translated in x-y + // to the proper positions on the two sides of the inner absorber + // - inner part of absorber, 2-N layers + // Their center is shifted wrt center of fulle absorber by length of 1st layer/2.0 + dd4hep::PlacedVolume passiveInnerPhysVol = passiveVol.placeVolume( + passiveInnerVol, + dd4hep::Position(0, 0, layerHeight[0] / 2.)); + // - inner part of absorber, first layer + // its center is shifted wrt center of full absorber by -(length of plane - length of 1st layer)/2.0 + dd4hep::PlacedVolume passiveInnerPhysVolFirstLayer = passiveVol.placeVolume( + passiveInnerVolFirstLayer, + dd4hep::Position(0, 0, layerFirstOffset)); + // - outer part of absorber, all layers, left side + dd4hep::PlacedVolume passiveOuterPhysVolBelow = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 2. - rotatedOuterThickness / 4., 0, 0))); + // - outer part of absorber, all layers, right side + dd4hep::PlacedVolume passiveOuterPhysVolAbove = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 2. + rotatedOuterThickness / 4., 0, 0))); + // - glue in absorber, all layers, left side + dd4hep::PlacedVolume passiveGluePhysVolBelow = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 4., 0, 0))); + // - glue in absorber, all layers, right side + dd4hep::PlacedVolume passiveGluePhysVolAbove = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 4., 0, 0))); + passiveInnerPhysVol.addPhysVolID("subtype", 0); + passiveInnerPhysVolFirstLayer.addPhysVolID("subtype", 0); + passiveOuterPhysVolBelow.addPhysVolID("subtype", 1); + passiveOuterPhysVolAbove.addPhysVolID("subtype", 2); + passiveGluePhysVolBelow.addPhysVolID("subtype", 3); + passiveGluePhysVolAbove.addPhysVolID("subtype", 4); + + // if the inner part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive + // first layer if (passiveInner.isSensitive()) { - lLog << MSG::DEBUG << "Passive inner volume set as sensitive" << endmsg; - // inner part starts at second layer + lLog << MSG::DEBUG << "Passive inner volume (1st layer) set as sensitive" << endmsg; + passiveInnerVolFirstLayer.setSensitiveDetector(aSensDet); + passiveInnerPhysVolFirstLayer.addPhysVolID("layer", 0); + dd4hep::DetElement passiveInnerDetElemFirstLayer("layer", 0); + passiveInnerDetElemFirstLayer.setPlacement(passiveInnerPhysVolFirstLayer); + } + // other layers + if (passiveInnerMax.isSensitive()) { + lLog << MSG::DEBUG << "Passive inner volume (2-N layers) set as sensitive" << endmsg; double layerOffset = layerFirstOffset + layerHeight[1] / 2.; for (uint iLayer = 1; iLayer < numLayers; iLayer++) { - //dd4hep::Box layerPassiveInnerShape(passiveInnerThickness / 2., caloDim.dz(), layerHeight[iLayer] / 2.); dd4hep::Trd1 layerPassiveInnerShape(passiveInnerThicknessLayer[iLayer] / 2., passiveInnerThicknessLayer[iLayer+1] / 2., caloDim.dz(), layerHeight[iLayer] / 2.); dd4hep::Volume layerPassiveInnerVol(passiveInnerMaterial, layerPassiveInnerShape, aLcdd.material(passiveInnerMaterial)); @@ -387,7 +501,10 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } } + if (passiveOuter.isSensitive()) { + // if the outer part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive lLog << MSG::DEBUG << "Passive outer volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset / cosPassiveAngle; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { @@ -405,7 +522,10 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } } + if (passiveGlue.isSensitive()) { + // if the glue is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive lLog << MSG::DEBUG << "Passive glue volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset / cosPassiveAngle; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { @@ -424,53 +544,13 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } - // translate and rotate the elements of the module appropriately - // the Pb absorber does not need to be rotated, but the glue and - // the outer absorbers have to, in case of trapezoidal absorbers. - // The glue and steel absorbers also have to be translated in x-y - // to the proper positions on the two sides of the inner absorber - dd4hep::PlacedVolume passiveInnerPhysVol = - passiveVol.placeVolume(passiveInnerVol, dd4hep::Position(0, 0, layerHeight[0] / 2.)); - dd4hep::PlacedVolume passiveInnerPhysVolFirstLayer = - passiveVol.placeVolume(passiveInnerVolFirstLayer, dd4hep::Position(0, 0, layerFirstOffset)); - dd4hep::PlacedVolume passiveOuterPhysVolBelow = passiveVol.placeVolume( - passiveOuterVol, - dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), - dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - - rotatedGlueThickness / 2. - rotatedOuterThickness / 4., 0, 0))); - dd4hep::PlacedVolume passiveOuterPhysVolAbove = passiveVol.placeVolume( - passiveOuterVol, - dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), - dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + - rotatedGlueThickness / 2. + rotatedOuterThickness / 4., 0, 0))); - dd4hep::PlacedVolume passiveGluePhysVolBelow = passiveVol.placeVolume( - passiveGlueVol, - dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), - dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - - rotatedGlueThickness / 4., 0, 0))); - dd4hep::PlacedVolume passiveGluePhysVolAbove = passiveVol.placeVolume( - passiveGlueVol, - dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), - dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + - rotatedGlueThickness / 4., 0, 0))); - passiveInnerPhysVol.addPhysVolID("subtype", 0); - passiveInnerPhysVolFirstLayer.addPhysVolID("subtype", 0); - passiveOuterPhysVolBelow.addPhysVolID("subtype", 1); - passiveOuterPhysVolAbove.addPhysVolID("subtype", 2); - passiveGluePhysVolBelow.addPhysVolID("subtype", 3); - passiveGluePhysVolAbove.addPhysVolID("subtype", 4); - if (passiveInner.isSensitive()) { - passiveInnerVolFirstLayer.setSensitiveDetector(aSensDet); - passiveInnerPhysVolFirstLayer.addPhysVolID("layer", 0); - dd4hep::DetElement passiveInnerDetElemFirstLayer("layer", 0); - passiveInnerDetElemFirstLayer.setPlacement(passiveInnerPhysVolFirstLayer); - } - ////////////////////////////// // READOUT PLANES ////////////////////////////// dd4hep::Box readoutShape(readoutThickness / 2., caloDim.dz(), planeLength / 2.); dd4hep::Volume readoutVol(readoutMaterial, readoutShape, aLcdd.material(readoutMaterial)); + // if the readout is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive if (readout.isSensitive()) { lLog << MSG::INFO << "ECAL readout volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset; @@ -490,55 +570,18 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } ////////////////////////////// - // ACTIVE + // ACTIVE ELEMENTS ////////////////////////////// - // The active (LAr/LKr) elements are constructed subtracting from their - // envelope the readout and passive elements - // This requires some calculations to - - // Thickness of active layers at inner radius and outer ( = distance between passive plane and readout plane) - // at inner radius: distance projected at plane perpendicular to readout plane - double activeInThickness = Rmin * sin(dPhi / 2.) * cos(angle); - activeInThickness -= passiveThickness * (0.5 - activePassiveOverlap); - // at outer radius: distance projected at plane perpendicular to readout plane - double activeOutThickness = (Rmin + planeLength) * sin(dPhi / 2.) * cos(angle); - // make correction for outer readius caused by inclination angle - // first calculate intersection of readout plane and plane parallel to shifted passive plane - double xIntersect = (Rmin * (tan(angle) - cos(dPhi / 2.) * tan(angle + dPhi / 2.)) - planeLength * sin(dPhi / 2.)) / - (tan(angle) - tan(angle + dPhi / 2.)); - double yIntersect = tan(angle) * xIntersect + Rmin * (sin(dPhi / 2.) - tan(angle)) + planeLength * sin(dPhi / 2.); - // distance from inner radius to intersection - double correction = - planeLength - sqrt(pow(xIntersect - Rmin * cos(dPhi / 2), 2) + pow(yIntersect - Rmin * sin(dPhi / 2), 2)); - // correction to the active thickness - activeOutThickness += 2. * correction * sin(dPhi / 4.); - activeOutThickness -= passiveThickness * (0.5 - activePassiveOverlap); - // print the active layer dimensions - double activeInThicknessAfterSubtraction = - 2. * activeInThickness - readoutThickness - 2. * activePassiveOverlap * passiveThickness; - double activeOutThicknessAfterSubtraction = - 2. * activeOutThickness - readoutThickness - 2. * activePassiveOverlap * - (passiveThickness + passiveInnerThicknessMax - passiveInnerThicknessMin); // correct thickness for trapezoid - lLog << MSG::INFO << "Active elements:" << endmsg; - lLog << MSG::INFO << " material = " << activeMaterial << endmsg; - lLog << MSG::INFO << " thickness at inner radius (cm) = " << activeInThicknessAfterSubtraction/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness at outer radius (cm) = " << activeOutThicknessAfterSubtraction/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness relative increase from inner to outer radius = " - << (activeOutThicknessAfterSubtraction - activeInThicknessAfterSubtraction) * 100 / - activeInThicknessAfterSubtraction - << " %." << endmsg; - lLog << MSG::INFO - << " active passive initial overlap (before subtraction) (cm) = " << passiveThickness/dd4hep::cm * activePassiveOverlap - << " = " << activePassiveOverlap * 100 << " %" << endmsg; - // creating shape for rows of layers (active material between two passive planes, with readout in the middle) - // first define area between two passive planes, area can reach up to the symmetry axis of passive plane + + // - first define area between two passive planes, area can reach up to the symmetry axis of passive plane dd4hep::Trd1 activeOuterShape(activeInThickness, activeOutThickness, caloDim.dz(), planeLength / 2.); - // subtract readout shape from the middle + + // - subtract readout shape from the middle dd4hep::SubtractionSolid activeShapeNoReadout(activeOuterShape, readoutShape); - // make calculation for active plane that is inclined with 0 deg (= offset + angle) + // - make calculation for active plane that is inclined with 0 deg (= offset + angle) double Cx = Rmin * cos(-angle) + planeLength / 2.; double Cy = Rmin * sin(-angle); double Ax = Rmin * cos(-angle + dPhi / 2.) + planeLength / 2. * cos(dPhi / 2.); @@ -557,20 +600,25 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, zprimB = CBx; xprimB = CBy; - // subtract passive volume above + // - subtract readout shape from the middle dd4hep::SubtractionSolid activeShapeNoPassiveAbove( activeShapeNoReadout, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), - dd4hep::Position(-fabs(xprim), 0, fabs(zprim)))); - // subtract passive volume below + dd4hep::Position(-fabs(xprim), 0, fabs(zprim)))); + + // - subtract passive volume below dd4hep::SubtractionSolid activeShape( activeShapeNoPassiveAbove, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), - dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB)))); + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB)))); + + // - create the active volume, which will contain the layers filled with LAr dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); - std::vector layerPhysVols; // place layers within active volume + std::vector layerPhysVols; + + // - first, calculate the layer widths at inner and outer radii std::vector layerInThickness; std::vector layerOutThickness; double layerIncreasePerUnitThickness = (activeOutThickness - activeInThickness) / layersTotalHeight; @@ -582,19 +630,29 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } layerOutThickness.push_back(layerInThickness[iLay] + layerIncreasePerUnitThickness * layerHeight[iLay]); } + + // - then, loop on the layers to create and place the volumes double layerOffset = layerFirstOffset; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + // define the layer envelope dd4hep::Trd1 layerOuterShape(layerInThickness[iLayer], layerOutThickness[iLayer], caloDim.dz(), layerHeight[iLayer] / 2.); + + // subtract readout shape from the middle dd4hep::SubtractionSolid layerShapeNoReadout(layerOuterShape, readoutShape); + + // subtract readout shape from the middle dd4hep::SubtractionSolid layerShapeNoPassiveAbove( layerShapeNoReadout, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), - dd4hep::Position(-fabs(xprim), 0, fabs(zprim) - layerOffset))); + dd4hep::Position(-fabs(xprim), 0, fabs(zprim) - layerOffset))); + // subtract passive volume below dd4hep::SubtractionSolid layerShape( layerShapeNoPassiveAbove, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), - dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB) - layerOffset))); + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB) - layerOffset))); + + // create the volume, filled with active material, set as sensitive, and position it properly within active volume dd4hep::Volume layerVol("layer", layerShape, aLcdd.material(activeMaterial)); layerVol.setSensitiveDetector(aSensDet); layerPhysVols.push_back(activeVol.placeVolume(layerVol, dd4hep::Position(0, 0, layerOffset))); @@ -604,12 +662,14 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } + // Place elements in bath: passive planes, readout planes and rows of layers dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); - std::vector activePhysVols; - // Next place elements: passive planes, readout planes and rows of layers for (uint iPlane = 0; iPlane < numPlanes; iPlane++) { - // first calculate positions of passive and readout planes + + // // PASSIVE + // + // calculate centre position of the plane without plane rotation double phi = offsetPassivePhi + iPlane * dPhi; double xRadial = (Rmin + planeLength / 2.) * cos(phi); @@ -621,18 +681,22 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, double xRotated = xRmin + (xRadial - xRmin) * cos(angle) - (yRadial - yRmin) * sin(angle); double yRotated = yRmin + (xRadial - xRmin) * sin(angle) + (yRadial - yRmin) * cos(angle); dd4hep::Transform3D transform(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane - * - dd4hep::RotationY(M_PI / 2. // to get pointed towards centre - - - phi - angle), - dd4hep::Position(xRotated, yRotated, 0)); + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phi - angle), + dd4hep::Position(xRotated, yRotated, 0)); + // create and place volume in bath dd4hep::PlacedVolume passivePhysVol = bathVol.placeVolume(passiveVol, transform); passivePhysVol.addPhysVolID("module", iPlane); passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout dd4hep::DetElement passiveDetElem(bathDetElem, "passive" + std::to_string(iPlane), iPlane); passiveDetElem.setPlacement(passivePhysVol); + // // READOUT + // + // calculate centre position of the plane without plane rotation double phiRead = offsetReadoutPhi + iPlane * dPhi; double xRadialRead = (Rmin + planeLength / 2.) * cos(phiRead); @@ -643,39 +707,45 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // rotate centre by angle wrt beginning of plane double xRotatedRead = xRminRead + (xRadialRead - xRminRead) * cos(angle) - (yRadialRead - yRminRead) * sin(angle); double yRotatedRead = yRminRead + (xRadialRead - xRminRead) * sin(angle) + (yRadialRead - yRminRead) * cos(angle); - dd4hep::Transform3D transformRead( - dd4hep::RotationX(-M_PI / 2.) // to get in XY plane - * - dd4hep::RotationY(M_PI / 2. // to get pointed towards centre - - - phiRead - angle), - dd4hep::Position(xRotatedRead, yRotatedRead, 0)); + dd4hep::Transform3D transformRead(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phiRead - angle), + dd4hep::Position(xRotatedRead, yRotatedRead, 0)); + // create and place volume in bath dd4hep::PlacedVolume readoutPhysVol = bathVol.placeVolume(readoutVol, transformRead); readoutPhysVol.addPhysVolID("module", iPlane); readoutPhysVol.addPhysVolID("type", 2); // 0 = active, 1 = passive, 2 = readout dd4hep::DetElement readoutDetElem(bathDetElem, "readout" + std::to_string(iPlane), iPlane); readoutDetElem.setPlacement(readoutPhysVol); + // // ACTIVE - dd4hep::Rotation3D rotationActive(dd4hep::RotationX(-M_PI / 2) * - dd4hep::RotationY(M_PI / 2 - phiRead - angle)); - activePhysVols.push_back(bathVol.placeVolume( - activeVol, - dd4hep::Transform3D(rotationActive, dd4hep::Position(xRotatedRead, yRotatedRead, 0)))); - activePhysVols.back().addPhysVolID("module", iPlane); - activePhysVols.back().addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout - } - dd4hep::PlacedVolume bathPhysVol = envelopeVol.placeVolume(bathVol); - bathDetElem.setPlacement(bathPhysVol); - for (uint iPlane = 0; iPlane < numPlanes; iPlane++) { + // + + // same positioning as readout + dd4hep::Transform3D transformActive(dd4hep::RotationX(-M_PI / 2) + * + dd4hep::RotationY(M_PI / 2 - phiRead - angle), + dd4hep::Position(xRotatedRead, yRotatedRead, 0)); + // create and place volume in bath + dd4hep::PlacedVolume activePhysVol = bathVol.placeVolume(activeVol, transformActive); + activePhysVol.addPhysVolID("module", iPlane); + activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout dd4hep::DetElement activeDetElem(bathDetElem, "active" + std::to_string(iPlane), iPlane); - activeDetElem.setPlacement(activePhysVols[iPlane]); + activeDetElem.setPlacement(activePhysVol); + // place the layers inside the active element for (uint iLayer = 0; iLayer < numLayers; iLayer++) { dd4hep::DetElement layerDetElem(activeDetElem, "layer" + std::to_string(iLayer), iLayer); layerDetElem.setPlacement(layerPhysVols[iLayer]); } } + // Place bath in envelope + dd4hep::PlacedVolume bathPhysVol = envelopeVol.placeVolume(bathVol); + bathDetElem.setPlacement(bathPhysVol); + // Place the envelope dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVol); From cb1da091e3c2020ecbaeceb6b971399b7893a597 Mon Sep 17 00:00:00 2001 From: Giovanni Marchiori Date: Thu, 7 Nov 2024 16:58:10 +0100 Subject: [PATCH 073/133] Revert "make material in 1st layer of ECAL absorber configurable. Set by default to G10 rather than LAr. Also add more comments and fix some whitespaces" This reverts commit 33615bec1aa50ae27f26629f469f477a48b909db. --- .../ECalBarrel_thetamodulemerged.xml | 8 +- ...alBarrel_thetamodulemerged_calibration.xml | 8 +- .../ECalBarrel_thetamodulemerged_upstream.xml | 8 +- ...leLiquid_InclinedTrapezoids_o1_v03_geo.cpp | 390 +++++++----------- 4 files changed, 172 insertions(+), 242 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml index 1bf3b73e3..5b7dc11fa 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged.xml @@ -126,11 +126,11 @@ - - + + - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml index a6101643e..c8c79f253 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_calibration.xml @@ -118,11 +118,11 @@ - - + + - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml index 6e79b4aba..b4e05e073 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalBarrel_thetamodulemerged_upstream.xml @@ -118,11 +118,11 @@ - - + + - - + + diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp index 51a3a133e..288b8c158 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp @@ -74,6 +74,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } lLog << MSG::DEBUG << "Total electrode length from calorimeter xml description (cm): " << layersTotalHeight/dd4hep::cm << endmsg; + // The following code checks if the xml geometry file contains a constant defining // the number of layers the barrel. In that case, it makes the program abort // if the number of planes in the xml is different from the one calculated from @@ -108,8 +109,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::xml::DetElement passiveInnerMax = passive.child(_Unicode(innerMax)); dd4hep::xml::DetElement passiveOuter = passive.child(_Unicode(outer)); dd4hep::xml::DetElement passiveGlue = passive.child(_Unicode(glue)); - std::string passiveInnerMaterial = passiveInnerMax.materialStr(); - std::string passiveInnerMaterialFirstLayer = passiveInner.materialStr(); + std::string passiveInnerMaterial = passiveInner.materialStr(); std::string passiveOuterMaterial = passiveOuter.materialStr(); std::string passiveGlueMaterial = passiveGlue.materialStr(); double passiveInnerThicknessMin = passiveInner.thickness(); @@ -119,7 +119,6 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, double passiveThickness = passiveInnerThicknessMin + passiveOuterThickness + passiveGlueThickness; // inclination angle double angle = passive.rotation().angle(); - // Retrieve info about bath dd4hep::xml::DetElement bath = aXmlElement.child(_Unicode(bath)); dd4hep::xml::Dimension bathDim(bath.dimensions()); @@ -135,17 +134,17 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); lLog << MSG::INFO - << "ECAL cryostat: front: rmin (cm) = " << cryoDim.rmin1()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + << "ECAL cryostat: front: rmin (cm) = " << cryoDim.rmin1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL cryostat: back: rmin (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax2()/dd4hep::cm - << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + << "ECAL cryostat: back: rmin (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL cryostat: side: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " dz (cm) = " << (cryoDim.dz() - caloDim.dz())/dd4hep::cm << endmsg; + << "ECAL cryostat: side: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << (cryoDim.dz() - caloDim.dz())/dd4hep::cm << endmsg; dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoSideVol(cryostat.nameStr()+"_side", cryoSideShape, aLcdd.material(cryostat.materialStr())); @@ -180,13 +179,13 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Tube servicesFrontShape(cryoDim.rmin2(), bathRmin, caloDim.dz()); dd4hep::Tube servicesBackShape(bathRmax, cryoDim.rmax1(), caloDim.dz()); lLog << MSG::INFO - << "ECAL services: front: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm - << " rmax (cm) = " << bathRmin/dd4hep::cm/dd4hep::cm - << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + << "ECAL services: front: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << bathRmin/dd4hep::cm/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; lLog << MSG::INFO - << "ECAL services: back: rmin (cm) = " << bathRmax/dd4hep::cm - << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm - << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + << "ECAL services: back: rmin (cm) = " << bathRmax/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; dd4hep::Volume servicesFrontVol("services_front", servicesFrontShape, aLcdd.material(activeMaterial)); dd4hep::Volume servicesBackVol("services_back", servicesBackShape, aLcdd.material(activeMaterial)); dd4hep::PlacedVolume servicesFrontPhysVol = envelopeVol.placeVolume(servicesFrontVol); @@ -227,16 +226,14 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // 3. Create the calorimeter by placing the passive material, trapezoid active layers, readout and again trapezoid // active layers in the bath. - // sensitive detector for the layers (and, if desired to study energy deposited in absorbers or up/downstream, in services and cryo) + // sensitive detector for the layers dd4hep::SensitiveDetector sd = aSensDet; dd4hep::xml::Dimension sdType = xmlDetElem.child(_U(sensitive)); sd.setType(sdType.typeStr()); - // 3.a. Create the passive planes, readout in between of 2 passive planes and the remaining space filled with active + // 3.a. Create the passive planes, readout in between of 2 passive planes and the remaining space fill with active // material - // Start by first calculating geometry parameters and printing out info - ////////////////////////////// // PASSIVE PLANES ////////////////////////////// @@ -244,18 +241,14 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // passive volumes consist of inner part and two outer, joined by glue lLog << MSG::INFO << "Passive elements:" << endmsg; lLog << MSG::INFO << " material in inner part of absorber (except 1st layer) = " << passiveInnerMaterial << endmsg; - lLog << MSG::INFO << " material in inner part of absorber (1st layer) = " << passiveInnerMaterialFirstLayer << endmsg; + lLog << MSG::INFO << " material in inner part of absorber (1st layer) = " << activeMaterial << endmsg; lLog << MSG::INFO << " material in outer part of absorber = " << passiveOuterMaterial << endmsg; - lLog << MSG::INFO << " material in middle part between inner and outer = " << passiveGlueMaterial << endmsg; - lLog << MSG::INFO << " thickness of inner part at inner radius (cm) = " << passiveInnerThicknessMin/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of inner part at outer radius (cm) = " << passiveInnerThicknessMax/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of outer part (cm) = " << passiveOuterThickness/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness of middle part (cm) = " << passiveGlueThickness/dd4hep::cm << endmsg; - lLog << MSG::INFO << " total thickness of absorber at inner radius (cm) = " << passiveThickness/dd4hep::cm << endmsg; - - ////////////////////////////// - // ELECTRODES - ////////////////////////////// + lLog << MSG::INFO << " material in between = " << passiveGlueMaterial << endmsg; + lLog << MSG::INFO << " thickness of inner part at inner radius (cm) = " << passiveInnerThicknessMin/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of inner part at outer radius (cm) = " << passiveInnerThicknessMax/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of outer part (cm) = " << passiveOuterThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of middle part (cm) = " << passiveGlueThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " total thickness of absorber (cm) = " << passiveThickness/dd4hep::cm << endmsg; lLog << MSG::INFO << "Electrodes:" << endmsg; lLog << MSG::INFO << " rotation angle (radians) = " << angle << " , (degrees) = " << angle*57.295780 << endmsg; @@ -292,7 +285,6 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // Andre, Alvaro, assert replaced by exception throw std::runtime_error("Incorrect number of planes (ECalBarrelNumPlanes) in calorimeter xml description!"); } - // Readout is in the middle between two passive planes double offsetPassivePhi = caloDim.offset() + dPhi / 2.; double offsetReadoutPhi = caloDim.offset() + 0; @@ -300,7 +292,8 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::INFO << " thickness of readout planes (cm) = " << readoutThickness/dd4hep::cm << endmsg; lLog << MSG::INFO << " number of layers = " << numLayers << endmsg; - // Electrode length, given inclination angle and min/max radius of the active calorimeter volume + + // electrode length, given inclination angle and min/max radius of the active calorimeter volume double planeLength = -Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2)); double runningHeight = 0.; @@ -315,14 +308,13 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::INFO << " layer " << iLay << " (cm) = " << rMin/dd4hep::cm << " - " << rMax/dd4hep::cm << endmsg; } - // Check that electrode length is consistent with calorimeter radial extent + // check that electrode length is consistent with calorimeter radial extent // and inclination angle to within 0.5 mm if (fabs(planeLength - layersTotalHeight) > 0.05*dd4hep::cm) { lLog << MSG::ERROR << " the sum of the electrode lengths per layer in the calorimeter xml file is not consistent with the length calculated from the calorimeter radial extent and the inclination angle" << endmsg; throw std::runtime_error("Incorrect length of electrode layers in calorimeter xml description!"); } - - // Calculate the thickness of the passive material in each layer + // calculate the thickness of the passive material in each layer // it's not constant in case of trapezoidal absorbers (passiveInnerThicknessMax != passiveInnerThicknessMin) // the code calculates the (max) passive thickness per layer i.e. at Rout of layer // rescaling by runningHeight / Ltot @@ -339,67 +331,17 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, lLog << MSG::DEBUG << " layer " << numLayers << " = " << passiveInnerThicknessLayer[numLayers] << " cm" << endmsg; - // Calculate the angle of the passive elements if trapezoidal absorbers are used (Max != Min) + // calculate the angle of the passive elements if trapezoidal absorbers are used (Max != Min) // if parallel absorbers are used then passiveAngle = 0 and cosPassiveAngle = 1 double passiveAngle = atan2((passiveInnerThicknessMax - passiveInnerThicknessMin) / 2., planeLength); double cosPassiveAngle = cos(passiveAngle); double rotatedOuterThickness = passiveOuterThickness / cosPassiveAngle; double rotatedGlueThickness = passiveGlueThickness / cosPassiveAngle; - // Distance from the center of the electrode to the center of the 1st layer, in the electrode direction + // distance from the center of the electrode to the center of the 1st layer, in the electrode direction double layerFirstOffset = -planeLength / 2. + layerHeight[0] / 2.; - ////////////////////////////// - // ACTIVE ELEMENTS - ////////////////////////////// - - // The active (LAr/LKr) elements are constructed subtracting from their - // envelope the readout and passive elements. - // This requires some calculations - - // Thickness of active layers at inner radius and outer ( = distance between passive plane and readout plane) - // at inner radius: distance projected at plane perpendicular to readout plane - double activeInThickness = Rmin * sin(dPhi / 2.) * cos(angle); - activeInThickness -= passiveThickness * (0.5 - activePassiveOverlap); - // at outer radius: distance projected at plane perpendicular to readout plane - double activeOutThickness = (Rmin + planeLength) * sin(dPhi / 2.) * cos(angle); - // make correction for outer readius caused by inclination angle - // first calculate intersection of readout plane and plane parallel to shifted passive plane - double xIntersect = (Rmin * (tan(angle) - cos(dPhi / 2.) * tan(angle + dPhi / 2.)) - planeLength * sin(dPhi / 2.)) / - (tan(angle) - tan(angle + dPhi / 2.)); - double yIntersect = tan(angle) * xIntersect + Rmin * (sin(dPhi / 2.) - tan(angle)) + planeLength * sin(dPhi / 2.); - // distance from inner radius to intersection - double correction = - planeLength - sqrt(pow(xIntersect - Rmin * cos(dPhi / 2), 2) + pow(yIntersect - Rmin * sin(dPhi / 2), 2)); - // correction to the active thickness - activeOutThickness += 2. * correction * sin(dPhi / 4.); - activeOutThickness -= passiveThickness * (0.5 - activePassiveOverlap); - // print the active layer dimensions - double activeInThicknessAfterSubtraction = - 2. * activeInThickness - readoutThickness - 2. * activePassiveOverlap * passiveThickness; - double activeOutThicknessAfterSubtraction = - 2. * activeOutThickness - readoutThickness - 2. * activePassiveOverlap * - (passiveThickness + passiveInnerThicknessMax - passiveInnerThicknessMin); // correct thickness for trapezoid - lLog << MSG::INFO << "Active elements:" << endmsg; - lLog << MSG::INFO << " material = " << activeMaterial << endmsg; - lLog << MSG::INFO << " thickness at inner radius (cm) = " << activeInThicknessAfterSubtraction/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness at outer radius (cm) = " << activeOutThicknessAfterSubtraction/dd4hep::cm << endmsg; - lLog << MSG::INFO << " thickness relative increase from inner to outer radius = " - << (activeOutThicknessAfterSubtraction - activeInThicknessAfterSubtraction) * 100 / - activeInThicknessAfterSubtraction - << " %." << endmsg; - lLog << MSG::INFO - << " active passive initial overlap (before subtraction) (cm) = " << passiveThickness/dd4hep::cm * activePassiveOverlap - << " = " << activePassiveOverlap * 100 << " %" << endmsg; - - - // Now create the volumes - - ////////////////////////////// - // PASSIVE ELEMENTS - ////////////////////////////// - - // in the first calo layer we might use a different material (LAr instead of Pb) for the inner passive material + // in the first calo layer we use a different material (LAr instead of Pb) for the inner passive material // to sample more uniformly for the upstream correction. So we need to split the volume into // passiveInnerShapeFirstLayer (for first layer) and passiveInnerShape (for other layers) // passiveInner elements' lengths along electrode are length of layer0 and suf of lengths of other layers @@ -417,76 +359,20 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, dd4hep::Box passiveGlueShape(passiveGlueThickness / 4., caloDim.dz(), planeLength / 2. / cosPassiveAngle); dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); dd4hep::Volume passiveInnerVol(passiveInnerMaterial + "_passive", passiveInnerShape, - aLcdd.material(passiveInnerMaterial)); - dd4hep::Volume passiveInnerVolFirstLayer(passiveInnerMaterialFirstLayer + "_passive", passiveInnerShapeFirstLayer, - aLcdd.material(passiveInnerMaterialFirstLayer)); + aLcdd.material(passiveInnerMaterial)); + dd4hep::Volume passiveInnerVolFirstLayer(activeMaterial + "_passive", passiveInnerShapeFirstLayer, + aLcdd.material(activeMaterial)); dd4hep::Volume passiveOuterVol(passiveOuterMaterial + "_passive", passiveOuterShape, - aLcdd.material(passiveOuterMaterial)); + aLcdd.material(passiveOuterMaterial)); dd4hep::Volume passiveGlueVol(passiveGlueMaterial + "_passive", passiveGlueShape, - aLcdd.material(passiveGlueMaterial)); - - // translate and rotate the elements of the module appropriately - // the Pb absorber does not need to be rotated, but the glue and - // the outer absorbers have to, in case of trapezoidal absorbers. - // The glue and steel absorbers also have to be translated in x-y - // to the proper positions on the two sides of the inner absorber + aLcdd.material(passiveGlueMaterial)); - // - inner part of absorber, 2-N layers - // Their center is shifted wrt center of fulle absorber by length of 1st layer/2.0 - dd4hep::PlacedVolume passiveInnerPhysVol = passiveVol.placeVolume( - passiveInnerVol, - dd4hep::Position(0, 0, layerHeight[0] / 2.)); - // - inner part of absorber, first layer - // its center is shifted wrt center of full absorber by -(length of plane - length of 1st layer)/2.0 - dd4hep::PlacedVolume passiveInnerPhysVolFirstLayer = passiveVol.placeVolume( - passiveInnerVolFirstLayer, - dd4hep::Position(0, 0, layerFirstOffset)); - // - outer part of absorber, all layers, left side - dd4hep::PlacedVolume passiveOuterPhysVolBelow = passiveVol.placeVolume( - passiveOuterVol, - dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), - dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - - rotatedGlueThickness / 2. - rotatedOuterThickness / 4., 0, 0))); - // - outer part of absorber, all layers, right side - dd4hep::PlacedVolume passiveOuterPhysVolAbove = passiveVol.placeVolume( - passiveOuterVol, - dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), - dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + - rotatedGlueThickness / 2. + rotatedOuterThickness / 4., 0, 0))); - // - glue in absorber, all layers, left side - dd4hep::PlacedVolume passiveGluePhysVolBelow = passiveVol.placeVolume( - passiveGlueVol, - dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), - dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - - rotatedGlueThickness / 4., 0, 0))); - // - glue in absorber, all layers, right side - dd4hep::PlacedVolume passiveGluePhysVolAbove = passiveVol.placeVolume( - passiveGlueVol, - dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), - dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + - rotatedGlueThickness / 4., 0, 0))); - passiveInnerPhysVol.addPhysVolID("subtype", 0); - passiveInnerPhysVolFirstLayer.addPhysVolID("subtype", 0); - passiveOuterPhysVolBelow.addPhysVolID("subtype", 1); - passiveOuterPhysVolAbove.addPhysVolID("subtype", 2); - passiveGluePhysVolBelow.addPhysVolID("subtype", 3); - passiveGluePhysVolAbove.addPhysVolID("subtype", 4); - - // if the inner part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer - // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive - // first layer if (passiveInner.isSensitive()) { - lLog << MSG::DEBUG << "Passive inner volume (1st layer) set as sensitive" << endmsg; - passiveInnerVolFirstLayer.setSensitiveDetector(aSensDet); - passiveInnerPhysVolFirstLayer.addPhysVolID("layer", 0); - dd4hep::DetElement passiveInnerDetElemFirstLayer("layer", 0); - passiveInnerDetElemFirstLayer.setPlacement(passiveInnerPhysVolFirstLayer); - } - // other layers - if (passiveInnerMax.isSensitive()) { - lLog << MSG::DEBUG << "Passive inner volume (2-N layers) set as sensitive" << endmsg; + lLog << MSG::DEBUG << "Passive inner volume set as sensitive" << endmsg; + // inner part starts at second layer double layerOffset = layerFirstOffset + layerHeight[1] / 2.; for (uint iLayer = 1; iLayer < numLayers; iLayer++) { + //dd4hep::Box layerPassiveInnerShape(passiveInnerThickness / 2., caloDim.dz(), layerHeight[iLayer] / 2.); dd4hep::Trd1 layerPassiveInnerShape(passiveInnerThicknessLayer[iLayer] / 2., passiveInnerThicknessLayer[iLayer+1] / 2., caloDim.dz(), layerHeight[iLayer] / 2.); dd4hep::Volume layerPassiveInnerVol(passiveInnerMaterial, layerPassiveInnerShape, aLcdd.material(passiveInnerMaterial)); @@ -501,10 +387,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } } - if (passiveOuter.isSensitive()) { - // if the outer part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer - // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive lLog << MSG::DEBUG << "Passive outer volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset / cosPassiveAngle; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { @@ -522,10 +405,7 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } } - if (passiveGlue.isSensitive()) { - // if the glue is sensitive (to study energy deposited in it, for calculation of per-layer - // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive lLog << MSG::DEBUG << "Passive glue volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset / cosPassiveAngle; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { @@ -544,13 +424,53 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } + // translate and rotate the elements of the module appropriately + // the Pb absorber does not need to be rotated, but the glue and + // the outer absorbers have to, in case of trapezoidal absorbers. + // The glue and steel absorbers also have to be translated in x-y + // to the proper positions on the two sides of the inner absorber + dd4hep::PlacedVolume passiveInnerPhysVol = + passiveVol.placeVolume(passiveInnerVol, dd4hep::Position(0, 0, layerHeight[0] / 2.)); + dd4hep::PlacedVolume passiveInnerPhysVolFirstLayer = + passiveVol.placeVolume(passiveInnerVolFirstLayer, dd4hep::Position(0, 0, layerFirstOffset)); + dd4hep::PlacedVolume passiveOuterPhysVolBelow = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 2. - rotatedOuterThickness / 4., 0, 0))); + dd4hep::PlacedVolume passiveOuterPhysVolAbove = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 2. + rotatedOuterThickness / 4., 0, 0))); + dd4hep::PlacedVolume passiveGluePhysVolBelow = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 4., 0, 0))); + dd4hep::PlacedVolume passiveGluePhysVolAbove = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 4., 0, 0))); + passiveInnerPhysVol.addPhysVolID("subtype", 0); + passiveInnerPhysVolFirstLayer.addPhysVolID("subtype", 0); + passiveOuterPhysVolBelow.addPhysVolID("subtype", 1); + passiveOuterPhysVolAbove.addPhysVolID("subtype", 2); + passiveGluePhysVolBelow.addPhysVolID("subtype", 3); + passiveGluePhysVolAbove.addPhysVolID("subtype", 4); + if (passiveInner.isSensitive()) { + passiveInnerVolFirstLayer.setSensitiveDetector(aSensDet); + passiveInnerPhysVolFirstLayer.addPhysVolID("layer", 0); + dd4hep::DetElement passiveInnerDetElemFirstLayer("layer", 0); + passiveInnerDetElemFirstLayer.setPlacement(passiveInnerPhysVolFirstLayer); + } + ////////////////////////////// // READOUT PLANES ////////////////////////////// dd4hep::Box readoutShape(readoutThickness / 2., caloDim.dz(), planeLength / 2.); dd4hep::Volume readoutVol(readoutMaterial, readoutShape, aLcdd.material(readoutMaterial)); - // if the readout is sensitive (to study energy deposited in it, for calculation of per-layer - // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive if (readout.isSensitive()) { lLog << MSG::INFO << "ECAL readout volume set as sensitive" << endmsg; double layerOffset = layerFirstOffset; @@ -570,18 +490,55 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } ////////////////////////////// - // ACTIVE ELEMENTS + // ACTIVE ////////////////////////////// - // creating shape for rows of layers (active material between two passive planes, with readout in the middle) + // The active (LAr/LKr) elements are constructed subtracting from their + // envelope the readout and passive elements + // This requires some calculations to - // - first define area between two passive planes, area can reach up to the symmetry axis of passive plane - dd4hep::Trd1 activeOuterShape(activeInThickness, activeOutThickness, caloDim.dz(), planeLength / 2.); + // Thickness of active layers at inner radius and outer ( = distance between passive plane and readout plane) + // at inner radius: distance projected at plane perpendicular to readout plane + double activeInThickness = Rmin * sin(dPhi / 2.) * cos(angle); + activeInThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // at outer radius: distance projected at plane perpendicular to readout plane + double activeOutThickness = (Rmin + planeLength) * sin(dPhi / 2.) * cos(angle); + // make correction for outer readius caused by inclination angle + // first calculate intersection of readout plane and plane parallel to shifted passive plane + double xIntersect = (Rmin * (tan(angle) - cos(dPhi / 2.) * tan(angle + dPhi / 2.)) - planeLength * sin(dPhi / 2.)) / + (tan(angle) - tan(angle + dPhi / 2.)); + double yIntersect = tan(angle) * xIntersect + Rmin * (sin(dPhi / 2.) - tan(angle)) + planeLength * sin(dPhi / 2.); + // distance from inner radius to intersection + double correction = + planeLength - sqrt(pow(xIntersect - Rmin * cos(dPhi / 2), 2) + pow(yIntersect - Rmin * sin(dPhi / 2), 2)); + // correction to the active thickness + activeOutThickness += 2. * correction * sin(dPhi / 4.); + activeOutThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // print the active layer dimensions + double activeInThicknessAfterSubtraction = + 2. * activeInThickness - readoutThickness - 2. * activePassiveOverlap * passiveThickness; + double activeOutThicknessAfterSubtraction = + 2. * activeOutThickness - readoutThickness - 2. * activePassiveOverlap * + (passiveThickness + passiveInnerThicknessMax - passiveInnerThicknessMin); // correct thickness for trapezoid + lLog << MSG::INFO << "Active elements:" << endmsg; + lLog << MSG::INFO << " material = " << activeMaterial << endmsg; + lLog << MSG::INFO << " thickness at inner radius (cm) = " << activeInThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness at outer radius (cm) = " << activeOutThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness relative increase from inner to outer radius = " + << (activeOutThicknessAfterSubtraction - activeInThicknessAfterSubtraction) * 100 / + activeInThicknessAfterSubtraction + << " %." << endmsg; + lLog << MSG::INFO + << " active passive initial overlap (before subtraction) (cm) = " << passiveThickness/dd4hep::cm * activePassiveOverlap + << " = " << activePassiveOverlap * 100 << " %" << endmsg; - // - subtract readout shape from the middle + // creating shape for rows of layers (active material between two passive planes, with readout in the middle) + // first define area between two passive planes, area can reach up to the symmetry axis of passive plane + dd4hep::Trd1 activeOuterShape(activeInThickness, activeOutThickness, caloDim.dz(), planeLength / 2.); + // subtract readout shape from the middle dd4hep::SubtractionSolid activeShapeNoReadout(activeOuterShape, readoutShape); - // - make calculation for active plane that is inclined with 0 deg (= offset + angle) + // make calculation for active plane that is inclined with 0 deg (= offset + angle) double Cx = Rmin * cos(-angle) + planeLength / 2.; double Cy = Rmin * sin(-angle); double Ax = Rmin * cos(-angle + dPhi / 2.) + planeLength / 2. * cos(dPhi / 2.); @@ -600,25 +557,20 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, zprimB = CBx; xprimB = CBy; - // - subtract readout shape from the middle + // subtract passive volume above dd4hep::SubtractionSolid activeShapeNoPassiveAbove( activeShapeNoReadout, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), - dd4hep::Position(-fabs(xprim), 0, fabs(zprim)))); - - // - subtract passive volume below + dd4hep::Position(-fabs(xprim), 0, fabs(zprim)))); + // subtract passive volume below dd4hep::SubtractionSolid activeShape( activeShapeNoPassiveAbove, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), - dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB)))); - - // - create the active volume, which will contain the layers filled with LAr + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB)))); dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); - // place layers within active volume std::vector layerPhysVols; - - // - first, calculate the layer widths at inner and outer radii + // place layers within active volume std::vector layerInThickness; std::vector layerOutThickness; double layerIncreasePerUnitThickness = (activeOutThickness - activeInThickness) / layersTotalHeight; @@ -630,29 +582,19 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } layerOutThickness.push_back(layerInThickness[iLay] + layerIncreasePerUnitThickness * layerHeight[iLay]); } - - // - then, loop on the layers to create and place the volumes double layerOffset = layerFirstOffset; for (uint iLayer = 0; iLayer < numLayers; iLayer++) { - // define the layer envelope dd4hep::Trd1 layerOuterShape(layerInThickness[iLayer], layerOutThickness[iLayer], caloDim.dz(), layerHeight[iLayer] / 2.); - - // subtract readout shape from the middle dd4hep::SubtractionSolid layerShapeNoReadout(layerOuterShape, readoutShape); - - // subtract readout shape from the middle dd4hep::SubtractionSolid layerShapeNoPassiveAbove( layerShapeNoReadout, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), - dd4hep::Position(-fabs(xprim), 0, fabs(zprim) - layerOffset))); - + dd4hep::Position(-fabs(xprim), 0, fabs(zprim) - layerOffset))); // subtract passive volume below dd4hep::SubtractionSolid layerShape( layerShapeNoPassiveAbove, passiveShape, dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), - dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB) - layerOffset))); - - // create the volume, filled with active material, set as sensitive, and position it properly within active volume + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB) - layerOffset))); dd4hep::Volume layerVol("layer", layerShape, aLcdd.material(activeMaterial)); layerVol.setSensitiveDetector(aSensDet); layerPhysVols.push_back(activeVol.placeVolume(layerVol, dd4hep::Position(0, 0, layerOffset))); @@ -662,14 +604,12 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, } } - // Place elements in bath: passive planes, readout planes and rows of layers dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); + std::vector activePhysVols; + // Next place elements: passive planes, readout planes and rows of layers for (uint iPlane = 0; iPlane < numPlanes; iPlane++) { - - // + // first calculate positions of passive and readout planes // PASSIVE - // - // calculate centre position of the plane without plane rotation double phi = offsetPassivePhi + iPlane * dPhi; double xRadial = (Rmin + planeLength / 2.) * cos(phi); @@ -681,22 +621,18 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, double xRotated = xRmin + (xRadial - xRmin) * cos(angle) - (yRadial - yRmin) * sin(angle); double yRotated = yRmin + (xRadial - xRmin) * sin(angle) + (yRadial - yRmin) * cos(angle); dd4hep::Transform3D transform(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane - * - dd4hep::RotationY(M_PI / 2. // to get pointed towards centre - - - phi - angle), - dd4hep::Position(xRotated, yRotated, 0)); - // create and place volume in bath + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phi - angle), + dd4hep::Position(xRotated, yRotated, 0)); dd4hep::PlacedVolume passivePhysVol = bathVol.placeVolume(passiveVol, transform); passivePhysVol.addPhysVolID("module", iPlane); passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout dd4hep::DetElement passiveDetElem(bathDetElem, "passive" + std::to_string(iPlane), iPlane); passiveDetElem.setPlacement(passivePhysVol); - // // READOUT - // - // calculate centre position of the plane without plane rotation double phiRead = offsetReadoutPhi + iPlane * dPhi; double xRadialRead = (Rmin + planeLength / 2.) * cos(phiRead); @@ -707,45 +643,39 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, // rotate centre by angle wrt beginning of plane double xRotatedRead = xRminRead + (xRadialRead - xRminRead) * cos(angle) - (yRadialRead - yRminRead) * sin(angle); double yRotatedRead = yRminRead + (xRadialRead - xRminRead) * sin(angle) + (yRadialRead - yRminRead) * cos(angle); - dd4hep::Transform3D transformRead(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane - * - dd4hep::RotationY(M_PI / 2. // to get pointed towards centre - - - phiRead - angle), - dd4hep::Position(xRotatedRead, yRotatedRead, 0)); - // create and place volume in bath + dd4hep::Transform3D transformRead( + dd4hep::RotationX(-M_PI / 2.) // to get in XY plane + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phiRead - angle), + dd4hep::Position(xRotatedRead, yRotatedRead, 0)); dd4hep::PlacedVolume readoutPhysVol = bathVol.placeVolume(readoutVol, transformRead); readoutPhysVol.addPhysVolID("module", iPlane); readoutPhysVol.addPhysVolID("type", 2); // 0 = active, 1 = passive, 2 = readout dd4hep::DetElement readoutDetElem(bathDetElem, "readout" + std::to_string(iPlane), iPlane); readoutDetElem.setPlacement(readoutPhysVol); - // // ACTIVE - // - - // same positioning as readout - dd4hep::Transform3D transformActive(dd4hep::RotationX(-M_PI / 2) - * - dd4hep::RotationY(M_PI / 2 - phiRead - angle), - dd4hep::Position(xRotatedRead, yRotatedRead, 0)); - // create and place volume in bath - dd4hep::PlacedVolume activePhysVol = bathVol.placeVolume(activeVol, transformActive); - activePhysVol.addPhysVolID("module", iPlane); - activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout + dd4hep::Rotation3D rotationActive(dd4hep::RotationX(-M_PI / 2) * + dd4hep::RotationY(M_PI / 2 - phiRead - angle)); + activePhysVols.push_back(bathVol.placeVolume( + activeVol, + dd4hep::Transform3D(rotationActive, dd4hep::Position(xRotatedRead, yRotatedRead, 0)))); + activePhysVols.back().addPhysVolID("module", iPlane); + activePhysVols.back().addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout + } + dd4hep::PlacedVolume bathPhysVol = envelopeVol.placeVolume(bathVol); + bathDetElem.setPlacement(bathPhysVol); + for (uint iPlane = 0; iPlane < numPlanes; iPlane++) { dd4hep::DetElement activeDetElem(bathDetElem, "active" + std::to_string(iPlane), iPlane); - activeDetElem.setPlacement(activePhysVol); - // place the layers inside the active element + activeDetElem.setPlacement(activePhysVols[iPlane]); for (uint iLayer = 0; iLayer < numLayers; iLayer++) { dd4hep::DetElement layerDetElem(activeDetElem, "layer" + std::to_string(iLayer), iLayer); layerDetElem.setPlacement(layerPhysVols[iLayer]); } } - // Place bath in envelope - dd4hep::PlacedVolume bathPhysVol = envelopeVol.placeVolume(bathVol); - bathDetElem.setPlacement(bathPhysVol); - // Place the envelope dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVol); From 4a90833159d8a62abaad098b7f5d42ba1ce8edf3 Mon Sep 17 00:00:00 2001 From: Giovanni Marchiori Date: Thu, 7 Nov 2024 16:58:46 +0100 Subject: [PATCH 074/133] move changes to new ALLEGRO version --- .../compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml | 122 +++ .../compact/ALLEGRO_o1_v04/DectDimensions.xml | 1 + .../ALLEGRO_o1_v04/DectEmptyMaster.xml | 1 + .../ALLEGRO_o1_v04/DriftChamber_o1_v02.xml | 1 + .../ECalBarrel_thetamodulemerged.xml | 165 ++++ ...alBarrel_thetamodulemerged_calibration.xml | 157 ++++ .../ECalBarrel_thetamodulemerged_upstream.xml | 157 ++++ .../ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml | 1 + .../ECalEndcaps_Turbine_calibration.xml | 1 + .../ALLEGRO_o1_v04/ECalEndcaps_coneCryo.xml | 1 + .../ALLEGRO_o1_v04/HCalBarrel_TileCal_v02.xml | 1 + .../HCalEndcaps_ThreeParts_TileCal_v02.xml | 1 + .../compact/ALLEGRO_o1_v04/LumiCal.xml | 1 + .../compact/ALLEGRO_o1_v04/MuonTagger.xml | 1 + .../ALLEGRO_o1_v04/SiliconWrapper_o1_v03.xml | 1 + .../VertexComplete_IDEA_o1_v03.xml | 1 + .../compact/ALLEGRO_o1_v04/elements.xml | 1 + .../compact/ALLEGRO_o1_v04/materials.xml | 1 + FCCee/ALLEGRO/compact/README.md | 2 + ...leLiquid_InclinedTrapezoids_o1_v04_geo.cpp | 767 ++++++++++++++++++ 20 files changed, 1384 insertions(+) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectDimensions.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectEmptyMaster.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DriftChamber_o1_v02.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_calibration.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_upstream.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_coneCryo.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v02.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v02.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/LumiCal.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/MuonTagger.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/SiliconWrapper_o1_v03.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/VertexComplete_IDEA_o1_v03.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/elements.xml create mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/materials.xml create mode 100644 detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml new file mode 100644 index 000000000..a0a5dcf1a --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml @@ -0,0 +1,122 @@ + + + + + + Master compact file describing the latest developments of the FCCee ALLEGRO detector concept. With respect to v02 it features an ECal barrel with 11 layers and cell corners projective along phi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectDimensions.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectDimensions.xml new file mode 120000 index 000000000..e998b2922 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectDimensions.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/DectDimensions.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectEmptyMaster.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectEmptyMaster.xml new file mode 120000 index 000000000..dc89bc09e --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DectEmptyMaster.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/DectEmptyMaster.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DriftChamber_o1_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DriftChamber_o1_v02.xml new file mode 120000 index 000000000..90e9942c5 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/DriftChamber_o1_v02.xml @@ -0,0 +1 @@ +../../../IDEA/compact/IDEA_o1_v03/DriftChamber_o1_v02.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged.xml new file mode 100644 index 000000000..fec0ee72c --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged.xml @@ -0,0 +1,165 @@ + + + + + + Settings for the inclined EM calorimeter. + The barrel is filled with liquid argon. Passive material includes lead in the middle and steal on the outside, glued together. + Passive plates are inclined by a certain angle from the radial direction. + In between of two passive plates there is a readout. + Space between the plate and readout is of trapezoidal shape and filled with liquid argon. + Definition of sizes, visualization settings, readout and longitudinal segmentation are specified. + The geometrical parameters (tilt and plane lengths) are adjusted, based on EMBarrel_rmin/max, to yield 1536 modules and cell corners aligned in phi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_calibration.xml new file mode 100644 index 000000000..e17a582d2 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_calibration.xml @@ -0,0 +1,157 @@ + + + + + Settings for the inclined EM calorimeter. + The barrel is filled with liquid argon. Passive material includes lead in the middle and steal on the outside, glued together. + Passive plates are inclined by a certain angle from the radial direction. + In between of two passive plates there is a readout. + Space between the plate and readout is of trapezoidal shape and filled with liquid argon. + Definition of sizes, visualization settings, readout and longitudinal segmentation are specified. + The geometrical parameters (tilt and plane lengths) are adjusted, based on EMBarrel_rmin/max, to yield 1536 modules and cell corners aligned in phi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_upstream.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_upstream.xml new file mode 100644 index 000000000..6e79b4aba --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalBarrel_thetamodulemerged_upstream.xml @@ -0,0 +1,157 @@ + + + + + Settings for the inclined EM calorimeter. + The barrel is filled with liquid argon. Passive material includes lead in the middle and steal on the outside, glued together. + Passive plates are inclined by a certain angle from the radial direction. + In between of two passive plates there is a readout. + Space between the plate and readout is of trapezoidal shape and filled with liquid argon. + Definition of sizes, visualization settings, readout and longitudinal segmentation are specified. + The geometrical parameters (tilt and plane lengths) are adjusted, based on EMBarrel_rmin/max, to yield 1536 modules and cell corners aligned in phi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,theta:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml new file mode 120000 index 000000000..1b74f8d80 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml new file mode 120000 index 000000000..1f39f7301 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_coneCryo.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_coneCryo.xml new file mode 120000 index 000000000..fe5d63a5d --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_coneCryo.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/ECalEndcaps_coneCryo.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v02.xml new file mode 120000 index 000000000..ba2dd5133 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v02.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/HCalBarrel_TileCal_v02.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v02.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v02.xml new file mode 120000 index 000000000..2544157c7 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v02.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v02.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/LumiCal.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/LumiCal.xml new file mode 120000 index 000000000..7d662eef0 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/LumiCal.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/LumiCal.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/MuonTagger.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/MuonTagger.xml new file mode 120000 index 000000000..e18a1e0df --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/MuonTagger.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/MuonTagger.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/SiliconWrapper_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/SiliconWrapper_o1_v03.xml new file mode 120000 index 000000000..70972fa9c --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/SiliconWrapper_o1_v03.xml @@ -0,0 +1 @@ +../../../IDEA/compact/IDEA_o1_v03/SiliconWrapper_o1_v03.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/VertexComplete_IDEA_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/VertexComplete_IDEA_o1_v03.xml new file mode 120000 index 000000000..b0bf97dfa --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/VertexComplete_IDEA_o1_v03.xml @@ -0,0 +1 @@ +../../../IDEA/compact/IDEA_o1_v03/VertexComplete_IDEA_o1_v03.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/elements.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/elements.xml new file mode 120000 index 000000000..3e4f55fdd --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/elements.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/elements.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/materials.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/materials.xml new file mode 120000 index 000000000..fe62b9a71 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/materials.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/materials.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/README.md b/FCCee/ALLEGRO/compact/README.md index 9da75a3de..d5c7e70f0 100644 --- a/FCCee/ALLEGRO/compact/README.md +++ b/FCCee/ALLEGRO/compact/README.md @@ -12,3 +12,5 @@ Magnetic fields (solenoid + MDI) have been added. Added "turbine-style" endcap ecal, and invoke this in the top-level xml (replacing the coneCyro geometry). Added HCalBarrel_TileCal_v02.xml which uses HCalTileBarrel_o1_v02_geo.cpp and removed unused readout BarHCal_Readout_phi. Added HCalEndcaps_ThreeParts_TileCal_v02.xml which uses HCalThreePartsEndcap_o1_v02_geo.cpp. Additionally, wrt v02 the readout was migrated to the theta-phi segmentation; unused readout *Readout_phi was removed; radial dimensions of layers were modified, so the outer radius of all three cylinders is the same. + +ALLEGRO_o1_v04: same as v03, but material in inner part of absorber in first layer of ECAL is configurable and set by default to G10 \ No newline at end of file diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp new file mode 100644 index 000000000..11eb17d16 --- /dev/null +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp @@ -0,0 +1,767 @@ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Handle.h" +#include "XML/Utilities.h" + +#include + +// like v02, but in xml the layer dimensions are along the electrode +// directions, without rescaling by R/L where R = radial extent of ECAL +// and L = electrode length + +// todo: remove gaudi logging and properly capture output +#define endmsg std::endl +#define lLog std::cout +namespace MSG { +const std::string ERROR = "createECalBarrelInclined ERROR "; +const std::string DEBUG = "createECalBarrelInclined DEBUG "; +const std::string INFO = "createECalBarrelInclined INFO "; +} + +namespace det { +static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, + dd4hep::xml::Handle_t aXmlElement, + dd4hep::SensitiveDetector aSensDet) { + + dd4hep::xml::DetElement xmlDetElem = aXmlElement; + std::string nameDet = xmlDetElem.nameStr(); + dd4hep::xml::Dimension dim(xmlDetElem.dimensions()); + dd4hep::DetElement caloDetElem(nameDet, xmlDetElem.id()); + + // Create air envelope for the whole barrel + dd4hep::Volume envelopeVol(nameDet + "_vol", dd4hep::Tube(dim.rmin(), dim.rmax(), dim.dz()), + aLcdd.material("Air")); + envelopeVol.setVisAttributes(aLcdd, dim.visStr()); + + // Retrieve cryostat data + dd4hep::xml::DetElement cryostat = aXmlElement.child(_Unicode(cryostat)); + dd4hep::xml::Dimension cryoDim(cryostat.dimensions()); + double cryoThicknessFront = cryoDim.rmin2() - cryoDim.rmin1(); + dd4hep::xml::DetElement cryoFront = cryostat.child(_Unicode(front)); + dd4hep::xml::DetElement cryoBack = cryostat.child(_Unicode(back)); + dd4hep::xml::DetElement cryoSide = cryostat.child(_Unicode(side)); + bool cryoFrontSensitive = cryoFront.isSensitive(); + bool cryoBackSensitive = cryoBack.isSensitive(); + bool cryoSideSensitive = cryoSide.isSensitive(); + + // Retrieve active and passive material data + dd4hep::xml::DetElement calo = aXmlElement.child(_Unicode(calorimeter)); + dd4hep::xml::Dimension caloDim(calo.dimensions()); + dd4hep::xml::DetElement active = calo.child(_Unicode(active)); + std::string activeMaterial = active.materialStr(); + double activeThickness = active.thickness(); + + // Retrieve information about active/passive overlap + dd4hep::xml::DetElement overlap = active.child(_Unicode(overlap)); + double activePassiveOverlap = overlap.offset(); + if (activePassiveOverlap < 0 || activePassiveOverlap > 0.5) { + // todo: ServiceHandle incidentSvc("IncidentSvc", "ECalConstruction"); + lLog << MSG::ERROR << "Overlap between active and passive cannot be more than half of passive plane!" << endmsg; + //todo: incidentSvc->fireIncident(Incident("ECalConstruction", "GeometryFailure")); + } + + // Retrieve length of layers along electrode + dd4hep::xml::DetElement layers = calo.child(_Unicode(layers)); + uint numLayers = 0; + std::vector layerHeight; + double layersTotalHeight = 0; + for (dd4hep::xml::Collection_t layer_coll(layers, _Unicode(layer)); layer_coll; ++layer_coll) { + dd4hep::xml::Component layer = layer_coll; + numLayers += layer.repeat(); + for (int iLay = 0; iLay < layer.repeat(); iLay++) { + layerHeight.push_back(layer.thickness()); + } + layersTotalHeight += layer.repeat() * layer.thickness(); + } + lLog << MSG::DEBUG << "Total electrode length from calorimeter xml description (cm): " << layersTotalHeight/dd4hep::cm << endmsg; + + // The following code checks if the xml geometry file contains a constant defining + // the number of layers the barrel. In that case, it makes the program abort + // if the number of planes in the xml is different from the one calculated from + // the geometry. This is because the number of layers is needed + // in other parts of the code (the readout for the FCC-ee ECAL with + // inclined modules). + int nLayers = -1; + try { + nLayers = aLcdd.constant("ECalBarrelNumLayers"); + } + catch(...) { + ; + } + if (nLayers > 0 && nLayers != int(numLayers)) { + lLog << MSG::ERROR << "Incorrect number of layers (ECalBarrelNumLayers) in readout in calorimeter xml description!" << endmsg; + lLog << MSG::ERROR << "Number of layers should be: " << numLayers << endmsg; + // todo: incidentSvc->fireIncident(Incident("ECalConstruction", "GeometryFailure")); + // make the code crash (incidentSvc does not work) + // Andre, Alvaro, assert replaced by exception + throw std::runtime_error("Incorrect number of layers (ECalBarrelNumLayers) in calorimeter xml description!"); + } + + // Retrieve information about the readout + dd4hep::xml::DetElement readout = calo.child(_Unicode(readout)); + std::string readoutMaterial = readout.materialStr(); + double readoutThickness = readout.thickness(); + + // Retrieve info about passive elements + // (glue, outer - typically steel, inner - typically Pb, and LAr in presampling layer) + dd4hep::xml::DetElement passive = calo.child(_Unicode(passive)); + dd4hep::xml::DetElement passiveInner = passive.child(_Unicode(inner)); + dd4hep::xml::DetElement passiveInnerMax = passive.child(_Unicode(innerMax)); + dd4hep::xml::DetElement passiveOuter = passive.child(_Unicode(outer)); + dd4hep::xml::DetElement passiveGlue = passive.child(_Unicode(glue)); + std::string passiveInnerMaterial = passiveInnerMax.materialStr(); + std::string passiveInnerMaterialFirstLayer = passiveInner.materialStr(); + std::string passiveOuterMaterial = passiveOuter.materialStr(); + std::string passiveGlueMaterial = passiveGlue.materialStr(); + double passiveInnerThicknessMin = passiveInner.thickness(); + double passiveInnerThicknessMax = passiveInnerMax.thickness(); + double passiveOuterThickness = passiveOuter.thickness(); + double passiveGlueThickness = passiveGlue.thickness(); + double passiveThickness = passiveInnerThicknessMin + passiveOuterThickness + passiveGlueThickness; + // inclination angle + double angle = passive.rotation().angle(); + + // Retrieve info about bath + dd4hep::xml::DetElement bath = aXmlElement.child(_Unicode(bath)); + dd4hep::xml::Dimension bathDim(bath.dimensions()); + double bathRmin = bathDim.rmin(); + double bathRmax = bathDim.rmax(); + dd4hep::Tube bathOuterShape(bathRmin, bathRmax, caloDim.dz()); // make it 4 volumes + 5th for detector envelope + dd4hep::Tube bathAndServicesOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), caloDim.dz()); // make it 4 volumes + 5th for detector envelope + + // 1. Create cryostat + if (cryoThicknessFront > 0) { + dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::Tube cryoBackShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); + dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); + lLog << MSG::INFO + << "ECAL cryostat: front: rmin (cm) = " << cryoDim.rmin1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + lLog << MSG::INFO + << "ECAL cryostat: back: rmin (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax2()/dd4hep::cm + << " dz (cm) = " << cryoDim.dz()/dd4hep::cm << endmsg; + lLog << MSG::INFO + << "ECAL cryostat: side: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << (cryoDim.dz() - caloDim.dz())/dd4hep::cm << endmsg; + dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoSideVol(cryostat.nameStr()+"_side", cryoSideShape, aLcdd.material(cryostat.materialStr())); + dd4hep::PlacedVolume cryoFrontPhysVol = envelopeVol.placeVolume(cryoFrontVol); + dd4hep::PlacedVolume cryoBackPhysVol = envelopeVol.placeVolume(cryoBackVol); + dd4hep::PlacedVolume cryoSidePhysVol = envelopeVol.placeVolume(cryoSideVol); + if (cryoFrontSensitive) { + cryoFrontVol.setSensitiveDetector(aSensDet); + cryoFrontPhysVol.addPhysVolID("cryo", 1); + cryoFrontPhysVol.addPhysVolID("type", 1); + lLog << MSG::INFO << "ECAL Cryostat front volume set as sensitive" << endmsg; + } + if (cryoBackSensitive) { + cryoBackVol.setSensitiveDetector(aSensDet); + cryoBackPhysVol.addPhysVolID("cryo", 1); + cryoBackPhysVol.addPhysVolID("type", 2); + lLog << MSG::INFO << "ECAL Cryostat back volume set as sensitive" << endmsg; + } + if (cryoSideSensitive) { + cryoSideVol.setSensitiveDetector(aSensDet); + cryoSidePhysVol.addPhysVolID("cryo", 1); + cryoSidePhysVol.addPhysVolID("type", 3); + lLog << MSG::INFO << "ECAL Cryostat front volume set as sensitive" << endmsg; + } + dd4hep::DetElement cryoFrontDetElem(caloDetElem, "cryo_front", 0); + cryoFrontDetElem.setPlacement(cryoFrontPhysVol); + dd4hep::DetElement cryoBackDetElem(caloDetElem, "cryo_back", 0); + cryoBackDetElem.setPlacement(cryoBackPhysVol); + dd4hep::DetElement cryoSideDetElem(caloDetElem, "cryo_side", 0); + cryoSideDetElem.setPlacement(cryoSidePhysVol); + // 1.2. Create place-holder for services + dd4hep::Tube servicesFrontShape(cryoDim.rmin2(), bathRmin, caloDim.dz()); + dd4hep::Tube servicesBackShape(bathRmax, cryoDim.rmax1(), caloDim.dz()); + lLog << MSG::INFO + << "ECAL services: front: rmin (cm) = " << cryoDim.rmin2()/dd4hep::cm + << " rmax (cm) = " << bathRmin/dd4hep::cm/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + lLog << MSG::INFO + << "ECAL services: back: rmin (cm) = " << bathRmax/dd4hep::cm + << " rmax (cm) = " << cryoDim.rmax1()/dd4hep::cm + << " dz (cm) = " << caloDim.dz()/dd4hep::cm << endmsg; + dd4hep::Volume servicesFrontVol("services_front", servicesFrontShape, aLcdd.material(activeMaterial)); + dd4hep::Volume servicesBackVol("services_back", servicesBackShape, aLcdd.material(activeMaterial)); + dd4hep::PlacedVolume servicesFrontPhysVol = envelopeVol.placeVolume(servicesFrontVol); + dd4hep::PlacedVolume servicesBackPhysVol = envelopeVol.placeVolume(servicesBackVol); + if (cryoFrontSensitive) { + servicesFrontVol.setSensitiveDetector(aSensDet); + servicesFrontPhysVol.addPhysVolID("cryo", 1); + servicesFrontPhysVol.addPhysVolID("type", 4); + lLog << MSG::INFO << "ECAL Services front volume set as sensitive" << endmsg; + } + if (cryoBackSensitive) { + servicesBackVol.setSensitiveDetector(aSensDet); + servicesBackPhysVol.addPhysVolID("cryo", 1); + servicesBackPhysVol.addPhysVolID("type", 5); + lLog << MSG::INFO << "ECAL Services back volume set as sensitive" << endmsg; + } + dd4hep::DetElement servicesFrontDetElem(caloDetElem, "services_front", 0); + servicesFrontDetElem.setPlacement(servicesFrontPhysVol); + dd4hep::DetElement servicesBackDetElem(caloDetElem, "services_back", 0); + servicesBackDetElem.setPlacement(servicesBackPhysVol); + } + + // 2. Create bath that is inside the cryostat and surrounds the detector + // Bath is filled with active material -> but not sensitive + dd4hep::Volume bathVol(activeMaterial + "_bath", bathOuterShape, aLcdd.material(activeMaterial)); + lLog << MSG::INFO << "ECAL bath: material = " << activeMaterial + << " rmin (cm) = " << bathRmin/dd4hep::cm + << " rmax (cm) = " << bathRmax/dd4hep::cm << endmsg; + double Rmin = caloDim.rmin(); + double Rmax = caloDim.rmax(); + double dR = Rmax - Rmin; + lLog << MSG::INFO + << "ECAL calorimeter volume rmin (cm) = " << Rmin/dd4hep::cm + << " rmax (cm) = " << Rmax/dd4hep::cm << endmsg; + lLog << MSG::INFO << "ECAL thickness of calorimeter (cm) = " << dR/dd4hep::cm << endmsg; + lLog << MSG::INFO << "ECAL thickness in front of calorimeter (between cryostat front and calorimeter) (cm) = " << (Rmin - cryoDim.rmin2())/dd4hep::cm << endmsg; + lLog << MSG::INFO << "ECAL thickness behind calorimeter (between calorimeter and cryostat back) (cm) = " << (cryoDim.rmax1() - Rmax)/dd4hep::cm << endmsg; + + // 3. Create the calorimeter by placing the passive material, trapezoid active layers, readout and again trapezoid + // active layers in the bath. + // sensitive detector for the layers (and, if desired to study energy deposited in absorbers or up/downstream, in services and cryo) + dd4hep::SensitiveDetector sd = aSensDet; + dd4hep::xml::Dimension sdType = xmlDetElem.child(_U(sensitive)); + sd.setType(sdType.typeStr()); + + // 3.a. Create the passive planes, readout in between of 2 passive planes and the remaining space filled with active + // material + + // Start by first calculating geometry parameters and printing out info + + ////////////////////////////// + // PASSIVE PLANES + ////////////////////////////// + + // passive volumes consist of inner part and two outer, joined by glue + lLog << MSG::INFO << "Passive elements:" << endmsg; + lLog << MSG::INFO << " material in inner part of absorber (except 1st layer) = " << passiveInnerMaterial << endmsg; + lLog << MSG::INFO << " material in inner part of absorber (1st layer) = " << passiveInnerMaterialFirstLayer << endmsg; + lLog << MSG::INFO << " material in outer part of absorber = " << passiveOuterMaterial << endmsg; + lLog << MSG::INFO << " material in middle part between inner and outer = " << passiveGlueMaterial << endmsg; + lLog << MSG::INFO << " thickness of inner part at inner radius (cm) = " << passiveInnerThicknessMin/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of inner part at outer radius (cm) = " << passiveInnerThicknessMax/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of outer part (cm) = " << passiveOuterThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness of middle part (cm) = " << passiveGlueThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " total thickness of absorber at inner radius (cm) = " << passiveThickness/dd4hep::cm << endmsg; + + ////////////////////////////// + // ELECTRODES + ////////////////////////////// + + lLog << MSG::INFO << "Electrodes:" << endmsg; + lLog << MSG::INFO << " rotation angle (radians) = " << angle << " , (degrees) = " << angle*57.295780 << endmsg; + + // calculate number of modules + uint numPlanes = + round(M_PI / asin((passiveThickness + activeThickness + readoutThickness) / (2. * Rmin * cos(angle)))); + + double dPhi = 2. * M_PI / numPlanes; + lLog << MSG::INFO << " number of planes (calculated) = " << numPlanes << " , azim. angle difference = " << dPhi << endmsg; + lLog << MSG::INFO << " distance at inner radius (cm) = " << 2. * M_PI * Rmin/dd4hep::cm / numPlanes << endmsg; + lLog << MSG::INFO << " distance at outer radius (cm) = " << 2. * M_PI * Rmax/dd4hep::cm / numPlanes << endmsg; + + // The following code checks if the xml geometry file contains a constant defining + // the number of planes in the barrel. In that case, it makes the program abort + // if the number of planes in the xml is different from the one calculated from + // the geometry. This is because the number of plane information (retrieved from the + // xml) is used in other parts of the code (the readout for the FCC-ee ECAL with + // inclined modules). In principle the code above should be refactored so that the number + // of planes is one of the inputs of the calculation and other geometrical parameters + // are adjusted accordingly. This is left for the future, and we use the workaround + // below to enforce for the time being that the number of planes is "correct" + int nModules = -1; + try { + nModules = aLcdd.constant("ECalBarrelNumPlanes"); + } + catch(...) { + ; + } + if (nModules > 0 && nModules != int(numPlanes)) { + lLog << MSG::ERROR << "Incorrect number of planes (ECalBarrelNumPlanes) in calorimeter xml description!" << endmsg; + // todo: incidentSvc->fireIncident(Incident("ECalConstruction", "GeometryFailure")); + // make the code crash (incidentSvc does not work) + // Andre, Alvaro, assert replaced by exception + throw std::runtime_error("Incorrect number of planes (ECalBarrelNumPlanes) in calorimeter xml description!"); + } + + // Readout is in the middle between two passive planes + double offsetPassivePhi = caloDim.offset() + dPhi / 2.; + double offsetReadoutPhi = caloDim.offset() + 0; + lLog << MSG::INFO << " readout material = " << readoutMaterial << endmsg; + lLog << MSG::INFO << " thickness of readout planes (cm) = " << readoutThickness/dd4hep::cm << endmsg; + lLog << MSG::INFO << " number of layers = " << numLayers << endmsg; + + // Electrode length, given inclination angle and min/max radius of the active calorimeter volume + double planeLength = -Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2)); + + double runningHeight = 0.; + lLog << MSG::INFO << " total length from Rmin, Rmax and angle (cm) = " << planeLength/dd4hep::cm << endmsg; + lLog << MSG::INFO << " predicted layer radii: " << endmsg; + for (uint iLay = 0; iLay < numLayers; iLay++) { + double Lmin = runningHeight; + double Lmax = runningHeight + layerHeight[iLay]; + runningHeight += layerHeight[iLay]; + double rMin = sqrt(Rmin*Rmin + Lmin*Lmin + 2*Rmin*Lmin*cos(angle)); + double rMax = sqrt(Rmin*Rmin + Lmax*Lmax + 2*Rmin*Lmax*cos(angle)); + lLog << MSG::INFO << " layer " << iLay << " (cm) = " << rMin/dd4hep::cm << " - " << rMax/dd4hep::cm << endmsg; + } + + // Check that electrode length is consistent with calorimeter radial extent + // and inclination angle to within 0.5 mm + if (fabs(planeLength - layersTotalHeight) > 0.05*dd4hep::cm) { + lLog << MSG::ERROR << " the sum of the electrode lengths per layer in the calorimeter xml file is not consistent with the length calculated from the calorimeter radial extent and the inclination angle" << endmsg; + throw std::runtime_error("Incorrect length of electrode layers in calorimeter xml description!"); + } + + // Calculate the thickness of the passive material in each layer + // it's not constant in case of trapezoidal absorbers (passiveInnerThicknessMax != passiveInnerThicknessMin) + // the code calculates the (max) passive thickness per layer i.e. at Rout of layer + // rescaling by runningHeight / Ltot + std::vector passiveInnerThicknessLayer(numLayers+1); + lLog << MSG::DEBUG << "passiveInnerThickness: " << endmsg; + runningHeight = 0.; + for (uint iLay = 0; iLay < numLayers; iLay++) { + passiveInnerThicknessLayer[iLay] = passiveInnerThicknessMin + (passiveInnerThicknessMax - passiveInnerThicknessMin) * + (runningHeight) / layersTotalHeight; + lLog << MSG::DEBUG << " layer " << iLay << " = " << passiveInnerThicknessLayer[iLay] << " cm" << endmsg; + } + passiveInnerThicknessLayer[numLayers] = passiveInnerThicknessMin + (passiveInnerThicknessMax - passiveInnerThicknessMin) * + (runningHeight) / layersTotalHeight; + + lLog << MSG::DEBUG << " layer " << numLayers << " = " << passiveInnerThicknessLayer[numLayers] << " cm" << endmsg; + + // Calculate the angle of the passive elements if trapezoidal absorbers are used (Max != Min) + // if parallel absorbers are used then passiveAngle = 0 and cosPassiveAngle = 1 + double passiveAngle = atan2((passiveInnerThicknessMax - passiveInnerThicknessMin) / 2., planeLength); + double cosPassiveAngle = cos(passiveAngle); + double rotatedOuterThickness = passiveOuterThickness / cosPassiveAngle; + double rotatedGlueThickness = passiveGlueThickness / cosPassiveAngle; + + // Distance from the center of the electrode to the center of the 1st layer, in the electrode direction + double layerFirstOffset = -planeLength / 2. + layerHeight[0] / 2.; + + ////////////////////////////// + // ACTIVE ELEMENTS + ////////////////////////////// + + // The active (LAr/LKr) elements are constructed subtracting from their + // envelope the readout and passive elements. + // This requires some calculations + + // Thickness of active layers at inner radius and outer ( = distance between passive plane and readout plane) + // at inner radius: distance projected at plane perpendicular to readout plane + double activeInThickness = Rmin * sin(dPhi / 2.) * cos(angle); + activeInThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // at outer radius: distance projected at plane perpendicular to readout plane + double activeOutThickness = (Rmin + planeLength) * sin(dPhi / 2.) * cos(angle); + // make correction for outer readius caused by inclination angle + // first calculate intersection of readout plane and plane parallel to shifted passive plane + double xIntersect = (Rmin * (tan(angle) - cos(dPhi / 2.) * tan(angle + dPhi / 2.)) - planeLength * sin(dPhi / 2.)) / + (tan(angle) - tan(angle + dPhi / 2.)); + double yIntersect = tan(angle) * xIntersect + Rmin * (sin(dPhi / 2.) - tan(angle)) + planeLength * sin(dPhi / 2.); + // distance from inner radius to intersection + double correction = + planeLength - sqrt(pow(xIntersect - Rmin * cos(dPhi / 2), 2) + pow(yIntersect - Rmin * sin(dPhi / 2), 2)); + // correction to the active thickness + activeOutThickness += 2. * correction * sin(dPhi / 4.); + activeOutThickness -= passiveThickness * (0.5 - activePassiveOverlap); + // print the active layer dimensions + double activeInThicknessAfterSubtraction = + 2. * activeInThickness - readoutThickness - 2. * activePassiveOverlap * passiveThickness; + double activeOutThicknessAfterSubtraction = + 2. * activeOutThickness - readoutThickness - 2. * activePassiveOverlap * + (passiveThickness + passiveInnerThicknessMax - passiveInnerThicknessMin); // correct thickness for trapezoid + lLog << MSG::INFO << "Active elements:" << endmsg; + lLog << MSG::INFO << " material = " << activeMaterial << endmsg; + lLog << MSG::INFO << " thickness at inner radius (cm) = " << activeInThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness at outer radius (cm) = " << activeOutThicknessAfterSubtraction/dd4hep::cm << endmsg; + lLog << MSG::INFO << " thickness relative increase from inner to outer radius = " + << (activeOutThicknessAfterSubtraction - activeInThicknessAfterSubtraction) * 100 / + activeInThicknessAfterSubtraction + << " %." << endmsg; + lLog << MSG::INFO + << " active passive initial overlap (before subtraction) (cm) = " << passiveThickness/dd4hep::cm * activePassiveOverlap + << " = " << activePassiveOverlap * 100 << " %" << endmsg; + + + // Now create the volumes + + ////////////////////////////// + // PASSIVE ELEMENTS + ////////////////////////////// + + // in the first calo layer we might use a different material (LAr instead of Pb) for the inner passive material + // to sample more uniformly for the upstream correction. So we need to split the volume into + // passiveInnerShapeFirstLayer (for first layer) and passiveInnerShape (for other layers) + // passiveInner elements' lengths along electrode are length of layer0 and suf of lengths of other layers + // for the other passive elements, which are boxes, their length has to be corrected for the rotation + // needed in case of trapezoidal absorbers, leading to the 1 / cosPassiveAngle factor + // For the same reason, their thickness in the direction perpendicular to the electrode + // has to be scaled by 1 / cosPassiveAngle, and thus we use rotatedOuterThickness and rotatedGlueThickness + // here + dd4hep::Trd1 passiveShape(passiveInnerThicknessMin / 2. + rotatedOuterThickness / 2. + rotatedGlueThickness / 2., + passiveInnerThicknessMax / 2. + rotatedOuterThickness / 2. + rotatedGlueThickness / 2., + caloDim.dz(), planeLength / 2.); + dd4hep::Trd1 passiveInnerShapeFirstLayer(passiveInnerThicknessMin / 2., passiveInnerThicknessLayer[1] / 2., caloDim.dz(), layerHeight[0] / 2.); + dd4hep::Trd1 passiveInnerShape(passiveInnerThicknessLayer[1] / 2., passiveInnerThicknessMax / 2., caloDim.dz(), planeLength / 2. - layerHeight[0] / 2.); + dd4hep::Box passiveOuterShape(passiveOuterThickness / 4., caloDim.dz(), planeLength / 2. / cosPassiveAngle); + dd4hep::Box passiveGlueShape(passiveGlueThickness / 4., caloDim.dz(), planeLength / 2. / cosPassiveAngle); + dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); + dd4hep::Volume passiveInnerVol(passiveInnerMaterial + "_passive", passiveInnerShape, + aLcdd.material(passiveInnerMaterial)); + dd4hep::Volume passiveInnerVolFirstLayer(passiveInnerMaterialFirstLayer + "_passive", passiveInnerShapeFirstLayer, + aLcdd.material(passiveInnerMaterialFirstLayer)); + dd4hep::Volume passiveOuterVol(passiveOuterMaterial + "_passive", passiveOuterShape, + aLcdd.material(passiveOuterMaterial)); + dd4hep::Volume passiveGlueVol(passiveGlueMaterial + "_passive", passiveGlueShape, + aLcdd.material(passiveGlueMaterial)); + + // translate and rotate the elements of the module appropriately + // the Pb absorber does not need to be rotated, but the glue and + // the outer absorbers have to, in case of trapezoidal absorbers. + // The glue and steel absorbers also have to be translated in x-y + // to the proper positions on the two sides of the inner absorber + + // - inner part of absorber, 2-N layers + // Their center is shifted wrt center of fulle absorber by length of 1st layer/2.0 + dd4hep::PlacedVolume passiveInnerPhysVol = passiveVol.placeVolume( + passiveInnerVol, + dd4hep::Position(0, 0, layerHeight[0] / 2.)); + // - inner part of absorber, first layer + // its center is shifted wrt center of full absorber by -(length of plane - length of 1st layer)/2.0 + dd4hep::PlacedVolume passiveInnerPhysVolFirstLayer = passiveVol.placeVolume( + passiveInnerVolFirstLayer, + dd4hep::Position(0, 0, layerFirstOffset)); + // - outer part of absorber, all layers, left side + dd4hep::PlacedVolume passiveOuterPhysVolBelow = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 2. - rotatedOuterThickness / 4., 0, 0))); + // - outer part of absorber, all layers, right side + dd4hep::PlacedVolume passiveOuterPhysVolAbove = passiveVol.placeVolume( + passiveOuterVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 2. + rotatedOuterThickness / 4., 0, 0))); + // - glue in absorber, all layers, left side + dd4hep::PlacedVolume passiveGluePhysVolBelow = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(-passiveAngle), + dd4hep::Position(-(passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. - + rotatedGlueThickness / 4., 0, 0))); + // - glue in absorber, all layers, right side + dd4hep::PlacedVolume passiveGluePhysVolAbove = passiveVol.placeVolume( + passiveGlueVol, + dd4hep::Transform3D(dd4hep::RotationY(passiveAngle), + dd4hep::Position((passiveInnerThicknessMin + passiveInnerThicknessMax) / 4. + + rotatedGlueThickness / 4., 0, 0))); + passiveInnerPhysVol.addPhysVolID("subtype", 0); + passiveInnerPhysVolFirstLayer.addPhysVolID("subtype", 0); + passiveOuterPhysVolBelow.addPhysVolID("subtype", 1); + passiveOuterPhysVolAbove.addPhysVolID("subtype", 2); + passiveGluePhysVolBelow.addPhysVolID("subtype", 3); + passiveGluePhysVolAbove.addPhysVolID("subtype", 4); + + // if the inner part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive + // first layer + if (passiveInner.isSensitive()) { + lLog << MSG::DEBUG << "Passive inner volume (1st layer) set as sensitive" << endmsg; + passiveInnerVolFirstLayer.setSensitiveDetector(aSensDet); + passiveInnerPhysVolFirstLayer.addPhysVolID("layer", 0); + dd4hep::DetElement passiveInnerDetElemFirstLayer("layer", 0); + passiveInnerDetElemFirstLayer.setPlacement(passiveInnerPhysVolFirstLayer); + } + // other layers + if (passiveInnerMax.isSensitive()) { + lLog << MSG::DEBUG << "Passive inner volume (2-N layers) set as sensitive" << endmsg; + double layerOffset = layerFirstOffset + layerHeight[1] / 2.; + for (uint iLayer = 1; iLayer < numLayers; iLayer++) { + dd4hep::Trd1 layerPassiveInnerShape(passiveInnerThicknessLayer[iLayer] / 2., passiveInnerThicknessLayer[iLayer+1] / 2., caloDim.dz(), layerHeight[iLayer] / 2.); + dd4hep::Volume layerPassiveInnerVol(passiveInnerMaterial, layerPassiveInnerShape, + aLcdd.material(passiveInnerMaterial)); + layerPassiveInnerVol.setSensitiveDetector(aSensDet); + dd4hep::PlacedVolume layerPassiveInnerPhysVol = + passiveInnerVol.placeVolume(layerPassiveInnerVol, dd4hep::Position(0, 0, layerOffset)); + layerPassiveInnerPhysVol.addPhysVolID("layer", iLayer); + dd4hep::DetElement layerPassiveInnerDetElem("layer", iLayer); + layerPassiveInnerDetElem.setPlacement(layerPassiveInnerPhysVol); + if (iLayer != numLayers - 1) { + layerOffset += layerHeight[iLayer] / 2. + layerHeight[iLayer + 1] / 2.; + } + } + } + + if (passiveOuter.isSensitive()) { + // if the outer part of the absorber is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive + lLog << MSG::DEBUG << "Passive outer volume set as sensitive" << endmsg; + double layerOffset = layerFirstOffset / cosPassiveAngle; + for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + dd4hep::Box layerPassiveOuterShape(passiveOuterThickness / 4., caloDim.dz(), layerHeight[iLayer] / 2. / cosPassiveAngle); + dd4hep::Volume layerPassiveOuterVol(passiveOuterMaterial, layerPassiveOuterShape, + aLcdd.material(passiveOuterMaterial)); + layerPassiveOuterVol.setSensitiveDetector(aSensDet); + dd4hep::PlacedVolume layerPassiveOuterPhysVol = + passiveOuterVol.placeVolume(layerPassiveOuterVol, dd4hep::Position(0, 0, layerOffset)); + layerPassiveOuterPhysVol.addPhysVolID("layer", iLayer); + dd4hep::DetElement layerPassiveOuterDetElem("layer", iLayer); + layerPassiveOuterDetElem.setPlacement(layerPassiveOuterPhysVol); + if (iLayer != numLayers - 1) { + layerOffset += (layerHeight[iLayer] / 2. + layerHeight[iLayer + 1] / 2.) / cosPassiveAngle; + } + } + } + + if (passiveGlue.isSensitive()) { + // if the glue is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive + lLog << MSG::DEBUG << "Passive glue volume set as sensitive" << endmsg; + double layerOffset = layerFirstOffset / cosPassiveAngle; + for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + dd4hep::Box layerPassiveGlueShape(passiveGlueThickness / 4., caloDim.dz(), layerHeight[iLayer] / 2. / cosPassiveAngle); + dd4hep::Volume layerPassiveGlueVol(passiveGlueMaterial, layerPassiveGlueShape, + aLcdd.material(passiveGlueMaterial)); + layerPassiveGlueVol.setSensitiveDetector(aSensDet); + dd4hep::PlacedVolume layerPassiveGluePhysVol = + passiveGlueVol.placeVolume(layerPassiveGlueVol, dd4hep::Position(0, 0, layerOffset)); + layerPassiveGluePhysVol.addPhysVolID("layer", iLayer); + dd4hep::DetElement layerPassiveGlueDetElem("layer", iLayer); + layerPassiveGlueDetElem.setPlacement(layerPassiveGluePhysVol); + if (iLayer != numLayers - 1) { + layerOffset += (layerHeight[iLayer] / 2. + layerHeight[iLayer + 1] / 2.) / cosPassiveAngle; + } + } + } + + ////////////////////////////// + // READOUT PLANES + ////////////////////////////// + dd4hep::Box readoutShape(readoutThickness / 2., caloDim.dz(), planeLength / 2.); + dd4hep::Volume readoutVol(readoutMaterial, readoutShape, aLcdd.material(readoutMaterial)); + // if the readout is sensitive (to study energy deposited in it, for calculation of per-layer + // sampling fraction), then it is divided in layer volumes, and each layer volume is set as sensitive + if (readout.isSensitive()) { + lLog << MSG::INFO << "ECAL readout volume set as sensitive" << endmsg; + double layerOffset = layerFirstOffset; + for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + dd4hep::Box layerReadoutShape(readoutThickness / 2., caloDim.dz(), layerHeight[iLayer] / 2.); + dd4hep::Volume layerReadoutVol(readoutMaterial, layerReadoutShape, aLcdd.material(readoutMaterial)); + layerReadoutVol.setSensitiveDetector(aSensDet); + dd4hep::PlacedVolume layerReadoutPhysVol = + readoutVol.placeVolume(layerReadoutVol, dd4hep::Position(0, 0, layerOffset)); + layerReadoutPhysVol.addPhysVolID("layer", iLayer); + dd4hep::DetElement layerReadoutDetElem("layer", iLayer); + layerReadoutDetElem.setPlacement(layerReadoutPhysVol); + if (iLayer != numLayers - 1) { + layerOffset += layerHeight[iLayer] / 2. + layerHeight[iLayer + 1] / 2.; + } + } + } + + ////////////////////////////// + // ACTIVE ELEMENTS + ////////////////////////////// + + // creating shape for rows of layers (active material between two passive planes, with readout in the middle) + + // - first define area between two passive planes, area can reach up to the symmetry axis of passive plane + dd4hep::Trd1 activeOuterShape(activeInThickness, activeOutThickness, caloDim.dz(), planeLength / 2.); + + // - subtract readout shape from the middle + dd4hep::SubtractionSolid activeShapeNoReadout(activeOuterShape, readoutShape); + + // - make calculation for active plane that is inclined with 0 deg (= offset + angle) + double Cx = Rmin * cos(-angle) + planeLength / 2.; + double Cy = Rmin * sin(-angle); + double Ax = Rmin * cos(-angle + dPhi / 2.) + planeLength / 2. * cos(dPhi / 2.); + double Ay = Rmin * sin(-angle + dPhi / 2.) + planeLength / 2. * sin(dPhi / 2.); + double CAx = fabs(Ax - Cx); + double CAy = fabs(Ay - Cy); + double zprim, xprim; + zprim = CAx; + xprim = CAy; + + double Bx = Rmin * cos(-angle - dPhi / 2.) + planeLength / 2. * cos(-dPhi / 2.); + double By = Rmin * sin(-angle - dPhi / 2.) + planeLength / 2. * sin(-dPhi / 2.); + double CBx = fabs(Bx - Cx); + double CBy = fabs(By - Cy); + double zprimB, xprimB; + zprimB = CBx; + xprimB = CBy; + + // - subtract readout shape from the middle + dd4hep::SubtractionSolid activeShapeNoPassiveAbove( + activeShapeNoReadout, passiveShape, + dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), + dd4hep::Position(-fabs(xprim), 0, fabs(zprim)))); + + // - subtract passive volume below + dd4hep::SubtractionSolid activeShape( + activeShapeNoPassiveAbove, passiveShape, + dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB)))); + + // - create the active volume, which will contain the layers filled with LAr + dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); + + // place layers within active volume + std::vector layerPhysVols; + + // - first, calculate the layer widths at inner and outer radii + std::vector layerInThickness; + std::vector layerOutThickness; + double layerIncreasePerUnitThickness = (activeOutThickness - activeInThickness) / layersTotalHeight; + for (uint iLay = 0; iLay < numLayers; iLay++) { + if (iLay == 0) { + layerInThickness.push_back(activeInThickness); + } else { + layerInThickness.push_back(layerOutThickness[iLay - 1]); + } + layerOutThickness.push_back(layerInThickness[iLay] + layerIncreasePerUnitThickness * layerHeight[iLay]); + } + + // - then, loop on the layers to create and place the volumes + double layerOffset = layerFirstOffset; + for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + // define the layer envelope + dd4hep::Trd1 layerOuterShape(layerInThickness[iLayer], layerOutThickness[iLayer], caloDim.dz(), layerHeight[iLayer] / 2.); + + // subtract readout shape from the middle + dd4hep::SubtractionSolid layerShapeNoReadout(layerOuterShape, readoutShape); + + // subtract readout shape from the middle + dd4hep::SubtractionSolid layerShapeNoPassiveAbove( + layerShapeNoReadout, passiveShape, + dd4hep::Transform3D(dd4hep::RotationY(-dPhi / 2.), + dd4hep::Position(-fabs(xprim), 0, fabs(zprim) - layerOffset))); + + // subtract passive volume below + dd4hep::SubtractionSolid layerShape( + layerShapeNoPassiveAbove, passiveShape, + dd4hep::Transform3D(dd4hep::RotationY(dPhi / 2.), + dd4hep::Position(fabs(xprimB), 0, -fabs(zprimB) - layerOffset))); + + // create the volume, filled with active material, set as sensitive, and position it properly within active volume + dd4hep::Volume layerVol("layer", layerShape, aLcdd.material(activeMaterial)); + layerVol.setSensitiveDetector(aSensDet); + layerPhysVols.push_back(activeVol.placeVolume(layerVol, dd4hep::Position(0, 0, layerOffset))); + layerPhysVols.back().addPhysVolID("layer", iLayer); + if (iLayer != numLayers - 1) { + layerOffset += layerHeight[iLayer] / 2. + layerHeight[iLayer + 1] / 2.; + } + } + + // Place elements in bath: passive planes, readout planes and rows of layers + dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); + for (uint iPlane = 0; iPlane < numPlanes; iPlane++) { + + // + // PASSIVE + // + + // calculate centre position of the plane without plane rotation + double phi = offsetPassivePhi + iPlane * dPhi; + double xRadial = (Rmin + planeLength / 2.) * cos(phi); + double yRadial = (Rmin + planeLength / 2.) * sin(phi); + // calculate position of the beginning of plane + double xRmin = Rmin * cos(phi); + double yRmin = Rmin * sin(phi); + // rotate centre by angle wrt beginning of plane + double xRotated = xRmin + (xRadial - xRmin) * cos(angle) - (yRadial - yRmin) * sin(angle); + double yRotated = yRmin + (xRadial - xRmin) * sin(angle) + (yRadial - yRmin) * cos(angle); + dd4hep::Transform3D transform(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phi - angle), + dd4hep::Position(xRotated, yRotated, 0)); + // create and place volume in bath + dd4hep::PlacedVolume passivePhysVol = bathVol.placeVolume(passiveVol, transform); + passivePhysVol.addPhysVolID("module", iPlane); + passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout + dd4hep::DetElement passiveDetElem(bathDetElem, "passive" + std::to_string(iPlane), iPlane); + passiveDetElem.setPlacement(passivePhysVol); + + // + // READOUT + // + + // calculate centre position of the plane without plane rotation + double phiRead = offsetReadoutPhi + iPlane * dPhi; + double xRadialRead = (Rmin + planeLength / 2.) * cos(phiRead); + double yRadialRead = (Rmin + planeLength / 2.) * sin(phiRead); + // calculate position of the beginning of plane + double xRminRead = Rmin * cos(phiRead); + double yRminRead = Rmin * sin(phiRead); + // rotate centre by angle wrt beginning of plane + double xRotatedRead = xRminRead + (xRadialRead - xRminRead) * cos(angle) - (yRadialRead - yRminRead) * sin(angle); + double yRotatedRead = yRminRead + (xRadialRead - xRminRead) * sin(angle) + (yRadialRead - yRminRead) * cos(angle); + dd4hep::Transform3D transformRead(dd4hep::RotationX(-M_PI / 2.) // to get in XY plane + * + dd4hep::RotationY(M_PI / 2. // to get pointed towards centre + - + phiRead - angle), + dd4hep::Position(xRotatedRead, yRotatedRead, 0)); + // create and place volume in bath + dd4hep::PlacedVolume readoutPhysVol = bathVol.placeVolume(readoutVol, transformRead); + readoutPhysVol.addPhysVolID("module", iPlane); + readoutPhysVol.addPhysVolID("type", 2); // 0 = active, 1 = passive, 2 = readout + dd4hep::DetElement readoutDetElem(bathDetElem, "readout" + std::to_string(iPlane), iPlane); + readoutDetElem.setPlacement(readoutPhysVol); + + // + // ACTIVE + // + + // same positioning as readout + dd4hep::Transform3D transformActive(dd4hep::RotationX(-M_PI / 2) + * + dd4hep::RotationY(M_PI / 2 - phiRead - angle), + dd4hep::Position(xRotatedRead, yRotatedRead, 0)); + // create and place volume in bath + dd4hep::PlacedVolume activePhysVol = bathVol.placeVolume(activeVol, transformActive); + activePhysVol.addPhysVolID("module", iPlane); + activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout + dd4hep::DetElement activeDetElem(bathDetElem, "active" + std::to_string(iPlane), iPlane); + activeDetElem.setPlacement(activePhysVol); + // place the layers inside the active element + for (uint iLayer = 0; iLayer < numLayers; iLayer++) { + dd4hep::DetElement layerDetElem(activeDetElem, "layer" + std::to_string(iLayer), iLayer); + layerDetElem.setPlacement(layerPhysVols[iLayer]); + } + } + + // Place bath in envelope + dd4hep::PlacedVolume bathPhysVol = envelopeVol.placeVolume(bathVol); + bathDetElem.setPlacement(bathPhysVol); + + // Place the envelope + dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); + dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(envelopeVol); + envelopePhysVol.addPhysVolID("system", xmlDetElem.id()); + caloDetElem.setPlacement(envelopePhysVol); + + // Create caloData object + auto caloData = new dd4hep::rec::LayeredCalorimeterData; + caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; + caloDetElem.addExtension(caloData); + + // Set type flags + dd4hep::xml::setDetectorTypeFlag(xmlDetElem, caloDetElem); + + return caloDetElem; +} +} // namespace det + +DECLARE_DETELEMENT(ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04, det::createECalBarrelInclined) From df737044d162067a01494f66e0db10e950a7f7b5 Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Fri, 26 Jul 2024 13:17:30 +0200 Subject: [PATCH 075/133] Include the layered calorimeter data part from version 1 for Pandora PFA --- ...leLiquid_InclinedTrapezoids_o1_v01_geo.cpp | 4 +- ...leLiquid_InclinedTrapezoids_o1_v03_geo.cpp | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v01_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v01_geo.cpp index 2f3777384..193f46a4c 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v01_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v01_geo.cpp @@ -624,8 +624,8 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, caloLayer.outer_thickness = difference_bet_r1r2 / 2; caloLayer.absorberThickness = absorberThickness; - caloLayer.cellSize0 = 2 * dd4hep::mm; - caloLayer.cellSize1 = 2 * dd4hep::mm; + caloLayer.cellSize0 = 20 * dd4hep::mm; + caloLayer.cellSize1 = 20 * dd4hep::mm; caloData->layers.push_back(caloLayer); } diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp index 288b8c158..e7593d885 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp @@ -687,8 +687,72 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; caloDetElem.addExtension(caloData); + caloData->extent[0] = Rmin; + caloData->extent[1] = Rmax; // or r_max ? + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = caloDim.dz(); + + // Set type flags dd4hep::xml::setDetectorTypeFlag(xmlDetElem, caloDetElem); + dd4hep::rec::MaterialManager matMgr(envelopeVol); + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + double rad_first = Rmin; + double rad_last = 0; + double scale_fact = dR / (-Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2))); + // since the layer height is given along the electrode and not along the radius it needs to be scaled to get the values of layer height radially + std::cout << "Scaling factor " << scale_fact << std::endl; + for (size_t il = 0; il < layerHeight.size(); il++) { + double thickness_sen = 0.; + double absorberThickness = 0.; + + rad_last = rad_first + (layerHeight[il] * scale_fact); + dd4hep::rec::Vector3D ivr1 = dd4hep::rec::Vector3D(0., rad_first, 0); // defining starting vector points of the given layer + dd4hep::rec::Vector3D ivr2 = dd4hep::rec::Vector3D(0., rad_last, 0); // defining end vector points of the given layer + + std::cout << "radius first " << rad_first << " radius last " << rad_last << std::endl; + const dd4hep::rec::MaterialVec &materials = matMgr.materialsBetween(ivr1, ivr2); // calling material manager to get material info between two points + auto mat = matMgr.createAveragedMaterial(materials); // creating average of all the material between two points to calculate X0 and lambda of averaged material + const double nRadiationLengths = mat.radiationLength(); + const double nInteractionLengths = mat.interactionLength(); + const double difference_bet_r1r2 = (ivr1 - ivr2).r(); + const double value_of_x0 = layerHeight[il] / nRadiationLengths; + const double value_of_lambda = layerHeight[il] / nInteractionLengths; + std::string str1("LAr"); + + for (size_t imat = 0; imat < materials.size(); imat++) { + + std::string str2(materials.at(imat).first.name()); + if (str1.compare(str2) == 0){ + thickness_sen += materials.at(imat).second; + } + else { + absorberThickness += materials.at(imat).second; + } + } + rad_first = rad_last; + std::cout << "The sensitive thickness is " << thickness_sen << std::endl; + std::cout << "The absorber thickness is " << absorberThickness << std::endl; + std::cout << "The radiation length is " << value_of_x0 << " and the interaction length is " << value_of_lambda << std::endl; + + caloLayer.distance = rad_first; + caloLayer.sensitive_thickness = thickness_sen; + caloLayer.inner_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.inner_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + + caloLayer.outer_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.outer_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2; + + caloLayer.absorberThickness = absorberThickness; + caloLayer.cellSize0 = 20 * dd4hep::mm; + caloLayer.cellSize1 = 20 * dd4hep::mm; + + caloData->layers.push_back(caloLayer); + } + return caloDetElem; } From 2189857d97047f1c8a56e12e1f66648cfbd8db4c Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Fri, 26 Jul 2024 16:42:28 +0200 Subject: [PATCH 076/133] update the LAr ECal barrel xml file to the latest version --- .../CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml index 55519bd5a..30dcef57a 100644 --- a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml +++ b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml @@ -45,13 +45,13 @@ - - - + + + - + @@ -71,7 +71,6 @@ - @@ -82,21 +81,21 @@ - - - system:5,cryo:1,type:3,subtype:3,layer:8,module:11,eta:9 + + + system:4,cryo:1,type:3,subtype:3,layer:8,module:11,eta:9 - - - system:5,cryo:1,type:3,subtype:3,layer:8,eta:9,phi:10 + + + system:4,cryo:1,type:3,subtype:3,layer:8,eta:9,phi:10 - + From a386e51d88214c519948677b925631d89ba0b1f2 Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Mon, 29 Jul 2024 11:33:28 +0200 Subject: [PATCH 077/133] Update ECalBarrel_NobelLiquid_InclinedTrapezoid_o1_v02_geo.cpp with layered calo data information for Pandora --- ...leLiquid_InclinedTrapezoids_o1_v02_geo.cpp | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp index bdb269ed6..6d9525da3 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp @@ -656,9 +656,70 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; caloDetElem.addExtension(caloData); + caloData->extent[0] = Rmin; + caloData->extent[1] = Rmax; // or r_max ? + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = caloDim.dz(); + // Set type flags dd4hep::xml::setDetectorTypeFlag(xmlDetElem, caloDetElem); - + dd4hep::rec::MaterialManager matMgr(envelopeVol); + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + double rad_first = Rmin; + double rad_last = 0; + double scale_fact = dR / (-Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2))); + // since the layer height is given along the electrode and not along the radius it needs to be scaled to get the values of layer height radially + std::cout << "Scaling factor " << scale_fact << std::endl; + for (size_t il = 0; il < layerHeight.size(); il++) { + double thickness_sen = 0.; + double absorberThickness = 0.; + + rad_last = rad_first + (layerHeight[il] * scale_fact); + dd4hep::rec::Vector3D ivr1 = dd4hep::rec::Vector3D(0., rad_first, 0); // defining starting vector points of the given layer + dd4hep::rec::Vector3D ivr2 = dd4hep::rec::Vector3D(0., rad_last, 0); // defining end vector points of the given layer + + std::cout << "radius first " << rad_first << " radius last " << rad_last << std::endl; + const dd4hep::rec::MaterialVec &materials = matMgr.materialsBetween(ivr1, ivr2); // calling material manager to get material info between two points + auto mat = matMgr.createAveragedMaterial(materials); // creating average of all the material between two points to calculate X0 and lambda of averaged material + const double nRadiationLengths = mat.radiationLength(); + const double nInteractionLengths = mat.interactionLength(); + const double difference_bet_r1r2 = (ivr1 - ivr2).r(); + const double value_of_x0 = layerHeight[il] / nRadiationLengths; + const double value_of_lambda = layerHeight[il] / nInteractionLengths; + std::string str1("LAr"); + + for (size_t imat = 0; imat < materials.size(); imat++) { + + std::string str2(materials.at(imat).first.name()); + if (str1.compare(str2) == 0){ + thickness_sen += materials.at(imat).second; + } + else { + absorberThickness += materials.at(imat).second; + } + } + rad_first = rad_last; + std::cout << "The sensitive thickness is " << thickness_sen << std::endl; + std::cout << "The absorber thickness is " << absorberThickness << std::endl; + std::cout << "The radiation length is " << value_of_x0 << " and the interaction length is " << value_of_lambda << std::endl; + + caloLayer.distance = rad_first; + caloLayer.sensitive_thickness = thickness_sen; + caloLayer.inner_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.inner_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + + caloLayer.outer_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.outer_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2; + + caloLayer.absorberThickness = absorberThickness; + caloLayer.cellSize0 = 20 * dd4hep::mm; + caloLayer.cellSize1 = 20 * dd4hep::mm; + + caloData->layers.push_back(caloLayer); + } return caloDetElem; } } // namespace det From 554d74560c72f30ff6013f30966c7a2b14c0a816 Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Tue, 30 Jul 2024 11:28:57 +0200 Subject: [PATCH 078/133] Add MaterialManager and Vector3D headers to both the versions of LAr ECAL --- .../ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp | 2 ++ .../ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp index 6d9525da3..8299b6bd1 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v02_geo.cpp @@ -1,6 +1,8 @@ #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/Handle.h" #include "XML/Utilities.h" +#include "DDRec/MaterialManager.h" +#include "DDRec/Vector3D.h" #include diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp index e7593d885..330f5162a 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp @@ -1,6 +1,8 @@ #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/Handle.h" #include "XML/Utilities.h" +#include "DDRec/MaterialManager.h" +#include "DDRec/Vector3D.h" #include From f734b31d21173aa6cf3accc665658755b8ebbd98 Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Wed, 13 Nov 2024 16:01:01 +0100 Subject: [PATCH 079/133] Update to latest the detector model --- FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml index 30dcef57a..6121afe66 100644 --- a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml +++ b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml @@ -95,7 +95,7 @@ - + From 55d968adcdc6e97fcd6f0d982e69c889885c057f Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Wed, 13 Nov 2024 16:09:08 +0100 Subject: [PATCH 080/133] Update ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp with CaloDataLayer snippet to be used for Pandora --- ...leLiquid_InclinedTrapezoids_o1_v04_geo.cpp | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp index 11eb17d16..cec23b447 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp @@ -757,9 +757,70 @@ static dd4hep::detail::Ref_t createECalBarrelInclined(dd4hep::Detector& aLcdd, caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::BarrelLayout; caloDetElem.addExtension(caloData); + caloData->extent[0] = Rmin; + caloData->extent[1] = Rmax; // or r_max ? + caloData->extent[2] = 0.; // NN: for barrel detectors this is 0 + caloData->extent[3] = caloDim.dz(); + // Set type flags dd4hep::xml::setDetectorTypeFlag(xmlDetElem, caloDetElem); - + dd4hep::rec::MaterialManager matMgr(envelopeVol); + dd4hep::rec::LayeredCalorimeterData::Layer caloLayer; + + double rad_first = Rmin; + double rad_last = 0; + double scale_fact = dR / (-Rmin * cos(angle) + sqrt(pow(Rmax, 2) - pow(Rmin * sin(angle), 2))); + // since the layer height is given along the electrode and not along the radius it needs to be scaled to get the values of layer height radially + std::cout << "Scaling factor " << scale_fact << std::endl; + for (size_t il = 0; il < layerHeight.size(); il++) { + double thickness_sen = 0.; + double absorberThickness = 0.; + + rad_last = rad_first + (layerHeight[il] * scale_fact); + dd4hep::rec::Vector3D ivr1 = dd4hep::rec::Vector3D(0., rad_first, 0); // defining starting vector points of the given layer + dd4hep::rec::Vector3D ivr2 = dd4hep::rec::Vector3D(0., rad_last, 0); // defining end vector points of the given layer + + std::cout << "radius first " << rad_first << " radius last " << rad_last << std::endl; + const dd4hep::rec::MaterialVec &materials = matMgr.materialsBetween(ivr1, ivr2); // calling material manager to get material info between two points + auto mat = matMgr.createAveragedMaterial(materials); // creating average of all the material between two points to calculate X0 and lambda of averaged material + const double nRadiationLengths = mat.radiationLength(); + const double nInteractionLengths = mat.interactionLength(); + const double difference_bet_r1r2 = (ivr1 - ivr2).r(); + const double value_of_x0 = layerHeight[il] / nRadiationLengths; + const double value_of_lambda = layerHeight[il] / nInteractionLengths; + std::string str1("LAr"); + + for (size_t imat = 0; imat < materials.size(); imat++) { + + std::string str2(materials.at(imat).first.name()); + if (str1.compare(str2) == 0){ + thickness_sen += materials.at(imat).second; + } + else { + absorberThickness += materials.at(imat).second; + } + } + rad_first = rad_last; + std::cout << "The sensitive thickness is " << thickness_sen << std::endl; + std::cout << "The absorber thickness is " << absorberThickness << std::endl; + std::cout << "The radiation length is " << value_of_x0 << " and the interaction length is " << value_of_lambda << std::endl; + + caloLayer.distance = rad_first; + caloLayer.sensitive_thickness = thickness_sen; + caloLayer.inner_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.inner_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.inner_thickness = difference_bet_r1r2 / 2.0; + + caloLayer.outer_nRadiationLengths = value_of_x0 / 2.0; + caloLayer.outer_nInteractionLengths = value_of_lambda / 2.0; + caloLayer.outer_thickness = difference_bet_r1r2 / 2; + + caloLayer.absorberThickness = absorberThickness; + caloLayer.cellSize0 = 20 * dd4hep::mm; + caloLayer.cellSize1 = 20 * dd4hep::mm; + + caloData->layers.push_back(caloLayer); + } return caloDetElem; } } // namespace det From 1d2721d13e8562dd8521c72cc6a81ce33ac072d7 Mon Sep 17 00:00:00 2001 From: Swathi Sasikumar Date: Thu, 14 Nov 2024 12:26:05 +0100 Subject: [PATCH 081/133] Add Material Manager and Vector3D header files --- .../ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp | 1 - .../ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp index 330f5162a..33a8380f1 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v03_geo.cpp @@ -3,7 +3,6 @@ #include "XML/Utilities.h" #include "DDRec/MaterialManager.h" #include "DDRec/Vector3D.h" - #include // like v02, but in xml the layer dimensions are along the electrode diff --git a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp index cec23b447..61e58fd5e 100644 --- a/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp +++ b/detector/calorimeter/ECalBarrel_NobleLiquid_InclinedTrapezoids_o1_v04_geo.cpp @@ -1,7 +1,8 @@ #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/Handle.h" #include "XML/Utilities.h" - +#include "DDRec/MaterialManager.h" +#include "DDRec/Vector3D.h" #include // like v02, but in xml the layer dimensions are along the electrode From 2846c3dbbc4887c99a590af9b7bd8a1a9c16e14f Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Wed, 30 Oct 2024 15:50:08 +0100 Subject: [PATCH 082/133] HCal new readout implementation --- .../compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 4 +- .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml | 133 ++++++++ .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 145 +++++++++ .../FCCSWHCalPhiThetaHandle_k4geo.h | 131 ++++++++ .../FCCSWHCalPhiTheta_k4geo.h | 193 ++++++++++++ .../src/FCCSWHCalPhiThetaHandle_k4geo.cpp | 4 + .../src/FCCSWHCalPhiTheta_k4geo.cpp | 284 ++++++++++++++++++ .../src/plugins/SegmentationFactories.cpp | 3 + 8 files changed, 895 insertions(+), 2 deletions(-) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml create mode 100644 detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h create mode 100644 detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h create mode 100644 detectorSegmentations/src/FCCSWHCalPhiThetaHandle_k4geo.cpp create mode 100644 detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index fc2ca3b09..0d478c06e 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -45,9 +45,9 @@ - + - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml new file mode 100644 index 000000000..cfcc37eac --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml @@ -0,0 +1,133 @@ + + + + The first FCCee HCal layout based on ATLAS HCal, not optimised yet + 1. Nov 2022, J. Faltova: update material and radial segmentation for FCCee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,layer:5,row:9,theta:9,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml new file mode 100644 index 000000000..5d64a9b5a --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -0,0 +1,145 @@ + + + + HCal layout based on ATLAS HCal, with realistic longitudinal segmentation and steel support + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,type:3,layer:6,row:11,theta:11,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h new file mode 100644 index 000000000..e787bbd45 --- /dev/null +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h @@ -0,0 +1,131 @@ +#ifndef DETECTORSEGMENTATIONS_HCALPHITHETAHANDLE_K4GEO_H +#define DETECTORSEGMENTATIONS_HCALPHITHETAHANDLE_K4GEO_H + +// FCCSW +#include "detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h" + +// DD4hep +#include "DD4hep/Segmentations.h" +#include "DD4hep/detail/SegmentationsInterna.h" + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { +/// Namespace for base segmentations + + +// Forward declarations +class Segmentation; +template class SegmentationWrapper; + +/// We need some abbreviation to make the code more readable. +typedef Handle> FCCSWGridPhiThetaHandle_k4geo; + +/// Implementation class for the HCal phi-theta segmentation. +/** + * Concrete user handle to serve specific needs of client code + * which requires access to the base functionality not served + * by the super-class Segmentation. + * + * Note: + * We only check the validity of the underlying handle. + * If for whatever reason the implementation object is not valid + * This is not checked. + * In principle this CANNOT happen unless some brain-dead has + * fiddled with the handled object directly..... + * + * Note: + * The handle base corrsponding to this object in for + * conveniance reasons instantiated in DD4hep/src/Segmentations.cpp. + * + */ +class FCCSWHCalPhiTheta_k4geo : public FCCSWGridPhiThetaHandle_k4geo { +public: + /// Defintion of the basic handled object + typedef FCCSWGridPhiThetaHandle_k4geo::Object Object; + +public: + /// Default constructor + FCCSWHCalPhiTheta_k4geo() = default; + /// Copy constructor + FCCSWHCalPhiTheta_k4geo(const FCCSWHCalPhiTheta_k4geo& e) = default; + /// Copy Constructor from segmentation base object + FCCSWHCalPhiTheta_k4geo(const Segmentation& e) : Handle(e) {} + /// Copy constructor from handle + FCCSWHCalPhiTheta_k4geo(const Handle& e) : Handle(e) {} + /// Copy constructor from other polymorph/equivalent handle + template + FCCSWHCalPhiTheta_k4geo(const Handle& e) : Handle(e) {} + /// Assignment operator + FCCSWHCalPhiTheta_k4geo& operator=(const FCCSWHCalPhiTheta_k4geo& seg) = default; + /// Equality operator + bool operator==(const FCCSWHCalPhiTheta_k4geo& seg) const { return m_element == seg.m_element; } + + /// determine the position based on the cell ID + inline Position position(const CellID& id) const { return Position(access()->implementation->position(id)); } + + /// determine the cell ID based on the position + inline dd4hep::CellID cellID(const Position& local, const Position& global, const VolumeID& volID) const { + return access()->implementation->cellID(local, global, volID); + } + + /// access the grid size in theta + inline double gridSizeTheta() const { return access()->implementation->gridSizeTheta(); } + + /// access the grid size in Phi + inline int phiBins() const { return access()->implementation->phiBins(); } + + /// access the coordinate offset in theta + inline double offsetTheta() const { return access()->implementation->offsetTheta(); } + + /// access the coordinate offset in Phi + inline double offsetPhi() const { return access()->implementation->offsetPhi(); } + + /// set the coordinate offset in theta + inline void setOffsetTheta(double offset) const { access()->implementation->setOffsetTheta(offset); } + + /// set the coordinate offset in Phi + inline void setOffsetPhi(double offset) const { access()->implementation->setOffsetPhi(offset); } + + /// set the coordinate offset in z-axis + inline void setOffsetZ(std::vector const&offset) const { access()->implementation->setOffsetZ(offset); } + + /// set the z width + inline void setWidthZ(std::vector const&width) const { access()->implementation->setWidthZ(width); } + + /// set the offset in radius + inline void setOffsetR(std::vector const&offset) const { access()->implementation->setOffsetR(offset); } + + /// set the number of layers with different dR + inline void setNumLayers(std::vector const&num) const { access()->implementation->setNumLayers(num); } + + /// set the dR of each layer + inline void setdRlayer(std::vector const&dRlayer) const { access()->implementation->setdRlayer(dRlayer); } + + /// set the grid size in theta + inline void setGridSizeTheta(double cellSize) const { access()->implementation->setGridSizeTheta(cellSize); } + + /// set the grid size in Phi + inline void setPhiBins(int cellSize) const { access()->implementation->setPhiBins(cellSize); } + + /// access the field name used for theta + inline const std::string& fieldNameTheta() const { return access()->implementation->fieldNameTheta(); } + + /// access the field name used for Phi + inline const std::string& fieldNamePhi() const { return access()->implementation->fieldNamePhi(); } + + /** \brief Returns a std::vector of the cellDimensions of the given cell ID + in natural order of dimensions (dPhi, dTheta) + + Returns a std::vector of the cellDimensions of the given cell ID + \param cellID is ignored as all cells have the same dimension + \return std::vector size 2: + -# size in phi + -# size in theta + */ + inline std::vector cellDimensions(const CellID& /*id*/) const { + return {access()->implementation->gridSizePhi(), access()->implementation->gridSizeTheta()}; + } +}; + +} /* End namespace dd4hep */ +#endif // DETECTORSEGMENTATIONS_HCALPHITHETAHANDLE_K4GEO_H diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h new file mode 100644 index 000000000..439d56ab7 --- /dev/null +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h @@ -0,0 +1,193 @@ +#ifndef DETECTORSEGMENTATIONS_HCALPHITHETA_K4GEO_H +#define DETECTORSEGMENTATIONS_HCALPHITHETA_K4GEO_H + +// FCCSW +#include "detectorSegmentations/GridTheta_k4geo.h" + +/** FCCSWHCalPhiTheta_k4geo Detector/detectorSegmentations/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h FCCSWHCalPhiTheta_k4geo.h + * + * Segmentation in theta and phi. + * Based on GridTheta_k4geo, addition of azimuthal angle coordinate. + * + * Rectangular shape cells are defined in r-z plan and all the hits within a defined cell boundaries are assigned the same cellID. + * + */ + +namespace dd4hep { + namespace DDSegmentation { + class FCCSWHCalPhiTheta_k4geo : public GridTheta_k4geo { + public: + /// default constructor using an arbitrary type + FCCSWHCalPhiTheta_k4geo(const std::string& aCellEncoding); + /// Default constructor used by derived classes passing an existing decoder + FCCSWHCalPhiTheta_k4geo(const BitFieldCoder* decoder); + + /// destructor + virtual ~FCCSWHCalPhiTheta_k4geo() = default; + + /** Determine the position of HCal cell based on the cellID. + * @warning This segmentation has no knowledge of radius, so radius = 1 is taken into calculations. + * @param[in] aCellId ID of a cell. + * return Position (radius = 1). + */ + virtual Vector3D position(const CellID& aCellID) const; + + /** Assign a cellID based on the global position. + * @param[in] aLocalPosition (not used). + * @param[in] aGlobalPosition position in the global coordinates. + * @param[in] aVolumeId ID of a volume. + * return Cell ID. + */ + virtual CellID cellID(const Vector3D& aLocalPosition, const Vector3D& aGlobalPosition, + const VolumeID& aVolumeID) const; + + /** Calculate layer radii and edges in z-axis, then define cell edges in each layer using defineCellEdges(). + */ + void defineCellsInRZplan() const; + + /** Define cell edges in z-axis for the given layer. + * Logic: + * 1) Find theta bin centers that fit within the given layer; + * 2) Define a cell edge in z-axis as the middle of each pair of theta bin centers + * @param[in] layer index + */ + void defineCellEdges(const unsigned int layer) const; + + /** Determine the azimuthal angle of HCal cell based on the cellID. + * @param[in] aCellId ID of a cell. + * return Phi. + */ + double phi(const CellID& aCellID) const; + + /** Get the grid size in phi. + * return Grid size in phi. + */ + inline double gridSizePhi() const { return 2 * M_PI / static_cast(m_phiBins); } + + /** Get the number of bins in azimuthal angle. + * return Number of bins in phi. + */ + inline int phiBins() const { return m_phiBins; } + + /** Get the coordinate offset in azimuthal angle. + * return The offset in phi. + */ + inline double offsetPhi() const { return m_offsetPhi; } + + /** Get the vector of theta bins (cells) in a give layer. + */ + inline std::vector thetaBins(const uint layer) const { + if(m_radii.empty()) defineCellsInRZplan(); + if(!m_thetaBins.empty()) return m_thetaBins[layer]; + else return std::vector(); + } + + /** Get the coordinate offset in z-axis. + * return The offset in z. + */ + inline std::vector offsetZ() const { return m_offsetZ; } + + /** Get the z width of the layer. + * return the z width. + */ + inline std::vector widthZ() const { return m_widthZ; } + + /** Get the coordinate offset in radius. + * return the offset in radius. + */ + inline std::vector offsetR() const { return m_offsetR; } + + /** Get the number of layers. + * return the number of layers. + */ + inline std::vector numLayers() const { return m_numLayers; } + + /** Get the dR of layers. + * return the dR. + */ + inline std::vector dRlayer() const { return m_dRlayer; } + + /** Get the field name for azimuthal angle. + * return The field name for phi. + */ + inline const std::string& fieldNamePhi() const { return m_phiID; } + + /** Get the postion og the geometric center of the cell based on the cellID + * @param[in] aCellID + * return the global coordinates of cell center + */ + inline Vector3D centerPosition(const CellID& cID) const; + + + /** Set the number of bins in azimuthal angle. + * @param[in] aNumberBins Number of bins in phi. + */ + inline void setPhiBins(int bins) { m_phiBins = bins; } + + /** Set the coordinate offset in azimuthal angle. + * @param[in] aOffset Offset in phi. + */ + inline void setOffsetPhi(double offset) { m_offsetPhi = offset; } + + /** Set the coordinate offset in z-axis. + * @param[in] offset in z (centre of the layer). + */ + inline void setOffsetZ(std::vector const&offset) { m_offsetZ = offset; } + + /** Set the z width. + * @param[in] width in z. + */ + inline void setWidthZ(std::vector const&width) { m_widthZ = width; } + + /** Set the coordinate offset in radius. + * @param[in] offset in radius. + */ + inline void setOffsetR(std::vector const&offset) { m_offsetR = offset; } + + /** Set the number of layers. + * @param[in] number of layers + */ + inline void setNumLayers(std::vector const&num) { m_numLayers = num; } + + /** Set the dR of layers. + * @param[in] dR of layers. + */ + inline void setdRlayer(std::vector const&dRlayer) { m_dRlayer = dRlayer; } + + + /** Set the field name used for azimuthal angle. + * @param[in] aFieldName Field name for phi. + */ + inline void setFieldNamePhi(const std::string& fieldName) { m_phiID = fieldName; } + + protected: + /// determine the azimuthal angle phi based on the current cell ID + double phi() const; + /// the number of bins in phi + int m_phiBins; + /// the coordinate offset in phi + double m_offsetPhi; + /// the field name used for phi + std::string m_phiID; + /// the z offset of middle of the layer + std::vector m_offsetZ; + /// the z width of the layer + std::vector m_widthZ; + /// the radius of the layer + std::vector m_offsetR; + /// number of layers + std::vector m_numLayers; + /// dR of the layer + std::vector m_dRlayer; + /// radius of each layer + mutable std::vector m_radii; + /// z-min and z-max of each layer + mutable std::vector > m_layerEdges; + /// theta bins (cells) in each layer + mutable std::vector > m_thetaBins; + /// z-min and z-max of each cell (theta bin) in each layer + mutable std::vector > > m_cellEdges; + }; + } +} +#endif /* DETSEGMENTATION_HCALPHITHETA_H */ diff --git a/detectorSegmentations/src/FCCSWHCalPhiThetaHandle_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiThetaHandle_k4geo.cpp new file mode 100644 index 000000000..1e3f8d0e4 --- /dev/null +++ b/detectorSegmentations/src/FCCSWHCalPhiThetaHandle_k4geo.cpp @@ -0,0 +1,4 @@ +#include "detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h" +#include "DD4hep/detail/Handle.inl" + +DD4HEP_INSTANTIATE_HANDLE_UNNAMED(dd4hep::DDSegmentation::FCCSWHCalPhiTheta_k4geo); diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp new file mode 100644 index 000000000..cc49d9e32 --- /dev/null +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -0,0 +1,284 @@ +#include "detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h" +#include "DD4hep/Printout.h" + +namespace dd4hep { +namespace DDSegmentation { + +/// default constructor using an encoding string +FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const std::string& cellEncoding) : GridTheta_k4geo(cellEncoding) { + // define type and description + _type = "FCCSWHCalPhiTheta_k4geo"; + _description = "Phi-theta segmentation in the global coordinates"; + + // register all necessary parameters (additional to those registered in GridTheta_k4geo) + registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); + registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); + registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); + registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); + registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); + registerParameter("numLayers", "Number of layers", m_numLayers, std::vector()); + registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); + registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); +} + +FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const BitFieldCoder* decoder) : GridTheta_k4geo(decoder) { + // define type and description + _type = "FCCSWHCalPhiTheta_k4geo"; + _description = "Phi-theta segmentation in the global coordinates"; + + // register all necessary parameters (additional to those registered in GridTheta_k4geo) + registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); + registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); + registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); + registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); + registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); + registerParameter("numLayers", "Number of layers", m_numLayers, std::vector()); + registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); + registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); +} + + +/// determine the global position based on the cell ID +Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { + uint layer = _decoder->get(cID,"layer"); + double radius = 1.0; + + if(m_radii.empty()) defineCellsInRZplan(); + if(!m_radii.empty()) radius = m_radii[layer]; + + return positionFromRThetaPhi(radius, theta(cID), phi(cID)); +} + + +/// determine the global position based on the cell ID +/// returns the geometric center of the cell +Vector3D FCCSWHCalPhiTheta_k4geo::centerPosition(const CellID& cID) const { + uint layer = _decoder->get(cID,"layer"); + int thetaID = _decoder->get(cID,"theta"); + double zpos = 0.; + double radius = 1.0; + + if(m_radii.empty()) defineCellsInRZplan(); + if(!m_radii.empty()) radius = m_radii[layer]; + if(!m_cellEdges.empty()) zpos = m_cellEdges[layer][thetaID].first + (m_cellEdges[layer][thetaID].second - m_cellEdges[layer][thetaID].first) * 0.5; + + auto pos = positionFromRThetaPhi(radius, theta(cID), phi(cID)); + + // retrun the position with corrected z corrdinate to match to the geometric center + return Vector3D(pos.x(),pos.y(),zpos); +} + + +void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { + if(m_radii.empty()) + { + // check if all necessary variables are available + if(m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!", + "One of the variables is missing: offset_z | width_z | offset_r | numLayers | dRlayer"); + return; + } + + // calculate the radius for each layer + if(m_offsetZ.size() == 1) // Barrel + { + dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","Barrel configuration found!"); + uint N_dR = m_numLayers.size(); + double moduleDepth = 0.; + for(uint i_dR = 0; i_dR < N_dR; i_dR++) + { + for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) + { + moduleDepth+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[0] + moduleDepth - m_dRlayer[i_dR]*0.5); + // layer lower and upper edges in z-axis + m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); + } + } + } // Barrel + + if(m_offsetZ.size() > 1) // ThreePartsEndCap + { + dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","ThreePartsEndCap configuration found!"); + uint N_dR = m_numLayers.size()/3; + double moduleDepth1 = 0.; + double moduleDepth2 = 0.; + double moduleDepth3 = 0.; + // part1 + for(uint i_dR = 0; i_dR < N_dR; i_dR++) + { + for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) + { + moduleDepth1+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[0] + moduleDepth1 - m_dRlayer[i_dR]*0.5); + // layer lower and upper edges in z-axis + m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); + } + } + // part2 + for(uint i_dR = 0; i_dR < N_dR; i_dR++) + { + for(int i_row = 1; i_row <= m_numLayers[i_dR + N_dR]; i_row++) + { + moduleDepth2+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[1] + moduleDepth2 - m_dRlayer[i_dR]*0.5); + // layer lower and upper edges in z-axis + m_layerEdges.push_back( std::make_pair(m_offsetZ[1] - 0.5*m_widthZ[1], m_offsetZ[1] + 0.5*m_widthZ[1]) ); + } + } + // part3 + for(uint i_dR = 0; i_dR < N_dR; i_dR++) + { + for(int i_row = 1; i_row <= m_numLayers[i_dR + 2*N_dR]; i_row++) + { + moduleDepth3+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[2] + moduleDepth3 - m_dRlayer[i_dR]*0.5); + // layer lower and upper edges in z-axis + m_layerEdges.push_back( std::make_pair(m_offsetZ[2] - 0.5*m_widthZ[2], m_offsetZ[2] + 0.5*m_widthZ[2]) ); + } + } + } // ThreePartsEndcap + + // print info of calculated radii and edges + for(uint i_layer = 0; i_layer < m_radii.size(); i_layer++){ + dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","layer %d radius: %.2f, z range: %.2f - %.2f cm", + i_layer, m_radii[i_layer], m_layerEdges[i_layer].first, m_layerEdges[i_layer].second); + } + + // allocate thetaBins vector for each layer + m_thetaBins.resize(m_radii.size()); + // allocate cellEdges vector for each layer + m_cellEdges.resize(m_radii.size()); + + // determine theta bins and cell edges for each layer + for(uint i_layer = 0; i_layer < m_radii.size(); i_layer++) defineCellEdges(i_layer); + } +} + + +void FCCSWHCalPhiTheta_k4geo::defineCellEdges(const uint layer) const { + if(m_thetaBins[layer].size()==0 && m_radii.size() > 0) + { + //find theta bins that fit within the given layer + int ibin = positionToBin(0.02, m_gridSizeTheta, m_offsetTheta); // <--- start from theta bin outside the HCal theta range + while(m_radii[layer]*std::cos(m_offsetTheta+ibin*m_gridSizeTheta)/std::sin(m_offsetTheta+ibin*m_gridSizeTheta) > m_layerEdges[layer].first) + { + if(m_radii[layer]*std::cos(m_offsetTheta+ibin*m_gridSizeTheta)/std::sin(m_offsetTheta+ibin*m_gridSizeTheta) < m_layerEdges[layer].second) + { + m_thetaBins[layer].push_back(ibin); + } + ibin++; + } + + // find edges of each cell (theta bin) in the given layer + auto prevBin = m_thetaBins[layer][0]; + // set the upper edge of the first cell in the given layer (starting from positive z part) + m_cellEdges[layer][prevBin] = std::make_pair(0.,m_layerEdges[layer].second); + for(auto bin : m_thetaBins[layer]) + { + if(bin!=prevBin) + { + double z1 = m_radii[layer]*std::cos(m_offsetTheta+bin*m_gridSizeTheta)/std::sin(m_offsetTheta+bin*m_gridSizeTheta); + double z2 = m_radii[layer]*std::cos(m_offsetTheta+prevBin*m_gridSizeTheta)/std::sin(m_offsetTheta+prevBin*m_gridSizeTheta); + // set the lower edge of the prevBin cell + m_cellEdges[layer][prevBin].first = z1 + 0.5*(z2 - z1); + // set the upper edge of current bin cell + m_cellEdges[layer][bin] = std::make_pair(0.,m_cellEdges[layer][prevBin].first); + prevBin = bin; + } + } + // set the lower edge of the last cell in the given layer + m_cellEdges[layer][prevBin].first = m_layerEdges[layer].first; + + // for the EndCap, do it again but for negative z part + if(m_offsetZ.size() > 1) + { + while(m_radii[layer]*std::cos(m_offsetTheta+ibin*m_gridSizeTheta)/std::sin(m_offsetTheta+ibin*m_gridSizeTheta) > (-m_layerEdges[layer].second)) + { + if(m_radii[layer]*std::cos(m_offsetTheta+ibin*m_gridSizeTheta)/std::sin(m_offsetTheta+ibin*m_gridSizeTheta) < (-m_layerEdges[layer].first)) + { + m_thetaBins[layer].push_back(ibin); + } + ibin++; + } + + // Create a span view over the theta bins corresponding to the Endcap in negative z part + std::span thetaBins(m_thetaBins[layer].begin() + m_thetaBins[layer].size()/2, m_thetaBins[layer].end()); + prevBin = thetaBins[0]; + + // set the upper edge of the first cell in the given layer at negative z part + m_cellEdges[layer][prevBin] = std::make_pair(0.,-m_layerEdges[layer].first); + for(auto bin : thetaBins) + { + if(bin!=prevBin) + { + double z1 = m_radii[layer]*std::cos(m_offsetTheta+bin*m_gridSizeTheta)/std::sin(m_offsetTheta+bin*m_gridSizeTheta); + double z2 = m_radii[layer]*std::cos(m_offsetTheta+prevBin*m_gridSizeTheta)/std::sin(m_offsetTheta+prevBin*m_gridSizeTheta); + // set the lower edge of the prevBin cell + m_cellEdges[layer][prevBin].first = z1 + 0.5*(z2 - z1); + // set the upper edge of current bin cell + m_cellEdges[layer][bin] = std::make_pair(0.,m_cellEdges[layer][prevBin].first); + prevBin = bin; + } + } + // set the lower edge of the last cell in the given layer + m_cellEdges[layer][prevBin].first = (-m_layerEdges[layer].second); + }// negative-z endcap + + dd4hep::printout(dd4hep::DEBUG, "FCCSWHCalPhiTheta_k4geo","Number of cells in layer %d: %d", layer, m_thetaBins[layer].size()); + for(auto bin : m_thetaBins[layer]) dd4hep::printout(dd4hep::DEBUG, "FCCSWHCalPhiTheta_k4geo","Layer %d cell theta bin: %d, edges: %.2f - %.2f cm", layer, bin, m_cellEdges[layer][bin]); + } +} + +/// create the cell ID based on the position +CellID FCCSWHCalPhiTheta_k4geo::cellID(const Vector3D& /* localPosition */, const Vector3D& globalPosition, + const VolumeID& vID) const { + + CellID cID = vID; + + // The volume ID comes with "row" field information (number of sequences) that would screw up the topo-clustering using cell + // neighbours map produced with RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNeighbours.cpp, + // therefore, lets set it to zero, as it is for the cell IDs in the neighbours map. + _decoder->set(cID, "row", 0); + + // For endcap, the volume ID comes with "type" field information which would screw up the topo-clustering as the "row" field, + // therefore, lets set it to zero, as it is for the cell IDs in the neighbours map. + if(m_offsetZ.size() > 1) _decoder->set(cID, "type", 0); + + double lTheta = thetaFromXYZ(globalPosition); + double lPhi = phiFromXYZ(globalPosition); + uint layer = _decoder->get(vID,"layer"); + + // define cell boundaries in R-z plan + if(m_radii.empty()) defineCellsInRZplan(); + + // check if the cells are defined for the given layer + if(m_thetaBins[layer].empty()) dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","No cells are defined for layer %d", layer); + + // find the cell (theta bin) corresponding to the hit and return the cellID + for(auto bin : m_thetaBins[layer]) + { + double posz = globalPosition.z(); + if(posz > m_cellEdges[layer][bin].first && posz < m_cellEdges[layer][bin].second) + { + _decoder->set(cID, m_thetaID, bin); + _decoder->set(cID, m_phiID, positionToBin(lPhi, 2 * M_PI / (double)m_phiBins, m_offsetPhi)); + return cID; + } + } + + dd4hep::printout(dd4hep::WARNING, "FCCSWHCalPhiTheta_k4geo","The hit is outside the defined range of the layer %d", layer); + + _decoder->set(cID, m_thetaID, positionToBin(lTheta, m_gridSizeTheta, m_offsetTheta)); + _decoder->set(cID, m_phiID, positionToBin(lPhi, 2 * M_PI / (double)m_phiBins, m_offsetPhi)); + return cID; +} + +/// determine the azimuthal angle phi based on the cell ID +double FCCSWHCalPhiTheta_k4geo::phi(const CellID& cID) const { + CellID phiValue = _decoder->get(cID, m_phiID); + return binToPosition(phiValue, 2. * M_PI / (double)m_phiBins, m_offsetPhi); +} +} +} diff --git a/detectorSegmentations/src/plugins/SegmentationFactories.cpp b/detectorSegmentations/src/plugins/SegmentationFactories.cpp index d362660de..9b0632c55 100644 --- a/detectorSegmentations/src/plugins/SegmentationFactories.cpp +++ b/detectorSegmentations/src/plugins/SegmentationFactories.cpp @@ -34,3 +34,6 @@ DECLARE_SEGMENTATION(GridDRcalo_k4geo, create_segmentation) + +#include "detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h" +DECLARE_SEGMENTATION(FCCSWHCalPhiTheta_k4geo, create_segmentation) From 9cacda72743b0827d12fea88480ff10ae39665f0 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Thu, 7 Nov 2024 12:01:00 +0100 Subject: [PATCH 083/133] Additional PhiRow segmentation for HCal --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml | 13 + .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 13 + .../FCCSWHCalPhiRowHandle_k4geo.h | 113 +++ .../FCCSWHCalPhiRow_k4geo.h | 240 +++++++ .../src/FCCSWHCalPhiRowHandle_k4geo.cpp | 4 + .../src/FCCSWHCalPhiRow_k4geo.cpp | 674 ++++++++++++++++++ .../src/plugins/SegmentationFactories.cpp | 3 + 7 files changed, 1060 insertions(+) create mode 100644 detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRowHandle_k4geo.h create mode 100644 detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h create mode 100644 detectorSegmentations/src/FCCSWHCalPhiRowHandle_k4geo.cpp create mode 100644 detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml index cfcc37eac..a62dab702 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml @@ -57,6 +57,19 @@ offset_phi="-pi+(pi/BarHCal_n_phi_modules)"/> system:4,layer:5,row:9,theta:9,phi:10 + + + system:4,layer:5,row:9,phi:10 + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml index 5d64a9b5a..c630263ca 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -56,6 +56,19 @@ offset_phi="-pi+(pi/EndcapHCal_n_phi_modules)"/> system:4,type:3,layer:6,row:11,theta:11,phi:10 + + + system:4,type:3,layer:6,row:-8,phi:10 + returning empty neighbours"); + return cellNeighbours; + } + + // part1 min and max layer index + minLayerIdEndcap[0] = minMaxLayerId[0].first; + maxLayerIdEndcap[0] = minMaxLayerId[0].second; + // part2 min and max layer index + minLayerIdEndcap[1] = minMaxLayerId[1].first; + maxLayerIdEndcap[1] = minMaxLayerId[1].second; + // part3 min and max layer index + minLayerIdEndcap[2] = minMaxLayerId[2].first; + maxLayerIdEndcap[2] = minMaxLayerId[2].second; + + // Part 1 + if(currentLayerId >= minLayerIdEndcap[0] && currentLayerId <= maxLayerIdEndcap[0]) + { + minLayerId = minLayerIdEndcap[0]; + maxLayerId = maxLayerIdEndcap[0]; + EndcapPart1 = true; + } + // Part 2 + if(currentLayerId >= minLayerIdEndcap[1] && currentLayerId <= maxLayerIdEndcap[1]) + { + minLayerId = minLayerIdEndcap[1]; + maxLayerId = maxLayerIdEndcap[1]; + EndcapPart2 = true; + } + // Part 3 + if(currentLayerId >= minLayerIdEndcap[2] && currentLayerId <= maxLayerIdEndcap[2]) + { + minLayerId = minLayerIdEndcap[2]; + maxLayerId = maxLayerIdEndcap[2]; + EndcapPart3 = true; + } + + // correct the min and max CellId for endcap + if(currentCellId < 0) // negative-z part (cell index is negative (-1, -2, ... -N)) + { + // second half of elements in m_cellIndexes[currentLayerId] vector corresponds to the negative-z layer cells + minCellId = m_cellIndexes[currentLayerId].back(); + maxCellId = m_cellIndexes[currentLayerId][m_cellIndexes[currentLayerId].size()/2]; + } + else // positive-z part (cell index is positive (1, 2, ... N)) + { + // first half of elements in m_cellIndexes[currentLayerId] vector corresponds to the positive-z layer cells + minCellId = m_cellIndexes[currentLayerId].front(); + maxCellId = m_cellIndexes[currentLayerId][m_cellIndexes[currentLayerId].size()/2 - 1]; + } + } + else // for Barrel + { + minLayerId = 0; + maxLayerId = m_radii.size()-1; + } + //-------------------------------- + + + //-------------------------------- + // Find neighbours + //-------------------------------- + + // if this is not the first layer then look for neighbours in the previous layer + if(currentLayerId > minLayerId) + { + CellID nID = cID ; + int prevLayerId = currentLayerId - 1; + _decoder->set(nID,"layer",prevLayerId); + + // if the granularity is the same for the previous layer then take the cells with currentCellId, currentCellId - 1, and currentCellId + 1 + if(m_gridSizeRow[prevLayerId] == m_gridSizeRow[currentLayerId]) + { + _decoder->set(nID,m_rowID,currentCellId); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + if(currentCellId > minCellId) + { + _decoder->set(nID,m_rowID,currentCellId - 1); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + if(currentCellId < maxCellId) + { + _decoder->set(nID,m_rowID,currentCellId + 1); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + // if the granularity is different + else + { + // determine the cell index in the previous layer that is below of the current cell + int idx = (currentCellId > 0) ? ((currentCellId-1)/m_gridSizeRow[prevLayerId] + 1) : ((currentCellId+1)/m_gridSizeRow[prevLayerId] - 1); + _decoder->set(nID,m_rowID,idx); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + + // + if((m_gridSizeRow[prevLayerId] - abs(currentCellId)%m_gridSizeRow[prevLayerId]) == (m_gridSizeRow[prevLayerId]-1) && currentCellId > minCellId) + { + _decoder->set(nID,m_rowID, (idx > 0) ? (idx - 1) : (idx + 1)); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + + // + if(abs(currentCellId)%m_gridSizeRow[prevLayerId] == 0 && currentCellId < maxCellId) + { + _decoder->set(nID,m_rowID, (idx > 0) ? (idx + 1) : (idx - 1)); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + } + + // if this is not the last layer then look for neighbours in the next layer + if(currentLayerId < maxLayerId) + { + CellID nID = cID ; + int nextLayerId = currentLayerId + 1; + _decoder->set(nID,"layer",nextLayerId); + + // if the granularity is the same for the next layer then take the cells with currentCellId, currentCellId - 1, and currentCellId + 1 + if(m_gridSizeRow[nextLayerId] == m_gridSizeRow[currentLayerId]) + { + _decoder->set(nID,m_rowID,currentCellId); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + if(currentCellId > minCellId) + { + _decoder->set(nID,m_rowID,currentCellId - 1); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + if(currentCellId < maxCellId) + { + _decoder->set(nID,m_rowID,currentCellId + 1); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + } + // if the granularity is different + else + { + // determine the cell index in the next layer that is below of the current cell + int idx = (currentCellId > 0) ? ((currentCellId-1)/m_gridSizeRow[nextLayerId] + 1) : ((currentCellId+1)/m_gridSizeRow[nextLayerId] - 1); + _decoder->set(nID,m_rowID,idx); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + + // + if((m_gridSizeRow[nextLayerId] - abs(currentCellId)%m_gridSizeRow[nextLayerId]) == (m_gridSizeRow[nextLayerId]-1) && currentCellId > minCellId) + { + _decoder->set(nID,m_rowID, (idx > 0) ? (idx - 1) : (idx + 1)); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + + // + if(abs(currentCellId)%m_gridSizeRow[nextLayerId] == 0 && currentCellId < maxCellId) + { + _decoder->set(nID,m_rowID, (idx > 0) ? (idx + 1) : (idx - 1)); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + } + } + + // if this is not the first cell in the given layer then add the previous cell + if(currentCellId > minCellId) + { + CellID nID = cID ; + _decoder->set(nID,m_rowID,currentCellId - 1); + cellNeighbours.push_back(nID); // add the previous cell from current layer of the same phi module + } + // if this is not the last cell in the given layer then add the next cell + if(currentCellId < maxCellId) + { + CellID nID = cID ; + _decoder->set(nID,m_rowID,currentCellId + 1); + cellNeighbours.push_back(nID); // add the next cell from current layer of the same phi module + } + + // if this is the Endcap then look for neighbours in different parts as well + if(m_offsetZ.size() > 1) + { + double currentLayerRmin = m_radii[currentLayerId] - 0.5*m_layerDepth[currentLayerId]; + double currentLayerRmax = m_radii[currentLayerId] + 0.5*m_layerDepth[currentLayerId]; + + // if the cell is in negative-z part, then swap min and max cell indexes + if(currentCellId < 0) + { + minCellId = m_cellIndexes[currentLayerId][m_cellIndexes[currentLayerId].size()/2]; // this should be -1 + maxCellId = m_cellIndexes[currentLayerId].back(); // this should be -N + } + + // if it is the last cell in the part1 + if(EndcapPart1 && currentCellId == maxCellId ) + { + // find the layers in the part2 that share a border with the current layer + for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + { + double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; + double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_rowID,minCellId); + cellNeighbours.push_back(nID); // add the first cell from part2 layer + } + } + } + + // if it is the first cell in the part2 + if(EndcapPart2 && currentCellId == minCellId) + { + // find the layers in part1 that share a border with the current layer + for(int part1layerId = minLayerIdEndcap[0]; part1layerId <= maxLayerIdEndcap[0]; part1layerId++) + { + double Rmin = m_radii[part1layerId] - 0.5*m_layerDepth[part1layerId]; + double Rmax = m_radii[part1layerId] + 0.5*m_layerDepth[part1layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part1layerId); + _decoder->set(nID,m_rowID,maxCellId); + cellNeighbours.push_back(nID); // add the last cell from the part1 layer + } + } + } + + // if it is the last cell in the part2 + if(EndcapPart2 && currentCellId == maxCellId) + { + // find the layers in the part3 that share a border with the current layer + for(int part3layerId = minLayerIdEndcap[2]; part3layerId <= maxLayerIdEndcap[2]; part3layerId++) + { + double Rmin = m_radii[part3layerId] - 0.5*m_layerDepth[part3layerId]; + double Rmax = m_radii[part3layerId] + 0.5*m_layerDepth[part3layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part3layerId); + _decoder->set(nID,m_rowID,minCellId); + cellNeighbours.push_back(nID); // add the first cell from the part3 layer + } + } + } + + // if it is the first cell in the part3 + if(EndcapPart3 && currentCellId == minCellId) + { + // find the layers in the part2 that share a border with the current layer + for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + { + double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; + double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_rowID,maxCellId); + cellNeighbours.push_back(nID); // add the last cell from the part2 layer + } + } + } + } + + // Now loop over the neighbours and add the cells from next/previous phi module + for(auto nID : cellNeighbours) + { + CellID newID = nID; + // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 + _decoder->set(newID,m_phiID, (_decoder->get(nID,m_phiID) == 0) ? m_phiBins - 1 : _decoder->get(nID,m_phiID) - 1); + cellNeighbours.push_back(newID); + // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 + _decoder->set(newID,m_phiID, (_decoder->get(nID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(nID,m_phiID) + 1); + cellNeighbours.push_back(newID); + } + + // At the end, find neighbours with the same layer/row in next/previous phi module + CellID nID = cID ; + // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 + _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == 0) ? m_phiBins - 1 : _decoder->get(cID,m_phiID) - 1); + cellNeighbours.push_back(nID); + // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 + _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(cID,m_phiID) + 1); + cellNeighbours.push_back(nID); + + return cellNeighbours; +} + +/// Determine minimum and maximum polar angle of the cell +std::array FCCSWHCalPhiRow_k4geo::cellTheta(const CellID& cID) const { + std::array cTheta = {M_PI,M_PI}; + + // get the cell index + int idx = _decoder->get(cID, m_rowID); + // get the layer index + uint layer = _decoder->get(cID,"layer"); + + if(m_radii.empty()) calculateLayerRadii(); + if(m_cellEdges.empty()) return cTheta; + + double zlow = m_cellEdges[layer][idx].first; + double zhigh = m_cellEdges[layer][idx].second; + + double Rmin = m_radii[layer] - 0.5*m_layerDepth[layer]; + double Rmax = m_radii[layer] + 0.5*m_layerDepth[layer]; + + if( theta(cID) < M_PI/2. ) + { + cTheta[0] = std::atan2(Rmin,zhigh); // theta min + cTheta[1] = std::atan2(Rmax,zlow); // theta max + } + else + { + cTheta[0] = std::atan2(Rmax,zhigh); // theta min + cTheta[1] = std::atan2(Rmin,zlow); // theta max + } + + return cTheta; +} + +} +} diff --git a/detectorSegmentations/src/plugins/SegmentationFactories.cpp b/detectorSegmentations/src/plugins/SegmentationFactories.cpp index 9b0632c55..a3ac9b0e9 100644 --- a/detectorSegmentations/src/plugins/SegmentationFactories.cpp +++ b/detectorSegmentations/src/plugins/SegmentationFactories.cpp @@ -37,3 +37,6 @@ DECLARE_SEGMENTATION(FCCSWEndcapTurbine_k4geo, create_segmentation) + +#include "detectorSegmentations/FCCSWHCalPhiRow_k4geo.h" +DECLARE_SEGMENTATION(FCCSWHCalPhiRow_k4geo, create_segmentation) From 9d636f56fa60cfb68f00987ca76c1641005b5146 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Thu, 7 Nov 2024 12:05:37 +0100 Subject: [PATCH 084/133] Updates for HCal PhiTheta segmentation: determine neighbours --- .../FCCSWHCalPhiThetaHandle_k4geo.h | 6 +- .../FCCSWHCalPhiTheta_k4geo.h | 22 +- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 453 ++++++++++++++++++ 3 files changed, 476 insertions(+), 5 deletions(-) diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h index e787bbd45..475b39649 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h @@ -18,7 +18,7 @@ class Segmentation; template class SegmentationWrapper; /// We need some abbreviation to make the code more readable. -typedef Handle> FCCSWGridPhiThetaHandle_k4geo; +typedef Handle> FCCSWHCalPhiThetaHandle_k4geo; /// Implementation class for the HCal phi-theta segmentation. /** @@ -38,10 +38,10 @@ typedef Handle> FCC * conveniance reasons instantiated in DD4hep/src/Segmentations.cpp. * */ -class FCCSWHCalPhiTheta_k4geo : public FCCSWGridPhiThetaHandle_k4geo { +class FCCSWHCalPhiTheta_k4geo : public FCCSWHCalPhiThetaHandle_k4geo { public: /// Defintion of the basic handled object - typedef FCCSWGridPhiThetaHandle_k4geo::Object Object; + typedef FCCSWHCalPhiThetaHandle_k4geo::Object Object; public: /// Default constructor diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h index 439d56ab7..58338b57a 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h @@ -26,9 +26,8 @@ namespace dd4hep { virtual ~FCCSWHCalPhiTheta_k4geo() = default; /** Determine the position of HCal cell based on the cellID. - * @warning This segmentation has no knowledge of radius, so radius = 1 is taken into calculations. * @param[in] aCellId ID of a cell. - * return Position (radius = 1). + * return Position. */ virtual Vector3D position(const CellID& aCellID) const; @@ -41,6 +40,12 @@ namespace dd4hep { virtual CellID cellID(const Vector3D& aLocalPosition, const Vector3D& aGlobalPosition, const VolumeID& aVolumeID) const; + /** Find neighbours of the cell + * @param[in] aCellId ID of a cell. + * return vector of neighbour cellIDs. + */ + std::vector neighbours(const CellID& cID) const; + /** Calculate layer radii and edges in z-axis, then define cell edges in each layer using defineCellEdges(). */ void defineCellsInRZplan() const; @@ -119,6 +124,17 @@ namespace dd4hep { inline Vector3D centerPosition(const CellID& cID) const; + /** Determine the minimum and maximum polar angle of HCal cell based on the cellID. + * @param[in] aCellId ID of a cell. + * return Theta. + */ + std::array cellTheta(const CellID& cID) const; + + /** Get the min and max layer indexes of each HCal part. + * For Endcap, returns the three elements vector, while for Barrel - single element vector. + */ + std::vector > getMinMaxLayerId() const ; + /** Set the number of bins in azimuthal angle. * @param[in] aNumberBins Number of bins in phi. */ @@ -183,6 +199,8 @@ namespace dd4hep { mutable std::vector m_radii; /// z-min and z-max of each layer mutable std::vector > m_layerEdges; + /// dR of each layer + mutable std::vector m_layerDepth; /// theta bins (cells) in each layer mutable std::vector > m_thetaBins; /// z-min and z-max of each cell (theta bin) in each layer diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index cc49d9e32..765b9b3fc 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -94,6 +94,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { m_radii.push_back(m_offsetR[0] + moduleDepth - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); + m_layerDepth.push_back(m_dRlayer[i_dR]); } } } // Barrel @@ -114,6 +115,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { m_radii.push_back(m_offsetR[0] + moduleDepth1 - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); + m_layerDepth.push_back(m_dRlayer[i_dR]); } } // part2 @@ -125,6 +127,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { m_radii.push_back(m_offsetR[1] + moduleDepth2 - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis m_layerEdges.push_back( std::make_pair(m_offsetZ[1] - 0.5*m_widthZ[1], m_offsetZ[1] + 0.5*m_widthZ[1]) ); + m_layerDepth.push_back(m_dRlayer[i_dR]); } } // part3 @@ -136,6 +139,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { m_radii.push_back(m_offsetR[2] + moduleDepth3 - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis m_layerEdges.push_back( std::make_pair(m_offsetZ[2] - 0.5*m_widthZ[2], m_offsetZ[2] + 0.5*m_widthZ[2]) ); + m_layerDepth.push_back(m_dRlayer[i_dR]); } } } // ThreePartsEndcap @@ -280,5 +284,454 @@ double FCCSWHCalPhiTheta_k4geo::phi(const CellID& cID) const { CellID phiValue = _decoder->get(cID, m_phiID); return binToPosition(phiValue, 2. * M_PI / (double)m_phiBins, m_offsetPhi); } + + +/// Get the min and max layer indexes for each part of the HCal +std::vector > FCCSWHCalPhiTheta_k4geo::getMinMaxLayerId() const { + /* + * hardcoded numbers would be the following: + * std::vector minLayerIdEndcap = {0, 6, 15}; + * std::vector maxLayerIdEndcap = {5, 14, 36}; + * but lets try to avoid hardcoding: + */ + + std::vector > minMaxLayerId; + + if(m_radii.empty()) defineCellsInRZplan(); + if(m_radii.empty()) return minMaxLayerId; + + + std::vector minLayerIdEndcap = {0, 0, 0}; + std::vector maxLayerIdEndcap = {-1, 0, 0}; + if(m_offsetZ.size() > 1) + { + uint Nl = m_numLayers.size()/3; + + // count the number of layers in the first part of the Endcap + for(uint i=0; i < Nl; i++) maxLayerIdEndcap[0] += m_numLayers[i]; + + minLayerIdEndcap[1] = maxLayerIdEndcap[0]+1; + maxLayerIdEndcap[1] = maxLayerIdEndcap[0]; + // count the number of layers in the second part of the Endcap + for(uint i=0; i < Nl; i++) maxLayerIdEndcap[1] += m_numLayers[i+Nl]; + + minLayerIdEndcap[2] = maxLayerIdEndcap[1]+1; + maxLayerIdEndcap[2] = maxLayerIdEndcap[1]; + // count the number of layers in the third part of the Endcap + for(uint i=0; i < Nl; i++) maxLayerIdEndcap[2] += m_numLayers[i+2*Nl]; + + minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[0],maxLayerIdEndcap[0])); + minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[1],maxLayerIdEndcap[1])); + minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[2],maxLayerIdEndcap[2])); + } + else // for Barrel + { + minMaxLayerId.push_back(std::make_pair(0,m_radii.size()-1)); + } + + return minMaxLayerId; +} + + +/// Calculates the neighbours of the given cell ID and adds them to the list of neighbours +std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) const { + std::vector cellNeighbours; + + if(m_radii.empty()) defineCellsInRZplan(); + if(m_thetaBins.empty()) return cellNeighbours; + + bool EndcapPart1 = false; + bool EndcapPart2 = false; + bool EndcapPart3 = false; + + int minLayerId = -1; + int maxLayerId = -1; + + int currentLayerId = _decoder->get(cID,"layer"); + int currentCellThetaBin = _decoder->get(cID,m_thetaID); + + int minCellThetaBin = m_thetaBins[currentLayerId].front(); + int maxCellThetaBin = m_thetaBins[currentLayerId].back(); + + //-------------------------------- + // Determine min and max layer Id + //-------------------------------- + // if this is the segmentation of three parts Endcap + std::vector minLayerIdEndcap = {0, 0, 0}; + std::vector maxLayerIdEndcap = {0, 0, 0}; + if(m_offsetZ.size() > 1) + { + std::vector > minMaxLayerId(getMinMaxLayerId()); + if(minMaxLayerId.empty()) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Can not get ThreePartsEndcap min and max layer indexes! --> returning empty neighbours"); + return cellNeighbours; + } + + // part1 min and max layer index + minLayerIdEndcap[0] = minMaxLayerId[0].first; + maxLayerIdEndcap[0] = minMaxLayerId[0].second; + // part2 min and max layer index + minLayerIdEndcap[1] = minMaxLayerId[1].first; + maxLayerIdEndcap[1] = minMaxLayerId[1].second; + // part3 min and max layer index + minLayerIdEndcap[2] = minMaxLayerId[2].first; + maxLayerIdEndcap[2] = minMaxLayerId[2].second; + + // Part 1 + if(currentLayerId >= minLayerIdEndcap[0] && currentLayerId <= maxLayerIdEndcap[0]) + { + minLayerId = minLayerIdEndcap[0]; + maxLayerId = maxLayerIdEndcap[0]; + EndcapPart1 = true; + } + // Part 2 + if(currentLayerId >= minLayerIdEndcap[1] && currentLayerId <= maxLayerIdEndcap[1]) + { + minLayerId = minLayerIdEndcap[1]; + maxLayerId = maxLayerIdEndcap[1]; + EndcapPart2 = true; + } + // Part 3 + if(currentLayerId >= minLayerIdEndcap[2] && currentLayerId <= maxLayerIdEndcap[2]) + { + minLayerId = minLayerIdEndcap[2]; + maxLayerId = maxLayerIdEndcap[2]; + EndcapPart3 = true; + } + + // correct the min and max theta bin for endcap + if(theta(cID) > M_PI/2) // negative-z part + { + // second half of elements in m_thetaBins[currentLayerId] vector corresponds to the negative-z layer cells + minCellThetaBin = m_thetaBins[currentLayerId][m_thetaBins[currentLayerId].size()/2]; + maxCellThetaBin = m_thetaBins[currentLayerId].back(); + } + else // positive-z part + { + // first half of elements in m_thetaBins[currentLayerId] vector corresponds to the positive-z layer cells + minCellThetaBin = m_thetaBins[currentLayerId].front(); + maxCellThetaBin = m_thetaBins[currentLayerId][m_thetaBins[currentLayerId].size()/2 - 1]; + } + } + else // for Barrel + { + minLayerId = 0; + maxLayerId = m_radii.size()-1; + } + //-------------------------------- + + + //-------------------------------- + // Find neighbours + //-------------------------------- + + //--------------------------------------------- + // this part is same for both Barrel and Endcap + //--------------------------------------------- + // if this is not the first cell in the given layer then add the previous cell + if(currentCellThetaBin > minCellThetaBin) + { + CellID nID = cID ; + _decoder->set(nID,m_thetaID,currentCellThetaBin - 1); + cellNeighbours.push_back(nID); // add the previous cell from current layer of the same phi module + } + // if this is not the last cell in the given layer then add the next cell + if(currentCellThetaBin < maxCellThetaBin) + { + CellID nID = cID ; + _decoder->set(nID,m_thetaID,currentCellThetaBin + 1); + cellNeighbours.push_back(nID); // add the next cell from current layer of the same phi module + } + //---------------------------------------------- + + // deal with the Barrel + if(m_offsetZ.size() == 1) + { + // if this is not the first layer then look for neighbours in the previous layer + if(currentLayerId > minLayerId) + { + CellID nID = cID ; + int prevLayerId = currentLayerId - 1; + _decoder->set(nID,"layer",prevLayerId); + + _decoder->set(nID,m_thetaID,currentCellThetaBin); + cellNeighbours.push_back(nID); // add the cell with the same theta bin from the previous layer of the same phi module + + // if the cID is in the positive-z side and prev layer cell is not in the first theta bin then add the cell from previous theta bin + if(theta(cID) < M_PI/2. && currentCellThetaBin > m_thetaBins[prevLayerId].front() ) + { + _decoder->set(nID,m_thetaID,currentCellThetaBin - 1); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + // if the cID is in the negative-z side and prev layer cell is not in the last theta bin then add the cell from previous theta bin + if(theta(cID) > M_PI/2. && currentCellThetaBin < m_thetaBins[prevLayerId].back() ) + { + _decoder->set(nID,m_thetaID,currentCellThetaBin + 1); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + + // if this is not the last layer then look for neighbours in the next layer + if(currentLayerId < maxLayerId) + { + double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; + double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; + + CellID nID = cID ; + int nextLayerId = currentLayerId + 1; + _decoder->set(nID,"layer",nextLayerId); + + _decoder->set(nID,m_thetaID,currentCellThetaBin); + cellNeighbours.push_back(nID); // add the cell with the same theta bin from the next layer of the same phi module + + // if the cID is in the positive-z side + if(theta(cID) < M_PI/2.) + { + //add the next layer cell from the next theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin + 1); + cellNeighbours.push_back(nID); + + //add the next layer cell from the next-to-next theta bin if it overlaps with the current cell in z-coordinate + double zmax = m_cellEdges[nextLayerId][currentCellThetaBin + 2].second; + if(zmax >= currentCellZmin) + { + //add the next layer cell from the next to next theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin + 2); + cellNeighbours.push_back(nID); + } + } + // if the cID is in the negative-z side + if(theta(cID) > M_PI/2.) + { + //add the next layer cell from the previous theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin - 1); + cellNeighbours.push_back(nID); + + //add the next layer cell from the next-to-next theta bin if it overlaps with the current cell in z-coordinate + double zmin = m_cellEdges[nextLayerId][currentCellThetaBin - 2].first; + if(zmin <= currentCellZmax) + { + //add the next layer cell from the next to next theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin - 2); + cellNeighbours.push_back(nID); + } + } + } + } + + // if this is the Endcap then look for neighbours in different parts as well + if(m_offsetZ.size() > 1) + { + double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; + double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; + + // if this is not the first layer then look for neighbours in the previous layer + if(currentLayerId > minLayerId) + { + CellID nID = cID ; + int prevLayerId = currentLayerId - 1; + _decoder->set(nID,"layer",prevLayerId); + // find the ones that share at least part of a border with the current cell + for( auto bin : m_thetaBins[prevLayerId] ) + { + double zmin = m_cellEdges[prevLayerId][bin].first; + double zmax = m_cellEdges[prevLayerId][bin].second; + + if( (zmin >= currentCellZmin && zmin <=currentCellZmax) + || (zmax >= currentCellZmin && zmax <=currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + } + // if this is not the last layer then look for neighbours in the next layer + if(currentLayerId < maxLayerId) + { + CellID nID = cID ; + int nextLayerId = currentLayerId + 1; + _decoder->set(nID,"layer",nextLayerId); + // find the ones that share at least part of a border with the current cell + for( auto bin : m_thetaBins[nextLayerId] ) + { + double zmin = m_cellEdges[nextLayerId][bin].first; + double zmax = m_cellEdges[nextLayerId][bin].second; + + if( (zmin >= currentCellZmin && zmin <=currentCellZmax) + || (zmax >= currentCellZmin && zmax <=currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + } + + + // + double currentLayerRmin = m_radii[currentLayerId] - 0.5*m_layerDepth[currentLayerId]; + double currentLayerRmax = m_radii[currentLayerId] + 0.5*m_layerDepth[currentLayerId]; + + + // if the cell is in negative-z part, then swap min and max theta bins + if(theta(cID) > M_PI/2.) + { + minCellThetaBin = m_thetaBins[currentLayerId].back(); + maxCellThetaBin = m_thetaBins[currentLayerId][m_thetaBins[currentLayerId].size()/2]; + } + + // if it is the last cell in the part1 + if(EndcapPart1 && currentCellThetaBin == minCellThetaBin ) + { + // find the layers in the part2 that share a border with the current layer + for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + { + double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; + double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer + } + } + } + + // if it is the last theta bin cell in the part2 + if(EndcapPart2 && currentCellThetaBin == maxCellThetaBin) + { + // find the layers in part1 that share a border with the current layer + for(int part1layerId = minLayerIdEndcap[0]; part1layerId <= maxLayerIdEndcap[0]; part1layerId++) + { + double Rmin = m_radii[part1layerId] - 0.5*m_layerDepth[part1layerId]; + double Rmax = m_radii[part1layerId] + 0.5*m_layerDepth[part1layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part1layerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer + } + } + } + + // if it is the first theta bin cell in the part2 + if(EndcapPart2 && currentCellThetaBin == minCellThetaBin) + { + // find the layers in the part3 that share a border with the current layer + for(int part3layerId = minLayerIdEndcap[2]; part3layerId <= maxLayerIdEndcap[2]; part3layerId++) + { + double Rmin = m_radii[part3layerId] - 0.5*m_layerDepth[part3layerId]; + double Rmax = m_radii[part3layerId] + 0.5*m_layerDepth[part3layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part3layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the first cell from the part3 layer + } + } + } + + // if it is the last theta bin cell in the part3 + if(EndcapPart3 && currentCellThetaBin == maxCellThetaBin) + { + // find the layers in the part2 that share a border with the current layer + for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + { + double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; + double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer + } + } + } + } + + // Now loop over the neighbours and add the cells from next/previous phi module + for(auto nID : cellNeighbours) + { + CellID newID = nID; + // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 + _decoder->set(newID,m_phiID, (_decoder->get(nID,m_phiID) == 0) ? m_phiBins - 1 : _decoder->get(nID,m_phiID) - 1); + cellNeighbours.push_back(newID); + // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 + _decoder->set(newID,m_phiID, (_decoder->get(nID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(nID,m_phiID) + 1); + cellNeighbours.push_back(newID); + } + + // At the end, find neighbours with the same layer/row in next/previous phi module + CellID nID = cID ; + // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 + _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == 0) ? m_phiBins - 1 : _decoder->get(cID,m_phiID) - 1); + cellNeighbours.push_back(nID); + // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 + _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(cID,m_phiID) + 1); + cellNeighbours.push_back(nID); + + return cellNeighbours; +} + +/// Determine minimum and maximum polar angle of the cell +std::array FCCSWHCalPhiTheta_k4geo::cellTheta(const CellID& cID) const { + std::array cTheta = {M_PI,M_PI}; + + // get the cell index + int idx = _decoder->get(cID, m_thetaID); + // get the layer index + uint layer = _decoder->get(cID,"layer"); + + if(m_radii.empty()) defineCellsInRZplan(); + if(m_cellEdges.empty()) return cTheta; + + double zlow = m_cellEdges[layer][idx].first; + double zhigh = m_cellEdges[layer][idx].second; + + double Rmin = m_radii[layer] - 0.5*m_layerDepth[layer]; + double Rmax = m_radii[layer] + 0.5*m_layerDepth[layer]; + + if( theta(cID) < M_PI/2. ) + { + cTheta[0] = std::atan2(Rmin,zhigh); // theta min + cTheta[1] = std::atan2(Rmax,zlow); // theta max + } + else + { + cTheta[0] = std::atan2(Rmax,zhigh); // theta min + cTheta[1] = std::atan2(Rmin,zlow); // theta max + } + + return cTheta; +} + } } From 6ee5a72c2789d8a343f3e41ec8a84a8aacc4a0e7 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sat, 9 Nov 2024 21:01:17 +0100 Subject: [PATCH 085/133] fix in the HCal neighbours --- .../detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h | 13 +++---------- detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp | 6 ++++-- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 9 +++++---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h index 58338b57a..75427523b 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h @@ -25,9 +25,9 @@ namespace dd4hep { /// destructor virtual ~FCCSWHCalPhiTheta_k4geo() = default; - /** Determine the position of HCal cell based on the cellID. - * @param[in] aCellId ID of a cell. - * return Position. + /** Get the postion of the geometric center of the cell based on the cellID + * @param[in] aCellID + * return the global coordinates of cell center */ virtual Vector3D position(const CellID& aCellID) const; @@ -117,13 +117,6 @@ namespace dd4hep { */ inline const std::string& fieldNamePhi() const { return m_phiID; } - /** Get the postion og the geometric center of the cell based on the cellID - * @param[in] aCellID - * return the global coordinates of cell center - */ - inline Vector3D centerPosition(const CellID& cID) const; - - /** Determine the minimum and maximum polar angle of HCal cell based on the cellID. * @param[in] aCellId ID of a cell. * return Theta. diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index 405261bdf..511f4adb4 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -614,8 +614,10 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const } } +/* // Now loop over the neighbours and add the cells from next/previous phi module - for(auto nID : cellNeighbours) + std::vector cellNeighboursCopy(cellNeighbours); + for(auto nID : cellNeighboursCopy) { CellID newID = nID; // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 @@ -634,7 +636,7 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(cID,m_phiID) + 1); cellNeighbours.push_back(nID); - +*/ return cellNeighbours; } diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index 765b9b3fc..6477d0a5d 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -38,7 +38,7 @@ FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const BitFieldCoder* decoder) : } -/// determine the global position based on the cell ID +/** /// determine the global position based on the cell ID Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { uint layer = _decoder->get(cID,"layer"); double radius = 1.0; @@ -48,11 +48,11 @@ Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { return positionFromRThetaPhi(radius, theta(cID), phi(cID)); } - +**/ /// determine the global position based on the cell ID /// returns the geometric center of the cell -Vector3D FCCSWHCalPhiTheta_k4geo::centerPosition(const CellID& cID) const { +Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { uint layer = _decoder->get(cID,"layer"); int thetaID = _decoder->get(cID,"theta"); double zpos = 0.; @@ -678,7 +678,8 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con } // Now loop over the neighbours and add the cells from next/previous phi module - for(auto nID : cellNeighbours) + std::vector cellNeighboursCopy(cellNeighbours); + for(auto nID : cellNeighboursCopy) { CellID newID = nID; // previous: if the current is 0 then previous is the last bin (id = m_phiBins - 1) else current - 1 From 019379ae9bc789ef6985535da628ac6f427b6d8c Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sat, 9 Nov 2024 21:57:45 +0100 Subject: [PATCH 086/133] New HCal readouts in ALLEGRO_o1_v04 --- .../compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml | 4 +- .../ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml | 146 ++++++++++++++++ .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 158 ++++++++++++++++++ 3 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml index a0a5dcf1a..4acb0d6f3 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml @@ -45,9 +45,9 @@ - + - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml new file mode 100644 index 000000000..a62dab702 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml @@ -0,0 +1,146 @@ + + + + The first FCCee HCal layout based on ATLAS HCal, not optimised yet + 1. Nov 2022, J. Faltova: update material and radial segmentation for FCCee + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,layer:5,row:9,theta:9,phi:10 + + + + system:4,layer:5,row:9,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml new file mode 100644 index 000000000..c630263ca --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -0,0 +1,158 @@ + + + + HCal layout based on ATLAS HCal, with realistic longitudinal segmentation and steel support + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,type:3,layer:6,row:11,theta:11,phi:10 + + + + system:4,type:3,layer:6,row:-8,phi:10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1380be1d6d4083e286a35433fd82adf46eb329a6 Mon Sep 17 00:00:00 2001 From: Archil-AD Date: Thu, 14 Nov 2024 10:31:04 +0100 Subject: [PATCH 087/133] Update detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp fixing typo Co-authored-by: Andre Sailer --- detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index 511f4adb4..a1be32584 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -67,7 +67,7 @@ Vector3D FCCSWHCalPhiRow_k4geo::position(const CellID& cID) const { // calculate z-coordinate of the cell center double zpos = minLayerZ + (idx-1) * m_dz_row * m_gridSizeRow[layer] + 0.5 * m_dz_row * m_gridSizeRow[layer]; - // for negative-z Endcap, the index is negetive (starts from -1!) + // for negative-z Endcap, the index is negative (starts from -1!) if(idx < 0) zpos = -minLayerZ + (idx+1) * m_dz_row * m_gridSizeRow[layer] - 0.5 * m_dz_row * m_gridSizeRow[layer]; return Vector3D( radius * std::cos(phi), radius * std::sin(phi), zpos ); From 39ad9ed387f732e654e3216f158f1a0d51922b84 Mon Sep 17 00:00:00 2001 From: Archil-AD Date: Thu, 14 Nov 2024 10:48:34 +0100 Subject: [PATCH 088/133] Update description of grid_size_row parameter --- detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index a1be32584..4a4202c11 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -16,7 +16,7 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const std::string& cellEncoding) : // register all necessary parameters registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); - registerParameter("grid_size_row", "Cell size in row", m_gridSizeRow, std::vector()); + registerParameter("grid_size_row", "Number of rows combined in a cell", m_gridSizeRow, std::vector()); registerParameter("dz_row", "dz of row", m_dz_row, 0.); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); @@ -35,7 +35,7 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const BitFieldCoder* decoder) : Seg // register all necessary parameters registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); - registerParameter("grid_size_row", "Cell size in row", m_gridSizeRow, std::vector()); + registerParameter("grid_size_row", "Number of rows combined in a cell", m_gridSizeRow, std::vector()); registerParameter("dz_row", "dz of row", m_dz_row, 0.); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); From 7348d72419798152dc017523a8fadd5654518d59 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sun, 17 Nov 2024 14:21:42 +0100 Subject: [PATCH 089/133] Added units in HCal xml files --- .../compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml | 3 ++- .../ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml | 3 ++- .../compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml | 5 +++-- .../ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml index a62dab702..f5ce03fe6 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml @@ -60,7 +60,7 @@ + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml index c630263ca..42e6904ef 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -59,7 +59,7 @@ + system:4,layer:5,row:9,theta:9,phi:10 - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml index c630263ca..48c59bb81 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -56,10 +56,10 @@ offset_phi="-pi+(pi/EndcapHCal_n_phi_modules)"/> system:4,type:3,layer:6,row:11,theta:11,phi:10 - + + Date: Sun, 17 Nov 2024 14:29:43 +0100 Subject: [PATCH 090/133] Fix in phi position calculation and added phi neigbours for HCal PhiRow segmentation --- detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index 4a4202c11..9cabe64ff 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -50,7 +50,6 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const BitFieldCoder* decoder) : Seg /// determine the global position based on the cell ID Vector3D FCCSWHCalPhiRow_k4geo::position(const CellID& cID) const { uint layer = _decoder->get(cID,"layer"); - double phi = _decoder->get(cID,m_phiID); if(m_radii.empty()) calculateLayerRadii(); if(m_radii.empty() || m_layerEdges.empty()) @@ -70,7 +69,7 @@ Vector3D FCCSWHCalPhiRow_k4geo::position(const CellID& cID) const { // for negative-z Endcap, the index is negative (starts from -1!) if(idx < 0) zpos = -minLayerZ + (idx+1) * m_dz_row * m_gridSizeRow[layer] - 0.5 * m_dz_row * m_gridSizeRow[layer]; - return Vector3D( radius * std::cos(phi), radius * std::sin(phi), zpos ); + return Vector3D( radius * std::cos(phi(cID)), radius * std::sin(phi(cID)), zpos ); } @@ -212,7 +211,7 @@ void FCCSWHCalPhiRow_k4geo::defineCellIndexes(const uint layer) const { double z1 = minLayerZ + (idx-1) * m_dz_row * m_gridSizeRow[layer]; // lower edge double z2 = minLayerZ + (idx) * m_dz_row * m_gridSizeRow[layer]; // upper edge - // for negative-z Endcap, the index is negetive (starts from -1!) + // for negative-z Endcap, the index is negative (starts from -1!) if(idx < 0) { z1 = -minLayerZ + (idx) * m_dz_row * m_gridSizeRow[layer]; // lower edge @@ -614,7 +613,6 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const } } -/* // Now loop over the neighbours and add the cells from next/previous phi module std::vector cellNeighboursCopy(cellNeighbours); for(auto nID : cellNeighboursCopy) @@ -636,7 +634,7 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const // next: if the current is the last bin (id = m_phiBins - 1) then the next is the first bin (id = 0) else current + 1 _decoder->set(nID,m_phiID, (_decoder->get(cID,m_phiID) == (m_phiBins - 1)) ? 0 : _decoder->get(cID,m_phiID) + 1); cellNeighbours.push_back(nID); -*/ + return cellNeighbours; } From 2dc0463607f53204246a81650d9b59b8ebcf4ce6 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sun, 17 Nov 2024 14:34:34 +0100 Subject: [PATCH 091/133] Added an option to add diagonal neighbour cells for HCal PhiTheta segmentation --- .../FCCSWHCalPhiTheta_k4geo.h | 2 +- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 181 ++++++++++++++---- 2 files changed, 145 insertions(+), 38 deletions(-) diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h index 75427523b..607caa2c4 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h @@ -44,7 +44,7 @@ namespace dd4hep { * @param[in] aCellId ID of a cell. * return vector of neighbour cellIDs. */ - std::vector neighbours(const CellID& cID) const; + std::vector neighbours(const CellID& cID, bool aDiagonal) const; /** Calculate layer radii and edges in z-axis, then define cell edges in each layer using defineCellEdges(). */ diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index 6477d0a5d..04c227ab1 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -334,7 +334,7 @@ std::vector > FCCSWHCalPhiTheta_k4geo::getMinMaxLayerId() c /// Calculates the neighbours of the given cell ID and adds them to the list of neighbours -std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) const { +std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, bool aDiagonal) const { std::vector cellNeighbours; if(m_radii.empty()) defineCellsInRZplan(); @@ -448,6 +448,9 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con // deal with the Barrel if(m_offsetZ.size() == 1) { + double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; + double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; + // if this is not the first layer then look for neighbours in the previous layer if(currentLayerId > minLayerId) { @@ -463,21 +466,40 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con { _decoder->set(nID,m_thetaID,currentCellThetaBin - 1); cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + if(aDiagonal && currentCellThetaBin > (m_thetaBins[prevLayerId].front()+1)) + { + //add the previous layer cell from the prev to prev theta bin if it overlaps with the current cell in z-coordinate + double zmin = m_cellEdges[prevLayerId][currentCellThetaBin - 2].first; + if(zmin <= currentCellZmax) + { + //add the previous layer cell from the prev to prev theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin - 2); + cellNeighbours.push_back(nID); + } + } } // if the cID is in the negative-z side and prev layer cell is not in the last theta bin then add the cell from previous theta bin if(theta(cID) > M_PI/2. && currentCellThetaBin < m_thetaBins[prevLayerId].back() ) { _decoder->set(nID,m_thetaID,currentCellThetaBin + 1); cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + if(aDiagonal && currentCellThetaBin < (m_thetaBins[prevLayerId].back()-1)) + { + //add the previous layer cell from the next to next theta bin if it overlaps with the current cell in z-coordinate + double zmax = m_cellEdges[prevLayerId][currentCellThetaBin + 2].second; + if(zmax >= currentCellZmin) + { + //add the previous layer cell from the next to next theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin + 2); + cellNeighbours.push_back(nID); + } + } } } // if this is not the last layer then look for neighbours in the next layer if(currentLayerId < maxLayerId) { - double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; - double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; - CellID nID = cID ; int nextLayerId = currentLayerId + 1; _decoder->set(nID,"layer",nextLayerId); @@ -492,13 +514,16 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,currentCellThetaBin + 1); cellNeighbours.push_back(nID); - //add the next layer cell from the next-to-next theta bin if it overlaps with the current cell in z-coordinate - double zmax = m_cellEdges[nextLayerId][currentCellThetaBin + 2].second; - if(zmax >= currentCellZmin) + if(aDiagonal) { - //add the next layer cell from the next to next theta bin - _decoder->set(nID,m_thetaID,currentCellThetaBin + 2); - cellNeighbours.push_back(nID); + //add the next layer cell from the next-to-next theta bin if it overlaps with the current cell in z-coordinate + double zmax = m_cellEdges[nextLayerId][currentCellThetaBin + 2].second; + if(zmax >= currentCellZmin) + { + //add the next layer cell from the next to next theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin + 2); + cellNeighbours.push_back(nID); + } } } // if the cID is in the negative-z side @@ -508,13 +533,16 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,currentCellThetaBin - 1); cellNeighbours.push_back(nID); - //add the next layer cell from the next-to-next theta bin if it overlaps with the current cell in z-coordinate - double zmin = m_cellEdges[nextLayerId][currentCellThetaBin - 2].first; - if(zmin <= currentCellZmax) + if(aDiagonal) { - //add the next layer cell from the next to next theta bin - _decoder->set(nID,m_thetaID,currentCellThetaBin - 2); - cellNeighbours.push_back(nID); + //add the next layer cell from the prev to prev theta bin if it overlaps with the current cell in z-coordinate + double zmin = m_cellEdges[nextLayerId][currentCellThetaBin - 2].first; + if(zmin <= currentCellZmax) + { + //add the next layer cell from the prev to prev theta bin + _decoder->set(nID,m_thetaID,currentCellThetaBin - 2); + cellNeighbours.push_back(nID); + } } } } @@ -538,13 +566,39 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con double zmin = m_cellEdges[prevLayerId][bin].first; double zmax = m_cellEdges[prevLayerId][bin].second; - if( (zmin >= currentCellZmin && zmin <=currentCellZmax) - || (zmax >= currentCellZmin && zmax <=currentCellZmax) - || (currentCellZmin >= zmin && currentCellZmax <= zmax) - ) + // if the cID is in the positive-z side + if(theta(cID) < M_PI/2.) { - _decoder->set(nID,m_thetaID,bin); - cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + if( (zmin >= currentCellZmin && zmin < currentCellZmax) + || (zmax >= currentCellZmin && zmax <= currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + if(aDiagonal && zmin == currentCellZmax) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + } + // if the cID is in the negative-z side + if(theta(cID) > M_PI/2.) + { + if( (zmin >= currentCellZmin && zmin <= currentCellZmax) + || (zmax > currentCellZmin && zmax <= currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } + if(aDiagonal && zmax == currentCellZmin) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + } } } } @@ -559,14 +613,39 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con { double zmin = m_cellEdges[nextLayerId][bin].first; double zmax = m_cellEdges[nextLayerId][bin].second; - - if( (zmin >= currentCellZmin && zmin <=currentCellZmax) - || (zmax >= currentCellZmin && zmax <=currentCellZmax) - || (currentCellZmin >= zmin && currentCellZmax <= zmax) - ) + // if the cID is in the positive-z side + if(theta(cID) < M_PI/2.) + { + if( (zmin >= currentCellZmin && zmin <=currentCellZmax) + || (zmax > currentCellZmin && zmax <=currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + if(aDiagonal && zmax == currentCellZmin) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + } + // if the cID is in the negative-z side + if(theta(cID) > M_PI/2.) { - _decoder->set(nID,m_thetaID,bin); - cellNeighbours.push_back(nID); // add the cell from the previous layer of the same phi module + if( (zmin >= currentCellZmin && zmin < currentCellZmax) + || (zmax >= currentCellZmin && zmax <=currentCellZmax) + || (currentCellZmin >= zmin && currentCellZmax <= zmax) + ) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } + if(aDiagonal && zmin == currentCellZmax) + { + _decoder->set(nID,m_thetaID,bin); + cellNeighbours.push_back(nID); // add the cell from the next layer of the same phi module + } } } } @@ -594,8 +673,8 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) ) { @@ -604,6 +683,13 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,maxCellThetaBin); cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer } + if(aDiagonal && Rmax == currentLayerRmin) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer + } } } @@ -616,10 +702,10 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con double Rmin = m_radii[part1layerId] - 0.5*m_layerDepth[part1layerId]; double Rmax = m_radii[part1layerId] + 0.5*m_layerDepth[part1layerId]; - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) ) { CellID nID = cID ; @@ -627,6 +713,13 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,minCellThetaBin); cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer } + if(aDiagonal && Rmin == currentLayerRmax) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part1layerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer + } } } @@ -640,8 +733,8 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con double Rmax = m_radii[part3layerId] + 0.5*m_layerDepth[part3layerId]; if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) ) { @@ -650,6 +743,13 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,maxCellThetaBin); cellNeighbours.push_back(nID); // add the first cell from the part3 layer } + if(aDiagonal && Rmax == currentLayerRmin) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part3layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the first cell from the part3 layer + } } } @@ -662,10 +762,10 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) ) { CellID nID = cID ; @@ -673,6 +773,13 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID) con _decoder->set(nID,m_thetaID,minCellThetaBin); cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer } + if(aDiagonal && Rmin == currentLayerRmax) + { + CellID nID = cID ; + _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer + } } } } From 5ba5e8ded5004c2a489c2b47b5840e95dd33062f Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Tue, 26 Nov 2024 16:07:45 +0100 Subject: [PATCH 092/133] adding a test for ALLEGRO v04 in test/CMakeLists.txt --- test/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0b0203867..46576dbf9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -131,6 +131,15 @@ ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" ) endif() +#-------------------------------------------------- +# test for ALLEGRO o1 v04 +if(DCH_INFO_H_EXIST) +SET( test_name "test_ALLEGRO_o1_v04" ) +ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml --runType=batch -G -N=1 --outputFile=testALLEGRO_o1_v04.root --gun.direction "1,0,1" ) +SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception;EXCEPTION;ERROR;Error" ) +endif() + #-------------------------------------------------- # test for ARC o1 v01 SET( test_name "test_ARC_o1_v01_run" ) From 5672b2d4a6eada63c367771b40264d7e1c243218 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Thu, 28 Nov 2024 11:50:11 +0100 Subject: [PATCH 093/133] creating HCal symlinks in ALLEGRO_o1_v04 from ALLEGRO_o1_v03 --- .../ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml | 148 +--------------- .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 160 +----------------- 2 files changed, 2 insertions(+), 306 deletions(-) mode change 100644 => 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml mode change 100644 => 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml deleted file mode 100644 index e108c7bb3..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - - The first FCCee HCal layout based on ATLAS HCal, not optimised yet - 1. Nov 2022, J. Faltova: update material and radial segmentation for FCCee - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - system:4,layer:5,row:9,theta:9,phi:10 - - - - system:4,layer:5,row:9,phi:10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml new file mode 120000 index 000000000..1bde7347d --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalBarrel_TileCal_v03.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml deleted file mode 100644 index 48c59bb81..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - HCal layout based on ATLAS HCal, with realistic longitudinal segmentation and steel support - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - system:4,type:3,layer:6,row:11,theta:11,phi:10 - - - - system:4,type:3,layer:6,row:-8,phi:10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml new file mode 120000 index 000000000..9fb72eebd --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -0,0 +1 @@ +../ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml \ No newline at end of file From 42a78a31103d668ea7b550eb625e86dbd036e553 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sat, 30 Nov 2024 16:44:26 +0100 Subject: [PATCH 094/133] HCal Endcap segmentation class is generalized for N-parts endcap --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml | 2 + .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 2 + .../FCCSWHCalPhiRowHandle_k4geo.h | 6 + .../FCCSWHCalPhiRow_k4geo.h | 45 +- .../FCCSWHCalPhiThetaHandle_k4geo.h | 7 + .../FCCSWHCalPhiTheta_k4geo.h | 47 +- .../src/FCCSWHCalPhiRow_k4geo.cpp | 292 +++++------- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 432 ++++++++---------- 8 files changed, 389 insertions(+), 444 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml index f5ce03fe6..1adb2a8fd 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml @@ -46,6 +46,7 @@ implementation->setOffsetPhi(offset); } + /// set the detector layout + inline void setDetLayout(int detLayout) const { access()->implementation->setDetLayout(detLayout); } + /// set the coordinate offset in z-axis inline void setOffsetZ(std::vector const&offset) const { access()->implementation->setOffsetZ(offset); } @@ -101,6 +104,9 @@ class FCCSWHCalPhiRow_k4geo : public FCCSWHCalPhiRowHandle_k4geo { /// set the grid size in Phi inline void setPhiBins(int cellSize) const { access()->implementation->setPhiBins(cellSize); } + /// access the field name used for layer + inline const std::string& fieldNameLayer() const { return access()->implementation->fieldNameLayer(); } + /// access the field name used for theta inline const std::string& fieldNameRow() const { return access()->implementation->fieldNameRow(); } diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h index ce9b6f44f..acda782e8 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h @@ -11,6 +11,9 @@ * Segmentation in row and phi. * * Cells are defined in r-z plan by merging the row/sequence of scintillator/absorber. + * Each row consists of 2 * Master_Plate + 1 * Spacer_Plate + 1 * Scintillator. + * Considering a single row as a single cell gives the highest possible granularity. + * More details: https://indico.cern.ch/event/1475808/contributions/6219554/attachments/2966253/5218774/FCC_FullSim_HCal_slides.pdf * */ @@ -42,6 +45,7 @@ namespace dd4hep { const VolumeID& aVolumeID) const; /** Find neighbours of the cell + * Definition of neighbours is explained on slide 7: https://indico.cern.ch/event/1475808/contributions/6219554/attachments/2966253/5218774/FCC_FullSim_HCal_slides.pdf * @param[in] aCellId ID of a cell. * return vector of neighbour cellIDs. */ @@ -49,6 +53,10 @@ namespace dd4hep { /** Calculate layer radii and edges in z-axis. + * Following member variables are calculated: + * m_radii + * m_layerEdges + * m_layerDepth */ void calculateLayerRadii() const; @@ -58,7 +66,9 @@ namespace dd4hep { * In case of a cell with single row/sequence, the index is directly the number of row in the layer. * In case of a cell with several rows/sequences merged, the index is the number of cell in the layer. * For the layers of negative-z Endcap, indexes of cells are negative. - * + * Following member variables are calculated: + * m_cellIndexes + * m_cellEdges * @param[in] layer index */ void defineCellIndexes(const unsigned int layer) const; @@ -79,7 +89,7 @@ namespace dd4hep { */ inline int phiBins() const { return m_phiBins; } - /** Get the coordinate offset in azimuthal angle. + /** Get the coordinate offset in azimuthal angle, which is the center of cell with m_phiID=0. * return The offset in phi. */ inline double offsetPhi() const { return m_offsetPhi; } @@ -114,27 +124,34 @@ namespace dd4hep { */ std::vector > getMinMaxLayerId() const ; - /** Get the coordinate offset in z-axis. + /** Get the coordinate offset in z-axis. + * Offset is the middle position of the Barrel or each section of the Endcap. + * For the Barrel, the vector size is 1, while for the Endcap - number of section. * return The offset in z. */ inline std::vector offsetZ() const { return m_offsetZ; } - /** Get the z width of the layer. - * return the z width. + /** Get the z length of the layer. + * return the z length. */ inline std::vector widthZ() const { return m_widthZ; } /** Get the coordinate offset in radius. + * Offset is the inner radius of the first layer in the Barrel or in each section of the Endcap. + * For the Barrel, the vector size is 1, while for the Endcap - number of sections. * return the offset in radius. */ inline std::vector offsetR() const { return m_offsetR; } - /** Get the number of layers. + /** Get the number of layers for each different thickness retrieved with dRlayer(). + * For the Barrel, the vector size equals to the number of different thicknesses used to form the layers. + * For the Endcap, the vector size equals to the number of sections in the Endcap times the number of different thicknesses used to form the layers. * return the number of layers. */ inline std::vector numLayers() const { return m_numLayers; } - /** Get the dR of layers. + /** Get the dR (thickness) of layers. + * The size of the vector equals to the number of different thicknesses used to form the layers. * return the dR. */ inline std::vector dRlayer() const { return m_dRlayer; } @@ -144,6 +161,11 @@ namespace dd4hep { */ inline const std::string& fieldNamePhi() const { return m_phiID; } + /** Get the field name for layer. + * return The field name for layer. + */ + inline const std::string& fieldNameLayer() const { return m_layerID; } + /** Get the field name for row number. * return The field name for row. */ @@ -164,6 +186,11 @@ namespace dd4hep { */ inline void setGridSizeRow(std::vector const&size) { m_gridSizeRow = size; } + /** Set the detector layout (0 = Barrel; 1 = Endcap). + * @param[in] detLayout + */ + inline void setDetLayout(int detLayout) { m_detLayout = detLayout; } + /** Set the coordinate offset in z-axis. * @param[in] offset in z (centre of the layer). */ @@ -208,12 +235,16 @@ namespace dd4hep { double m_offsetPhi; /// the field name used for phi std::string m_phiID; + /// the field name used for layer + std::string m_layerID; /// the grid size in row for each layer std::vector m_gridSizeRow; /// dz of row double m_dz_row; /// the field name used for row std::string m_rowID; + /// the detector layout (0 = Barrel; 1 = Endcap) + int m_detLayout; /// the z offset of middle of the layer std::vector m_offsetZ; /// the z width of the layer diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h index 475b39649..a9f128147 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiThetaHandle_k4geo.h @@ -86,6 +86,9 @@ class FCCSWHCalPhiTheta_k4geo : public FCCSWHCalPhiThetaHandle_k4geo { /// set the coordinate offset in Phi inline void setOffsetPhi(double offset) const { access()->implementation->setOffsetPhi(offset); } + /// set the detector layout + inline void setDetLayout(int detLayout) const { access()->implementation->setDetLayout(detLayout); } + /// set the coordinate offset in z-axis inline void setOffsetZ(std::vector const&offset) const { access()->implementation->setOffsetZ(offset); } @@ -113,6 +116,10 @@ class FCCSWHCalPhiTheta_k4geo : public FCCSWHCalPhiThetaHandle_k4geo { /// access the field name used for Phi inline const std::string& fieldNamePhi() const { return access()->implementation->fieldNamePhi(); } + /// access the field name used for layer + inline const std::string& fieldNameLayer() const { return access()->implementation->fieldNameLayer(); } + + /** \brief Returns a std::vector of the cellDimensions of the given cell ID in natural order of dimensions (dPhi, dTheta) diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h index 607caa2c4..e02ad0ede 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h @@ -10,6 +10,8 @@ * Based on GridTheta_k4geo, addition of azimuthal angle coordinate. * * Rectangular shape cells are defined in r-z plan and all the hits within a defined cell boundaries are assigned the same cellID. + * Cell borders are defined such that closely follow the theta projective towers. + * More details: https://indico.cern.ch/event/1475808/contributions/6219554/attachments/2966253/5218774/FCC_FullSim_HCal_slides.pdf * */ @@ -40,13 +42,21 @@ namespace dd4hep { virtual CellID cellID(const Vector3D& aLocalPosition, const Vector3D& aGlobalPosition, const VolumeID& aVolumeID) const; - /** Find neighbours of the cell + /** Find neighbours of the cell. + * Definition of neighbours is explained on slide 9: https://indico.cern.ch/event/1475808/contributions/6219554/attachments/2966253/5218774/FCC_FullSim_HCal_slides.pdf * @param[in] aCellId ID of a cell. + * @param[in] aDiagonal if true, will include neighbours from diagonal positions in the next and previous layers. * return vector of neighbour cellIDs. */ std::vector neighbours(const CellID& cID, bool aDiagonal) const; /** Calculate layer radii and edges in z-axis, then define cell edges in each layer using defineCellEdges(). + * Following member variables are calculated: + * m_radii + * m_layerEdges + * m_layerDepth + * m_thetaBins (updated through defineCellEdges()) + * m_cellEdges (updated through defineCellEdges()) */ void defineCellsInRZplan() const; @@ -74,12 +84,12 @@ namespace dd4hep { */ inline int phiBins() const { return m_phiBins; } - /** Get the coordinate offset in azimuthal angle. + /** Get the coordinate offset in azimuthal angle, which is the center of cell with m_phiID=0 * return The offset in phi. */ inline double offsetPhi() const { return m_offsetPhi; } - /** Get the vector of theta bins (cells) in a give layer. + /** Get the vector of theta bins (cells) in a given layer. */ inline std::vector thetaBins(const uint layer) const { if(m_radii.empty()) defineCellsInRZplan(); @@ -87,27 +97,34 @@ namespace dd4hep { else return std::vector(); } - /** Get the coordinate offset in z-axis. + /** Get the coordinate offset in z-axis. + * Offset is the middle position of the Barrel or each section of the Endcap. + * For the Barrel, the vector size is 1, while for the Endcap - number of section. * return The offset in z. */ inline std::vector offsetZ() const { return m_offsetZ; } - /** Get the z width of the layer. - * return the z width. + /** Get the z length of the layer. + * return the z length. */ inline std::vector widthZ() const { return m_widthZ; } /** Get the coordinate offset in radius. + * Offset is the inner radius of the first layer in the Barrel or in each section of the Endcap. + * For the Barrel, the vector size is 1, while for the Endcap - number of sections. * return the offset in radius. */ inline std::vector offsetR() const { return m_offsetR; } - /** Get the number of layers. + /** Get the number of layers for each different thickness retrieved with dRlayer(). + * For the Barrel, the vector size equals to the number of different thicknesses used to form the layers. + * For the Endcap, the vector size equals to the number of sections in the Endcap times the number of different thicknesses used to form the layers. * return the number of layers. */ inline std::vector numLayers() const { return m_numLayers; } - /** Get the dR of layers. + /** Get the dR (thickness) of layers. + * The size of the vector equals to the number of different thicknesses used to form the layers. * return the dR. */ inline std::vector dRlayer() const { return m_dRlayer; } @@ -117,6 +134,11 @@ namespace dd4hep { */ inline const std::string& fieldNamePhi() const { return m_phiID; } + /** Get the field name for layer. + * return The field name for layer. + */ + inline const std::string& fieldNameLayer() const { return m_layerID; } + /** Determine the minimum and maximum polar angle of HCal cell based on the cellID. * @param[in] aCellId ID of a cell. * return Theta. @@ -138,6 +160,11 @@ namespace dd4hep { */ inline void setOffsetPhi(double offset) { m_offsetPhi = offset; } + /** Set the detector layout (0 = Barrel; 1 = Endcap). + * @param[in] detLayout + */ + inline void setDetLayout(int detLayout) { m_detLayout = detLayout; } + /** Set the coordinate offset in z-axis. * @param[in] offset in z (centre of the layer). */ @@ -178,6 +205,10 @@ namespace dd4hep { double m_offsetPhi; /// the field name used for phi std::string m_phiID; + /// the field name used for layer + std::string m_layerID; + /// the detector layout (0 = Barrel; 1 = Endcap) + int m_detLayout; /// the z offset of middle of the layer std::vector m_offsetZ; /// the z width of the layer diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index 9cabe64ff..f17059abb 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -18,6 +18,7 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const std::string& cellEncoding) : registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); registerParameter("grid_size_row", "Number of rows combined in a cell", m_gridSizeRow, std::vector()); registerParameter("dz_row", "dz of row", m_dz_row, 0.); + registerParameter("detLayout", "The detector layout (0 = Barrel; 1 = Endcap)", m_detLayout, -1); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); @@ -25,6 +26,7 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const std::string& cellEncoding) : registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); registerIdentifier("identifier_row", "Cell ID identifier for row", m_rowID, "row"); + registerIdentifier("identifier_layer", "Cell ID identifier for layer", m_layerID, "layer"); } FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const BitFieldCoder* decoder) : Segmentation(decoder) { @@ -37,6 +39,7 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const BitFieldCoder* decoder) : Seg registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); registerParameter("grid_size_row", "Number of rows combined in a cell", m_gridSizeRow, std::vector()); registerParameter("dz_row", "dz of row", m_dz_row, 0.); + registerParameter("detLayout", "The detector layout (0 = Barrel; 1 = Endcap)", m_detLayout, -1); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); @@ -44,12 +47,13 @@ FCCSWHCalPhiRow_k4geo::FCCSWHCalPhiRow_k4geo(const BitFieldCoder* decoder) : Seg registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); registerIdentifier("identifier_row", "Cell ID identifier for row", m_rowID, "row"); + registerIdentifier("identifier_layer", "Cell ID identifier for layer", m_layerID, "layer"); } /// determine the global position based on the cell ID Vector3D FCCSWHCalPhiRow_k4geo::position(const CellID& cID) const { - uint layer = _decoder->get(cID,"layer"); + uint layer = _decoder->get(cID,m_layerID); if(m_radii.empty()) calculateLayerRadii(); if(m_radii.empty() || m_layerEdges.empty()) @@ -62,7 +66,7 @@ Vector3D FCCSWHCalPhiRow_k4geo::position(const CellID& cID) const { double minLayerZ = m_layerEdges[layer].first; // get index of the cell in the layer (index starts from 1!) - int idx = _decoder->get(cID, "row"); + int idx = _decoder->get(cID, m_rowID); // calculate z-coordinate of the cell center double zpos = minLayerZ + (idx-1) * m_dz_row * m_gridSizeRow[layer] + 0.5 * m_dz_row * m_gridSizeRow[layer]; @@ -77,76 +81,33 @@ void FCCSWHCalPhiRow_k4geo::calculateLayerRadii() const { if(m_radii.empty()) { // check if all necessary variables are available - if(m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) + if(m_detLayout==-1 || m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) { dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!", - "One of the variables is missing: offset_z | width_z | offset_r | numLayers | dRlayer"); + "One of the variables is missing: detLayout | offset_z | width_z | offset_r | numLayers | dRlayer"); return; } - // calculate the radius for each layer - if(m_offsetZ.size() == 1) // Barrel - { - dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); - uint N_dR = m_numLayers.size(); - double moduleDepth = 0.; - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) - { - moduleDepth+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[0] + moduleDepth - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - } // Barrel + if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); + else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","EndCap configuration found!"); - if(m_offsetZ.size() > 1) // ThreePartsEndCap + // calculate the radius for each layer + uint N_dR = m_numLayers.size()/m_offsetZ.size(); + std::vector moduleDepth(m_offsetZ.size()); + for(uint i_section = 0; i_section < m_offsetZ.size(); i_section++) { - dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","ThreePartsEndCap configuration found!"); - uint N_dR = m_numLayers.size()/3; - double moduleDepth1 = 0.; - double moduleDepth2 = 0.; - double moduleDepth3 = 0.; - // part1 - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) - { - moduleDepth1+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[0] + moduleDepth1 - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - // part2 for(uint i_dR = 0; i_dR < N_dR; i_dR++) { - for(int i_row = 1; i_row <= m_numLayers[i_dR + N_dR]; i_row++) + for(int i_row = 1; i_row <= m_numLayers[i_dR+i_section*N_dR]; i_row++) { - moduleDepth2+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[1] + moduleDepth2 - m_dRlayer[i_dR]*0.5); + moduleDepth[i_section]+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[i_section] + moduleDepth[i_section] - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[1] - 0.5*m_widthZ[1], m_offsetZ[1] + 0.5*m_widthZ[1]) ); + m_layerEdges.push_back( std::make_pair(m_offsetZ[i_section] - 0.5*m_widthZ[i_section], m_offsetZ[i_section] + 0.5*m_widthZ[i_section]) ); m_layerDepth.push_back(m_dRlayer[i_dR]); } } - // part3 - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR + 2*N_dR]; i_row++) - { - moduleDepth3+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[2] + moduleDepth3 - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[2] - 0.5*m_widthZ[2], m_offsetZ[2] + 0.5*m_widthZ[2]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - } // ThreePartsEndcap + } // print info of calculated radii and edges for(uint i_layer = 0; i_layer < m_radii.size(); i_layer++){ @@ -191,7 +152,7 @@ void FCCSWHCalPhiRow_k4geo::defineCellIndexes(const uint layer) const { } // for the EndCap, do it again but for negative-z part - if(m_offsetZ.size() > 1) + if(m_detLayout == 1) { irow = 0; while( (minLayerZ + (irow+1) * m_dz_row) < (maxLayerZ+0.0001) ) @@ -230,9 +191,9 @@ CellID FCCSWHCalPhiRow_k4geo::cellID(const Vector3D& /* localPosition */, const const VolumeID& vID) const { // get the row number from volumeID (starts from 0!) - int nrow = _decoder->get(vID, "row"); + int nrow = _decoder->get(vID, m_rowID); // get the layer number from volumeID - uint layer = _decoder->get(vID,"layer"); + uint layer = _decoder->get(vID,m_layerID); CellID cID = vID; @@ -240,14 +201,14 @@ CellID FCCSWHCalPhiRow_k4geo::cellID(const Vector3D& /* localPosition */, const int idx = floor(nrow/m_gridSizeRow[layer]) + 1; // if the hit is in the negative-z part of the Endcap then assign negative index - if(m_offsetZ.size() > 1 && globalPosition.z() < 0) idx *= -1; + if(m_detLayout == 1 && globalPosition.z() < 0) idx *= -1; _decoder->set(cID, m_rowID, idx); _decoder->set(cID, m_phiID, positionToBin(dd4hep::DDSegmentation::Util::phiFromXYZ(globalPosition), 2 * M_PI / (double)m_phiBins, m_offsetPhi)); // For endcap, the volume ID comes with "type" field information which would screw up the topo-clustering, // therefore, lets set it to zero, as it is for the cell IDs in the neighbours map. - if(m_offsetZ.size() > 1) _decoder->set(cID, "type", 0); + if(m_detLayout == 1) _decoder->set(cID, "type", 0); return cID; } @@ -266,33 +227,27 @@ std::vector > FCCSWHCalPhiRow_k4geo::getMinMaxLayerId() con if(m_radii.empty()) calculateLayerRadii(); if(m_radii.empty()) return minMaxLayerId; + std::vector minLayerId(m_offsetZ.size(), 0); + std::vector maxLayerId(m_offsetZ.size(), 0); - std::vector minLayerIdEndcap = {0, 0, 0}; - std::vector maxLayerIdEndcap = {-1, 0, 0}; - if(m_offsetZ.size() > 1) - { - uint Nl = m_numLayers.size()/3; + uint Nl = m_numLayers.size()/m_offsetZ.size(); - // count the number of layers in the first part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[0] += m_numLayers[i]; + for(uint i_section = 0; i_section < m_offsetZ.size(); i_section++) + { + if(i_section > 0) + { + minLayerId[i_section] = maxLayerId[i_section-1] + 1; + maxLayerId[i_section] = maxLayerId[i_section-1]; + } - minLayerIdEndcap[1] = maxLayerIdEndcap[0]+1; - maxLayerIdEndcap[1] = maxLayerIdEndcap[0]; - // count the number of layers in the second part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[1] += m_numLayers[i+Nl]; + for(uint i=0; i < Nl; i++) + { + maxLayerId[i_section] += m_numLayers[i+i_section*Nl]; + } - minLayerIdEndcap[2] = maxLayerIdEndcap[1]+1; - maxLayerIdEndcap[2] = maxLayerIdEndcap[1]; - // count the number of layers in the third part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[2] += m_numLayers[i+2*Nl]; + if(i_section==0) maxLayerId[0] -= 1; - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[0],maxLayerIdEndcap[0])); - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[1],maxLayerIdEndcap[1])); - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[2],maxLayerIdEndcap[2])); - } - else // for Barrel - { - minMaxLayerId.push_back(std::make_pair(0,m_radii.size()-1)); + minMaxLayerId.push_back(std::make_pair(minLayerId[i_section], maxLayerId[i_section])); } return minMaxLayerId; @@ -306,14 +261,11 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const if(m_radii.empty()) calculateLayerRadii(); if(m_cellIndexes.empty()) return cellNeighbours; - bool EndcapPart1 = false; - bool EndcapPart2 = false; - bool EndcapPart3 = false; - + uint EndcapPart = 0; int minLayerId = -1; int maxLayerId = -1; - int currentLayerId = _decoder->get(cID,"layer"); + int currentLayerId = _decoder->get(cID,m_layerID); int currentCellId = _decoder->get(cID,m_rowID); int minCellId = m_cellIndexes[currentLayerId].front(); @@ -322,54 +274,29 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const //-------------------------------- // Determine min and max layer Id //-------------------------------- - // if this is the segmentation of three parts Endcap - /* - * hardcoded numbers would be the following: - * std::vector minLayerIdEndcap = {0, 6, 15}; - * std::vector maxLayerIdEndcap = {5, 14, 36}; - * but lets try to avoid hardcoding: - */ - std::vector minLayerIdEndcap = {0, 0, 0}; - std::vector maxLayerIdEndcap = {0, 0, 0}; - if(m_offsetZ.size() > 1) + std::vector minLayerIdEndcap(m_offsetZ.size(),0); + std::vector maxLayerIdEndcap(m_offsetZ.size(),0); + if(m_detLayout == 1) // Endcap { std::vector > minMaxLayerId(getMinMaxLayerId()); if(minMaxLayerId.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Can not get ThreePartsEndcap min and max layer indexes! --> returning empty neighbours"); + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Can not get Endcap min and max layer indexes! --> returning empty neighbours"); return cellNeighbours; } - // part1 min and max layer index - minLayerIdEndcap[0] = minMaxLayerId[0].first; - maxLayerIdEndcap[0] = minMaxLayerId[0].second; - // part2 min and max layer index - minLayerIdEndcap[1] = minMaxLayerId[1].first; - maxLayerIdEndcap[1] = minMaxLayerId[1].second; - // part3 min and max layer index - minLayerIdEndcap[2] = minMaxLayerId[2].first; - maxLayerIdEndcap[2] = minMaxLayerId[2].second; - - // Part 1 - if(currentLayerId >= minLayerIdEndcap[0] && currentLayerId <= maxLayerIdEndcap[0]) + // determine min and max layer Ids and which section/part it is + for(uint i_section = 0; i_section < minMaxLayerId.size(); i_section++) { - minLayerId = minLayerIdEndcap[0]; - maxLayerId = maxLayerIdEndcap[0]; - EndcapPart1 = true; - } - // Part 2 - if(currentLayerId >= minLayerIdEndcap[1] && currentLayerId <= maxLayerIdEndcap[1]) - { - minLayerId = minLayerIdEndcap[1]; - maxLayerId = maxLayerIdEndcap[1]; - EndcapPart2 = true; - } - // Part 3 - if(currentLayerId >= minLayerIdEndcap[2] && currentLayerId <= maxLayerIdEndcap[2]) - { - minLayerId = minLayerIdEndcap[2]; - maxLayerId = maxLayerIdEndcap[2]; - EndcapPart3 = true; + minLayerIdEndcap[i_section] = minMaxLayerId[i_section].first; + maxLayerIdEndcap[i_section] = minMaxLayerId[i_section].second; + + if(currentLayerId >= minLayerIdEndcap[i_section] && currentLayerId <= maxLayerIdEndcap[i_section]) + { + minLayerId = minLayerIdEndcap[i_section]; + maxLayerId = maxLayerIdEndcap[i_section]; + EndcapPart = i_section; + } } // correct the min and max CellId for endcap @@ -403,7 +330,7 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const { CellID nID = cID ; int prevLayerId = currentLayerId - 1; - _decoder->set(nID,"layer",prevLayerId); + _decoder->set(nID,m_layerID,prevLayerId); // if the granularity is the same for the previous layer then take the cells with currentCellId, currentCellId - 1, and currentCellId + 1 if(m_gridSizeRow[prevLayerId] == m_gridSizeRow[currentLayerId]) @@ -450,7 +377,7 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const { CellID nID = cID ; int nextLayerId = currentLayerId + 1; - _decoder->set(nID,"layer",nextLayerId); + _decoder->set(nID,m_layerID,nextLayerId); // if the granularity is the same for the next layer then take the cells with currentCellId, currentCellId - 1, and currentCellId + 1 if(m_gridSizeRow[nextLayerId] == m_gridSizeRow[currentLayerId]) @@ -507,8 +434,8 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const cellNeighbours.push_back(nID); // add the next cell from current layer of the same phi module } - // if this is the Endcap then look for neighbours in different parts as well - if(m_offsetZ.size() > 1) + // if this is the Endcap (and consists of more than 1 part/section) then look for neighbours in different parts as well + if(m_detLayout == 1 && m_offsetZ.size() > 1) { double currentLayerRmin = m_radii[currentLayerId] - 0.5*m_layerDepth[currentLayerId]; double currentLayerRmax = m_radii[currentLayerId] + 0.5*m_layerDepth[currentLayerId]; @@ -520,8 +447,8 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const maxCellId = m_cellIndexes[currentLayerId].back(); // this should be -N } - // if it is the last cell in the part1 - if(EndcapPart1 && currentCellId == maxCellId ) + // if it is the last cell in the first part + if(EndcapPart == 0 && currentCellId == maxCellId ) { // find the layers in the part2 that share a border with the current layer for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) @@ -536,67 +463,72 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const ) { CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_layerID,part2layerId); _decoder->set(nID,m_rowID,minCellId); cellNeighbours.push_back(nID); // add the first cell from part2 layer } } } - // if it is the first cell in the part2 - if(EndcapPart2 && currentCellId == minCellId) + // if the Endcap consists of more than 2 parts: + for(uint i_section = 1; i_section < (m_offsetZ.size()-1); i_section++) { - // find the layers in part1 that share a border with the current layer - for(int part1layerId = minLayerIdEndcap[0]; part1layerId <= maxLayerIdEndcap[0]; part1layerId++) - { - double Rmin = m_radii[part1layerId] - 0.5*m_layerDepth[part1layerId]; - double Rmax = m_radii[part1layerId] + 0.5*m_layerDepth[part1layerId]; + if(i_section != EndcapPart) continue; - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) - ) + // if it is the first cell then look for neighbours in previous part + if(currentCellId == minCellId) + { + // find the layers in previous part that share a border with the current layer + for(int prevPartLayerId = minLayerIdEndcap[i_section-1]; prevPartLayerId <= maxLayerIdEndcap[i_section-1]; prevPartLayerId++) { - CellID nID = cID ; - _decoder->set(nID,"layer",part1layerId); - _decoder->set(nID,m_rowID,maxCellId); - cellNeighbours.push_back(nID); // add the last cell from the part1 layer + double Rmin = m_radii[prevPartLayerId] - 0.5*m_layerDepth[prevPartLayerId]; + double Rmax = m_radii[prevPartLayerId] + 0.5*m_layerDepth[prevPartLayerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,prevPartLayerId); + _decoder->set(nID,m_rowID,maxCellId); + cellNeighbours.push_back(nID); // add the last cell from the previous part layer + } } } - } - - // if it is the last cell in the part2 - if(EndcapPart2 && currentCellId == maxCellId) - { - // find the layers in the part3 that share a border with the current layer - for(int part3layerId = minLayerIdEndcap[2]; part3layerId <= maxLayerIdEndcap[2]; part3layerId++) + // if it is the last cell then look for neighbours in the next part + if(currentCellId == maxCellId) { - double Rmin = m_radii[part3layerId] - 0.5*m_layerDepth[part3layerId]; - double Rmax = m_radii[part3layerId] + 0.5*m_layerDepth[part3layerId]; - - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) - ) + // find the layers in the next that share a border with the current layer + for(int nextPartLayerId = minLayerIdEndcap[i_section+1]; nextPartLayerId <= maxLayerIdEndcap[i_section+1]; nextPartLayerId++) { - CellID nID = cID ; - _decoder->set(nID,"layer",part3layerId); - _decoder->set(nID,m_rowID,minCellId); - cellNeighbours.push_back(nID); // add the first cell from the part3 layer + double Rmin = m_radii[nextPartLayerId] - 0.5*m_layerDepth[nextPartLayerId]; + double Rmax = m_radii[nextPartLayerId] + 0.5*m_layerDepth[nextPartLayerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,nextPartLayerId); + _decoder->set(nID,m_rowID,minCellId); + cellNeighbours.push_back(nID); // add the first cell from the next part layer + } } } } - // if it is the first cell in the part3 - if(EndcapPart3 && currentCellId == minCellId) + // if it is the first cell in the last part of the Endcap + if(EndcapPart == (m_offsetZ.size() - 1) && currentCellId == minCellId) { - // find the layers in the part2 that share a border with the current layer - for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + // find the layers in the previous part that share a border with the current layer + for(int prevPartLayerId = minLayerIdEndcap[m_offsetZ.size()-2]; prevPartLayerId <= maxLayerIdEndcap[m_offsetZ.size()-2]; prevPartLayerId++) { - double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; - double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + double Rmin = m_radii[prevPartLayerId] - 0.5*m_layerDepth[prevPartLayerId]; + double Rmax = m_radii[prevPartLayerId] + 0.5*m_layerDepth[prevPartLayerId]; if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) @@ -605,7 +537,7 @@ std::vector FCCSWHCalPhiRow_k4geo::neighbours(const CellID& cID) const ) { CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); + _decoder->set(nID,m_layerID,prevPartLayerId); _decoder->set(nID,m_rowID,maxCellId); cellNeighbours.push_back(nID); // add the last cell from the part2 layer } @@ -645,7 +577,7 @@ std::array FCCSWHCalPhiRow_k4geo::cellTheta(const CellID& cID) const // get the cell index int idx = _decoder->get(cID, m_rowID); // get the layer index - uint layer = _decoder->get(cID,"layer"); + uint layer = _decoder->get(cID,m_layerID); if(m_radii.empty()) calculateLayerRadii(); if(m_cellEdges.empty()) return cTheta; diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index 04c227ab1..a6248a3d3 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -13,12 +13,14 @@ FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const std::string& cellEncoding // register all necessary parameters (additional to those registered in GridTheta_k4geo) registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); + registerParameter("detLayout", "The detector layout (0 = Barrel; 1 = Endcap)", m_detLayout, -1); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); registerParameter("numLayers", "Number of layers", m_numLayers, std::vector()); registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); + registerIdentifier("identifier_layer", "Cell ID identifier for layer", m_layerID, "layer"); } FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const BitFieldCoder* decoder) : GridTheta_k4geo(decoder) { @@ -29,18 +31,20 @@ FCCSWHCalPhiTheta_k4geo::FCCSWHCalPhiTheta_k4geo(const BitFieldCoder* decoder) : // register all necessary parameters (additional to those registered in GridTheta_k4geo) registerParameter("phi_bins", "Number of bins phi", m_phiBins, 1); registerParameter("offset_phi", "Angular offset in phi", m_offsetPhi, 0., SegmentationParameter::AngleUnit, true); + registerParameter("detLayout", "The detector layout (0 = Barrel; 1 = Endcap)", m_detLayout, -1); registerParameter("offset_z", "Offset in z-axis of the layer center", m_offsetZ, std::vector()); registerParameter("width_z", "Width in z of the layer", m_widthZ, std::vector()); registerParameter("offset_r", "Offset in radius of the layer (Rmin)", m_offsetR, std::vector()); registerParameter("numLayers", "Number of layers", m_numLayers, std::vector()); registerParameter("dRlayer", "dR of the layer", m_dRlayer, std::vector()); registerIdentifier("identifier_phi", "Cell ID identifier for phi", m_phiID, "phi"); + registerIdentifier("identifier_layer", "Cell ID identifier for layer", m_layerID, "layer"); } /** /// determine the global position based on the cell ID Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { - uint layer = _decoder->get(cID,"layer"); + uint layer = _decoder->get(cID,m_layerID); double radius = 1.0; if(m_radii.empty()) defineCellsInRZplan(); @@ -53,8 +57,8 @@ Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { /// determine the global position based on the cell ID /// returns the geometric center of the cell Vector3D FCCSWHCalPhiTheta_k4geo::position(const CellID& cID) const { - uint layer = _decoder->get(cID,"layer"); - int thetaID = _decoder->get(cID,"theta"); + uint layer = _decoder->get(cID,m_layerID); + int thetaID = _decoder->get(cID,m_thetaID); double zpos = 0.; double radius = 1.0; @@ -73,76 +77,33 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { if(m_radii.empty()) { // check if all necessary variables are available - if(m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) + if(m_detLayout==-1 || m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!", - "One of the variables is missing: offset_z | width_z | offset_r | numLayers | dRlayer"); + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!", + "One of the variables is missing: detLayout | offset_z | width_z | offset_r | numLayers | dRlayer"); return; } - // calculate the radius for each layer - if(m_offsetZ.size() == 1) // Barrel - { - dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","Barrel configuration found!"); - uint N_dR = m_numLayers.size(); - double moduleDepth = 0.; - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) - { - moduleDepth+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[0] + moduleDepth - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - } // Barrel + if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); + else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","EndCap configuration found!"); - if(m_offsetZ.size() > 1) // ThreePartsEndCap + // calculate the radius for each layer + uint N_dR = m_numLayers.size()/m_offsetZ.size(); + std::vector moduleDepth(m_offsetZ.size()); + for(uint i_section = 0; i_section < m_offsetZ.size(); i_section++) { - dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","ThreePartsEndCap configuration found!"); - uint N_dR = m_numLayers.size()/3; - double moduleDepth1 = 0.; - double moduleDepth2 = 0.; - double moduleDepth3 = 0.; - // part1 for(uint i_dR = 0; i_dR < N_dR; i_dR++) { - for(int i_row = 1; i_row <= m_numLayers[i_dR]; i_row++) + for(int i_row = 1; i_row <= m_numLayers[i_dR+i_section*N_dR]; i_row++) { - moduleDepth1+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[0] + moduleDepth1 - m_dRlayer[i_dR]*0.5); + moduleDepth[i_section]+=m_dRlayer[i_dR]; + m_radii.push_back(m_offsetR[i_section] + moduleDepth[i_section] - m_dRlayer[i_dR]*0.5); // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[0] - 0.5*m_widthZ[0], m_offsetZ[0] + 0.5*m_widthZ[0]) ); + m_layerEdges.push_back( std::make_pair(m_offsetZ[i_section] - 0.5*m_widthZ[i_section], m_offsetZ[i_section] + 0.5*m_widthZ[i_section]) ); m_layerDepth.push_back(m_dRlayer[i_dR]); } } - // part2 - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR + N_dR]; i_row++) - { - moduleDepth2+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[1] + moduleDepth2 - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[1] - 0.5*m_widthZ[1], m_offsetZ[1] + 0.5*m_widthZ[1]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - // part3 - for(uint i_dR = 0; i_dR < N_dR; i_dR++) - { - for(int i_row = 1; i_row <= m_numLayers[i_dR + 2*N_dR]; i_row++) - { - moduleDepth3+=m_dRlayer[i_dR]; - m_radii.push_back(m_offsetR[2] + moduleDepth3 - m_dRlayer[i_dR]*0.5); - // layer lower and upper edges in z-axis - m_layerEdges.push_back( std::make_pair(m_offsetZ[2] - 0.5*m_widthZ[2], m_offsetZ[2] + 0.5*m_widthZ[2]) ); - m_layerDepth.push_back(m_dRlayer[i_dR]); - } - } - } // ThreePartsEndcap + } // print info of calculated radii and edges for(uint i_layer = 0; i_layer < m_radii.size(); i_layer++){ @@ -196,7 +157,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellEdges(const uint layer) const { m_cellEdges[layer][prevBin].first = m_layerEdges[layer].first; // for the EndCap, do it again but for negative z part - if(m_offsetZ.size() > 1) + if(m_detLayout == 1) { while(m_radii[layer]*std::cos(m_offsetTheta+ibin*m_gridSizeTheta)/std::sin(m_offsetTheta+ibin*m_gridSizeTheta) > (-m_layerEdges[layer].second)) { @@ -248,11 +209,11 @@ CellID FCCSWHCalPhiTheta_k4geo::cellID(const Vector3D& /* localPosition */, cons // For endcap, the volume ID comes with "type" field information which would screw up the topo-clustering as the "row" field, // therefore, lets set it to zero, as it is for the cell IDs in the neighbours map. - if(m_offsetZ.size() > 1) _decoder->set(cID, "type", 0); + if(m_detLayout == 1) _decoder->set(cID, "type", 0); double lTheta = thetaFromXYZ(globalPosition); double lPhi = phiFromXYZ(globalPosition); - uint layer = _decoder->get(vID,"layer"); + uint layer = _decoder->get(vID,m_layerID); // define cell boundaries in R-z plan if(m_radii.empty()) defineCellsInRZplan(); @@ -288,45 +249,32 @@ double FCCSWHCalPhiTheta_k4geo::phi(const CellID& cID) const { /// Get the min and max layer indexes for each part of the HCal std::vector > FCCSWHCalPhiTheta_k4geo::getMinMaxLayerId() const { - /* - * hardcoded numbers would be the following: - * std::vector minLayerIdEndcap = {0, 6, 15}; - * std::vector maxLayerIdEndcap = {5, 14, 36}; - * but lets try to avoid hardcoding: - */ - std::vector > minMaxLayerId; if(m_radii.empty()) defineCellsInRZplan(); if(m_radii.empty()) return minMaxLayerId; + std::vector minLayerId(m_offsetZ.size(), 0); + std::vector maxLayerId(m_offsetZ.size(), 0); - std::vector minLayerIdEndcap = {0, 0, 0}; - std::vector maxLayerIdEndcap = {-1, 0, 0}; - if(m_offsetZ.size() > 1) - { - uint Nl = m_numLayers.size()/3; + uint Nl = m_numLayers.size()/m_offsetZ.size(); - // count the number of layers in the first part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[0] += m_numLayers[i]; + for(uint i_section = 0; i_section < m_offsetZ.size(); i_section++) + { + if(i_section > 0) + { + minLayerId[i_section] = maxLayerId[i_section-1] + 1; + maxLayerId[i_section] = maxLayerId[i_section-1]; + } - minLayerIdEndcap[1] = maxLayerIdEndcap[0]+1; - maxLayerIdEndcap[1] = maxLayerIdEndcap[0]; - // count the number of layers in the second part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[1] += m_numLayers[i+Nl]; + for(uint i=0; i < Nl; i++) + { + maxLayerId[i_section] += m_numLayers[i+i_section*Nl]; + } - minLayerIdEndcap[2] = maxLayerIdEndcap[1]+1; - maxLayerIdEndcap[2] = maxLayerIdEndcap[1]; - // count the number of layers in the third part of the Endcap - for(uint i=0; i < Nl; i++) maxLayerIdEndcap[2] += m_numLayers[i+2*Nl]; + if(i_section == 0) maxLayerId[0] -= 1; - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[0],maxLayerIdEndcap[0])); - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[1],maxLayerIdEndcap[1])); - minMaxLayerId.push_back(std::make_pair(minLayerIdEndcap[2],maxLayerIdEndcap[2])); - } - else // for Barrel - { - minMaxLayerId.push_back(std::make_pair(0,m_radii.size()-1)); + minMaxLayerId.push_back(std::make_pair(minLayerId[i_section], maxLayerId[i_section])); } return minMaxLayerId; @@ -340,14 +288,11 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo if(m_radii.empty()) defineCellsInRZplan(); if(m_thetaBins.empty()) return cellNeighbours; - bool EndcapPart1 = false; - bool EndcapPart2 = false; - bool EndcapPart3 = false; - + uint EndcapPart = 0; int minLayerId = -1; int maxLayerId = -1; - int currentLayerId = _decoder->get(cID,"layer"); + int currentLayerId = _decoder->get(cID,m_layerID); int currentCellThetaBin = _decoder->get(cID,m_thetaID); int minCellThetaBin = m_thetaBins[currentLayerId].front(); @@ -356,48 +301,29 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo //-------------------------------- // Determine min and max layer Id //-------------------------------- - // if this is the segmentation of three parts Endcap - std::vector minLayerIdEndcap = {0, 0, 0}; - std::vector maxLayerIdEndcap = {0, 0, 0}; - if(m_offsetZ.size() > 1) + std::vector minLayerIdEndcap(m_offsetZ.size(),0); + std::vector maxLayerIdEndcap(m_offsetZ.size(),0); + if(m_detLayout == 1) { std::vector > minMaxLayerId(getMinMaxLayerId()); if(minMaxLayerId.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Can not get ThreePartsEndcap min and max layer indexes! --> returning empty neighbours"); + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Can not get Endcap min and max layer indexes! --> returning empty neighbours"); return cellNeighbours; } - // part1 min and max layer index - minLayerIdEndcap[0] = minMaxLayerId[0].first; - maxLayerIdEndcap[0] = minMaxLayerId[0].second; - // part2 min and max layer index - minLayerIdEndcap[1] = minMaxLayerId[1].first; - maxLayerIdEndcap[1] = minMaxLayerId[1].second; - // part3 min and max layer index - minLayerIdEndcap[2] = minMaxLayerId[2].first; - maxLayerIdEndcap[2] = minMaxLayerId[2].second; - - // Part 1 - if(currentLayerId >= minLayerIdEndcap[0] && currentLayerId <= maxLayerIdEndcap[0]) + // determine min and max layer Ids and which section/part it is + for(uint i_section = 0; i_section < minMaxLayerId.size(); i_section++) { - minLayerId = minLayerIdEndcap[0]; - maxLayerId = maxLayerIdEndcap[0]; - EndcapPart1 = true; - } - // Part 2 - if(currentLayerId >= minLayerIdEndcap[1] && currentLayerId <= maxLayerIdEndcap[1]) - { - minLayerId = minLayerIdEndcap[1]; - maxLayerId = maxLayerIdEndcap[1]; - EndcapPart2 = true; - } - // Part 3 - if(currentLayerId >= minLayerIdEndcap[2] && currentLayerId <= maxLayerIdEndcap[2]) - { - minLayerId = minLayerIdEndcap[2]; - maxLayerId = maxLayerIdEndcap[2]; - EndcapPart3 = true; + minLayerIdEndcap[i_section] = minMaxLayerId[i_section].first; + maxLayerIdEndcap[i_section] = minMaxLayerId[i_section].second; + + if(currentLayerId >= minLayerIdEndcap[i_section] && currentLayerId <= maxLayerIdEndcap[i_section]) + { + minLayerId = minLayerIdEndcap[i_section]; + maxLayerId = maxLayerIdEndcap[i_section]; + EndcapPart = i_section; + } } // correct the min and max theta bin for endcap @@ -446,7 +372,7 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo //---------------------------------------------- // deal with the Barrel - if(m_offsetZ.size() == 1) + if(m_detLayout == 0) { double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; @@ -456,7 +382,7 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo { CellID nID = cID ; int prevLayerId = currentLayerId - 1; - _decoder->set(nID,"layer",prevLayerId); + _decoder->set(nID,m_layerID,prevLayerId); _decoder->set(nID,m_thetaID,currentCellThetaBin); cellNeighbours.push_back(nID); // add the cell with the same theta bin from the previous layer of the same phi module @@ -502,7 +428,7 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo { CellID nID = cID ; int nextLayerId = currentLayerId + 1; - _decoder->set(nID,"layer",nextLayerId); + _decoder->set(nID,m_layerID,nextLayerId); _decoder->set(nID,m_thetaID,currentCellThetaBin); cellNeighbours.push_back(nID); // add the cell with the same theta bin from the next layer of the same phi module @@ -548,8 +474,8 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo } } - // if this is the Endcap then look for neighbours in different parts as well - if(m_offsetZ.size() > 1) + // Endcap + if(m_detLayout == 1) { double currentCellZmin = m_cellEdges[currentLayerId][currentCellThetaBin].first; double currentCellZmax = m_cellEdges[currentLayerId][currentCellThetaBin].second; @@ -559,7 +485,7 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo { CellID nID = cID ; int prevLayerId = currentLayerId - 1; - _decoder->set(nID,"layer",prevLayerId); + _decoder->set(nID,m_layerID,prevLayerId); // find the ones that share at least part of a border with the current cell for( auto bin : m_thetaBins[prevLayerId] ) { @@ -607,7 +533,7 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo { CellID nID = cID ; int nextLayerId = currentLayerId + 1; - _decoder->set(nID,"layer",nextLayerId); + _decoder->set(nID,m_layerID,nextLayerId); // find the ones that share at least part of a border with the current cell for( auto bin : m_thetaBins[nextLayerId] ) { @@ -650,135 +576,143 @@ std::vector FCCSWHCalPhiTheta_k4geo::neighbours(const CellID& cID, boo } } - - // - double currentLayerRmin = m_radii[currentLayerId] - 0.5*m_layerDepth[currentLayerId]; - double currentLayerRmax = m_radii[currentLayerId] + 0.5*m_layerDepth[currentLayerId]; - - - // if the cell is in negative-z part, then swap min and max theta bins - if(theta(cID) > M_PI/2.) + // if the Endcap consists of more than 1 part/section then look for neighbours in different parts as well + if(m_offsetZ.size() > 1) { - minCellThetaBin = m_thetaBins[currentLayerId].back(); - maxCellThetaBin = m_thetaBins[currentLayerId][m_thetaBins[currentLayerId].size()/2]; - } + // + double currentLayerRmin = m_radii[currentLayerId] - 0.5*m_layerDepth[currentLayerId]; + double currentLayerRmax = m_radii[currentLayerId] + 0.5*m_layerDepth[currentLayerId]; - // if it is the last cell in the part1 - if(EndcapPart1 && currentCellThetaBin == minCellThetaBin ) - { - // find the layers in the part2 that share a border with the current layer - for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + // if the cell is in negative-z part, then swap min and max theta bins + if(theta(cID) > M_PI/2.) { - double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; - double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; - - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) - ) - { - CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); - _decoder->set(nID,m_thetaID,maxCellThetaBin); - cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer - } - if(aDiagonal && Rmax == currentLayerRmin) - { - CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); - _decoder->set(nID,m_thetaID,maxCellThetaBin); - cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer - } + minCellThetaBin = m_thetaBins[currentLayerId].back(); + maxCellThetaBin = m_thetaBins[currentLayerId][m_thetaBins[currentLayerId].size()/2]; } - } - // if it is the last theta bin cell in the part2 - if(EndcapPart2 && currentCellThetaBin == maxCellThetaBin) - { - // find the layers in part1 that share a border with the current layer - for(int part1layerId = minLayerIdEndcap[0]; part1layerId <= maxLayerIdEndcap[0]; part1layerId++) + // if it is the last cell in the part1 + if(EndcapPart == 0 && currentCellThetaBin == minCellThetaBin ) { - double Rmin = m_radii[part1layerId] - 0.5*m_layerDepth[part1layerId]; - double Rmax = m_radii[part1layerId] + 0.5*m_layerDepth[part1layerId]; - - if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) - ) - { - CellID nID = cID ; - _decoder->set(nID,"layer",part1layerId); - _decoder->set(nID,m_thetaID,minCellThetaBin); - cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer - } - if(aDiagonal && Rmin == currentLayerRmax) + // find the layers in the part2 that share a border with the current layer + for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) { - CellID nID = cID ; - _decoder->set(nID,"layer",part1layerId); - _decoder->set(nID,m_thetaID,minCellThetaBin); - cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer + double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; + double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,part2layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer + } + if(aDiagonal && Rmax == currentLayerRmin) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,part2layerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the last theta bin cell from part2 layer + } } } - } - // if it is the first theta bin cell in the part2 - if(EndcapPart2 && currentCellThetaBin == minCellThetaBin) - { - // find the layers in the part3 that share a border with the current layer - for(int part3layerId = minLayerIdEndcap[2]; part3layerId <= maxLayerIdEndcap[2]; part3layerId++) + // if the Endcap consists of more than 2 parts: + for(uint i_section = 1; i_section < (m_offsetZ.size()-1); i_section++) { - double Rmin = m_radii[part3layerId] - 0.5*m_layerDepth[part3layerId]; - double Rmax = m_radii[part3layerId] + 0.5*m_layerDepth[part3layerId]; - - if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) - || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) - || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) - ) + if(i_section != EndcapPart) continue; + + // if it is the last theta bin cell then look for neighbours in previous part + if(currentCellThetaBin == maxCellThetaBin) { - CellID nID = cID ; - _decoder->set(nID,"layer",part3layerId); - _decoder->set(nID,m_thetaID,maxCellThetaBin); - cellNeighbours.push_back(nID); // add the first cell from the part3 layer + // find the layers in the previous part that share a border with the current layer + for(int prevPartLayerId = minLayerIdEndcap[i_section-1]; prevPartLayerId <= maxLayerIdEndcap[i_section-1]; prevPartLayerId++) + { + double Rmin = m_radii[prevPartLayerId] - 0.5*m_layerDepth[prevPartLayerId]; + double Rmax = m_radii[prevPartLayerId] + 0.5*m_layerDepth[prevPartLayerId]; + + if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,prevPartLayerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer + } + if(aDiagonal && Rmin == currentLayerRmax) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,prevPartLayerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part1 layer + } + } } - if(aDiagonal && Rmax == currentLayerRmin) + + // if it is the first theta bin cell then look for neighbours in the next part + if(currentCellThetaBin == minCellThetaBin) { - CellID nID = cID ; - _decoder->set(nID,"layer",part3layerId); - _decoder->set(nID,m_thetaID,maxCellThetaBin); - cellNeighbours.push_back(nID); // add the first cell from the part3 layer + // find the layers in the next part that share a border with the current layer + for(int nextPartLayerId = minLayerIdEndcap[i_section+1]; nextPartLayerId <= maxLayerIdEndcap[i_section+1]; nextPartLayerId++) + { + double Rmin = m_radii[nextPartLayerId] - 0.5*m_layerDepth[nextPartLayerId]; + double Rmax = m_radii[nextPartLayerId] + 0.5*m_layerDepth[nextPartLayerId]; + + if( (Rmin >= currentLayerRmin && Rmin <= currentLayerRmax) + || (Rmax > currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin < Rmax) + || (currentLayerRmax >= Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,nextPartLayerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the first cell from the part3 layer + } + if(aDiagonal && Rmax == currentLayerRmin) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,nextPartLayerId); + _decoder->set(nID,m_thetaID,maxCellThetaBin); + cellNeighbours.push_back(nID); // add the first cell from the part3 layer + } + } } } - } - // if it is the last theta bin cell in the part3 - if(EndcapPart3 && currentCellThetaBin == maxCellThetaBin) - { - // find the layers in the part2 that share a border with the current layer - for(int part2layerId = minLayerIdEndcap[1]; part2layerId <= maxLayerIdEndcap[1]; part2layerId++) + // if it is the last theta bin cell in the last part of the Endcap + if(EndcapPart == (m_offsetZ.size() - 1) && currentCellThetaBin == maxCellThetaBin) { - double Rmin = m_radii[part2layerId] - 0.5*m_layerDepth[part2layerId]; - double Rmax = m_radii[part2layerId] + 0.5*m_layerDepth[part2layerId]; - - if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) - || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) - || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) - || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) - ) + // find the layers in the previous part that share a border with the current layer + for(int prevPartLayerId = minLayerIdEndcap[m_offsetZ.size()-2]; prevPartLayerId <= maxLayerIdEndcap[m_offsetZ.size()-2]; prevPartLayerId++) { - CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); - _decoder->set(nID,m_thetaID,minCellThetaBin); - cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer - } - if(aDiagonal && Rmin == currentLayerRmax) - { - CellID nID = cID ; - _decoder->set(nID,"layer",part2layerId); - _decoder->set(nID,m_thetaID,minCellThetaBin); - cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer + double Rmin = m_radii[prevPartLayerId] - 0.5*m_layerDepth[prevPartLayerId]; + double Rmax = m_radii[prevPartLayerId] + 0.5*m_layerDepth[prevPartLayerId]; + + if( (Rmin >= currentLayerRmin && Rmin < currentLayerRmax) + || (Rmax >= currentLayerRmin && Rmax <= currentLayerRmax) + || (currentLayerRmin >= Rmin && currentLayerRmin <= Rmax) + || (currentLayerRmax > Rmin && currentLayerRmax <= Rmax) + ) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,prevPartLayerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer + } + if(aDiagonal && Rmin == currentLayerRmax) + { + CellID nID = cID ; + _decoder->set(nID,m_layerID,prevPartLayerId); + _decoder->set(nID,m_thetaID,minCellThetaBin); + cellNeighbours.push_back(nID); // add the first theta bin cell from the part2 layer + } } } } @@ -816,7 +750,7 @@ std::array FCCSWHCalPhiTheta_k4geo::cellTheta(const CellID& cID) cons // get the cell index int idx = _decoder->get(cID, m_thetaID); // get the layer index - uint layer = _decoder->get(cID,"layer"); + uint layer = _decoder->get(cID,m_layerID); if(m_radii.empty()) defineCellsInRZplan(); if(m_cellEdges.empty()) return cTheta; From 5600027f0b88ee93c3785c79952bf3d810f9a78e Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Sat, 30 Nov 2024 21:27:43 +0100 Subject: [PATCH 095/133] Add the method thetaMax() for HCal phi-row segmentation needed for SW clustering --- .../FCCSWHCalPhiRow_k4geo.h | 7 ++++- .../src/FCCSWHCalPhiRow_k4geo.cpp | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h index acda782e8..1df1353d9 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWHCalPhiRow_k4geo.h @@ -111,7 +111,7 @@ namespace dd4hep { */ std::array cellTheta(const CellID& cID) const; - /** Get the vector of cell indexes in a give layer. + /** Get the vector of cell indexes in a given layer. */ inline std::vector cellIndexes(const uint layer) const { if(m_radii.empty()) calculateLayerRadii(); @@ -119,6 +119,11 @@ namespace dd4hep { else return std::vector(); } + /** Get the thetaMax needed for SW clustering + * return max theta value of the detector + */ + double thetaMax() const; + /** Get the min and max layer indexes of each HCal part. * For Endcap, returns the three elements vector, while for Barrel - single element vector. */ diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index f17059abb..09d644982 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -602,5 +602,32 @@ std::array FCCSWHCalPhiRow_k4geo::cellTheta(const CellID& cID) const return cTheta; } +/// determine maximum theta value of the detector. This is used by SW clustering +double FCCSWHCalPhiRow_k4geo::thetaMax() const { + std::vector > minMaxLayerId(getMinMaxLayerId()); + if(minMaxLayerId.empty()) return 0.; + + // get the first layerId in the Barrel or in the last part of the Endcap + uint layer = minMaxLayerId[minMaxLayerId.size()-1].first; + + if(m_radii.empty()) calculateLayerRadii(); + if(m_cellEdges.empty()) return 0; + + // get the last cell index (which is in the positive-z side) + int idx = abs(m_cellIndexes[layer].back()); + + // get the z-coordinate of the right-hand edge of the last cell + double zhigh = m_cellEdges[layer][idx].second; + + // get the inner radius of the first layer + double Rmin = m_radii[layer] - 0.5*m_layerDepth[layer]; + + // calculate the minimum theta of the last cell in the first layer -> this is the minimum theta of the detector (Barrel or Endcap) + double thetaMin = std::atan2(Rmin,zhigh); // theta min + + return (M_PI - thetaMin); // theta max +} + + } } From d5b35aeea54b9046d20b4cec17ef4fb452b081f2 Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Mon, 2 Dec 2024 13:04:19 +0100 Subject: [PATCH 096/133] Adding some description in the HCal xml files --- .../ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml | 44 ++++++++++++++++-- .../HCalEndcaps_ThreeParts_TileCal_v03.xml | 46 +++++++++++++++++-- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 2 +- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml index 1adb2a8fd..8b9e9a07e 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalBarrel_TileCal_v03.xml @@ -27,6 +27,10 @@ + + + + @@ -45,13 +49,28 @@ + system:4,layer:5,row:9,theta:9,phi:10 + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml index 28a31ba69..32f2978bf 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/HCalEndcaps_ThreeParts_TileCal_v03.xml @@ -25,6 +25,10 @@ + + + + @@ -44,13 +48,29 @@ + system:4,type:3,layer:6,row:11,theta:11,phi:10 + Date: Mon, 2 Dec 2024 15:41:50 +0100 Subject: [PATCH 097/133] Added some sanity checks of the HCal xml --- .../src/FCCSWHCalPhiRow_k4geo.cpp | 42 ++++++++++++++++++- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 34 ++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp index 09d644982..3bae5de42 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiRow_k4geo.cpp @@ -83,11 +83,51 @@ void FCCSWHCalPhiRow_k4geo::calculateLayerRadii() const { // check if all necessary variables are available if(m_detLayout==-1 || m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", "One of the variables is missing: detLayout | offset_z | width_z | offset_r | numLayers | dRlayer"); return; } + // some sanity checks of the xml + if( m_offsetZ.size() != m_offsetR.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in offsetZ and offsetR must be the same!"); + return; + } + if( m_widthZ.size() != m_offsetR.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in widthZ and offsetR must be the same!"); + return; + } + if( m_detLayout == 0 && m_offsetZ.size() != 1) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in offsetZ/offsetR/widthZ must be 1 for the Barrel!"); + return; + } + if( m_numLayers.size() % m_offsetZ.size() != 0 ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in numLayers must be multiple of offsetZ.size()!"); + return; + } + if( m_dRlayer.size() != m_numLayers.size()/m_offsetZ.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in dRlayer must be equal to numLayers.size()/offsetZ.size()!"); + return; + } + uint nlayers = 0; + for(auto n : m_numLayers) nlayers+=n; + if( m_gridSizeRow.size() != nlayers ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in gridSizeRow must be equal to sum of contents of numLayers!"); + return; + } + if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","EndCap configuration found!"); diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index 07770e633..08346e4f6 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -79,11 +79,43 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { // check if all necessary variables are available if(m_detLayout==-1 || m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", "One of the variables is missing: detLayout | offset_z | width_z | offset_r | numLayers | dRlayer"); return; } + // some sanity checks of the xml + if( m_offsetZ.size() != m_offsetR.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in offsetZ and offsetR must be the same!"); + return; + } + if( m_widthZ.size() != m_offsetR.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in widthZ and offsetR must be the same!"); + return; + } + if( m_detLayout == 0 && m_offsetZ.size() != 1) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in offsetZ/offsetR/widthZ must be 1 for the Barrel!"); + return; + } + if( m_numLayers.size() % m_offsetZ.size() != 0 ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in numLayers must be multiple of offsetZ.size()!"); + return; + } + if( m_dRlayer.size() != m_numLayers.size()/m_offsetZ.size() ) + { + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + "Number of elements in dRlayer must be equal to numLayers.size()/offsetZ.size()!"); + return; + } + if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","EndCap configuration found!"); From 05a200b52456fa3f404cbc1acdd15c785eb3aa2c Mon Sep 17 00:00:00 2001 From: Archil Durglishvili Date: Mon, 2 Dec 2024 15:57:06 +0100 Subject: [PATCH 098/133] Fixing typo: PhiRow to PhiTheta --- .../src/FCCSWHCalPhiTheta_k4geo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp index 08346e4f6..e71688951 100644 --- a/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWHCalPhiTheta_k4geo.cpp @@ -79,7 +79,7 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { // check if all necessary variables are available if(m_detLayout==-1 || m_offsetZ.empty() || m_widthZ.empty() || m_offsetR.empty() || m_numLayers.empty() || m_dRlayer.empty()) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "One of the variables is missing: detLayout | offset_z | width_z | offset_r | numLayers | dRlayer"); return; } @@ -87,37 +87,37 @@ void FCCSWHCalPhiTheta_k4geo::defineCellsInRZplan() const { // some sanity checks of the xml if( m_offsetZ.size() != m_offsetR.size() ) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "Number of elements in offsetZ and offsetR must be the same!"); return; } if( m_widthZ.size() != m_offsetR.size() ) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "Number of elements in widthZ and offsetR must be the same!"); return; } if( m_detLayout == 0 && m_offsetZ.size() != 1) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "Number of elements in offsetZ/offsetR/widthZ must be 1 for the Barrel!"); return; } if( m_numLayers.size() % m_offsetZ.size() != 0 ) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "Number of elements in numLayers must be multiple of offsetZ.size()!"); return; } if( m_dRlayer.size() != m_numLayers.size()/m_offsetZ.size() ) { - dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiRow_k4geo","Please check the readout description in the XML file!\n%s", + dd4hep::printout(dd4hep::ERROR, "FCCSWHCalPhiTheta_k4geo","Please check the readout description in the XML file!\n%s", "Number of elements in dRlayer must be equal to numLayers.size()/offsetZ.size()!"); return; } - if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","Barrel configuration found!"); - else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiRow_k4geo","EndCap configuration found!"); + if(m_detLayout==0) dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","Barrel configuration found!"); + else dd4hep::printout(dd4hep::INFO, "FCCSWHCalPhiTheta_k4geo","EndCap configuration found!"); // calculate the radius for each layer uint N_dR = m_numLayers.size()/m_offsetZ.size(); From 80e7826faf73dfa785018e3e77726087759e3e97 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Sun, 27 Oct 2024 15:07:59 +0100 Subject: [PATCH 099/133] Add dual-readout-tubes endcap calo geometry Add geometry for the dual-readout tubes-based endcap calorimeter (taken from https://github.com/lopezzot/DREndcapTube/tree/v0.3). Add CMake code to compile geometries under detector/calorimeter/dual-readout-tubes/*, the barrel geometry will be added there. --- CMakeLists.txt | 4 + detector/calorimeter/README.md | 6 + .../include/DREndcapTubes.hh | 332 +++++++++++ .../src/DREndcapTubes_o1_v01.cpp | 518 ++++++++++++++++++ 4 files changed, 860 insertions(+) create mode 100644 detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh create mode 100644 detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7832f679a..811779559 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ file(GLOB sources ./detector/tracker/*.cpp ./detector/calorimeter/*.cpp ./detector/calorimeter/dual-readout/src/*.cpp + ./detector/calorimeter/dual-readout-tubes/src/*.cpp ./detector/fcal/*.cpp ./detector/muonSystem/*.cpp ./detector/other/*.cpp @@ -134,6 +135,9 @@ target_include_directories(${PackageName}G4 PRIVATE ${PROJECT_SOURCE_DIR}/detect target_include_directories(${PackageName} PRIVATE ${PROJECT_SOURCE_DIR}/detector/calorimeter/dual-readout/include ) target_include_directories(${PackageName}G4 PRIVATE ${PROJECT_SOURCE_DIR}/detector/calorimeter/dual-readout/include ) +target_include_directories(${PackageName} PRIVATE ${PROJECT_SOURCE_DIR}/detector/calorimeter/dual-readout-tubes/include ) +target_include_directories(${PackageName}G4 PRIVATE ${PROJECT_SOURCE_DIR}/detector/calorimeter/dual-readout-tubes/include ) + target_link_libraries(${PackageName} DD4hep::DDCore DD4hep::DDRec DD4hep::DDParsers ROOT::Core detectorSegmentations) target_link_libraries(${PackageName}G4 DD4hep::DDCore DD4hep::DDRec DD4hep::DDParsers DD4hep::DDG4 ROOT::Core podio::podioRootIO EDM4HEP::edm4hep ${Geant4_LIBRARIES}) diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index 1306a0a87..e76042ded 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -55,3 +55,9 @@ Changes wrt o1_v01: Added extension (LayeredCalorimeterData) to store radial lay ### o1_v01 This sub-detector makes full 4-pi monolithic fiber dual-readout calorimeter. Inside the single tower (trapezoidal copper absorber), two types of optical fibers (Cherenkov and scintillation) are implemented. The readout (SiPM) is attached at the rear side of the tower. The tower is repeated in both eta and phi direction to cover both barrel and endcap region. + +## dual-readout-tubes + +### o1_v01 +This folder containes the subdetectors (endcap + barrel) to make a full 4-pi fiber dual-readout calorimeter exploiting the INFN capillary-tubes technology. Each trapezoidal tower is constructed with brass capillary-tubes housing optical fibers (Cherenkov and scintillating). +For the moment, only the endcap subdetector is included, the barrel will be added with a dedicated PR. diff --git a/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh b/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh new file mode 100644 index 000000000..2d7d66e4c --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh @@ -0,0 +1,332 @@ +//************************************************************************** +// \file DREndcapTube.hh +// \brief: Auxiliary class to handle complex computations for the IDEA +// dual-readout calorimeter with the capillary tubes technology +// \author: Lorenzo Pezzotti (CERN) @lopezzot +// \start date: 12 July 2024 +//************************************************************************** + +#ifndef DREndcapTube_H +# define DREndcapTube_H + +// This struct represents a plane corresponding to a tower's face. +// I construct it with the 4 edges (points) of the tower's face, +// however only 3 points will be used to define the plane. +struct Plane +{ + Vector3D P1, P2, P3, P4; + Plane(Vector3D p1, Vector3D p2, Vector3D p3, Vector3D p4) : P1(p1), P2(p2), P3(p3), P4(p4){}; +}; + +// This struct represents a line towards negatize Z +// given its starting point (origin). +// The starting points will be distributed over the back face +// of the a tower. The corresponding lines will be used to find +// the intersection with the tower's faces. +struct ZLine +{ + Vector3D origin; + Vector3D fuZ = Vector3D(0, 0, -1); + ZLine(Vector3D P) : origin(P){}; +}; + +// Custom exception class for intersecting ZLines with Planes +class IntersectException : public std::exception +{ + public: + const char* what() const noexcept override + { + return "IntersectLinePlane: Invalid intersection of ZLine with a Plane"; + } +}; + +class DREndcapTubeHelper +{ + public: + // Constructor and de-constructor + DREndcapTubeHelper() = default; + ~DREndcapTubeHelper() = default; + + private: + // Class fields + // + // Fields to be set + double fTubeRadius; // Radius of tubes (same for Scin and Cher) + double fPhiZRot; // tower phi dimension + bool fRbool; // set to true to build right endcap + bool fCalBasicBool; // has CalBasic already being called? + double fInnerR; // inner radius at theta = 0. rad + double fTowerHeight; // tower height/length + double fNumZRot; // number of rotations around Z axis + double fDeltaTheta; // theta dimension of current tower + double fDeltaTheta2; // theta dimension of next tower + double fThetaOfCenter; // theta angle pointing to center of current tower + double fThetaOfCenter2; // theta angle pointing to center of next tower + // Fields to be computed + double finnerR_new; + double finnerR_new2; + double fTrns_Length; + Vector3D fTrns_Vector; + Vector3D fV1; + Vector3D fV2; + Vector3D fV3; + Vector3D fV4; + double Ratio; + double Ratio2; + + public: + // Methods to set class fields + void SetRbool(bool rBool) { fRbool = rBool; } // set to True if building right endcap + void SetInnerR(double innerR) { fInnerR = innerR; } + void SetTowerHeight(double towerHeight) { fTowerHeight = towerHeight; } + void SetNumZRot(int num) + { + fNumZRot = num; + fPhiZRot = 2 * M_PI / (double)num; + } + void SetDeltaTheta(double theta) { fDeltaTheta = theta; } + void SetThetaOfCenter(double theta) { fThetaOfCenter = theta; } + void SetDeltaTheta2(double theta) { fDeltaTheta2 = theta; } + void SetThetaOfCenter2(double theta) { fThetaOfCenter2 = theta; } + void SetTubeRadius(double tubeRadius) { fTubeRadius = tubeRadius; } + + // Methods to calculate towers parameters + // + void CalBasic(); + // Get origin on tower within its phi slice/stave + Vector3D GetOrigin(int i); + // Get 8 vector/points for the tower Trap edges + void Getpt(Vector3D* pt); + + // Methods to calculate tubes lengths + // + // This method finds the "intersection" between a ZLine (tube) and a Plane (tower face) + void IntersectLinePlane(const ZLine& line, const Plane& plane, Vector3D& intersection); + // This method calculates a tube length given the cylindrical structure of the tube + // and each tower face + double GetTubeLength(const Vector3D (&pt)[8], const Vector3D& point); +}; + +inline void DREndcapTubeHelper::CalBasic() +{ + fCalBasicBool = 1; + + // distance from center to front face of first tower + // radius is 2500 mm which is same as distance from center to front face of very + // last tower. + // To get distance to first tower I divide this radius by cosine of first tower. + // To understand impact of sin*tan part + finnerR_new = fInnerR / (cos(fThetaOfCenter) - sin(fThetaOfCenter) * tan(fDeltaTheta / 2.)); + // distance from center to front face of second tower (same as above) + finnerR_new2 = fInnerR / (cos(fThetaOfCenter2) - sin(fThetaOfCenter2) * tan(fDeltaTheta2 / 2.)); + + // Half size at front face of first tower given by effective radius times tan of half delta + double innerSide_half = finnerR_new * tan(fDeltaTheta / 2.); + // Half size at back face + // double outerSide_half = (finnerR_new+fTowerHeight)*tan(fDeltaTheta/2.); + + // Half size at front face of second tower (same as above) + double innerSide_half2 = finnerR_new2 * tan(fDeltaTheta2 / 2.); + + // Distance from origin to center of first tower + fTrns_Length = fTowerHeight / 2. + finnerR_new; + + // Vector from origin to center of first tower + // Remember towers are placed starting from the one laying on the x-axis + fTrns_Vector = dd4hep::rec::Vector3D(cos(fThetaOfCenter) * fTrns_Length, 0, + sin(fThetaOfCenter) * fTrns_Length); + + double dx1 = fInnerR; // inner radius hardcoded in detector construction + double dxi = sin(fThetaOfCenter) * finnerR_new + innerSide_half * cos(fThetaOfCenter); + double dxi2 = sin(fThetaOfCenter2) * finnerR_new2 + innerSide_half2 * cos(fThetaOfCenter2); + Ratio = dxi / dx1; + Ratio2 = dxi2 / dx1; + + // These vectors are distributed over the plane of the tower closest to the barrel + // The difference between fV1 and fV2 (fV3 and fV4) is the correction of finnerR_new+fTowerHeight + // that meake the vector start at the begin and end of the tower surface + fV1 = dd4hep::rec::Vector3D((Ratio2) + * (cos(fThetaOfCenter) * finnerR_new + + sin(fThetaOfCenter) * finnerR_new * tan(fDeltaTheta / 2.)), + 0, + sin(fThetaOfCenter) * finnerR_new + - sin(fThetaOfCenter) * finnerR_new * tan(fDeltaTheta / 2.)); + + fV2 = dd4hep::rec::Vector3D( + (Ratio2) + * (cos(fThetaOfCenter) * (finnerR_new + fTowerHeight) + + sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) * tan(fDeltaTheta / 2.)), + 0, + sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) + - sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) * tan(fDeltaTheta / 2.)); + + fV3 = dd4hep::rec::Vector3D((Ratio) + * (cos(fThetaOfCenter) * finnerR_new + - sin(fThetaOfCenter) * finnerR_new * tan(fDeltaTheta / 2.)), + 0, + sin(fThetaOfCenter) * finnerR_new + + sin(fThetaOfCenter) * finnerR_new * tan(fDeltaTheta / 2.)); + + fV4 = dd4hep::rec::Vector3D( + (Ratio) + * (cos(fThetaOfCenter) * (finnerR_new + fTowerHeight) + - sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) * tan(fDeltaTheta / 2.)), + 0, + sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) + + sin(fThetaOfCenter) * (finnerR_new + fTowerHeight) * tan(fDeltaTheta / 2.)); +} + +// Get 8 vector/points for the tower Trap edges +inline void DREndcapTubeHelper::Getpt(dd4hep::rec::Vector3D* pt) +{ + double innerSide_half = finnerR_new * tan(fDeltaTheta / 2.); + double outerSide_half = (finnerR_new + fTowerHeight) * tan(fDeltaTheta / 2.); + + if (fRbool == 1) { + pt[0] = + dd4hep::rec::Vector3D(-(fV1.x() * tan(fPhiZRot / 2.)), -innerSide_half, -fTowerHeight / 2.); + pt[1] = + dd4hep::rec::Vector3D((fV1.x() * tan(fPhiZRot / 2.)), -innerSide_half, -fTowerHeight / 2.); + pt[2] = + dd4hep::rec::Vector3D(-(fV3.x() * tan(fPhiZRot / 2.)), innerSide_half, -fTowerHeight / 2.); + pt[3] = + dd4hep::rec::Vector3D((fV3.x() * tan(fPhiZRot / 2.)), innerSide_half, -fTowerHeight / 2.); + pt[4] = + dd4hep::rec::Vector3D(-(fV2.x() * tan(fPhiZRot / 2.)), -outerSide_half, fTowerHeight / 2.); + pt[5] = + dd4hep::rec::Vector3D((fV2.x() * tan(fPhiZRot / 2.)), -outerSide_half, fTowerHeight / 2.); + pt[6] = + dd4hep::rec::Vector3D(-(fV4.x() * tan(fPhiZRot / 2.)), outerSide_half, fTowerHeight / 2.); + pt[7] = + dd4hep::rec::Vector3D((fV4.x() * tan(fPhiZRot / 2.)), outerSide_half, fTowerHeight / 2.); + } + else { + pt[0] = + dd4hep::rec::Vector3D(-(fV1.x() * tan(fPhiZRot / 2.)), -innerSide_half, -fTowerHeight / 2.); + pt[1] = + dd4hep::rec::Vector3D((fV1.x() * tan(fPhiZRot / 2.)), -innerSide_half, -fTowerHeight / 2.); + pt[2] = + dd4hep::rec::Vector3D(-(fV3.x() * tan(fPhiZRot / 2.)), innerSide_half, -fTowerHeight / 2.); + pt[3] = + dd4hep::rec::Vector3D((fV3.x() * tan(fPhiZRot / 2.)), innerSide_half, -fTowerHeight / 2.); + pt[4] = + dd4hep::rec::Vector3D(-(fV2.x() * tan(fPhiZRot / 2.)), -outerSide_half, fTowerHeight / 2.); + pt[5] = + dd4hep::rec::Vector3D((fV2.x() * tan(fPhiZRot / 2.)), -outerSide_half, fTowerHeight / 2.); + pt[6] = + dd4hep::rec::Vector3D(-(fV4.x() * tan(fPhiZRot / 2.)), outerSide_half, fTowerHeight / 2.); + pt[7] = + dd4hep::rec::Vector3D((fV4.x() * tan(fPhiZRot / 2.)), outerSide_half, fTowerHeight / 2.); + } +} + +// Get origin on tower within its phi slice/stave +inline dd4hep::rec::Vector3D DREndcapTubeHelper::GetOrigin(int i) +{ + if (fCalBasicBool == 0) { + std::cout << "fCalBasicBool = 0" << std::endl; + return dd4hep::rec::Vector3D(); + } + else { + if (fRbool == 1) { + double x, y, z; + x = cos(i * fPhiZRot) * fTrns_Vector.x(); + y = sin(i * fPhiZRot) * fTrns_Vector.x(); + z = fTrns_Vector.z(); + + return dd4hep::rec::Vector3D(x, y, z); + } + else { + double x, y, z; + x = cos(i * fPhiZRot) * fTrns_Vector.x(); + y = sin(i * fPhiZRot) * fTrns_Vector.x(); + z = -fTrns_Vector.z(); + + return dd4hep::rec::Vector3D(x, y, z); + } + } +} + +// This method finds the "intersection" between a ZLine (tube) and a Plane (tower face). +// Only the first 3 points of the plane and needed to define the plane. +// The "intersection" is updated with the Vector3D at the intersection found. +// Exceptions are handled by this function if the line is parallel to the plane or the +// intersection is behind the line origin, i.e. below the backface of the tower. +// Both cases are to be considered errors. +inline void DREndcapTubeHelper::IntersectLinePlane(const ZLine& line, const Plane& plane, + Vector3D& intersection) +{ + Vector3D p0 = plane.P1; + Vector3D p1 = plane.P2; + Vector3D p2 = plane.P3; + + // Compute the plane normal + Vector3D u = Vector3D(p1.x() - p0.x(), p1.y() - p0.y(), p1.z() - p0.z()); + Vector3D v = Vector3D(p2.x() - p0.x(), p2.y() - p0.y(), p2.z() - p0.z()); + Vector3D normal = Vector3D(u.y() * v.z() - u.z() * v.y(), u.z() * v.x() - u.x() * v.z(), + u.x() * v.y() - u.y() * v.x()); + + double denominator = + normal.x() * line.fuZ.x() + normal.y() * line.fuZ.y() + normal.z() * line.fuZ.z(); + + if (std::fabs(denominator) < 1e-6) { + throw IntersectException(); // The line is parallel to the plane + } + + double d = normal.x() * p0.x() + normal.y() * p0.y() + normal.z() * p0.z(); + double t = + (d - normal.x() * line.origin.x() - normal.y() * line.origin.y() - normal.z() * line.origin.z()) + / denominator; + + if (t < 0) { + throw IntersectException(); // The intersection is behind the line origin + } + + intersection = Vector3D(line.origin.x() + t * line.fuZ.x(), line.origin.y() + t * line.fuZ.y(), + line.origin.z() + t * line.fuZ.z()); +}; + +// This method calculates a tube length given the cylindrical structure of the tube +// and each tower face. +// The intersection is calculated over 5 planes (tower front, up, down, left and right faces). +// For each plane the intersection is calculated over four points on the tube surface (up, down, +// left, right). The shortest intersection is the one to be used. +inline double DREndcapTubeHelper::GetTubeLength(const Vector3D (&pt)[8], const Vector3D& point) +{ + Plane FirstPlane(pt[0], pt[1], pt[2], pt[3]); // front plane (smallest one) + Plane SecondPlane(pt[1], pt[5], pt[3], pt[7]); // right plane (looking at the front face) + Plane ThirdPlane(pt[2], pt[3], pt[6], pt[7]); // top plane + Plane FourthPlane(pt[0], pt[4], pt[2], pt[6]); // left plane + Plane FifthPlane(pt[0], pt[1], pt[5], pt[4]); // bottom plane + std::array Planes{FirstPlane, SecondPlane, ThirdPlane, FourthPlane, FifthPlane}; + + ZLine PointZLine(point); // Axis of the tube with origin on tower back plane + ZLine UpPointZLine(Vector3D(point.x(), point.y() + fTubeRadius, point.z())); + ZLine DownPointZLine(Vector3D(point.x(), point.y() - fTubeRadius, point.z())); + ZLine LeftPointZLine(Vector3D(point.x() - fTubeRadius, point.y(), point.z())); + ZLine RightPointZLine(Vector3D(point.x() + fTubeRadius, point.y(), point.z())); + std::array Lines{UpPointZLine, DownPointZLine, LeftPointZLine, RightPointZLine}; + + Vector3D intersection; // intersection to be found + double tubeLength{0.}; // tube length to be returned + + for (std::size_t k = 0; k < Lines.size(); k++) { // loop over cylinder surface points + for (std::size_t i = 0; i < Planes.size(); i++) { // loop over tower's planes + IntersectLinePlane(Lines.at(k), Planes.at(i), intersection); + double fiberLengthPlane = (Lines.at(k).origin - intersection).r(); + if (k == 0 && i == 0) + tubeLength = fiberLengthPlane; + else if (tubeLength > fiberLengthPlane) + tubeLength = fiberLengthPlane; + else { + ; + } + } // end of loop over tower's planes + } // end of loop over cylinder surface points + + return tubeLength; +}; + +#endif // DREndcapTube_H + +//************************************************************************** diff --git a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp new file mode 100644 index 000000000..3679b658b --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp @@ -0,0 +1,518 @@ +//************************************************************************** +// \file DREndcapTubes.cpp +// \brief: Implementation of the endcap geometry of the IDEA dual-readout +// calorimeter using the capillary tubes technology +// \author: Lorenzo Pezzotti (CERN) @lopezzot +// \start date: 12 July 2024 +//************************************************************************** + +// Includers from DD4hep +#include "DDRec/Vector3D.h" +#include + +// Includers from stl +#include +#include +#include +#include + +using namespace dd4hep; +using namespace dd4hep::rec; // for dd4hep::rec::Vector3D + +// Includers from project files +#include "DREndcapTubes.hh" + +#define COUNTTUBES // if defined it counts the tubes in each tower +// #define DUMPTOWEREDGES // if defined it prints tower edges x and y position (cm) + +// This methods unifies in 32 bits two IDs of 16 bits max +// It is used to create a G4 copynumber for volumes with two IDs +unsigned int CalcCpNo32bits(int id1, int id2) +{ + if (id1 > 0xFFF || id2 > 0xFFF){ + throw std::invalid_argument("row and col IDs should not take more than 16 bits"); + } + unsigned int CpNo = (id1 << 16) | id2; + return CpNo; +} + +// This methods unifies in 32 bits two IDs of 1 bit only +unsigned int CalcCpNo2bits(int id1, int id2) +{ + if (id1 > 1 || id2 > 1) { + throw std::invalid_argument("core and cherenkov ID must be 0 or 1"); + } + unsigned int CpNo = (id1 << 1) | id2; + return CpNo; +} + +// Create the endcap calorimeter +// +static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) +{ + std::cout << "--> DREndcapTubes::create_detector() start" << std::endl; + + // Get info from the xml file + // + // Info for the main detector element DREndcapTube + sens.setType("calorimeter"); + xml_det_t x_det = e; + std::string det_name = x_det.nameStr(); // DREndcapTube volume + std::cout << "--> DREndcapTubes: going to create " << det_name << ", with ID: " << x_det.id() + << std::endl; + xml_dim_t x_dim = x_det.dimensions(); + const double innerR = x_dim.inner_radius(); // inner radius at theta = 0. rad + const double tower_height = x_dim.z_length(); // tower height/length + const double length = tower_height; // alias for tower height/length + const int NbOfZRot = static_cast(x_dim.deltaphi()); // number or rations aroung Z axis + const double phi_unit = 2 * M_PI / (double)NbOfZRot; // slice delta phi + std::cout << "--> DREndcapTubes: from XML description: innerR " << innerR / m + << " m, tower length " << tower_height / m << " m, z-rotations " << NbOfZRot; + // Info for subdetectors + xml_det_t x_assembly = x_det.child(_Unicode(assembly)); + xml_det_t x_stave = x_det.child(_Unicode(stave)); + xml_det_t x_tower = x_det.child(_Unicode(tower)); + xml_det_t x_capillary_S = x_det.child(_Unicode(tube_S)); + xml_det_t x_capillary_C = x_det.child(_Unicode(tube_C)); + xml_det_t x_clad_S = x_det.child(_Unicode(clad_S)); + xml_det_t x_clad_C = x_det.child(_Unicode(clad_C)); + auto x_clad_C_sens = x_clad_C.isSensitive(); + xml_det_t x_core_S = x_det.child(_Unicode(core_S)); + auto x_core_S_sens = x_core_S.isSensitive(); + xml_det_t x_core_C = x_det.child(_Unicode(core_C)); + auto x_core_C_sens = x_core_C.isSensitive(); + const double tubeRadius = x_capillary_S.outer_radius(); + std::cout << ", tube radius " << tubeRadius / mm << " mm" << std::endl; + const double cladRadius = x_clad_S.outer_radius(); + const double coreRadius = x_core_S.outer_radius(); + + // Hardcoded parameters (not supposed to be changed) + constexpr double thetaB{M_PI / 4}; // theta at the end of barrel (45 deg) + constexpr int NbOfEndcap{40}; // number of eta towers for the endcap. + // De facto I will stop at 35 to leave + // room for the beam pipe. + constexpr int NbOfEndcapReduced{35}; + // Length correction to be applied to capillary tubes + // with length reduced by the intersection + // with the tower's planes. + // It is needed for the intersections with + // the lateral sides for which the intersecting + // point is not exactly the left or right edge of the tube + constexpr double TubeLengthOffset{0.1 * mm}; + const double tubeDiameter = tubeRadius * 2.; + const double y_pitch = tubeDiameter * sqrt(3) / 2.; // y-distance from tube center to center + // fixed by the tubes positioning + // The 8 vertices of a tower to be defined later + Vector3D pt[8]; + // Create the geometry helper and set paramters + DREndcapTubeHelper Helper; + Helper.SetInnerR(innerR); + Helper.SetTowerHeight(tower_height); + Helper.SetNumZRot(NbOfZRot); + Helper.SetTubeRadius(tubeRadius); + + // Start building the geometry + // + + // The phi-slices (staves) will be placed inside an assembly volume + Assembly AssemblyEndcap("DREndcapTubes"); + AssemblyEndcap.setVisAttributes(description, x_assembly.visStr()); + + // Volume that contains a slice of the right endcap + // I use the EightPointSolid/Arb8/G4Generictrap so I define directly its 8 points + // + // The first two points of the inner face collide on the beam pipe into (0,0) + // The second two points of the inner face are at (x=tan(0.5*phi_unit, y=innerR) + // x with plus or minus sign + double vertices[16]; + vertices[0] = static_cast(0.); + vertices[1] = static_cast(0.); + vertices[2] = static_cast(0.); + vertices[3] = static_cast(0.); + vertices[4] = static_cast(-innerR * tan(0.5 * phi_unit)); + vertices[5] = static_cast(innerR); + vertices[6] = static_cast(innerR * tan(0.5 * phi_unit)); + vertices[7] = static_cast(innerR); + // The first two points of the outer face collide on the beam pipe into (0,0) + // The second two poits of the outer face are same as before with innerR+tower_height + vertices[8] = static_cast(0.); + vertices[9] = static_cast(0.); + vertices[10] = static_cast(0.); + vertices[11] = static_cast(0.); + vertices[12] = static_cast(-(innerR + tower_height) * tan(0.5 * phi_unit)); + vertices[13] = static_cast(innerR + tower_height); + vertices[14] = static_cast((innerR + tower_height) * tan(0.5 * phi_unit)); + vertices[15] = static_cast(innerR + tower_height); + // Equivalent of Geant4 GenericTrap shape constructor + EightPointSolid phiER("phiER", tower_height / 2., vertices); + Volume phiERLog("phiER", phiER, description.material(x_stave.attr(_U(material)))); + phiERLog.setVisAttributes(description, x_stave.visStr()); + + // Place logical volume containing the Endcap R slice multiple times + // + // Rotate the endcap R slice around the Z axis + for (std::size_t j = 0; j < static_cast(NbOfZRot); j++) { + // Placement of right endcap (positive z-coordinate) + RotationZ rotz1(M_PI / 2.); // here I discovered that dd4hep rotations around Z are inverted + RotationZ rotz2(j * phi_unit); // w.r.t. Geant4 (+->-) + RotationX rotx(M_PI); + RotationY roty(M_PI); + Transform3D slice_trnsform(rotz1 * rotz2 * rotx * roty, + Position(0, 0, (innerR)*tan(thetaB) + length / 2.)); + PlacedVolume phiERPlaced = AssemblyEndcap.placeVolume(phiERLog, j, slice_trnsform); + // ID this volume with one number, the rotation + phiERPlaced.addPhysVolID("stave", j); + + // Placement of left endcap (negative z-coordinate) + RotationY rotyleft(0.); + Transform3D slice_trnsformleft(rotz1 * rotz2 * rotx * rotyleft, + Position(0, 0, -1. * ((innerR)*tan(thetaB) + length / 2.))); + PlacedVolume phiELPlaced = AssemblyEndcap.placeVolume(phiERLog, j+NbOfZRot, slice_trnsformleft); + phiELPlaced.addPhysVolID("stave", j+NbOfZRot); + } // end of slice/stave placement + + // Create an S tube with full tower length + Tube capillary_S(0. * mm, tubeRadius, tower_height / 2., 2 * M_PI); + Volume capillary_SLog("capillary_SLog", capillary_S, + description.material(x_capillary_S.attr(_U(material)))); + capillary_SLog.setVisAttributes(description, x_capillary_S.visStr()); + Tube clad_S(0. * mm, cladRadius, tower_height / 2., 2 * M_PI); // cladding S + Volume clad_SLog("clad_SLog", clad_S, + description.material(x_clad_S.attr(_U(material)))); + clad_SLog.setVisAttributes(description, x_clad_S.visStr()); + PlacedVolume clad_SPlaced = capillary_SLog.placeVolume(clad_SLog, 1, Position(0., 0., 0.)); + // ID this volume with clad ID (0/1) + clad_SPlaced.addPhysVolID("clad", 1); + Tube core_S(0. * mm, coreRadius, tower_height / 2., 2 * M_PI); // core S + Volume core_SLog("DRETScoreS_Log", core_S, + description.material(x_core_S.attr(_U(material)))); + core_SLog.setVisAttributes(description, x_core_S.visStr()); + if (x_core_S_sens) core_SLog.setSensitiveDetector(sens); + PlacedVolume core_SPlaced = clad_SLog.placeVolume(core_SLog, CalcCpNo2bits(1,0)); + core_SPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 0); + + // Create a C tube with full tower length + Tube capillary_C(0. * mm, tubeRadius, tower_height / 2., 2 * M_PI); + Volume capillary_CLog("capillary_CLog", capillary_C, + description.material(x_capillary_C.attr(_U(material)))); + capillary_CLog.setVisAttributes(description, x_capillary_C.visStr()); + Tube clad_C(0. * mm, cladRadius, tower_height / 2., 2 * M_PI); // cladding C + Volume clad_CLog("DRETSclad_CLog", clad_C, + description.material(x_clad_C.attr(_U(material)))); + clad_CLog.setVisAttributes(description, x_clad_C.visStr()); + if (x_clad_C_sens) clad_CLog.setSensitiveDetector(sens); + PlacedVolume clad_CPlaced = capillary_CLog.placeVolume(clad_CLog, 1, Position(0., 0., 0.)); + clad_CPlaced.addPhysVolID("clad", 1); + Tube core_C(0. * mm, coreRadius, tower_height / 2., 2 * M_PI); // core C + Volume core_CLog("DRETScoreC_Log", core_C, + description.material(x_core_C.attr(_U(material)))); + core_CLog.setVisAttributes(description, x_core_C.visStr()); + if (x_core_C_sens) core_CLog.setSensitiveDetector(sens); + PlacedVolume core_CPlaced = clad_CLog.placeVolume(core_CLog, CalcCpNo2bits(1,1)); + core_CPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 1); + + // Build the towers inside and endcap R slice + // + Helper.SetRbool(1); // Build the right endcap (will reflect it for left part) + double thetaofcenter = 0.; // theta angle to center of tower being constructed + double thetaofcenter2 = 0.; // theta angle to center of next tower + // I fix delta theta of every tower to be the same for every tower + double deltatheta_endcap[40] = {0.}; + for (int i = 0; i < NbOfEndcap; i++) + deltatheta_endcap[i] = M_PI / 4 / (NbOfEndcap); + double thetaE = 0.; + for (int i = 0; i < NbOfEndcap; i++) + thetaE += deltatheta_endcap[i]; + double fulltheta = thetaE; // 45 deg by construction + +#ifdef COUNTTUBES + unsigned int totalTubeNo{0}; + unsigned int tubeNo{0}; + double totalTubeLength{0.}; +#endif + + // Loop over tower number, stop at tower 35 to leave room for beam pipe + for (int i = 0; i < NbOfEndcapReduced; i++) { +#ifdef COUNTTUBES + tubeNo = 0; +#endif + + // Center of first (highest) tower is 45 deg - deltatheta_endcap[1]/2 + thetaofcenter = fulltheta - deltatheta_endcap[i] / 2.; + // Center of the next tower + thetaofcenter2 = thetaofcenter - deltatheta_endcap[i] / 2. - deltatheta_endcap[i + 1] / 2.; + // Update Helper class parameters accordingly + Helper.SetDeltaTheta(deltatheta_endcap[i]); + Helper.SetThetaOfCenter(thetaofcenter); + Helper.SetDeltaTheta2(deltatheta_endcap[i + 1]); + Helper.SetThetaOfCenter2(thetaofcenter2); + Helper.CalBasic(); // Perform internal calculations + Helper.Getpt(pt); // Update 8 Vectors defining the tower edges + +#ifdef DUMPTOWEREDGES + std::cout << "DREndcapTubes: Tower " << i << " edges (cm):" << std::endl; + for (std::size_t edge = 0; edge < 8; edge++) { + std::cout << "x " << pt[edge].x() << " y " << pt[edge].y() << std::endl; + } +#endif + + // Create now the tower as a Trap + // + // Problem: G4Trap has a constructors using the 8 vertices of the trapezoid + // but DD4hep Trap does not have such constructor. + // Therefore I calculate here the parameters to be passed to the DD4hep Trap. + auto pDz = (pt[7]).z(); + auto pDy1 = ((pt[2]).y() - (pt[1]).y()) * 0.5; + auto pDx1 = ((pt[1]).x() - (pt[0]).x()) * 0.5; + auto pDx2 = ((pt[3]).x() - (pt[2]).x()) * 0.5; + auto fTalpha1 = ((pt[2]).x() + (pt[3]).x() - (pt[1]).x() - (pt[0]).x()) * 0.25 / pDy1; + auto pAlp1 = std::atan(fTalpha1); + auto pDy2 = ((pt[6]).y() - (pt[5]).y()) * 0.5; + auto pDx3 = ((pt[5]).x() - (pt[4]).x()) * 0.5; + auto pDx4 = ((pt[7]).x() - (pt[6]).x()) * 0.5; + auto fTalpha2 = ((pt[6]).x() + (pt[7]).x() - (pt[5]).x() - (pt[4]).x()) * 0.25 / pDy2; + auto pAlp2 = std::atan(fTalpha2); + auto fThetaCphi = ((pt[4]).x() + pDy2 * fTalpha2 + pDx3) / pDz; + auto fThetaSphi = ((pt[4]).y() + pDy2) / pDz; + double pPhi = 0.; + double pTheta = 0.; + if (fThetaSphi == 0. && fThetaCphi == 0.) { + } + else { + pPhi = std::atan(fThetaSphi / fThetaCphi); + pTheta = std::atan(fThetaCphi / std::cos(pPhi)); + } // end of Trap parameters calculation + + Trap tower("phiER", pDz, pTheta, pPhi, pDy1, pDx1, pDx2, pAlp1, pDy2, pDx3, pDx4, pAlp2); + Volume towerLog("towerLog", tower, + description.material(x_tower.attr(_U(material)))); + towerLog.setVisAttributes(description, x_tower.visStr()); + + RotationX rotX(-thetaofcenter); // Rotation matrix for this tower + RotationY rotY(0.); + RotationZ rotZ(0.); + Vector3D c = Helper.GetOrigin(0); // Get origin of tower + Vector3D c_new(-c.y(), c.z(), c.x() - (innerR + 0.5 * length)); + if (i < NbOfEndcapReduced) + { // Place towers up to 35, this "if" is just a protection in case the loop range is changed +#ifndef COUNTTUBES + std::cout << "----> DREndcapTubes: tower " << i << " being constructed" << std::endl; +#endif +#ifdef COUNTTUBES + std::cout << "----> DREndcapTubes: tower " << i << " being constructed"; +#endif + Transform3D tower_trnsform(rotX * rotY * rotZ, Position(c_new.x(), c_new.y(), c_new.z())); + PlacedVolume towerPlaced = phiERLog.placeVolume(towerLog, i, tower_trnsform); + // ID this volume with tower ID, for the moment I leave air ID to 0 (dummy) + towerPlaced.addPhysVolID("tower", i).addPhysVolID("air", 0); + } + // Or, to debug, place towers one next to each other in assembly volume + //if(i<35) { + // double z = static_cast(i/15)*(length+40*cm); + // double x = (i-static_cast(i/15)*15)*100*cm - 5*m; + // AssemblyEndcap.placeVolume(towerLog,i,Position(-1.*x,0.,-1.*z)); + //} + + // Capillary placement inside tower (both S and C) + // + // Fill a tower along y (vertical direction) + // per each row calculate x and y of the starting tube (left most) + const double y_backplane = pt[4].y(); // y-coordinate of bottom left corner of back face + const double x_backplane = pt[4].x(); // x-coordinate of bottom left corner of back face + for (std::size_t k = 0; k < 200; k++) { + double x_start = x_backplane; + double y_tube = 0.; + double delta_x = 0.; // correction to tune x-coordinate + // if it is the first row fix the y coordinate + if (k == 0) + y_tube = y_backplane + tubeRadius + + 1.0 * mm; // add 1 mm otherwise the tube immediately intersect with a plane + else { + y_tube = y_backplane + tubeRadius + 1.0 * mm + k * 2. * y_pitch; + + // Adjust starting x given the opening angle of the trapezoidal back face + double hypotenuse = sqrt(pow((-1 * y_backplane) * 2, 2) + pow(pt[6].x() - pt[4].x(), 2)); + double angle = acos(((-1 * y_backplane) * 2) / hypotenuse); + delta_x = ((-1. * y_backplane) - (-1. * y_tube)) * tan(angle); + } + if (delta_x > tubeDiameter) { + // Calculate how many fibers should be inserted in x. + // Caveat: casting to int does not round takes only the + // integer part (i.e. 6.9 -> 6) + auto newTubesNo = static_cast(delta_x / tubeDiameter); + x_start = x_start - newTubesNo * tubeDiameter; + } + + // Fill a tower row along x (lateral direction) + for (std::size_t j = 0; j < 1000; j++) { + auto x_tube = + x_start + tubeRadius + j * (tubeDiameter); // locate the center of the tube in x + Vector3D capillaryPos(x_tube, y_tube, length / 2.); // locate tube on tower back face + auto capillaryLength = Helper.GetTubeLength(pt, capillaryPos); // calculate tube length + if (std::fabs(capillaryLength - length) < 0.0001 * mm) { + PlacedVolume capillaryPlaced = + towerLog.placeVolume(capillary_SLog, CalcCpNo32bits(j,k), Position(x_tube, y_tube, 0.)); + // ID this volume with row ID and column ID + capillaryPlaced.addPhysVolID("row", k).addPhysVolID("col", j); +#ifdef COUNTTUBES + tubeNo++; + totalTubeLength += tower_height; +#endif + } + else if (capillaryLength > 5.0 * cm) { + // Note: the root visualizer does not display tubes with capillaryLength < 4.5 cm. + // Such tubes are usually the ones closest to the left or right side of a tower. + // They seem to be placed correctly but not displayed. + // I am adding a cut over tube length of 5.0 cm: tubes below it will not be placed. + Tube capillaryShort(0. * mm, tubeRadius, (capillaryLength - TubeLengthOffset) / 2., + 2 * M_PI); // reduced capillary length + // by a fixed offset + Volume capillaryShortLog( + "capillaryShortLog", capillaryShort, + description.material(x_capillary_S.attr(_U(material)))); + capillaryShortLog.setVisAttributes(description, x_capillary_S.visStr()); + + Tube cladShort_S(0. * mm, cladRadius, (capillaryLength - TubeLengthOffset) / 2., + 2 * M_PI); // cladding S + Volume cladShort_SLog("cladShort_SLog", cladShort_S, + description.material(x_clad_S.attr(_U(material)))); + cladShort_SLog.setVisAttributes(description, x_clad_S.visStr()); + PlacedVolume cladShort_SPlaced = + capillaryShortLog.placeVolume(cladShort_SLog, 1, Position(0., 0., 0.)); + cladShort_SPlaced.addPhysVolID("clad", 1); + Tube coreShort_S(0. * mm, coreRadius, (capillaryLength - TubeLengthOffset) / 2., + 2 * M_PI); // core S + Volume coreShort_SLog("DRETScoreSShort_Log", coreShort_S, + description.material(x_core_S.attr(_U(material)))); + coreShort_SLog.setVisAttributes(description, x_core_S.visStr()); + if (x_core_S_sens) coreShort_SLog.setSensitiveDetector(sens); + PlacedVolume coreShort_SPlaced = cladShort_SLog.placeVolume(coreShort_SLog, CalcCpNo2bits(1,0)); + coreShort_SPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 0); + + PlacedVolume capillaryShortPlaced = towerLog.placeVolume( + capillaryShortLog, CalcCpNo32bits(j,k), + Position(x_tube, y_tube, length / 2. - capillaryLength / 2. + TubeLengthOffset / 2.)); + // ID this volume with row ID and column ID + capillaryShortPlaced.addPhysVolID("row", k).addPhysVolID("col", j); +#ifdef COUNTTUBES + tubeNo++; + totalTubeLength += capillaryLength; // neglecting the offset +#endif + } + else { + ; + } + + // Now C tubes are placed. + // Check there is enough room in y-direction + bool IsLastRow_C = (-1. * y_backplane) - y_tube < y_pitch + tubeRadius ? true : false; + // Check there is enough room in x-direction to place a C tube after its S one + bool IsLastTube_C = -1. * x_backplane + delta_x - x_tube < tubeDiameter ? true : false; + + // After the S tube placement I place the closest C tube above it + // according to the fixed structure of the tubes placement (gluing) + // + // If the S tube below was not placed (too short) do not place the C either + // && if there is not enough room in x-direction do not place the C tube + // && if there is not enough room in y-direction do not place the C tube + if (capillaryLength > 5.0 * cm && !IsLastTube_C && !IsLastRow_C) { + double x_tube_C = x_tube + tubeRadius; + double y_tube_C = y_tube + y_pitch; + Vector3D capillaryPos_C(x_tube_C, y_tube_C, length / 2.); + auto capillaryLength_C = Helper.GetTubeLength(pt, capillaryPos_C); + if (std::fabs(capillaryLength_C - length) < 0.0001 * mm) { + PlacedVolume capillaryPlaced_C = towerLog.placeVolume(capillary_CLog, CalcCpNo32bits(j,k), + Position(x_tube_C, y_tube_C, 0.)); + capillaryPlaced_C.addPhysVolID("row", k).addPhysVolID("col", j); +#ifdef COUNTTUBES + tubeNo++; + totalTubeLength += tower_height; +#endif + } + else if (capillaryLength_C > 5.0 * cm) { + Tube capillaryShort_C(0. * mm, tubeRadius, (capillaryLength_C - TubeLengthOffset) / 2., + 2 * M_PI); // reduced capillary length + // by a fixed offset + Volume capillaryShortLog_C( + "capillaryShortLog_C", capillaryShort_C, + description.material(x_capillary_C.attr(_U(material)))); + capillaryShortLog_C.setVisAttributes(description, x_capillary_C.visStr()); + + Tube cladShort_C(0. * mm, cladRadius, (capillaryLength_C - TubeLengthOffset) / 2., + 2 * M_PI); // cladding C + Volume cladShort_CLog("DRETScladShort_CLog", cladShort_C, + description.material(x_clad_C.attr(_U(material)))); + cladShort_CLog.setVisAttributes(description, x_clad_C.visStr()); + if (x_clad_C_sens) cladShort_CLog.setSensitiveDetector(sens); + PlacedVolume cladShort_CPlaced = + capillaryShortLog_C.placeVolume(cladShort_CLog, 1, Position(0., 0., 0.)); + cladShort_CPlaced.addPhysVolID("clad", 1); + Tube coreShort_C(0. * mm, coreRadius, (capillaryLength_C - TubeLengthOffset) / 2., + 2 * M_PI); // core C + Volume coreShort_CLog("DRETScoreCShort_Log", coreShort_C, + description.material(x_core_C.attr(_U(material)))); + coreShort_CLog.setVisAttributes(description, x_core_C.visStr()); + if (x_core_C_sens) coreShort_CLog.setSensitiveDetector(sens); + PlacedVolume coreShort_CPlaced = cladShort_CLog.placeVolume(coreShort_CLog, CalcCpNo2bits(1,1)); + coreShort_CPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 1); + + PlacedVolume capillaryShortPlaced_C = towerLog.placeVolume( + capillaryShortLog_C, CalcCpNo32bits(j,k), + Position(x_tube_C, y_tube_C, + length / 2. - capillaryLength_C / 2. + TubeLengthOffset / 2.)); + capillaryShortPlaced_C.addPhysVolID("row", k).addPhysVolID("col", j); +#ifdef COUNTTUBES + tubeNo++; + totalTubeLength += capillaryLength_C; // neglecting the offset +#endif + } + else { + ; + } + } + + // condition for stopping S capillary placement along x + if (-1. * x_backplane + delta_x - x_tube < tubeDiameter + tubeRadius) break; + } // end x loop + + // Condition for stopping S capillary placement along y. + // y_backplane is equal up and down so I can keep the same for exiting loop + if ((-1. * y_backplane) - y_tube < (2. * y_pitch + tubeRadius)) break; + } // End y loop and tube placement + + // Update parameters + Helper.Getpt(pt); + fulltheta = fulltheta - deltatheta_endcap[i]; +#ifdef COUNTTUBES + totalTubeNo += tubeNo; + std::cout << " with " << tubeNo << " tubes" << std::endl; +#endif + } // End of towers creation and placement + +#ifdef COUNTTUBES + std::cout << "--> DREndcapTubes: number of tubes per stave/phi-slice " << totalTubeNo + << std::endl; + std::cout << "--> DREndcapTubes: number of tubes for both endcaps " << totalTubeNo * NbOfZRot * 2 + << " and total length " << (NbOfZRot * 2 * totalTubeLength) / km << " km" << std::endl; +#endif + + // Create a (DetElement) corresponding to MyDetector. + // From DD4hep docs + // https://dd4hep.web.cern.ch/dd4hep/usermanuals/DD4hepManual/DD4hepManualch2.html "Construct the + // main detector element of this subdetector.This will be the unique entry point to access any + // information of the subdetector." + DetElement sdet(det_name, x_det.id()); + // Then "Place the subdetector envelope into its mother (typically the top level (world) volume)." + Volume motherVolume = description.pickMotherVolume(sdet); + // Place the assembly container inside the mother volume + PlacedVolume AssemblyEndcapPV = motherVolume.placeVolume(AssemblyEndcap); + sdet.setPlacement(AssemblyEndcapPV); + + std::cout << "--> DREndcapTubes::create_detector() end" << std::endl; + + return sdet; +} + +DECLARE_DETELEMENT(DREndcapTubes, create_detector) + +//************************************************************************** From d94d8eca1a6b4b18f5a992501fc41b4f0affeb05 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Sun, 27 Oct 2024 16:48:07 +0100 Subject: [PATCH 100/133] Add IDEA_o2_v01.xml file Add xml description file for IDEA_o2_v01. It includes the dual-readout-tubes endcap calorimeter. As this option will include a crystal em-section, the preshower is removed from the xml file. --- .../IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 319 +++++++ .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 105 +++ FCCee/IDEA/compact/IDEA_o2_v01/elements.xml | 884 ++++++++++++++++++ FCCee/IDEA/compact/README.md | 7 + 4 files changed, 1315 insertions(+) create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/elements.xml diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml new file mode 100644 index 000000000..9671925a4 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -0,0 +1,319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1 + + + + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml new file mode 100644 index 000000000..e29092eb7 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -0,0 +1,105 @@ + + + + + + + + Version o2_v01 of the IDEA detector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml b/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml new file mode 100644 index 000000000..f35eb3454 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml @@ -0,0 +1,884 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/IDEA/compact/README.md b/FCCee/IDEA/compact/README.md index e5ebd2add..1a64df13e 100644 --- a/FCCee/IDEA/compact/README.md +++ b/FCCee/IDEA/compact/README.md @@ -25,3 +25,10 @@ August 2024: Added an updated vertex detector (also with the ultra-light inner v implementation of the silicon wrapper. September 2024: Added detailed version of the pre-shower, based on muon system builder. + +IDEA_o2_v01 +------------ + +Second option of IDEA detector. The inner part up to the drift-chamber is identical to IDEA_o1, the dual-readout calorimeter uses the INFN capillary-tubes technology and replaces the monolithic calorimeter description. Between the drift-chamber and the dual-readout calorimeter a dual-readout crystal electromagnetic calorimeter is will place, consequentially the preshower is removed. The muon system is identical to IDEA_o1. + +October 2024: first implementation using the dual-readout capillary-tubes endcap geometry. From 07eea7c41bb917b1d8268e4c6f358f25acb86400 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 18 Nov 2024 17:30:23 +0100 Subject: [PATCH 101/133] Add DRTubesSDAction Add DRTubesSDAction as in lopezzot/DREndcapTube v0.3. Comment out RunAction and EventAction classes which are not needed for execution inside k4geo. File name changed from DREndcapTubesSDAction to DRTubesSDAction as this SDAction code will be used for DR barrel detector using capillary tubes. --- CMakeLists.txt | 2 + plugins/DRTubesSDAction.cpp | 291 ++++++++++++++++++++++++++++++++++++ plugins/DRTubesSglHpr.hh | 178 ++++++++++++++++++++++ 3 files changed, 471 insertions(+) create mode 100644 plugins/DRTubesSDAction.cpp create mode 100644 plugins/DRTubesSglHpr.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 811779559..e6f765ad1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,8 @@ file(GLOB G4sources ./plugins/Geant4Output2EDM4hep_DRC.cpp ./plugins/DRCaloFastSimModel.cpp ./plugins/DRCaloFastSimModel.h + ./plugins/DRTubesSDAction.hh + ./plugins/DRTubesSDAction.cpp ) if(DD4HEP_USE_PYROOT) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp new file mode 100644 index 000000000..ba238f15d --- /dev/null +++ b/plugins/DRTubesSDAction.cpp @@ -0,0 +1,291 @@ +//************************************************************************** +// \file DRTubesSDAction.cpp +// \brief: Implementation of Geant4SensitiveAction template class for +// dual-readout-tubes calorimeters +// \author: Lorenzo Pezzotti (CERN) @lopezzot +// \start date: 11 August 2024 +//************************************************************************** + +// Includers from DD4HEP +#include "DD4hep/Segmentations.h" +#include "DD4hep/Version.h" +#include "DDG4/Factories.h" +#include "DDG4/Geant4EventAction.h" +#include "DDG4/Geant4GeneratorAction.h" +#include "DDG4/Geant4Mapping.h" +#include "DDG4/Geant4RunAction.h" +#include "DDG4/Geant4SensDetAction.inl" + +// Includers from Geant4 +#include "G4OpBoundaryProcess.hh" +#include "G4OpticalPhoton.hh" +#include "G4Poisson.hh" +#include "G4ProcessManager.hh" +#include "G4Types.hh" +#include "G4UserSteppingAction.hh" +#include "G4VProcess.hh" +#include "globals.hh" + +// Includers from project files +#include "DRTubesSglHpr.hh" + +// #define DREndcapTubesSDDebug + +namespace dd4hep +{ +namespace sim +{ +class DREndcapTubesSDData +{ + // Constructor and destructor + // + public: + DREndcapTubesSDData() = default; + ~DREndcapTubesSDData() = default; + + // Methods + // + public: + //void beginRun(const G4Run* run) + //{ + //fRunAction = new DREndcapTubesRunAction; + //fEvtAction = new DREndcapTubesEvtAction; + //fRunAction->BeginOfRunAction(run); + //} + + //void endRun(const G4Run* run) { fRunAction->EndOfRunAction(run); } + + //void beginEvent(const G4Event* event) { fEvtAction->BeginOfEventAction(event); } + + //void endEvent(const G4Event* event) { fEvtAction->EndOfEventAction(event); } + + // Fields + // + public: + //DREndcapTubesRunAction* fRunAction; + //DREndcapTubesEvtAction* fEvtAction; + Geant4Sensitive* sensitive{}; + int collection_cher_right; + int collection_cher_left; + int collection_scin_left; +}; +} // namespace sim +} // namespace dd4hep + +namespace dd4hep +{ +namespace sim +{ + +// Function template specialization of Geant4SensitiveAction class. +// Define actions +template<> +void Geant4SensitiveAction::initialize() +{ + //eventAction().callAtBegin(&m_userData, &DREndcapTubesSDData::beginEvent); + //eventAction().callAtEnd(&m_userData, &DREndcapTubesSDData::endEvent); + + //runAction().callAtBegin(&m_userData, &DREndcapTubesSDData::beginRun); + //runAction().callAtEnd(&m_userData, &DREndcapTubesSDData::endRun); + + m_userData.sensitive = this; +} + +// Function template specialization of Geant4SensitiveAction class. +// Define collections created by this sensitivie action object +template<> +void Geant4SensitiveAction::defineCollections() +{ + std::string ROname = m_sensitive.readout().name(); + m_collectionID = defineCollection(ROname + "ScinRight"); + m_userData.collection_cher_right = defineCollection(ROname + "CherRight"); + m_userData.collection_scin_left = defineCollection(ROname + "ScinLeft"); + m_userData.collection_cher_left = defineCollection(ROname + "CherLeft"); +} + +// Function template specialization of Geant4SensitiveAction class. +// Method that accesses the G4Step object at each track step. +template<> +bool Geant4SensitiveAction::process(const G4Step* aStep, + G4TouchableHistory* /*history*/) +{ + // NOTE: Here we do manipulation of the signal in each fiber (Scintillating and Cherenkov) + // to compute the calorimeter signal and populate the corresponding hit. + // Sensitive volumes are associated in the steering file using the DD4hep regexSensitiveDetector + // and matching the substring DRETS. Usually DD4hep volIDs are retrieved with something like this + // --- + // dd4hep::BitFieldCoder + // decoder("stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1"); + // auto VolID = volumeID(aStep); auto CherenkovID = decoder.get(VolID,"cherenkov"); + // --- + // However using regexSensitiveDetector does not populate the cache that allows using the + // volumeID() method. One can still access volIDs in this sensitive detector action with something + // like this + // --- + // G4VPhysicalVolume* PhysVol = aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume(); + // Geant4Mapping& Mapping = Geant4Mapping::instance(); + // PlacedVolume PlacedVol = Mapping.placement(PhysVol); + // const PlacedVolumeExtension::VolIDs& TestIDs = PlacedVol.volIDs(); + // auto it = TestIDs.find("name"); + // std::cout<first<<" "<second<GetTotalEnergyDeposit(); + auto cpNo = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(); + // The second bit of the CopyNumber corresponds to the "core" entry: + // 1 if the step is in the fiber core (S or C) and 0 if it is + // in the fiber cladding (C only) + unsigned int CoreID = (cpNo & 0b10) >> 1; // take CpNo 2nd bit + bool IsCherClad = (CoreID == 0); + // The first bit of the CopyNumber corresponds to the "cherenkov" entry + // 1 for C fibers and 0 for S fibers + unsigned int CherenkovID = cpNo & 0b1; + bool IsScin = (CherenkovID == 0); + // Skip this step if edep is 0 and it is a scintillating fiber + if (IsScin && Edep == 0.) return true; + // If it is a track inside the cherenkov CLADDING skip this step, + // if it is an optical photon kill it first + if (IsCherClad) { + if (aStep->GetTrack()->GetParticleDefinition() == G4OpticalPhoton::Definition()) { + aStep->GetTrack()->SetTrackStatus(fStopAndKill); + } + return true; + } + + // Now we are inside fibers' core volume (either Scintillating or Cherenkov) + + // We recreate the TubeID from the tube copynumber: + // fist16 bits for the columnID and second 16 bits for the rowID + auto TubeID = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(2); + unsigned int ColumnID = TubeID >> 16; + unsigned int RawID = TubeID & 0xFFFF; + auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3)); + auto StaveID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); + + VolumeID VolID = 0; // recreate the 64-bit VolumeID + BitFieldCoder bc("stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1"); + bc.set(VolID, "stave" , StaveID); + bc.set(VolID, "tower" , TowerID); + bc.set(VolID, "air", 0); + bc.set(VolID, "col", ColumnID); + bc.set(VolID, "row", RawID); + bc.set(VolID, "clad", 1); + bc.set(VolID, "core", CoreID); + bc.set(VolID, "cherenkov", CherenkovID); + + bool IsRight = (aStep->GetPreStepPoint()->GetPosition().z() > 0.); + + // We now calculate the signal in S and C fiber according to the step contribution + // + G4double steplength = aStep->GetStepLength(); + G4int signalhit = 0; + Geant4HitCollection* coll = (IsRight && IsScin) ? collection(m_collectionID) + : (IsRight && !IsScin) ? collection(m_userData.collection_cher_right) + : (!IsRight && IsScin) ? collection(m_userData.collection_scin_left) + : collection(m_userData.collection_cher_left); + + if (IsScin) { // it is a scintillating fiber + + //m_userData.fEvtAction->AddEdepScin(Edep); + + if (aStep->GetTrack()->GetDefinition()->GetPDGCharge() == 0 || steplength == 0.) { + return true; // not ionizing particle + } + G4double distance_to_sipm = DRTubesSglHpr::GetDistanceToSiPM(aStep); + signalhit = + DRTubesSglHpr::SmearSSignal(DRTubesSglHpr::ApplyBirks(Edep, steplength)); + signalhit = DRTubesSglHpr::AttenuateSSignal(signalhit, distance_to_sipm); + if (signalhit == 0) return true; + //m_userData.fEvtAction->AddSglScin(signalhit); + } // end of scintillating fibre sigal calculation + + else { // it is a Cherenkov fiber + // save mc truth info in analysismanager auxiliary outputfile + //m_userData.fEvtAction->AddEdepCher(Edep); + // calculate the signal in terms of Cherenkov photo-electrons + if (aStep->GetTrack()->GetParticleDefinition() == G4OpticalPhoton::Definition()) { + G4OpBoundaryProcessStatus theStatus = Undefined; + G4ProcessManager* OpManager = G4OpticalPhoton::OpticalPhoton()->GetProcessManager(); + + if (OpManager) { + G4int MAXofPostStepLoops = OpManager->GetPostStepProcessVector()->entries(); + G4ProcessVector* fPostStepDoItVector = OpManager->GetPostStepProcessVector(typeDoIt); + + for (G4int i = 0; i < MAXofPostStepLoops; i++) { + G4VProcess* fCurrentProcess = (*fPostStepDoItVector)[i]; + G4OpBoundaryProcess* fOpProcess = dynamic_cast(fCurrentProcess); + if (fOpProcess) { + theStatus = fOpProcess->GetStatus(); + break; + } + } + } + + switch (theStatus) { + case TotalInternalReflection: { + // Kill Cherenkov photons inside fibers travelling towards the inner tip + if (!DRTubesSglHpr::IsReflectedForward(aStep)) return true; + G4double distance_to_sipm = DRTubesSglHpr::GetDistanceToSiPM(aStep); + G4int c_signal = DRTubesSglHpr::SmearCSignal(); + signalhit = DRTubesSglHpr::AttenuateCSignal(c_signal, distance_to_sipm); + if (signalhit == 0) return true; + // save mc truth info in analysismanager auxiliary outputfile + //m_userData.fEvtAction->AddSglCher(signalhit); + aStep->GetTrack()->SetTrackStatus(fStopAndKill); + break; + } + default: + aStep->GetTrack()->SetTrackStatus(fStopAndKill); + return true; + } // end of swich cases + } // end of optical photon + else { + return true; + } + } // end of Cherenkov fiber + + // We are going to create an hit per each fiber with a signal above 0 + // Each fiber is identified with a unique volID + // + Geant4Calorimeter::Hit* hit = coll->findByKey(VolID); // the hit + if (!hit) { // if the hit does not exist yet, create it + hit = new Geant4Calorimeter::Hit(); + hit->cellID = VolID; // this should be assigned only once + G4ThreeVector FiberVec = DRTubesSglHpr::CalculateFiberPosition(aStep); + Position FiberPos(FiberVec.x(), FiberVec.y(), FiberVec.z()); + hit->position = FiberPos; // this should be assigned only once + // Note, when the hit is saved in edm4hep format the energyDeposit is + // divided by 1000, i.e. it translates from MeV (Geant4 unit) to GeV (DD4hep unit). + // Here I am using this field to save photo-electrons, so I multiply it by 1000 + hit->energyDeposit = signalhit * 1000; + coll->add(VolID, hit); // add the hit to the hit collection + } + else { // if the hit exists already, increment its fields + hit->energyDeposit += signalhit * 1000; + } + return true; +} // end of Geant4SensitiveAction::process() method specialization + +} // namespace sim +} // namespace dd4hep + +//--- Factory declaration +namespace dd4hep +{ +namespace sim +{ +typedef Geant4SensitiveAction DREndcapTubesSDAction; +} +} // namespace dd4hep +DECLARE_GEANT4SENSITIVE(DREndcapTubesSDAction) + +//************************************************************************** diff --git a/plugins/DRTubesSglHpr.hh b/plugins/DRTubesSglHpr.hh new file mode 100644 index 000000000..6baa3fc10 --- /dev/null +++ b/plugins/DRTubesSglHpr.hh @@ -0,0 +1,178 @@ +//************************************************************************** +// \file DRTubesSglHpr.hh +// \brief: definition of DRTubesSglHpr class +// \author: Lorenzo Pezzotti (CERN) @lopezzot +// \start date: 13 August 2024 +//************************************************************************** + +// Header-only utility class to store methods needed when computing +// the DREndcapTubes signals in scintillating and Cherenkov fibers + +#ifndef DRTubesSglHpr_h +# define DRTubesSglHpr_h 1 + +// Includers from Geant4 +// +# include "G4Tubs.hh" +# include "globals.hh" + +# include "CLHEP/Units/SystemOfUnits.h" + +class DRTubesSglHpr +{ + public: + DRTubesSglHpr() = delete; + + private: + // Fields + // + static constexpr G4double fk_B = 0.126; // Birks constant + static constexpr G4double fSAttenuationLength = 1000.0 * CLHEP::m; + static constexpr G4double fCAttenuationLength = 1000.0 * CLHEP::m; + + public: + // Methods + // + // Apply Briks Law + static constexpr G4double ApplyBirks(const G4double& de, const G4double& steplength) + { + return (de / steplength) / (1 + fk_B * (de / steplength)) * steplength; + } + + // Smear S signal according to Poissonian fluctuations and light yield + static G4int SmearSSignal(const G4double& satde) { return G4Poisson(satde * 9.5); } + + // Smear C signal according to Poissonian fluctuations and light yield + static G4int SmearCSignal() { return G4Poisson(0.177); } + + // Calculate distance from step in fiber to SiPM + inline static G4double GetDistanceToSiPM(const G4Step* step, bool prestep); + static G4double GetDistanceToSiPM(const G4Step* step) { return GetDistanceToSiPM(step, true); } + + // Calculate how many photons survived after light attenuation + inline static G4int AttenuateHelper(const G4int& signal, const G4double& distance, + const G4double& attenuation_length); + + // Attenuate light in fibers + static G4int AttenuateSSignal(const G4int& signal, const G4double& distance) + { + return AttenuateHelper(signal, distance, fSAttenuationLength); + } + + static G4int AttenuateCSignal(const G4int& signal, const G4double& distance) + { + return AttenuateHelper(signal, distance, fCAttenuationLength); + } + + inline static G4ThreeVector CalculateFiberPosition(const G4Step* step); + + // Check if photon is travelling towards SiPM + inline static bool IsReflectedForward(const G4Step* step); + + // Print step info for debugging purposes + inline static void PrintStepInfo(const G4Step* aStep); +}; + +inline G4double DRTubesSglHpr::GetDistanceToSiPM(const G4Step* step, bool prestep) +{ + // Get the pre-step point + const G4StepPoint* StepPoint = prestep ? step->GetPreStepPoint() : step->GetPostStepPoint(); + // Get the global position of the step point + G4ThreeVector globalPos = StepPoint->GetPosition(); + // Get the local position of the step point in the current volume's coordinate system + G4ThreeVector localPos = + StepPoint->GetTouchableHandle()->GetHistory()->GetTopTransform().TransformPoint(globalPos); + + // Get the logical volume of the current step + G4LogicalVolume* currentVolume = StepPoint->GetTouchableHandle()->GetVolume()->GetLogicalVolume(); + // Get the solid associated with the logical volume + G4Tubs* solid = dynamic_cast(currentVolume->GetSolid()); + // Get the dimensions of the solid (size of the volume) + G4double size = solid->GetZHalfLength(); + + G4double distance_to_sipm = size - localPos.z(); + return distance_to_sipm; +} + +inline G4int DRTubesSglHpr::AttenuateHelper(const G4int& signal, const G4double& distance, + const G4double& attenuation_length) +{ + double probability_of_survival = exp(-distance / attenuation_length); + + G4int survived_photons = 0; + for (int i = 0; i < signal; i++) { + // Simulate drawing between 0 and 1 with probability x of getting 1 + if (G4UniformRand() <= probability_of_survival) survived_photons++; + } + return survived_photons; +} + +inline G4ThreeVector DRTubesSglHpr::CalculateFiberPosition(const G4Step* step) +{ + G4TouchableHandle theTouchable = step->GetPreStepPoint()->GetTouchableHandle(); + G4ThreeVector origin(0., 0., 0.); + G4ThreeVector zdir(0., 0., 1.); + G4ThreeVector vectPos = + theTouchable->GetHistory()->GetTopTransform().Inverse().TransformPoint(origin); + G4ThreeVector direction = + theTouchable->GetHistory()->GetTopTransform().Inverse().TransformAxis(zdir); + + // Get the logical volume of the current step + G4LogicalVolume* currentVolume = + step->GetPreStepPoint()->GetTouchableHandle()->GetVolume()->GetLogicalVolume(); + // Get the solid associated with the logical volume + G4Tubs* solid = dynamic_cast(currentVolume->GetSolid()); + // Get the dimensions of the solid (size of the volume) + G4double size = solid->GetZHalfLength(); + G4double lengthfiber = size * 2.; + G4ThreeVector Halffibervect = direction * lengthfiber / 2; + // Fibre tip position + G4ThreeVector vectPostip = vectPos - Halffibervect; + // SiPM position + // G4ThreeVector SiPMvecPos = vectPos + Halffibervect; + + return vectPostip; +} + +// Check if photon is travelling towards SiPM +// If a (Cherenkov) photon is internally reflected in fibers +// it might travel towards the SiPM or the inner finer tip. +// As we do not consider reflections at the inner fiber tip +// photons travelling backwards should be killed. +inline bool DRTubesSglHpr::IsReflectedForward(const G4Step* step) +{ + double PreStepDistance = GetDistanceToSiPM(step, true); + double PostStepDistance = GetDistanceToSiPM(step, false); + bool IsReflectedForward = (PostStepDistance < PreStepDistance) ? true : false; + return IsReflectedForward; +} + +inline void DRTubesSglHpr::PrintStepInfo(const G4Step* aStep) +{ + std::cout << "-------------------------------" << std::endl; + std::cout << "--> DREndcapTubes: track info: " << std::endl; + std::cout << "----> Track #: " << aStep->GetTrack()->GetTrackID() << " " + << "Step #: " << aStep->GetTrack()->GetCurrentStepNumber() << " " + << "Volume: " << aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume()->GetName() + << " " << std::endl; + std::cout << "--> DREndcapTubes:: position info(mm): " << std::endl; + std::cout << "----> x: " << aStep->GetPreStepPoint()->GetPosition().x() + << " y: " << aStep->GetPreStepPoint()->GetPosition().y() + << " z: " << aStep->GetPreStepPoint()->GetPosition().z() << std::endl; + std::cout << "--> DREndcapTubes: particle info: " << std::endl; + std::cout << "----> Particle " << aStep->GetTrack()->GetParticleDefinition()->GetParticleName() + << " " + << "Dep(MeV) " << aStep->GetTotalEnergyDeposit() << " " + << "Mat " << aStep->GetPreStepPoint()->GetMaterial()->GetName() << " " + << "Vol " << aStep->GetPreStepPoint()->GetTouchableHandle()->GetVolume()->GetName() + << " " + << "CpNo " << aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber() << " " + << "CpNo1 " << aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(1) << " " + << "CpNo2 " << aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(2) << " " + << "CpNo3 " << aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3) << " " + << "CpNo4 " << aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4) << std::endl; +} + +#endif // DRTubesSglHpr_h + +//************************************************************************** From 57f10aac9b7f3e55246208023e4599cca42ff72a Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 19 Nov 2024 13:54:50 +0100 Subject: [PATCH 102/133] Rename DREndcapTubesSDData Rename DREndcapTubesSDData to DRTubesSDData as DRTubesSDAction will be common for endcap and barrel tubes calorimeter. Also typedef to DRTubesSDAction. --- plugins/DRTubesSDAction.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index ba238f15d..f88c0ce7b 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -29,19 +29,19 @@ // Includers from project files #include "DRTubesSglHpr.hh" -// #define DREndcapTubesSDDebug +// #define DRTubesSDDebug namespace dd4hep { namespace sim { -class DREndcapTubesSDData +class DRTubesSDData { // Constructor and destructor // public: - DREndcapTubesSDData() = default; - ~DREndcapTubesSDData() = default; + DRTubesSDData() = default; + ~DRTubesSDData() = default; // Methods // @@ -80,7 +80,7 @@ namespace sim // Function template specialization of Geant4SensitiveAction class. // Define actions template<> -void Geant4SensitiveAction::initialize() +void Geant4SensitiveAction::initialize() { //eventAction().callAtBegin(&m_userData, &DREndcapTubesSDData::beginEvent); //eventAction().callAtEnd(&m_userData, &DREndcapTubesSDData::endEvent); @@ -94,7 +94,7 @@ void Geant4SensitiveAction::initialize() // Function template specialization of Geant4SensitiveAction class. // Define collections created by this sensitivie action object template<> -void Geant4SensitiveAction::defineCollections() +void Geant4SensitiveAction::defineCollections() { std::string ROname = m_sensitive.readout().name(); m_collectionID = defineCollection(ROname + "ScinRight"); @@ -106,7 +106,7 @@ void Geant4SensitiveAction::defineCollections() // Function template specialization of Geant4SensitiveAction class. // Method that accesses the G4Step object at each track step. template<> -bool Geant4SensitiveAction::process(const G4Step* aStep, +bool Geant4SensitiveAction::process(const G4Step* aStep, G4TouchableHistory* /*history*/) { // NOTE: Here we do manipulation of the signal in each fiber (Scintillating and Cherenkov) @@ -133,7 +133,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // (see https://github.com/AIDASoft/DD4hep/issues/1319). // Therefore we use copynumbers instead of volIDs. -#ifdef DREndcapTubesSDDebug +#ifdef DRTubesSDDebug // Print out some info step-by-step in sensitive volumes // DRTubesSglHpr::PrintStepInfo(aStep); @@ -283,9 +283,9 @@ namespace dd4hep { namespace sim { -typedef Geant4SensitiveAction DREndcapTubesSDAction; +typedef Geant4SensitiveAction DRTubesSDAction; } } // namespace dd4hep -DECLARE_GEANT4SENSITIVE(DREndcapTubesSDAction) +DECLARE_GEANT4SENSITIVE(DRTubesSDAction) //************************************************************************** From bea4bb8a0e482eb52dd6f6fe002e14dc298f862b Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 19 Nov 2024 13:57:56 +0100 Subject: [PATCH 103/133] Rm RunAction and EventAction from DRTubesSDAction RunAction and EventAction will not be used in key4geo simulation. They were used in standalone simulation to produced plain root files with G4AnalysisManager. --- plugins/DRTubesSDAction.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index f88c0ce7b..8c38b30f9 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -43,27 +43,9 @@ class DRTubesSDData DRTubesSDData() = default; ~DRTubesSDData() = default; - // Methods - // - public: - //void beginRun(const G4Run* run) - //{ - //fRunAction = new DREndcapTubesRunAction; - //fEvtAction = new DREndcapTubesEvtAction; - //fRunAction->BeginOfRunAction(run); - //} - - //void endRun(const G4Run* run) { fRunAction->EndOfRunAction(run); } - - //void beginEvent(const G4Event* event) { fEvtAction->BeginOfEventAction(event); } - - //void endEvent(const G4Event* event) { fEvtAction->EndOfEventAction(event); } - // Fields // public: - //DREndcapTubesRunAction* fRunAction; - //DREndcapTubesEvtAction* fEvtAction; Geant4Sensitive* sensitive{}; int collection_cher_right; int collection_cher_left; @@ -82,12 +64,6 @@ namespace sim template<> void Geant4SensitiveAction::initialize() { - //eventAction().callAtBegin(&m_userData, &DREndcapTubesSDData::beginEvent); - //eventAction().callAtEnd(&m_userData, &DREndcapTubesSDData::endEvent); - - //runAction().callAtBegin(&m_userData, &DREndcapTubesSDData::beginRun); - //runAction().callAtEnd(&m_userData, &DREndcapTubesSDData::endRun); - m_userData.sensitive = this; } From 9ff4a17f3cf2d53a04abdaa44ae49fbc8ce920b6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 19 Nov 2024 15:50:43 +0100 Subject: [PATCH 104/133] Add example SteeringFile for IDEA_o2 Same as SteeringFile_IDEA_o1_v03.py file but lines for DRC have been removed and those specific for the DRTubes subdetector have been added (e.g. regexSD). --- example/SteeringFile_IDEA_o2_v01.py | 646 ++++++++++++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 example/SteeringFile_IDEA_o2_v01.py diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py new file mode 100644 index 000000000..3c3dbe361 --- /dev/null +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -0,0 +1,646 @@ +from DDSim.DD4hepSimulation import DD4hepSimulation +from g4units import mm, GeV, MeV + +SIM = DD4hepSimulation() + +## The compact XML file, or multiple compact files, if the last one is the closer. +SIM.compactFile = ["../FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml"] +## Lorentz boost for the crossing angle, in radian! +SIM.crossingAngleBoost = 0.0 +SIM.enableDetailedShowerMode = False +SIM.enableG4GPS = False +SIM.enableG4Gun = False +SIM.enableGun = True +## InputFiles for simulation .stdhep, .slcio, .HEPEvt, .hepevt, .pairs, .hepmc, .hepmc.gz, .hepmc.xz, .hepmc.bz2, .hepmc3, .hepmc3.gz, .hepmc3.xz, .hepmc3.bz2, .hepmc3.tree.root files are supported +SIM.inputFiles = [] +## Macro file to execute for runType 'run' or 'vis' +SIM.macroFile = "" +## number of events to simulate, used in batch mode +SIM.numberOfEvents = 100 +## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported +SIM.outputFile = "IDEA_o2_v01.root" +## Physics list to use in simulation +SIM.physicsList = None +## Verbosity use integers from 1(most) to 7(least) verbose +## or strings: VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL, ALWAYS +SIM.printLevel = 3 +## The type of action to do in this invocation +## batch: just simulate some events, needs numberOfEvents, and input file or gun +## vis: enable visualisation, run the macroFile if it is set +## qt: enable visualisation in Qt shell, run the macroFile if it is set +## run: run the macroFile and exit +## shell: enable interactive session +SIM.runType = "batch" +## Skip first N events when reading a file +SIM.skipNEvents = 0 +## Steering file to change default behaviour +SIM.steeringFile = None +## FourVector of translation for the Smearing of the Vertex position: x y z t +SIM.vertexOffset = [0.0, 0.0, 0.0, 0.0] +## FourVector of the Sigma for the Smearing of the Vertex position: x y z t +SIM.vertexSigma = [0.0, 0.0, 0.0, 0.0] + + +################################################################################ +## Helper holding sensitive detector and other actions. +## +## The default tracker and calorimeter sensitive actions can be set with +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.tracker=('Geant4TrackerWeightedAction', {'HitPositionCombination': 2, 'CollectSingleDeposits': False}) +## >>> SIM.action.calo = "Geant4CalorimeterAction" +## +## The default sensitive actions for calorimeters and trackers are applied based on the sensitive type. +## The list of sensitive types can be changed with +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.trackerSDTypes = ['tracker', 'myTrackerSensType'] +## >>> SIM.calor.calorimeterSDTypes = ['calorimeter', 'myCaloSensType'] +## +## For specific subdetectors specific sensitive detectors can be set based on patterns in the name of the subdetector. +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.mapActions['tpc'] = "TPCSDAction" +## +## and additional parameters for the sensitive detectors can be set when the map is given a tuple +## +## >>> SIM = DD4hepSimulation() +## >>> SIM.action.mapActions['ecal'] =( "CaloPreShowerSDAction", {"FirstLayerNumber": 1} ) +## +## Additional actions can be set as well with the following syntax variations: +## +## >>> SIM = DD4hepSimulation() +## # single action by name only: +## >>> SIM.action.run = "Geant4TestRunAction" +## # multiple actions with comma-separated names: +## >>> SIM.action.event = "Geant4TestEventAction/Action0,Geant4TestEventAction/Action1" +## # single action by tuple of name and parameter dict: +## >>> SIM.action.track = ( "Geant4TestTrackAction", {"Property_int": 10} ) +## # single action by dict of name and parameter dict: +## >>> SIM.action.step = { "name": "Geant4TestStepAction", "parameter": {"Property_int": 10} } +## # multiple actions by list of dict of name and parameter dict: +## >>> SIM.action.stack = [ { "name": "Geant4TestStackAction", "parameter": {"Property_int": 10} } ] +## +## On the command line or in python, these actions can be specified as JSON strings: +## $ ddsim --action.stack '{ "name": "Geant4TestStackAction", "parameter": { "Property_int": 10 } }' +## or +## >>> SIM.action.stack = ''' +## { +## "name": "Geant4TestStackAction", +## "parameter": { +## "Property_int": 10, +## "Property_double": "1.0*mm" +## } +## } +## ''' +## +## +################################################################################ + +SIM.action.calo = "DRTubesSDAction" +SIM.action.calorimeterSDTypes = [u'calorimeter'] +SIM.action.mapActions['DREndcapTubes'] = "DRTubesSDAction" +SIM.filter.calo = "" +# Configure the regexSD +SIM.geometry.regexSensitiveDetector['DREndcapTubes'] = {'Match': ['DRETS'], + 'OutputLevel': 4, + } + +## set the default run action +SIM.action.run = [] + +## set the default stack action +SIM.action.stack = [] + +## set the default step action +SIM.action.step = [] + +## set the default track action +SIM.action.track = [] + +## set the default tracker action +SIM.action.tracker = ( + "Geant4TrackerWeightedAction", + {"HitPositionCombination": 2, "CollectSingleDeposits": False}, +) + +## List of patterns matching sensitive detectors of type Tracker. +SIM.action.trackerSDTypes = ["tracker"] + + +################################################################################ +## Configuration for the magnetic field (stepper) +################################################################################ +SIM.field.delta_chord = 0.25 +SIM.field.delta_intersection = 0.001 +SIM.field.delta_one_step = 0.01 +SIM.field.eps_max = 0.001 +SIM.field.eps_min = 5e-05 +SIM.field.equation = "Mag_UsualEqRhs" +SIM.field.largest_step = 10000.0 +SIM.field.min_chord_step = 0.01 +SIM.field.stepper = "ClassicalRK4" + + +################################################################################ +## Configuration for sensitive detector filters +## +## Set the default filter for 'tracker' +## >>> SIM.filter.tracker = "edep1kev" +## Use no filter for 'calorimeter' by default +## >>> SIM.filter.calo = "" +## +## Assign a filter to a sensitive detector via pattern matching +## >>> SIM.filter.mapDetFilter['FTD'] = "edep1kev" +## +## Or more than one filter: +## >>> SIM.filter.mapDetFilter['FTD'] = ["edep1kev", "geantino"] +## +## Don't use the default filter or anything else: +## >>> SIM.filter.mapDetFilter['TPC'] = None ## or "" or [] +## +## Create a custom filter. The dictionary is used to instantiate the filter later on +## >>> SIM.filter.filters['edep3kev'] = dict(name="EnergyDepositMinimumCut/3keV", parameter={"Cut": 3.0*keV} ) +## +## +################################################################################ + +## +## default filter for calorimeter sensitive detectors; +## this is applied if no other filter is used for a calorimeter +## +SIM.filter.calo = "edep0" + +## list of filter objects: map between name and parameter dictionary +SIM.filter.filters = { + "geantino": {"name": "GeantinoRejectFilter/GeantinoRejector", "parameter": {}}, + "edep1kev": {"name": "EnergyDepositMinimumCut", "parameter": {"Cut": 0.001}}, + "edep0": {"name": "EnergyDepositMinimumCut/Cut0", "parameter": {"Cut": 0.0}}, +} + +## a map between patterns and filter objects, using patterns to attach filters to sensitive detector +SIM.filter.mapDetFilter = {} + +## default filter for tracking sensitive detectors; this is applied if no other filter is used for a tracker +SIM.filter.tracker = "edep1kev" + + +################################################################################ +## Configuration for the Detector Construction. +################################################################################ +SIM.geometry.dumpGDML = "" +SIM.geometry.dumpHierarchy = 0 + +## Print Debug information about Elements +SIM.geometry.enableDebugElements = False + +## Print Debug information about Materials +SIM.geometry.enableDebugMaterials = False + +## Print Debug information about Placements +SIM.geometry.enableDebugPlacements = False + +## Print Debug information about Reflections +SIM.geometry.enableDebugReflections = False + +## Print Debug information about Regions +SIM.geometry.enableDebugRegions = False + +## Print Debug information about Shapes +SIM.geometry.enableDebugShapes = False + +## Print Debug information about Surfaces +SIM.geometry.enableDebugSurfaces = False + +## Print Debug information about Volumes +SIM.geometry.enableDebugVolumes = False + +## Print information about placements +SIM.geometry.enablePrintPlacements = False + +## Print information about Sensitives +SIM.geometry.enablePrintSensitives = False + + +################################################################################ +## Configuration for the GuineaPig InputFiles +################################################################################ + +## Set the number of pair particles to simulate per event. +## Only used if inputFile ends with ".pairs" +## If "-1" all particles will be simulated in a single event +## +SIM.guineapig.particlesPerEvent = "-1" + + +################################################################################ +## Configuration for the DDG4 ParticleGun +################################################################################ + +## direction of the particle gun, 3 vector +SIM.gun.direction = (1.0, 1.0, 1.0) + +## choose the distribution of the random direction for theta +## +## Options for random distributions: +## +## 'uniform' is the default distribution, flat in theta +## 'cos(theta)' is flat in cos(theta) +## 'eta', or 'pseudorapidity' is flat in pseudorapity +## 'ffbar' is distributed according to 1+cos^2(theta) +## +## Setting a distribution will set isotrop = True +## +SIM.gun.distribution = None + +## Total energy (including mass) for the particle gun. +## +## If not None, it will overwrite the setting of momentumMin and momentumMax +SIM.gun.energy = None + +## Maximal pseudorapidity for random distibution (overrides thetaMin) +SIM.gun.etaMax = None + +## Minimal pseudorapidity for random distibution (overrides thetaMax) +SIM.gun.etaMin = None + +## isotropic distribution for the particle gun +## +## use the options phiMin, phiMax, thetaMin, and thetaMax to limit the range of randomly distributed directions +## if one of these options is not None the random distribution will be set to True and cannot be turned off! +## +SIM.gun.isotrop = False + +## Maximal momentum when using distribution (default = 0.0) +SIM.gun.momentumMax = 10000.0 + +## Minimal momentum when using distribution (default = 0.0) +SIM.gun.momentumMin = 0.0 +SIM.gun.multiplicity = 1 +SIM.gun.particle = "mu-" + +## Maximal azimuthal angle for random distribution +SIM.gun.phiMax = None + +## Minimal azimuthal angle for random distribution +SIM.gun.phiMin = None + +## position of the particle gun, 3 vector +SIM.gun.position = (0.0, 0.0, 0.0) + +## Maximal polar angle for random distribution +SIM.gun.thetaMax = None + +## Minimal polar angle for random distribution +SIM.gun.thetaMin = None + + +################################################################################ +## Configuration for the hepmc3 InputFiles +################################################################################ + +## Set the name of the attribute contraining color flow information index 0. +SIM.hepmc3.Flow1 = "flow1" + +## Set the name of the attribute contraining color flow information index 1. +SIM.hepmc3.Flow2 = "flow2" + +## Set to false if the input should be opened with the hepmc2 ascii reader. +## +## If ``True`` a '.hepmc' file will be opened with the HEPMC3 Reader Factory. +## +## Defaults to true if DD4hep was build with HEPMC3 support. +## +SIM.hepmc3.useHepMC3 = True + + +################################################################################ +## Configuration for Input Files. +################################################################################ + +## Set one or more functions to configure input steps. +## +## The functions must take a ``DD4hepSimulation`` object as their only argument and return the created generatorAction +## ``gen`` (for example). +## +## For example one can add this to the ddsim steering file: +## +## def exampleUserPlugin(dd4hepSimulation): +## '''Example code for user created plugin. +## +## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed +## :return: GeneratorAction +## ''' +## from DDG4 import GeneratorAction, Kernel +## # Geant4InputAction is the type of plugin, Cry1 just an identifier +## gen = GeneratorAction(Kernel(), 'Geant4InputAction/Cry1' , True) +## # CRYEventReader is the actual plugin, steeringFile its constructor parameter +## gen.Input = 'CRYEventReader|' + 'steeringFile' +## # we can give a dictionary of Parameters that has to be interpreted by the setParameters function of the plugin +## gen.Parameters = {'DataFilePath': '/path/to/files/data'} +## gen.enableUI() +## return gen +## +## SIM.inputConfig.userInputPlugin = exampleUserPlugin +## +## Repeat function definition and assignment to add multiple input steps +## +## +SIM.inputConfig.userInputPlugin = [] + + +################################################################################ +## Configuration for the generator-level InputFiles +################################################################################ + +## Set the name of the collection containing the MCParticle input. +## Default is "MCParticle". +## +SIM.lcio.mcParticleCollectionName = "MCParticle" + + +################################################################################ +## Configuration for the LCIO output file settings +################################################################################ + +## The event number offset to write in slcio output file. E.g setting it to 42 will start counting events from 42 instead of 0 +SIM.meta.eventNumberOffset = 0 + +## Event parameters to write in every event. Use C/F/I ids to specify parameter type. E.g parameterName/F=0.42 to set a float parameter +SIM.meta.eventParameters = [] + +## The run number offset to write in slcio output file. E.g setting it to 42 will start counting runs from 42 instead of 0 +SIM.meta.runNumberOffset = 0 + + +################################################################################ +## Configuration for the output levels of DDG4 components +################################################################################ + +## Output level for geometry. +SIM.output.geometry = 2 + +## Output level for input sources +SIM.output.inputStage = 3 + +## Output level for Geant4 kernel +SIM.output.kernel = 3 + +## Output level for ParticleHandler +SIM.output.part = 3 + +## Output level for Random Number Generator setup +SIM.output.random = 6 + + +################################################################################ +## Configuration for Output Files. +################################################################################ + +## Use the DD4HEP output plugin regardless of outputfilename. +SIM.outputConfig.forceDD4HEP = False + +## Use the EDM4HEP output plugin regardless of outputfilename. +SIM.outputConfig.forceEDM4HEP = False + +## Use the LCIO output plugin regardless of outputfilename. +SIM.outputConfig.forceLCIO = False + +## Set a function to configure the outputFile. +## +## The function must take a ``DD4hepSimulation`` object as its only argument and return ``None``. +## +## For example one can add this to the ddsim steering file: +## +## def exampleUserPlugin(dd4hepSimulation): +## '''Example code for user created plugin. +## +## :param DD4hepSimulation dd4hepSimulation: The DD4hepSimulation instance, so all parameters can be accessed +## :return: None +## ''' +## from DDG4 import EventAction, Kernel +## dd = dd4hepSimulation # just shorter variable name +## evt_root = EventAction(Kernel(), 'Geant4Output2ROOT/' + dd.outputFile, True) +## evt_root.HandleMCTruth = True or False +## evt_root.Control = True +## output = dd.outputFile +## if not dd.outputFile.endswith(dd.outputConfig.myExtension): +## output = dd.outputFile + dd.outputConfig.myExtension +## evt_root.Output = output +## evt_root.enableUI() +## Kernel().eventAction().add(evt_root) +## return None +## +## SIM.outputConfig.userOutputPlugin = exampleUserPlugin +## # arbitrary options can be created and set via the steering file or command line +## SIM.outputConfig.myExtension = '.csv' +## + + +################################################################################ +## Configuration for the Particle Handler/ MCTruth treatment +################################################################################ + +## Enable lots of printout on simulated hits and MC-truth information +SIM.part.enableDetailedHitsAndParticleInfo = False + +## Keep all created particles +SIM.part.keepAllParticles = False + +## Minimal distance between particle vertex and endpoint of parent after +## which the vertexIsNotEndpointOfParent flag is set +## +SIM.part.minDistToParentVertex = 2.2e-14 + +## MinimalKineticEnergy to store particles created in the tracking region +SIM.part.minimalKineticEnergy = 1.0 + +## Printout at End of Tracking +SIM.part.printEndTracking = False + +## Printout at Start of Tracking +SIM.part.printStartTracking = False + +## List of processes to save, on command line give as whitespace separated string in quotation marks +SIM.part.saveProcesses = ["Decay"] + +## Optionally enable an extended Particle Handler +SIM.part.userParticleHandler = "Geant4TCUserParticleHandler" + + +################################################################################ +## Configuration for the PhysicsList and Monte Carlo particle selection. +## +## To load arbitrary plugins, add a function to be executed. +## +## The function must take the DDG4.Kernel() object as the only argument. +## +## For example, add a function definition and the call to a steering file:: +## +## def setupCerenkov(kernel): +## from DDG4 import PhysicsList +## seq = kernel.physicsList() +## cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys') +## cerenkov.MaxNumPhotonsPerStep = 10 +## cerenkov.MaxBetaChangePerStep = 10.0 +## cerenkov.TrackSecondariesFirst = True +## cerenkov.VerboseLevel = 2 +## cerenkov.enableUI() +## seq.adopt(cerenkov) +## ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys') +## ph.addParticleConstructor('G4OpticalPhoton') +## ph.VerboseLevel = 2 +## ph.enableUI() +## seq.adopt(ph) +## return None +## +## SIM.physics.setupUserPhysics(setupCerenkov) +## +## # End of example +## +################################################################################ + +## Set of Generator Statuses that are used to mark unstable particles that should decay inside of Geant4. +## +SIM.physics.alternativeDecayStatuses = set() + +## If true, add decay processes for all particles. +## +## Only enable when creating a physics list not based on an existing Geant4 list! +## +SIM.physics.decays = False + +## The name of the Geant4 Physics list. +SIM.physics.list = "FTFP_BERT" + +## location of particle.tbl file containing extra particles and their lifetime information +## +## For example in $DD4HEP/examples/DDG4/examples/particle.tbl +## +SIM.physics.pdgfile = None + +## The global geant4 rangecut for secondary production +## +## Default is 0.7 mm as is the case in geant4 10 +## +## To disable this plugin and be absolutely sure to use the Geant4 default range cut use "None" +## +## Set printlevel to DEBUG to see a printout of all range cuts, +## but this only works if range cut is not "None" +## +SIM.physics.rangecut = 0.7 + +## Set of PDG IDs that will not be passed from the input record to Geant4. +## +## Quarks, gluons and W's Z's etc should not be treated by Geant4 +## +SIM.physics.rejectPDGs = { + 1, + 2, + 3, + 4, + 5, + 6, + 3201, + 3203, + 4101, + 4103, + 21, + 23, + 24, + 5401, + 25, + 2203, + 5403, + 3101, + 3103, + 4403, + 2101, + 5301, + 2103, + 5303, + 4301, + 1103, + 4303, + 5201, + 5203, + 3303, + 4201, + 4203, + 5101, + 5103, + 5503, +} + +## Set of PDG IDs for particles that should not be passed to Geant4 if their properTime is 0. +## +## The properTime of 0 indicates a documentation to add FSR to a lepton for example. +## +SIM.physics.zeroTimePDGs = {17, 11, 13, 15} + +def setupCerenkov(kernel): + from DDG4 import PhysicsList + seq = kernel.physicsList() + cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys') + cerenkov.MaxNumPhotonsPerStep = 1000 + # cerenkov.MaxBetaChangePerStep = 10.0 + # cerenkov.TrackSecondariesFirst = True + cerenkov.VerboseLevel = 0 + cerenkov.enableUI() + seq.adopt(cerenkov) + ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys') + ph.addParticleConstructor('G4OpticalPhoton') + ph.VerboseLevel = 0 + ph.enableUI() + seq.adopt(ph) + return None + +SIM.physics.setupUserPhysics(setupCerenkov) + +################################################################################ +## Properties for the random number generator +################################################################################ + +## If True, calculate random seed for each event basedon eventID and runID +## Allows reproducibility even whenSkippingEvents +SIM.random.enableEventSeed = False +SIM.random.file = None +SIM.random.luxury = 1 +SIM.random.replace_gRandom = True +SIM.random.seed = None +SIM.random.type = None + + +################################################################################ +## Configuration for setting commands to run during different phases. +## +## In this section, one can configure commands that should be run during the different phases of the Geant4 execution. +## +## 1. Configuration +## 2. Initialization +## 3. Pre Run +## 4. Post Run +## 5. Terminate / Finalization +## +## For example, one can add +## +## >>> SIM.ui.commandsConfigure = ['/physics_lists/em/SyncRadiation true'] +## +## Further details should be taken from the Geant4 documentation. +## +################################################################################ + +## List of UI commands to run during the 'Configure' phase. +SIM.ui.commandsConfigure = [] + +## List of UI commands to run during the 'Initialize' phase. +SIM.ui.commandsInitialize = [] + +## List of UI commands to run during the 'PostRun' phase. +SIM.ui.commandsPostRun = [] + +## List of UI commands to run during the 'PreRun' phase. +SIM.ui.commandsPreRun = [] + +## List of UI commands to run during the 'Terminate' phase. +SIM.ui.commandsTerminate = [] From a2849849aed9d723e614c48100dac4f2b205c679 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 20 Nov 2024 10:53:51 +0100 Subject: [PATCH 105/133] Rm elements.xml file from IDEA_o2 Remove elements.xml file, it is identical to the one sourced from IDEA_o1_v03 directory. Also fix typos in IDEA//README.md IDEA_o2 description. --- .../IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 4 - FCCee/IDEA/compact/IDEA_o2_v01/elements.xml | 884 ------------------ FCCee/IDEA/compact/README.md | 2 +- 3 files changed, 1 insertion(+), 889 deletions(-) delete mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/elements.xml diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml index 9671925a4..bd7b210d3 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -209,10 +209,6 @@ "/> - - - - diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml b/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml deleted file mode 100644 index f35eb3454..000000000 --- a/FCCee/IDEA/compact/IDEA_o2_v01/elements.xml +++ /dev/null @@ -1,884 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FCCee/IDEA/compact/README.md b/FCCee/IDEA/compact/README.md index 1a64df13e..d6c9ee960 100644 --- a/FCCee/IDEA/compact/README.md +++ b/FCCee/IDEA/compact/README.md @@ -29,6 +29,6 @@ September 2024: Added detailed version of the pre-shower, based on muon system b IDEA_o2_v01 ------------ -Second option of IDEA detector. The inner part up to the drift-chamber is identical to IDEA_o1, the dual-readout calorimeter uses the INFN capillary-tubes technology and replaces the monolithic calorimeter description. Between the drift-chamber and the dual-readout calorimeter a dual-readout crystal electromagnetic calorimeter is will place, consequentially the preshower is removed. The muon system is identical to IDEA_o1. +Second option of IDEA detector. The inner part up to the drift-chamber is identical to IDEA_o1, the dual-readout calorimeter uses the INFN capillary-tubes technology and replaces the monolithic calorimeter description. Between the drift-chamber and the dual-readout calorimeter a dual-readout crystal electromagnetic calorimeter will be placed, consequentially the preshower is removed. The muon system is identical to IDEA_o1. October 2024: first implementation using the dual-readout capillary-tubes endcap geometry. From fb9825354313c70d6aa6c15be693cd6619deedce Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 20 Nov 2024 13:53:24 +0100 Subject: [PATCH 106/133] Add materials_o2_v01 file Add XML file for materials definition for IDEA_o2. At the moment is identical to IDEA_o1_v03 but new materials (e.g. crystal ones) will be included. Also remove Vacuum and Air material definition from DREndcapTubes_o1_v01 XML file. --- .../IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 12 - .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 2 +- .../compact/IDEA_o2_v01/materials_o2_v01.xml | 577 ++++++++++++++++++ 3 files changed, 578 insertions(+), 13 deletions(-) create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/materials_o2_v01.xml diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml index bd7b210d3..2a4fb960b 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -210,18 +210,6 @@ - - - - - - - - - - - - diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml index e29092eb7..3ef5873c4 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -20,7 +20,7 @@ - + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/materials_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/materials_o2_v01.xml new file mode 100644 index 000000000..c7f888533 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/materials_o2_v01.xml @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CMS ECAL https://gitlab.cern.ch/geant4/geant4/-/blob/master/examples/advanced/composite_calorimeter/dataglobal/material.cms#L183 + + + + + + + + + + + + + + + + 0.98810714*2.7 + 0.011892860*10.49 + + field wire center: 50 um Al (core), 0.3 um Ag (coating) + + + + + 0.98516708*2.7 + 0.014832922*10.49 + + field wires top/bottom: 40 um Al (core), 0.3 um Ag (coating) + + + + + 0.97066175*19.28+0.029338250*19.3 + + sense wire: 20 um W (core), 0.3 um Au (coating) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From bab5972b18eea51c819a78a8256ffa752895f74c Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 20 Nov 2024 17:47:50 +0100 Subject: [PATCH 107/133] Add DectDimensions_IDEA_o2_v01 XML file Add XML file with dimensions for IDEA_o2. Same as DectDimensions_IDEA_o1_v01 but Fiber dual-readout calorimeter dimensions have been removed and dual-readout-tubes endcap calorimeter dimensions have been added. Also DREndcapTubes DetID is set in DectDimensions_IDEA_o2_v01. In future the preshower dimensions should be removed as well. --- .../IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 29 +- .../DectDimensions_IDEA_o2_v01.xml | 298 ++++++++++++++++++ .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 4 +- 3 files changed, 309 insertions(+), 22 deletions(-) create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml index 2a4fb960b..e04343349 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -28,15 +28,6 @@ - - - - - - - - - + + inner_radius="DRETinnerRadius" + z_length="DRETtowerHeight" + deltaphi="DRETNbOfZRot"/> - - - - - - + + + + + + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml new file mode 100644 index 000000000..3ce08369e --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml index 3ef5873c4..05ab70138 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -3,8 +3,6 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd"> - - - + From 5ec9b60f1a710b0bc0e345ca9a20c5bbac04bd17 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 20 Nov 2024 18:12:18 +0100 Subject: [PATCH 108/133] Move DRET vis attr to DectDimensions_IDEA_o2_v01 Move vis attributes definition for dual-readout-tubes endcap calorimeter inside DectDimensions_IDEA_o2_v01. Remove vis attributes from dr fiber calorimeter. --- .../IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 36 ++++++------------- .../DectDimensions_IDEA_o2_v01.xml | 21 ++++++----- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml index e04343349..10e4c2eba 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -241,43 +241,27 @@ - - - - - - - - - - - - - - + - - - - - - - - - + + + + + + + + + diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml index 3ce08369e..5f9dcdc67 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -224,6 +224,7 @@ + @@ -272,15 +273,17 @@ - - - - - - - - - + + + + + + + + + + + From bd481ef1b4a32a9079757e5d6a01307ad8cc3ad6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 21 Nov 2024 11:22:51 +0100 Subject: [PATCH 109/133] Assign DRTubesSDAction only to DREndcapTubes Fix bug in SteeringFile_IDEA_o2_v01.py, the DRTubesSDAction was assigned to every calorimeter, it should be assigned only to DREndcapTubes (and later on to the dual-readout-tubes barrel calorimeter). --- example/SteeringFile_IDEA_o2_v01.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py index 3c3dbe361..1c00a75e2 100644 --- a/example/SteeringFile_IDEA_o2_v01.py +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -97,14 +97,16 @@ ## ################################################################################ -SIM.action.calo = "DRTubesSDAction" -SIM.action.calorimeterSDTypes = [u'calorimeter'] +## set the default calorimeter action +SIM.action.calo = "Geant4ScintillatorCalorimeterAction" + +## List of patterns matching sensitive detectors of type Calorimeter. +SIM.action.calorimeterSDTypes = ["calorimeter"] + +## Replace SDAction for DREndcapTubes subdetector SIM.action.mapActions['DREndcapTubes'] = "DRTubesSDAction" -SIM.filter.calo = "" -# Configure the regexSD -SIM.geometry.regexSensitiveDetector['DREndcapTubes'] = {'Match': ['DRETS'], - 'OutputLevel': 4, - } +## Configure the regexSD for DREndcapTubes subdetector +SIM.geometry.regexSensitiveDetector['DREndcapTubes'] = {'Match': ['DRETS'],'OutputLevel': 4,} ## set the default run action SIM.action.run = [] From 3b8d4dedaa502b51ef2def13984b53e289e57206 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 21 Nov 2024 15:20:09 +0100 Subject: [PATCH 110/133] Fix bug due to calo.filter The calo.filter="edep0" in SteeringFile_IDEA_o2_v01.py did not let the DRTubesSDAction be executed on opticalphotons which did not deposit energy in fibers. However the SDAction must be executed on those steps as they are counted to create the Cherenkov signal and they are killed to speedup the simulation. Replace to calo.filter=None. Also set the physicsList as FTFP_BERT. And the beam to 10 GeV e- shot directly into the endcap calorimeter to monitor the time per event. --- example/SteeringFile_IDEA_o2_v01.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py index 1c00a75e2..363439aed 100644 --- a/example/SteeringFile_IDEA_o2_v01.py +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -1,5 +1,5 @@ from DDSim.DD4hepSimulation import DD4hepSimulation -from g4units import mm, GeV, MeV +from g4units import cm, mm, GeV, MeV SIM = DD4hepSimulation() @@ -16,11 +16,11 @@ ## Macro file to execute for runType 'run' or 'vis' SIM.macroFile = "" ## number of events to simulate, used in batch mode -SIM.numberOfEvents = 100 +SIM.numberOfEvents = 10 ## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported SIM.outputFile = "IDEA_o2_v01.root" ## Physics list to use in simulation -SIM.physicsList = None +SIM.physicsList = "FTFP_BERT" ## Verbosity use integers from 1(most) to 7(least) verbose ## or strings: VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL, ALWAYS SIM.printLevel = 3 @@ -171,7 +171,7 @@ ## default filter for calorimeter sensitive detectors; ## this is applied if no other filter is used for a calorimeter ## -SIM.filter.calo = "edep0" +SIM.filter.calo = "" ## list of filter objects: map between name and parameter dictionary SIM.filter.filters = { @@ -240,7 +240,7 @@ ################################################################################ ## direction of the particle gun, 3 vector -SIM.gun.direction = (1.0, 1.0, 1.0) +SIM.gun.direction = (0, 0, 1) ## choose the distribution of the random direction for theta ## @@ -258,7 +258,7 @@ ## Total energy (including mass) for the particle gun. ## ## If not None, it will overwrite the setting of momentumMin and momentumMax -SIM.gun.energy = None +SIM.gun.energy = 10.*GeV ## Maximal pseudorapidity for random distibution (overrides thetaMin) SIM.gun.etaMax = None @@ -279,7 +279,7 @@ ## Minimal momentum when using distribution (default = 0.0) SIM.gun.momentumMin = 0.0 SIM.gun.multiplicity = 1 -SIM.gun.particle = "mu-" +SIM.gun.particle = "e-" ## Maximal azimuthal angle for random distribution SIM.gun.phiMax = None @@ -288,7 +288,7 @@ SIM.gun.phiMin = None ## position of the particle gun, 3 vector -SIM.gun.position = (0.0, 0.0, 0.0) +SIM.gun.position = (0.0, 90.0*cm, 0.0) ## Maximal polar angle for random distribution SIM.gun.thetaMax = None From 5dcece7c4c97cca08e93c4b7cf37e07d7dd9c676 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 21 Nov 2024 17:20:30 +0100 Subject: [PATCH 111/133] Change DREndcapTubes dimensions According to indications from the IDEA members, the new dimensions for the calorimeter are: inner radius 2.8 m and length 1.8 m. Also changed the number of rotations around Z-axis to 72. --- .../IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml index 5f9dcdc67..637a31692 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -218,9 +218,9 @@ - - - + + + From cd45d76b7e4bca42d85c71a553be3479684a2e05 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 21 Nov 2024 17:27:25 +0100 Subject: [PATCH 112/133] Change slenoid dimensions for IDEA_o2 The new em-crystal section will be included inside the solenoid. The solenoid dimensions are changes to inner radius 2.5 m and outer radius 2.8 m. --- FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml index 637a31692..4e8b87443 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -114,8 +114,8 @@ - - + + From 46ebb2cbf654217378227a25c06e4ca1bf18bc3d Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 21 Nov 2024 17:31:33 +0100 Subject: [PATCH 113/133] Rm preshower in IDEA_o2 XML file IDEA_o2 will not include the preshower, therefore I remove it from IDEA_o2_v01.xml file. Also the preshower dimensions are removed from DectDimensions_IDEA_o2_v01.xml. --- .../IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 11 ----------- FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 4 ---- 2 files changed, 15 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml index 4e8b87443..9895c63b1 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -206,17 +206,6 @@ - - - - - - - - - - - diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml index 05ab70138..eb4f52957 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -58,10 +58,6 @@ - - - - From 28b233eb9812ad348d09916d8b4ed17d87a75a64 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Fri, 22 Nov 2024 14:55:10 +0100 Subject: [PATCH 114/133] Fix overlap of DREndcapTubes and comp solenoid The DREndcapTubes phi air staves reached the beam pipe (y=0), this was clearly causing an overlap with the compensating solenoid. To fix this a new variable set the starting y of the phi air staves to 22 cm from the z-axis. This commit was checked for overlaps with a tolerance of 10 um (fibers not included in towers) and no overlaps were detected. --- .../src/DREndcapTubes_o1_v01.cpp | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp index 3679b658b..c4b374f3c 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp @@ -121,27 +121,32 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s // Volume that contains a slice of the right endcap // I use the EightPointSolid/Arb8/G4Generictrap so I define directly its 8 points // - // The first two points of the inner face collide on the beam pipe into (0,0) + // Distance between z-axis and the starting point of the Air stave containing + // the towers, it is included to avoid overlaps with the compensating solenoid + const double DistancetoSolenoid = 22*cm; + // The first two points of the inner face are defined by DistancetoSolenoid + // similarly to the second two points // The second two points of the inner face are at (x=tan(0.5*phi_unit, y=innerR) // x with plus or minus sign double vertices[16]; - vertices[0] = static_cast(0.); - vertices[1] = static_cast(0.); - vertices[2] = static_cast(0.); - vertices[3] = static_cast(0.); - vertices[4] = static_cast(-innerR * tan(0.5 * phi_unit)); + vertices[0] = static_cast(-DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[1] = static_cast(DistancetoSolenoid); + vertices[2] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[3] = static_cast(DistancetoSolenoid); + vertices[4] = static_cast(innerR * tan(0.5 * phi_unit)); vertices[5] = static_cast(innerR); - vertices[6] = static_cast(innerR * tan(0.5 * phi_unit)); + vertices[6] = static_cast(-innerR * tan(0.5 * phi_unit)); vertices[7] = static_cast(innerR); - // The first two points of the outer face collide on the beam pipe into (0,0) + // The first two points of the outer face are at the same distance to the z-axis + // as in the inner face // The second two poits of the outer face are same as before with innerR+tower_height - vertices[8] = static_cast(0.); - vertices[9] = static_cast(0.); - vertices[10] = static_cast(0.); - vertices[11] = static_cast(0.); - vertices[12] = static_cast(-(innerR + tower_height) * tan(0.5 * phi_unit)); + vertices[8] = static_cast(-DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[9] = static_cast(DistancetoSolenoid); + vertices[10] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[11] = static_cast(DistancetoSolenoid); + vertices[12] = static_cast((innerR + tower_height) * tan(0.5 * phi_unit)); vertices[13] = static_cast(innerR + tower_height); - vertices[14] = static_cast((innerR + tower_height) * tan(0.5 * phi_unit)); + vertices[14] = static_cast(-(innerR + tower_height) * tan(0.5 * phi_unit)); vertices[15] = static_cast(innerR + tower_height); // Equivalent of Geant4 GenericTrap shape constructor EightPointSolid phiER("phiER", tower_height / 2., vertices); From 1710bbbc328b690aa2b01e3ef5202523fbd05d9c Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Fri, 22 Nov 2024 16:54:00 +0100 Subject: [PATCH 115/133] Set number of events to 1000 for IDEA_o2 example To monitor the event rate 1000 events are needed to get stable results. With this example we have around 0.8-1.0 s/evt for 10 GeV e- showeing in the endcap calorimeter. --- example/SteeringFile_IDEA_o2_v01.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py index 363439aed..98a330286 100644 --- a/example/SteeringFile_IDEA_o2_v01.py +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -16,7 +16,7 @@ ## Macro file to execute for runType 'run' or 'vis' SIM.macroFile = "" ## number of events to simulate, used in batch mode -SIM.numberOfEvents = 10 +SIM.numberOfEvents = 1000 ## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported SIM.outputFile = "IDEA_o2_v01.root" ## Physics list to use in simulation From 73061269d5def44cecf5fa1c058f12534b7f05bf Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 25 Nov 2024 14:15:07 +0100 Subject: [PATCH 116/133] Add IDEA_o2 CMake test and reorder G4GenericTrap Adding a CMake test for IDEA_o2_v01. ctest -R t_test_IDEA_o2_v01 takes about 211 s on lxplus9 machines. This test spotted one "Error" keyword due to anticlockwise ordering of G4GenericTrap constructor edges (they were internally reordered by root). To fix it I reordered them clockwise. --- .../src/DREndcapTubes_o1_v01.cpp | 16 ++++++++-------- test/CMakeLists.txt | 8 ++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp index c4b374f3c..3f2ae408c 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp @@ -131,23 +131,23 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s double vertices[16]; vertices[0] = static_cast(-DistancetoSolenoid * tan(0.5 * phi_unit)); vertices[1] = static_cast(DistancetoSolenoid); - vertices[2] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); - vertices[3] = static_cast(DistancetoSolenoid); + vertices[2] = static_cast(-innerR * tan(0.5 * phi_unit)); + vertices[3] = static_cast(innerR); vertices[4] = static_cast(innerR * tan(0.5 * phi_unit)); vertices[5] = static_cast(innerR); - vertices[6] = static_cast(-innerR * tan(0.5 * phi_unit)); - vertices[7] = static_cast(innerR); + vertices[6] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[7] = static_cast(DistancetoSolenoid); // The first two points of the outer face are at the same distance to the z-axis // as in the inner face // The second two poits of the outer face are same as before with innerR+tower_height vertices[8] = static_cast(-DistancetoSolenoid * tan(0.5 * phi_unit)); vertices[9] = static_cast(DistancetoSolenoid); - vertices[10] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); - vertices[11] = static_cast(DistancetoSolenoid); + vertices[10] = static_cast(-(innerR + tower_height) * tan(0.5 * phi_unit)); + vertices[11] = static_cast(innerR + tower_height); vertices[12] = static_cast((innerR + tower_height) * tan(0.5 * phi_unit)); vertices[13] = static_cast(innerR + tower_height); - vertices[14] = static_cast(-(innerR + tower_height) * tan(0.5 * phi_unit)); - vertices[15] = static_cast(innerR + tower_height); + vertices[14] = static_cast(DistancetoSolenoid * tan(0.5 * phi_unit)); + vertices[15] = static_cast(DistancetoSolenoid); // Equivalent of Geant4 GenericTrap shape constructor EightPointSolid phiER("phiER", tower_height / 2., vertices); Volume phiERLog("phiER", phiER, description.material(x_stave.attr(_U(material)))); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 46576dbf9..83f57d83a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -114,6 +114,14 @@ ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) endif() +#-------------------------------------------------- +# test for IDEA o2 v01 +if(DCH_INFO_H_EXIST) +SET( test_name "test_IDEA_o2_v01" ) +ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml -N 1 -G --gun.distribution uniform --random.seed 1988301045 --outputFile=testIDEA_o2_v01.root ) + SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) +endif() #-------------------------------------------------- # test for ALLEGRO o1 v02 From 85c59c47af360745d54be5de2fbfded58f886736 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 25 Nov 2024 14:56:08 +0100 Subject: [PATCH 117/133] Fix pre-commit hook error in SteeringFile Fix indentation of SteeringFile_IDEA_o2_v01.py file causing an error against pre-commit hook. --- example/SteeringFile_IDEA_o2_v01.py | 46 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py index 98a330286..9133c506c 100644 --- a/example/SteeringFile_IDEA_o2_v01.py +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -16,7 +16,7 @@ ## Macro file to execute for runType 'run' or 'vis' SIM.macroFile = "" ## number of events to simulate, used in batch mode -SIM.numberOfEvents = 1000 +SIM.numberOfEvents = 10 ## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported SIM.outputFile = "IDEA_o2_v01.root" ## Physics list to use in simulation @@ -104,9 +104,12 @@ SIM.action.calorimeterSDTypes = ["calorimeter"] ## Replace SDAction for DREndcapTubes subdetector -SIM.action.mapActions['DREndcapTubes'] = "DRTubesSDAction" +SIM.action.mapActions["DREndcapTubes"] = "DRTubesSDAction" ## Configure the regexSD for DREndcapTubes subdetector -SIM.geometry.regexSensitiveDetector['DREndcapTubes'] = {'Match': ['DRETS'],'OutputLevel': 4,} +SIM.geometry.regexSensitiveDetector["DREndcapTubes"] = { + "Match": ["DRETS"], + "OutputLevel": 4, +} ## set the default run action SIM.action.run = [] @@ -258,7 +261,7 @@ ## Total energy (including mass) for the particle gun. ## ## If not None, it will overwrite the setting of momentumMin and momentumMax -SIM.gun.energy = 10.*GeV +SIM.gun.energy = 10.0 * GeV ## Maximal pseudorapidity for random distibution (overrides thetaMin) SIM.gun.etaMax = None @@ -288,7 +291,7 @@ SIM.gun.phiMin = None ## position of the particle gun, 3 vector -SIM.gun.position = (0.0, 90.0*cm, 0.0) +SIM.gun.position = (0.0, 90.0 * cm, 0.0) ## Maximal polar angle for random distribution SIM.gun.thetaMax = None @@ -580,22 +583,25 @@ ## SIM.physics.zeroTimePDGs = {17, 11, 13, 15} + def setupCerenkov(kernel): - from DDG4 import PhysicsList - seq = kernel.physicsList() - cerenkov = PhysicsList(kernel, 'Geant4CerenkovPhysics/CerenkovPhys') - cerenkov.MaxNumPhotonsPerStep = 1000 - # cerenkov.MaxBetaChangePerStep = 10.0 - # cerenkov.TrackSecondariesFirst = True - cerenkov.VerboseLevel = 0 - cerenkov.enableUI() - seq.adopt(cerenkov) - ph = PhysicsList(kernel, 'Geant4OpticalPhotonPhysics/OpticalGammaPhys') - ph.addParticleConstructor('G4OpticalPhoton') - ph.VerboseLevel = 0 - ph.enableUI() - seq.adopt(ph) - return None + from DDG4 import PhysicsList + + seq = kernel.physicsList() + cerenkov = PhysicsList(kernel, "Geant4CerenkovPhysics/CerenkovPhys") + cerenkov.MaxNumPhotonsPerStep = 1000 + # cerenkov.MaxBetaChangePerStep = 10.0 + # cerenkov.TrackSecondariesFirst = True + cerenkov.VerboseLevel = 0 + cerenkov.enableUI() + seq.adopt(cerenkov) + ph = PhysicsList(kernel, "Geant4OpticalPhotonPhysics/OpticalGammaPhys") + ph.addParticleConstructor("G4OpticalPhoton") + ph.VerboseLevel = 0 + ph.enableUI() + seq.adopt(ph) + return None + SIM.physics.setupUserPhysics(setupCerenkov) From cc654bc16b93802e2d9770b8febc3756002a2ae6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 26 Nov 2024 16:38:48 +0100 Subject: [PATCH 118/133] Use steerfile in IDEA_o2 cmake test Change cmake test for IDEA_o2 in order to use the IDEA_o2 example steering file. This test takes about 350 s on lxplus9 machines and correctly fills DREndcapTubes calo hit with 1 event. --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 83f57d83a..5ccbce058 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -119,7 +119,7 @@ endif() if(DCH_INFO_H_EXIST) SET( test_name "test_IDEA_o2_v01" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" - ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml -N 1 -G --gun.distribution uniform --random.seed 1988301045 --outputFile=testIDEA_o2_v01.root ) + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml --steeringFile=${CMAKE_CURRENT_SOURCE_DIR}/../example/SteeringFile_IDEA_o2_v01.py -N 1 --random.seed 1988301045 --outputFile=testIDEA_o2_v01.root ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) endif() From 2bf6aa4cd51afd08124b4d0eab8d42aa49b0e252 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 26 Nov 2024 16:56:45 +0100 Subject: [PATCH 119/133] Change DRTubesSDAction.cpp units comment Fix comment for unit translation from Geant4 units to EDM4hep units. Co-authored-by: Andre Sailer --- plugins/DRTubesSDAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 8c38b30f9..d47e6d0e4 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -240,7 +240,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, Position FiberPos(FiberVec.x(), FiberVec.y(), FiberVec.z()); hit->position = FiberPos; // this should be assigned only once // Note, when the hit is saved in edm4hep format the energyDeposit is - // divided by 1000, i.e. it translates from MeV (Geant4 unit) to GeV (DD4hep unit). + // divided by 1000, i.e. it translates from MeV (Geant4 unit) to GeV (EDM4hep unit). // Here I am using this field to save photo-electrons, so I multiply it by 1000 hit->energyDeposit = signalhit * 1000; coll->add(VolID, hit); // add the hit to the hit collection From 162f242560fcb797debe0915468b1ea661241938 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 26 Nov 2024 18:38:38 +0100 Subject: [PATCH 120/133] Add comment on light smearing parameters Add a comment to explain how photoelectrons are computed from Monte Carlo information: energy deposited in S fibers and number of C photons trapped in fibers. --- plugins/DRTubesSglHpr.hh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/DRTubesSglHpr.hh b/plugins/DRTubesSglHpr.hh index 6baa3fc10..a0c54b97e 100644 --- a/plugins/DRTubesSglHpr.hh +++ b/plugins/DRTubesSglHpr.hh @@ -40,9 +40,24 @@ class DRTubesSglHpr } // Smear S signal according to Poissonian fluctuations and light yield + // + // This method calculates how many Scintillation photo electrons are + // detected given an energy deposited in MeV (satde). 9.5 is a convertion + // factor that translates the average energy deposited in MonteCarlo + // to the average Scintillating photo electrons observed (from 2023 test-beam). + // A Poissonian smearing is applyed at every step to include poissonian + // fluctuations of light emission. static G4int SmearSSignal(const G4double& satde) { return G4Poisson(satde * 9.5); } // Smear C signal according to Poissonian fluctuations and light yield + // + // This method calculates how many cherenkov photo electrons are detected + // per single Cherenkov photon trapped inside a fiber in the simulation. + // Given the average number of Cherenkov photons emitted by Geant4 this + // number is converted in average number of Cherenkov photons as measured + // in test-beams (0.177 comes from 2023 test-beam). + // A poissonian smearing is added at every calculation to include + // poissonian light fluctuations. static G4int SmearCSignal() { return G4Poisson(0.177); } // Calculate distance from step in fiber to SiPM From e7a48c4013b968136e66ff9398e84b9ac219cc92 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 27 Nov 2024 13:53:53 +0100 Subject: [PATCH 121/133] Add comment on Birks' Law usage in SDAction Add comment about using our custom Birks' Law implementation in the SDAction. In particular to avoid potential double application of Birks' correction if the Geant4StepHandler is used on this subdetector. --- plugins/DRTubesSDAction.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index d47e6d0e4..6f06a3206 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -109,6 +109,13 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // (see https://github.com/AIDASoft/DD4hep/issues/1319). // Therefore we use copynumbers instead of volIDs. + // NOTE: in this SDAction we apply our custom Birks' Law correction + // on the G4Step via the method DRTubesSglHpr::ApplyBirks(). + // However it should be known that the dd4hep Geant4StepHandler can apply Birks' Law + // correction too (using internally the Geant4 class G4EmSaturation). + // Therefore, if the Geant4StepHandler is used on this subdetector it might + // lead to a double application of Birks' correction. + #ifdef DRTubesSDDebug // Print out some info step-by-step in sensitive volumes // From 2e136e371fcc1287f3a90c56e36fd6aba05d5edb Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Fri, 29 Nov 2024 14:23:56 +0100 Subject: [PATCH 122/133] Add "system" id to DREndcapTubes subdetector Add "system" id to DREndcapTubes xml file and assign it to the highest volume in the geometry node. While recreating the volumeID in the DRTubesSDAction, "system" id is set as in DectDimensions_IDEA_o2_v01.xml file. In both xml files add a comment on ids to prevent unwanted modifications. --- .../compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml | 15 ++++++++++++++- .../IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 5 +++++ .../src/DREndcapTubes_o1_v01.cpp | 1 + plugins/DRTubesSDAction.cpp | 10 ++-------- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml index 10e4c2eba..78d485cf4 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DREndcapTubes_o1_v01.xml @@ -270,8 +270,21 @@ + + - stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1 + system:5,stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1 diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml index 9895c63b1..d8e9a9470 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml @@ -53,6 +53,11 @@ + diff --git a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp index 3f2ae408c..a9061e6fd 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp @@ -511,6 +511,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s Volume motherVolume = description.pickMotherVolume(sdet); // Place the assembly container inside the mother volume PlacedVolume AssemblyEndcapPV = motherVolume.placeVolume(AssemblyEndcap); + AssemblyEndcapPV.addPhysVolID("system",x_det.id()); sdet.setPlacement(AssemblyEndcapPV); std::cout << "--> DREndcapTubes::create_detector() end" << std::endl; diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 6f06a3206..483846579 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -155,7 +155,8 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, auto StaveID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); VolumeID VolID = 0; // recreate the 64-bit VolumeID - BitFieldCoder bc("stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1"); + BitFieldCoder bc("system:5,stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1"); + bc.set(VolID, "system", 25); // this number is set in DectDimensions_IDEA_o2_v01.xml bc.set(VolID, "stave" , StaveID); bc.set(VolID, "tower" , TowerID); bc.set(VolID, "air", 0); @@ -178,8 +179,6 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, if (IsScin) { // it is a scintillating fiber - //m_userData.fEvtAction->AddEdepScin(Edep); - if (aStep->GetTrack()->GetDefinition()->GetPDGCharge() == 0 || steplength == 0.) { return true; // not ionizing particle } @@ -188,12 +187,9 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, DRTubesSglHpr::SmearSSignal(DRTubesSglHpr::ApplyBirks(Edep, steplength)); signalhit = DRTubesSglHpr::AttenuateSSignal(signalhit, distance_to_sipm); if (signalhit == 0) return true; - //m_userData.fEvtAction->AddSglScin(signalhit); } // end of scintillating fibre sigal calculation else { // it is a Cherenkov fiber - // save mc truth info in analysismanager auxiliary outputfile - //m_userData.fEvtAction->AddEdepCher(Edep); // calculate the signal in terms of Cherenkov photo-electrons if (aStep->GetTrack()->GetParticleDefinition() == G4OpticalPhoton::Definition()) { G4OpBoundaryProcessStatus theStatus = Undefined; @@ -221,8 +217,6 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, G4int c_signal = DRTubesSglHpr::SmearCSignal(); signalhit = DRTubesSglHpr::AttenuateCSignal(c_signal, distance_to_sipm); if (signalhit == 0) return true; - // save mc truth info in analysismanager auxiliary outputfile - //m_userData.fEvtAction->AddSglCher(signalhit); aStep->GetTrack()->SetTrackStatus(fStopAndKill); break; } From 6d0cfb7600ad54bc0d2267b60e79cbdcf52ec343 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 5 Dec 2024 13:40:44 +0100 Subject: [PATCH 123/133] Add comment to check volumeIDs Add a comment in DRTubesSDAction to check that 64-bits volumeIDs created with g4-copynumbers are identical to the original DD4hep volumeIDs. --- plugins/DRTubesSDAction.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 483846579..b9bdd5bff 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -166,6 +166,24 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, bc.set(VolID, "core", CoreID); bc.set(VolID, "cherenkov", CherenkovID); + /* If you want to compare the 64-bits VolID created here + * with the original DD4hep volumeID: + * 1. set in DREndcapTubes_o1_v01.xml clad_C, core_C and core_S + * volumes as sensitive + * 2. associate DRTubesSDAction to DREncapTubes subdetector + * in the steering file (instead of using RegexSD) + * 3. Uncomment the code below */ + /*std::cout<<"Volume id, created "<GetPreStepPoint()->GetPosition().z() > 0.); // We now calculate the signal in S and C fiber according to the step contribution From 37e6562fd7b7cb7bad9c289e4d696b21c748a849 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 5 Dec 2024 15:21:38 +0100 Subject: [PATCH 124/133] Apply clang-format to DREndcapTubes code clang-format .cpp and .hh files for DREndcapTubes subdetector. I checked that this formatting does not change physics results. --- .../include/DREndcapTubes.hh | 4 +- .../src/DREndcapTubes_o1_v01.cpp | 41 ++++++++++--------- plugins/DRTubesSDAction.cpp | 25 ++++++----- plugins/DRTubesSglHpr.hh | 2 +- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh b/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh index 2d7d66e4c..c9b252062 100644 --- a/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh +++ b/detector/calorimeter/dual-readout-tubes/include/DREndcapTubes.hh @@ -15,7 +15,7 @@ struct Plane { Vector3D P1, P2, P3, P4; - Plane(Vector3D p1, Vector3D p2, Vector3D p3, Vector3D p4) : P1(p1), P2(p2), P3(p3), P4(p4){}; + Plane(Vector3D p1, Vector3D p2, Vector3D p3, Vector3D p4) : P1(p1), P2(p2), P3(p3), P4(p4) {}; }; // This struct represents a line towards negatize Z @@ -27,7 +27,7 @@ struct ZLine { Vector3D origin; Vector3D fuZ = Vector3D(0, 0, -1); - ZLine(Vector3D P) : origin(P){}; + ZLine(Vector3D P) : origin(P) {}; }; // Custom exception class for intersecting ZLines with Planes diff --git a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp index a9061e6fd..871c2c7ea 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DREndcapTubes_o1_v01.cpp @@ -29,10 +29,10 @@ using namespace dd4hep::rec; // for dd4hep::rec::Vector3D // It is used to create a G4 copynumber for volumes with two IDs unsigned int CalcCpNo32bits(int id1, int id2) { - if (id1 > 0xFFF || id2 > 0xFFF){ + if (id1 > 0xFFF || id2 > 0xFFF) { throw std::invalid_argument("row and col IDs should not take more than 16 bits"); } - unsigned int CpNo = (id1 << 16) | id2; + unsigned int CpNo = (id1 << 16) | id2; return CpNo; } @@ -40,8 +40,8 @@ unsigned int CalcCpNo32bits(int id1, int id2) unsigned int CalcCpNo2bits(int id1, int id2) { if (id1 > 1 || id2 > 1) { - throw std::invalid_argument("core and cherenkov ID must be 0 or 1"); - } + throw std::invalid_argument("core and cherenkov ID must be 0 or 1"); + } unsigned int CpNo = (id1 << 1) | id2; return CpNo; } @@ -123,7 +123,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s // // Distance between z-axis and the starting point of the Air stave containing // the towers, it is included to avoid overlaps with the compensating solenoid - const double DistancetoSolenoid = 22*cm; + const double DistancetoSolenoid = 22 * cm; // The first two points of the inner face are defined by DistancetoSolenoid // similarly to the second two points // The second two points of the inner face are at (x=tan(0.5*phi_unit, y=innerR) @@ -172,8 +172,9 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s RotationY rotyleft(0.); Transform3D slice_trnsformleft(rotz1 * rotz2 * rotx * rotyleft, Position(0, 0, -1. * ((innerR)*tan(thetaB) + length / 2.))); - PlacedVolume phiELPlaced = AssemblyEndcap.placeVolume(phiERLog, j+NbOfZRot, slice_trnsformleft); - phiELPlaced.addPhysVolID("stave", j+NbOfZRot); + PlacedVolume phiELPlaced = + AssemblyEndcap.placeVolume(phiERLog, j + NbOfZRot, slice_trnsformleft); + phiELPlaced.addPhysVolID("stave", j + NbOfZRot); } // end of slice/stave placement // Create an S tube with full tower length @@ -193,7 +194,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s description.material(x_core_S.attr(_U(material)))); core_SLog.setVisAttributes(description, x_core_S.visStr()); if (x_core_S_sens) core_SLog.setSensitiveDetector(sens); - PlacedVolume core_SPlaced = clad_SLog.placeVolume(core_SLog, CalcCpNo2bits(1,0)); + PlacedVolume core_SPlaced = clad_SLog.placeVolume(core_SLog, CalcCpNo2bits(1, 0)); core_SPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 0); // Create a C tube with full tower length @@ -213,7 +214,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s description.material(x_core_C.attr(_U(material)))); core_CLog.setVisAttributes(description, x_core_C.visStr()); if (x_core_C_sens) core_CLog.setSensitiveDetector(sens); - PlacedVolume core_CPlaced = clad_CLog.placeVolume(core_CLog, CalcCpNo2bits(1,1)); + PlacedVolume core_CPlaced = clad_CLog.placeVolume(core_CLog, CalcCpNo2bits(1, 1)); core_CPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 1); // Build the towers inside and endcap R slice @@ -312,7 +313,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s towerPlaced.addPhysVolID("tower", i).addPhysVolID("air", 0); } // Or, to debug, place towers one next to each other in assembly volume - //if(i<35) { + // if(i<35) { // double z = static_cast(i/15)*(length+40*cm); // double x = (i-static_cast(i/15)*15)*100*cm - 5*m; // AssemblyEndcap.placeVolume(towerLog,i,Position(-1.*x,0.,-1.*z)); @@ -355,8 +356,8 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s Vector3D capillaryPos(x_tube, y_tube, length / 2.); // locate tube on tower back face auto capillaryLength = Helper.GetTubeLength(pt, capillaryPos); // calculate tube length if (std::fabs(capillaryLength - length) < 0.0001 * mm) { - PlacedVolume capillaryPlaced = - towerLog.placeVolume(capillary_SLog, CalcCpNo32bits(j,k), Position(x_tube, y_tube, 0.)); + PlacedVolume capillaryPlaced = towerLog.placeVolume(capillary_SLog, CalcCpNo32bits(j, k), + Position(x_tube, y_tube, 0.)); // ID this volume with row ID and column ID capillaryPlaced.addPhysVolID("row", k).addPhysVolID("col", j); #ifdef COUNTTUBES @@ -391,11 +392,12 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s description.material(x_core_S.attr(_U(material)))); coreShort_SLog.setVisAttributes(description, x_core_S.visStr()); if (x_core_S_sens) coreShort_SLog.setSensitiveDetector(sens); - PlacedVolume coreShort_SPlaced = cladShort_SLog.placeVolume(coreShort_SLog, CalcCpNo2bits(1,0)); + PlacedVolume coreShort_SPlaced = + cladShort_SLog.placeVolume(coreShort_SLog, CalcCpNo2bits(1, 0)); coreShort_SPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 0); PlacedVolume capillaryShortPlaced = towerLog.placeVolume( - capillaryShortLog, CalcCpNo32bits(j,k), + capillaryShortLog, CalcCpNo32bits(j, k), Position(x_tube, y_tube, length / 2. - capillaryLength / 2. + TubeLengthOffset / 2.)); // ID this volume with row ID and column ID capillaryShortPlaced.addPhysVolID("row", k).addPhysVolID("col", j); @@ -426,8 +428,8 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s Vector3D capillaryPos_C(x_tube_C, y_tube_C, length / 2.); auto capillaryLength_C = Helper.GetTubeLength(pt, capillaryPos_C); if (std::fabs(capillaryLength_C - length) < 0.0001 * mm) { - PlacedVolume capillaryPlaced_C = towerLog.placeVolume(capillary_CLog, CalcCpNo32bits(j,k), - Position(x_tube_C, y_tube_C, 0.)); + PlacedVolume capillaryPlaced_C = towerLog.placeVolume( + capillary_CLog, CalcCpNo32bits(j, k), Position(x_tube_C, y_tube_C, 0.)); capillaryPlaced_C.addPhysVolID("row", k).addPhysVolID("col", j); #ifdef COUNTTUBES tubeNo++; @@ -458,11 +460,12 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s description.material(x_core_C.attr(_U(material)))); coreShort_CLog.setVisAttributes(description, x_core_C.visStr()); if (x_core_C_sens) coreShort_CLog.setSensitiveDetector(sens); - PlacedVolume coreShort_CPlaced = cladShort_CLog.placeVolume(coreShort_CLog, CalcCpNo2bits(1,1)); + PlacedVolume coreShort_CPlaced = + cladShort_CLog.placeVolume(coreShort_CLog, CalcCpNo2bits(1, 1)); coreShort_CPlaced.addPhysVolID("core", 1).addPhysVolID("cherenkov", 1); PlacedVolume capillaryShortPlaced_C = towerLog.placeVolume( - capillaryShortLog_C, CalcCpNo32bits(j,k), + capillaryShortLog_C, CalcCpNo32bits(j, k), Position(x_tube_C, y_tube_C, length / 2. - capillaryLength_C / 2. + TubeLengthOffset / 2.)); capillaryShortPlaced_C.addPhysVolID("row", k).addPhysVolID("col", j); @@ -511,7 +514,7 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s Volume motherVolume = description.pickMotherVolume(sdet); // Place the assembly container inside the mother volume PlacedVolume AssemblyEndcapPV = motherVolume.placeVolume(AssemblyEndcap); - AssemblyEndcapPV.addPhysVolID("system",x_det.id()); + AssemblyEndcapPV.addPhysVolID("system", x_det.id()); sdet.setPlacement(AssemblyEndcapPV); std::cout << "--> DREndcapTubes::create_detector() end" << std::endl; diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index b9bdd5bff..b3073b1e9 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -83,7 +83,7 @@ void Geant4SensitiveAction::defineCollections() // Method that accesses the G4Step object at each track step. template<> bool Geant4SensitiveAction::process(const G4Step* aStep, - G4TouchableHistory* /*history*/) + G4TouchableHistory* /*history*/) { // NOTE: Here we do manipulation of the signal in each fiber (Scintillating and Cherenkov) // to compute the calorimeter signal and populate the corresponding hit. @@ -126,8 +126,8 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, auto cpNo = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(); // The second bit of the CopyNumber corresponds to the "core" entry: // 1 if the step is in the fiber core (S or C) and 0 if it is - // in the fiber cladding (C only) - unsigned int CoreID = (cpNo & 0b10) >> 1; // take CpNo 2nd bit + // in the fiber cladding (C only) + unsigned int CoreID = (cpNo & 0b10) >> 1; // take CpNo 2nd bit bool IsCherClad = (CoreID == 0); // The first bit of the CopyNumber corresponds to the "cherenkov" entry // 1 for C fibers and 0 for S fibers @@ -151,14 +151,16 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, auto TubeID = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(2); unsigned int ColumnID = TubeID >> 16; unsigned int RawID = TubeID & 0xFFFF; - auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3)); - auto StaveID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); + auto TowerID = + static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3)); + auto StaveID = + static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); - VolumeID VolID = 0; // recreate the 64-bit VolumeID + VolumeID VolID = 0; // recreate the 64-bit VolumeID BitFieldCoder bc("system:5,stave:10,tower:6,air:1,col:16,row:16,clad:1,core:1,cherenkov:1"); - bc.set(VolID, "system", 25); // this number is set in DectDimensions_IDEA_o2_v01.xml - bc.set(VolID, "stave" , StaveID); - bc.set(VolID, "tower" , TowerID); + bc.set(VolID, "system", 25); // this number is set in DectDimensions_IDEA_o2_v01.xml + bc.set(VolID, "stave", StaveID); + bc.set(VolID, "tower", TowerID); bc.set(VolID, "air", 0); bc.set(VolID, "col", ColumnID); bc.set(VolID, "row", RawID); @@ -173,6 +175,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, * 2. associate DRTubesSDAction to DREncapTubes subdetector * in the steering file (instead of using RegexSD) * 3. Uncomment the code below */ + // clang-format off /*std::cout<<"Volume id, created "<::process(const G4Step* aStep, std::cout<<"clad id, created "<<1<<" and DD4hep original "<GetPreStepPoint()->GetPosition().z() > 0.); @@ -201,8 +205,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, return true; // not ionizing particle } G4double distance_to_sipm = DRTubesSglHpr::GetDistanceToSiPM(aStep); - signalhit = - DRTubesSglHpr::SmearSSignal(DRTubesSglHpr::ApplyBirks(Edep, steplength)); + signalhit = DRTubesSglHpr::SmearSSignal(DRTubesSglHpr::ApplyBirks(Edep, steplength)); signalhit = DRTubesSglHpr::AttenuateSSignal(signalhit, distance_to_sipm); if (signalhit == 0) return true; } // end of scintillating fibre sigal calculation diff --git a/plugins/DRTubesSglHpr.hh b/plugins/DRTubesSglHpr.hh index a0c54b97e..be82c01cc 100644 --- a/plugins/DRTubesSglHpr.hh +++ b/plugins/DRTubesSglHpr.hh @@ -110,7 +110,7 @@ inline G4double DRTubesSglHpr::GetDistanceToSiPM(const G4Step* step, bool preste } inline G4int DRTubesSglHpr::AttenuateHelper(const G4int& signal, const G4double& distance, - const G4double& attenuation_length) + const G4double& attenuation_length) { double probability_of_survival = exp(-distance / attenuation_length); From 3c58f08c12265b6d77c08a0bc3a242d6a48929d0 Mon Sep 17 00:00:00 2001 From: faltovaj Date: Sun, 15 Dec 2024 18:25:27 +0100 Subject: [PATCH 125/133] CLD_o4_v05: fixing LAr_ECalBarrel.xml (#412) --- FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml index 6121afe66..e0ad42891 100644 --- a/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml +++ b/FCCee/CLD/compact/CLD_o4_v05/LAr_ECalBarrel.xml @@ -45,13 +45,13 @@ - - - + + + - + @@ -71,6 +71,7 @@ + @@ -83,19 +84,19 @@ - system:4,cryo:1,type:3,subtype:3,layer:8,module:11,eta:9 + system:5,cryo:1,type:3,subtype:3,layer:8,module:11,eta:9 - system:4,cryo:1,type:3,subtype:3,layer:8,eta:9,phi:10 + system:5,cryo:1,type:3,subtype:3,layer:8,eta:9,phi:10 - + From 1d5bee8640250499e7fcf0a6fea5706907444583 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 12:20:43 +0100 Subject: [PATCH 126/133] new implementation of tt, transparent to the user --- detector/tracker/DriftChamber_o1_v02.cpp | 82 +++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/detector/tracker/DriftChamber_o1_v02.cpp b/detector/tracker/DriftChamber_o1_v02.cpp index a174f804f..04f5d4842 100644 --- a/detector/tracker/DriftChamber_o1_v02.cpp +++ b/detector/tracker/DriftChamber_o1_v02.cpp @@ -25,6 +25,8 @@ using DCH_length_t = dd4hep::rec::DCH_info_struct::DCH_length_t; using DCH_angle_t = dd4hep::rec::DCH_info_struct::DCH_angle_t; using DCH_layer = dd4hep::rec::DCH_info_struct::DCH_layer; +dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_rout_z0, double dz, double dphi, const dd4hep::rec::DCH_info & DCH_i); + /// Function to build DCH static dd4hep::Ref_t create_DCH_o1_v02(dd4hep::Detector &desc, dd4hep::xml::Handle_t handle, dd4hep::SensitiveDetector sens) { @@ -75,6 +77,7 @@ static dd4hep::Ref_t create_DCH_o1_v02(dd4hep::Detector &desc, dd4hep::xml::Hand } bool debugGeometry = detElem.hasChild(_Unicode(debugGeometry)); + bool useG4TT = detElem.hasChild(_Unicode(useG4TT)); auto gasElem = detElem.child("gas"); auto gasvolMat = desc.material(gasElem.attr(_Unicode(material))); auto gasvolVis = desc.visAttributes(gasElem.attr(_Unicode(vis))); @@ -285,7 +288,9 @@ static dd4hep::Ref_t create_DCH_o1_v02(dd4hep::Detector &desc, dd4hep::xml::Hand DCH_length_t cell_rout_zLhalf = DCH_i->Radius_zLhalf(cell_rout_z0); DCH_length_t cell_dz = DCH_i->Lhalf; DCH_angle_t cell_phi_width = phi_step - safety_phi_interspace; - dd4hep::TwistedTube cell_s( cell_twistangle, cell_rin_zLhalf, cell_rout_zLhalf, cell_dz, 1, cell_phi_width); + dd4hep::Solid cell_s; + if( useG4TT ) cell_s = dd4hep::TwistedTube ( cell_twistangle, cell_rin_zLhalf, cell_rout_zLhalf, cell_dz, 1, cell_phi_width); + else cell_s = CompositeTT(cell_twistangle, cell_rin_z0, cell_rout_z0, cell_dz, cell_phi_width, *DCH_i); // initialize cell volume std::string cell_name = detName+"_layer"+std::to_string(ilayer)+"_cell"; @@ -510,6 +515,81 @@ static dd4hep::Ref_t create_DCH_o1_v02(dd4hep::Detector &desc, dd4hep::xml::Hand } +inline double Circumradius(double Apothem, double dphi){return Apothem/cos(0.5*dphi/dd4hep::rad);} + +dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_rout_z0, double dz, double dphi, const dd4hep::rec::DCH_info & DCH_i) +{ + + //----------------- G. trapezoid ------------- + // make generic trapezoid bigger, later intersected with hyperboloid of proper radii + double rmin_zLhalf = DCH_i.Radius_zLhalf(cell_rin_z0 ); + double rout_zLhalf = DCH_i.Radius_zLhalf(cell_rout_z0); + double trap_rin = 0.9*rmin_zLhalf; + double trap_rout = Circumradius(1.1*rout_zLhalf, dphi); + + double poly_angle = dphi/2; + double twist_angle_half = twist_angle/2.; + // change sign, so the final shape has the same orientation as G4 twisted tube + twist_angle_half*= -1; + + // define points of 8 genenric trapezoid + struct point2d + { + double x = {0.0}; + double y = {0.0}; + }; + + struct face + { + point2d A; + point2d B; + point2d C; + point2d D; + }; + + face fZneg; + face fZpos; + + fZpos.A = { trap_rin*cos( poly_angle + twist_angle_half ), trap_rin*sin( poly_angle + twist_angle_half ) }; + fZpos.B = { trap_rin*cos( -poly_angle + twist_angle_half ), trap_rin*sin( -poly_angle + twist_angle_half ) }; + + fZneg.A = { trap_rin*cos( poly_angle - twist_angle_half ), trap_rin*sin( poly_angle - twist_angle_half ) }; + fZneg.B = { trap_rin*cos( -poly_angle - twist_angle_half ), trap_rin*sin( -poly_angle - twist_angle_half ) }; + + fZpos.C = { trap_rout*cos( poly_angle + twist_angle_half ), trap_rout*sin( poly_angle + twist_angle_half ) }; + fZpos.D = { trap_rout*cos( -poly_angle + twist_angle_half ), trap_rout*sin( -poly_angle + twist_angle_half ) }; + + fZneg.C = { trap_rout*cos( poly_angle - twist_angle_half ), trap_rout*sin( poly_angle - twist_angle_half ) }; + fZneg.D = { trap_rout*cos( -poly_angle - twist_angle_half ), trap_rout*sin( -poly_angle - twist_angle_half ) }; + + std::vector vertices_array = { fZpos.B.x, fZpos.B.y, + fZpos.A.x, fZpos.A.y, + fZpos.C.x, fZpos.C.y, + fZpos.D.x, fZpos.D.y, + fZneg.B.x, fZneg.B.y, + fZneg.A.x, fZneg.A.y, + fZneg.C.x, fZneg.C.y, + fZneg.D.x, fZneg.D.y + }; + + dd4hep::EightPointSolid gtrap_shape(dz, vertices_array.data() ); + + //----------------- Hyperboloid ------------- + // ROOT hyperboloid require stereoangles stin and stout + //-- stereo for rmin + double stin = DCH_i.stereoangle_z0(cell_rin_z0); + //-- stereo for rour + double stout = DCH_i.stereoangle_z0(cell_rout_z0); + + // make hyperboloid longer, later intersection with gtrap will lead to proper length + double dz_safe = 1.1*dz; + dd4hep::Hyperboloid layer_s(cell_rin_z0, stin, cell_rout_z0, stout, dz_safe); + + // create a twisted tube as intersection of the generic trapezoid and the hyperboloid + dd4hep::Solid mytt = dd4hep::IntersectionSolid(gtrap_shape,layer_s); + return mytt; +} + }; // end DCH_v2 namespace From 4c1b642011582af4b7b5f9d1bfd23c2f3519c413 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 12:41:47 +0100 Subject: [PATCH 127/133] overlap test is slower now... --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5ccbce058..8f80a3fa7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -169,7 +169,7 @@ SET( test_name "test_DCH_o1_v02_overlap" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/compact/DCH_standalone_o1_v02.xml --runType run --part.userParticleHandler= --macroFile=${CMAKE_CURRENT_SOURCE_DIR}/../utils/overlap.mac ) SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Exception;EXCEPTION;ERROR;Error" ) -set_tests_properties( t_${test_name} PROPERTIES TIMEOUT 60) +set_tests_properties( t_${test_name} PROPERTIES TIMEOUT 400) endif() #-------------------------------------------------- From 8741db27287de963f21bf23f4ec6fc1970181ce0 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 13:28:21 +0100 Subject: [PATCH 128/133] fix typo, thanks Andre! --- detector/tracker/DriftChamber_o1_v02.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detector/tracker/DriftChamber_o1_v02.cpp b/detector/tracker/DriftChamber_o1_v02.cpp index 04f5d4842..81185f32b 100644 --- a/detector/tracker/DriftChamber_o1_v02.cpp +++ b/detector/tracker/DriftChamber_o1_v02.cpp @@ -578,7 +578,7 @@ dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_ // ROOT hyperboloid require stereoangles stin and stout //-- stereo for rmin double stin = DCH_i.stereoangle_z0(cell_rin_z0); - //-- stereo for rour + //-- stereo for rout double stout = DCH_i.stereoangle_z0(cell_rout_z0); // make hyperboloid longer, later intersection with gtrap will lead to proper length From 549894465bc20d5650b32533aa2e9ea317e3c7f1 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 13:31:55 +0100 Subject: [PATCH 129/133] extend time out limit for full IDEA test --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8f80a3fa7..5b6df935b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -111,7 +111,7 @@ if(DCH_INFO_H_EXIST) SET( test_name "test_IDEA_with_DRC_o1_v03" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/compact/IDEA_withDRC_o1_v03.xml --steeringFile=${CMAKE_CURRENT_SOURCE_DIR}/../example/SteeringFile_IDEA_o1_v03.py -G --gun.distribution uniform --random.seed 1988301045 ) - SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) + SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 900) endif() #-------------------------------------------------- From f95da2458996f3a6661fb11c3abbfe61777e47da Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 13:40:26 +0100 Subject: [PATCH 130/133] add comments about how to build the compositeTT --- detector/tracker/DriftChamber_o1_v02.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/detector/tracker/DriftChamber_o1_v02.cpp b/detector/tracker/DriftChamber_o1_v02.cpp index 81185f32b..b2b0c7703 100644 --- a/detector/tracker/DriftChamber_o1_v02.cpp +++ b/detector/tracker/DriftChamber_o1_v02.cpp @@ -517,6 +517,8 @@ static dd4hep::Ref_t create_DCH_o1_v02(dd4hep::Detector &desc, dd4hep::xml::Hand inline double Circumradius(double Apothem, double dphi){return Apothem/cos(0.5*dphi/dd4hep::rad);} +/// Solid equivalent to a twisted tube, resulting from the intersection of an hyperboloid and a generic trapezoid +/// the hyperboloid provides the hyperboloidal surfaces, the trapezoid provides the other two types of surfaces dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_rout_z0, double dz, double dphi, const dd4hep::rec::DCH_info & DCH_i) { From 16d32b7260b4145c4ef47c2d078dad21641c9cd1 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 13:48:25 +0100 Subject: [PATCH 131/133] add comments --- detector/tracker/DriftChamber_o1_v02.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/detector/tracker/DriftChamber_o1_v02.cpp b/detector/tracker/DriftChamber_o1_v02.cpp index b2b0c7703..d1829b920 100644 --- a/detector/tracker/DriftChamber_o1_v02.cpp +++ b/detector/tracker/DriftChamber_o1_v02.cpp @@ -519,6 +519,7 @@ inline double Circumradius(double Apothem, double dphi){return Apothem/cos(0.5*d /// Solid equivalent to a twisted tube, resulting from the intersection of an hyperboloid and a generic trapezoid /// the hyperboloid provides the hyperboloidal surfaces, the trapezoid provides the other two types of surfaces +/// the generic trapezoid is built in such a manner that circumscribe the twisted tube dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_rout_z0, double dz, double dphi, const dd4hep::rec::DCH_info & DCH_i) { @@ -552,6 +553,9 @@ dd4hep::Solid CompositeTT(double twist_angle, double cell_rin_z0, double cell_ face fZneg; face fZpos; + // The generic trapezoid is built in such a manner as to circumscribe the twisted tube + // The following points correspond to the corners of the twisted tube + fZpos.A = { trap_rin*cos( poly_angle + twist_angle_half ), trap_rin*sin( poly_angle + twist_angle_half ) }; fZpos.B = { trap_rin*cos( -poly_angle + twist_angle_half ), trap_rin*sin( -poly_angle + twist_angle_half ) }; From 953bfc13733eca587874d545a52a6d430c83a670 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado Date: Mon, 16 Dec 2024 14:34:38 +0100 Subject: [PATCH 132/133] extend test time out --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5b6df935b..131736ffa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -102,7 +102,7 @@ if(DCH_INFO_H_EXIST) SET( test_name "test_IDEA_o1_v03" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml -N 1 -G --gun.distribution uniform --random.seed 1988301045 ) - SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 100) + SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 300) endif() #-------------------------------------------------- From d7fec087cd0494d6973835bb2b4a546564d09066 Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Fri, 3 Jan 2025 20:46:25 +0100 Subject: [PATCH 133/133] Remove colorflow, needed after https://github.com/key4hep/EDM4hep/pull/389 (#417) --- plugins/Geant4Output2EDM4hep_DRC.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/Geant4Output2EDM4hep_DRC.cpp b/plugins/Geant4Output2EDM4hep_DRC.cpp index 6d408424e..fad2fde9f 100644 --- a/plugins/Geant4Output2EDM4hep_DRC.cpp +++ b/plugins/Geant4Output2EDM4hep_DRC.cpp @@ -401,7 +401,6 @@ void Geant4Output2EDM4hep_DRC::saveParticles(Geant4ParticleMap* particles) { mcp.setGeneratorStatus( 0 ) ; mcp.setSpin(p->spin); - mcp.setColorFlow(p->colorFlow); p_ids[id] = cnt++; p_part.push_back(p);