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)