28#include <fairlogger/Logger.h>
37 const int numberOfChips = mGeometry->
getSize();
38 mChips.resize(numberOfChips);
39 for (
int i = numberOfChips;
i--;) {
40 mChips[
i].setChipIndex(
i);
55 LOG(info) <<
"Initializing IOTOF digitizer";
56 LOG(info) <<
" Time resolution: " << digitizerParams.timeResolution * 1e3 <<
" ps";
57 LOG(info) <<
" Charge threshold: " << digitizerParams.chargeThreshold <<
" electrons";
58 LOG(info) <<
" Detection efficiency: " << digitizerParams.efficiency * 100 <<
" %";
59 LOG(info) <<
" Continuous mode: " << (mContinuous ?
"ON" :
"OFF");
60 sSegmentation = o2::iotof::Segmentation::Instance();
67 LOG(
debug) <<
"Digitizing IOTOF hits: " << hits->size() <<
" hits from event " << evID <<
" source " << srcID;
69 if (!hits || hits->empty()) {
74 std::vector<int> hitIdx(hits->size());
75 std::iota(hitIdx.begin(), hitIdx.end(), 0);
76 std::sort(hitIdx.begin(), hitIdx.end(),
77 [hits](
int lhs,
int rhs) {
78 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
82 for (
int i : hitIdx) {
83 processHit((*hits)[
i], evID, srcID);
88 LOG(
debug) <<
"Inner flushing for non-continuous mode";
94void Digitizer::processHit(
const o2::itsmft::Hit& hit,
int evID,
int srcID)
100 LOG(
debug) <<
"Hit rejected by efficiency cut";
106 auto& chip = mChips[chipID];
107 if (chip.isDisabled()) {
108 LOG(
debug) <<
"Hit rejected because chip " << chipID <<
" is disabled";
114 int charge = energyToCharge(energyLoss);
116 int electronsPerStep =
static_cast<int>(
charge / digitizerParams.nSimSteps);
119 if (
charge < digitizerParams.chargeThreshold) {
120 LOG(
debug) <<
"Hit rejected by charge threshold: " <<
charge <<
" < " << digitizerParams.chargeThreshold;
126 double hitTime = hit.
GetTime() * sec2ns;
127 double eventTimeNS = mEventTime.
getTimeNS();
128 double absoluteTime = hitTime + eventTimeNS;
129 double smearedTime = smearTime(absoluteTime);
131 if (chipID < 0 || chipID >= mGeometry->
getSize() || mGeometry->
getSize() < 1) {
132 LOG(
debug) <<
"Invalid detector ID: " << chipID <<
", geometry size: " << mGeometry->
getSize();
138 const int roFrameAbs = 0;
141 float** respMatrix =
nullptr;
142 int rowStart = 0, colStart = 0, rowSpan = 0, colSpan = 0;
143 stepping(hit, respMatrix, rowStart, colStart, rowSpan, colSpan);
145 for (
int irow = rowSpan; irow--;) {
146 uint16_t rowIS = irow + rowStart;
147 for (
int icol = colSpan; icol--;) {
148 uint16_t colIS = icol + colStart;
149 float nEleResp = respMatrix[irow][icol];
153 const int nElectronsSampled = gRandom->Poisson(electronsPerStep * nEleResp);
156 registerDigits(chip, roFrameAbs, smearedTime, nROF,
157 static_cast<uint16_t
>(rowIS),
static_cast<uint16_t
>(colIS), nElectronsSampled,
label);
161 for (
int irow = 0; irow < rowSpan; ++irow) {
162 delete[] respMatrix[irow];
167void Digitizer::stepping(
const o2::itsmft::Hit& hit,
float**& respMatrix,
int& rowStart,
int& colStart,
int& rowSpan,
int& colSpan)
173 auto xyzPositionStart(matrix ^ (hit.
GetPosStart()));
174 auto xyzPositionEnd(matrix ^ (hit.
GetPos()));
177 const auto stepVector = (xyzPositionEnd - xyzPositionStart) / digitizerParams.nSimSteps;
178 xyzPositionStart = xyzPositionStart + stepVector * 0.5f;
179 xyzPositionEnd = xyzPositionEnd - stepVector * 0.5f;
183 int rowEnd = -1, colEnd = -1, nSkip = 0, nSteps = digitizerParams.nSimSteps;
184 while (!sSegmentation->
localToDetector(xyzPositionStart.X(), xyzPositionStart.Z(), rowStart, colStart, mGeometry->
getIOTOFLayer(chipID))) {
185 if (++nSkip > digitizerParams.nSimSteps) {
186 LOG(
debug) <<
"Hit position out of bounds for detector ID " << chipID;
189 xyzPositionStart += stepVector;
193 if (++nSkip > digitizerParams.nSimSteps) {
194 LOG(
debug) <<
"Hit position out of bounds for detector ID " << chipID;
197 xyzPositionEnd += stepVector;
200 if (rowStart > rowEnd) {
201 std::swap(rowStart, rowEnd);
203 if (colStart > colEnd) {
204 std::swap(colStart, colEnd);
208 rowStart -= digitizerParams.responseMatrixSize / 2;
209 rowEnd += digitizerParams.responseMatrixSize / 2;
210 rowStart = std::max(rowStart, 0);
211 colStart = std::max(colStart, 0);
213 rowEnd = std::min(rowEnd, (subdetectorID == 0 ? sSegmentation->
mITofSpecsConfig.
NRows : sSegmentation->mOTofSpecsConfig.NRows) - 1);
214 colEnd = std::min(colEnd, (subdetectorID == 0 ? sSegmentation->
mITofSpecsConfig.
NCols : sSegmentation->mOTofSpecsConfig.NCols) - 1);
215 rowSpan = rowEnd - rowStart + 1;
216 colSpan = colEnd - colStart + 1;
218 respMatrix =
new float*[rowSpan];
219 for (
int i = 0;
i < rowSpan; ++
i) {
220 respMatrix[
i] =
new float[colSpan]();
223 int rowPrev = -1, colPrev = -1,
row = 0,
col = 0;
224 if (!respMatrix || rowSpan <= 0 || colSpan <= 0) {
231 auto& currentPosLocal = xyzPositionStart;
232 for (
int iStep = nSteps; iStep--;) {
234 if (
row != rowPrev ||
col != colPrev) {
239 currentPosLocal += stepVector;
241 for (
int irow = digitizerParams.responseMatrixSize; irow--;) {
242 int rowDest =
row + irow - (digitizerParams.responseMatrixSize / 2) - rowStart;
243 if (rowDest < 0 || rowDest >= rowSpan) {
246 for (
int icol = digitizerParams.responseMatrixSize; icol--;) {
247 int colDest =
col + icol - (digitizerParams.responseMatrixSize / 2) - colStart;
248 if (colDest < 0 || colDest >= colSpan) {
251 respMatrix[rowDest][colDest] += 1.;
258double Digitizer::smearTime(
double time)
const
262 if (digitizerParams.timeResolution > 0) {
263 return time + gRandom->Gaus(0, digitizerParams.timeResolution);
269int Digitizer::energyToCharge(
float energyLoss)
const
275 return static_cast<int>(energyLoss * digitizerParams.energyToNElectrons);
279bool Digitizer::isEfficient()
const
283 return gRandom->Uniform() < digitizerParams.efficiency;
289 LOG(info) <<
"Filling output container with digits from chips";
290 LOG(
debug) <<
"Number of chips: " << mChips.size();
297 const auto* extraLabelBuffer = mExtraLabelBuffer.empty() ? nullptr : mExtraLabelBuffer.front().get();
298 for (
auto& chip : mChips) {
300 if (chip.isDisabled()) {
306 if (chip.isEmpty()) {
310 auto& chipDigits = chip.getDigits();
311 for (
const auto& [
key, digit] : chipDigits) {
313 if (digit.getCharge() < digitizerParams.chargeThreshold) {
317 int digitID = mDigits->size();
318 mDigits->emplace_back(digit.getChipIndex(), digit.getRow(), digit.getColumn(), digit.getCharge(), digit.getTime());
320 mMCLabels->
addElement(digitID, digit.getLabel().mLabel);
322 auto labelRef = digit.getLabel();
324 while (mMCLabels && extraLabelBuffer !=
nullptr && labelRef.mNext >= 0) {
325 labelRef = (*extraLabelBuffer)[labelRef.mNext];
326 mMCLabels->
addElement(digitID, labelRef.mLabel);
333 rof.
setBCData(mContinuous ? mROFRecordIR : mEventTime);
334 mROFRecords->push_back(rof);
335 LOG(
debug) <<
"Created ROF record with " << mDigits->size() <<
" digits";
342void Digitizer::registerDigits(
Chip& chip, uint32_t roFrame,
double time,
int nROF,
349 if (!existingDigit) {
354 const int storedCharge = existingDigit->
getCharge();
355 existingDigit->
setCharge(storedCharge + nElectrons);
360 std::vector<o2::iotof::McLabelRef>* extra = getExtraLabelBuffer(roFrame);
361 auto labelRef = existingDigit->
getLabel();
362 const auto next =
static_cast<int>(extra->size());
363 extra->emplace_back(
label, labelRef.mNext);
364 labelRef.
mNext = next;
Definition of the ALICE3 TOF digitizer.
math_utils::Point3D< T > GetPos() const
unsigned short GetDetectorID() const
static const DPLDigitizerParam & Instance()
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...
o2::iotof::LabeledDigit * findDigit(ULong64_t key)
reset points container
void addDigit(UShort_t row, UShort_t col, Int_t charge, double time, o2::MCCompLabel label)
Int_t getChipIndex() const
void setTime(double time)
static UInt_t getOrderingKey(UShort_t chipindex, UShort_t row, UShort_t col)
void init()
Initialize the digitizer.
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.
int getIOTOFLayer(int index) const
McLabelRef getLabel() const
void setLabel(McLabelRef label)
ChipSpecifics mITofSpecsConfig
bool localToDetector(float x, float z, int &iRow, int &iCol, const int subDetectorID)
void setCharge(Int_t charge)
Set the charge of the digit.
Int_t getCharge() const
Get the accumulated charged of the digit.
math_utils::Point3D< Float_t > GetPosStart() const
void setBCData(const BCData &bc)
void setFirstEntry(int idx)
int getFirstEntry() const
GLuint GLsizei const GLchar * label
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
double getTimeNS() const
get time in ns from orbit=0/bc=0
int mNext
eventual next contribution to the same pixel
o2::MCCompLabel mLabel
hit label
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"