ATLAS Offline Software
Loading...
Searching...
No Matches
AFPSiDLinRegTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
10
11
13
14
16 const std::string& name,
17 const IInterface* parent ) :
18 base_class( type, name, parent )
19{
20}
21
22
24{
25 if(m_trackSelection=="loose" || m_trackSelection=="Loose")
26 {
27 m_selectionFunction = [](const std::vector<const xAOD::AFPSiHitsCluster*>&) { return true; };
28 }
29 else if(m_trackSelection=="medium" || m_trackSelection=="Medium")
30 {
31 m_selectionFunction = [this](const std::vector<const xAOD::AFPSiHitsCluster*>& t) {
32 std::vector<int> plane{0, 0, 0, 0};
33
34 for (auto&& cluster : t) {
35 const int p = cluster->pixelLayerID();
36 plane[p]++;
37 }
38
39 auto HasAnyClusters = [](int n) { return n > 0; };
40
41 return std::count_if(plane.begin(), plane.end(), HasAnyClusters) >= m_minimalNumberOfPlanesInTrack;
42 };
43 }
44 else if(m_trackSelection=="tight" || m_trackSelection=="Tight")
45 {
46 m_selectionFunction = [this](const std::vector<const xAOD::AFPSiHitsCluster*>& t) {
47 std::vector<int> plane{0, 0, 0, 0};
48
49 for (auto&& cluster : t) {
50 const int p = cluster->pixelLayerID();
51 plane[p]++;
52 }
53
54 auto HasMultipleClusters = [](int n) { return n > 1; };
55
56 if (std::any_of(plane.begin(), plane.end(), HasMultipleClusters)) { return false; }
57
58 // Check number of planes (cluster/plane == 1)
59 if (t.size() < m_minimalNumberOfPlanesInTrack) { return false; }
60
61 return true;
62 };
63 }
64 else
65 {
66 ATH_MSG_ERROR("unknown trackSelection "<<m_trackSelection<<", allowed values are \"Loose\", \"Medium\", or \"Tight\" ");
67 return StatusCode::FAILURE;
68 }
69
70 CHECK( m_hitsClusterContainerKey.initialize() );
71
72 return StatusCode::SUCCESS;
73}
74
75
77{
78 // All clusters should be in same station, so no need for checking
79
80 const double xa = a->xLocal();
81 const double ya = a->yLocal();
82
83 const double xb = b->xLocal();
84 const double yb = b->yLocal();
85
86 const double dx = xa - xb;
87 const double dy = ya - yb;
89 return dx * dx + dy * dy <= maxDistanceSq;
90}
91
92
93std::vector<const xAOD::AFPSiHitsCluster*> AFPSiDLinRegTool::findClusterAroundElement(std::list<const xAOD::AFPSiHitsCluster*>& toJoin, const xAOD::AFPSiHitsCluster* init) const
94{
95 // Push initial cluster
96 std::vector<const xAOD::AFPSiHitsCluster*> track;
97 track.push_back(init);
98
99 std::vector<const xAOD::AFPSiHitsCluster*> newNeighbours;
100
101 // Repeat while new neighbours are found
102 do {
103 newNeighbours.clear();
104 for (auto&& b : toJoin) {
105 bool isNew = false;
106 for (auto&& a : track) {
107 if (areNeighbours(a, b)) { isNew = true; }
108 }
109
110 if (isNew) {
111 newNeighbours.push_back(b);
112 track.push_back(b);
113 }
114 }
115
116 // Clustered clusters are taken out from "clusters" container
117 for (auto& t : newNeighbours) {
118 toJoin.remove(t);
119 }
120
121 } while (!newNeighbours.empty());
122
123 return track;
124}
125
126
127std::pair<double, double> AFPSiDLinRegTool::linearRegression(const std::vector<std::pair<double, double>>& YX) const
128{
129 // here, "x" is Z axis and "y" is X or Y axis
130
131 double meanx = 0, meany = 0;
132 for (const auto& [y, x] : YX) {
133 meany += y;
134 meanx += x;
135 }
136 meanx /= YX.size();
137 meany /= YX.size();
138
139 double numerator = 0, denominator = 0;
140 for (const auto& [y, x] : YX) {
141 const double dy = y - meany;
142 const double dx = x - meanx;
143
144 numerator += dx * dy;
145 denominator += dx * dx;
146 }
147 if (denominator == 0){
148 ATH_MSG_WARNING("AFPSiDLinRegTool::linearRegression: denominator is zero");
149 return {0.,0.};
150 }
151 const double slope = numerator / denominator;
152 const double position = meany - slope * meanx;
153
154 return {position, slope};
155}
156
157
158StatusCode AFPSiDLinRegTool::reconstructTracks(std::unique_ptr<xAOD::AFPTrackContainer>& outputContainer, const EventContext& ctx) const
159{
161 if(!clusters.isValid())
162 {
163 // this is allowed, there might be no AFP data in the input
164 return StatusCode::SUCCESS;
165 }
166
167 // Select clusters in given station
168 std::list<const xAOD::AFPSiHitsCluster*> clustersInStation;
169 std::copy_if(clusters->begin(), clusters->end(), std::back_inserter(clustersInStation),
170 [this](auto cluster) { return cluster->stationID() == m_stationID; });
171
172 ATH_MSG_DEBUG("clusters in " << m_stationID << " size: " << clustersInStation.size());
173
174
175 // Loop until all clusters are used
176 while (!clustersInStation.empty())
177 {
178 // Take first element from the list...
179 const auto *const initialCluster = clustersInStation.front();
180 clustersInStation.pop_front();
181
182 // ...and find other clusters around it
183 const auto clusterOfClusters = findClusterAroundElement(clustersInStation, initialCluster);
184
185 // If track candidate does not pass chosen selection, skip it
186 if (!m_selectionFunction(clusterOfClusters)) {
187 ATH_MSG_DEBUG("track candidate of size " << clusterOfClusters.size() << " did not pass selection.");
188 continue;
189 }
190
191 auto *track = outputContainer->push_back(std::make_unique<xAOD::AFPTrack>());
192
193 // Set stationID
194 track->setStationID(m_stationID);
195
196 // Add links to clusters
197 for (const auto *const cluster : clusterOfClusters) {
199 clusterLink.toContainedElement(*clusters, cluster);
200 track->addCluster(clusterLink);
201 }
202
203 const int nClusters = track->clusters().size();
204
205 if(nClusters>0)
206 {
207 track->setNClusters(nClusters);
208 }
209 else
210 {
211 ATH_MSG_DEBUG("track candidate has 0 clusters, erasing ");
212 outputContainer->pop_back();
213 continue;
214 }
215
216 // Fit the clusters with a line in X and Y direction along Z
217 double x = 0.;
218 double y = 0.;
219 double xSlope = 0.;
220 double ySlope = 0.;
221 double chi2 = 0.;
222
223 if (nClusters == 1) {
224 x = (*(track->clusters().at(0)))->xLocal();
225 y = (*(track->clusters().at(0)))->yLocal();
226 }
227 else
228 {
229 std::vector<std::pair<double, double>> XZ;
230 std::vector<std::pair<double, double>> YZ;
231
232 for (int i = 0; i < nClusters; i++) {
233 const xAOD::AFPSiHitsCluster* cluster = *(track->clusters().at(i));
234
235 XZ.emplace_back(cluster->xLocal(), cluster->zLocal());
236 YZ.emplace_back(cluster->yLocal(), cluster->zLocal());
237 }
238
239 auto linregx = linearRegression(XZ);
240 auto linregy = linearRegression(YZ);
241
242 std::tie(x, xSlope) = linregx;
243 std::tie(y, ySlope) = linregy;
244
245 for (int i = 0; i < nClusters; i++) {
246 const xAOD::AFPSiHitsCluster* cluster = *(track->clusters().at(i));
247
248 const double z = cluster->zLocal();
249 const double ex = cluster->xLocalErr();
250 const double ey = cluster->yLocalErr();
251
252 const double dx = cluster->xLocal() - (x + xSlope * z);
253 const double dy = cluster->yLocal() - (y + ySlope * z);
254
255 chi2 += dx * dx / (ex * ex);
256 chi2 += dy * dy / (ey * ey);
257 }
258 }
259
260 // Set track properties
261 track->setChi2(chi2);
262 track->setXLocal(x);
263 track->setXSlope(xSlope);
264 track->setYLocal(y);
265 track->setYSlope(ySlope);
266 track->setZLocal(0.); // because positions of x/y are calculated at z=0
267
268 track->setAlgID(xAOD::AFPTrackRecoAlgID::linReg);
269
270 std::vector<int> clustersPlane{0, 0, 0, 0};
271 for (const auto& cl : track->clusters()) {
272 ++clustersPlane[(*cl)->pixelLayerID()];
273 }
274 auto HasNoClusters = [](int n) { return n == 0; };
275 track->setNHoles(std::count_if(clustersPlane.begin(), clustersPlane.end(), HasNoClusters));
276
277
278 ATH_MSG_DEBUG("new track with " << track->clusters().size() << " clusters, x: " << track->xLocal()
279 << ", y: " << track->yLocal() << ", sx: " << track->xSlope()
280 << ", sy: " << track->ySlope() << ", chi2: " << track->chi2());
281 for (auto&& cluster : track->clusters())
282 {
283 ATH_MSG_DEBUG('\t' << (*cluster)->xLocal() << " " << (*cluster)->yLocal() << " " << (*cluster)->zLocal());
284 }
285 }
286
287 return StatusCode::SUCCESS;
288}
Header file for AFPSiDLinRegTool used in tracks reconstruction. Adapted from AfpAnalysisToolbox.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t a
#define y
#define x
#define z
Gaudi::Property< unsigned int > m_minimalNumberOfPlanesInTrack
Minimal numer of planes required for track candidate.
StatusCode reconstructTracks(std::unique_ptr< xAOD::AFPTrackContainer > &outputContainer, const EventContext &ctx) const override
Reconstructs tracks properties from track candidates.
SG::ReadHandleKey< xAOD::AFPSiHitsClusterContainer > m_hitsClusterContainerKey
Name of the xAOD container with clusters to be used in track reconstruction.
virtual StatusCode initialize() override
Read parameters from job options and print tool configuration.
bool areNeighbours(const xAOD::AFPSiHitsCluster *a, const xAOD::AFPSiHitsCluster *b) const
Checks if clusters are neighbours Compares distance between them to m_allowedDistanceBetweenClustersI...
std::pair< double, double > linearRegression(const std::vector< std::pair< double, double > > &YX) const
Simple linear regression Used to calculate track postions and slopes.
std::function< bool(const std::vector< const xAOD::AFPSiHitsCluster * > &)> m_selectionFunction
Gaudi::Property< int > m_stationID
AFP station ID for which tracks will be reconstructed.
Gaudi::Property< std::string > m_trackSelection
Track selection type:
AFPSiDLinRegTool(const std::string &type, const std::string &name, const IInterface *parent)
std::vector< const xAOD::AFPSiHitsCluster * > findClusterAroundElement(std::list< const xAOD::AFPSiHitsCluster * > &toJoin, const xAOD::AFPSiHitsCluster *init) const
Looks for cluster around init cluster.
Gaudi::Property< double > m_allowedDistanceBetweenClustersInTrack
Maximum allowed distance between clusters to be considered coming from the same proton.
float zLocal() const
Cluster position along Z axis in station local coordinate system.
float yLocalErr() const
Uncertainty of cluster position along Y axis in station local coordinate system.
float xLocal() const
Cluster position along X axis in station local coordinate system.
float yLocal() const
Cluster position along Y axis in station local coordinate system.
float xLocalErr() const
Uncertainty of cluster position along X axis in station local coordinate system.
static constexpr int linReg
linear regression algorithm id=1
double chi2(TH1 *h0, TH1 *h1)
AFPSiHitsCluster_v1 AFPSiHitsCluster