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)