Project
Loading...
Searching...
No Matches
Digitizer.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
18
23
24#include <TCollection.h>
25#include <TFile.h>
26#include <TKey.h>
27#include <TRandom.h>
28
29#include <set>
30#include <string_view>
31#include <vector>
32#include <iostream>
33#include <numeric>
34#include <algorithm>
35#include <fairlogger/Logger.h>
36
37namespace o2::iotof
38{
39
40o2::iotof::Segmentation* Digitizer::sSegmentation = nullptr;
41//_______________________________________________________________________
43{
44 const int numberOfChips = mGeometry->getSize();
45 mChips.resize(numberOfChips);
46
47 const auto& specsConfig = ChipSpecificsParam::Instance();
48 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
49 const int nReadOutCols = specsConfig.NCols / digitizerParams.nColsPerGroup + 1;
50 for (int i = numberOfChips; i--;) {
51 mChips[i].setChipIndex(i);
56
62
63 // initialize the vector of TDC states
64 mChips[i].resizeTDCStates(nReadOutCols);
65 for (auto& tdcStates : mChips[i].getTDCStates()) {
66 tdcStates[0] = -999.f;
67 tdcStates[1] = -999.f;
68 }
69 }
70
71 LOG(info) << "Initializing IOTOF digitizer";
72 LOG(info) << " Time resolution: " << digitizerParams.timeResolution * 1e3 << " ps";
73 LOG(info) << " Charge threshold: " << digitizerParams.chargeThreshold << " electrons";
74 LOG(info) << " Continuous mode: " << (mContinuous ? "ON" : "OFF");
75
76 loadMap(mEfficiencyMap, digitizerParams.efficiencyMapPath, "hEfficiencyMap");
77 if (!mEfficiencyMap) {
78 LOG(info) << "No efficiency map loaded, using uniform efficiency: " << digitizerParams.efficiency * 100 << " %";
79 }
80
81 loadMap(mResolutionMap, digitizerParams.resolutionMapPath, "hSigmaPixel");
82 prepareScaledResolutionMap();
83 if (!mResolutionMap) {
84 LOG(info) << "No resolution map loaded, using uniform time resolution: " << digitizerParams.timeResolution * 1e3 << " ps";
85 }
86
87 loadMap(mTimeOfArrivalMap, digitizerParams.timeOfArrivalMapPath, "toa_pixel");
88 if (!mTimeOfArrivalMap) {
89 LOG(info) << "No time of arrival map loaded";
90 }
91
92 sSegmentation = o2::iotof::Segmentation::Instance();
93}
94
95//_______________________________________________________________________
96void Digitizer::process(const std::vector<o2::itsmft::Hit>* hits, int evID, int srcID)
97{
98 // Digitize hits from a single event
99 LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID;
100
101 if (!hits || hits->empty()) {
102 return;
103 }
104
105 // Sort hits by detector ID for better cache locality
106 std::vector<int> hitIdx(hits->size());
107 std::iota(hitIdx.begin(), hitIdx.end(), 0);
108 std::sort(hitIdx.begin(), hitIdx.end(),
109 [hits](int lhs, int rhs) {
110 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
111 });
112
113 // Process each hit
114 for (int i : hitIdx) {
115 processHit((*hits)[i], evID, srcID);
116 }
117
118 // In triggered mode, flush output after each event
119 if (!mContinuous) {
120 LOG(debug) << "Inner flushing for non-continuous mode";
122 }
123}
124
125//_______________________________________________________________________
126void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
127{
128 LOG(debug) << "\nProcessing hit with detector ID: " << hit.GetDetectorID() << ", track ID: " << hit.GetTrackID() << ", energy loss: " << hit.GetEnergyLoss() << " GeV, time: " << hit.GetTime() * sec2ns << " ns";
129 // Process a single hit and create a digit if it passes all cuts
130
131 // Get detector element ID
132 const int chipID = hit.GetDetectorID();
133 if (chipID < 0 || chipID >= mGeometry->getSize() || mGeometry->getSize() < 1) {
134 LOG(debug) << "Invalid detector ID: " << chipID << ", geometry size: " << mGeometry->getSize();
135 return; // invalid detector ID
136 }
137 const int subdetectorID = mGeometry->getIOTOFLayer(chipID);
138
139 auto& chip = mChips[chipID];
140 if (chip.isDisabled()) {
141 LOG(debug) << "Hit rejected because chip " << chipID << " is disabled";
142 return;
143 }
144
145 // Convert energy loss to charge (number of electrons)
146 float energyLoss = hit.GetEnergyLoss(); // in GeV
147 int charge = energyToCharge(energyLoss);
148 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
149 int electronsPerStep = static_cast<int>(charge / digitizerParams.nSimSteps);
150
151 // Apply charge threshold
152 if (charge < digitizerParams.chargeThreshold) {
153 LOG(debug) << "Hit rejected by charge threshold: " << charge << " < " << digitizerParams.chargeThreshold;
154 return;
155 }
156
157 // Get hit time and apply smearing
158 // Hit time is in seconds, convert to ns and add event time
159 double hitTime = hit.GetTime() * sec2ns; // convert to ns
160 double eventTimeInBC = mEventTime.getTimeOffsetWrtBC(); // event time wrt bc
161 double hitTimeWrtBC = hitTime + eventTimeInBC; // hit time wrt bc
162
163 // Create the digit with time information
164 o2::MCCompLabel label(hit.GetTrackID(), evID, srcID, false);
165 const int roFrameAbs = 0; // For now, we can set this to 0 or calculate based on time if needed
166 const int nROF = 1; // For now, we can assume the signal is contained in one ROF, this can be extended to multiple ROFs based on the time
167
168 float** respMatrix = nullptr;
169 float** avgHitLocalX = nullptr;
170 float** avgHitLocalZ = nullptr;
171 int rowStart = 0, colStart = 0, rowSpan = 0, colSpan = 0;
172 stepping(hit, respMatrix, avgHitLocalX, avgHitLocalZ, rowStart, colStart, rowSpan, colSpan);
173
174 float xPixelCenter = 0.0f, zPixelCenter = 0.0f;
175 for (int irow = rowSpan; irow--;) {
176 uint16_t rowIS = irow + rowStart;
177 for (int icol = colSpan; icol--;) {
178 uint16_t colIS = icol + colStart;
179 float nEleResp = respMatrix[irow][icol];
180 if (!nEleResp) {
181 continue;
182 }
183
184 // Apply efficiency cut based on the hit segment mean position relative to the pixel center
185 sSegmentation->detectorToLocal(rowIS, colIS, xPixelCenter, zPixelCenter, subdetectorID);
186 if (!isEfficient(avgHitLocalX[irow][icol] - xPixelCenter, avgHitLocalZ[irow][icol] - zPixelCenter)) {
187 LOG(debug) << "Hit rejected by efficiency cut at pixel (row,col) = (" << rowIS << ", " << colIS << ")";
188 continue;
189 }
190 double smearedTime = smearTime(hitTimeWrtBC, avgHitLocalX[irow][icol] - xPixelCenter, avgHitLocalZ[irow][icol] - zPixelCenter);
191
192 const int nElectronsSampled = gRandom->Poisson(electronsPerStep * nEleResp);
193 // Noise can be added here if needed
194
195 registerDigits(chip, roFrameAbs, smearedTime, nROF,
196 static_cast<uint16_t>(rowIS), static_cast<uint16_t>(colIS), nElectronsSampled, label);
197 }
198 }
199
200 for (int irow = 0; irow < rowSpan; ++irow) {
201 delete[] respMatrix[irow];
202 delete[] avgHitLocalX[irow];
203 delete[] avgHitLocalZ[irow];
204 }
205 delete[] respMatrix;
206 delete[] avgHitLocalX;
207 delete[] avgHitLocalZ;
208}
209
210void Digitizer::stepping(const o2::itsmft::Hit& hit, float**& respMatrix, float**& avgHitLocalX, float**& avgHitLocalZ, int& rowStart, int& colStart, int& rowSpan, int& colSpan)
211{
212 const int chipID = hit.GetDetectorID();
213 const auto& matrix = mGeometry->getMatrixL2G(chipID);
214 const int subdetectorID = mGeometry->getIOTOFLayer(chipID);
215
216 auto xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame
217 auto xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame
218
219 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
220 auto stepVector = (xyzPositionEnd - xyzPositionStart) / digitizerParams.nSimSteps;
221 xyzPositionStart = xyzPositionStart + stepVector * 0.5f; // center the start position in the middle of the step
222
223 rowStart = -1;
224 colStart = -1;
225 int rowEnd = -1, colEnd = -1, nSkip = 0, nSteps = digitizerParams.nSimSteps;
226 while (!sSegmentation->localToDetector(xyzPositionStart.X(), xyzPositionStart.Z(), rowStart, colStart, mGeometry->getIOTOFLayer(chipID))) {
227 if (++nSkip > digitizerParams.nSimSteps) { // additional check to add: should we exclude something?
228 LOG(debug) << "Hit position out of bounds for detector ID " << chipID;
229 return; // hit is outside the active area
230 }
231 xyzPositionStart += stepVector;
232 }
233
234 // Re-compute end position based on the step vector,
235 // to avoid issues due to floating-point arithmetic,
236 xyzPositionEnd = xyzPositionStart + stepVector * (nSteps - 1 - nSkip);
237 while (!sSegmentation->localToDetector(xyzPositionEnd.X(), xyzPositionEnd.Z(), rowEnd, colEnd, mGeometry->getIOTOFLayer(chipID))) {
238 if (++nSkip > digitizerParams.nSimSteps) { // additional check to add: should we exclude something?
239 LOG(debug) << "Hit position out of bounds for detector ID " << chipID;
240 return; // hit is outside the active area
241 }
242 xyzPositionEnd -= stepVector;
243 }
244
245 if (nSkip) {
246 nSteps -= nSkip;
247 }
248 if (rowStart > rowEnd) {
249 std::swap(rowStart, rowEnd);
250 }
251 if (colStart > colEnd) {
252 std::swap(colStart, colEnd);
253 }
254
255 // Expand the range to take into account the effects of charge sharing
256 rowStart -= digitizerParams.responseMatrixSize / 2;
257 rowEnd += digitizerParams.responseMatrixSize / 2;
258 rowStart = std::max(rowStart, 0);
259 colStart = std::max(colStart, 0);
260
261 const auto& specsConfig = ChipSpecificsParam::Instance();
262 rowEnd = std::min(rowEnd, (specsConfig.NRows) - 1);
263 colEnd = std::min(colEnd, (specsConfig.NCols) - 1);
264 rowSpan = rowEnd - rowStart + 1;
265 colSpan = colEnd - colStart + 1;
266 if (rowSpan <= 0 || colSpan <= 0) {
267 return;
268 }
269
270 respMatrix = new float*[rowSpan];
271 avgHitLocalX = new float*[rowSpan];
272 avgHitLocalZ = new float*[rowSpan];
273 for (int i = 0; i < rowSpan; ++i) {
274 respMatrix[i] = new float[colSpan]();
275 avgHitLocalX[i] = new float[colSpan]();
276 avgHitLocalZ[i] = new float[colSpan]();
277 }
278
279 if (!respMatrix || !avgHitLocalX || !avgHitLocalZ) {
280 return;
281 }
282
283 int rowPrev = -1, colPrev = -1, row = 0, col = 0, nSkipPassive = 0;
284 auto pixelStartPosLocal = xyzPositionStart;
285 auto pixelCurrentPosLocal = xyzPositionStart;
286 for (int iStep{0}; iStep < nSteps; ++iStep) {
287 pixelCurrentPosLocal = xyzPositionStart + iStep * stepVector;
288
289 // Step does not contribute if it is in the passive area
290 if (!sSegmentation->localToDetector(pixelCurrentPosLocal.X(), pixelCurrentPosLocal.Z(), row, col, subdetectorID)) {
291 LOG(debug) << "Step is in passive area: (" << pixelCurrentPosLocal.X() << ", " << pixelCurrentPosLocal.Z() << ") is outside the active area of chip " << subdetectorID;
292 nSkipPassive++;
293 continue;
294 }
295
296 // The step has reached another pixel, compute mean hit segment positions
297 // for pixel efficiency evaluation and reset the start position for the next pixel
298 // LOG(debug) << "iStep: " << iStep << ", Current pixel: (row,col) = (" << row << ", " << col << "), Previous pixel: (rowPrev,colPrev) = (" << rowPrev << ", " << colPrev << ")";
299 if (row != rowPrev || col != colPrev) {
300
301 // Finalize the previous pixel
302 if (rowPrev != -1 && colPrev != -1) {
303 const int irow = rowPrev - rowStart;
304 const int icol = colPrev - colStart;
305 avgHitLocalX[irow][icol] = 0.5f * (pixelStartPosLocal.X() + pixelCurrentPosLocal.X() - (nSkipPassive + 1) * stepVector.X());
306 avgHitLocalZ[irow][icol] = 0.5f * (pixelStartPosLocal.Z() + pixelCurrentPosLocal.Z() - (nSkipPassive + 1) * stepVector.Z());
307 pixelStartPosLocal = pixelCurrentPosLocal;
308 nSkipPassive = 0;
309 }
310
311 // Start the new pixel
312 rowPrev = row;
313 colPrev = col;
314 }
315
316 for (int irow = digitizerParams.responseMatrixSize; irow--;) {
317 int rowDest = row + irow - (digitizerParams.responseMatrixSize / 2) - rowStart; // destination row in the respMatrix
318 if (rowDest < 0 || rowDest >= rowSpan) {
319 continue;
320 }
321 for (int icol = digitizerParams.responseMatrixSize; icol--;) {
322 int colDest = col + icol - (digitizerParams.responseMatrixSize / 2) - colStart; // destination column in the respMatrix
323 if (colDest < 0 || colDest >= colSpan) {
324 continue;
325 }
326 respMatrix[rowDest][colDest] += 1.;
327 }
328 }
329 }
330
331 // Finalize the last pixel
332 if (rowPrev != -1 && colPrev != -1) {
333 const int irow = rowPrev - rowStart;
334 const int icol = colPrev - colStart;
335 // Sizes of avgHitLocalX, avgHitLocalZ
336 avgHitLocalX[irow][icol] = 0.5f * (pixelStartPosLocal.X() + pixelCurrentPosLocal.X() - nSkipPassive * stepVector.X());
337 avgHitLocalZ[irow][icol] = 0.5f * (pixelStartPosLocal.Z() + pixelCurrentPosLocal.Z() - nSkipPassive * stepVector.Z());
338 }
339}
340
341//_______________________________________________________________________
342double Digitizer::smearTime(double time, const float x, const float y) const
343{
344 // Apply Gaussian smearing to simulate detector time resolution
345 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
346
347 float resolution = digitizerParams.timeResolution;
348 if (mScaledResolutionMap) {
349 int bin = mScaledResolutionMap->FindBin(x * o2::iotof::Digitizer::cm2um, y * o2::iotof::Digitizer::cm2um);
350 resolution = mScaledResolutionMap->GetBinContent(bin);
351 LOG(debug) << "Time resolution map check: x=" << x * o2::iotof::Digitizer::cm2um << ", y=" << y * o2::iotof::Digitizer::cm2um << ", bin=" << bin << ", resolution=" << resolution;
352 }
353 float timeOfArrivalOffset = 0.;
354 if (mTimeOfArrivalMap) {
355 int bin = mTimeOfArrivalMap->FindBin(x * o2::iotof::Digitizer::cm2um, y * o2::iotof::Digitizer::cm2um);
356 timeOfArrivalOffset = mTimeOfArrivalMap->GetBinContent(bin) * o2::iotof::Digitizer::ps2ns; // convert to ns
357 LOG(debug) << "Time of arrival map check: x=" << x * o2::iotof::Digitizer::cm2um << ", y=" << y * o2::iotof::Digitizer::cm2um << ", bin=" << bin << ", time offset=" << timeOfArrivalOffset;
358 }
359
360 if (digitizerParams.timeResolution > 0) {
361 return time + gRandom->Gaus(timeOfArrivalOffset, resolution);
362 }
363 return time;
364}
365
366//_______________________________________________________________________
367int Digitizer::energyToCharge(float energyLoss) const
368{
369 // Convert energy loss (GeV) to number of electrons
370 // Typical value: 3.6 eV per electron-hole pair in silicon
371 // energyLoss is in GeV, energyToNElectrons is electrons per GeV
372 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
373 return static_cast<int>(energyLoss * digitizerParams.energyToNElectrons);
374}
375
376//_______________________________________________________________________
377
378void Digitizer::loadMap(TH2D*& map, const std::string& path, const char* mapName)
379{
380 // Load a map either from CCDB (path prefixed with "ccdb://") or from a ROOT file
381 // (anything TFile::Open understands: local path, alien://, root://, http://, ...)
382 static constexpr std::string_view ccdbPrefix = "ccdb://";
383
384 if (path.empty()) {
385 return;
386 }
387
388 TH2D* rawMap = nullptr;
389 TFile* file = nullptr;
390
391 if (path.rfind(ccdbPrefix, 0) == 0) {
392 const std::string ccdbPath = path.substr(ccdbPrefix.size());
393 LOG(info) << "Loading " << mapName << " from CCDB: " << ccdbPath;
394 rawMap = o2::ccdb::BasicCCDBManager::instance().get<TH2D>(ccdbPath); // owned by the CCDB manager
395 if (!rawMap) {
396 LOG(error) << "Failed to retrieve " << mapName << " from CCDB path: " << ccdbPath;
397 return;
398 }
399 } else {
400 LOG(info) << "Loading " << mapName << " from file: " << path;
401 file = TFile::Open(path.c_str());
402 if (!file || !file->IsOpen()) {
403 LOG(error) << "Failed to open file: " << path;
404 delete file;
405 return;
406 }
407 rawMap = dynamic_cast<TH2D*>(file->Get(mapName));
408 if (!rawMap) {
409 LOG(error) << "Failed to retrieve " << mapName << " from file: " << path;
410 LOG(error) << "Available keys in the file:";
411 TIter next(file->GetListOfKeys());
412 TKey* key;
413 while ((key = dynamic_cast<TKey*>(next()))) {
414 LOG(error) << " " << key->GetName() << " (" << key->GetClassName() << ")";
415 }
416 file->Close();
417 delete file;
418 return;
419 }
420 }
421
422 map = dynamic_cast<TH2D*>(rawMap->Clone());
423 map->SetDirectory(nullptr); // Detach from file to avoid deletion when file is closed
424 LOG(info) << "Loaded " << mapName << " (" << map->GetNbinsX() << " x " << map->GetNbinsY() << " bins)";
425
426 if (file) {
427 file->Close();
428 delete file;
429 }
430}
431
432void Digitizer::prepareScaledResolutionMap()
433{
434 if (!mResolutionMap) {
435 LOG(warn) << "No resolution map available to prepare scaled resolution map.";
436 return;
437 }
438
439 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
440 const float nominalTimeResolution = digitizerParams.timeResolution;
441 const float minimumResolution = mResolutionMap->GetMinimum();
442 if (minimumResolution <= 0) {
443 LOG(warn) << "Minimum resolution in the map is non-positive, cannot prepare scaled resolution map.";
444 return;
445 }
446
447 mScaledResolutionMap = dynamic_cast<TH2D*>(mResolutionMap->Clone("hScaledResolutionMap"));
448 mScaledResolutionMap->SetDirectory(nullptr); // Detach from file to avoid deletion when file is closed
449
450 for (int binX = 1; binX <= mScaledResolutionMap->GetNbinsX(); ++binX) {
451 for (int binY = 1; binY <= mScaledResolutionMap->GetNbinsY(); ++binY) {
452 float originalValue = mScaledResolutionMap->GetBinContent(binX, binY);
453 float scalingValue = originalValue / minimumResolution;
454 mScaledResolutionMap->SetBinContent(binX, binY, scalingValue * nominalTimeResolution);
455 }
456 }
457}
458
459//_______________________________________________________________________
460bool Digitizer::isEfficient(const float x, const float z) const
461{
462 // Apply efficiency cut using random number
463 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
464 if (mEfficiencyMap) {
465 // int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um);
466 int bin = mEfficiencyMap->FindBin(x * o2::iotof::Digitizer::cm2um, z * o2::iotof::Digitizer::cm2um);
467 float efficiency = mEfficiencyMap->GetBinContent(bin);
468 LOG(debug) << "Efficiency map check: x=" << x * o2::iotof::Digitizer::cm2um << ", z=" << z * o2::iotof::Digitizer::cm2um << ", bin=" << bin << ", efficiency=" << efficiency;
469 return gRandom->Uniform() < efficiency;
470 }
471 return gRandom->Uniform() < digitizerParams.efficiency;
472}
473
474//_______________________________________________________________________
476{
477 LOG(info) << "Filling output container with digits from chips";
478 LOG(debug) << "Number of chips: " << mChips.size();
479
480 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
481
483 rof.setFirstEntry(mDigits->size()); // index of the first digit
484
485 const auto* extraLabelBuffer = mExtraLabelBuffer.empty() ? nullptr : mExtraLabelBuffer.front().get();
486 for (auto& chip : mChips) {
487
488 if (chip.isDisabled()) {
489 continue;
490 }
491
493
494 if (chip.isEmpty()) {
495 continue;
496 }
497
498 auto& chipDigits = chip.getDigits();
499 auto& tdcStates = chip.getTDCStates();
500
501 for (const auto& [key, digit] : chipDigits) {
502
503 if (digit.getCharge() < digitizerParams.chargeThreshold) {
504 continue; // skip digits below threshold
505 }
506
507 const int colInGroup = digit.getColumn() / digitizerParams.nColsPerGroup;
508 const double digitTime = digit.getTime();
509 if (digitTime - tdcStates[colInGroup][0] < digitizerParams.tdcBusyTime && digitTime - tdcStates[colInGroup][1] < digitizerParams.tdcBusyTime) {
510 // TODO: improve labels treatment if multiple hits cross the same pixel during
511 continue; // both tdc pairs are busy
512 } else if (digitTime - tdcStates[colInGroup][0] > digitizerParams.tdcBusyTime) {
513 tdcStates[colInGroup][0] = digitTime;
514 } else if (digitTime - tdcStates[colInGroup][1] > digitizerParams.tdcBusyTime) {
515 tdcStates[colInGroup][1] = digitTime;
516 }
517
518 int digitID = mDigits->size();
519 mDigits->emplace_back(digit.getChipIndex(), digit.getRow(), digit.getColumn(), digit.getCharge(), digit.getTime(), digit.getBc(), digit.getTdc());
520 if (mMCLabels) {
521 mMCLabels->addElement(digitID, digit.getLabel().mLabel);
522 }
523 auto labelRef = digit.getLabel();
524
525 while (mMCLabels && extraLabelBuffer != nullptr && labelRef.mNext >= 0) {
526 labelRef = (*extraLabelBuffer)[labelRef.mNext];
527 mMCLabels->addElement(digitID, labelRef.mLabel);
528 }
529 }
530 chipDigits.clear(); // clear chip digits after copying to output
531 }
532
533 rof.setNEntries(mDigits->size() - rof.getFirstEntry()); // number of digits
534 rof.setBCData(mContinuous ? mROFRecordIR : mEventTime);
535 mROFRecords->push_back(rof);
536 LOG(debug) << "Created ROF record with " << mDigits->size() << " digits";
537
538 // extraLabelBuffer.clear(); // clear buffer for extra labels
539 // mExtraLabelBuffer.emplace_back(mExtraLabelBuffer.front().release()); // move current buffer to the end
540 // mExtraLabelBuffer.pop_front();
541}
542
543void Digitizer::registerDigits(Chip& chip, uint32_t roFrame, double time, int nROF,
544 uint16_t row, uint16_t col, int nElectrons, o2::MCCompLabel& label)
545{
546 // (void)nROF;
547
548 const auto& digitizerParams = o2::iotof::DPLDigitizerParam::Instance();
549
550 uint64_t nbc = static_cast<uint64_t>(time / o2::constants::lhc::LHCBunchSpacingNS);
551 int tdc = int((time - nbc * o2::constants::lhc::LHCBunchSpacingNS) / digitizerParams.tdcBin);
552 nbc += mEventTime.toLong();
553
554 double absoluteTime = tdc * digitizerParams.tdcBin + nbc * o2::constants::lhc::LHCBunchSpacingNS;
555
556 auto key = o2::iotof::Digit::getOrderingKey(nbc, tdc, row, col);
557 o2::iotof::LabeledDigit* existingDigit = chip.findDigit(key);
558
559 if (!existingDigit) {
560 // No existing digit, create a new one
561 chip.addDigit(row, col, nElectrons, absoluteTime, nbc, tdc, label);
562 } else {
563 // Digit already exists, update charge and labels
564 const int storedCharge = existingDigit->getCharge();
565 existingDigit->setCharge(storedCharge + nElectrons);
566 existingDigit->setTime(std::min(existingDigit->getTime(), time));
567 if (existingDigit->getLabel().mLabel == label) {
568 return; // don't store the same label twice
569 }
570 std::vector<o2::iotof::McLabelRef>* extra = getExtraLabelBuffer(roFrame);
571 auto labelRef = existingDigit->getLabel();
572 const auto next = static_cast<int>(extra->size());
573 extra->emplace_back(label, labelRef.mNext);
574 labelRef.mNext = next;
575 existingDigit->setLabel(labelRef);
576 }
577 LOG(debug) << "Registered digit at (row,col) = (" << row << ", " << col << ") with charge: " << nElectrons << ", time: " << time << ", nbc: " << nbc << ", tdc: " << tdc;
578}
579
580} // namespace o2::iotof
std::ostringstream debug
int16_t charge
Definition RawEventData.h:5
int16_t time
Definition RawEventData.h:4
int32_t i
std::string ccdbPath(const std::string badChannelType)
uint32_t col
Definition RawData.h:4
Definition of the ALICE3 TOF digitizer.
StringRef key
int GetTrackID() const
Definition BaseHits.h:30
V GetEnergyLoss() const
Definition BaseHits.h:103
math_utils::Point3D< T > GetPos() const
Definition BaseHits.h:67
E GetTime() const
Definition BaseHits.h:71
unsigned short GetDetectorID() const
Definition BaseHits.h:73
static BasicCCDBManager & instance()
T * get(std::string const &path)
retrieve an object of type T from CCDB as stored under path; will use the timestamp member
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
const Mat3D & getMatrixL2G(int sensID) const
Container for similated points connected to a given TOF Chip This will be used in order to allow a mo...
Definition Chip.h:41
void addDigit(UShort_t row, UShort_t col, Int_t charge, double time, ULong64_t bc, Int_t tdc, o2::MCCompLabel label)
Definition Chip.cxx:35
o2::iotof::LabeledDigit * findDigit(DigitKey key)
reset points container
Definition Chip.h:94
double getTime() const
Definition Digit.h:52
void setTime(double time)
Definition Digit.h:49
static DigitKey getOrderingKey(ULong64_t bc, UInt_t tdc, uint16_t row, uint16_t col)
Definition Digit.h:56
void init()
Initialize the digitizer.
Definition Digitizer.cxx:42
void fillOutputContainer()
Flush the output container.
void process(const std::vector< o2::itsmft::Hit > *hits, int evID, int srcID)
Steer conversion of hits to digits.
Definition Digitizer.cxx:96
int getIOTOFLayer(int index) const
McLabelRef getLabel() const
Definition Digit.h:90
void setLabel(McLabelRef label)
Definition Digit.h:89
Segmentation and response for pixels in inner and outer TOF of the ALICE 3 apparatus.
bool detectorToLocal(L row, L col, T &xRow, T &zCol, const int subDetectorID) const
bool localToDetector(float x, float z, int &iRow, int &iCol, const int subDetectorID) const
void setCharge(Int_t charge)
Set the charge of the digit.
Definition Digit.h:62
Int_t getCharge() const
Get the accumulated charged of the digit.
Definition Digit.h:49
math_utils::Point3D< Float_t > GetPosStart() const
Definition Hit.h:60
void setNEntries(int n)
Definition ROFRecord.h:48
void setBCData(const BCData &bc)
Definition ROFRecord.h:44
void setFirstEntry(int idx)
Definition ROFRecord.h:47
int getFirstEntry() const
Definition ROFRecord.h:63
GLint GLenum GLint x
Definition glcorearb.h:403
GLint y
Definition glcorearb.h:270
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
int32_t const char * file
int mNext
eventual next contribution to the same pixel
Definition Digit.h:76
o2::MCCompLabel mLabel
hit label
Definition Digit.h:75
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row