Project
Loading...
Searching...
No Matches
HwClusterer.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
14
18#include "TPCBase/CRU.h"
19#include "TPCBase/Mapper.h"
21
22#include <fairlogger/Logger.h>
23
24#include <cassert>
25#include <limits>
26
27using namespace o2::tpc;
28
29//______________________________________________________________________________
30HwClusterer::HwClusterer(
31 std::vector<ClusterHardwareContainer8kb>* clusterOutputContainer,
32 int sectorid, MCLabelContainer* labelOutput)
33 : Clusterer(),
34 mNumRows(0),
35 mNumRowSets(0),
36 mCurrentMcContainerInBuffer(0),
37 mSplittingMode(0),
38 mClusterSector(sectorid),
39 mPreviousTimebin(-1),
40 mFirstTimebin(0),
41 mLastTimebin(200000),
42 mLastHB(0),
43 mPeakChargeThreshold(2),
44 mContributionChargeThreshold(0),
45 mClusterCounter(0),
46 mIsContinuousReadout(true),
47 mRejectSinglePadClusters(false),
48 mRejectSingleTimeClusters(false),
49 mRejectLaterTimebin(false),
50 mPadsPerRowSet(),
51 mGlobalRowToRegion(),
52 mGlobalRowToLocalRow(),
53 mGlobalRowToVcIndex(),
54 mGlobalRowToRowSet(),
55 mDataBuffer(),
56 mIndexBuffer(),
57 mMCtruth(),
58 mTmpClusterArray(),
59 mTmpLabelArray(),
60 mClusterMcLabelArray(labelOutput),
61 mClusterArray(clusterOutputContainer)
62{
63 LOG(debug) << "Enter Initializer of HwClusterer";
64
65 // Given sector ID must be within 0 and 35 for a proper CRU ID calculation
66 assert(sectorid >= 0 && sectorid < 36);
67
68 /*
69 * Prepare temporary storage for digits
70 */
71 Mapper& mapper = Mapper::instance();
72
73 mNumRows = mapper.getNumberOfRows();
74 mNumRowSets = std::ceil(mapper.getNumberOfRows() / Vc::uint_v::Size);
75 mDataBuffer.resize(mNumRowSets);
76 mIndexBuffer.resize(mNumRowSets);
77 mPadsPerRowSet.resize(mNumRowSets);
78
79 mGlobalRowToVcIndex.resize(mNumRows);
80 mGlobalRowToRowSet.resize(mNumRows);
81 for (unsigned short row = 0; row < mNumRowSets; ++row) {
82 // add two empty pads on the left and on the right
83 int max = 0;
84 for (int subrow = 0; subrow < Vc::uint_v::Size; ++subrow) {
85 max = std::max(max, mapper.getNumberOfPadsInRowSector(row * Vc::uint_v::Size + subrow) + 2 + 2);
86 mGlobalRowToRowSet[row * Vc::uint_v::Size + subrow] = row;
87 mGlobalRowToVcIndex[row * Vc::uint_v::Size + subrow] = subrow;
88 }
89 mPadsPerRowSet[row] = max;
90
91 // prepare for number of timebins
92 mDataBuffer[row].resize(mPadsPerRowSet[row] * mTimebinsInBuffer, 0);
93 mIndexBuffer[row].resize(mPadsPerRowSet[row] * mTimebinsInBuffer, -1);
94 }
95
96 mTmpClusterArray.resize(10);
97 mTmpLabelArray.resize(10);
98 for (unsigned short region = 0; region < 10; ++region) {
99 mTmpClusterArray[region] = std::make_unique<std::vector<ClusterHardware>>();
100 mTmpLabelArray[region] = std::make_unique<std::vector<std::vector<std::pair<MCCompLabel, unsigned>>>>();
101 }
102
103 mGlobalRowToRegion.resize(mNumRows);
104 mGlobalRowToLocalRow.resize(mNumRows);
105 unsigned short row = 0;
106 for (unsigned short region = 0; region < 10; ++region) {
107 for (unsigned short localRow = 0; localRow < mapper.getNumberOfRowsRegion(region); ++localRow) {
108 mGlobalRowToRegion[row] = region;
109 mGlobalRowToLocalRow[row] = localRow;
110 ++row;
111 }
112 }
113 mMCtruth.resize(mTimebinsInBuffer, nullptr);
114}
115
116//______________________________________________________________________________
118{
119 const auto& param = HwClustererParam::Instance();
120
121 mPeakChargeThreshold = param.peakChargeThreshold;
122 mContributionChargeThreshold = param.contributionChargeThreshold;
123 mFirstTimebin = param.firstTimeBin;
124 mLastTimebin = param.lastTimeBin;
125 mSplittingMode = param.splittingMode;
126 mIsContinuousReadout = param.isContinuousReadout;
127 mRejectSinglePadClusters = param.rejectSinglePadClusters;
128 mRejectSingleTimeClusters = param.rejectSingleTimeClusters;
129 mRejectLaterTimebin = param.rejectLaterTimebin;
130}
131
132//______________________________________________________________________________
133void HwClusterer::process(gsl::span<o2::tpc::Digit const> const& digits, ConstMCLabelContainerView const& mcDigitTruth, bool clearContainerFirst)
134{
135 if (clearContainerFirst) {
136 if (mClusterArray) {
137 mClusterArray->clear();
138 }
139
140 if (mClusterMcLabelArray) {
141 mClusterMcLabelArray->clear();
142 }
143 mClusterCounter = 0;
144 }
145
146 int digitIndex = 0;
147 int index;
148 unsigned HB;
149 mCurrentMcContainerInBuffer = 0;
150
151 /*
152 * Loop over all (time ordered) digits
153 */
154 for (const auto& digit : digits) {
155 /*
156 * This loop does the following:
157 * - add digits to the tmp storage
158 * - look for clusters
159 * - fill cluster output
160 *
161 * Before adding current digit to the storage, the new timebin has to be
162 * prepared first, by setting it completely 0, or to pedestal or ...
163 *
164 * This needs to be done only of the timestamps changes, otherwise it was
165 * already done.
166 */
167
168 const auto timeBin = digit.getTimeStamp();
169
170 if (timeBin < mFirstTimebin) {
171 continue;
172 } else if (timeBin > mLastTimebin) {
173 break;
174 }
175
176 if (timeBin != mPreviousTimebin) {
177 /*
178 * If the timebin changes, it could change by more then just 1 (not every
179 * timebin has digits). Since the tmp storage covers mTimebinsInBuffer,
180 * at most mTimebinsInBuffer new timebins need to be prepared and checked
181 * for clusters.
182 */
183 for (int i = mPreviousTimebin; (i < timeBin) && (i - mPreviousTimebin < mTimebinsInBuffer); ++i) {
184
185 /*
186 * If the HB of the cluster which will be found in a few lines, NOT the
187 * current timebin is a new one, we have to fill the output container
188 * with the so far found clusters. Because cluster center and timebin
189 * have an offset of two with respect to each other (see next comment),
190 * the HB is calculated with (i-2). By the way, it is not possible, that
191 * a cluster is found with a negative HB, because at least 2 timebins
192 * have to be filled to be able to find a cluster.
193 */
194 HB = i < 3 ? 0 : (i - 3) / 447; // integer division on purpose
195 if (HB != mLastHB) {
196 writeOutputWithTimeOffset(mLastHB * 447);
197 }
198
199 /*
200 * For each row(set), we first compute all the pad relations for the
201 * latest timebin (i), afterwards the clusters for timebin i-2 are
202 * collected and computed. We need the -2 because a cluster spreads
203 * over 5 timbins, and the relations are always computed with respect
204 * to the older timebin. Also a (i-1) and (i-2) would be possible, but
205 * doens't matter.
206 *
207 * If mTimebinsInBuffer would be 5 and i 5 is the new digit timebin (4
208 * would be mPreviousTimebin), then 0 is the oldest one timebin and will to
209 * be replaced by the new arriving one. The cluster which could be
210 * found, would then range from timebin 0 to 4 and has its center at
211 * timebin 2. Threrefore we are looking in (i - 2) for clusters and
212 * clearing (i - 4), or (i + 1) afterwards.
213 * ---------
214 * -> 0 |
215 * 1 |
216 * 2 | XXXXXX
217 * 3 |
218 * 4 |
219 * ---------
220 */
221 findPeaksForTime(i);
222 computeClusterForTime(i - 3);
223
224 clearBuffer(i + 1);
225
226 mLastHB = HB;
227 }
228
229 // we have to copy the MC truth container because we need the information
230 // maybe only in the next events (we store permanently 5 timebins), where
231 // the original pointer could already point to the next container.
232 if (mcDigitTruth.getBuffer().size()) {
233 if (mCurrentMcContainerInBuffer == 0) {
234 auto tmp = std::make_shared<MCLabelContainer>();
235 tmp->restore_from(mcDigitTruth.getBuffer().data(), mcDigitTruth.getBuffer().size());
236 mMCtruth[mapTimeInRange(timeBin)] = tmp;
237 } else {
238 mMCtruth[mapTimeInRange(timeBin)] = std::shared_ptr<MCLabelContainer const>(mMCtruth[getFirstSetBitOfField()]);
239 }
240 mCurrentMcContainerInBuffer |= (0x1 << (mapTimeInRange(timeBin)));
241 }
242 }
243
244 /*
245 * add current digit to storage
246 */
247 const auto row = digit.getRow();
248 const auto pad = digit.getPad();
249 index = mapTimeInRange(timeBin) * mPadsPerRowSet[mGlobalRowToRowSet[row]] + (pad + 2);
250 // offset of digit pad because of 2 empty pads on both sides
251
252 float charge = digit.getChargeFloat();
253
254 // TODO: fill noise here as well if necessary
255 if (mPedestalObject) {
256 charge -= mPedestalObject->getValue(CRU(digit.getCRU()), row, pad);
257 }
258 /*
259 * charge could be smaller than 0 due to pedestal subtraction, if so set it to zero
260 * noise thresholds for zero suppression could also be done here ...
261 */
262 mDataBuffer[mGlobalRowToRowSet[row]][index][mGlobalRowToVcIndex[row]] =
263 charge < 0 ? 0 : ((charge < float(0x3FFF) / (1 << 4)) ? (charge * (1 << 4)) : 0x3FFF);
264
265 mIndexBuffer[mGlobalRowToRowSet[row]][index][mGlobalRowToVcIndex[row]] = digitIndex++;
266
267 mPreviousTimebin = timeBin;
268 }
269
270 if (!mIsContinuousReadout) {
271 finishFrame(true);
272 }
273
274 if (digits.size() != 0) {
275 LOG(debug) << "Event ranged from time bin " << digits[0].getTimeStamp() << " to " << digits[digits.size() - 1].getTimeStamp() << ".";
276 }
277}
278
279//______________________________________________________________________________
280void HwClusterer::finishProcess(gsl::span<o2::tpc::Digit const> const& digits, ConstMCLabelContainerView const& mcDigitTruth, bool clearContainerFirst)
281{
282 // Process the last digits (if there are any)
283 process(digits, mcDigitTruth, clearContainerFirst);
284
285 // Search in last remaining timebins
286 finishFrame(false);
287}
288
289//______________________________________________________________________________
290void HwClusterer::hwClusterProcessor(const Vc::uint_m peakMask, unsigned qMaxIndex, short centerPad, int centerTime, unsigned short row)
291{
292 Vc::uint_v qTot = 0;
293 Vc::int_v pad = 0;
294 Vc::int_v time = 0;
295 Vc::int_v sigmaPad2 = 0;
296 Vc::int_v sigmaTime2 = 0;
297 Vc::int_v flags = 0;
298
299 using labelPair = std::pair<MCCompLabel, unsigned>;
300 std::vector<std::unique_ptr<std::vector<labelPair>>> mcLabels(Vc::uint_v::Size);
301 for (int i = 0; i < Vc::uint_v::Size; ++i) {
302 mcLabels[i] = std::make_unique<std::vector<labelPair>>();
303 }
304
305 const unsigned llttIndex = mapTimeInRange(centerTime - 2) * mPadsPerRowSet[row] + centerPad - 2;
306 const unsigned lltIndex = mapTimeInRange(centerTime - 1) * mPadsPerRowSet[row] + centerPad - 2;
307 const unsigned llIndex = mapTimeInRange(centerTime + 0) * mPadsPerRowSet[row] + centerPad - 2;
308 const unsigned llbIndex = mapTimeInRange(centerTime + 1) * mPadsPerRowSet[row] + centerPad - 2;
309 const unsigned llbbIndex = mapTimeInRange(centerTime + 2) * mPadsPerRowSet[row] + centerPad - 2;
310
311 const unsigned lttIndex = llttIndex + 1;
312 const unsigned ltIndex = lltIndex + 1;
313 const unsigned lIndex = llIndex + 1;
314 const unsigned lbIndex = llbIndex + 1;
315 const unsigned lbbIndex = llbbIndex + 1;
316
317 const unsigned ttIndex = lttIndex + 1;
318 const unsigned tIndex = ltIndex + 1;
319 const unsigned bIndex = lbIndex + 1;
320 const unsigned bbIndex = lbbIndex + 1;
321
322 const unsigned rttIndex = ttIndex + 1;
323 const unsigned rtIndex = tIndex + 1;
324 const unsigned rIndex = lIndex + 2;
325 const unsigned rbIndex = bIndex + 1;
326 const unsigned rbbIndex = bbIndex + 1;
327
328 const unsigned rrttIndex = rttIndex + 1;
329 const unsigned rrtIndex = rtIndex + 1;
330 const unsigned rrIndex = rIndex + 1;
331 const unsigned rrbIndex = rbIndex + 1;
332 const unsigned rrbbIndex = rbbIndex + 1;
333
334 Vc::uint_m selectionMask;
335 if (mSplittingMode == 0) {
336 // Charge is not splitted between nearby peaks, every peak uses all charges
337
338 // Cluster:
339 //
340 // o o o o o
341 // o i i i o
342 // o i C i o
343 // o i i i o
344 // o o o o o
345
346 // Use always inner 3x3 matrix
347 // i i i
348 // i C i
349 // i i i
350 for (short dt = -1; dt <= 1; ++dt) {
351 for (short dp = -1; dp <= 1; ++dp) {
352 updateCluster(peakMask, row, centerPad, centerTime, dp, dt, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
353 }
354 }
355
356 // Use outer pads (o) only, if corresponding inner pad (i) is above contribution threshold
357 // o
358 // i
359 // o i C i o
360 // i
361 // o
362 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][lIndex]) > (mContributionChargeThreshold << 4));
363 updateCluster(selectionMask, row, centerPad, centerTime, -2, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
364
365 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][rIndex]) > (mContributionChargeThreshold << 4));
366 updateCluster(selectionMask, row, centerPad, centerTime, +2, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
367
368 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][tIndex]) > (mContributionChargeThreshold << 4));
369 updateCluster(selectionMask, row, centerPad, centerTime, 0, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
370
371 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][bIndex]) > (mContributionChargeThreshold << 4));
372 updateCluster(selectionMask, row, centerPad, centerTime, 0, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
373
374 // o o o o
375 // o i i o
376 // C
377 // o i i o
378 // o o o o
379 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][ltIndex]) > (mContributionChargeThreshold << 4));
380 updateCluster(selectionMask, row, centerPad, centerTime, -2, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
381 updateCluster(selectionMask, row, centerPad, centerTime, -2, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
382 updateCluster(selectionMask, row, centerPad, centerTime, -1, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
383
384 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][lbIndex]) > (mContributionChargeThreshold << 4));
385 updateCluster(selectionMask, row, centerPad, centerTime, -2, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
386 updateCluster(selectionMask, row, centerPad, centerTime, -2, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
387 updateCluster(selectionMask, row, centerPad, centerTime, -1, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
388
389 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][rtIndex]) > (mContributionChargeThreshold << 4));
390 updateCluster(selectionMask, row, centerPad, centerTime, +2, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
391 updateCluster(selectionMask, row, centerPad, centerTime, +2, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
392 updateCluster(selectionMask, row, centerPad, centerTime, +1, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
393
394 selectionMask = peakMask & (getFpOfADC(mDataBuffer[row][rbIndex]) > (mContributionChargeThreshold << 4));
395 updateCluster(selectionMask, row, centerPad, centerTime, +2, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
396 updateCluster(selectionMask, row, centerPad, centerTime, +2, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
397 updateCluster(selectionMask, row, centerPad, centerTime, +1, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
398
399 } else if (mSplittingMode == 1) {
400 // Charge is split at minimum, the minimum itself contributes half too all
401 // adjacent peaks (even if there are 3).
402
403 // Use always inner 3x3 matrix
404 // i i i
405 // i C i
406 // i i i
407 // but only half the charge if (i) is minimum
408
409 // center
410 updateCluster(peakMask, row, centerPad, centerTime, 0, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels);
411
412 // horizontal, look for minimum in pad direction
413 auto splitMask = (((mDataBuffer[row][lIndex] >> 26) & 0x1) == 0x1);
414 updateCluster(peakMask, row, centerPad, centerTime, -1, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
415
416 splitMask = (((mDataBuffer[row][rIndex] >> 26) & 0x1) == 0x1);
417 updateCluster(peakMask, row, centerPad, centerTime, +1, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
418
419 // vertical look for minimum in time direction
420 splitMask = (((mDataBuffer[row][tIndex] >> 25) & 0x1) == 0x1);
421 updateCluster(peakMask, row, centerPad, centerTime, 0, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
422
423 splitMask = (((mDataBuffer[row][bIndex] >> 25) & 0x1) == 0x1);
424 updateCluster(peakMask, row, centerPad, centerTime, 0, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
425
426 // diagonal tl/br, look for minimum in 1. diagonal + vertical + horizontal direction
427 splitMask = (((mDataBuffer[row][ltIndex] >> 24) & 0x1) == 0x1) |
428 (((mDataBuffer[row][ltIndex] >> 25) & 0x1) == 0x1) |
429 (((mDataBuffer[row][ltIndex] >> 26) & 0x1) == 0x1);
430 updateCluster(peakMask, row, centerPad, centerTime, -1, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
431
432 splitMask = (((mDataBuffer[row][rbIndex] >> 24) & 0x1) == 0x1) |
433 (((mDataBuffer[row][rbIndex] >> 25) & 0x1) == 0x1) |
434 (((mDataBuffer[row][rbIndex] >> 26) & 0x1) == 0x1);
435 updateCluster(peakMask, row, centerPad, centerTime, +1, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
436
437 // diagonal tr/bl, look for minimum in 2. diagonal + vertical + horizontal direction
438 splitMask = (((mDataBuffer[row][rtIndex] >> 23) & 0x1) == 0x1) |
439 (((mDataBuffer[row][rtIndex] >> 25) & 0x1) == 0x1) |
440 (((mDataBuffer[row][rtIndex] >> 26) & 0x1) == 0x1);
441 updateCluster(peakMask, row, centerPad, centerTime, +1, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
442
443 splitMask = (((mDataBuffer[row][lbIndex] >> 23) & 0x1) == 0x1) |
444 (((mDataBuffer[row][lbIndex] >> 25) & 0x1) == 0x1) |
445 (((mDataBuffer[row][lbIndex] >> 26) & 0x1) == 0x1);
446 updateCluster(peakMask, row, centerPad, centerTime, -1, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
447
448 // Use outer pads (o) only, if corresponding inner pad (i) is above contribution threshold
449 // o
450 // i
451 // o i C i o
452 // i
453 // o
454 // and only if inner pad (i) is not a minimum (in corresponding direction).
455 // Split charge, if (o) is a minimum.
456 selectionMask = peakMask & // using (o) (if we have a peak in the center)
457 (getFpOfADC(mDataBuffer[row][lIndex]) > (mContributionChargeThreshold << 4)) & // AND (i) is above threshold
458 (((mDataBuffer[row][lIndex] >> 26) & 0x1) != 0x1); // AND (i) is not minimum in corresponding direction
459 splitMask = (((mDataBuffer[row][llIndex] >> 26) & 0x1) == 0x1); // split (o) if it is miminum in corresponding direction
460 updateCluster(selectionMask, row, centerPad, centerTime, -2, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
461
462 selectionMask = peakMask &
463 (getFpOfADC(mDataBuffer[row][rIndex]) > (mContributionChargeThreshold << 4)) &
464 (((mDataBuffer[row][rIndex] >> 26) & 0x1) != 0x1);
465 splitMask = (((mDataBuffer[row][rrIndex] >> 26) & 0x1) == 0x1);
466 updateCluster(selectionMask, row, centerPad, centerTime, +2, 0, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
467
468 selectionMask = peakMask &
469 (getFpOfADC(mDataBuffer[row][tIndex]) > (mContributionChargeThreshold << 4)) &
470 (((mDataBuffer[row][tIndex] >> 25) & 0x1) != 0x1);
471 splitMask = (((mDataBuffer[row][ttIndex] >> 26) & 0x1) == 0x1);
472 updateCluster(selectionMask, row, centerPad, centerTime, 0, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
473
474 selectionMask = peakMask &
475 (getFpOfADC(mDataBuffer[row][bIndex]) > (mContributionChargeThreshold << 4)) &
476 (((mDataBuffer[row][bIndex] >> 25) & 0x1) != 0x1);
477 splitMask = (((mDataBuffer[row][bbIndex] >> 26) & 0x1) == 0x1);
478 updateCluster(selectionMask, row, centerPad, centerTime, 0, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
479
480 // o o o o
481 // o i i o
482 // C
483 // o i i o
484 // o o o o
485 selectionMask = peakMask & // using (o) (if we have a peak in the center)
486 (getFpOfADC(mDataBuffer[row][ltIndex]) > (mContributionChargeThreshold << 4)) & // AND (i) is above threshold
487 (((mDataBuffer[row][ltIndex] >> 26) & 0x1) != 0x1); // AND (i) is not minimum in corresponding direction
488 splitMask = (((mDataBuffer[row][lltIndex] >> 26) & 0x1) == 0x1) | // split (o) if it is miminum in corresponding directions
489 (((mDataBuffer[row][lltIndex] >> 24) & 0x1) == 0x1);
490 updateCluster(selectionMask, row, centerPad, centerTime, -2, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
491
492 selectionMask = peakMask & // using (o) (if we have a peak in the center)
493 (getFpOfADC(mDataBuffer[row][ltIndex]) > (mContributionChargeThreshold << 4)) & // AND (i) is above threshold
494 (((mDataBuffer[row][ltIndex] >> 24) & 0x1) != 0x1) & // AND (i) is not minimum in corresponding directions
495 (((mDataBuffer[row][ltIndex] >> 25) & 0x1) != 0x1) &
496 (((mDataBuffer[row][ltIndex] >> 26) & 0x1) != 0x1) &
497 (((mDataBuffer[row][lltIndex] >> 25) & 0x1) != 0x1) & // AND other (o) is not minimum in corresponding direction
498 (((mDataBuffer[row][lttIndex] >> 26) & 0x1) != 0x1); // AND other (o) is not minimum in corresponding direction
499 splitMask = (((mDataBuffer[row][llttIndex] >> 24) & 0x1) == 0x1) | // split (o) if it is miminum in corresponding direction
500 (((mDataBuffer[row][llttIndex] >> 25) & 0x1) == 0x1) |
501 (((mDataBuffer[row][llttIndex] >> 26) & 0x1) == 0x1);
502 updateCluster(selectionMask, row, centerPad, centerTime, -2, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
503
504 selectionMask = peakMask &
505 (getFpOfADC(mDataBuffer[row][ltIndex]) > (mContributionChargeThreshold << 4)) &
506 (((mDataBuffer[row][ltIndex] >> 25) & 0x1) != 0x1);
507 splitMask = (((mDataBuffer[row][lttIndex] >> 25) & 0x1) == 0x1) |
508 (((mDataBuffer[row][lttIndex] >> 24) & 0x1) == 0x1);
509 updateCluster(selectionMask, row, centerPad, centerTime, -1, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
510
511 selectionMask = peakMask &
512 (getFpOfADC(mDataBuffer[row][lbIndex]) > (mContributionChargeThreshold << 4)) &
513 (((mDataBuffer[row][lbIndex] >> 26) & 0x1) != 0x1);
514 splitMask = (((mDataBuffer[row][llbIndex] >> 26) & 0x1) == 0x1) |
515 (((mDataBuffer[row][llbIndex] >> 23) & 0x1) == 0x1);
516 updateCluster(selectionMask, row, centerPad, centerTime, -2, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
517
518 selectionMask = peakMask &
519 (getFpOfADC(mDataBuffer[row][lbIndex]) > (mContributionChargeThreshold << 4)) &
520 (((mDataBuffer[row][lbIndex] >> 23) & 0x1) != 0x1) &
521 (((mDataBuffer[row][lbIndex] >> 25) & 0x1) != 0x1) &
522 (((mDataBuffer[row][lbIndex] >> 26) & 0x1) != 0x1) &
523 (((mDataBuffer[row][llbIndex] >> 25) & 0x1) != 0x1) &
524 (((mDataBuffer[row][lbbIndex] >> 26) & 0x1) != 0x1);
525 splitMask = (((mDataBuffer[row][llbbIndex] >> 23) & 0x1) == 0x1) |
526 (((mDataBuffer[row][llbbIndex] >> 25) & 0x1) == 0x1) |
527 (((mDataBuffer[row][llbbIndex] >> 26) & 0x1) == 0x1);
528 updateCluster(selectionMask, row, centerPad, centerTime, -2, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
529
530 selectionMask = peakMask &
531 (getFpOfADC(mDataBuffer[row][lbIndex]) > (mContributionChargeThreshold << 4)) &
532 (((mDataBuffer[row][lbIndex] >> 25) & 0x1) != 0x1);
533 splitMask = (((mDataBuffer[row][lbbIndex] >> 25) & 0x1) == 0x1) |
534 (((mDataBuffer[row][lbbIndex] >> 23) & 0x1) == 0x1);
535 updateCluster(selectionMask, row, centerPad, centerTime, -1, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
536
537 selectionMask = peakMask &
538 (getFpOfADC(mDataBuffer[row][rtIndex]) > (mContributionChargeThreshold << 4)) &
539 (((mDataBuffer[row][rtIndex] >> 26) & 0x1) != 0x1);
540 splitMask = (((mDataBuffer[row][rrtIndex] >> 26) & 0x1) == 0x1) |
541 (((mDataBuffer[row][rrtIndex] >> 23) & 0x1) == 0x1);
542 updateCluster(selectionMask, row, centerPad, centerTime, +2, -1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
543
544 selectionMask = peakMask &
545 (getFpOfADC(mDataBuffer[row][rtIndex]) > (mContributionChargeThreshold << 4)) &
546 (((mDataBuffer[row][rtIndex] >> 23) & 0x1) != 0x1) &
547 (((mDataBuffer[row][rtIndex] >> 25) & 0x1) != 0x1) &
548 (((mDataBuffer[row][rtIndex] >> 26) & 0x1) != 0x1) &
549 (((mDataBuffer[row][rrtIndex] >> 25) & 0x1) != 0x1) &
550 (((mDataBuffer[row][rttIndex] >> 26) & 0x1) != 0x1);
551 splitMask = (((mDataBuffer[row][rrttIndex] >> 23) & 0x1) == 0x1) |
552 (((mDataBuffer[row][rrttIndex] >> 25) & 0x1) == 0x1) |
553 (((mDataBuffer[row][rrttIndex] >> 26) & 0x1) == 0x1);
554 updateCluster(selectionMask, row, centerPad, centerTime, +2, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
555
556 selectionMask = peakMask &
557 (getFpOfADC(mDataBuffer[row][rtIndex]) > (mContributionChargeThreshold << 4)) &
558 (((mDataBuffer[row][rtIndex] >> 25) & 0x1) != 0x1);
559 splitMask = (((mDataBuffer[row][rttIndex] >> 25) & 0x1) == 0x1) |
560 (((mDataBuffer[row][rttIndex] >> 23) & 0x1) == 0x1);
561 updateCluster(selectionMask, row, centerPad, centerTime, +1, -2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
562
563 selectionMask = peakMask &
564 (getFpOfADC(mDataBuffer[row][rbIndex]) > (mContributionChargeThreshold << 4)) &
565 (((mDataBuffer[row][rbIndex] >> 26) & 0x1) != 0x1);
566 splitMask = (((mDataBuffer[row][rrbIndex] >> 26) & 0x1) == 0x1) |
567 (((mDataBuffer[row][rrbIndex] >> 24) & 0x1) == 0x1);
568 updateCluster(selectionMask, row, centerPad, centerTime, +2, +1, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
569
570 selectionMask = peakMask &
571 (getFpOfADC(mDataBuffer[row][rbIndex]) > (mContributionChargeThreshold << 4)) &
572 (((mDataBuffer[row][rbIndex] >> 24) & 0x1) != 0x1) &
573 (((mDataBuffer[row][rbIndex] >> 25) & 0x1) != 0x1) &
574 (((mDataBuffer[row][rbIndex] >> 26) & 0x1) != 0x1) &
575 (((mDataBuffer[row][rrbIndex] >> 25) & 0x1) != 0x1) &
576 (((mDataBuffer[row][rbbIndex] >> 26) & 0x1) != 0x1);
577 splitMask = (((mDataBuffer[row][rrbbIndex] >> 24) & 0x1) == 0x1) |
578 (((mDataBuffer[row][rrbbIndex] >> 25) & 0x1) == 0x1) |
579 (((mDataBuffer[row][rrbbIndex] >> 26) & 0x1) == 0x1);
580 updateCluster(selectionMask, row, centerPad, centerTime, +2, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
581
582 selectionMask = peakMask &
583 (getFpOfADC(mDataBuffer[row][rbIndex]) > (mContributionChargeThreshold << 4)) &
584 (((mDataBuffer[row][rbIndex] >> 25) & 0x1) != 0x1);
585 splitMask = (((mDataBuffer[row][rbbIndex] >> 25) & 0x1) == 0x1) |
586 (((mDataBuffer[row][rbbIndex] >> 24) & 0x1) == 0x1);
587 updateCluster(selectionMask, row, centerPad, centerTime, +1, +2, qTot, pad, time, sigmaPad2, sigmaTime2, mcLabels, splitMask);
588 }
589
590 selectionMask = peakMask;
591 if (mRejectSinglePadClusters) {
592 selectionMask &= !(sigmaPad2 == 0);
593 }
594 if (mRejectSingleTimeClusters) {
595 selectionMask &= !(sigmaTime2 == 0);
596 }
597
598 ClusterHardware tmpCluster;
599 for (int i = 0; i < Vc::uint_v::Size; ++i) {
600 if (selectionMask[i]) {
601
602 mTmpClusterArray[mGlobalRowToRegion[row * Vc::uint_v::Size + i]]->emplace_back();
603 mTmpClusterArray[mGlobalRowToRegion[row * Vc::uint_v::Size + i]]->back().setCluster(
604 centerPad - 2, // we have two artificial empty pads "on the left" which needs to be subtracted
605 centerTime % 447, // the time within a HB
606 pad[i], time[i],
607 sigmaPad2[i], sigmaTime2[i],
608 (getFpOfADC(mDataBuffer[row][qMaxIndex])[i] >> 3), // keep only 1 fixed point precision bit
609 qTot[i],
610 mGlobalRowToLocalRow[row * Vc::uint_v::Size + i], // the hardware knows only about the local row
611 flags[i]);
612
613 std::sort(mcLabels[i]->begin(), mcLabels[i]->end(), [](const labelPair& a, const labelPair& b) { return a.second > b.second; });
614 mTmpLabelArray[mGlobalRowToRegion[row * Vc::uint_v::Size + i]]->push_back(std::move(*mcLabels[i]));
615 }
616 }
617}
618
619//______________________________________________________________________________
620void HwClusterer::hwPeakFinder(unsigned qMaxIndex, short centerPad, int mappedCenterTime, unsigned short row)
621{
622
623 // Always the center pad is compared with a fixed other pad. The first
624 // comparison is in pad direction. That bin (p,t) is a peak in pad direction,
625 // it has to be >= then (p-1,t) and in the next iteration, where the next pad
626 // is the center, the comparison of (the new center with the new left one)
627 // must be false, so that (p+1,t) > (p,t). Afterwards, this is also done in
628 // time direction and both diagonal directions. With those 4 comparisons, all
629 // 8 neighboring pads are checked iteratively.
630 //
631 // Example in pad direction:
632 // p-2 p-1 p p+1 p+2 p-1 p p+1 p+2 p+3
633 // t-2 o o o o o o o o o o
634 // t-1 o i i i o next iteration o i i i o
635 // t o I<->C i o ---------------> O I<->c i o
636 // t+1 o i i i o o i i i o
637 // t+2 o o o o o o o o o o
638 //
639 //
640 // Meaning of the set bit:
641 //
642 // bit | meaning if set
643 // 31 | peak in pad direction
644 // 30 | peak in time direction
645 // 29 | peak in 1. diagonal direction, top left to bottom right
646 // 28 | peak in 2. diagonal direction, top right to bottom left
647 // 27 | ADC above peak threshold
648 // 26 | minimum in pad direction
649 // 25 | minimum in time direction
650 // 24 | minimum in 1. diagonal direction
651 // 23 | minimum in 2. diagonal direction
652
653 const int compareIndex0 = mappedCenterTime * mPadsPerRowSet[row] + centerPad - 1;
654 const int compareIndex1 = mapTimeInRange(mappedCenterTime - 1) * mPadsPerRowSet[row] + centerPad;
655 const int compareIndex2 = compareIndex1 - 1;
656 const int compareIndex3 = compareIndex1 + 1;
657 const auto adcMask = (getFpOfADC(mDataBuffer[row][qMaxIndex]) == 0) &
658 (getFpOfADC(mDataBuffer[row][compareIndex0]) == 0) &
659 (getFpOfADC(mDataBuffer[row][compareIndex1]) == 0) &
660 (getFpOfADC(mDataBuffer[row][compareIndex2]) == 0) &
661 (getFpOfADC(mDataBuffer[row][compareIndex3]) == 0);
662 if (adcMask.isFull()) {
663 // if all 0, we can skip the following part and directly set the bits where
664 // the comparisons were true, TODO: still possible if difference is applied?
665 mDataBuffer[row][qMaxIndex] |= (0x1 << 31);
666 mDataBuffer[row][compareIndex0] &= ~(0x1 << 31);
667 mDataBuffer[row][qMaxIndex] |= (0x1 << 30);
668 mDataBuffer[row][compareIndex1] &= ~(0x1 << 30);
669 mDataBuffer[row][qMaxIndex] |= (0x1 << 29);
670 mDataBuffer[row][compareIndex2] &= ~(0x1 << 29);
671 mDataBuffer[row][qMaxIndex] |= (0x1 << 28);
672 mDataBuffer[row][compareIndex3] &= ~(0x1 << 28);
673 return;
674 }
675
677 // Comparison in pad direction
678 // TODO: define needed difference
679 auto tmpMask = getFpOfADC(mDataBuffer[row][qMaxIndex]) >= getFpOfADC(mDataBuffer[row][compareIndex0]);
680 // if true:
681 // - current center could be peak
682 // - cleare possible maxBit of other
683 // - other is minimum if minBit was already set before
684 Vc::where(tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 31);
685 Vc::where(tmpMask) | mDataBuffer[row][compareIndex0] &= ~(0x1 << 31);
686
687 // if false:
688 // - current center could be minimum
689 // - cleare possible minBit of other
690 // - other is peak if maxBit was already set before
691 Vc::where(!tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 26);
692 Vc::where(!tmpMask) | mDataBuffer[row][compareIndex0] &= ~(0x1 << 26);
693
695 // Comparison in time direction
696 tmpMask = getFpOfADC(mDataBuffer[row][qMaxIndex]) >= getFpOfADC(mDataBuffer[row][compareIndex1]);
697 Vc::where(tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 30);
698 Vc::where(tmpMask) | mDataBuffer[row][compareIndex1] &= ~(0x1 << 30);
699 Vc::where(!tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 25);
700 Vc::where(!tmpMask) | mDataBuffer[row][compareIndex1] &= ~(0x1 << 25);
701
703 // Comparison in 1. diagonal direction
704 tmpMask = getFpOfADC(mDataBuffer[row][qMaxIndex]) >= getFpOfADC(mDataBuffer[row][compareIndex2]);
705 Vc::where(tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 29);
706 Vc::where(tmpMask) | mDataBuffer[row][compareIndex2] &= ~(0x1 << 29);
707 Vc::where(!tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 24);
708 Vc::where(!tmpMask) | mDataBuffer[row][compareIndex2] &= ~(0x1 << 24);
709
711 // Comparison in 2. diagonal direction
712 tmpMask = getFpOfADC(mDataBuffer[row][qMaxIndex]) >= getFpOfADC(mDataBuffer[row][compareIndex3]);
713 Vc::where(tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 28);
714 Vc::where(tmpMask) | mDataBuffer[row][compareIndex3] &= ~(0x1 << 28);
715 Vc::where(!tmpMask) | mDataBuffer[row][qMaxIndex] |= (0x1 << 23);
716 Vc::where(!tmpMask) | mDataBuffer[row][compareIndex3] &= ~(0x1 << 23);
717
719 // Comparison peak threshold
720 Vc::where(getFpOfADC(mDataBuffer[row][qMaxIndex]) > (mPeakChargeThreshold << 4)) | mDataBuffer[row][qMaxIndex] |= (0x1 << 27);
721}
722
723//______________________________________________________________________________
724void HwClusterer::writeOutputWithTimeOffset(int timeOffset)
725{
726 // Check in which regions cluster were found
727 for (unsigned int region = 0; region < 10; ++region) {
728 if (mTmpClusterArray[region]->size() == 0) {
729 continue;
730 }
731
732 if (mClusterArray) {
733 // Create new container
734 mClusterArray->emplace_back();
735 auto clusterContainer = mClusterArray->back().getContainer();
736
737 // Set meta data
738 clusterContainer->CRU = mClusterSector * 10 + region;
739 clusterContainer->numberOfClusters = 0;
740 clusterContainer->timeBinOffset = timeOffset;
741
742 for (int c = 0; c < mTmpClusterArray[region]->size(); ++c) {
743 // if the container is full, create a new one
744 if (clusterContainer->numberOfClusters == mClusterArray->back().getMaxNumberOfClusters()) {
745 mClusterArray->emplace_back();
746 clusterContainer = mClusterArray->back().getContainer();
747 clusterContainer->CRU = mClusterSector * 10 + region;
748 clusterContainer->numberOfClusters = 0;
749 clusterContainer->timeBinOffset = timeOffset;
750 }
751 // Copy cluster and increment cluster counter
752 clusterContainer->clusters[clusterContainer->numberOfClusters++] = std::move((*mTmpClusterArray[region])[c]);
753 if (mClusterMcLabelArray) {
754 for (auto& mcLabel : (*mTmpLabelArray[region])[c]) {
755 mClusterMcLabelArray->addElement(mClusterCounter, mcLabel.first);
756 }
757 }
758 ++mClusterCounter;
759 }
760 }
761
762 // Clear copied temporary storage
763 mTmpClusterArray[region]->clear();
764 mTmpLabelArray[region]->clear();
765 }
766}
767
768//______________________________________________________________________________
769void HwClusterer::findPeaksForTime(int timebin)
770{
771 if (timebin < 0) {
772 return;
773 }
774
775 const unsigned timeBinWrapped = mapTimeInRange(timebin);
776 for (unsigned short row = 0; row < mNumRowSets; ++row) {
777 const unsigned padOffset = timeBinWrapped * mPadsPerRowSet[row];
778 // two empty pads on the left and right without a cluster peak, check one
779 // beyond rightmost pad for remaining relations
780 for (short pad = 1; pad < mPadsPerRowSet[row] - 1; ++pad) {
781 const unsigned qMaxIndex = padOffset + pad;
782 hwPeakFinder(qMaxIndex, pad, timeBinWrapped, row);
783 }
784 }
785}
786
787//______________________________________________________________________________
788void HwClusterer::computeClusterForTime(int timebin)
789{
790 if (timebin < 0) {
791 return;
792 }
793
794 const unsigned timeBinWrapped = mapTimeInRange(timebin);
795 if (mRejectLaterTimebin) {
796 const unsigned previousTimeBinWrapped = mapTimeInRange(timebin - 2);
797 for (unsigned short row = 0; row < mNumRowSets; ++row) {
798 const unsigned padOffset = timeBinWrapped * mPadsPerRowSet[row];
799 const unsigned previousPadOffset = previousTimeBinWrapped * mPadsPerRowSet[row];
800 // two empty pads on the left and right without a cluster peak
801 for (short pad = 2; pad < mPadsPerRowSet[row] - 2; ++pad) {
802 const unsigned qMaxIndex = padOffset + pad;
803 const unsigned qMaxPreviousIndex = previousPadOffset + pad;
804
805 // TODO: define needed difference
806 const auto peakMask = ((mDataBuffer[row][qMaxIndex] >> 27) == 0x1F) & // True if current pad is peak AND
807 (getFpOfADC(mDataBuffer[row][qMaxIndex]) > getFpOfADC(mDataBuffer[row][qMaxPreviousIndex]) | // previous has smaller charge
808 !((mDataBuffer[row][qMaxPreviousIndex] >> 27) == 0x1F)); // or previous one was not a peak
809 if (peakMask.isEmpty()) {
810 continue;
811 }
812
813 hwClusterProcessor(peakMask, qMaxIndex, pad, timebin, row);
814 }
815 }
816 } else {
817 for (unsigned short row = 0; row < mNumRowSets; ++row) {
818 const unsigned padOffset = timeBinWrapped * mPadsPerRowSet[row];
819 // two empty pads on the left and right without a cluster peak
820 for (short pad = 2; pad < mPadsPerRowSet[row] - 2; ++pad) {
821 const unsigned qMaxIndex = padOffset + pad;
822
823 const auto peakMask = ((mDataBuffer[row][qMaxIndex] >> 27) == 0x1F);
824 if (peakMask.isEmpty()) {
825 continue;
826 }
827
828 hwClusterProcessor(peakMask, qMaxIndex, pad, timebin, row);
829 }
830 }
831 }
832}
833
834//______________________________________________________________________________
835void HwClusterer::finishFrame(bool clear)
836{
837 unsigned HB;
838 // Search in last remaining timebins for clusters
839 for (int i = mPreviousTimebin; i - mPreviousTimebin < mTimebinsInBuffer; ++i) {
840 HB = i < 3 ? 0 : (i - 3) / 447; // integer division on purpose
841 if (HB != mLastHB) {
842 writeOutputWithTimeOffset(mLastHB * 447);
843 }
844
845 findPeaksForTime(i);
846 computeClusterForTime(i - 3);
847 clearBuffer(i + 1);
848 mLastHB = HB;
849 }
850 writeOutputWithTimeOffset(mLastHB * 447);
851
852 if (clear) {
853 for (int i = 0; i < mTimebinsInBuffer; ++i) {
854 clearBuffer(i);
855 }
856 }
857}
858
859//______________________________________________________________________________
860void HwClusterer::clearBuffer(int timebin)
861{
862 const int wrappedTime = mapTimeInRange(timebin);
863 mMCtruth[wrappedTime].reset();
864 mCurrentMcContainerInBuffer &= ~(0x1 << wrappedTime); // clear bit
865 for (unsigned short row = 0; row < mNumRowSets; ++row) {
866 // reset timebin which is not needed anymore
867 std::fill(mDataBuffer[row].begin() + wrappedTime * mPadsPerRowSet[row],
868 mDataBuffer[row].begin() + wrappedTime * mPadsPerRowSet[row] + mPadsPerRowSet[row], 0);
869 std::fill(mIndexBuffer[row].begin() + wrappedTime * mPadsPerRowSet[row],
870 mIndexBuffer[row].begin() + wrappedTime * mPadsPerRowSet[row] + mPadsPerRowSet[row], -1);
871 }
872}
873
874//______________________________________________________________________________
875void HwClusterer::updateCluster(
876 const Vc::uint_m selectionMask, int row, short centerPad, int centerTime, short dp, short dt,
877 Vc::uint_v& qTot, Vc::int_v& pad, Vc::int_v& time, Vc::int_v& sigmaPad2, Vc::int_v& sigmaTime2,
878 std::vector<std::unique_ptr<std::vector<std::pair<MCCompLabel, unsigned>>>>& mcLabels, const Vc::uint_m splitMask)
879{
880 if (selectionMask.isEmpty()) {
881 return;
882 }
883
884 const int mappedTime = mapTimeInRange(centerTime + dt);
885 const int index = mappedTime * mPadsPerRowSet[row] + centerPad + dp;
886
887 // If the charge should be split, only half of the charge is used
888 Vc::where(selectionMask & splitMask) | qTot += (getFpOfADC(mDataBuffer[row][index]) >> 1);
889 Vc::where(selectionMask & splitMask) | pad += (getFpOfADC(mDataBuffer[row][index]) >> 1) * dp;
890 Vc::where(selectionMask & splitMask) | time += (getFpOfADC(mDataBuffer[row][index]) >> 1) * dt;
891 Vc::where(selectionMask & splitMask) | sigmaPad2 += (getFpOfADC(mDataBuffer[row][index]) >> 1) * dp * dp;
892 Vc::where(selectionMask & splitMask) | sigmaTime2 += (getFpOfADC(mDataBuffer[row][index]) >> 1) * dt * dt;
893
894 // Otherwise the full charge
895 Vc::where(selectionMask & (!splitMask)) | qTot += getFpOfADC(mDataBuffer[row][index]);
896 Vc::where(selectionMask & (!splitMask)) | pad += getFpOfADC(mDataBuffer[row][index]) * dp;
897 Vc::where(selectionMask & (!splitMask)) | time += getFpOfADC(mDataBuffer[row][index]) * dt;
898 Vc::where(selectionMask & (!splitMask)) | sigmaPad2 += getFpOfADC(mDataBuffer[row][index]) * dp * dp;
899 Vc::where(selectionMask & (!splitMask)) | sigmaTime2 += getFpOfADC(mDataBuffer[row][index]) * dt * dt;
900
901 for (int i = 0; i < Vc::uint_v::Size; ++i) {
902 if (selectionMask[i] && mMCtruth[mappedTime] != nullptr) {
903 for (auto& label : mMCtruth[mappedTime]->getLabels(mIndexBuffer[row][index][i])) {
904 bool isKnown = false;
905 for (auto& vecLabel : *mcLabels[i]) {
906 if (label == vecLabel.first) {
907 ++vecLabel.second;
908 isKnown = true;
909 }
910 }
911 if (!isKnown) {
912 mcLabels[i]->emplace_back(label, 1);
913 }
914 }
915 }
916 }
917}
Class of a TPC cluster as produced by the hardware cluster finder (needs a postprocessing step to con...
Definition of the TPC Digit.
std::ostringstream debug
int16_t charge
Definition RawEventData.h:5
int16_t time
Definition RawEventData.h:4
int32_t i
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 for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions false
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc true
configStandalone Reconstruction rec_tpc float
Implementation of the parameter class for the hardware clusterer.
Class for TPC HW cluster finding.
uint32_t c
Definition RawData.h:2
const gsl::span< const char > & getBuffer() const
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
const T getValue(const int sec, const int globalPadInSector) const
Definition CalDet.h:160
Base Class for TPC clusterer.
Definition Clusterer.h:36
CalDet< float > * mPedestalObject
Pointer to the CalDet object for the pedestal subtraction.
Definition Clusterer.h:63
void process(gsl::span< o2::tpc::Digit const > const &digits, ConstMCLabelContainerView const &mcDigitTruth) override
void init()
initialize the clusterer from HwClustererParam
void finishProcess(gsl::span< o2::tpc::Digit const > const &digits, ConstMCLabelContainerView const &mcDigitTruth) override
int getNumberOfRows() const
Definition Mapper.h:297
int getNumberOfPadsInRowSector(int row) const
Definition Mapper.h:340
static Mapper & instance(const std::string mappingDir="")
Definition Mapper.h:44
int getNumberOfRowsRegion(int region) const
Definition Mapper.h:309
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLenum GLfloat param
Definition glcorearb.h:271
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
std::unique_ptr< const o2::dataformats::MCTruthContainer< MCLabel > > getLabels(framework::ProcessingContext &pc, std::string_view dataBind, EventType eventType=EventType::Standard)
Global TPC definitions and constants.
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:158
constexpr uint32_t HB
Definition Triggers.h:27
constexpr size_t max
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
vec clear()
std::vector< Digit > digits
std::vector< int > row