CbmRoot
Loading...
Searching...
No Matches
CbmRichDigitizer.cxx
Go to the documentation of this file.
1/* Copyright (C) 2015-2024 GSI/JINR-LIT, Darmstadt/Dubna
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Martin Beyer, Andrey Lebedev [committer], Volker Friese, Florian Uhlig, Semen Lebedev */
4
12#include "CbmRichDigitizer.h"
13
14#include "CbmLink.h"
15#include "CbmMCTrack.h"
16#include "CbmMatch.h"
17#include "CbmRichDetectorData.h"
18#include "CbmRichDigi.h"
20#include "CbmRichGeoManager.h"
21#include "CbmRichPoint.h"
22
23#include <FairRootManager.h>
24#include <Logger.h>
25
26#include <TClonesArray.h>
27#include <TMath.h>
28#include <TRandom.h>
29#include <TStopwatch.h>
30
31#include <cstdlib>
32#include <iomanip>
33#include <iostream>
34
35using std::fixed;
36using std::left;
37using std::right;
38using std::setprecision;
39using std::setw;
40
42{
43 std::cout << std::endl;
44 LOG(info) << "==========================================================";
45 LOG(info) << GetName() << ": Initialisation";
46
47 if (!fEventMode) { LOG(info) << "CbmRichDigitizer uses TimeBased mode."; }
48 else {
49 LOG(info) << "CbmRichDigitizer uses Events mode.";
50 }
51
52 FairRootManager* manager = FairRootManager::Instance();
53
54 // --- Initialise helper singletons in order not to do it in event
55 // --- processing (spoils timing measurement)
58
59 fRichPoints = static_cast<TClonesArray*>(manager->GetObject("RichPoint"));
60 if (!fRichPoints) LOG(fatal) << "CbmRichDigitizer::Init: No RichPoint array!";
61
62 fMcTracks = static_cast<TClonesArray*>(manager->GetObject("MCTrack"));
63 if (!fMcTracks) LOG(fatal) << "CbmRichDigitizer::Init: No MCTrack array!";
64
66
67 // --- Read list of inactive channels
68 if (!fInactiveChannelFileName.IsNull()) {
69 LOG(info) << GetName() << ": Reading inactive channels from " << fInactiveChannelFileName;
70 auto result = ReadInactiveChannels();
71 if (!result.second) {
72 LOG(error) << GetName() << ": Error in reading from file! Task will be inactive.";
73 return kFATAL;
74 }
75 LOG(info) << GetName() << ": " << std::get<0>(result) << " lines read from file, " << fInactiveChannels.size()
76 << " channels set inactive";
77 }
78
79 LOG(info) << GetName() << ": Initialisation successful";
80 LOG(info) << "==========================================================";
81 std::cout << std::endl;
82
83 return kSUCCESS;
84}
85
86void CbmRichDigitizer::Exec(Option_t* /*option*/)
87{
88 TStopwatch timer;
89 timer.Start();
90
91 Double_t oldEventTime = fCurrentEventTime;
93
94 Int_t nPoints = ProcessMcEvent();
95
96 Double_t tNoiseStart = fEventNum ? oldEventTime : fRunStartTime;
98
100 Double_t processTime = fEventMode ? -1. : fCurrentEventTime;
101 Int_t nDigis = ProcessBuffers(processTime);
102
103 // --- Statistics
104 timer.Stop();
105 fEventNum++;
106 fNofPoints += nPoints;
107 fNofDigis += nDigis;
108 fTimeTot += timer.RealTime();
109
110 // --- Event log
111 LOG(info) << "+ " << setw(15) << GetName() << ": Event " << setw(6) << right << fCurrentEvent << " at " << fixed
112 << setprecision(3) << fCurrentEventTime << " ns, points: " << nPoints << ", digis: " << nDigis
113 << ". Exec time " << setprecision(6) << timer.RealTime() << " s.";
114}
115
117{
118 TStopwatch timer;
119 if (!fEventMode) {
120 std::cout << std::endl;
121 LOG(info) << GetName() << ": Finish run";
122 LOG(info) << GetName() << ": Processing analogue buffers";
123 timer.Start();
124 Int_t nDigis = ProcessBuffers(-1.);
125 timer.Stop();
126 fTimeTot += timer.RealTime();
127 LOG(info) << GetName() << ": " << nDigis << " digis created and sent to DAQ";
128 fNofDigis += nDigis;
129 }
130
131 std::cout << std::endl;
132 LOG(info) << "=====================================";
133 LOG(info) << GetName() << ": Run summary";
134 LOG(info) << "Events processed : " << fEventNum;
135 LOG(info) << "RichPoint / event : " << setprecision(6) << fNofPoints / Double_t(fEventNum);
136 LOG(info) << "RichDigi / event : " << fNofDigis / Double_t(fEventNum);
137 LOG(info) << "Digis per point : " << setprecision(6) << fNofDigis / Double_t(fNofPoints);
138 LOG(info) << "Real time per event : " << fTimeTot / Double_t(fEventNum) << " s";
139 LOG(info) << "=====================================";
140}
141
143{
144 Int_t nofRichPoints = fRichPoints->GetEntriesFast();
145
146 LOG(debug) << fName << ": EventNum:" << fCurrentEvent << " InputNum:" << fCurrentInput
147 << " EventTime:" << fCurrentEventTime << " nofRichPoints:" << nofRichPoints;
148
149 for (Int_t j = 0; j < nofRichPoints; j++) {
150 CbmRichPoint* point = static_cast<CbmRichPoint*>(fRichPoints->At(j));
152 }
153
155
156 return nofRichPoints;
157}
158
159void CbmRichDigitizer::ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t eventNum, Int_t inputNum)
160{
161 Int_t address = point->GetDetectorID();
162 if (address == -1) {
163 LOG(error) << "CbmRichDigitizer::ProcessPoint: address == -1";
164 return;
165 }
166 Int_t trackId = point->GetTrackID();
167 if (trackId < 0) return;
168 CbmMCTrack* mcTrack = static_cast<CbmMCTrack*>(fMcTracks->At(trackId));
169 if (!mcTrack) return;
170 Int_t gcode = TMath::Abs(mcTrack->GetPdgCode());
171
172 Bool_t isDetected = false;
173 // For photons weight with quantum efficiency of PMT
174 if (gcode == 50000050) {
175 TVector3 mom;
176 point->Momentum(mom);
177 Double_t momTotal = TMath::Sqrt(mom.Px() * mom.Px() + mom.Py() * mom.Py() + mom.Pz() * mom.Pz());
178 isDetected = fPmt.isPhotonDetected(fDetectorType, momTotal);
179 }
180 else { // If not photon
181 // Worst case: assume that all charged particles crossing
182 // the PMTplane leave Cherenkov light in the PMTglass which will be detected
183 isDetected = true;
184 }
185
186 if (isDetected) {
187 Double_t time = fCurrentEventTime + point->GetTime();
188 CbmLink link(1., pointId, eventNum, inputNum);
189 AddSignalToBuffer(address, time, link);
190 if (gcode == 50000050 && address > 0) AddCrossTalk(address, time, link);
191 if (fClusterSize > 0 && mcTrack->GetCharge() != 0. && address > 0) {
192 AddChargedParticleCluster(address, time, eventNum, inputNum);
193 }
194 }
195}
196
197void CbmRichDigitizer::AddSignalToBuffer(Int_t address, Double_t time, const CbmLink& link)
198{
199 fSignalBuffer[address].emplace_back(std::make_pair(time, new CbmLink(link)));
200}
201
202void CbmRichDigitizer::AddCrossTalk(Int_t address, Double_t time, const CbmLink& link)
203{
204 std::vector<Int_t> directHorizontalPixels =
206 std::vector<Int_t> directVerticalPixels =
208 std::vector<Int_t> diagonalPixels = CbmRichDigiMapManager::GetInstance().GetDiagonalNeighbourPixels(address);
209 /* clang-format off */
210 Double_t crosstalkProbability = 1 - pow(1 - fCrossTalkProbability[0], directHorizontalPixels.size()) *
211 pow(1 - fCrossTalkProbability[1], directVerticalPixels.size()) *
212 pow(1 - fCrossTalkProbability[2], diagonalPixels.size());
213 Int_t crosstalkAddress = -1;
214 if (gRandom->Uniform() < crosstalkProbability) {
215 // Split into 3 intervals based on crosstalk probability and number of pixels
216 Double_t denom = directHorizontalPixels.size() * fCrossTalkProbability[0] +
217 directVerticalPixels.size() * fCrossTalkProbability[1] +
218 diagonalPixels.size() * fCrossTalkProbability[2];
219 // Threshold values for end of each interval
220 Double_t thHorizontal = directHorizontalPixels.size() * fCrossTalkProbability[0] / denom;
221 Double_t thVertical = directVerticalPixels.size() * fCrossTalkProbability[1] / denom + thHorizontal;
222 Double_t rnd = gRandom->Uniform();
223 if (rnd < thHorizontal) {
224 crosstalkAddress = directHorizontalPixels[gRandom->Integer(directHorizontalPixels.size())];
225 }
226 else if (rnd < thVertical) {
227 crosstalkAddress = directVerticalPixels[gRandom->Integer(directVerticalPixels.size())];
228 } else {
229 crosstalkAddress = diagonalPixels[gRandom->Integer(diagonalPixels.size())];
230 }
231 }
232 /* clang-format on */
233 if (crosstalkAddress != -1) AddSignalToBuffer(crosstalkAddress, time, link);
234}
235
236void CbmRichDigitizer::AddChargedParticleCluster(Int_t address, Double_t time, Int_t eventNum, Int_t inputNum)
237{
238 // pixelId % 8 is x index, pixelId / 8 is y index
239 auto sourcePixelIdx = std::div(CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(address)->fPixelId, 8);
240 std::vector<Int_t> neighbourAddresses =
242 for (const Int_t& addr : neighbourAddresses) {
243 auto iPixelIdx = std::div(CbmRichDigiMapManager::GetInstance().GetPixelDataByAddress(addr)->fPixelId, 8);
244 Double_t d = TMath::Sqrt((sourcePixelIdx.rem - iPixelIdx.rem) * (sourcePixelIdx.rem - iPixelIdx.rem)
245 + (sourcePixelIdx.quot - iPixelIdx.quot) * (sourcePixelIdx.quot - iPixelIdx.quot));
246 if (gRandom->Uniform(1.) < fClusterSignalProbability / d) {
247 CbmLink link(1., -1, eventNum, inputNum);
248 AddSignalToBuffer(addr, time, link);
249 }
250 }
251}
252
253void CbmRichDigitizer::AddEventNoise(Int_t eventNum, Int_t inputNum)
254{
255 Int_t nofPixels = static_cast<Int_t>(CbmRichDigiMapManager::GetInstance().GetPixelAddresses().size());
256 Double_t nofRichPoints = fRichPoints->GetEntriesFast();
257 Double_t nofNoiseDigis = nofRichPoints * nofPixels * fEventNoiseInterval * (fEventNoiseRate / 1.e9);
258
259 LOG(debug) << "CbmRichDigitizer::AddEventNoise NofAllPixels:" << nofPixels << " nofNoiseDigis:" << nofNoiseDigis;
260
261 for (Int_t j = 0; j < nofNoiseDigis; j++) {
263 CbmLink link(1., -1, eventNum, inputNum);
264 Double_t time = fCurrentEventTime + gRandom->Uniform(0, fEventNoiseInterval);
265 AddSignalToBuffer(address, time, link);
266 }
267}
268
269void CbmRichDigitizer::AddDarkRateNoise(Double_t oldEventTime, Double_t newEventTime)
270{
271 Int_t nofPixels = static_cast<Int_t>(CbmRichDigiMapManager::GetInstance().GetPixelAddresses().size());
272 Double_t dT = newEventTime - oldEventTime;
273 Double_t nofNoisePixels = nofPixels * dT * (fDarkRatePerPixel / 1.e9);
274
275 LOG(debug) << "CbmRichDigitizer::AddDarkRateNoise deltaTime:" << dT << " nofPixels:" << nofPixels
276 << " nofNoisePixels:" << nofNoisePixels;
277
278 for (Int_t j = 0; j < nofNoisePixels; j++) {
280 CbmLink link(1., -1, -1, -1);
281 Double_t time = gRandom->Uniform(oldEventTime, newEventTime);
282 AddSignalToBuffer(address, time, link);
283 }
284}
285
286Int_t CbmRichDigitizer::ProcessBuffers(Double_t processTime)
287{
288 Double_t maxNewDigiTime = processTime - fPixelDeadTime;
289 Int_t nofDigis {};
290
291 for (auto& dm : fSignalBuffer) {
292 std::sort(
293 dm.second.begin(), dm.second.end(),
294 [](const std::pair<Double_t, CbmLink*>& a, const std::pair<Double_t, CbmLink*>& b) { return a.first < b.first; });
295
296 CbmRichDigi* digi = nullptr;
297 CbmMatch* digiMatch = nullptr;
298 auto it = dm.second.begin();
299 for (; it != dm.second.end(); ++it) {
300 Double_t signalTime = it->first;
301 if (processTime >= 0. && signalTime > processTime) break;
302 CbmLink* link = it->second;
303 Bool_t createsDigi = true;
304
305 auto itFpm = fPixelsLastFiredTime.find(dm.first);
306 if (itFpm != fPixelsLastFiredTime.end()) {
307 Double_t lastFiredTime = itFpm->second;
308 if (signalTime - lastFiredTime < fPixelDeadTime) createsDigi = false;
309 }
310
311 if (createsDigi) {
312 if (digi) { // Add previous digi if exists
313 fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
314 nofDigis++;
315 digi = nullptr; // Needed because of potential break statement
316 digiMatch = nullptr;
317 }
318 Double_t digiTime = signalTime + gRandom->Gaus(0., fTimeResolution);
319 if (processTime >= 0. && digiTime > maxNewDigiTime) break;
320 digi = new CbmRichDigi();
321 digi->SetAddress(dm.first);
322 digi->SetTime(digiTime);
323 if (fCreateMatches) { // If fCreateMatches is false, SendData does not take over ownership via unique_ptr
324 digiMatch = new CbmMatch();
325 digiMatch->AddLink(*link);
326 }
327 fPixelsLastFiredTime[dm.first] = signalTime; // Deadtime is from signal to signal
328 }
329 else {
330 if (digi && digiMatch) digiMatch->AddLink(*link);
331 }
332 delete it->second;
333 }
334 dm.second.erase(dm.second.begin(), it);
335 if (digi) { // Add last digi if exists
336 fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
337 nofDigis++;
338 }
339 }
340
341 return nofDigis;
342}
343
ClassImp(CbmConverterManager)
Class for producing RICH digis from from MCPoints.
virtual std::pair< size_t, bool > ReadInactiveChannels()
Set of inactive channels, indicated by CbmAddress.
Int_t fCurrentEvent
Number of current input.
TString fInactiveChannelFileName
Time of current MC event [ns].
std::set< uint32_t > fInactiveChannels
Name of file with inactive channels.
Double_t fRunStartTime
Flag for creation of links to MC.
void GetEventInfo()
Get event information.
Int_t fCurrentInput
Start time of run [ns].
Double_t fCurrentEventTime
Number of current MC entry.
Int_t fCurrentMCEntry
Number of current MC event.
Bool_t fCreateMatches
Flag for production of inter-event noise.
Bool_t fProduceNoise
Flag for event-by-event mode.
void SendData(Double_t time, CbmRichDigi *digi, CbmMatch *match=nullptr)
double GetCharge() const
Charge of the associated particle.
int32_t GetPdgCode() const
Definition CbmMCTrack.h:68
void AddLink(const CbmLink &newLink)
Definition CbmMatch.cxx:47
static CbmRichDigiMapManager & GetInstance()
Return Instance of CbmRichGeoManager.
std::vector< Int_t > GetDirectNeighbourPixels(Int_t address, Bool_t horizontal=true, Bool_t vertical=true)
Return the addresses of the direct neighbour pixels.
std::vector< Int_t > GetNxNNeighbourPixels(Int_t address, Int_t n)
Return the addresses of pixels in a (2n+1)*(2n+1) grid, with the address pixel in the center of the g...
Int_t GetRandomPixelAddress()
Return random address. Needed for noise digi.
std::vector< Int_t > GetPixelAddresses()
Return addresses of all pixels.
std::vector< Int_t > GetDiagonalNeighbourPixels(Int_t address)
Return the addresses of the diagonal neighbour pixels.
void SetTime(double time)
Definition CbmRichDigi.h:88
double GetTime() const
Definition CbmRichDigi.h:72
void SetAddress(int32_t address)
Definition CbmRichDigi.h:83
Class for producing RICH digis from from MCPoints.
Int_t ProcessBuffers(Double_t processTime)
Process signals in all buffers until processTime. New Digis are only created until processTime - fPix...
virtual void Exec(Option_t *option)
std::map< Int_t, Double_t > fPixelsLastFiredTime
TClonesArray * fMcTracks
Int_t ProcessMcEvent()
Process current MC event.
std::map< Int_t, std::vector< std::pair< Double_t, CbmLink * > > > fSignalBuffer
TClonesArray * fRichPoints
std::array< Double_t, 3 > fCrossTalkProbability
Double_t fClusterSignalProbability
void ProcessPoint(CbmRichPoint *point, Int_t pointId, Int_t eventNum, Int_t inputNum)
CbmRichPmtTypeEnum fDetectorType
virtual InitStatus Init()
void AddEventNoise(Int_t eventNum, Int_t inputNum)
Add additional noise for each event based on fEventNoiseRate and fEventNoiseInterval.
void AddCrossTalk(Int_t address, Double_t time, const CbmLink &link)
Add crosstalk assuming fCrossTalkProbability. Only add maximum one cross talk signal per MC point....
virtual void Finish()
void AddSignalToBuffer(Int_t address, Double_t time, const CbmLink &link)
void AddChargedParticleCluster(Int_t address, Double_t time, Int_t eventNum, Int_t inputNum)
Add additional signals to nearby pixels if a charged particle directly passes through the PMT,...
void AddDarkRateNoise(Double_t oldEventTime, Double_t newEventTime)
static CbmRichGeoManager & GetInstance()
Bool_t isPhotonDetected(CbmRichPmtTypeEnum detType, Double_t momentum)