diff --git a/CMakeLists.txt b/CMakeLists.txt index 61ebd49..6aa8cf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR) project(luxegeo) +# install(DIRECTORY compact DESTINATION share/luxegeo/) +# SET( CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" ) +SET( CMAKE_INSTALL_LIBDIR "lib" ) + # project version SET( ${PROJECT_NAME}_VERSION_MAJOR 0 ) SET( ${PROJECT_NAME}_VERSION_MINOR 0 ) @@ -15,6 +19,7 @@ find_package(DD4hep REQUIRED COMPONENTS DDG4) set(sources ./src/SimpleTracker_geo.cpp ./src/LUXETracker_geo.cpp + ./src/LUXEEcal_geo.cpp ) add_dd4hep_plugin(${PROJECT_NAME} SHARED ${sources}) # link it with DDCore, or whatever you need diff --git a/compact/ECAL_commondefs.xml b/compact/ECAL_commondefs.xml new file mode 100644 index 0000000..b3748bd --- /dev/null +++ b/compact/ECAL_commondefs.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/ECAL_commondisp.xml b/compact/ECAL_commondisp.xml new file mode 100644 index 0000000..5058e30 --- /dev/null +++ b/compact/ECAL_commondisp.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/compact/ECALe_luxe/ECALe_luxe_2512.xml b/compact/ECALe_luxe/ECALe_luxe_2512.xml new file mode 100644 index 0000000..cb73076 --- /dev/null +++ b/compact/ECALe_luxe/ECALe_luxe_2512.xml @@ -0,0 +1,132 @@ + + + + + + + The compact File for LUXE ECAL-E (updated December 2025) + + + + Additional design specific material definitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:8,layer:8,x:16,y:16,slice:8,module:4 + + + + system:8,layer:5,slice:4,module:3,x:4,y:4 + + + + + system:8,layer:5,slice:4,module:3,x:4,y:4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/ECALe_luxe/README.md b/compact/ECALe_luxe/README.md new file mode 100644 index 0000000..f317a53 --- /dev/null +++ b/compact/ECALe_luxe/README.md @@ -0,0 +1,57 @@ +LUXE ECAL-E - DD4hep +==================== + +## Structure +This directory contains the definition of the detector model geometries and configurations. +The following descriptions used by all detectors are stored in `..` directory: +* chemical elements, +* materials and extra materials, +* common definitions on the geometry of ECALs, and +* common definitions on the visulisation of ECALs. + +The names of compact files for LUXE ECAL-E are formatted as `ECALe_luxe_{variant}.xml` and put under directory `ECALe_luxe`. + +The detector consists of multiple layers that are stacked along the longitudinal _z_ direction. +Each layer is then further divided into several slices, which includes a tungsten plate, air gaps, and several silicon and electronic modules. +A module can be moved horizontally within the boundary of a layer, +and more than one module can be placed at the same _z_ position. + +Current variant `ECALe_luxe_2512.xml`, partially based on this [interim report for DRD-Calo SiW ECAL](https://indico.cern.ch/event/1551941/contributions/6683124). +- Detector type `LUXEEcal`, id `2500`. +- 15 layers/18 X0 in total. +- Layer composition: + - Pure tungsten (4.2 mm), + - Carbon fibre support (1.5 mm, to be confirmed [TBC]), + - Active sensor unit (ASU), which consists of + - High-voltage film (0.1 mm copper, TBC), + - Conductive glue (0.1 mm air, TBC), + - Si wafer (0.5 mm), + - Conductive glue (0.1 mm air, TBC), + - PCB board (1.7 mm), + - On board ASIC (1.2 mm PCB, TBC), and + - Air gap to make 15 mm longitudinal pitch. +- Per-slice module placement to implement the dead areas between ASUs and wafers. + - This variant has 2 ASUs and 8 wafers. + + +_**TODO**_ +- The readouts in the compact files are not properly implemented. +- The historic definitions should be cleaned out. + + +## Visualization +To test and visualize the detector, run +```shell +geoDisplay detector_compactfile.xml # or any other geometry +``` +To check materials, distances and possible overlappings, run +```shell +materialScan detector_compactfile.xml x0 y0 z0 x1 y1 z1 +``` +It will display a list of materials encountered by a straight line from `(x0,y0,z0)` to `(x1,y1,z1)`. + + +## Contribution +This subrepository is based on [Gyros (permission required)](https://gitlab.desy.de/luxe-ecal/performance/gyros/-/tree/main/generation/geometry) by the LUXE ECAL group. + +For previous variants `ECALe_luxe_v{0-2}.xml`, please also check the said Gyros repository. diff --git a/compact/ECALp_luxe/ECALp_luxe_2512.xml b/compact/ECALp_luxe/ECALp_luxe_2512.xml new file mode 100644 index 0000000..382840e --- /dev/null +++ b/compact/ECALp_luxe/ECALp_luxe_2512.xml @@ -0,0 +1,142 @@ + + + + + + + The compact File for LUXE ECAL-P (updated December 2025) + + + + Additional design specific material definitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:8,layer:8,x:16,y:16,slice:8,module:4 + + + + system:8,layer:5,slice:4,module:3,x:4,y:4 + + + + + system:8,layer:5,slice:4,module:3,x:4,y:4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/ECALp_luxe/README.md b/compact/ECALp_luxe/README.md new file mode 100644 index 0000000..40b909e --- /dev/null +++ b/compact/ECALp_luxe/README.md @@ -0,0 +1,55 @@ +LUXE ECAL-P - DD4hep +==================== + +## Structure +This directory contains the definition of the detector model geometries and configurations. +The following descriptions used by all detectors are stored in `..` directory: +* chemical elements, +* materials and extra materials, +* common definitions on the geometry of ECALs, and +* common definitions on the visulisation of ECALs. + +The names of compact files for LUXE ECAL-P are formatted as `ECALp_luxe_{variant}.xml` and put under directory `ECALp_luxe`. + +The detector consists of multiple layers that are stacked along the longitudinal _z_ direction. +Each layer is then further divided into several slices, which includes a tungsten plate, air gaps, and several silicon and electronic modules. +A module can be moved horizontally within the boundary of a layer, +and more than one module can be placed at the same _z_ position. + +Current variant `ECALp_luxe_2512.xml`, partially based on the updated design for ECAL-P TB2025. +- Detector type `LUXEEcal`, id `2000`. +- 20 layers/20 X0 in total. +- Layer composition: + - Pure tungsten (3.55 mm), + - Compact silicon sandwich (CSIS), which consists of + - Carbon fibre support (0.25 mm, to be confirmed [TBC]), + - Regular glue (0.05 mm air, TBC), + - Fanout film (0.1 mm copper, TBC), + - Conductive glue (0.05 mm air, TBC), + - Si wafer (0.32 mm), + - Conductive glue (0.05 mm air, TBC), + - High-voltage film (0.1 mm copper, TBC), and + - Air gap to make 4.5 mm longitudinal pitch. +- Per-slice module placement to implement the dead areas between CSISs. + - This variant has 6 CSISs. + + +_**TODO**_ +- The readouts in the compact files are not properly implemented. +- The historic definitions should be cleaned out. + + +## Visualization +To test and visualize the detector, run +```shell +geoDisplay detector_compactfile.xml # or any other geometry +``` +To check materials, distances and possible overlappings, run +```shell +materialScan detector_compactfile.xml x0 y0 z0 x1 y1 z1 +``` +It will display a list of materials encountered by a straight line from `(x0,y0,z0)` to `(x1,y1,z1)`. + + +## Contribution +This subrepository is based on [Gyros (permission required)](https://gitlab.desy.de/luxe-ecal/performance/gyros/-/tree/main/generation/geometry) by the LUXE ECAL group. diff --git a/compact/Materials_v1.xml b/compact/Materials_v1.xml new file mode 100644 index 0000000..5b1dca9 --- /dev/null +++ b/compact/Materials_v1.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + diff --git a/compact/extra_materials.xml b/compact/extra_materials.xml new file mode 100644 index 0000000..992ceec --- /dev/null +++ b/compact/extra_materials.xml @@ -0,0 +1,43 @@ + + + + extra materials + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/materials_ecal.xml b/compact/materials_ecal.xml new file mode 100644 index 0000000..a034301 --- /dev/null +++ b/compact/materials_ecal.xml @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + materials introduced for the BeamCal + + + + + + + + + + + + + + + + diff --git a/src/LUXEEcal_geo.cpp b/src/LUXEEcal_geo.cpp new file mode 100644 index 0000000..d417fe4 --- /dev/null +++ b/src/LUXEEcal_geo.cpp @@ -0,0 +1,211 @@ +//==================================================================== +// DD4hep Geometry driver for LUXE ECAL prototypes +// forked from the driver for Sampling Calo BOX prototype +// https://github.com/key4hep/k4geo/tree/main/CaloTB +// & the driver for LUXE Tracker prototype +// https://github.com/LUXEsoftware/luxegeo +//-------------------------------------------------------------------- +// S. Huang, IFIC Valencia +// Originally by S. Lu, DESY (CaloTB) +// & Y.C. Yap, DESY (LUXEGeo) +// $Id: $ +//==================================================================== +#include "DD4hep/Printout.h" +#include "DD4hep/DetFactoryHelper.h" +#include "XML/Layering.h" +#include "XML/Utilities.h" +#include "DDSegmentation/TiledLayerGridXY.h" + + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::detail; + + + +static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) { + + xml_det_t x_det = element; + string det_name = x_det.nameStr(); + DetElement sdet( det_name,x_det.id() ); + + Layering layering(x_det); + xml_dim_t dim = x_det.dimensions(); + + // --- create an envelope volume and position it into the world --------------------- + + Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ; + + dd4hep::xml::setDetectorTypeFlag( element, sdet ) ; + + if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ; + + //----------------------------------------------------------------------------------- + + Material air = theDetector.air(); + + sens.setType("calorimeter"); + +//==================================================================== +// +// Read all the dimensions from compact.xml, user can update the value. +// Use them to build a calo box prototye. +// +//==================================================================== + + double Calo_dim_x = dim.x(); + double Calo_dim_y = dim.y(); + double Calo_dim_z = dim.z(); + + printout( dd4hep::DEBUG, "building LUXEEcalPrototype", + "Ecal_dim_x : %e Ecal_dim_y: %e Ecal_dim_z: %e ", + Calo_dim_x, Calo_dim_y, Calo_dim_z) ; + + + Readout readout = sens.readout(); + Segmentation seg = readout.segmentation(); + + //unused: std::vector cellSizeVector = seg.segmentation()->cellDimensions(0); + //unused: double cell_sizeX = cellSizeVector[0]; + //unused: double cell_sizeY = cellSizeVector[1]; + + // check if we have a TiledLayerGridXY segmentation : + dd4hep::DDSegmentation::TiledLayerGridXY* tileSeg = + dynamic_cast< dd4hep::DDSegmentation::TiledLayerGridXY*>( seg.segmentation() ) ; + // TO CHECK: if readout.segmentation() does not have type TiledLayerGridXY, can it be converted? + + //access the layer identifier via the segmentation. + //the layer identifier is defined in the compact xml file. + //and use it to set the volumeID layer value later here. + string identifierLayer = tileSeg->fieldNameLayer(); // "K" or "layer" or "..." + +//==================================================================== +// +// general calculated parameters +// +//==================================================================== + + //calorimeter dimensions + double cal_hx = Calo_dim_x/2.0; + double cal_hy = Calo_dim_y/2.0; + double cal_hz = Calo_dim_z/2.0; + + +//==================================================================== +// +// build sampling layers in the CaloBox +// +//==================================================================== + + int layer_num = 0; + int layerType = 0; + + double layer_pos_z = - cal_hz; + + for (xml_coll_t c(x_det, _U(layer)); c; ++c) { + xml_comp_t x_layer = c; + int repeat = x_layer.repeat(); // Get number of times to repeat this layer. + const Layer* lay = layering.layer(layer_num); // Get the layer from the layering engine. + double layer_thickness = lay->thickness(); + string layer_type_name = _toString(layerType,"layerType%d"); + + // Loop over repeats for this layer. + for (int j = 0; j < repeat; j++) { + string layer_name = _toString(layer_num, "layer%d"); + DetElement layer(layer_name, layer_num); + + // Layer box & volume + Volume layer_vol(layer_type_name, Box(cal_hx, cal_hy, layer_thickness / 2), air); + + // Create the slices (sublayers) within the layer. + double slice_pos_z = -(layer_thickness / 2); + int slice_number = 0; + + for (xml_coll_t k(x_layer, _U(slice)); k; ++k) { + xml_comp_t x_slice = k; + string slice_name = _toString(slice_number, "slice%d"); + double slice_thickness = x_slice.thickness(); + Material slice_material = theDetector.material(x_slice.materialStr()); + DetElement slice(layer, slice_name, slice_number); + bool sliceHasModules = false; + if (x_slice.hasAttr(_Unicode(sliceHasModules))) { + sliceHasModules = x_slice.attr(_Unicode(sliceHasModules)); + } + + slice_pos_z += slice_thickness / 2; + // Slice volume & box + Volume slice_vol(slice_name, Box(cal_hx, cal_hy, slice_thickness / 2), air); // Material to be set later + + + if (sliceHasModules) { + for (xml_coll_t q(x_slice, _U(module)); q; ++q) { + xml_comp_t x_module = q; + int module_number = x_module.id(); + string module_name = slice_name + _toString(module_number, "_module%d"); + double module_offsetX = x_module.x_offset(); + double module_offsetY = x_module.y_offset(); + double module_sizeX = x_module.dx(); + double module_sizeY = x_module.dy(); + DetElement module(slice, module_name, module_number); + + // Module volume & box + Volume module_vol(module_name, Box(0.5*module_sizeX, 0.5*module_sizeY, slice_thickness / 2), slice_material); + if (x_slice.isSensitive()) { // sensitivity is written in slice level + // sens.setType("calorimeter"); + module_vol.setSensitiveDetector(sens); + } + // Set region, limitset, and vis. + module_vol.setAttributes(theDetector, x_module.regionStr(), x_module.limitsStr(), x_module.visStr()); + // module PlacedVolume + PlacedVolume module_phv = slice_vol.placeVolume(module_vol, Position(0 + module_offsetX, 0 + module_offsetY, 0)); + module_phv.addPhysVolID("module", module_number); + module.setPlacement(module_phv); + } + } else { + slice_vol.setMaterial(slice_material); + if (x_slice.isSensitive()) { + // sens.setType("calorimeter"); + slice_vol.setSensitiveDetector(sens); + } + } + + + // Set region, limitset, and vis. + slice_vol.setAttributes(theDetector, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr()); + // slice PlacedVolume + PlacedVolume slice_phv = layer_vol.placeVolume(slice_vol, Position(0, 0, slice_pos_z)); + slice_phv.addPhysVolID("slice", slice_number); + slice.setPlacement(slice_phv); + + // Increment Z position for next slice. + slice_pos_z += slice_thickness / 2; + // Increment slice number. + ++slice_number; + } + + + // Set region, limitset, and vis. + layer_vol.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); + + // Layer position in Z within the stave. + layer_pos_z += layer_thickness / 2; + // Layer physical volume. + PlacedVolume layer_phv = envelope.placeVolume(layer_vol, Position(0, 0, layer_pos_z)); + layer_phv.addPhysVolID(identifierLayer, layer_num); + layer.setPlacement(layer_phv); + + // Increment the layer Z position. + layer_pos_z += layer_thickness / 2; + // Increment the layer number. + ++layer_num; + } + + ++layerType; + } + + + return sdet; + +} + +DECLARE_DETELEMENT(LUXEEcal, create_detector)