1717// /
1818
1919#include " IOTOFSimulation/Digitizer.h"
20+ #include " IOTOFSimulation/DPLDigitizerParam.h"
2021#include " DetectorsRaw/HBFUtils.h"
2122
2223#include < TRandom.h>
@@ -30,7 +31,6 @@ namespace o2::iotof
3031{
3132
3233o2::iotof::Segmentation* Digitizer::sSegmentation = nullptr ;
33-
3434// _______________________________________________________________________
3535void Digitizer::init ()
3636{
@@ -100,7 +100,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
100100 }
101101
102102 // Get detector element ID
103- int chipID = hit.GetDetectorID ();
103+ const int chipID = hit.GetDetectorID ();
104104 auto & chip = mChips [chipID];
105105 if (chip.isDisabled ()) {
106106 LOG (debug) << " Hit rejected because chip " << chipID << " is disabled" ;
@@ -110,6 +110,8 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
110110 // Convert energy loss to charge (number of electrons)
111111 float energyLoss = hit.GetEnergyLoss (); // in GeV
112112 int charge = energyToCharge (energyLoss);
113+ const auto & digitizerParams = o2::iotof::DPLDigitizerParam::Instance ();
114+ int electronsPerStep = static_cast <int >(charge / digitizerParams.nSimSteps );
113115
114116 // Apply charge threshold
115117 if (charge < mChargeThreshold ) {
@@ -128,25 +130,126 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
128130 LOG (debug) << " Invalid detector ID: " << chipID << " , geometry size: " << mGeometry ->getSize ();
129131 return ; // invalid detector ID
130132 }
133+
134+ // Create the digit with time information
135+ o2::MCCompLabel label (hit.GetTrackID (), evID, srcID, false );
136+ const int roFrameAbs = 0 ; // For now, we can set this to 0 or calculate based on time if needed
137+ 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
138+
139+ float ** respMatrix = nullptr ;
140+ int rowStart = 0 , colStart = 0 , rowSpan = 0 , colSpan = 0 ;
141+ stepping (hit, respMatrix, rowStart, colStart, rowSpan, colSpan);
142+
143+ for (int irow = rowSpan; irow--;) {
144+ uint16_t rowIS = irow + rowStart;
145+ for (int icol = colSpan; icol--;) {
146+ uint16_t colIS = icol + colStart;
147+ float nEleResp = respMatrix[irow][icol];
148+ if (!nEleResp) {
149+ continue ;
150+ }
151+ const int nElectronsSampled = gRandom ->Poisson (electronsPerStep * nEleResp);
152+ // Noise can be added here if needed
153+
154+ registerDigits (chip, roFrameAbs, smearedTime, nROF,
155+ static_cast <uint16_t >(rowIS), static_cast <uint16_t >(colIS), nElectronsSampled, label);
156+ }
157+ }
158+
159+ for (int irow = 0 ; irow < rowSpan; ++irow) {
160+ delete[] respMatrix[irow];
161+ }
162+ delete[] respMatrix;
163+ }
164+
165+ void Digitizer::stepping (const o2::itsmft::Hit& hit, float **& respMatrix, int & rowStart, int & colStart, int & rowSpan, int & colSpan)
166+ {
131167 const auto & matrix = mGeometry ->getMatrixL2G (hit.GetDetectorID ());
168+ const int chipID = hit.GetDetectorID ();
169+ const int subdetectorID = mGeometry ->getIOTOFLayer (chipID);
170+
171+ auto xyzPositionStart (matrix ^ (hit.GetPosStart ())); // start position in sensor frame
172+ auto xyzPositionEnd (matrix ^ (hit.GetPos ())); // end position in sensor frame
173+
174+ const auto & digitizerParams = o2::iotof::DPLDigitizerParam::Instance ();
175+ const auto stepVector = (xyzPositionEnd - xyzPositionStart) / digitizerParams.nSimSteps ;
176+ xyzPositionStart = xyzPositionStart + stepVector * 0 .5f ; // center the start position in the middle of the step
177+ xyzPositionEnd = xyzPositionEnd - stepVector * 0 .5f ; // center the end position in the middle of the step
178+
179+ rowStart = -1 ;
180+ colStart = -1 ;
181+ int rowEnd = -1 , colEnd = -1 , nSkip = 0 , nSteps = digitizerParams.nSimSteps ;
182+ while (!sSegmentation ->localToDetector (xyzPositionStart.X (), xyzPositionStart.Z (), rowStart, colStart, mGeometry ->getIOTOFLayer (chipID))) {
183+ if (++nSkip > digitizerParams.nSimSteps ) { // additional check to add: should we exclude something?
184+ LOG (debug) << " Hit position out of bounds for detector ID " << chipID;
185+ return ; // hit is outside the active area
186+ }
187+ xyzPositionStart += stepVector;
188+ }
189+
190+ while (!sSegmentation ->localToDetector (xyzPositionEnd.X (), xyzPositionEnd.Z (), rowEnd, colEnd, mGeometry ->getIOTOFLayer (chipID))) {
191+ if (++nSkip > digitizerParams.nSimSteps ) { // additional check to add: should we exclude something?
192+ LOG (debug) << " Hit position out of bounds for detector ID " << chipID;
193+ return ; // hit is outside the active area
194+ }
195+ xyzPositionEnd += stepVector;
196+ }
132197
133- math_utils::Vector3D<float > xyzPositionStart (matrix ^ (hit.GetPosStart ())); // start position in sensor frame
134- // math_utils::Vector3D<float> xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame
198+ if (rowStart > rowEnd) {
199+ std::swap (rowStart, rowEnd);
200+ }
201+ if (colStart > colEnd) {
202+ std::swap (colStart, colEnd);
203+ }
135204
136- int row = 0 ; // Will be determined from start hit position
137- int col = 0 ; // Will be determined from start hit position
205+ // Expand the range to take into account the effects of charge sharing
206+ rowStart -= digitizerParams.responseMatrixSize / 2 ;
207+ rowEnd += digitizerParams.responseMatrixSize / 2 ;
208+ rowStart = std::max (rowStart, 0 );
209+ colStart = std::max (colStart, 0 );
138210
139- if (!sSegmentation ->localToDetector (xyzPositionStart.X (), xyzPositionStart.Z (), row, col, mGeometry ->getIOTOFLayer (chipID))) {
140- LOG (debug) << " Hit position out of bounds for detector ID " << chipID;
141- return ; // hit is outside the active area
211+ rowEnd = std::min (rowEnd, (subdetectorID == 0 ? sSegmentation ->mITofSpecsConfig .NRows : sSegmentation ->mOTofSpecsConfig .NRows ) - 1 );
212+ colEnd = std::min (colEnd, (subdetectorID == 0 ? sSegmentation ->mITofSpecsConfig .NCols : sSegmentation ->mOTofSpecsConfig .NCols ) - 1 );
213+ rowSpan = rowEnd - rowStart + 1 ;
214+ colSpan = colEnd - colStart + 1 ;
215+
216+ respMatrix = new float *[rowSpan];
217+ for (int i = 0 ; i < rowSpan; ++i) {
218+ respMatrix[i] = new float [colSpan]();
142219 }
143220
144- // Create the digit with time information
145- o2::MCCompLabel label (hit.GetTrackID (), evID, srcID, false );
146- const int roFrameAbs = 0 ; // For now, we can set this to 0 or calculate based on time if needed
147- 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
221+ int rowPrev = -1 , colPrev = -1 , row = 0 , col = 0 ;
222+ if (!respMatrix || rowSpan <= 0 || colSpan <= 0 ) {
223+ return ;
224+ }
225+ if (nSkip) {
226+ nSteps -= nSkip;
227+ }
148228
149- registerDigits (chip, roFrameAbs, smearedTime, nROF, static_cast <uint16_t >(row), static_cast <uint16_t >(col), charge, label);
229+ auto & currentPosLocal = xyzPositionStart;
230+ for (int iStep = nSteps; iStep--;) {
231+ sSegmentation ->localToDetector (currentPosLocal.X (), currentPosLocal.Z (), row, col, subdetectorID);
232+ if (row != rowPrev || col != colPrev) {
233+ rowPrev = row;
234+ colPrev = col;
235+ }
236+
237+ currentPosLocal += stepVector; // Move to the next step position
238+
239+ for (int irow = digitizerParams.responseMatrixSize ; irow--;) {
240+ int rowDest = row + irow - (digitizerParams.responseMatrixSize / 2 ) - rowStart; // destination row in the respMatrix
241+ if (rowDest < 0 || rowDest >= rowSpan) {
242+ continue ;
243+ }
244+ for (int icol = digitizerParams.responseMatrixSize ; icol--;) {
245+ int colDest = col + icol - (digitizerParams.responseMatrixSize / 2 ) - colStart; // destination column in the respMatrix
246+ if (colDest < 0 || colDest >= colSpan) {
247+ continue ;
248+ }
249+ respMatrix[rowDest][colDest] += 1 .;
250+ }
251+ }
252+ }
150253}
151254
152255// _______________________________________________________________________
@@ -200,10 +303,9 @@ void Digitizer::fillOutputContainer()
200303 auto & chipDigits = chip.getDigits ();
201304 for (const auto & [key, digit] : chipDigits) {
202305
203- // / Charge threshold not implemented yet
204- // / if (digit.getCharge() < mChargeThreshold) {
205- // / continue; // skip digits below threshold
206- // / }
306+ if (digit.getCharge () < mChargeThreshold ) {
307+ continue ; // skip digits below threshold
308+ }
207309
208310 int digitID = mDigits ->size ();
209311 mDigits ->emplace_back (digit.getChipIndex (), digit.getRow (), digit.getColumn (), digit.getCharge (), digit.getTime ());
0 commit comments