39 LOG(info) <<
"Initializing digitizer";
40 mNumberOfChips = mGeometry->getNumberOfChips();
41 mChips.resize(mNumberOfChips);
42 for (
int i = mNumberOfChips;
i--;) {
43 mChips[
i].setChipIndex(
i);
45 mChips[
i].setNoiseMap(mNoiseMap);
48 mChips[
i].disable(mDeadChanMap->isFullChipMasked(
i));
49 mChips[
i].setDeadChanMap(mDeadChanMap);
54 mChipSimResp = mParams.getResponse();
55 mChipSimRespVD = mChipSimResp;
56 mChipSimRespMLOT = mChipSimResp;
60 LOG(info) <<
" Depth max VD: " << mChipSimRespVD->getDepthMax();
61 LOG(info) <<
" Depth min VD: " << mChipSimRespVD->getDepthMin();
63 LOG(info) <<
" Depth max MLOT: " << mChipSimRespMLOT->getDepthMax();
64 LOG(info) <<
" Depth min MLOT: " << mChipSimRespMLOT->getDepthMin();
66 float thicknessVD = 0.0095;
69 LOG(info) <<
"Using response name: " << mRespName;
70 mSimRespOrientation =
false;
72 if (mRespName ==
"APTS") {
75 mSimRespVDShift = mChipSimRespVD->getDepthMax();
78 mSimRespOrientation =
true;
79 }
else if (mRespName ==
"ALICE3") {
82 mSimRespVDShift = mChipSimRespVD->getDepthMax();
86 LOG(fatal) <<
"Unknown response name: " << mRespName;
89 mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - thicknessMLOT / 2.f;
93 LOGP(info,
"VD shift = {} ; ML/OT shift = {} = {} - {}", mSimRespVDShift, mSimRespMLOTShift, mChipSimRespMLOT->getDepthMax(), thicknessMLOT / 2.f);
94 LOGP(info,
"VD pixel scale on x = {} ; z = {}", mSimRespVDScaleX, mSimRespVDScaleZ);
95 LOGP(info,
"ML/OT pixel scale on x = {} ; z = {}", mSimRespMLOTScaleX, mSimRespMLOTScaleZ);
96 LOGP(info,
"Response orientation: {}", mSimRespOrientation ?
"flipped" :
"normal");
104 if (mGeometry->getSubDetID(chipID) == 0) {
105 return mChipSimRespVD;
108 else if (mGeometry->getSubDetID(chipID) == 1 || mGeometry->getSubDetID(chipID) == 2) {
109 return mChipSimRespMLOT;
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 <<
" Min/Max ROFrames " << mROFrameMin <<
"/" << mROFrameMax <<
" layer " <<
layer;
129 if (mNewROFrame > mROFrameMin) {
130 fillOutputContainer(mNewROFrame - 1,
layer);
133 int nHits = hits->size();
134 std::vector<int> hitIdx(nHits);
135 std::iota(std::begin(hitIdx), std::end(hitIdx), 0);
137 std::sort(hitIdx.begin(), hitIdx.end(),
138 [hits](
auto lhs,
auto rhs) {
139 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
141 LOG(info) <<
"Processing " << nHits <<
" hits";
142 for (
int i : hitIdx |
std::views::
filter([&](int idx) {
146 return getROFLayer((*hits)[idx].GetDetectorID()) ==
layer;
148 processHit((*hits)[
i], mROFrameMax, evID, srcID,
layer);
156 LOG(info) <<
"Setting event time to " << irt.
getTimeNS() <<
" ns after orbit 0 bc 0";
161 auto nbc = mEventTime.differenceInBC(mIRFirstSampledTF);
163 if (mCollisionTimeWrtROF < 0 && nbc > 0) {
167 mROFsWrtFirstRO = std::floor(
float(nbc) / mParams.getROFrameLengthInBC(
layer));
171 mNewROFrame = nbc / mParams.getROFrameLengthInBC(
layer);
174 LOG(
debug) <<
" NewROFrame " << mNewROFrame <<
" nbc " << nbc <<
" ROFsWrtFirstRO " << mROFsWrtFirstRO;
177 mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC(
layer)) * o2::constants::lhc::LHCBunchSpacingNS;
179 if (mNewROFrame < mROFrameMin) {
180 LOG(error) <<
"New ROFrame " << mNewROFrame <<
" (" << irt <<
") precedes currently cashed " << mROFrameMin;
181 throw std::runtime_error(
"deduced ROFrame precedes already processed one");
184 if (mROFrameMax < mNewROFrame) {
185 mROFrameMax = mNewROFrame - 1;
194 if (frameLast > mROFrameMax) {
195 frameLast = mROFrameMax;
198 getExtraDigBuffer(mROFrameMax);
199 LOG(info) <<
"Filling " << mGeometry->getName() <<
" digits output for RO frames " << mROFrameMin <<
":"
205 for (; mROFrameMin <= frameLast; mROFrameMin++) {
209 auto& extra = *(mExtraBuff.front().get());
210 for (
auto& chip : mChips) {
211 if (chip.isDisabled() || (
layer >= 0 && getROFLayer(chip.getChipIndex()) !=
layer)) {
214 chip.addNoise(mROFrameMin, mROFrameMin, &mParams, mGeometry->getSubDetID(chip.getChipIndex()), mGeometry->getLayer(chip.getChipIndex()));
215 auto&
buffer = chip.getPreDigits();
219 auto itBeg =
buffer.begin();
221 ULong64_t maxKey = chip.getOrderingKey(mROFrameMin + 1, 0, 0) - 1;
222 for (; iter !=
buffer.end(); ++iter) {
223 if (iter->first > maxKey) {
226 auto& preDig = iter->second;
227 if (preDig.charge >= mParams.getChargeThreshold()) {
228 int digID = mDigits->size();
229 mDigits->emplace_back(chip.getChipIndex(), preDig.row, preDig.col, preDig.charge, preDig.toa);
230 LOG(
debug) <<
"Adding digit ID: " << digID <<
" with chipID: " << chip.getChipIndex() <<
", row: " << preDig.row <<
", col: " << preDig.col <<
", charge: " << preDig.charge <<
", ToA: " << preDig.toa;
231 mMCLabels->addElement(digID, preDig.labelRef.label);
232 auto& nextRef = preDig.labelRef;
233 while (nextRef.next >= 0) {
234 nextRef = extra[nextRef.next];
235 mMCLabels->addElement(digID, nextRef.label);
239 buffer.erase(itBeg, iter);
245 mROFRecords->push_back(rcROF);
249 mExtraBuff.emplace_back(mExtraBuff.front().release());
250 mExtraBuff.pop_front();
259 int subDetID = mGeometry->getSubDetID(chipID);
261 int layer = mGeometry->getLayer(chipID);
262 int disk = getDisk(chipID);
265 LOG(
debug) <<
"Skipping VD disk " << disk;
269 LOG(
debug) <<
"Processing hit for chip " << chipID;
270 auto& chip = mChips[chipID];
271 if (chip.isDisabled()) {
272 LOG(
debug) <<
"Skipping disabled chip " << chipID;
275 float timeInROF = hit.
GetTime() * sec2ns;
276 LOG(
debug) <<
"Hit time: " << timeInROF <<
" ns";
277 if (timeInROF > 20e3) {
278 const int maxWarn = 10;
279 static int warnNo = 0;
280 if (warnNo < maxWarn) {
281 LOG(warning) <<
"Ignoring hit with time_in_event = " << timeInROF <<
" ns"
282 << ((++warnNo < maxWarn) ?
"" :
" (suppressing further warnings)");
286 timeInROF += mCollisionTimeWrtROF;
287 if (mROFsWrtFirstRO < -1 || (mROFsWrtFirstRO == -1 && timeInROF < 0)) {
289 LOG(
debug) <<
"Ignoring hit with timeInROF = " << timeInROF;
297 float tTot = mParams.getSignalShape().getMaxDuration();
299 int roFrameRel =
int(timeInROF * mParams.getROFrameLengthInv(rofLayer));
301 float toaInROF = timeInROF - roFrameRel * mParams.getROFrameLength(rofLayer);
304 uint32_t roFrameRelMax = (timeInROF + tTot) * mParams.getROFrameLengthInv(rofLayer);
305 int nFrames = roFrameRelMax + 1 - roFrameRel;
306 uint32_t roFrameMax = mNewROFrame + roFrameRelMax;
307 if (roFrameMax > maxFr) {
312 float nStepsInv = mParams.getNSimStepsInv();
313 int nSteps = mParams.getNSimSteps();
315 const auto& matrix = mGeometry->getMatrixL2G(hit.
GetDetectorID());
319 math_utils::Vector3D<float> xyzLocS(matrix ^ (hit.
GetPosStart()));
320 math_utils::Vector3D<float> xyzLocE(matrix ^ (hit.
GetPos()));
326 LOG(
debug) <<
"Called curved to flat: " << xyzLocS.x() <<
" -> " << xyFlatS.x() <<
", " << xyzLocS.y() <<
" -> " << xyFlatS.y();
328 xyzLocS.SetXYZ(xyFlatS.x(), xyFlatS.y(), xyzLocS.Z());
329 xyzLocE.SetXYZ(xyFlatE.x(), xyFlatE.y(), xyzLocE.Z());
338 math_utils::Vector3D<float>
step(xyzLocE);
343 math_utils::Vector3D<float> stepH(step * 0.5);
347 LOG(
debug) <<
"Step into the sensitive volume: " <<
step <<
". Number of steps: " << nSteps;
348 int rowS = -1, colS = -1, rowE = -1, colE = -1, nSkip = 0;
353 if (++nSkip >= nSteps) {
354 LOG(
debug) <<
"Did not enter to sensitive matrix, " << nSkip <<
" >= " << nSteps;
362 if (++nSkip >= nSteps) {
363 LOG(
debug) <<
"Did not enter to sensitive matrix, " << nSkip <<
" >= " << nSteps;
374 std::swap(rowS, rowE);
377 std::swap(colS, colE);
395 int rowSpan = rowE - rowS + 1, colSpan = colE - colS + 1;
397 float respMatrix[rowSpan][colSpan];
398 std::fill(&respMatrix[0][0], &respMatrix[0][0] + rowSpan * colSpan, 0.f);
400 float nElectrons = hit.
GetEnergyLoss() * mParams.getEnergyToNElectrons();
401 nElectrons *= nStepsInv;
406 int rowPrev = -1, colPrev = -1,
row,
col;
407 float cRowPix = 0.f, cColPix = 0.f;
418 xyzLocS.SetY(xyzLocS.Y() + ((subDetID == 0) ? mSimRespVDShift : mSimRespMLOTShift));
422 for (
int iStep = nSteps; iStep--;) {
425 if (
row != rowPrev ||
col != colPrev) {
432 bool flipCol =
false, flipRow =
false;
434 float rowMax{}, colMax{};
439 rspmat = resp->
getResponse(mSimRespVDScaleX * (xyzLocS.X() - cRowPix), mSimRespVDScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax);
443 rspmat = resp->
getResponse(mSimRespMLOTScaleX * (xyzLocS.X() - cRowPix), mSimRespMLOTScaleZ * (xyzLocS.Z() - cColPix), xyzLocS.Y(), flipRow, flipCol, rowMax, colMax);
448 if (rspmat ==
nullptr) {
449 LOG(
debug) <<
"Error in rspmat for step " << iStep <<
" / " << nSteps;
458 if (rowDest < 0 || rowDest >= rowSpan) {
463 if (colDest < 0 || colDest >= colSpan) {
466 respMatrix[rowDest][colDest] += rspmat->getValue(irow, icol, mSimRespOrientation ? !flipRow : flipRow, flipCol);
470 LOG(info) <<
"Response done; adding labels; making digits";
473 auto roFrameAbs = mNewROFrame + roFrameRel;
474 LOG(
debug) <<
"\nSpanning through rows and columns; rowspan = " << rowSpan <<
" colspan = " << colSpan <<
" = " << colE <<
" - " << colS <<
" +1 ";
475 for (
int irow = rowSpan; irow--;) {
476 uint16_t rowIS = irow + rowS;
477 for (
int icol = colSpan; icol--;) {
478 float nEleResp = respMatrix[irow][icol];
479 if (nEleResp <= 1.e-36) {
482 LOG(
debug) <<
"nEleResp: value " << nEleResp <<
" for pixel " << irow <<
" " << icol;
483 int nEle = gRandom->Poisson(nElectrons * nEleResp);
484 LOG(
debug) <<
"Charge detected in the pixel: " << nEle <<
" for pixel " << irow <<
" " << icol;
486 if (nEle < mParams.getMinChargeToAccount()) {
487 LOG(
debug) <<
"Ignoring pixel with nEle = " << nEle <<
" < min charge to account "
488 << mParams.getMinChargeToAccount() <<
" for pixel " << irow <<
" " << icol;
492 uint16_t colIS = icol + colS;
493 if (mNoiseMap && mNoiseMap->isNoisy(chipID, rowIS, colIS)) {
496 if (mDeadChanMap && mDeadChanMap->isNoisy(chipID, rowIS, colIS)) {
499 registerDigits(chip, roFrameAbs, toaInROF, nFrames, rowIS, colIS, nEle, lbl, rofLayer);
512 LOG(
debug) <<
"Registering digits for chip " << chip.
getChipIndex() <<
" at ROFrame " << roFrame
513 <<
" row " <<
row <<
" col " <<
col <<
" nEle " << nEle <<
" label " << lbl <<
" layer " <<
layer <<
" toa " << toaInROF;
514 float tStrobe = mParams.getStrobeDelay(
layer) - toaInROF;
515 for (
int i = 0;
i < nROF;
i++) {
516 uint32_t roFr = roFrame +
i;
517 float toaROF = toaInROF -
i * mParams.getROFrameLength(
layer);
518 int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength(
layer));
519 tStrobe += mParams.getROFrameLength(
layer);
522 if (nEleROF < mParams.getMinChargeToAccount()) {
525 if (roFr > mEventROFrameMax) {
526 mEventROFrameMax = roFr;
528 if (roFr < mEventROFrameMin) {
529 mEventROFrameMin = roFr;
535 LOG(
debug) <<
"Added digit with key: " <<
key <<
" ROF: " << roFr <<
" row: " <<
row <<
" col: " <<
col <<
" charge: " << nEleROF;
537 LOG(
debug) <<
"Added to pre-digit with key: " <<
key <<
" ROF: " << roFr <<
" row: " <<
row <<
" col: " <<
col <<
" charge: " << nEleROF;
539 pd->
toa = std::min(pd->
toa, toaROF);
543 ExtraDig* extra = getExtraDigBuffer(roFr);
547 if ((*extra)[nxt].
label == lbl) {
551 nxt = (*extra)[nxt].next;
558 extra->emplace_back(lbl);