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
14
19#include "MathUtils/Cartesian.h"
22
23#include <TRandom.h>
24#include <climits>
25#include <vector>
26#include <numeric>
27#include <fairlogger/Logger.h> // for LOG
28
30using o2::itsmft::Hit;
32
33using namespace o2::itsmft;
34// using namespace o2::base;
35
36//_______________________________________________________________________
38{
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 // importing the parameters from DPLDigitizerParam.h
55
56 // initializing response according to detector and back-bias value
57 if (doptMFT.Vbb == 0.0) { // for MFT
58 mAlpSimRespMFT = mAlpSimResp[0];
59 LOG(info) << "Choosing Vbb=0V for MFT";
60 } else if (doptMFT.Vbb == 3.0) {
61 mAlpSimRespMFT = mAlpSimResp[1];
62 LOG(info) << "Choosing Vbb=-3V for MFT";
63 } else {
64 LOG(fatal) << "Invalid MFT back-bias value";
65 }
66
67 if (doptITS.IBVbb == 0.0) { // for ITS Inner Barrel
68 mAlpSimRespIB = mAlpSimResp[0];
69 LOG(info) << "Choosing Vbb=0V for ITS IB";
70 } else if (doptITS.IBVbb == 3.0) {
71 mAlpSimRespIB = mAlpSimResp[1];
72 LOG(info) << "Choosing Vbb=-3V for ITS IB";
73 } else {
74 LOG(fatal) << "Invalid ITS Inner Barrel back-bias value";
75 }
76 if (doptITS.OBVbb == 0.0) { // for ITS Outter Barrel
77 mAlpSimRespOB = mAlpSimResp[0];
78 LOG(info) << "Choosing Vbb=0V for ITS OB";
79 } else if (doptITS.OBVbb == 3.0) {
80 mAlpSimRespOB = mAlpSimResp[1];
81 LOG(info) << "Choosing Vbb=-3V for ITS OB";
82 } else {
83 LOG(fatal) << "Invalid ITS Outter Barrel back-bias value";
84 }
85 mParams.print();
87
88 //
89 LOG(info) << "First IR sampled in digitization is: " << mIRFirstSampledTF;
90 LOG(info) << "First IR ns " << mIRFirstSampledTF.bc2ns();
91}
92
94{
95 if (mNumberOfChips < 10000) { // in MFT
96 return mAlpSimRespMFT;
97 }
98
99 if (chipID < 432) { // in ITS Inner Barrel
100 return mAlpSimRespIB;
101 } else { // in ITS Outter Barrel
102 return mAlpSimRespOB;
103 }
104}
105
106//_______________________________________________________________________
107void Digitizer::process(const std::vector<Hit>* hits, int evID, int srcID)
108{
109 // digitize single event, the time must have been set beforehand
110
111 LOG(info) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source "
112 << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")"
113 << " cont.mode: " << isContinuous()
114 << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax;
115
116 // is there something to flush ?
117 if (mNewROFrame > mROFrameMin) {
118 fillOutputContainer(mNewROFrame - 1); // flush out all frame preceding the new one
119 }
120
121 int nHits = hits->size();
122 std::vector<int> hitIdx(nHits);
123 std::iota(std::begin(hitIdx), std::end(hitIdx), 0);
124 // sort hits to improve memory access
125 std::sort(hitIdx.begin(), hitIdx.end(),
126 [hits](auto lhs, auto rhs) {
127 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
128 });
129 for (int i : hitIdx) {
130 processHit((*hits)[i], mROFrameMax, evID, srcID);
131 }
132 // in the triggered mode store digits after every MC event
133 // TODO: in the real triggered mode this will not be needed, this is actually for the
134 // single event processing only
135 if (!mParams.isContinuous()) {
136 fillOutputContainer(mROFrameMax);
137 }
138}
139
140//_______________________________________________________________________
142{
143 // assign event time in ns
144 mEventTime = irt;
145 if (!mParams.isContinuous()) {
146 mROFrameMin = 0; // in triggered mode reset the frame counters
147 mROFrameMax = 0;
148 }
149 // RO frame corresponding to provided time
150 mCollisionTimeWrtROF = mEventTime.timeInBCNS; // in triggered mode the ROF starts at BC (is there a delay?)
151 if (mParams.isContinuous()) {
152 auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF);
153 if (mCollisionTimeWrtROF < 0 && nbc > 0) {
154 nbc--;
155 }
156
157 // we might get interactions to digitize from before
158 // the first sampled IR
159 if (nbc < 0) {
160 mNewROFrame = 0;
161 // this event is before the first RO
162 mIsBeforeFirstRO = true;
163 } else {
164 mNewROFrame = nbc / mParams.getROFrameLengthInBC();
165 mIsBeforeFirstRO = false;
166 }
167 LOG(info) << " NewROFrame " << mNewROFrame << " nbc " << nbc;
168
169 // in continuous mode depends on starts of periodic readout frame
170 mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS;
171 } else {
172 mNewROFrame = 0;
173 }
174
175 if (mNewROFrame < mROFrameMin) {
176 LOG(error) << "New ROFrame " << mNewROFrame << " (" << irt << ") precedes currently cashed " << mROFrameMin;
177 throw std::runtime_error("deduced ROFrame precedes already processed one");
178 }
179
180 if (mParams.isContinuous() && mROFrameMax < mNewROFrame) {
181 mROFrameMax = mNewROFrame - 1; // all frames up to this are finished
182 }
183}
184
185//_______________________________________________________________________
186void Digitizer::fillOutputContainer(uint32_t frameLast)
187{
188 // fill output with digits from min.cached up to requested frame, generating the noise beforehand
189 if (frameLast > mROFrameMax) {
190 frameLast = mROFrameMax;
191 }
192 // make sure all buffers for extra digits are created up to the maxFrame
193 getExtraDigBuffer(mROFrameMax);
194
195 LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":"
196 << frameLast;
197
199
200 // we have to write chips in RO increasing order, therefore have to loop over the frames here
201 for (; mROFrameMin <= frameLast; mROFrameMin++) {
202 rcROF.setROFrame(mROFrameMin);
203 rcROF.setFirstEntry(mDigits->size()); // start of current ROF in digits
204
205 auto& extra = *(mExtraBuff.front().get());
206 for (auto& chip : mChips) {
207 if (chip.isDisabled()) {
208 continue;
209 }
210 chip.addNoise(mROFrameMin, mROFrameMin, &mParams);
211 auto& buffer = chip.getPreDigits();
212 if (buffer.empty()) {
213 continue;
214 }
215 auto itBeg = buffer.begin();
216 auto iter = itBeg;
217 ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1; // fetch digits with key below that
218 for (; iter != buffer.end(); ++iter) {
219 if (iter->first > maxKey) {
220 break; // is the digit ROFrame from the key > the max requested frame
221 }
222 auto& preDig = iter->second; // preDigit
223 if (preDig.charge >= mParams.getChargeThreshold()) {
224 int digID = mDigits->size();
225 mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge);
226 mMCLabels->addElement(digID, preDig.labelRef.label);
227 auto& nextRef = preDig.labelRef; // extra contributors are in extra array
228 while (nextRef.next >= 0) {
229 nextRef = extra[nextRef.next];
230 mMCLabels->addElement(digID, nextRef.label);
231 }
232 }
233 }
234 buffer.erase(itBeg, iter);
235 }
236 // finalize ROF record
237 rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits
238 if (isContinuous()) {
239 rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC());
240 } else {
241 rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay?
242 }
243 if (mROFRecords) {
244 mROFRecords->push_back(rcROF);
245 }
246 extra.clear(); // clear container for extra digits of the mROFrameMin ROFrame
247 // and move it as a new slot in the end
248 mExtraBuff.emplace_back(mExtraBuff.front().release());
249 mExtraBuff.pop_front();
250 }
251}
252
253//_______________________________________________________________________
254void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID)
255{
256 // convert single hit to digits
257 auto chipID = hit.GetDetectorID();
258 auto& chip = mChips[chipID];
259 if (chip.isDisabled()) {
260 LOG(debug) << "skip disabled chip " << chipID;
261 return;
262 }
263 float timeInROF = hit.GetTime() * sec2ns;
264 if (timeInROF > 20e3) {
265 const int maxWarn = 10;
266 static int warnNo = 0;
267 if (warnNo < maxWarn) {
268 LOG(warning) << "Ignoring hit with time_in_event = " << timeInROF << " ns"
269 << ((++warnNo < maxWarn) ? "" : " (suppressing further warnings)");
270 }
271 return;
272 }
273 if (isContinuous()) {
274 timeInROF += mCollisionTimeWrtROF;
275 }
276 if (mIsBeforeFirstRO && timeInROF < 0) {
277 // disregard this hit because it comes from an event before readout starts and it does not effect this RO
278 return;
279 }
280
281 // calculate RO Frame for this hit
282 if (timeInROF < 0) {
283 timeInROF = 0.;
284 }
285 float tTot = mParams.getSignalShape().getMaxDuration();
286 // frame of the hit signal start wrt event ROFrame
287 int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv());
288 // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame
289 uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel;
290 int nFrames = roFrameRelMax + 1 - roFrameRel;
291 uint32_t roFrameMax = mNewROFrame + roFrameRelMax;
292 if (roFrameMax > maxFr) {
293 maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter
294 }
295
296 // here we start stepping in the depth of the sensor to generate charge diffusion
297 float nStepsInv = mParams.getNSimStepsInv();
298 int nSteps = mParams.getNSimSteps();
299 const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID());
300 math_utils::Vector3D<float> xyzLocS(matrix ^ (hit.GetPosStart())); // start position in sensor frame
301 math_utils::Vector3D<float> xyzLocE(matrix ^ (hit.GetPos())); // end position in sensor frame
302
304 step -= xyzLocS;
305 step *= nStepsInv; // position increment at each step
306 // the electrons will injected in the middle of each step
307 math_utils::Vector3D<float> stepH(step * 0.5);
308 xyzLocS += stepH;
309 xyzLocE -= stepH;
310
311 int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0;
312 // get entrance pixel row and col
313 while (!Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), rowS, colS)) { // guard-ring ?
314 if (++nSkip >= nSteps) {
315 return; // did not enter to sensitive matrix
316 }
317 xyzLocS += step;
318 }
319 // get exit pixel row and col
320 while (!Segmentation::localToDetector(xyzLocE.X(), xyzLocE.Z(), rowE, colE)) { // guard-ring ?
321 if (++nSkip >= nSteps) {
322 return; // did not enter to sensitive matrix
323 }
324 xyzLocE -= step;
325 }
326 // estimate the limiting min/max row and col where the non-0 response is possible
327 if (rowS > rowE) {
328 std::swap(rowS, rowE);
329 }
330 if (colS > colE) {
331 std::swap(colS, colE);
332 }
333 rowS -= AlpideRespSimMat::NPix / 2;
334 rowE += AlpideRespSimMat::NPix / 2;
335 if (rowS < 0) {
336 rowS = 0;
337 }
338 if (rowE >= Segmentation::NRows) {
339 rowE = Segmentation::NRows - 1;
340 }
341 colS -= AlpideRespSimMat::NPix / 2;
342 colE += AlpideRespSimMat::NPix / 2;
343 if (colS < 0) {
344 colS = 0;
345 }
346 if (colE >= Segmentation::NCols) {
347 colE = Segmentation::NCols - 1;
348 }
349 int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1; // size of plaquet where some response is expected
350
351 float respMatrix[rowSpan][colSpan]; // response accumulated here
352 std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f);
353
354 float nElectrons = hit.GetEnergyLoss() * mParams.getEnergyToNElectrons(); // total number of deposited electrons
355 nElectrons *= nStepsInv; // N electrons injected per step
356 if (nSkip) {
357 nSteps -= nSkip;
358 }
359 //
360 int rowPrev = -1, colPrev = -1, row, col;
361 float cRowPix = 0.f, cColPix = 0.f; // local coordinated of the current pixel center
362
364
365 // take into account that the AlpideSimResponse depth defintion has different min/max boundaries
366 // although the max should coincide with the surface of the epitaxial layer, which in the chip
367 // local coordinates has Y = +SensorLayerThickness/2
368
369 xyzLocS.SetY(xyzLocS.Y() + resp->getDepthMax() - Segmentation::SensorLayerThickness / 2.);
370
371 // collect charge in every pixel which might be affected by the hit
372 for (int iStep = nSteps; iStep--;) {
373 // Get the pixel ID
374 Segmentation::localToDetector(xyzLocS.X(), xyzLocS.Z(), row, col);
375 if (row != rowPrev || col != colPrev) { // update pixel and coordinates of its center
376 if (!Segmentation::detectorToLocal(row, col, cRowPix, cColPix)) {
377 continue; // should not happen
378 }
379 rowPrev = row;
380 colPrev = col;
381 }
382 bool flipCol, flipRow;
383 // note that response needs coordinates along column row (locX) (locZ) then depth (locY)
384 auto rspmat = resp->getResponse(xyzLocS.X() - cRowPix, xyzLocS.Z() - cColPix, xyzLocS.Y(), flipRow, flipCol);
385
386 xyzLocS += step;
387 if (!rspmat) {
388 continue;
389 }
390
391 for (int irow = AlpideRespSimMat::NPix; irow--;) {
392 int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix
393 if (rowDest < 0 || rowDest >= rowSpan) {
394 continue;
395 }
396 for (int icol = AlpideRespSimMat::NPix; icol--;) {
397 int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix
398 if (colDest < 0 || colDest >= colSpan) {
399 continue;
400 }
401 respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, flipRow, flipCol);
402 }
403 }
404 }
405
406 // fire the pixels assuming Poisson(n_response_electrons)
407 o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false);
408 auto roFrameAbs = mNewROFrame + roFrameRel;
409 for (int irow = rowSpan; irow--;) {
410 uint16_t rowIS = irow + rowS;
411 for (int icol = colSpan; icol--;) {
412 float nEleResp = respMatrix[irow][icol];
413 if (!nEleResp) {
414 continue;
415 }
416 int nEle = gRandom->Poisson(nElectrons * nEleResp); // total charge in given pixel
417 // ignore charge which have no chance to fire the pixel
418 if (nEle < mParams.getMinChargeToAccount()) {
419 continue;
420 }
421 uint16_t colIS = icol + colS;
422 if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) {
423 continue;
424 }
425 if (mDeadChanMap && mDeadChanMap->isNoisy(chipID, rowIS, colIS)) {
426 continue;
427 }
428 //
429 registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl);
430 }
431 }
432}
433
434//________________________________________________________________________________
435void Digitizer::registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF,
436 uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl)
437{
438 // Register digits for given pixel, accounting for the possible signal contribution to
439 // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame
440 // In every ROFrame we check the collected signal during strobe
441
442 float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start
443 for (int i = 0; i < nROF; i++) {
444 uint32_t roFr = roFrame + i;
445 int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength());
446 tStrobe += mParams.getROFrameLength(); // for the next ROF
447
448 // discard too small contributions, they have no chance to produce a digit
449 if (nEleROF < mParams.getMinChargeToAccount()) {
450 continue;
451 }
452 if (roFr > mEventROFrameMax) {
453 mEventROFrameMax = roFr;
454 }
455 if (roFr < mEventROFrameMin) {
456 mEventROFrameMin = roFr;
457 }
458 auto key = chip.getOrderingKey(roFr, row, col);
459 PreDigit* pd = chip.findDigit(key);
460 if (!pd) {
461 chip.addDigit(key, roFr, row, col, nEleROF, lbl);
462 } else { // there is already a digit at this slot, account as PreDigitExtra contribution
463 pd->charge += nEleROF;
464 if (pd->labelRef.label == lbl) { // don't store the same label twice
465 continue;
466 }
467 ExtraDig* extra = getExtraDigBuffer(roFr);
468 int& nxt = pd->labelRef.next;
469 bool skip = false;
470 while (nxt >= 0) {
471 if ((*extra)[nxt].label == lbl) { // don't store the same label twice
472 skip = true;
473 break;
474 }
475 nxt = (*extra)[nxt].next;
476 }
477 if (skip) {
478 continue;
479 }
480 // new predigit will be added in the end of the chain
481 nxt = extra->size();
482 extra->emplace_back(lbl);
483 }
484 }
485}
Definition of the ITSMFT digit.
std::ostringstream debug
int32_t i
Definition of the ITS digitizer.
Definition of a container to keep Monte Carlo truth external to simulation objects.
uint32_t col
Definition RawData.h:4
Definition of the SegmentationAlpide class.
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 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
Container for similated points connected to a given chip.
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)
static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col)
Get global ordering key made of readout frame, column and row.
int getMinChargeToAccount() const
Definition DigiParams.h:82
float getROFrameLengthInv() const
Definition DigiParams.h:59
virtual void print() const
const SignalShape & getSignalShape() const
Definition DigiParams.h:96
float getEnergyToNElectrons() const
Definition DigiParams.h:85
int getROFrameLengthInBC() const
Definition DigiParams.h:54
float getStrobeDelay() const
Definition DigiParams.h:62
bool isContinuous() const
Definition DigiParams.h:52
int getChargeThreshold() const
Definition DigiParams.h:81
float getNSimStepsInv() const
Definition DigiParams.h:84
float getROFrameLength() const
Definition DigiParams.h:58
int getNSimSteps() const
Definition DigiParams.h:83
float getStrobeLength() const
Definition DigiParams.h:65
Digit class for the ITS.
Definition Digit.h:30
void setEventTime(const o2::InteractionTimeRecord &irt)
auto getChipResponse(int chipID)
Definition Digitizer.cxx:93
bool isContinuous() const
Definition Digitizer.h:79
void process(const std::vector< Hit > *hits, int evID, int srcID)
Steer conversion of hits to digits.
void fillOutputContainer(uint32_t maxFrame=0xffffffff)
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 constexpr float SensorLayerThickness
static bool localToDetector(float x, float z, int &iRow, int &iCol)
static bool detectorToLocal(L row, L col, T &xRow, T &zCol)
GLuint buffer
Definition glcorearb.h:655
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
constexpr double LHCBunchSpacingNS
value_T step
Definition TrackUtils.h:42
static double bc2ns(int bc, unsigned int orbit)
int64_t differenceInBC(const InteractionRecord &other) const
void setFromLong(int64_t l)
double timeInBCNS
time in NANOSECONDS relative to orbit/bc
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