ATLAS Offline Software
Loading...
Searching...
No Matches
MuonFastRecoTester.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
12#include "CxxUtils/phihelper.h"
13
14namespace {
15 static const Muon::MuonSectorMapping sectorMap{};
16 static const SG::ConstAccessor<ElementLink<MuonR4::GlobalPatternContainer>> patLinkAcc{"globalPatternLink"};
17
18 void resize_all (const std::size_t nEle, const std::size_t size, auto&&... vecs) {
19 for (std::size_t idx = 0; idx < nEle; ++idx) {
20 (vecs[idx].resize(size), ...);
21 }
22 };
23 double inDegrees(double angle) {
24 return angle / Gaudi::Units::deg;
25 }
26}
27
28namespace MuonValR4 {
29 using namespace MuonR4;
30 using namespace MuonVal;
32 constexpr std::size_t s_nStations {Acts::toUnderlying(StIndex::StIndexMax)};
33 using simHitSet = std::unordered_set<const xAOD::MuonSimHit*>;
34 using TruthParticleMap = std::map<const xAOD::TruthParticle*, std::vector<simHitSet>>;
35 std::optional<std::size_t> isTruthMatched (const xAOD::MuonMeasurement& meas,
36 const TruthParticleMap& truthHits) {
37 const xAOD::MuonSimHit* hit {getTruthMatchedHit(meas)};
38 if (!hit) return std::nullopt;
39 std::size_t idx{0};
40 for (const auto& [tp, truthHitSets] : truthHits) {
41 for (const simHitSet& truthHitSet : truthHitSets) {
42 if (truthHitSet.count(hit)) {
43 if (tp) return idx;
44 else return truthHits.size(); // Pileup muon
45 }
46 }
47 if (tp) ++idx;
48 }
49 return std::nullopt;
50 };
51 bool isInPattern (const SpacePoint* sp,
52 const StIndex station,
53 const GlobalPattern& pattern){
54 for (const SpacePoint* hit : pattern.hitsInStation(station)) {
55 if (hit == sp) return true;
56 }
57 return false;
58 };
59
61 ATH_CHECK(m_geoCtxKey.initialize());
62 {
63 int infoOpts = 0;
64 if (m_isMC) infoOpts = EventInfoBranch::isMC;
65 m_tree.addBranch(std::make_unique<EventInfoBranch>(m_tree, infoOpts));
66 }
67 ATH_CHECK(m_spKey.initialize(!m_spKey.empty()));
68 ATH_CHECK(m_NSWspKey.initialize(!m_NSWspKey.empty()));
71 if (!m_spKey.empty()) {
72 m_spTester = std::make_shared<SpacePointTesterModule>(m_tree, m_spKey.key(), msgLevel(), "Muon");
73 m_tree.addBranch(m_spTester);
74 if (!m_isMC) m_tree.disableBranch(m_spMatchedToTruth.name());
75 }
76 if (!m_NSWspKey.empty()) {
77 m_NSWspTester = std::make_shared<SpacePointTesterModule>(m_tree, m_NSWspKey.key(), msgLevel(), "Nsw");
78 m_tree.addBranch(m_NSWspTester);
79 if (!m_isMC) m_tree.disableBranch(m_NSWspMatchedToTruth.name());
80 }
81 } else {
82 m_tree.disableBranch(m_spType.name());
83 m_tree.disableBranch(m_NSWspType.name());
84 m_tree.disableBranch(m_spMatchedToPattern.name());
85 m_tree.disableBranch(m_NSWspMatchedToPattern.name());
86 m_tree.disableBranch(m_spMatchedToTruth.name());
87 m_tree.disableBranch(m_NSWspMatchedToTruth.name());
88 }
89 if (!m_isMC) {
90 m_tree.disableBranch(m_gen_Eta.name());
91 m_tree.disableBranch(m_gen_Phi.name());
92 m_tree.disableBranch(m_gen_Pt.name());
93 m_tree.disableBranch(m_gen_Q.name());
94 m_tree.disableBranch(m_pat_nTruthNonPrecMeas.name());
95 m_tree.disableBranch(m_pat_nTruthPrecMeas.name());
96 m_tree.disableBranch(m_pat_nTruthPhiMeas.name());
97 m_tree.disableBranch(m_pat_MatchedToTruth.name());
98 }
99 if (!m_isSeededReco) {
100 m_tree.disableBranch(m_roi_EtaMin.name());
101 m_tree.disableBranch(m_roi_EtaMax.name());
102 m_tree.disableBranch(m_roi_PhiMin.name());
103 m_tree.disableBranch(m_roi_PhiMax.name());
104 m_tree.disableBranch(m_roi_ZMin.name());
105 m_tree.disableBranch(m_roi_ZMax.name());
106 }
107 ATH_CHECK(m_patternKey.initialize());
108 ATH_CHECK(m_fastMuonKey.initialize());
109 ATH_CHECK(m_truthSegmentKey.initialize(!m_truthSegmentKey.empty()));
110 ATH_CHECK(m_tree.init(this));
111 ATH_CHECK(m_idHelperSvc.retrieve());
112 return StatusCode::SUCCESS;
113 }
114
116 ATH_CHECK(m_tree.write());
117 return StatusCode::SUCCESS;
118 }
119 StatusCode MuonFastRecoTester::execute(const EventContext& ctx) {
120
121 //const ActsTrk::GeometryContext* gctxPtr{nullptr};
122 //ATH_CHECK(SG::get(gctxPtr, m_geoCtxKey, ctx));
123
124 const SpacePointContainer* spContainer {nullptr};
125 ATH_CHECK(SG::get(spContainer, m_spKey, ctx));
126
127 const SpacePointContainer* NSWspContainer {nullptr};
128 ATH_CHECK(SG::get(NSWspContainer, m_NSWspKey, ctx));
129
130 const GlobalPatternContainer* globPatterns{nullptr};
131 ATH_CHECK(SG::get(globPatterns, m_patternKey, ctx));
132
133 const xAOD::MuonContainer* fastMuons{nullptr};
134 ATH_CHECK(SG::get(fastMuons, m_fastMuonKey, ctx));
135
136 const xAOD::MuonSegmentContainer* readTruthSegments{nullptr};
137 if(m_isMC){
138 ATH_CHECK(SG::get(readTruthSegments , m_truthSegmentKey, ctx));
139 }
140 const TrigRoiDescriptorCollection* roiCollection{nullptr};
141 if(m_isSeededReco) {
142 ATH_CHECK(SG::get(roiCollection, m_roiCollectionKey, ctx));
143 }
144
145 ATH_MSG_DEBUG("Succesfully retrieved input collections: Global Patterns: "<<globPatterns->size()
146 <<", truth segments: "<<(readTruthSegments? std::to_string(readTruthSegments->size()) : std::to_string(-1))
147 <<", Rois: "<<(roiCollection ? std::to_string(roiCollection->size()) : std::to_string(-1)));
148
149 const TruthParticleMap truthMap{fillTruthMap(readTruthSegments, roiCollection)};
150 fillTruthInfo(truthMap, {spContainer, NSWspContainer});
151 fillRoIInfo(roiCollection);
152
153 if (m_writeSpacePoints) {
154 fillSpacePointInfo(spContainer, globPatterns, truthMap,
156 fillSpacePointInfo(NSWspContainer, globPatterns, truthMap,
158 }
159 fillGlobPatternInfo(globPatterns, truthMap,
160 std::vector<const MuonR4::SpacePointContainer*>{spContainer, NSWspContainer});
161
162 fillFastRecoMuonInfo(fastMuons, globPatterns);
163
164 ATH_CHECK(m_tree.fill(ctx));
165 return StatusCode::SUCCESS;
166 }
168 const TrigRoiDescriptorCollection* roiCollection) const {
169 if (!truthSegments) return TruthParticleMap{};
170 ATH_MSG_VERBOSE("Filling truth map with "<<truthSegments->size());
172 auto isInROI = [roiCollection](const xAOD::TruthParticle* tp) {
173 for (const TrigRoiDescriptor* roi : *roiCollection) {
175 if (tp->eta() < roi->etaMinus() || tp->eta() > roi->etaPlus()) continue;
177 const double dPhiPlus = CxxUtils::deltaPhi(roi->phiPlus(), tp->phi());
178 const double dPhiMinus = CxxUtils::deltaPhi(roi->phiMinus(), tp->phi());
179 if (dPhiPlus >= 0. && dPhiMinus <= 0.) return true;
180 }
181 return false;
182 };
183
184 TruthParticleMap truthMap{};
185 for (const xAOD::MuonSegment* truth : *truthSegments) {
187 // In case of seeded reco, we only save truth particles that are in the RoIs
188 if (!m_isSeededReco || !tp || isInROI(tp)){
189 truthMap[tp].push_back(getMatchingSimHits(*truth));
190 }
191 }
192 return truthMap;
193 }
195 const std::vector<const MuonR4::SpacePointContainer*>& spContainers) {
196 if (!m_isMC || truthHits.empty()) return;
197 resize_all(truthHits.size(), s_nStations,
199 using enum measType;
200 using LayerBookeeper = std::unordered_map<const MuonGMR4::SpectrometerSector*, std::set<unsigned>>;
201 using MeasBookeeper = std::array<std::vector<const SpacePoint*>, Acts::toUnderlying(nTypes)>;
203 MeasBookeeper measInStation{};
204 LayerBookeeper seenEtaLayers{};
205 LayerBookeeper seenPhiLayers{};
206
207 auto processMeas = [&truthHits, &measInStation, &seenEtaLayers, &seenPhiLayers, this]
208 (const SpacePoint* sp, const measType type, const bool process2Dmeas, const int tpIdx, const std::size_t stIdx) {
210 const bool isPrec {MuonR4::isPrecisionHit(*sp)};
211 if ((type == Prec && !isPrec) ||
212 (type == NonPrec && (isPrec || !sp->measuresEta())) || (type == Phi && sp->measuresEta())) {
213 return;
214 }
215 /* Check if the hit has already been counted, i.e. duplicated hits. Needed for precision hits, since we can have multiple on the same layer */
216 std::vector<const SpacePoint*>& outCont {measInStation[Acts::toUnderlying(type)]};
217 if (std::ranges::find_if(outCont, [sp](const SpacePoint* s) {
218 return s->primaryMeasurement() == sp->primaryMeasurement(); }) != outCont.end()) {
219 return;
220 }
222 if (isTruthMatched(*sp->primaryMeasurement(), truthHits) != tpIdx) return;
223
224 const bool isDoubleMatched {sp->dimension() == 2u && sp->secondaryMeasurement() && isTruthMatched(*sp->secondaryMeasurement(), truthHits) == tpIdx};
225 if (process2Dmeas && !isDoubleMatched) return;
226
227 /* Check if we have already measurements in the same layer, except for precision hits */
228 const unsigned layNum {m_spSorter.sectorLayerNum(*sp)};
229
230 if (sp->measuresEta()) {
231 const bool isSeenLayer {seenEtaLayers[sp->msSector()].count(layNum) > 0};
232 if (isSeenLayer && !sp->isStraw()) return;
233 if (!isSeenLayer) seenEtaLayers[sp->msSector()].insert(layNum);
234 auto& measCounter = isPrec ? m_gen_nPrecMeas : m_gen_nNonPrecMeas;
235 ++measCounter[tpIdx][stIdx];
236
237 // Eta hit can also have phi measurements. For combined spacepoints, need to be check the secondaty measurements. No need for 2D spacepoints.
238 if (sp->measuresPhi() && isDoubleMatched) {
239 seenPhiLayers[sp->msSector()].insert(layNum);
240 ++m_gen_nPhiMeas[tpIdx][stIdx];
241 measInStation[Acts::toUnderlying(Phi)].push_back(sp);
242 }
243 } else {
244 if (seenPhiLayers[sp->msSector()].count(layNum) > 0) return;
245 seenPhiLayers[sp->msSector()].insert(layNum);
246 ++m_gen_nPhiMeas[tpIdx][stIdx];
247 }
248 outCont.push_back(sp);
249 ATH_MSG_VERBOSE("---> "<<(isPrec ? "Prec" : (type == NonPrec ? "Trig" : "Phi "))<< " " << *sp << " in sector "<<sp->msSector()->identString() << " lay "<<layNum);
250 };
251
252 int tpIdx{-1};
253 for (const auto& [tp, _] : truthHits) {
254 if(!tp) continue;
255 m_gen_Eta.push_back(tp->eta());
256 m_gen_Phi.push_back(tp->phi());
257 m_gen_Pt.push_back(tp->pt());
258 m_gen_Q.push_back(tp->charge());
259 ++tpIdx;
260 // Save the sectors compatible for the tp
261 std::vector<int> sectors{};
262 sectorMap.getSectors(tp->phi(), sectors);
263 const int side {tp->eta() > 0 ? 1 : -1};
266 ATH_MSG_VERBOSE("tp: " << tpIdx << ", Eta: " << tp->eta() << ", Phi: " << inDegrees(tp->phi()) << ", Pt [GeV]: " << tp->pt() * 1e-3 << ", Q: " << tp->charge());
267 for (std::size_t stIdx = 0; stIdx < s_nStations; ++stIdx) {
268 ATH_MSG_VERBOSE("\tStation "<< stName(static_cast<StIndex>(stIdx)) << ": matched hits before layer deduplication: ");
269 // Clear the bookkeeping structures for the new station
270 for (auto& vec : measInStation) vec.clear();
271 seenEtaLayers.clear();
272 seenPhiLayers.clear();
273 // We fill per measurement type, so we give priority to precision hits if they are in the same layer as trigger hits, e.g. sTGCs
274 for (const measType type : {Prec, NonPrec, Phi}) {
275 // We fill first 2D measurements and then 1D ones
276 for (const bool process2Dmeas : {true, false}) {
277 for (const auto& spContainer : spContainers) {
278 if (!spContainer) continue;
279 for (const SpacePointBucket* bucket : *spContainer) {
281 if (static_cast<std::size_t>(m_idHelperSvc->stationIndex(bucket->front()->identify())) != stIdx) continue;
283 if (bucket->msSector()->side() != side ||
284 std::ranges::none_of(sectors, [&](int s){ return bucket->msSector()->sector() == s; })) {
285 continue;
286 }
287 for (const auto& sp : *bucket) {
288 /* Process first the precision hits, 2D measurements first and then 1D */
289 processMeas(sp.get(), type, process2Dmeas, tpIdx, stIdx);
290 }
291 } // End loop over buckets
292 } // End loop over containers
293 } // End loop over "process2Dmeas" flag
294 } // End loop over measurement types
295 if (msgLevel(MSG::VERBOSE)) {
296 const auto gen_nNonPrecHits {static_cast<unsigned>(m_gen_nNonPrecMeas[tpIdx][stIdx])};
297 const auto gen_nPrecHits {static_cast<unsigned>(m_gen_nPrecMeas[tpIdx][stIdx])};
298 const auto gen_nPhiHits {static_cast<unsigned>(m_gen_nPhiMeas[tpIdx][stIdx])};
299 if (gen_nNonPrecHits + gen_nPrecHits + gen_nPhiHits > 0) {
300 ATH_MSG_VERBOSE("\t after deduplication: N trig/Prec/phi meas: "
301 << gen_nNonPrecHits << "/" << gen_nPrecHits << "/" << gen_nPhiHits);
302 }
303 }
304
305 } // End loop over stations
306 } // End loop over truth particles
307 }
309 if (!m_isSeededReco || !roiCollection || roiCollection->empty()) return;
310 for (const TrigRoiDescriptor* roi : *roiCollection) {
311 m_roi_EtaMin.push_back(roi->etaMinus());
312 m_roi_EtaMax.push_back(roi->etaPlus());
313 m_roi_PhiMin.push_back(roi->phiMinus());
314 m_roi_PhiMax.push_back(roi->phiPlus());
315 m_roi_ZMin.push_back(roi->zedMinus());
316 m_roi_ZMax.push_back(roi->zedPlus());
317 }
318 }
320 const MuonR4::GlobalPatternContainer* patternCont,
321 const TruthParticleMap& truthHits,
322 SpacePointTesterModule& spTester,
324 MuonVal::MatrixBranch<unsigned char>& spMatchedToPatternBranch,
325 MuonVal::MatrixBranch<unsigned char>& spMatchedToTruthBranch) const {
326 if (!spc) return;
327 for (const SpacePointBucket* bucket : *spc) {
328 for (const auto& sp : *bucket) {
330 spTypeBranch.push_back(Acts::toUnderlying(type));
331 if(!m_isMC) continue;
332 if (const auto tpIdx {isTruthMatched(*sp->primaryMeasurement(), truthHits)}; tpIdx.has_value()) {
333 unsigned treeIdx = spTester.push_back(*sp);
334 spMatchedToTruthBranch[tpIdx.value()].push_back(treeIdx);
335 }
336 }
337 }
338 std::size_t patternIdx{0};
339 for (const GlobalPattern* pattern : *patternCont) {
340 for (const StIndex station : pattern->getStations()) {
341 for (const SpacePoint* sp : pattern->hitsInStation(station)) {
342 unsigned treeIdx = spTester.push_back(*sp);
343 spMatchedToPatternBranch[patternIdx].push_back(treeIdx);
344 }
345 }
346 ++patternIdx;
347 }
348 }
350 const TruthParticleMap& truthHits,
351 const std::vector<const MuonR4::SpacePointContainer*>& spContainers) {
352 m_pat_n = patternCont->size();
353 // Resize all the matrix branches
354 resize_all(patternCont->size(), s_nStations,
358 if (m_isMC) {
359 resize_all(patternCont->size(), s_nStations,
362 }
363 auto isSecondaryMatched = [&truthHits](const SpacePoint* sp, std::size_t tpIdx) {
364 return sp->secondaryMeasurement() && isTruthMatched(*sp->secondaryMeasurement(), truthHits) == tpIdx;
365 };
366 std::size_t patternIdx{0};
367 for (const GlobalPattern* pattern : *patternCont) {
368 // We define a map of truth particles and associated hits for the current pattern, so we can determine the main truth particle is multiple are associated
369 std::unordered_map<std::size_t, std::vector<const SpacePoint*>> patternTruthHits{};
370
371 const std::vector<StIndex> stations {pattern->getStations()};
372 for (const StIndex station : stations) {
373 for (const SpacePoint* sp : pattern->hitsInStation(station)) {
374 updatePatHitInfo(ePatBranchType::eReco, patternIdx, station, sp);
375
376 if (!m_isMC) continue;
377 if (const auto tpIdx {isTruthMatched(*sp->primaryMeasurement(), truthHits)}; tpIdx.has_value()) {
378 // By convention, if truth particle index is equal to the size of the truth map, it means it's a pileup particle
379 if (*tpIdx >= truthHits.size() ) {
380 updatePatHitInfo(ePatBranchType::ePileup, patternIdx, station, sp, isSecondaryMatched(sp, *tpIdx));
381 } else {
382 patternTruthHits[*tpIdx].push_back(sp);
383 }
384 }
385 }
386 }
387 if (!patternTruthHits.empty()) {
388 // Sort the TPs by number of matched hits and define the main truth particle as the one with the most hits in the pattern
389 std::vector<std::size_t> sortedTPs {};
390 std::ranges::transform(patternTruthHits, std::back_inserter(sortedTPs), [](const auto& pair){ return pair.first; });
391 std::ranges::sort(sortedTPs, [&patternTruthHits](const auto& a, const auto& b){
392 return patternTruthHits.at(a).size() > patternTruthHits.at(b).size();
393 });
394 const auto mainTP = sortedTPs.front();
395 for (const SpacePoint* sp : patternTruthHits[mainTP]) {
396 const StIndex station {m_idHelperSvc->stationIndex(sp->identify())};
397 updatePatHitInfo(ePatBranchType::eTruth, patternIdx, station, sp, isSecondaryMatched(sp, mainTP));
398 }
399 // Add truth hits that are matched to other truth particles than the main one
400 for (const auto& [tpIdx, hits] : patternTruthHits) {
401 if (tpIdx == mainTP) continue;
402 for (const SpacePoint* sp : hits) {
403 const StIndex station {m_idHelperSvc->stationIndex(sp->identify())};
404 updatePatHitInfo(ePatBranchType::eMismatched, patternIdx, station, sp, isSecondaryMatched(sp, tpIdx));
405 }
406 }
407 // Save the matched truth particle index in the tree, either is a signal or pileup particle
408 std::ranges::transform(sortedTPs, std::back_inserter(m_pat_MatchedToTruth[patternIdx]), [](const std::size_t& tp){ return tp; });
409 }
410 // Loop over the space point containers to count the number of hits in the buckets crossed by the pattern
411 for (const SpacePointContainer* spContainer : spContainers) {
412 if (!spContainer) continue;
413 for (const SpacePointBucket* bucket : *spContainer) {
414 bool bucketInPattern{false};
415 const StIndex bucketStation {m_idHelperSvc->stationIndex(bucket->front()->identify())};
416 std::vector<const SpacePoint*> allHits{};
417
418 for (const auto& sp : *bucket) {
419 if (isInPattern(sp.get(), bucketStation, *pattern)) {
420 bucketInPattern = true;
421 }
422 allHits.push_back(sp.get());
423 }
424 if (bucketInPattern) {
425 for (const SpacePoint* sp : allHits) {
426 updatePatHitInfo(ePatBranchType::eAll, patternIdx, bucketStation, sp);
427 }
428 }
429 }
430 }
431 m_pat_Eta.push_back(-std::log(std::tan(pattern->theta()/2.)));
432 m_pat_phi.push_back(pattern->phi());
433 m_pat_sector1.push_back(pattern->sector());
434 m_pat_sector2.push_back(pattern->secondarySector());
435 m_pat_meanNormResidual2.push_back(pattern->meanNormResidual2());
436 m_pat_side.push_back(pattern->hitsInStation(stations.front()).front()->msSector()->side());
437 m_pat_nStations.push_back(stations.size());
438
439 if (msgLevel(MSG::VERBOSE)) {
440 const auto mainTP {m_pat_MatchedToTruth[patternIdx].size() > 0 ? static_cast<int>(m_pat_MatchedToTruth[patternIdx].front()) : -1};
441 unsigned nPrecHits{0}, nNonPrecHits{0}, nPhiHits{0};
442 unsigned gen_nPrecHits{0}, gen_nNonPrecHits{0}, gen_nPhiHits{0};
443 for (std::size_t stIdx = 0; stIdx < s_nStations; ++stIdx) {
444 nPrecHits += static_cast<unsigned>(m_pat_nTruthPrecMeas[patternIdx][stIdx]);
445 nNonPrecHits += static_cast<unsigned>(m_pat_nTruthNonPrecMeas[patternIdx][stIdx]);
446 nPhiHits += static_cast<unsigned>(m_pat_nTruthPhiMeas[patternIdx][stIdx]);
447 if (mainTP < 0) continue;
448 gen_nPrecHits += static_cast<unsigned>(m_gen_nPrecMeas[mainTP][stIdx]);
449 gen_nNonPrecHits += static_cast<unsigned>(m_gen_nNonPrecMeas[mainTP][stIdx]);
450 gen_nPhiHits += static_cast<unsigned>(m_gen_nPhiMeas[mainTP][stIdx]);
451 }
452 ATH_MSG_VERBOSE("Pat #" << patternIdx<< ": " << *pattern << "mainTP: "<<std::to_string(mainTP)
453 <<", nTruthMatchedHits Trig: "<<nNonPrecHits<<" / "<<gen_nNonPrecHits<<", Prec: "<<nPrecHits<<" / "<<gen_nPrecHits<<", Phi: "<<nPhiHits<<" / "<<gen_nPhiHits);
454 }
455 patternIdx++;
456 }
457 }
459 const GlobalPatternContainer* patternCont) {
460 if (!fastMuons) return;
461
462
463 for (const xAOD::Muon* mu : *fastMuons) {
464 m_muon_Eta.push_back(mu->eta());
465 m_muon_Phi.push_back(mu->phi());
466 m_muon_Pt.push_back(mu->pt());
467 m_muon_Q.push_back(mu->charge());
468
469 auto patItr {std::ranges::find(*patternCont, *patLinkAcc(*mu))};
470 assert(patItr != patternCont->end());
471 const std::size_t patIdx = std::distance(patternCont->begin(), patItr);
472 m_muon_MatchedToPattern.push_back(patIdx);
473
474 ATH_MSG_VERBOSE("FastMuonSA eta: "<<mu->eta()<<", phi[Deg]: "<<inDegrees(mu->phi())
475 <<", pt[GeV]: "<<mu->pt()/Gaudi::Units::GeV<<", q: "<<mu->charge());
476 }
477 }
479 const std::size_t patIdx,
481 const MuonR4::SpacePoint* sp,
482 const bool isSecondaryMatched) {
483 using enum ePatBranchType;
484 const bool isTruthInfo = (type == ePatBranchType::eTruth || type == ePatBranchType::eMismatched);
485 const auto updateCounts = [&](unsigned char& nonPrecCount,
486 unsigned char& precCount,
487 unsigned char& phiCount) {
488 if (sp->measuresEta()) {
489 if (MuonR4::isPrecisionHit(*sp)) precCount++;
490 else nonPrecCount++;
492 ATH_MSG_VERBOSE("---> "<<(MuonR4::isPrecisionHit(*sp) ? "Prec" : "Trig")<< " " << *sp << " in sector "<<sp->msSector()->identString() << " lay "<<m_spSorter.sectorLayerNum(*sp));
493 }
494 }
495 if (sp->measuresPhi() && (!isTruthInfo || isSecondaryMatched)) {
496 ++phiCount;
498 ATH_MSG_VERBOSE("---> "<<"Phi " << *sp << " in sector "<<sp->msSector()->identString() << " lay "<<m_spSorter.sectorLayerNum(*sp));
499 }
500 }
501 };
502 const auto stIdx = Acts::toUnderlying(hitSt);
503 switch (type) {
504 case eReco:
505 updateCounts(m_pat_nNonPrecMeas[patIdx][stIdx],
506 m_pat_nPrecMeas[patIdx][stIdx], m_pat_nPhiMeas[patIdx][stIdx]);
507 return;
508 case eTruth:
509 updateCounts(m_pat_nTruthNonPrecMeas[patIdx][stIdx],
510 m_pat_nTruthPrecMeas[patIdx][stIdx], m_pat_nTruthPhiMeas[patIdx][stIdx]);
511 return;
512 case eMismatched:
513 updateCounts(m_pat_nMisTruthNonPrecMeas[patIdx][stIdx],
514 m_pat_nMisTruthPrecMeas[patIdx][stIdx], m_pat_nMisTruthPhiMeas[patIdx][stIdx]);
515 return;
516 case eAll:
517 updateCounts(m_pat_nAllNonPrecMeas[patIdx][stIdx],
518 m_pat_nAllPrecMeas[patIdx][stIdx], m_pat_nAllPhiMeas[patIdx][stIdx]);
519 return;
520 case ePileup:
521 updateCounts(m_pat_nPileupNonPrecMeas[patIdx][stIdx],
522 m_pat_nPileupPrecMeas[patIdx][stIdx], m_pat_nPileupPhiMeas[patIdx][stIdx]);
523 return;
524 }
525 }
526} // namespace MuonValR4
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
std::vector< size_t > vec
static Double_t sp
static Double_t a
size_t size() const
Number of registered mappings.
double angle(const GeoTrf::Vector2D &a, const GeoTrf::Vector2D &b)
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
Data class to represent an eta maximum in hough space.
: The muon space point bucket represents a collection of points that will bre processed together in t...
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
void fillTruthInfo(const TruthParticleMap &truthHits, const std::vector< const MuonR4::SpacePointContainer * > &spContainers)
Fill the truth particle information into the tree.
MuonVal::VectorBranch< float > & m_gen_Phi
MuonVal::MatrixBranch< unsigned char > & m_pat_nAllNonPrecMeas
Number of trigger eta measurements in the buckets crossed by the pattern, grouped by station.
MuonVal::VectorBranch< unsigned char > & m_spType
Type of spacepoints: 1 for trigger eta, 2 for precision, 3 for only-phi.
MuonVal::VectorBranch< float > & m_roi_ZMax
SG::ReadHandleKey< MuonR4::SpacePointContainer > m_NSWspKey
ActsTrk::GeoContextReadKey_t m_geoCtxKey
MuonVal::MatrixBranch< unsigned char > & m_pat_nNonPrecMeas
Number of trigger eta measurements per station.
measType
Enum for measurement types.
SG::ReadHandleKey< xAOD::MuonContainer > m_fastMuonKey
MuonVal::MatrixBranch< unsigned char > & m_pat_nAllPhiMeas
Number of phi measurements in the buckets crossed by the pattern, grouped by station.
MuonVal::MatrixBranch< unsigned char > & m_pat_nTruthPrecMeas
Number of truth precision measurements per station.
SG::ReadHandleKey< MuonR4::GlobalPatternContainer > m_patternKey
MuonVal::ScalarBranch< unsigned > & m_pat_n
====== Global Pattern block ===========
MuonVal::MatrixBranch< unsigned char > & m_spMatchedToPattern
Branch indicating which space points in the tree are associated to the i-th pattern.
MuonVal::VectorBranch< unsigned char > & m_muon_MatchedToPattern
MuonVal::MatrixBranch< unsigned char > & m_pat_nMisTruthPhiMeas
Number of mismatched truth phi measurements per station.
MuonVal::VectorBranch< unsigned char > & m_pat_nStations
Number of stations.
MuonVal::MatrixBranch< unsigned char > & m_NSWspMatchedToTruth
MuonVal::MatrixBranch< unsigned char > & m_pat_nPileupPhiMeas
Number of pileup phi measurements per station.
void fillRoIInfo(const TrigRoiDescriptorCollection *roiCollection)
Fill the RoI information into the tree.
MuonVal::VectorBranch< uint16_t > & m_pat_sector2
MuonVal::VectorBranch< float > & m_gen_Eta
MuonVal::MatrixBranch< unsigned char > & m_pat_nAllPrecMeas
Number of precision measurements in the buckets crossed by the pattern, grouped by station.
MuonVal::MatrixBranch< unsigned char > & m_pat_nPileupPrecMeas
Number of pileup precision measurements per station.
MuonVal::VectorBranch< float > & m_muon_Pt
MuonVal::VectorBranch< float > & m_pat_phi
MuonVal::VectorBranch< short > & m_muon_Q
SG::ReadHandleKey< TrigRoiDescriptorCollection > m_roiCollectionKey
std::map< const xAOD::TruthParticle *, std::vector< simHitSet > > TruthParticleMap
MuonVal::VectorBranch< short > & m_gen_Q
====== Truth particle block ===========
virtual StatusCode finalize() override
MuonVal::MatrixBranch< unsigned char > & m_gen_nPrecMeas
Number of precision measurements per station.
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
void updatePatHitInfo(const ePatBranchType type, const std::size_t patIdx, const Muon::MuonStationIndex::StIndex hitSt, const MuonR4::SpacePoint *sp, const bool isSecondaryMatched=false)
Update the hit counts for a given pattern branch type.
ePatBranchType
Enum for different types of pattern hit content branches.
SG::ReadHandleKey< xAOD::MuonSegmentContainer > m_truthSegmentKey
MuonVal::VectorBranch< float > & m_roi_EtaMin
====== RoI info ===========
MuonVal::MatrixBranch< unsigned char > & m_pat_nTruthPhiMeas
Number of truth phi measurements per station.
void fillFastRecoMuonInfo(const xAOD::MuonContainer *muonCont, const MuonR4::GlobalPatternContainer *patternCont)
Fill the info associated to fast reco muons.
std::shared_ptr< SpacePointTesterModule > m_NSWspTester
MuonVal::VectorBranch< float > & m_roi_PhiMin
MuonVal::VectorBranch< float > & m_roi_PhiMax
std::shared_ptr< SpacePointTesterModule > m_spTester
====== Spacepoint block ===========
MuonVal::MatrixBranch< unsigned char > & m_pat_nTruthNonPrecMeas
Number of truth trigger eta measurements per station.
virtual StatusCode initialize() override
MuonVal::MatrixBranch< unsigned char > & m_pat_nPhiMeas
Number of phi measurements per station.
MuonVal::MatrixBranch< unsigned char > & m_pat_nPrecMeas
Number of precision measurements per station.
MuonVal::VectorBranch< float > & m_muon_Phi
MuonVal::VectorBranch< float > & m_roi_EtaMax
MuonVal::VectorBranch< float > & m_pat_meanNormResidual2
mean square normalized pattern residual
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
MuonVal::VectorBranch< float > & m_gen_Pt
void fillSpacePointInfo(const MuonR4::SpacePointContainer *spc, const MuonR4::GlobalPatternContainer *patternCont, const TruthParticleMap &truthHits, SpacePointTesterModule &spTester, MuonVal::VectorBranch< unsigned char > &spTypeBranch, MuonVal::MatrixBranch< unsigned char > &spMatchedToPatternBranch, MuonVal::MatrixBranch< unsigned char > &spMatchedToTruthBranch) const
Fill the space point information into the tree.
MuonVal::MatrixBranch< unsigned char > & m_pat_nMisTruthNonPrecMeas
Number of mismatched truth trigger eta measurements per station.
MuonVal::VectorBranch< unsigned char > & m_NSWspType
void fillGlobPatternInfo(const MuonR4::GlobalPatternContainer *patternCont, const TruthParticleMap &truthHits, const std::vector< const MuonR4::SpacePointContainer * > &spContainers)
Fill the info associated to the global patterns into the tree.
MuonVal::VectorBranch< uint16_t > & m_pat_sector1
pattern primary & secondary sectors (different if the pattern is in the sector overlap)
MuonVal::MatrixBranch< unsigned char > & m_NSWspMatchedToPattern
MuonVal::MatrixBranch< unsigned char > & m_pat_nMisTruthPrecMeas
Number of mismatched truth precision measurements per station.
MuonVal::MuonTesterTree m_tree
MuonVal::VectorBranch< float > & m_muon_Eta
====== Fast Reco Muon info ===========
MuonVal::VectorBranch< short > & m_pat_side
+1 for A-, -1 of C-side
MuonVal::MatrixBranch< unsigned char > & m_pat_MatchedToTruth
Branch indicating which truth particles in the tree are associated to the i-th pattern.
MuonR4::SpacePointPerLayerSorter m_spSorter
MuonVal::MatrixBranch< unsigned char > & m_spMatchedToTruth
Branch indicating which space points in the tree are associated to the i-th truth particle.
MuonVal::MatrixBranch< unsigned char > & m_gen_nPhiMeas
Number of phi measurements per station.
MuonVal::MatrixBranch< unsigned char > & m_pat_nPileupNonPrecMeas
Number of pileup trigger eta measurements per station.
MuonVal::VectorBranch< float > & m_pat_Eta
pattern average theta & phi
MuonVal::MatrixBranch< unsigned char > & m_gen_nNonPrecMeas
Number of trigger eta measurements per station.
SG::ReadHandleKey< MuonR4::SpacePointContainer > m_spKey
TruthParticleMap fillTruthMap(const xAOD::MuonSegmentContainer *truthSegments, const TrigRoiDescriptorCollection *roiCollection) const
Fill the truth particle map.
MuonVal::VectorBranch< float > & m_roi_ZMin
unsigned int push_back(const MuonR4::SpacePointBucket &bucket)
@ isMC
Flag determining whether the branch is simulation.
void push_back(size_t i, const T &value)
void push_back(const T &value)
Adds a new element at the end of the vector.
void getSectors(double phi, std::vector< int > &sectors) const
returns the main sector plus neighboring if the phi position is in an overlap region
Helper class to provide constant type-safe access to aux data.
nope - should be used for standalone also, perhaps need to protect the class def bits ifndef XAOD_ANA...
STL class.
constexpr T deltaPhi(T phiA, T phiB)
Return difference phiA - phiB in range [-pi, pi].
Definition phihelper.h:59
const xAOD::TruthParticle * getTruthMatchedParticle(const xAOD::MuonSegment &segment)
Returns the particle truth-matched to the segment.
std::unordered_set< const xAOD::MuonSimHit * > getMatchingSimHits(const xAOD::MuonSegment &segment)
: Returns all sim hits matched to a xAOD::MuonSegment
const xAOD::MuonSimHit * getTruthMatchedHit(const xAOD::MuonMeasurement &prdHit)
Returns the MuonSimHit, if there's any, matched to the uncalibrated muon measurement.
DataVector< GlobalPattern > GlobalPatternContainer
Abrivation of the GlobalPattern container type.
bool isPrecisionHit(const SpacePoint &hit)
Returns whether the uncalibrated spacepoint is a precision hit (Mdt, micromegas, stgc strips).
DataVector< SpacePointBucket > SpacePointContainer
Abrivation of the space point container type.
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
std::unordered_set< const xAOD::MuonSimHit * > simHitSet
bool isInPattern(const SpacePoint *sp, const StIndex station, const GlobalPattern &pattern)
std::map< const xAOD::TruthParticle *, std::vector< simHitSet > > TruthParticleMap
constexpr std::size_t s_nStations
std::optional< std::size_t > isTruthMatched(const xAOD::MuonMeasurement &meas, const TruthParticleMap &truthHits)
StIndex
enum to classify the different station layers in the muon spectrometer
const std::string & stName(StIndex index)
convert StIndex into a string
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MuonSegmentContainer_v1 MuonSegmentContainer
Definition of the current "MuonSegment container version".
MuonMeasurement_v1 MuonMeasurement
MuonSimHit_v1 MuonSimHit
Defined the version of the MuonSimHit.
Definition MuonSimHit.h:12
TruthParticle_v1 TruthParticle
Typedef to implementation.
Muon_v1 Muon
Reference the current persistent version:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
MuonSegment_v1 MuonSegment
Reference the current persistent version:
Helper for azimuthal angle calculations.