diff --git a/compact/tracking/definitions_craterlake.xml b/compact/tracking/definitions_craterlake.xml index e11e6dbe8..3963c0ec5 100644 --- a/compact/tracking/definitions_craterlake.xml +++ b/compact/tracking/definitions_craterlake.xml @@ -41,15 +41,18 @@ Main parameters for Barrel TOF layers Barrel TOF region - - + + + + + Forward TOF region - - + + diff --git a/compact/tracking/tof_barrel.xml b/compact/tracking/tof_barrel.xml index 7a1b6949a..1e8bfee61 100644 --- a/compact/tracking/tof_barrel.xml +++ b/compact/tracking/tof_barrel.xml @@ -63,19 +63,21 @@ - - - - + + + + + + - - - + + + + + + + - - - - @@ -91,52 +93,104 @@ insideTrackingVolume="true"> + rmin="BarrelTOF_rmin - 1*mm" + rmax="BarrelTOF_rmax + 1*mm" + length="BarrelTOF_length" + /> Tracker Barrel Modules - - + + keep_layer means the next module is located at the same thickness level + so you can place component side by side + Just make sure all components you placed side by side share the same thickness + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + - - + + + - - + + - - + + + - - + + + - + + diff --git a/compact/tracking/tof_endcap.xml b/compact/tracking/tof_endcap.xml index e0c78530b..ebec385ff 100644 --- a/compact/tracking/tof_endcap.xml +++ b/compact/tracking/tof_endcap.xml @@ -107,7 +107,7 @@ 1 um padding to not have layer and module touch (ACTS requirement) - + @@ -122,8 +122,8 @@ - - + + @@ -133,19 +133,25 @@ - - - - - - - + + + + + + + + + + + - + + + @@ -155,12 +161,14 @@ - + + - + + @@ -205,7 +213,7 @@ reflect="false"> - + @@ -218,19 +226,99 @@ - - + + + + + + + + + + + - + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -244,13 +332,16 @@ - + + + zstart="ForwardTOF_zmin" + xoffset="EndcapTOF_Module_length_design/2" + /> @@ -261,13 +352,300 @@ rmin="ForwardTOFLayer_rmin" rmax="ForwardTOFLayer_rmax" length="12*mm" - zstart="ForwardTOF_zmin" /> + zstart="ForwardTOF_zmin" + xoffset="EndcapTOF_Module_length_design/2" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + spacing="EndcapTOF_Module_spacing" + board_gap="EndcapTOF_Board_spacing" /> @@ -280,8 +658,8 @@ - - system:8,layer:4,module:8,idx:7,idy:5,x:32:-16,y:-16 + + system:8,layer:4,module:2,idx:5,idy:5,ids:6,x:36:-12,y:-16 diff --git a/src/BarrelTOFTracker_geo.cpp b/src/BarrelTOFTracker_geo.cpp index 6a9cf6c75..6598bc961 100644 --- a/src/BarrelTOFTracker_geo.cpp +++ b/src/BarrelTOFTracker_geo.cpp @@ -136,7 +136,8 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector // Compute module total thickness from components xml_coll_t ci(x_mod, _U(module_component)); for (ci.reset(), total_thickness = 0.0; ci; ++ci) { - total_thickness += xml_comp_t(ci).thickness(); + if (!getAttrOrDefault(xml_comp_t(ci), _Unicode(keep_layer), false)) + total_thickness += xml_comp_t(ci).thickness(); } // the module assembly volume Assembly m_vol(m_nam); @@ -174,18 +175,49 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector xml_comp_t x_comp = mci; xml_comp_t x_pos = x_comp.position(false); xml_comp_t x_rot = x_comp.rotation(false); - auto make_box = [&](double pos_x = 0, double pos_y = 0, double pos_z = 0, double rot_x = 0, - double rot_y = 0, double rot_z = 0, bool z_stacking = true) { + auto make_box = [&](double width, double length, double thickness, double pos_x = 0, + double pos_y = 0, double pos_z = 0, double rot_x = 0, double rot_y = 0, + double rot_z = 0, bool z_stacking = true) { + // Utility variable for the relative z-offset based off the previous components + const double zoff = thickness_sum + thickness / 2.0; + const string c_nam = _toString(ncomponents, "component%d"); ++ncomponents; - Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2); - Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr())); + Box c_box(width / 2, length / 2, thickness / 2); + Volume c_vol; + + xml_coll_t ci_tube(x_comp, _Unicode(inner_tube)); + if (ci_tube) { + double max_r = 0; + for (; ci_tube; ++ci_tube) { + // fill the hole with tube + xml_comp_t ct = ci_tube; + max_r = std::max(max_r, ct.rmax()); + Tube c_tube(ct.rmin(), ct.rmax(), length / 2); + Volume c_tubevol(c_nam + ct.nameStr(), c_tube, description.material(ct.materialStr())); + if (ct.visStr() != "") + c_tubevol.setVisAttributes(description, ct.visStr()); + m_vol.placeVolume(c_tubevol, Transform3D(RotationZYX(0, 0, -M_PI / 2), + Position(pos_x, pos_y, pos_z + zoff))); + } - // Utility variable for the relative z-offset based off the previous components - const double zoff = thickness_sum + x_comp.thickness() / 2.0; + Tube c_fbox(0, max_r, length / 2 + 1); + SubtractionSolid c_sbox(c_box, c_fbox, + Transform3D(RotationZYX(0, 0, -M_PI / 2), + Position(0, 0, 0))); //pos_x, pos_y, pos_z + zoff))); + + c_vol = Volume(c_nam, c_sbox, description.material(x_comp.materialStr())); + } else + c_vol = Volume(c_nam, c_box, description.material(x_comp.materialStr())); + + Volume test; + test = c_vol; + + // center if off by half the box length if box length is cut in half Position c_pos(pos_x, pos_y, pos_z + zoff); RotationZYX c_rot(rot_z, rot_y, rot_x); pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); + c_vol.setRegion(description, x_comp.regionStr()); c_vol.setLimitSet(description, x_comp.limitsStr()); c_vol.setVisAttributes(description, x_comp.visStr()); @@ -193,9 +225,8 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector pv.addPhysVolID("sensor", sensor_number++); c_vol.setSensitiveDetector(sens); sensitives[m_nam].push_back(pv); - module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, - total_thickness - thickness_so_far - - x_comp.thickness() / 2.0}; + module_thicknesses[m_nam] = {thickness_so_far + thickness / 2.0, + total_thickness - thickness_so_far - thickness / 2.0}; // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- Vector3D u(-1., 0., 0.); @@ -219,8 +250,8 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector //-------------------------------------------- } if (z_stacking) { - thickness_sum += x_comp.thickness(); - thickness_so_far += x_comp.thickness(); + thickness_sum += thickness; + thickness_so_far += thickness; // apply relative offsets in z-position used to stack components side-by-side thickness_sum += pos_z; thickness_so_far += pos_z; @@ -239,6 +270,11 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector pos_y = x_pos.y(0); pos_z = x_pos.z(0); } + double width = x_comp.width(); + double length = x_comp.length(); + double thickness = x_comp.thickness(); + bool keep_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + if (x_comp.hasChild(_Unicode(GridSensors))) { auto x_comp_t = x_comp.child(_Unicode(GridSensors)); // x-distance between centers of neighboring sensors @@ -262,23 +298,40 @@ static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector // || || || // ring_extra_width is the extra width between boundaries of the sensor boundaries (including dead space) double ring_extra_width = getAttrOrDefault(x_comp_t, _Unicode(ring_extra_width), 0); + auto half_length_str = + getAttrOrDefault(x_comp_t, _Unicode(half_length), "none"); double current_x = start_x; for (int nx = 0; nx < nsensors_x; ++nx) { double current_y = start_y; for (int ny = 0; ny < nsensors_y; ++ny) { - make_box(current_x, current_y, start_z, rot_x, rot_y, rot_z, - ((nx == nsensors_x - 1) && - (ny == nsensors_y - 1))); // all sensors are located at the same z-layer + double sensor_length = length; + double tmp_sensors_ydist = sensors_ydist; + // when we draw half a sensor, the center has to be shifted by 0.25 times the length of a sensor + // distance between centers to the next sensor also has to be reduced by 0.25 times the length of a sensor + if ((half_length_str == "left" || half_length_str == "both") && ny == 0) { + sensor_length = 0.5 * length; + current_y += 0.25 * length; + tmp_sensors_ydist -= 0.25 * length; + } + // same idea, but when you are drawing to the right, the right sensor center has to move in -y direction + if ((half_length_str == "right" || half_length_str == "both") && ny == nsensors_y - 1) { + sensor_length = 0.5 * length; + current_y -= 0.25 * length; + } + make_box(width, sensor_length, thickness, current_x, current_y, start_z, rot_x, rot_y, + rot_z, + (((nx == nsensors_x - 1) && (ny == nsensors_y - 1))) && + !keep_layer); // all sensors are located at the same z-layer // increment z-layers only at the end, after the last sensor is added - current_y += sensors_ydist; + current_y += tmp_sensors_ydist; if (ny + 1 == ny_before_ring) current_y += ring_extra_width; } current_x += sensors_xdist; } } else - make_box(pos_x, pos_y, pos_z, rot_x, rot_y, rot_z); + make_box(width, length, thickness, pos_x, pos_y, pos_z, rot_x, rot_y, rot_z, !keep_layer); } } diff --git a/src/EndcapTOF_geo.cpp b/src/EndcapTOF_geo.cpp index c4edc64a8..5e6c0c01c 100644 --- a/src/EndcapTOF_geo.cpp +++ b/src/EndcapTOF_geo.cpp @@ -1,9 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Nicolas Schmidt +// Copyright (C) 2022 - 2024, Nicolas Schmidt, Chun Yuen Tsang /** \addtogroup Trackers Trackers * \brief Type: **Endcap Tracker with TOF**. - * \author N. Schmidt * * \ingroup trackers * @@ -19,6 +18,7 @@ #include "XML/Utilities.h" #include #include +#include using namespace std; using namespace dd4hep; @@ -83,152 +83,220 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s double module_y = x_modsz.width(); double module_overlap = getAttrOrDefault(x_modsz, _Unicode(overlap), 0.); // x_modsz.overlap(); double module_spacing = getAttrOrDefault(x_modsz, _Unicode(spacing), 0.); // x_modsz.overlap(); + double board_gap = getAttrOrDefault(x_modsz, _Unicode(board_gap), 0.); //! Add support structure xml_comp_t x_supp = x_det.child(_Unicode(support)); xml_comp_t x_supp_envelope = x_supp.child(_Unicode(envelope), false); - double total_thickness = 0; - xml_comp_t x_modFront = x_det.child(_Unicode(moduleFront)); - xml_comp_t x_modBack = x_det.child(_Unicode(moduleBack)); - - // Compute module total thickness from components - xml_coll_t ci(x_modFront, _U(module_component)); - for (ci.reset(), total_thickness = 0.0; ci; ++ci) { - total_thickness += xml_comp_t(ci).thickness(); - } - - int module = 0; - int nx = 25; - int ny = 15; - for (int ix = 0; ix < 2 * nx; ix++) { - float xcoord = (ix - nx) * (module_x + module_spacing); - for (int iy = 0; iy < 2 * ny; iy++) { - float ycoord = (iy - ny) * (module_y - module_overlap); - //! Note the module ordering is different for front and back side - xml_comp_t x_modCurr = iy % 2 == 0 ? x_modFront : x_modBack; - - double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2; - if (iy % 2 == 0) { - module_z *= -1; - } - float corner_x1 = xcoord + module_x / 2; - float corner_x2 = xcoord - module_x / 2; - float corner_y1 = ycoord + module_y / 2; - float corner_y2 = ycoord - module_y / 2; - float maxRadius = - std::max(std::max(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)), - std::max(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1))); - float minRadius = - std::min(std::min(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)), - std::min(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1))); - if (maxRadius > envelope.rmax() || minRadius < envelope.rmin()) { - continue; - } - - string module_name = Form("module%d_%d_%d", module, ix, iy); - DetElement mod_elt(lay_elt, module_name, module); - - // create individual sensor layers here - string m_nam = Form("EndcapTOF_Module1_%d_%d", ix, iy); - - int ncomponents = 0; - // the module assembly volume - Assembly m_vol(m_nam); - m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr())); - - double thickness_so_far = 0.0; - double thickness_sum = -total_thickness / 2.0; - double thickness_carbonsupp = 0.0; - for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) { - xml_comp_t x_comp = mci; - xml_comp_t x_pos = x_comp.position(false); - xml_comp_t x_rot = x_comp.rotation(false); - const string c_nam = Form("component_%d_%d", ix, iy); - Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2); - Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr())); - if (x_comp.materialStr() == "CarbonFiber") { - thickness_carbonsupp = x_comp.thickness(); - } - // Utility variable for the relative z-offset based off the previous components - const double zoff = thickness_sum + x_comp.thickness() / 2.0; - if (x_pos && x_rot) { - Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff); - RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0)); - pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); - } else if (x_rot) { - Position c_pos(0, 0, zoff); - pv = m_vol.placeVolume( - c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos)); - } else if (x_pos) { - pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff)); + xml_comp_t x_modFrontLeft = x_det.child(_Unicode(moduleFrontLeft)); + xml_comp_t x_modFrontRight = x_det.child(_Unicode(moduleFrontRight)); + xml_comp_t x_modBackLeft = x_det.child(_Unicode(moduleBackLeft)); + xml_comp_t x_modBackRight = x_det.child(_Unicode(moduleBackRight)); + + xml_comp_t x_sensor_layout_front_left = x_det.child(_Unicode(sensor_layout_front_left)); + xml_comp_t x_sensor_layout_back_left = x_det.child(_Unicode(sensor_layout_back_left)); + xml_comp_t x_sensor_layout_front_right = x_det.child(_Unicode(sensor_layout_front_right)); + xml_comp_t x_sensor_layout_back_right = x_det.child(_Unicode(sensor_layout_back_right)); + + for (bool left : std::vector{true, false}) { + for (bool front : std::vector{true, false}) { + int module = (front << 1) + left; + float ycoord = envelope.rmax() - + module_y / 2.; // y-center-coord of the top sensor. Start from the top row + int iy = 0; + xml_comp_t x_sensor_layout = x_sensor_layout_front_left; + xml_comp_t x_modCurr = x_modFrontLeft; + + if (front) { + if (left) { + x_sensor_layout = x_sensor_layout_front_left; + x_modCurr = x_modFrontLeft; } else { - pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff)); - } - c_vol.setRegion(description, x_comp.regionStr()); - c_vol.setLimitSet(description, x_comp.limitsStr()); - c_vol.setVisAttributes(description, x_comp.visStr()); - if (x_comp.isSensitive()) { - pv.addPhysVolID("idx", ix); - pv.addPhysVolID("idy", iy); - c_vol.setSensitiveDetector(sens); - module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, - total_thickness - thickness_so_far - - x_comp.thickness() / 2.0}; - - // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- - Vector3D u(-1., 0., 0.); - Vector3D v(0., -1., 0.); - Vector3D n(0., 0., 1.); - - // compute the inner and outer thicknesses that need to be assigned to the tracking surface - // depending on wether the support is above or below the sensor - double inner_thickness = module_thicknesses[m_nam][0]; - double outer_thickness = module_thicknesses[m_nam][1]; - - SurfaceType type(SurfaceType::Sensitive); - - VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); - - DetElement comp_de(mod_elt, std::string("de_") + pv.volume().name(), module); - comp_de.setPlacement(pv); - - auto& comp_de_params = - DD4hepDetectorHelper::ensureExtension(comp_de); - comp_de_params.set("axis_definitions", "XYZ"); - volSurfaceList(comp_de)->push_back(surf); - - //-------------------------------------------- + x_sensor_layout = x_sensor_layout_front_right; + x_modCurr = x_modFrontRight; } - thickness_sum += x_comp.thickness(); - thickness_so_far += x_comp.thickness(); - // apply relative offsets in z-position used to stack components side-by-side - if (x_pos) { - thickness_sum += x_pos.z(0); - thickness_so_far += x_pos.z(0); + } else { + if (left) { + x_sensor_layout = x_sensor_layout_back_left; + x_modCurr = x_modBackLeft; + } else { + x_sensor_layout = x_sensor_layout_back_right; + x_modCurr = x_modBackRight; } } - const string suppb_nam = - Form("suppbar_%d_%d", ix, iy); //_toString(ncomponents, "component%d"); - Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2, - x_supp_envelope.length() / 2); - Volume suppb_vol(suppb_nam, suppb_box, carbon); - Transform3D trsupp(RotationZYX(0, 0, 0), - Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0)); - suppb_vol.setVisAttributes(description, "AnlGray"); + double total_thickness = 0; + // Compute module total thickness from components + xml_coll_t ci(x_modCurr, _U(module_component)); - pv = lay_vol.placeVolume(suppb_vol, trsupp); - // module built! + for (ci.reset(), total_thickness = 0.0; ci; ++ci) { + xml_comp_t x_comp = ci; + bool keep_same_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + if (!keep_same_layer) + total_thickness += x_comp.thickness(); + } - Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z)); + for (xml_coll_t lrow(x_sensor_layout, _Unicode(row)); lrow; ++lrow) { + xml_comp_t x_row = lrow; + double deadspace = getAttrOrDefault(x_row, _Unicode(deadspace), 0); + if (deadspace > 0) { + ycoord -= deadspace; + continue; + } + double x_offset = getAttrOrDefault(x_row, _Unicode(x_offset), 0); + int nsensors = getAttrOrDefault(x_row, _Unicode(nsensors), 0); + + // find the sensor id that corrsponds to the rightmost sensor in a board + // we need to know where to apply additional spaces between neighboring board + std::unordered_set sensors_id_board_edge; + int curr_ix = nsensors; // the first sensor to the right of center has ix of nsensors + for (xml_coll_t lboard(x_row, _Unicode(board)); lboard; ++lboard) { + xml_comp_t x_board = lboard; + int nboard_sensors = getAttrOrDefault(x_board, _Unicode(nsensors), 1); + curr_ix += nboard_sensors; + sensors_id_board_edge.insert(curr_ix); + sensors_id_board_edge.insert(2 * nsensors - curr_ix - + 1); // reflected to sensor id on the left + } - pv = lay_vol.placeVolume(m_vol, tr); - pv.addPhysVolID("module", module); - mod_elt.setPlacement(pv); + double accum_xoffset = x_offset; + for (int ix = (left ? nsensors - 1 : nsensors); (ix >= 0) && (ix < 2 * nsensors); + ix = ix + (left ? -1 : 1)) { + // add board spacing + if (sensors_id_board_edge.find(ix) != sensors_id_board_edge.end()) + accum_xoffset = accum_xoffset + board_gap; + + // there is a hole in the middle, with radius = x_offset + float xcoord = (ix - nsensors + 0.5) * (module_x + module_spacing) + + +(left ? -accum_xoffset : accum_xoffset); + //! Note the module ordering is different for front and back side + + double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2; + if (front) + module_z *= -1; + + string module_name = Form("module%d_%d_%d", module, ix, iy); + DetElement mod_elt(lay_elt, module_name, module); + + // create individual sensor layers here + string m_nam = Form("EndcapTOF_Module%d_%d_%d", module, ix, iy); + + int ncomponents = 0; + // the module assembly volume + Assembly m_vol(m_nam); + m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr())); + + double thickness_so_far = 0.0; + double thickness_sum = -total_thickness / 2.0; + double thickness_carbonsupp = 0.0; + int sensitive_id = 0; + for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) { + xml_comp_t x_comp = mci; + xml_comp_t x_pos = x_comp.position(false); + xml_comp_t x_rot = x_comp.rotation(false); + const string c_nam = Form("component_%d_%d_%d", module, ix, iy); + + Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2); + Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr())); + if (x_comp.materialStr() == "CarbonFiber") { + thickness_carbonsupp = x_comp.thickness(); + } + // Utility variable for the relative z-offset based off the previous components + const double zoff = thickness_sum + x_comp.thickness() / 2.0; + if (x_pos && x_rot) { + Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff); + RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0)); + pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos)); + } else if (x_rot) { + Position c_pos(0, 0, zoff); + pv = m_vol.placeVolume( + c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos)); + } else if (x_pos) { + pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff)); + } else { + pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff)); + } + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); + if (x_comp.isSensitive()) { + pv.addPhysVolID("idx", ix); + pv.addPhysVolID("idy", iy); + pv.addPhysVolID("ids", sensitive_id); + ++sensitive_id; + + c_vol.setSensitiveDetector(sens); + module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, + total_thickness - thickness_so_far - + x_comp.thickness() / 2.0}; + + // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- + Vector3D u(-1., 0., 0.); + Vector3D v(0., -1., 0.); + Vector3D n(0., 0., 1.); + + // compute the inner and outer thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor + double inner_thickness = module_thicknesses[m_nam][0]; + double outer_thickness = module_thicknesses[m_nam][1]; + + SurfaceType type(SurfaceType::Sensitive); + + VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); + + DetElement comp_de(mod_elt, + std::string("de_") + pv.volume().name() + "_" + + std::to_string(sensitive_id), + module); + comp_de.setPlacement(pv); + + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(surf); + + //-------------------------------------------- + } + bool keep_same_layer = getAttrOrDefault(x_comp, _Unicode(keep_layer), false); + if (!keep_same_layer) { + thickness_sum += x_comp.thickness(); + thickness_so_far += x_comp.thickness(); + // apply relative offsets in z-position used to stack components side-by-side + if (x_pos) { + thickness_sum += x_pos.z(0); + thickness_so_far += x_pos.z(0); + } + } + } + + if (front) { + // only draw support bar on one side + // if you draw on both sides, they may overlap + const string suppb_nam = + Form("suppbar_%d_%d", ix, iy); //_toString(ncomponents, "component%d"); + Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2, + x_supp_envelope.length() / 2); + Volume suppb_vol(suppb_nam, suppb_box, carbon); + Transform3D trsupp(RotationZYX(0, 0, 0), + Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0)); + suppb_vol.setVisAttributes(description, "AnlGray"); + + pv = lay_vol.placeVolume(suppb_vol, trsupp); + } + // module built! + + Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z)); + + pv = lay_vol.placeVolume(m_vol, tr); + pv.addPhysVolID("module", module); + mod_elt.setPlacement(pv); + } + ycoord -= (module_y - module_overlap); + ++iy; + } } } - // Create the PhysicalVolume for the layer. pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother pv.addPhysVolID("layer", lay_id); // Set the layer ID.