ATLAS Offline Software
Loading...
Searching...
No Matches
TgcL0OverlapClassification.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
7
8#include <algorithm>
9#include <cmath>
10#include <cstdint>
11#include <numeric>
12#include <vector>
13
14namespace {
15
16bool sameChamber(const L0Muon::TgcL0Candidate& first,
17 const L0Muon::TgcL0Candidate& second,
18 std::uint8_t stationBit) {
19 if (stationBit == 0x1U) {
20 return first.m1StationEta == second.m1StationEta &&
21 first.m1StationPhi == second.m1StationPhi;
22 }
23 if (stationBit == 0x2U) {
24 return first.m2StationEta == second.m2StationEta &&
25 first.m2StationPhi == second.m2StationPhi;
26 }
27 return first.m3StationEta == second.m3StationEta &&
28 first.m3StationPhi == second.m3StationPhi;
29}
30
31std::size_t countBits(std::uint8_t value) {
32 std::size_t count{0U};
33 while (value != 0U) {
34 count += value & 0x1U;
35 value >>= 1U;
36 }
37 return count;
38}
39
40bool isOverlapPair(
41 const L0Muon::TgcL0Candidate& first,
42 const L0Muon::TgcL0Candidate& second,
44 if (first.bcTag != second.bcTag ||
45 first.subdetectorId != second.subdetectorId) {
46 return false;
47 }
48 if (std::abs(first.eta - second.eta) >= config.maxDeltaEta ||
49 std::abs(xAOD::P4Helpers::deltaPhi(first.phi, second.phi)) >= config.maxDeltaPhi) {
50 return false;
51 }
52
53 const std::uint8_t commonMask = static_cast<std::uint8_t>(
54 first.positionStationMask & second.positionStationMask);
55 if (countBits(commonMask) < config.minCommonStations) return false;
56
57 bool differentChamber{false};
58 for (const std::uint8_t stationBit : {0x1U, 0x2U, 0x4U}) {
59 if ((commonMask & stationBit) != 0U &&
60 !sameChamber(first, second, stationBit)) {
61 differentChamber = true;
62 break;
63 }
64 }
65 return differentChamber;
66}
67
68class DisjointSet {
69 public:
70 explicit DisjointSet(std::size_t size) : m_parent(size), m_size(size, 1U) {
71 std::iota(m_parent.begin(), m_parent.end(), 0U);
72 }
73
74 std::size_t find(std::size_t value) {
75 if (m_parent[value] != value) m_parent[value] = find(m_parent[value]);
76 return m_parent[value];
77 }
78
79 void join(std::size_t first, std::size_t second) {
80 first = find(first);
81 second = find(second);
82 if (first == second) return;
83 if (m_size[first] < m_size[second]) std::swap(first, second);
84 m_parent[second] = first;
85 m_size[first] += m_size[second];
86 }
87
88 private:
89 std::vector<std::size_t> m_parent;
90 std::vector<std::size_t> m_size;
91};
92
93} // namespace
94
95namespace L0Muon {
96namespace TgcL0Floating {
97
100
102 TgcL0CandidateContainer& candidates,
103 OverlapClassificationStatistics& statistics) const {
104 statistics = OverlapClassificationStatistics{};
105 for (TgcL0Candidate& candidate : candidates) {
106 candidate.overlapGroupId = 0U;
107 candidate.overlapMultiplicity = 1U;
108 candidate.inChamberOverlap = false;
109 }
110 if (candidates.size() < 2U) return;
111
112 DisjointSet groups(candidates.size());
113 for (std::size_t first = 0U; first < candidates.size(); ++first) {
114 for (std::size_t second = first + 1U; second < candidates.size(); ++second) {
115 if (isOverlapPair(candidates[first], candidates[second], m_config)) {
116 groups.join(first, second);
117 }
118 }
119 }
120
121 std::vector<std::size_t> roots(candidates.size());
122 std::vector<std::size_t> multiplicities(candidates.size(), 0U);
123 for (std::size_t index = 0U; index < candidates.size(); ++index) {
124 roots[index] = groups.find(index);
125 ++multiplicities[roots[index]];
126 }
127
128 std::vector<std::uint16_t> groupIds(candidates.size(), 0U);
129 std::uint16_t nextGroupId{1U};
130 for (std::size_t index = 0U; index < candidates.size(); ++index) {
131 const std::size_t root = roots[index];
132 if (multiplicities[root] < 2U) continue;
133 if (groupIds[root] == 0U) {
134 groupIds[root] = nextGroupId++;
135 ++statistics.nGroups;
136 statistics.maxMultiplicity =
137 std::max(statistics.maxMultiplicity, multiplicities[root]);
138 }
139 TgcL0Candidate& candidate = candidates[index];
140 candidate.overlapGroupId = groupIds[root];
141 candidate.overlapMultiplicity = static_cast<std::uint8_t>(
142 std::min<std::size_t>(multiplicities[root], 0xffU));
143 candidate.inChamberOverlap = true;
144 ++statistics.nCandidates;
145 }
146}
147
148} // namespace TgcL0Floating
149} // namespace L0Muon
size_t size() const
Number of registered mappings.
void classify(TgcL0CandidateContainer &candidates, OverlapClassificationStatistics &statistics) const
OverlapClassification(OverlapClassificationConfig config=OverlapClassificationConfig{})
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:140
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
bool first
Definition DeMoScan.py:534
std::vector< TgcL0Candidate > TgcL0CandidateContainer
Event-local candidate collection.
std::string join(const std::vector< std::string > &v, const char c=',')
Definition index.py:1
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Event-local candidate used by the TGC simulation tools.
bool inChamberOverlap
True when the candidate has a nearby partner from a different chamber path.
std::uint8_t overlapMultiplicity
Number of candidates in the classified overlap group.
std::uint16_t overlapGroupId
Event-local overlap group. Zero means no classified overlap partner.