From 58ac41221af6f5eb2d2d43b29bf3188779b2ef61 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 13 Nov 2025 18:27:40 +0100 Subject: [PATCH 1/8] MPGD Barrel: Add "5SensVolumes" versions of XML. Modified Detector Constructors. - "5SensVolumes" are designed for a 2D-strip readout, via "MPGDTrackerDigi". - Modified constructors provide for both standard and "5SensVolumes". - OuterBarrel constructor: + Simplified: providing now for only one and one tag. + Sensisitive DetElement: in line with other constructors ("volSurfaceList",...). --- compact/tracking/mpgd_barrel.5SensVolumes.xml | 153 +++++ .../mpgd_outerbarrel.5SensVolumes.xml | 198 ++++++ src/BarrelPlanarMPGDTracker_geo.cpp | 584 ++++++++++-------- src/MPGDCylinderBarrelTracker_geo.cpp | 126 ++-- 4 files changed, 773 insertions(+), 288 deletions(-) create mode 100644 compact/tracking/mpgd_barrel.5SensVolumes.xml create mode 100644 compact/tracking/mpgd_outerbarrel.5SensVolumes.xml diff --git a/compact/tracking/mpgd_barrel.5SensVolumes.xml b/compact/tracking/mpgd_barrel.5SensVolumes.xml new file mode 100644 index 0000000000..12a5379fcc --- /dev/null +++ b/compact/tracking/mpgd_barrel.5SensVolumes.xml @@ -0,0 +1,153 @@ + + + + + + + + + + Inner MPGD tracking layer(s) + + Note: the inner and outer layers are implemented as separate detectors, as they + belong to different ACTS tracking volumes. If this restriction goes away + in the future they could be put together in a single tag. + + + + + Intrinsic parameters... + ...Thicknesses + + + + + + + + + + + + + FIXME: No support material is here, so fudge factor used to bring material budget to ~0.5% for barrel. + + FIXME: No definite plan for connections/services to the inner sectors yet, so guess value. + + 2DStrip: Multiple Sensitive Volumes. => Subdivide GasGap: 3 thin slices (pixel and (p|n)strips) at the centre, enclosed by 2 thick radiators. + + + ...Dimensions + + + + + + + ...Positioning + + + + In principle, stave count should not be independenty specified: it is fixed by above intrinsic parameters + + + + + + + + + + + + + + + + + Models describe the overlapping of staves along phi, either (I) via offsets or (II) via distinct radii ("rmin1/2"). Solution (II) is only partially implemented: would require FOUR distinct "radius" in the readout segmentation. Note that in any case "rsensor" must be set equal the "radius" of the corresponding segmentation and is used internally to double-check the consistency between the stack of "module_component" and the segmentation "radius". + + + + + This includes cables => Kapton as a material is overoptimistic. + Going from the inside (sensitive) side to the readout side + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 768 strips in phi yield a segmentation of 2pi/8/768 ~= 1mrad. Which in turn, yields ~160 um in resolution. + + + + + + + + + + + + + + + + + + system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 + + + + diff --git a/compact/tracking/mpgd_outerbarrel.5SensVolumes.xml b/compact/tracking/mpgd_outerbarrel.5SensVolumes.xml new file mode 100644 index 0000000000..269dc30535 --- /dev/null +++ b/compact/tracking/mpgd_outerbarrel.5SensVolumes.xml @@ -0,0 +1,198 @@ + + + + + + + + + Frames + + + + Module constants + + + + + + + + + + + + + + + Layer parameters + + + + + + + + + + 2DStrip: Multiple Sensitive Volumes. => Subdivide DriftGap: 3 thin slices (pixel and (p|n)strips) at the centre, enclosed by 2 thick radiators. + + + + + + + + + + + MPGD DIRC module components + + + + + + + + + + + + + + + + + + + + + Frame width gets subtracted from the gas module volumes + see src/BarrelPlanarMPGDTracker_geo.cpp + + + + + + + Layout for MPGD DIRC layers + + + + + + + + + + + + + + Strip segmentations ("strip" field !=0) are not used at simulation time but only in digitization at reconstruction time, see digitization class, "MPGDTrackerDigi". + + + + + + + system:8,layer:4,module:12,sensor:2,strip:28:4,u:-16,v:-16 + + + + + + + + + + + + + diff --git a/src/BarrelPlanarMPGDTracker_geo.cpp b/src/BarrelPlanarMPGDTracker_geo.cpp index 1e13bf7c0b..8d3f714680 100644 --- a/src/BarrelPlanarMPGDTracker_geo.cpp +++ b/src/BarrelPlanarMPGDTracker_geo.cpp @@ -36,19 +36,36 @@ using namespace dd4hep::rec; * and surrounds the rectangular perimeter) * - Detector is setup as a "tracker" so we can use the hits * + * - Two distinct versions of ".xml" are covered: + * I) Single Sensitive Volume (which name is then "DriftGap"): "eicrecon" is to + * be executed while setting bit 0x2 of option "MPGD:SiFactoryPattern". + * II) Multiple Sensitive Volume: Bit 0x2 of above-mentioned option not set. + * */ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, SensitiveDetector sens) { - typedef vector Placements; xml_det_t x_det = e; // Material air = description.air(); int det_id = x_det.id(); string det_name = x_det.nameStr(); DetElement sdet(det_name, det_id); - map volumes; - map sensitives; - map> volplane_surfaces; + + Volume *volume; + // Sensitive volumes and associated surfaces + // - There can be either one or five. + int sensitiveVolumeSet = 5; // 1: single volume, 5: 5 volumes, -1: error + vector sensitives; + vector volplane_surfaces; + PlacedVolume pv; + + //#define DEBUG_BarrelPlanarMPGDTracker +#ifdef DEBUG_BarrelPlanarMPGDTracker + // TEMPORARILY INCREASE VERBOSITY level for debugging purposes + PrintLevel priorPrintLevel = printLevel(); + setPrintLevel(DEBUG); +#endif + dd4hep::xml::Dimension dimensions(x_det.dimensions()); xml_dim_t mpgd_pos = x_det.position(); Assembly assembly(det_name); @@ -66,277 +83,346 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, "boundary_material"); } - map> module_thicknesses; sens.setType("tracker"); - // loop over the modules - for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) { - xml_comp_t x_mod = mi; - string m_nam = x_mod.nameStr(); + // ********** MODULE + // ***** ONE AND ONLY ONE MODULE + xml_coll_t modules(x_det, _U(module)); + if (modules.size() != 1) { + // Present detector constructor can only handle ONE tag + printout(ERROR, "BarrelPlanarMPGDTracker_geo", "Number of modules = %u. Must be = 1", + modules.size()); + throw runtime_error("Logics error in building modules."); + } + xml_comp_t x_mod = modules; + string m_nam = x_mod.nameStr(); - if (volumes.find(m_nam) != volumes.end()) { - printout(ERROR, "BarrelPlanarMPGDTracker_geo", - string((string("Module with named ") + m_nam + string(" already exists."))).c_str()); - throw runtime_error("Logics error in building modules."); - } + int ncomponents = 0; + int sensor_number = 0; + double total_thickness = 0; - int ncomponents = 0; - int sensor_number = 1; - double total_thickness = 0; + // 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(); + } + // the module assembly volume + Assembly m_vol(m_nam); + volume = &m_vol; + m_vol.setVisAttributes(description, x_mod.visStr()); + + // Optional module frame. + // frame is 4 bars around the perimeter of the rectangular module. The frame will eat the + // overlapping module area + // + // ___ + // |___| <-- example module cross section (x-y plane), frame is flush with the + // bottom of the module and protrudes on the top if needed + + // Get frame width, as it impacts the main module for being built. We + // construct the actual frame structure later (once we know the module width) + double frame_width = 0; + if (x_mod.hasChild(_U(frame))) { + xml_comp_t m_frame = x_mod.child(_U(frame)); + frame_width = m_frame.width(); + } - // 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(); - } - // the module assembly volume - Assembly m_vol(m_nam); - volumes[m_nam] = m_vol; - m_vol.setVisAttributes(description, x_mod.visStr()); - - // Optional module frame. - // frame is 4 bars around the perimeter of the rectangular module. The frame will eat the - // overlapping module area + double thickness_so_far = 0.0; + double thickness_sum = -total_thickness / 2.0; + double max_component_width = 0; + double max_component_length = 0; + double gas_thickness = 0.0; + // Pattern of Multiple Sensitive Volumes + // - In order to have one sensitive component per strip coordinate (and + // accessorily, some extras), the "DriftGap" is subdivided into subVolumes. + int nSensitives = 0; + for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) { + xml_comp_t x_comp = mci; + string c_nam = _toString(ncomponents, "component%d"); + string comp_name = x_comp.nameStr(); + double comp_thickness = x_comp.thickness(); + double box_width = x_comp.width(); + double box_length = x_comp.length(); + Box c_box; + // Since MPGD frames are layed over the MPGD foils, the foil material is pressent under the frame as well. + // The gas volumes are not present under the frames, so our frames must eat only the gas module areas // - // ___ - // |___| <-- example module cross section (x-y plane), frame is flush with the - // bottom of the module and protrudes on the top if needed - - // Get frame width, as it impacts the main module for being built. We - // construct the actual frame structure later (once we know the module width) - double frame_width = 0; - if (x_mod.hasChild(_U(frame))) { - xml_comp_t m_frame = x_mod.child(_U(frame)); - frame_width = m_frame.width(); + // ------------------- MPGD foil + // -- -- Frame + // -- gas volume -- Frame + // -- -- Frame + // ------------------- MPGD foil + + // Look for gas modules to subtract frame thickness from + // FIXME: these module names are hard coded for now. Should find + // a way to set an attribute via the module tag to flag what components + // need to have frame thickness subtracted. + bool isDriftGap = comp_name == "DriftGap" || + /* */ comp_name.find("ThinGap") !=std::string::npos || + /* */ comp_name.find("Radiator")!=std::string::npos; + if (isDriftGap || comp_name == "WindowGasGap") { + box_width = x_comp.width() - 2.0 * frame_width; + box_length = x_comp.length() - 2.0 * frame_width; + max_component_width = box_width; + max_component_length = box_length; + gas_thickness += comp_thickness; + c_box = {box_width / 2, box_length / 2, comp_thickness / 2}; + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "gas: %s", comp_name.c_str()); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_width: %f", box_width); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_length: %f", box_length); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_thickness: %f", comp_thickness); + } else { + c_box = {x_comp.width() / 2, x_comp.length() / 2, comp_thickness / 2}; + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "Not gas: %s", comp_name.c_str()); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_width: %f", x_comp.width()); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_length: %f", x_comp.length()); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_thickness: %f", + comp_thickness); } + Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())}; - double thickness_so_far = 0.0; - double thickness_sum = -total_thickness / 2.0; - double max_component_width = 0; - double max_component_length = 0; - double gas_thickness = 0.0; - for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) { - xml_comp_t x_comp = mci; - string c_nam = _toString(ncomponents, "component%d"); - string comp_name = x_comp.nameStr(); - - double box_width = x_comp.width(); - double box_length = x_comp.length(); - Box c_box; - // Since MPGD frames are layed over the MPGD foils, the foil material is pressent under the frame as well. - // The gas volumes are not present under the frames, so our frames must eat only the gas module areas - // - // ------------------- MPGD foil - // -- -- Frame - // -- gas volume -- Frame - // -- -- Frame - // ------------------- MPGD foil - - // Look for gas modules to subtract frame thickness from - // FIXME: these module names are hard coded for now. Should find - // a way to set a arribut via the moduel tag to flag what components - // need to have frame thickness subtracted. - if ((comp_name == "DriftGap" || comp_name == "WindowGasGap")) { - box_width = x_comp.width() - 2.0 * frame_width; - box_length = x_comp.length() - 2.0 * frame_width; - max_component_width = box_width; - max_component_length = box_length; - gas_thickness += x_comp.thickness(); - c_box = {box_width / 2, box_length / 2, x_comp.thickness() / 2}; - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "gas: %s", comp_name.c_str()); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_width: %f", box_width); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_length: %f", box_length); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_thickness: %f", x_comp.thickness()); - } else { - c_box = {x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2}; - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "Not gas: %s", comp_name.c_str()); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_width: %f", x_comp.width()); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_length: %f", x_comp.length()); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_thickness: %f", - x_comp.thickness()); - } - Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())}; - - c_vol.setRegion(description, x_comp.regionStr()); - c_vol.setLimitSet(description, x_comp.limitsStr()); - c_vol.setVisAttributes(description, x_comp.visStr()); + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); - pcb_feb_ext = x_comp.offset(); + pcb_feb_ext = x_comp.offset(); - pv = m_vol.placeVolume( - c_vol, Position(0, -pcb_feb_ext / 2.0, thickness_sum + x_comp.thickness() / 2.0)); + pv = m_vol.placeVolume( + c_vol, Position(0, -pcb_feb_ext / 2.0, thickness_sum + comp_thickness / 2.0)); - if (x_comp.isSensitive()) { - 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}; - // -------- 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]; + if (x_comp.isSensitive()) { + // ***** SENSITIVE VOLUME + if (nSensitives >= 5) { + sensitiveVolumeSet = -1; + break; + } + pv.addPhysVolID("sensor", sensor_number); + // StripID. Single Sensitive Volume? + int strip_id; + if (comp_name == "DriftGap") { + if (nSensitives != 0) { + sensitiveVolumeSet = -1; + break; + } + strip_id = 0; + sensitiveVolumeSet = 1; + } + else { + int strip_ids[5] = {3,1,0,2,4}; strip_id = strip_ids[nSensitives]; + } + pv.addPhysVolID("strip", strip_id); + c_vol.setSensitiveDetector(sens); + sensitives.push_back(pv); + + // -------- create a measurement plane for the tracking surface attached to the sensitive volume ----- + Vector3D u(-1., 0., 0.); + Vector3D v(0., -1., 0.); + Vector3D n(0., 0., 1.); + + // Compute the inner (i.e. thickness until mid-sensitive-volume) and + // outer (from mid-sensitive-volume to top) + // thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor. + double inner_thickness, outer_thickness; + if (sensitiveVolumeSet == 1) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } + else if (nSensitives == 0) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = comp_thickness / 2; + } + else if (nSensitives == 4) { + inner_thickness = comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } + else { + inner_thickness = outer_thickness = comp_thickness / 2; + } + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", + "Sensitive surface @ R = %.4f (%.4f,%.4f) cm", + (thickness_sum + comp_thickness / 2) / cm, inner_thickness / cm, + outer_thickness / cm); - SurfaceType type(rec::SurfaceType::Sensitive); + SurfaceType type(rec::SurfaceType::Sensitive); - VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; - volplane_surfaces[m_nam].push_back(surf); - } - thickness_sum += x_comp.thickness(); - thickness_so_far += x_comp.thickness(); - } - // Now add-on the frame - if (x_mod.hasChild(_U(frame))) { - xml_comp_t m_frame = x_mod.child(_U(frame)); - double frame_thickness = getAttrOrDefault(m_frame, _U(thickness), total_thickness); - - Box lframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, - frame_thickness / 2.0}; - Box rframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, - frame_thickness / 2.0}; - Box tframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; - Box bframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; - - // Keep track of frame with so we can adjust the module bars appropriately - - Volume lframe_vol{"left_frame", lframe_box, description.material(m_frame.materialStr())}; - Volume rframe_vol{"right_frame", rframe_box, description.material(m_frame.materialStr())}; - Volume tframe_vol{"top_frame", tframe_box, description.material(m_frame.materialStr())}; - Volume bframe_vol{"bottom_frame", bframe_box, description.material(m_frame.materialStr())}; - - lframe_vol.setVisAttributes(description, m_frame.visStr()); - rframe_vol.setVisAttributes(description, m_frame.visStr()); - tframe_vol.setVisAttributes(description, m_frame.visStr()); - bframe_vol.setVisAttributes(description, m_frame.visStr()); - - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness: %f", frame_thickness); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "total_thickness: %f", total_thickness); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness + total_thickness: %f", - frame_thickness + total_thickness); - - m_vol.placeVolume(lframe_vol, Position(frame_width / 2.0 + max_component_width / 2, 0.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(rframe_vol, Position(-frame_width / 2.0 - max_component_width / 2.0, 0.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(tframe_vol, Position(0.0, frame_width / 2.0 + max_component_length / 2, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(bframe_vol, Position(0.0, -frame_width / 2.0 - max_component_length / 2.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); + VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; + volplane_surfaces.push_back(surf); + nSensitives++; } + thickness_sum += comp_thickness; + thickness_so_far += comp_thickness; + } + if (sensitiveVolumeSet < 0 || + sensitiveVolumeSet != nSensitives) { + printout(ERROR, "BarrelPlanarMPGDTracker_geo", + "Invalid set of Sensitive Volumes: it's either one (named \"DriftGap\") or 5"); + throw runtime_error("Logics error in building modules."); + } + // Now add-on the frame + if (x_mod.hasChild(_U(frame))) { + xml_comp_t m_frame = x_mod.child(_U(frame)); + double frame_thickness = getAttrOrDefault(m_frame, _U(thickness), total_thickness); + + Box lframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, + frame_thickness / 2.0}; + Box rframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, + frame_thickness / 2.0}; + Box tframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; + Box bframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; + + // Keep track of frame with so we can adjust the module bars appropriately + + Volume lframe_vol{"left_frame", lframe_box, description.material(m_frame.materialStr())}; + Volume rframe_vol{"right_frame", rframe_box, description.material(m_frame.materialStr())}; + Volume tframe_vol{"top_frame", tframe_box, description.material(m_frame.materialStr())}; + Volume bframe_vol{"bottom_frame", bframe_box, description.material(m_frame.materialStr())}; + + lframe_vol.setVisAttributes(description, m_frame.visStr()); + rframe_vol.setVisAttributes(description, m_frame.visStr()); + tframe_vol.setVisAttributes(description, m_frame.visStr()); + bframe_vol.setVisAttributes(description, m_frame.visStr()); + + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness: %f", frame_thickness); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "total_thickness: %f", total_thickness); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness + total_thickness: %f", + frame_thickness + total_thickness); + + m_vol.placeVolume(lframe_vol, Position(frame_width / 2.0 + max_component_width / 2, 0.0, + frame_thickness / 2.0 - total_thickness / 2.0 - + gas_thickness / 2.0)); + m_vol.placeVolume(rframe_vol, Position(-frame_width / 2.0 - max_component_width / 2.0, 0.0, + frame_thickness / 2.0 - total_thickness / 2.0 - + gas_thickness / 2.0)); + m_vol.placeVolume(tframe_vol, Position(0.0, frame_width / 2.0 + max_component_length / 2, + frame_thickness / 2.0 - total_thickness / 2.0 - + gas_thickness / 2.0)); + m_vol.placeVolume(bframe_vol, Position(0.0, -frame_width / 2.0 - max_component_length / 2.0, + frame_thickness / 2.0 - total_thickness / 2.0 - + gas_thickness / 2.0)); } + // ********** LAYER + // ***** ONE AND ONLY ONE LAYER + xml_coll_t li(x_det, _U(layer)); + if (li.size() != 1) { + printout(ERROR, "BarrelPlanarMPGDTracker_geo", "Number of layers = %d. Must be = 1", + (int)li.size()); + throw runtime_error("Logics error in building modules."); + } // build the layers the modules will be arranged around - for (xml_coll_t li(x_det, _U(layer)); li; ++li) { - xml_comp_t x_layer = li; - xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); - xml_comp_t z_layout = x_layer.child(_U(z_layout)); - int lay_id = x_layer.id(); - string m_nam = x_layer.moduleStr(); - string lay_nam = det_name + _toString(x_layer.id(), "_layer%d"); - xml_comp_t envelope_tolerance = x_layer.child(_Unicode(envelope_tolerance), false); - double envelope_r_min = 0; - double envelope_r_max = 0; - double envelope_z_min = 0; - double envelope_z_max = 0; - if (envelope_tolerance) { - envelope_r_min = getAttrOrDefault(envelope_tolerance, _Unicode(r_min), 0); - envelope_r_max = getAttrOrDefault(envelope_tolerance, _Unicode(r_max), 0); - envelope_z_min = getAttrOrDefault(envelope_tolerance, _Unicode(z_min), 0); - envelope_z_max = getAttrOrDefault(envelope_tolerance, _Unicode(z_max), 0); - } + xml_comp_t x_layer = li; + xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); + xml_comp_t z_layout = x_layer.child(_U(z_layout)); + int lay_id = x_layer.id(); + string lay_nam = det_name + _toString(x_layer.id(), "_layer%d"); + xml_comp_t envelope_tolerance = x_layer.child(_Unicode(envelope_tolerance), false); + double envelope_r_min = 0; + double envelope_r_max = 0; + double envelope_z_min = 0; + double envelope_z_max = 0; + if (envelope_tolerance) { + envelope_r_min = getAttrOrDefault(envelope_tolerance, _Unicode(r_min), 0); + envelope_r_max = getAttrOrDefault(envelope_tolerance, _Unicode(r_max), 0); + envelope_z_min = getAttrOrDefault(envelope_tolerance, _Unicode(z_min), 0); + envelope_z_max = getAttrOrDefault(envelope_tolerance, _Unicode(z_max), 0); + } - double phi0 = x_layout.phi0(); // starting phi of first module - double phi_tilt = x_layout.phi_tilt(); // Phi tilit of module - double rc = x_layout.rc(); // Radius of the module - int nphi = x_layout.nphi(); // Number of modules in phi - double rphi_dr = x_layout.dr(); // The delta radius of every other module - double phi_incr = (2 * M_PI) / nphi; // Phi increment for one module - double phic = phi0; // Phi of the module - int nz = 2; // Number of modules placed in z - double z_dr = z_layout.dr(); // Radial offest of modules in z - double z0 = z_layout.z0(); // Sets how much overlap in z the nz modules have - - Assembly layer_assembly(lay_nam); - Volume module_env = volumes[m_nam]; - DetElement lay_elt(sdet, lay_nam, lay_id); - Placements& sensVols = sensitives[m_nam]; - auto& layerParams = - DD4hepDetectorHelper::ensureExtension(lay_elt); - - pv = assembly.placeVolume(layer_assembly); - pv.addPhysVolID("layer", lay_id); - lay_elt.setPlacement(pv); - - int module = 1; - // loop over the modules in phi - for (int ii = 0; ii < nphi; ii++) { - double xc = rc * std::cos(phic); // Basic x position of module - double yc = rc * std::sin(phic); // Basic y position of module - double dx = z_dr * std::cos(phic + phi_tilt); // Deta x of module position - double dy = z_dr * std::sin(phic + phi_tilt); // Deta y of module position - // loop over the modules in z - for (int j = 0; j < nz; j++) { - string module_name = _toString(module, "module%d"); - DetElement mod_elt(lay_elt, module_name, module); - double mod_z = 0.5 * dimensions.length(); - double z_placement = mod_z - 0.5 * pcb_feb_ext - - j * (nz * mod_z - pcb_feb_ext); // z location for module placement - double z_offset = - z_placement > 0 - ? -z0 / 2.0 - : z0 / 2.0; // determine the amount of overlap in z the z nz modules have - - Transform3D tr( - RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2) * RotationZ(j * M_PI), - Position( - xc, yc, - mpgd_pos.z() + z_placement + - z_offset)); //RotZYX rotates planes around azimuth, RotZ flips plane so pcb_feb_ext is facing endcaps - - pv = layer_assembly.placeVolume(module_env, tr); - pv.addPhysVolID("module", module); - mod_elt.setPlacement(pv); - for (size_t ic = 0; ic < sensVols.size(); ++ic) { - PlacedVolume sens_pv = sensVols[ic]; - DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module); - comp_de.setPlacement(sens_pv); - } - // increas module counter - module++; - // adjust x and y coordinates - xc += dx; - yc += dy; + double phi0 = x_layout.phi0(); // starting phi of first module + double phi_tilt = x_layout.phi_tilt(); // Phi tilit of module + double rc = x_layout.rc(); // Radius of the module + int nphi = x_layout.nphi(); // Number of modules in phi + double rphi_dr = x_layout.dr(); // The delta radius of every other module + double phi_incr = (2 * M_PI) / nphi; // Phi increment for one module + double phic = phi0; // Phi of the module + int nz = 2; // Number of modules placed in z + double z_dr = z_layout.dr(); // Radial offest of modules in z + double z0 = z_layout.z0(); // Sets how much overlap in z the nz modules have + + Assembly layer_assembly(lay_nam); + Volume module_env = *volume; + DetElement lay_elt(sdet, lay_nam, lay_id); + auto& layerParams = + DD4hepDetectorHelper::ensureExtension(lay_elt); + + pv = assembly.placeVolume(layer_assembly); + pv.addPhysVolID("layer", lay_id); + lay_elt.setPlacement(pv); + + int module = 0; + // loop over the modules in phi + for (int ii = 0; ii < nphi; ii++) { + double xc = rc * std::cos(phic); // Basic x position of module + double yc = rc * std::sin(phic); // Basic y position of module + double dx = z_dr * std::cos(phic + phi_tilt); // Deta x of module position + double dy = z_dr * std::sin(phic + phi_tilt); // Deta y of module position + // loop over the modules in z + for (int j = 0; j < nz; j++) { + string module_name = _toString(module, "module%02d"); + DetElement mod_elt(lay_elt, module_name, module); + double mod_z = 0.5 * dimensions.length(); + double z_placement = mod_z - 0.5 * pcb_feb_ext - + j * (nz * mod_z - pcb_feb_ext); // z location for module placement + double z_offset = + z_placement > 0 + ? -z0 / 2.0 + : z0 / 2.0; // determine the amount of overlap in z the z nz modules have + + Transform3D tr( + RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2) * RotationZ(j * M_PI), + Position( + xc, yc, + mpgd_pos.z() + z_placement + + z_offset)); //RotZYX rotates planes around azimuth, RotZ flips plane so pcb_feb_ext is facing endcaps + + pv = layer_assembly.placeVolume(module_env, tr); + pv.addPhysVolID("module", module); + mod_elt.setPlacement(pv); + for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { + // ***** SENSITIVE COMPONENTS + PlacedVolume& sens_pv = sensitives[iSensitive]; + int de_id = nphi * iSensitive + module; + DetElement comp_de( + mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), + de_id); + comp_de.setPlacement(sens_pv); + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive]); } - // increment counters - phic += phi_incr; - rc += rphi_dr; - } - layer_assembly->GetShape()->ComputeBBox(); - layerParams.set("envelope_r_min", envelope_r_min); - layerParams.set("envelope_r_max", envelope_r_max); - layerParams.set("envelope_z_min", envelope_z_min); - layerParams.set("envelope_z_max", envelope_z_max); - - for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) { - xml_comp_t x_layer_material = lmat; - DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams, - "layer_material"); + // increas module counter + module++; + // adjust x and y coordinates + xc += dx; + yc += dy; } + // increment counters + phic += phi_incr; + rc += rphi_dr; + } + layer_assembly->GetShape()->ComputeBBox(); + layerParams.set("envelope_r_min", envelope_r_min); + layerParams.set("envelope_r_max", envelope_r_max); + layerParams.set("envelope_z_min", envelope_z_min); + layerParams.set("envelope_z_max", envelope_z_max); + + for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) { + xml_comp_t x_layer_material = lmat; + DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams, + "layer_material"); } sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); assembly.setVisAttributes(description.invisible()); pv = description.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", det_id); // Set the subdetector system ID sdet.setPlacement(pv); + +#ifdef DEBUG_BarrelPlanarMPGDTracker + // Reset initial print level before exiting + setPrintLevel(priorPrintLevel); +#endif + return sdet; } diff --git a/src/MPGDCylinderBarrelTracker_geo.cpp b/src/MPGDCylinderBarrelTracker_geo.cpp index 2700f887ce..e4066799f9 100644 --- a/src/MPGDCylinderBarrelTracker_geo.cpp +++ b/src/MPGDCylinderBarrelTracker_geo.cpp @@ -41,6 +41,11 @@ using ROOT::Math::XYVector; * - Several models of modules, with each a distinct radius of curvature * but a single XML and a single . * + * - Two distinct versions of ".xml" are covered: + * I) Single Sensitive Volume (which name is then "GasGap"): "eicrecon" is to + * be executed while setting bit 0x1 of option "MPGD:SiFactoryPattern". + * II) Multiple Sensitive Volume: Bit 0x1 of above-mentioned option not set. + * * \code * \endcode * @@ -56,8 +61,11 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, DetElement sdet(det_name, det_id); vector volumes; - vector sensitives; - vector volplane_surfaces; + // Sensitive volumes and associated surfaces + // - There can be either one or five. + int sensitiveVolumeSet = 5; // 1: single volume, 5: 5 volumes, -1: error + vector sensitives[5]; + vector volplane_surfaces[5]; PlacedVolume pv; @@ -395,7 +403,10 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, // ********** LOOP OVER COMPONENTS double comp_rmin = stave_rmin; double thickness_so_far = 0; - xml_comp_t* sensitiveComp = 0; + // Pattern of Multiple Sensitive Volumes + // - The "GasGap" may be subdivided into subVolumes (this order to have one + // sensitive component per strip coordinate (and accessorily, some extras). + int nSensitives = 0; for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) { xml_comp_t x_comp = mci; const string c_nam = x_comp.nameStr(); @@ -408,51 +419,85 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, c_vol.setVisAttributes(description, x_comp.visStr()); if (x_comp.isSensitive()) { // ***** SENSITIVE VOLUME - if (sensitiveComp) { - printout(ERROR, "MPGDCylinderBarrelTracker", - "Component \"%s\": 2nd sensitive component in module \"%s\" (1st is \"%s\"). " - "One only allowed.", - c_nam.c_str(), m_nam.c_str(), sensitiveComp->nameStr().c_str()); - throw runtime_error("Logics error in building modules."); - } - sensitiveComp = &x_comp; // TODO: Add second sensitive + if (nSensitives >= 5) { + sensitiveVolumeSet = -1; + break; + } pv.addPhysVolID("sensor", sensor_number); + // StripID. Single Sensitive Volume? + int strip_id; + if (c_nam == "GasGap") { + if (nSensitives != 0) { + sensitiveVolumeSet = -1; + break; + } + strip_id = 0; + sensitiveVolumeSet = 1; + } + else { + int strip_ids[5] = {3,1,0,2,4}; strip_id = strip_ids[nSensitives]; + } + pv.addPhysVolID("strip", strip_id); c_vol.setSensitiveDetector(sens); - sensitives.push_back(pv); + sensitives[nSensitives].push_back(pv); // -------- create a measurement plane for the tracking surface attached to the sensitive volume ----- Vector3D u(-1., 0., 0.); Vector3D v(0., -1., 0.); Vector3D n(0., 0., 1.); + if (strip_id == 0) { + // Consistency(+/-1um) check: segmentation consistent w/ stack of module components? + double rXCheck = comp_rmin + comp_thickness / 2; + if (fabs(staveModel.rsensor - rXCheck) > .0001 / cm) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Sensitive Component \"%s\" of StaveModel #%d,\"%s\": rsensor(%.4f cm) != " + "radius @ sensitive surface(%.4f cm)", + c_nam.c_str(), iSM, staveModel.name.c_str(), staveModel.rsensor / cm, + rXCheck / cm); + throw runtime_error("Logics error in building modules."); + } + } + // Compute the inner (i.e. thickness until mid-sensitive-volume) and // outer (from mid-sensitive-volume to top) // thicknesses that need to be assigned to the tracking surface - // depending on wether the support is above or below the sensor (!?) - double inner_thickness = thickness_so_far + comp_thickness / 2; - double outer_thickness = total_thickness - inner_thickness; - // Consistency(+/-1um) check: segmentation = stack of module components - double rXCheck = comp_rmin + comp_thickness / 2; - if (fabs(staveModel.rsensor - rXCheck) > .0001 / cm) { - printout(ERROR, "MPGDCylinderBarrelTracker", - "Sensitive Component \"%s\" of StaveModel #%d,\"%s\": rsensor(%.4f cm) != " - "radius @ sensitive surface(%.4f cm)", - iSM, c_nam.c_str(), staveModel.name.c_str(), staveModel.rsensor / cm, - rXCheck / cm); - throw runtime_error("Logics error in building modules."); - } - printout(DEBUG, "MPGDCylinderBarrelTracker", - "Stave Model #%d,\"%s\": Sensitive surface @ R = %.4f (%.4f,%.4f) cm", iSM, - staveModel.name.c_str(), staveModel.rsensor / cm, inner_thickness / cm, - outer_thickness / cm); + // depending on wether the support is above or below the sensor. + double inner_thickness, outer_thickness; + if (sensitiveVolumeSet == 1) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = total_thickness - inner_thickness; + } + else if (nSensitives == 0) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = comp_thickness / 2; + } + else if (nSensitives == 4) { + inner_thickness = comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } + else { + inner_thickness = outer_thickness = comp_thickness / 2; + } + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Stave Model #%d,\"%s\": Sensitive surface @ R = %.4f (%.4f,%.4f) cm", iSM, + staveModel.name.c_str(), staveModel.rsensor / cm, inner_thickness / cm, + outer_thickness / cm); SurfaceType type(SurfaceType::Sensitive); VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; - volplane_surfaces.push_back(surf); + volplane_surfaces[nSensitives].push_back(surf); + nSensitives++; } comp_rmin += comp_thickness; thickness_so_far += comp_thickness; } //end of module component loop + if (sensitiveVolumeSet < 0 || + sensitiveVolumeSet != nSensitives) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Invalid set of Sensitive Volumes: it's either one (named \"GasGap\") or 5"); + throw runtime_error("Logics error in building modules."); + } } //end of stave model loop // ********** LAYER @@ -520,16 +565,19 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, pv = lay_vol.placeVolume(module_vol, tr); pv.addPhysVolID("module", nModules); mod_elt.setPlacement(pv); - // ***** SENSITIVE COMPONENT - PlacedVolume& sens_pv = sensitives[iV]; - DetElement comp_de( - mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(8 * iz + iphi, "%02d"), - nModules); - comp_de.setPlacement(sens_pv); - auto& comp_de_params = + for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { + // ***** SENSITIVE COMPONENTS + PlacedVolume& sens_pv = sensitives[iSensitive][iV]; + int de_id = 32 * iSensitive + nModules; + DetElement comp_de( + mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), + de_id); + comp_de.setPlacement(sens_pv); + auto& comp_de_params = DD4hepDetectorHelper::ensureExtension(comp_de); - comp_de_params.set("axis_definitions", "XYZ"); - volSurfaceList(comp_de)->push_back(volplane_surfaces[iV]); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive][iV]); + } } } From 84febddb68e054447d5283c0d7fde4ae37e33df7 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Sun, 16 Nov 2025 13:48:55 +0100 Subject: [PATCH 2/8] MPGD Barrel: Simplification. "5SensVolumes" renamed "2DStrip". Add dedicated configuration. - Simplication: Standard XML (almost-)free of any reference to strips. - Dedicated "craterlake_tracking_only_2DStrip" implementing "2DStrip" XMLs. --- compact/tracking/mpgd_barrel.xml | 26 ++++++--------- ...ensVolumes.xml => mpgd_barrel_2DStrip.xml} | 0 compact/tracking/mpgd_outerbarrel.xml | 33 +++++++++---------- ...lumes.xml => mpgd_outerbarrel_2DStrip.xml} | 0 .../craterlake_tracking_only_2DStrip.yml | 21 ++++++++++++ src/BarrelPlanarMPGDTracker_geo.cpp | 4 +-- 6 files changed, 48 insertions(+), 36 deletions(-) rename compact/tracking/{mpgd_barrel.5SensVolumes.xml => mpgd_barrel_2DStrip.xml} (100%) rename compact/tracking/{mpgd_outerbarrel.5SensVolumes.xml => mpgd_outerbarrel_2DStrip.xml} (100%) create mode 100644 configurations/craterlake_tracking_only_2DStrip.yml diff --git a/compact/tracking/mpgd_barrel.xml b/compact/tracking/mpgd_barrel.xml index 5060cc7402..8956dc1e55 100644 --- a/compact/tracking/mpgd_barrel.xml +++ b/compact/tracking/mpgd_barrel.xml @@ -36,9 +36,9 @@ - FIXME: No support material is here, so fudge factor used to bring material budget to ~0.5% for barrel + FIXME: No support material is here, so fudge factor used to bring material budget to ~0.5% for barrel. - FIXME: No definite plan for connections/services to the inner sectors yet, so guess value + FIXME: No definite plan for connections/services to the inner sectors yet, so guess value. ...Dimensions @@ -53,6 +53,8 @@ In principle, stave count should not be independenty specified: it is fixed by above intrinsic parameters + + @@ -98,8 +100,8 @@ @@ -122,19 +124,11 @@ 768 strips in phi yield a segmentation of 2pi/8/768 ~= 1mrad. Which in turn, yields ~160 um in resolution. - Strip segmentations ("strip" field !=0) are not used at simulation time but only in digitization at reconstruction time, see digitization class, "MPGDTrackerDigi". - - - - - - - - - - + + - system:8,layer:4,module:12,sensor:2,strip:30:2,phi:-16,z:-16 + "strip" field is ineffective... but required. + system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 diff --git a/compact/tracking/mpgd_barrel.5SensVolumes.xml b/compact/tracking/mpgd_barrel_2DStrip.xml similarity index 100% rename from compact/tracking/mpgd_barrel.5SensVolumes.xml rename to compact/tracking/mpgd_barrel_2DStrip.xml diff --git a/compact/tracking/mpgd_outerbarrel.xml b/compact/tracking/mpgd_outerbarrel.xml index 2c2933dfe4..83945db150 100644 --- a/compact/tracking/mpgd_outerbarrel.xml +++ b/compact/tracking/mpgd_outerbarrel.xml @@ -27,7 +27,8 @@ - + + Layer parameters @@ -59,7 +60,7 @@ thickness="MPGDOuterBarrelDriftGap_thickness" vis="TrackerMPGDGasVis" offset="0" - length="MPGDOuterBarrelModule_length - MPGDOuterBarrelModule_PCB_offset"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length"/> - - Strip segmentations ("strip" field !=0) are not used at simulation time but only in digitization at reconstruction time, see digitization class, "MPGDTrackerDigi". - - - - - system:8,layer:4,module:12,sensor:2,strip:30:2,u:-16,v:-16 + + "strip" field is ineffective... but required. + system:8,layer:4,module:12,sensor:2,strip:28:4,x:-16,y:-16 diff --git a/compact/tracking/mpgd_outerbarrel.5SensVolumes.xml b/compact/tracking/mpgd_outerbarrel_2DStrip.xml similarity index 100% rename from compact/tracking/mpgd_outerbarrel.5SensVolumes.xml rename to compact/tracking/mpgd_outerbarrel_2DStrip.xml diff --git a/configurations/craterlake_tracking_only_2DStrip.yml b/configurations/craterlake_tracking_only_2DStrip.yml new file mode 100644 index 0000000000..bb8e21b631 --- /dev/null +++ b/configurations/craterlake_tracking_only_2DStrip.yml @@ -0,0 +1,21 @@ +features: + beampipe: + fields: + marco: + tracking: + definitions_craterlake: + vertex_barrel: + vertex_barrel_support: + silicon_barrel: + mpgd_barrel_2DStrip: + support_service_craterlake: + mpgd_outerbarrel_2DStrip: + mpgd_forward_endcap: + mpgd_backward_endcap: + silicon_disks: + tof_barrel: + tof_endcap: + far_forward: + default: + far_backward: + default: diff --git a/src/BarrelPlanarMPGDTracker_geo.cpp b/src/BarrelPlanarMPGDTracker_geo.cpp index 8d3f714680..35ac411143 100644 --- a/src/BarrelPlanarMPGDTracker_geo.cpp +++ b/src/BarrelPlanarMPGDTracker_geo.cpp @@ -354,8 +354,8 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, for (int ii = 0; ii < nphi; ii++) { double xc = rc * std::cos(phic); // Basic x position of module double yc = rc * std::sin(phic); // Basic y position of module - double dx = z_dr * std::cos(phic + phi_tilt); // Deta x of module position - double dy = z_dr * std::sin(phic + phi_tilt); // Deta y of module position + double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position + double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position // loop over the modules in z for (int j = 0; j < nz; j++) { string module_name = _toString(module, "module%02d"); From 5c3e53f0240b3bd22a13e2227ca3633cce723130 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Wed, 26 Nov 2025 16:53:13 +0100 Subject: [PATCH 3/8] MPGD Barrel: Backward compatibility via cmake option "-DMPGD_INSTALL_PIXEL". - 2 flavours of Barrel MPGDs implemented in 2 distinct XMLs: "_pixel"/"_2DStrip". - "-DMPGD_INSTALL_PIXEL" allows to install "_pixel" instead of default "_2DStrip". --- CMakeLists.txt | 40 +++++++++++++++++-- compact/tracking/mpgd_barrel_2DStrip.xml | 8 ++-- ...{mpgd_barrel.xml => mpgd_barrel_pixel.xml} | 8 ++-- compact/tracking/mpgd_outerbarrel_2DStrip.xml | 20 ++++++---- ...rbarrel.xml => mpgd_outerbarrel_pixel.xml} | 6 +++ .../craterlake_tracking_only_2DStrip.yml | 21 ---------- 6 files changed, 61 insertions(+), 42 deletions(-) rename compact/tracking/{mpgd_barrel.xml => mpgd_barrel_pixel.xml} (96%) rename compact/tracking/{mpgd_outerbarrel.xml => mpgd_outerbarrel_pixel.xml} (97%) delete mode 100644 configurations/craterlake_tracking_only_2DStrip.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fdfa3b6d6..b299cd2cb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,12 +92,46 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_full.xml ) #----------------------------------------------------------------------------------- -# Install the detector description files. +# Install the detector description files... +# ...excluding MPGD pixel/2DStrip, which are handled later on install(DIRECTORY compact/ DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact - FILES_MATCHING PATTERN "*.xml" PATTERN "*.gdml" + FILES_MATCHING + PATTERN "*.xml" + PATTERN "*.gdml" + PATTERN "*_pixel.xml" EXCLUDE + PATTERN "*_2DStrip.xml" EXCLUDE ) - +# Install MPGD pixel/2DStrip files +set(MPGD_INSTALL_PIXEL FALSE CACHE BOOL "Use \"pixel\" flavour of MPGD XMLs instead of default \"2DStrip\"") +IF(${MPGD_INSTALL_PIXEL}) + file(GLOB_RECURSE MPGD_FILES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking + "compact/tracking/*_pixel.xml" + ) + foreach(FILE IN ITEMS ${MPGD_FILES}) + execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_pixel//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + install(FILES compact/tracking/${FILE} + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking + RENAME ${INSTALL_FILE} + ) + endforeach() + message(STATUS "MPGD: \"pixel\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") +ELSE() + file(GLOB_RECURSE MPGD_FILES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking + "compact/tracking/*_2DStrip.xml" + ) + foreach(FILE IN ITEMS ${MPGD_FILES}) + execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_2DStrip//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + install(FILES compact/tracking/${FILE} + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking + RENAME ${INSTALL_FILE} + ) + endforeach() + MESSAGE(STATUS "MPGD: \"2DStrip\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") +ENDIF() + #----------------------------------------------------------------------------------- # Install the detector calibration files. install(DIRECTORY calibrations/ diff --git a/compact/tracking/mpgd_barrel_2DStrip.xml b/compact/tracking/mpgd_barrel_2DStrip.xml index 12a5379fcc..eb8b53031a 100644 --- a/compact/tracking/mpgd_barrel_2DStrip.xml +++ b/compact/tracking/mpgd_barrel_2DStrip.xml @@ -13,12 +13,10 @@ - Inner MPGD tracking layer(s) - - Note: the inner and outer layers are implemented as separate detectors, as they - belong to different ACTS tracking volumes. If this restriction goes away - in the future they could be put together in a single tag. + Inner MPGD tracking layer = CyMBaL + Note: MPGDs come in two distinct flavours: pixel and 2DStrip. + diff --git a/compact/tracking/mpgd_barrel.xml b/compact/tracking/mpgd_barrel_pixel.xml similarity index 96% rename from compact/tracking/mpgd_barrel.xml rename to compact/tracking/mpgd_barrel_pixel.xml index f848588655..4c6a0cd5b0 100644 --- a/compact/tracking/mpgd_barrel.xml +++ b/compact/tracking/mpgd_barrel_pixel.xml @@ -11,12 +11,10 @@ - Inner MPGD tracking layer(s) - - Note: the inner and outer layers are implemented as separate detectors, as they - belong to different ACTS tracking volumes. If this restriction goes away - in the future they could be put together in a single tag. + Inner MPGD tracking layer = CyMBaL + Note: MPGDs come in two distinct flavours: pixel and 2DStrip. + diff --git a/compact/tracking/mpgd_outerbarrel_2DStrip.xml b/compact/tracking/mpgd_outerbarrel_2DStrip.xml index 269dc30535..0756c62cde 100644 --- a/compact/tracking/mpgd_outerbarrel_2DStrip.xml +++ b/compact/tracking/mpgd_outerbarrel_2DStrip.xml @@ -2,16 +2,20 @@ - - + + Title: Micro-Pattern Gas Detector Planar Barrel Layer + Author: @mposik1983 + Status: development + Version: 1.0 + + + Outer MPGD tracking layer + Note: MPGDs come in two distinct flavours: pixel and 2DStrip. + + + Frames diff --git a/compact/tracking/mpgd_outerbarrel.xml b/compact/tracking/mpgd_outerbarrel_pixel.xml similarity index 97% rename from compact/tracking/mpgd_outerbarrel.xml rename to compact/tracking/mpgd_outerbarrel_pixel.xml index c1e978c139..b631b48000 100644 --- a/compact/tracking/mpgd_outerbarrel.xml +++ b/compact/tracking/mpgd_outerbarrel_pixel.xml @@ -10,6 +10,12 @@ + + Outer MPGD tracking layer + Note: MPGDs come in two distinct flavours: pixel and 2DStrip. + + + Frames diff --git a/configurations/craterlake_tracking_only_2DStrip.yml b/configurations/craterlake_tracking_only_2DStrip.yml deleted file mode 100644 index bb8e21b631..0000000000 --- a/configurations/craterlake_tracking_only_2DStrip.yml +++ /dev/null @@ -1,21 +0,0 @@ -features: - beampipe: - fields: - marco: - tracking: - definitions_craterlake: - vertex_barrel: - vertex_barrel_support: - silicon_barrel: - mpgd_barrel_2DStrip: - support_service_craterlake: - mpgd_outerbarrel_2DStrip: - mpgd_forward_endcap: - mpgd_backward_endcap: - silicon_disks: - tof_barrel: - tof_endcap: - far_forward: - default: - far_backward: - default: From f30c59f57aa87a46628862eef50a18d90a398e38 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Mon, 8 Dec 2025 19:53:33 +0100 Subject: [PATCH 4/8] MPGD Barrel: Install "_pixel" flavors of XMLs by default. Erase pre-existing files in "install" directory. - "_pixel" by default: so that the PR checks run successfully even when the new version of "MPGDTrackerDigi" (see "https://github.com/eic/EICrecon/pull/2177") is not in place. - Pre-existing files explicitly erased: since the cmake command "install" does not overwrite existing files. --- CMakeLists.txt | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b299cd2cb1..1c542a1e8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,15 +102,24 @@ install(DIRECTORY compact/ PATTERN "*_pixel.xml" EXCLUDE PATTERN "*_2DStrip.xml" EXCLUDE ) -# Install MPGD pixel/2DStrip files -set(MPGD_INSTALL_PIXEL FALSE CACHE BOOL "Use \"pixel\" flavour of MPGD XMLs instead of default \"2DStrip\"") +# Install MPGD files: +# - pixel or 2DStrip version depending upon option "MPGD_INSTALL_PIXEL" +# - The "install" command turns out to not be able to overwrite pre-existing. +# => We use the "file" command to work around that. Which later command takes +# effect immediately, at cmake execution time. => Emit a warning message. +set(MPGD_INSTALL_PIXEL TRUE CACHE BOOL "Use \"pixel\" flavour of MPGD XMLs instead of \"2DStrip\". It's temporarily the default.") IF(${MPGD_INSTALL_PIXEL}) file(GLOB_RECURSE MPGD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking "compact/tracking/*_pixel.xml" ) foreach(FILE IN ITEMS ${MPGD_FILES}) - execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_pixel//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_pixel//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) + if(EXISTS ${PRE_EXISTING_FILE}) + message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") + file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) + endif() install(FILES compact/tracking/${FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking RENAME ${INSTALL_FILE} @@ -124,6 +133,11 @@ ELSE() ) foreach(FILE IN ITEMS ${MPGD_FILES}) execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_2DStrip//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) + if(EXISTS ${PRE_EXISTING_FILE}) + message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") + file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) + endif() install(FILES compact/tracking/${FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking RENAME ${INSTALL_FILE} From 53a2b0b487e84b244cb756b50ddb549dc44b5660 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:29:39 +0000 Subject: [PATCH 5/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- CMakeLists.txt | 36 ++--- compact/tracking/mpgd_barrel_2DStrip.xml | 2 +- src/BarrelPlanarMPGDTracker_geo.cpp | 161 +++++++++++------------ src/MPGDCylinderBarrelTracker_geo.cpp | 128 +++++++++--------- 4 files changed, 158 insertions(+), 169 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c542a1e8b..8f79cd3e27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,41 +111,41 @@ set(MPGD_INSTALL_PIXEL TRUE CACHE BOOL "Use \"pixel\" flavour of MPGD XMLs inste IF(${MPGD_INSTALL_PIXEL}) file(GLOB_RECURSE MPGD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking - "compact/tracking/*_pixel.xml" + "compact/tracking/*_pixel.xml" ) foreach(FILE IN ITEMS ${MPGD_FILES}) execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_pixel//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) - set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) - if(EXISTS ${PRE_EXISTING_FILE}) - message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") + set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) + if(EXISTS ${PRE_EXISTING_FILE}) + message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) - endif() - install(FILES compact/tracking/${FILE} + endif() + install(FILES compact/tracking/${FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking - RENAME ${INSTALL_FILE} - ) + RENAME ${INSTALL_FILE} + ) endforeach() message(STATUS "MPGD: \"pixel\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") ELSE() file(GLOB_RECURSE MPGD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking - "compact/tracking/*_2DStrip.xml" + "compact/tracking/*_2DStrip.xml" ) foreach(FILE IN ITEMS ${MPGD_FILES}) - execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_2DStrip//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) - set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) - if(EXISTS ${PRE_EXISTING_FILE}) - message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") + execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_2DStrip//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) + set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) + if(EXISTS ${PRE_EXISTING_FILE}) + message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) - endif() - install(FILES compact/tracking/${FILE} + endif() + install(FILES compact/tracking/${FILE} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking - RENAME ${INSTALL_FILE} - ) + RENAME ${INSTALL_FILE} + ) endforeach() MESSAGE(STATUS "MPGD: \"2DStrip\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") ENDIF() - + #----------------------------------------------------------------------------------- # Install the detector calibration files. install(DIRECTORY calibrations/ diff --git a/compact/tracking/mpgd_barrel_2DStrip.xml b/compact/tracking/mpgd_barrel_2DStrip.xml index eb8b53031a..0e0df50cc7 100644 --- a/compact/tracking/mpgd_barrel_2DStrip.xml +++ b/compact/tracking/mpgd_barrel_2DStrip.xml @@ -142,7 +142,7 @@ - + system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 diff --git a/src/BarrelPlanarMPGDTracker_geo.cpp b/src/BarrelPlanarMPGDTracker_geo.cpp index 35ac411143..045fa15e3c 100644 --- a/src/BarrelPlanarMPGDTracker_geo.cpp +++ b/src/BarrelPlanarMPGDTracker_geo.cpp @@ -50,7 +50,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, string det_name = x_det.nameStr(); DetElement sdet(det_name, det_id); - Volume *volume; + Volume* volume; // Sensitive volumes and associated surfaces // - There can be either one or five. int sensitiveVolumeSet = 5; // 1: single volume, 5: 5 volumes, -1: error @@ -94,8 +94,8 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, modules.size()); throw runtime_error("Logics error in building modules."); } - xml_comp_t x_mod = modules; - string m_nam = x_mod.nameStr(); + xml_comp_t x_mod = modules; + string m_nam = x_mod.nameStr(); int ncomponents = 0; int sensor_number = 0; @@ -137,12 +137,12 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, // accessorily, some extras), the "DriftGap" is subdivided into subVolumes. int nSensitives = 0; for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) { - xml_comp_t x_comp = mci; - string c_nam = _toString(ncomponents, "component%d"); - string comp_name = x_comp.nameStr(); + xml_comp_t x_comp = mci; + string c_nam = _toString(ncomponents, "component%d"); + string comp_name = x_comp.nameStr(); double comp_thickness = x_comp.thickness(); - double box_width = x_comp.width(); - double box_length = x_comp.length(); + double box_width = x_comp.width(); + double box_length = x_comp.length(); Box c_box; // Since MPGD frames are layed over the MPGD foils, the foil material is pressent under the frame as well. // The gas volumes are not present under the frames, so our frames must eat only the gas module areas @@ -158,8 +158,8 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, // a way to set an attribute via the module tag to flag what components // need to have frame thickness subtracted. bool isDriftGap = comp_name == "DriftGap" || - /* */ comp_name.find("ThinGap") !=std::string::npos || - /* */ comp_name.find("Radiator")!=std::string::npos; + /* */ comp_name.find("ThinGap") != std::string::npos || + /* */ comp_name.find("Radiator") != std::string::npos; if (isDriftGap || comp_name == "WindowGasGap") { box_width = x_comp.width() - 2.0 * frame_width; box_length = x_comp.length() - 2.0 * frame_width; @@ -176,8 +176,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "Not gas: %s", comp_name.c_str()); printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_width: %f", x_comp.width()); printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_length: %f", x_comp.length()); - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_thickness: %f", - comp_thickness); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_thickness: %f", comp_thickness); } Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())}; @@ -187,28 +186,28 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, pcb_feb_ext = x_comp.offset(); - pv = m_vol.placeVolume( - c_vol, Position(0, -pcb_feb_ext / 2.0, thickness_sum + comp_thickness / 2.0)); + pv = m_vol.placeVolume(c_vol, + Position(0, -pcb_feb_ext / 2.0, thickness_sum + comp_thickness / 2.0)); if (x_comp.isSensitive()) { // ***** SENSITIVE VOLUME if (nSensitives >= 5) { - sensitiveVolumeSet = -1; - break; + sensitiveVolumeSet = -1; + break; } pv.addPhysVolID("sensor", sensor_number); // StripID. Single Sensitive Volume? int strip_id; if (comp_name == "DriftGap") { - if (nSensitives != 0) { - sensitiveVolumeSet = -1; - break; - } - strip_id = 0; - sensitiveVolumeSet = 1; - } - else { - int strip_ids[5] = {3,1,0,2,4}; strip_id = strip_ids[nSensitives]; + if (nSensitives != 0) { + sensitiveVolumeSet = -1; + break; + } + strip_id = 0; + sensitiveVolumeSet = 1; + } else { + int strip_ids[5] = {3, 1, 0, 2, 4}; + strip_id = strip_ids[nSensitives]; } pv.addPhysVolID("strip", strip_id); c_vol.setSensitiveDetector(sens); @@ -224,25 +223,21 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, // thicknesses that need to be assigned to the tracking surface // depending on wether the support is above or below the sensor. double inner_thickness, outer_thickness; - if (sensitiveVolumeSet == 1) { - inner_thickness = thickness_so_far + comp_thickness / 2; - outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; - } - else if (nSensitives == 0) { - inner_thickness = thickness_so_far + comp_thickness / 2; - outer_thickness = comp_thickness / 2; - } - else if (nSensitives == 4) { - inner_thickness = comp_thickness / 2; - outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; - } - else { - inner_thickness = outer_thickness = comp_thickness / 2; + if (sensitiveVolumeSet == 1) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } else if (nSensitives == 0) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = comp_thickness / 2; + } else if (nSensitives == 4) { + inner_thickness = comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } else { + inner_thickness = outer_thickness = comp_thickness / 2; } - printout(DEBUG, "BarrelPlanarMPGDTracker_geo", - "Sensitive surface @ R = %.4f (%.4f,%.4f) cm", - (thickness_sum + comp_thickness / 2) / cm, inner_thickness / cm, - outer_thickness / cm); + printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "Sensitive surface @ R = %.4f (%.4f,%.4f) cm", + (thickness_sum + comp_thickness / 2) / cm, inner_thickness / cm, + outer_thickness / cm); SurfaceType type(rec::SurfaceType::Sensitive); @@ -253,10 +248,9 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, thickness_sum += comp_thickness; thickness_so_far += comp_thickness; } - if (sensitiveVolumeSet < 0 || - sensitiveVolumeSet != nSensitives) { + if (sensitiveVolumeSet < 0 || sensitiveVolumeSet != nSensitives) { printout(ERROR, "BarrelPlanarMPGDTracker_geo", - "Invalid set of Sensitive Volumes: it's either one (named \"DriftGap\") or 5"); + "Invalid set of Sensitive Volumes: it's either one (named \"DriftGap\") or 5"); throw runtime_error("Logics error in building modules."); } // Now add-on the frame @@ -265,9 +259,9 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, double frame_thickness = getAttrOrDefault(m_frame, _U(thickness), total_thickness); Box lframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, - frame_thickness / 2.0}; + frame_thickness / 2.0}; Box rframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0, - frame_thickness / 2.0}; + frame_thickness / 2.0}; Box tframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; Box bframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0}; @@ -286,20 +280,20 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness: %f", frame_thickness); printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "total_thickness: %f", total_thickness); printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness + total_thickness: %f", - frame_thickness + total_thickness); - - m_vol.placeVolume(lframe_vol, Position(frame_width / 2.0 + max_component_width / 2, 0.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(rframe_vol, Position(-frame_width / 2.0 - max_component_width / 2.0, 0.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(tframe_vol, Position(0.0, frame_width / 2.0 + max_component_length / 2, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); - m_vol.placeVolume(bframe_vol, Position(0.0, -frame_width / 2.0 - max_component_length / 2.0, - frame_thickness / 2.0 - total_thickness / 2.0 - - gas_thickness / 2.0)); + frame_thickness + total_thickness); + + m_vol.placeVolume( + lframe_vol, Position(frame_width / 2.0 + max_component_width / 2, 0.0, + frame_thickness / 2.0 - total_thickness / 2.0 - gas_thickness / 2.0)); + m_vol.placeVolume( + rframe_vol, Position(-frame_width / 2.0 - max_component_width / 2.0, 0.0, + frame_thickness / 2.0 - total_thickness / 2.0 - gas_thickness / 2.0)); + m_vol.placeVolume( + tframe_vol, Position(0.0, frame_width / 2.0 + max_component_length / 2, + frame_thickness / 2.0 - total_thickness / 2.0 - gas_thickness / 2.0)); + m_vol.placeVolume( + bframe_vol, Position(0.0, -frame_width / 2.0 - max_component_length / 2.0, + frame_thickness / 2.0 - total_thickness / 2.0 - gas_thickness / 2.0)); } // ********** LAYER @@ -343,7 +337,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, Volume module_env = *volume; DetElement lay_elt(sdet, lay_nam, lay_id); auto& layerParams = - DD4hepDetectorHelper::ensureExtension(lay_elt); + DD4hepDetectorHelper::ensureExtension(lay_elt); pv = assembly.placeVolume(layer_assembly); pv.addPhysVolID("layer", lay_id); @@ -362,34 +356,33 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, DetElement mod_elt(lay_elt, module_name, module); double mod_z = 0.5 * dimensions.length(); double z_placement = mod_z - 0.5 * pcb_feb_ext - - j * (nz * mod_z - pcb_feb_ext); // z location for module placement + j * (nz * mod_z - pcb_feb_ext); // z location for module placement double z_offset = - z_placement > 0 - ? -z0 / 2.0 - : z0 / 2.0; // determine the amount of overlap in z the z nz modules have + z_placement > 0 ? -z0 / 2.0 + : z0 / 2.0; // determine the amount of overlap in z the z nz modules have Transform3D tr( - RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2) * RotationZ(j * M_PI), - Position( - xc, yc, - mpgd_pos.z() + z_placement + - z_offset)); //RotZYX rotates planes around azimuth, RotZ flips plane so pcb_feb_ext is facing endcaps + RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2) * RotationZ(j * M_PI), + Position( + xc, yc, + mpgd_pos.z() + z_placement + + z_offset)); //RotZYX rotates planes around azimuth, RotZ flips plane so pcb_feb_ext is facing endcaps pv = layer_assembly.placeVolume(module_env, tr); pv.addPhysVolID("module", module); mod_elt.setPlacement(pv); for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { - // ***** SENSITIVE COMPONENTS - PlacedVolume& sens_pv = sensitives[iSensitive]; - int de_id = nphi * iSensitive + module; - DetElement comp_de( - mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), - de_id); - comp_de.setPlacement(sens_pv); - auto& comp_de_params = - DD4hepDetectorHelper::ensureExtension(comp_de); - comp_de_params.set("axis_definitions", "XYZ"); - volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive]); + // ***** SENSITIVE COMPONENTS + PlacedVolume& sens_pv = sensitives[iSensitive]; + int de_id = nphi * iSensitive + module; + DetElement comp_de(mod_elt, + std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), + de_id); + comp_de.setPlacement(sens_pv); + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive]); } // increas module counter module++; @@ -410,7 +403,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) { xml_comp_t x_layer_material = lmat; DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams, - "layer_material"); + "layer_material"); } sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); assembly.setVisAttributes(description.invisible()); diff --git a/src/MPGDCylinderBarrelTracker_geo.cpp b/src/MPGDCylinderBarrelTracker_geo.cpp index e4066799f9..7d88e41910 100644 --- a/src/MPGDCylinderBarrelTracker_geo.cpp +++ b/src/MPGDCylinderBarrelTracker_geo.cpp @@ -401,8 +401,8 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, } // ********** LOOP OVER COMPONENTS - double comp_rmin = stave_rmin; - double thickness_so_far = 0; + double comp_rmin = stave_rmin; + double thickness_so_far = 0; // Pattern of Multiple Sensitive Volumes // - The "GasGap" may be subdivided into subVolumes (this order to have one // sensitive component per strip coordinate (and accessorily, some extras). @@ -419,25 +419,25 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, c_vol.setVisAttributes(description, x_comp.visStr()); if (x_comp.isSensitive()) { // ***** SENSITIVE VOLUME - if (nSensitives >= 5) { - sensitiveVolumeSet = -1; - break; - } + if (nSensitives >= 5) { + sensitiveVolumeSet = -1; + break; + } pv.addPhysVolID("sensor", sensor_number); - // StripID. Single Sensitive Volume? - int strip_id; - if (c_nam == "GasGap") { - if (nSensitives != 0) { - sensitiveVolumeSet = -1; - break; - } - strip_id = 0; - sensitiveVolumeSet = 1; - } - else { - int strip_ids[5] = {3,1,0,2,4}; strip_id = strip_ids[nSensitives]; - } - pv.addPhysVolID("strip", strip_id); + // StripID. Single Sensitive Volume? + int strip_id; + if (c_nam == "GasGap") { + if (nSensitives != 0) { + sensitiveVolumeSet = -1; + break; + } + strip_id = 0; + sensitiveVolumeSet = 1; + } else { + int strip_ids[5] = {3, 1, 0, 2, 4}; + strip_id = strip_ids[nSensitives]; + } + pv.addPhysVolID("strip", strip_id); c_vol.setSensitiveDetector(sens); sensitives[nSensitives].push_back(pv); @@ -446,56 +446,52 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, Vector3D v(0., -1., 0.); Vector3D n(0., 0., 1.); - if (strip_id == 0) { - // Consistency(+/-1um) check: segmentation consistent w/ stack of module components? - double rXCheck = comp_rmin + comp_thickness / 2; - if (fabs(staveModel.rsensor - rXCheck) > .0001 / cm) { - printout(ERROR, "MPGDCylinderBarrelTracker", - "Sensitive Component \"%s\" of StaveModel #%d,\"%s\": rsensor(%.4f cm) != " - "radius @ sensitive surface(%.4f cm)", - c_nam.c_str(), iSM, staveModel.name.c_str(), staveModel.rsensor / cm, - rXCheck / cm); - throw runtime_error("Logics error in building modules."); - } - } + if (strip_id == 0) { + // Consistency(+/-1um) check: segmentation consistent w/ stack of module components? + double rXCheck = comp_rmin + comp_thickness / 2; + if (fabs(staveModel.rsensor - rXCheck) > .0001 / cm) { + printout(ERROR, "MPGDCylinderBarrelTracker", + "Sensitive Component \"%s\" of StaveModel #%d,\"%s\": rsensor(%.4f cm) != " + "radius @ sensitive surface(%.4f cm)", + c_nam.c_str(), iSM, staveModel.name.c_str(), staveModel.rsensor / cm, + rXCheck / cm); + throw runtime_error("Logics error in building modules."); + } + } // Compute the inner (i.e. thickness until mid-sensitive-volume) and // outer (from mid-sensitive-volume to top) // thicknesses that need to be assigned to the tracking surface // depending on wether the support is above or below the sensor. double inner_thickness, outer_thickness; - if (sensitiveVolumeSet == 1) { - inner_thickness = thickness_so_far + comp_thickness / 2; - outer_thickness = total_thickness - inner_thickness; - } - else if (nSensitives == 0) { - inner_thickness = thickness_so_far + comp_thickness / 2; - outer_thickness = comp_thickness / 2; - } - else if (nSensitives == 4) { - inner_thickness = comp_thickness / 2; - outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; - } - else { - inner_thickness = outer_thickness = comp_thickness / 2; - } - printout(DEBUG, "MPGDCylinderBarrelTracker", - "Stave Model #%d,\"%s\": Sensitive surface @ R = %.4f (%.4f,%.4f) cm", iSM, - staveModel.name.c_str(), staveModel.rsensor / cm, inner_thickness / cm, - outer_thickness / cm); + if (sensitiveVolumeSet == 1) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = total_thickness - inner_thickness; + } else if (nSensitives == 0) { + inner_thickness = thickness_so_far + comp_thickness / 2; + outer_thickness = comp_thickness / 2; + } else if (nSensitives == 4) { + inner_thickness = comp_thickness / 2; + outer_thickness = total_thickness - thickness_so_far - comp_thickness / 2; + } else { + inner_thickness = outer_thickness = comp_thickness / 2; + } + printout(DEBUG, "MPGDCylinderBarrelTracker", + "Stave Model #%d,\"%s\": Sensitive surface @ R = %.4f (%.4f,%.4f) cm", iSM, + staveModel.name.c_str(), staveModel.rsensor / cm, inner_thickness / cm, + outer_thickness / cm); SurfaceType type(SurfaceType::Sensitive); VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; volplane_surfaces[nSensitives].push_back(surf); - nSensitives++; + nSensitives++; } comp_rmin += comp_thickness; thickness_so_far += comp_thickness; } //end of module component loop - if (sensitiveVolumeSet < 0 || - sensitiveVolumeSet != nSensitives) { + if (sensitiveVolumeSet < 0 || sensitiveVolumeSet != nSensitives) { printout(ERROR, "MPGDCylinderBarrelTracker", - "Invalid set of Sensitive Volumes: it's either one (named \"GasGap\") or 5"); + "Invalid set of Sensitive Volumes: it's either one (named \"GasGap\") or 5"); throw runtime_error("Logics error in building modules."); } } //end of stave model loop @@ -566,17 +562,17 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, pv.addPhysVolID("module", nModules); mod_elt.setPlacement(pv); for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { - // ***** SENSITIVE COMPONENTS - PlacedVolume& sens_pv = sensitives[iSensitive][iV]; - int de_id = 32 * iSensitive + nModules; - DetElement comp_de( - mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), - de_id); - comp_de.setPlacement(sens_pv); - auto& comp_de_params = - DD4hepDetectorHelper::ensureExtension(comp_de); - comp_de_params.set("axis_definitions", "XYZ"); - volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive][iV]); + // ***** SENSITIVE COMPONENTS + PlacedVolume& sens_pv = sensitives[iSensitive][iV]; + int de_id = 32 * iSensitive + nModules; + DetElement comp_de(mod_elt, + std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), + de_id); + comp_de.setPlacement(sens_pv); + auto& comp_de_params = + DD4hepDetectorHelper::ensureExtension(comp_de); + comp_de_params.set("axis_definitions", "XYZ"); + volSurfaceList(comp_de)->push_back(volplane_surfaces[iSensitive][iV]); } } } From 8c4a367c89397ad183301c0eb46463b77a2bb851 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Fri, 19 Dec 2025 11:26:23 +0100 Subject: [PATCH 6/8] MPGD: Cancel switching _pixel/_2DStrip from cmake. Add a special _2DStrip configurations. --- CMakeLists.txt | 52 +------------------ ...{mpgd_barrel_pixel.xml => mpgd_barrel.xml} | 0 compact/tracking/mpgd_barrel_2DStrip.xml | 8 +-- ...rbarrel_pixel.xml => mpgd_outerbarrel.xml} | 0 compact/tracking/mpgd_outerbarrel_2DStrip.xml | 4 +- .../craterlake_tracking_2DStrip.yml | 21 ++++++++ 6 files changed, 29 insertions(+), 56 deletions(-) rename compact/tracking/{mpgd_barrel_pixel.xml => mpgd_barrel.xml} (100%) rename compact/tracking/{mpgd_outerbarrel_pixel.xml => mpgd_outerbarrel.xml} (100%) create mode 100644 configurations/craterlake_tracking_2DStrip.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f79cd3e27..5fdfa3b6d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,59 +92,11 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_full.xml ) #----------------------------------------------------------------------------------- -# Install the detector description files... -# ...excluding MPGD pixel/2DStrip, which are handled later on +# Install the detector description files. install(DIRECTORY compact/ DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact - FILES_MATCHING - PATTERN "*.xml" - PATTERN "*.gdml" - PATTERN "*_pixel.xml" EXCLUDE - PATTERN "*_2DStrip.xml" EXCLUDE + FILES_MATCHING PATTERN "*.xml" PATTERN "*.gdml" ) -# Install MPGD files: -# - pixel or 2DStrip version depending upon option "MPGD_INSTALL_PIXEL" -# - The "install" command turns out to not be able to overwrite pre-existing. -# => We use the "file" command to work around that. Which later command takes -# effect immediately, at cmake execution time. => Emit a warning message. -set(MPGD_INSTALL_PIXEL TRUE CACHE BOOL "Use \"pixel\" flavour of MPGD XMLs instead of \"2DStrip\". It's temporarily the default.") -IF(${MPGD_INSTALL_PIXEL}) - file(GLOB_RECURSE MPGD_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking - "compact/tracking/*_pixel.xml" - ) - foreach(FILE IN ITEMS ${MPGD_FILES}) - execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_pixel//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) - set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) - if(EXISTS ${PRE_EXISTING_FILE}) - message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") - file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) - endif() - install(FILES compact/tracking/${FILE} - DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking - RENAME ${INSTALL_FILE} - ) - endforeach() - message(STATUS "MPGD: \"pixel\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") -ELSE() - file(GLOB_RECURSE MPGD_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/compact/tracking - "compact/tracking/*_2DStrip.xml" - ) - foreach(FILE IN ITEMS ${MPGD_FILES}) - execute_process(COMMAND bash -c "echo ${FILE} | sed -e 's/_2DStrip//'" OUTPUT_VARIABLE INSTALL_FILE OUTPUT_STRIP_TRAILING_WHITESPACE) - set(PRE_EXISTING_FILE ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking/${INSTALL_FILE}) - if(EXISTS ${PRE_EXISTING_FILE}) - message(STATUS "MPGD: Remove ${PRE_EXISTING_FILE}") - file(REMOVE_RECURSE ${PRE_EXISTING_FILE}) - endif() - install(FILES compact/tracking/${FILE} - DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/compact/tracking - RENAME ${INSTALL_FILE} - ) - endforeach() - MESSAGE(STATUS "MPGD: \"2DStrip\" flavour of XMLs \"${MPGD_FILES}\" to be installed.") -ENDIF() #----------------------------------------------------------------------------------- # Install the detector calibration files. diff --git a/compact/tracking/mpgd_barrel_pixel.xml b/compact/tracking/mpgd_barrel.xml similarity index 100% rename from compact/tracking/mpgd_barrel_pixel.xml rename to compact/tracking/mpgd_barrel.xml diff --git a/compact/tracking/mpgd_barrel_2DStrip.xml b/compact/tracking/mpgd_barrel_2DStrip.xml index 0e0df50cc7..88ae358681 100644 --- a/compact/tracking/mpgd_barrel_2DStrip.xml +++ b/compact/tracking/mpgd_barrel_2DStrip.xml @@ -2,12 +2,12 @@ - diff --git a/compact/tracking/mpgd_outerbarrel_pixel.xml b/compact/tracking/mpgd_outerbarrel.xml similarity index 100% rename from compact/tracking/mpgd_outerbarrel_pixel.xml rename to compact/tracking/mpgd_outerbarrel.xml diff --git a/compact/tracking/mpgd_outerbarrel_2DStrip.xml b/compact/tracking/mpgd_outerbarrel_2DStrip.xml index 0756c62cde..805b9b37a8 100644 --- a/compact/tracking/mpgd_outerbarrel_2DStrip.xml +++ b/compact/tracking/mpgd_outerbarrel_2DStrip.xml @@ -4,9 +4,9 @@ Title: Micro-Pattern Gas Detector Planar Barrel Layer - Author: @mposik1983 + Author: @ybedfer Status: development - Version: 1.0 + Version: 1.1 diff --git a/configurations/craterlake_tracking_2DStrip.yml b/configurations/craterlake_tracking_2DStrip.yml new file mode 100644 index 0000000000..bb8e21b631 --- /dev/null +++ b/configurations/craterlake_tracking_2DStrip.yml @@ -0,0 +1,21 @@ +features: + beampipe: + fields: + marco: + tracking: + definitions_craterlake: + vertex_barrel: + vertex_barrel_support: + silicon_barrel: + mpgd_barrel_2DStrip: + support_service_craterlake: + mpgd_outerbarrel_2DStrip: + mpgd_forward_endcap: + mpgd_backward_endcap: + silicon_disks: + tof_barrel: + tof_endcap: + far_forward: + default: + far_backward: + default: From 89a123af86dee8cc721d3a98d3509ee13aca1105 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Mon, 2 Feb 2026 00:08:50 +0100 Subject: [PATCH 7/8] MPGD: 2DStrip,v.2 (realistic pitch and correct apperture) StripID from XML. - 2DStrip: + CyMBaL: v2.1 is the 5-SUBVOLUME version, v2.2 is clusterisation compatible. + Outer: same thing w/ v1.1 and v1.2. - StripID: Merge in #767a3c7a0 of branch Multi-SensitiveVolume-MPGD. --- compact/tracking/mpgd_barrel.xml | 2 +- compact/tracking/mpgd_barrel_2DStrip.xml | 45 ++++++++++--------- compact/tracking/mpgd_outerbarrel.xml | 3 +- compact/tracking/mpgd_outerbarrel_2DStrip.xml | 26 ++++++----- src/BarrelPlanarMPGDTracker_geo.cpp | 10 ++--- src/MPGDCylinderBarrelTracker_geo.cpp | 44 +++++++++--------- 6 files changed, 67 insertions(+), 63 deletions(-) diff --git a/compact/tracking/mpgd_barrel.xml b/compact/tracking/mpgd_barrel.xml index 4c6a0cd5b0..0a75fe8e85 100644 --- a/compact/tracking/mpgd_barrel.xml +++ b/compact/tracking/mpgd_barrel.xml @@ -82,7 +82,7 @@ - + diff --git a/compact/tracking/mpgd_barrel_2DStrip.xml b/compact/tracking/mpgd_barrel_2DStrip.xml index 88ae358681..55fd57c570 100644 --- a/compact/tracking/mpgd_barrel_2DStrip.xml +++ b/compact/tracking/mpgd_barrel_2DStrip.xml @@ -2,18 +2,16 @@ - - + + Title: Micro Pattern Gas Detectors + Author: @mposik1983 + Status: development + Version: 2.2 + - Inner MPGD tracking layer = CyMBaL + Inner MPGD tracking layer (=CyMBaL) with realistic pitch Note: MPGDs come in two distinct flavours: pixel and 2DStrip. @@ -57,10 +55,17 @@ + "MMModuleWidth" is to be understood as the width at the inner wall. Width expands as one moves away from it. - - + + + Strip layout: Pitch is derived from size and # of strips, assuming sensitive area to fill all available space. + + + + + @@ -87,11 +92,11 @@ - - - - - + + + + + @@ -131,15 +136,15 @@ - - + + - - + + diff --git a/compact/tracking/mpgd_outerbarrel.xml b/compact/tracking/mpgd_outerbarrel.xml index b631b48000..944ef7ea25 100644 --- a/compact/tracking/mpgd_outerbarrel.xml +++ b/compact/tracking/mpgd_outerbarrel.xml @@ -64,7 +64,8 @@ thickness="MPGDOuterBarrelDriftGap_thickness" vis="TrackerMPGDGasVis" offset="0" - length="MPGDOuterBarrelModule_Inset_length"/> + length="MPGDOuterBarrelModule_Inset_length" + key="0"/> Title: Micro-Pattern Gas Detector Planar Barrel Layer - Author: @ybedfer + Author: @mposik1983 Status: development - Version: 1.1 + Version: 1.2 - Outer MPGD tracking layer + Outer MPGD tracking layer with realistic pitch Note: MPGDs come in two distinct flavours: pixel and 2DStrip. @@ -48,6 +48,10 @@ 2DStrip: Multiple Sensitive Volumes. => Subdivide DriftGap: 3 thin slices (pixel and (p|n)strips) at the centre, enclosed by 2 thick radiators. + Strip layout: Pitch and #channels are taken from CM of 2025 @ Frascati. + #channels is used by the MPGD factory to set up the digitization configuration. + + @@ -60,11 +64,11 @@ - - - - - + + + + + Strip segmentations ("strip" field !=0) are not used at simulation time but only in digitization at reconstruction time, see digitization class, "MPGDTrackerDigi". - - - + + + system:8,layer:4,module:12,sensor:2,strip:28:4,u:-16,v:-16 diff --git a/src/BarrelPlanarMPGDTracker_geo.cpp b/src/BarrelPlanarMPGDTracker_geo.cpp index 045fa15e3c..60f9f79ff1 100644 --- a/src/BarrelPlanarMPGDTracker_geo.cpp +++ b/src/BarrelPlanarMPGDTracker_geo.cpp @@ -197,18 +197,14 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, } pv.addPhysVolID("sensor", sensor_number); // StripID. Single Sensitive Volume? - int strip_id; if (comp_name == "DriftGap") { if (nSensitives != 0) { sensitiveVolumeSet = -1; break; } - strip_id = 0; sensitiveVolumeSet = 1; - } else { - int strip_ids[5] = {3, 1, 0, 2, 4}; - strip_id = strip_ids[nSensitives]; } + int strip_id = x_comp.key(); pv.addPhysVolID("strip", strip_id); c_vol.setSensitiveDetector(sens); sensitives.push_back(pv); @@ -323,7 +319,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, } double phi0 = x_layout.phi0(); // starting phi of first module - double phi_tilt = x_layout.phi_tilt(); // Phi tilit of module + double phi_tilt = x_layout.phi_tilt(); // Phi tilt of module double rc = x_layout.rc(); // Radius of the module int nphi = x_layout.nphi(); // Number of modules in phi double rphi_dr = x_layout.dr(); // The delta radius of every other module @@ -374,7 +370,7 @@ static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e, for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { // ***** SENSITIVE COMPONENTS PlacedVolume& sens_pv = sensitives[iSensitive]; - int de_id = nphi * iSensitive + module; + int de_id = nphi * nz * iSensitive + module; DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), de_id); diff --git a/src/MPGDCylinderBarrelTracker_geo.cpp b/src/MPGDCylinderBarrelTracker_geo.cpp index 7d88e41910..6c3a8e343a 100644 --- a/src/MPGDCylinderBarrelTracker_geo.cpp +++ b/src/MPGDCylinderBarrelTracker_geo.cpp @@ -128,28 +128,28 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, double barrel_z0 = getAttrOrDefault(x_barrel, _U(z0), 0.); // ***** LAYOUTS xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); - double phi0 = x_layout.phi0(); // Starting phi of first module. - xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element. + double phi0 = x_layout.phi0(); // Starting phi of first module. + xml_comp_t z_layout = x_layer.child(_U(z_layout)); double z_gap = z_layout.gap(); - // ***** UNVALID LAYOUT PROPERTIES + // ***** INVALID LAYOUT PROPERTIES // # of staves (along phi) and sectors (along z) are now derived from stave // width and sector length. Used to be specified directly. In order to remind // the user this is no longer the case, let's forbid the use of the // corresponding (and a few more) tags. - const int nUnvalids = 4; - const xml::Tag_t unvalidTags[nUnvalids] = {_U(phi_tilt), _U(nphi), _U(rc), _U(dr)}; - for (int uv = 0; uv < nUnvalids; uv++) { - if (x_barrel.hasChild(unvalidTags[uv])) { + const int nInvalids = 4; + const xml::Tag_t invalidTags[nInvalids] = {_U(phi_tilt), _U(nphi), _U(rc), _U(dr)}; + for (int uv = 0; uv < nInvalids; uv++) { + if (x_barrel.hasChild(invalidTags[uv])) { const string tag = _U(nphi); printout(ERROR, "MPGDCylinderBarrelTracker", - "Layer \"%s\": Unvalid property \"%s\" in \"rphi_layout\"", m_nam.c_str(), + "Layer \"%s\": Invalid property \"%s\" in \"rphi_layout\"", m_nam.c_str(), tag.c_str()); throw runtime_error("Logics error in building modules."); } } // ***** MODELS - // Model = set of two radii of curvature used alternatingly for staves + // Model = set of two radii of curvature used alternatively for staves // + an offset to be applied radially. // - The offset may be null if the two radii are different enough that // staves adjacent along phi do not overlap. @@ -168,7 +168,8 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, double offset; int io; } StaveModel; - StaveModel staveModels[4]; + const int nSectors = 4; + StaveModel staveModels[nSectors]; int sector2Models[2][2]; xml_coll_t mi(x_mod, _U(model)); if (mi.size() != 2) { @@ -311,7 +312,7 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, double dPhi = acos(vEdge0.Dot(vEdge1) / Mag0 / Mag1); RMx += total_thickness; if (io == 1) { - RMn -= service_thickness; // Outer sector: acount for services to inner sector + RMn -= service_thickness; // Outer sector: account for services to inner sector outerPhiSuperpos = dPhi; } printout( @@ -404,7 +405,7 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, double comp_rmin = stave_rmin; double thickness_so_far = 0; // Pattern of Multiple Sensitive Volumes - // - The "GasGap" may be subdivided into subVolumes (this order to have one + // - The "GasGap" may be subdivided into SUBVOLUMES (this order to have one // sensitive component per strip coordinate (and accessorily, some extras). int nSensitives = 0; for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) { @@ -425,18 +426,14 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, } pv.addPhysVolID("sensor", sensor_number); // StripID. Single Sensitive Volume? - int strip_id; if (c_nam == "GasGap") { if (nSensitives != 0) { sensitiveVolumeSet = -1; break; } - strip_id = 0; sensitiveVolumeSet = 1; - } else { - int strip_ids[5] = {3, 1, 0, 2, 4}; - strip_id = strip_ids[nSensitives]; } + int strip_id = x_comp.key(); pv.addPhysVolID("strip", strip_id); c_vol.setSensitiveDetector(sens); sensitives[nSensitives].push_back(pv); @@ -462,7 +459,7 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, // Compute the inner (i.e. thickness until mid-sensitive-volume) and // outer (from mid-sensitive-volume to top) // thicknesses that need to be assigned to the tracking surface - // depending on wether the support is above or below the sensor. + // depending on whether the support is above or below the sensor. double inner_thickness, outer_thickness; if (sensitiveVolumeSet == 1) { inner_thickness = thickness_so_far + comp_thickness / 2; @@ -518,10 +515,11 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, // ***** SECTOR POSITIONS ALONG Z // These are the 4 central values in Z where the four sets of modules, called // sectors, will be placed. - double modz_pos[4] = {-barrel_length / 2 + (total_length) / 2, -(total_length + z_gap) / 2, - +(total_length + z_gap) / 2, +barrel_length / 2 - (total_length) / 2}; - int nModules = 0; - for (int iz = 0; iz < 4; iz++) { + double modz_pos[nSectors] = {-barrel_length / 2 + (total_length) / 2, -(total_length + z_gap) / 2, + +(total_length + z_gap) / 2, + +barrel_length / 2 - (total_length) / 2}; + int nModules = 0; + for (int iz = 0; iz < nSectors; iz++) { int io = (iz == 1 || iz == 2) ? 0 : 1; int iSMs[2] = {sector2Models[io][0], sector2Models[io][1]}; int iSM0 = iSMs[0]; @@ -564,7 +562,7 @@ static Ref_t create_MPGDCylinderBarrelTracker(Detector& description, xml_h e, for (int iSensitive = 0; iSensitive < sensitiveVolumeSet; iSensitive++) { // ***** SENSITIVE COMPONENTS PlacedVolume& sens_pv = sensitives[iSensitive][iV]; - int de_id = 32 * iSensitive + nModules; + int de_id = nphi * nSectors * iSensitive + nModules; DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name() + _toString(de_id, "%02d"), de_id); From 9809ef0f97f123e101e70a5e0a0f4655d08e6ead Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:10:06 +0000 Subject: [PATCH 8/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- compact/tracking/mpgd_barrel_2DStrip.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compact/tracking/mpgd_barrel_2DStrip.xml b/compact/tracking/mpgd_barrel_2DStrip.xml index 55fd57c570..7d3801d478 100644 --- a/compact/tracking/mpgd_barrel_2DStrip.xml +++ b/compact/tracking/mpgd_barrel_2DStrip.xml @@ -61,10 +61,10 @@ Strip layout: Pitch is derived from size and # of strips, assuming sensitive area to fill all available space. - + - +