Project
Loading...
Searching...
No Matches
PreClusterFinder.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
13
14#include <chrono>
15#include <memory>
16#include <stdexcept>
17#include <vector>
18
19#include <fairmq/Tools.h>
20#include <fairlogger/Logger.h>
21
22#include "MCHBase/Error.h"
24
25namespace o2::mch
26{
27
29 std::unique_ptr<Mapping::MpDE> mapping; // mapping of this DE including the list of pads
30 std::vector<const Digit*> digits; // list of pointers to digits (not owner)
31 uint16_t nFiredPads[2]; // number of fired pads on each plane
32 std::vector<uint16_t> firedPads[2]; // indices of fired pads on each plane
33 uint16_t nOrderedPads[2]; // current number of fired pads in the following arrays
34 std::vector<uint16_t> orderedPads[2]; // indices of fired pads ordered after preclustering and merging
35};
36
37using namespace std;
38
39//_________________________________________________________________________________________________
41{
43 for (auto i = 0; i < SNDEs; i++) {
44 mDEs.emplace_back(new DetectionElement);
45 }
46}
47
48//_________________________________________________________________________________________________
50
51//_________________________________________________________________________________________________
53{
55
56 createMapping();
57
58 for (int iDE = 0; iDE < SNDEs; ++iDE) {
59 for (int iPlane = 0; iPlane < 2; ++iPlane) {
60 mPreClusters[iDE][iPlane].reserve(100);
61 }
62 }
63}
64
65//_________________________________________________________________________________________________
67{
69 reset();
70 mDEIndices.clear();
71 mErrorMap.clear();
72}
73
74//_________________________________________________________________________________________________
76{
78 for (int iDE = 0; iDE < SNDEs; ++iDE) {
79 reset(iDE);
80 }
81}
82
83//_________________________________________________________________________________________________
84void PreClusterFinder::reset(int deIndex)
85{
87
88 Mapping::MpPad* pad(nullptr);
89 DetectionElement& de(*(mDEs[deIndex]));
90
91 // loop over planes
92 for (int iPlane = 0; iPlane < 2; ++iPlane) {
93
94 // clear number of preclusters
95 mNPreClusters[deIndex][iPlane] = 0;
96
97 // loop over fired pads
98 for (int iFiredPad = 0; iFiredPad < de.nFiredPads[iPlane]; ++iFiredPad) {
99
100 pad = &de.mapping->pads[de.firedPads[iPlane][iFiredPad]];
101 pad->iDigit = 0;
102 pad->useMe = false;
103 }
104
105 // clear number of fired pads
106 de.nFiredPads[iPlane] = 0;
107 }
108
109 // clear ordered number of fired pads
110 de.nOrderedPads[0] = 0;
111 de.nOrderedPads[1] = 0;
112}
113
114//_________________________________________________________________________________________________
115void PreClusterFinder::loadDigits(gsl::span<const Digit> digits)
116{
118 for (const auto& digit : digits) {
119 loadDigit(digit);
120 }
121}
122
123//_________________________________________________________________________________________________
125{
127
128 int deIndex = mDEIndices.at(digit.getDetID());
129
130 DetectionElement& de(*(mDEs[deIndex]));
131
132 if (digit.getPadID() < 0 || digit.getPadID() >= de.mapping->nPads[0] + de.mapping->nPads[1]) {
133 throw out_of_range("invalid pad index");
134 }
135
136 uint16_t iPad = digit.getPadID();
137 int iPlane = (iPad < de.mapping->nPads[0]) ? 0 : 1;
138
139 // check that the pad is not already fired
140 if (de.mapping->pads[iPad].useMe) {
142 return;
143 }
144
145 // register this digit
146 uint16_t iDigit = de.nFiredPads[0] + de.nFiredPads[1];
147 if (iDigit >= de.digits.size()) {
148 de.digits.push_back(&digit);
149 } else {
150 de.digits[iDigit] = &digit;
151 }
152 de.mapping->pads[iPad].iDigit = iDigit;
153 de.mapping->pads[iPad].useMe = true;
154
155 // set this pad as fired
156 if (de.nFiredPads[iPlane] < de.firedPads[iPlane].size()) {
157 de.firedPads[iPlane][de.nFiredPads[iPlane]] = iPad;
158 } else {
159 de.firedPads[iPlane].push_back(iPad);
160 }
161 ++de.nFiredPads[iPlane];
162}
163
164//_________________________________________________________________________________________________
165int PreClusterFinder::discardHighOccupancy(bool perDE, bool perEvent)
166{
168
169 static constexpr double maxOccupancy = 0.2;
170 static constexpr int maxHighOccupancyDE = 4;
171
172 if (!perDE && !perEvent) {
173 return 0;
174 }
175
176 // discard DE with high occupancy in either bending or non-bending plane on stations 3-4-5
177 int nDigits(0);
178 int nRemovedDigits(0);
179 int nHighOccupancyDE(0);
180 for (int iDE = 0; iDE < SNDEs; ++iDE) {
181 DetectionElement& de(*(mDEs[iDE]));
182 nDigits += de.nFiredPads[0] + de.nFiredPads[1];
183 if (de.mapping->uid >= 500 &&
184 (de.nFiredPads[0] > maxOccupancy * de.mapping->nPads[0] ||
185 de.nFiredPads[1] > maxOccupancy * de.mapping->nPads[1])) {
186 ++nHighOccupancyDE;
187 if (perDE) {
188 nRemovedDigits += de.nFiredPads[0] + de.nFiredPads[1];
189 reset(iDE);
190 }
191 }
192 }
193
194 // discard events with too many high-occupancy DE
195 if (perEvent && nHighOccupancyDE > maxHighOccupancyDE) {
196 nRemovedDigits = nDigits;
197 reset();
198 }
199
200 return nRemovedDigits;
201}
202
203//_________________________________________________________________________________________________
205{
207 preClusterizeRecursive();
208 return mergePreClusters();
209}
210
211//_________________________________________________________________________________________________
212void PreClusterFinder::getPreClusters(std::vector<o2::mch::PreCluster>& preClusters, std::vector<Digit>& digits)
213{
217
218 for (int iDE = 0, nDEs = SNDEs; iDE < nDEs; ++iDE) {
219
220 DetectionElement& de(*(mDEs[iDE]));
221 if (de.nOrderedPads[1] == 0) {
222 continue;
223 }
224
225 for (int iPlane = 0; iPlane < 2; ++iPlane) {
226 for (int iCluster = 0; iCluster < mNPreClusters[iDE][iPlane]; ++iCluster) {
227
228 PreCluster* cluster = mPreClusters[iDE][iPlane][iCluster].get();
229 if (!cluster->storeMe) {
230 continue;
231 }
232
233 // add this precluster
234 uint32_t firstDigit = digits.size();
235 uint32_t nDigits = cluster->lastPad - cluster->firstPad + 1;
236 preClusters.push_back({firstDigit, nDigits});
237
238 // add the digits of this precluster
239 for (uint16_t iOrderedPad = cluster->firstPad; iOrderedPad <= cluster->lastPad; ++iOrderedPad) {
240 digits.emplace_back(*de.digits[de.mapping->pads[de.orderedPads[1][iOrderedPad]].iDigit]);
241 }
242 }
243 }
244 }
245}
246
247//_________________________________________________________________________________________________
248void PreClusterFinder::preClusterizeRecursive()
249{
251
252 PreCluster* cluster(nullptr);
253 uint16_t iPad(0);
254
255 // loop over DEs
256 for (int iDE = 0; iDE < SNDEs; ++iDE) {
257
258 DetectionElement& de(*(mDEs[iDE]));
259
260 // loop over planes
261 for (int iPlane = 0; iPlane < 2; ++iPlane) {
262
263 // loop over fired pads
264 for (int iFiredPad = 0; iFiredPad < de.nFiredPads[iPlane]; ++iFiredPad) {
265
266 iPad = de.firedPads[iPlane][iFiredPad];
267
268 if (de.mapping->pads[iPad].useMe) {
269
270 // create the precluster if needed
271 if (mNPreClusters[iDE][iPlane] >= mPreClusters[iDE][iPlane].size()) {
272 mPreClusters[iDE][iPlane].push_back(std::make_unique<PreCluster>());
273 }
274
275 // get the precluster
276 cluster = mPreClusters[iDE][iPlane][mNPreClusters[iDE][iPlane]].get();
277 ++mNPreClusters[iDE][iPlane];
278
279 // reset its content
280 cluster->area[0][0] = 1.e6;
281 cluster->area[0][1] = -1.e6;
282 cluster->area[1][0] = 1.e6;
283 cluster->area[1][1] = -1.e6;
284 cluster->useMe = true;
285 cluster->storeMe = false;
286
287 // add the pad and its fired neighbours recusively
288 cluster->firstPad = de.nOrderedPads[0];
289 addPad(de, iPad, *cluster);
290 }
291 }
292 }
293 }
294}
295
296//_________________________________________________________________________________________________
297void PreClusterFinder::addPad(DetectionElement& de, uint16_t iPad, PreCluster& cluster)
298{
300
301 Mapping::MpPad* pads(de.mapping->pads.get());
302
303 // add the given pad
304 Mapping::MpPad& pad(pads[iPad]);
305 if (de.nOrderedPads[0] < de.orderedPads[0].size()) {
306 de.orderedPads[0][de.nOrderedPads[0]] = iPad;
307 } else {
308 de.orderedPads[0].push_back(iPad);
309 }
310 cluster.lastPad = de.nOrderedPads[0];
311 ++de.nOrderedPads[0];
312 if (pad.area[0][0] < cluster.area[0][0]) {
313 cluster.area[0][0] = pad.area[0][0];
314 }
315 if (pad.area[0][1] > cluster.area[0][1]) {
316 cluster.area[0][1] = pad.area[0][1];
317 }
318 if (pad.area[1][0] < cluster.area[1][0]) {
319 cluster.area[1][0] = pad.area[1][0];
320 }
321 if (pad.area[1][1] > cluster.area[1][1]) {
322 cluster.area[1][1] = pad.area[1][1];
323 }
324
325 pad.useMe = false;
326
327 // loop over its neighbours
328 for (int iNeighbour = 0; iNeighbour < pad.nNeighbours; ++iNeighbour) {
329
330 if (pads[pad.neighbours[iNeighbour]].useMe) {
331
332 // add the pad to the precluster
333 addPad(de, pad.neighbours[iNeighbour], cluster);
334 }
335 }
336}
337
338//_________________________________________________________________________________________________
339int PreClusterFinder::mergePreClusters()
340{
343
344 PreCluster* cluster(nullptr);
345 int nPreClusters(0);
346
347 // loop over DEs
348 for (int iDE = 0; iDE < SNDEs; ++iDE) {
349
350 DetectionElement& de(*(mDEs[iDE]));
351
352 // loop over preclusters of one plane
353 for (int iCluster = 0; iCluster < mNPreClusters[iDE][0]; ++iCluster) {
354
355 if (!mPreClusters[iDE][0][iCluster]->useMe) {
356 continue;
357 }
358
359 cluster = mPreClusters[iDE][0][iCluster].get();
360 cluster->useMe = false;
361
362 // look for overlapping preclusters in the other plane
363 PreCluster* mergedCluster(nullptr);
364 mergePreClusters(*cluster, mPreClusters[iDE], mNPreClusters[iDE], de, 1, mergedCluster);
365
366 // add the current one
367 if (!mergedCluster) {
368 mergedCluster = usePreClusters(cluster, de);
369 } else {
370 mergePreClusters(*mergedCluster, *cluster, de);
371 }
372
373 ++nPreClusters;
374 }
375
376 // loop over preclusters of the other plane
377 for (int iCluster = 0; iCluster < mNPreClusters[iDE][1]; ++iCluster) {
378
379 if (!mPreClusters[iDE][1][iCluster]->useMe) {
380 continue;
381 }
382
383 // all remaining preclusters have to be stored
384 usePreClusters(mPreClusters[iDE][1][iCluster].get(), de);
385
386 ++nPreClusters;
387 }
388 }
389
390 return nPreClusters;
391}
392
393//_________________________________________________________________________________________________
394void PreClusterFinder::mergePreClusters(PreCluster& cluster, std::vector<std::unique_ptr<PreCluster>> preClusters[2],
395 int nPreClusters[2], DetectionElement& de, int iPlane,
396 PreCluster*& mergedCluster)
397{
399
400 // overlap precision in cm: positive(negative) = increase(decrease) precluster size
401 constexpr float overlapPrecision = -1.e-4;
402
403 PreCluster* cluster2(nullptr);
404
405 // loop over preclusters in the given plane
406 for (int iCluster = 0; iCluster < nPreClusters[iPlane]; ++iCluster) {
407
408 if (!preClusters[iPlane][iCluster]->useMe) {
409 continue;
410 }
411
412 cluster2 = preClusters[iPlane][iCluster].get();
413 if (Mapping::areOverlapping(cluster.area, cluster2->area, overlapPrecision) &&
414 areOverlapping(cluster, *cluster2, de, overlapPrecision)) {
415
416 cluster2->useMe = false;
417
418 // look for new overlapping preclusters in the other plane
419 mergePreClusters(*cluster2, preClusters, nPreClusters, de, (iPlane + 1) % 2, mergedCluster);
420
421 // store overlapping preclusters and merge them
422 if (!mergedCluster) {
423 mergedCluster = usePreClusters(cluster2, de);
424 } else {
425 mergePreClusters(*mergedCluster, *cluster2, de);
426 }
427 }
428 }
429}
430
431//_________________________________________________________________________________________________
432PreClusterFinder::PreCluster* PreClusterFinder::usePreClusters(PreCluster* cluster, DetectionElement& de)
433{
435
436 uint16_t firstPad = de.nOrderedPads[1];
437
438 // move the fired pads
439 for (int iOrderPad = cluster->firstPad; iOrderPad <= cluster->lastPad; ++iOrderPad) {
440
441 if (de.nOrderedPads[1] < de.orderedPads[1].size()) {
442 de.orderedPads[1][de.nOrderedPads[1]] = de.orderedPads[0][iOrderPad];
443 } else {
444 de.orderedPads[1].push_back(de.orderedPads[0][iOrderPad]);
445 }
446
447 ++de.nOrderedPads[1];
448 }
449
450 cluster->firstPad = firstPad;
451 cluster->lastPad = de.nOrderedPads[1] - 1;
452
453 cluster->storeMe = true;
454
455 return cluster;
456}
457
458//_________________________________________________________________________________________________
459void PreClusterFinder::mergePreClusters(PreCluster& cluster1, PreCluster& cluster2, DetectionElement& de)
460{
462
463 // move the fired pads
464 for (int iOrderPad = cluster2.firstPad; iOrderPad <= cluster2.lastPad; ++iOrderPad) {
465
466 if (de.nOrderedPads[1] < de.orderedPads[1].size()) {
467 de.orderedPads[1][de.nOrderedPads[1]] = de.orderedPads[0][iOrderPad];
468 } else {
469 de.orderedPads[1].push_back(de.orderedPads[0][iOrderPad]);
470 }
471
472 ++de.nOrderedPads[1];
473 }
474
475 cluster1.lastPad = de.nOrderedPads[1] - 1;
476}
477
478//_________________________________________________________________________________________________
479bool PreClusterFinder::areOverlapping(PreCluster& cluster1, PreCluster& cluster2, DetectionElement& de, float precision)
480{
483
484 // loop over all pads of the precluster1
485 for (int iOrderPad1 = cluster1.firstPad; iOrderPad1 <= cluster1.lastPad; ++iOrderPad1) {
486
487 // loop over all pads of the precluster2
488 for (int iOrderPad2 = cluster2.firstPad; iOrderPad2 <= cluster2.lastPad; ++iOrderPad2) {
489
490 if (Mapping::areOverlapping(de.mapping->pads[de.orderedPads[0][iOrderPad1]].area,
491 de.mapping->pads[de.orderedPads[0][iOrderPad2]].area, precision)) {
492 return true;
493 }
494 }
495 }
496
497 return false;
498}
499
500//_________________________________________________________________________________________________
501void PreClusterFinder::createMapping()
502{
504
505 auto tStart = std::chrono::high_resolution_clock::now();
506
507 std::vector<std::unique_ptr<Mapping::MpDE>> mpDEs = Mapping::createMapping();
508
509 if (mpDEs.size() != SNDEs) {
510 throw runtime_error("invalid mapping");
511 }
512
513 mDEIndices.reserve(SNDEs);
514
515 for (int iDE = 0; iDE < SNDEs; ++iDE) {
516
517 DetectionElement& de(*(mDEs[iDE]));
518
519 de.mapping = std::move(mpDEs[iDE]);
520
521 mDEIndices.emplace(de.mapping->uid, iDE);
522
523 int initialSize = (de.mapping->nPads[0] / 10 + de.mapping->nPads[1] / 10); // 10 % occupancy
524
525 de.digits.reserve(initialSize);
526 de.nOrderedPads[0] = 0;
527 de.orderedPads[0].reserve(initialSize);
528 de.nOrderedPads[1] = 0;
529 de.orderedPads[1].reserve(initialSize);
530
531 for (int iPlane = 0; iPlane < 2; ++iPlane) {
532 de.nFiredPads[iPlane] = 0;
533 de.firedPads[iPlane].reserve(de.mapping->nPads[iPlane] / 10); // 10% occupancy
534 }
535 }
536
537 auto tEnd = std::chrono::high_resolution_clock::now();
538 LOG(info) << "create mapping in: " << std::chrono::duration<double, std::milli>(tEnd - tStart).count() << " ms";
539}
540
541} // namespace o2::mch
definition of the MCH processing errors
int32_t i
MCH digit implementation.
Definition Digit.h:31
int getPadID() const
Definition Digit.h:54
int getDetID() const
Definition Digit.h:52
void add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n=1)
Definition ErrorMap.cxx:33
static std::vector< std::unique_ptr< MpDE > > createMapping()
static bool areOverlapping(float area1[2][2], float area2[2][2], float precision)
void loadDigits(gsl::span< const Digit > digits)
void loadDigit(const Digit &digit)
int discardHighOccupancy(bool perDE, bool perEvent)
void getPreClusters(std::vector< o2::mch::PreCluster > &preClusters, std::vector< Digit > &digits)
GLsizeiptr size
Definition glcorearb.h:659
GLenum GLint GLint * precision
Definition glcorearb.h:1899
RuntimeErrorRef runtime_error(const char *)
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
@ PreClustering_MultipleDigitsInSamePad
gsl::span< const PreCluster > preClusters(preClusterizer.getPreClusters().data(), preClusterizer.getPreClusters().size())
Defining DataPointCompositeObject explicitly as copiable.
std::unique_ptr< Mapping::MpDE > mapping
precluster minimal structure
Definition PreCluster.h:33
uint16_t de
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits