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 LOG(info) << "Initializing IOTOF digitizer";
38 LOG(info) << " Time resolution: " << mTimeResolution * 1e3 << " ps";
39 LOG(info) << " Charge threshold: " << mChargeThreshold << " electrons";
40 LOG(info) << " Detection efficiency: " << mEfficiency * 100 << " %";
41 LOG(info) << " Continuous mode: " << (mContinuous ? "ON" : "OFF");
42 sSegmentation = o2::iotof::Segmentation::Instance();
43}
44
45//_______________________________________________________________________
46void Digitizer::process(const std::vector<o2::itsmft::Hit>* hits, int evID, int srcID)
47{
48 // Digitize hits from a single event
49 LOG(debug) << "Digitizing IOTOF hits: " << hits->size() << " hits from event " << evID << " source " << srcID;
50
51 if (!hits || hits->empty()) {
52 return;
53 }
54
55 // Sort hits by detector ID for better cache locality
56 std::vector<int> hitIdx(hits->size());
57 std::iota(hitIdx.begin(), hitIdx.end(), 0);
58 std::sort(hitIdx.begin(), hitIdx.end(),
59 [hits](int lhs, int rhs) {
60 return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID();
61 });
62
63 // Process each hit
64 for (int i : hitIdx) {
65 processHit((*hits)[i], evID, srcID);
66 }
67
68 // In triggered mode, flush output after each event
69 if (!mContinuous) {
71 }
72}
73
74//_______________________________________________________________________
75void Digitizer::processHit(const o2::itsmft::Hit& hit, int evID, int srcID)
76{
77 // Process a single hit and create a digit if it passes all cuts
78
79 // Apply efficiency cut
80 if (!isEfficient()) {
81 LOG(debug) << "Hit rejected by efficiency cut";
82 return;
83 }
84
85 // Get detector element ID
86 int detID = hit.GetDetectorID();
87
88 // Convert energy loss to charge (number of electrons)
89 float energyLoss = hit.GetEnergyLoss(); // in GeV
90 int charge = energyToCharge(energyLoss);
91
92 // Apply charge threshold
93 if (charge < mChargeThreshold) {
94 LOG(debug) << "Hit rejected by charge threshold: " << charge << " < " << mChargeThreshold;
95 return;
96 }
97
98 // Get hit time and apply smearing
99 // Hit time is in seconds, convert to ns and add event time
100 double hitTime = hit.GetTime() * sec2ns; // convert to ns
101 double eventTimeNS = mEventTime.getTimeNS(); // event time since orbit 0
102 double absoluteTime = hitTime + eventTimeNS; // absolute time
103 double smearedTime = smearTime(absoluteTime); // apply detector resolution
104
105 // For now, use simple row/col mapping from detector ID
106 // TODO: Implement proper segmentation when geometry is finalized
107 uint16_t chipIndex = static_cast<uint16_t>(detID);
108
109 if (detID > mGeometry->getSize() || mGeometry->getSize() < 1) {
110 LOG(debug) << "Invalid detector ID: " << detID;
111 return; // invalid detector ID
112 }
113 const auto& matrix = mGeometry->getMatrixL2G(hit.GetDetectorID());
114
115 math_utils::Vector3D<float> xyzPositionStart(matrix ^ (hit.GetPosStart())); // start position in sensor frame
116 // math_utils::Vector3D<float> xyzPositionEnd(matrix ^ (hit.GetPos())); // end position in sensor frame
117
118 int row = 0; // Will be determined from start hit position
119 int col = 0; // Will be determined from start hit position
120
121 if (!sSegmentation->localToDetector(xyzPositionStart.X(), xyzPositionStart.Z(), row, col, mGeometry->getIOTOFLayer(detID))) {
122 LOG(debug) << "Hit position out of bounds for detector ID " << detID;
123 return; // hit is outside the active area
124 }
125
126 // Create the digit with time information
127 int digID = mDigits->size();
128 mDigits->emplace_back(chipIndex, static_cast<uint16_t>(row), static_cast<uint16_t>(col), charge, smearedTime);
129
130 LOG(debug) << "Created digit #" << digID << " chip=" << chipIndex
131 << " charge=" << charge << " time=" << smearedTime << " ns";
132
133 // Add MC truth label
134 if (mMCLabels) {
135 o2::MCCompLabel lbl(hit.GetTrackID(), evID, srcID, false);
136 mMCLabels->addElement(digID, lbl);
137 }
138}
139
140//_______________________________________________________________________
141double Digitizer::smearTime(double time) const
142{
143 // Apply Gaussian smearing to simulate detector time resolution
144 if (mTimeResolution > 0) {
145 return time + gRandom->Gaus(0, mTimeResolution);
146 }
147 return time;
148}
149
150//_______________________________________________________________________
151int Digitizer::energyToCharge(float energyLoss) const
152{
153 // Convert energy loss (GeV) to number of electrons
154 // Typical value: 3.6 eV per electron-hole pair in silicon
155 // energyLoss is in GeV, mEnergyToCharge is GeV per electron
156 return static_cast<int>(energyLoss / mEnergyToCharge);
157}
158
159//_______________________________________________________________________
160bool Digitizer::isEfficient() const
161{
162 // Apply efficiency cut using random number
163 return gRandom->Uniform() < mEfficiency;
164}
165
166//_______________________________________________________________________
168{
169 // Create ROF record for the current event
170 if (mROFRecords && mDigits && !mDigits->empty()) {
172 rof.setFirstEntry(0);
173 rof.setNEntries(mDigits->size());
174 rof.setBCData(mEventTime);
175 mROFRecords->push_back(rof);
176 LOG(debug) << "Created ROF record with " << mDigits->size() << " digits";
177 }
178}
179
180} // 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.
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
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:46
int getIOTOFLayer(int index) const
bool localToDetector(float x, float z, int &iRow, int &iCol, const int subDetectorID)
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
double getTimeNS() const
get time in ns from orbit=0/bc=0
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row