diff --git a/src/GenericDetectors/CMakeLists.txt b/src/GenericDetectors/CMakeLists.txt
index f5afe5681908ae8f994190400a370ff45e4d434b..243e68bc8c194ecab98798628fbeffd0924aba10 100644
--- a/src/GenericDetectors/CMakeLists.txt
+++ b/src/GenericDetectors/CMakeLists.txt
@@ -33,6 +33,8 @@ dd4hep_add_plugin(GenDetectors
calorimeters/src/EcalBarrel_geo.cpp
calorimeters/src/PolyhedraEndcapCalorimeter3_geo.cpp
calorimeters/src/HexagonalShashlykSamplingECAL_geo.cpp
+ calorimeters/src/EndcapECAL_geo.cpp
+ calorimeters/src/CrystalEndcapECAL_geo.cpp
beamline/src/Beampipe_geo.cpp
pid/src/GenericRICH_geo.cpp
pid/src/HexagonalScintPreShower_geo.cpp
diff --git a/src/GenericDetectors/calorimeters/compact/CrystalEndcapECAL_example.xml b/src/GenericDetectors/calorimeters/compact/CrystalEndcapECAL_example.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3ebc4422527998a54bcd62e64592383e25514c9
--- /dev/null
+++ b/src/GenericDetectors/calorimeters/compact/CrystalEndcapECAL_example.xml
@@ -0,0 +1,144 @@
+
+
+
+
+ Electron Endcap EMCAL detector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Common Generic visualization attributes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Electromagnetic Calorimeter Endcaps
+
+
+
+
+
+
+
+ system:8,sector:4,module:20,layer:6,x:48:-8,y:-8
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/GenericDetectors/calorimeters/compact/Electron_Endcap_EMcal_PbWO4_example.xml b/src/GenericDetectors/calorimeters/compact/Electron_Endcap_EMcal_PbWO4_example.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ebacc28f48fab33d05fc43cc16828bbb18eb97eb
--- /dev/null
+++ b/src/GenericDetectors/calorimeters/compact/Electron_Endcap_EMcal_PbWO4_example.xml
@@ -0,0 +1,184 @@
+
+
+
+
+ Electron Endcap EMCAL detector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Common Generic visualization attributes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Electromagnetic Calorimeter Endcaps
+
+
+
+
+
+
+
+
+
+
+
+ Electromagnetic Calorimeter Barrel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ system:8,barrel:3,module:4,layer:6,slice:5,x:32:-16,y:-16
+
+
+
+
+ system:6,barrel:3,module:4,layer:6,slice:5,x:32:-16,y:-16
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/GenericDetectors/calorimeters/compact/materials.xml b/src/GenericDetectors/calorimeters/compact/materials.xml
index c351e08f00d476e494e4bd43a6c59a5d28e618a4..bfd331088756c5cb713ded8187f9586934c25b72 100644
--- a/src/GenericDetectors/calorimeters/compact/materials.xml
+++ b/src/GenericDetectors/calorimeters/compact/materials.xml
@@ -178,4 +178,11 @@
+
+
+
+
+
+
+
diff --git a/src/GenericDetectors/calorimeters/src/CrystalEndcapECAL_geo.cpp b/src/GenericDetectors/calorimeters/src/CrystalEndcapECAL_geo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8f05d57f2750f9cc731a72ffbbc098fb312a58db
--- /dev/null
+++ b/src/GenericDetectors/calorimeters/src/CrystalEndcapECAL_geo.cpp
@@ -0,0 +1,245 @@
+//==========================================================================
+// Crystal Endcap EM Calorimeter Detector implementation
+//--------------------------------------------------------------------------
+//
+// Authors : W.Armstrong
+//
+//==========================================================================
+// J.KIM 2020-04-01
+// Added box assembly of volumes
+//==========================================================================
+#include "DD4hep/DetFactoryHelper.h"
+#include "XML/Layering.h"
+#include
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::detail;
+
+static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
+ xml_det_t x_det = e;
+ xml_dim_t dim = x_det.dimensions();
+ int det_id = x_det.id();
+ string det_name = x_det.nameStr();
+ Material PbWO4 = description.material("PbWO4");
+ double rmin = dim.rmin();
+ double rmax = dim.rmax();
+ double zmin = dim.zmin();
+ double zmax = dim.zmax();
+ double thickness = zmax - zmin;
+ double z_pos = zmin + thickness / 2.0;
+
+ Assembly assembly(det_name);
+ DetElement endcap_DE(det_name,det_id);
+
+ // Create a tube to represent the calorimeter
+ Tube tube(rmin, rmax, thickness / 2.0);
+ Volume Vol("tube_volume", tube, PbWO4);
+ //auto PV = assembly.placeVolume(Vol, Position(0.0, 0.0, 0.0));
+ //PV.addPhysVolID("layer", 0);
+ //sens.setType("calorimeter");
+ //Vol.setSensitiveDetector(sens);
+
+ // Tube is filled with box-shaped crystals forming a grid.
+ Assembly box_assembly("box_assembly");
+ PlacedVolume pv_box;
+
+ // Box-shaped crystal dimension
+ double box_x_width = 2*cm;
+ double box_y_width = 2*cm;
+ double box_z_length = 60.5*cm;
+ // Gap between box-shaped crystals
+ double offset_x = 1*mm;
+ double offset_y = 1*mm;
+ // Number of crystals in a grid
+ int nx = floor(rmax/box_x_width);
+ int ny = floor(rmax/box_y_width);
+ // X or Y spacing increasement
+ double x_spacing = box_x_width + offset_x;
+ double y_spacing = box_y_width + offset_y;
+ // initial positions in X or Y.
+ double pos_x = 0*cm;
+ double pos_y = 0*cm;
+
+ // Create Box and Volume
+ Box box(box_x_width/2.0, box_y_width/2.0, box_z_length/2.0);
+ Volume vol("box_volume", box, PbWO4);
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Divide tube into 4 sections; top left, top right, bottom left, and bottom right
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Top left
+ ////////////////////////////////////////////////////////////////////////////////////
+ int i_module = 0;
+ for(int iy=0; iy rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ else
+ {
+ // Move to +X
+ pos_x += x_spacing;
+ if(sqrt((pos_x*pos_x) + (pos_y*pos_y)) < rmax && sqrt((pos_x*pos_x) + (pos_y*pos_y)) > rmin)
+ {
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ pv_box.addPhysVolID("sector",1).addPhysVolID("module",i_module);
+ sens.setType("calorimeter");
+ vol.setSensitiveDetector(sens);
+ }
+ // Move to +Y
+ pos_y += y_spacing;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Top right
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Initialize position in Y
+ pos_y = 0.0;
+ i_module=0;
+ for(int iy=0; iy rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ else
+ {
+ // Move to -X
+ pos_x -= x_spacing;
+ if(sqrt((pos_x*pos_x) + (pos_y*pos_y)) < rmax && sqrt((pos_x*pos_x) + (pos_y*pos_y)) > rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ pv_box.addPhysVolID("sector",2).addPhysVolID("module",i_module);
+ sens.setType("calorimeter");
+ vol.setSensitiveDetector(sens);
+ }
+ // Move to +Y
+ pos_y += y_spacing;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Bottom left
+ ////////////////////////////////////////////////////////////////////////////////////
+ // It's below the first row of the section of Top left
+ // That's why ny goes up to ny -2 (the first row of Bottom left starts one row less)
+ pos_y = -y_spacing;
+ i_module=0;
+ for(int iy=0; iy rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ else
+ {
+ // Move to +X
+ pos_x += x_spacing;
+ if(sqrt((pos_x*pos_x) + (pos_y*pos_y)) < rmax && sqrt((pos_x*pos_x) + (pos_y*pos_y)) > rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ pv_box.addPhysVolID("sector",3).addPhysVolID("module",i_module);
+ sens.setType("calorimeter");
+ vol.setSensitiveDetector(sens);
+ }
+ // Move to -Y
+ pos_y -= y_spacing;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Bottom right
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Again it's below the first row of the section of Top left
+ // That's why ny goes up to ny -2 (the first row of Bottom left starts one row less)
+ pos_y = -y_spacing;
+ i_module=0;
+ for(int iy=0; iy rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ else
+ {
+ // Move to -X
+ pos_x -= x_spacing;
+ if(sqrt((pos_x*pos_x) + (pos_y*pos_y)) < rmax && sqrt((pos_x*pos_x) + (pos_y*pos_y)) > rmin){
+ pv_box = assembly.placeVolume(vol, Position(pos_x,pos_y,0.0));
+ i_module++;
+ }
+ else{
+ continue;
+ }
+ }
+ pv_box.addPhysVolID("sector",4).addPhysVolID("module",i_module);
+ sens.setType("calorimeter");
+ vol.setSensitiveDetector(sens);
+ }
+ // Move to -Y
+ pos_y -= y_spacing;
+ }
+ ////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ Volume motherVol = description.pickMotherVolume(endcap_DE);
+ auto pv = motherVol.placeVolume(assembly, Position(0.0, 0.0, z_pos));
+ pv.addPhysVolID("system", det_id);
+ endcap_DE.setPlacement(pv);
+ return endcap_DE;
+}
+
+DECLARE_DETELEMENT(CrystalEndcapECAL,create_detector)
diff --git a/src/GenericDetectors/calorimeters/src/EndcapECAL_geo.cpp b/src/GenericDetectors/calorimeters/src/EndcapECAL_geo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8de145e0b73f1e685e16efdb9db625ae46d93009
--- /dev/null
+++ b/src/GenericDetectors/calorimeters/src/EndcapECAL_geo.cpp
@@ -0,0 +1,134 @@
+//==========================================================================
+// AIDA Detector description implementation
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author : M.Frank
+//
+//==========================================================================
+//
+// Specialized generic detector constructor
+//
+//==========================================================================
+#include "DD4hep/DetFactoryHelper.h"
+#include "XML/Layering.h"
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::detail;
+
+static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
+ xml_det_t x_det = e;
+ xml_dim_t dim = x_det.dimensions();
+ int det_id = x_det.id();
+ bool reflect = x_det.reflect(true);
+ string det_name = x_det.nameStr();
+ Material air = description.air();
+ int numsides = dim.numsides();
+ double rmin = dim.rmin();
+ double rmax = dim.rmax()*std::cos(M_PI/numsides);
+ double zmin = dim.zmin();
+ Layering layering(x_det);
+ double totalThickness = layering.totalThickness();
+ Volume endcapVol("endcap",PolyhedraRegular(numsides,rmin,rmax,totalThickness),air);
+ DetElement endcap("endcap",det_id);
+
+ int l_num = 1;
+ int layerType = 0;
+ double layerZ = -totalThickness/2;
+
+ endcapVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
+
+ for(xml_coll_t xc(x_det,_U(layer)); xc; ++xc) {
+ xml_comp_t x_layer = xc;
+ double l_thick = layering.layer(l_num-1)->thickness();
+ string l_name = _toString(layerType,"layer%d");
+ int l_repeat = x_layer.repeat();
+ Volume l_vol(l_name,PolyhedraRegular(numsides,rmin,rmax,l_thick),air);
+ vector sensitives;
+
+ int s_num = 1;
+ double sliceZ = -l_thick/2;
+ for(xml_coll_t xs(x_layer,_U(slice)); xs; ++xs) {
+ xml_comp_t x_slice = xs;
+ string s_name = _toString(s_num,"slice%d");
+ double s_thick = x_slice.thickness();
+ Material s_mat = description.material(x_slice.materialStr());
+ Volume s_vol(s_name,PolyhedraRegular(numsides,rmin,rmax,s_thick),s_mat);
+
+ s_vol.setVisAttributes(description.visAttributes(x_slice.visStr()));
+ sliceZ += s_thick/2;
+ PlacedVolume s_phv = l_vol.placeVolume(s_vol,Position(0,0,sliceZ));
+ s_phv.addPhysVolID("slice",s_num);
+ if ( x_slice.isSensitive() ) {
+ sens.setType("calorimeter");
+ s_vol.setSensitiveDetector(sens);
+ sensitives.push_back(s_phv);
+ }
+ sliceZ += s_thick/2;
+ s_num++;
+ }
+ l_vol.setVisAttributes(description.visAttributes(x_layer.visStr()));
+ if ( l_repeat <= 0 ) throw std::runtime_error(x_det.nameStr()+"> Invalid repeat value");
+ for(int j=0; jSetName((det_name+"_A").c_str());
+ DetElement sdetB = endcap.clone(det_name+"_B",x_det.id());
+
+ pv = assembly.placeVolume(endcapVol,Transform3D(RotationZYX(M_PI/numsides,0,0),
+ Position(0,0,z_pos)));
+ pv.addPhysVolID("barrel", 1);
+ sdetA.setPlacement(pv);
+
+ pv = assembly.placeVolume(endcapVol,Transform3D(RotationZYX(M_PI/numsides,M_PI,0),
+ Position(0,0,-z_pos)));
+ pv.addPhysVolID("barrel", 2);
+ sdetB.setPlacement(pv);
+
+ pv = motherVol.placeVolume(assembly);
+ pv.addPhysVolID("system", det_id);
+ both_endcaps.setPlacement(pv);
+ both_endcaps.add(sdetA);
+ both_endcaps.add(sdetB);
+ return both_endcaps;
+ }
+ Volume motherVol = description.pickMotherVolume(endcap);
+ pv = motherVol.placeVolume(endcapVol,Transform3D(RotationZYX(M_PI/numsides,0,0),
+ Position(0,0,z_pos)));
+ pv.addPhysVolID("system", det_id);
+ pv.addPhysVolID("barrel", 1);
+ endcap.setPlacement(pv);
+ Ref_t(endcap)->SetName(det_name.c_str());
+ return endcap;
+}
+
+DECLARE_DETELEMENT(EndcapECAL,create_detector)
+//DECLARE_DEPRECATED_DETELEMENT(EndcapECAL,create_detector)