Project
Loading...
Searching...
No Matches
Clusterizer.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
17
19
20namespace o2
21{
22namespace mid
23{
24
25//______________________________________________________________________________
26bool Clusterizer::loadPreClusters(gsl::span<const PreCluster>& preClusters)
27{
28 // Loop on pre-clusters in the BP
29 mActiveDEs.clear();
30 mPreClusters = preClusters;
31 for (auto& pc : preClusters) {
32 auto& de = mPreClustersDE[pc.deId];
33 de.setDEId(pc.deId);
34 size_t idx = &pc - &preClusters[0];
35 if (pc.cathode == 0) {
36 de.getPreClustersBP(pc.firstColumn).push_back({idx, 0, mPreClusterHelper.getArea(pc)});
37 } else {
38 de.getPreClustersNBP().push_back({idx, 0});
39 for (int icolumn = pc.firstColumn; icolumn <= pc.lastColumn; ++icolumn) {
40 de.getPreClustersNBP().back().area[icolumn] = mPreClusterHelper.getArea(icolumn, pc);
41 }
42 }
43
44 mActiveDEs.emplace(pc.deId);
45 }
46
47 return (preClusters.size() > 0);
48}
49
50//______________________________________________________________________________
51void Clusterizer::process(gsl::span<const PreCluster> preClusters, bool accumulate)
52{
53 // Reset cluster information
54 if (!accumulate) {
55 mClusters.clear();
56 }
57 if (loadPreClusters(preClusters)) {
58 // Loop only on fired detection elements
59 for (auto& deId : mActiveDEs) {
60 makeClusters(mPreClustersDE[deId]);
61 }
62 }
63}
64
65void Clusterizer::process(gsl::span<const PreCluster> preClusters, gsl::span<const ROFRecord> rofRecords)
66{
67 mClusters.clear();
68 mROFRecords.clear();
69 for (auto& rofRecord : rofRecords) {
70 mPreClusterOffset = rofRecord.firstEntry;
71 auto firstEntry = mClusters.size();
72 process(preClusters.subspan(rofRecord.firstEntry, rofRecord.nEntries), true);
73 auto nEntries = mClusters.size() - firstEntry;
74 mROFRecords.emplace_back(rofRecord, firstEntry, nEntries);
75 }
76}
77
78//______________________________________________________________________________
79bool Clusterizer::makeClusters(PreClustersDE& pcs)
80{
81 auto deId = pcs.getDEId();
82
83 // loop over pre-clusters in the non-bending plane
84 for (int inb = 0; inb < pcs.getNPreClustersNBP(); ++inb) {
85 auto& pcNB = pcs.getPreClusterNBP(inb);
86 // Try to find matching pre-clusters in the bending plane
87 int icolumn = mPreClusters[pcNB.index].firstColumn;
88 if (icolumn == mPreClusters[pcNB.index].lastColumn) {
89 // This is the most simple and common case: the NBP pre-cluster is on
90 // one single column. So it can be easily matched with the BP
91 // since the corresponding contours are both rectangles
92 for (int ib = 0; ib < pcs.getNPreClustersBP(icolumn); ++ib) {
93 auto& pcB = pcs.getPreClusterBP(icolumn, ib);
94 makeCluster(pcB.area, pcNB.area[icolumn], deId);
95 pcB.paired = 1;
96 pcNB.paired = 1;
97 mFunction(mClusters.size() - 1, pcB.index + mPreClusterOffset);
98 mFunction(mClusters.size() - 1, pcNB.index + mPreClusterOffset);
99 }
100 } else {
101 // The NBP pre-cluster spans different columns.
102 // The BP contour is therefore a series of neighbour rectangles
103 // Here we could build a giant cluster with all neighbour pre-clusters
104 // in the bending plane.
105 // However, the pre-cluster in the BP might be close to more than one pre-clusters
106 // in the BP of the neighbour column, thus leading to a pattern with non-contiguous
107 // pre-clusters along the y axis...which are treated as separate clusters
108 // in the standard configuration.
109 // All in all, since the strips are huge, we decided to pair the clusters only between
110 // two adjacent columns.
111 // In this way, a huge cluster spanning three columns will be transformed in
112 // two clusters centered at the border between two columns.
113 // This leads to a redundancy. Still, the sigma of the resulting cluster will be so large
114 // to have no impact whatsoever in the track reconstruction.
115 int pairId = 10 + inb;
116 for (; icolumn <= mPreClusters[pcNB.index].lastColumn; ++icolumn) {
117 int neighColumn = icolumn + 1;
118 for (int ib = 0; ib < pcs.getNPreClustersBP(icolumn); ++ib) {
119 PreClustersDE::BP& pcB = pcs.getPreClusterBP(icolumn, ib);
120 // This function checks for the neighbours only in icolumn+1
121 std::vector<int> neighbours = pcs.getNeighbours(icolumn, ib);
122 // It can happen that the NBP spans two columns...but there are fired strips only on
123 // one column of the BP. In this case we only consider the column with a hit in the BP.
124 // Of course, we need to check that the current pre-cluster was not already paired
125 // with the pre-cluster in the previous column.
126 if (neighbours.empty() && pcB.paired != pairId) {
127 makeCluster(pcB.area, pcNB.area[icolumn], deId);
128 mFunction(mClusters.size() - 1, pcB.index + mPreClusterOffset);
129 mFunction(mClusters.size() - 1, pcNB.index + mPreClusterOffset);
130 } else {
131 for (auto& jb : neighbours) {
132 PreClustersDE::BP& pcBneigh = pcs.getPreClusterBP(neighColumn, jb);
133 makeCluster(pcB, pcBneigh, pcNB, deId);
134 // Here we set the paired flag to a custom ID of the pre-cluster in the NBP
135 // So that, when we move to the next column, we do not add it twice.
136 pcBneigh.paired = pairId;
137 mFunction(mClusters.size() - 1, pcB.index + mPreClusterOffset);
138 mFunction(mClusters.size() - 1, pcBneigh.index + mPreClusterOffset);
139 mFunction(mClusters.size() - 1, pcNB.index + mPreClusterOffset);
140 }
141 }
142 pcB.paired = 1;
143 pcNB.paired = 1;
144 } // loop on pre-clusters in the BP
145 } // loop on columns
146 }
147
148 if (pcNB.paired == 0) {
149 // If it is not paired, it means that we have
150 // a monocathodic cluster in the NBP
151 for (int icolumn = mPreClusters[pcNB.index].firstColumn; icolumn <= mPreClusters[pcNB.index].lastColumn; ++icolumn) {
152 makeCluster(pcNB.area[icolumn], deId, 1);
153 mFunction(mClusters.size() - 1, pcNB.index + mPreClusterOffset);
154 }
155 }
156 } // loop on pre-clusters in the NBP
157
159 for (int icolumn = 0; icolumn <= 6; ++icolumn) {
160 for (int ib = 0; ib < pcs.getNPreClustersBP(icolumn); ++ib) {
161 PreClustersDE::BP& pcB = pcs.getPreClusterBP(icolumn, ib);
162 if (pcB.paired == 0) {
163 makeCluster(pcB.area, deId, 0);
164 mFunction(mClusters.size() - 1, pcB.index + mPreClusterOffset);
165 }
166 }
167 }
168
169 // Reset the pre-clusters before exiting
170 pcs.reset();
171
172 return true;
173}
174
175//______________________________________________________________________________
176bool Clusterizer::init(std::function<void(size_t, size_t)> func)
177{
178 // prepare storage of clusters and PreClusters
179 mPreClustersDE.reserve(detparams::NDetectionElements);
180 mFunction = func;
181
182 return true;
183}
184
185//______________________________________________________________________________
186void Clusterizer::makeCluster(const MpArea& areaBP, const MpArea& areaNBP, uint8_t deId)
187{
188 constexpr double sqrt12 = 3.4641016;
189 double xCoor = 0.5 * (areaNBP.getXmax() + areaNBP.getXmin());
190 double yCoor = 0.5 * (areaBP.getYmax() + areaBP.getYmin());
191 double errX = (areaNBP.getXmax() - areaNBP.getXmin()) / sqrt12;
192 double errY = (areaBP.getYmax() - areaBP.getYmin()) / sqrt12;
193 mClusters.push_back({static_cast<float>(xCoor), static_cast<float>(yCoor), 0., static_cast<float>(errX), static_cast<float>(errY), deId});
194 mClusters.back().setBothFired();
195}
196
197//______________________________________________________________________________
198void Clusterizer::makeCluster(const MpArea& area, uint8_t deId, int cathode)
199{
200 makeCluster(area, area, deId);
201 mClusters.back().setFired(1 - cathode, false);
202}
203
204//______________________________________________________________________________
205void Clusterizer::makeCluster(const PreClustersDE::BP& pcBP, const PreClustersDE::BP& pcBPNeigh, const PreClustersDE::NBP& pcNBP, uint8_t deId)
206{
207 // This is the general case:
208 // perform the full calculation assuming a uniform charge distribution
209
210 double x2[2][2] = {{0., 0.}, {0., 0.}};
211 double x3[2][2] = {{0., 0.}, {0., 0.}};
212 double dim[2][2];
213 double delta[2];
214 double sumArea = 0.;
215
216 std::vector<const PreClustersDE::BP*> pcBlist = {&pcBP, &pcBPNeigh};
217
218 for (auto* pc : pcBlist) {
219 int icolumn = mPreClusters[pc->index].firstColumn;
220 dim[0][0] = pcNBP.area[icolumn].getXmin();
221 dim[0][1] = pcNBP.area[icolumn].getXmax();
222 dim[1][0] = pc->area.getYmin();
223 dim[1][1] = pc->area.getYmax();
224 for (int iplane = 0; iplane < 2; ++iplane) {
225 delta[iplane] = dim[iplane][1] - dim[iplane][0];
226 }
227 // area = dx * dy
228 sumArea += delta[0] * delta[1];
229 for (int iplane = 0; iplane < 2; ++iplane) {
230 for (int ip = 0; ip < 2; ++ip) {
231 // second momentum = x_i * x_i * dy
232 double currX2 = dim[iplane][ip] * dim[iplane][ip] * delta[1 - iplane];
233 x2[iplane][ip] += currX2;
234 // third momentum = x_i * x_i * x_i * dy
235 x3[iplane][ip] += currX2 * dim[iplane][ip];
236 }
237 }
238 } // loop on column
239
240 double coor[2], sigma[2];
241 for (int iplane = 0; iplane < 2; ++iplane) {
242 coor[iplane] = (x2[iplane][1] - x2[iplane][0]) / sumArea / 2.;
243 sigma[iplane] = std::sqrt((x3[iplane][1] - x3[iplane][0]) / sumArea / 3. - coor[iplane] * coor[iplane]);
244 }
245
246 mClusters.push_back({static_cast<float>(coor[0]), static_cast<float>(coor[1]), 0., static_cast<float>(sigma[0]), static_cast<float>(sigma[1]), deId});
247 mClusters.back().setBothFired();
248}
249
250//______________________________________________________________________________
251void Clusterizer::reset()
252{
253 mActiveDEs.clear();
254 mClusters.clear();
255}
256} // namespace mid
257} // namespace o2
Useful detector parameters for MID.
Cluster reconstruction algorithm for MID.
bool init(std::function< void(size_t, size_t)> func=[](size_t, size_t) {})
void process(gsl::span< const PreCluster > preClusters, bool accumulate=false)
double getXmax() const
Get x max.
Definition MpArea.h:49
double getYmin() const
Get y min.
Definition MpArea.h:51
double getYmax() const
Get y max.
Definition MpArea.h:53
double getXmin() const
Get x min.
Definition MpArea.h:47
MpArea getArea(const PreCluster &pc) const
NBP & getPreClusterNBP(int idx)
Gets the pre-cluster in the NBP.
size_t getNPreClustersNBP() const
Gets the number of pre-clusters in the NBP.
std::vector< int > getNeighbours(int icolumn, int idx) const
uint8_t getDEId() const
Gets the detection element ID.
BP & getPreClusterBP(int icolumn, int idx)
Gets pre-cluster in the BP.
size_t getNPreClustersBP(int icolumn) const
Gets the number of pre-clusters in the BP.
GLenum func
Definition glcorearb.h:778
const float3 float float x2
Definition MathUtils.h:42
const float3 float float float float x3
Definition MathUtils.h:42
constexpr int NDetectionElements
Number of RPCs.
gsl::span< const PreCluster > preClusters(preClusterizer.getPreClusters().data(), preClusterizer.getPreClusters().size())
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
uint16_t de