From 15316cc2017220fc00d8ec4b24d7ecf09def6286 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 6 Nov 2025 17:35:40 +0100 Subject: [PATCH 01/47] MPGDTrackerDigi: Multi-SensitiveVolume solution for the 2D-strip readout. --- src/algorithms/digi/MPGDTrackerDigi.cc | 1337 ++++++++++++++++++++++-- src/algorithms/digi/MPGDTrackerDigi.h | 47 + 2 files changed, 1293 insertions(+), 91 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 502ddfe593..363bbdc7b0 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -5,18 +5,81 @@ Digitization specific to MPGDs. - What's special in MPGDs is their 2D-strip readout: i.e. simultaneous registering along two sets of coordinate strips. - - The "process" method involves a combination of segmentation, simulation and - digitization. - - The segmentation done when producing "sim_hits", and stored as a pixel - cellID, is overwritten by strip cellIDs, via "dd4hep::MultiSegmentation". - - The simulation will eventually involve simulating the amplitude and timing - correlation of the two coordinates, and the spreading of the charge on - adjacent strips producing multi-hit clusters. - The preliminary version is rudimentary: single-hit clusters, with identical - timing and uncorrelated amplitudes. - - The digitization follows the standard steps, only that it needs to be - convoluted with the simulation. - NOTA BENE: The file could be simplified, see issue #1702. + - The fact imposes strong constraints on digitization, stemming from DD4hep's + provision that one and only one readout surface be associated to a sensitive + volume. The one-and-only-one rule is enforced through to ACTS's TrackState, + forbidding simple solutions exploiting MultiSegmentation to create two strip + hits on a same surface. + - Present solution is based on multiple sensitive SUBVOLUMES. FIVE of them: + + TWO persistent ones, acting as READOUT SURFACES (i.e. to which raw hits + are assigned, in both RealData and MC): very thin and sitting very close + to mid-plane, + + THREE HELPER ones: TWO RADIATORS, thick, serving temporarily to collect + energy deposit and ONE REFERENCE, thin and sitting exactly at mid-plane. + (The REFERENCE is not essential, but found to help rationalize the source + code.) + - Each SUBVOLUME has a distinct ID, w/ a distinctive "STRIP" FIELD, but all + share a common XML thanks to a MultiSegmentation based on the + "STRIP" FIELD. + - Several subHits are created (up to five, one per individual SUBVOLUME) + corresponding to a SINGLE I[ONISATION]+A[MPLIFICATION] process, inducing in + turn CORRELATED SIGNALS ON TWO COORDINATES. + - These subHits are extrapolated to the REFERENCE SUBVOLUME (its mid-plane), + so as to reconstitute the proper hit position of the TRAVERSING particle. + This, for particles that are determined to be indeed traversing. + - We then want to preserve the I+A correlation when accumulating hits on the + readout channels. This cannot be obtained by accumulating directly subHits ( + as is done in "SiliconTrackerDigi", as of commit #151496af). We have to + first COALESCE separately subHits into hits corresponding to a given I+A. + Then apply a common smearing simulating I+A, then apply independent + smearings simulating CHARGE SHARING and CHARGE SPREADING. Then accumulate + channel by channel. Then, possibly, apply smearing simulating FE electronics. + - Therefore we have a DOUBLE LOOP ON INPUT SimTrackerHits, to collect those + subHits deemed to arise from the same I+A. I.e. SAME P[ARTICLE], M[ODULE] (a + particle can fire two overlapping modules, not to be mixed) and O[RIGIN] ( + direct or via secondary). + - The double loop is optimized for speed (by keeping track of the start index + of the second loop) in order to not waste time on high multiplicity events. + - A priori, subHits with same PMO should come in sequence. We nevertheless + provide for them to be intertwined. This, except for subHits of secondary + origin. + - A number of checks are conducted before undertaking subHit COALESCENCE: + I) SubHits should be TRAVERSING, i.e. exiting/entering through opposite + walls, as opposed to exiting/entering through the edge or dying/being-born + within their SUBVOLUME, see methods "(c|b)Traversing". + II) SubHits have SAME PMO, see "samePMO". + III) SubHits extrapolate to a common point, see "outInDistance". + All these checks are done to be on the safe side. A subset of them, + hinging on (III), should be sufficient. But there are so many cases to take + into account that it's difficult to settle on a minimal subset. + - Evaluation: + + With 3 mm overall sensitive volume (=> ~1.5 mm SUBVOLUME), MIPs turn out + firing most of the time only one SUBVOLUME. + + MIPs are found to be properly handled: hits are assigned to mid-plane, + are COALESCED when needed... + ...Except for few cases, see "flagUnexpected". + + For lower energy particles, there are at times ambiguous cases where + seemingly related subHits turn out to not be COALESCED, because they fail + to pass above-mentioned checks due to their erratic trajectories. + Note that even if they are genuinely related, this is not dramatic: + subHits will still be directly accumulated on their common (within pitch + precision) cell, only that we miss the correlation. + + The special case of a particle exiting and reEntering the same SUBVOLUME, + in a cylindrical setup, is catered for, but has not been evaluated. + - Imperfections: + + In order to validate (III), one has to fix a tolerance. The ideal would + be to fix it based on multiscattering. This not done. Instead a, somewhat + arbitrary, built-in value is used. + - Future developments: + In addition to DIGITIZATION proper, the method involves SIMULATION and + (re)SEGMENTATION. + + SIMULATION will eventually involve simulating the amplitude and timing + correlation of the two coordinates, and the spreading of the charge on + adjacent strips producing multi-hit clusters. But present version is + preliminary: single-hit clusters, with identical timing and same + amplitude. + + DIGITIZATION follows the standard steps. Remains to agree on the handling + of the discrimination threshold, see Issue #1722. */ #include "MPGDTrackerDigi.h" @@ -42,6 +105,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +120,10 @@ #include "algorithms/digi/MPGDTrackerDigiConfig.h" +#include "DDRec/SurfaceManager.h" +#include "DDRec/SurfaceHelper.h" +#include "DDRec/Surface.h" + using namespace dd4hep; namespace eicrecon { @@ -63,6 +131,7 @@ namespace eicrecon { void MPGDTrackerDigi::init() { // Access id decoder m_detector = algorithms::GeoSvc::instance().detector(); + const dd4hep::BitFieldCoder* m_id_dec = nullptr; if (m_cfg.readout.empty()) { throw JException("Readout is empty"); @@ -74,33 +143,85 @@ void MPGDTrackerDigi::init() { critical("Failed to load ID decoder for \"{}\" readout.", m_cfg.readout); throw JException("Failed to load ID decoder"); } - // Method "process" relies on a strict assumption on the IDDescriptor: - // - Must have a "strip" field. - // - That "strip" field includes bits 30|31. + // Method "process" relies on an assumption on the IDDescriptor's strip field. // Let's check. - if (m_id_dec->get(((CellID)0x3) << 30, "strip") != 0x3) { - critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" - readout.)", + debug(R"(Find valid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); + if (m_id_dec->get(m_stripBits, "strip") != 0xf) { + critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); throw JException("Invalid IDDescriptor"); } - debug(R"(Find valid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); + + // Ordering of SUBVOLUMES (based on "STRIP" FIELD) + m_stripRank = [=](CellID vID) { + int rank; + CellID sID = vID & m_stripBits; + for (rank = 0; rank < 5; rank++) + if (sID == m_stripIDs[rank]) return rank; + return -1; + }; + m_orientation = [=](CellID vID, CellID vJD) { + int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); + if (rankj > ranki) return +1; + else if (rankj < ranki) return -1; + else return 0; + }; + m_isUpstream = [](int orientation, unsigned int status) { + // Outgoing particle exits... + bool isUpstream = + (orientation < 0 && (status & 0x2)) || // ...lower wall + (orientation > 0 && (status & 0x8)) || // ...upper wall + (orientation == 0 && (status & 0x102) == 0x102); // ...lower wall and can reEnter + return isUpstream; + }; + m_isDownstream = [](int orientation, unsigned int status) { + // Incoming particle enters... + bool isDownstream = + (orientation > 0 && (status & 0x1)) || // ...lower wall + (orientation < 0 && (status & 0x4)) || // ...upper wall + (orientation == 0 && (status & 0101) == 0x101); // ...lower wall and can be reEntering + return isDownstream; + }; } +// Interfaces +void getLocalPosMom(const edm4hep::SimTrackerHit &sim_hit, + const TGeoHMatrix& toModule, + double *lpos, double *lmom); +unsigned int cTraversing(const double *lpos, const double *lmom, double path, bool isSecondary, // Input subHit + double rMin, double rMax, // Current instance of SUBVOLUME + double dZ, double startPhi, double endPhi, // Module parameters + double lins[][3], double louts[][3], + double *lpini, double *lpend); +bool cExtrapolate(const double *lpos, const double *lmom, // Input subHit + double rT, // Target radius + double *lext); // Extrapolated position @ +double getRef2Cur(DetElement refVol, DetElement curVol); +unsigned int bTraversing(const double *lpos, const double *lmom, double ref2Cur, double path, bool isSecondary, // Input subHit + double dZ, // Current instance of SUBVOLUME + double dX, double dY, // Module parameters + double lins[][3], double louts[][3], + double *lpini, double *lpend); +bool bExtrapolate(const double *lpos, const double *lmom, // Input subHit + double zT, // Target Z + double *lext); // Extrapolated position @ +std::string inconsistency(const edm4hep::EventHeader &event, unsigned int status, + CellID cID, const double *lpos, const double *lmom); +std::string oddity(const edm4hep::EventHeader &event, unsigned int status, double dist, + CellID cID, const double *lpos, const double *lmom, + CellID cJD, const double *lpoj, const double *lmoj); +double outInDistance(int shape, int orientation, + double lins[][3], double louts[][3], + double *lmom, double *lmoj); +void flagUnexpected(const edm4hep::EventHeader &event, + int shape, double expected, + const edm4hep::SimTrackerHit &sim_hit, + double *lpini, double *lpend, + double *lpos, double *lmom); + void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, const MPGDTrackerDigi::Output& output) const { - // ********** SIMULATE THE 2D-strip READOUT of MPGDs. - // - Overwrite and extend segmentation stored in "sim_hit", which is anyway - // expected to be along a single coordinate (this happens to allow one to - // reconstruct data w/ a segmentation differing from that used when - // generating the data). - // - New segmentation is along two coordinates, described by two cellID's - // with each a distinctive "strip" field. - // N.B.: Assumptions on the IDDescriptor: the "strip" specification - // is fixed = cellID>>32&0x3. - // - The simulation is simplistic: single-hit cluster per coordinate. - const auto [headers, sim_hits] = input; auto [raw_hits, associations] = output; @@ -108,95 +229,412 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, auto seed = m_uid.getUniqueID(*headers, name()); std::default_random_engine generator(seed); std::normal_distribution gaussian; - + // A map of unique cellIDs with temporary structure RawHit std::unordered_map cell_hit_map; + // A map of strip cellIDs with vector of contributing cellIDs + std::map> stripID2cIDs; // Prepare for strip segmentation const Position dummy(0, 0, 0); const VolumeManager& volman = m_detector->volumeManager(); - using CellIDs = std::pair; - using Sim2IDs = std::vector; - Sim2IDs sim2IDs; - for (const edm4hep::SimTrackerHit& sim_hit : *sim_hits) { + // Reference to event, to be used to document "critical" error messages + // (N.B.: I don't know how to properly handle these "headers": may there + // be ore than one? none?...) + const edm4hep::EventHeader &header = headers->at(0); + + std::vector usedHits; + size_t sim_size = sim_hits->size(); + for (int idx = 0; idx<(int)sim_size; idx++) { + const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); // ***** TIME SMEARING // - Simplistic treatment. // - A more realistic one would have to distinguish a smearing common to - // both coordinates of the 2D-strip readout (due to the drifting of the - // leading primary electrons) from other smearing effects, specific to - // each coordinate. + // both coordinates of the 2D-strip readout (mainly due to the drifting of + // the leading primary electrons of the I+A process) from other smearing + // effects, specific to each coordinate. double time_smearing = gaussian(generator) * m_cfg.timeResolution; - double result_time = sim_hit.getTime() + time_smearing; - auto hit_time_stamp = (std::int32_t)(result_time * 1e3); + // ***** USED HIT? + int usedHit = 0; for (int jdx : usedHits) { + if (jdx == idx) { usedHit = 1; break; } + } + if (usedHit) continue; + else usedHits.push_back(idx); // useful?... + // ***** SEGMENTATION - // - The two cellID's are encoded via a "dd4hep::MultiSegmentation" + // - The two cellIDs are encoded via a "dd4hep::MultiSegmentation" // discriminating on the strip field, w/ "strip" setting of 0x1 ( - // called 'p') and 0x2 (called 'n'). - // - They are evaluated based on "sim_hit" Cartesian coordinates - // positions + // called 'p') or 0x2 (called 'n') and 0x3/0x4 for the inner/outer + // RADIATORS, and 0x0 for the REFERENCE SUBVOLUME. + // - They are evaluated based on "sim_hit" Cartesian position and momentum. + // + Extrapolating to REFERENCE SUBVOLUME. + // + COALESCING all subHits with SAME PMO. // Given that all the segmentation classes foreseen for MPGDs ( // "CartesianGrid.." for Outer and EndCaps, "CylindricalGridPhiZ" for // "CyMBaL") disregard the _global_ position argument to // "dd4hep::Segmentation::cellID", we need the _local_ position and // only that. - const edm4hep::Vector3d& pos = sim_hit.getPosition(); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => the middle slice + DetElement refVol = volman.lookupDetElement(refID); + const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); + double lpos[3], lmom[3]; getLocalPosMom(sim_hit,toRefVol,lpos,lmom); + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; using dd4hep::mm; - Position gpos(pos.x * mm, pos.y * mm, pos.z * mm); - CellID vID = // Note: Only the bits corresponding to the volumeID will - // be used. The rest, encoding the segmentation stored in "sim_hit", - // being disregared. - sim_hit.getCellID(); - DetElement local = volman.lookupDetElement(vID); - const auto lpos = local.nominal().worldToLocal(gpos); + using edm4eic::unit::eV, edm4eic::unit::GeV; + // Hit in progress + double eDep = sim_hit.getEDep(), time = sim_hit.getTime(); + // ***** COALESCE ALL MUTUALLY CONSISTENT SUBHITS + // EXTEND TRAVERSING SUBHITS + // - Needed because we want to preserve the correlation between 'p' and + // 'n' strip hits resulting from a given I+A process (which is lost when + // one accumulates hits based on cellID). + std::vector same_idcs; + std::vector cIDs; + const auto &shape = refVol.solid(); + if (!strcmp(shape.type(),"TGeoTubeSeg")) { + // ********** TUBE GEOMETRY + const Tube &tRef = refVol.solid(); // REFERENCE SUBVOLUME + double dZ = tRef.dZ(); + // phi? + // In "https://root.cern.ch/root/html534/guides/users-guide/Geometry.html" + // TGeoTubeSeg: "phi1 is converted to [0,360] (but still expressed in + // radian, as far as I can tell) and phi2 > phi1." + // => Convert it to [-pi,+pi]. + double startPhi = tRef.startPhi()*radian; startPhi -= 2*TMath::Pi(); + double endPhi = tRef.endPhi()*radian; endPhi -= 2*TMath::Pi(); + // Get current SUBVOLUME + DetElement curVol = volman.lookupDetElement(vID); + const Tube &tCur = curVol.solid(); + double rMin = tCur.rMin(), rMax = tCur.rMax(); + // Is TRAVERSING? + double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); + unsigned int status = + cTraversing(lpos,lmom,sim_hit.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), + rMin,rMax,dZ,startPhi,endPhi, + lins,louts,lpini,lpend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); + continue; + } + cIDs.push_back(sim_hit.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(idx); + } + // Continuations. Particle may exit and then re-enter through "rMin". + bool isContinuation = status & 0x5; + bool hasContinuation = status & 0xa; + bool canReEnter = status & 0x100; int rank = m_stripRank(vID); + if (!canReEnter) { + if (rank == 0 && (status & 0x1)) isContinuation = false; + if (rank == 0 && (status & 0x2)) hasContinuation = false; + } + if (rank == 4 && (status & 0x4)) isContinuation = false; + if (rank == 4 && (status & 0x8)) hasContinuation = false; + if (hasContinuation) { + // ***** LOOP OVER HITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + for (jdx = idx+1, unbroken = 1; jdx<(int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + // Particle may start inward and re-enter, being then outward-going. + // => Orientation has to be evaluated w.r.t. previous vID. + int orientation = m_orientation(vIDPrv,vJD); + bool isUpstream = m_isUpstream(orientation,status); + bool pmoStatus = samePMO(sim_hit,sim_hjt,unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header,0,sim_hit.getCellID(),lpos,lmom)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // Get 'j' radii + curVol = volman.lookupDetElement(vJD); + const Tube &tubj = curVol.solid(); + rMin = tubj.rMin(); rMax = tubj.rMax(); + double lpoj[3], lmoj[3]; getLocalPosMom(sim_hjt,toRefVol,lpoj,lmoj); + // Is TRAVERSING through the (quasi-)common wall? + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = + cTraversing(lpoj,lmoj,sim_hjt.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), + rMin,rMax,dZ,startPhi,endPhi, + ljns,lovts,lpjni,lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header,status,sim_hjt.getCellID(),lpoj,lmoj)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation,status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) break; + else { // Allow for primary hits to not come in unbroken sequence + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double dist = outInDistance(0,orientation,ljns,louts,lmom,lmoj); + const double tolerance = 25*dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header,status,dist,sim_hit.getCellID(),lpos,lmom, + /* */ sim_hjt.getCellID(),lpoj,lmoj)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // ***** UPDATE + vIDPrv = vJD; eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(jdx); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + canReEnter = status & 0x100; + if (!canReEnter && m_stripRank(vJD) == 4) hasContinuation = false; + if (!hasContinuation) { jdx++; break; } + else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) idx = jdx-1; + } + // ***** EXTENSION?... + if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) + if (denyExtension(sim_hit,tCur.rMax()-tCur.rMin())) { + isContinuation=hasContinuation = false; + } + for (int io = 0; io<2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + status = extendHit(refID,direction,lpini,lmom,lpend,lmend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); + continue; + } + } + // ***** FLAG CASES W/ UNEXPECTED OUTCOME + flagUnexpected(header,0,(tRef.rMin()+tRef.rMax())/2, + sim_hit,lpini,lpend,lpos,lmom); + // ***** UPDATE (local position , DoF + double DoF2 = 0, dir = 0; for (int i = 0; i<3; i++) { + double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; lpos[i] = neu; + double d = neu-alt; dir += d*lmom[i]; DoF2 += d*d; + } + // Update time by ToF from original subHit to extended/COALESCED. + time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; + } + else if (!strcmp(shape.type(),"TGeoBBox")) { + // ********** BOX GEOMETRY + const Box &bRef = refVol.solid(); // REFERENCE SUBVOLUME + double dX = bRef.x(), dY = bRef.y(); + // Get current SUBVOLUME + DetElement curVol = volman.lookupDetElement(vID); + const Box &bCur = curVol.solid(); + double dZ = bCur.z(); + double ref2Cur = getRef2Cur(refVol,curVol); + // Is TRAVERSING? + double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); + unsigned int status = + bTraversing(lpos,lmom,ref2Cur,sim_hit.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), + dZ,dX,dY, + lins,louts,lpini,lpend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); + continue; + } + cIDs.push_back(sim_hit.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(idx); + } + // Continuations. + int rank = m_stripRank(vID); + bool isContinuation = status & 0x5; + bool hasContinuation = status & 0xa; + if ((rank == 0 && (status & 0x1)) || + (rank == 4 && (status & 0x4))) isContinuation = false; + if ((rank == 0 && (status & 0x2)) || + (rank == 4 && (status & 0x8))) hasContinuation = false; + if (hasContinuation) { + // ***** LOOP OVER SUBHITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + for (jdx = idx+1, unbroken = 1; jdx<(int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + int orientation = m_orientation(vIDPrv,vJD); + bool isUpstream = m_isUpstream(orientation,status); + bool pmoStatus = samePMO(sim_hit,sim_hjt,unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header,0,sim_hit.getCellID(),lpos,lmom)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // Get 'j' Z + curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME + const Box &boxj = curVol.solid(); + dZ = boxj.z(); + double ref2j = getRef2Cur(refVol,curVol); + // Is TRAVERSING through the (quasi)-common border? + double lpoj[3], lmoj[3]; getLocalPosMom(sim_hjt,toRefVol,lpoj,lmoj); + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = + bTraversing(lpoj,lmoj,ref2j,sim_hjt.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), + dZ,dX,dY, + ljns,lovts,lpjni,lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header,status,sim_hjt.getCellID(),lpoj,lmoj)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation,status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) break; + else { + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double zMin = -dZ-ref2j, zMax = dZ-ref2j; + double dist = outInDistance(1,orientation,ljns,louts,lmom,lmoj); + const double tolerance = 25*dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header,status,dist,sim_hit.getCellID(),lpos,lmom, + /* */ sim_hjt.getCellID(),lpoj,lmoj)); + if (unbroken) idx = jdx-1; unbroken = 0; continue; + } + // ***** UPDATE + vIDPrv = vJD; eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(jdx); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + if (!hasContinuation) { jdx++; break; } + else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) idx = jdx-1; + } + // ***** EXTENSION?... + if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) + if (denyExtension(sim_hit,bCur.z())) { + isContinuation=hasContinuation = false; + } + for (int io = 0; io<2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + status = extendHit(refID,direction,lpini,lmom,lpend,lmend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); + continue; + } + } + // ***** FLAG CASES W/ UNEXPECTED OUTCOME + flagUnexpected(header,1,0, + sim_hit,lpini,lpend,lpos,lmom); + // ***** UPDATE (local position , DoF) + double DoF2 = 0, dir = 0; for (int i = 0; i<3; i++) { + double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; lpos[i] = neu; + double d = neu-alt; dir += d*lmom[i]; DoF2 += d*d; + } + // Update time by ToF from original subHit to extended/COALESCED. + time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; + } + else { + critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", + refID,shape.type()); + throw JException("Bad input data: invalid geometry"); + + } + // ***** CELLIDS of (p|n)-STRIP HITS + Position locPos(lpos[0],lpos[1],lpos[2]); // Simplification: strip surface = REFERENCE surface // p "strip" - CellID stripBitp = ((CellID)0x1) << 30; - CellID vIDp = vID | stripBitp; - CellID cIDp = m_seg->cellID(lpos, dummy, vIDp); + CellID vIDp = refID | m_pStripBit; + CellID cIDp = m_seg->cellID(locPos, dummy, vIDp); // n "strip" - CellID stripBitn = ((CellID)0x2) << 30; - CellID vIDn = vID | stripBitn; - CellID cIDn = m_seg->cellID(lpos, dummy, vIDn); + CellID vIDn = refID | m_nStripBit; + CellID cIDn = m_seg->cellID(locPos, dummy, vIDn); + double result_time = time + time_smearing; + auto hit_time_stamp = (std::int32_t)(result_time * 1e3); - sim2IDs.emplace_back(cIDp, cIDn); // Remember cellIDs. // ***** DEBUGGING INFO if (level() >= algorithms::LogLevel::kDebug) { - CellID hIDp = cIDp >> 32; - CellID sIDp = cIDp >> 30 & 0x3; debug("--------------------"); - debug("Hit cellIDp = 0x{:08x}, 0x{:08x} 0x{:02x}", hIDp, vIDp, sIDp); - CellID hIDn = cIDn >> 32; - CellID sIDn = cIDn >> 30 & 0x3; - debug("Hit cellIDn = 0x{:08x}, 0x{:08x} 0x{:02x}", hIDn, vIDn, sIDn); - debug(" position = ({:.2f}, {:.2f}, {:.2f})", sim_hit.getPosition().x, - sim_hit.getPosition().y, sim_hit.getPosition().z); - debug(" xy_radius = {:.2f}", std::hypot(sim_hit.getPosition().x, sim_hit.getPosition().y)); - debug(" momentum = ({:.2f}, {:.2f}, {:.2f})", sim_hit.getMomentum().x, - sim_hit.getMomentum().y, sim_hit.getMomentum().z); - debug(" edep = {:.2f}", sim_hit.getEDep()); - debug(" time = {:.4f}[ns]", sim_hit.getTime()); + for (CellID cID : {cIDp,cIDn}) { + std::string sCellID = cID == cIDp ? "cellIDp" : "cellIDn"; + CellID hID = cID >> 32, vID = cID & m_volumeBits, sID = vID >> 28 & 0xff; + debug ("Hit {} = 0x{:08x}, 0x{:08x} 0x{:02x}", sCellID, hID, vID, sID); + Position stripPos = m_seg->position(cID); + Position globPos = refVol.nominal().localToWorld(stripPos); + debug (" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", globPos.X()/mm, globPos.Y()/mm, globPos.Z()/mm); + } + debug (" edep = {:.0f} [eV]", eDep / eV); + debug (" time = {:.2f} [ns]", time); #if EDM4HEP_BUILD_VERSION >= EDM4HEP_VERSION(0, 99, 0) - debug(" particle time = {}[ns]", sim_hit.getParticle().getTime()); + debug (" particle time = {} [ns]", sim_hit.getParticle().getTime()); #else - debug(" particle time = {}[ns]", sim_hit.getMCParticle().getTime()); + debug (" particle time = {} [ns]", sim_hit.getMCParticle().getTime()); #endif - debug(" time smearing: {:.4f}, resulting time = {:.4f} [ns]", time_smearing, result_time); - debug(" hit_time_stamp: {} [~ps]", hit_time_stamp); + debug (" time smearing: {:.2f}, resulting time = {:.2f} [ns]", time_smearing, result_time); + debug (" hit_time_stamp: {} [~ps]", hit_time_stamp); + for (int ldx = 0; ldx<(int)same_idcs.size(); ldx++) { + int jdx = same_idcs[ldx]; const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + CellID cIDk = sim_hjt.getCellID(); + CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; + debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx, hIDk, vIDk, sIDk); + debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hjt.getPosition().x/edmm, + sim_hjt.getPosition().y/edmm, sim_hjt.getPosition().z/edmm); + debug(" xy_radius = {:.2f}", std::hypot(sim_hjt.getPosition().x, sim_hjt.getPosition().y)/edmm); + debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hjt.getMomentum().x/GeV, + sim_hjt.getMomentum().y/GeV, sim_hjt.getMomentum().z/GeV); + debug(" edep = {:.0f} [eV]", sim_hjt.getEDep()/eV); + debug(" time = {:.2f} [ns]", sim_hjt.getTime()); + } } // ***** APPLY THRESHOLD - if (sim_hit.getEDep() < m_cfg.threshold) { + if (eDep < m_cfg.threshold) { debug(" edep is below threshold of {:.2f} [keV]", m_cfg.threshold / keV); continue; } // ***** HIT ACCUMULATION for (CellID cID : {cIDp, cIDn}) { + stripID2cIDs[cID] = cIDs; if (!cell_hit_map.contains(cID)) { // This cell doesn't have hits cell_hit_map[cID] = { - cID, (std::int32_t)std::llround(sim_hit.getEDep() * 1e6), + cID, (std::int32_t)std::llround(eDep * 1e6), hit_time_stamp // ns->ps }; } else { @@ -209,28 +647,745 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // sum deposited energy auto charge = hit.getCharge(); - hit.setCharge(charge + (std::int32_t)std::llround(sim_hit.getEDep() * 1e6)); + hit.setCharge(charge + (std::int32_t)std::llround(eDep * 1e6)); // TODO: accumulate charge: shouldn't it be float? } } } - // ***** raw_hit INSTANTIATION AND raw<-sim_hit's ASSOCIATION + // ***** raw_hit INSTANTIATION AND raw<-sim_hit's ASSOCIATION: for (auto item : cell_hit_map) { raw_hits->push_back(item.second); - auto sim_it = sim2IDs.cbegin(); - for (const auto& sim_hit : *sim_hits) { - CellIDs cIDs = *sim_it++; - for (CellID cID : {cIDs.first, cIDs.second}) { - if (item.first == cID) { - // set association - auto hitassoc = associations->create(); - hitassoc.setWeight(1.0); - hitassoc.setRawHit(item.second); - hitassoc.setSimHit(sim_hit); - } + CellID stripID = item.first; + const auto is = stripID2cIDs.find(stripID); + if (is == stripID2cIDs.end()) { + critical("Inconsistency: CellID {:x} not found in \"stripID2cIDs\" map", + stripID); + throw JException("Inconsistency in the handling of \"stripID2cIDs\" map"); + } + std::vector cIDs = is->second; + for (CellID cID : cIDs) { + for (const auto& sim_hit : *sim_hits) { + if (sim_hit.getCellID() == cID) { + // set association + auto hitassoc = associations->create(); + hitassoc.setWeight(1.0); + hitassoc.setRawHit(item.second); + hitassoc.setSimHit(sim_hit); + } + } + } + } +} + +void getLocalPosMom(const edm4hep::SimTrackerHit &sim_hit, + const TGeoHMatrix& toModule, + double *lpos, double *lmom) { + const edm4hep::Vector3d& pos = sim_hit.getPosition(); + // Length: Inputs are in EDM4eic units. Let's move to DD4hep units. + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; + const double gpos[3] = {pos.x*ed2dd, pos.y*ed2dd, pos.z*ed2dd}; + const edm4hep::Vector3f& mom = sim_hit.getMomentum(); + const double gmom[3] = {mom.x, mom.y, mom.z}; + toModule.MasterToLocal(gpos,lpos); + toModule.MasterToLocalVect(gmom,lmom); +} + +// ******************** TRAVERSING? +// Particle can be born/dead (then its position is not (entrance+exit)/2). +// Or it can exit through the edge. +// - Returned bit pattern: +// 0x1: Enters through lower wall +// 0x2: Exits through lower wall +// 0x4: Enters through upper wall +// 0x8: Exits through upper wall +// 0x100: Can reEnter (in a cylindrical volume) +// Also, for internal use: +// 0x10: Enters through edge +// 0x20: Exits through edge +// 0xff000: Inconsistency... +// - /: Positions @ lower/upper wall upon Enter-/Exit-ing (when endorsed by ) +// - /: Positions of extrema +// - Tolerance? For MIPs, a tolerance of 1 µM works fine. But for lower energy, +// looks like we need something somewhat larger. The ideal would be to base +// the value on Molière width. Here, I use a somewhat arbitrary, built-in, of +// 25 µm. +// - If particle found to reach wall, w/in tolerance, assign end points to +// walls (instead of +/-path/2). It will make so that the eventual +// extrapolated position falls exactly at mid-plane, even in the case of a +// low energy particle, where path may be affected by multiscattering. This, +// provided that particle is not a secondary. +unsigned int cTraversing(const double *lpos, const double *lmom, double path, bool isSecondary, // Input subHit + double rMin, double rMax, // Current instance of SUBVOLUME + double dZ, double startPhi, double endPhi, // Module parameters + double lins[][3], double louts[][3], + double *lpini, double *lpend) +{ + unsigned int status = 0; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx*Mx+My*My; + double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; + // Intersection w/ the edge in phi + double tIn = 0, tOut = 0; + for (double phi : {startPhi,endPhi}) { + // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); + double Ux = cos(phi), Uy = sin(phi); + double D = Px*Uy-Px*Ux; if (D) { // If P not // to U + double t = (My*Ux-Mx*Uy)/D; + double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey), Ez = Mz+t*Pz; + if (rMin < rE && rE < rMax && fabs(Ez) < dZ) { + if (t < 0) { status |= 0x10; tIn = t; } + else { status |= 0x20; tOut = t; } + } + } + } + // Intersection w/ the edge in Z + double zLow = -dZ, zUp = +dZ; for (double Z: {zLow,zUp}) { + // Mz+t*Pz = Z + if (Pz) { + double t = (Z-Mz)/Pz; + double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey); + double phi = atan2(Ey,Ex); + if (rMin < rE && rE < rMax && startPhi < phi && phi < endPhi) { + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= 0x10; tIn = t; + } + } + else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= 0x20; tOut = t; + } + } + } + } + } + // Intersection w/ tube walls + double ts[3/* rMin/rMax/edge */][2/* In/Out */] = {{0,0},{0,0},{tIn,tOut}}; // Up to two intersections + double a = Px*Px+Py*Py, b = Px*Mx+Py*My; + for (int lu = 0; lu < 2; lu++) { // rMin/rMax + double R; unsigned int statGene; + if (lu == 1) { R = rMax; statGene = 0x4; } + else { R = rMin; statGene = 0x1; } + double c = M2-R*R; + if (!a) { // P is // to Z. Yet no intersect w/ Z edge. + if ((status & 0x30) != 0x30) status |= 0x1000; continue; // Inconsistency + } + else if (!c) { // Hit is on wall: inconsistency. + status |= 0x2000; continue; + } + else { + double det = b*b-a*c; if (det < 0) { + if (lu == 1) { // No intersection w/ outer wall: inconsistency. + status |= 0x4000; continue; + } + } + else { + double sqdet = sqrt(det); + for (int is = 0; is<2; is++) { + int s = 1-2*is; double t = (-b+s*sqdet)/a; + double Ix = Mx+t*Px, Iy = My+t*Py, Iz = Mz+t*Pz, phi = atan2(Iy,Ix); + if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi) continue; + if (t < 0) { + // Two rMin intersects in same back/forward direction may happen + // (one and and only one of them may then be hidden by edge). + // => Have to allow wall intersect to coexist w/ edge intersect. + // This only for rMin, but for simplicity's sake... + if (status & statGene) { // Two <0 ts: can only happen when rMin + double tPrv = ts[lu][0]; if (t > tPrv) { + ts[lu][0] = t; ts[lu][1] = tPrv; // Current is actually IN, previous is OUT despite being <0 + } + status |= statGene<<1; + } + else { ts[lu][0] = t; status |= statGene; } + } + else { // (if t > 0) + if (status & statGene<<1) { // Two >0 ts: can only happen when rMin + double tPrv = ts[lu][1]; if (t < tPrv) { + ts[lu][1] = t; ts[lu][0] = tPrv; // Current is actually OUT, previous is IN despite being >0 + } + status |= statGene; + } + else { ts[lu][1] = t; status |= statGene<<1; } + } + } + } + } + } + // Combine w/ edge in/out, based on "t" + for (int lu = 0; lu < 2; lu++) { // rMin/rMax + unsigned int statGene = lu ? 0x4 : 0x1; + if (status & statGene) { + double t = ts[lu][0]; if (t < 0) { + if (status & 0x10) { + if (t < 0 && t > tIn) status |= 0x10000; + status &= ~statGene; + } + } + else { // if (t > 0) + if (status & 0x20) { + if (t > 0 && t < tOut) status |= 0x20000; + status &= ~statGene; + } + } + } + if (status & statGene<<1) { + double t = ts[lu][1]; if (t < 0) { + if (status & 0x10) { + if (t < 0 && t > tIn) status |= 0x40000; + status &= ~(statGene<<1); + } + } + else { // if (t > 0) + if (status & 0x20) { + if (t > 0 && t < tOut) status |= 0x80000; + status &= ~(statGene<<1); + } + } + } + } + // Is particle born/dead prior to entering/exiting? + // - sim_hit must have been assigned the mean position: (entrance+exit)/2 + // - Let's then check entrance/exit against sim_hit's position +/- path/2. + // When the latter is too short, it means that the particle firing the + // hit gets born or dies in the SUBVOLUME. + // => We remove the corresponding bit in the pattern. + // - Note that we not only require that the path be long enough, but also + // that it matches exactly distances to entrance/exit. + bool isReEntering = (status & 0x3) == 0x3; + if (isReEntering) status |= 0x100; // Remember that particle can re-enter. + double norm = sqrt(a+Pz*Pz), at = path/2/norm; + unsigned int statws = 0; + for (int is = 0; is < 2; is++) { + int s = 1-2*is; double Ix = s*at*Px, Iy = s*at*Py, Iz = s*at*Pz; + for (int lu = 0; lu < 2; lu++) { // Lower/upper wall + unsigned int statvs = lu ? 0x4 : 0x1; + for (int io = 0; io<2; io++) { + statvs <<= io; if (status & statvs) { + double t = ts[lu][io]; if (t*s < 0) continue; + double dIx = t*Px-Ix, dIy = t*Py-Iy, dIz = t*Pz-Iz; + double dist = sqrt(dIx*dIx+dIy*dIy+dIz*dIz); + const double tolerance = 20*dd4hep::um; + if (dist < tolerance) statws |= statvs; + } + } + } + } + if (!(statws & 0x5)) /* No entrance */ status &= ~0x5; + if (!(statws & 0xa)) /* No exit */ status &= ~0xa; + // ***** End points + // Assign end points to walls, if not a secondary and provided it's not a + // reEntrance case, which case is more difficult to handle and we leave aside. + if (((status & 0x5) == 0x1 || (status & 0x5) == 0x4) && !isSecondary) { + double tIn = (status & 0x1) ? ts[0][0] : ts[1][0]; + lpini[0] = Mx+tIn*Px; lpini[1] = My+tIn*Py; lpini[2] = Mz+tIn*Pz; + } + else { + lpini[0] = Mx-at*Px; lpini[1] = My-at*Py; lpini[2] = Mz-at*Pz; + } + if (((status & 0xa) == 0x2 || (status & 0xa) == 0x8) && !isSecondary) { + double tOut = (status & 0x2) ? ts[0][1] : ts[1][1]; + lpend[0] = Mx+tOut*Px; lpend[1] = My+tOut*Py; lpend[2] = Mz+tOut*Pz; + } + else { + lpend[0] = Mx+at*Px; lpend[1] = My+at*Py; lpend[2] = Mz+at*Pz; + } + // End points when on the walls + for (int lu = 0; lu < 2; lu++) { + unsigned int statvs = lu ? 0x4 : 0x1; + double tIn = ts[lu][0], tOut = ts[lu][1]; + if (status & statvs) { + lins [lu][0] = Mx+tIn* Px; lins [lu][1] = My+tIn* Py; lins [lu][2] = Mz+tIn* Pz; + } + statvs <<= 1; + if (status & statvs) { + louts[lu][0] = Mx+tOut*Px; louts[lu][1] = My+tOut*Py; louts[lu][2] = Mz+tOut*Pz; + } + } + return status; +} +unsigned int bTraversing(const double *lpos, const double *lmom, double ref2Cur, double path, bool isSecondary, // Input subHit + double dZ, // Current instance of SUBVOLUME + double dX, double dY, // Module parameters + double lins[][3], double louts[][3], + double *lpini, double *lpend) +{ + unsigned int status = 0; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx,My}, M2 = Mx*Mx+My*My; + double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px,Py}; + double Mz = lpos[2]+ref2Cur, Pz = lmom[2]; + // Intersection w/ the edge in X,Y + double tIn = 0, tOut = 0; + double xyLow[2] = {-dX,+dX}, xyUp[2] = {-dY,+dY}; + for (int xy = 0; xy < 2; xy++) { + int yx = 1-xy; + double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; + double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; + for (double A: {aLow,aUp}) { + // Mz+t*Pz = A + if (Pa) { + double t = (A-Mz)/Pa; + double Eb = Mb+t*Pb, Ez = Mz+t*Pz; + if (bLow < Eb && Eb < bUp && fabs(Ez) < dZ) { + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= 0x10; tIn = t; + } + } + else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= 0x20; tOut = t; + } + } + } + } + } + } + if (status) { + printf("DEBUG: Edge 0x%x\n",status); + } + // Intersection w/ box walls + for (int lu = 0; lu < 2; lu++) { + int s = 2*lu-1; double Z = s*dZ; unsigned int statGene = lu ? 0x4 : 0x1; + // Mz+t*Pz = Z + if (Pz) { + double t = (Z-Mz)/Pz; + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= statGene; tIn = t; + } + } + else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= statGene<<1; tOut = t; + } } } } + // Is particle born/dead prior to entering/exiting? + // - sim_hit must have been assigned the mean position: (entrance+exit)/2 + // - Let's then check entrance/exit against sim_hit's position +/- path/2. + // When the latter is too short, it means that the particle firing the + // hit gets born or dies in the SUBVOLUME. + // => We remove the corresponding bit in the pattern. + // - Note that we not only require that the path be long enough, but also + // that it matches exactly distances to entrance/exit. + double norm = sqrt(Px*Px+Py*Py+Pz*Pz), at = path/2/norm; + unsigned int statws = 0; + for (int is = 0; is < 2; is++) { + int s = 1-2*is; double Ix = s*at*Px, Iy = s*at*Py, Iz = s*at*Pz; + for (int lu = 0; lu < 2; lu++) { // Lower/upper wall + unsigned int statvs = lu ? 0x4 : 0x1; + for (int io = 0; io<2; io++) { + statvs <<= io; if (status & statvs) { + double t = io ? tOut : tIn; if (t*s < 0) continue; + double dIx = t*Px-Ix, dIy = t*Py-Iy, dIz = t*Pz-Iz; + double dist = sqrt(dIx*dIx+dIy*dIy+dIz*dIz); + const double tolerance = 20*dd4hep::um; + if (dist < tolerance) statws |= statvs; + } + } + } + } + if (!(statws & 0x5)) /* No entrance */ status &= ~0x5; + if (!(statws & 0xa)) /* No exit */ status &= ~0xa; + // ***** OUTPUT POSITIONS + Mz -= ref2Cur; // Go back to REFERENCE SUBVOLUME + // End points: + // Assign end points to walls, if not a secondary. + if ((status & 0x5) && !isSecondary) { + lpini[0] = Mx+tIn*Px; lpini[1] = My+tIn*Py; lpini[2] = Mz+tIn*Pz; + } + else { + lpini[0] = Mx-at*Px; lpini[1] = My-at*Py; lpini[2] = Mz-at*Pz; + } + if ((status & 0xa) && !isSecondary) { + lpend[0] = Mx+tOut*Px; lpend[1] = My+tOut*Py; lpend[2] = Mz+tOut*Pz; + } + else { + lpend[0] = Mx+at*Px; lpend[1] = My+at*Py; lpend[2] = Mz+at*Pz; + } + // End points when on the walls: + for (int lu = 0; lu < 2; lu++) { + unsigned int statvs = lu ? 0x4 : 0x1; + if (status & statvs) { + lins [lu][0] = Mx+tIn* Px; lins [lu][1] = My+tIn* Py; lins [lu][2] = Mz+tIn* Pz; + } + statvs <<= 1; + if (status & statvs) { + louts[lu][0] = Mx+tOut*Px; louts[lu][1] = My+tOut*Py; louts[lu][2] = Mz+tOut*Pz; + } + } + return status; +} + +// ***** EXTRAPOLATE +bool cExtrapolate(const double *lpos, const double *lmom, // Input subHit + double rT, // Target radius + double *lext) // Extrapolated position @ +{ + bool ok = false; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx*Mx+My*My; + double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; + double a = Px*Px+Py*Py, b = Px*Mx+Py*My, c = M2-rT*rT; + double tF = 0; + if (!c) ok = true; + else if (a) { // P is not // to Z + double det = b*b-a*c; if (det >= 0) { + double sqdet = sqrt(det); + for (int is = 0; is<2; is++) { + int s = 1-2*is; double t = (-b+s*sqdet)/a; if (t < 0) continue; + if (!ok || + // Two intersects: let's retain the earliest one. + (ok && fabs(t) < fabs(tF))) { + tF = t; ok = true; + } + } + } + } + if (ok) { + lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + } + return ok; +} +bool bExtrapolate(const double *lpos, const double *lmom, // Input subHit + double zT, // Target Z + double *lext) // Extrapolated position @ +{ + bool ok = false; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2]; + double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; + double tF = 0; + if (Pz) { + tF = (zT-Mz)/Pz; ok = tF > 0; + } + if (ok) { + lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + } + return ok; +} + +// ***** EXTENSION +// At variance to EXTRAPOLATION, we take edges (phi,Z/X,Y) into account. +// - Returns 0x1 if +// - there is an extrapolation between position and target, +// - within edge limits, +// - along momentum , +// - in direction . +// - Returns something in the 0xff000: Inconsistency... +// - contains the position of farthest extension. +unsigned int MPGDTrackerDigi::cExtension(double const *lpos, double const *lmom, // Input subHit + double rT, // Target radius + int direction, + double dZ, double startPhi, double endPhi, // Module parameters + double *lext) const +{ + unsigned int status = 0; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2]; + double Px = lmom[0], Py = lmom[1], Pz = lmom[2], norm = sqrt(Px*Px+Py*Py+Pz*Pz); + // Move some distance away from , which is expected to be sitting on + // the wall of the SUBVOLUME to be ``extended''. + const double margin = 10*dd4hep::um; + double t = direction*margin/norm; Mx += t*Px; My += t*Py; Mz += t*Pz; + double M2 = Mx*Mx+My*My, rIni = sqrt(M2), rLow, rUp; + if (rIni < rT) { rLow = rIni; rUp = rT; } + else { rLow = rT; rUp = rIni; } + // Intersection w/ the edge in phi + double tF = 0; + for (double phi : {startPhi,endPhi}) { + // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); + double Ux = cos(phi), Uy = sin(phi); + double D = Px*Uy-Px*Ux; if (D) { // If P not // to U + double t = (My*Ux-Mx*Uy)/D; if (t*direction < 0) continue; + double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey), Ez = Mz+t*Pz; + if (rLow < rE && rE < rUp && fabs(Ez) < dZ) { status |= 0x1; tF = t; } + } + } + // Intersection w/ the edge in Z + double zLow = -dZ, zUp = +dZ; for (double Z: {zLow,zUp}) { + // Mz+t*Pz = Z + if (Pz) { + double t = (Z-Mz)/Pz; if (t*direction < 0) continue; + double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey); + double phi = atan2(Ey,Ex); + if (rLow < rE && rE < rUp && startPhi < phi && phi < endPhi) { + if (t < 0) { + if (!status || (status && t > tF)) { status |= 0x1; tF = t; } + } + else if (t > 0) { + if (!status || (status && t < tF)) { status |= 0x1; tF = t; } + } + } + } + } + // Else intersection w/ target radius + if (!status) { + double a = Px*Px+Py*Py, b = Px*Mx+Py*My, c = M2-rT*rT; + if (!a) { // P is // to Z + if (!status) status |= 0x1000; // Inconsistency + } + else if (!c) { // Hit is on target + status |= 0x2000; // Inconsistency + } + else { + double det = b*b-a*c; if (det >= 0) { + double sqdet = sqrt(det); + for (int is = 0; is<2; is++) { + int s = 1-2*is; double t = (-b+s*sqdet)/a; if (t*direction < 0) continue; + double Ix = Mx+t*Px, Iy = My+t*Py, Iz = Mz+t*Pz, phi = atan2(Iy,Ix); + if (fabs(Iz) > dZ && phi < startPhi || endPhi < phi) continue; + if (!(status & 0x1) || + // Two intersects: let's retain the earliest one. + ((status & 0x1) && fabs(t) < fabs(tF))) { + tF = t; status |= 0x1; + } + } + } + } + } + if (status) { + lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + } + return status; +} +unsigned int MPGDTrackerDigi::bExtension(const double *lpos, const double *lmom, // Input subHit + double zT, // Target Z + int direction, + double dX, double dY, // Module parameters + double *lext) const +{ + unsigned int status = 0; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx,My}, M2 = Mx*Mx+My*My; + double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px,Py}; + double Mz = lpos[2], Pz = lmom[2]; + double norm = sqrt(Px*Px+Py*Py+Pz*Pz); + // Move some distance away from , which is expected to be sitting on + // the wall of the SUBVOLUME to be ``extended''. + const double margin = 10*dd4hep::um; + double t = direction*margin/norm; Mx += t*Px; My += t*Py; Mz += t*Pz; + double &zIni = Mz, zLow, zUp; + if (zIni < zT) { zLow = zIni; zUp = zT; } + else { zLow = zT; zUp = zIni; } + // Intersection w/ the edge in X,Y + double tF = 0; + double xyLow[2] = {-dX,+dX}, xyUp[2] = {-dY,+dY}; + for (int xy = 0; xy < 2; xy++) { + int yx = 1-xy; + double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; + double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; + for (double A: {aLow,aUp}) { + // Mz+t*Pz = A + if (Pa) { + double t = (A-Mz)/Pa; if (t*direction < 0) continue; + double Eb = Mb+t*Pb, Ez = Mz+t*Pz; + if (zLow < Ez && Ez < zUp && bLow < Eb && Eb < bUp) { + if (!status || (status && fabs(t) < fabs(tF))) { + status |= 0x1; tF = t; + } + } + } + } + } + // Else intersection w/ target Z + if (!status) { + if (Pz) { + tF = (zT-Mz)/Pz; if (tF*direction > 0) status = 0x1; + } + } + if (status) { + lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + } + return status; +} + +double getRef2Cur(DetElement refVol, DetElement curVol) +{ + const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); + const TGeoHMatrix& toCurVol = curVol.nominal().worldTransformation(); + const double *TRef = toRefVol.GetTranslation(); + const double *TCur = toCurVol.GetTranslation(); + // For some reason, it has to be "Ref-Cur", while I (Y.B) would have expected the opposite... + double gdT[3]; for (int i = 0; i < 3; i++) gdT[i] = TRef[i]-TCur[i]; + double ldT[3]; toRefVol.MasterToLocalVect(gdT,ldT); + return ldT[2]; +} + +std::string inconsistency(const edm4hep::EventHeader &event, unsigned int status, + CellID cID, const double *lpos, const double *lmom) +{ + using edm4eic::unit::GeV, dd4hep::mm; + return fmt::format("Event {}#{}, SimHit 0x{:016x} @ {:.2f},{:.2f},{:.2f} mm, P = {:.2f},{:.2f},{:.2f} GeV inconsistency 0x{:x}", + event.getRunNumber(),event.getEventNumber(), + cID, lpos[0]/mm, lpos[1]/mm, lpos[2]/mm, + lmom[0]/GeV, lmom[1]/GeV, lmom[2]/GeV, status); +} +std::string oddity(const edm4hep::EventHeader &event, unsigned int status, double dist, + CellID cID, const double *lpos, const double *lmom, + CellID cJD, const double *lpoj, const double *lmoj) +{ + using edm4eic::unit::GeV, dd4hep::mm; + return fmt::format("Event {}#{}, Bizarre SimHit sequence: 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = {:.2f},{:.2f},{:.2f} GeV and 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = {:.2f},{:.2f},{:.2f} GeV: status 0x{:x}, distance {:.4f}", + event.getRunNumber(),event.getEventNumber(), + cID, lpos[0]/mm, lpos[1]/mm, lpos[2]/mm, + lmom[0]/GeV, lmom[1]/GeV, lmom[2]/GeV, + cJD, lpoj[0]/mm, lpoj[1]/mm, lpoj[2]/mm, + lmoj[0]/GeV, lmoj[1]/GeV, lmoj[2]/GeV, + status,dist); +} + +bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, + const edm4hep::SimTrackerHit& sim_hjt, + int unbroken) const +{ + // Status: + // 0: Same Particle, same Module, same Origin + // 0x1: Not same + // Particle + using MCParticle = edm4hep::MCParticle; +#if EDM4HEP_BUILD_VERSION >= EDM4HEP_VERSION(0, 99, 0) + bool sameParticle = sim_hjt.getParticle() == sim_hit.getParticle(); +#else + bool sameParticle = sim_hjt.getMCParticle() == sim_hit.getMCParticle(); +#endif + // Module + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => the middle slice + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + CellID refJD = vJD & m_moduleBits; // => the middle slice + bool sameModule = refJD == refID; + // Origin + // Note: edm4hep::SimTrackerHit possesses an "Overlay" quality. Since I don't + // know what this is, I ignore it. + bool isSecondary = sim_hit.isProducedBySecondary(); + bool jsSecondary = sim_hjt.isProducedBySecondary(); + bool sameOrigin = jsSecondary == isSecondary; + if (isSecondary) { // Secondary subHit + // A given primary particle can give rise to several secondaries, producing + // unrelated subHits that we do not want to mix. + // => Let's impose more condition in that case... + sameOrigin &= unbroken; // ...Unbroken sequence of subHits + } + return sameParticle && sameModule && sameOrigin; +} + +double outInDistance(int shape, int orientation, + double lins[][3], double louts[][3], + double *lmom, double *lmoj) +{ + // Outgoing/incoming distance + bool ok; double lext[3]; + double lmOI[3]; for (int i = 0; i < 3; i++) lmOI[i] = (lmom[i]+lmoj[i])/2; + double *lOut, *lIn; + if (orientation > 0) { lOut = louts[1]; lIn = lins[0]; } + else if (orientation < 0) { lOut = louts[0]; lIn = lins[1]; } + else { lOut = louts[0]; lIn = lins[0]; } + if (shape == 0) { // "TGeoTubeSeg" + double rIn = sqrt(lIn [0]*lIn [0]+lIn [1]*lIn [1]); + ok = cExtrapolate(lOut,lmOI,rIn,lext); + } + else { // "TGeoBBox" + ok = bExtrapolate(lOut,lmOI,lIn[2],lext); + } + if (ok) { + double dist2 = 0; for (int i = 0; i < 3; i++) { + double d = lext[i]-lIn[i]; dist2 += d*d; + } + return sqrt(dist2); + } + else + return -1; +} + +unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, + double *lpini, double *lmini, double *lpend, double *lmend) const +{ + unsigned int status = 0; + const VolumeManager& volman = m_detector->volumeManager(); + DetElement refVol = volman.lookupDetElement(refID); + const auto &shape = refVol.solid(); + double *lpoE, *lmoE; // Starting position/momentum + if (direction < 0) { lpoE = lpini; lmoE = lmini; } + else { lpoE = lpend; lmoE = lmend; } + // Let's test both extremes of the SUBVOLUMES, in order to catch cases where + // particle re-enters. + for (int rankE : {0,4}) { + CellID vIDE = refID | m_stripIDs[rankE]; + DetElement volE = volman.lookupDetElement(vIDE); + double lext[3]; + if (!strcmp(shape.type(),"TGeoTubeSeg")) { + const Tube &tubE = volE.solid(); + double R = rankE == 0 ? tubE.rMin() : tubE.rMax(); + double startPhi = tubE.startPhi()*radian; startPhi -= 2*TMath::Pi(); + double endPhi = tubE.endPhi()*radian; endPhi -= 2*TMath::Pi(); + double dZ = tubE.dZ(); + status = cExtension(lpoE,lmoE,R,direction,dZ,startPhi,endPhi,lext); + } + else if (!strcmp(shape.type(),"TGeoBBox")) { + const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); + double ref2E = getRef2Cur(refVol,volE); + const Box &boxE = volE.solid(); + double Z = rankE == 0 ? -boxE.z() : +boxE.z(); Z -= ref2E; + double dX = boxE.x(), dY = boxE.y(); + status = bExtension(lpoE,lmoE,Z,direction,dX,dY,lext); + } + else status = 0x10000; + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + return status; + } + if (status != 0x1) continue; + if (direction < 0) { + for (int i = 0; i < 3; i++) lpini[i] = lext[i]; + } + else { + for (int i = 0; i < 3; i++) lpend[i] = lext[i]; + } + break; + } + return status; +} + +bool MPGDTrackerDigi::denyExtension(const edm4hep::SimTrackerHit &sim_hit, + double depth) const +{ + // Non COALESCED secondary: do not extend... + // ...if in HELPER SUBVOLUME: if it is TRAVERSING, it's probably + // merely because SUBVOLUME is very thin. + CellID vID = sim_hit.getCellID() & m_volumeBits; + bool isHelperVolume = m_stripRank(vID) != 0 && m_stripRank(vID) != 4; + // ...else if path length is negligible compared to potential + // extension (here, we cannot avoid using a built-in: 10%). + const double fraction = .10; + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; + bool smallPathLength = sim_hit.getPathLength()*ed2dd < fraction * depth; + return isHelperVolume || smallPathLength; +} + +void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader &event, + int shape, double expected, + const edm4hep::SimTrackerHit &sim_hit, + double *lpini, double *lpend, + double *lpos, double *lmom) const +{ + // Expectation: + // - Primary particle: position = middle of overall sensitive volume. + // - Secondary particle: no diff w.r.t. initial. + // N.B: At times, when, supposedly, delta ray is created w/in SUBVOLUME, path + // of primary does not span the whole volume. The present, simplistic, + // version of "flagUnexpected" does flag the case. This, even though + // everything is perfectly under control. + double Rnew2 = 0, Znew, diff2 = 0; for (int i = 0; i<3; i++) { + double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; + double d = neu-alt; diff2 += d*d; + if (i != 2) Rnew2 += neu*neu; + if (i == 2) Znew = neu; + } + double found = shape ? Znew : sqrt(Rnew2), residual = found-expected; + bool isSecondary = sim_hit.isProducedBySecondary(); + bool isPrimary = !isSecondary && sqrt(lmom[0]*lmom[0]+lmom[1]*lmom[1]+lmom[2]*lmom[2]) > .1*GeV; + if (fabs(residual) > .000001 && isPrimary || + sqrt(diff2) > .000001 && isSecondary) { + debug("Event {}#{}, SimHit 0x{:016x} origin {:d}: d{:x} = {:.5f} diff = {:.5f}", + event.getRunNumber(),event.getEventNumber(), + sim_hit.getCellID(),shape?'Z':'R',isSecondary,residual,sqrt(diff2)); + } } } // namespace eicrecon diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 5c5005dc3a..acb903d701 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -10,6 +10,10 @@ #include #include #include +//#define MC_PARTICLE_ASSOCIATION +#ifdef MC_PARTICLE_ASSOCIATION +# include +#endif #include #include @@ -20,7 +24,11 @@ namespace eicrecon { using MPGDTrackerDigiAlgorithm = algorithms::Algorithm< +#ifdef MC_PARTICLE_ASSOCIATION + algorithms::Input, +#else algorithms::Input, +#endif algorithms::Output>; @@ -42,9 +50,48 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, private: const algorithms::UniqueIDGenSvc& m_uid = algorithms::UniqueIDGenSvc::instance(); + // Member methods for checking the consistency of subHits to be accumulated + unsigned int extendHit(dd4hep::CellID modID, int direction, + double *lpini, double *lmini, double *lpend, double *lmend) const; + unsigned int cExtension(double const *lpos, double const *lmom, // Input subHit + double rT, // Target radius + int direction, + double dZ, double startPhi, double endPhi, // Module parameters + double *lext) const; + unsigned int bExtension(const double *lpos, const double *lmom, // Input subHit + double zT, // Target Z + int direction, + double dX, double dY, // Module parameters + double *lext) const; + bool samePMO(const edm4hep::SimTrackerHit&, + const edm4hep::SimTrackerHit&, + int unbroken) const; + bool denyExtension(const edm4hep::SimTrackerHit &sim_hit, + double depth) const; + void flagUnexpected(const edm4hep::EventHeader &event, + int shape, double expected, + const edm4hep::SimTrackerHit &sim_hit, + double *lpini, double *lpend, + double *lpos, double *lmom) const; + /** Segmentation */ const dd4hep::Detector* m_detector{nullptr}; dd4hep::Segmentation m_seg; + // Built-in constants specifying IDDescriptor fields. + // The "init" should method double-check these are actually implemented in the XMLs of MPGDs. + static constexpr dd4hep::CellID m_volumeBits = 0xffffffff; // 32 least weight bits + static constexpr dd4hep::CellID m_stripBits = ((dd4hep::CellID)0xf)<<28; + static constexpr dd4hep::CellID m_stripMask = ~m_stripBits; + static constexpr dd4hep::CellID m_moduleBits = m_volumeBits & m_stripMask; + static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1)<<28; + static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2)<<28; + static constexpr dd4hep::CellID m_stripIDs[5] = + { ((dd4hep::CellID)0x3)<<28, m_pStripBit, 0, m_nStripBit, ((dd4hep::CellID)0x4)<<28 }; + /** Ordering of Multiple Sensitive Volumes */ + std::function m_stripRank; + std::function m_orientation; + std::function m_isUpstream; + std::function m_isDownstream; }; } // namespace eicrecon From 7cc9f5771183754c1040fa0486ef94649b54eeb6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:58:37 +0000 Subject: [PATCH 02/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 1630 +++++++++++++----------- src/algorithms/digi/MPGDTrackerDigi.h | 65 +- 2 files changed, 939 insertions(+), 756 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 363bbdc7b0..2cc8edd0fe 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -13,7 +13,7 @@ - Present solution is based on multiple sensitive SUBVOLUMES. FIVE of them: + TWO persistent ones, acting as READOUT SURFACES (i.e. to which raw hits are assigned, in both RealData and MC): very thin and sitting very close - to mid-plane, + to mid-plane, + THREE HELPER ones: TWO RADIATORS, thick, serving temporarily to collect energy deposit and ONE REFERENCE, thin and sitting exactly at mid-plane. (The REFERENCE is not essential, but found to help rationalize the source @@ -130,7 +130,7 @@ namespace eicrecon { void MPGDTrackerDigi::init() { // Access id decoder - m_detector = algorithms::GeoSvc::instance().detector(); + m_detector = algorithms::GeoSvc::instance().detector(); const dd4hep::BitFieldCoder* m_id_dec = nullptr; if (m_cfg.readout.empty()) { @@ -157,67 +157,67 @@ void MPGDTrackerDigi::init() { int rank; CellID sID = vID & m_stripBits; for (rank = 0; rank < 5; rank++) - if (sID == m_stripIDs[rank]) return rank; + if (sID == m_stripIDs[rank]) + return rank; return -1; }; m_orientation = [=](CellID vID, CellID vJD) { int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); - if (rankj > ranki) return +1; - else if (rankj < ranki) return -1; - else return 0; + if (rankj > ranki) + return +1; + else if (rankj < ranki) + return -1; + else + return 0; }; - m_isUpstream = [](int orientation, unsigned int status) { + m_isUpstream = [](int orientation, unsigned int status) { // Outgoing particle exits... bool isUpstream = - (orientation < 0 && (status & 0x2)) || // ...lower wall - (orientation > 0 && (status & 0x8)) || // ...upper wall - (orientation == 0 && (status & 0x102) == 0x102); // ...lower wall and can reEnter + (orientation < 0 && (status & 0x2)) || // ...lower wall + (orientation > 0 && (status & 0x8)) || // ...upper wall + (orientation == 0 && (status & 0x102) == 0x102); // ...lower wall and can reEnter return isUpstream; }; m_isDownstream = [](int orientation, unsigned int status) { // Incoming particle enters... bool isDownstream = - (orientation > 0 && (status & 0x1)) || // ...lower wall - (orientation < 0 && (status & 0x4)) || // ...upper wall - (orientation == 0 && (status & 0101) == 0x101); // ...lower wall and can be reEntering + (orientation > 0 && (status & 0x1)) || // ...lower wall + (orientation < 0 && (status & 0x4)) || // ...upper wall + (orientation == 0 && (status & 0101) == 0x101); // ...lower wall and can be reEntering return isDownstream; }; } // Interfaces -void getLocalPosMom(const edm4hep::SimTrackerHit &sim_hit, - const TGeoHMatrix& toModule, - double *lpos, double *lmom); -unsigned int cTraversing(const double *lpos, const double *lmom, double path, bool isSecondary, // Input subHit - double rMin, double rMax, // Current instance of SUBVOLUME - double dZ, double startPhi, double endPhi, // Module parameters - double lins[][3], double louts[][3], - double *lpini, double *lpend); -bool cExtrapolate(const double *lpos, const double *lmom, // Input subHit - double rT, // Target radius - double *lext); // Extrapolated position @ +void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& toModule, + double* lpos, double* lmom); +unsigned int cTraversing(const double* lpos, const double* lmom, double path, + bool isSecondary, // Input subHit + double rMin, double rMax, // Current instance of SUBVOLUME + double dZ, double startPhi, double endPhi, // Module parameters + double lins[][3], double louts[][3], double* lpini, double* lpend); +bool cExtrapolate(const double* lpos, const double* lmom, // Input subHit + double rT, // Target radius + double* lext); // Extrapolated position @ double getRef2Cur(DetElement refVol, DetElement curVol); -unsigned int bTraversing(const double *lpos, const double *lmom, double ref2Cur, double path, bool isSecondary, // Input subHit - double dZ, // Current instance of SUBVOLUME - double dX, double dY, // Module parameters - double lins[][3], double louts[][3], - double *lpini, double *lpend); -bool bExtrapolate(const double *lpos, const double *lmom, // Input subHit - double zT, // Target Z - double *lext); // Extrapolated position @ -std::string inconsistency(const edm4hep::EventHeader &event, unsigned int status, - CellID cID, const double *lpos, const double *lmom); -std::string oddity(const edm4hep::EventHeader &event, unsigned int status, double dist, - CellID cID, const double *lpos, const double *lmom, - CellID cJD, const double *lpoj, const double *lmoj); -double outInDistance(int shape, int orientation, - double lins[][3], double louts[][3], - double *lmom, double *lmoj); -void flagUnexpected(const edm4hep::EventHeader &event, - int shape, double expected, - const edm4hep::SimTrackerHit &sim_hit, - double *lpini, double *lpend, - double *lpos, double *lmom); +unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double path, + bool isSecondary, // Input subHit + double dZ, // Current instance of SUBVOLUME + double dX, double dY, // Module parameters + double lins[][3], double louts[][3], double* lpini, double* lpend); +bool bExtrapolate(const double* lpos, const double* lmom, // Input subHit + double zT, // Target Z + double* lext); // Extrapolated position @ +std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status, CellID cID, + const double* lpos, const double* lmom); +std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID, + const double* lpos, const double* lmom, CellID cJD, const double* lpoj, + const double* lmoj); +double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, + double* lmoj); +void flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected, + const edm4hep::SimTrackerHit& sim_hit, double* lpini, double* lpend, + double* lpos, double* lmom); void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, const MPGDTrackerDigi::Output& output) const { @@ -229,7 +229,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, auto seed = m_uid.getUniqueID(*headers, name()); std::default_random_engine generator(seed); std::normal_distribution gaussian; - + // A map of unique cellIDs with temporary structure RawHit std::unordered_map cell_hit_map; // A map of strip cellIDs with vector of contributing cellIDs @@ -241,11 +241,11 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // Reference to event, to be used to document "critical" error messages // (N.B.: I don't know how to properly handle these "headers": may there // be ore than one? none?...) - const edm4hep::EventHeader &header = headers->at(0); + const edm4hep::EventHeader& header = headers->at(0); std::vector usedHits; size_t sim_size = sim_hits->size(); - for (int idx = 0; idx<(int)sim_size; idx++) { + for (int idx = 0; idx < (int)sim_size; idx++) { const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); // ***** TIME SMEARING @@ -257,12 +257,18 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, double time_smearing = gaussian(generator) * m_cfg.timeResolution; // ***** USED HIT? - int usedHit = 0; for (int jdx : usedHits) { - if (jdx == idx) { usedHit = 1; break; } + int usedHit = 0; + for (int jdx : usedHits) { + if (jdx == idx) { + usedHit = 1; + break; + } } - if (usedHit) continue; - else usedHits.push_back(idx); // useful?... - + if (usedHit) + continue; + else + usedHits.push_back(idx); // useful?... + // ***** SEGMENTATION // - The two cellIDs are encoded via a "dd4hep::MultiSegmentation" // discriminating on the strip field, w/ "strip" setting of 0x1 ( @@ -276,12 +282,13 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // "CyMBaL") disregard the _global_ position argument to // "dd4hep::Segmentation::cellID", we need the _local_ position and // only that. - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => the middle slice - DetElement refVol = volman.lookupDetElement(refID); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => the middle slice + DetElement refVol = volman.lookupDetElement(refID); const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); - double lpos[3], lmom[3]; getLocalPosMom(sim_hit,toRefVol,lpos,lmom); - const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; + double lpos[3], lmom[3]; + getLocalPosMom(sim_hit, toRefVol, lpos, lmom); + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; using dd4hep::mm; using edm4eic::unit::eV, edm4eic::unit::GeV; // Hit in progress @@ -293,332 +300,382 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // one accumulates hits based on cellID). std::vector same_idcs; std::vector cIDs; - const auto &shape = refVol.solid(); - if (!strcmp(shape.type(),"TGeoTubeSeg")) { + const auto& shape = refVol.solid(); + if (!strcmp(shape.type(), "TGeoTubeSeg")) { // ********** TUBE GEOMETRY - const Tube &tRef = refVol.solid(); // REFERENCE SUBVOLUME - double dZ = tRef.dZ(); + const Tube& tRef = refVol.solid(); // REFERENCE SUBVOLUME + double dZ = tRef.dZ(); // phi? // In "https://root.cern.ch/root/html534/guides/users-guide/Geometry.html" // TGeoTubeSeg: "phi1 is converted to [0,360] (but still expressed in // radian, as far as I can tell) and phi2 > phi1." // => Convert it to [-pi,+pi]. - double startPhi = tRef.startPhi()*radian; startPhi -= 2*TMath::Pi(); - double endPhi = tRef.endPhi()*radian; endPhi -= 2*TMath::Pi(); + double startPhi = tRef.startPhi() * radian; + startPhi -= 2 * TMath::Pi(); + double endPhi = tRef.endPhi() * radian; + endPhi -= 2 * TMath::Pi(); // Get current SUBVOLUME DetElement curVol = volman.lookupDetElement(vID); - const Tube &tCur = curVol.solid(); + const Tube& tCur = curVol.solid(); double rMin = tCur.rMin(), rMax = tCur.rMax(); // Is TRAVERSING? double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = - cTraversing(lpos,lmom,sim_hit.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), - rMin,rMax,dZ,startPhi,endPhi, - lins,louts,lpini,lpend); + cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), + rMin, rMax, dZ, startPhi, endPhi, lins, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); - continue; + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + continue; } cIDs.push_back(sim_hit.getCellID()); if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(idx); + same_idcs.push_back(idx); } // Continuations. Particle may exit and then re-enter through "rMin". - bool isContinuation = status & 0x5; + bool isContinuation = status & 0x5; bool hasContinuation = status & 0xa; - bool canReEnter = status & 0x100; int rank = m_stripRank(vID); + bool canReEnter = status & 0x100; + int rank = m_stripRank(vID); if (!canReEnter) { - if (rank == 0 && (status & 0x1)) isContinuation = false; - if (rank == 0 && (status & 0x2)) hasContinuation = false; + if (rank == 0 && (status & 0x1)) + isContinuation = false; + if (rank == 0 && (status & 0x2)) + hasContinuation = false; } - if (rank == 4 && (status & 0x4)) isContinuation = false; - if (rank == 4 && (status & 0x8)) hasContinuation = false; + if (rank == 4 && (status & 0x4)) + isContinuation = false; + if (rank == 4 && (status & 0x8)) + hasContinuation = false; if (hasContinuation) { - // ***** LOOP OVER HITS - int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; - for (jdx = idx+1, unbroken = 1; jdx<(int)sim_size; jdx++) { - const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - // Used hit? If indeed, it's going to be discarded anyway in the - // following: current "sim_hit" is by construction at variance to it. - CellID vJD = sim_hjt.getCellID() & m_volumeBits; - // Particle may start inward and re-enter, being then outward-going. - // => Orientation has to be evaluated w.r.t. previous vID. - int orientation = m_orientation(vIDPrv,vJD); - bool isUpstream = m_isUpstream(orientation,status); - bool pmoStatus = samePMO(sim_hit,sim_hjt,unbroken); - if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header,0,sim_hit.getCellID(),lpos,lmom)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // Get 'j' radii - curVol = volman.lookupDetElement(vJD); - const Tube &tubj = curVol.solid(); - rMin = tubj.rMin(); rMax = tubj.rMax(); - double lpoj[3], lmoj[3]; getLocalPosMom(sim_hjt,toRefVol,lpoj,lmoj); - // Is TRAVERSING through the (quasi-)common wall? - double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = - cTraversing(lpoj,lmoj,sim_hjt.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), - rMin,rMax,dZ,startPhi,endPhi, - ljns,lovts,lpjni,lpfnd); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header,status,sim_hjt.getCellID(),lpoj,lmoj)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // ij-Compatibility: status - bool jsDownstream = m_isDownstream(orientation,status); - if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) break; - else { // Allow for primary hits to not come in unbroken sequence - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - } - // ij-Compatibility: close exit/entrance-distance - double dist = outInDistance(0,orientation,ljns,louts,lmom,lmoj); - const double tolerance = 25*dd4hep::um; - bool isCompatible = dist > 0 && dist < tolerance; - if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header,status,dist,sim_hit.getCellID(),lpos,lmom, - /* */ sim_hjt.getCellID(),lpoj,lmoj)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // ***** UPDATE - vIDPrv = vJD; eDep += sim_hjt.getEDep(); - for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; lmend[i] = lmoj[i]; - } - // ***** BOOK-KEEPING - usedHits.push_back(jdx); - cIDs.push_back(sim_hjt.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(jdx); - } - // ***** CONTINUATION? - hasContinuation = status & 0xa; - canReEnter = status & 0x100; - if (!canReEnter && m_stripRank(vJD) == 4) hasContinuation = false; - if (!hasContinuation) { jdx++; break; } - else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; louts[1][i] = lovts[1][i]; - } - } - } - if (unbroken) idx = jdx-1; + // ***** LOOP OVER HITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + // Particle may start inward and re-enter, being then outward-going. + // => Orientation has to be evaluated w.r.t. previous vID. + int orientation = m_orientation(vIDPrv, vJD); + bool isUpstream = m_isUpstream(orientation, status); + bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // Get 'j' radii + curVol = volman.lookupDetElement(vJD); + const Tube& tubj = curVol.solid(); + rMin = tubj.rMin(); + rMax = tubj.rMax(); + double lpoj[3], lmoj[3]; + getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); + // Is TRAVERSING through the (quasi-)common wall? + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), rMin, rMax, dZ, startPhi, endPhi, + ljns, lovts, lpjni, lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation, status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) + break; + else { // Allow for primary hits to not come in unbroken sequence + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double dist = outInDistance(0, orientation, ljns, louts, lmom, lmoj); + const double tolerance = 25 * dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ***** UPDATE + vIDPrv = vJD; + eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(jdx); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + canReEnter = status & 0x100; + if (!canReEnter && m_stripRank(vJD) == 4) + hasContinuation = false; + if (!hasContinuation) { + jdx++; + break; + } else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) + idx = jdx - 1; } // ***** EXTENSION?... if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) - if (denyExtension(sim_hit,tCur.rMax()-tCur.rMin())) { - isContinuation=hasContinuation = false; - } - for (int io = 0; io<2; io++) { // ...into/out-of - if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) - continue; - int direction = io ? +1 : -1; - status = extendHit(refID,direction,lpini,lmom,lpend,lmend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); - continue; - } + if (denyExtension(sim_hit, tCur.rMax() - tCur.rMin())) { + isContinuation = hasContinuation = false; + } + for (int io = 0; io < 2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + status = extendHit(refID, direction, lpini, lmom, lpend, lmend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + continue; + } } // ***** FLAG CASES W/ UNEXPECTED OUTCOME - flagUnexpected(header,0,(tRef.rMin()+tRef.rMax())/2, - sim_hit,lpini,lpend,lpos,lmom); + flagUnexpected(header, 0, (tRef.rMin() + tRef.rMax()) / 2, sim_hit, lpini, lpend, lpos, lmom); // ***** UPDATE (local position , DoF - double DoF2 = 0, dir = 0; for (int i = 0; i<3; i++) { - double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; lpos[i] = neu; - double d = neu-alt; dir += d*lmom[i]; DoF2 += d*d; + double DoF2 = 0, dir = 0; + for (int i = 0; i < 3; i++) { + double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; + lpos[i] = neu; + double d = neu - alt; + dir += d * lmom[i]; + DoF2 += d * d; } // Update time by ToF from original subHit to extended/COALESCED. time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; - } - else if (!strcmp(shape.type(),"TGeoBBox")) { + } else if (!strcmp(shape.type(), "TGeoBBox")) { // ********** BOX GEOMETRY - const Box &bRef = refVol.solid(); // REFERENCE SUBVOLUME + const Box& bRef = refVol.solid(); // REFERENCE SUBVOLUME double dX = bRef.x(), dY = bRef.y(); // Get current SUBVOLUME DetElement curVol = volman.lookupDetElement(vID); - const Box &bCur = curVol.solid(); - double dZ = bCur.z(); - double ref2Cur = getRef2Cur(refVol,curVol); + const Box& bCur = curVol.solid(); + double dZ = bCur.z(); + double ref2Cur = getRef2Cur(refVol, curVol); // Is TRAVERSING? double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = - bTraversing(lpos,lmom,ref2Cur,sim_hit.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), - dZ,dX,dY, - lins,louts,lpini,lpend); + bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, lins, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); - continue; + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + continue; } cIDs.push_back(sim_hit.getCellID()); if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(idx); + same_idcs.push_back(idx); } // Continuations. - int rank = m_stripRank(vID); - bool isContinuation = status & 0x5; + int rank = m_stripRank(vID); + bool isContinuation = status & 0x5; bool hasContinuation = status & 0xa; - if ((rank == 0 && (status & 0x1)) || - (rank == 4 && (status & 0x4))) isContinuation = false; - if ((rank == 0 && (status & 0x2)) || - (rank == 4 && (status & 0x8))) hasContinuation = false; + if ((rank == 0 && (status & 0x1)) || (rank == 4 && (status & 0x4))) + isContinuation = false; + if ((rank == 0 && (status & 0x2)) || (rank == 4 && (status & 0x8))) + hasContinuation = false; if (hasContinuation) { - // ***** LOOP OVER SUBHITS - int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; - for (jdx = idx+1, unbroken = 1; jdx<(int)sim_size; jdx++) { - const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - // Used hit? If indeed, it's going to be discarded anyway in the - // following: current "sim_hit" is by construction at variance to it. - CellID vJD = sim_hjt.getCellID() & m_volumeBits; - int orientation = m_orientation(vIDPrv,vJD); - bool isUpstream = m_isUpstream(orientation,status); - bool pmoStatus = samePMO(sim_hit,sim_hjt,unbroken); - if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header,0,sim_hit.getCellID(),lpos,lmom)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // Get 'j' Z - curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME - const Box &boxj = curVol.solid(); - dZ = boxj.z(); - double ref2j = getRef2Cur(refVol,curVol); - // Is TRAVERSING through the (quasi)-common border? - double lpoj[3], lmoj[3]; getLocalPosMom(sim_hjt,toRefVol,lpoj,lmoj); - double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = - bTraversing(lpoj,lmoj,ref2j,sim_hjt.getPathLength()*ed2dd,sim_hit.isProducedBySecondary(), - dZ,dX,dY, - ljns,lovts,lpjni,lpfnd); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header,status,sim_hjt.getCellID(),lpoj,lmoj)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // ij-Compatibility: status - bool jsDownstream = m_isDownstream(orientation,status); - if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) break; - else { - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - } - // ij-Compatibility: close exit/entrance-distance - double zMin = -dZ-ref2j, zMax = dZ-ref2j; - double dist = outInDistance(1,orientation,ljns,louts,lmom,lmoj); - const double tolerance = 25*dd4hep::um; - bool isCompatible = dist > 0 && dist < tolerance; - if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header,status,dist,sim_hit.getCellID(),lpos,lmom, - /* */ sim_hjt.getCellID(),lpoj,lmoj)); - if (unbroken) idx = jdx-1; unbroken = 0; continue; - } - // ***** UPDATE - vIDPrv = vJD; eDep += sim_hjt.getEDep(); - for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; lmend[i] = lmoj[i]; - } - // ***** BOOK-KEEPING - usedHits.push_back(jdx); - cIDs.push_back(sim_hjt.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(jdx); - } - // ***** CONTINUATION? - hasContinuation = status & 0xa; - if (!hasContinuation) { jdx++; break; } - else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; louts[1][i] = lovts[1][i]; - } - } - } - if (unbroken) idx = jdx-1; + // ***** LOOP OVER SUBHITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + int orientation = m_orientation(vIDPrv, vJD); + bool isUpstream = m_isUpstream(orientation, status); + bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // Get 'j' Z + curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME + const Box& boxj = curVol.solid(); + dZ = boxj.z(); + double ref2j = getRef2Cur(refVol, curVol); + // Is TRAVERSING through the (quasi)-common border? + double lpoj[3], lmoj[3]; + getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = + bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation, status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) + break; + else { + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double zMin = -dZ - ref2j, zMax = dZ - ref2j; + double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj); + const double tolerance = 25 * dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ***** UPDATE + vIDPrv = vJD; + eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + same_idcs.push_back(jdx); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + if (!hasContinuation) { + jdx++; + break; + } else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) + idx = jdx - 1; } // ***** EXTENSION?... if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) - if (denyExtension(sim_hit,bCur.z())) { - isContinuation=hasContinuation = false; - } - for (int io = 0; io<2; io++) { // ...into/out-of - if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) - continue; - int direction = io ? +1 : -1; - status = extendHit(refID,direction,lpini,lmom,lpend,lmend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header,status,sim_hit.getCellID(),lpos,lmom)); - continue; - } + if (denyExtension(sim_hit, bCur.z())) { + isContinuation = hasContinuation = false; + } + for (int io = 0; io < 2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + status = extendHit(refID, direction, lpini, lmom, lpend, lmend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + continue; + } } - // ***** FLAG CASES W/ UNEXPECTED OUTCOME - flagUnexpected(header,1,0, - sim_hit,lpini,lpend,lpos,lmom); + // ***** FLAG CASES W/ UNEXPECTED OUTCOME + flagUnexpected(header, 1, 0, sim_hit, lpini, lpend, lpos, lmom); // ***** UPDATE (local position , DoF) - double DoF2 = 0, dir = 0; for (int i = 0; i<3; i++) { - double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; lpos[i] = neu; - double d = neu-alt; dir += d*lmom[i]; DoF2 += d*d; + double DoF2 = 0, dir = 0; + for (int i = 0; i < 3; i++) { + double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; + lpos[i] = neu; + double d = neu - alt; + dir += d * lmom[i]; + DoF2 += d * d; } // Update time by ToF from original subHit to extended/COALESCED. time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; - } - else { - critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", - refID,shape.type()); + } else { + critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", refID, shape.type()); throw JException("Bad input data: invalid geometry"); - } // ***** CELLIDS of (p|n)-STRIP HITS - Position locPos(lpos[0],lpos[1],lpos[2]); // Simplification: strip surface = REFERENCE surface + Position locPos(lpos[0], lpos[1], lpos[2]); // Simplification: strip surface = REFERENCE surface // p "strip" - CellID vIDp = refID | m_pStripBit; + CellID vIDp = refID | m_pStripBit; CellID cIDp = m_seg->cellID(locPos, dummy, vIDp); // n "strip" - CellID vIDn = refID | m_nStripBit; - CellID cIDn = m_seg->cellID(locPos, dummy, vIDn); - double result_time = time + time_smearing; - auto hit_time_stamp = (std::int32_t)(result_time * 1e3); + CellID vIDn = refID | m_nStripBit; + CellID cIDn = m_seg->cellID(locPos, dummy, vIDn); + double result_time = time + time_smearing; + auto hit_time_stamp = (std::int32_t)(result_time * 1e3); // ***** DEBUGGING INFO if (level() >= algorithms::LogLevel::kDebug) { debug("--------------------"); - for (CellID cID : {cIDp,cIDn}) { - std::string sCellID = cID == cIDp ? "cellIDp" : "cellIDn"; - CellID hID = cID >> 32, vID = cID & m_volumeBits, sID = vID >> 28 & 0xff; - debug ("Hit {} = 0x{:08x}, 0x{:08x} 0x{:02x}", sCellID, hID, vID, sID); - Position stripPos = m_seg->position(cID); - Position globPos = refVol.nominal().localToWorld(stripPos); - debug (" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", globPos.X()/mm, globPos.Y()/mm, globPos.Z()/mm); + for (CellID cID : {cIDp, cIDn}) { + std::string sCellID = cID == cIDp ? "cellIDp" : "cellIDn"; + CellID hID = cID >> 32, vID = cID & m_volumeBits, sID = vID >> 28 & 0xff; + debug("Hit {} = 0x{:08x}, 0x{:08x} 0x{:02x}", sCellID, hID, vID, sID); + Position stripPos = m_seg->position(cID); + Position globPos = refVol.nominal().localToWorld(stripPos); + debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", globPos.X() / mm, globPos.Y() / mm, + globPos.Z() / mm); } - debug (" edep = {:.0f} [eV]", eDep / eV); - debug (" time = {:.2f} [ns]", time); + debug(" edep = {:.0f} [eV]", eDep / eV); + debug(" time = {:.2f} [ns]", time); #if EDM4HEP_BUILD_VERSION >= EDM4HEP_VERSION(0, 99, 0) - debug (" particle time = {} [ns]", sim_hit.getParticle().getTime()); + debug(" particle time = {} [ns]", sim_hit.getParticle().getTime()); #else - debug (" particle time = {} [ns]", sim_hit.getMCParticle().getTime()); + debug(" particle time = {} [ns]", sim_hit.getMCParticle().getTime()); #endif - debug (" time smearing: {:.2f}, resulting time = {:.2f} [ns]", time_smearing, result_time); - debug (" hit_time_stamp: {} [~ps]", hit_time_stamp); - for (int ldx = 0; ldx<(int)same_idcs.size(); ldx++) { - int jdx = same_idcs[ldx]; const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - CellID cIDk = sim_hjt.getCellID(); - CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; - debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx, hIDk, vIDk, sIDk); - debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hjt.getPosition().x/edmm, - sim_hjt.getPosition().y/edmm, sim_hjt.getPosition().z/edmm); - debug(" xy_radius = {:.2f}", std::hypot(sim_hjt.getPosition().x, sim_hjt.getPosition().y)/edmm); - debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hjt.getMomentum().x/GeV, - sim_hjt.getMomentum().y/GeV, sim_hjt.getMomentum().z/GeV); - debug(" edep = {:.0f} [eV]", sim_hjt.getEDep()/eV); - debug(" time = {:.2f} [ns]", sim_hjt.getTime()); + debug(" time smearing: {:.2f}, resulting time = {:.2f} [ns]", time_smearing, result_time); + debug(" hit_time_stamp: {} [~ps]", hit_time_stamp); + for (int ldx = 0; ldx < (int)same_idcs.size(); ldx++) { + int jdx = same_idcs[ldx]; + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + CellID cIDk = sim_hjt.getCellID(); + CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; + debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx, hIDk, vIDk, sIDk); + debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hjt.getPosition().x / edmm, + sim_hjt.getPosition().y / edmm, sim_hjt.getPosition().z / edmm); + debug(" xy_radius = {:.2f}", + std::hypot(sim_hjt.getPosition().x, sim_hjt.getPosition().y) / edmm); + debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hjt.getMomentum().x / GeV, + sim_hjt.getMomentum().y / GeV, sim_hjt.getMomentum().z / GeV); + debug(" edep = {:.0f} [eV]", sim_hjt.getEDep() / eV); + debug(" time = {:.2f} [ns]", sim_hjt.getTime()); } } @@ -647,7 +704,8 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // sum deposited energy auto charge = hit.getCharge(); - hit.setCharge(charge + (std::int32_t)std::llround(eDep * 1e6)); // TODO: accumulate charge: shouldn't it be float? + hit.setCharge(charge + (std::int32_t)std::llround( + eDep * 1e6)); // TODO: accumulate charge: shouldn't it be float? } } } @@ -656,38 +714,36 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, for (auto item : cell_hit_map) { raw_hits->push_back(item.second); CellID stripID = item.first; - const auto is = stripID2cIDs.find(stripID); + const auto is = stripID2cIDs.find(stripID); if (is == stripID2cIDs.end()) { - critical("Inconsistency: CellID {:x} not found in \"stripID2cIDs\" map", - stripID); + critical("Inconsistency: CellID {:x} not found in \"stripID2cIDs\" map", stripID); throw JException("Inconsistency in the handling of \"stripID2cIDs\" map"); } std::vector cIDs = is->second; for (CellID cID : cIDs) { for (const auto& sim_hit : *sim_hits) { - if (sim_hit.getCellID() == cID) { - // set association - auto hitassoc = associations->create(); - hitassoc.setWeight(1.0); - hitassoc.setRawHit(item.second); - hitassoc.setSimHit(sim_hit); - } + if (sim_hit.getCellID() == cID) { + // set association + auto hitassoc = associations->create(); + hitassoc.setWeight(1.0); + hitassoc.setRawHit(item.second); + hitassoc.setSimHit(sim_hit); + } } } } } -void getLocalPosMom(const edm4hep::SimTrackerHit &sim_hit, - const TGeoHMatrix& toModule, - double *lpos, double *lmom) { +void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& toModule, + double* lpos, double* lmom) { const edm4hep::Vector3d& pos = sim_hit.getPosition(); // Length: Inputs are in EDM4eic units. Let's move to DD4hep units. - const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; - const double gpos[3] = {pos.x*ed2dd, pos.y*ed2dd, pos.z*ed2dd}; + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; + const double gpos[3] = {pos.x * ed2dd, pos.y * ed2dd, pos.z * ed2dd}; const edm4hep::Vector3f& mom = sim_hit.getMomentum(); - const double gmom[3] = {mom.x, mom.y, mom.z}; - toModule.MasterToLocal(gpos,lpos); - toModule.MasterToLocalVect(gmom,lmom); + const double gmom[3] = {mom.x, mom.y, mom.z}; + toModule.MasterToLocal(gpos, lpos); + toModule.MasterToLocalVect(gmom, lmom); } // ******************** TRAVERSING? @@ -714,99 +770,124 @@ void getLocalPosMom(const edm4hep::SimTrackerHit &sim_hit, // extrapolated position falls exactly at mid-plane, even in the case of a // low energy particle, where path may be affected by multiscattering. This, // provided that particle is not a secondary. -unsigned int cTraversing(const double *lpos, const double *lmom, double path, bool isSecondary, // Input subHit - double rMin, double rMax, // Current instance of SUBVOLUME - double dZ, double startPhi, double endPhi, // Module parameters - double lins[][3], double louts[][3], - double *lpini, double *lpend) -{ +unsigned int cTraversing(const double* lpos, const double* lmom, double path, + bool isSecondary, // Input subHit + double rMin, double rMax, // Current instance of SUBVOLUME + double dZ, double startPhi, double endPhi, // Module parameters + double lins[][3], double louts[][3], double* lpini, double* lpend) { unsigned int status = 0; - double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx*Mx+My*My; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx * Mx + My * My; double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; // Intersection w/ the edge in phi double tIn = 0, tOut = 0; - for (double phi : {startPhi,endPhi}) { - // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); + for (double phi : {startPhi, endPhi}) { + // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); double Ux = cos(phi), Uy = sin(phi); - double D = Px*Uy-Px*Ux; if (D) { // If P not // to U - double t = (My*Ux-Mx*Uy)/D; - double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey), Ez = Mz+t*Pz; + double D = Px * Uy - Px * Ux; + if (D) { // If P not // to U + double t = (My * Ux - Mx * Uy) / D; + double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey), Ez = Mz + t * Pz; if (rMin < rE && rE < rMax && fabs(Ez) < dZ) { - if (t < 0) { status |= 0x10; tIn = t; } - else { status |= 0x20; tOut = t; } + if (t < 0) { + status |= 0x10; + tIn = t; + } else { + status |= 0x20; + tOut = t; + } } } } // Intersection w/ the edge in Z - double zLow = -dZ, zUp = +dZ; for (double Z: {zLow,zUp}) { + double zLow = -dZ, zUp = +dZ; + for (double Z : {zLow, zUp}) { // Mz+t*Pz = Z if (Pz) { - double t = (Z-Mz)/Pz; - double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey); - double phi = atan2(Ey,Ex); + double t = (Z - Mz) / Pz; + double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey); + double phi = atan2(Ey, Ex); if (rMin < rE && rE < rMax && startPhi < phi && phi < endPhi) { - if (t < 0) { - if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { - status |= 0x10; tIn = t; - } - } - else if (t > 0) { - if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { - status |= 0x20; tOut = t; - } - } + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= 0x10; + tIn = t; + } + } else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= 0x20; + tOut = t; + } + } } } } // Intersection w/ tube walls - double ts[3/* rMin/rMax/edge */][2/* In/Out */] = {{0,0},{0,0},{tIn,tOut}}; // Up to two intersections - double a = Px*Px+Py*Py, b = Px*Mx+Py*My; + double ts[3 /* rMin/rMax/edge */][2 /* In/Out */] = { + {0, 0}, {0, 0}, {tIn, tOut}}; // Up to two intersections + double a = Px * Px + Py * Py, b = Px * Mx + Py * My; for (int lu = 0; lu < 2; lu++) { // rMin/rMax - double R; unsigned int statGene; - if (lu == 1) { R = rMax; statGene = 0x4; } - else { R = rMin; statGene = 0x1; } - double c = M2-R*R; - if (!a) { // P is // to Z. Yet no intersect w/ Z edge. - if ((status & 0x30) != 0x30) status |= 0x1000; continue; // Inconsistency - } - else if (!c) { // Hit is on wall: inconsistency. - status |= 0x2000; continue; + double R; + unsigned int statGene; + if (lu == 1) { + R = rMax; + statGene = 0x4; + } else { + R = rMin; + statGene = 0x1; } - else { - double det = b*b-a*c; if (det < 0) { - if (lu == 1) { // No intersection w/ outer wall: inconsistency. - status |= 0x4000; continue; - } - } - else { - double sqdet = sqrt(det); - for (int is = 0; is<2; is++) { - int s = 1-2*is; double t = (-b+s*sqdet)/a; - double Ix = Mx+t*Px, Iy = My+t*Py, Iz = Mz+t*Pz, phi = atan2(Iy,Ix); - if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi) continue; - if (t < 0) { - // Two rMin intersects in same back/forward direction may happen - // (one and and only one of them may then be hidden by edge). - // => Have to allow wall intersect to coexist w/ edge intersect. - // This only for rMin, but for simplicity's sake... - if (status & statGene) { // Two <0 ts: can only happen when rMin - double tPrv = ts[lu][0]; if (t > tPrv) { - ts[lu][0] = t; ts[lu][1] = tPrv; // Current is actually IN, previous is OUT despite being <0 - } - status |= statGene<<1; - } - else { ts[lu][0] = t; status |= statGene; } - } - else { // (if t > 0) - if (status & statGene<<1) { // Two >0 ts: can only happen when rMin - double tPrv = ts[lu][1]; if (t < tPrv) { - ts[lu][1] = t; ts[lu][0] = tPrv; // Current is actually OUT, previous is IN despite being >0 - } - status |= statGene; - } - else { ts[lu][1] = t; status |= statGene<<1; } - } - } + double c = M2 - R * R; + if (!a) { // P is // to Z. Yet no intersect w/ Z edge. + if ((status & 0x30) != 0x30) + status |= 0x1000; + continue; // Inconsistency + } else if (!c) { // Hit is on wall: inconsistency. + status |= 0x2000; + continue; + } else { + double det = b * b - a * c; + if (det < 0) { + if (lu == 1) { // No intersection w/ outer wall: inconsistency. + status |= 0x4000; + continue; + } + } else { + double sqdet = sqrt(det); + for (int is = 0; is < 2; is++) { + int s = 1 - 2 * is; + double t = (-b + s * sqdet) / a; + double Ix = Mx + t * Px, Iy = My + t * Py, Iz = Mz + t * Pz, phi = atan2(Iy, Ix); + if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi) + continue; + if (t < 0) { + // Two rMin intersects in same back/forward direction may happen + // (one and and only one of them may then be hidden by edge). + // => Have to allow wall intersect to coexist w/ edge intersect. + // This only for rMin, but for simplicity's sake... + if (status & statGene) { // Two <0 ts: can only happen when rMin + double tPrv = ts[lu][0]; + if (t > tPrv) { + ts[lu][0] = t; + ts[lu][1] = tPrv; // Current is actually IN, previous is OUT despite being <0 + } + status |= statGene << 1; + } else { + ts[lu][0] = t; + status |= statGene; + } + } else { // (if t > 0) + if (status & statGene << 1) { // Two >0 ts: can only happen when rMin + double tPrv = ts[lu][1]; + if (t < tPrv) { + ts[lu][1] = t; + ts[lu][0] = tPrv; // Current is actually OUT, previous is IN despite being >0 + } + status |= statGene; + } else { + ts[lu][1] = t; + status |= statGene << 1; + } + } + } } } } @@ -814,31 +895,35 @@ unsigned int cTraversing(const double *lpos, const double *lmom, double path, bo for (int lu = 0; lu < 2; lu++) { // rMin/rMax unsigned int statGene = lu ? 0x4 : 0x1; if (status & statGene) { - double t = ts[lu][0]; if (t < 0) { - if (status & 0x10) { - if (t < 0 && t > tIn) status |= 0x10000; - status &= ~statGene; - } - } - else { // if (t > 0) - if (status & 0x20) { - if (t > 0 && t < tOut) status |= 0x20000; - status &= ~statGene; - } + double t = ts[lu][0]; + if (t < 0) { + if (status & 0x10) { + if (t < 0 && t > tIn) + status |= 0x10000; + status &= ~statGene; + } + } else { // if (t > 0) + if (status & 0x20) { + if (t > 0 && t < tOut) + status |= 0x20000; + status &= ~statGene; + } } } - if (status & statGene<<1) { - double t = ts[lu][1]; if (t < 0) { - if (status & 0x10) { - if (t < 0 && t > tIn) status |= 0x40000; - status &= ~(statGene<<1); - } - } - else { // if (t > 0) - if (status & 0x20) { - if (t > 0 && t < tOut) status |= 0x80000; - status &= ~(statGene<<1); - } + if (status & statGene << 1) { + double t = ts[lu][1]; + if (t < 0) { + if (status & 0x10) { + if (t < 0 && t > tIn) + status |= 0x40000; + status &= ~(statGene << 1); + } + } else { // if (t > 0) + if (status & 0x20) { + if (t > 0 && t < tOut) + status |= 0x80000; + status &= ~(statGene << 1); + } } } } @@ -851,112 +936,133 @@ unsigned int cTraversing(const double *lpos, const double *lmom, double path, bo // - Note that we not only require that the path be long enough, but also // that it matches exactly distances to entrance/exit. bool isReEntering = (status & 0x3) == 0x3; - if (isReEntering) status |= 0x100; // Remember that particle can re-enter. - double norm = sqrt(a+Pz*Pz), at = path/2/norm; + if (isReEntering) + status |= 0x100; // Remember that particle can re-enter. + double norm = sqrt(a + Pz * Pz), at = path / 2 / norm; unsigned int statws = 0; for (int is = 0; is < 2; is++) { - int s = 1-2*is; double Ix = s*at*Px, Iy = s*at*Py, Iz = s*at*Pz; + int s = 1 - 2 * is; + double Ix = s * at * Px, Iy = s * at * Py, Iz = s * at * Pz; for (int lu = 0; lu < 2; lu++) { // Lower/upper wall unsigned int statvs = lu ? 0x4 : 0x1; - for (int io = 0; io<2; io++) { - statvs <<= io; if (status & statvs) { - double t = ts[lu][io]; if (t*s < 0) continue; - double dIx = t*Px-Ix, dIy = t*Py-Iy, dIz = t*Pz-Iz; - double dist = sqrt(dIx*dIx+dIy*dIy+dIz*dIz); - const double tolerance = 20*dd4hep::um; - if (dist < tolerance) statws |= statvs; - } + for (int io = 0; io < 2; io++) { + statvs <<= io; + if (status & statvs) { + double t = ts[lu][io]; + if (t * s < 0) + continue; + double dIx = t * Px - Ix, dIy = t * Py - Iy, dIz = t * Pz - Iz; + double dist = sqrt(dIx * dIx + dIy * dIy + dIz * dIz); + const double tolerance = 20 * dd4hep::um; + if (dist < tolerance) + statws |= statvs; + } } } } - if (!(statws & 0x5)) /* No entrance */ status &= ~0x5; - if (!(statws & 0xa)) /* No exit */ status &= ~0xa; + if (!(statws & 0x5)) /* No entrance */ + status &= ~0x5; + if (!(statws & 0xa)) /* No exit */ + status &= ~0xa; // ***** End points // Assign end points to walls, if not a secondary and provided it's not a // reEntrance case, which case is more difficult to handle and we leave aside. if (((status & 0x5) == 0x1 || (status & 0x5) == 0x4) && !isSecondary) { - double tIn = (status & 0x1) ? ts[0][0] : ts[1][0]; - lpini[0] = Mx+tIn*Px; lpini[1] = My+tIn*Py; lpini[2] = Mz+tIn*Pz; - } - else { - lpini[0] = Mx-at*Px; lpini[1] = My-at*Py; lpini[2] = Mz-at*Pz; + double tIn = (status & 0x1) ? ts[0][0] : ts[1][0]; + lpini[0] = Mx + tIn * Px; + lpini[1] = My + tIn * Py; + lpini[2] = Mz + tIn * Pz; + } else { + lpini[0] = Mx - at * Px; + lpini[1] = My - at * Py; + lpini[2] = Mz - at * Pz; } if (((status & 0xa) == 0x2 || (status & 0xa) == 0x8) && !isSecondary) { double tOut = (status & 0x2) ? ts[0][1] : ts[1][1]; - lpend[0] = Mx+tOut*Px; lpend[1] = My+tOut*Py; lpend[2] = Mz+tOut*Pz; - } - else { - lpend[0] = Mx+at*Px; lpend[1] = My+at*Py; lpend[2] = Mz+at*Pz; + lpend[0] = Mx + tOut * Px; + lpend[1] = My + tOut * Py; + lpend[2] = Mz + tOut * Pz; + } else { + lpend[0] = Mx + at * Px; + lpend[1] = My + at * Py; + lpend[2] = Mz + at * Pz; } // End points when on the walls for (int lu = 0; lu < 2; lu++) { unsigned int statvs = lu ? 0x4 : 0x1; double tIn = ts[lu][0], tOut = ts[lu][1]; if (status & statvs) { - lins [lu][0] = Mx+tIn* Px; lins [lu][1] = My+tIn* Py; lins [lu][2] = Mz+tIn* Pz; + lins[lu][0] = Mx + tIn * Px; + lins[lu][1] = My + tIn * Py; + lins[lu][2] = Mz + tIn * Pz; } statvs <<= 1; - if (status & statvs) { - louts[lu][0] = Mx+tOut*Px; louts[lu][1] = My+tOut*Py; louts[lu][2] = Mz+tOut*Pz; + if (status & statvs) { + louts[lu][0] = Mx + tOut * Px; + louts[lu][1] = My + tOut * Py; + louts[lu][2] = Mz + tOut * Pz; } } return status; } -unsigned int bTraversing(const double *lpos, const double *lmom, double ref2Cur, double path, bool isSecondary, // Input subHit - double dZ, // Current instance of SUBVOLUME - double dX, double dY, // Module parameters - double lins[][3], double louts[][3], - double *lpini, double *lpend) -{ +unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double path, + bool isSecondary, // Input subHit + double dZ, // Current instance of SUBVOLUME + double dX, double dY, // Module parameters + double lins[][3], double louts[][3], double* lpini, double* lpend) { unsigned int status = 0; - double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx,My}, M2 = Mx*Mx+My*My; - double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px,Py}; - double Mz = lpos[2]+ref2Cur, Pz = lmom[2]; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}, M2 = Mx * Mx + My * My; + double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py}; + double Mz = lpos[2] + ref2Cur, Pz = lmom[2]; // Intersection w/ the edge in X,Y double tIn = 0, tOut = 0; - double xyLow[2] = {-dX,+dX}, xyUp[2] = {-dY,+dY}; + double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { - int yx = 1-xy; + int yx = 1 - xy; double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; - for (double A: {aLow,aUp}) { + for (double A : {aLow, aUp}) { // Mz+t*Pz = A if (Pa) { - double t = (A-Mz)/Pa; - double Eb = Mb+t*Pb, Ez = Mz+t*Pz; - if (bLow < Eb && Eb < bUp && fabs(Ez) < dZ) { - if (t < 0) { - if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { - status |= 0x10; tIn = t; - } - } - else if (t > 0) { - if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { - status |= 0x20; tOut = t; - } - } - } + double t = (A - Mz) / Pa; + double Eb = Mb + t * Pb, Ez = Mz + t * Pz; + if (bLow < Eb && Eb < bUp && fabs(Ez) < dZ) { + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= 0x10; + tIn = t; + } + } else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= 0x20; + tOut = t; + } + } + } } } } if (status) { - printf("DEBUG: Edge 0x%x\n",status); + printf("DEBUG: Edge 0x%x\n", status); } // Intersection w/ box walls for (int lu = 0; lu < 2; lu++) { - int s = 2*lu-1; double Z = s*dZ; unsigned int statGene = lu ? 0x4 : 0x1; + int s = 2 * lu - 1; + double Z = s * dZ; + unsigned int statGene = lu ? 0x4 : 0x1; // Mz+t*Pz = Z if (Pz) { - double t = (Z-Mz)/Pz; - if (t < 0) { - if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { - status |= statGene; tIn = t; - } - } - else if (t > 0) { - if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { - status |= statGene<<1; tOut = t; - } + double t = (Z - Mz) / Pz; + if (t < 0) { + if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { + status |= statGene; + tIn = t; + } + } else if (t > 0) { + if (!(status & 0x20) || ((status & 0x20) && t < tOut)) { + status |= statGene << 1; + tOut = t; + } } } } @@ -968,97 +1074,125 @@ unsigned int bTraversing(const double *lpos, const double *lmom, double ref2Cur, // => We remove the corresponding bit in the pattern. // - Note that we not only require that the path be long enough, but also // that it matches exactly distances to entrance/exit. - double norm = sqrt(Px*Px+Py*Py+Pz*Pz), at = path/2/norm; + double norm = sqrt(Px * Px + Py * Py + Pz * Pz), at = path / 2 / norm; unsigned int statws = 0; for (int is = 0; is < 2; is++) { - int s = 1-2*is; double Ix = s*at*Px, Iy = s*at*Py, Iz = s*at*Pz; + int s = 1 - 2 * is; + double Ix = s * at * Px, Iy = s * at * Py, Iz = s * at * Pz; for (int lu = 0; lu < 2; lu++) { // Lower/upper wall unsigned int statvs = lu ? 0x4 : 0x1; - for (int io = 0; io<2; io++) { - statvs <<= io; if (status & statvs) { - double t = io ? tOut : tIn; if (t*s < 0) continue; - double dIx = t*Px-Ix, dIy = t*Py-Iy, dIz = t*Pz-Iz; - double dist = sqrt(dIx*dIx+dIy*dIy+dIz*dIz); - const double tolerance = 20*dd4hep::um; - if (dist < tolerance) statws |= statvs; - } + for (int io = 0; io < 2; io++) { + statvs <<= io; + if (status & statvs) { + double t = io ? tOut : tIn; + if (t * s < 0) + continue; + double dIx = t * Px - Ix, dIy = t * Py - Iy, dIz = t * Pz - Iz; + double dist = sqrt(dIx * dIx + dIy * dIy + dIz * dIz); + const double tolerance = 20 * dd4hep::um; + if (dist < tolerance) + statws |= statvs; + } } } } - if (!(statws & 0x5)) /* No entrance */ status &= ~0x5; - if (!(statws & 0xa)) /* No exit */ status &= ~0xa; + if (!(statws & 0x5)) /* No entrance */ + status &= ~0x5; + if (!(statws & 0xa)) /* No exit */ + status &= ~0xa; // ***** OUTPUT POSITIONS Mz -= ref2Cur; // Go back to REFERENCE SUBVOLUME // End points: // Assign end points to walls, if not a secondary. if ((status & 0x5) && !isSecondary) { - lpini[0] = Mx+tIn*Px; lpini[1] = My+tIn*Py; lpini[2] = Mz+tIn*Pz; - } - else { - lpini[0] = Mx-at*Px; lpini[1] = My-at*Py; lpini[2] = Mz-at*Pz; + lpini[0] = Mx + tIn * Px; + lpini[1] = My + tIn * Py; + lpini[2] = Mz + tIn * Pz; + } else { + lpini[0] = Mx - at * Px; + lpini[1] = My - at * Py; + lpini[2] = Mz - at * Pz; } if ((status & 0xa) && !isSecondary) { - lpend[0] = Mx+tOut*Px; lpend[1] = My+tOut*Py; lpend[2] = Mz+tOut*Pz; - } - else { - lpend[0] = Mx+at*Px; lpend[1] = My+at*Py; lpend[2] = Mz+at*Pz; + lpend[0] = Mx + tOut * Px; + lpend[1] = My + tOut * Py; + lpend[2] = Mz + tOut * Pz; + } else { + lpend[0] = Mx + at * Px; + lpend[1] = My + at * Py; + lpend[2] = Mz + at * Pz; } // End points when on the walls: for (int lu = 0; lu < 2; lu++) { unsigned int statvs = lu ? 0x4 : 0x1; if (status & statvs) { - lins [lu][0] = Mx+tIn* Px; lins [lu][1] = My+tIn* Py; lins [lu][2] = Mz+tIn* Pz; + lins[lu][0] = Mx + tIn * Px; + lins[lu][1] = My + tIn * Py; + lins[lu][2] = Mz + tIn * Pz; } statvs <<= 1; - if (status & statvs) { - louts[lu][0] = Mx+tOut*Px; louts[lu][1] = My+tOut*Py; louts[lu][2] = Mz+tOut*Pz; + if (status & statvs) { + louts[lu][0] = Mx + tOut * Px; + louts[lu][1] = My + tOut * Py; + louts[lu][2] = Mz + tOut * Pz; } } return status; } // ***** EXTRAPOLATE -bool cExtrapolate(const double *lpos, const double *lmom, // Input subHit - double rT, // Target radius - double *lext) // Extrapolated position @ +bool cExtrapolate(const double* lpos, const double* lmom, // Input subHit + double rT, // Target radius + double* lext) // Extrapolated position @ { - bool ok = false; - double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx*Mx+My*My; + bool ok = false; + double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx * Mx + My * My; double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; - double a = Px*Px+Py*Py, b = Px*Mx+Py*My, c = M2-rT*rT; + double a = Px * Px + Py * Py, b = Px * Mx + Py * My, c = M2 - rT * rT; double tF = 0; - if (!c) ok = true; + if (!c) + ok = true; else if (a) { // P is not // to Z - double det = b*b-a*c; if (det >= 0) { + double det = b * b - a * c; + if (det >= 0) { double sqdet = sqrt(det); - for (int is = 0; is<2; is++) { - int s = 1-2*is; double t = (-b+s*sqdet)/a; if (t < 0) continue; - if (!ok || - // Two intersects: let's retain the earliest one. - (ok && fabs(t) < fabs(tF))) { - tF = t; ok = true; - } + for (int is = 0; is < 2; is++) { + int s = 1 - 2 * is; + double t = (-b + s * sqdet) / a; + if (t < 0) + continue; + if (!ok || + // Two intersects: let's retain the earliest one. + (ok && fabs(t) < fabs(tF))) { + tF = t; + ok = true; + } } } } if (ok) { - lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + lext[0] = Mx + tF * Px; + lext[1] = My + tF * Py; + lext[2] = Mz + tF * Pz; } return ok; } -bool bExtrapolate(const double *lpos, const double *lmom, // Input subHit - double zT, // Target Z - double *lext) // Extrapolated position @ +bool bExtrapolate(const double* lpos, const double* lmom, // Input subHit + double zT, // Target Z + double* lext) // Extrapolated position @ { - bool ok = false; + bool ok = false; double Mx = lpos[0], My = lpos[1], Mz = lpos[2]; double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; double tF = 0; if (Pz) { - tF = (zT-Mz)/Pz; ok = tF > 0; + tF = (zT - Mz) / Pz; + ok = tF > 0; } if (ok) { - lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + lext[0] = Mx + tF * Px; + lext[1] = My + tF * Py; + lext[2] = Mz + tF * Pz; } return ok; } @@ -1072,298 +1206,348 @@ bool bExtrapolate(const double *lpos, const double *lmom, // Input subHit // - in direction . // - Returns something in the 0xff000: Inconsistency... // - contains the position of farthest extension. -unsigned int MPGDTrackerDigi::cExtension(double const *lpos, double const *lmom, // Input subHit - double rT, // Target radius - int direction, - double dZ, double startPhi, double endPhi, // Module parameters - double *lext) const -{ - unsigned int status = 0; +unsigned int MPGDTrackerDigi::cExtension(double const* lpos, double const* lmom, // Input subHit + double rT, // Target radius + int direction, double dZ, double startPhi, + double endPhi, // Module parameters + double* lext) const { + unsigned int status = 0; double Mx = lpos[0], My = lpos[1], Mz = lpos[2]; - double Px = lmom[0], Py = lmom[1], Pz = lmom[2], norm = sqrt(Px*Px+Py*Py+Pz*Pz); + double Px = lmom[0], Py = lmom[1], Pz = lmom[2], norm = sqrt(Px * Px + Py * Py + Pz * Pz); // Move some distance away from , which is expected to be sitting on // the wall of the SUBVOLUME to be ``extended''. - const double margin = 10*dd4hep::um; - double t = direction*margin/norm; Mx += t*Px; My += t*Py; Mz += t*Pz; - double M2 = Mx*Mx+My*My, rIni = sqrt(M2), rLow, rUp; - if (rIni < rT) { rLow = rIni; rUp = rT; } - else { rLow = rT; rUp = rIni; } + const double margin = 10 * dd4hep::um; + double t = direction * margin / norm; + Mx += t * Px; + My += t * Py; + Mz += t * Pz; + double M2 = Mx * Mx + My * My, rIni = sqrt(M2), rLow, rUp; + if (rIni < rT) { + rLow = rIni; + rUp = rT; + } else { + rLow = rT; + rUp = rIni; + } // Intersection w/ the edge in phi double tF = 0; - for (double phi : {startPhi,endPhi}) { - // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); + for (double phi : {startPhi, endPhi}) { + // M+t*P = 0 + t'*U. t = (My*Ux-Mx*Uy)/(Px*Uy-Py*Ux); double Ux = cos(phi), Uy = sin(phi); - double D = Px*Uy-Px*Ux; if (D) { // If P not // to U - double t = (My*Ux-Mx*Uy)/D; if (t*direction < 0) continue; - double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey), Ez = Mz+t*Pz; - if (rLow < rE && rE < rUp && fabs(Ez) < dZ) { status |= 0x1; tF = t; } + double D = Px * Uy - Px * Ux; + if (D) { // If P not // to U + double t = (My * Ux - Mx * Uy) / D; + if (t * direction < 0) + continue; + double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey), Ez = Mz + t * Pz; + if (rLow < rE && rE < rUp && fabs(Ez) < dZ) { + status |= 0x1; + tF = t; + } } } // Intersection w/ the edge in Z - double zLow = -dZ, zUp = +dZ; for (double Z: {zLow,zUp}) { + double zLow = -dZ, zUp = +dZ; + for (double Z : {zLow, zUp}) { // Mz+t*Pz = Z if (Pz) { - double t = (Z-Mz)/Pz; if (t*direction < 0) continue; - double Ex = Mx+t*Px, Ey = My+t*Py, rE = sqrt(Ex*Ex+Ey*Ey); - double phi = atan2(Ey,Ex); + double t = (Z - Mz) / Pz; + if (t * direction < 0) + continue; + double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey); + double phi = atan2(Ey, Ex); if (rLow < rE && rE < rUp && startPhi < phi && phi < endPhi) { - if (t < 0) { - if (!status || (status && t > tF)) { status |= 0x1; tF = t; } - } - else if (t > 0) { - if (!status || (status && t < tF)) { status |= 0x1; tF = t; } - } + if (t < 0) { + if (!status || (status && t > tF)) { + status |= 0x1; + tF = t; + } + } else if (t > 0) { + if (!status || (status && t < tF)) { + status |= 0x1; + tF = t; + } + } } } } // Else intersection w/ target radius if (!status) { - double a = Px*Px+Py*Py, b = Px*Mx+Py*My, c = M2-rT*rT; - if (!a) { // P is // to Z - if (!status) status |= 0x1000; // Inconsistency - } - else if (!c) { // Hit is on target - status |= 0x2000; // Inconsistency - } - else { - double det = b*b-a*c; if (det >= 0) { - double sqdet = sqrt(det); - for (int is = 0; is<2; is++) { - int s = 1-2*is; double t = (-b+s*sqdet)/a; if (t*direction < 0) continue; - double Ix = Mx+t*Px, Iy = My+t*Py, Iz = Mz+t*Pz, phi = atan2(Iy,Ix); - if (fabs(Iz) > dZ && phi < startPhi || endPhi < phi) continue; - if (!(status & 0x1) || - // Two intersects: let's retain the earliest one. - ((status & 0x1) && fabs(t) < fabs(tF))) { - tF = t; status |= 0x1; - } - } + double a = Px * Px + Py * Py, b = Px * Mx + Py * My, c = M2 - rT * rT; + if (!a) { // P is // to Z + if (!status) + status |= 0x1000; // Inconsistency + } else if (!c) { // Hit is on target + status |= 0x2000; // Inconsistency + } else { + double det = b * b - a * c; + if (det >= 0) { + double sqdet = sqrt(det); + for (int is = 0; is < 2; is++) { + int s = 1 - 2 * is; + double t = (-b + s * sqdet) / a; + if (t * direction < 0) + continue; + double Ix = Mx + t * Px, Iy = My + t * Py, Iz = Mz + t * Pz, phi = atan2(Iy, Ix); + if (fabs(Iz) > dZ && phi < startPhi || endPhi < phi) + continue; + if (!(status & 0x1) || + // Two intersects: let's retain the earliest one. + ((status & 0x1) && fabs(t) < fabs(tF))) { + tF = t; + status |= 0x1; + } + } } } } if (status) { - lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + lext[0] = Mx + tF * Px; + lext[1] = My + tF * Py; + lext[2] = Mz + tF * Pz; } return status; } -unsigned int MPGDTrackerDigi::bExtension(const double *lpos, const double *lmom, // Input subHit - double zT, // Target Z - int direction, - double dX, double dY, // Module parameters - double *lext) const -{ - unsigned int status = 0; - double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx,My}, M2 = Mx*Mx+My*My; - double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px,Py}; +unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, // Input subHit + double zT, // Target Z + int direction, double dX, double dY, // Module parameters + double* lext) const { + unsigned int status = 0; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}, M2 = Mx * Mx + My * My; + double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py}; double Mz = lpos[2], Pz = lmom[2]; - double norm = sqrt(Px*Px+Py*Py+Pz*Pz); + double norm = sqrt(Px * Px + Py * Py + Pz * Pz); // Move some distance away from , which is expected to be sitting on // the wall of the SUBVOLUME to be ``extended''. - const double margin = 10*dd4hep::um; - double t = direction*margin/norm; Mx += t*Px; My += t*Py; Mz += t*Pz; + const double margin = 10 * dd4hep::um; + double t = direction * margin / norm; + Mx += t * Px; + My += t * Py; + Mz += t * Pz; double &zIni = Mz, zLow, zUp; - if (zIni < zT) { zLow = zIni; zUp = zT; } - else { zLow = zT; zUp = zIni; } + if (zIni < zT) { + zLow = zIni; + zUp = zT; + } else { + zLow = zT; + zUp = zIni; + } // Intersection w/ the edge in X,Y - double tF = 0; - double xyLow[2] = {-dX,+dX}, xyUp[2] = {-dY,+dY}; + double tF = 0; + double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { - int yx = 1-xy; + int yx = 1 - xy; double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; - for (double A: {aLow,aUp}) { + for (double A : {aLow, aUp}) { // Mz+t*Pz = A if (Pa) { - double t = (A-Mz)/Pa; if (t*direction < 0) continue; - double Eb = Mb+t*Pb, Ez = Mz+t*Pz; - if (zLow < Ez && Ez < zUp && bLow < Eb && Eb < bUp) { - if (!status || (status && fabs(t) < fabs(tF))) { - status |= 0x1; tF = t; - } - } + double t = (A - Mz) / Pa; + if (t * direction < 0) + continue; + double Eb = Mb + t * Pb, Ez = Mz + t * Pz; + if (zLow < Ez && Ez < zUp && bLow < Eb && Eb < bUp) { + if (!status || (status && fabs(t) < fabs(tF))) { + status |= 0x1; + tF = t; + } + } } } } // Else intersection w/ target Z if (!status) { if (Pz) { - tF = (zT-Mz)/Pz; if (tF*direction > 0) status = 0x1; + tF = (zT - Mz) / Pz; + if (tF * direction > 0) + status = 0x1; } } if (status) { - lext[0] = Mx+tF*Px; lext[1] = My+tF*Py; lext[2] = Mz+tF*Pz; + lext[0] = Mx + tF * Px; + lext[1] = My + tF * Py; + lext[2] = Mz + tF * Pz; } return status; } -double getRef2Cur(DetElement refVol, DetElement curVol) -{ +double getRef2Cur(DetElement refVol, DetElement curVol) { const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); const TGeoHMatrix& toCurVol = curVol.nominal().worldTransformation(); - const double *TRef = toRefVol.GetTranslation(); - const double *TCur = toCurVol.GetTranslation(); + const double* TRef = toRefVol.GetTranslation(); + const double* TCur = toCurVol.GetTranslation(); // For some reason, it has to be "Ref-Cur", while I (Y.B) would have expected the opposite... - double gdT[3]; for (int i = 0; i < 3; i++) gdT[i] = TRef[i]-TCur[i]; - double ldT[3]; toRefVol.MasterToLocalVect(gdT,ldT); + double gdT[3]; + for (int i = 0; i < 3; i++) + gdT[i] = TRef[i] - TCur[i]; + double ldT[3]; + toRefVol.MasterToLocalVect(gdT, ldT); return ldT[2]; } -std::string inconsistency(const edm4hep::EventHeader &event, unsigned int status, - CellID cID, const double *lpos, const double *lmom) -{ +std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status, CellID cID, + const double* lpos, const double* lmom) { using edm4eic::unit::GeV, dd4hep::mm; - return fmt::format("Event {}#{}, SimHit 0x{:016x} @ {:.2f},{:.2f},{:.2f} mm, P = {:.2f},{:.2f},{:.2f} GeV inconsistency 0x{:x}", - event.getRunNumber(),event.getEventNumber(), - cID, lpos[0]/mm, lpos[1]/mm, lpos[2]/mm, - lmom[0]/GeV, lmom[1]/GeV, lmom[2]/GeV, status); + return fmt::format("Event {}#{}, SimHit 0x{:016x} @ {:.2f},{:.2f},{:.2f} mm, P = " + "{:.2f},{:.2f},{:.2f} GeV inconsistency 0x{:x}", + event.getRunNumber(), event.getEventNumber(), cID, lpos[0] / mm, lpos[1] / mm, + lpos[2] / mm, lmom[0] / GeV, lmom[1] / GeV, lmom[2] / GeV, status); } -std::string oddity(const edm4hep::EventHeader &event, unsigned int status, double dist, - CellID cID, const double *lpos, const double *lmom, - CellID cJD, const double *lpoj, const double *lmoj) -{ +std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID, + const double* lpos, const double* lmom, CellID cJD, const double* lpoj, + const double* lmoj) { using edm4eic::unit::GeV, dd4hep::mm; - return fmt::format("Event {}#{}, Bizarre SimHit sequence: 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = {:.2f},{:.2f},{:.2f} GeV and 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = {:.2f},{:.2f},{:.2f} GeV: status 0x{:x}, distance {:.4f}", - event.getRunNumber(),event.getEventNumber(), - cID, lpos[0]/mm, lpos[1]/mm, lpos[2]/mm, - lmom[0]/GeV, lmom[1]/GeV, lmom[2]/GeV, - cJD, lpoj[0]/mm, lpoj[1]/mm, lpoj[2]/mm, - lmoj[0]/GeV, lmoj[1]/GeV, lmoj[2]/GeV, - status,dist); + return fmt::format("Event {}#{}, Bizarre SimHit sequence: 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P " + "= {:.2f},{:.2f},{:.2f} GeV and 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = " + "{:.2f},{:.2f},{:.2f} GeV: status 0x{:x}, distance {:.4f}", + event.getRunNumber(), event.getEventNumber(), cID, lpos[0] / mm, lpos[1] / mm, + lpos[2] / mm, lmom[0] / GeV, lmom[1] / GeV, lmom[2] / GeV, cJD, lpoj[0] / mm, + lpoj[1] / mm, lpoj[2] / mm, lmoj[0] / GeV, lmoj[1] / GeV, lmoj[2] / GeV, + status, dist); } bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, - const edm4hep::SimTrackerHit& sim_hjt, - int unbroken) const -{ + const edm4hep::SimTrackerHit& sim_hjt, int unbroken) const { // Status: // 0: Same Particle, same Module, same Origin // 0x1: Not same // Particle using MCParticle = edm4hep::MCParticle; #if EDM4HEP_BUILD_VERSION >= EDM4HEP_VERSION(0, 99, 0) - bool sameParticle = sim_hjt.getParticle() == sim_hit.getParticle(); + bool sameParticle = sim_hjt.getParticle() == sim_hit.getParticle(); #else bool sameParticle = sim_hjt.getMCParticle() == sim_hit.getMCParticle(); #endif // Module - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => the middle slice - CellID vJD = sim_hjt.getCellID() & m_volumeBits; - CellID refJD = vJD & m_moduleBits; // => the middle slice - bool sameModule = refJD == refID; + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => the middle slice + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + CellID refJD = vJD & m_moduleBits; // => the middle slice + bool sameModule = refJD == refID; // Origin // Note: edm4hep::SimTrackerHit possesses an "Overlay" quality. Since I don't // know what this is, I ignore it. bool isSecondary = sim_hit.isProducedBySecondary(); bool jsSecondary = sim_hjt.isProducedBySecondary(); - bool sameOrigin = jsSecondary == isSecondary; + bool sameOrigin = jsSecondary == isSecondary; if (isSecondary) { // Secondary subHit // A given primary particle can give rise to several secondaries, producing // unrelated subHits that we do not want to mix. // => Let's impose more condition in that case... - sameOrigin &= unbroken; // ...Unbroken sequence of subHits + sameOrigin &= unbroken; // ...Unbroken sequence of subHits } return sameParticle && sameModule && sameOrigin; } -double outInDistance(int shape, int orientation, - double lins[][3], double louts[][3], - double *lmom, double *lmoj) -{ +double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, + double* lmoj) { // Outgoing/incoming distance - bool ok; double lext[3]; - double lmOI[3]; for (int i = 0; i < 3; i++) lmOI[i] = (lmom[i]+lmoj[i])/2; + bool ok; + double lext[3]; + double lmOI[3]; + for (int i = 0; i < 3; i++) + lmOI[i] = (lmom[i] + lmoj[i]) / 2; double *lOut, *lIn; - if (orientation > 0) { lOut = louts[1]; lIn = lins[0]; } - else if (orientation < 0) { lOut = louts[0]; lIn = lins[1]; } - else { lOut = louts[0]; lIn = lins[0]; } - if (shape == 0) { // "TGeoTubeSeg" - double rIn = sqrt(lIn [0]*lIn [0]+lIn [1]*lIn [1]); - ok = cExtrapolate(lOut,lmOI,rIn,lext); + if (orientation > 0) { + lOut = louts[1]; + lIn = lins[0]; + } else if (orientation < 0) { + lOut = louts[0]; + lIn = lins[1]; + } else { + lOut = louts[0]; + lIn = lins[0]; } - else { // "TGeoBBox" - ok = bExtrapolate(lOut,lmOI,lIn[2],lext); + if (shape == 0) { // "TGeoTubeSeg" + double rIn = sqrt(lIn[0] * lIn[0] + lIn[1] * lIn[1]); + ok = cExtrapolate(lOut, lmOI, rIn, lext); + } else { // "TGeoBBox" + ok = bExtrapolate(lOut, lmOI, lIn[2], lext); } if (ok) { - double dist2 = 0; for (int i = 0; i < 3; i++) { - double d = lext[i]-lIn[i]; dist2 += d*d; + double dist2 = 0; + for (int i = 0; i < 3; i++) { + double d = lext[i] - lIn[i]; + dist2 += d * d; } return sqrt(dist2); - } - else + } else return -1; } -unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, - double *lpini, double *lmini, double *lpend, double *lmend) const -{ - unsigned int status = 0; +unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, double* lpini, double* lmini, + double* lpend, double* lmend) const { + unsigned int status = 0; const VolumeManager& volman = m_detector->volumeManager(); - DetElement refVol = volman.lookupDetElement(refID); - const auto &shape = refVol.solid(); + DetElement refVol = volman.lookupDetElement(refID); + const auto& shape = refVol.solid(); double *lpoE, *lmoE; // Starting position/momentum - if (direction < 0) { lpoE = lpini; lmoE = lmini; } - else { lpoE = lpend; lmoE = lmend; } + if (direction < 0) { + lpoE = lpini; + lmoE = lmini; + } else { + lpoE = lpend; + lmoE = lmend; + } // Let's test both extremes of the SUBVOLUMES, in order to catch cases where // particle re-enters. - for (int rankE : {0,4}) { - CellID vIDE = refID | m_stripIDs[rankE]; + for (int rankE : {0, 4}) { + CellID vIDE = refID | m_stripIDs[rankE]; DetElement volE = volman.lookupDetElement(vIDE); double lext[3]; - if (!strcmp(shape.type(),"TGeoTubeSeg")) { - const Tube &tubE = volE.solid(); - double R = rankE == 0 ? tubE.rMin() : tubE.rMax(); - double startPhi = tubE.startPhi()*radian; startPhi -= 2*TMath::Pi(); - double endPhi = tubE.endPhi()*radian; endPhi -= 2*TMath::Pi(); + if (!strcmp(shape.type(), "TGeoTubeSeg")) { + const Tube& tubE = volE.solid(); + double R = rankE == 0 ? tubE.rMin() : tubE.rMax(); + double startPhi = tubE.startPhi() * radian; + startPhi -= 2 * TMath::Pi(); + double endPhi = tubE.endPhi() * radian; + endPhi -= 2 * TMath::Pi(); double dZ = tubE.dZ(); - status = cExtension(lpoE,lmoE,R,direction,dZ,startPhi,endPhi,lext); - } - else if (!strcmp(shape.type(),"TGeoBBox")) { + status = cExtension(lpoE, lmoE, R, direction, dZ, startPhi, endPhi, lext); + } else if (!strcmp(shape.type(), "TGeoBBox")) { const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); - double ref2E = getRef2Cur(refVol,volE); - const Box &boxE = volE.solid(); - double Z = rankE == 0 ? -boxE.z() : +boxE.z(); Z -= ref2E; + double ref2E = getRef2Cur(refVol, volE); + const Box& boxE = volE.solid(); + double Z = rankE == 0 ? -boxE.z() : +boxE.z(); + Z -= ref2E; double dX = boxE.x(), dY = boxE.y(); - status = bExtension(lpoE,lmoE,Z,direction,dX,dY,lext); - } - else status = 0x10000; + status = bExtension(lpoE, lmoE, Z, direction, dX, dY, lext); + } else + status = 0x10000; if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" return status; } - if (status != 0x1) continue; + if (status != 0x1) + continue; if (direction < 0) { - for (int i = 0; i < 3; i++) lpini[i] = lext[i]; - } - else { - for (int i = 0; i < 3; i++) lpend[i] = lext[i]; + for (int i = 0; i < 3; i++) + lpini[i] = lext[i]; + } else { + for (int i = 0; i < 3; i++) + lpend[i] = lext[i]; } break; } return status; } -bool MPGDTrackerDigi::denyExtension(const edm4hep::SimTrackerHit &sim_hit, - double depth) const -{ +bool MPGDTrackerDigi::denyExtension(const edm4hep::SimTrackerHit& sim_hit, double depth) const { // Non COALESCED secondary: do not extend... // ...if in HELPER SUBVOLUME: if it is TRAVERSING, it's probably // merely because SUBVOLUME is very thin. - CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID vID = sim_hit.getCellID() & m_volumeBits; bool isHelperVolume = m_stripRank(vID) != 0 && m_stripRank(vID) != 4; // ...else if path length is negligible compared to potential // extension (here, we cannot avoid using a built-in: 10%). const double fraction = .10; - const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm/edmm; - bool smallPathLength = sim_hit.getPathLength()*ed2dd < fraction * depth; - return isHelperVolume || smallPathLength; + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; + bool smallPathLength = sim_hit.getPathLength() * ed2dd < fraction * depth; + return isHelperVolume || smallPathLength; } -void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader &event, - int shape, double expected, - const edm4hep::SimTrackerHit &sim_hit, - double *lpini, double *lpend, - double *lpos, double *lmom) const -{ +void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected, + const edm4hep::SimTrackerHit& sim_hit, double* lpini, + double* lpend, double* lpos, double* lmom) const { // Expectation: // - Primary particle: position = middle of overall sensitive volume. // - Secondary particle: no diff w.r.t. initial. @@ -1371,20 +1555,24 @@ void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader &event, // of primary does not span the whole volume. The present, simplistic, // version of "flagUnexpected" does flag the case. This, even though // everything is perfectly under control. - double Rnew2 = 0, Znew, diff2 = 0; for (int i = 0; i<3; i++) { - double neu = (lpini[i]+lpend[i])/2, alt = lpos[i]; - double d = neu-alt; diff2 += d*d; - if (i != 2) Rnew2 += neu*neu; - if (i == 2) Znew = neu; + double Rnew2 = 0, Znew, diff2 = 0; + for (int i = 0; i < 3; i++) { + double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; + double d = neu - alt; + diff2 += d * d; + if (i != 2) + Rnew2 += neu * neu; + if (i == 2) + Znew = neu; } - double found = shape ? Znew : sqrt(Rnew2), residual = found-expected; + double found = shape ? Znew : sqrt(Rnew2), residual = found - expected; bool isSecondary = sim_hit.isProducedBySecondary(); - bool isPrimary = !isSecondary && sqrt(lmom[0]*lmom[0]+lmom[1]*lmom[1]+lmom[2]*lmom[2]) > .1*GeV; - if (fabs(residual) > .000001 && isPrimary || - sqrt(diff2) > .000001 && isSecondary) { + bool isPrimary = + !isSecondary && sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]) > .1 * GeV; + if (fabs(residual) > .000001 && isPrimary || sqrt(diff2) > .000001 && isSecondary) { debug("Event {}#{}, SimHit 0x{:016x} origin {:d}: d{:x} = {:.5f} diff = {:.5f}", - event.getRunNumber(),event.getEventNumber(), - sim_hit.getCellID(),shape?'Z':'R',isSecondary,residual,sqrt(diff2)); + event.getRunNumber(), event.getEventNumber(), sim_hit.getCellID(), shape ? 'Z' : 'R', + isSecondary, residual, sqrt(diff2)); } } diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index acb903d701..7102f1012d 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -12,7 +12,7 @@ #include //#define MC_PARTICLE_ASSOCIATION #ifdef MC_PARTICLE_ASSOCIATION -# include +#include #endif #include #include @@ -25,7 +25,8 @@ namespace eicrecon { using MPGDTrackerDigiAlgorithm = algorithms::Algorithm< #ifdef MC_PARTICLE_ASSOCIATION - algorithms::Input, + algorithms::Input, #else algorithms::Input, #endif @@ -51,47 +52,41 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, const algorithms::UniqueIDGenSvc& m_uid = algorithms::UniqueIDGenSvc::instance(); // Member methods for checking the consistency of subHits to be accumulated - unsigned int extendHit(dd4hep::CellID modID, int direction, - double *lpini, double *lmini, double *lpend, double *lmend) const; - unsigned int cExtension(double const *lpos, double const *lmom, // Input subHit - double rT, // Target radius - int direction, - double dZ, double startPhi, double endPhi, // Module parameters - double *lext) const; - unsigned int bExtension(const double *lpos, const double *lmom, // Input subHit - double zT, // Target Z - int direction, - double dX, double dY, // Module parameters - double *lext) const; - bool samePMO(const edm4hep::SimTrackerHit&, - const edm4hep::SimTrackerHit&, - int unbroken) const; - bool denyExtension(const edm4hep::SimTrackerHit &sim_hit, - double depth) const; - void flagUnexpected(const edm4hep::EventHeader &event, - int shape, double expected, - const edm4hep::SimTrackerHit &sim_hit, - double *lpini, double *lpend, - double *lpos, double *lmom) const; + unsigned int extendHit(dd4hep::CellID modID, int direction, double* lpini, double* lmini, + double* lpend, double* lmend) const; + unsigned int cExtension(double const* lpos, double const* lmom, // Input subHit + double rT, // Target radius + int direction, double dZ, double startPhi, + double endPhi, // Module parameters + double* lext) const; + unsigned int bExtension(const double* lpos, const double* lmom, // Input subHit + double zT, // Target Z + int direction, double dX, double dY, // Module parameters + double* lext) const; + bool samePMO(const edm4hep::SimTrackerHit&, const edm4hep::SimTrackerHit&, int unbroken) const; + bool denyExtension(const edm4hep::SimTrackerHit& sim_hit, double depth) const; + void flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected, + const edm4hep::SimTrackerHit& sim_hit, double* lpini, double* lpend, + double* lpos, double* lmom) const; /** Segmentation */ const dd4hep::Detector* m_detector{nullptr}; dd4hep::Segmentation m_seg; // Built-in constants specifying IDDescriptor fields. // The "init" should method double-check these are actually implemented in the XMLs of MPGDs. - static constexpr dd4hep::CellID m_volumeBits = 0xffffffff; // 32 least weight bits - static constexpr dd4hep::CellID m_stripBits = ((dd4hep::CellID)0xf)<<28; - static constexpr dd4hep::CellID m_stripMask = ~m_stripBits; - static constexpr dd4hep::CellID m_moduleBits = m_volumeBits & m_stripMask; - static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1)<<28; - static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2)<<28; - static constexpr dd4hep::CellID m_stripIDs[5] = - { ((dd4hep::CellID)0x3)<<28, m_pStripBit, 0, m_nStripBit, ((dd4hep::CellID)0x4)<<28 }; + static constexpr dd4hep::CellID m_volumeBits = 0xffffffff; // 32 least weight bits + static constexpr dd4hep::CellID m_stripBits = ((dd4hep::CellID)0xf) << 28; + static constexpr dd4hep::CellID m_stripMask = ~m_stripBits; + static constexpr dd4hep::CellID m_moduleBits = m_volumeBits & m_stripMask; + static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1) << 28; + static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2) << 28; + static constexpr dd4hep::CellID m_stripIDs[5] = {((dd4hep::CellID)0x3) << 28, m_pStripBit, 0, + m_nStripBit, ((dd4hep::CellID)0x4) << 28}; /** Ordering of Multiple Sensitive Volumes */ std::function m_stripRank; - std::function m_orientation; - std::function m_isUpstream; - std::function m_isDownstream; + std::function m_orientation; + std::function m_isUpstream; + std::function m_isDownstream; }; } // namespace eicrecon From 778a2a5d6b797d7c24d4b5d303697396a35422d0 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 6 Nov 2025 20:00:29 +0100 Subject: [PATCH 03/47] MPGDTrackerDigi.cc: Fix compilation warnings. --- src/algorithms/digi/MPGDTrackerDigi.cc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 2cc8edd0fe..d2aa00c417 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -153,7 +153,7 @@ void MPGDTrackerDigi::init() { } // Ordering of SUBVOLUMES (based on "STRIP" FIELD) - m_stripRank = [=](CellID vID) { + m_stripRank = [=,this](CellID vID) { int rank; CellID sID = vID & m_stripBits; for (rank = 0; rank < 5; rank++) @@ -161,7 +161,7 @@ void MPGDTrackerDigi::init() { return rank; return -1; }; - m_orientation = [=](CellID vID, CellID vJD) { + m_orientation = [=,this](CellID vID, CellID vJD) { int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); if (rankj > ranki) return +1; @@ -557,7 +557,6 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, } } // ij-Compatibility: close exit/entrance-distance - double zMin = -dZ - ref2j, zMax = dZ - ref2j; double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj); const double tolerance = 25 * dd4hep::um; bool isCompatible = dist > 0 && dist < tolerance; @@ -1011,7 +1010,7 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double dX, double dY, // Module parameters double lins[][3], double louts[][3], double* lpini, double* lpend) { unsigned int status = 0; - double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}, M2 = Mx * Mx + My * My; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}; double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py}; double Mz = lpos[2] + ref2Cur, Pz = lmom[2]; // Intersection w/ the edge in X,Y @@ -1019,7 +1018,7 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { int yx = 1 - xy; - double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; + double aLow = xyLow[xy], aUp = xyUp[xy]; double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; for (double A : {aLow, aUp}) { // Mz+t*Pz = A @@ -1289,7 +1288,7 @@ unsigned int MPGDTrackerDigi::cExtension(double const* lpos, double const* lmom, if (t * direction < 0) continue; double Ix = Mx + t * Px, Iy = My + t * Py, Iz = Mz + t * Pz, phi = atan2(Iy, Ix); - if (fabs(Iz) > dZ && phi < startPhi || endPhi < phi) + if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi) continue; if (!(status & 0x1) || // Two intersects: let's retain the earliest one. @@ -1313,7 +1312,7 @@ unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, int direction, double dX, double dY, // Module parameters double* lext) const { unsigned int status = 0; - double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}, M2 = Mx * Mx + My * My; + double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}; double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py}; double Mz = lpos[2], Pz = lmom[2]; double norm = sqrt(Px * Px + Py * Py + Pz * Pz); @@ -1337,7 +1336,7 @@ unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { int yx = 1 - xy; - double aLow = xyLow[xy], aUp = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy]; + double aLow = xyLow[xy], aUp = xyUp[xy]; double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; for (double A : {aLow, aUp}) { // Mz+t*Pz = A @@ -1439,8 +1438,8 @@ bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, return sameParticle && sameModule && sameOrigin; } -double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, - double* lmoj) { +double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], + double* lmom, double* lmoj) { // Outgoing/incoming distance bool ok; double lext[3]; @@ -1505,7 +1504,6 @@ unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, double* lpi double dZ = tubE.dZ(); status = cExtension(lpoE, lmoE, R, direction, dZ, startPhi, endPhi, lext); } else if (!strcmp(shape.type(), "TGeoBBox")) { - const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); double ref2E = getRef2Cur(refVol, volE); const Box& boxE = volE.solid(); double Z = rankE == 0 ? -boxE.z() : +boxE.z(); @@ -1569,7 +1567,8 @@ void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader& event, int shap bool isSecondary = sim_hit.isProducedBySecondary(); bool isPrimary = !isSecondary && sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]) > .1 * GeV; - if (fabs(residual) > .000001 && isPrimary || sqrt(diff2) > .000001 && isSecondary) { + if ((fabs(residual) > .000001 && isPrimary) || + (sqrt(diff2) > .000001 && isSecondary)) { debug("Event {}#{}, SimHit 0x{:016x} origin {:d}: d{:x} = {:.5f} diff = {:.5f}", event.getRunNumber(), event.getEventNumber(), sim_hit.getCellID(), shape ? 'Z' : 'R', isSecondary, residual, sqrt(diff2)); From ca4e3dcc446fe0f301f85df0476d946e9b2d549f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:04:30 +0000 Subject: [PATCH 04/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index d2aa00c417..349aa25f2b 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -153,7 +153,7 @@ void MPGDTrackerDigi::init() { } // Ordering of SUBVOLUMES (based on "STRIP" FIELD) - m_stripRank = [=,this](CellID vID) { + m_stripRank = [=, this](CellID vID) { int rank; CellID sID = vID & m_stripBits; for (rank = 0; rank < 5; rank++) @@ -161,7 +161,7 @@ void MPGDTrackerDigi::init() { return rank; return -1; }; - m_orientation = [=,this](CellID vID, CellID vJD) { + m_orientation = [=, this](CellID vID, CellID vJD) { int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); if (rankj > ranki) return +1; @@ -1438,8 +1438,8 @@ bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, return sameParticle && sameModule && sameOrigin; } -double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], - double* lmom, double* lmoj) { +double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, + double* lmoj) { // Outgoing/incoming distance bool ok; double lext[3]; @@ -1504,9 +1504,9 @@ unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, double* lpi double dZ = tubE.dZ(); status = cExtension(lpoE, lmoE, R, direction, dZ, startPhi, endPhi, lext); } else if (!strcmp(shape.type(), "TGeoBBox")) { - double ref2E = getRef2Cur(refVol, volE); - const Box& boxE = volE.solid(); - double Z = rankE == 0 ? -boxE.z() : +boxE.z(); + double ref2E = getRef2Cur(refVol, volE); + const Box& boxE = volE.solid(); + double Z = rankE == 0 ? -boxE.z() : +boxE.z(); Z -= ref2E; double dX = boxE.x(), dY = boxE.y(); status = bExtension(lpoE, lmoE, Z, direction, dX, dY, lext); @@ -1567,8 +1567,7 @@ void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader& event, int shap bool isSecondary = sim_hit.isProducedBySecondary(); bool isPrimary = !isSecondary && sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]) > .1 * GeV; - if ((fabs(residual) > .000001 && isPrimary) || - (sqrt(diff2) > .000001 && isSecondary)) { + if ((fabs(residual) > .000001 && isPrimary) || (sqrt(diff2) > .000001 && isSecondary)) { debug("Event {}#{}, SimHit 0x{:016x} origin {:d}: d{:x} = {:.5f} diff = {:.5f}", event.getRunNumber(), event.getEventNumber(), sim_hit.getCellID(), shape ? 'Z' : 'R', isSecondary, residual, sqrt(diff2)); From 85fda0d960bf596a3e2d8b3e0c4ece699c824894 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 6 Nov 2025 20:41:54 +0100 Subject: [PATCH 05/47] MPGDTrackerDigi.cc: Fix codespell issues. --- src/algorithms/digi/MPGDTrackerDigi.cc | 86 +++++++++++++------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 349aa25f2b..b85a10f92d 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -195,7 +195,7 @@ unsigned int cTraversing(const double* lpos, const double* lmom, double path, bool isSecondary, // Input subHit double rMin, double rMax, // Current instance of SUBVOLUME double dZ, double startPhi, double endPhi, // Module parameters - double lins[][3], double louts[][3], double* lpini, double* lpend); + double lintos[][3], double louts[][3], double* lpini, double* lpend); bool cExtrapolate(const double* lpos, const double* lmom, // Input subHit double rT, // Target radius double* lext); // Extrapolated position @ @@ -204,7 +204,7 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, bool isSecondary, // Input subHit double dZ, // Current instance of SUBVOLUME double dX, double dY, // Module parameters - double lins[][3], double louts[][3], double* lpini, double* lpend); + double lintos[][3], double louts[][3], double* lpini, double* lpend); bool bExtrapolate(const double* lpos, const double* lmom, // Input subHit double zT, // Target Z double* lext); // Extrapolated position @ @@ -213,7 +213,7 @@ std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID, const double* lpos, const double* lmom, CellID cJD, const double* lpoj, const double* lmoj); -double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, +double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], double* lmom, double* lmoj); void flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected, const edm4hep::SimTrackerHit& sim_hit, double* lpini, double* lpend, @@ -240,7 +240,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // Reference to event, to be used to document "critical" error messages // (N.B.: I don't know how to properly handle these "headers": may there - // be ore than one? none?...) + // be more than one? none?...) const edm4hep::EventHeader& header = headers->at(0); std::vector usedHits; @@ -319,11 +319,11 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, const Tube& tCur = curVol.solid(); double rMin = tCur.rMin(), rMax = tCur.rMax(); // Is TRAVERSING? - double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), - rMin, rMax, dZ, startPhi, endPhi, lins, louts, lpini, lpend); + rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); continue; @@ -483,11 +483,11 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, double dZ = bCur.z(); double ref2Cur = getRef2Cur(refVol, curVol); // Is TRAVERSING? - double lins[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), dZ, dX, dY, lins, louts, lpini, lpend); + sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); continue; @@ -758,7 +758,7 @@ void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& to // 0x10: Enters through edge // 0x20: Exits through edge // 0xff000: Inconsistency... -// - /: Positions @ lower/upper wall upon Enter-/Exit-ing (when endorsed by ) +// - /: Positions @ lower/upper wall upon Enter-/Exit-ing (when endorsed by ) // - /: Positions of extrema // - Tolerance? For MIPs, a tolerance of 1 µM works fine. But for lower energy, // looks like we need something somewhat larger. The ideal would be to base @@ -773,7 +773,7 @@ unsigned int cTraversing(const double* lpos, const double* lmom, double path, bool isSecondary, // Input subHit double rMin, double rMax, // Current instance of SUBVOLUME double dZ, double startPhi, double endPhi, // Module parameters - double lins[][3], double louts[][3], double* lpini, double* lpend) { + double lintos[][3], double louts[][3], double* lpini, double* lpend) { unsigned int status = 0; double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx * Mx + My * My; double Px = lmom[0], Py = lmom[1], Pz = lmom[2]; @@ -991,9 +991,9 @@ unsigned int cTraversing(const double* lpos, const double* lmom, double path, unsigned int statvs = lu ? 0x4 : 0x1; double tIn = ts[lu][0], tOut = ts[lu][1]; if (status & statvs) { - lins[lu][0] = Mx + tIn * Px; - lins[lu][1] = My + tIn * Py; - lins[lu][2] = Mz + tIn * Pz; + lintos[lu][0] = Mx + tIn * Px; + lintos[lu][1] = My + tIn * Py; + lintos[lu][2] = Mz + tIn * Pz; } statvs <<= 1; if (status & statvs) { @@ -1008,7 +1008,7 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, bool isSecondary, // Input subHit double dZ, // Current instance of SUBVOLUME double dX, double dY, // Module parameters - double lins[][3], double louts[][3], double* lpini, double* lpend) { + double lintos[][3], double louts[][3], double* lpini, double* lpend) { unsigned int status = 0; double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My}; double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py}; @@ -1018,14 +1018,14 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { int yx = 1 - xy; - double aLow = xyLow[xy], aUp = xyUp[xy]; - double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; - for (double A : {aLow, aUp}) { + double a_Low = xyLow[xy], a_Up = xyUp[xy], Pa = Pxy[xy]; + double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; + for (double A : {a_Low, a_Up}) { // Mz+t*Pz = A if (Pa) { double t = (A - Mz) / Pa; double Eb = Mb + t * Pb, Ez = Mz + t * Pz; - if (bLow < Eb && Eb < bUp && fabs(Ez) < dZ) { + if (b_Low < Eb && Eb < b_Up && fabs(Ez) < dZ) { if (t < 0) { if (!(status & 0x10) || ((status & 0x10) && t > tIn)) { status |= 0x10; @@ -1125,9 +1125,9 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, for (int lu = 0; lu < 2; lu++) { unsigned int statvs = lu ? 0x4 : 0x1; if (status & statvs) { - lins[lu][0] = Mx + tIn * Px; - lins[lu][1] = My + tIn * Py; - lins[lu][2] = Mz + tIn * Pz; + lintos[lu][0] = Mx + tIn * Px; + lintos[lu][1] = My + tIn * Py; + lintos[lu][2] = Mz + tIn * Pz; } statvs <<= 1; if (status & statvs) { @@ -1336,16 +1336,16 @@ unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { int yx = 1 - xy; - double aLow = xyLow[xy], aUp = xyUp[xy]; - double bLow = xyLow[yx], bUp = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; - for (double A : {aLow, aUp}) { + double a_Low = xyLow[xy], a_Up = xyUp[xy], Pa = Pxy[xy]; + double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; + for (double A : {a_Low, a_Up}) { // Mz+t*Pz = A if (Pa) { double t = (A - Mz) / Pa; if (t * direction < 0) continue; double Eb = Mb + t * Pb, Ez = Mz + t * Pz; - if (zLow < Ez && Ez < zUp && bLow < Eb && Eb < bUp) { + if (zLow < Ez && Ez < zUp && b_Low < Eb && Eb < b_Up) { if (!status || (status && fabs(t) < fabs(tF))) { status |= 0x1; tF = t; @@ -1438,35 +1438,35 @@ bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, return sameParticle && sameModule && sameOrigin; } -double outInDistance(int shape, int orientation, double lins[][3], double louts[][3], double* lmom, +double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], double* lmom, double* lmoj) { // Outgoing/incoming distance bool ok; - double lext[3]; + double lExt[3]; double lmOI[3]; for (int i = 0; i < 3; i++) lmOI[i] = (lmom[i] + lmoj[i]) / 2; - double *lOut, *lIn; + double *lOut, *lInto; if (orientation > 0) { lOut = louts[1]; - lIn = lins[0]; + lInto = lintos[0]; } else if (orientation < 0) { lOut = louts[0]; - lIn = lins[1]; + lInto = lintos[1]; } else { lOut = louts[0]; - lIn = lins[0]; + lInto = lintos[0]; } if (shape == 0) { // "TGeoTubeSeg" - double rIn = sqrt(lIn[0] * lIn[0] + lIn[1] * lIn[1]); - ok = cExtrapolate(lOut, lmOI, rIn, lext); + double rInto = sqrt(lInto[0] * lInto[0] + lInto[1] * lInto[1]); + ok = cExtrapolate(lOut, lmOI, rInto, lExt); } else { // "TGeoBBox" - ok = bExtrapolate(lOut, lmOI, lIn[2], lext); + ok = bExtrapolate(lOut, lmOI, lInto[2], lExt); } if (ok) { double dist2 = 0; for (int i = 0; i < 3; i++) { - double d = lext[i] - lIn[i]; + double d = lExt[i] - lInto[i]; dist2 += d * d; } return sqrt(dist2); @@ -1495,20 +1495,20 @@ unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, double* lpi DetElement volE = volman.lookupDetElement(vIDE); double lext[3]; if (!strcmp(shape.type(), "TGeoTubeSeg")) { - const Tube& tubE = volE.solid(); - double R = rankE == 0 ? tubE.rMin() : tubE.rMax(); - double startPhi = tubE.startPhi() * radian; + const Tube& tExt = volE.solid(); + double R = rankE == 0 ? tExt.rMin() : tExt.rMax(); + double startPhi = tExt.startPhi() * radian; startPhi -= 2 * TMath::Pi(); - double endPhi = tubE.endPhi() * radian; + double endPhi = tExt.endPhi() * radian; endPhi -= 2 * TMath::Pi(); - double dZ = tubE.dZ(); + double dZ = tExt.dZ(); status = cExtension(lpoE, lmoE, R, direction, dZ, startPhi, endPhi, lext); } else if (!strcmp(shape.type(), "TGeoBBox")) { double ref2E = getRef2Cur(refVol, volE); - const Box& boxE = volE.solid(); - double Z = rankE == 0 ? -boxE.z() : +boxE.z(); + const Box& bExt = volE.solid(); + double Z = rankE == 0 ? -bExt.z() : +bExt.z(); Z -= ref2E; - double dX = boxE.x(), dY = boxE.y(); + double dX = bExt.x(), dY = bExt.y(); status = bExtension(lpoE, lmoE, Z, direction, dX, dY, lext); } else status = 0x10000; From 961a3eb7d11cba75c479c87b31e756e60f691f0c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:42:35 +0000 Subject: [PATCH 06/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index b85a10f92d..d769f02781 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -213,8 +213,8 @@ std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID, const double* lpos, const double* lmom, CellID cJD, const double* lpoj, const double* lmoj); -double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], double* lmom, - double* lmoj); +double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], + double* lmom, double* lmoj); void flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected, const edm4hep::SimTrackerHit& sim_hit, double* lpini, double* lpend, double* lpos, double* lmom); @@ -1017,7 +1017,7 @@ unsigned int bTraversing(const double* lpos, const double* lmom, double ref2Cur, double tIn = 0, tOut = 0; double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { - int yx = 1 - xy; + int yx = 1 - xy; double a_Low = xyLow[xy], a_Up = xyUp[xy], Pa = Pxy[xy]; double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; for (double A : {a_Low, a_Up}) { @@ -1335,7 +1335,7 @@ unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, double tF = 0; double xyLow[2] = {-dX, +dX}, xyUp[2] = {-dY, +dY}; for (int xy = 0; xy < 2; xy++) { - int yx = 1 - xy; + int yx = 1 - xy; double a_Low = xyLow[xy], a_Up = xyUp[xy], Pa = Pxy[xy]; double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx]; for (double A : {a_Low, a_Up}) { @@ -1438,8 +1438,8 @@ bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, return sameParticle && sameModule && sameOrigin; } -double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], double* lmom, - double* lmoj) { +double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3], + double* lmom, double* lmoj) { // Outgoing/incoming distance bool ok; double lExt[3]; @@ -1448,14 +1448,14 @@ double outInDistance(int shape, int orientation, double lintos[][3], double lout lmOI[i] = (lmom[i] + lmoj[i]) / 2; double *lOut, *lInto; if (orientation > 0) { - lOut = louts[1]; - lInto = lintos[0]; + lOut = louts[1]; + lInto = lintos[0]; } else if (orientation < 0) { - lOut = louts[0]; - lInto = lintos[1]; + lOut = louts[0]; + lInto = lintos[1]; } else { - lOut = louts[0]; - lInto = lintos[0]; + lOut = louts[0]; + lInto = lintos[0]; } if (shape == 0) { // "TGeoTubeSeg" double rInto = sqrt(lInto[0] * lInto[0] + lInto[1] * lInto[1]); From e6bce9669a0fc544ede739fd15affe6c81afe224 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Fri, 7 Nov 2025 07:59:20 +0100 Subject: [PATCH 07/47] MPGDTrackerDigi.cc: Getting rid of "dangling-reference" compilation warning. --- src/algorithms/digi/MPGDTrackerDigi.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index b85a10f92d..1b32a102eb 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -181,9 +181,9 @@ void MPGDTrackerDigi::init() { m_isDownstream = [](int orientation, unsigned int status) { // Incoming particle enters... bool isDownstream = - (orientation > 0 && (status & 0x1)) || // ...lower wall - (orientation < 0 && (status & 0x4)) || // ...upper wall - (orientation == 0 && (status & 0101) == 0x101); // ...lower wall and can be reEntering + (orientation > 0 && (status & 0x1)) || // ...lower wall + (orientation < 0 && (status & 0x4)) || // ...upper wall + (orientation == 0 && (status & 0x101) == 0x101); // ...lower wall and can be reEntering return isDownstream; }; } @@ -285,7 +285,9 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, CellID vID = sim_hit.getCellID() & m_volumeBits; CellID refID = vID & m_moduleBits; // => the middle slice DetElement refVol = volman.lookupDetElement(refID); - const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); + // TGeoHMatrix: In order to avoid a "dangling-reference" warning, + // let's take a copy of the matrix instead of a reference to it. + const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); double lpos[3], lmom[3]; getLocalPosMom(sim_hit, toRefVol, lpos, lmom); const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; @@ -1371,8 +1373,10 @@ unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom, } double getRef2Cur(DetElement refVol, DetElement curVol) { - const TGeoHMatrix& toRefVol = refVol.nominal().worldTransformation(); - const TGeoHMatrix& toCurVol = curVol.nominal().worldTransformation(); + // TGeoHMatrix: In order to avoid a "dangling-reference" warning, + // let's take a copy of the matrix instead of a reference to it. + const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); + const TGeoHMatrix toCurVol = curVol.nominal().worldTransformation(); const double* TRef = toRefVol.GetTranslation(); const double* TCur = toCurVol.GetTranslation(); // For some reason, it has to be "Ref-Cur", while I (Y.B) would have expected the opposite... From ec482b8ded92b634a29330997eaf8bb062ed1e0e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:04:06 +0000 Subject: [PATCH 08/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 7bb3d26a7e..cd38b25b89 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -282,9 +282,9 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // "CyMBaL") disregard the _global_ position argument to // "dd4hep::Segmentation::cellID", we need the _local_ position and // only that. - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => the middle slice - DetElement refVol = volman.lookupDetElement(refID); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => the middle slice + DetElement refVol = volman.lookupDetElement(refID); // TGeoHMatrix: In order to avoid a "dangling-reference" warning, // let's take a copy of the matrix instead of a reference to it. const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); @@ -1377,8 +1377,8 @@ double getRef2Cur(DetElement refVol, DetElement curVol) { // let's take a copy of the matrix instead of a reference to it. const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); const TGeoHMatrix toCurVol = curVol.nominal().worldTransformation(); - const double* TRef = toRefVol.GetTranslation(); - const double* TCur = toCurVol.GetTranslation(); + const double* TRef = toRefVol.GetTranslation(); + const double* TCur = toCurVol.GetTranslation(); // For some reason, it has to be "Ref-Cur", while I (Y.B) would have expected the opposite... double gdT[3]; for (int i = 0; i < 3; i++) From 831aed82b48ad6addfbcaccf58e6b4636b531b67 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Fri, 7 Nov 2025 12:49:29 +0100 Subject: [PATCH 09/47] MPGDTrackerDigi.cc: Fix compilation warning. --- src/algorithms/digi/MPGDTrackerDigi.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 7bb3d26a7e..a1a3fb9902 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -1415,7 +1415,6 @@ bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit, // 0: Same Particle, same Module, same Origin // 0x1: Not same // Particle - using MCParticle = edm4hep::MCParticle; #if EDM4HEP_BUILD_VERSION >= EDM4HEP_VERSION(0, 99, 0) bool sameParticle = sim_hjt.getParticle() == sim_hit.getParticle(); #else From 6bfac70d9057e8589f4f64526e1209b1ad7b6b7e Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 7 Nov 2025 16:28:43 -0500 Subject: [PATCH 10/47] `[=, this]` -> `[&]` ``` /home/runner/work/EICrecon/EICrecon/src/algorithms/digi/MPGDTrackerDigi.cc:156:21: error: lambda capture 'this' is not used [-Werror,-Wunused-lambda-capture] 156 | m_stripRank = [=, this](CellID vID) { | ~~^~~~ 1 error generated. ``` --- src/algorithms/digi/MPGDTrackerDigi.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 2620a1fc7c..87d53ede94 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -153,7 +153,7 @@ void MPGDTrackerDigi::init() { } // Ordering of SUBVOLUMES (based on "STRIP" FIELD) - m_stripRank = [=, this](CellID vID) { + m_stripRank = [&](CellID vID) { int rank; CellID sID = vID & m_stripBits; for (rank = 0; rank < 5; rank++) @@ -161,7 +161,7 @@ void MPGDTrackerDigi::init() { return rank; return -1; }; - m_orientation = [=, this](CellID vID, CellID vJD) { + m_orientation = [&](CellID vID, CellID vJD) { int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); if (rankj > ranki) return +1; From 6f4dcd77368c8a66f1c7234be67dfaaa006823e0 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Fri, 7 Nov 2025 17:31:22 -0600 Subject: [PATCH 11/47] =?UTF-8?q?MPGDTrackerDigi:=20Multi-SensitiveVolume?= =?UTF-8?q?=20solution=20for=20the=202D-strip=20read=E2=80=A6=20(fix:=20iw?= =?UTF-8?q?yu)=20(#2180)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/19181728533. Please merge this PR into the branch `MultiSensitiveMPGD` to resolve failures in PR #2177. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 12 +++++++----- src/algorithms/digi/MPGDTrackerDigi.h | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 87d53ede94..6ed14604da 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -98,21 +99,26 @@ #include #include #include +#include +#include // Access "algorithms:GeoSvc" #include #include +#include #include #include #include #include -#include #include +#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -120,10 +126,6 @@ #include "algorithms/digi/MPGDTrackerDigiConfig.h" -#include "DDRec/SurfaceManager.h" -#include "DDRec/SurfaceHelper.h" -#include "DDRec/Surface.h" - using namespace dd4hep; namespace eicrecon { diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 7102f1012d..69e47dc071 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #ifdef MC_PARTICLE_ASSOCIATION #include #endif +#include #include #include From 6f83484e04877bf15571fd2231b60c05c3c6f7f6 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Sat, 8 Nov 2025 15:55:17 +0100 Subject: [PATCH 12/47] MPGDTrackerDigi.cc: Implement Clang-Tidy suggestions. --- src/algorithms/digi/MPGDTrackerDigi.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 6ed14604da..167381a228 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -110,8 +110,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -156,21 +156,26 @@ void MPGDTrackerDigi::init() { // Ordering of SUBVOLUMES (based on "STRIP" FIELD) m_stripRank = [&](CellID vID) { - int rank; CellID sID = vID & m_stripBits; - for (rank = 0; rank < 5; rank++) - if (sID == m_stripIDs[rank]) + for (int rank = 0; rank < 5; rank++) { + if (sID == m_stripIDs[rank]) { return rank; + } + } return -1; }; m_orientation = [&](CellID vID, CellID vJD) { - int ranki = m_stripRank(vID), rankj = m_stripRank(vJD); - if (rankj > ranki) + int ranki = m_stripRank(vID); + int rankj = m_stripRank(vJD); + if (rankj > ranki) { return +1; - else if (rankj < ranki) + } + else if (rankj < ranki) { return -1; - else + } + else { return 0; + } }; m_isUpstream = [](int orientation, unsigned int status) { // Outgoing particle exits... From ce5c92b320e44ab3878f8a97a127a029b9a20930 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:56:13 +0000 Subject: [PATCH 13/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 167381a228..1c5c02a7e8 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -169,11 +169,9 @@ void MPGDTrackerDigi::init() { int rankj = m_stripRank(vJD); if (rankj > ranki) { return +1; - } - else if (rankj < ranki) { + } else if (rankj < ranki) { return -1; - } - else { + } else { return 0; } }; From f7094540791de07c5bb485b0c5938a6a494d7c89 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Sat, 8 Nov 2025 16:29:44 +0100 Subject: [PATCH 14/47] Update src/algorithms/digi/MPGDTrackerDigi.cc by Clang-Tidy. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 1c5c02a7e8..b71978d6bf 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -169,7 +169,7 @@ void MPGDTrackerDigi::init() { int rankj = m_stripRank(vJD); if (rankj > ranki) { return +1; - } else if (rankj < ranki) { + } if (rankj < ranki) { return -1; } else { return 0; From 4d27afaa5adcc364403f319b5cd941eaef41b101 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:29:53 +0000 Subject: [PATCH 15/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index b71978d6bf..7d65523eaa 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -169,7 +169,8 @@ void MPGDTrackerDigi::init() { int rankj = m_stripRank(vJD); if (rankj > ranki) { return +1; - } if (rankj < ranki) { + } + if (rankj < ranki) { return -1; } else { return 0; From 9aec43163a3726a1f3ec07b2e656c29efac027ea Mon Sep 17 00:00:00 2001 From: ybedfer Date: Sat, 8 Nov 2025 21:06:03 +0100 Subject: [PATCH 16/47] Update src/algorithms/digi/MPGDTrackerDigi.cc by Clang-Tidy. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 7d65523eaa..863c94e625 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -172,9 +172,8 @@ void MPGDTrackerDigi::init() { } if (rankj < ranki) { return -1; - } else { - return 0; - } + } return 0; + }; m_isUpstream = [](int orientation, unsigned int status) { // Outgoing particle exits... From d1c963ac0e9cb1b24dee7b05d493c6690f64de37 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 20:06:13 +0000 Subject: [PATCH 17/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 863c94e625..3c9ed88dad 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -172,8 +172,8 @@ void MPGDTrackerDigi::init() { } if (rankj < ranki) { return -1; - } return 0; - + } + return 0; }; m_isUpstream = [](int orientation, unsigned int status) { // Outgoing particle exits... From 6ed9bd5ac6437f394830a9d339536365cf2644de Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Mon, 17 Nov 2025 00:00:04 +0100 Subject: [PATCH 18/47] TrackerMeasurementFromHits: Rotate the cov. matrix of OuterMPGDBarrel. This, when it happens to use UV segmentation. --- .../tracking/TrackerMeasurementFromHits.cc | 59 ++++++++++++++++++- .../tracking/TrackerMeasurementFromHits.h | 4 ++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index c8cf74050a..eee774f8cf 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -13,10 +13,16 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include +// Access "algorithms:GeoSvc" +#include #include #include #include @@ -34,6 +40,44 @@ namespace eicrecon { void TrackerMeasurementFromHits::init() { m_detid_b0tracker = m_dd4hepGeo->constant("B0Tracker_Station_1_ID"); + // OuterMPGDBarrel: + std::string readout = "OuterMPGDBarrelHits"; + // If "CartesianGridUV" segmentation, we need to rotate the cov. matrix. + // Particularly when 2D-strip readout, with large uncertainty along strips. + // i) Determine whether "CartesianGridUV", possibly embedded in a + // MultiSegmentation (discriminating on a "strip" IDDescriptor field). + // ii) If indeed, set "m_detid_OuterMPGD" to single out corresponding hits. + unsigned int required = 0, fulfilled = 0; + const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector();; + dd4hep::Segmentation seg; + try { + seg = detector->readout(readout).segmentation(); + } catch (...) { + critical("Failed to load Segmentation for \"{}\" readout.", readout); + throw JException("Failed to load ID Segmentation"); + } + using Segmentation = dd4hep::DDSegmentation::Segmentation; + const Segmentation *segmentation = seg->segmentation; + if (segmentation->type() == "MultiSegmentation"){ + required = m_pStripBit | m_nStripBit; + using MultiSegmentation = dd4hep::DDSegmentation::MultiSegmentation; + const auto* multiSeg = + dynamic_cast(segmentation); + for (dd4hep::CellID stripID : {m_pStripBit,m_nStripBit}) { + const Segmentation& stripSeg = multiSeg->subsegmentation(stripID); + if (stripSeg.type() == "CartesianGridUV") fulfilled |= stripID; + } + } + else { + required = 0x1; + if (segmentation->type() == "CartesianGridUV") fulfilled = 0x1; + } + if (required == fulfilled) { + m_detid_OuterMPGD = m_dd4hepGeo->constant("TrackerBarrel_5_ID"); + } + else { + m_detid_OuterMPGD = 0; + } } void TrackerMeasurementFromHits::process(const Input& input, const Output& output) const { @@ -50,10 +94,24 @@ void TrackerMeasurementFromHits::process(const Input& input, const Output& outpu // For now, one hit = one measurement. for (const auto& hit : *trk_hits) { + auto hit_det = hit.getCellID() & 0xFF; + Acts::SquareMatrix2 cov = Acts::SquareMatrix2::Zero(); cov(0, 0) = hit.getPositionError().xx * mm_acts * mm_acts; // note mm = 1 (Acts) cov(1, 1) = hit.getPositionError().yy * mm_acts * mm_acts; cov(0, 1) = cov(1, 0) = 0.0; + if (hit_det==m_detid_OuterMPGD){ + const double sqrt2o2 = sqrt(2)/2; + const Acts::RotationMatrix2 rot { + { sqrt2o2, sqrt2o2}, + {-sqrt2o2, sqrt2o2} + }; + const Acts::RotationMatrix2 inv { + { sqrt2o2,-sqrt2o2}, + { sqrt2o2, sqrt2o2} + }; + cov = rot*cov*inv; + } const auto* vol_ctx = m_converter->findContext(hit.getCellID()); auto vol_id = vol_ctx->identifier; @@ -75,7 +133,6 @@ void TrackerMeasurementFromHits::process(const Input& input, const Output& outpu const auto& hit_pos = hit.getPosition(); // 3d position Acts::Vector2 pos; - auto hit_det = hit.getCellID() & 0xFF; auto onSurfaceTolerance = 0.1 * Acts::UnitConstants::um; // By default, ACTS uses 0.1 micron as the on surface tolerance diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.h b/src/algorithms/tracking/TrackerMeasurementFromHits.h index 127e9f7207..eb80541e4f 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.h +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.h @@ -46,6 +46,10 @@ class TrackerMeasurementFromHits : public TrackerMeasurementFromHitsAlgorithm, /// Detector-specific information unsigned long m_detid_b0tracker; + unsigned long m_detid_OuterMPGD; + static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1) << 28; + static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2) << 28; + }; } // namespace eicrecon From 81d460021a7db3b1615b6dabd4346b4b81ba8195 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 16 Nov 2025 23:02:51 +0000 Subject: [PATCH 19/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../tracking/TrackerMeasurementFromHits.cc | 48 ++++++++----------- .../tracking/TrackerMeasurementFromHits.h | 5 +- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index eee774f8cf..69b1806b30 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -42,40 +42,40 @@ void TrackerMeasurementFromHits::init() { m_detid_b0tracker = m_dd4hepGeo->constant("B0Tracker_Station_1_ID"); // OuterMPGDBarrel: std::string readout = "OuterMPGDBarrelHits"; - // If "CartesianGridUV" segmentation, we need to rotate the cov. matrix. + // If "CartesianGridUV" segmentation, we need to rotate the cov. matrix. // Particularly when 2D-strip readout, with large uncertainty along strips. // i) Determine whether "CartesianGridUV", possibly embedded in a // MultiSegmentation (discriminating on a "strip" IDDescriptor field). // ii) If indeed, set "m_detid_OuterMPGD" to single out corresponding hits. unsigned int required = 0, fulfilled = 0; - const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector();; + const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector(); + ; dd4hep::Segmentation seg; try { - seg = detector->readout(readout).segmentation(); + seg = detector->readout(readout).segmentation(); } catch (...) { critical("Failed to load Segmentation for \"{}\" readout.", readout); throw JException("Failed to load ID Segmentation"); } - using Segmentation = dd4hep::DDSegmentation::Segmentation; - const Segmentation *segmentation = seg->segmentation; - if (segmentation->type() == "MultiSegmentation"){ - required = m_pStripBit | m_nStripBit; + using Segmentation = dd4hep::DDSegmentation::Segmentation; + const Segmentation* segmentation = seg->segmentation; + if (segmentation->type() == "MultiSegmentation") { + required = m_pStripBit | m_nStripBit; using MultiSegmentation = dd4hep::DDSegmentation::MultiSegmentation; - const auto* multiSeg = - dynamic_cast(segmentation); - for (dd4hep::CellID stripID : {m_pStripBit,m_nStripBit}) { + const auto* multiSeg = dynamic_cast(segmentation); + for (dd4hep::CellID stripID : {m_pStripBit, m_nStripBit}) { const Segmentation& stripSeg = multiSeg->subsegmentation(stripID); - if (stripSeg.type() == "CartesianGridUV") fulfilled |= stripID; + if (stripSeg.type() == "CartesianGridUV") + fulfilled |= stripID; } - } - else { + } else { required = 0x1; - if (segmentation->type() == "CartesianGridUV") fulfilled = 0x1; + if (segmentation->type() == "CartesianGridUV") + fulfilled = 0x1; } if (required == fulfilled) { m_detid_OuterMPGD = m_dd4hepGeo->constant("TrackerBarrel_5_ID"); - } - else { + } else { m_detid_OuterMPGD = 0; } } @@ -100,17 +100,11 @@ void TrackerMeasurementFromHits::process(const Input& input, const Output& outpu cov(0, 0) = hit.getPositionError().xx * mm_acts * mm_acts; // note mm = 1 (Acts) cov(1, 1) = hit.getPositionError().yy * mm_acts * mm_acts; cov(0, 1) = cov(1, 0) = 0.0; - if (hit_det==m_detid_OuterMPGD){ - const double sqrt2o2 = sqrt(2)/2; - const Acts::RotationMatrix2 rot { - { sqrt2o2, sqrt2o2}, - {-sqrt2o2, sqrt2o2} - }; - const Acts::RotationMatrix2 inv { - { sqrt2o2,-sqrt2o2}, - { sqrt2o2, sqrt2o2} - }; - cov = rot*cov*inv; + if (hit_det == m_detid_OuterMPGD) { + const double sqrt2o2 = sqrt(2) / 2; + const Acts::RotationMatrix2 rot{{sqrt2o2, sqrt2o2}, {-sqrt2o2, sqrt2o2}}; + const Acts::RotationMatrix2 inv{{sqrt2o2, -sqrt2o2}, {sqrt2o2, sqrt2o2}}; + cov = rot * cov * inv; } const auto* vol_ctx = m_converter->findContext(hit.getCellID()); diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.h b/src/algorithms/tracking/TrackerMeasurementFromHits.h index eb80541e4f..d4cc73352a 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.h +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.h @@ -47,9 +47,8 @@ class TrackerMeasurementFromHits : public TrackerMeasurementFromHitsAlgorithm, /// Detector-specific information unsigned long m_detid_b0tracker; unsigned long m_detid_OuterMPGD; - static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1) << 28; - static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2) << 28; - + static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1) << 28; + static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2) << 28; }; } // namespace eicrecon From 9795eba68a1f4eadc3416aec40866cc8ae3d1420 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Mon, 17 Nov 2025 00:13:12 +0100 Subject: [PATCH 20/47] Update src/algorithms/tracking/TrackerMeasurementFromHits.cc Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index 69b1806b30..8418fa097e 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -47,7 +47,8 @@ void TrackerMeasurementFromHits::init() { // i) Determine whether "CartesianGridUV", possibly embedded in a // MultiSegmentation (discriminating on a "strip" IDDescriptor field). // ii) If indeed, set "m_detid_OuterMPGD" to single out corresponding hits. - unsigned int required = 0, fulfilled = 0; + unsigned int required = 0; + unsigned int fulfilled = 0; const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector(); ; dd4hep::Segmentation seg; From 6c3e87da927d67d1e6806c94cd4fe45a8852e3af Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 16 Nov 2025 23:13:21 +0000 Subject: [PATCH 21/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index 8418fa097e..dfa17a2c7e 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -47,8 +47,8 @@ void TrackerMeasurementFromHits::init() { // i) Determine whether "CartesianGridUV", possibly embedded in a // MultiSegmentation (discriminating on a "strip" IDDescriptor field). // ii) If indeed, set "m_detid_OuterMPGD" to single out corresponding hits. - unsigned int required = 0; - unsigned int fulfilled = 0; + unsigned int required = 0; + unsigned int fulfilled = 0; const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector(); ; dd4hep::Segmentation seg; From 52a803a5f08ac4185b13fd4fb1030ca364a661a5 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 17 Nov 2025 09:44:19 -0600 Subject: [PATCH 22/47] =?UTF-8?q?MPGDTrackerDigi:=20Multi-SensitiveVolume?= =?UTF-8?q?=20solution=20for=20the=202D-strip=20read=E2=80=A6=20(fix:=20iw?= =?UTF-8?q?yu)=20(#2189)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/19430351038. Please merge this PR into the branch `MultiSensitiveMPGD` to resolve failures in PR #2177. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 11 ++++++++--- src/algorithms/tracking/TrackerMeasurementFromHits.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index dfa17a2c7e..846af835bb 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -12,11 +12,14 @@ #include #include #include -#include +#include +#include #include -#include -#include +#include +#include #include +#include +#include #include #include #include @@ -30,7 +33,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.h b/src/algorithms/tracking/TrackerMeasurementFromHits.h index d4cc73352a..7282147fa2 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.h +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include From 3455025b5b8f64770de066ac7c35d0f8a2445014 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Mon, 17 Nov 2025 16:56:29 +0100 Subject: [PATCH 23/47] Clang-Tidy. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index 846af835bb..017286e819 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -76,7 +76,7 @@ void TrackerMeasurementFromHits::init() { } } else { required = 0x1; - if (segmentation->type() == "CartesianGridUV") + if (segmentation->type() == "CartesianGridUV") { fulfilled = 0x1; } if (required == fulfilled) { From 0d847aaef61311434192d7d0e367ba0b742d5418 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Mon, 17 Nov 2025 16:57:03 +0100 Subject: [PATCH 24/47] Clang-Tidy Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index 017286e819..d364b1b1f0 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -78,6 +78,7 @@ void TrackerMeasurementFromHits::init() { required = 0x1; if (segmentation->type() == "CartesianGridUV") { fulfilled = 0x1; +} } if (required == fulfilled) { m_detid_OuterMPGD = m_dd4hepGeo->constant("TrackerBarrel_5_ID"); From a5ee86db6fefd781c49ca777cbfe0fed5c2e8130 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:57:34 +0000 Subject: [PATCH 25/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/tracking/TrackerMeasurementFromHits.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index d364b1b1f0..d1e39f608d 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -78,7 +78,7 @@ void TrackerMeasurementFromHits::init() { required = 0x1; if (segmentation->type() == "CartesianGridUV") { fulfilled = 0x1; -} + } } if (required == fulfilled) { m_detid_OuterMPGD = m_dd4hepGeo->constant("TrackerBarrel_5_ID"); From bc26b25435ff4e5ae99e529604b7c3c443501689 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Tue, 18 Nov 2025 19:44:02 +0100 Subject: [PATCH 26/47] MPGDTrackerDigi: Remove debugging leftovers. Improve handling of inconsistences. --- src/algorithms/digi/MPGDTrackerDigi.cc | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 3c9ed88dad..fb97f0f725 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -461,11 +461,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) continue; int direction = io ? +1 : -1; - status = extendHit(refID, direction, lpini, lmom, lpend, lmend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); - continue; - } + extendHit(refID, direction, lpini, lmom, lpend, lmend); } // ***** FLAG CASES W/ UNEXPECTED OUTCOME flagUnexpected(header, 0, (tRef.rMin() + tRef.rMax()) / 2, sim_hit, lpini, lpend, lpos, lmom); @@ -613,11 +609,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) continue; int direction = io ? +1 : -1; - status = extendHit(refID, direction, lpini, lmom, lpend, lmend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); - continue; - } + extendHit(refID, direction, lpini, lmom, lpend, lmend); } // ***** FLAG CASES W/ UNEXPECTED OUTCOME flagUnexpected(header, 1, 0, sim_hit, lpini, lpend, lpos, lmom); @@ -634,7 +626,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; } else { critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", refID, shape.type()); - throw JException("Bad input data: invalid geometry"); + throw JException("Inconsistency: Inappropriate Sim_hits fed to \"MPGDTRackerDigi\"."); } // ***** CELLIDS of (p|n)-STRIP HITS Position locPos(lpos[0], lpos[1], lpos[2]); // Simplification: strip surface = REFERENCE surface @@ -1518,10 +1510,9 @@ unsigned int MPGDTrackerDigi::extendHit(CellID refID, int direction, double* lpi Z -= ref2E; double dX = bExt.x(), dY = bExt.y(); status = bExtension(lpoE, lmoE, Z, direction, dX, dY, lext); - } else - status = 0x10000; - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - return status; + } else { + critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", refID, shape.type()); + throw JException("Inconsistency: Inappropriate Sim_hits fed to \"MPGDTRackerDigi\"."); } if (status != 0x1) continue; From 9004d666ddaa6f3a0b0586ee358a6aa50236de07 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Wed, 19 Nov 2025 20:18:08 +0100 Subject: [PATCH 27/47] MPGDTrackerDigi: VolumeID mask from IDDescriptor; debugging leftovers removed. - The VolumeID mask was previously built-in. - Debugging leftovers were not removed in previous commit (#bc26b254), by mistake. --- src/algorithms/digi/MPGDTrackerDigi.cc | 34 ++++++++++++++++++++++---- src/algorithms/digi/MPGDTrackerDigi.h | 16 ++++-------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index fb97f0f725..f6454546f3 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -145,14 +145,38 @@ void MPGDTrackerDigi::init() { critical("Failed to load ID decoder for \"{}\" readout.", m_cfg.readout); throw JException("Failed to load ID decoder"); } - // Method "process" relies on an assumption on the IDDescriptor's strip field. - // Let's check. - debug(R"(Find valid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); + + // IDDescriptor + // "volume": excluding channel specfication. + debug("(Retrieve volume mask in IDDescriptor for \"{}\" readout.)", m_cfg.readout); + m_volumeBits = 0; + for (const char *fieldName : m_fieldNames){ + CellID fieldID = 0; + try { + fieldID = m_id_dec->get(~((CellID)0x0), fieldName); + } + catch (const std::runtime_error& error) { + critical("No field \"{}\" in IDDescriptor of readout \"{}\".", + fieldName, m_cfg.readout.c_str()); + throw JException("Invalid IDDescriptor"); + } + const BitFieldElement& field = (*m_id_dec)[fieldName]; + unsigned int offset = field.offset(); + m_volumeBits |= fieldID << field.offset(); + } + // MPGDTrackerDigi relies on a number of assumptions on the strip field of + // the IDDescriptor, encoded in the /** Segmentation */ block of the header. + // As an illustration, here is the IDDescriptor of CyMBaL (as of 2025/11): + // //system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 + // Let's double-check part of the assumptions, viz.:"m_stripBits". + debug("(Find valid \"strip\" field in IDDescriptor for \"{}\" readout.)", m_cfg.readout); if (m_id_dec->get(m_stripBits, "strip") != 0xf) { - critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" readout.)", + critical("Missing or invalid \"strip\" field in IDDescriptor for \"{}\" readout.", m_cfg.readout); throw JException("Invalid IDDescriptor"); } + // "volume" cleared of its "strip" bits. + m_moduleBits = m_volumeBits & m_stripMask; // Ordering of SUBVOLUMES (based on "STRIP" FIELD) m_stripRank = [&](CellID vID) { @@ -288,7 +312,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // "dd4hep::Segmentation::cellID", we need the _local_ position and // only that. CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => the middle slice + CellID refID = vID & m_moduleBits; // REFERENCE SUBVOLUME DetElement refVol = volman.lookupDetElement(refID); // TGeoHMatrix: In order to avoid a "dangling-reference" warning, // let's take a copy of the matrix instead of a reference to it. diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 69e47dc071..02137fb664 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -11,10 +11,6 @@ #include #include #include -//#define MC_PARTICLE_ASSOCIATION -#ifdef MC_PARTICLE_ASSOCIATION -#include -#endif #include #include #include @@ -26,12 +22,7 @@ namespace eicrecon { using MPGDTrackerDigiAlgorithm = algorithms::Algorithm< -#ifdef MC_PARTICLE_ASSOCIATION - algorithms::Input, -#else algorithms::Input, -#endif algorithms::Output>; @@ -74,12 +65,15 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, /** Segmentation */ const dd4hep::Detector* m_detector{nullptr}; dd4hep::Segmentation m_seg; + // IDDescriptor + static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specfication + {"system","layer","module","sensor","strip"}; + dd4hep::CellID m_volumeBits; // "volume" bits, as opposed to channel# bits + dd4hep::CellID m_moduleBits; // "volume" cleared of its "strip" bits. // Built-in constants specifying IDDescriptor fields. // The "init" should method double-check these are actually implemented in the XMLs of MPGDs. - static constexpr dd4hep::CellID m_volumeBits = 0xffffffff; // 32 least weight bits static constexpr dd4hep::CellID m_stripBits = ((dd4hep::CellID)0xf) << 28; static constexpr dd4hep::CellID m_stripMask = ~m_stripBits; - static constexpr dd4hep::CellID m_moduleBits = m_volumeBits & m_stripMask; static constexpr dd4hep::CellID m_pStripBit = ((dd4hep::CellID)0x1) << 28; static constexpr dd4hep::CellID m_nStripBit = ((dd4hep::CellID)0x2) << 28; static constexpr dd4hep::CellID m_stripIDs[5] = {((dd4hep::CellID)0x3) << 28, m_pStripBit, 0, From 134544135f3a4d0242053091a46bd04bc2c12592 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:24:32 +0000 Subject: [PATCH 28/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 11 +++++------ src/algorithms/digi/MPGDTrackerDigi.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index f6454546f3..a3e274036d 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -150,18 +150,17 @@ void MPGDTrackerDigi::init() { // "volume": excluding channel specfication. debug("(Retrieve volume mask in IDDescriptor for \"{}\" readout.)", m_cfg.readout); m_volumeBits = 0; - for (const char *fieldName : m_fieldNames){ + for (const char* fieldName : m_fieldNames) { CellID fieldID = 0; try { fieldID = m_id_dec->get(~((CellID)0x0), fieldName); - } - catch (const std::runtime_error& error) { - critical("No field \"{}\" in IDDescriptor of readout \"{}\".", - fieldName, m_cfg.readout.c_str()); + } catch (const std::runtime_error& error) { + critical("No field \"{}\" in IDDescriptor of readout \"{}\".", fieldName, + m_cfg.readout.c_str()); throw JException("Invalid IDDescriptor"); } const BitFieldElement& field = (*m_id_dec)[fieldName]; - unsigned int offset = field.offset(); + unsigned int offset = field.offset(); m_volumeBits |= fieldID << field.offset(); } // MPGDTrackerDigi relies on a number of assumptions on the strip field of diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 02137fb664..dc3d5e91b3 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -67,7 +67,7 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, dd4hep::Segmentation m_seg; // IDDescriptor static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specfication - {"system","layer","module","sensor","strip"}; + {"system", "layer", "module", "sensor", "strip"}; dd4hep::CellID m_volumeBits; // "volume" bits, as opposed to channel# bits dd4hep::CellID m_moduleBits; // "volume" cleared of its "strip" bits. // Built-in constants specifying IDDescriptor fields. From 1c7fa6117d882d13cae2cb88d9fca0e408566583 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Wed, 19 Nov 2025 20:51:07 +0100 Subject: [PATCH 29/47] MPGDTrackerDigi: Fix spelling. --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- src/algorithms/digi/MPGDTrackerDigi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index f6454546f3..092ee9a8a9 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -147,7 +147,7 @@ void MPGDTrackerDigi::init() { } // IDDescriptor - // "volume": excluding channel specfication. + // "volume": excluding channel specification. debug("(Retrieve volume mask in IDDescriptor for \"{}\" readout.)", m_cfg.readout); m_volumeBits = 0; for (const char *fieldName : m_fieldNames){ diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 02137fb664..a08c675a24 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -66,7 +66,7 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, const dd4hep::Detector* m_detector{nullptr}; dd4hep::Segmentation m_seg; // IDDescriptor - static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specfication + static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specification {"system","layer","module","sensor","strip"}; dd4hep::CellID m_volumeBits; // "volume" bits, as opposed to channel# bits dd4hep::CellID m_moduleBits; // "volume" cleared of its "strip" bits. From 58bb0b12c061679228131318f6c1f95adcfcb014 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Wed, 19 Nov 2025 16:03:58 -0500 Subject: [PATCH 30/47] rm unused variable --- src/algorithms/digi/MPGDTrackerDigi.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index a3e274036d..6da1511c27 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -160,7 +160,6 @@ void MPGDTrackerDigi::init() { throw JException("Invalid IDDescriptor"); } const BitFieldElement& field = (*m_id_dec)[fieldName]; - unsigned int offset = field.offset(); m_volumeBits |= fieldID << field.offset(); } // MPGDTrackerDigi relies on a number of assumptions on the strip field of From 0c7e8af31ea55f06581bf54200824c287e2d2525 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 05:59:56 +0000 Subject: [PATCH 31/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index a08c675a24..f2d4e7bd34 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -67,7 +67,7 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, dd4hep::Segmentation m_seg; // IDDescriptor static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specification - {"system","layer","module","sensor","strip"}; + {"system", "layer", "module", "sensor", "strip"}; dd4hep::CellID m_volumeBits; // "volume" bits, as opposed to channel# bits dd4hep::CellID m_moduleBits; // "volume" cleared of its "strip" bits. // Built-in constants specifying IDDescriptor fields. From 098a4f93bff37fa4e718f89bfddd2bd59b8e0287 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Thu, 20 Nov 2025 07:04:04 +0100 Subject: [PATCH 32/47] Update src/algorithms/digi/MPGDTrackerDigi.cc Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 068fe6690d..cf54454a30 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -167,7 +167,7 @@ void MPGDTrackerDigi::init() { // As an illustration, here is the IDDescriptor of CyMBaL (as of 2025/11): // //system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 // Let's double-check part of the assumptions, viz.:"m_stripBits". - debug("(Find valid \"strip\" field in IDDescriptor for \"{}\" readout.)", m_cfg.readout); + debug(R"((Find valid "strip" field in IDDescriptor for "{}" readout.))", m_cfg.readout); if (m_id_dec->get(m_stripBits, "strip") != 0xf) { critical("Missing or invalid \"strip\" field in IDDescriptor for \"{}\" readout.", m_cfg.readout); From f3a148144e1d73506351c2cd3dd8ca75767b3949 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Thu, 20 Nov 2025 07:04:33 +0100 Subject: [PATCH 33/47] Update src/algorithms/digi/MPGDTrackerDigi.cc Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index cf54454a30..8cc1c150a8 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -155,7 +155,7 @@ void MPGDTrackerDigi::init() { try { fieldID = m_id_dec->get(~((CellID)0x0), fieldName); } catch (const std::runtime_error& error) { - critical("No field \"{}\" in IDDescriptor of readout \"{}\".", fieldName, + critical(R"(No field "{}" in IDDescriptor of readout "{}".)", fieldName, m_cfg.readout.c_str()); throw JException("Invalid IDDescriptor"); } From b3e909fc658a366d43a06dd2db221715b32350c6 Mon Sep 17 00:00:00 2001 From: ybedfer Date: Thu, 20 Nov 2025 07:05:00 +0100 Subject: [PATCH 34/47] Update src/algorithms/digi/MPGDTrackerDigi.cc Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 8cc1c150a8..cedf9c9c92 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -169,7 +169,7 @@ void MPGDTrackerDigi::init() { // Let's double-check part of the assumptions, viz.:"m_stripBits". debug(R"((Find valid "strip" field in IDDescriptor for "{}" readout.))", m_cfg.readout); if (m_id_dec->get(m_stripBits, "strip") != 0xf) { - critical("Missing or invalid \"strip\" field in IDDescriptor for \"{}\" readout.", + critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); throw JException("Invalid IDDescriptor"); } From b5bae93363b00ea6dc1a1811784a84284734fa81 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 20 Nov 2025 07:12:47 +0100 Subject: [PATCH 35/47] MPGDTrackerDigi: Clang-Tidy stuff... --- src/algorithms/digi/MPGDTrackerDigi.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index cedf9c9c92..afac4fa555 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -150,7 +150,8 @@ void MPGDTrackerDigi::init() { // "volume": excluding channel specification. debug("(Retrieve volume mask in IDDescriptor for \"{}\" readout.)", m_cfg.readout); m_volumeBits = 0; - for (const char* fieldName : m_fieldNames) { + for (int field = 0; field < 5; field++) { + const char* fieldName = m_fieldNames[field]; CellID fieldID = 0; try { fieldID = m_id_dec->get(~((CellID)0x0), fieldName); @@ -159,8 +160,8 @@ void MPGDTrackerDigi::init() { m_cfg.readout.c_str()); throw JException("Invalid IDDescriptor"); } - const BitFieldElement& field = (*m_id_dec)[fieldName]; - m_volumeBits |= fieldID << field.offset(); + const BitFieldElement& fieldElement = (*m_id_dec)[fieldName]; + m_volumeBits |= fieldID << fieldElement.offset(); } // MPGDTrackerDigi relies on a number of assumptions on the strip field of // the IDDescriptor, encoded in the /** Segmentation */ block of the header. From 7a9680365e587f00737c8d24948c40e6e62530d8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 06:15:58 +0000 Subject: [PATCH 36/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index afac4fa555..f80c920ef3 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -152,7 +152,7 @@ void MPGDTrackerDigi::init() { m_volumeBits = 0; for (int field = 0; field < 5; field++) { const char* fieldName = m_fieldNames[field]; - CellID fieldID = 0; + CellID fieldID = 0; try { fieldID = m_id_dec->get(~((CellID)0x0), fieldName); } catch (const std::runtime_error& error) { From 4877a84878874ed77a0bfb615a1da53031598f61 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Thu, 20 Nov 2025 01:11:32 -0600 Subject: [PATCH 37/47] =?UTF-8?q?MPGDTrackerDigi:=20Multi-SensitiveVolume?= =?UTF-8?q?=20solution=20for=20the=202D-strip=20read=E2=80=A6=20(fix:=20iw?= =?UTF-8?q?yu)=20(#2196)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/19527585648. Please merge this PR into the branch `MultiSensitiveMPGD` to resolve failures in PR #2177. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index f80c920ef3..bd3a52bc58 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -110,16 +110,17 @@ #include #include #include -#include -#include #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include From 0becd75b27b3d7fc694a67cdc544b3cdeaae17e8 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Sat, 22 Nov 2025 18:49:08 +0100 Subject: [PATCH 38/47] MPGDTrackerDigi: More modular design. Check Segmentation of MPGDs is appropriate. --- src/algorithms/digi/MPGDTrackerDigi.cc | 897 ++++++++++-------- src/algorithms/digi/MPGDTrackerDigi.h | 14 +- .../tracking/TrackerMeasurementFromHits.cc | 1 - 3 files changed, 515 insertions(+), 397 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index bd3a52bc58..931ce51fb6 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -24,9 +24,10 @@ - Several subHits are created (up to five, one per individual SUBVOLUME) corresponding to a SINGLE I[ONISATION]+A[MPLIFICATION] process, inducing in turn CORRELATED SIGNALS ON TWO COORDINATES. - - These subHits are extrapolated to the REFERENCE SUBVOLUME (its mid-plane), - so as to reconstitute the proper hit position of the TRAVERSING particle. - This, for particles that are determined to be indeed traversing. + - These subHits are EXTENDED so as to span the full sensitive volume and be + on the sensitive surface of the REFERENCE SUBVOLUME (its mid-plane), and + hence reconstitute the proper hit position of the TRAVERSING particle. + This, for particles that are determined to be indeed traversing. - We then want to preserve the I+A correlation when accumulating hits on the readout channels. This cannot be obtained by accumulating directly subHits ( as is done in "SiliconTrackerDigi", as of commit #151496af). We have to @@ -94,6 +95,7 @@ #include #include #include +#include #include #include #include @@ -135,7 +137,6 @@ void MPGDTrackerDigi::init() { // Access id decoder m_detector = algorithms::GeoSvc::instance().detector(); - const dd4hep::BitFieldCoder* m_id_dec = nullptr; if (m_cfg.readout.empty()) { throw JException("Readout is empty"); } @@ -143,40 +144,13 @@ void MPGDTrackerDigi::init() { m_seg = m_detector->readout(m_cfg.readout).segmentation(); m_id_dec = m_detector->readout(m_cfg.readout).idSpec().decoder(); } catch (...) { - critical("Failed to load ID decoder for \"{}\" readout.", m_cfg.readout); + critical(R"(Failed to load ID decoder for "{}" readout.)", m_cfg.readout); throw JException("Failed to load ID decoder"); } - // IDDescriptor - // "volume": excluding channel specification. - debug("(Retrieve volume mask in IDDescriptor for \"{}\" readout.)", m_cfg.readout); - m_volumeBits = 0; - for (int field = 0; field < 5; field++) { - const char* fieldName = m_fieldNames[field]; - CellID fieldID = 0; - try { - fieldID = m_id_dec->get(~((CellID)0x0), fieldName); - } catch (const std::runtime_error& error) { - critical(R"(No field "{}" in IDDescriptor of readout "{}".)", fieldName, - m_cfg.readout.c_str()); - throw JException("Invalid IDDescriptor"); - } - const BitFieldElement& fieldElement = (*m_id_dec)[fieldName]; - m_volumeBits |= fieldID << fieldElement.offset(); - } - // MPGDTrackerDigi relies on a number of assumptions on the strip field of - // the IDDescriptor, encoded in the /** Segmentation */ block of the header. - // As an illustration, here is the IDDescriptor of CyMBaL (as of 2025/11): - // //system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16 - // Let's double-check part of the assumptions, viz.:"m_stripBits". - debug(R"((Find valid "strip" field in IDDescriptor for "{}" readout.))", m_cfg.readout); - if (m_id_dec->get(m_stripBits, "strip") != 0xf) { - critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" readout.)", - m_cfg.readout); - throw JException("Invalid IDDescriptor"); - } - // "volume" cleared of its "strip" bits. - m_moduleBits = m_volumeBits & m_stripMask; + // IDDescriptor and Segmentation + parseIDDescriptor(); + parseSegmentation(); // Ordering of SUBVOLUMES (based on "STRIP" FIELD) m_stripRank = [&](CellID vID) { @@ -298,358 +272,27 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, else usedHits.push_back(idx); // useful?... - // ***** SEGMENTATION - // - The two cellIDs are encoded via a "dd4hep::MultiSegmentation" - // discriminating on the strip field, w/ "strip" setting of 0x1 ( - // called 'p') or 0x2 (called 'n') and 0x3/0x4 for the inner/outer - // RADIATORS, and 0x0 for the REFERENCE SUBVOLUME. - // - They are evaluated based on "sim_hit" Cartesian position and momentum. - // + Extrapolating to REFERENCE SUBVOLUME. - // + COALESCING all subHits with SAME PMO. - // Given that all the segmentation classes foreseen for MPGDs ( - // "CartesianGrid.." for Outer and EndCaps, "CylindricalGridPhiZ" for - // "CyMBaL") disregard the _global_ position argument to - // "dd4hep::Segmentation::cellID", we need the _local_ position and - // only that. - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // REFERENCE SUBVOLUME + // ***** REFERENCE SUBVOLUME + CellID refID = sim_hit.getCellID() & m_moduleBits; DetElement refVol = volman.lookupDetElement(refID); - // TGeoHMatrix: In order to avoid a "dangling-reference" warning, - // let's take a copy of the matrix instead of a reference to it. - const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); - double lpos[3], lmom[3]; - getLocalPosMom(sim_hit, toRefVol, lpos, lmom); - const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; - using dd4hep::mm; - using edm4eic::unit::eV, edm4eic::unit::GeV; - // Hit in progress - double eDep = sim_hit.getEDep(), time = sim_hit.getTime(); // ***** COALESCE ALL MUTUALLY CONSISTENT SUBHITS // EXTEND TRAVERSING SUBHITS // - Needed because we want to preserve the correlation between 'p' and // 'n' strip hits resulting from a given I+A process (which is lost when - // one accumulates hits based on cellID). - std::vector same_idcs; + // one accumulates hits independently based on cellID). + double lpos[3], eDep, time; std::vector cIDs; const auto& shape = refVol.solid(); if (!strcmp(shape.type(), "TGeoTubeSeg")) { // ********** TUBE GEOMETRY - const Tube& tRef = refVol.solid(); // REFERENCE SUBVOLUME - double dZ = tRef.dZ(); - // phi? - // In "https://root.cern.ch/root/html534/guides/users-guide/Geometry.html" - // TGeoTubeSeg: "phi1 is converted to [0,360] (but still expressed in - // radian, as far as I can tell) and phi2 > phi1." - // => Convert it to [-pi,+pi]. - double startPhi = tRef.startPhi() * radian; - startPhi -= 2 * TMath::Pi(); - double endPhi = tRef.endPhi() * radian; - endPhi -= 2 * TMath::Pi(); - // Get current SUBVOLUME - DetElement curVol = volman.lookupDetElement(vID); - const Tube& tCur = curVol.solid(); - double rMin = tCur.rMin(), rMax = tCur.rMax(); - // Is TRAVERSING? - double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; - std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); - unsigned int status = - cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), - rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); - continue; - } - cIDs.push_back(sim_hit.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(idx); - } - // Continuations. Particle may exit and then re-enter through "rMin". - bool isContinuation = status & 0x5; - bool hasContinuation = status & 0xa; - bool canReEnter = status & 0x100; - int rank = m_stripRank(vID); - if (!canReEnter) { - if (rank == 0 && (status & 0x1)) - isContinuation = false; - if (rank == 0 && (status & 0x2)) - hasContinuation = false; - } - if (rank == 4 && (status & 0x4)) - isContinuation = false; - if (rank == 4 && (status & 0x8)) - hasContinuation = false; - if (hasContinuation) { - // ***** LOOP OVER HITS - int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; - for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { - const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - // Used hit? If indeed, it's going to be discarded anyway in the - // following: current "sim_hit" is by construction at variance to it. - CellID vJD = sim_hjt.getCellID() & m_volumeBits; - // Particle may start inward and re-enter, being then outward-going. - // => Orientation has to be evaluated w.r.t. previous vID. - int orientation = m_orientation(vIDPrv, vJD); - bool isUpstream = m_isUpstream(orientation, status); - bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); - if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // Get 'j' radii - curVol = volman.lookupDetElement(vJD); - const Tube& tubj = curVol.solid(); - rMin = tubj.rMin(); - rMax = tubj.rMax(); - double lpoj[3], lmoj[3]; - getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); - // Is TRAVERSING through the (quasi-)common wall? - double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), rMin, rMax, dZ, startPhi, endPhi, - ljns, lovts, lpjni, lpfnd); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // ij-Compatibility: status - bool jsDownstream = m_isDownstream(orientation, status); - if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) - break; - else { // Allow for primary hits to not come in unbroken sequence - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - } - // ij-Compatibility: close exit/entrance-distance - double dist = outInDistance(0, orientation, ljns, louts, lmom, lmoj); - const double tolerance = 25 * dd4hep::um; - bool isCompatible = dist > 0 && dist < tolerance; - if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, - /* */ sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // ***** UPDATE - vIDPrv = vJD; - eDep += sim_hjt.getEDep(); - for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; - lmend[i] = lmoj[i]; - } - // ***** BOOK-KEEPING - usedHits.push_back(jdx); - cIDs.push_back(sim_hjt.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(jdx); - } - // ***** CONTINUATION? - hasContinuation = status & 0xa; - canReEnter = status & 0x100; - if (!canReEnter && m_stripRank(vJD) == 4) - hasContinuation = false; - if (!hasContinuation) { - jdx++; - break; - } else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; - louts[1][i] = lovts[1][i]; - } - } - } - if (unbroken) - idx = jdx - 1; - } - // ***** EXTENSION?... - if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) - if (denyExtension(sim_hit, tCur.rMax() - tCur.rMin())) { - isContinuation = hasContinuation = false; - } - for (int io = 0; io < 2; io++) { // ...into/out-of - if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) - continue; - int direction = io ? +1 : -1; - extendHit(refID, direction, lpini, lmom, lpend, lmend); - } - // ***** FLAG CASES W/ UNEXPECTED OUTCOME - flagUnexpected(header, 0, (tRef.rMin() + tRef.rMax()) / 2, sim_hit, lpini, lpend, lpos, lmom); - // ***** UPDATE (local position , DoF - double DoF2 = 0, dir = 0; - for (int i = 0; i < 3; i++) { - double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; - lpos[i] = neu; - double d = neu - alt; - dir += d * lmom[i]; - DoF2 += d * d; - } - // Update time by ToF from original subHit to extended/COALESCED. - time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; - } else if (!strcmp(shape.type(), "TGeoBBox")) { + if (!cCoalesceExtend(input,idx,usedHits,cIDs,lpos,eDep,time)) continue; + } + else if (!strcmp(shape.type(), "TGeoBBox")) { // ********** BOX GEOMETRY - const Box& bRef = refVol.solid(); // REFERENCE SUBVOLUME - double dX = bRef.x(), dY = bRef.y(); - // Get current SUBVOLUME - DetElement curVol = volman.lookupDetElement(vID); - const Box& bCur = curVol.solid(); - double dZ = bCur.z(); - double ref2Cur = getRef2Cur(refVol, curVol); - // Is TRAVERSING? - double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; - std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); - unsigned int status = - bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" - critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); - continue; - } - cIDs.push_back(sim_hit.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(idx); - } - // Continuations. - int rank = m_stripRank(vID); - bool isContinuation = status & 0x5; - bool hasContinuation = status & 0xa; - if ((rank == 0 && (status & 0x1)) || (rank == 4 && (status & 0x4))) - isContinuation = false; - if ((rank == 0 && (status & 0x2)) || (rank == 4 && (status & 0x8))) - hasContinuation = false; - if (hasContinuation) { - // ***** LOOP OVER SUBHITS - int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; - for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { - const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - // Used hit? If indeed, it's going to be discarded anyway in the - // following: current "sim_hit" is by construction at variance to it. - CellID vJD = sim_hjt.getCellID() & m_volumeBits; - int orientation = m_orientation(vIDPrv, vJD); - bool isUpstream = m_isUpstream(orientation, status); - bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); - if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // Get 'j' Z - curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME - const Box& boxj = curVol.solid(); - dZ = boxj.z(); - double ref2j = getRef2Cur(refVol, curVol); - // Is TRAVERSING through the (quasi)-common border? - double lpoj[3], lmoj[3]; - getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); - double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = - bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd); - if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // ij-Compatibility: status - bool jsDownstream = m_isDownstream(orientation, status); - if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) - break; - else { - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - } - // ij-Compatibility: close exit/entrance-distance - double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj); - const double tolerance = 25 * dd4hep::um; - bool isCompatible = dist > 0 && dist < tolerance; - if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, - /* */ sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } - // ***** UPDATE - vIDPrv = vJD; - eDep += sim_hjt.getEDep(); - for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; - lmend[i] = lmoj[i]; - } - // ***** BOOK-KEEPING - usedHits.push_back(jdx); - cIDs.push_back(sim_hjt.getCellID()); - if (level() >= algorithms::LogLevel::kDebug) { - same_idcs.push_back(jdx); - } - // ***** CONTINUATION? - hasContinuation = status & 0xa; - if (!hasContinuation) { - jdx++; - break; - } else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; - louts[1][i] = lovts[1][i]; - } - } - } - if (unbroken) - idx = jdx - 1; - } - // ***** EXTENSION?... - if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) - if (denyExtension(sim_hit, bCur.z())) { - isContinuation = hasContinuation = false; - } - for (int io = 0; io < 2; io++) { // ...into/out-of - if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) - continue; - int direction = io ? +1 : -1; - extendHit(refID, direction, lpini, lmom, lpend, lmend); - } - // ***** FLAG CASES W/ UNEXPECTED OUTCOME - flagUnexpected(header, 1, 0, sim_hit, lpini, lpend, lpos, lmom); - // ***** UPDATE (local position , DoF) - double DoF2 = 0, dir = 0; - for (int i = 0; i < 3; i++) { - double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; - lpos[i] = neu; - double d = neu - alt; - dir += d * lmom[i]; - DoF2 += d * d; - } - // Update time by ToF from original subHit to extended/COALESCED. - time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; - } else { - critical("Bad input data: CellID {:x} has invalid shape (=\"{}\")", refID, shape.type()); + if (!bCoalesceExtend(input,idx,usedHits,cIDs,lpos,eDep,time)) continue; + } + else { + critical(R"(Bad input data: CellID {:x} has invalid shape (="{}"))", refID, shape.type()); throw JException("Inconsistency: Inappropriate Sim_hits fed to \"MPGDTRackerDigi\"."); } // ***** CELLIDS of (p|n)-STRIP HITS @@ -665,7 +308,6 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // ***** DEBUGGING INFO if (level() >= algorithms::LogLevel::kDebug) { - debug("--------------------"); for (CellID cID : {cIDp, cIDn}) { std::string sCellID = cID == cIDp ? "cellIDp" : "cellIDn"; CellID hID = cID >> 32, vID = cID & m_volumeBits, sID = vID >> 28 & 0xff; @@ -684,21 +326,6 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, #endif debug(" time smearing: {:.2f}, resulting time = {:.2f} [ns]", time_smearing, result_time); debug(" hit_time_stamp: {} [~ps]", hit_time_stamp); - for (int ldx = 0; ldx < (int)same_idcs.size(); ldx++) { - int jdx = same_idcs[ldx]; - const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); - CellID cIDk = sim_hjt.getCellID(); - CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; - debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx, hIDk, vIDk, sIDk); - debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hjt.getPosition().x / edmm, - sim_hjt.getPosition().y / edmm, sim_hjt.getPosition().z / edmm); - debug(" xy_radius = {:.2f}", - std::hypot(sim_hjt.getPosition().x, sim_hjt.getPosition().y) / edmm); - debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hjt.getMomentum().x / GeV, - sim_hjt.getMomentum().y / GeV, sim_hjt.getMomentum().z / GeV); - debug(" edep = {:.0f} [eV]", sim_hjt.getEDep() / eV); - debug(" time = {:.2f} [ns]", sim_hjt.getTime()); - } } // ***** APPLY THRESHOLD @@ -726,8 +353,9 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // sum deposited energy auto charge = hit.getCharge(); + // Accumulate charge: shouldn't it be 'float' instead of 'int'? hit.setCharge(charge + (std::int32_t)std::llround( - eDep * 1e6)); // TODO: accumulate charge: shouldn't it be float? + eDep * 1e6)); } } } @@ -738,7 +366,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, CellID stripID = item.first; const auto is = stripID2cIDs.find(stripID); if (is == stripID2cIDs.end()) { - critical("Inconsistency: CellID {:x} not found in \"stripID2cIDs\" map", stripID); + critical(R"(Inconsistency: CellID {:x} not found in "stripID2cIDs" map)", stripID); throw JException("Inconsistency in the handling of \"stripID2cIDs\" map"); } std::vector cIDs = is->second; @@ -756,6 +384,485 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, } } +void MPGDTrackerDigi::parseIDDescriptor() +{ + // Parse IDDescriptor => Retrieve volume mask; check "strip" field. + + // "volume" mask: excluding channel specification. + debug(R"(Retrieve volume mask in IDDescriptor for "{}" readout.)", m_cfg.readout); + m_volumeBits = 0; + for (int field = 0; field < 5; field++) { + const char* fieldName = m_fieldNames[field]; + CellID fieldID = 0; + try { + fieldID = m_id_dec->get(~((CellID)0x0), fieldName); + } catch (const std::runtime_error& error) { + critical(R"(No field "{}" in IDDescriptor of readout "{}".)", fieldName, + m_cfg.readout.c_str()); + throw JException("Invalid IDDescriptor"); + } + const BitFieldElement& fieldElement = (*m_id_dec)[fieldName]; + m_volumeBits |= fieldID << fieldElement.offset(); + } + // MPGDTrackerDigi relies on a number of assumptions on the "strip" field of + // the IDDescriptor, encoded in the /** Segmentation */ block of the header. + // Let's double-check part of the assumptions, viz.: "m_stripBits". + // (As an illustration, here is the IDDescriptor of CyMBaL (as of 2025/11): + // system:8,layer:4,module:12,sensor:2,strip:28:4,phi:-16,z:-16.) + debug(R"(Find valid "strip" field in IDDescriptor for "{}" readout.)", m_cfg.readout); + if (m_id_dec->get(m_stripBits, "strip") != 0xf) { + critical(R"(Missing or invalid "strip" field in IDDescriptor for "{}" readout.)", + m_cfg.readout); + throw JException("Invalid IDDescriptor"); + } + // "volume" cleared of its "strip" bits. + m_moduleBits = m_volumeBits & m_stripMask; +} +void MPGDTrackerDigi::parseSegmentation() +{ + // MPGDTrackerDigi relies on a number of assumptions concerning the + // structure of the MPGD detector and its subdivision into SUBVOLUMES. These + // assumptions imply in turn a particular segmentation scheme. In particular, + // a MultiSegmentation allowing to navigate among the SUBVOLUMES. + // The MultiSegmentation has a discriminator named "strip", see IDDescriptor. + // It may itself be embedded in a super MultiSegmentation: case of CyMBaL. + // Let's check (limiting ourselves to main features..). + debug(R"(Find valid "MultiSegmentation" for "{}" readout.)", m_cfg.readout); + bool ok = false; + using Segmentation = dd4hep::DDSegmentation::Segmentation; + const Segmentation* segmentation = m_seg->segmentation; + if (segmentation->type() == "MultiSegmentation") { + using MultiSegmentation = dd4hep::DDSegmentation::MultiSegmentation; + const auto* multiSeg = dynamic_cast(segmentation); + if (multiSeg->discriminatorName() == "strip") ok = true; + if (!ok) { + for (const auto entry : multiSeg->subSegmentations()){ + const Segmentation* subSegmentation = entry.segmentation; + if (subSegmentation->type() == "MultiSegmentation") { + const auto* subMultiSeg + = dynamic_cast(subSegmentation); + if (subMultiSeg->discriminatorName() == "strip") { + ok = true; + } + else { + ok = false; + break; + } + } + } + } + } + if (!ok) { + critical(R"(Segmentation for readout "{}" is not, or is not embedding, a MultiSegmentation discriminating on a "strip" field.)", m_cfg.readout.c_str()); + throw JException("Invalid Segmentation"); + } +} + +// ***** COALESCE subHits with same PMO +// EXTEND hits (subHits or coalesced subHits) to full sensitive volume +// - Input = Elementary subHit, specified as index into collection of SimHits. +// - Output = Coalesced/extended hit, specified by: +// + list of cellIDs of elementary subHits contributiong, +// + local position, +// + EDep, +// + time. +// Given that all segmentation classes foreseen for MPGDs ("CartesianGrid.." +// for Outer and EndCaps, "CylindricalGridPhiZ" for "CyMBaL") disregard the +// _global_ position argument to "dd4hep::Segmentation::cellID", we need +// the _local_ position and only that. +// - Also returned: updated index, vector of used subHits. +bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, + int& idx, std::vector& usedHits, + std::vector &cIDs, double *lpos, double& eDep, double& time) const +{ + const auto [headers, sim_hits] = input; + const edm4hep::EventHeader& header = headers->at(0); + const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME + const VolumeManager& volman = m_detector->volumeManager(); + DetElement refVol = volman.lookupDetElement(refID); + // TGeoHMatrix: In order to avoid a "dangling-reference" warning, let's take + // a copy of the matrix instead of a reference to it. + const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); + double lmom[3]; + getLocalPosMom(sim_hit, toRefVol, lpos, lmom); + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; + using dd4hep::mm; + using edm4eic::unit::eV, edm4eic::unit::GeV; + // Hit in progress + eDep = sim_hit.getEDep(); time = sim_hit.getTime(); + // Get VOLUME parameters + const Tube& tRef = refVol.solid(); + double dZ = tRef.dZ(); + // phi? + // In "https://root.cern.ch/root/html534/guides/users-guide/Geometry.html" + // TGeoTubeSeg: "phi1 is converted to [0,360] (but still expressed in + // radian, as far as I can tell) and phi2 > phi1." + // => Convert it to [-pi,+pi]. + double startPhi = tRef.startPhi() * radian; + startPhi -= 2 * TMath::Pi(); + double endPhi = tRef.endPhi() * radian; + endPhi -= 2 * TMath::Pi(); + // Get current SUBVOLUME + DetElement curVol = volman.lookupDetElement(vID); + const Tube& tCur = curVol.solid(); + double rMin = tCur.rMin(), rMax = tCur.rMax(); + // Is TRAVERSING? + double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); + unsigned int status = + cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), + rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + return false; + } + cIDs.push_back(sim_hit.getCellID()); + std::vector subHitList; + if (level() >= algorithms::LogLevel::kDebug) { + subHitList.push_back(&sim_hit); + } + // Continuations. Particle may exit and then re-enter through "rMin". + bool isContinuation = status & 0x5; + bool hasContinuation = status & 0xa; + bool canReEnter = status & 0x100; + int rank = m_stripRank(vID); + if (!canReEnter) { + if (rank == 0 && (status & 0x1)) + isContinuation = false; + if (rank == 0 && (status & 0x2)) + hasContinuation = false; + } + if (rank == 4 && (status & 0x4)) + isContinuation = false; + if (rank == 4 && (status & 0x8)) + hasContinuation = false; + if (hasContinuation) { + // ***** LOOP OVER HITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + size_t sim_size = sim_hits->size(); + for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + // Particle may start inward and re-enter, being then outward-going. + // => Orientation has to be evaluated w.r.t. previous vID. + int orientation = m_orientation(vIDPrv, vJD); + bool isUpstream = m_isUpstream(orientation, status); + bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // Get 'j' radii + curVol = volman.lookupDetElement(vJD); + const Tube& tubj = curVol.solid(); + rMin = tubj.rMin(); + rMax = tubj.rMax(); + double lpoj[3], lmoj[3]; + getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); + // Is TRAVERSING through the (quasi-)common wall? + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), rMin, rMax, dZ, startPhi, endPhi, + ljns, lovts, lpjni, lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation, status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) + break; + else { // Allow for primary hits to not come in unbroken sequence + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double dist = outInDistance(0, orientation, ljns, louts, lmom, lmoj); + const double tolerance = 25 * dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ***** UPDATE + vIDPrv = vJD; + eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + subHitList.push_back(&sim_hjt); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + canReEnter = status & 0x100; + if (!canReEnter && m_stripRank(vJD) == 4) + hasContinuation = false; + if (!hasContinuation) { + jdx++; + break; + } else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) + idx = jdx - 1; + } + // ***** EXTENSION?... + if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) + if (denyExtension(sim_hit, tCur.rMax() - tCur.rMin())) { + isContinuation = hasContinuation = false; + } + for (int io = 0; io < 2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + extendHit(refID, direction, lpini, lmom, lpend, lmend); + } + // ***** FLAG CASES W/ UNEXPECTED OUTCOME + flagUnexpected(header, 0, (tRef.rMin() + tRef.rMax()) / 2, sim_hit, lpini, lpend, lpos, lmom); + // ***** UPDATE (local position , DoF) + double DoF2 = 0, dir = 0; + for (int i = 0; i < 3; i++) { + double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; + lpos[i] = neu; + double d = neu - alt; + dir += d * lmom[i]; + DoF2 += d * d; + } + // Update time by ToF from original subHit to extended/COALESCED. + time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; + if (level() >= algorithms::LogLevel::kDebug) { + debug("--------------------"); + printSubHitList(subHitList); + } + return true; +} +bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, + int& idx, std::vector& usedHits, + std::vector &cIDs, double *lpos, double& eDep, double& time) const +{ + const auto [headers, sim_hits] = input; + const edm4hep::EventHeader& header = headers->at(0); + const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME + const VolumeManager& volman = m_detector->volumeManager(); + DetElement refVol = volman.lookupDetElement(refID); + // TGeoHMatrix: In order to avoid a "dangling-reference" warning, let's take + // a copy of the matrix instead of a reference to it. + const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); + double lmom[3]; + getLocalPosMom(sim_hit, toRefVol, lpos, lmom); + const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm; + using dd4hep::mm; + using edm4eic::unit::eV, edm4eic::unit::GeV; + // Hit in progress + eDep = sim_hit.getEDep(); time = sim_hit.getTime(); + // Get VOLUME parameters + const Box& bRef = refVol.solid(); // REFERENCE SUBVOLUME + double dX = bRef.x(), dY = bRef.y(); + // Get current SUBVOLUME + DetElement curVol = volman.lookupDetElement(vID); + const Box& bCur = curVol.solid(); + double dZ = bCur.z(); + double ref2Cur = getRef2Cur(refVol, curVol); + // Is TRAVERSING? + double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; + std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); + unsigned int status = + bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" + critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); + return false; + } + cIDs.push_back(sim_hit.getCellID()); + std::vector subHitList; + if (level() >= algorithms::LogLevel::kDebug) { + subHitList.push_back(&sim_hit); + } + // Continuations. + int rank = m_stripRank(vID); + bool isContinuation = status & 0x5; + bool hasContinuation = status & 0xa; + if ((rank == 0 && (status & 0x1)) || (rank == 4 && (status & 0x4))) + isContinuation = false; + if ((rank == 0 && (status & 0x2)) || (rank == 4 && (status & 0x8))) + hasContinuation = false; + if (hasContinuation) { + // ***** LOOP OVER SUBHITS + int jdx, unbroken /* unbroken succession of indices */; + CellID vIDPrv = vID; + size_t sim_size = sim_hits->size(); + for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { + const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); + // Used hit? If indeed, it's going to be discarded anyway in the + // following: current "sim_hit" is by construction at variance to it. + CellID vJD = sim_hjt.getCellID() & m_volumeBits; + int orientation = m_orientation(vIDPrv, vJD); + bool isUpstream = m_isUpstream(orientation, status); + bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); + if (!pmoStatus || !isUpstream) { + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // Get 'j' Z + curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME + const Box& boxj = curVol.solid(); + dZ = boxj.z(); + double ref2j = getRef2Cur(refVol, curVol); + // Is TRAVERSING through the (quasi)-common border? + double lpoj[3], lmoj[3]; + getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); + double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; + status = + bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd); + if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ij-Compatibility: status + bool jsDownstream = m_isDownstream(orientation, status); + if (!jsDownstream) { + if (sim_hit.isProducedBySecondary()) + break; + else { + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + } + // ij-Compatibility: close exit/entrance-distance + double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj); + const double tolerance = 25 * dd4hep::um; + bool isCompatible = dist > 0 && dist < tolerance; + if (!isCompatible) { + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } + // ***** UPDATE + vIDPrv = vJD; + eDep += sim_hjt.getEDep(); + for (int i = 0; i < 3; i++) { // Update end point position/momentum. + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; + } + // ***** BOOK-KEEPING + usedHits.push_back(jdx); + cIDs.push_back(sim_hjt.getCellID()); + if (level() >= algorithms::LogLevel::kDebug) { + subHitList.push_back(&sim_hjt); + } + // ***** CONTINUATION? + hasContinuation = status & 0xa; + if (!hasContinuation) { + jdx++; + break; + } else { // Update outgoing position/momentum for next iteration. + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } + } + } + if (unbroken) + idx = jdx - 1; + } + // ***** EXTENSION?... + if (sim_hit.isProducedBySecondary() && cIDs.size() < 2) + if (denyExtension(sim_hit, bCur.z())) { + isContinuation = hasContinuation = false; + } + for (int io = 0; io < 2; io++) { // ...into/out-of + if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation)) + continue; + int direction = io ? +1 : -1; + extendHit(refID, direction, lpini, lmom, lpend, lmend); + } + // ***** FLAG CASES W/ UNEXPECTED OUTCOME + flagUnexpected(header, 1, 0, sim_hit, lpini, lpend, lpos, lmom); + // ***** UPDATE (local position , DoF) + double DoF2 = 0, dir = 0; + for (int i = 0; i < 3; i++) { + double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i]; + lpos[i] = neu; + double d = neu - alt; + dir += d * lmom[i]; + DoF2 += d * d; + } + // Update time by ToF from original subHit to extended/COALESCED. + time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light; + if (level() >= algorithms::LogLevel::kDebug) { + debug("--------------------"); + printSubHitList(subHitList); + } + return true; +} +void MPGDTrackerDigi::printSubHitList(std::vector &subHitList) const +{ + const double edmm = edm4eic::unit::mm; + using edm4eic::unit::eV, edm4eic::unit::GeV; + int ldx = 0; + for (const edm4hep::SimTrackerHit* sim_hp : subHitList) { + CellID cIDk = sim_hp->getCellID(); + CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; + debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx++, hIDk, vIDk, sIDk); + debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hp->getPosition().x / edmm, + sim_hp->getPosition().y / edmm, sim_hp->getPosition().z / edmm); + debug(" xy_radius = {:.2f}", + std::hypot(sim_hp->getPosition().x, sim_hp->getPosition().y) / edmm); + debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hp->getMomentum().x / GeV, + sim_hp->getMomentum().y / GeV, sim_hp->getMomentum().z / GeV); + debug(" edep = {:.0f} [eV]", sim_hp->getEDep() / eV); + debug(" time = {:.2f} [ns]", sim_hp->getTime()); + } +} + void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& toModule, double* lpos, double* lmom) { const edm4hep::Vector3d& pos = sim_hit.getPosition(); diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index f2d4e7bd34..29ee9c1e17 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -44,7 +44,18 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, private: const algorithms::UniqueIDGenSvc& m_uid = algorithms::UniqueIDGenSvc::instance(); - // Member methods for checking the consistency of subHits to be accumulated + // IDDESCRIPTOR and SEGMENTATION + void parseIDDescriptor(); + void parseSegmentation(); + + // COALESCE and EXTEND + bool cCoalesceExtend(const Input& input, + int& idx, std::vector& usedHits, + std::vector &cIDs, double *lpos, double& eDep, double& time) const; + bool bCoalesceExtend(const Input& input, + int& idx, std::vector& usedHits, + std::vector &cIDs, double *lpos, double& eDep, double& time) const; + void printSubHitList(std::vector &subHitList) const; unsigned int extendHit(dd4hep::CellID modID, int direction, double* lpini, double* lmini, double* lpend, double* lmend) const; unsigned int cExtension(double const* lpos, double const* lmom, // Input subHit @@ -66,6 +77,7 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, const dd4hep::Detector* m_detector{nullptr}; dd4hep::Segmentation m_seg; // IDDescriptor + const dd4hep::BitFieldCoder* m_id_dec{nullptr}; static constexpr const char* m_fieldNames[5] = // "volume": excluding channel specification {"system", "layer", "module", "sensor", "strip"}; dd4hep::CellID m_volumeBits; // "volume" bits, as opposed to channel# bits diff --git a/src/algorithms/tracking/TrackerMeasurementFromHits.cc b/src/algorithms/tracking/TrackerMeasurementFromHits.cc index d1e39f608d..16742620ff 100644 --- a/src/algorithms/tracking/TrackerMeasurementFromHits.cc +++ b/src/algorithms/tracking/TrackerMeasurementFromHits.cc @@ -55,7 +55,6 @@ void TrackerMeasurementFromHits::init() { unsigned int required = 0; unsigned int fulfilled = 0; const dd4hep::Detector* detector = algorithms::GeoSvc::instance().detector(); - ; dd4hep::Segmentation seg; try { seg = detector->readout(readout).segmentation(); From f8fe3bc75c5bb7662e0e571ebe63bd97df49e4a5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 17:56:17 +0000 Subject: [PATCH 39/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/algorithms/digi/MPGDTrackerDigi.cc | 281 ++++++++++++------------- src/algorithms/digi/MPGDTrackerDigi.h | 14 +- 2 files changed, 146 insertions(+), 149 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 931ce51fb6..673fbc209d 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -285,13 +285,13 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, const auto& shape = refVol.solid(); if (!strcmp(shape.type(), "TGeoTubeSeg")) { // ********** TUBE GEOMETRY - if (!cCoalesceExtend(input,idx,usedHits,cIDs,lpos,eDep,time)) continue; - } - else if (!strcmp(shape.type(), "TGeoBBox")) { + if (!cCoalesceExtend(input, idx, usedHits, cIDs, lpos, eDep, time)) + continue; + } else if (!strcmp(shape.type(), "TGeoBBox")) { // ********** BOX GEOMETRY - if (!bCoalesceExtend(input,idx,usedHits,cIDs,lpos,eDep,time)) continue; - } - else { + if (!bCoalesceExtend(input, idx, usedHits, cIDs, lpos, eDep, time)) + continue; + } else { critical(R"(Bad input data: CellID {:x} has invalid shape (="{}"))", refID, shape.type()); throw JException("Inconsistency: Inappropriate Sim_hits fed to \"MPGDTRackerDigi\"."); } @@ -353,9 +353,8 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, // sum deposited energy auto charge = hit.getCharge(); - // Accumulate charge: shouldn't it be 'float' instead of 'int'? - hit.setCharge(charge + (std::int32_t)std::llround( - eDep * 1e6)); + // Accumulate charge: shouldn't it be 'float' instead of 'int'? + hit.setCharge(charge + (std::int32_t)std::llround(eDep * 1e6)); } } } @@ -384,8 +383,7 @@ void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input, } } -void MPGDTrackerDigi::parseIDDescriptor() -{ +void MPGDTrackerDigi::parseIDDescriptor() { // Parse IDDescriptor => Retrieve volume mask; check "strip" field. // "volume" mask: excluding channel specification. @@ -418,8 +416,7 @@ void MPGDTrackerDigi::parseIDDescriptor() // "volume" cleared of its "strip" bits. m_moduleBits = m_volumeBits & m_stripMask; } -void MPGDTrackerDigi::parseSegmentation() -{ +void MPGDTrackerDigi::parseSegmentation() { // MPGDTrackerDigi relies on a number of assumptions concerning the // structure of the MPGD detector and its subdivision into SUBVOLUMES. These // assumptions imply in turn a particular segmentation scheme. In particular, @@ -428,32 +425,33 @@ void MPGDTrackerDigi::parseSegmentation() // It may itself be embedded in a super MultiSegmentation: case of CyMBaL. // Let's check (limiting ourselves to main features..). debug(R"(Find valid "MultiSegmentation" for "{}" readout.)", m_cfg.readout); - bool ok = false; + bool ok = false; using Segmentation = dd4hep::DDSegmentation::Segmentation; const Segmentation* segmentation = m_seg->segmentation; if (segmentation->type() == "MultiSegmentation") { using MultiSegmentation = dd4hep::DDSegmentation::MultiSegmentation; const auto* multiSeg = dynamic_cast(segmentation); - if (multiSeg->discriminatorName() == "strip") ok = true; + if (multiSeg->discriminatorName() == "strip") + ok = true; if (!ok) { - for (const auto entry : multiSeg->subSegmentations()){ - const Segmentation* subSegmentation = entry.segmentation; - if (subSegmentation->type() == "MultiSegmentation") { - const auto* subMultiSeg - = dynamic_cast(subSegmentation); - if (subMultiSeg->discriminatorName() == "strip") { - ok = true; - } - else { - ok = false; - break; - } - } + for (const auto entry : multiSeg->subSegmentations()) { + const Segmentation* subSegmentation = entry.segmentation; + if (subSegmentation->type() == "MultiSegmentation") { + const auto* subMultiSeg = dynamic_cast(subSegmentation); + if (subMultiSeg->discriminatorName() == "strip") { + ok = true; + } else { + ok = false; + break; + } + } } } } if (!ok) { - critical(R"(Segmentation for readout "{}" is not, or is not embedding, a MultiSegmentation discriminating on a "strip" field.)", m_cfg.readout.c_str()); + critical( + R"(Segmentation for readout "{}" is not, or is not embedding, a MultiSegmentation discriminating on a "strip" field.)", + m_cfg.readout.c_str()); throw JException("Invalid Segmentation"); } } @@ -471,17 +469,16 @@ void MPGDTrackerDigi::parseSegmentation() // _global_ position argument to "dd4hep::Segmentation::cellID", we need // the _local_ position and only that. // - Also returned: updated index, vector of used subHits. -bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, - int& idx, std::vector& usedHits, - std::vector &cIDs, double *lpos, double& eDep, double& time) const -{ - const auto [headers, sim_hits] = input; - const edm4hep::EventHeader& header = headers->at(0); +bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, int& idx, std::vector& usedHits, + std::vector& cIDs, double* lpos, double& eDep, + double& time) const { + const auto [headers, sim_hits] = input; + const edm4hep::EventHeader& header = headers->at(0); const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME - const VolumeManager& volman = m_detector->volumeManager(); - DetElement refVol = volman.lookupDetElement(refID); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME + const VolumeManager& volman = m_detector->volumeManager(); + DetElement refVol = volman.lookupDetElement(refID); // TGeoHMatrix: In order to avoid a "dangling-reference" warning, let's take // a copy of the matrix instead of a reference to it. const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); @@ -491,7 +488,8 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, using dd4hep::mm; using edm4eic::unit::eV, edm4eic::unit::GeV; // Hit in progress - eDep = sim_hit.getEDep(); time = sim_hit.getTime(); + eDep = sim_hit.getEDep(); + time = sim_hit.getTime(); // Get VOLUME parameters const Tube& tRef = refVol.solid(); double dZ = tRef.dZ(); @@ -512,8 +510,8 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = - cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), - rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend); + cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), + rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); return false; @@ -541,7 +539,7 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, if (hasContinuation) { // ***** LOOP OVER HITS int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; + CellID vIDPrv = vID; size_t sim_size = sim_hits->size(); for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); @@ -554,13 +552,13 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, bool isUpstream = m_isUpstream(orientation, status); bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // Get 'j' radii curVol = volman.lookupDetElement(vJD); @@ -571,67 +569,67 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); // Is TRAVERSING through the (quasi-)common wall? double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), rMin, rMax, dZ, startPhi, endPhi, - ljns, lovts, lpjni, lpfnd); + status = + cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(), + rMin, rMax, dZ, startPhi, endPhi, ljns, lovts, lpjni, lpfnd); if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // ij-Compatibility: status bool jsDownstream = m_isDownstream(orientation, status); if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) - break; - else { // Allow for primary hits to not come in unbroken sequence - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } + if (sim_hit.isProducedBySecondary()) + break; + else { // Allow for primary hits to not come in unbroken sequence + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } } // ij-Compatibility: close exit/entrance-distance double dist = outInDistance(0, orientation, ljns, louts, lmom, lmoj); const double tolerance = 25 * dd4hep::um; bool isCompatible = dist > 0 && dist < tolerance; if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, - /* */ sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // ***** UPDATE vIDPrv = vJD; eDep += sim_hjt.getEDep(); for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; - lmend[i] = lmoj[i]; + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; } // ***** BOOK-KEEPING usedHits.push_back(jdx); cIDs.push_back(sim_hjt.getCellID()); if (level() >= algorithms::LogLevel::kDebug) { - subHitList.push_back(&sim_hjt); + subHitList.push_back(&sim_hjt); } // ***** CONTINUATION? hasContinuation = status & 0xa; canReEnter = status & 0x100; if (!canReEnter && m_stripRank(vJD) == 4) - hasContinuation = false; + hasContinuation = false; if (!hasContinuation) { - jdx++; - break; + jdx++; + break; } else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; - louts[1][i] = lovts[1][i]; - } + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } } } if (unbroken) @@ -667,17 +665,16 @@ bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, } return true; } -bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, - int& idx, std::vector& usedHits, - std::vector &cIDs, double *lpos, double& eDep, double& time) const -{ - const auto [headers, sim_hits] = input; - const edm4hep::EventHeader& header = headers->at(0); +bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, int& idx, std::vector& usedHits, + std::vector& cIDs, double* lpos, double& eDep, + double& time) const { + const auto [headers, sim_hits] = input; + const edm4hep::EventHeader& header = headers->at(0); const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx); - CellID vID = sim_hit.getCellID() & m_volumeBits; - CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME - const VolumeManager& volman = m_detector->volumeManager(); - DetElement refVol = volman.lookupDetElement(refID); + CellID vID = sim_hit.getCellID() & m_volumeBits; + CellID refID = vID & m_moduleBits; // => The REFERENCE SUBVOLUME + const VolumeManager& volman = m_detector->volumeManager(); + DetElement refVol = volman.lookupDetElement(refID); // TGeoHMatrix: In order to avoid a "dangling-reference" warning, let's take // a copy of the matrix instead of a reference to it. const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation(); @@ -687,7 +684,8 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, using dd4hep::mm; using edm4eic::unit::eV, edm4eic::unit::GeV; // Hit in progress - eDep = sim_hit.getEDep(); time = sim_hit.getTime(); + eDep = sim_hit.getEDep(); + time = sim_hit.getTime(); // Get VOLUME parameters const Box& bRef = refVol.solid(); // REFERENCE SUBVOLUME double dX = bRef.x(), dY = bRef.y(); @@ -700,8 +698,8 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3]; std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend)); unsigned int status = - bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend); + bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend); if (status & 0xff000) { // Inconsistency => Drop current "sim_hit" critical(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom)); return false; @@ -722,7 +720,7 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, if (hasContinuation) { // ***** LOOP OVER SUBHITS int jdx, unbroken /* unbroken succession of indices */; - CellID vIDPrv = vID; + CellID vIDPrv = vID; size_t sim_size = sim_hits->size(); for (jdx = idx + 1, unbroken = 1; jdx < (int)sim_size; jdx++) { const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx); @@ -733,13 +731,13 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, bool isUpstream = m_isUpstream(orientation, status); bool pmoStatus = samePMO(sim_hit, sim_hjt, unbroken); if (!pmoStatus || !isUpstream) { - if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) - // Bizarre: let's flag the case while debugging - debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) + // Bizarre: let's flag the case while debugging + debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // Get 'j' Z curVol = volman.lookupDetElement(vJD); // 'j' SUBVOLUME @@ -750,64 +748,63 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, double lpoj[3], lmoj[3]; getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj); double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3]; - status = - bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd, - sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd); + status = bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd, + sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd); if (status & 0xff000) { // Inconsistency => Drop current "sim_hjt" - critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + critical(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // ij-Compatibility: status bool jsDownstream = m_isDownstream(orientation, status); if (!jsDownstream) { - if (sim_hit.isProducedBySecondary()) - break; - else { - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; - } + if (sim_hit.isProducedBySecondary()) + break; + else { + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; + } } // ij-Compatibility: close exit/entrance-distance double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj); const double tolerance = 25 * dd4hep::um; bool isCompatible = dist > 0 && dist < tolerance; if (!isCompatible) { - if (!sim_hit.isProducedBySecondary()) - debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, - /* */ sim_hjt.getCellID(), lpoj, lmoj)); - if (unbroken) - idx = jdx - 1; - unbroken = 0; - continue; + if (!sim_hit.isProducedBySecondary()) + debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom, + /* */ sim_hjt.getCellID(), lpoj, lmoj)); + if (unbroken) + idx = jdx - 1; + unbroken = 0; + continue; } // ***** UPDATE vIDPrv = vJD; eDep += sim_hjt.getEDep(); for (int i = 0; i < 3; i++) { // Update end point position/momentum. - lpend[i] = lpfnd[i]; - lmend[i] = lmoj[i]; + lpend[i] = lpfnd[i]; + lmend[i] = lmoj[i]; } // ***** BOOK-KEEPING usedHits.push_back(jdx); cIDs.push_back(sim_hjt.getCellID()); if (level() >= algorithms::LogLevel::kDebug) { - subHitList.push_back(&sim_hjt); + subHitList.push_back(&sim_hjt); } // ***** CONTINUATION? hasContinuation = status & 0xa; if (!hasContinuation) { - jdx++; - break; + jdx++; + break; } else { // Update outgoing position/momentum for next iteration. - for (int i = 0; i < 3; i++) { - louts[0][i] = lovts[0][i]; - louts[1][i] = lovts[1][i]; - } + for (int i = 0; i < 3; i++) { + louts[0][i] = lovts[0][i]; + louts[1][i] = lovts[1][i]; + } } } if (unbroken) @@ -843,21 +840,21 @@ bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, } return true; } -void MPGDTrackerDigi::printSubHitList(std::vector &subHitList) const -{ +void MPGDTrackerDigi::printSubHitList( + std::vector& subHitList) const { const double edmm = edm4eic::unit::mm; using edm4eic::unit::eV, edm4eic::unit::GeV; int ldx = 0; for (const edm4hep::SimTrackerHit* sim_hp : subHitList) { - CellID cIDk = sim_hp->getCellID(); + CellID cIDk = sim_hp->getCellID(); CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits, sIDk = vIDk >> 28 & 0xff; debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x} 0x{:02x}", ldx++, hIDk, vIDk, sIDk); debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hp->getPosition().x / edmm, - sim_hp->getPosition().y / edmm, sim_hp->getPosition().z / edmm); + sim_hp->getPosition().y / edmm, sim_hp->getPosition().z / edmm); debug(" xy_radius = {:.2f}", - std::hypot(sim_hp->getPosition().x, sim_hp->getPosition().y) / edmm); + std::hypot(sim_hp->getPosition().x, sim_hp->getPosition().y) / edmm); debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hp->getMomentum().x / GeV, - sim_hp->getMomentum().y / GeV, sim_hp->getMomentum().z / GeV); + sim_hp->getMomentum().y / GeV, sim_hp->getMomentum().z / GeV); debug(" edep = {:.0f} [eV]", sim_hp->getEDep() / eV); debug(" time = {:.2f} [ns]", sim_hp->getTime()); } diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index 29ee9c1e17..dd814d97bf 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -49,13 +49,13 @@ class MPGDTrackerDigi : public MPGDTrackerDigiAlgorithm, void parseSegmentation(); // COALESCE and EXTEND - bool cCoalesceExtend(const Input& input, - int& idx, std::vector& usedHits, - std::vector &cIDs, double *lpos, double& eDep, double& time) const; - bool bCoalesceExtend(const Input& input, - int& idx, std::vector& usedHits, - std::vector &cIDs, double *lpos, double& eDep, double& time) const; - void printSubHitList(std::vector &subHitList) const; + bool cCoalesceExtend(const Input& input, int& idx, std::vector& usedHits, + std::vector& cIDs, double* lpos, double& eDep, + double& time) const; + bool bCoalesceExtend(const Input& input, int& idx, std::vector& usedHits, + std::vector& cIDs, double* lpos, double& eDep, + double& time) const; + void printSubHitList(std::vector& subHitList) const; unsigned int extendHit(dd4hep::CellID modID, int direction, double* lpini, double* lmini, double* lpend, double* lmend) const; unsigned int cExtension(double const* lpos, double const* lmom, // Input subHit From b4feddd70e5326c535bd7c3dfbf530d4dc193b52 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Sat, 22 Nov 2025 19:16:13 +0100 Subject: [PATCH 40/47] MPGDTRackerDigi: Fix spelling mistake. --- src/algorithms/digi/MPGDTrackerDigi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index 673fbc209d..ec816e0dc6 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -460,7 +460,7 @@ void MPGDTrackerDigi::parseSegmentation() { // EXTEND hits (subHits or coalesced subHits) to full sensitive volume // - Input = Elementary subHit, specified as index into collection of SimHits. // - Output = Coalesced/extended hit, specified by: -// + list of cellIDs of elementary subHits contributiong, +// + list of cellIDs of elementary subHits contributing, // + local position, // + EDep, // + time. From df028e17ba490070b2847963b0c98a684a389c0b Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Sat, 22 Nov 2025 14:13:12 -0600 Subject: [PATCH 41/47] =?UTF-8?q?MPGDTrackerDigi:=20Multi-SensitiveVolume?= =?UTF-8?q?=20solution=20for=20the=202D-strip=20read=E2=80=A6=20(fix:=20iw?= =?UTF-8?q?yu)=20(#2199)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/19599402189. Please merge this PR into the branch `MultiSensitiveMPGD` to resolve failures in PR #2177. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/algorithms/digi/MPGDTrackerDigi.cc | 1 + src/algorithms/digi/MPGDTrackerDigi.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index ec816e0dc6..bec9d6d173 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -96,6 +96,7 @@ #include #include #include +#include #include #include #include diff --git a/src/algorithms/digi/MPGDTrackerDigi.h b/src/algorithms/digi/MPGDTrackerDigi.h index dd814d97bf..e84eaf8aa5 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.h +++ b/src/algorithms/digi/MPGDTrackerDigi.h @@ -11,9 +11,11 @@ #include #include #include +#include #include #include #include +#include #include "MPGDTrackerDigiConfig.h" #include "algorithms/interfaces/UniqueIDGenSvc.h" From 0ba231786c6432f2621974621b730863136c2b1d Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Wed, 26 Nov 2025 17:12:57 +0100 Subject: [PATCH 42/47] MPGD Barrel: Default digitization factory determined from XML file (and cosmetics...) - Constant "_2DStrip" is expected to be defined in XML file. - If successfully queried and its value turns out !=0, "MPGDTrackerDigi" becomes default. --- src/algorithms/digi/MPGDTrackerDigi.cc | 5 ++- src/detectors/MPGD/MPGD.cc | 53 ++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/algorithms/digi/MPGDTrackerDigi.cc b/src/algorithms/digi/MPGDTrackerDigi.cc index bec9d6d173..8a34929eca 100644 --- a/src/algorithms/digi/MPGDTrackerDigi.cc +++ b/src/algorithms/digi/MPGDTrackerDigi.cc @@ -54,8 +54,9 @@ hinging on (III), should be sufficient. But there are so many cases to take into account that it's difficult to settle on a minimal subset. - Evaluation: - + With 3 mm overall sensitive volume (=> ~1.5 mm SUBVOLUME), MIPs turn out - firing most of the time only one SUBVOLUME. + + With 3 mm overall sensitive volume (=> ~1.5 mm SUBVOLUME) and a cutoff + on deposited energy of 1 keV, MIPs turn out firing most of the time only + one SUBVOLUME. + MIPs are found to be properly handled: hits are assigned to mid-plane, are COALESCED when needed... ...Except for few cases, see "flagUnexpected". diff --git a/src/detectors/MPGD/MPGD.cc b/src/detectors/MPGD/MPGD.cc index 082cc77cfe..262c639388 100644 --- a/src/detectors/MPGD/MPGD.cc +++ b/src/detectors/MPGD/MPGD.cc @@ -16,11 +16,12 @@ #include "factories/digi/MPGDTrackerDigi_factory.h" #include "factories/digi/SiliconTrackerDigi_factory.h" #include "factories/tracking/TrackerHitReconstruction_factory.h" +#include "services/log/Log_service.h" -// 2D-STRIP DIGITIZATION = DEFAULT +// 2D-STRIP DIGITIZATION // - Is produced by "MPGDTrackerDigi". -// - Relies on "MultiSegmentation" in "compact" geometry file. -// PIXEL DIGITIZATION = BROUGHT INTO PLAY BY OPTION "MPGD:SiFactoryPattern". +// - Relies on 2DStrip version of "compact" geometry file. +// PIXEL DIGITIZATION // - Is produced by "SiliconTrackerDigi". extern "C" { @@ -29,10 +30,40 @@ void InitPlugin(JApplication* app) { using namespace eicrecon; - // PIXEL DIGITIZATION? - // It's encoded in bit pattern "SiFactoryPattern": 0x1=CyMBaL, 0x2=OuterBarrel, ... - // unsigned int SiFactoryPattern = 0x0; // no SiliconTrackerDigi - unsigned int SiFactoryPattern = 0x3; // using SiliconTrackerDigi + // ***** PIXEL or 2DSTRIP DIGITIZATION? + // - This determines which of the MPGDTrackerDigi or SiliconTrackerDigi + // factory is used. + // - It's encoded in XML constants "_2DStrip", which can be + // conveniently set in the XMLs of the MPGDs. + // - It can be reset from command line via the "MPGD:SiFactoryPattern" option, + // which is a bit pattern: 0x1=CyMBaL, 0x2=OuterBarrel, ... + // - It defaults (when neither XML constant nor command line option) to + // SiliconTrackerDigi. + // Default + unsigned int SiFactoryPattern = 0x3; // Full-scale SiliconTrackerDigi + // XML constant + auto log_service = app->GetService(); + auto mLog = log_service->logger("tracking"); + const char *MPGD_names[] = {"InnerMPGDBarrel","MPGDOuterBarrel"}; + int nMPGDs = sizeof(MPGD_names)/sizeof(char*); + for (int mpgd = 0; mpgd < nMPGDs; mpgd++){ + std::string MPGD_name(MPGD_names[mpgd]); + std::string constant_name = MPGD_name + std::string("_2DStrip"); + try { + auto detector = app->GetService()->detector(); + int constant = detector->constant(constant_name); + if (constant == 1) { + SiFactoryPattern &= ~(0x1 << mpgd); + mLog->info(R"(2DStrip XML loaded for "{}")",MPGD_name); + } + else { + mLog->info(R"(pixel XML loaded for "{}")",MPGD_name); + } + } catch (...) { + // Variable not present apply legacy pixel readout + } + } + // Command line option std::string SiFactoryPattern_str; app->SetDefaultParameter("MPGD:SiFactoryPattern", SiFactoryPattern_str, "Hexadecimal Pattern of MPGDs digitized via \"SiliconTrackerDigi\""); @@ -46,6 +77,14 @@ void InitPlugin(JApplication* app) { e.what(), SiFactoryPattern_str.c_str()); } } + for (int mpgd = 0; mpgd < nMPGDs; mpgd++){ + std::string MPGD_name(MPGD_names[mpgd]); + if (SiFactoryPattern & (0x1 << mpgd)) { + mLog->info(R"(2DStrip digitization will be applied to "{}")",MPGD_name); + } else { + mLog->info(R"(pixel digitization will be applied to "{}")",MPGD_name); + } + } // ***** "MPGDBarrel" (=CyMBaL) // Digitization From aba8e894553ffc0fc00d3b3585f3b10b4d59e485 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:13:34 +0000 Subject: [PATCH 43/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/detectors/MPGD/MPGD.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/detectors/MPGD/MPGD.cc b/src/detectors/MPGD/MPGD.cc index 262c639388..80c8587f93 100644 --- a/src/detectors/MPGD/MPGD.cc +++ b/src/detectors/MPGD/MPGD.cc @@ -42,22 +42,21 @@ void InitPlugin(JApplication* app) { // Default unsigned int SiFactoryPattern = 0x3; // Full-scale SiliconTrackerDigi // XML constant - auto log_service = app->GetService(); - auto mLog = log_service->logger("tracking"); - const char *MPGD_names[] = {"InnerMPGDBarrel","MPGDOuterBarrel"}; - int nMPGDs = sizeof(MPGD_names)/sizeof(char*); - for (int mpgd = 0; mpgd < nMPGDs; mpgd++){ + auto log_service = app->GetService(); + auto mLog = log_service->logger("tracking"); + const char* MPGD_names[] = {"InnerMPGDBarrel", "MPGDOuterBarrel"}; + int nMPGDs = sizeof(MPGD_names) / sizeof(char*); + for (int mpgd = 0; mpgd < nMPGDs; mpgd++) { std::string MPGD_name(MPGD_names[mpgd]); std::string constant_name = MPGD_name + std::string("_2DStrip"); try { auto detector = app->GetService()->detector(); - int constant = detector->constant(constant_name); + int constant = detector->constant(constant_name); if (constant == 1) { - SiFactoryPattern &= ~(0x1 << mpgd); - mLog->info(R"(2DStrip XML loaded for "{}")",MPGD_name); - } - else { - mLog->info(R"(pixel XML loaded for "{}")",MPGD_name); + SiFactoryPattern &= ~(0x1 << mpgd); + mLog->info(R"(2DStrip XML loaded for "{}")", MPGD_name); + } else { + mLog->info(R"(pixel XML loaded for "{}")", MPGD_name); } } catch (...) { // Variable not present apply legacy pixel readout @@ -77,12 +76,12 @@ void InitPlugin(JApplication* app) { e.what(), SiFactoryPattern_str.c_str()); } } - for (int mpgd = 0; mpgd < nMPGDs; mpgd++){ + for (int mpgd = 0; mpgd < nMPGDs; mpgd++) { std::string MPGD_name(MPGD_names[mpgd]); if (SiFactoryPattern & (0x1 << mpgd)) { - mLog->info(R"(2DStrip digitization will be applied to "{}")",MPGD_name); + mLog->info(R"(2DStrip digitization will be applied to "{}")", MPGD_name); } else { - mLog->info(R"(pixel digitization will be applied to "{}")",MPGD_name); + mLog->info(R"(pixel digitization will be applied to "{}")", MPGD_name); } } From 2d8450c16451cc12c7b5c122d993f16ef3866457 Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Wed, 26 Nov 2025 19:39:13 +0100 Subject: [PATCH 44/47] MPGD Barrel: Fix Clang-Tidy warning in "MPGD.cc". --- src/detectors/MPGD/MPGD.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detectors/MPGD/MPGD.cc b/src/detectors/MPGD/MPGD.cc index 80c8587f93..e379fdefef 100644 --- a/src/detectors/MPGD/MPGD.cc +++ b/src/detectors/MPGD/MPGD.cc @@ -44,8 +44,8 @@ void InitPlugin(JApplication* app) { // XML constant auto log_service = app->GetService(); auto mLog = log_service->logger("tracking"); - const char* MPGD_names[] = {"InnerMPGDBarrel", "MPGDOuterBarrel"}; - int nMPGDs = sizeof(MPGD_names) / sizeof(char*); + const int nMPGDs = 2; + const char* MPGD_names[nMPGDs] = {"InnerMPGDBarrel", "MPGDOuterBarrel"}; for (int mpgd = 0; mpgd < nMPGDs; mpgd++) { std::string MPGD_name(MPGD_names[mpgd]); std::string constant_name = MPGD_name + std::string("_2DStrip"); From 495f44badd73de63f64649f58021ea3971d92a1b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 18:40:12 +0000 Subject: [PATCH 45/47] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/detectors/MPGD/MPGD.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detectors/MPGD/MPGD.cc b/src/detectors/MPGD/MPGD.cc index e379fdefef..8df0bbe3d4 100644 --- a/src/detectors/MPGD/MPGD.cc +++ b/src/detectors/MPGD/MPGD.cc @@ -42,9 +42,9 @@ void InitPlugin(JApplication* app) { // Default unsigned int SiFactoryPattern = 0x3; // Full-scale SiliconTrackerDigi // XML constant - auto log_service = app->GetService(); - auto mLog = log_service->logger("tracking"); - const int nMPGDs = 2; + auto log_service = app->GetService(); + auto mLog = log_service->logger("tracking"); + const int nMPGDs = 2; const char* MPGD_names[nMPGDs] = {"InnerMPGDBarrel", "MPGDOuterBarrel"}; for (int mpgd = 0; mpgd < nMPGDs; mpgd++) { std::string MPGD_name(MPGD_names[mpgd]); From 25852193e8d85fff5cd093cf8d1cf4c5c0836d1e Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Wed, 26 Nov 2025 12:58:18 -0600 Subject: [PATCH 46/47] =?UTF-8?q?MPGDTrackerDigi:=20Multi-SensitiveVolume?= =?UTF-8?q?=20solution=20for=20the=202D-strip=20read=E2=80=A6=20(fix:=20iw?= =?UTF-8?q?yu)=20(#2204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/19710271095. Please merge this PR into the branch `MultiSensitiveMPGD` to resolve failures in PR #2177. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/detectors/MPGD/MPGD.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/detectors/MPGD/MPGD.cc b/src/detectors/MPGD/MPGD.cc index 8df0bbe3d4..fb933e7c74 100644 --- a/src/detectors/MPGD/MPGD.cc +++ b/src/detectors/MPGD/MPGD.cc @@ -3,11 +3,17 @@ // // +#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -16,6 +22,7 @@ #include "factories/digi/MPGDTrackerDigi_factory.h" #include "factories/digi/SiliconTrackerDigi_factory.h" #include "factories/tracking/TrackerHitReconstruction_factory.h" +#include "services/geometry/dd4hep/DD4hep_service.h" #include "services/log/Log_service.h" // 2D-STRIP DIGITIZATION From 7afe33a64309f533e98f27b898f4dbd5d314deaf Mon Sep 17 00:00:00 2001 From: yann bedfer Date: Thu, 27 Nov 2025 19:24:33 +0100 Subject: [PATCH 47/47] trigger GitHub actions