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
11
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"
19#include "CbmRichGeoHandler.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) {
48 LOG(info) << "CbmRichDigitizer uses TimeBased mode.";
49 }
50 else {
51 LOG(info) << "CbmRichDigitizer uses Events mode.";
52 }
53
54 FairRootManager* manager = FairRootManager::Instance();
55
56 // --- Initialise helper singletons in order not to do it in event
57 // --- processing (spoils timing measurement)
60
61 fRichPoints = static_cast<TClonesArray*>(manager->GetObject("RichPoint"));
62 if (!fRichPoints) LOG(fatal) << "CbmRichDigitizer::Init: No RichPoint array!";
63
64 fMcTracks = static_cast<TClonesArray*>(manager->GetObject("MCTrack"));
65 if (!fMcTracks) LOG(fatal) << "CbmRichDigitizer::Init: No MCTrack array!";
66
68
69 // --- Read list of inactive channels
70 if (!fInactiveChannelFileName.IsNull()) {
71 LOG(info) << GetName() << ": Reading inactive channels from " << fInactiveChannelFileName;
72 auto result = ReadInactiveChannels();
73 if (!result.second) {
74 LOG(error) << GetName() << ": Error in reading from file! Task will be inactive.";
75 return kFATAL;
76 }
77 LOG(info) << GetName() << ": " << std::get<0>(result) << " lines read from file, " << fInactiveChannels.size()
78 << " channels set inactive";
79 }
80
81 LOG(info) << GetName() << ": Initialisation successful";
82 LOG(info) << "==========================================================";
83 std::cout << std::endl;
84
85 return kSUCCESS;
86}
87
88void CbmRichDigitizer::Exec(Option_t* /*option*/)
89{
90 TStopwatch timer;
91 timer.Start();
92
93 Double_t oldEventTime = fCurrentEventTime;
95
96 Int_t nPoints = ProcessMcEvent();
97
98 Double_t tNoiseStart = fEventNum ? oldEventTime : fRunStartTime;
100
101 if (fEventMode) fPixelsLastFiredTime.clear();
102 Double_t processTime = fEventMode ? -1. : fCurrentEventTime;
103 Int_t nDigis = ProcessBuffers(processTime);
104
105 // --- Statistics
106 timer.Stop();
107 fEventNum++;
108 fNofPoints += nPoints;
109 fNofDigis += nDigis;
110 fTimeTot += timer.RealTime();
111
112 // --- Event log
113 LOG(info) << "+ " << setw(15) << GetName() << ": Event " << setw(6) << right << fCurrentEvent << " at " << fixed
114 << setprecision(3) << fCurrentEventTime << " ns, points: " << nPoints << ", digis: " << nDigis
115 << ". Exec time " << setprecision(6) << timer.RealTime() << " s.";
116}
117
119{
120 TStopwatch timer;
121 if (!fEventMode) {
122 std::cout << std::endl;
123 LOG(info) << GetName() << ": Finish run";
124 LOG(info) << GetName() << ": Processing analogue buffers";
125 timer.Start();
126 Int_t nDigis = ProcessBuffers(-1.);
127 timer.Stop();
128 fTimeTot += timer.RealTime();
129 LOG(info) << GetName() << ": " << nDigis << " digis created and sent to DAQ";
130 fNofDigis += nDigis;
131 }
132
133 std::cout << std::endl;
134 LOG(info) << "=====================================";
135 LOG(info) << GetName() << ": Run summary";
136 LOG(info) << "Events processed : " << fEventNum;
137 LOG(info) << "RichPoint / event : " << setprecision(6) << fNofPoints / Double_t(fEventNum);
138 LOG(info) << "RichDigi / event : " << fNofDigis / Double_t(fEventNum);
139 LOG(info) << "Digis per point : " << setprecision(6) << fNofDigis / Double_t(fNofPoints);
140 LOG(info) << "Real time per event : " << fTimeTot / Double_t(fEventNum) << " s";
141 LOG(info) << "=====================================";
142}
143
145{
146 Int_t nofRichPoints = fRichPoints->GetEntriesFast();
147
148 LOG(debug) << fName << ": EventNum:" << fCurrentEvent << " InputNum:" << fCurrentInput
149 << " EventTime:" << fCurrentEventTime << " nofRichPoints:" << nofRichPoints;
150
151 for (Int_t iPoint = 0; iPoint < nofRichPoints; iPoint++) {
152 CbmRichPoint* point = static_cast<CbmRichPoint*>(fRichPoints->At(iPoint));
154 }
155
157
158 return nofRichPoints;
159}
160
161void CbmRichDigitizer::ProcessPoint(CbmRichPoint* point, Int_t pointId, Int_t eventNum, Int_t inputNum)
162{
163 Int_t address = point->GetDetectorID();
164 if (address == -1) {
165 LOG(error) << "CbmRichDigitizer::ProcessPoint: address == -1";
166 return;
167 }
168 Int_t trackId = point->GetTrackID();
169 if (trackId < 0) return;
170 CbmMCTrack* mcTrack = static_cast<CbmMCTrack*>(fMcTracks->At(trackId));
171 if (!mcTrack) return;
172 Int_t gcode = TMath::Abs(mcTrack->GetPdgCode());
173
174 Bool_t isDetected = false;
175 // For photons weight with quantum efficiency of PMT
176 if (gcode == 50000050) {
177 TVector3 mom;
178 point->Momentum(mom);
179 Double_t momTotal = TMath::Sqrt(mom.Px() * mom.Px() + mom.Py() * mom.Py() + mom.Pz() * mom.Pz());
180 isDetected = fPmt.isPhotonDetected(fDetectorType, momTotal);
181 }
182 else { // If not photon
183 // Worst case: assume that all charged particles crossing
184 // the PMTplane leave Cherenkov light in the PMTglass which will be detected
185 isDetected = true;
186 }
187
188 if (isDetected) {
189 Double_t time = fCurrentEventTime + point->GetTime();
190 CbmLink link(1., pointId, eventNum, inputNum);
191 AddSignalToBuffer(address, time, link);
192 if (gcode == 50000050 && address > 0) AddCrossTalk(address, time, link);
193 if (fClusterSize > 0 && mcTrack->GetCharge() != 0. && address > 0) {
194 AddChargedParticleCluster(address, time, eventNum, inputNum);
195 }
196 }
197}
198
199void CbmRichDigitizer::AddSignalToBuffer(Int_t address, Double_t time, const CbmLink& link)
200{
201 fSignalBuffer[address].emplace_back(std::make_pair(time, new CbmLink(link)));
202}
203
204void CbmRichDigitizer::AddCrossTalk(Int_t address, Double_t time, const CbmLink& link)
205{
206 std::vector<Int_t> directHorizontalPixels =
208 std::vector<Int_t> directVerticalPixels =
210 std::vector<Int_t> diagonalPixels = CbmRichGeoHandler::GetInstance().GetDiagonalNeighbourPixels(address);
211 /* clang-format off */
212 Double_t crosstalkProbability = 1 - pow(1 - fCrossTalkProbability[0], directHorizontalPixels.size()) *
213 pow(1 - fCrossTalkProbability[1], directVerticalPixels.size()) *
214 pow(1 - fCrossTalkProbability[2], diagonalPixels.size());
215 Int_t crosstalkAddress = -1;
216 if (gRandom->Uniform() < crosstalkProbability) {
217 // Split into 3 intervals based on crosstalk probability and number of pixels
218 Double_t denom = directHorizontalPixels.size() * fCrossTalkProbability[0] +
219 directVerticalPixels.size() * fCrossTalkProbability[1] +
220 diagonalPixels.size() * fCrossTalkProbability[2];
221 // Threshold values for end of each interval
222 Double_t thHorizontal = directHorizontalPixels.size() * fCrossTalkProbability[0] / denom;
223 Double_t thVertical = directVerticalPixels.size() * fCrossTalkProbability[1] / denom + thHorizontal;
224 Double_t rnd = gRandom->Uniform();
225 if (rnd < thHorizontal) {
226 crosstalkAddress = directHorizontalPixels[gRandom->Integer(directHorizontalPixels.size())];
227 }
228 else if (rnd < thVertical) {
229 crosstalkAddress = directVerticalPixels[gRandom->Integer(directVerticalPixels.size())];
230 } else {
231 crosstalkAddress = diagonalPixels[gRandom->Integer(diagonalPixels.size())];
232 }
233 }
234 /* clang-format on */
235 if (crosstalkAddress != -1) AddSignalToBuffer(crosstalkAddress, time, link);
236}
237
238void CbmRichDigitizer::AddChargedParticleCluster(Int_t address, Double_t time, Int_t eventNum, Int_t inputNum)
239{
240 // pixelId % 8 is x index, pixelId / 8 is y index
241 auto sourcePixelIdx = std::div(CbmRichGeoHandler::GetInstance().GetPixelDataByAddress(address)->fPixelId, 8);
242 std::vector<Int_t> neighbourAddresses = CbmRichGeoHandler::GetInstance().GetNxNNeighbourPixels(address, fClusterSize);
243 for (const Int_t& addr : neighbourAddresses) {
244 auto iPixelIdx = std::div(CbmRichGeoHandler::GetInstance().GetPixelDataByAddress(addr)->fPixelId, 8);
245 Double_t d = TMath::Sqrt((sourcePixelIdx.rem - iPixelIdx.rem) * (sourcePixelIdx.rem - iPixelIdx.rem)
246 + (sourcePixelIdx.quot - iPixelIdx.quot) * (sourcePixelIdx.quot - iPixelIdx.quot));
247 if (gRandom->Uniform(1.) < fClusterSignalProbability / d) {
248 CbmLink link(1., -1, eventNum, inputNum);
249 AddSignalToBuffer(addr, time, link);
250 }
251 }
252}
253
255{
256 Int_t nofPixels = static_cast<Int_t>(CbmRichGeoHandler::GetInstance().GetPixelAddresses().size());
257 Double_t nofRichPoints = fRichPoints->GetEntriesFast();
258 Double_t nofNoiseDigis = nofRichPoints * nofPixels * fEventNoiseInterval * (fEventNoiseRate / 1.e9);
259
260 LOG(debug) << "CbmRichDigitizer::AddEventNoise NofAllPixels:" << nofPixels << " nofNoiseDigis:" << nofNoiseDigis;
261
262 for (Int_t j = 0; j < nofNoiseDigis; j++) {
264 CbmLink link(1., -1, eventNum, inputNum);
265 Double_t time = fCurrentEventTime + gRandom->Uniform(0, fEventNoiseInterval);
266 AddSignalToBuffer(address, time, link);
267 }
268}
269
270void CbmRichDigitizer::AddDarkRateNoise(Double_t oldEventTime, Double_t newEventTime)
271{
272 Int_t nofPixels = static_cast<Int_t>(CbmRichGeoHandler::GetInstance().GetPixelAddresses().size());
273 Double_t dT = newEventTime - oldEventTime;
274 Double_t nofNoisePixels = nofPixels * dT * (fDarkRatePerPixel / 1.e9);
275
276 LOG(debug) << "CbmRichDigitizer::AddDarkRateNoise deltaTime:" << dT << " nofPixels:" << nofPixels
277 << " nofNoisePixels:" << nofNoisePixels;
278
279 for (Int_t j = 0; j < nofNoisePixels; j++) {
281 CbmLink link(1., -1, -1, -1);
282 Double_t time = gRandom->Uniform(oldEventTime, newEventTime);
283 AddSignalToBuffer(address, time, link);
284 }
285}
286
288{
289 Double_t maxNewDigiTime = processTime - fPixelDeadTime;
290 Int_t nofDigis{};
291
292 for (auto& dm : fSignalBuffer) {
293 std::sort(
294 dm.second.begin(), dm.second.end(),
295 [](const std::pair<Double_t, CbmLink*>& a, const std::pair<Double_t, CbmLink*>& b) { return a.first < b.first; });
296
297 CbmRichDigi* digi = nullptr;
298 CbmMatch* digiMatch = nullptr;
299 auto it = dm.second.begin();
300 for (; it != dm.second.end(); ++it) {
301 Double_t signalTime = it->first;
302 if (processTime >= 0. && signalTime > processTime) break;
303 CbmLink* link = it->second;
304 Bool_t createsDigi = true;
305
306 auto itFpm = fPixelsLastFiredTime.find(dm.first);
307 if (itFpm != fPixelsLastFiredTime.end()) {
308 Double_t lastFiredTime = itFpm->second;
309 if (signalTime - lastFiredTime < fPixelDeadTime) createsDigi = false;
310 }
311
312 if (createsDigi) {
313 if (digi) { // Add previous digi if exists
314 fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
315 nofDigis++;
316 digi = nullptr; // Needed because of potential break statement
317 digiMatch = nullptr;
318 }
319 Double_t digiTime = signalTime + gRandom->Gaus(0., fTimeResolution);
320 if (processTime >= 0. && digiTime > maxNewDigiTime) break;
321 digi = new CbmRichDigi();
322 digi->SetAddress(dm.first);
323 digi->SetTime(digiTime);
324 if (fCreateMatches) { // If fCreateMatches is false, SendData does not take over ownership via unique_ptr
325 digiMatch = new CbmMatch();
326 digiMatch->AddLink(*link);
327 }
328 fPixelsLastFiredTime[dm.first] = signalTime; // Deadtime is from signal to signal
329 }
330 else {
331 if (digi && digiMatch) digiMatch->AddLink(*link);
332 }
333 delete it->second;
334 }
335 dm.second.erase(dm.second.begin(), it);
336 if (digi) { // Add last digi if exists
337 fCreateMatches ? SendData(digi->GetTime(), digi, digiMatch) : SendData(digi->GetTime(), digi);
338 nofDigis++;
339 }
340 }
341
342 return nofDigis;
343}
344
ClassImp(CbmConverterManager)
Class for producing RICH digis from from MCPoints.
int Int_t
bool Bool_t
virtual std::pair< size_t, bool > ReadInactiveChannels()
std::set< uint32_t > fInactiveChannels
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:67
void AddLink(const CbmLink &newLink)
Definition CbmMatch.cxx:47
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)
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 > GetDiagonalNeighbourPixels(Int_t address)
Return the addresses of the diagonal 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...
std::vector< Int_t > GetPixelAddresses()
static CbmRichGeoHandler & GetInstance()
static CbmRichGeoManager & GetInstance()