From b464a1fb0b954d689f44760f607e3925ba78021f Mon Sep 17 00:00:00 2001 From: jmcarcell Date: Fri, 6 Sep 2024 22:14:05 +0200 Subject: [PATCH 001/134] 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 002/134] 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 003/134] 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 004/134] 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 005/134] 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 006/134] 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 007/134] 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 008/134] 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 009/134] 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 010/134] 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 017/134] [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 018/134] 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 019/134] 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 020/134] 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 021/134] 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 022/134] 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 023/134] 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 024/134] 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 025/134] 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 026/134] 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 027/134] 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 028/134] 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 029/134] 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 030/134] 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 031/134] 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 032/134] 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 033/134] 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 034/134] [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 035/134] 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 036/134] 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 037/134] 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 038/134] 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 039/134] 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 040/134] 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 041/134] 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 042/134] 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 043/134] 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 044/134] 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 045/134] 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 046/134] 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 047/134] 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 048/134] 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 049/134] 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 050/134] 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 051/134] 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 052/134] 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 053/134] 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 054/134] 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 055/134] 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 056/134] 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 057/134] 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 058/134] 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 059/134] 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 060/134] 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 061/134] 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 062/134] 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 063/134] 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 064/134] 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 065/134] 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 066/134] 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 067/134] 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 068/134] 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 069/134] 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 070/134] 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 071/134] 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 072/134] 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 073/134] 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 074/134] 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 075/134] 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 076/134] 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 077/134] 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 078/134] 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 079/134] 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 080/134] 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 081/134] 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 082/134] 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 083/134] 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 084/134] 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 085/134] 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 086/134] 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 087/134] 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 088/134] 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 089/134] 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 090/134] 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 091/134] 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 092/134] 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 093/134] 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 094/134] 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 095/134] 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 096/134] 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 097/134] 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 098/134] 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 099/134] 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 100/134] 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); From c57742cefdeb71f171bbbef2de4eb01158b7621b Mon Sep 17 00:00:00 2001 From: scott-snyder Date: Wed, 22 Jan 2025 16:54:53 +0000 Subject: [PATCH 101/134] Avoid potential use of dangling temporary objects. (#418) --- detectorCommon/src/DetUtils_k4geo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detectorCommon/src/DetUtils_k4geo.cpp b/detectorCommon/src/DetUtils_k4geo.cpp index 711118248..624a530f5 100644 --- a/detectorCommon/src/DetUtils_k4geo.cpp +++ b/detectorCommon/src/DetUtils_k4geo.cpp @@ -452,7 +452,7 @@ std::array tubeEtaExtremes(uint64_t aVolumeId) { // check if it is a cylinder centred at z=0 dd4hep::VolumeManager volMgr = dd4hep::Detector::getInstance().volumeManager(); auto detelement = volMgr.lookupDetElement(aVolumeId); - const auto& transformMatrix = detelement.nominal().worldTransformation(); + const auto transformMatrix = detelement.nominal().worldTransformation(); double outGlobal[3]; double inLocal[] = {0, 0, 0}; // to get middle of the volume transformMatrix.LocalToMaster(inLocal, outGlobal); @@ -477,7 +477,7 @@ std::array tubeEtaExtremes(uint64_t aVolumeId) { std::array envelopeEtaExtremes (uint64_t aVolumeId) { dd4hep::VolumeManager volMgr = dd4hep::Detector::getInstance().volumeManager(); auto detelement = volMgr.lookupDetElement(aVolumeId); - const auto& transformMatrix = detelement.nominal().worldTransformation(); + const auto transformMatrix = detelement.nominal().worldTransformation(); // calculate values of eta in all possible corners of the envelope auto dim = envelopeDimensions(aVolumeId); double minEta = 0; From c2455bc3d2905362ef921546059d979785349c8c Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 26 Nov 2024 10:01:09 +0100 Subject: [PATCH 102/134] Add DRBarrelTubes calorimeter subdetector Co-authored-by: Andreas Loeschcke Centeno --- .../include/DRTubesconstructor.h | 144 ++++ .../dual-readout-tubes/include/DRutils.h | 23 + .../dual-readout-tubes/src/DDDRCaloTubes.cpp | 55 ++ .../src/DRTubesconstructor.cpp | 710 ++++++++++++++++++ .../dual-readout-tubes/src/DRutils.cpp | 61 ++ 5 files changed, 993 insertions(+) create mode 100644 detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h create mode 100644 detector/calorimeter/dual-readout-tubes/include/DRutils.h create mode 100644 detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp create mode 100644 detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp create mode 100644 detector/calorimeter/dual-readout-tubes/src/DRutils.cpp diff --git a/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h new file mode 100644 index 000000000..f3cec11a6 --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h @@ -0,0 +1,144 @@ +#ifndef DRconstructor_H +#define DRconstructor_H 1 + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Objects.h" +#include "XML/Layering.h" +#include "XML/Utilities.h" +#include "DDRec/DetectorData.h" + +#include "DRutils.h" + +using namespace dd4hep; + +namespace DDDRCaloTubes { + +class DRTubesconstructor { +public: + // Constructor + DRTubesconstructor(Detector* description, + xml_h& entities, + SensitiveDetector* sens); + + // Destructor + ~DRTubesconstructor() {} + + void calculate_tower_parameters(); + void calculate_phi_parameters(); + void calculate_theta_parameters(); + void prepare_tube_volumes(); + void assert_tube_existence(int key, bool cher); + double calculate_trap_width(double given_y, double given_z, bool backface = false); + double calculate_tower_width(int given_row, bool backface = true); + void assemble_tower(Volume& tower_air_volume); + void construct_tower_trapezoid(Volume& trap_volume); + void calculate_tower_position(); + void construct_tower(Volume& trap_volume); + void increase_covered_theta(const double& delta_theta) {m_covered_theta += delta_theta;} + void place_tower(Volume& stave_volume, + Volume& tower_volume, + unsigned int layer); + + void construct_calorimeter(Volume& calorimeter_volume); + +private: + Detector* m_description; + xml_h m_entities; + SensitiveDetector* m_sens; + + // Calorimeter parameters + double m_calo_inner_r; + double m_calo_outer_r; + double m_calo_inner_half_z; + + double m_barrel_endcap_angle; // calculated from m_calo_inner_half_z and m_calo_inner_r + + // Tube parameters + double m_capillary_outer_r; + double m_scin_clad_outer_r; + double m_scin_core_outer_r; + double m_cher_clad_outer_r; + double m_cher_core_outer_r; + Material m_capillary_material; + Material m_scin_clad_material; + Material m_scin_core_material; + Material m_cher_clad_material; + Material m_cher_core_material; + std::string m_capillary_visString; + std::string m_scin_clad_visString; + std::string m_scin_core_visString; + std::string m_cher_clad_visString; + std::string m_cher_core_visString; + bool m_capillary_isSensitive; + bool m_scin_clad_isSensitive; + bool m_scin_core_isSensitive; + bool m_cher_clad_isSensitive; + bool m_cher_core_isSensitive; + + + std::unordered_map m_scin_tube_volume_map; + std::unordered_map m_cher_tube_volume_map; + + double m_tolerance; + + double m_capillary_diameter; // calculated from m_capillary_outer_r + + // Constants used through the function (calculated from other parameters) + // double m_D; // Long diagonal of hexagaon with capillary_outer_r as inradius + double m_V; // Vertical spacing for pointy top oriented tubes + + // Tower parameters + double m_tower_theta; + double m_tower_phi; + + double m_tower_half_phi; + double m_tower_tan_half_phi; // calculated from m_tower_phi + double m_tower_half_length; // calculated from m_calo_inner_r and m_calo_outer_r and m_trap_half_length + + // Tower Phi parameters + unsigned int m_num_phi_towers; // number of towers in phi direction + double m_tower_frontface_rightangleedge_x; + double m_tower_frontface_thetaangleedge_x; + double m_tower_backface_rightangleedge_x; + double m_tower_backface_thetaangleedge_x; + double m_angle_edges_x; + + // Tower Theta parameters + double m_tower_tan_theta; + double m_tower_frontface_y; + double m_tower_backface_y; + double m_tower_polar_angle; + double m_tower_azimuthal_angle; + + // Trapezoid support parameters + double m_stave_half_length; + double m_trap_wall_thickness_sides; + double m_trap_wall_thickness_front; + double m_trap_wall_thickness_back; + double m_trap_frontface_rightangleedge_x; // width for frontface + double m_trap_frontface_thetaangleedge_x; + double m_trap_backface_rightangleedge_x; // width for backface + double m_trap_backface_thetaangleedge_x; + double m_trap_frontface_y; // height for frontface + double m_trap_backface_y; // height for backface + double m_trap_azimuthal_angle; // azimuthal angle for the trapezoid + double m_trap_polar_angle; // polar angle for the trapezoid + double m_trap_half_length; // half length for the trapezoid + Material m_trap_material; + std::string m_trap_visString; + + + // Construction parameters + double m_covered_theta; + double m_back_shift; + Position m_tower_position; + // Assembly* m_tower_volume; + + Material m_air; + std::string m_air_visString; + +}; + +} // namespace DDDRCaloTubes + +#endif // DRCONSTRUCTOR_H diff --git a/detector/calorimeter/dual-readout-tubes/include/DRutils.h b/detector/calorimeter/dual-readout-tubes/include/DRutils.h new file mode 100644 index 000000000..8c6c03090 --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/include/DRutils.h @@ -0,0 +1,23 @@ +#ifndef DRutils_h +#define DRutils_h 1 + +#include + +#include "DD4hep/Objects.h" +#include "DD4hep/DD4hepUnits.h" + +using namespace dd4hep; + +namespace DDDRCaloTubes +{ + int fast_floor(double x); + int fast_ceil(double x); + bool check_for_integer(double x); + + std::vector get_plane_equation(const Position& point1, const Position& point2, const Position& point3); + Position get_intersection(const std::vector& plane_coefficients, const Position& line_point, const Direction& line_direction); + Position get_intersection(const Direction& plane_normal, const Position& plane_point, const Position& line_point, const Direction& line_direction); + double distance_from_plane(const std::vector& plane_coefficients, const Position& point); +} // namespace DDDRCaloTubes + +#endif // DRutils_h diff --git a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp b/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp new file mode 100644 index 000000000..e67856844 --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp @@ -0,0 +1,55 @@ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Objects.h" +#include "XML/Layering.h" +#include "XML/Utilities.h" +#include "DDRec/DetectorData.h" + +#include "DRutils.h" +#include "DRTubesconstructor.h" + +using namespace dd4hep; + + +static Ref_t create_detector(Detector& description, + xml_h entities, + SensitiveDetector sens) +{ + xml_det_t x_det = entities; + int det_id = x_det.id(); + std::string det_name = x_det.nameStr(); + + Material air = description.air(); + + sens.setType("calorimeter"); + + // Cylinder encompassing entire calorimeter + xml_dim_t x_dim = x_det.dimensions(); + double calo_inner_r = x_dim.inner_radius(); + double calo_outer_r = x_dim.outer_radius(); + + double tower_length = calo_outer_r - calo_inner_r; + if (tower_length<=0*mm) throw std::runtime_error("Outer calorimeter radius needs to be larger than inner radius"); + + Assembly barrel_volume("calorimeter_barrel"); + barrel_volume.setMaterial(air); + barrel_volume.setVisAttributes(description, "assembly_vis"); + + DetElement s_detElement(det_name, det_id); + Volume mother_volume = description.pickMotherVolume(s_detElement); + + + DDDRCaloTubes::DRTubesconstructor constructor(&description, entities, &sens); + constructor.construct_calorimeter(barrel_volume); + + + PlacedVolume barrel_placed = mother_volume.placeVolume(barrel_volume); + barrel_placed.addPhysVolID("system", det_id); + s_detElement.setPlacement(barrel_placed); + + + + return s_detElement; +} + + +DECLARE_DETELEMENT(DDDRCaloTubes,create_detector) diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp new file mode 100644 index 000000000..bf5ed1c96 --- /dev/null +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -0,0 +1,710 @@ +#include "DRTubesconstructor.h" + +#include + +using namespace dd4hep; +using namespace DDDRCaloTubes; + +DDDRCaloTubes::DRTubesconstructor::DRTubesconstructor(Detector* description, + xml_h& entities, + SensitiveDetector* sens): + m_entities(entities) +{ + // Initialising the all the calorimeter and tower variables + + m_description = description; + m_sens = sens; + + xml_dim_t x_dim = ((xml_det_t) entities).dimensions(); + + // Calorimeter parameters + m_calo_inner_r = x_dim.inner_radius(); + m_calo_outer_r = x_dim.outer_radius(); + m_calo_inner_half_z = x_dim.z_length(); + + + // Trap parameters + xml_comp_t x_trap = entities.child(_Unicode(trap)); + xml_comp_t x_trap_support = x_trap.child(_Unicode(support)); + m_trap_wall_thickness_front = x_trap_support.depth(); + m_trap_wall_thickness_sides = x_trap_support.width(); + m_trap_wall_thickness_back = x_trap_support.z2(); + m_trap_material = m_description->material(x_trap_support.materialStr()); + m_trap_visString = x_trap_support.visStr(); + + + // Tube parameters + xml_comp_t x_tube = entities.child(_Unicode(tube)); + + xml_comp_t x_capillary = x_tube.child(_Unicode(capillary)); + m_capillary_material = m_description->material(x_capillary.materialStr()); + m_capillary_outer_r = x_capillary.outer_r(); + m_capillary_visString = x_capillary.visStr(); + m_capillary_isSensitive = x_capillary.isSensitive(); + m_tolerance = x_capillary.threshold(50*um); + + xml_comp_t x_scin_clad = x_tube.child(_Unicode(scin_clad)); + m_scin_clad_material = m_description->material(x_scin_clad.materialStr()); + m_scin_clad_outer_r = x_scin_clad.outer_r(); + m_scin_clad_visString = x_scin_clad.visStr(); + m_scin_clad_isSensitive = x_scin_clad.isSensitive(); + + xml_comp_t x_scin_core = x_tube.child(_Unicode(scin_core)); + m_scin_core_material = m_description->material(x_scin_core.materialStr()); + m_scin_core_outer_r = x_scin_core.outer_r(); + m_scin_core_visString = x_scin_core.visStr(); + m_scin_core_isSensitive = x_scin_core.isSensitive(); + + xml_comp_t x_cher_clad = x_tube.child(_Unicode(cher_clad)); + m_cher_clad_material = m_description->material(x_cher_clad.materialStr()); + m_cher_clad_outer_r = x_cher_clad.outer_r(); + m_cher_clad_visString = x_cher_clad.visStr(); + m_cher_clad_isSensitive = x_cher_clad.isSensitive(); + + xml_comp_t x_cher_core = x_tube.child(_Unicode(cher_core)); + m_cher_core_material = m_description->material(x_cher_core.materialStr()); + m_cher_core_outer_r = x_cher_core.outer_r(); + m_cher_core_visString = x_cher_core.visStr(); + m_cher_core_isSensitive = x_cher_core.isSensitive(); + + // Some safety checks for the entered tube parameters + if (m_capillary_outer_r <= 0.0*mm) throw std::runtime_error("Capillary radius needs to be larger than 0"); + if (m_capillary_outer_r < m_scin_clad_outer_r || m_capillary_outer_r < m_cher_clad_outer_r) throw std::runtime_error("Capillary radius needs to be larger than scintillation cladding and cherenkov cladding radii"); + if (m_scin_clad_outer_r < m_scin_core_outer_r) throw std::runtime_error("Scintillation cladding radius needs to be larger than scintillation core radius"); + if (m_cher_clad_outer_r < m_cher_core_outer_r) throw std::runtime_error("Cherenkov cladding radius needs to be larger than cherenkov core radius"); + + + // Tower parameters + m_tower_theta = x_dim.deltatheta(); + m_tower_phi = x_dim.deltaphi(); + + + // Construction parameters which change for each placed tower in a stave + m_covered_theta = 0.0*deg; + m_back_shift = 0.0*mm; + + // Calculate all the derived parameters which are not taken from the xml file + this->calculate_tower_parameters(); + this->calculate_phi_parameters(); + + m_tower_tan_theta = 0.0; + + m_air = m_description->material("Air"); + + xml_comp_t x_air = x_trap.child(_Unicode(air)); + m_air = m_description->material(x_air.materialStr()); + m_air_visString = x_air.visStr(); + +} + +// Function to calculate all tower parameters which are derived from user given values +void DDDRCaloTubes::DRTubesconstructor::calculate_tower_parameters() +{ + // Angle where endcap and barrel meet + m_barrel_endcap_angle = std::atan2(m_calo_inner_half_z, m_calo_inner_r); + + m_capillary_diameter = 2*m_capillary_outer_r; + + // Constants used through the function + double D = 4.0*m_capillary_outer_r/sqrt(3.0); // Long diagonal of hexagaon with capillary_outer_r as inradius + m_V = 3.0*D/4.0; // Vertical spacing for pointy top oriented tubes + + // Some values which are used multiple times are calculated here once + m_tower_half_phi = m_tower_phi/2.0; // Half of the tower phi angle + m_tower_tan_half_phi = std::tan(m_tower_half_phi); // Needed several times, calculate once here + + + m_stave_half_length = (m_calo_outer_r*std::cos(m_tower_half_phi) - m_calo_inner_r)/2; // Trapezoid half length + + // Protection against tilted towers in theta going past the outer radius of the calorimeter + double protect_covered_z = std::tan(m_tower_theta)*m_calo_inner_r; + double protect_tower_z = std::tan(2*m_tower_theta)*m_calo_inner_r - protect_covered_z; + double protect_back_shift = std::sin(m_tower_theta)*protect_tower_z; + + // "_trap_" always* refers to the Trap volume including the support structure + m_trap_half_length = m_stave_half_length/std::cos(m_tower_theta) - protect_back_shift/2; + + // "_tower_" always* refers to the collection of tubes forming the tower + // "Tower" volume encapsulates the air, which is "hollowing out" the trapezoid volume + m_tower_half_length = m_trap_half_length - m_trap_wall_thickness_front/2.0 - m_trap_wall_thickness_back/2.0; // Tower half length + + // * "always" means that I tried to use it consistently, but there might be exceptions (like m_tower_phi&theta refer to the full strucutre, including support) + // due to the history of the code, where I started out without the support, only the collection of tubes +} + +// Function to calculate tower parameters specifically for phi direction +void DDDRCaloTubes::DRTubesconstructor::calculate_phi_parameters() +{ + double num_phi_towers_d = 360.0*deg/m_tower_phi; + if (num_phi_towers_d < 0.0) throw std::runtime_error("Negative tower phi coverage not allowed"); + // Check if num_phi_towers is a whole number + if (check_for_integer(num_phi_towers_d)) m_num_phi_towers = static_cast(std::round(num_phi_towers_d)); + else throw std::runtime_error("Not an integer number of towers in phi direction"); + + +} + +// Function to calculate the size parameters for the trap volume (including support) +// Depends a lot on m_covered_theta, which is increased with each tower placement in theta direction +/* Sketch of a tower in the z-x (or z-y) plane + ____________ + | / Each tower is a trapezoid with a front face (bottom in the sketch) and a back face (top in the sketch) + | / The front face is narrower than the back face, to ensure that the tower is projective + | / Also each tower has a right angled face with the front and back face (left in the sketch) + | / and a theta angle side (right in the sketch) + | / Anytime a variable contains "edge" it refers to the edge that would be running in y direction in this sketch with global coordinates + | / (but would be x direction in the local coordinate system of the Trap volume) + x | / + ^ | / + | |___/ + | + |____> z + +*/ +void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() +{ + // How much the front faces of the placed towers cover in z direction in the global coordinate system + double covered_z = std::tan(m_covered_theta)*m_calo_inner_r; + + // The cummulative theta value which this trapezoid will cover once placed + double trap_theta = m_covered_theta+m_tower_theta; + // Distance the front face of this trapezoid will cover in z + double trap_z = std::tan(trap_theta)*m_calo_inner_r - covered_z; + // Tower height + double trap_frontface_y = std::cos(m_covered_theta)*trap_z; + + if (trap_frontface_y < m_capillary_diameter) + { + throw std::runtime_error("Can't construct tower with given tower_theta and calo_inner_radius"); + } + + // Used throughout construction, so calculate once here + m_tower_tan_theta = std::tan(m_tower_theta); + + // Front and back face of the trapezoid + m_trap_frontface_y = trap_frontface_y; + m_trap_backface_y = trap_frontface_y + 2*m_trap_half_length*m_tower_tan_theta; // calculated based on how much the tower widens in the back + + // Tower sizes based on the wall thickness of the "support" envelope (needs adjustment for angles of tower) + m_tower_frontface_y = m_trap_frontface_y + m_trap_wall_thickness_front*m_tower_tan_theta - m_trap_wall_thickness_sides*(1+1/std::cos(m_tower_theta)); + m_tower_backface_y = m_trap_backface_y - m_trap_wall_thickness_back*m_tower_tan_theta - m_trap_wall_thickness_sides*(1+1/std::cos(m_tower_theta)); + + // Distance by which right angle edge of this tower is shifted backwards to ensure inner radius of calorimeter + m_back_shift = std::tan(m_covered_theta)*m_trap_frontface_y; + + // Width in y direction in sketch above (x direction in local coordinates) + m_trap_frontface_rightangleedge_x = (m_calo_inner_r+std::cos(m_covered_theta)*m_back_shift)*2*m_tower_tan_half_phi; + m_trap_frontface_thetaangleedge_x = m_calo_inner_r*2*m_tower_tan_half_phi; + + // by how much the backface widens for both tower and trap for the right angled side of the tower + double tower_backface_phi_increase_rightangleedge = 2*m_trap_half_length*std::cos(m_covered_theta) * 2*m_tower_tan_half_phi; + // the theta angles side widens differently, because they are not the same length + double tower_backface_phi_increase_thetaangleedge = 2*m_trap_half_length/std::cos(m_tower_theta)*std::cos(m_covered_theta+m_tower_theta) * 2*m_tower_tan_half_phi; + + m_trap_backface_rightangleedge_x = m_trap_frontface_rightangleedge_x + tower_backface_phi_increase_rightangleedge; + m_trap_backface_thetaangleedge_x = m_trap_frontface_thetaangleedge_x + tower_backface_phi_increase_thetaangleedge; + + // The effective thickness is used to calculate the size of the "air" tower volume + // It takes into account, that the wall is tilted in phi direction + double effective_side_wall_thickness_x = m_trap_wall_thickness_sides/std::cos(m_tower_phi); + + // When looking at the tower from the front (or back), the angle created by a vertical line and the sides of the tower + m_angle_edges_x = std::atan2((m_trap_backface_rightangleedge_x-m_trap_backface_thetaangleedge_x)/2.0, m_trap_backface_y); + /* + ________________ + \ / So the angle in the bottom left (or right) corner here + \ _| / + y^ \ | / + | \|_______/ + | + |______> x + + */ + + // Calculating all tower widths (horizontal lines in sketch above) for both front and back face (in z direction) + m_tower_frontface_rightangleedge_x = calculate_trap_width(m_trap_wall_thickness_sides, m_trap_wall_thickness_front, false) - 2.0*effective_side_wall_thickness_x; + + m_tower_backface_rightangleedge_x = calculate_trap_width(m_trap_wall_thickness_sides, m_trap_wall_thickness_back, true) - 2.0*effective_side_wall_thickness_x; + + m_tower_frontface_thetaangleedge_x = calculate_trap_width(m_tower_frontface_y+m_trap_wall_thickness_sides, m_trap_wall_thickness_front, false) - 2*effective_side_wall_thickness_x; + + m_tower_backface_thetaangleedge_x = calculate_trap_width(m_tower_backface_y+m_trap_wall_thickness_sides, m_trap_wall_thickness_back, true) - 2*effective_side_wall_thickness_x; + +} + + +// Check if tube of this (half-)length already exists, if not, create it +void DDDRCaloTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher) +{ + std::unordered_map* tube_volume_map; + + // Select the right volume maps depending on whether we are creating cherenkov or scintillation tubes + if (cher) { + tube_volume_map = &m_cher_tube_volume_map; + } else { + tube_volume_map = &m_scin_tube_volume_map; + } + + // If this length already exists, return + if (tube_volume_map->find(key) != tube_volume_map->end()) return; + + // The map key is the multiple of the tolerance forming the tube length + double length_rounded_down = key*m_tolerance; + // std::cout << "Creating tube with length " << length_rounded_down/mm << " mm" << std::endl; + + // Creating the volumes + // Capillary tube + Tube capillary_solid(0.0*mm, m_capillary_outer_r, length_rounded_down); + Volume capillary_volume("capillary", capillary_solid, m_capillary_material); + if (m_capillary_isSensitive) capillary_volume.setSensitiveDetector(*m_sens); + capillary_volume.setVisAttributes(*m_description, m_capillary_visString); + + // Create the right fibres + if (cher) + { + // Cherenkov cladding + Tube cher_clad_solid(0.0*mm, m_cher_clad_outer_r, length_rounded_down); + Volume cher_clad_volume("cher_clad", cher_clad_solid, m_cher_clad_material); + if (m_cher_clad_isSensitive) cher_clad_volume.setSensitiveDetector(*m_sens); + PlacedVolume cher_clad_placed = capillary_volume.placeVolume(cher_clad_volume); + cher_clad_volume.setVisAttributes(*m_description, m_cher_clad_visString); + cher_clad_placed.addPhysVolID("clad", 1).addPhysVolID("cherenkov", 1); + + // Chrerenkov core + Tube cher_core_solid(0.0*mm, m_cher_core_outer_r, length_rounded_down); + Volume cher_core_volume("DRBT_cher_core", cher_core_solid, m_cher_core_material); + if (m_cher_core_isSensitive) cher_core_volume.setSensitiveDetector(*m_sens); + PlacedVolume cher_core_placed = cher_clad_volume.placeVolume(cher_core_volume); + cher_core_volume.setVisAttributes(*m_description, m_cher_core_visString); + cher_core_placed.addPhysVolID("core", 1).addPhysVolID("clad", 0); + + } else { + // Scintillation cladding + Tube scin_clad_solid(0.0*mm, m_scin_clad_outer_r, length_rounded_down); + Volume scin_clad_volume("scin_clad", scin_clad_solid, m_scin_clad_material); + if (m_scin_clad_isSensitive) scin_clad_volume.setSensitiveDetector(*m_sens); + PlacedVolume scin_clad_placed = capillary_volume.placeVolume(scin_clad_volume); + scin_clad_volume.setVisAttributes(*m_description, m_scin_clad_visString); + scin_clad_placed.addPhysVolID("clad", 1).addPhysVolID("cherenkov", 0); + + // Scintillation core + Tube scin_core_solid(0.0*mm, m_scin_core_outer_r, length_rounded_down); + Volume scin_core_volume("DRBT_scin_core", scin_core_solid, m_scin_core_material); + if (m_scin_core_isSensitive) scin_core_volume.setSensitiveDetector(*m_sens); + PlacedVolume scin_core_placed = scin_clad_volume.placeVolume(scin_core_volume); + scin_core_volume.setVisAttributes(*m_description, m_scin_core_visString); + scin_core_placed.addPhysVolID("core", 1).addPhysVolID("clad", 0); + } + + tube_volume_map->insert(std::make_pair(key, capillary_volume)); + +} + + +// Similar to calculate_tower_width (see abelow), but for the encasing trapezoid support volume +// Width is calculated for any given point in th z-y plane +double DDDRCaloTubes::DRTubesconstructor::calculate_trap_width(double given_y, double given_z, bool backface) +{ + // Calculate width (x_direction) of trapezoid at given y + // Assuming y=0 corresponds to right angle edge of the tower + if (given_z>2*m_trap_half_length) throw std::runtime_error("calculate_trap_width: Given z is larger than length of trapezoid"); + + // Since the height (in y direction of the trapezoid) changes along z, we need to calculate the maximum y for a given z + double max_y_for_given_z; + // given_z can be interpreted as distance from either the front or the back of the tower (in z direction) + if (backface) max_y_for_given_z = m_trap_backface_y - given_z*m_tower_tan_theta; + else max_y_for_given_z = m_trap_frontface_y + given_z*m_tower_tan_theta; + if (given_y > max_y_for_given_z) throw std::runtime_error("calculate_trap_width: Given y is larger than maximum y for given z"); + + // How much the width (x direction) changes due to the y position + double delta_y = -2.0*given_y*std::tan(m_angle_edges_x); + // How much the width (x direction) changes due to the z position + double delta_z; + if (backface) delta_z = -2.0*given_z*std::cos(m_covered_theta)*m_tower_tan_half_phi; + else delta_z = 2.0*given_z*std::cos(m_covered_theta)*m_tower_tan_half_phi; + + double trap_x; + if (backface) trap_x = m_trap_backface_rightangleedge_x + delta_y + delta_z; + else trap_x = m_trap_frontface_rightangleedge_x + delta_y + delta_z; + + return trap_x; + +} + + +// Calculate width of tower in x direction at given row of tubes +/* + Sketch of the tower volume shape in the xy plane + _____________________ + \ / + \-----------------/ Note that the width will not be calculated at the centre of the row + \ / but instead, where the tubes first touch the wall + y^ \ / + | \___________/ + | + |______> x + / + |/_ z */ +double DDDRCaloTubes::DRTubesconstructor::calculate_tower_width(int given_row, bool backface) +{ + // Calculate width (x_direction) of tower at given row + // Assuming row 0 is at the right angle edge + + // y distance where tube hits side of the wall with given angle between backfaces (y=0 corresponds to m_tower_backface_rightangleedge_x) + double y = m_capillary_outer_r + given_row*m_V + std::cos(90*deg-m_angle_edges_x)*m_capillary_outer_r; + + + double tower_x; + // Toggle between the back and front in z direction (not shown in sketch) + if (backface) tower_x = m_tower_backface_rightangleedge_x - 2.0*y*std::tan(m_angle_edges_x); + else tower_x = m_tower_frontface_rightangleedge_x - 2.0*y*std::tan(m_angle_edges_x); + + return tower_x; +} + + +// Place all tubes which make up the tower +void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) +{ + // Y-distance of rightangle wall from coordinate system origin + // Used throughout this function + double tower_centre_r = m_tower_half_length/std::cos(m_tower_polar_angle); + double tower_centre_half_y = tower_centre_r*std::sin(m_tower_polar_angle)*std::sin(m_tower_azimuthal_angle) + m_tower_frontface_y/2.0; + + + // Coordinates of corners of trapezoid + // when looking at the tower from the front with the right angle edge on top + Position back_upper_right_corner = Position(m_tower_backface_rightangleedge_x/2.0, -tower_centre_half_y, m_tower_half_length); + Position back_lower_right_corner = Position(m_tower_backface_thetaangleedge_x/2.0, tower_centre_half_y, m_tower_half_length); + Position front_upper_right_corner = Position(m_tower_frontface_rightangleedge_x/2.0, -tower_centre_half_y, -m_tower_half_length); + + // plane equations to calculate length of tubes at the tower sides + std::vector plane_right_coefficients = get_plane_equation(back_upper_right_corner, back_lower_right_corner, front_upper_right_corner); + Direction line_direction = Direction(0, 0, -1); + + // width of tower at row 0 (right angle edge) + // "at row X" meaning the width of the tower at the height of where the tubes first touch the wall in row X + double tower_x = calculate_tower_width(0); + + // number of total columns of tubes at the back face of the tower + unsigned int num_back_cols_rightangleedge = 1 + fast_floor((tower_x-2*std::sin(90*deg-m_angle_edges_x)*m_capillary_outer_r)/m_capillary_diameter); + + /* + Depending on even or odd number of tubes in the row, the column ID looks like this: + + Odd: \ O O O O O O O / + -6 -4 -2 0 2 4 6 central tube has column ID 0, then increasing by two (with negative values on one side) + + Even: \ O O O O O O / + -5 -3 -1 1 3 5 there is no single "central" tube, so start with one and increase by two + + This way, it's immediately clear if you are in a row with even number of tubes or not. + Easier for the position reconstruction, since there is an offset between even and odd rows in hexagonal stacking + Essentially following doubled offset coordinates from https://www.redblobgames.com/grids/hexagons/#coordinates-doubled + */ + + // Safety counter, should be 0 at the end + int num_bad_rows = 0; + + // How much distance in y is covered already by the tubes (increases in loop) + // This value is always: how much this row will cover, once it is placed (for checking when we need to start shortening tubes) + double covered_tower_y = m_capillary_diameter; + + // Number of rows of tubes in the back face of the tower + unsigned int num_rows = fast_floor((m_tower_backface_y-m_capillary_diameter)/m_V) + 1; + + std::cout << "TOTAL ROWS = " << num_rows << " COLS = " << num_back_cols_rightangleedge << std::endl; + + // Loop over the rows of tubes in the tower, starting at the right angle edge + for (unsigned int row = 0; row < num_rows; row++, covered_tower_y+=m_V) + { + + // Staggering of tubes at the lower edge (theta edge/face) + double row_staggered_z = 0.0*mm; + if (covered_tower_y > m_tower_frontface_y) row_staggered_z = (covered_tower_y-m_tower_frontface_y)/m_tower_tan_theta/2.0; + + // Failsafe for tubes which would have 'negative length' + // Should not happen, but if it does, following rows will also be too short, so can skip the rest + if (row_staggered_z > m_tower_half_length) { + num_bad_rows = num_rows-row; + std::cout << "Encountered bad row at row " << row << std::endl; + std::cout << "Number of leftover bad rows: " << num_bad_rows << std::endl; + break; + } + + + // Update the tower width for this row + tower_x = calculate_tower_width(row); + + // First row is the defining row. It has either even or odd number of tubes. + // The following rows will need to alternate between odd and even, because of the hexagonal stacking. + // + // Calculate starting column ID based on even or odd row and adapt the covered_tower_x accordingly. + unsigned int col; + if (num_back_cols_rightangleedge & 1) // Uneven number of tubes (so we have a central tube with column ID = 0) + { + col = (row&1) ? 1 : 0; // alternating between 0 and 1 (row index starts at 0, so first is colID = 0) + + } else // Even number of tubes (no central tube, colID starts at 1) + { + col = (row&1) ? 0 : 1; + } + + double covered_tower_x; // How much the first tube covers in x direction, then increases in loop + // Start value depends on whether there is a central tube or not: + covered_tower_x = (col & 1) ? m_capillary_outer_r + m_capillary_outer_r*std::cos(m_angle_edges_x) + : m_capillary_outer_r*std::cos(m_angle_edges_x); + + // Width of the tower at the front face for this row + // Used to check when to shorten the tubes, along with covered_tower_x + double tower_front_x = calculate_tower_width(row, false); + + // We don't calculate how many tubes will fit beforehand, since this varies between rows + // Instead, place tubes as long as there is space + // The column placement starts in the middle and goes outwards in both directions + while (covered_tower_x < tower_x/2.0) + { + // TODO: Check what objects can be moved outside of loop (string _name, Tube _solid, etc.) + + // Calculate the position of the tube + double x = col*m_capillary_outer_r; + double y = row*m_V + m_capillary_outer_r; + + // To calculate the length of the tubes on the tower sides ("wings"), we use a plane equation to get the point where the tube intersects the wall + double col_staggered_z = 0.0*mm; + if (covered_tower_x > tower_front_x/2.0) // Beyond the front face of the tower, the tubes need to be shortened + { + // Point of tube where it hits the wall is not the centre, it will be at the outer edge of course + // But exact position depends on the angle of the walls (m_angle_edges_x) + Position line_point = Position(x+m_capillary_outer_r*std::cos(m_angle_edges_x), y-tower_centre_half_y+m_capillary_outer_r*std::sin(m_angle_edges_x), m_tower_half_length); + Position intersection = get_intersection(plane_right_coefficients, line_point, line_direction); + col_staggered_z = (m_tower_half_length + intersection.z())/2.0; + } + + // Negative length tubes are not allowed + // Shouldn't occur, unless I have made a mistake somewhere (this has saved me in the past already) + if (row_staggered_z > m_tower_half_length) + { + std::cout << "Encountered bad column at (row, col) = (" << row << ", " << col << ")" << std::endl; + break; + } + + // If we stagger in both directions, take the shorter length, so the bigger stagger value + double z = (row_staggered_z > col_staggered_z) ? row_staggered_z : col_staggered_z ; + + double tube_half_length = m_tower_half_length - z; + + // Reference point for tube placement in tower (trapezoid) centre + auto position = Position(x, y-tower_centre_half_y, z); + // And mirrored position for the other side of the tower (since the tower is symmetric in phi (left-right), the tubes are identical) + auto position_mirrored = Position(-x, y-tower_centre_half_y, z); + + // TubeID composed of col in first 16 bits, row in last 16 bits + int tube_id = (col << 16) | row; + int tube_id_mirrored = (-col << 16) | row; + + + // Selecting the right fibre to be placed + bool cher = (row & 1); + std::unordered_map* volume_map; + if (cher) volume_map = &m_cher_tube_volume_map; + else volume_map = &m_scin_tube_volume_map; + // Round length down to next multiple of tolerance + int key = static_cast(fast_floor(tube_half_length / m_tolerance)); + // Zero or negative length tubes shouldn't occur at this point, but if so, try with the next tube + if (key < 1) + { + col += 2; + covered_tower_x += m_capillary_diameter; + continue; + } + this->assert_tube_existence(key, cher); + + // Get the right tube to be placed, including daughters + Volume capillary_vol_to_be_placed = volume_map->at(key); + + // Place the right side tube + PlacedVolume tube_placed = tower_air_volume.placeVolume(capillary_vol_to_be_placed, tube_id, position); + tube_placed.addPhysVolID("air",0).addPhysVolID("col", col).addPhysVolID("row", row); + + // If column is not the central one, place the mirrored tube on the other side of the tower + if (col>0) + { + PlacedVolume tube_placed2 = tower_air_volume.placeVolume(capillary_vol_to_be_placed, tube_id_mirrored, position_mirrored); + tube_placed2.addPhysVolID("air",0).addPhysVolID("col", -col).addPhysVolID("row", row); + } + + col += 2; + covered_tower_x += m_capillary_diameter; + } + + } + +} + + +// Function to calculate the position of the tower in stave +void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() +{ + // Since the Trapezoids are defined including polar and azimuthal angles, we need to convert between cartesian and polar coordinates + double trap_centre_r = m_trap_half_length/std::cos(m_trap_polar_angle); + + double trap_centre_half_y = trap_centre_r*std::sin(m_trap_polar_angle)*std::sin(m_trap_azimuthal_angle) + m_trap_frontface_y/2.0; + + // distance in radial direction (from the interaction point) along the z direction of the trapezoid + // Due to the coordinate system of the trapezoid, this is not in the centre of x and y + double trap_rad_centre = m_calo_inner_r/std::cos(m_covered_theta) + m_back_shift + m_trap_half_length; + + // coordinates of the tower as if it was in global coordinates (was easier to visualise this way during development) + double stave_x = std::cos(m_covered_theta)*trap_rad_centre - std::sin(m_covered_theta)*trap_centre_half_y; + double stave_z = std::sin(m_covered_theta)*trap_rad_centre + std::cos(m_covered_theta)*trap_centre_half_y; + + // coordinates of the tower converted to the stave coordinate system + double tower_x = 0; + double tower_y = stave_z; + double tower_z = stave_x-(m_calo_inner_r+m_stave_half_length); + + m_tower_position = dd4hep::Position(tower_x, tower_y, tower_z); +} + + +// Function to construct the trapezoidal supoprt structure for the tower in which fibres are placed +void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_volume) +{ + + + // polar coordinate conversion + double delta_y = (m_trap_backface_y - m_trap_frontface_y)/2.0; + double delta_z = 2.0*m_trap_half_length; + m_trap_polar_angle = std::acos(delta_z/std::sqrt(delta_y*delta_y + delta_z*delta_z)); + m_trap_azimuthal_angle = 90.0*deg; + + Trap trap_solid("trap_solid", m_trap_half_length, m_trap_polar_angle, m_trap_azimuthal_angle, + m_trap_frontface_y/2.0, m_trap_frontface_rightangleedge_x/2.0, m_trap_frontface_thetaangleedge_x/2.0, 0., + m_trap_backface_y/2.0, m_trap_backface_rightangleedge_x/2.0, m_trap_backface_thetaangleedge_x/2.0, 0.); + + + // Air volume in which fibres are placed + double delta_y_air = (m_tower_backface_y - m_tower_frontface_y)/2.0; + double delta_z_air = 2.0*m_tower_half_length; + m_tower_polar_angle = std::acos(delta_z_air/std::sqrt(delta_y_air*delta_y_air + delta_z_air*delta_z_air)); + m_tower_azimuthal_angle = 90.0*deg; + + Trap tower_air_solid("tower_solid", m_tower_half_length, m_tower_polar_angle, m_tower_azimuthal_angle, + m_tower_frontface_y/2.0, m_tower_frontface_rightangleedge_x/2.0, m_tower_frontface_thetaangleedge_x/2.0, 0., + m_tower_backface_y/2.0, m_tower_backface_rightangleedge_x/2.0, m_tower_backface_thetaangleedge_x/2.0, 0.); + + // Position of the air volume in the trapezoid + // y coordinate depends on wall thickness at the sides and how much the one wall is rotated in theta + // z coordinates depedns on how thick the front and back walls are + Position tower_air_pos = Position(0, + (1.0-1.0/std::cos(m_tower_theta))*m_trap_wall_thickness_sides, + (m_trap_wall_thickness_front-m_trap_wall_thickness_back)/2.0/* +10*nm */); + + + // Subtraction solid used sometimes for easier visualisation. NOT TO BE USED IN FINAL GEOMETRY + // SubtractionSolid solid = SubtractionSolid("trap_final", trap_solid, tower_air_solid, tower_air_pos); + Volume tower_air_volume("tower_air_volume", tower_air_solid, m_air); + tower_air_volume.setVisAttributes(*m_description, m_air_visString); + + trap_volume.setSolid(trap_solid); + trap_volume.setVisAttributes(*m_description, m_trap_visString); + + PlacedVolume tower_air_placed = trap_volume.placeVolume(tower_air_volume, tower_air_pos); + tower_air_placed.addPhysVolID("air", 1); + + // Place all the tubes inside the tower + this->assemble_tower(tower_air_volume); + +} + + +void DDDRCaloTubes::DRTubesconstructor::construct_tower(Volume& trap_volume) +{ + // For each placed tower, recalculate the parameters + this->calculate_theta_parameters(); + // and construct the tower from this + this->construct_tower_trapezoid(trap_volume); +} + + +// Placement of the tower in the stave volume +void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, + Volume& tower_volume, + unsigned int tower) +{ + + double tower_x = m_tower_position.x(); + double tower_y = m_tower_position.y(); + double tower_z = m_tower_position.z(); + + // Forward barrel region + RotationX rot_fwd = RotationX(-m_covered_theta); + Transform3D tower_fwd_tr(rot_fwd, Position(tower_x, tower_y, tower_z)); + PlacedVolume tower_fwd_placed = stave_volume.placeVolume(tower_volume, tower, tower_fwd_tr); + tower_fwd_placed.addPhysVolID("tower", tower); + + // Backward barrel region + Position m_tower_bwd_pos = Position(tower_x, -tower_y, tower_z); + RotationZ rot_first_bwd = RotationZ(180*deg); + RotationX rot_second_bwd = RotationX(m_covered_theta); + Transform3D tower_bwd_tr(rot_second_bwd*rot_first_bwd, m_tower_bwd_pos); + PlacedVolume tower_bwd_placed = stave_volume.placeVolume(tower_volume, -tower, tower_bwd_tr); + tower_bwd_placed.addPhysVolID("tower", -tower); + +} + + +void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimeter_volume) +{ + // Parameters for stave contruction. Shape is a trapezoid over the full barrel region (forward and backward) + double dy1 = m_calo_inner_half_z; + double dy2 = m_calo_inner_half_z+2*m_stave_half_length; + double dx1 = m_calo_inner_r*m_tower_tan_half_phi; + double dx2 = m_calo_outer_r*std::sin(m_tower_half_phi); + Trap stave_solid("stave_solid", m_stave_half_length, 0., 0., + dy1, dx1, dx1, 0., + dy2, dx2, dx2, 0.); + Volume stave_volume("stave_volume", stave_solid, m_air); + stave_volume.setVisAttributes(*m_description, "stave_vis"); + RotationZ rot_first = RotationZ(90*deg); + RotationY rot_second = RotationY(90*deg); + short int tower = 1; + // Place towers in theta direection into the stave as long we are in the barrel region + while (m_covered_thetaconstruct_tower(trap_volume); + + this->calculate_tower_position(); + /* if (tower==8) */this->place_tower(stave_volume, trap_volume, tower); + this->increase_covered_theta(m_tower_theta); + + // if (tower >= 1) break; + tower++; + } + + double phi = 0*deg; + // Variable used to calculate stave position + double centre_stave_vol = m_calo_inner_r + m_stave_half_length; + + + // Placing of the staves + for (unsigned int stave=0; stave (int) x); + } + + bool check_for_integer(double x) + { + return (std::abs(x - std::round(x)) < 1e-6); + } + + std::vector get_plane_equation(const Position& point1, const Position& point2, const Position& point3) + { + Direction normal = (point2 - point1).Cross(point3 - point1).Unit(); + double A = normal.x(); + double B = normal.y(); + double C = normal.z(); + double D = -1.0 * (A * point1.x() + B * point1.y() + C * point1.z()); + std::vector coefficients = {A, B, C, D}; + return coefficients; + } + + Position get_intersection(const std::vector& plane_coefficients, const Position& line_point, const Direction& line_direction) + { + double A = plane_coefficients[0]; + double B = plane_coefficients[1]; + double C = plane_coefficients[2]; + double D = plane_coefficients[3]; + double t = (-1.0*(A * line_point.x() + B * line_point.y() + C * line_point.z() + D)) / (A * line_direction.x() + B * line_direction.y() + C * line_direction.z()); + Position intersection = line_point + t * line_direction; + return intersection; + } + + Position get_intersection(const Direction& plane_normal, const Position& plane_point, const Position& line_point, const Direction& line_direction) + { + double t = (plane_normal.Dot(plane_point - line_point)) / plane_normal.Dot(line_direction); + Position intersection = line_point + t * line_direction; + return intersection; + } + + double distance_from_plane(const std::vector& plane_coefficients, const Position& point) + { + double A = plane_coefficients[0]; + double B = plane_coefficients[1]; + double C = plane_coefficients[2]; + double D = plane_coefficients[3]; + return std::abs(A * point.x() + B * point.y() + C * point.z() + D); + } + +} // namespace DDDRCaloTubes From e699708b55e4ea94e4788b17704283ecc479a484 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 26 Nov 2024 14:23:15 +0100 Subject: [PATCH 103/134] Add DRBarrelTubes in IDEA_o2, adjust muon params Add dual-readout capillary-tubes barrel calorimeter inside the IDEA_o2 xml file. Change IDEA_o2 muon system dimensions to avoid overlaps with the barrel calorimeter (new params checked with Mahmoud Ali). --- .../compact/IDEA_o2_v01/DDDRCaloTubes.xml | 400 ++++++++++++++++++ .../DectDimensions_IDEA_o2_v01.xml | 8 +- .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 9 +- 3 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml new file mode 100644 index 000000000..e5b053069 --- /dev/null +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + +--> + + + My first detector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:5,stave:10,tower:-8,air:1,col:-11,row:7,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 d8e9a9470..9c7cd30d0 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 @@ -223,12 +223,12 @@ - - + + - + - + 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 eb4f52957..f67ca2fe4 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -58,11 +58,14 @@ - - + + + + + - + From 526125f1300e5a5d1e2f02c35dbeb6b73da79f51 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 2 Dec 2024 11:12:00 +0100 Subject: [PATCH 104/134] Move DDDRCalTubes dimensions in IDEA_o2 xml Move the detector dimensions parameters inside DectDimensions_IDEA_o2_v01.xml. --- .../compact/IDEA_o2_v01/DDDRCaloTubes.xml | 70 +++---------------- .../DectDimensions_IDEA_o2_v01.xml | 18 +++++ .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 2 +- 3 files changed, 30 insertions(+), 60 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml index e5b053069..6212c331c 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml @@ -30,37 +30,6 @@ My first detector - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - @@ -295,23 +247,23 @@ + inner_radius="DRBTInnerCaloRadius" + outer_radius="DRBTOuterCaloRadius" + z_length="DRBTInnerCaloHalfLength" + deltatheta="DRBTTowerThetaCoverage" + deltaphi="DRBTTowerPhiCoverage" /> - + - - - - - + + + + + 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 9c7cd30d0..983c58245 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 @@ -220,6 +220,24 @@ + + + + + + + + + + + + + + + + + + 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 f67ca2fe4..eece3d13a 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -59,7 +59,7 @@ - + From 59d40411e224073493a3299775de648cd23164dc Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 2 Dec 2024 11:33:25 +0100 Subject: [PATCH 105/134] Move DRBarrelTubes vis attr to DectDimensions xml Move the vis attributes for DRBarrelTubes subdetector to DectDimensions_IDEA_o2_v01.xml. --- .../compact/IDEA_o2_v01/DDDRCaloTubes.xml | 79 ++----------------- .../DectDimensions_IDEA_o2_v01.xml | 12 +++ 2 files changed, 20 insertions(+), 71 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml index 6212c331c..4cd1b7aba 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml @@ -242,7 +242,7 @@ type="DDDRCaloTubes" id="1234" readout="MyReadout" - vis="MyVis" > + vis="DRBTVis" > @@ -254,16 +254,16 @@ deltaphi="DRBTTowerPhiCoverage" /> - - + + - - - - - + + + + + @@ -280,69 +280,6 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + From 1593752f42bbe0b2adcfb83cff04091fa3131c0c Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 2 Dec 2024 11:41:08 +0100 Subject: [PATCH 106/134] Increase DRBarrelTubes granularity Increase DRTubesGranularity to 72 rotations aroung the beam pipe (as the endcap). --- FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 59c08a1bf..4d3457b79 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 @@ -231,7 +231,7 @@ - + From 6044731a44d20806cabed1c3ff15d758b124af13 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 2 Dec 2024 11:47:59 +0100 Subject: [PATCH 107/134] Cosmetic changes to DRTubesconstructor print Make explicit printout from DRTubesconstructor. --- .../dual-readout-tubes/src/DRTubesconstructor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp index bf5ed1c96..c2c95ba5e 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -413,7 +413,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // Number of rows of tubes in the back face of the tower unsigned int num_rows = fast_floor((m_tower_backface_y-m_capillary_diameter)/m_V) + 1; - std::cout << "TOTAL ROWS = " << num_rows << " COLS = " << num_back_cols_rightangleedge << std::endl; + std::cout << "----> DRBarrelTubes: TOTAL ROWS = " << num_rows << " COLS = " << num_back_cols_rightangleedge << std::endl; // Loop over the rows of tubes in the tower, starting at the right angle edge for (unsigned int row = 0; row < num_rows; row++, covered_tower_y+=m_V) @@ -673,7 +673,7 @@ void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimete // Place towers in theta direection into the stave as long we are in the barrel region while (m_covered_theta DRBarrelTubes: tower = " << tower << std::endl; Volume trap_volume("tower"); trap_volume.setMaterial(m_trap_material); this->construct_tower(trap_volume); @@ -704,7 +704,7 @@ void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimete } //Print length of tube map m_cher_tube_volume_map and m_scin_tube_volume_map - std::cout << "Length of C map = " << m_cher_tube_volume_map.size() << std::endl; - std::cout << "Length of S map = " << m_scin_tube_volume_map.size() << std::endl; + std::cout << "----> DRBarrelTubes: Length of C map = " << m_cher_tube_volume_map.size() << std::endl; + std::cout << "----> DRBarrelTubes: Length of S map = " << m_scin_tube_volume_map.size() << std::endl; } From bf67cbf51ef4b3dafd8a3fd1748943c3d44667f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 2 Dec 2024 17:34:28 +0100 Subject: [PATCH 108/134] Rename to DDDRCaloTubes_o1_v01 Rename DDDRCaloTubes subdetector for consistency with k4geo standards. --- .../{DDDRCaloTubes.xml => DDDRCaloTubes_o1_v01.xml} | 6 +++--- FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 2 +- .../src/{DDDRCaloTubes.cpp => DDDRCaloTubes_o1_v01.cpp} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename FCCee/IDEA/compact/IDEA_o2_v01/{DDDRCaloTubes.xml => DDDRCaloTubes_o1_v01.xml} (99%) rename detector/calorimeter/dual-readout-tubes/src/{DDDRCaloTubes.cpp => DDDRCaloTubes_o1_v01.cpp} (100%) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml similarity index 99% rename from FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml rename to FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml index 4cd1b7aba..3d7cbb91e 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml @@ -23,11 +23,11 @@ xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">--> - My first detector + version="0.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 index eece3d13a..be15287d7 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -62,7 +62,7 @@ - + diff --git a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp b/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp similarity index 100% rename from detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes.cpp rename to detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp From cf9b61632b86ed9b5a984eeeb4604b055400322e Mon Sep 17 00:00:00 2001 From: Andreas Loeschcke Centeno Date: Sat, 7 Dec 2024 18:37:51 +0100 Subject: [PATCH 109/134] Fixed overlap of towers with stave by correct shortening of towers --- .../src/DRTubesconstructor.cpp | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp index c2c95ba5e..1e6e5adc8 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -114,19 +114,41 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_parameters() m_tower_tan_half_phi = std::tan(m_tower_half_phi); // Needed several times, calculate once here - m_stave_half_length = (m_calo_outer_r*std::cos(m_tower_half_phi) - m_calo_inner_r)/2; // Trapezoid half length + m_stave_half_length = (m_calo_outer_r*std::cos(m_tower_half_phi) - m_calo_inner_r)/2; // Maximal trapezoid half length + + /* Protection against tilted towers in theta going past the outer radius of the calorimeter + Depending on other parameters, it is not obvious which one of the towers is the one to "stick out" the most + (Usually 2nd - 3rd tower) + Calculate the maximal distance a tower can stick out, by looping over all tower and saving the maximal one + In the end, make the trapezoids (towers) a bit shorter to accomodate for this */ + double shortening = 0.0; + unsigned int tower_number = 2; + // First tower has protrusion 0 because it is placed without tilting, so start with second tower + for (double theta = m_tower_theta; theta < m_barrel_endcap_angle; theta += m_tower_theta, tower_number++) + { + double protection_covered_z = std::tan(theta)*m_calo_inner_r; + double protection_tower_z = std::tan(theta+m_tower_theta)*m_calo_inner_r - protection_covered_z; + double protection_back_shift = std::sin(theta)*protection_tower_z; + + // Calculate how much the trapezoid needs to be shortened + double protection_shortening = 2*m_stave_half_length+protection_back_shift - 2*m_stave_half_length/std::cos(theta); + + if (protection_shortening > shortening) { + shortening = protection_shortening; // Save the new highest shortening value + // std::cout << "Tower number: " << tower_number << " shortening: " << shortening/mm << "mm" << std::endl; + } + else break; // If the required shortening is decreasing, we have found the maximal value + } - // Protection against tilted towers in theta going past the outer radius of the calorimeter - double protect_covered_z = std::tan(m_tower_theta)*m_calo_inner_r; - double protect_tower_z = std::tan(2*m_tower_theta)*m_calo_inner_r - protect_covered_z; - double protect_back_shift = std::sin(m_tower_theta)*protect_tower_z; // "_trap_" always* refers to the Trap volume including the support structure - m_trap_half_length = m_stave_half_length/std::cos(m_tower_theta) - protect_back_shift/2; + m_trap_half_length = m_stave_half_length - shortening/2; + if (m_trap_half_length <= 0.0) throw std::runtime_error("Could not construct sensible towers with given parameters!"); // "_tower_" always* refers to the collection of tubes forming the tower // "Tower" volume encapsulates the air, which is "hollowing out" the trapezoid volume m_tower_half_length = m_trap_half_length - m_trap_wall_thickness_front/2.0 - m_trap_wall_thickness_back/2.0; // Tower half length + if (m_tower_half_length <= 0.0) throw std::runtime_error("Could not construct sensible towers with given parameters!"); // * "always" means that I tried to use it consistently, but there might be exceptions (like m_tower_phi&theta refer to the full strucutre, including support) // due to the history of the code, where I started out without the support, only the collection of tubes From 98b743f19fca67c4ee8f8078860c1aff10ec4045 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 9 Dec 2024 10:14:22 +0100 Subject: [PATCH 110/134] Avoid overlap between drbarrel staves and solenoid Displace the barrel inner radius by 0.5 cm to avoid overlaps between the calo barrel staves and the solenoid. --- .../compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 8 +++++--- 1 file changed, 5 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 4d3457b79..a40ad94fe 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 @@ -225,10 +225,12 @@ - - + + - + From 515ea035235f152dcc19104e6d74e67e3a45bbfd Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 9 Dec 2024 11:33:52 +0100 Subject: [PATCH 111/134] Fix bug in materials definition Materials names defined in DDDRCaloTubes_o1_v01.xml where already defined in the endcap xml file, therefore the barrel geometry was using the endcap materials. This is a problem in case one wants to activate/inactivate optical properties for such materials in the endcap or barrel separately. Fixed by changing names of DDDRCaloTubes materials. Also, set particle direction to (0,1,0) in the IDEA_o2_vo1.py file to shoot into the barrel instead of the endcap. --- .../IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml | 20 +++++++++---------- example/SteeringFile_IDEA_o2_v01.py | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml index 3d7cbb91e..d1a98fc81 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml @@ -204,13 +204,13 @@ - + - + @@ -218,7 +218,7 @@ --> - + @@ -227,7 +227,7 @@ --> - + @@ -254,16 +254,16 @@ deltaphi="DRBTTowerPhiCoverage" /> - + - - - - - + + + + + diff --git a/example/SteeringFile_IDEA_o2_v01.py b/example/SteeringFile_IDEA_o2_v01.py index 9133c506c..5ae2f034b 100644 --- a/example/SteeringFile_IDEA_o2_v01.py +++ b/example/SteeringFile_IDEA_o2_v01.py @@ -243,7 +243,7 @@ ################################################################################ ## direction of the particle gun, 3 vector -SIM.gun.direction = (0, 0, 1) +SIM.gun.direction = (0, 1, 0) ## choose the distribution of the random direction for theta ## @@ -291,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, 0.0, 0.0) ## Maximal polar angle for random distribution SIM.gun.thetaMax = None From 1af5416a77e829b507b4029ca6ee9d77c31c1715 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 9 Dec 2024 11:49:24 +0100 Subject: [PATCH 112/134] Set DDDRCaloTubes detID and assign Set the subdetector ID in DectDimensions_IDEA_o2_v01.xml file and assign. --- FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml | 2 +- FCCee/IDEA/compact/IDEA_o2_v01/DectDimensions_IDEA_o2_v01.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml index d1a98fc81..02f6f3fce 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml @@ -240,7 +240,7 @@ 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 a40ad94fe..a690cafcb 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 @@ -63,6 +63,9 @@ + + + From 3bbcb0181f00ba7b1fa31e017a29e3b8fed5f693 Mon Sep 17 00:00:00 2001 From: Andreas Loeschcke Centeno Date: Mon, 9 Dec 2024 13:22:14 +0100 Subject: [PATCH 113/134] Added and reworked comments to explain calorimeter barrel construction --- .../src/DDDRCaloTubes_o1_v01.cpp | 8 +- .../src/DRTubesconstructor.cpp | 206 ++++++++++++------ 2 files changed, 139 insertions(+), 75 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp index e67856844..99178d149 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp @@ -22,22 +22,24 @@ static Ref_t create_detector(Detector& description, sens.setType("calorimeter"); - // Cylinder encompassing entire calorimeter xml_dim_t x_dim = x_det.dimensions(); double calo_inner_r = x_dim.inner_radius(); double calo_outer_r = x_dim.outer_radius(); + // Safety check to make sure dimensions are sensible double tower_length = calo_outer_r - calo_inner_r; if (tower_length<=0*mm) throw std::runtime_error("Outer calorimeter radius needs to be larger than inner radius"); + // The barrel volume is an assembly of staves (Trap volumes) + // A cylindrical volume would only be an approximation and lead to overlaps Assembly barrel_volume("calorimeter_barrel"); barrel_volume.setMaterial(air); - barrel_volume.setVisAttributes(description, "assembly_vis"); + barrel_volume.setVisAttributes(description, "DRBTassembly_vis"); DetElement s_detElement(det_name, det_id); Volume mother_volume = description.pickMotherVolume(s_detElement); - + // Helper class to construct the calorimeter DDDRCaloTubes::DRTubesconstructor constructor(&description, entities, &sens); constructor.construct_calorimeter(barrel_volume); diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp index 1e6e5adc8..027bc7dc0 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -89,8 +89,6 @@ DDDRCaloTubes::DRTubesconstructor::DRTubesconstructor(Detector* description, m_tower_tan_theta = 0.0; - m_air = m_description->material("Air"); - xml_comp_t x_air = x_trap.child(_Unicode(air)); m_air = m_description->material(x_air.materialStr()); m_air_visString = x_air.visStr(); @@ -103,11 +101,14 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_parameters() // Angle where endcap and barrel meet m_barrel_endcap_angle = std::atan2(m_calo_inner_half_z, m_calo_inner_r); + // Diameter is used of few times, so calculate only once here m_capillary_diameter = 2*m_capillary_outer_r; - // Constants used through the function - double D = 4.0*m_capillary_outer_r/sqrt(3.0); // Long diagonal of hexagaon with capillary_outer_r as inradius - m_V = 3.0*D/4.0; // Vertical spacing for pointy top oriented tubes + // Long diagonal of hexagaon with capillary_outer_r as inradius + double D = 4.0*m_capillary_outer_r/sqrt(3.0); + // Vertical spacing for pointy top oriented tubes (used for placing of tubes) + // (see https://www.redblobgames.com/grids/hexagons/#spacing) + m_V = 3.0*D/4.0; // Some values which are used multiple times are calculated here once m_tower_half_phi = m_tower_phi/2.0; // Half of the tower phi angle @@ -166,33 +167,44 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_phi_parameters() } -// Function to calculate the size parameters for the trap volume (including support) -// Depends a lot on m_covered_theta, which is increased with each tower placement in theta direction -/* Sketch of a tower in the z-x (or z-y) plane + +/* Function to calculate the size parameters for the trap volume (including support structure). + Depends on m_covered_theta, which is a "running" variable (increased with each tower placement in theta direction). + The length of the trap/tower is already determined from the outer and inner calorimeter radius constraints. + This function determines the trap widths, since it is different for each tower. + The placement of the towers starts at theta=90deg, and m_covered_theta starts at 0deg. + + Sketch of a tower in the global z-x (or z-y) plane: ____________ - | / Each tower is a trapezoid with a front face (bottom in the sketch) and a back face (top in the sketch) - | / The front face is narrower than the back face, to ensure that the tower is projective - | / Also each tower has a right angled face with the front and back face (left in the sketch) - | / and a theta angle side (right in the sketch) - | / Anytime a variable contains "edge" it refers to the edge that would be running in y direction in this sketch with global coordinates - | / (but would be x direction in the local coordinate system of the Trap volume) + | / + | / + | / + | / + | / + | / x | / ^ | / | |___/ | - |____> z - + |-----> z + + Each tower is a Trap volume with a front face (bottom in the sketch) and a back face (top in the sketch). + The front face is narrower than the back face, to ensure that the tower is projective. + Also each tower has a right angled face with the front and back face (left in the sketch). + and a theta angle side (right in the sketch). + Anytime a variable contains "edge" it refers to the edge that would be running in y direction in this sketch with global coordinates + (but is the x direction in the local coordinate system of the Trap volume). */ void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() { - // How much the front faces of the placed towers cover in z direction in the global coordinate system + // How much the front faces of the already placed towers cover in global z direction in the global coordinate system double covered_z = std::tan(m_covered_theta)*m_calo_inner_r; // The cummulative theta value which this trapezoid will cover once placed double trap_theta = m_covered_theta+m_tower_theta; - // Distance the front face of this trapezoid will cover in z + // Cummulative distance the front face of this trapezoid will cover in global z once placed double trap_z = std::tan(trap_theta)*m_calo_inner_r - covered_z; - // Tower height + // Tower height double trap_frontface_y = std::cos(m_covered_theta)*trap_z; if (trap_frontface_y < m_capillary_diameter) @@ -227,16 +239,18 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() m_trap_backface_thetaangleedge_x = m_trap_frontface_thetaangleedge_x + tower_backface_phi_increase_thetaangleedge; // The effective thickness is used to calculate the size of the "air" tower volume - // It takes into account, that the wall is tilted in phi direction + // It takes into account, that the support wall is tilted in phi direction double effective_side_wall_thickness_x = m_trap_wall_thickness_sides/std::cos(m_tower_phi); - // When looking at the tower from the front (or back), the angle created by a vertical line and the sides of the tower + // When looking at the tower from the front (or back), the angle created by a vertical line and the left/right sides of the tower m_angle_edges_x = std::atan2((m_trap_backface_rightangleedge_x-m_trap_backface_thetaangleedge_x)/2.0, m_trap_backface_y); /* + So the angle in the bottom left (or right) corner here + (local Trap coordinate system in this sketch) ________________ - \ / So the angle in the bottom left (or right) corner here - \ _| / - y^ \ | / + \ / + \ _| / + y^ \ | / | \|_______/ | |______> x @@ -244,6 +258,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() */ // Calculating all tower widths (horizontal lines in sketch above) for both front and back face (in z direction) + // Tower now referring to the "air" volume without the support structure m_tower_frontface_rightangleedge_x = calculate_trap_width(m_trap_wall_thickness_sides, m_trap_wall_thickness_front, false) - 2.0*effective_side_wall_thickness_x; m_tower_backface_rightangleedge_x = calculate_trap_width(m_trap_wall_thickness_sides, m_trap_wall_thickness_back, true) - 2.0*effective_side_wall_thickness_x; @@ -256,21 +271,23 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() // Check if tube of this (half-)length already exists, if not, create it +// and store it in the corresponding volume map void DDDRCaloTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher) { std::unordered_map* tube_volume_map; - // Select the right volume maps depending on whether we are creating cherenkov or scintillation tubes + // Select the right volume map depending on whether we are creating cherenkov or scintillation tubes if (cher) { tube_volume_map = &m_cher_tube_volume_map; } else { tube_volume_map = &m_scin_tube_volume_map; } - // If this length already exists, return - if (tube_volume_map->find(key) != tube_volume_map->end()) return; + // If this length already exists, return because there is nothing to do + if (tube_volume_map->find(key) != tube_volume_map->end()) return; - // The map key is the multiple of the tolerance forming the tube length + // The map key is the multiple of the tolerance forming the tube half length + // e.g. tolerance = 0.5 mm, key = 100 -> tube half length = 50 mm double length_rounded_down = key*m_tolerance; // std::cout << "Creating tube with length " << length_rounded_down/mm << " mm" << std::endl; @@ -288,34 +305,34 @@ void DDDRCaloTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher Tube cher_clad_solid(0.0*mm, m_cher_clad_outer_r, length_rounded_down); Volume cher_clad_volume("cher_clad", cher_clad_solid, m_cher_clad_material); if (m_cher_clad_isSensitive) cher_clad_volume.setSensitiveDetector(*m_sens); - PlacedVolume cher_clad_placed = capillary_volume.placeVolume(cher_clad_volume); + PlacedVolume cher_clad_placed = capillary_volume.placeVolume(cher_clad_volume, 1); cher_clad_volume.setVisAttributes(*m_description, m_cher_clad_visString); - cher_clad_placed.addPhysVolID("clad", 1).addPhysVolID("cherenkov", 1); + cher_clad_placed.addPhysVolID("clad", 1); // Chrerenkov core Tube cher_core_solid(0.0*mm, m_cher_core_outer_r, length_rounded_down); Volume cher_core_volume("DRBT_cher_core", cher_core_solid, m_cher_core_material); if (m_cher_core_isSensitive) cher_core_volume.setSensitiveDetector(*m_sens); - PlacedVolume cher_core_placed = cher_clad_volume.placeVolume(cher_core_volume); + PlacedVolume cher_core_placed = cher_clad_volume.placeVolume(cher_core_volume, ((1 << 1) | 1)); cher_core_volume.setVisAttributes(*m_description, m_cher_core_visString); - cher_core_placed.addPhysVolID("core", 1).addPhysVolID("clad", 0); + cher_core_placed.addPhysVolID("core", 1).addPhysVolID("cherenkov", 1); } else { // Scintillation cladding Tube scin_clad_solid(0.0*mm, m_scin_clad_outer_r, length_rounded_down); Volume scin_clad_volume("scin_clad", scin_clad_solid, m_scin_clad_material); if (m_scin_clad_isSensitive) scin_clad_volume.setSensitiveDetector(*m_sens); - PlacedVolume scin_clad_placed = capillary_volume.placeVolume(scin_clad_volume); + PlacedVolume scin_clad_placed = capillary_volume.placeVolume(scin_clad_volume, 1); scin_clad_volume.setVisAttributes(*m_description, m_scin_clad_visString); - scin_clad_placed.addPhysVolID("clad", 1).addPhysVolID("cherenkov", 0); + scin_clad_placed.addPhysVolID("clad", 1); // Scintillation core Tube scin_core_solid(0.0*mm, m_scin_core_outer_r, length_rounded_down); Volume scin_core_volume("DRBT_scin_core", scin_core_solid, m_scin_core_material); if (m_scin_core_isSensitive) scin_core_volume.setSensitiveDetector(*m_sens); - PlacedVolume scin_core_placed = scin_clad_volume.placeVolume(scin_core_volume); + PlacedVolume scin_core_placed = scin_clad_volume.placeVolume(scin_core_volume, ((1 << 1) | 0)); scin_core_volume.setVisAttributes(*m_description, m_scin_core_visString); - scin_core_placed.addPhysVolID("core", 1).addPhysVolID("clad", 0); + scin_core_placed.addPhysVolID("core", 1).addPhysVolID("cherenkov", 0); } tube_volume_map->insert(std::make_pair(key, capillary_volume)); @@ -372,12 +389,13 @@ double DDDRCaloTubes::DRTubesconstructor::calculate_tower_width(int given_row, b // Calculate width (x_direction) of tower at given row // Assuming row 0 is at the right angle edge - // y distance where tube hits side of the wall with given angle between backfaces (y=0 corresponds to m_tower_backface_rightangleedge_x) + // y distance where tube hits side of the wall with given angle between top and bottom edges in the sketch + // (y=0 corresponds to the right angle edge (top in the sketch)) double y = m_capillary_outer_r + given_row*m_V + std::cos(90*deg-m_angle_edges_x)*m_capillary_outer_r; double tower_x; - // Toggle between the back and front in z direction (not shown in sketch) + // Toggle between the back and front face in z direction (not shown in sketch) if (backface) tower_x = m_tower_backface_rightangleedge_x - 2.0*y*std::tan(m_angle_edges_x); else tower_x = m_tower_frontface_rightangleedge_x - 2.0*y*std::tan(m_angle_edges_x); @@ -393,7 +411,38 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) double tower_centre_r = m_tower_half_length/std::cos(m_tower_polar_angle); double tower_centre_half_y = tower_centre_r*std::sin(m_tower_polar_angle)*std::sin(m_tower_azimuthal_angle) + m_tower_frontface_y/2.0; - + /* The tower Trap volume has a front face in which all tubes have the same length and then the sides, + where the tubes become shortened due to the projective shape of the overall tower. + Imagine looking at the tower from the front, as in the sketch below (local coordinate system). + The smaller trapzoidal face is the front face, the larger one the back face. + This volume has four sides, but one is of no concern, because it forms a 90deg angle with the front and back face + (the side at the "top" of this sketch). + The other three sides of the Trap volume are the left, right, and botton area between the front and back face + (imagine drawing lines from the front face corners to the corresponding back face corners to create the 3 areas). + The shortening of tubes hitting the bottom side is easy to calculate, because this side is only angled in one direction + (this calculation is done the loop where the tubes are placed) + The sides on the left and right are more complicated, because they are angled in two directions. + + __________________________________ + \ \ / / + \ \ / / + \ \ / / + \ \_______/ / + \ / + \ / + y^ \ / + | \__________________/ + | + |______> x + / + |/_ (negative)z + + To calculate the length of the tubes at the left and right sides, we calculate the plane equations of these faces + and check where the tube would intersect the side wall. + To create the plane equations, we need three points on the plane (we select three of the corners). + Because the tower is left-right symmetric, we only need to calculate the tube length for one side, and i + + */ // Coordinates of corners of trapezoid // when looking at the tower from the front with the right angle edge on top Position back_upper_right_corner = Position(m_tower_backface_rightangleedge_x/2.0, -tower_centre_half_y, m_tower_half_length); @@ -405,7 +454,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) Direction line_direction = Direction(0, 0, -1); // width of tower at row 0 (right angle edge) - // "at row X" meaning the width of the tower at the height of where the tubes first touch the wall in row X + // "at row X" meaning the width of the tower at the height of where the tubes first touch the left and right side walls in row X double tower_x = calculate_tower_width(0); // number of total columns of tubes at the back face of the tower @@ -428,7 +477,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // Safety counter, should be 0 at the end int num_bad_rows = 0; - // How much distance in y is covered already by the tubes (increases in loop) + // How much distance in the local y is covered already by the tubes (increases in loop) // This value is always: how much this row will cover, once it is placed (for checking when we need to start shortening tubes) double covered_tower_y = m_capillary_diameter; @@ -438,16 +487,18 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) std::cout << "----> DRBarrelTubes: TOTAL ROWS = " << num_rows << " COLS = " << num_back_cols_rightangleedge << std::endl; // Loop over the rows of tubes in the tower, starting at the right angle edge + // The "top" edge in the sketches where we a looking at the front (or back) face of the tower for (unsigned int row = 0; row < num_rows; row++, covered_tower_y+=m_V) { - // Staggering of tubes at the lower edge (theta edge/face) - double row_staggered_z = 0.0*mm; - if (covered_tower_y > m_tower_frontface_y) row_staggered_z = (covered_tower_y-m_tower_frontface_y)/m_tower_tan_theta/2.0; + // shortening of tubes at the bottom edge (theta edge/face) + // The "easy" calculation from the description above + double row_shortened_z = 0.0*mm; + if (covered_tower_y > m_tower_frontface_y) row_shortened_z = (covered_tower_y-m_tower_frontface_y)/m_tower_tan_theta/2.0; // Failsafe for tubes which would have 'negative length' // Should not happen, but if it does, following rows will also be too short, so can skip the rest - if (row_staggered_z > m_tower_half_length) { + if (row_shortened_z > m_tower_half_length) { num_bad_rows = num_rows-row; std::cout << "Encountered bad row at row " << row << std::endl; std::cout << "Number of leftover bad rows: " << num_bad_rows << std::endl; @@ -478,7 +529,8 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) : m_capillary_outer_r*std::cos(m_angle_edges_x); // Width of the tower at the front face for this row - // Used to check when to shorten the tubes, along with covered_tower_x + // Used to check when to shorten the tubes for the left and right side, along with covered_tower_x + // Once the covered_tower_x exceeds this value, we need to shorten the tubes, using the plnae equation to calculate the length double tower_front_x = calculate_tower_width(row, false); // We don't calculate how many tubes will fit beforehand, since this varies between rows @@ -486,33 +538,32 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // The column placement starts in the middle and goes outwards in both directions while (covered_tower_x < tower_x/2.0) { - // TODO: Check what objects can be moved outside of loop (string _name, Tube _solid, etc.) // Calculate the position of the tube double x = col*m_capillary_outer_r; double y = row*m_V + m_capillary_outer_r; // To calculate the length of the tubes on the tower sides ("wings"), we use a plane equation to get the point where the tube intersects the wall - double col_staggered_z = 0.0*mm; + double col_shortened_z = 0.0*mm; if (covered_tower_x > tower_front_x/2.0) // Beyond the front face of the tower, the tubes need to be shortened { - // Point of tube where it hits the wall is not the centre, it will be at the outer edge of course + // Point of tube where it hits the wall is not the centre, it will be at the outer edge of the tube // But exact position depends on the angle of the walls (m_angle_edges_x) Position line_point = Position(x+m_capillary_outer_r*std::cos(m_angle_edges_x), y-tower_centre_half_y+m_capillary_outer_r*std::sin(m_angle_edges_x), m_tower_half_length); Position intersection = get_intersection(plane_right_coefficients, line_point, line_direction); - col_staggered_z = (m_tower_half_length + intersection.z())/2.0; + col_shortened_z = (m_tower_half_length + intersection.z())/2.0; } // Negative length tubes are not allowed // Shouldn't occur, unless I have made a mistake somewhere (this has saved me in the past already) - if (row_staggered_z > m_tower_half_length) + if (row_shortened_z > m_tower_half_length) { std::cout << "Encountered bad column at (row, col) = (" << row << ", " << col << ")" << std::endl; break; } - // If we stagger in both directions, take the shorter length, so the bigger stagger value - double z = (row_staggered_z > col_staggered_z) ? row_staggered_z : col_staggered_z ; + // If we shorten in both directions, take the shorter length, so the bigger shortening value + double z = (row_shortened_z > col_shortened_z) ? row_shortened_z : col_shortened_z ; double tube_half_length = m_tower_half_length - z; @@ -527,6 +578,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // Selecting the right fibre to be placed + // We have two different maps for cherenkov and scintillation tubes and fibres bool cher = (row & 1); std::unordered_map* volume_map; if (cher) volume_map = &m_cher_tube_volume_map; @@ -540,6 +592,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) covered_tower_x += m_capillary_diameter; continue; } + // Make sure the volume for this tube exists, if not: create it this->assert_tube_existence(key, cher); // Get the right tube to be placed, including daughters @@ -547,13 +600,13 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // Place the right side tube PlacedVolume tube_placed = tower_air_volume.placeVolume(capillary_vol_to_be_placed, tube_id, position); - tube_placed.addPhysVolID("air",0).addPhysVolID("col", col).addPhysVolID("row", row); + tube_placed.addPhysVolID("col", col).addPhysVolID("row", row); // If column is not the central one, place the mirrored tube on the other side of the tower if (col>0) { - PlacedVolume tube_placed2 = tower_air_volume.placeVolume(capillary_vol_to_be_placed, tube_id_mirrored, position_mirrored); - tube_placed2.addPhysVolID("air",0).addPhysVolID("col", -col).addPhysVolID("row", row); + PlacedVolume tube_placed_mirrored = tower_air_volume.placeVolume(capillary_vol_to_be_placed, tube_id_mirrored, position_mirrored); + tube_placed_mirrored.addPhysVolID("col", -col).addPhysVolID("row", row); } col += 2; @@ -565,7 +618,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) } -// Function to calculate the position of the tower in stave +// Function to calculate the position of the tower inside the stave void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() { // Since the Trapezoids are defined including polar and azimuthal angles, we need to convert between cartesian and polar coordinates @@ -573,11 +626,12 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() double trap_centre_half_y = trap_centre_r*std::sin(m_trap_polar_angle)*std::sin(m_trap_azimuthal_angle) + m_trap_frontface_y/2.0; - // distance in radial direction (from the interaction point) along the z direction of the trapezoid - // Due to the coordinate system of the trapezoid, this is not in the centre of x and y + // distance in radial direction (from the interaction point) along the local z direction of the trapezoid + // Due to the coordinate system of the trapezoid, this is not in the centre of the local x and y double trap_rad_centre = m_calo_inner_r/std::cos(m_covered_theta) + m_back_shift + m_trap_half_length; // coordinates of the tower as if it was in global coordinates (was easier to visualise this way during development) + // Converted below into the stave coordinate system double stave_x = std::cos(m_covered_theta)*trap_rad_centre - std::sin(m_covered_theta)*trap_centre_half_y; double stave_z = std::sin(m_covered_theta)*trap_rad_centre + std::cos(m_covered_theta)*trap_centre_half_y; @@ -593,9 +647,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() // Function to construct the trapezoidal supoprt structure for the tower in which fibres are placed void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_volume) { - - - // polar coordinate conversion + // Coordinate conversion, since the Trap volume uses polar coordinates double delta_y = (m_trap_backface_y - m_trap_frontface_y)/2.0; double delta_z = 2.0*m_trap_half_length; m_trap_polar_angle = std::acos(delta_z/std::sqrt(delta_y*delta_y + delta_z*delta_z)); @@ -606,7 +658,9 @@ void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_v m_trap_backface_y/2.0, m_trap_backface_rightangleedge_x/2.0, m_trap_backface_thetaangleedge_x/2.0, 0.); - // Air volume in which fibres are placed + // Air volume which hollows out the support structure and into which fibres are placed + // Note that the _tower_ variables are used which include the contribution from the support wall thicknesses + // Otherwise, the air Trap is identical to the support trap, just a bit smaller double delta_y_air = (m_tower_backface_y - m_tower_frontface_y)/2.0; double delta_z_air = 2.0*m_tower_half_length; m_tower_polar_angle = std::acos(delta_z_air/std::sqrt(delta_y_air*delta_y_air + delta_z_air*delta_z_air)); @@ -617,8 +671,8 @@ void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_v m_tower_backface_y/2.0, m_tower_backface_rightangleedge_x/2.0, m_tower_backface_thetaangleedge_x/2.0, 0.); // Position of the air volume in the trapezoid - // y coordinate depends on wall thickness at the sides and how much the one wall is rotated in theta - // z coordinates depedns on how thick the front and back walls are + // y coordinates depend on wall thickness at the sides and how much the one wall is rotated in theta + // z coordinates depend on how thick the front and back walls are Position tower_air_pos = Position(0, (1.0-1.0/std::cos(m_tower_theta))*m_trap_wall_thickness_sides, (m_trap_wall_thickness_front-m_trap_wall_thickness_back)/2.0/* +10*nm */); @@ -651,6 +705,7 @@ void DDDRCaloTubes::DRTubesconstructor::construct_tower(Volume& trap_volume) // Placement of the tower in the stave volume +// One tower is being placed twice, once in the forward and once in the backward region void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, Volume& tower_volume, unsigned int tower) @@ -668,6 +723,7 @@ void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, // Backward barrel region Position m_tower_bwd_pos = Position(tower_x, -tower_y, tower_z); + // First rotation is to mirror orientation with repsect to the forward region RotationZ rot_first_bwd = RotationZ(180*deg); RotationX rot_second_bwd = RotationX(m_covered_theta); Transform3D tower_bwd_tr(rot_second_bwd*rot_first_bwd, m_tower_bwd_pos); @@ -676,7 +732,9 @@ void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, } - +// Highest level function to construct the calorimeter +// In first loop all the towers are created and placed inside a stave +// In the second loop the staves are placed in the calorimeter void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimeter_volume) { // Parameters for stave contruction. Shape is a trapezoid over the full barrel region (forward and backward) @@ -688,9 +746,9 @@ void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimete dy1, dx1, dx1, 0., dy2, dx2, dx2, 0.); Volume stave_volume("stave_volume", stave_solid, m_air); - stave_volume.setVisAttributes(*m_description, "stave_vis"); - RotationZ rot_first = RotationZ(90*deg); - RotationY rot_second = RotationY(90*deg); + stave_volume.setVisAttributes(*m_description, "DRBTstave_vis"); + + // TowerID starts at 1, so that negative values can be used for the backward region short int tower = 1; // Place towers in theta direection into the stave as long we are in the barrel region while (m_covered_theta DRBarrelTubes: tower = " << tower << std::endl; Volume trap_volume("tower"); trap_volume.setMaterial(m_trap_material); + + // Function in which the shape of the tower is calculated and constructed this->construct_tower(trap_volume); this->calculate_tower_position(); - /* if (tower==8) */this->place_tower(stave_volume, trap_volume, tower); + this->place_tower(stave_volume, trap_volume, tower); this->increase_covered_theta(m_tower_theta); - // if (tower >= 1) break; tower++; } + // Start value for placing the towers in phi double phi = 0*deg; // Variable used to calculate stave position double centre_stave_vol = m_calo_inner_r + m_stave_half_length; - + // Rotations needed to place the staves + RotationZ rot_first = RotationZ(90*deg); + RotationY rot_second = RotationY(90*deg); // Placing of the staves for (unsigned int stave=0; stave Date: Mon, 9 Dec 2024 15:08:16 +0100 Subject: [PATCH 114/134] More comments and removal of unused function --- .../include/DRTubesconstructor.h | 50 ++++++++++++++----- .../dual-readout-tubes/include/DRutils.h | 6 ++- .../dual-readout-tubes/src/DRutils.cpp | 15 +++--- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h index f3cec11a6..59ec9b80f 100644 --- a/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h +++ b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h @@ -23,22 +23,45 @@ class DRTubesconstructor { // Destructor ~DRTubesconstructor() {} + // Function to calculate some (but not all) tower size parameters void calculate_tower_parameters(); + + // Function to calculate all parameters which only depend on the tower phi void calculate_phi_parameters(); + + // Function to calculate all parameters which depend on theta (both tower theta and the theta that has been covered by placing towers) + // Since this is different for each tower, this function is called multiple times void calculate_theta_parameters(); - void prepare_tube_volumes(); + + // Function to create tube volumes and store the in a map, if they don't already exist void assert_tube_existence(int key, bool cher); + + // Function to calculate the width of the support Trap volume at a given y and z + // with the option to toggle calculation for the backface or frontface width double calculate_trap_width(double given_y, double given_z, bool backface = false); + // Same as trap width, but for the tower volume (so dimension of "air" insdie the support structure which is the _trap_ volume) double calculate_tower_width(int given_row, bool backface = true); + + // Function to calculate the tube lengths and place them to create the actual tower (not the air) void assemble_tower(Volume& tower_air_volume); + + // Mostly just a wrapper function void construct_tower_trapezoid(Volume& trap_volume); + + // Function to calculate the position of the tower inside the stave void calculate_tower_position(); + + // Function to construct the trapezoidal support structure for the tower in which fibres are placed void construct_tower(Volume& trap_volume); + void increase_covered_theta(const double& delta_theta) {m_covered_theta += delta_theta;} + + // Function to place the tower in the stave volume void place_tower(Volume& stave_volume, - Volume& tower_volume, - unsigned int layer); + Volume& tower_volume, + unsigned int layer); + // Overarching function to construct the calorimeter void construct_calorimeter(Volume& calorimeter_volume); private: @@ -75,36 +98,40 @@ class DRTubesconstructor { bool m_cher_clad_isSensitive; bool m_cher_core_isSensitive; - + // Maps to store the tube volumes, so that one volume can be used multiple times + // The key to the map is an indicator of the tube length (multiple of the tolerance) std::unordered_map m_scin_tube_volume_map; std::unordered_map m_cher_tube_volume_map; + // Tolerance for which new tube volumes are created + // e.g 1mm, then all tube lengths are rounded (down) to the nearest mm double m_tolerance; - double m_capillary_diameter; // calculated from m_capillary_outer_r // Constants used through the function (calculated from other parameters) - // double m_D; // Long diagonal of hexagaon with capillary_outer_r as inradius + double m_capillary_diameter; // calculated from m_capillary_outer_r double m_V; // Vertical spacing for pointy top oriented tubes - // Tower parameters + // Tower angle parameters (and derived parameters) double m_tower_theta; double m_tower_phi; double m_tower_half_phi; double m_tower_tan_half_phi; // calculated from m_tower_phi double m_tower_half_length; // calculated from m_calo_inner_r and m_calo_outer_r and m_trap_half_length + double m_tower_tan_theta; - // Tower Phi parameters + // Tower size parameters depending on phi unsigned int m_num_phi_towers; // number of towers in phi direction + // Tower widths at four edges double m_tower_frontface_rightangleedge_x; double m_tower_frontface_thetaangleedge_x; double m_tower_backface_rightangleedge_x; double m_tower_backface_thetaangleedge_x; + // Angle between the parallel edges of the front/back face double m_angle_edges_x; - // Tower Theta parameters - double m_tower_tan_theta; + // Tower size parameters derived from theta double m_tower_frontface_y; double m_tower_backface_y; double m_tower_polar_angle; @@ -128,11 +155,10 @@ class DRTubesconstructor { std::string m_trap_visString; - // Construction parameters + // Construction parameters (which change for each tower) double m_covered_theta; double m_back_shift; Position m_tower_position; - // Assembly* m_tower_volume; Material m_air; std::string m_air_visString; diff --git a/detector/calorimeter/dual-readout-tubes/include/DRutils.h b/detector/calorimeter/dual-readout-tubes/include/DRutils.h index 8c6c03090..34d6cb518 100644 --- a/detector/calorimeter/dual-readout-tubes/include/DRutils.h +++ b/detector/calorimeter/dual-readout-tubes/include/DRutils.h @@ -8,16 +8,20 @@ using namespace dd4hep; + +// Utility functions for the construction of the barrel dual-readout calorimeter (based on tubes) namespace DDDRCaloTubes { + // Quick rounding functions int fast_floor(double x); int fast_ceil(double x); + // Make sure a given double is an integer (within a tolerance) bool check_for_integer(double x); + // Functions which are used to calculate the tube lengths using the crossing point of a line and a plane std::vector get_plane_equation(const Position& point1, const Position& point2, const Position& point3); Position get_intersection(const std::vector& plane_coefficients, const Position& line_point, const Direction& line_direction); Position get_intersection(const Direction& plane_normal, const Position& plane_point, const Position& line_point, const Direction& line_direction); - double distance_from_plane(const std::vector& plane_coefficients, const Position& point); } // namespace DDDRCaloTubes #endif // DRutils_h diff --git a/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp b/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp index 37c5835c0..f5c47c0a7 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp @@ -5,6 +5,7 @@ using namespace dd4hep; namespace DDDRCaloTubes { + // Fast rounding function which do not do some safety checks the std:: functions provide, since we don't expect problems with the input int fast_floor(double x) { return (int) x - (x < (int) x); @@ -15,11 +16,13 @@ namespace DDDRCaloTubes return (int) x + (x > (int) x); } + // Check if a double is an integer within a certain tolerance bool check_for_integer(double x) { return (std::abs(x - std::round(x)) < 1e-6); } + // Plane equation based on three points on the plane std::vector get_plane_equation(const Position& point1, const Position& point2, const Position& point3) { Direction normal = (point2 - point1).Cross(point3 - point1).Unit(); @@ -31,6 +34,7 @@ namespace DDDRCaloTubes return coefficients; } + // Intersection of a line and a plane, based on the plane equation coefficients Position get_intersection(const std::vector& plane_coefficients, const Position& line_point, const Direction& line_direction) { double A = plane_coefficients[0]; @@ -42,6 +46,8 @@ namespace DDDRCaloTubes return intersection; } + // Alternative way of getting the intersection of a line and a plane, based on the plane normal and a point on the plane + // Used during development for double checking Position get_intersection(const Direction& plane_normal, const Position& plane_point, const Position& line_point, const Direction& line_direction) { double t = (plane_normal.Dot(plane_point - line_point)) / plane_normal.Dot(line_direction); @@ -49,13 +55,4 @@ namespace DDDRCaloTubes return intersection; } - double distance_from_plane(const std::vector& plane_coefficients, const Position& point) - { - double A = plane_coefficients[0]; - double B = plane_coefficients[1]; - double C = plane_coefficients[2]; - double D = plane_coefficients[3]; - return std::abs(A * point.x() + B * point.y() + C * point.z() + D); - } - } // namespace DDDRCaloTubes From 9e9c6c73da5d68c1581aca40c337966b62d965e0 Mon Sep 17 00:00:00 2001 From: Andreas Loeschcke Centeno Date: Mon, 9 Dec 2024 15:36:07 +0100 Subject: [PATCH 115/134] Renamed DDDRCaloTubes to DRBarrelTubes for consistency with endcaps --- ...es_o1_v01.xml => DRBarrelTubes_o1_v01.xml} | 10 +++---- .../IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml | 2 +- .../include/DRTubesconstructor.h | 4 +-- .../dual-readout-tubes/include/DRutils.h | 4 +-- ...es_o1_v01.cpp => DRBarrelTubes_o1_v01.cpp} | 4 +-- .../src/DRTubesconstructor.cpp | 28 +++++++++---------- .../dual-readout-tubes/src/DRutils.cpp | 4 +-- 7 files changed, 28 insertions(+), 28 deletions(-) rename FCCee/IDEA/compact/IDEA_o2_v01/{DDDRCaloTubes_o1_v01.xml => DRBarrelTubes_o1_v01.xml} (98%) rename detector/calorimeter/dual-readout-tubes/src/{DDDRCaloTubes_o1_v01.cpp => DRBarrelTubes_o1_v01.cpp} (93%) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml similarity index 98% rename from FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml rename to FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml index 02f6f3fce..33c2f2b07 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DDDRCaloTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml @@ -22,7 +22,7 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema" xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">--> - @@ -270,7 +270,7 @@ - + system:5,stave:10,tower:-8,air:1,col:-11,row:7,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 index be15287d7..4c41f961c 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/IDEA_o2_v01.xml @@ -62,7 +62,7 @@ - + diff --git a/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h index 59ec9b80f..1c97955fe 100644 --- a/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h +++ b/detector/calorimeter/dual-readout-tubes/include/DRTubesconstructor.h @@ -11,7 +11,7 @@ using namespace dd4hep; -namespace DDDRCaloTubes { +namespace DRBarrelTubes { class DRTubesconstructor { public: @@ -165,6 +165,6 @@ class DRTubesconstructor { }; -} // namespace DDDRCaloTubes +} // namespace DRBarrelTubes #endif // DRCONSTRUCTOR_H diff --git a/detector/calorimeter/dual-readout-tubes/include/DRutils.h b/detector/calorimeter/dual-readout-tubes/include/DRutils.h index 34d6cb518..08331ad27 100644 --- a/detector/calorimeter/dual-readout-tubes/include/DRutils.h +++ b/detector/calorimeter/dual-readout-tubes/include/DRutils.h @@ -10,7 +10,7 @@ using namespace dd4hep; // Utility functions for the construction of the barrel dual-readout calorimeter (based on tubes) -namespace DDDRCaloTubes +namespace DRBarrelTubes { // Quick rounding functions int fast_floor(double x); @@ -22,6 +22,6 @@ namespace DDDRCaloTubes std::vector get_plane_equation(const Position& point1, const Position& point2, const Position& point3); Position get_intersection(const std::vector& plane_coefficients, const Position& line_point, const Direction& line_direction); Position get_intersection(const Direction& plane_normal, const Position& plane_point, const Position& line_point, const Direction& line_direction); -} // namespace DDDRCaloTubes +} // namespace DRBarrelTubes #endif // DRutils_h diff --git a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp b/detector/calorimeter/dual-readout-tubes/src/DRBarrelTubes_o1_v01.cpp similarity index 93% rename from detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp rename to detector/calorimeter/dual-readout-tubes/src/DRBarrelTubes_o1_v01.cpp index 99178d149..366952b0f 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DDDRCaloTubes_o1_v01.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRBarrelTubes_o1_v01.cpp @@ -40,7 +40,7 @@ static Ref_t create_detector(Detector& description, Volume mother_volume = description.pickMotherVolume(s_detElement); // Helper class to construct the calorimeter - DDDRCaloTubes::DRTubesconstructor constructor(&description, entities, &sens); + DRBarrelTubes::DRTubesconstructor constructor(&description, entities, &sens); constructor.construct_calorimeter(barrel_volume); @@ -54,4 +54,4 @@ static Ref_t create_detector(Detector& description, } -DECLARE_DETELEMENT(DDDRCaloTubes,create_detector) +DECLARE_DETELEMENT(DRBarrelTubes,create_detector) diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp index 027bc7dc0..d96c45454 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -3,9 +3,9 @@ #include using namespace dd4hep; -using namespace DDDRCaloTubes; +using namespace DRBarrelTubes; -DDDRCaloTubes::DRTubesconstructor::DRTubesconstructor(Detector* description, +DRBarrelTubes::DRTubesconstructor::DRTubesconstructor(Detector* description, xml_h& entities, SensitiveDetector* sens): m_entities(entities) @@ -96,7 +96,7 @@ DDDRCaloTubes::DRTubesconstructor::DRTubesconstructor(Detector* description, } // Function to calculate all tower parameters which are derived from user given values -void DDDRCaloTubes::DRTubesconstructor::calculate_tower_parameters() +void DRBarrelTubes::DRTubesconstructor::calculate_tower_parameters() { // Angle where endcap and barrel meet m_barrel_endcap_angle = std::atan2(m_calo_inner_half_z, m_calo_inner_r); @@ -156,7 +156,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_parameters() } // Function to calculate tower parameters specifically for phi direction -void DDDRCaloTubes::DRTubesconstructor::calculate_phi_parameters() +void DRBarrelTubes::DRTubesconstructor::calculate_phi_parameters() { double num_phi_towers_d = 360.0*deg/m_tower_phi; if (num_phi_towers_d < 0.0) throw std::runtime_error("Negative tower phi coverage not allowed"); @@ -195,7 +195,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_phi_parameters() Anytime a variable contains "edge" it refers to the edge that would be running in y direction in this sketch with global coordinates (but is the x direction in the local coordinate system of the Trap volume). */ -void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() +void DRBarrelTubes::DRTubesconstructor::calculate_theta_parameters() { // How much the front faces of the already placed towers cover in global z direction in the global coordinate system double covered_z = std::tan(m_covered_theta)*m_calo_inner_r; @@ -272,7 +272,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_theta_parameters() // Check if tube of this (half-)length already exists, if not, create it // and store it in the corresponding volume map -void DDDRCaloTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher) +void DRBarrelTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher) { std::unordered_map* tube_volume_map; @@ -342,7 +342,7 @@ void DDDRCaloTubes::DRTubesconstructor::assert_tube_existence(int key, bool cher // Similar to calculate_tower_width (see abelow), but for the encasing trapezoid support volume // Width is calculated for any given point in th z-y plane -double DDDRCaloTubes::DRTubesconstructor::calculate_trap_width(double given_y, double given_z, bool backface) +double DRBarrelTubes::DRTubesconstructor::calculate_trap_width(double given_y, double given_z, bool backface) { // Calculate width (x_direction) of trapezoid at given y // Assuming y=0 corresponds to right angle edge of the tower @@ -384,7 +384,7 @@ double DDDRCaloTubes::DRTubesconstructor::calculate_trap_width(double given_y, d |______> x / |/_ z */ -double DDDRCaloTubes::DRTubesconstructor::calculate_tower_width(int given_row, bool backface) +double DRBarrelTubes::DRTubesconstructor::calculate_tower_width(int given_row, bool backface) { // Calculate width (x_direction) of tower at given row // Assuming row 0 is at the right angle edge @@ -404,7 +404,7 @@ double DDDRCaloTubes::DRTubesconstructor::calculate_tower_width(int given_row, b // Place all tubes which make up the tower -void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) +void DRBarrelTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) { // Y-distance of rightangle wall from coordinate system origin // Used throughout this function @@ -619,7 +619,7 @@ void DDDRCaloTubes::DRTubesconstructor::assemble_tower(Volume& tower_air_volume) // Function to calculate the position of the tower inside the stave -void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() +void DRBarrelTubes::DRTubesconstructor::calculate_tower_position() { // Since the Trapezoids are defined including polar and azimuthal angles, we need to convert between cartesian and polar coordinates double trap_centre_r = m_trap_half_length/std::cos(m_trap_polar_angle); @@ -645,7 +645,7 @@ void DDDRCaloTubes::DRTubesconstructor::calculate_tower_position() // Function to construct the trapezoidal supoprt structure for the tower in which fibres are placed -void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_volume) +void DRBarrelTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_volume) { // Coordinate conversion, since the Trap volume uses polar coordinates double delta_y = (m_trap_backface_y - m_trap_frontface_y)/2.0; @@ -695,7 +695,7 @@ void DDDRCaloTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_v } -void DDDRCaloTubes::DRTubesconstructor::construct_tower(Volume& trap_volume) +void DRBarrelTubes::DRTubesconstructor::construct_tower(Volume& trap_volume) { // For each placed tower, recalculate the parameters this->calculate_theta_parameters(); @@ -706,7 +706,7 @@ void DDDRCaloTubes::DRTubesconstructor::construct_tower(Volume& trap_volume) // Placement of the tower in the stave volume // One tower is being placed twice, once in the forward and once in the backward region -void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, +void DRBarrelTubes::DRTubesconstructor::place_tower(Volume& stave_volume, Volume& tower_volume, unsigned int tower) { @@ -735,7 +735,7 @@ void DDDRCaloTubes::DRTubesconstructor::place_tower(Volume& stave_volume, // Highest level function to construct the calorimeter // In first loop all the towers are created and placed inside a stave // In the second loop the staves are placed in the calorimeter -void DDDRCaloTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimeter_volume) +void DRBarrelTubes::DRTubesconstructor::construct_calorimeter(Volume& calorimeter_volume) { // Parameters for stave contruction. Shape is a trapezoid over the full barrel region (forward and backward) double dy1 = m_calo_inner_half_z; diff --git a/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp b/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp index f5c47c0a7..548ca21d3 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRutils.cpp @@ -3,7 +3,7 @@ using namespace dd4hep; -namespace DDDRCaloTubes +namespace DRBarrelTubes { // Fast rounding function which do not do some safety checks the std:: functions provide, since we don't expect problems with the input int fast_floor(double x) @@ -55,4 +55,4 @@ namespace DDDRCaloTubes return intersection; } -} // namespace DDDRCaloTubes +} // namespace DRBarrelTubes From bd8085003213d9d2b1d475cb50679b8b158a535e Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 10 Dec 2024 11:01:14 +0100 Subject: [PATCH 116/134] Add barrel in dual-readout-tubes_o1_v01 readme Add description of the barrel dual-readout-tubes caloriemter in detectors/calorimeter README.md file. --- detector/calorimeter/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index e76042ded..771b6acf6 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -59,5 +59,4 @@ Inside the single tower (trapezoidal copper absorber), two types of optical fibe ## 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. +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). Endcap and barrel calorimeters are implemented ad separate subdetectors. From acd519b081efcfef73c49d4b0dd19916cfba9221 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 10 Dec 2024 11:05:03 +0100 Subject: [PATCH 117/134] Update IDEA_o2 README description By adding inclusion of the dual-readout-tubes barrel calorimeter in Decemeber 2024. --- FCCee/IDEA/compact/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FCCee/IDEA/compact/README.md b/FCCee/IDEA/compact/README.md index d6c9ee960..b4ce02514 100644 --- a/FCCee/IDEA/compact/README.md +++ b/FCCee/IDEA/compact/README.md @@ -32,3 +32,5 @@ 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 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. + +December 2024: Added the dual-readout capillary-tubes barrel calorimeter. From 54564973bc1084c1ca57632f7407429346634a95 Mon Sep 17 00:00:00 2001 From: Andreas Loeschcke Centeno Date: Mon, 16 Dec 2024 17:54:46 +0100 Subject: [PATCH 118/134] Added forgotten copynumber for air volume inside tower --- .../calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp index d96c45454..737c22077 100644 --- a/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp +++ b/detector/calorimeter/dual-readout-tubes/src/DRTubesconstructor.cpp @@ -686,7 +686,7 @@ void DRBarrelTubes::DRTubesconstructor::construct_tower_trapezoid(Volume& trap_v trap_volume.setSolid(trap_solid); trap_volume.setVisAttributes(*m_description, m_trap_visString); - PlacedVolume tower_air_placed = trap_volume.placeVolume(tower_air_volume, tower_air_pos); + PlacedVolume tower_air_placed = trap_volume.placeVolume(tower_air_volume, 1, tower_air_pos); tower_air_placed.addPhysVolID("air", 1); // Place all the tubes inside the tower From bfbc227796c8b766620751704cfe8c87339553d3 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Mon, 16 Dec 2024 18:49:42 +0100 Subject: [PATCH 119/134] Extend DRTubsSDAction to handle barrel signals First attempt to produce signals from the barrel dual-readout-tubes calorimeter. --- .../IDEA_o2_v01/DRBarrelTubes_o1_v01.xml | 2 +- .../src/DRTubesconstructor.cpp | 2 +- example/SteeringFile_IDEA_o2_v01.py | 8 + plugins/DRTubesSDAction.cpp | 165 ++++++++++++------ plugins/DRTubesSglHpr.hh | 6 +- 5 files changed, 126 insertions(+), 57 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml index 33c2f2b07..0d1407b73 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml @@ -272,7 +272,7 @@ - system:5,stave:10,tower:-8,air:1,col:-11,row:7,clad:1,core:1,cherenkov:1 + system:5,stave:10,tower:-8,air:1,col:-16,row:16,clad:1,core:1,cherenkov:1 ::defineCollections() m_userData.collection_cher_right = defineCollection(ROname + "CherRight"); m_userData.collection_scin_left = defineCollection(ROname + "ScinLeft"); m_userData.collection_cher_left = defineCollection(ROname + "CherLeft"); + m_userData.collection_drbt_cher = defineCollection("DRBTCher"); + m_userData.collection_drbt_scin = defineCollection("DRBTScin"); } // Function template specialization of Geant4SensitiveAction class. @@ -122,6 +126,9 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, DRTubesSglHpr::PrintStepInfo(aStep); #endif + // This part is needed to kill non ionizing particles in S fibers, + // skipping steps in C fibers cladding and killing optical photons + // in C fibers cladding. It is common to the endcap and barrel calo. auto Edep = aStep->GetTotalEnergyDeposit(); auto cpNo = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(); // The second bit of the CopyNumber corresponds to the "core" entry: @@ -133,6 +140,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // 1 for C fibers and 0 for S fibers unsigned int CherenkovID = cpNo & 0b1; bool IsScin = (CherenkovID == 0); + std::cout << "coreid " << CoreID << " is scin " << IsScin << std::endl; // 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, @@ -146,59 +154,112 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // 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("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); - 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); - - /* 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 */ - // clang-format off - /*std::cout<<"Volume id, created "<GetPreStepPoint()->GetPosition().z() > 0.); - - // We now calculate the signal in S and C fiber according to the step contribution - // + // Now we check if we are in the barrel and the endcap calo + double theta = aStep->GetPreStepPoint()->GetMomentumDirection().theta(); + bool IsBarrel = (theta >= 45.0 * deg && theta <= 135.0 * deg) ? true : false; + std::cout << theta << " " << IsBarrel << std::endl; + VolumeID VolID = 0; // this 64-bits VolumeID will be recreated for barrel and endcap volumes + Geant4HitCollection* coll = nullptr; // to be assigned correctly below + + if (!IsBarrel) { // get VolumeID and hit collection for endcap + // 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)); + + 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); + 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); + + /* 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 */ + // clang-format off + /*std::cout<<"Volume id, created "<GetPreStepPoint()->GetPosition().z() > 0.); + + 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); + } // end of encap VolumeID and hit collection creation + else { // create VolumeID and hit collection for the barrel + + // 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); + int ColumnID = TubeID >> 16; + unsigned int RowID = TubeID & 0xFFFF; + auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); + auto StaveID = + static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(5)); + + BitFieldCoder bc("system:5,stave:10,tower:-8,air:1,col:-16,row:16,clad:1,core:1,cherenkov:1"); + bc.set(VolID, "system", 28); // this number is set in DectDimensions_IDEA_o2_v01.xml + bc.set(VolID, "stave", StaveID); + bc.set(VolID, "tower", TowerID); + bc.set(VolID, "air", 1); + bc.set(VolID, "col", ColumnID); + bc.set(VolID, "row", RowID); + bc.set(VolID, "clad", 1); + bc.set(VolID, "core", CoreID); + bc.set(VolID, "cherenkov", CherenkovID); + std::cout << "volid barrel " << VolID << std::endl; + + /* If you want to compare the 64-bits VolID created here + * with the original DD4hep volumeID: + * 1. set in DRBarrelTubes_o1_v01.xml clad_C, core_C and core_S + * volumes as sensitive + * 2. associate DRTubesSDAction to DRBarrelTubes subdetector + * in the steering file (instead of using RegexSD) + * 3. Uncomment the code below */ + // clang-format off + /*std::cout<<"Volume id, created "<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 if (aStep->GetTrack()->GetDefinition()->GetPDGCharge() == 0 || steplength == 0.) { diff --git a/plugins/DRTubesSglHpr.hh b/plugins/DRTubesSglHpr.hh index be82c01cc..34f8a8f6b 100644 --- a/plugins/DRTubesSglHpr.hh +++ b/plugins/DRTubesSglHpr.hh @@ -165,16 +165,16 @@ inline bool DRTubesSglHpr::IsReflectedForward(const G4Step* step) inline void DRTubesSglHpr::PrintStepInfo(const G4Step* aStep) { std::cout << "-------------------------------" << std::endl; - std::cout << "--> DREndcapTubes: track info: " << std::endl; + std::cout << "--> DRTubesSglHpr: 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 << "--> DRTubesSglHpt:: 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 << "--> DRTubesSglHpr: particle info: " << std::endl; std::cout << "----> Particle " << aStep->GetTrack()->GetParticleDefinition()->GetParticleName() << " " << "Dep(MeV) " << aStep->GetTotalEnergyDeposit() << " " From 35b24ba55b715f22c4e7b05912be8c2b40a4bacf Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Tue, 17 Dec 2024 17:29:09 +0100 Subject: [PATCH 120/134] Fix bug in DRTubesSDAction theta coordinate The theta coordinate was taken from the track momentum direction, instead is should be taken from the G4Step position to discriminate if a G4Step is inside the barrel or the endcap geometry. --- plugins/DRTubesSDAction.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 4b4c564cb..d31f2ca07 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -155,9 +155,9 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // Now we are inside fibers' core volume (either Scintillating or Cherenkov) // Now we check if we are in the barrel and the endcap calo - double theta = aStep->GetPreStepPoint()->GetMomentumDirection().theta(); + double theta = aStep->GetPreStepPoint()->GetPosition().theta(); bool IsBarrel = (theta >= 45.0 * deg && theta <= 135.0 * deg) ? true : false; - std::cout << theta << " " << IsBarrel << std::endl; + std::cout <<"theta deg"<::process(const G4Step* aStep, auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); auto StaveID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(5)); - - BitFieldCoder bc("system:5,stave:10,tower:-8,air:1,col:-16,row:16,clad:1,core:1,cherenkov:1"); - bc.set(VolID, "system", 28); // this number is set in DectDimensions_IDEA_o2_v01.xml - bc.set(VolID, "stave", StaveID); - bc.set(VolID, "tower", TowerID); - bc.set(VolID, "air", 1); - bc.set(VolID, "col", ColumnID); - bc.set(VolID, "row", RowID); - bc.set(VolID, "clad", 1); - bc.set(VolID, "core", CoreID); - bc.set(VolID, "cherenkov", CherenkovID); + std::cout<<" tube id "< Date: Tue, 17 Dec 2024 17:48:52 +0100 Subject: [PATCH 121/134] Change name of DRTubesSDAction hit collections Change the name of hit collections to avoid duplication of hits while using ROName in the hit collection name. The barrel was creating also hit collection for cher_right/left and scin_right/left which are only for the endcap. --- plugins/DRTubesSDAction.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index d31f2ca07..ced55de5d 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -75,10 +75,10 @@ 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"); + m_collectionID = defineCollection("DRETScinRight"); + m_userData.collection_cher_right = defineCollection("DRETCherRight"); + m_userData.collection_scin_left = defineCollection("DRETScinLeft"); + m_userData.collection_cher_left = defineCollection("DRETCherLeft"); m_userData.collection_drbt_cher = defineCollection("DRBTCher"); m_userData.collection_drbt_scin = defineCollection("DRBTScin"); } From 03fa75d142fc872740f202ca732969e45a97c6c0 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 18 Dec 2024 11:25:30 +0100 Subject: [PATCH 122/134] Restore optical properties for DRBarrelTubes Reinclude optical properties for fiber materials. Create PMMA_Scin material to differentiate between material used in Scin and Cher fibers in order to not have optical photons in Scin fibers but only in Cher fibers. --- .../IDEA_o2_v01/DRBarrelTubes_o1_v01.xml | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml index 0d1407b73..7c9acd77c 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml @@ -214,8 +214,17 @@ - + + + + + + + + + @@ -223,15 +232,15 @@ - + + - + @@ -260,7 +269,7 @@ - + From 9f0b86f53f8975ef0227672d825538dd30094125 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 18 Dec 2024 11:30:55 +0100 Subject: [PATCH 123/134] Remove DRTubesSDAction printout Remove printout and apply clang-format. I checked that this version of the custom SD action is consistent with the speedup obtained originally with the endcap geometry only (about 1 s/evt for 10 GeV e- events). --- plugins/DRTubesSDAction.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index ced55de5d..08f0fa9c7 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -29,7 +29,7 @@ // Includers from project files #include "DRTubesSglHpr.hh" -#define DRTubesSDDebug +// #define DRTubesSDDebug namespace dd4hep { @@ -140,7 +140,6 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // 1 for C fibers and 0 for S fibers unsigned int CherenkovID = cpNo & 0b1; bool IsScin = (CherenkovID == 0); - std::cout << "coreid " << CoreID << " is scin " << IsScin << std::endl; // 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, @@ -157,7 +156,6 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // Now we check if we are in the barrel and the endcap calo double theta = aStep->GetPreStepPoint()->GetPosition().theta(); bool IsBarrel = (theta >= 45.0 * deg && theta <= 135.0 * deg) ? true : false; - std::cout <<"theta deg"<::process(const G4Step* aStep, auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(4)); auto StaveID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(5)); - std::cout<<" tube id "<::process(const G4Step* aStep, bcbarrel.set(VolID, "clad", 1); bcbarrel.set(VolID, "core", CoreID); bcbarrel.set(VolID, "cherenkov", CherenkovID); - std::cout << "volid barrel " << VolID << std::endl; /* If you want to compare the 64-bits VolID created here * with the original DD4hep volumeID: From 712f7577dc26f736b8a993dbce23254d2e027e7b Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 18 Dec 2024 15:28:18 +0100 Subject: [PATCH 124/134] Fix printout of DRTubesSDAction Fix printout to check that volIDs of the DRBarrelTubes are correctly reproduced. --- plugins/DRTubesSDAction.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 08f0fa9c7..660c4af05 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -164,7 +164,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // 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; + unsigned int RowID = TubeID & 0xFFFF; auto TowerID = static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3)); auto StaveID = @@ -176,7 +176,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, bc.set(VolID, "tower", TowerID); bc.set(VolID, "air", 0); bc.set(VolID, "col", ColumnID); - bc.set(VolID, "row", RawID); + bc.set(VolID, "row", RowID); bc.set(VolID, "clad", 1); bc.set(VolID, "core", CoreID); bc.set(VolID, "cherenkov", CherenkovID); @@ -195,7 +195,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, std::cout<<"tower id, created "<::process(const G4Step* aStep, * in the steering file (instead of using RegexSD) * 3. Uncomment the code below */ // clang-format off - /*std::cout<<"Volume id, created "< Date: Thu, 19 Dec 2024 15:41:57 +0100 Subject: [PATCH 125/134] Comment out volID check for barrel calo Commet out volID printout check for barrel calo in DRTubesSDAction. This was used to check that the 64-bits volIDs recreated from the barrel copynumbers are identical to the DD4hep ones. However marking barrel fibers as sensitive makes the memory footprint explode (34 Gb before it is killed on lxplus). So the test was done on a single stave. --- plugins/DRTubesSDAction.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 660c4af05..88020cf8d 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -189,7 +189,7 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, * 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, * 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<<"row id, created "< Date: Tue, 21 Jan 2025 18:54:37 +0100 Subject: [PATCH 126/134] Changed air copy number to 63 for quick differentiation between endcaps and barrel --- FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml | 2 +- .../dual-readout-tubes/src/DRTubesconstructor.cpp | 6 ++++-- plugins/DRTubesSDAction.cpp | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml index 7c9acd77c..3d4121ef7 100644 --- a/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o2_v01/DRBarrelTubes_o1_v01.xml @@ -281,7 +281,7 @@ - system:5,stave:10,tower:-8,air:1,col:-16,row:16,clad:1,core:1,cherenkov:1 + system:5,stave:10,tower:-8,air:6,col:-16,row:16,clad:1,core:1,cherenkov:1 assemble_tower(tower_air_volume); diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index 88020cf8d..d4deac7ea 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -220,11 +220,11 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, static_cast(aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(5)); BitFieldCoder bcbarrel( - "system:5,stave:10,tower:-8,air:1,col:-16,row:16,clad:1,core:1,cherenkov:1"); + "system:5,stave:10,tower:-8,air:6,col:-16,row:16,clad:1,core:1,cherenkov:1"); bcbarrel.set(VolID, "system", 28); // this number is set in DectDimensions_IDEA_o2_v01.xml bcbarrel.set(VolID, "stave", StaveID); bcbarrel.set(VolID, "tower", TowerID); - bcbarrel.set(VolID, "air", 1); + bcbarrel.set(VolID, "air", 63); bcbarrel.set(VolID, "col", ColumnID); bcbarrel.set(VolID, "row", RowID); bcbarrel.set(VolID, "clad", 1); From 6e950c35595817755d0482dbacd07b95592cc2aa Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Wed, 22 Jan 2025 15:28:53 +0100 Subject: [PATCH 127/134] Change DRTubesSDAction IsBarrel implementation Change logic to differentiate between barrel and endcap calo in DRTubesSDAction. Instead of using theta from global coordinates use copy numbers. --- plugins/DRTubesSDAction.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/DRTubesSDAction.cpp b/plugins/DRTubesSDAction.cpp index d4deac7ea..608aac59b 100644 --- a/plugins/DRTubesSDAction.cpp +++ b/plugins/DRTubesSDAction.cpp @@ -153,9 +153,13 @@ bool Geant4SensitiveAction::process(const G4Step* aStep, // Now we are inside fibers' core volume (either Scintillating or Cherenkov) - // Now we check if we are in the barrel and the endcap calo - double theta = aStep->GetPreStepPoint()->GetPosition().theta(); - bool IsBarrel = (theta >= 45.0 * deg && theta <= 135.0 * deg) ? true : false; + // Now we check if we are in the barrel and the endcap calo. + // For the barrel GetCopyNumber(3) would be the air-volume with cpno 63 + // For the endcap GetCopyNumber(3) is never 63 + // (patchy for the moment, can be improved later on) + // + bool IsBarrel = aStep->GetPreStepPoint()->GetTouchable()->GetCopyNumber(3) == 63; + VolumeID VolID = 0; // this 64-bits VolumeID will be recreated for barrel and endcap volumes Geant4HitCollection* coll = nullptr; // to be assigned correctly below From 915923dd041d9157a83e2fec4a17e02606279823 Mon Sep 17 00:00:00 2001 From: Lorenzo Pezzotti Date: Thu, 23 Jan 2025 11:45:36 +0100 Subject: [PATCH 128/134] Comment out IDEA_o2 test --- test/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 131736ffa..f769bdecc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -116,12 +116,12 @@ 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 --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() +#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 --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() #-------------------------------------------------- # test for ALLEGRO o1 v02 From 3cd447f559ea7fcf64327f231f216aa988b49c85 Mon Sep 17 00:00:00 2001 From: Juan Miguel Carceller <22276694+jmcarcell@users.noreply.github.com> Date: Fri, 24 Jan 2025 10:28:39 +0100 Subject: [PATCH 129/134] Improve check for a header file from DD4hep (#400) --- CMakeLists.txt | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6f765ad1..b6087ec46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,15 +97,10 @@ if(NOT K4GEO_USE_LCIO) message(STATUS "Use of LCIO is DISABLED, some detectors that depend on LCIO will not be built: ${lcio_sources}") endif() -include(CheckIncludeFileCXX) -set(CMAKE_REQUIRED_LIBRARIES DD4hep::DDRec) -CHECK_INCLUDE_FILE_CXX(DDRec/DCH_info.h DCH_INFO_H_EXIST) -set(CMAKE_REQUIRED_LIBRARIES) -set(FILES_DEPENDINGON_DCH_INFO_H "DriftChamber_o1_v02.cpp" ) - -if(NOT DCH_INFO_H_EXIST) - list(FILTER sources EXCLUDE REGEX "${FILES_DEPENDINGON_DCH_INFO_H}") - message(WARNING "Subdetector ${FILES_DEPENDINGON_DCH_INFO_H} will not be built because header file DDRec/DCH_info.h was not found") +if(${DD4hep_VERSION} VERSION_LESS 1.29) + set(FILES_DEPENDINGON_DCH_INFO_H "DriftChamber_o1_v02.cpp" ) + list(FILTER sources EXCLUDE REGEX "${FILES_DEPENDINGON_DCH_INFO_H}") + message(WARNING "Subdetector ${FILES_DEPENDINGON_DCH_INFO_H} will not be built because the current version of DD4hep does not ship with the header file DDRec/DCH_info.h") endif() find_package(EDM4HEP) From 0a49f40a1252ff7c43590b59b8d20d86b5bbb210 Mon Sep 17 00:00:00 2001 From: Alvaro Tolosa Delgado <114166109+atolosadelgado@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:21:12 +0100 Subject: [PATCH 130/134] add Default material to CLD o4 v5 material file (#422) --- FCCee/CLD/compact/CLD_o4_v05/materials.xml | 7 +++++++ test/CMakeLists.txt | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/FCCee/CLD/compact/CLD_o4_v05/materials.xml b/FCCee/CLD/compact/CLD_o4_v05/materials.xml index 64eba58d9..adccb4a1c 100644 --- a/FCCee/CLD/compact/CLD_o4_v05/materials.xml +++ b/FCCee/CLD/compact/CLD_o4_v05/materials.xml @@ -265,4 +265,11 @@ + + + + + + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f769bdecc..79ded71e7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -84,6 +84,11 @@ ADD_TEST( t_test_${det_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName 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" ) +SET( det_name "CLD_o4_v05" ) +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" ) + SET( test_name "test_steeringFile" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" ddsim --steeringFile=${CMAKE_CURRENT_SOURCE_DIR}/../example/steeringFile.py --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../CLIC/compact/CLIC_o2_v04/CLIC_o2_v04.xml --runType=batch -G -N=1 --outputFile=testCLIC_o2_v04.slcio ) From 666a5e79767284ace7c1eebd6c9e3c2a2b189ee7 Mon Sep 17 00:00:00 2001 From: Victor Schwan Date: Tue, 28 Jan 2025 14:54:22 +0100 Subject: [PATCH 131/134] add DefaultMaterial to ILD materials for compatibility with MDI v01 --- ILD/compact/ILD_common_v02/materials.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ILD/compact/ILD_common_v02/materials.xml b/ILD/compact/ILD_common_v02/materials.xml index 726cdde45..ff34ed059 100644 --- a/ILD/compact/ILD_common_v02/materials.xml +++ b/ILD/compact/ILD_common_v02/materials.xml @@ -635,6 +635,12 @@ + + + + + + From d5a765651a175a3caebe8ff974ab3282d3f6e860 Mon Sep 17 00:00:00 2001 From: Victor Schwan Date: Tue, 28 Jan 2025 15:04:22 +0100 Subject: [PATCH 132/134] minor: add comma for improved readability --- FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 7c3cf258e..b42a37c01 100644 --- a/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml @@ -67,7 +67,7 @@ - + From 211e0de041e0cef434a8f76df24794ecc1d6b72d Mon Sep 17 00:00:00 2001 From: Victor Schwan Date: Fri, 24 Jan 2025 13:30:04 +0100 Subject: [PATCH 133/134] collect MDI files in common MDI folder to avoid hard-coding all files in each detector description --- FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml | 7 +++---- FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml | 7 +++---- FCCee/MDI/compact/MDI_o1_v00/MDI_o1_v00_collection.xml | 7 +++++++ FCCee/MDI/compact/MDI_o1_v01/MDI_o1_v01_collection.xml | 6 ++++++ 4 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 FCCee/MDI/compact/MDI_o1_v00/MDI_o1_v00_collection.xml create mode 100644 FCCee/MDI/compact/MDI_o1_v01/MDI_o1_v01_collection.xml 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 index 0c159e67b..118dcf5a7 100644 --- a/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v01/ILD_FCCee_v01.xml @@ -61,10 +61,9 @@ - - - - + + + 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 index b42a37c01..526d3bc6f 100644 --- a/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml +++ b/FCCee/ILD_FCCee/compact/ILD_FCCee_v02/ILD_FCCee_v02.xml @@ -62,10 +62,9 @@ - - - - + + + diff --git a/FCCee/MDI/compact/MDI_o1_v00/MDI_o1_v00_collection.xml b/FCCee/MDI/compact/MDI_o1_v00/MDI_o1_v00_collection.xml new file mode 100644 index 000000000..a40cd7165 --- /dev/null +++ b/FCCee/MDI/compact/MDI_o1_v00/MDI_o1_v00_collection.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/FCCee/MDI/compact/MDI_o1_v01/MDI_o1_v01_collection.xml b/FCCee/MDI/compact/MDI_o1_v01/MDI_o1_v01_collection.xml new file mode 100644 index 000000000..69536bcb2 --- /dev/null +++ b/FCCee/MDI/compact/MDI_o1_v01/MDI_o1_v01_collection.xml @@ -0,0 +1,6 @@ + + + + + + From 8bd7462d3c73d3b78577b44ae76b95248a69f842 Mon Sep 17 00:00:00 2001 From: Sanghyun Ko Date: Thu, 30 Jan 2025 22:09:12 +0900 Subject: [PATCH 134/134] one giant commit to solve the rebase conflict --- .../DectDimensions_IDEA_o1_v03.xml | 60 +- .../FiberDualReadoutCalo_o1_v01.xml | 6 +- .../IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml | 8 +- .../dual-readout/src/DRconstructor.cpp | 11 +- example/SteeringFile_IDEA_o1_v03.py | 36 +- plugins/DRCaloFastSimModel.cpp | 299 +-------- plugins/DRCaloFastSimModel.h | 362 +++++++++-- plugins/FiberDRCaloSDAction.cpp | 593 +++++++++++++----- plugins/FiberDRCaloSDAction.h | 1 + plugins/Geant4Output2EDM4hep_DRC.cpp | 43 +- 10 files changed, 833 insertions(+), 586 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 7a72d28eb..386c212c4 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 @@ -16,15 +16,15 @@ - + - + - + @@ -40,10 +40,10 @@ - + - + @@ -68,7 +68,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -113,7 +113,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -135,71 +135,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -207,10 +207,10 @@ - + - + @@ -232,18 +232,18 @@ - + - + - - + + diff --git a/FCCee/IDEA/compact/IDEA_o1_v03/FiberDualReadoutCalo_o1_v01.xml b/FCCee/IDEA/compact/IDEA_o1_v03/FiberDualReadoutCalo_o1_v01.xml index 8961ffac4..b97641e84 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/FiberDualReadoutCalo_o1_v01.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/FiberDualReadoutCalo_o1_v01.xml @@ -13,7 +13,7 @@ The compact format for the dual-readout calorimeter (for FCCee IDEA) - + - + @@ -691,7 +691,7 @@ - system:5,assembly:1,eta:-8,phi:9,x:32:-11,y:-9,c:1,module:2 + system:5,assembly:1,eta:-8,phi:9,x:32:-12,y:-12,c:1,module:2 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 2cdcd42f1..5fe33a2c8 100644 --- a/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml +++ b/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml @@ -11,7 +11,7 @@ url="no" status="development" version="o1_v03"> - + Version o1_v03 of the IDEA detector @@ -37,9 +37,9 @@ - + - @@ -65,7 +65,7 @@ - + diff --git a/detector/calorimeter/dual-readout/src/DRconstructor.cpp b/detector/calorimeter/dual-readout/src/DRconstructor.cpp index c01afa77f..094a9e2d4 100644 --- a/detector/calorimeter/dual-readout/src/DRconstructor.cpp +++ b/detector/calorimeter/dual-readout/src/DRconstructor.cpp @@ -87,7 +87,7 @@ void ddDRcalo::DRconstructor::implementTowers(xml_comp_t& x_theta, dd4hep::DDSeg dd4hep::Volume towerVol( "tower", tower, fDescription->material(x_theta.materialStr()) ); towerVol.setVisAttributes(*fDescription, x_theta.visStr()); - + implementFibers(x_theta, towerVol, tower, param); xml_comp_t x_wafer ( fX_sipmDim.child( _Unicode(sipmWafer) ) ); @@ -123,7 +123,10 @@ void ddDRcalo::DRconstructor::placeAssembly(dd4hep::DDSegmentation::DRparamBase_ int towerId32 = fSegmentation->getFirst32bits(towerId64); dd4hep::Position towerPos = param->GetTowerPos(nPhi) + dd4hep::Position(0, 0, -(fX_worldTube.height()/2.)); - AssemblyBoxVol.placeVolume( towerVol, towerId32, dd4hep::Transform3D( param->GetRotationZYX(nPhi), towerPos ) ); + dd4hep::PlacedVolume towerPhys = AssemblyBoxVol.placeVolume( towerVol, towerId32, dd4hep::Transform3D( param->GetRotationZYX(nPhi), towerPos ) ); + towerPhys.addPhysVolID("eta", towerNoLR); + towerPhys.addPhysVolID("phi", nPhi); + towerPhys.addPhysVolID("module", 2); // Remove sipmLayer dd4hep::Position sipmPos = param->GetSipmLayerPos(nPhi) + dd4hep::Position(0, 0, -(fX_worldTube.height()/2.)); @@ -250,6 +253,8 @@ void ddDRcalo::DRconstructor::implementFiber(dd4hep::Volume& towerVol, dd4hep::P if (fVis) coreVol.setVisAttributes(*fDescription, fX_coreC.visStr()); cladVol.placeVolume( coreVol ); + // we use the region for the sensitive elements for + // manipulating optical photons (DRCaloFastSimModel) coreVol.setRegion(*fDescription, fX_det.regionStr()); cladVol.setRegion(*fDescription, fX_det.regionStr()); } else { // s fiber @@ -261,6 +266,8 @@ void ddDRcalo::DRconstructor::implementFiber(dd4hep::Volume& towerVol, dd4hep::P if (fVis) coreVol.setVisAttributes(*fDescription, fX_coreS.visStr()); cladVol.placeVolume( coreVol ); + // we use the region for the sensitive elements for + // manipulating optical photons (DRCaloFastSimModel) coreVol.setRegion(*fDescription, fX_det.regionStr()); cladVol.setRegion(*fDescription, fX_det.regionStr()); } diff --git a/example/SteeringFile_IDEA_o1_v03.py b/example/SteeringFile_IDEA_o1_v03.py index 102085aa5..0796bb359 100644 --- a/example/SteeringFile_IDEA_o1_v03.py +++ b/example/SteeringFile_IDEA_o1_v03.py @@ -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 = 1 +SIM.numberOfEvents = 10 ## Outputfile from the simulation: .slcio, edm4hep.root and .root output files are supported SIM.outputFile = "testIDEA_o1_v03.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 @@ -112,7 +112,7 @@ ## ## SIM.action.mapActions['tpc'] = "TPCSDAction" ## -SIM.action.mapActions = {"DRcalo": "DRCaloSDAction"} +SIM.action.mapActions["DRcalo"] = "DRCaloSDAction" ## set the default run action SIM.action.run = [] @@ -177,7 +177,8 @@ ## default filter for calorimeter sensitive detectors; ## this is applied if no other filter is used for a calorimeter ## -SIM.filter.calo = "edep0" +# note: do not turn on the calo filter, otherwise all optical photons will be killed! +SIM.filter.calo = "" ## list of filter objects: map between name and parameter dictionary SIM.filter.filters = { @@ -229,6 +230,8 @@ ## Print information about Sensitives SIM.geometry.enablePrintSensitives = False +## configure regex SD +SIM.geometry.regexSensitiveDetector["DRcalo"] = {"Match": ["(core|clad)"], "OutputLevel": 3} ################################################################################ ## Configuration for the GuineaPig InputFiles @@ -246,7 +249,7 @@ ################################################################################ ## direction of the particle gun, 3 vector -SIM.gun.direction = (1.0, 1.0, 1.0) +SIM.gun.direction = (1.0, 0.1, 0.1) ## choose the distribution of the random direction for theta ## @@ -264,7 +267,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.0 * GeV ## Maximal pseudorapidity for random distibution (overrides thetaMin) SIM.gun.etaMax = None @@ -280,12 +283,12 @@ SIM.gun.isotrop = False ## Maximal momentum when using distribution (default = 0.0) -SIM.gun.momentumMax = 10000.0 +# SIM.gun.momentumMax = 10000.0 ## Minimal momentum when using distribution (default = 0.0) -SIM.gun.momentumMin = 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 @@ -552,7 +555,7 @@ def Geant4Output2EDM4hep_DRC_plugin(dd4hepSimulation): ## 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 +SIM.physics.rangecut = None ## Set of PDG IDs that will not be passed from the input record to Geant4. ## @@ -613,17 +616,11 @@ def setupOpticalPhysics(kernel): cerenkov.enableUI() seq.adopt(cerenkov) - 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.VerboseLevel = 1 - opt.BoundaryInvokeSD = True + # set BoundaryInvokeSD to true when using DRC wafer as the SD + # opt.BoundaryInvokeSD = True opt.enableUI() seq.adopt(opt) @@ -656,7 +653,8 @@ def setupDRCFastSim(kernel): phys.dump() -SIM.physics.setupUserPhysics(setupDRCFastSim) +# turn-on fastsim if the skipScint option of the SD is set to false +# SIM.physics.setupUserPhysics(setupDRCFastSim) ################################################################################ ## Properties for the random number generator diff --git a/plugins/DRCaloFastSimModel.cpp b/plugins/DRCaloFastSimModel.cpp index 5caa21456..c29789386 100644 --- a/plugins/DRCaloFastSimModel.cpp +++ b/plugins/DRCaloFastSimModel.cpp @@ -1,15 +1,7 @@ // Framework include files #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "G4FastStep.hh" // C/C++ include files #include "DRCaloFastSimModel.h" @@ -17,246 +9,9 @@ /// Namespace for the AIDA detector description toolkit namespace dd4hep { - /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace sim { - - class DRCFiberModel - { - public: - // G4FastSimHitMaker hitMaker { }; - G4OpBoundaryProcess *pOpBoundaryProc{nullptr}; - G4OpAbsorption *pOpAbsorption{nullptr}; - G4OpWLS *pOpWLS{nullptr}; - G4bool fProcAssigned{false}; - - FastFiberData mDataPrevious{FastFiberData(0, 0., 0., 0., G4ThreeVector(0), G4ThreeVector(0), G4ThreeVector(0))}; - FastFiberData mDataCurrent{FastFiberData(0, 0., 0., 0., G4ThreeVector(0), G4ThreeVector(0), G4ThreeVector(0))}; - - G4int fSafety{2}; - G4double mNtransport{0.}; - G4double mTransportUnit{0.}; - G4ThreeVector mFiberPos{G4ThreeVector(0)}; - G4ThreeVector mFiberAxis{G4ThreeVector(0)}; - G4bool fKill{false}; - G4bool fTransported{false}; - G4bool fSwitch{true}; - G4int fVerbose{0}; - - G4bool checkTotalInternalReflection(const G4Track *track) - { - if (!fProcAssigned) - setPostStepProc(track); // locate OpBoundaryProcess only once - - if (track->GetTrackStatus() == fStopButAlive || track->GetTrackStatus() == fStopAndKill) - return false; - - // accumulate step length - mDataCurrent.AddStepLengthInterval(track->GetStepLength()); - - G4int theStatus = pOpBoundaryProc->GetStatus(); - - if (fVerbose > 1) - { - G4cout << "DRCFiberModel::checkTotalInternalReflection | TrackID = " << std::setw(4) << track->GetTrackID(); - G4cout << " | G4OpBoundaryProcessStatus = " << std::setw(2) << theStatus; - G4cout << " | StepLength = " << std::setw(9) << track->GetStepLength() << G4endl; - } - - // skip exceptional iteration with FresnelReflection - if (theStatus == G4OpBoundaryProcessStatus::FresnelReflection) - mDataCurrent.SetOpBoundaryStatus(theStatus); - - // some cases have a status StepTooSmall when the reflection happens between the boundary of cladding & outer volume (outside->cladding) since the outer volume is not a G4Region - if (theStatus == G4OpBoundaryProcessStatus::TotalInternalReflection || theStatus == G4OpBoundaryProcessStatus::StepTooSmall) - { - if (theStatus != G4OpBoundaryProcessStatus::TotalInternalReflection) - { // skip StepTooSmall if the track already has TotalInternalReflection - if (mDataCurrent.GetOpBoundaryStatus() == G4OpBoundaryProcessStatus::TotalInternalReflection) - return false; - if (mDataPrevious.GetOpBoundaryStatus() == G4OpBoundaryProcessStatus::TotalInternalReflection) - return false; - } - - G4int trackID = track->GetTrackID(); - G4double kineticEnergy = track->GetKineticEnergy(); - G4double globalTime = track->GetGlobalTime(); - G4double pathLength = track->GetStepLength(); - G4ThreeVector globalPosition = track->GetPosition(); - G4ThreeVector momentumDirection = track->GetMomentumDirection(); - G4ThreeVector polarization = track->GetPolarization(); - - auto candidate = FastFiberData(trackID, kineticEnergy, globalTime, pathLength, globalPosition, momentumDirection, polarization, theStatus); - if (pOpAbsorption != nullptr) - candidate.SetAbsorptionNILL(pOpAbsorption->GetNumberOfInteractionLengthLeft()); - if (pOpWLS != nullptr) - candidate.SetWLSNILL(pOpWLS->GetNumberOfInteractionLengthLeft()); - - G4bool repetitive = false; - if (candidate.checkRepetitive(mDataCurrent, false) && mDataCurrent.checkRepetitive(mDataPrevious)) - repetitive = true; - - mDataPrevious = mDataCurrent; - mDataCurrent = candidate; - - return repetitive; - } - - return false; - } - - G4bool checkAbsorption(const G4double prevNILL, const G4double currentNILL) - { - if (prevNILL < 0. || currentNILL < 0.) - return false; // the number of interaction length left has to be reset - if (prevNILL == currentNILL) - return false; // no absorption - if (prevNILL == DBL_MAX || currentNILL == DBL_MAX) - return false; // NILL is re-initialized - - G4double deltaNILL = prevNILL - currentNILL; - - if (currentNILL - deltaNILL * (mNtransport + fSafety) < 0.) - return true; // absorbed before reaching fiber end - - return false; - } - - G4bool checkNILL() - { - if (!fTransported) - return true; // do nothing if the track is not already transported - - G4double wlsNILL = DBL_MAX; - G4double absorptionNILL = DBL_MAX; - - if (pOpWLS != nullptr) - { - wlsNILL = pOpWLS->GetNumberOfInteractionLengthLeft(); - if (mDataPrevious.GetWLSNILL() == DBL_MAX || mDataCurrent.GetWLSNILL() == DBL_MAX) - return true; // NILL is re-initialized - } - - if (pOpAbsorption != nullptr) - { - absorptionNILL = pOpAbsorption->GetNumberOfInteractionLengthLeft(); - if (mDataPrevious.GetAbsorptionNILL() == DBL_MAX || mDataCurrent.GetAbsorptionNILL() == DBL_MAX) - return true; // NILL is re-initialized - } - - if (wlsNILL < 0. || absorptionNILL < 0.) - return true; // let GEANT4 to reset them - - G4double deltaWlsNILL = mDataPrevious.GetWLSNILL() - mDataCurrent.GetWLSNILL(); - G4double deltaAbsorptionNILL = mDataPrevious.GetAbsorptionNILL() - mDataCurrent.GetAbsorptionNILL(); - - G4double finalWlsNILL = wlsNILL - deltaWlsNILL * fSafety; - G4double finalAbsorptionNILL = absorptionNILL - deltaAbsorptionNILL * fSafety; - - // prevent double counting of the probability of getting absorbed (which already estimated before transportation) - // reset NILL again - if (finalWlsNILL < 0. || finalAbsorptionNILL < 0.) - return false; - - return true; - } - - void setPostStepProc(const G4Track *track) - { - G4ProcessManager *pm = track->GetDefinition()->GetProcessManager(); - auto postStepProcessVector = pm->GetPostStepProcessVector(); - - for (unsigned int np = 0; np < postStepProcessVector->entries(); np++) - { - auto theProcess = (*postStepProcessVector)[np]; - - auto theType = theProcess->GetProcessType(); - - if (theType != fOptical) - continue; - - if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpBoundary) - pOpBoundaryProc = dynamic_cast(theProcess); - else if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpAbsorption) - pOpAbsorption = dynamic_cast(theProcess); - else if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpWLS) - pOpWLS = dynamic_cast(theProcess); - } - - fProcAssigned = true; - - return; - } - - void reset() - { - mNtransport = 0.; - mTransportUnit = 0.; - mFiberPos = G4ThreeVector(0); - mFiberAxis = G4ThreeVector(0); - fKill = false; - fTransported = false; - mDataCurrent.reset(); - mDataPrevious.reset(); - } - - void print() - { - if (fVerbose > 1) - { - G4cout << G4endl; - - G4cout << "mDataPrevious.trackID = " << mDataPrevious.trackID; - G4cout << " | .mOpBoundaryStatus = " << std::setw(4) << mDataPrevious.GetOpBoundaryStatus(); - G4cout << " | .mStepLengthInterval = " << mDataPrevious.GetStepLengthInterval() << G4endl; - - if (fVerbose > 2) - { - G4cout << " | globalPosition = (" << std::setw(9) << mDataPrevious.globalPosition.x(); - G4cout << "," << std::setw(9) << mDataPrevious.globalPosition.y(); - G4cout << "," << std::setw(9) << mDataPrevious.globalPosition.z() << ")" << G4endl; - - G4cout << " | momentumDirection = (" << std::setw(9) << mDataPrevious.momentumDirection.x(); - G4cout << "," << std::setw(9) << mDataPrevious.momentumDirection.y(); - G4cout << "," << std::setw(9) << mDataPrevious.momentumDirection.z() << ")" << G4endl; - - G4cout << " | polarization = (" << std::setw(9) << mDataPrevious.polarization.x(); - G4cout << "," << std::setw(9) << mDataPrevious.polarization.y(); - G4cout << "," << std::setw(9) << mDataPrevious.polarization.z() << ")" << G4endl; - - G4cout << " | globalTime = " << std::setw(9) << mDataPrevious.globalTime << G4endl; - G4cout << " | WLSNILL = " << std::setw(9) << mDataPrevious.GetWLSNILL() << G4endl; - G4cout << " | AbsorptionNILL = " << std::setw(9) << mDataPrevious.GetAbsorptionNILL() << G4endl; - } - - G4cout << "mDataCurrent.trackID = " << mDataCurrent.trackID; - G4cout << " | .mOpBoundaryStatus = " << std::setw(4) << mDataCurrent.GetOpBoundaryStatus() << G4endl; - - if (fVerbose > 2) - { - G4cout << " | globalPosition = (" << std::setw(9) << mDataCurrent.globalPosition.x(); - G4cout << "," << std::setw(9) << mDataCurrent.globalPosition.y(); - G4cout << "," << std::setw(9) << mDataCurrent.globalPosition.z() << ")" << G4endl; - - G4cout << " | momentumDirection = (" << std::setw(9) << mDataCurrent.momentumDirection.x(); - G4cout << "," << std::setw(9) << mDataCurrent.momentumDirection.y(); - G4cout << "," << std::setw(9) << mDataCurrent.momentumDirection.z() << ")" << G4endl; - - G4cout << " | polarization = (" << std::setw(9) << mDataCurrent.polarization.x(); - G4cout << "," << std::setw(9) << mDataCurrent.polarization.y(); - G4cout << "," << std::setw(9) << mDataCurrent.polarization.z() << ")" << G4endl; - - G4cout << " | globalTime = " << std::setw(9) << mDataCurrent.globalTime << G4endl; - G4cout << " | WLSNILL = " << std::setw(9) << mDataCurrent.GetWLSNILL() << G4endl; - G4cout << " | AbsorptionNILL = " << std::setw(9) << mDataCurrent.GetAbsorptionNILL() << G4endl; - } - - G4cout << G4endl; - } - } - }; - template <> void Geant4FSShowerModel::initialize() { @@ -305,8 +60,7 @@ namespace dd4hep } template <> - bool Geant4FSShowerModel::check_trigger(const G4FastTrack &fasttrack) - { + bool Geant4FSShowerModel::check_trigger(const G4FastTrack &fasttrack) { if (!locals.fSwitch) return false; // turn on/off the model @@ -316,55 +70,12 @@ namespace dd4hep if (locals.mDataCurrent.trackID != track->GetTrackID()) locals.reset(); - // make sure that the track does not get absorbed after transportation, as number of interaction length left is reset when doing transportation + // make sure that the track does not get absorbed after transportation + // as number of interaction length left is reset when doing transportation if (!locals.checkNILL()) return true; // track is already transported but did not pass NILL check, attempt to reset NILL - if (locals.fTransported) - { // track is already transported and did pass NILL check, nothing to do - if (locals.mFiberAxis.dot(track->GetMomentumDirection()) * locals.mFiberAxis.dot(locals.mDataCurrent.momentumDirection) < 0) // different propagation direction (e.g. mirror) - locals.reset(); - - return false; - } - - if (!locals.checkTotalInternalReflection(track)) - return false; // nothing to do if the track has no repetitive total internal reflection - - auto theTouchable = track->GetTouchableHandle(); - auto solid = theTouchable->GetSolid(); - - if (solid->GetEntityType() != "G4Tubs") - return false; // only works for G4Tubs at the moment - - if (locals.fVerbose > 0) - locals.print(); // at this point, the track should have passed all prerequisites before entering computationally heavy operations - - G4Tubs *tubs = static_cast(solid); - G4double fiberLen = 2. * tubs->GetZHalfLength(); - - locals.mFiberPos = theTouchable->GetHistory()->GetTopTransform().Inverse().TransformPoint(G4ThreeVector(0., 0., 0.)); - locals.mFiberAxis = theTouchable->GetHistory()->GetTopTransform().Inverse().TransformAxis(G4ThreeVector(0., 0., 1.)); - - auto delta = locals.mDataCurrent.globalPosition - locals.mDataPrevious.globalPosition; - locals.mTransportUnit = delta.dot(locals.mFiberAxis); - - // estimate the number of expected total internal reflections before reaching fiber end - auto fiberEnd = (locals.mTransportUnit > 0.) ? locals.mFiberPos + locals.mFiberAxis * fiberLen / 2. : locals.mFiberPos - locals.mFiberAxis * fiberLen / 2.; - auto toEnd = fiberEnd - track->GetPosition(); - G4double toEndAxis = toEnd.dot(locals.mFiberAxis); - G4double maxTransport = std::floor(toEndAxis / locals.mTransportUnit); - locals.mNtransport = maxTransport - locals.fSafety; - - if (locals.mNtransport < 1.) - return false; // require at least n = fSafety of total internal reflections at the end - - if (locals.checkAbsorption(locals.mDataPrevious.GetWLSNILL(), locals.mDataCurrent.GetWLSNILL())) - return false; // do nothing if WLS happens before reaching fiber end - if (locals.checkAbsorption(locals.mDataPrevious.GetAbsorptionNILL(), locals.mDataCurrent.GetAbsorptionNILL())) - locals.fKill = true; // absorbed before reaching fiber end - - return true; + return locals.check_trigger(track); } typedef Geant4FSShowerModel Geant4DRCFiberModel; diff --git a/plugins/DRCaloFastSimModel.h b/plugins/DRCaloFastSimModel.h index a8f29cb14..3b9273ce2 100644 --- a/plugins/DRCaloFastSimModel.h +++ b/plugins/DRCaloFastSimModel.h @@ -1,17 +1,43 @@ -#include "G4OpBoundaryProcess.hh" +#ifndef DRCaloFastSimModel_h +#define DRCaloFastSimModel_h +#include "G4OpBoundaryProcess.hh" +#include "G4GenericMessenger.hh" +#include "G4OpAbsorption.hh" +#include "G4OpWLS.hh" +#include "G4Material.hh" +#include +#include +#include +#include +#include +#include -struct FastFiberData -{ +struct FastFiberData { public: - FastFiberData(G4int, G4double, G4double, G4double, G4ThreeVector, G4ThreeVector, G4ThreeVector, G4int status = G4OpBoundaryProcessStatus::Undefined); - FastFiberData& operator=(const FastFiberData& theData) = default; - - FastFiberData(const FastFiberData& theData) = default; - ~FastFiberData() = default; - + FastFiberData(G4int id, G4double en, G4double globTime, G4double path, + G4ThreeVector pos, G4ThreeVector mom, G4ThreeVector pol, + G4int status = G4OpBoundaryProcessStatus::Undefined) { + trackID = id; + kineticEnergy = en; + globalTime = globTime; + pathLength = path; + globalPosition = pos; + momentumDirection = mom; + polarization = pol; + mOpBoundaryStatus = status; + mOpAbsorptionNumIntLenLeft = DBL_MAX; + mOpWLSNumIntLenLeft = DBL_MAX; + mStepLengthInterval = 0.; + } + ~FastFiberData()=default; - void reset(); + void reset() { + this->mOpBoundaryStatus = G4OpBoundaryProcessStatus::Undefined; + this->mOpAbsorptionNumIntLenLeft = DBL_MAX; + this->mOpWLSNumIntLenLeft = DBL_MAX; + this->mStepLengthInterval = 0.; + } G4double GetAbsorptionNILL() { return mOpAbsorptionNumIntLenLeft; } void SetAbsorptionNILL(G4double in) { mOpAbsorptionNumIntLenLeft = in; } @@ -25,7 +51,16 @@ struct FastFiberData G4double GetStepLengthInterval() { return mStepLengthInterval; } void AddStepLengthInterval(G4double in) { mStepLengthInterval += in; } - G4bool checkRepetitive(const FastFiberData, G4bool checkInterval = true); + G4bool checkRepetitive(const FastFiberData theData, G4bool checkInterval = true) { + if (this->trackID != theData.trackID) + return false; + if (this->mOpBoundaryStatus != theData.mOpBoundaryStatus) + return false; + if (checkInterval && std::abs(this->mStepLengthInterval - theData.mStepLengthInterval) > G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()) + return false; + + return true; + } G4int trackID; G4double kineticEnergy; @@ -42,37 +77,282 @@ struct FastFiberData G4double mStepLengthInterval; }; -FastFiberData::FastFiberData(G4int id, G4double en, G4double globTime, G4double path, G4ThreeVector pos, G4ThreeVector mom, G4ThreeVector pol, G4int status) -{ - trackID = id; - kineticEnergy = en; - globalTime = globTime; - pathLength = path; - globalPosition = pos; - momentumDirection = mom; - polarization = pol; - mOpBoundaryStatus = status; - mOpAbsorptionNumIntLenLeft = DBL_MAX; - mOpWLSNumIntLenLeft = DBL_MAX; - mStepLengthInterval = 0.; -} - -G4bool FastFiberData::checkRepetitive(const FastFiberData theData, G4bool checkInterval) -{ - if (this->trackID != theData.trackID) - return false; - if (this->mOpBoundaryStatus != theData.mOpBoundaryStatus) +class DRCFiberModel { +public: + DRCFiberModel()=default; + ~DRCFiberModel()=default; + + G4OpBoundaryProcess* pOpBoundaryProc = nullptr; + G4OpAbsorption* pOpAbsorption = nullptr; + G4OpWLS* pOpWLS = nullptr; + G4bool fProcAssigned = false; + + FastFiberData mDataPrevious = FastFiberData(0, 0., 0., 0., G4ThreeVector(0), G4ThreeVector(0), G4ThreeVector(0)); + FastFiberData mDataCurrent = FastFiberData(0, 0., 0., 0., G4ThreeVector(0), G4ThreeVector(0), G4ThreeVector(0)); + + G4int fSafety = 1; + G4double mNtransport = 0.; + G4double mTransportUnit = 0.; + G4ThreeVector mFiberPos = G4ThreeVector(0); + G4ThreeVector mFiberAxis = G4ThreeVector(0); + G4bool fKill = false; + G4bool fTransported = false; + G4bool fSwitch = true; + G4int fVerbose = 0; + + G4bool checkTotalInternalReflection(const G4Track *track) { + if (!fProcAssigned) + setPostStepProc(track); // locate OpBoundaryProcess only once + + G4int theStatus = pOpBoundaryProc->GetStatus(); + + if (fVerbose > 1) { + std::cout << "DRCFiberModel::checkTotalInternalReflection | TrackID = " << std::setw(4) << track->GetTrackID(); + std::cout << " | G4OpBoundaryProcessStatus = " << std::setw(2) << theStatus; + std::cout << " | Track status = " << track->GetTrackStatus(); + std::cout << " | StepLength = " << std::setw(9) << track->GetStepLength() << std::endl; + } + + if (track->GetTrackStatus() == fStopButAlive || track->GetTrackStatus() == fStopAndKill) + return false; + + // accumulate step length + mDataCurrent.AddStepLengthInterval(track->GetStepLength()); + + // skip exceptional iteration with FresnelReflection + if (theStatus == G4OpBoundaryProcessStatus::FresnelReflection) + mDataCurrent.SetOpBoundaryStatus(theStatus); + + // some cases have a status StepTooSmall when the reflection happens + // between the boundary of cladding & outer volume (outside->cladding) + // since the outer volume is not a G4Region + if (theStatus == G4OpBoundaryProcessStatus::TotalInternalReflection || theStatus == G4OpBoundaryProcessStatus::StepTooSmall) { + if (theStatus != G4OpBoundaryProcessStatus::TotalInternalReflection) { + // skip StepTooSmall if the track already has TotalInternalReflection + if (mDataCurrent.GetOpBoundaryStatus() == G4OpBoundaryProcessStatus::TotalInternalReflection) + return false; + if (mDataPrevious.GetOpBoundaryStatus() == G4OpBoundaryProcessStatus::TotalInternalReflection) + return false; + } + + G4int trackID = track->GetTrackID(); + G4double kineticEnergy = track->GetKineticEnergy(); + G4double globalTime = track->GetGlobalTime(); + G4double pathLength = track->GetStepLength(); + G4ThreeVector globalPosition = track->GetPosition(); + G4ThreeVector momentumDirection = track->GetMomentumDirection(); + G4ThreeVector polarization = track->GetPolarization(); + + auto candidate = FastFiberData(trackID, kineticEnergy, globalTime, pathLength, + globalPosition, momentumDirection, polarization, theStatus); + + if (pOpAbsorption != nullptr) + candidate.SetAbsorptionNILL(pOpAbsorption->GetNumberOfInteractionLengthLeft()); + if (pOpWLS != nullptr) + candidate.SetWLSNILL(pOpWLS->GetNumberOfInteractionLengthLeft()); + + G4bool repetitive = false; + + if (candidate.checkRepetitive(mDataCurrent, false) && mDataCurrent.checkRepetitive(mDataPrevious)) + repetitive = true; + + mDataPrevious = mDataCurrent; + mDataCurrent = candidate; + + return repetitive; + } + return false; - if (checkInterval && std::abs(this->mStepLengthInterval - theData.mStepLengthInterval) > G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()) + } // checkTotalInternalReflection + + G4bool checkAbsorption(const G4double prevNILL, const G4double currentNILL) { + if (prevNILL < 0. || currentNILL < 0.) + return false; // the number of interaction length left has to be reset + if (prevNILL == currentNILL) + return false; // no absorption + if (prevNILL == DBL_MAX || currentNILL == DBL_MAX) + return false; // NILL is re-initialized + + G4double deltaNILL = prevNILL - currentNILL; + + if (currentNILL - deltaNILL * (mNtransport + fSafety) < 0.) + return true; // absorbed before reaching fiber end + return false; + } // checkAbsorption + + G4bool checkNILL() { + if (!fTransported) + return true; // do nothing if the track is not already transported + + G4double wlsNILL = DBL_MAX; + G4double absorptionNILL = DBL_MAX; + + if (pOpWLS != nullptr) { + wlsNILL = pOpWLS->GetNumberOfInteractionLengthLeft(); + if (mDataPrevious.GetWLSNILL() == DBL_MAX || mDataCurrent.GetWLSNILL() == DBL_MAX) + return true; // NILL is re-initialized + } + + if (pOpAbsorption != nullptr) { + absorptionNILL = pOpAbsorption->GetNumberOfInteractionLengthLeft(); + if (mDataPrevious.GetAbsorptionNILL() == DBL_MAX || mDataCurrent.GetAbsorptionNILL() == DBL_MAX) + return true; // NILL is re-initialized + } + + if (wlsNILL < 0. || absorptionNILL < 0.) + return true; // let GEANT4 to reset them + + G4double deltaWlsNILL = mDataPrevious.GetWLSNILL() - mDataCurrent.GetWLSNILL(); + G4double deltaAbsorptionNILL = mDataPrevious.GetAbsorptionNILL() - mDataCurrent.GetAbsorptionNILL(); + + G4double finalWlsNILL = wlsNILL - deltaWlsNILL * fSafety; + G4double finalAbsorptionNILL = absorptionNILL - deltaAbsorptionNILL * fSafety; + + // prevent double counting of the probability of getting absorbed + // (which already estimated before transportation) + // reset NILL again + if (finalWlsNILL < 0. || finalAbsorptionNILL < 0.) + return false; + + return true; + } // checkNILL + + bool check_trigger(const G4Track* track) { + if (fTransported) { + // different propagation direction (e.g. mirror) + if (mFiberAxis.dot(track->GetMomentumDirection()) * mFiberAxis.dot(mDataCurrent.momentumDirection) < 0) + reset(); + + // track is already transported and did pass NILL check, nothing to do + return false; + } + + if (!checkTotalInternalReflection(track)) + return false; // nothing to do if the track has no repetitive total internal reflection + + auto theTouchable = track->GetTouchableHandle(); + auto solid = theTouchable->GetSolid(); + + if (fVerbose > 0) + print(); // at this point, the track should have passed all prerequisites before entering computationally heavy operations + + if (solid->GetEntityType() != "G4Tubs") + return false; // only works for G4Tubs at the moment + + G4Tubs* tubs = static_cast(solid); + G4double fiberLen = 2. * tubs->GetZHalfLength(); + + mFiberPos = theTouchable->GetHistory()->GetTopTransform().Inverse().TransformPoint(G4ThreeVector(0., 0., 0.)); + mFiberAxis = theTouchable->GetHistory()->GetTopTransform().Inverse().TransformAxis(G4ThreeVector(0., 0., 1.)); + + auto delta = mDataCurrent.globalPosition - mDataPrevious.globalPosition; + mTransportUnit = delta.dot(mFiberAxis); + + // estimate the number of expected total internal reflections before reaching fiber end + auto fiberEnd = (mTransportUnit > 0.) ? mFiberPos + mFiberAxis * fiberLen / 2. : mFiberPos - mFiberAxis * fiberLen / 2.; + auto toEnd = fiberEnd - track->GetPosition(); + G4double toEndAxis = toEnd.dot(mFiberAxis); + G4double maxTransport = std::floor(toEndAxis / mTransportUnit); + mNtransport = maxTransport - fSafety; + + if (mNtransport < 1.) + return false; // require at least n = fSafety of total internal reflections at the end + + if (checkAbsorption(mDataPrevious.GetWLSNILL(), mDataCurrent.GetWLSNILL())) + return false; // do nothing if WLS happens before reaching fiber end + if (checkAbsorption(mDataPrevious.GetAbsorptionNILL(), mDataCurrent.GetAbsorptionNILL())) + fKill = true; // absorbed before reaching fiber end + + return true; + } + + void setPostStepProc(const G4Track *track) { + G4ProcessManager *pm = track->GetDefinition()->GetProcessManager(); + auto postStepProcessVector = pm->GetPostStepProcessVector(); + + for (unsigned int np = 0; np < postStepProcessVector->entries(); np++) { + auto theProcess = (*postStepProcessVector)[np]; + + auto theType = theProcess->GetProcessType(); + + if (theType != fOptical) + continue; + + if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpBoundary) + pOpBoundaryProc = dynamic_cast(theProcess); + else if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpAbsorption) + pOpAbsorption = dynamic_cast(theProcess); + else if (theProcess->GetProcessSubType() == G4OpProcessSubType::fOpWLS) + pOpWLS = dynamic_cast(theProcess); + } + + fProcAssigned = true; + + return; + } // setPostStepProc + + void reset() { + mNtransport = 0.; + mTransportUnit = 0.; + mFiberPos = G4ThreeVector(0); + mFiberAxis = G4ThreeVector(0); + fKill = false; + fTransported = false; + mDataCurrent.reset(); + mDataPrevious.reset(); + } + + void print() { + if (fVerbose > 1) { + G4cout << G4endl; + + G4cout << "mDataPrevious.trackID = " << mDataPrevious.trackID; + G4cout << " | .mOpBoundaryStatus = " << std::setw(4) << mDataPrevious.GetOpBoundaryStatus(); + G4cout << " | .mStepLengthInterval = " << mDataPrevious.GetStepLengthInterval() << G4endl; + + if (fVerbose > 2) { + G4cout << " | globalPosition = (" << std::setw(9) << mDataPrevious.globalPosition.x(); + G4cout << "," << std::setw(9) << mDataPrevious.globalPosition.y(); + G4cout << "," << std::setw(9) << mDataPrevious.globalPosition.z() << ")" << G4endl; + + G4cout << " | momentumDirection = (" << std::setw(9) << mDataPrevious.momentumDirection.x(); + G4cout << "," << std::setw(9) << mDataPrevious.momentumDirection.y(); + G4cout << "," << std::setw(9) << mDataPrevious.momentumDirection.z() << ")" << G4endl; + + G4cout << " | polarization = (" << std::setw(9) << mDataPrevious.polarization.x(); + G4cout << "," << std::setw(9) << mDataPrevious.polarization.y(); + G4cout << "," << std::setw(9) << mDataPrevious.polarization.z() << ")" << G4endl; + + G4cout << " | globalTime = " << std::setw(9) << mDataPrevious.globalTime << G4endl; + G4cout << " | WLSNILL = " << std::setw(9) << mDataPrevious.GetWLSNILL() << G4endl; + G4cout << " | AbsorptionNILL = " << std::setw(9) << mDataPrevious.GetAbsorptionNILL() << G4endl; + } + + G4cout << "mDataCurrent.trackID = " << mDataCurrent.trackID; + G4cout << " | .mOpBoundaryStatus = " << std::setw(4) << mDataCurrent.GetOpBoundaryStatus() << G4endl; + + if (fVerbose > 2) { + G4cout << " | globalPosition = (" << std::setw(9) << mDataCurrent.globalPosition.x(); + G4cout << "," << std::setw(9) << mDataCurrent.globalPosition.y(); + G4cout << "," << std::setw(9) << mDataCurrent.globalPosition.z() << ")" << G4endl; + + G4cout << " | momentumDirection = (" << std::setw(9) << mDataCurrent.momentumDirection.x(); + G4cout << "," << std::setw(9) << mDataCurrent.momentumDirection.y(); + G4cout << "," << std::setw(9) << mDataCurrent.momentumDirection.z() << ")" << G4endl; + + G4cout << " | polarization = (" << std::setw(9) << mDataCurrent.polarization.x(); + G4cout << "," << std::setw(9) << mDataCurrent.polarization.y(); + G4cout << "," << std::setw(9) << mDataCurrent.polarization.z() << ")" << G4endl; + + G4cout << " | globalTime = " << std::setw(9) << mDataCurrent.globalTime << G4endl; + G4cout << " | WLSNILL = " << std::setw(9) << mDataCurrent.GetWLSNILL() << G4endl; + G4cout << " | AbsorptionNILL = " << std::setw(9) << mDataCurrent.GetAbsorptionNILL() << G4endl; + } - return true; -} + G4cout << G4endl; + } + } // print +}; // end of the class -void FastFiberData::reset() -{ - this->mOpBoundaryStatus = G4OpBoundaryProcessStatus::Undefined; - this->mOpAbsorptionNumIntLenLeft = DBL_MAX; - this->mOpWLSNumIntLenLeft = DBL_MAX; - this->mStepLengthInterval = 0.; -} +#endif diff --git a/plugins/FiberDRCaloSDAction.cpp b/plugins/FiberDRCaloSDAction.cpp index 1d946ff21..37dc55d9c 100644 --- a/plugins/FiberDRCaloSDAction.cpp +++ b/plugins/FiberDRCaloSDAction.cpp @@ -1,6 +1,4 @@ // DD4hep Framework include files -#include "DD4hep/Version.h" -#include "DD4hep/Objects.h" #include "DD4hep/Segmentations.h" #include "DDG4/Geant4Random.h" #include "DDG4/Geant4SensDetAction.inl" @@ -9,8 +7,22 @@ #include "G4OpticalPhoton.hh" // k4geo Framework include files - #include "FiberDRCaloSDAction.h" +#include "DRCaloFastSimModel.h" + +// Geant4 include files +#include "G4SystemOfUnits.hh" +#include "G4PhysicalConstants.hh" +#include "G4Step.hh" +#include "G4TouchableHistory.hh" +#include "G4ThreeVector.hh" +#include "G4HCofThisEvent.hh" +#include "G4SDManager.hh" +#include "G4ParticleDefinition.hh" +#include "G4ParticleTypes.hh" +#include "G4OpticalPhoton.hh" +#include "G4OpBoundaryProcess.hh" +#include "G4OpProcessSubType.hh" #if DD4HEP_VERSION_GE(1, 21) #define GEANT4_CONST_STEP const @@ -29,15 +41,15 @@ namespace dd4hep /* * Geant4SensitiveAction sensitive detector for the Dual-readout calorimeter * - * \author Sungwon Kim + * \author Sungwon Kim, Sanghyun Ko * \version 1.0 * \ingroup DD4HEP_SIMULATION */ - struct DRCData - { - Geant4HitCollection *fHitCollection; - G4int fHCID; + struct DRCData { + public: + bool skipScint = true; + DRCFiberModel fastfiber; G4int fWavBin; G4int fTimeBin; @@ -47,63 +59,136 @@ namespace dd4hep G4float fTimeEnd; G4float fWavlenStep; G4float fTimeStep; - static const int fArraySize = 24; - double fGraph_X[fArraySize] ={1.37760 * dd4hep::eV, - 1.45864 * dd4hep::eV, - 1.54980 * dd4hep::eV, - 1.65312 * dd4hep::eV, - 1.71013 * dd4hep::eV, - 1.77120 * dd4hep::eV, - 1.83680 * dd4hep::eV, - 1.90745 * dd4hep::eV, - 1.98375 * dd4hep::eV, - 2.06640 * dd4hep::eV, - 2.10143 * dd4hep::eV, - 2.13766 * dd4hep::eV, - 2.17516 * dd4hep::eV, - 2.21400 * dd4hep::eV, - 2.25426 * dd4hep::eV, - 2.29600 * dd4hep::eV, - 2.33932 * dd4hep::eV, - 2.38431 * dd4hep::eV, - 2.43106 * dd4hep::eV, - 2.47968 * dd4hep::eV, - 2.53029 * dd4hep::eV, - 2.58300 * dd4hep::eV, - 2.63796 * dd4hep::eV, - 2.69531 * dd4hep::eV}; - double fGraph_Y[fArraySize] ={0.903 * 0.903, - 0.903 * 0.903, - 0.903 * 0.903, - 0.903 * 0.903, - 0.903 * 0.903, - 0.903 * 0.903, - 0.902 * 0.902, - 0.901 * 0.901, - 0.898 * 0.898, - 0.895 * 0.895, - 0.893 * 0.893, - 0.891 * 0.891, - 0.888 * 0.888, - 0.883 * 0.883, - 0.87 * 0.87, - 0.838 * 0.838, - 0.76 * 0.76, - 0.62 * 0.62, - 0.488 * 0.488, - 0.345 * 0.345, - 0.207 * 0.207, - 0.083 * 0.083, - 0.018 * 0.018, - 0.}; - - G4double wavToE(G4double wav) { return CLHEP::h_Planck * CLHEP::c_light / wav; } - - int findWavBin(G4double en) - { + + private: + // from 900 nm to 460 nm + const std::vector fGraph_X = { + 1.37760 * CLHEP::eV, + 1.45864 * CLHEP::eV, + 1.54980 * CLHEP::eV, + 1.65312 * CLHEP::eV, + 1.71013 * CLHEP::eV, + 1.77120 * CLHEP::eV, + 1.83680 * CLHEP::eV, + 1.90745 * CLHEP::eV, + 1.98375 * CLHEP::eV, + 2.06640 * CLHEP::eV, + + 2.10143 * CLHEP::eV, + 2.13766 * CLHEP::eV, + 2.17516 * CLHEP::eV, + 2.21400 * CLHEP::eV, + 2.25426 * CLHEP::eV, + 2.29600 * CLHEP::eV, + 2.33932 * CLHEP::eV, + 2.38431 * CLHEP::eV, + 2.43106 * CLHEP::eV, + 2.47968 * CLHEP::eV, + + 2.53029 * CLHEP::eV, + 2.58300 * CLHEP::eV, + 2.63796 * CLHEP::eV, + 2.69531 * CLHEP::eV, + 2.75520 * CLHEP::eV, + 2.81782 * CLHEP::eV, + 2.88335 * CLHEP::eV, + 2.95200 * CLHEP::eV, + 3.09960 * CLHEP::eV, + 3.54241 * CLHEP::eV, + + 4.13281 * CLHEP::eV + }; + // filter efficiency of the Kodak Wratten No.9 filter + const std::vector fKodakEff = { + 0.903, + 0.903, + 0.903, + 0.903, + 0.903, + 0.903, + 0.902, + 0.901, + 0.898, + 0.895, + + 0.893, + 0.891, + 0.888, + 0.883, + 0.87, + 0.838, + 0.76, + 0.62, + 0.488, + 0.345, + + 0.207, + 0.083, + 0.018, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + + 0. + }; + + // SiPM efficiency Hamamatsu S14160-1310PS + // TODO migrate this part to the digitization step! + // Note: Ideally, this should be part of the digitization step. + // (not the simulation step) + // But, to do this, we need to store the distribution + // of the optical photon wavelength. + // While we can develop another feature to enable this, + // let's emulate the SiPM efficiency in the simulation step for now. + // We just need a working code and without this, + // the number of Cherenkov photon will be order of magnitude higher + const std::vector fSipmEff = { + 0.02, + 0.025, + 0.045, + 0.06, + 0.0675, + 0.075, + 0.0925, + 0.11, + 0.125, + 0.14, + + 0.146, + 0.152, + 0.158, + 0.164, + 0.17, + 0.173, + 0.176, + 0.178, + 0.179, + 0.18, + + 0.181, + 0.182, + 0.183, + 0.184, + 0.18, + 0.173, + 0.166, + 0.158, + 0.15, + 0.12, + + 0.05 + }; + + public: + G4double wavToE(G4double wav) const { return CLHEP::h_Planck * CLHEP::c_light / wav; } + + int findWavBin(G4double en) const { int i = 0; - for (; i < fWavBin + 1; i++) - { + for (; i < fWavBin + 1; i++) { if (en < wavToE((fWavlenStart - static_cast(i) * fWavlenStep) * CLHEP::nm)) break; } @@ -111,11 +196,9 @@ namespace dd4hep return fWavBin + 1 - i; } - int findTimeBin(G4double stepTime) - { + int findTimeBin(G4double stepTime) const { int i = 0; - for (; i < fTimeBin + 1; i++) - { + for (; i < fTimeBin + 1; i++) { if (stepTime < ((fTimeStart + static_cast(i) * fTimeStep) * CLHEP::ns)) break; } @@ -123,37 +206,31 @@ namespace dd4hep return i; } - // Linear interpolation function for calculating the efficiency of yellow filter, used in rejectedByYellowFilter - double getFilterEff(G4double G4energy) { - double energy = (G4energy * (dd4hep::MeV / CLHEP::MeV)); // Convert G4 MeV to dd4hep MeV - if (energy <= fGraph_X[0]) // If the photon energy <= 1.37760 eV, than return maximum filter efficiency - return fGraph_Y[0]; - - for(int idx = 0; idx < fArraySize; ++idx) { - if (energy <= fGraph_X[idx]) { - double x1 = fGraph_X[idx - 1]; - double x2 = fGraph_X[idx]; - double y1 = fGraph_Y[idx - 1]; - double y2 = fGraph_Y[idx]; - - return (y1 + ((y2 - y1) / (x2 - x1))*(energy - x1)); // return linear interpolated filter efficiency + // Linear interpolation function for calculating the efficiency of yellow filter + // used in rejectedByYellowFilter + double getFilterEff(const std::vector& yarray, const G4double G4energy) const { + // If the photon energy <= 1.37760 eV, than return maximum filter efficiency + if (G4energy <= fGraph_X.at(0)) + return yarray.at(0); + + for(unsigned idx = 1; idx < yarray.size(); ++idx) { + if (G4energy <= fGraph_X.at(idx)) { + double x1 = fGraph_X.at(idx-1); + double x2 = fGraph_X.at(idx); + double y1 = yarray.at(idx-1); + double y2 = yarray.at(idx); + + // return linear interpolated filter efficiency + return (y1 + ((y2 - y1) / (x2 - x1))*(G4energy - x1)); } } - // This should not happen - std::cout << "Error in Yellow filter efficiency with photon energy : " << energy << " MeV" << std::endl; - std::cout << "Cannot find corresponding filter efficiency" << std::endl; return 0.; } // If true, then the photon is rejected by yellow filter - bool rejectedByYellowFilter(G4double G4energy, double rndVal) - { - double energy = (G4energy * (dd4hep::MeV / CLHEP::MeV)); // Convert G4 MeV to dd4hep MeV - if ( energy >= fGraph_X[fArraySize-1] ) // Photon w/ E > 2.69531 eV rejected - return true; - - double FilterEff = getFilterEff(G4energy); // Get efficiency of filter using photon's energy + bool rejectedByYellowFilter(G4double G4energy, double rndVal) const { + const double FilterEff = getFilterEff(fKodakEff,G4energy); // Get efficiency of filter using photon's energy // filter efficiency == probability of photon accepted by filter // == Probability of random value (from uniform distribution with range 0 ~ 1) smaller than filter efficiency @@ -161,97 +238,299 @@ namespace dd4hep return (rndVal > FilterEff); } + // check sipm efficiency + // TODO migrate this to the digitization step + bool rejectedBySiPM(double G4energy, double rndVal) const { + return (rndVal > getFilterEff(fSipmEff,G4energy)); + } + DRCData() - : fHitCollection(0), fHCID(-1), fWavBin(120), fTimeBin(650), - fWavlenStart(900.), fWavlenEnd(300.), fTimeStart(5.), fTimeEnd(70.) + : fWavBin(120), fTimeBin(650), fWavlenStart(900.), + fWavlenEnd(300.), fTimeStart(5.), fTimeEnd(70.) { fWavlenStep = (fWavlenStart - fWavlenEnd) / (float)fWavBin; fTimeStep = (fTimeEnd - fTimeStart) / (float)fTimeBin; } - }; + }; // struct DRCData - /// Define collections created by this sensitive action object template <> - void Geant4SensitiveAction::defineCollections() + Geant4SensitiveAction::Geant4SensitiveAction(Geant4Context* ctxt, + const std::string& nam, + DetElement det, + Detector& desc) + : Geant4Sensitive(ctxt,nam,det,desc), m_collectionName(), m_collectionID(0) { + declareProperty("skipScint", m_userData.skipScint = true); + declareProperty("ReadoutName", m_readoutName); + declareProperty("CollectionName", m_collectionName); + initialize(); + InstanceCount::increment(this); + + m_userData.fastfiber.fSafety = 1; + m_userData.fastfiber.fVerbose = 0; + } + + /// Define collections created by this sensitive action object + template <> + void Geant4SensitiveAction::defineCollections() { std::string readout_name = m_sensitive.readout().name(); m_collectionID = defineCollection(m_sensitive.readout().name()); std::cout << "defineCollection Geant4DRCalorimeter readout_name : " << readout_name << std::endl; std::cout << "defineCollection Geant4DRCalorimeter m_collectionID : " << m_collectionID << std::endl; + + if (m_userData.skipScint) { + defineCollection(std::string(m_sensitive.readout().name())+"_scint"); + std::cout << "defineCollection Geant4Calorimeter readout_name : " << readout_name + "_scint" << std::endl; + std::cout << "defineCollection Geant4Calorimeter m_collectionID : " << m_collectionID + 1 << std::endl; + } } /// Method for generating hit(s) using the information of G4Step object. template <> - G4bool Geant4SensitiveAction::process(G4Step GEANT4_CONST_STEP *step, G4TouchableHistory*) - { - if (step->GetTrack()->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition()) - return false; - - typedef Geant4DRCalorimeter::Hit Hit; - - Geant4StepHandler h(step); - Geant4HitCollection *coll = collection(m_collectionID); - HitContribution contrib = Hit::extractContribution(step); - - auto theTouchable = step->GetPostStepPoint()->GetTouchable(); - dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager(); - dd4hep::VolumeID volID = volMgr.volumeID(theTouchable); - G4ThreeVector global = step->GetPostStepPoint()->GetPosition(); - G4ThreeVector local = theTouchable->GetHistory()->GetTopTransform().TransformPoint(global); - // MoveUpHistory(GetHistoryDepth - 2) -> tower touchable, local position - dd4hep::Position loc(local.x() * dd4hep::millimeter / CLHEP::millimeter, local.y() * dd4hep::millimeter / CLHEP::millimeter, local.z() * dd4hep::millimeter / CLHEP::millimeter); - dd4hep::Position glob(global.x() * dd4hep::millimeter / CLHEP::millimeter, global.y() * dd4hep::millimeter / CLHEP::millimeter, global.z() * dd4hep::millimeter / CLHEP::millimeter); - - auto cID = m_segmentation->cellID(loc, glob, volID); // This returns cID corresponding to SiPM Wafer - Hit *hit = coll->find(CellIDCompare(cID)); - - G4double hitTime = step->GetPostStepPoint()->GetGlobalTime(); - G4double energy = step->GetTrack()->GetTotalEnergy(); - - // Apply yellow filter here - // Get random number from (0~1) uniform distribution - // If the photon is from Scint. process, calculate the filter eff. based on its energy - // If (random number) > (Eff), the photon is rejected by yellow filter (= do not make hit (or count photon) for that photon) - dd4hep::DDSegmentation::VolumeID ceren = static_cast(m_segmentation->decoder()->get(cID, "c")); - bool IsCeren = static_cast(ceren); - if (!(IsCeren)) - { - Geant4Event& evt = context()->event(); + G4bool Geant4SensitiveAction::process(G4Step GEANT4_CONST_STEP *step, G4TouchableHistory *) { + // optical photons traveling through the cladding is not interesting + // but consume lots of computation power + // let's kill optical photons inside the cladding whose status is not StepTooSmall + if ( step->GetPreStepPoint() && + step->GetPreStepPoint()->GetPhysicalVolume()->GetLogicalVolume()->GetNoDaughters()==1 && + step->GetTrack()->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition() ) { + // 1e-9 is the default tolerance + // for the warnings, see https://geant4-forum.web.cern.ch/t/error-occurs-when-an-optical-photon-hits-the-edge-of-a-cubic-scintillator/8748 + // we're not interested in the optical photon position + // but only the number of photons (and timing) + // so we assume it's fine to ignore the warnings + if (step->GetStepLength() > 1e-8 * CLHEP::mm) + step->GetTrack()->SetTrackStatus(fStopAndKill); + } + // the fiber itself is the SD + // we skip the scintillation process and only account for the Cherenkov process + // remember to turn off the scintillation process! + if (m_userData.skipScint) { + // we need to move the touchable to the tower to retrieve volID + auto* touchable = const_cast(step->GetPostStepPoint()->GetTouchable()); + const auto* logicalVol = touchable->GetVolume()->GetLogicalVolume(); + + // we're not interested in the world or assembly volume + if (touchable->GetHistoryDepth() < 2) + return false; + + // we're only interested in the fiber core + if ( logicalVol->GetNoDaughters()!=0 ) + return false; + + // now let's make the touchable points to the tower + // world -> assembly -> tower + touchable->MoveUpHistory( touchable->GetHistoryDepth()-2 ); + + // now the touchable is the tower + // get local position and volumeID + // dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager(); + // dd4hep::VolumeID volID = volMgr.volumeID(touchable); + // note the above method started to throw warnings since the PR DD4hep#1390 + // so we switch to the copy number + + // trick: we retrieve the tower's volID by using the fact that + // in the DRconstructor.cpp, the first 32bits of the volID + // contain the information relevant to the tower + // and this 32bit integer becomes the tower's copy number + auto copyNo = touchable->GetCopyNumber(); + + // ideally the below operation should be GridDRcalo_k4geo::convertFirst32to64 + // but this is trivial, so let's avoid doing dynamic cast + dd4hep::VolumeID volID = static_cast(copyNo); + G4ThreeVector global = step->GetPostStepPoint()->GetPosition(); + G4ThreeVector local = touchable->GetHistory()->GetTopTransform().TransformPoint(global); + + // convert G4 position to dd4hep position + dd4hep::Position loc(local.x() * dd4hep::millimeter / CLHEP::millimeter, local.y() * dd4hep::millimeter / CLHEP::millimeter, local.z() * dd4hep::millimeter / CLHEP::millimeter); + dd4hep::Position glob(global.x() * dd4hep::millimeter / CLHEP::millimeter, global.y() * dd4hep::millimeter / CLHEP::millimeter, global.z() * dd4hep::millimeter / CLHEP::millimeter); + + // retrieve cellID and distinguish Cherenkov & scintillation fibers + auto cID = m_segmentation->cellID(loc, glob, volID); + auto ceren = static_cast(m_segmentation->decoder()->get(cID, "c")); + bool IsCeren = static_cast(ceren); + + Geant4HitCollection* coll = collection(m_collectionID); + + if (IsCeren) { + // Cherenkov fiber + // skip anything else than optical photons + if (step->GetTrack()->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition()) + return false; + + const auto* track = step->GetTrack(); + + // reset when moving to the next track + if (m_userData.fastfiber.mDataCurrent.trackID != track->GetTrackID()) + m_userData.fastfiber.reset(); + + // need repetitive total internal reflection + if (!m_userData.fastfiber.check_trigger(track)) + return false; + + // absorption + if (m_userData.fastfiber.fKill) { + step->GetTrack()->SetTrackStatus(fStopAndKill); + + return false; + } + + // backward transportation + if (m_userData.fastfiber.mTransportUnit < 0.) { + step->GetTrack()->SetTrackStatus(fStopAndKill); + + return false; + } + + // for timing measurement + double timeUnit = m_userData.fastfiber.mDataCurrent.globalTime - m_userData.fastfiber.mDataPrevious.globalTime; + double timeShift = timeUnit * m_userData.fastfiber.mNtransport; + + // check wheter the optical photon will be rejected by the SiPM + // TODO migrate this to the digitization step + Geant4Event& evt = context()->event(); + Geant4Random& rnd = evt.random(); // Get random generator + double rndVal = rnd.uniform(0, 1); // Get random number from uniform distribution [0, 1] + G4double energy = step->GetTrack()->GetTotalEnergy(); + + if (m_userData.rejectedBySiPM(energy, rndVal)) { + step->GetTrack()->SetTrackStatus(fStopAndKill); + + return false; + } + + // default hit (optical photon count) + Geant4DRCalorimeter::Hit* drHit = coll->find(CellIDCompare(cID)); + + if (!drHit) { + drHit = new Geant4DRCalorimeter::Hit(m_userData.fWavlenStep, m_userData.fTimeStep); + drHit->cellID = cID; + drHit->SetSiPMnum(cID); + drHit->SetTimeStart(m_userData.fTimeStart); + drHit->SetTimeEnd(m_userData.fTimeEnd); + drHit->SetWavlenMax(m_userData.fWavlenStart); + drHit->SetWavlenMin(m_userData.fWavlenEnd); + coll->add(cID, drHit); + } + + // everything should be in the G4 unit + // (approximate) timing at the end of the fiber + G4double hitTime = step->GetPostStepPoint()->GetGlobalTime() + timeShift; + + drHit->photonCount(); + int wavBin = m_userData.findWavBin(energy); + drHit->CountWavlenSpectrum(wavBin); + int timeBin = m_userData.findTimeBin(hitTime); + drHit->CountTimeStruct(timeBin); + + drHit->position = glob; + + // finally kill optical photon + step->GetTrack()->SetTrackStatus(fStopAndKill); + + return true; + } else { + // scintillation calo hit + + // assume nPhoton_scint >> nPhoton_cherenkov + // kill optical photons (from Cherenkov process) + if (step->GetTrack()->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition()) { + step->GetTrack()->SetTrackStatus(fStopAndKill); + + return false; + } + + // copy-paste of the dd4hep scintillation calorimeter SD + Geant4HitCollection* coll_scint = collection(m_collectionID+1); + Geant4Calorimeter::Hit* caloHit = coll_scint->find(CellIDCompare(cID)); + HitContribution contrib = Geant4Calorimeter::Hit::extractContribution(step,true); + + if ( !caloHit ) { + caloHit = new Geant4Calorimeter::Hit(glob); + caloHit->cellID = cID; + coll_scint->add(cID, caloHit); + } + + caloHit->truth.emplace_back(contrib); + caloHit->energyDeposit += contrib.deposit; + + Geant4StepHandler h(step); + mark(h.track); + + return true; + } // !IsCeren + } else { + // no skipping optical photon propagation + // SiPM wafers are SD in this case + if (step->GetTrack()->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition()) + return false; + + typedef Geant4DRCalorimeter::Hit Hit; + + Geant4HitCollection *coll = collection(m_collectionID); + + auto* touchable = step->GetPostStepPoint()->GetTouchable(); + dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager(); + dd4hep::VolumeID volID = volMgr.volumeID(touchable); + G4ThreeVector global = step->GetPostStepPoint()->GetPosition(); + G4ThreeVector local = touchable->GetHistory()->GetTopTransform().TransformPoint(global); + + dd4hep::Position loc(local.x() * dd4hep::millimeter / CLHEP::millimeter, local.y() * dd4hep::millimeter / CLHEP::millimeter, local.z() * dd4hep::millimeter / CLHEP::millimeter); + dd4hep::Position glob(global.x() * dd4hep::millimeter / CLHEP::millimeter, global.y() * dd4hep::millimeter / CLHEP::millimeter, global.z() * dd4hep::millimeter / CLHEP::millimeter); + + auto cID = m_segmentation->cellID(loc, glob, volID); // This returns cID corresponding to SiPM Wafer + Hit *hit = coll->find(CellIDCompare(cID)); + + G4double hitTime = step->GetPostStepPoint()->GetGlobalTime(); + G4double energy = step->GetTrack()->GetTotalEnergy(); + + // Apply yellow filter here + // Get random number from (0~1) uniform distribution + // If the photon is from Scint. process, calculate the filter eff. based on its energy + // If (random number) > (Eff), the photon is rejected by yellow filter (= do not make hit (or count photon) for that photon) + dd4hep::DDSegmentation::VolumeID ceren = static_cast(m_segmentation->decoder()->get(cID, "c")); + bool IsCeren = static_cast(ceren); + + Geant4Event& evt = context()->event(); Geant4Random& rnd = evt.random(); // Get random generator double rndVal = rnd.uniform(0, 1); // Get random number from uniform distribution [0, 1] - if (m_userData.rejectedByYellowFilter(energy, rndVal)) - return true; - } - if (!hit) - { - hit = new Geant4DRCalorimeter::Hit(m_userData.fWavlenStep, m_userData.fTimeStep); - hit->cellID = cID; - hit->SetSiPMnum(cID); - hit->SetTimeStart(m_userData.fTimeStart); - hit->SetTimeEnd(m_userData.fTimeEnd); - hit->SetWavlenMax(m_userData.fWavlenStart); - hit->SetWavlenMin(m_userData.fWavlenEnd); - coll->add(hit); - } + if (!IsCeren) { + if (m_userData.rejectedByYellowFilter(energy, rndVal)) + return false; + } - hit->photonCount(); - int wavBin = m_userData.findWavBin(energy); - hit->CountWavlenSpectrum(wavBin); - int timeBin = m_userData.findTimeBin(hitTime); - hit->CountTimeStruct(timeBin); + // check wheter the optical photon will be rejected by the SiPM + // TODO migrate this to the digitization step + if (m_userData.rejectedBySiPM(energy, rndVal)) + return false; + + if (!hit) { + hit = new Geant4DRCalorimeter::Hit(m_userData.fWavlenStep, m_userData.fTimeStep); + hit->cellID = cID; + hit->SetSiPMnum(cID); + hit->SetTimeStart(m_userData.fTimeStart); + hit->SetTimeEnd(m_userData.fTimeEnd); + hit->SetWavlenMax(m_userData.fWavlenStart); + hit->SetWavlenMin(m_userData.fWavlenEnd); + coll->add(cID,hit); + } - hit->position = glob; - hit->energyDeposit += contrib.deposit; - hit->truth.emplace_back(contrib); + hit->photonCount(); + int wavBin = m_userData.findWavBin(energy); + hit->CountWavlenSpectrum(wavBin); + int timeBin = m_userData.findTimeBin(hitTime); + hit->CountTimeStruct(timeBin); - return true; - } + hit->position = glob; + + return true; + } // !skipScint + } // Geant4SensitiveAction::process typedef Geant4SensitiveAction DRCaloSDAction; } } #include "DDG4/Factories.h" - DECLARE_GEANT4SENSITIVE(DRCaloSDAction) diff --git a/plugins/FiberDRCaloSDAction.h b/plugins/FiberDRCaloSDAction.h index 11c4e04ad..0815a2558 100644 --- a/plugins/FiberDRCaloSDAction.h +++ b/plugins/FiberDRCaloSDAction.h @@ -149,4 +149,5 @@ namespace dd4hep } } + #endif diff --git a/plugins/Geant4Output2EDM4hep_DRC.cpp b/plugins/Geant4Output2EDM4hep_DRC.cpp index fad2fde9f..864b9b0b4 100644 --- a/plugins/Geant4Output2EDM4hep_DRC.cpp +++ b/plugins/Geant4Output2EDM4hep_DRC.cpp @@ -75,7 +75,7 @@ namespace dd4hep { int m_eventNo { 0 }; int m_eventNumberOffset { 0 }; bool m_filesByRun { false }; - + /// Data conversion interface for MC particles to EDM4hep format void saveParticles(Geant4ParticleMap* particles); /// Store the metadata frame with e.g. the cellID encoding strings @@ -111,7 +111,7 @@ namespace dd4hep { } } }; - + template <> void EventParameters::extractParameters(podio::Frame& frame) { for(auto const& p: this->intParameters()) { printout(DEBUG, "Geant4OutputEDM4hep", "Saving event parameter: %s", p.first.c_str()); @@ -161,7 +161,7 @@ namespace dd4hep { #endif // DD4HEP_DDG4_Geant4Output2EDM4hep_DRC_H //========================================================================== -// AIDA Detector description implementation +// AIDA Detector description implementation //-------------------------------------------------------------------------- // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) // All rights reserved. @@ -590,42 +590,13 @@ void Geant4Output2EDM4hep_DRC::saveCollection(OutputContext& /*ctxt*/, } } //------------------------------------------------------------------- - } - else if( typeid( Geant4DRCalorimeter::Hit ) == coll->type().type() ){ - Geant4Sensitive* sd = coll->sensitive(); - int hit_creation_mode = sd->hitCreationMode(); + } else if( typeid( Geant4DRCalorimeter::Hit ) == coll->type().type() ) { // Create the hit container even if there are no entries! - auto& hits = m_calorimeterHits[colName]; auto& DRhits = m_drcaloHits[colName]; auto& DRwaves = m_drcaloWaves[colName]; - for(unsigned i=0 ; i < nhits ; ++i){ - auto sch = hits.first->create(); + for(unsigned i=0; i < nhits; ++i) { const Geant4DRCalorimeter::Hit* hit = coll->hit(i); - const auto& pos = hit->position; - sch.setCellID( hit->cellID ); - sch.setPosition({float(pos.x()/CLHEP::mm), float(pos.y()/CLHEP::mm), float(pos.z()/CLHEP::mm)}); - sch.setEnergy( hit->energyDeposit/CLHEP::GeV ); - - // now add the individual step contributions - for(auto ci=hit->truth.begin(); ci != hit->truth.end(); ++ci){ - - auto sCaloHitCont = hits.second->create(); - sch.addToContributions( sCaloHitCont ); - - const Geant4HitData::Contribution& c = *ci; - int trackID = pm->particleID(c.trackID); - auto mcp = m_particles.at(trackID); - sCaloHitCont.setEnergy( c.deposit/CLHEP::GeV ); - sCaloHitCont.setTime( c.time/CLHEP::ns ); - sCaloHitCont.setParticle( mcp ); - - if ( hit_creation_mode == Geant4Sensitive::DETAILED_MODE ) { - edm4hep::Vector3f p(c.x/CLHEP::mm, c.y/CLHEP::mm, c.z/CLHEP::mm); - sCaloHitCont.setPDG( c.pdgID ); - sCaloHitCont.setStepPosition( p ); - } - } // For DRC raw calo hit & raw time series auto rawCaloHits = DRhits.first->create(); @@ -636,7 +607,7 @@ void Geant4Output2EDM4hep_DRC::saveCollection(OutputContext& /*ctxt*/, float timeStart = hit->GetTimeStart(); float timeEnd = hit->GetTimeEnd(); auto& timemap = hit->GetTimeStruct(); - + rawTimeStruct.setInterval(samplingT); rawTimeStruct.setTime(timeStart); rawTimeStruct.setCharge( static_cast(hit->GetPhotonCount()) ); @@ -691,4 +662,4 @@ void Geant4Output2EDM4hep_DRC::saveCollection(OutputContext& /*ctxt*/, } else { error("+++ unknown type in Geant4HitCollection %s ", coll->type().type().name()); } -} \ No newline at end of file +}