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.
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to process
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of neighbours
Cluster reconstruction algorithm for MID.
int32_t nEntries
Definition Objects.cxx:40
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
float float x2
Definition MathUtils.h:49
float float float float x3
Definition MathUtils.h:49
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