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
13
20
21#include <TRandom.h>
22// #include <climits>
23#include <vector>
24#include <iostream>
25#include <numeric>
26#include <fairlogger/Logger.h> // for LOG
27
29using o2::trk::Hit;
31
32using namespace o2::trk;
33using namespace o2::itsmft;
34// using namespace o2::base;
35//_______________________________________________________________________
36void Digitizer::init()
37{
38 LOG(info) << "Initializing digitizer";
39 mNumberOfChips = mGeometry->getNumberOfChips();
40 mChips.resize(mNumberOfChips);
41 for (int i = mNumberOfChips; i--;) {
42 mChips[i].setChipIndex(i);
43 if (mNoiseMap) {
44 mChips[i].setNoiseMap(mNoiseMap);
45 }
46 if (mDeadChanMap) {
47 mChips[i].disable(mDeadChanMap->isFullChipMasked(i));
48 mChips[i].setDeadChanMap(mDeadChanMap);
49 }
50 }
51
52 // setting the correct response function (for the moment, for both VD and MLOT the same response function is used)
53 mChipSimResp = mParams.getAlpSimResponse();
54 mChipSimRespVD = mChipSimResp;
55 mChipSimRespMLOT = mChipSimResp;
56
58 // TODO: adjust Y shift when the geometry is improved
59 LOG(info) << " Depth max VD: " << mChipSimRespVD->getDepthMax();
60 LOG(info) << " Depth min VD: " << mChipSimRespVD->getDepthMin();
61
62 LOG(info) << " Depth max MLOT: " << mChipSimRespMLOT->getDepthMax();
63 LOG(info) << " Depth min MLOT: " << mChipSimRespMLOT->getDepthMin();
64
65 float thicknessVD = 0.0095; // cm --- hardcoded based on geometry currently present
66 float thicknessMLOT = o2::trk::SegmentationChip::SiliconThicknessMLOT; // 0.01 cm = 100 um --- based on geometry currently present
67
68 LOG(info) << "Using response name: " << mRespName;
69 mSimRespOrientation = false;
70
71 if (mRespName == "APTS") { // default
74 mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -45. Must add ~10 um (= max depth) to match the APTS response.
77 mSimRespOrientation = true;
78 } else if (mRespName == "ALICE3") {
81 mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -95 um. Must align the start of epi layer with the response function.
84 } else {
85 LOG(fatal) << "Unknown response name: " << mRespName;
86 }
87
88 mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - thicknessMLOT / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response
89
90 // importing the parameters from DPLDigitizerParam.h
92
93 LOGP(info, "TRK Digitizer is initialised.");
94 mParams.print();
95 LOGP(info, "VD shift = {} ; ML/OT shift = {} = {} - {}", mSimRespVDShift, mSimRespMLOTShift, mChipSimRespMLOT->getDepthMax(), thicknessMLOT / 2.f);
96 LOGP(info, "VD pixel scale on x = {} ; z = {}", mSimRespVDScaleX, mSimRespVDScaleZ);
97 LOGP(info, "ML/OT pixel scale on x = {} ; z = {}", mSimRespMLOTScaleX, mSimRespMLOTScaleZ);
98 LOGP(info, "Response orientation: {}", mSimRespOrientation ? "flipped" : "normal");
99
100 mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR();
101}
102
104{
105 if (mGeometry->getSubDetID(chipID) == 0) {
106 return mChipSimRespVD;
107 }
108
109 else if (mGeometry->getSubDetID(chipID) == 1) {
110 return mChipSimRespMLOT;
111 }
112 return nullptr;
113};
114
115//_______________________________________________________________________
116void Digitizer::process(const std::vector<Hit>* hits, int evID, int srcID)
117{
118 // digitize single event, the time must have been set beforehand
119
120 LOG(info) << " Digitizing " << mGeometry->getName() << " (ID: " << mGeometry->getDetID()
121 << ") hits of event " << evID << " from source " << srcID
122 << " at time " << mEventTime.getTimeNS() << " ROFrame = " << mNewROFrame
123 << " cont.mode: " << isContinuous()
124 << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax;
125
126 std::cout << "Printing segmentation info: " << std::endl;
128
129 // // is there something to flush ?
130 if (mNewROFrame > mROFrameMin) {
131 fillOutputContainer(mNewROFrame - 1); // flush out all frames preceding the new one
132 }
133
134 int nHits = hits->size();
135 std::vector<int> hitIdx(nHits);
136 std::iota(std::begin(hitIdx), std::end(hitIdx), 0);
137 // sort hits to improve memory access
138 std::sort(hitIdx.begin(), hitIdx.end(),
139 [hits](auto lhs, auto rhs) {
140 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
141 });
142 LOG(info) << "Processing " << nHits << " hits";
143 for (int i : hitIdx) {
144 processHit((*hits)[i], mROFrameMax, evID, srcID);
145 }
146
147 // in the triggered mode store digits after every MC event
148 // TODO: in the real triggered mode this will not be needed, this is actually for the
149 // single event processing only
150 if (!mParams.isContinuous()) {
151 fillOutputContainer(mROFrameMax);
152 }
153}
154
155//_______________________________________________________________________
157{
158 LOG(info) << "Setting event time to " << irt.getTimeNS() << " ns after orbit 0 bc 0";
159 // assign event time in ns
160 mEventTime = irt;
161 if (!mParams.isContinuous()) {
162 mROFrameMin = 0; // in triggered mode reset the frame counters
163 mROFrameMax = 0;
164 }
165 // RO frame corresponding to provided time
166 mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?)
167 if (mParams.isContinuous()) {
168 auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF);
169
170 if (mCollisionTimeWrtROF < 0 && nbc > 0) {
171 nbc--;
172 }
173
174 mNewROFrame = nbc / mParams.getROFrameLengthInBC();
175
176 LOG(debug) << " NewROFrame " << mNewROFrame << " = " << nbc << "/" << mParams.getROFrameLengthInBC() << " (nbc/mParams.getROFrameLengthInBC()";
177
178 // in continuous mode depends on starts of periodic readout frame
179 mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS;
180 } else {
181 mNewROFrame = 0;
182 }
183
184 if (mNewROFrame < mROFrameMin) {
185 LOG(error) << "New ROFrame " << mNewROFrame << " (" << irt << ") precedes currently cashed " << mROFrameMin;
186 throw std::runtime_error("deduced ROFrame precedes already processed one");
187 }
188
189 if (mParams.isContinuous() && mROFrameMax < mNewROFrame) {
190 mROFrameMax = mNewROFrame - 1; // all frames up to this are finished
191 }
192}
193
194//_______________________________________________________________________
195void Digitizer::fillOutputContainer(uint32_t frameLast)
196{
197 // // fill output with digits from min.cached up to requested frame, generating the noise beforehand
198 if (frameLast > mROFrameMax) {
199 frameLast = mROFrameMax;
200 }
201 // // make sure all buffers for extra digits are created up to the maxFrame
202 getExtraDigBuffer(mROFrameMax);
203 LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":"
204 << frameLast;
205
207
208 // we have to write chips in RO increasing order, therefore have to loop over the frames here
209 for (; mROFrameMin <= frameLast; mROFrameMin++) {
210 rcROF.setROFrame(mROFrameMin);
211 rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits
212
213 auto& extra = *(mExtraBuff.front().get());
214 for (auto& chip : mChips) {
215 if (chip.isDisabled()) {
216 continue;
217 }
218 chip.addNoise(mROFrameMin, mROFrameMin, &mParams, mGeometry->getSubDetID(chip.getChipIndex()), mGeometry->getLayer(chip.getChipIndex()));
219 auto& buffer = chip.getPreDigits();
220 if (buffer.empty()) {
221 continue;
222 }
223 auto itBeg = buffer.begin();
224 auto iter = itBeg;
225 ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1; // fetch digits with key below that
226 for (; iter != buffer.end(); ++iter) {
227 if (iter->first > maxKey) {
228 break; // is the digit ROFrame from the key > the max requested frame
229 }
230 auto& preDig = iter->second; // preDigit
231 if (preDig.charge >= mParams.getChargeThreshold()) {
232 int digID = mDigits->size();
233 mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge);
234 LOG(debug) << "Adding digit ID: " << digID << " with chipID: " << chip.getChipIndex() << ", row: " << preDig.row << ", col: " << preDig.col << ", charge: " << preDig.charge;
235 mMCLabels->addElement(digID, preDig.labelRef.label);
236 auto& nextRef = preDig.labelRef; // extra contributors are in extra array
237 while (nextRef.next >= 0) {
238 nextRef = extra[nextRef.next];
239 mMCLabels->addElement(digID, nextRef.label);
240 }
241 }
242 }
243 buffer.erase(itBeg, iter);
244 }
245 // finalize ROF record
246 rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits
247 if (isContinuous()) {
248 rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC());
249 } else {
250 rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay?
251 }
252 if (mROFRecords) {
253 mROFRecords->push_back(rcROF);
254 }
255 extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame
256 // and move it as a new slot in the end
257 mExtraBuff.emplace_back(mExtraBuff.front().release());
258 mExtraBuff.pop_front();
259 }
260}
261
262//_______________________________________________________________________
263void Digitizer::processHit(const o2::trk::Hit& hit, uint32_t& maxFr, int evID, int srcID)
264{
265 int chipID = hit.GetDetectorID();
266 int subDetID = mGeometry->getSubDetID(chipID);
267
268 int layer = mGeometry->getLayer(chipID);
269 int disk = mGeometry->getDisk(chipID);
270
271 if (disk != -1) {
272 LOG(debug) << "Skipping disk " << disk;
273 return; // skipping hits on disks for the moment
274 }
275
276 LOG(debug) << "Processing hit for chip " << chipID;
277 auto& chip = mChips[chipID];
278 if (chip.isDisabled()) {
279 LOG(debug) << "Skipping disabled chip " << chipID;
280 return;
281 }
282 float timeInROF = hit.GetTime() * sec2ns;
283 LOG(debug) << "Hit time: " << timeInROF << " ns";
284 if (timeInROF > 20e3) {
285 const int maxWarn = 10;
286 static int warnNo = 0;
287 if (warnNo < maxWarn) {
288 LOG(warning) << "Ignoring hit with time_in_event = " << timeInROF << " ns"
289 << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)");
290 }
291 return;
292 }
293 if (isContinuous()) {
294 timeInROF += mCollisionTimeWrtROF;
295 }
296 if (mIsBeforeFirstRO && timeInROF < 0) {
297 // disregard this hit because it comes from an event byefore readout starts and it does not effect this RO
298 LOG(debug) << "Ignoring hit with timeInROF = " << timeInROF;
299 return;
300 }
301
302 // calculate RO Frame for this hit
303 if (timeInROF < 0) {
304 timeInROF = 0.;
305 }
306 float tTot = mParams.getSignalShape().getMaxDuration();
307 // frame of the hit signal start wrt event ROFrame
308 int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv());
309 // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame
310 uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel;
311 int nFrames = roFrameRelMax + 1 - roFrameRel;
312 uint32_t roFrameMax = mNewROFrame + roFrameRelMax;
313 if (roFrameMax > maxFr) {
314 maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter
315 }
316
317 // here we start stepping in the depth of the sensor to generate charge diffusion
318 float nStepsInv = mParams.getNSimStepsInv();
319 int nSteps = mParams.getNSimSteps();
320
321 const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID());
322 // matrix.print();
323
325 math_utils::Vector3D<float> xyzLocS(matrix ^ (hit.GetPosStart())); // start position in sensor frame
326 math_utils::Vector3D<float> xyzLocE(matrix ^ (hit.GetPos())); // end position in sensor frame
327
328 if (subDetID == 0) { // VD - need to take into account for the curved layers. TODO: consider the disks
329 // transform the point on the curved surface to a flat one
330 math_utils::Vector2D<float> xyFlatS = Segmentation::curvedToFlat(layer, xyzLocS.x(), xyzLocS.y());
331 math_utils::Vector2D<float> xyFlatE = Segmentation::curvedToFlat(layer, xyzLocE.x(), xyzLocE.y());
332 LOG(debug) << "Called curved to flat: " << xyzLocS.x() << " -> " << xyFlatS.x() << ", " << xyzLocS.y() << " -> " << xyFlatS.y();
333 // update the local coordinates with the flattened ones
334 xyzLocS.SetXYZ(xyFlatS.x(), xyFlatS.y(), xyzLocS.Z());
335 xyzLocE.SetXYZ(xyFlatE.x(), xyFlatE.y(), xyzLocE.Z());
336 }
337
338 // std::cout<<"Printing example of point in 0.35 0.35 0 in global frame: "<<std::endl;
339 // math_utils::Point3D<float> examplehitGlob(0.35, 0.35, 0);
340 // math_utils::Vector3D<float> exampleLoc(matrix ^ (examplehitGlob)); // start position in sensor frame
341 // std::cout<< "Example hit in local frame: " << exampleLoc << std::endl;
342 // std::cout<<"Going back to glob coordinates: " << (matrix * exampleLoc) << std::endl;
343
345 step -= xyzLocS;
346 step *= nStepsInv; // position increment at each step
347 // the electrons will injected in the middle of each step
348 // starting from the middle of the first step
349 math_utils::Vector3D<float> stepH(step * 0.5);
350 xyzLocS += stepH;
351 xyzLocE -= stepH;
352
353 LOG(debug) << "Step into the sensitive volume: " << step << ". Number of steps: " << nSteps;
354 int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0;
355
357 // get entrance pixel row and col
358 while (!Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS, subDetID, layer, disk)) { // guard-ring ?
359 if (++nSkip >= nSteps) {
360 LOG(debug) << "Did not enter to sensitive matrix, " << nSkip << " >= " << nSteps;
361 return; // did not enter to sensitive matrix
362 }
363 xyzLocS += step;
364 }
365
366 // get exit pixel row and col
367 while (!Segmentation::localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE, subDetID, layer, disk)) {
368 if (++nSkip >= nSteps) {
369 LOG(debug) << "Did not enter to sensitive matrix, " << nSkip << " >= " << nSteps;
370 return; // did not enter to sensitive matrix
371 }
372 xyzLocE -= step;
373 }
374
375 int nCols = getNCols(subDetID, layer);
376 int nRows = getNRows(subDetID, layer);
377
378 // estimate the limiting min/max row and col where the non-0 response is possible
379 if (rowS > rowE) {
380 std::swap(rowS, rowE);
381 }
382 if (colS > colE) {
383 std::swap(colS, colE);
384 }
385 rowS -= AlpideRespSimMat::NPix / 2;
386 rowE += AlpideRespSimMat::NPix / 2;
387 if (rowS < 0) {
388 rowS = 0;
389 }
390 if (rowE >= nRows) {
391 rowE = nRows - 1;
392 }
393 colS -= AlpideRespSimMat::NPix / 2;
394 colE += AlpideRespSimMat::NPix / 2;
395 if (colS < 0) {
396 colS = 0;
397 }
398 if (colE >= nCols) {
399 colE = nCols - 1;
400 }
401 int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1; // size of plaquet where some response is expected
402
403 float respMatrix[rowSpan][colSpan]; // response accumulated here
404 std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f);
405
406 float nElectrons = hit.GetEnergyLoss() * mParams.getEnergyToNElectrons(); // total number of deposited electrons
407 nElectrons *= nStepsInv; // N electrons injected per step
408 if (nSkip) {
409 nSteps -= nSkip;
410 }
411
412 int rowPrev = -1, colPrev = -1, row, col;
413 float cRowPix = 0.f, cColPix = 0.f; // local coordinate of the current pixel center
414
415 const o2::trk::ChipSimResponse* resp = getChipResponse(chipID);
416 // std::cout << "Printing chip response:" << std::endl;
417 // resp->print();
418
419 // take into account that the ChipSimResponse depth defintion has different min/max boundaries
420 // although the max should coincide with the surface of the epitaxial layer, which in the chip
421 // local coordinates has Y = +SensorLayerThickness/2
422 // LOG(info)<<"SubdetID = " << subDetID<< " shift: "<<mSimRespVDShift<<" or "<<mSimRespMLOTShift;
423 // LOG(info)<< " Before shift: S = " << xyzLocS.Y()*1e4 << " E = " << xyzLocE.Y()*1e4;
424 xyzLocS.SetY(xyzLocS.Y() + ((subDetID == 0) ? mSimRespVDShift : mSimRespMLOTShift));
425 // LOG(info)<< " After shift: S = " << xyzLocS.Y()*1e4 << " E = " << xyzLocE.Y()*1e4;
426
427 // collect charge in every pixel which might be affected by the hit
428 for (int iStep = nSteps; iStep--;) {
429 // Get the pixel ID
430 Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col, subDetID, layer, disk);
431 if (row != rowPrev || col != colPrev) { // update pixel and coordinates of its center
432 if (!Segmentation::detectorToLocal(row, col, cRowPix, cColPix, subDetID, layer, disk)) {
433 continue; // should not happen
434 }
435 rowPrev = row;
436 colPrev = col;
437 }
438 bool flipCol = false, flipRow = false;
439 // note that response needs coordinates along column row (locX) (locZ) then depth (locY)
440 float rowMax{}, colMax{};
441 const AlpideRespSimMat* rspmat{nullptr};
442 if (subDetID == 0) { // VD
443 rowMax = 0.5f * Segmentation::PitchRowVD * mSimRespVDScaleX;
444 colMax = 0.5f * Segmentation::PitchColVD * mSimRespVDScaleZ;
445 rspmat = resp->getResponse(mSimRespVDScaleX * (xyzLocS.X() - cRowPix), mSimRespVDScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax);
446 } else { // ML/OT
447 rowMax = 0.5f * Segmentation::PitchRowMLOT * mSimRespMLOTScaleX;
448 colMax = 0.5f * Segmentation::PitchColMLOT * mSimRespMLOTScaleZ;
449 rspmat = resp->getResponse(mSimRespMLOTScaleX * (xyzLocS.X() - cRowPix), mSimRespMLOTScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax);
450 }
451
452 xyzLocS += step;
453
454 if (rspmat == nullptr) {
455 LOG(debug) << "Error in rspmat for step " << iStep << " / " << nSteps;
456 continue;
457 }
458 // LOG(info) << "rspmat valid! for step " << iStep << " / " << nSteps << ", (row,col) = (" << row << "," << col << ")";
459 // LOG(info) << "rspmat valid! for step " << iStep << " / " << nSteps << " Y= " << xyzLocS.Y()*1e4 << " , (row,col) = (" << row << "," << col << ")";
460 // rspmat->print(); // print the response matrix for debugging
461
462 for (int irow = AlpideRespSimMat::NPix; irow--;) {
463 int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix
464 if (rowDest < 0 || rowDest >= rowSpan) {
465 continue;
466 }
467 for (int icol = AlpideRespSimMat::NPix; icol--;) {
468 int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix
469 if (colDest < 0 || colDest >= colSpan) {
470 continue;
471 }
472 respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, mSimRespOrientation ? !flipRow : flipRow, flipCol);
473 }
474 }
475 }
476
477 // fire the pixels assuming Poisson(n_response_electrons)
478 o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false);
479 auto roFrameAbs = mNewROFrame + roFrameRel;
480 LOG(debug) << "\nSpanning through rows and columns; rowspan = " << rowSpan << " colspan = " << colSpan << " = " << colE << " - " << colS << " +1 ";
481 for (int irow = rowSpan; irow--;) { // irow ranging from 4 to 0
482 uint16_t rowIS = irow + rowS; // row distant irow from the row of the hit start
483 for (int icol = colSpan; icol--;) { // icol ranging from 4 to 0
484 float nEleResp = respMatrix[irow][icol]; // value of the probability of the response in this pixel
485 if (nEleResp <= 1.e-36) {
486 continue;
487 }
488 LOG(debug) << "nEleResp: value " << nEleResp << " for pixel " << irow << " " << icol;
489 int nEle = gRandom->Poisson(nElectrons * nEleResp); // total charge in given pixel = number of electrons generated in the hit multiplied by the probability of being detected in their position
490 LOG(debug) << "Charge detected in the pixel: " << nEle << " for pixel " << irow << " " << icol;
491 // ignore charge which have no chance to fire the pixel
492 if (nEle < mParams.getMinChargeToAccount()) {
493 LOG(debug) << "Ignoring pixel with nEle = " << nEle << " < min charge to account "
494 << mParams.getMinChargeToAccount() << " for pixel " << irow << " " << icol;
495 continue;
496 }
497
498 uint16_t colIS = icol + colS; // col distant icol from the col of the hit start
499 if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) {
500 continue;
501 }
502 if (mDeadChanMap && mDeadChanMap->isNoisy(chipID, rowIS, colIS)) {
503 continue;
504 }
505 registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl);
506 }
507 }
508}
509
510//________________________________________________________________________________
511void Digitizer::registerDigits(o2::trk::ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF,
512 uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl)
513{
514 // Register digits for given pixel, accounting for the possible signal contribution to
515 // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame
516 // In every ROFrame we check the collected signal during strobe
517 LOG(debug) << "Registering digits for chip " << chip.getChipIndex() << " at ROFrame " << roFrame
518 << " row " << row << " col " << col << " nEle " << nEle << " label " << lbl;
519 float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start
520 for (int i = 0; i < nROF; i++) { // loop on all the ROFs occupied by the same signal to calculate the charge accumulated in that ROF
521 uint32_t roFr = roFrame + i;
522 int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength());
523 tStrobe += mParams.getROFrameLength(); // for the next ROF
524
525 // discard too small contributions, they have no chance to produce a digit
526 if (nEleROF < mParams.getMinChargeToAccount()) {
527 continue;
528 }
529 if (roFr > mEventROFrameMax) {
530 mEventROFrameMax = roFr;
531 }
532 if (roFr < mEventROFrameMin) {
533 mEventROFrameMin = roFr;
534 }
535 auto key = chip.getOrderingKey(roFr, row, col);
537 if (!pd) {
538 chip.addDigit(key, roFr, row, col, nEleROF, lbl);
539 LOG(debug) << "Added digit with key: " << key << " ROF: " << roFr << " row: " << row << " col: " << col << " charge: " << nEleROF;
540 } else { // there is already a digit at this slot, account as PreDigitExtra contribution
541 LOG(debug) << "Added to pre-digit with key: " << key << " ROF: " << roFr << " row: " << row << " col: " << col << " charge: " << nEleROF;
542 pd->charge += nEleROF;
543 if (pd->labelRef.label == lbl) { // don't store the same label twice
544 continue;
545 }
546 ExtraDig* extra = getExtraDigBuffer(roFr);
547 int& nxt = pd->labelRef.next;
548 bool skip = false;
549 while (nxt >= 0) {
550 if ((*extra)[nxt].label == lbl) { // don't store the same label twice
551 skip = true;
552 break;
553 }
554 nxt = (*extra)[nxt].next;
555 }
556 if (skip) {
557 continue;
558 }
559 // new predigit will be added in the end of the chain
560 nxt = extra->size();
561 extra->emplace_back(lbl);
562 }
563 }
564}
Definition of the ITSMFT digit.
std::ostringstream debug
int32_t i
uint32_t col
Definition RawData.h:4
Definition of the SegmentationChipclass.
Definition of the TRK 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
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
const char * getName() const
const o2::detectors::DetID & getDetID() const
const Mat3D & getMatrixL2G(int sensID) const
float getCollectedCharge(float totalNEle, float tMin, float tMax) const
bool getResponse(float vRow, float vCol, float cDepth, AlpideRespSimMat &dest) const
void addDigit(ULong64_t key, UInt_t roframe, UShort_t row, UShort_t col, int charge, o2::MCCompLabel lbl)
o2::itsmft::PreDigit * findDigit(ULong64_t key)
int getMinChargeToAccount() const
Definition DigiParams.h:84
float getStrobeDelay(int layer=-1) const
Definition DigiParams.h:64
const o2::itsmft::AlpideSimResponse * getAlpSimResponse() const
Definition DigiParams.h:95
virtual void print() const
float getROFrameLengthInv(int layer=-1) const
Definition DigiParams.h:61
const SignalShape & getSignalShape() const
Definition DigiParams.h:98
float getStrobeLength(int layer=-1) const
Definition DigiParams.h:67
float getEnergyToNElectrons() const
Definition DigiParams.h:87
int getROFrameLengthInBC(int layer=-1) const
Definition DigiParams.h:56
bool isContinuous() const
Definition DigiParams.h:54
int getChargeThreshold() const
Definition DigiParams.h:83
float getNSimStepsInv() const
Definition DigiParams.h:86
float getROFrameLength(int layer=-1) const
Definition DigiParams.h:60
int getNSimSteps() const
Definition DigiParams.h:85
Digit class for the ITS.
Definition Digit.h:30
void fillOutputContainer(uint32_t maxFrame=0xffffffff, int layer=-1)
auto getChipResponse(int chipID)
Definition Digitizer.cxx:95
bool isContinuous() const
Definition Digitizer.h:81
void setEventTime(const o2::InteractionTimeRecord &irt, int layer=-1)
void process(const std::vector< Hit > *hits, int evID, int srcID, int layer=-1)
Steer conversion of hits to digits.
virtual Int_t getLayer(Int_t index) const
Int_t getNumberOfChips() const
math_utils::Point3D< Float_t > GetPosStart() const
Definition Hit.h:60
bool isFullChipMasked(int chip) const
Definition NoiseMap.h:186
bool isNoisy(int chip, int row, int col) const
Definition NoiseMap.h:151
void setNEntries(int n)
Definition ROFRecord.h:48
const BCData & getBCData() const
Definition ROFRecord.h:58
void setFirstEntry(int idx)
Definition ROFRecord.h:47
int getFirstEntry() const
Definition ROFRecord.h:63
void setROFrame(ROFtype rof)
Definition ROFRecord.h:45
static bool localToDetector(float x, float z, int &iRow, int &iCol)
static bool detectorToLocal(L row, L col, T &xRow, T &zCol)
static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col)
Get global ordering key made of readout frame, column and row.
static constexpr float PitchColVD
static constexpr float PitchColMLOT
static constexpr float PitchRowMLOT
static void Print() noexcept
Print segmentation info.
static constexpr float PitchRowVD
static constexpr float SiliconThicknessMLOT
GLuint buffer
Definition glcorearb.h:655
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
constexpr double LHCBunchSpacingNS
value_T step
Definition TrackUtils.h:42
constexpr std::array< int, nLayers > nRows
Definition Specs.h:57
constexpr double pitchZ
Definition Specs.h:137
constexpr double pitchX
Definition Specs.h:136
constexpr double pitchZ
Definition Specs.h:129
constexpr double pitchX
Definition Specs.h:128
int64_t differenceInBC(const InteractionRecord &other) const
void setFromLong(int64_t l)
double timeInBCNS
time in NANOSECONDS relative to orbit/bc
double getTimeNS() const
get time in ns from orbit=0/bc=0
int next
eventual next contribution to the same pixel
Definition PreDigit.h:36
o2::MCCompLabel label
hit label
Definition PreDigit.h:35
int charge
N electrons.
Definition PreDigit.h:46
PreDigitLabelRef labelRef
label and reference to the next one
Definition PreDigit.h:47
IR getFirstSampledTFIR() const
get TF and HB (abs) for this IR
Definition HBFUtils.h:74
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row