41 {
46 }
47
48 const MmDigitContainer* mmDigits{nullptr};
50 const ActsTrk::GeometryContext* gctx{nullptr};
52
54
55 unsigned int nCollections{0}, nHitsTotal{0};
56 for (const MmDigitCollection* digitCollection : *mmDigits) {
57
58 std::vector<MMT_Hit> ev_hits;
59 double tanStereoAngle{0.};
60 unsigned int nOutOfRange{0}, nNegTime{0}, nInfSlope{0};
61 Identifier firstHitId{};
62
63 for (const MmDigit* digit : *digitCollection) {
64 const Identifier
id =
digit->identify();
66
67
68
70
71
72
73
74 const MuonGMR4::MmReadoutElement* readout =
m_detMgr->getMmReadoutElement(
id);
75 const IdentifierHash layHash = readout->
layerHash(
id);
77 const int numStrips = readout->
numStrips(layHash);
79
80 tanStereoAngle = std::max(tanStereoAngle, std::tan(std::abs(design.
stereoAngle())));
81 if (channel < firstStrip || channel >= firstStrip + numStrips) {
82 ++nOutOfRange;
84 << " allowed [" << firstStrip << ", " << firstStrip + numStrips - 1 << "]");
85 continue;
86 }
87
88 const float stripTime =
digit->stripResponseTime();
89
90 if (stripTime < 0.) {
91 ++nNegTime;
92 continue;
93 }
94 const int BC =
static_cast<int>(std::ceil(stripTime / kBunchSpacing));
95 ev_hits.emplace_back(
id, stripTime, BC,
m_detMgr, *gctx);
96
97 if (ev_hits.back().infSlope()) {
99 ++nInfSlope;
100 ev_hits.pop_back();
101 continue;
102 }
104
105
107 const MMT_Hit&
h = ev_hits.back();
108 MMHitInfo&
info =
debug->hits.emplace_back();
109 info.stationEta =
h.getStationEta();
110 info.stationPhi =
h.getStationPhi();
111 info.sectorPhi =
h.getSectorPhi();
112 info.sector =
h.getSector();
113 info.plane =
h.getPlane();
114 info.strip =
h.getChannel();
115 info.VMM =
h.getVMM();
116 info.ART =
h.getART();
118 info.time =
h.getTime();
121 info.RZslope =
h.getRZSlope();
122 info.shift =
h.getShift();
123 }
124 }
125
126 if (ev_hits.empty() && nOutOfRange == 0) continue;
127 ++nCollections;
128 nHitsTotal += ev_hits.size();
129
131 << ": " << ev_hits.size() << " hits"
132 << " (dropped: out-of-range " << nOutOfRange << ", negative time " << nNegTime
133 << ", inf slope " << nInfSlope << ")");
134
135
138 << ", less than X+UV threshold, skipping digit collection");
139 continue;
140 }
141
142 const bool isLarge = std::ranges::all_of(ev_hits, [](
const auto&
hit) {
return hit.getSector() ==
'L'; });
143 const SideType side = std::ranges::all_of(ev_hits, [](
const auto&
hit) {
return hit.getStationEta() < 0; })
145 const int sectorPhi = ev_hits[0].getSectorPhi();
146 const bool allSectorPhi = std::ranges::all_of(ev_hits,
147 [&](
const auto&
hit) {
return hit.getSectorPhi() == sectorPhi; });
148 if (!allSectorPhi) {
149 ATH_MSG_ERROR(
"Available digits belongs to different sectors IDs, unable to assign an unique ID");
150 return StatusCode::FAILURE;
151 }
152 const bool isEta1 = std::ranges::all_of(ev_hits,
153 [](
const auto&
hit) {
return std::abs(
hit.getStationEta()) == 1; });
154
155
156 std::vector<MMT_Road> ev_roads;
157 m_diamond->createRoads(ev_roads, isLarge, isEta1);
158
159
160 std::vector<slope_t> diamondSlopes;
161 m_diamond->findDiamonds(ev_hits, ev_roads, diamondSlopes, sectorPhi, tanStereoAngle);
162 ATH_MSG_DEBUG(
" -> " << diamondSlopes.size() <<
" coincidence(s) in sector " << sectorPhi << side);
163 if (diamondSlopes.empty()) continue;
164 if (
debug)
debug->nTrig.push_back(diamondSlopes.size());
165
166
167
168
169
170 const MuonGMR4::MmReadoutElement* stationEl =
m_detMgr->getMmReadoutElement(firstHitId);
171 const double sectorCentrePhi = stationEl->
center(*gctx).phi();
172
173 for (const slope_t& slope : diamondSlopes) {
174 MMCandidate& cand =
candidates.emplace_back();
175 cand.sectorPhi = sectorPhi;
177 cand.BC = slope.BC;
178 cand.eta = slope.eta;
179 cand.phi = slope.phi;
180 cand.phiShf = slope.phiShf;
181
183 cand.dtheta = slope.dtheta;
184 cand.lowRes = slope.lowRes;
185 cand.iX = slope.iRoad;
186 cand.iU = slope.iRoadu;
187 cand.iV = slope.iRoadv;
188 cand.nHits = slope.totalCount;
189
190 cand.sector = isLarge ? 'L' : 'S';
191 cand.xCount = slope.xCount;
192 cand.uCount = slope.uCount;
193 cand.age = slope.age;
194 cand.mx = slope.mx;
195 cand.my = slope.my;
196 cand.mxl = slope.mxl;
197 cand.uavg = slope.uavg;
198 cand.vavg = slope.vavg;
199 cand.theta = slope.theta;
200 cand.secCentrePhi = sectorCentrePhi;
201 }
202 }
203
204 ATH_MSG_DEBUG(
"MM trigger: " << nHitsTotal <<
" hits in " << nCollections
205 <<
" digit collections -> " <<
candidates.size() <<
" candidates");
206 return StatusCode::SUCCESS;
207 }
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
bool is_valid() const
Check if id is in a valid state.
int channel(const Identifier &id) const override
const StripLayer & stripLayer(const Identifier &measId) const
unsigned int numStrips(const IdentifierHash &layerHash) const
Returns the number of total active strips.
IdentifierHash layerHash(const Identifier &measId) const override final
The layer hash removes the bits from the IdentifierHash corresponding to the measurement's channel nu...
unsigned int firstStrip(const IdentifierHash &layerHash) const
Returns the first active strip.
Amg::Vector3D center(const ActsTrk::GeometryContext &ctx) const
Returns the geometrical center point of the readout element.
double stereoAngle() const
Returns the value of the stereo angle.
const StripDesign & design(bool phiView=false) const
Returns the underlying strip design.
SideType
Detector side. The value is the sign of z, so that it can be used as a sign (e.g. Acts::copySign).
double wrapTwoPi(double phi)
Map any angle to [0, 2pi).
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.