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
18
21
22#include <TRandom.h>
23#include <vector>
24#include <iostream>
25#include <numeric>
26#include <algorithm>
27#include <fairlogger/Logger.h>
28
29namespace o2::iotof
30{
31
32o2::iotof::Segmentation* Digitizer::sSegmentation = nullptr;
33
34//_______________________________________________________________________
36{
37 const int numberOfChips = mGeometry->getSize();
38 mChips.resize(numberOfChips);
39 for (int i = numberOfChips; i--;) {
40 mChips[i].setChipIndex(i);
45
51 }
52
53 LOG(info) << "Initializing IOTOF digitizer";
54 LOG(info) << " Time resolution: " << mTimeResolution * 1e3 << " ps";
55 LOG(info) << " Charge threshold: " << mChargeThreshold << " electrons";
56 LOG(info) << " Detection efficiency: " << mEfficiency * 100 << " %";
57 LOG(info) << " Continuous mode: " << (mContinuous ? "ON" : "OFF");
58 sSegmentation = o2::iotof::Segmentation::Instance();
59}
60
61//_______________________________________________________________________
62void Digitizer::process(const std::vector<o2::itsmft::Hit>* hits, int evID, int srcID)
63{
64 // Digitize hits from a single event
65 LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID;
66
67 if (!hits || hits->empty()) {
68 return;
69 }
70
71 // Sort hits by detector ID for better cache locality
72 std::vector<int> hitIdx(hits->size());
73 std::iota(hitIdx.begin(), hitIdx.end(), 0);
74 std::sort(hitIdx.begin(), hitIdx.end(),
75 [hits](int lhs, int rhs) {
76 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
77 });
78
79 // Process each hit
80 for (int i : hitIdx) {
81 processHit((*hits)[i], evID, srcID);
82 }
83
84 // In triggered mode, flush output after each event
85 if (!mContinuous) {
86 LOG(debug) << "Inner flushing for non-continuous mode";
88 }
89}
90
91//_______________________________________________________________________
92void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
93{
94 // Process a single hit and create a digit if it passes all cuts
95
96 // Apply efficiency cut
97 if (!isEfficient()) {
98 LOG(debug) << "Hit rejected by efficiency cut";
99 return;
100 }
101
102 // Get detector element ID
103 int chipID = hit.GetDetectorID();
104 auto& chip = mChips[chipID];
105 if (chip.isDisabled()) {
106 LOG(debug) << "Hit rejected because chip " << chipID << " is disabled";
107 return;
108 }
109
110 // Convert energy loss to charge (number of electrons)
111 float energyLoss = hit.GetEnergyLoss(); // in GeV
112 int charge = energyToCharge(energyLoss);
113
114 // Apply charge threshold
115 if (charge < mChargeThreshold) {
116 LOG(debug) << "Hit rejected by charge threshold: " << charge << " < " << mChargeThreshold;
117 return;
118 }
119
120 // Get hit time and apply smearing
121 // Hit time is in seconds, convert to ns and add event time
122 double hitTime = hit.GetTime() * sec2ns; // convert to ns
123 double eventTimeNS = mEventTime.getTimeNS(); // event time since orbit 0
124 double absoluteTime = hitTime + eventTimeNS; // absolute time
125 double smearedTime = smearTime(absoluteTime); // apply detector resolution
126
127 if (chipID < 0 || chipID >= mGeometry->getSize() || mGeometry->getSize() < 1) {
128 LOG(debug) << "Invalid detector ID: " << chipID << ", geometry size: " << mGeometry->getSize();
129 return; // invalid detector ID
130 }
131 const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID());
132
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
135
136 int row = 0; // Will be determined from start hit position
137 int col = 0; // Will be determined from start hit position
138
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
142 }
143
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
148
149 registerDigits(chip, roFrameAbs, smearedTime, nROF, static_cast<uint16_t>(row), static_cast<uint16_t>(col), charge, label);
150}
151
152//_______________________________________________________________________
153double Digitizer::smearTime(double time) const
154{
155 // Apply Gaussian smearing to simulate detector time resolution
156 if (mTimeResolution > 0) {
157 return time + gRandom->Gaus(0, mTimeResolution);
158 }
159 return time;
160}
161
162//_______________________________________________________________________
163int Digitizer::energyToCharge(float energyLoss) const
164{
165 // Convert energy loss (GeV) to number of electrons
166 // Typical value: 3.6 eV per electron-hole pair in silicon
167 // energyLoss is in GeV, mEnergyToCharge is GeV per electron
168 return static_cast<int>(energyLoss / mEnergyToCharge);
169}
170
171//_______________________________________________________________________
172bool Digitizer::isEfficient() const
173{
174 // Apply efficiency cut using random number
175 return gRandom->Uniform() < mEfficiency;
176}
177
178//_______________________________________________________________________
180{
181 LOG(info) << "Filling output container with digits from chips";
182 LOG(debug) << "Number of chips: " << mChips.size();
183
185 rof.setFirstEntry(mDigits->size()); // index of the first digit
186
187 const auto* extraLabelBuffer = mExtraLabelBuffer.empty() ? nullptr : mExtraLabelBuffer.front().get();
188 for (auto& chip : mChips) {
189
190 if (chip.isDisabled()) {
191 continue;
192 }
193
195
196 if (chip.isEmpty()) {
197 continue;
198 }
199
200 auto& chipDigits = chip.getDigits();
201 for (const auto& [key, digit] : chipDigits) {
202
207
208 int digitID = mDigits->size();
209 mDigits->emplace_back(digit.getChipIndex(), digit.getRow(), digit.getColumn(), digit.getCharge(), digit.getTime());
210 if (mMCLabels) {
211 mMCLabels->addElement(digitID, digit.getLabel().mLabel);
212 }
213 auto labelRef = digit.getLabel();
214
215 while (mMCLabels && extraLabelBuffer != nullptr && labelRef.mNext >= 0) {
216 labelRef = (*extraLabelBuffer)[labelRef.mNext];
217 mMCLabels->addElement(digitID, labelRef.mLabel);
218 }
219 }
220 chipDigits.clear(); // clear chip digits after copying to output
221 }
222
223 rof.setNEntries(mDigits->size() - rof.getFirstEntry()); // number of digits
224 rof.setBCData(mContinuous ? mROFRecordIR : mEventTime);
225 mROFRecords->push_back(rof);
226 LOG(debug) << "Created ROF record with " << mDigits->size() << " digits";
227
228 // extraLabelBuffer.clear(); // clear buffer for extra labels
229 // mExtraLabelBuffer.emplace_back(mExtraLabelBuffer.front().release()); // move current buffer to the end
230 // mExtraLabelBuffer.pop_front();
231}
232
233void Digitizer::registerDigits(Chip& chip, uint32_t roFrame, double time, int nROF,
234 uint16_t row, uint16_t col, int nElectrons, o2::MCCompLabel& label)
235{
236 (void)nROF;
237
239 o2::iotof::LabeledDigit* existingDigit = chip.findDigit(key);
240 if (!existingDigit) {
241 // No existing digit, create a new one
242 chip.addDigit(row, col, nElectrons, time, label);
243 } else {
244 // Digit already exists, update charge and labels
245 const int storedCharge = existingDigit->getCharge();
246 existingDigit->setCharge(storedCharge + nElectrons);
247 existingDigit->setTime(std::min(existingDigit->getTime(), time));
248 if (existingDigit->getLabel().mLabel == label) {
249 return; // don't store the same label twice
250 }
251 std::vector<o2::iotof::McLabelRef>* extra = getExtraLabelBuffer(roFrame);
252 auto labelRef = existingDigit->getLabel();
253 const auto next = static_cast<int>(extra->size());
254 extra->emplace_back(label, labelRef.mNext);
255 labelRef.mNext = next;
256 existingDigit->setLabel(labelRef);
257 }
258}
259
260} // namespace o2::iotof
std::ostringstream debug
int16_t charge
Definition RawEventData.h:5
int16_t time
Definition RawEventData.h:4
int32_t i
uint32_t col
Definition RawData.h:4
Definition of the ALICE3 TOF digitizer.
StringRef key
int GetTrackID() const
Definition BaseHits.h:30
V GetEnergyLoss() const
Definition BaseHits.h:103
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 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...
Definition Chip.h:41
o2::iotof::LabeledDigit * findDigit(ULong64_t key)
reset points container
Definition Chip.h:89
void addDigit(UShort_t row, UShort_t col, Int_t charge, double time, o2::MCCompLabel label)
Definition Chip.cxx:35
Int_t getChipIndex() const
Definition Chip.h:67
double getTime() const
Definition Digit.h:38
void setTime(double time)
Definition Digit.h:35
static UInt_t getOrderingKey(UShort_t chipindex, UShort_t row, UShort_t col)
Definition Digit.h:40
void init()
Initialize the digitizer.
Definition Digitizer.cxx:35
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.
Definition Digitizer.cxx:62
int getIOTOFLayer(int index) const
McLabelRef getLabel() const
Definition Digit.h:67
void setLabel(McLabelRef label)
Definition Digit.h:66
bool localToDetector(float x, float z, int &iRow, int &iCol, const int subDetectorID)
void setCharge(Int_t charge)
Set the charge of the digit.
Definition Digit.h:62
Int_t getCharge() const
Get the accumulated charged of the digit.
Definition Digit.h:49
math_utils::Point3D< Float_t > GetPosStart() const
Definition Hit.h:60
void setNEntries(int n)
Definition ROFRecord.h:48
void setBCData(const BCData &bc)
Definition ROFRecord.h:44
void setFirstEntry(int idx)
Definition ROFRecord.h:47
int getFirstEntry() const
Definition ROFRecord.h:63
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
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
Definition Digit.h:53
o2::MCCompLabel mLabel
hit label
Definition Digit.h:52
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row