diff --git a/.gitignore b/.gitignore
index 16ecd1f1b6..1c67a52076 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ build/*
*/*.pyc
**.pyc
+install/
lib/
share/
diff --git a/compact/hcal/lfhcal.xml b/compact/hcal/lfhcal.xml
index b7b1ef40b0..ceed721269 100644
--- a/compact/hcal/lfhcal.xml
+++ b/compact/hcal/lfhcal.xml
@@ -8,50 +8,7 @@
-
- #### Material Thickness
-
-
-
-
-
-
-
- - Hcal Endcap N Layers and computed Thickness
-
-
- FIXME: Need actual values once they are decided upon
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -1340,6 +1297,18 @@
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 6 bits [0-63] ModuleID X
+ 6 bits [0-63] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 4 bit [0-15] readout layer z
+ 4 bit [0-15] layer z in readout layer
+
system:8,moduleIDx:6,moduleIDy:6,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:4,layerz:4
diff --git a/compact/hcal/lfhcal/module_definitions.xml b/compact/hcal/lfhcal/module_definitions.xml
new file mode 100644
index 0000000000..83ca7ff4a7
--- /dev/null
+++ b/compact/hcal/lfhcal/module_definitions.xml
@@ -0,0 +1,48 @@
+
+
+
+ #### Material Thickness
+
+
+
+
+
+
+
+ - Hcal Endcap N Layers and computed Thickness
+
+
+ FIXME: Need actual values once they are decided upon
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/compact/hcal/lfhcal_2024_TB.xml b/compact/hcal/lfhcal_2024_TB.xml
new file mode 100644
index 0000000000..aa9ae61df2
--- /dev/null
+++ b/compact/hcal/lfhcal_2024_TB.xml
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### Forward (Positive Z) Endcap Hadronic Calorimeter
+
+ This is the ECCE LFHCAL design without individual tower placements and electronics
+ As deployed during thestbeam in 2024
+ The HCal forward insert shape is cut out from this detector
+
+ So then, actual detector area is "LFHCAL_length - LFHCALElectronicsThickness" long
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### for testing of a single module
+
+
+
+
+
+
+
+ ### positions of modules for full area LFHCAL (sorted by ascending r, x, y)
+
+
+
+
+
+
+
+
+
+
+
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 4 bits [0-15] ModuleID X
+ 4 bits [0-15] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 6 bit [0-63] readout layer z
+ 6 bit [0-63] layer z in readout layer
+
+
+ system:8,moduleIDx:4,moduleIDy:4,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:6,layerz:6
+
+
+
+
diff --git a/compact/hcal/lfhcal_2025_TB.xml b/compact/hcal/lfhcal_2025_TB.xml
new file mode 100644
index 0000000000..6efc2fc454
--- /dev/null
+++ b/compact/hcal/lfhcal_2025_TB.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### Forward (Positive Z) Endcap Hadronic Calorimeter
+ Test beam setup 2025
+
+ LFHCal module features 60 layers of Steel/Sc 1.6 cm/0.4 cm
+ Summing scheme 5-5-10-10-10-10-5-5
+ Currently don't have an implementation of electronics, so just leave that area (final 10 cm) empty
+ So then, actual detector area is "LFHCAL_length - LFHCALElectronicsThickness" long
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### for testing of a single module
+
+
+
+
+
+
+
+
+ ### positions of modules for full area LFHCAL (sorted by ascending x, y)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 4 bits [0-15] ModuleID X
+ 4 bits [0-15] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 6 bit [0-63] readout layer z
+ 6 bit [0-63] layer z in readout layer
+
+ system:8,moduleIDx:4,moduleIDy:4,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:6,layerz:6
+
+
+
+
diff --git a/compact/hcal/lfhcal_2026_TB_opt1.xml b/compact/hcal/lfhcal_2026_TB_opt1.xml
new file mode 100644
index 0000000000..7f79ff05ca
--- /dev/null
+++ b/compact/hcal/lfhcal_2026_TB_opt1.xml
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### Forward (Positive Z) Endcap Hadronic Calorimeter
+ Test beam setup 2026
+
+ LFHCal module features 60 layers of Steel/Sc 1.6 cm/0.4 cm
+ Summing scheme 5-5-10-10-10-10-5-5
+ Currently don't have an implementation of electronics, so just leave that area (final 10 cm) empty
+ So then, actual detector area is "LFHCAL_length - LFHCALElectronicsThickness" long
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### for testing of a single module
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### positions of modules for full area LFHCAL (sorted by ascending x, y)
+
+
+
+
+
+
+
+
+
+
+
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 4 bits [0-15] ModuleID X
+ 4 bits [0-15] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 6 bit [0-63] readout layer z
+ 6 bit [0-63] layer z in readout layer
+
+
+ system:8,moduleIDx:4,moduleIDy:4,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:6,layerz:6
+
+
+
+
diff --git a/compact/hcal/lfhcal_2026_TB_opt2.xml b/compact/hcal/lfhcal_2026_TB_opt2.xml
new file mode 100644
index 0000000000..d0c1883258
--- /dev/null
+++ b/compact/hcal/lfhcal_2026_TB_opt2.xml
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### Forward (Positive Z) Endcap Hadronic Calorimeter
+ Test beam setup 2026
+
+ LFHCal module features 60 layers of Steel/Sc 1.6 cm/0.4 cm
+ Summing scheme 5-5-5-5-10-10-10-10
+ Currently don't have an implementation of electronics, so just leave that area (final 10 cm) empty
+ So then, actual detector area is "LFHCAL_length - LFHCALElectronicsThickness" long
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### for testing of a single module
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### positions of modules for full area LFHCAL (sorted by ascending x, y)
+
+
+
+
+
+
+
+
+
+
+
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 4 bits [0-15] ModuleID X
+ 4 bits [0-15] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 6 bit [0-63] readout layer z
+ 6 bit [0-63] layer z in readout layer
+
+
+ system:8,moduleIDx:4,moduleIDy:4,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:4,layerz:6
+
+
+
+
diff --git a/compact/hcal/lfhcal_2028_TB_opt2.xml b/compact/hcal/lfhcal_2028_TB_opt2.xml
new file mode 100644
index 0000000000..6892ea4d6a
--- /dev/null
+++ b/compact/hcal/lfhcal_2028_TB_opt2.xml
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### Forward (Positive Z) Endcap Hadronic Calorimeter
+ Test beam setup 2028
+
+ LFHCal module features 60 layers of Steel/Sc 1.6 cm/0.4 cm
+ Summing scheme 5-5-5-5-10-10-10-10
+ Currently don't have an implementation of electronics, so just leave that area (final 10 cm) empty
+ So then, actual detector area is "LFHCAL_length - LFHCALElectronicsThickness" long
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### for testing of a single module
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ### positions of modules for full area LFHCAL (sorted by ascending x, y)
+
+
+
+
+
+
+
+
+
+
+
+
+ Explanation of CellIDs total 64 bits
+ first 8 bits system ID: 116 for LFHCal
+ followed by:
+ 4 bits [0-15] ModuleID X
+ 4 bits [0-15] ModuleID Y
+ 1 bit [0-1] Module type 0 - 8M , 1 - 4M
+ 2 bit [0-3] tower X
+ 1 bit [0-1] tower Y
+ 6 bit [0-63] readout layer z
+ 6 bit [0-63] layer z in readout layer
+
+
+ system:8,moduleIDx:4,moduleIDy:4,moduletype:1,passive:1,towerx:2,towery:1,rlayerz:4,layerz:6
+
+
+
+
diff --git a/configurations/lfhcal_2024_TB.yml b/configurations/lfhcal_2024_TB.yml
new file mode 100644
index 0000000000..29701b0394
--- /dev/null
+++ b/configurations/lfhcal_2024_TB.yml
@@ -0,0 +1,3 @@
+features:
+ hcal:
+ lfhcal_2024_TB:
diff --git a/configurations/lfhcal_2025_TB.yml b/configurations/lfhcal_2025_TB.yml
new file mode 100644
index 0000000000..aa0aa34e64
--- /dev/null
+++ b/configurations/lfhcal_2025_TB.yml
@@ -0,0 +1,3 @@
+features:
+ hcal:
+ lfhcal_2025_TB:
diff --git a/configurations/lfhcal_2026_TB_opt1.yml b/configurations/lfhcal_2026_TB_opt1.yml
new file mode 100644
index 0000000000..a0269f0058
--- /dev/null
+++ b/configurations/lfhcal_2026_TB_opt1.yml
@@ -0,0 +1,3 @@
+features:
+ hcal:
+ lfhcal_2026_TB_opt1:
diff --git a/configurations/lfhcal_2026_TB_opt2.yml b/configurations/lfhcal_2026_TB_opt2.yml
new file mode 100644
index 0000000000..de29611c27
--- /dev/null
+++ b/configurations/lfhcal_2026_TB_opt2.yml
@@ -0,0 +1,3 @@
+features:
+ hcal:
+ lfhcal_2026_TB_opt2:
diff --git a/configurations/lfhcal_2028_TB_opt2.yml b/configurations/lfhcal_2028_TB_opt2.yml
new file mode 100644
index 0000000000..3c300d6a1b
--- /dev/null
+++ b/configurations/lfhcal_2028_TB_opt2.yml
@@ -0,0 +1,3 @@
+features:
+ hcal:
+ lfhcal_2028_TB_opt2:
diff --git a/macro/vis.mac b/macro/vis.mac
index 715d769818..23a06b0dc4 100644
--- a/macro/vis.mac
+++ b/macro/vis.mac
@@ -15,8 +15,8 @@
/vis/viewer/set/viewpointThetaPhi -120 -30
/vis/viewer/addCutawayPlane 0 0 0 m 1 0 0
/vis/viewer/addCutawayPlane 0 0 0 m 0 -1 0
-/vis/viewer/zoom 4
-/vis/viewer/panTo 130 50 cm
+#/vis/viewer/zoom 4
+#/vis/viewer/panTo 130 50 cm
#/vis/filtering/trajectories/create/particleFilter
#/vis/filtering/trajectories/particleFilter-0/add gamma
diff --git a/src/LFHCAL_geo.cpp b/src/LFHCAL_geo.cpp
index 6ed7ae505a..e9fc336ed5 100644
--- a/src/LFHCAL_geo.cpp
+++ b/src/LFHCAL_geo.cpp
@@ -316,7 +316,7 @@ Assembly createScintillatorPlateEightM(Detector& desc, std::string basename,
// loop over all towers within same module
for (int i = 0; i < 8; i++) {
- // printout(DEBUG, "LFHCAL_geo", basename + _toString(i, "_tower_%d") + "\t" + _toString(modID) + "\t" + _toString(i) + "\t" + _toString(layerID));
+ // printout(DEBUG, "LFHCAL_geo", basename + _toString(i, "_tower_%d") + "\ttile:\t " + _toString(i) + "\t idX:" + _toString(towerx) + "\tidY:" + _toString(towery) + "\tID layer:"+ _toString(layerID) + "\tRO-layer:" + _toString(roLayer));
Volume modScintTowerAss =
createScintillatorTower(desc, basename + _toString(i, "_tower_%d"), w_tow, h_tow, t_slice,
slice_mat, region, limit, vis, sens, renderComp);
@@ -467,7 +467,8 @@ Assembly createScintillatorPlateFourM(Detector& desc, std::string basename,
Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
std::vector sl_params,
// int modID,
- double length, SensitiveDetector sens, bool renderComp, bool allSen) {
+ double length, SensitiveDetector sens, bool renderComp, bool allSen,
+ bool testbeam, int orientation) {
std::string baseName = "LFHCAL_8M";
// assembly definition
@@ -514,7 +515,8 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
if (allSen) {
sens.setType("calorimeter");
- vol_mountingPlate.setSensitiveDetector(sens);
+ if (!testbeam)
+ vol_mountingPlate.setSensitiveDetector(sens);
vol_modFrontPlate.setSensitiveDetector(sens);
vol_modBackPlate.setSensitiveDetector(sens);
vol_modSidePlateL.setSensitiveDetector(sens);
@@ -524,9 +526,10 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
}
if (renderComp) {
- vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
- // mod_params.mod_visStr);
- "LFHCALLayerTungstenVis");
+ if (!testbeam)
+ vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
+ // mod_params.mod_visStr);
+ "LFHCALLayerTungstenVis");
vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
// mod_params.mod_visStr);
"LFHCALLayerSteelVis");
@@ -544,8 +547,9 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
// mod_params.mod_visStr);
"LFHCALLayerSteelVis");
} else {
- vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
- "InvisibleNoDaughters");
+ if (!testbeam)
+ vol_mountingPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
+ "InvisibleNoDaughters");
vol_modFrontPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
"InvisibleNoDaughters");
vol_modBackPlate.setAttributes(desc, mod_params.mod_regStr, mod_params.mod_limStr,
@@ -573,13 +577,29 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
"InvisibleNoDaughters");
}
- int layer_num = 0;
- double slice_z = -length / 2 + mod_params.mod_MPThick +
- mod_params.mod_FWThick; // Keeps track of layers' local z locations
+ int layer_num = 0;
+
+ double total_stack = 0.0;
+ for (int i = 0; i < (int)sl_params.size(); i++) {
+ total_stack += sl_params[i].slice_thick + sl_params[i].slice_offset;
+ }
+
+ double slice_z = 0;
+
+ // Mirroring the start and end points of the slices without changing the order in which they're built for orientation 1
+ if (orientation == 1) {
+ slice_z = -length / 2 + mod_params.mod_MPThick + mod_params.mod_FWThick +
+ (length - (mod_params.mod_BWThick + mod_params.mod_FWThick) - mod_params.mod_MPThick -
+ total_stack);
+ } else {
+ slice_z = -length / 2 + mod_params.mod_MPThick + mod_params.mod_FWThick;
+ }
+
// Looping through the number of repeated layers & slices in each section
for (int i = 0; i < (int)sl_params.size(); i++) {
slice_z += sl_params[i].slice_offset +
sl_params[i].slice_thick / 2.; // Going to halfway point in layer
+
layer_num = sl_params[i].layer_ID;
//*************************************************
// absorber plates
@@ -595,8 +615,15 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
// Placing slice within layer
if (allSen)
modAbsAssembly.setSensitiveDetector(sens);
- pvm = vol_mod.placeVolume(modAbsAssembly,
- Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z)));
+ // orientations for absorber plates
+ if (orientation == 2) {
+ pvm = vol_mod.placeVolume(modAbsAssembly,
+ Transform3D(RotationZYX(M_PI, 0, 0), Position(0., 0., slice_z)));
+ } else {
+ pvm = vol_mod.placeVolume(modAbsAssembly,
+ Transform3D(RotationZYX(0, 0, 0), Position(0., 0., slice_z)));
+ }
+
if (allSen)
pvm.addPhysVolID("towerx", 0)
.addPhysVolID("towery", 0)
@@ -618,9 +645,17 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
// Placing slice within layer
if (allSen)
modFillAssembly.setSensitiveDetector(sens);
- pvm = vol_mod.placeVolume(
- modFillAssembly, Transform3D(RotationZYX(0, 0, 0),
- Position((mod_params.mod_notchDepth) / 2., 0., slice_z)));
+ // orientations for filler plates
+ if (orientation == 2) {
+ pvm = vol_mod.placeVolume(
+ modFillAssembly, Transform3D(RotationZYX(0, 0, 0),
+ Position(-(mod_params.mod_notchDepth) / 2., 0., slice_z)));
+ } else {
+ pvm = vol_mod.placeVolume(
+ modFillAssembly, Transform3D(RotationZYX(0, 0, 0),
+ Position((mod_params.mod_notchDepth) / 2., 0., slice_z)));
+ }
+
if (allSen)
pvm.addPhysVolID("towerx", 1)
.addPhysVolID("towery", 0)
@@ -639,26 +674,52 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
sl_params[i].slice_regStr, sl_params[i].slice_limStr, sl_params[i].slice_visStr, sens,
renderComp);
// Placing slice within layer
- pvm = vol_mod.placeVolume(
- modScintAssembly, Transform3D(RotationZYX(0, 0, 0),
- Position((mod_params.mod_notchDepth) / 2., 0, slice_z)));
+ // orientations for scintillator plates
+ if (orientation == 2) {
+ pvm = vol_mod.placeVolume(
+ modScintAssembly, Transform3D(RotationZYX(0, 0, 0),
+ Position(-(mod_params.mod_notchDepth) / 2., 0, slice_z)));
+ } else {
+ pvm = vol_mod.placeVolume(
+ modScintAssembly, Transform3D(RotationZYX(0, 0, 0),
+ Position((mod_params.mod_notchDepth) / 2., 0, slice_z)));
+ }
}
+
slice_z += sl_params[i].slice_thick / 2.;
}
// placement 8M module casing
- pvm = vol_mod.placeVolume(vol_mountingPlate,
- Position(0, 0, -(length - mod_params.mod_MPThick) / 2.));
- pvm = vol_mod.placeVolume(
- vol_modFrontPlate,
- Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick));
+ if (!testbeam)
+ pvm = vol_mod.placeVolume(vol_mountingPlate,
+ Position(0, 0, -(length - mod_params.mod_MPThick) / 2.));
+
+ // front plate with orientations
+ if (orientation == 1) {
+ pvm = vol_mod.placeVolume(vol_modFrontPlate,
+ Position(0, 0, (length - mod_params.mod_BWThick) / 2.));
+ } else {
+ pvm = vol_mod.placeVolume(
+ vol_modFrontPlate,
+ Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick));
+ }
+
if (allSen)
pvm.addPhysVolID("towerx", 2)
.addPhysVolID("towery", 0)
.addPhysVolID("layerz", 0)
.addPhysVolID("passive", 1);
- pvm =
- vol_mod.placeVolume(vol_modBackPlate, Position(0, 0, (length - mod_params.mod_BWThick) / 2.));
+
+ // back plate with orientations
+ if (orientation == 1) {
+ pvm = vol_mod.placeVolume(
+ vol_modBackPlate,
+ Position(0, 0, -(length - mod_params.mod_FWThick) / 2. + mod_params.mod_MPThick));
+ } else {
+ pvm = vol_mod.placeVolume(vol_modBackPlate,
+ Position(0, 0, (length - mod_params.mod_BWThick) / 2.));
+ }
+
if (allSen)
pvm.addPhysVolID("towerx", 2)
.addPhysVolID("towery", 0)
@@ -707,17 +768,32 @@ Volume createEightMModule(Detector& desc, moduleParamsStrct mod_params,
(mod_params.mod_FWThick + mod_params.mod_MPThick + mod_params.mod_BWThick) / 2 -
(lengthA - mod_params.mod_pcbLength) / 2.;
- pvm = vol_mod.placeVolume(
- vol_modPCB,
- Position(-(mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
- 2.,
- 0, z_offSetPCB));
+ //PCB placement with orientations
+ if (orientation == 1) {
+ pvm = vol_mod.placeVolume(
+ vol_modPCB,
+ Position(-(mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
+ 2.,
+ 0, -z_offSetPCB));
+ } else if (orientation == 2) {
+ pvm = vol_mod.placeVolume(
+ vol_modPCB,
+ Position((mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
+ 2.,
+ 0, z_offSetPCB));
+ } else {
+ pvm = vol_mod.placeVolume(
+ vol_modPCB,
+ Position(-(mod_params.mod_width - 2 * mod_params.mod_SWThick - mod_params.mod_notchDepth) /
+ 2.,
+ 0, z_offSetPCB));
+ }
return vol_mod;
}
//************************************************************************************************************
-//************************** create 8M module assembly ******************************************************
+//************************** create 4M module assembly ******************************************************
//************************************************************************************************************
Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params,
std::vector sl_params,
@@ -973,6 +1049,212 @@ Volume createFourMModule(Detector& desc, moduleParamsStrct mod_params,
return vol_mod;
}
+//********************************************************************************************
+//* *
+//* Create test beam *
+//============================== MAIN FUNCTION =============================================
+//* *
+//* The Test Beam setup only include 8M module support. *
+//* *
+//********************************************************************************************
+static Ref_t createTestBeam(Detector& desc, xml_h handle, SensitiveDetector sens) {
+ // global detector variables
+ xml_det_t detElem = handle;
+ std::string detName = detElem.nameStr();
+ int detID = detElem.id();
+
+ // general detector dimensions
+ xml_dim_t dim = detElem.dimensions();
+ double length = dim.z(); // Size along z-axis
+
+ // general detector position
+ xml_dim_t pos = detElem.position();
+ printout(DEBUG, "LFHCAL_geo",
+ "global LFHCal position " + _toString(pos.x()) + "\t" + _toString(pos.y()) + "\t" +
+ _toString(pos.z()));
+ std::cout << "Global LFHCal position:\n X: " << pos.x() << "\tY: " << pos.y()
+ << "\t Z: " << pos.z() << std::endl;
+ std::cout << "Envelope dimensions:\n X: " << dim.x() << "\tY: " << dim.y() << "\t Z: " << dim.z()
+ << std::endl;
+
+ struct position {
+ double x, y, z;
+ int orientation = 0;
+ int IDx = -1;
+ int IDy = -1;
+ };
+
+ std::vector pos8M;
+
+ xml_coll_t eightMPos(detElem, _Unicode(eightmodulepositions));
+ for (xml_coll_t position_i(eightMPos, _U(position)); position_i; ++position_i) {
+ xml_comp_t position_comp = position_i;
+ if (!getAttrOrDefault(position_comp, _Unicode(if), true)) {
+ printout(DEBUG, "LFHCAL_geo", "skipping x = %.1f cm, y = %.1f cm", position_comp.x(),
+ position_comp.y());
+ continue;
+ }
+ // Get orientation and ID attributes
+ int orientation = getAttrOrDefault(position_comp, _Unicode(orientation), 0);
+ int IDx = getAttrOrDefault(position_comp, _Unicode(IDx), -1);
+ int IDy = getAttrOrDefault(position_comp, _Unicode(IDy), -1);
+ pos8M.push_back(
+ {position_comp.x(), position_comp.y(), position_comp.z(), orientation, IDx, IDy});
+ }
+
+ // 8M module specific loading
+ xml_comp_t eightM_xml = detElem.child(_Unicode(eightmodule));
+ xml_dim_t eightMmod_dim = eightM_xml.dimensions();
+ moduleParamsStrct eightM_params(
+ getAttrOrDefault(eightMmod_dim, _Unicode(widthBackInner), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(heightBackInner), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(widthSideWall), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(widthTopWall), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(thicknessMountingPlate), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(thicknessFrontWall), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(thicknessBackWall), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(width), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(height), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(notchDepth), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(notchHeight), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(foilThick), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(pcbLength), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(pcbThick), 0.),
+ getAttrOrDefault(eightMmod_dim, _Unicode(pcbWidth), 0.), eightM_xml.visStr(),
+ eightM_xml.regionStr(), eightM_xml.limitsStr());
+
+ double minX = 10000;
+ double minY = 10000;
+ double maxX = -10000;
+ double maxY = -10000;
+ double minZ = 10000;
+ double maxZ = -10000;
+
+ std::cout << "Original module positions" << std::endl;
+ std::cout << "module width: " << eightM_params.mod_width
+ << "\t height: " << eightM_params.mod_height << "\t length: " << dim.z() << std::endl;
+ for (int e = 0; e < (int)pos8M.size(); e++) {
+ std::cout << pos8M[e].IDx << "\t" << pos8M[e].IDy << "\t" << pos8M[e].x << "\t"
+ << "\t" << pos8M[e].y << "\t" << pos8M[e].z << std::endl;
+ if (minX > pos8M[e].x)
+ minX = pos8M[e].x;
+ if (minY > pos8M[e].y)
+ minY = pos8M[e].y;
+ if (minZ > pos8M[e].z)
+ minZ = pos8M[e].z;
+ if (maxX < pos8M[e].x)
+ maxX = pos8M[e].x;
+ if (maxY < pos8M[e].y)
+ maxY = pos8M[e].y;
+ if (maxZ < pos8M[e].z)
+ maxZ = pos8M[e].z;
+ }
+ std::cout << "Maximum X: " << minX << "\t-\t" << maxX << "\t Y: " << minY << "\t - \t" << maxY
+ << "\t Z: " << minZ << "\t - \t" << maxZ << std::endl;
+
+ // envelope volume
+ xml_comp_t x_env = detElem.child(_Unicode(envelope));
+ Box env_box(dim.x() / 2, dim.y() / 2, dim.z() / 2);
+ Volume env_vol(detName + "_env", env_box, desc.material(x_env.materialStr()));
+
+ bool renderComponents = getAttrOrDefault(detElem, _Unicode(renderComponents), 0.);
+ bool allSensitive = getAttrOrDefault(detElem, _Unicode(allSensitive), 0.);
+ if (renderComponents) {
+ printout(DEBUG, "LFHCAL_geo", "enabled visualization");
+ } else {
+ printout(DEBUG, "LFHCAL_geo", "switchted off visualization");
+ }
+
+ std::vector slice_Params;
+ int layer_num = 0;
+ int readLayerC = 0;
+ for (xml_coll_t c(detElem, _U(layer)); c; ++c) {
+ xml_comp_t x_layer = c;
+ int repeat = x_layer.repeat();
+ int readlayer = getAttrOrDefault(x_layer, _Unicode(readoutlayer), 0.);
+ if (readLayerC != readlayer) {
+ readLayerC = readlayer;
+ layer_num = 0;
+ }
+ // Looping through the number of repeated layers in each section
+ for (int i = 0; i < repeat; i++) {
+ int slice_num = 0;
+
+ // Looping over each layer's slices
+ for (xml_coll_t l(x_layer, _U(slice)); l; ++l) {
+ xml_comp_t x_slice = l;
+ sliceParamsStrct slice_param(layer_num, slice_num, getAttrOrDefault(l, _Unicode(type), 0.),
+ x_slice.thickness(), getAttrOrDefault(l, _Unicode(offset), 0.),
+ readlayer, x_slice.materialStr(), x_slice.visStr(),
+ x_slice.regionStr(), x_slice.limitsStr());
+ slice_Params.push_back(slice_param);
+ ++slice_num;
+ }
+ layer_num++;
+ }
+ }
+
+ // create mother volume
+ DetElement det(detName, detID);
+ Assembly assembly(detName);
+ PlacedVolume phv;
+
+ int moduleIDx = -1;
+ int moduleIDy = -1;
+
+ // create 8M modules
+ for (int e = 0; e < (int)pos8M.size(); e++) {
+ if (e % 20 == 0)
+ printout(DEBUG, "LFHCAL_geo",
+ "LFHCAL placing 8M module: " + _toString(e) + "/" + _toString((int)pos8M.size()) +
+ "\t" + _toString(pos8M[e].x) + "\t" + _toString(pos8M[e].y) + "\t" +
+ _toString(pos8M[e].z));
+
+ // Calculate IDx and IDy based on preset values
+ moduleIDx = pos8M[e].IDx;
+ moduleIDy = pos8M[e].IDy;
+
+ // If moduleIDx or moduleIDy is not set, calculate based on position
+ if (moduleIDx < 0) {
+ moduleIDx = (int(pos8M[e].x + 20) / 10);
+ }
+ if (moduleIDy < 0) {
+ moduleIDy = (int(pos8M[e].y + 15) / 10);
+ }
+
+ std::cout << moduleIDx << "\t" << moduleIDy << "\t" << pos8M[e].x << "\t" << pos8M[e].y
+ << std::endl;
+ if (moduleIDx < 0 || moduleIDy < 0) {
+ printout(DEBUG, "LFHCAL_geo",
+ "LFHCAL WRONG ID FOR 8M module: " + _toString(e) + "/" +
+ _toString((int)pos8M.size()) + "\t" + _toString(moduleIDx) + "\t" +
+ _toString(moduleIDy));
+ }
+
+ // Accounting for individual orientations
+ Volume eightMassembly =
+ createEightMModule(desc, eightM_params, slice_Params, length, sens, renderComponents,
+ allSensitive, true, pos8M[e].orientation);
+
+ // Placing modules in world volume
+ auto tr8M = Transform3D(Position(-pos8M[e].x, -pos8M[e].y, pos8M[e].z));
+ phv = assembly.placeVolume(eightMassembly, tr8M);
+
+ phv.addPhysVolID("moduleIDx", moduleIDx)
+ .addPhysVolID("moduleIDy", moduleIDy)
+ .addPhysVolID("moduletype", 0);
+ }
+
+ Volume motherVol = desc.pickMotherVolume(det);
+ phv = env_vol.placeVolume(assembly);
+ phv = motherVol.placeVolume(env_vol,
+ Transform3D(Position(pos.x(), pos.y(), pos.z() + length / 2.)));
+ phv.addPhysVolID("system", detID);
+ det.setPlacement(phv);
+
+ return det;
+}
+
//********************************************************************************************
//* *
//* Create detector *
@@ -1091,6 +1373,9 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens
struct position {
double x, y, z;
+ int orientation = 0;
+ int IDx = -1;
+ int IDy = -1;
};
std::vector pos8M;
@@ -1098,12 +1383,19 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens
xml_coll_t eightMPos(detElem, _Unicode(eightmodulepositions));
for (xml_coll_t position_i(eightMPos, _U(position)); position_i; ++position_i) {
xml_comp_t position_comp = position_i;
- pos8M.push_back({position_comp.x(), position_comp.y(), position_comp.z()});
+ if (!getAttrOrDefault(position_comp, _Unicode(if), true)) {
+ printout(DEBUG, "LFHCAL_geo", "skipping x = %.1f cm, y = %.1f cm", position_comp.x(),
+ position_comp.y());
+ continue;
+ }
+ int orientation = getAttrOrDefault(position_comp, _Unicode(orientation), 0);
+ int IDx = getAttrOrDefault(position_comp, _Unicode(IDx), -1);
+ int IDy = getAttrOrDefault(position_comp, _Unicode(IDy), -1);
+ pos8M.push_back(
+ {position_comp.x(), position_comp.y(), position_comp.z(), orientation, IDx, IDy});
}
// create 8M modules
- Volume eightMassembly = createEightMModule(desc, eightM_params, slice_Params, length, sens,
- renderComponents, allSensitive);
for (int e = 0; e < (int)pos8M.size(); e++) {
if (e % 20 == 0)
printout(DEBUG, "LFHCAL_geo",
@@ -1116,12 +1408,29 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens
_toString((int)pos8M.size()) + "\t" + _toString(moduleIDx) + "\t" +
_toString(moduleIDy));
}
- moduleIDx = ((pos8M[e].x + 270) / 10);
- moduleIDy = ((pos8M[e].y + 265) / 10);
+
+ // Calculate IDx and IDy based on preset values
+ moduleIDx = pos8M[e].IDx;
+ moduleIDy = pos8M[e].IDy;
+
+ // If IDx or IDy is not set, calculate based on position
+ if (moduleIDx < 0) {
+ moduleIDx = ((pos8M[e].x + 270) / 10);
+ }
+ if (moduleIDy < 0) {
+ moduleIDy = ((pos8M[e].y + 265) / 10);
+ }
+
+ // Accounting for individual orientations
+
+ Volume eightMassembly =
+ createEightMModule(desc, eightM_params, slice_Params, length, sens, renderComponents,
+ allSensitive, false, pos8M[e].orientation);
// Placing modules in world volume
auto tr8M = Transform3D(Position(-pos8M[e].x, -pos8M[e].y, pos8M[e].z));
phv = assembly.placeVolume(eightMassembly, tr8M);
+
phv.addPhysVolID("moduleIDx", moduleIDx)
.addPhysVolID("moduleIDy", moduleIDy)
.addPhysVolID("moduletype", 0);
@@ -1132,7 +1441,13 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens
xml_coll_t fourMPos(detElem, _Unicode(fourmodulepositions));
for (xml_coll_t position_i(fourMPos, _U(position)); position_i; ++position_i) {
xml_comp_t position_comp = position_i;
- pos4M.push_back({position_comp.x(), position_comp.y(), position_comp.z()});
+ if (!getAttrOrDefault(position_comp, _Unicode(if), true)) {
+ printout(DEBUG, "LFHCAL_geo", "skipping x = %.1f cm, y = %.1f cm", position_comp.x(),
+ position_comp.y());
+ continue;
+ }
+ int orientation = getAttrOrDefault(position_comp, _Unicode(orientation), 0);
+ pos4M.push_back({position_comp.x(), position_comp.y(), position_comp.z(), orientation});
}
// create 4M modules
@@ -1169,4 +1484,40 @@ static Ref_t createDetector(Detector& desc, xml_h handle, SensitiveDetector sens
return det;
}
+
+//*************************************************************************************************
+// Definition of Detector elements:
+// - first argument defines which detector type is checked
+// - second argument which function is called
+// the "type" is the primary identifier in the xml files, what kind of detector you are buidling
+//*************************************************************************************************
+//=================================================================================================
+// in the xml files this looks as follows for the full geom
+// example from compact/lfhcal.xml
+//
+//=================================================================================================
DECLARE_DETELEMENT(epic_LFHCAL, createDetector)
+//=================================================================================================
+// in the xml files this looks as follows for the Test beam geom
+// example from compact/lfhcal_2026_TB.xml
+//
+//=================================================================================================
+DECLARE_DETELEMENT(epic_LFHCAL_TestBeam, createTestBeam)