CbmRoot
Loading...
Searching...
No Matches
CbmTofDigitize.cxx
Go to the documentation of this file.
1/* Copyright (C) 2013-2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Pierre-Alain Loizeau [committer], Norbert Herrmann */
4
10#include "CbmTofDigitize.h"
11
12// C++ includes
13#include <algorithm>
14#include <cassert>
15#include <iomanip>
16
17// ROOT includes
18#include "TClonesArray.h"
19#include "TDirectory.h"
20#include "TF2.h"
21#include "TGeoManager.h"
22#include "TLine.h"
23#include "TMath.h"
24#include "TROOT.h"
25#include "TRandom3.h"
26#include "TVector3.h"
27#include <TFile.h>
28
29// FAIR classes and includes
30#include "FairEventHeader.h"
31#include "FairMCEventHeader.h"
32#include "FairRootManager.h"
33#include "FairRunAna.h"
34#include "FairRunSim.h"
35#include "FairRuntimeDb.h"
36#include <Logger.h>
37
38// CBM includes
39#include "CbmLink.h"
40#include "CbmMCTrack.h"
41#include "CbmMatch.h"
42#include "CbmTofAddress.h" // in cbmdata/tof
43#include "CbmTofDigi.h" // in cbmdata/tof
44#include "CbmTofPoint.h" // in cbmdata/tof
45
46// TOF includes
47#include "CbmTofCell.h" // in tof/TofData
48#include "CbmTofCreateDigiPar.h" // in tof/TofTools
49#include "CbmTofDetectorId_v12b.h" // in cbmdata/tof
50#include "CbmTofDetectorId_v14a.h" // in cbmdata/tof
51#include "CbmTofDetectorId_v21a.h" // in cbmdata/tof
52#include "CbmTofDigiBdfPar.h" // in tof/TofParam
53#include "CbmTofDigiPar.h" // in tof/TofParam
54#include "CbmTofGeoHandler.h" // in tof/TofTools
55
56using std::cout;
57using std::endl;
58using std::fixed;
59using std::right;
60using std::setprecision;
61using std::setw;
62
63// Gauss Integration Constants
64const Int_t kiNbIntPts = 2;
65Bool_t bFakeBeamCounter = kFALSE;
66
67/************************************************************************************/
69 typedef std::pair<CbmTofDigi*, CbmMatch*> data;
70 bool operator()(data pair1, data pair2)
71 {
72 Bool_t bOK = (pair1.first->GetTime() < pair2.first->GetTime());
73 /*
74 if(!bOK) {
75 LOG(debug) << Form(" ReSort digis 0x%08x , %f, %f", pDigi1->GetAddress(), pDigi1->GetTime(), pDigi2->GetTime() )
76 ;
77 }
78 */
79 return bOK;
80 }
82
83// If enabled add an offset depending on the strip length by making the full propagation time
84// to each strips end
85// If disabled just the time to the center is used
86// TODO: Add this as parameter
87//#define FULL_PROPAGATION_TIME
89
90/************************************************************************************/
92 : CbmDigitize<CbmTofDigi>("TofDigitize")
93 , fdFeeGainSigma(0.)
94 , fdFeeTotThr(0.)
95 , fdTimeResElec(0.)
96 , fdSignalPropSpeed(0.)
97 , fh1ClusterSizeProb()
98 , fh1ClusterTotProb()
99 , fvdSignalVelocityRpc()
100 , fdChannelGain()
101 , fGeoHandler(new CbmTofGeoHandler())
102 , fTofId(NULL)
103 , fDigiPar(NULL)
104 , fChannelInfo(NULL)
105 , fDigiBdfPar(NULL)
106 , fiNbElecChTot(0)
107 , fvRpcChOffs()
108 , fTofPointsColl(NULL)
109 , fMcTracksColl(NULL)
110 , fStorDigi()
111 , fStorDigiMatch()
112 , fvlTrckChAddr()
113 , fvlTrckRpcAddr()
114 , fvlTrckRpcTime()
115 , fiNbDigis(0)
116 , fsHistoOutFilename("")
117 , fhTofPointsPerTrack(NULL)
118 , fhTofPtsInTrkVsGapInd(NULL)
119 , fhTofPtsInTrkVsGapIndPrm(NULL)
120 , fhTofPtsInTrkVsGapIndSec(NULL)
121 , fhTofPtsPosVsGap()
122 , fhEvtProcTime(NULL)
123 , fhDigiMergeTime(NULL)
124 , fhDigiNbElecCh(NULL)
125 , fhProcTimeEvtSize(NULL)
126 , fhMeanDigiPerTrack(NULL)
127 , fhMeanFiredPerTrack(NULL)
128 , fhPtTime(NULL)
129 , fhDigiTime(NULL)
130 , fhDigiTimeRes(NULL)
131 , fhDigiTimeResB(NULL)
132 , fhToTDist(NULL)
133 , fhElecChOccup(NULL)
134 , fhMultiDigiEvtElCh(NULL)
135 , fhNbDigiEvtElCh(NULL)
136 , fhNbTracksEvtElCh(NULL)
137 , fhFiredEvtElCh(NULL)
138 , fhMultiProbElCh(NULL)
139 , fStart()
140 , fStop()
141 , fdDigitizeTime(0.)
142 , fdMergeTime(0.)
143 , fTimer()
144 , fiNofEvents(0)
145 , fdNofTofMcTrkTot(0.)
146 , fdNofPointsTot(0.)
147 , fdNofDigisTot(0.)
148 , fdTimeTot(0.)
149 , fsBeamInputFile("")
150 , fbMonitorHistos(kTRUE)
151 , fbMcTrkMonitor(kFALSE)
152 , fbTimeBasedOutput(kFALSE)
153 , fbAllowPointsWithoutTrack(kFALSE)
154 ,
155 //fiCurrentFileId(-1),
156 //fiCurrentEventId(-1),
157 //fdCurrentEventTime(0.),
158 fdDigiTimeConvFactor(1.)
159{
160}
161
162CbmTofDigitize::CbmTofDigitize(const char* name, Int_t)
163 : CbmDigitize<CbmTofDigi>(name)
164 , fdFeeGainSigma(0.)
165 , fdFeeTotThr(0.)
166 , fdTimeResElec(0.)
167 , fdSignalPropSpeed(0.)
168 , fh1ClusterSizeProb()
169 , fh1ClusterTotProb()
170 , fvdSignalVelocityRpc()
171 , fdChannelGain()
172 , fGeoHandler(new CbmTofGeoHandler())
173 , fTofId(NULL)
174 , fDigiPar(NULL)
175 , fChannelInfo(NULL)
176 , fDigiBdfPar(NULL)
177 , fiNbElecChTot(0)
178 , fvRpcChOffs()
179 , fTofPointsColl(NULL)
180 , fMcTracksColl(NULL)
181 , fStorDigi()
182 , fStorDigiMatch()
183 , fvlTrckChAddr()
184 , fvlTrckRpcAddr()
185 , fvlTrckRpcTime()
186 , fiNbDigis(0)
187 , fsHistoOutFilename("")
188 , fhTofPointsPerTrack(NULL)
189 , fhTofPtsInTrkVsGapInd(NULL)
190 , fhTofPtsInTrkVsGapIndPrm(NULL)
191 , fhTofPtsInTrkVsGapIndSec(NULL)
192 , fhTofPtsPosVsGap()
193 , fhEvtProcTime(NULL)
194 , fhDigiMergeTime(NULL)
195 , fhDigiNbElecCh(NULL)
196 , fhProcTimeEvtSize(NULL)
197 , fhMeanDigiPerTrack(NULL)
198 , fhMeanFiredPerTrack(NULL)
199 , fhPtTime(NULL)
200 , fhDigiTime(NULL)
201 , fhDigiTimeRes(NULL)
202 , fhDigiTimeResB(NULL)
203 , fhToTDist(NULL)
204 , fhElecChOccup(NULL)
205 , fhMultiDigiEvtElCh(NULL)
206 , fhNbDigiEvtElCh(NULL)
207 , fhNbTracksEvtElCh(NULL)
208 , fhFiredEvtElCh(NULL)
209 , fhMultiProbElCh(NULL)
210 , fStart()
211 , fStop()
212 , fdDigitizeTime(0.)
213 , fdMergeTime(0.)
214 , fTimer()
215 , fiNofEvents(0)
216 , fdNofTofMcTrkTot(0.)
217 , fdNofPointsTot(0.)
218 , fdNofDigisTot(0.)
219 , fdTimeTot(0.)
220 , fsBeamInputFile("")
221 , fbMonitorHistos(kTRUE)
222 , fbMcTrkMonitor(kFALSE)
223 , fbTimeBasedOutput(kFALSE)
224 , fbAllowPointsWithoutTrack(kFALSE)
225 ,
226 //fiCurrentFileId(-1),
227 //fiCurrentEventId(-1),
228 //fdCurrentEventTime(0.),
229 fdDigiTimeConvFactor(1.)
230{
231}
232
234{
235 if (fGeoHandler) delete fGeoHandler;
236 // DeleteHistos(); // <-- if needed ?
237}
238
239/************************************************************************************/
240// FairTasks inherited functions
242{
243 std::cout << std::endl;
244 LOG(info) << "==========================================================";
245 LOG(info) << GetName() << ": Initialisation";
246 if (fEventMode) LOG(info) << GetName() << ": Using event mode.";
247
248 // If input file was not set explicitly, use default one
249 if (fsBeamInputFile.IsNull()) {
250 TString fileName = gSystem->Getenv("VMCWORKDIR");
251 fileName += "/parameters/tof/test_bdf_input.root";
252 SetInputFileName(fileName);
253 LOG(info) << GetName() << ": Using default parameter file " << fileName;
254 }
255
256 if (kFALSE == RegisterInputs()) return kFATAL;
257
259
260 if (kFALSE == InitParameters()) return kFATAL;
261
262 if (kFALSE == LoadBeamtimeValues()) return kFATAL;
263
264 if (kFALSE == CreateHistos()) return kFATAL;
265
266 // --- Read list of inactive channels
267 if (!fInactiveChannelFileName.IsNull()) {
268 LOG(info) << GetName() << ": Reading inactive channels from " << fInactiveChannelFileName;
269 auto result = ReadInactiveChannels();
270 if (!result.second) {
271 LOG(error) << GetName() << ": Error in reading from file! Task will be inactive.";
272 return kFATAL;
273 }
274 LOG(info) << GetName() << ": " << std::get<0>(result) << " lines read from file, " << fInactiveChannels.size()
275 << " channels set inactive";
276 }
277
278
279 LOG(info) << GetName() << ": Initialisation successful";
280 LOG(info) << "==========================================================";
281 return kSUCCESS;
282}
283
285{
286 LOG(info) << " CbmTofDigitize => Get the digi parameters for tof";
287
288 // Get Base Container
289 FairRun* ana = FairRun::Instance();
290 FairRuntimeDb* rtdb = ana->GetRuntimeDb();
291
292 fDigiPar = (CbmTofDigiPar*) (rtdb->getContainer("CbmTofDigiPar"));
293
294 fDigiBdfPar = (CbmTofDigiBdfPar*) (rtdb->getContainer("CbmTofDigiBdfPar"));
295}
296
297void CbmTofDigitize::Exec(Option_t* /*option*/)
298{
299 // --- Start timer and reset counters
300 fTimer.Start();
301
302 // Get FairEventHeader information for CbmLink objects
303 GetEventInfo();
304 LOG(debug) << fName << ": Processing event " << fCurrentEvent << " at " << fCurrentEventTime << " ns";
305
306
307 fiNbDigis = 0;
308 Int_t nPoints = fTofPointsColl->GetEntriesFast();
309
310 fStart.Set();
311 LOG(debug) << fName << ": Using cluster model " << fDigiBdfPar->GetClusterModel();
312 switch (fDigiBdfPar->GetClusterModel()) {
313 case 0: DigitizeDirectClusterSize(); break;
314 case 1: DigitizeFlatDisc(); break;
315 case 2: DigitizeGaussCharge(); break;
316 default: DigitizeDirectClusterSize(); break;
317 }
318
319 fStop.Set();
320 fdDigitizeTime = fStop.GetSec() - fStart.GetSec() + (fStop.GetNanoSec() - fStart.GetNanoSec()) / 1e9;
321
322 LOG(debug) << fName << ": Merge digis ";
324 fStart.Set();
325 fdMergeTime = fStart.GetSec() - fStop.GetSec() + (fStart.GetNanoSec() - fStop.GetNanoSec()) / 1e9;
326
327 // --- Counters
328 fTimer.Stop();
329 fiNofEvents++;
330 fdNofPointsTot += nPoints;
332 fdTimeTot += fTimer.RealTime();
333
334 // --- Event log
335 LOG(info) << "+ " << setw(15) << GetName() << ": Event " << setw(6) << right << fCurrentEvent << " at " << fixed
336 << setprecision(3) << fCurrentEventTime << " ns, points: " << nPoints << ", digis: " << fiNbDigis
337 << ". Exec time " << setprecision(6) << fTimer.RealTime() << " s.";
338}
339
341{
342 std::cout << std::endl;
343 LOG(info) << "=====================================";
344
345 // Final printout for reference
346 LOG(info) << GetName() << ": Run summary (Time includes Hist filling)";
347 LOG(info) << "Events processed : " << fiNofEvents;
348 if (fbMcTrkMonitor) {
349 LOG(info) << "Tof MC Track / event: " << fdNofPointsTot / fdNofTofMcTrkTot;
350 } // if( fbMcTrkMonitor )
351 LOG(info) << "TofPoint / event : " << fdNofPointsTot / static_cast<Double_t>(fiNofEvents);
352 LOG(info) << "TofDigi / event : " << fdNofDigisTot / static_cast<Double_t>(fiNofEvents);
353 LOG(info) << "Digis per point : " << fdNofDigisTot / fdNofPointsTot;
354 if (fbMcTrkMonitor) {
355 LOG(info) << "Digis per TofMcTrack: " << fdNofDigisTot / fdNofTofMcTrkTot;
356 } // if( fbMcTrkMonitor )
357 LOG(info) << "Real time per event : " << fdTimeTot / static_cast<Double_t>(fiNofEvents) << " s";
358
359 WriteHistos();
360 // Prevent them from being sucked in by the CbmHadronAnalysis WriteHistograms method
361 DeleteHistos();
362
363 // Clear the cluster size and efficiency histos copies inside the parameter
365 LOG(info) << "=====================================";
366}
367
368/************************************************************************************/
369// Functions common for all clusters approximations
371{
372 FairRootManager* fManager = FairRootManager::Instance();
373
374 fTofPointsColl = (TClonesArray*) fManager->GetObject("TofPoint");
375 if (NULL == fTofPointsColl) {
376 LOG(error) << "CbmTofDigitize::RegisterInputs => Could not get the "
377 "TofPoint TClonesArray!!!";
378 return kFALSE;
379 } // if( NULL == fTofPointsColl)
380
381 fMcTracksColl = (TClonesArray*) fManager->GetObject("MCTrack");
382 if (NULL == fMcTracksColl) {
383 LOG(error) << "CbmTofDigitize::RegisterInputs => Could not get the MCTrack "
384 "TClonesArray!!!";
385 return kFALSE;
386 } // if( NULL == fMcTracksColl)
387
388 return kTRUE;
389}
391{
392 // Initialize the TOF GeoHandler
393 Bool_t isSimulation = kFALSE;
394 Int_t iGeoVersion = fGeoHandler->Init(isSimulation);
395 if (k12b > iGeoVersion) {
396 LOG(error) << "CbmTofDigitize::InitParameters => Only compatible with "
397 "geometries after v12b !!!";
398 return kFALSE;
399 }
400
401 LOG(info) << fName << ": GeoVersion " << iGeoVersion;
402
403 switch (iGeoVersion) {
404 case k12b: fTofId = new CbmTofDetectorId_v12b(); break;
405 case k14a: fTofId = new CbmTofDetectorId_v14a(); break;
406 case k21a: fTofId = new CbmTofDetectorId_v21a(); break;
407 default: LOG(error) << "CbmTofDigitize::InitParameters: Invalid Detector ID " << iGeoVersion; break;
408 }
409
410 // create digitization parameters from geometry file
411 CbmTofCreateDigiPar* tofDigiPar = new CbmTofCreateDigiPar("TOF Digi Producer", "TOF task");
412 LOG(info) << "Create DigiPar";
413 tofDigiPar->Init();
414
415 // Printout option for crosscheck
416 LOG(debug) << " CbmTofDigitize::LoadBeamtimeValues Digi Par contains " << fDigiPar->GetNrOfModules() << " cells ";
417 return kTRUE;
418}
420{
421 LOG(info) << fName << ": Load beamtime values from " << fsBeamInputFile;
422
424
425 // Add Param printout only if DEBUG level ON
426 if (fair::Logger::Logging(fair::Severity::debug)) fDigiBdfPar->printParams();
427
428 if (kFALSE == fDigiBdfPar->LoadBeamtimeHistos()) {
429 LOG(fatal) << "CbmTofDigitize::LoadBeamtimeValues: Cluster properties from "
430 "testbeam could not be loaded! ";
431 return kFALSE;
432 }
433
434 // // Printout option for crosscheck
435 // fDigiBdfPar->printParams();
436
437 // Obtain some of the constants
442
443 // Generate the gain/fee channel matrix
444 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
445
446 LOG(debug2) << "CbmTofDigitize::LoadBeamtimeValues: ini gain values for SmTypes " << iNbSmTypes;
447
448 fdChannelGain.resize(iNbSmTypes);
449
450 TRandom3 randFeeGain;
451 // randFeeGain.SetSeed(0);
452
453 // Save the total number of electronic channels for the "Occupancy" estimation
454 // and the first channel of each RPC for the multiple signals estimation
455 fiNbElecChTot = 0;
456 fvRpcChOffs.resize(iNbSmTypes);
457 fvdSignalVelocityRpc.resize(iNbSmTypes);
458
459 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
460 LOG(debug2) << "CbmTofDigitize::LoadBeamtimeValues => Gain for SM type " << iSmType;
461 Int_t iNbSm = fDigiBdfPar->GetNbSm(iSmType);
462 Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
463
464 fvdSignalVelocityRpc[iSmType].resize(iNbSm);
465 fdChannelGain[iSmType].resize(iNbSm * iNbRpc);
466 fvRpcChOffs[iSmType].resize(iNbSm);
467
468 if (iSmType == 5 && iNbSm > 0) {
469 bFakeBeamCounter = kTRUE;
470 LOG(info) << "Generate Fake Beam Counter digis";
471 }
472
473 for (Int_t iSm = 0; iSm < iNbSm; iSm++) {
474 fvdSignalVelocityRpc[iSmType][iSm].resize(iNbRpc);
475 for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
476 if (0.0 < fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc))
477 fvdSignalVelocityRpc[iSmType][iSm][iRpc] =
478 fDigiBdfPar->GetSigVel(iSmType, iSm, iRpc); // convert into cm/ns if necessary (FIXME)
479 else
480 fvdSignalVelocityRpc[iSmType][iSm][iRpc] = fdSignalPropSpeed;
481 LOG(debug) << "Init signal velocity of TSR " << iSmType << iSm << iRpc << " to "
482 << fvdSignalVelocityRpc[iSmType][iSm][iRpc];
483 }
484 }
485
486 for (Int_t iSm = 0; iSm < iNbSm; iSm++) {
487 fvRpcChOffs[iSmType][iSm].resize(iNbRpc);
488
489 for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
490 LOG(debug2) << "CbmTofDigitize::LoadBeamtimeValues => Gain for SM/Rpc " << iSm << "/" << iRpc;
491 Int_t iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
492 Int_t iNbSides = 2 - fDigiBdfPar->GetChanType(iSmType, iRpc);
493
494 // Save the total number of electronic channels for the "Occupancy" estimation
495 // and the first channel of each RPC for the multiple signals estimation
496 fiNbElecChTot += iNbCh * iNbSides;
497 fvRpcChOffs[iSmType][iSm][iRpc] = fiNbElecChTot;
498
499 fdChannelGain[iSmType][iSm * iNbRpc + iRpc].resize(iNbCh * iNbSides);
500
501 for (Int_t iCh = 0; iCh < iNbCh; iCh++)
502 for (Int_t iSide = 0; iSide < iNbSides; iSide++) {
503 if (0 < fdFeeGainSigma) {
504 fdChannelGain[iSmType][iSm * iNbRpc + iRpc][iCh * iNbSides + iSide] =
505 randFeeGain.Gaus(1.0, fdFeeGainSigma);
506 if (fdChannelGain[iSmType][iSm * iNbRpc + iRpc][iCh * iNbSides + iSide] < 0.0)
507 LOG(error) << "CbmTofDigitize::LoadBeamtimeValues => Neg. Gain "
508 "for SM/Rpc "
509 << iSm << "/" << iRpc << " "
510 << fdChannelGain[iSmType][iSm * iNbRpc + iRpc][iCh * iNbSides + iSide];
511 } // if( 0 < fdFeeGainSigma )
512 else
513 fdChannelGain[iSmType][iSm * iNbRpc + iRpc][iCh * iNbSides + iSide] = 1;
514 //if(iSmType==5) fdChannelGain[iSmType][iSm*iNbRpc + iRpc][iCh*iNbSides + iSide] *= 10.; //FIXME, Diamond
515 }
516 } // for( Int_t iRpc = 0; iRpc < iNbRpc; iRpc++ )
517 } // for( Int_t iSm = 0; iSm < iNbSm; iSm++ )
518 } // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
519
520 TDirectory* oldir = gDirectory;
521 gROOT->cd();
522 // Generate the Probability conversion histograms for Cluster size
523 // and cluster charge
524 fh1ClusterSizeProb.resize(iNbSmTypes);
525 fh1ClusterTotProb.resize(iNbSmTypes);
526 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
527 LOG(debug2) << "CbmTofDigitize::LoadBeamtimeValues => SM type " << iSmType;
528
529 if (0 == fDigiBdfPar->GetClusterModel()) {
530 // Generating the Cluster Radius Probability from the Cluster Size distribution
531 fh1ClusterSizeProb[iSmType] =
532 new TH1D(Form("ClusterSizeProb%03d", iSmType), "Random throw to Cluster size mapping", 10000, 0.0, 1.0);
533 TH1* hClusterSize = fDigiBdfPar->GetClustSizeHist(iSmType);
534 Int_t iNbBinsSize = hClusterSize->GetNbinsX();
535 Double_t dNbBinsProb = fh1ClusterSizeProb[iSmType]->GetNbinsX();
536 Int_t iProbBin = 1;
537 Double_t dIntegral = 0.;
538 // Double_t dIntSize = hClusterSize->GetEntries();
539 // BUGFIX
540 // The histogram integral is the sum of bin contents (1-N), while the
541 // number of histogram entries is given by the number of times the
542 // Fill() method was called.
543 // The quantile histogram 'fh1ClusterSizeProb' computed below might
544 // contain a few F^-1(u) = 0 towards u = 1 if the underflow and/or
545 // overflow bins of the original PDF histogram were populated. This
546 // in return would lead to an excess at 0 in the spectrum of values
547 // sampled from the quantile histogram.
548 Double_t dIntSize = hClusterSize->Integral();
549 Double_t dSizeVal = 0.;
550
551 for (Int_t iBin = 1; iBin <= iNbBinsSize; iBin++) {
552 dIntegral += hClusterSize->GetBinContent(iBin);
553 if ((Double_t) iProbBin / dNbBinsProb < dIntegral / dIntSize) dSizeVal = hClusterSize->GetBinCenter(iBin);
554 while ((Double_t) iProbBin / dNbBinsProb < dIntegral / dIntSize) {
555 fh1ClusterSizeProb[iSmType]->SetBinContent(iProbBin, dSizeVal);
556 iProbBin++;
557 } // while( (Double_t)iProbBin/dNbBinsProb < dIntegral/dIntTot )
558 } // for( Int_t iBin = 1; iBin <= iNbBinsTot; iBin++ )
559 fh1ClusterSizeProb[iSmType]->SetBinContent(iProbBin, dSizeVal);
560 } // if( 0 == fDigiBdfPar->GetClusterModel() )
561 else
563 case 0: {
564 // Single value using the beamtime cluster size distribution mean
565 // => Just copy pointer to the beamtime histogram
567 LOG(debug) << "CbmTofDigitize::LoadBeamtimeValues => SM type " << iSmType << " Mean Cluster Size "
568 << (fh1ClusterSizeProb[iSmType]->GetMean());
569 break;
570 }
571 case 1: {
572 // from beamtime cluster size distribution
573 // Ingo tip: use Landau distribution until it matchs
575 LOG(debug) << "CbmTofDigitize::LoadBeamtimeValues => SM type " << iSmType << " Mean Cluster Size "
576 << (fh1ClusterSizeProb[iSmType]->GetMean());
577 break;
578 }
579 default: {
580 // Should not happen !
581 fh1ClusterSizeProb[iSmType] = 0;
582 break;
583 }
584 } // switch( fDigiBdfPar->GetClusterRadiusModel() )
585
586
587 fh1ClusterTotProb[iSmType] =
588 new TH1D(Form("ClusterTotProb%03d", iSmType), "Random throw to Cluster Tot mapping", 10000, 0.0, 1.0);
589 TH1* hClusterTot = fDigiBdfPar->GetClustTotHist(iSmType);
590 Int_t iNbBinsTot = hClusterTot->GetNbinsX();
591 Double_t dNbBinsProb = fh1ClusterTotProb[iSmType]->GetNbinsX();
592 Int_t iProbBin = 1;
593 Double_t dIntegral = 0.;
594 // Double_t dIntTot = hClusterTot->GetEntries();
595 // BUGFIX
596 // The histogram integral is the sum of bin contents (1-N), while the
597 // number of histogram entries is given by the number of times the
598 // Fill() method was called.
599 // The quantile histogram 'fh1ClusterTotProb' computed below might
600 // contain a few F^-1(u) = 0 towards u = 1 if the underflow and/or
601 // overflow bins of the original PDF histogram were populated. This
602 // in return would lead to an excess at 0 in the spectrum of values
603 // sampled from the quantile histogram.
604 Double_t dIntTot = hClusterTot->Integral();
605 Double_t dTotVal = 0.;
606 Double_t dPsToNs = 1e3; // FIXME? Most histograms from analysis are in ps, simulation used ns !!
607
608 for (Int_t iBin = 1; iBin <= iNbBinsTot; iBin++) {
609 dIntegral += hClusterTot->GetBinContent(iBin);
610 if ((Double_t) iProbBin / dNbBinsProb < dIntegral / dIntTot) dTotVal = hClusterTot->GetBinLowEdge(iBin) / dPsToNs;
611 while ((Double_t) iProbBin / dNbBinsProb < dIntegral / dIntTot) {
612 fh1ClusterTotProb[iSmType]->SetBinContent(iProbBin, dTotVal);
613 iProbBin++;
614 } // while( (Double_t)iProbBin/dNbBinsProb < dIntegral/dIntTot )
615 } // for( Int_t iBin = 1; iBin <= iNbBinsTot; iBin++ )
616 fh1ClusterTotProb[iSmType]->SetBinContent(iProbBin, dTotVal);
617 } // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
618 gDirectory->cd(oldir->GetPath());
619
620 // Prepare the intermediate Digi storage
621 fStorDigi.resize(iNbSmTypes);
622 fStorDigiMatch.resize(iNbSmTypes);
623 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
624 Int_t iNbSm = fDigiBdfPar->GetNbSm(iSmType);
625 Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
626 fStorDigi[iSmType].resize(iNbSm * iNbRpc);
627 fStorDigiMatch[iSmType].resize(iNbSm * iNbRpc);
628 for (Int_t iSm = 0; iSm < iNbSm; iSm++)
629 for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
630 Int_t iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
631 Int_t iNbSides = 2 - fDigiBdfPar->GetChanType(iSmType, iRpc);
632 fStorDigi[iSmType][iSm * iNbRpc + iRpc].resize(iNbCh * iNbSides);
633 fStorDigiMatch[iSmType][iSm * iNbRpc + iRpc].resize(iNbCh * iNbSides);
634 } // for each (Sm, rpc) pair
635 } // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
636
637 LOG(debug) << "CbmTofDigitize::LoadBeamtimeValues: GeoVersion " << fGeoHandler->GetGeoVersion();
638
639 // TEST stupid stuffs
640 Int_t iNbGeantChannels = fDigiPar->GetNrOfModules();
641 Int_t iMinSmType = 17; // 4b for sm type in ID v12b normally
642 Int_t iMaxSmType = -1; // 4b for sm type in ID v12b normally
643 Int_t iMinSm = 257; // 8b for sm type in ID v12b normally
644 Int_t iMaxSm = -1; // 8b for sm type in ID v12b normally
645 Int_t iMinRpc = 9; // 3b for sm type in ID v12b normally
646 Int_t iMaxRpc = -1; // 3b for sm type in ID v12b normally
647 Int_t iMinGap = 17; // 4b for sm type in ID v12b normally
648 Int_t iMaxGap = -1; // 4b for sm type in ID v12b normally
649 Int_t iMinCell = 257; // 8b for sm type in ID v12b normally
650 Int_t iMaxCell = -1; // 4b for sm type in ID v12b normally
651 for (Int_t iCellInd = 0; iCellInd < iNbGeantChannels; iCellInd++) {
652 Int_t iCellId = fDigiPar->GetCellId(iCellInd);
653
654 if (iMinSmType > fTofId->GetSMType(iCellId)) iMinSmType = fTofId->GetSMType(iCellId);
655 if (iMaxSmType < fTofId->GetSMType(iCellId)) iMaxSmType = fTofId->GetSMType(iCellId);
656
657 if (iMinSm > fTofId->GetSModule(iCellId)) iMinSm = fTofId->GetSModule(iCellId);
658 if (iMaxSm < fTofId->GetSModule(iCellId)) iMaxSm = fTofId->GetSModule(iCellId);
659
660 if (iMinRpc > fTofId->GetCounter(iCellId)) iMinRpc = fTofId->GetCounter(iCellId);
661 if (iMaxRpc < fTofId->GetCounter(iCellId)) iMaxRpc = fTofId->GetCounter(iCellId);
662
663 if (iMinGap > fTofId->GetGap(iCellId)) iMinGap = fTofId->GetGap(iCellId);
664 if (iMaxGap < fTofId->GetGap(iCellId)) iMaxGap = fTofId->GetGap(iCellId);
665
666 if (iMinCell > fTofId->GetCell(iCellId)) iMinCell = fTofId->GetCell(iCellId);
667 if (iMaxCell < fTofId->GetCell(iCellId)) iMaxCell = fTofId->GetCell(iCellId);
668 }
669 LOG(debug) << "SM type min " << iMinSmType << " max " << iMaxSmType;
670 LOG(debug) << "SM min " << iMinSm << " max " << iMaxSm;
671 LOG(debug) << "Rpc min " << iMinRpc << " max " << iMaxRpc;
672 LOG(debug) << "Gap min " << iMinGap << " max " << iMaxGap;
673 LOG(debug) << "Chan min " << iMinCell << " max " << iMaxCell;
674 //
675 return kTRUE;
676}
677/************************************************************************************/
678// Histogramming functions
680{
681 if (!fbMonitorHistos) { return kTRUE; }
682
683 TDirectory* oldir = gDirectory; // <= To prevent histos from being sucked in by the param file of the TRootManager!
684 gROOT->cd(); // <= To prevent histos from being sucked in by the param file of the TRootManager !
685
686 fhTofPointsPerTrack = new TH1I("TofDigiBdf_TofPtPerTrk",
687 "Number of Tof Points per MC track reaching "
688 "the TOF; Nb Tof Points in Tracks []",
689 16, 0.0, 16.0);
690 fhTofPtsInTrkVsGapInd = new TH2I("TofDigiBdf_TofPtInTrkGap",
691 "Gap index vs Number of Tof Points in corresponding MC Track; Nb "
692 "Tof Pts in Track []; Gap Index []",
693 16, 0.0, 16.0, 10, -0.5, 9.5);
694 fhTofPtsInTrkVsGapIndPrm = new TH2I("TofDigiBdf_TofPtInTrkGapPrm",
695 "Gap index vs Number of Tof Points in corresponding MC Track, "
696 "primaries; Nb Tof Pts in Track []; Gap Index []",
697 16, 0.0, 16.0, 10, -0.5, 9.5);
698 fhTofPtsInTrkVsGapIndSec = new TH2I("TofDigiBdf_TofPtInTrkGapSec",
699 "Gap index vs Number of Tof Points in corresponding MC Track, "
700 "secondaries; Nb Tof Pts in Track []; Gap Index []",
701 16, 0.0, 16.0, 10, -0.5, 9.5);
702 for (Int_t iGap = 0; iGap < 10; iGap++)
703 fhTofPtsPosVsGap[iGap] =
704 new TH2I(Form("TofDigiBdf_fhTofPtsPosVsGap%d", iGap), Form("Tof Point positions in gap %d; X [cm]; Y [cm]", iGap),
705 750, -750, 750, 500, -500, 500);
706 /*
707 fhTofPointsPerTrackVsPdg = new TH2I( "TofDigiBdf_TofPtPerTrkVsPdg", "Number of Tof Points per MC track in each event; PDG []; Nb Points/Nb Tracks []",
708 800, -4000, 4000,
709 16, 0.0, 16.0 );
710 fhMeanPointPerTrack = new TH1I( "TofDigiBdf_PtPerTrk", "Mean Number of Tof Points per MC track in each event; Nb Points/Nb Tracks []",
711 800, 0.0, 16.0 );
712 fhMeanPointPerTrack2d = new TH2I( "TofDigiBdf_PtPerTrk2d", "Mean Number of Tof Points per MC track in each event; Nb Tracks []; Nb Tof Points/Nb Tracks []",
713 300, 0.0, 3000.0,
714 800, 0.0, 16.0 );
715 fhMeanDigiPerPoint = new TH1I( "TofDigiBdf_DigiPerPt", "Mean Number of ToF Digi per Tof Point in each event; Nb Digi/Nb Points []",
716 500, 0.0, 10.0 );
717 fhMeanFiredPerPoint = new TH1I( "TofDigiBdf_FirPerPt", "Mean Number of fired channel per Tof Point in each event; Nb Fired/Nb Points []",
718 500, 0.0, 10.0 );
719*/
720 fhEvtProcTime = new TH1I("TofDigiBdf_EvtProcTime", "Time needed to process each event; Time [s]", 40000, 0.0, 40.0);
722 new TH1I("TofDigiBdf_DigiMergeTime", "Time needed to merge the digis for each event; Time [s]", 4000, 0.0, 0.4);
723 fhDigiNbElecCh = new TH1I("TofDigiBdf_DigiNbElecCh",
724 "Nb of digis per channel before merging; Nb Digis in same elec. ch []", 50, 0.0, 50);
725 fhProcTimeEvtSize = new TH2I("TofDigiBdf_ProcTimeEvtSize",
726 "Time needed to process each event vs Event "
727 "Size; Event Size [TofPoints]; Time [s]",
728 600, 0.0, 12000.0, 400, 0.0, 4.0);
730 new TH1I("TofDigiBdf_DigiPerTrk", "Mean Number of ToF Digi per MC track in each event; Nb Digi/Nb Tracks []", 500,
731 0.0, 10.0);
732 fhMeanFiredPerTrack = new TH1I("TofDigiBdf_FirPerTrk",
733 "Mean Number of fired channel per MC track in "
734 "each event; Nb Fired/Nb Tracks []",
735 500, 0.0, 10.0);
736 fhPtTime = new TH1I("TofDigiBdf_PtTime", "TofPoints Time distribution, summed for all Pts/channels; Time [ns]", 10000,
737 0.0, 10000.0);
738 fhDigiTime =
739 new TH1I("TofDigiBdf_DigiTime", "Time distribution, summed for all digis/channels; Time [ns]", 10000, 0.0, 10000.0);
740 fhDigiTimeRes = new TH1I("TofDigiBdf_DigiTimeRes",
741 "Time to True time distribution, summed for all "
742 "digis/channels; Time Digi - Time Pt [ns]",
743 10000, -50.0, 50.0);
744 fhDigiTimeResB = new TH2I("TofDigiBdf_DigiTimeResB",
745 "Time to True time distribution, summed for all "
746 "digis/channels; Time Digi - Time Pt [ns]",
747 10000, -50.0, 50.0, 6, 0, 6);
748 fhToTDist =
749 new TH1I("TofDigiBdf_ToTDist", "ToT distribution, summed for all digis/channels; Tot [ns]", 500, 0.0, 50.0);
750
751 fhElecChOccup = new TH1I("TofDigiBdf_ElecChOccup",
752 "Percentage of ToF electronic channels fired per "
753 "event; Elect. chan occupancy [%]",
754 1000, 0.0, 100.0);
755 fhMultiDigiEvtElCh = new TH1D("TofDigiBdf_MultiDigiEvtElCh",
756 "Number of events with multiple digi (~MC track) per electronic "
757 "channel; Elect. chan index []",
759 fhNbDigiEvtElCh = new TH2D("TofDigiBdf_NbDigiEvtElCh",
760 "Number of digis per event before merging for each electronic "
761 "channel; Elect. chan index []; Nb Digis in Event []",
762 fiNbElecChTot, 0.0, fiNbElecChTot, 10, 0.5, 10.5);
763 fhNbTracksEvtElCh = new TH2D("TofDigiBdf_NbTracksEvtElCh",
764 "Number of tracks per event before merging for each electronic "
765 "channel; Elect. chan index []; Nb tracks in Event []",
766 fiNbElecChTot, 0.0, fiNbElecChTot, 10, 0.5, 10.5);
767 fhFiredEvtElCh = new TH1D("TofDigiBdf_FiredEvtElCh",
768 "Number of events with at least 1 digi per "
769 "electronic channel; Elect. chan index []",
771 fhMultiProbElCh = new TH1D("TofDigiBdf_MultiProbElCh",
772 "Probability of having multiple digi (~MC track) event per electronic "
773 "channel; Elect. chan index []; Multiple signal prob. [%]",
775
776 gDirectory->cd(oldir->GetPath()); // <= To prevent histos from being sucked in by the param file of the TRootManager!
777
778 return kTRUE;
779}
781{
782
783 // (VF) This does not run with digi vectors. Should be moved into a QA class.
784 /*
785 if(!fbMonitorHistos)
786 {
787 return kTRUE;
788 }
789
790 Int_t nTofPoint = fTofPointsColl->GetEntriesFast();
791 Int_t nTracks = fMcTracksColl->GetEntriesFast();
792 // Int_t nTofDigi = fDigis->GetEntriesFast();
793 Int_t iNbTofTracks = 0;
794 Double_t nTofFired = 0;
795 Double_t dProcessTime = fdDigitizeTime + fdMergeTime;
796
797 // --- Update run Counters
798 fdNofPointsTot += nTofPoint;
799
800 // Tracks Info
801 CbmMCTrack *pMcTrk;
802 if( fbMcTrkMonitor )
803 {
804 Int_t iNbTofTracksPrim = 0;
805 for(Int_t iTrkInd = 0; iTrkInd < nTracks; iTrkInd++)
806 {
807 pMcTrk = (CbmMCTrack*) fMcTracksColl->At( iTrkInd );
808 // Jump all tracks not making 8 points for test
809 // if( 8 != pMcTrk->GetNPoints(ECbmModuleId::kTof) )
810 // continue;
811 if( 0 < pMcTrk->GetNPoints(ECbmModuleId::kTof) )
812 {
813 iNbTofTracks++;
814 fhTofPointsPerTrack->Fill( pMcTrk->GetNPoints(ECbmModuleId::kTof) );
815 fhTofPointsPerTrackVsPdg->Fill( pMcTrk->GetPdgCode(), pMcTrk->GetNPoints(ECbmModuleId::kTof) );
816 }
817 if( 0 < pMcTrk->GetNPoints(ECbmModuleId::kTof) && -1 == pMcTrk->GetMotherId() )
818 iNbTofTracksPrim++;
819
820 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
821
822 // --- Update run Counters
823 fdNofTofMcTrkTot += iNbTofTracks;
824 } // if( fbMcTrkMonitor )
825 LOG(info) << "Monitor tracks" ;
826
827 // Tof Points info
828 CbmTofPoint *pTofPt;
829 for(Int_t iPtInd = 0; iPtInd < nTofPoint; iPtInd++)
830 {
831 pTofPt = (CbmTofPoint*) fTofPointsColl->At( iPtInd );
832 fhPtTime->Fill( pTofPt->GetTime() );
833
834 if( fbMcTrkMonitor )
835 {
836 Int_t iDetId = pTofPt->GetDetectorID();
837 Int_t iGap = fGeoHandler->GetGap(iDetId);
838
839 pMcTrk = (CbmMCTrack*) fMcTracksColl->At( pTofPt->GetTrackID() );
840
841 fhTofPtsInTrkVsGapInd->Fill( pMcTrk->GetNPoints(ECbmModuleId::kTof), iGap );
842 if( -1 == pMcTrk->GetMotherId() )
843 fhTofPtsInTrkVsGapIndPrm->Fill( pMcTrk->GetNPoints(ECbmModuleId::kTof), iGap );
844 else if( 11 != pMcTrk->GetPdgCode() ) // Remove electrons
845 fhTofPtsInTrkVsGapIndSec->Fill( pMcTrk->GetNPoints(ECbmModuleId::kTof), iGap );
846
847 // Get TofPoint Position
848 TVector3 vPntPos;
849 pTofPt->Position( vPntPos );
850 if( 8-pMcTrk->GetNPoints(ECbmModuleId::kTof) <= iGap &&
851 pMcTrk->GetNPoints(ECbmModuleId::kTof) < 8 &&
852 -1 != pMcTrk->GetMotherId() )
853 fhTofPtsPosVsGap[iGap]->Fill( vPntPos.X(), vPntPos.Y() );
854 } // if( fbMcTrkMonitor )
855 } // for(Int_t iPtInd = 0; iPtInd < nTofPoint; iPtInd++)
856 LOG(info) << "Monitor points" ;
857
858
859 fhDigiMergeTime->Fill( fdMergeTime );
860 fhEvtProcTime->Fill( dProcessTime );
861 fhProcTimeEvtSize->Fill( nTofPoint, dProcessTime );
862 if( fbMcTrkMonitor )
863 // fhMeanDigiPerTrack->Fill( (Double_t)nTofDigi/(Double_t)iNbTofTracks );
864// fhMeanDigiPerPoint->Fill( (Double_t)nTofDigi/(Double_t)nTofPoint );
865// fhMeanPointPerTrack->Fill( (Double_t)nTofPoint/(Double_t)iNbTofTracks);
866// fhMeanPointPerTrack2d->Fill( iNbTofTracks, (Double_t)nTofPoint/(Double_t)iNbTofTracks);
867
868 // Assume for the occupancy that we can only have one Digi per electronic channel
869 // No Multiple hits/digi in same event!
870 fhElecChOccup->Fill( 100.0*(Double_t)nTofDigi/(Double_t)fiNbElecChTot );
871 LOG(info) << "Monitor 1" ;
872
873 if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
874 {
875 LOG(info) << "Monitor 2" ;
876 CbmTofDigiExp *pDigi;
877 for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )
878 {
879 LOG(info) << "Digi " << iDigInd ;
880 pDigi = (CbmTofDigiExp*) fTofDigisColl->At( iDigInd );
881 assert(pDigi);
882 CbmMatch* digiMatch=(CbmMatch *)fTofDigiMatchPointsColl->At(iDigInd);
883 assert(digiMatch);
884 CbmLink L0 = digiMatch->GetMatchedLink();
885 CbmTofPoint* point = (CbmTofPoint*)fTofPointsColl->At( L0.GetIndex());
886 assert(point);
887
888 if( pDigi->GetTot() < 0 )
889 cout<<iDigInd<<"/"<<nTofDigi<<" "<<pDigi->GetTot()<<endl;
890 fhDigiTime->Fill( pDigi->GetTime() );
891 fhDigiTimeRes->Fill( pDigi->GetTime() - point->GetTime() );
892 fhDigiTimeResB->Fill( pDigi->GetTime() - point->GetTime(),
893 pDigi->GetType() );
894 fhToTDist->Fill( pDigi->GetTot() );
895
896 nTofFired += 1.0/( 2.0 - fDigiBdfPar->GetChanType( pDigi->GetType(), pDigi->GetRpc() ) );
897 } // for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )
898 } // if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
899 else
900 {
901 LOG(info) << "Monitor 3" ;
902
903 CbmTofDigi *pDigi;
904 for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )
905 {
906 pDigi = (CbmTofDigi*) fTofDigisColl->At( iDigInd );
907 CbmMatch* digiMatch=(CbmMatch *)fTofDigiMatchPointsColl->At(iDigInd);
908 CbmLink L0 = digiMatch->GetMatchedLink();
909 CbmTofPoint* point = (CbmTofPoint*)fTofPointsColl->At( L0.GetIndex());
910 // CbmTofPoint* point = (CbmTofPoint*)fTofPointsColl->At(pDigi->GetMatch()->GetMatchedLink().GetIndex());
911 if( pDigi->GetTot() < 0 )
912 cout<<iDigInd<<"/"<<nTofDigi<<" "<<pDigi->GetTot()<<endl;
913 fhDigiTime->Fill( pDigi->GetTime() );
914 fhDigiTimeRes->Fill( pDigi->GetTime() - point->GetTime() );
915 fhToTDist->Fill( pDigi->GetTot() );
916
917 nTofFired += 1.0/( 2.0 - fDigiBdfPar->GetChanType( pDigi->GetType(), pDigi->GetRpc() ) );
918 } // for( Int_t iDigInd = 0; iDigInd < nTofDigi; iDigInd++ )
919 } // else of if( kTRUE == fDigiBdfPar->UseExpandedDigi() )
920
921// fhMeanFiredPerPoint->Fill( nTofFired / (Double_t)nTofPoint);
922 fhMeanFiredPerTrack->Fill( nTofFired/(Double_t)iNbTofTracks );
923 LOG(info) << "Monitor time" ;
924*/
925
926 return kTRUE;
927}
928Bool_t CbmTofDigitize::SetHistoFileName(TString sFilenameIn)
929{
930 fsHistoOutFilename = sFilenameIn;
931 return kTRUE;
932}
933
934
936{
937 if ("" == fsHistoOutFilename || !fbMonitorHistos) {
938 LOG(info) << "CbmTofDigitize::WriteHistos => Control histograms will not "
939 "be written to disk!";
940 LOG(info) << "CbmTofDigitize::WriteHistos => To change this behavior "
941 "please provide a full path "
942 << "with the SetHistoFileName method";
943 return kTRUE;
944 } // if( "" == fsHistoOutFilename )
945
947 TFile* oldFile = gFile;
948 TDirectory* oldDir = gDirectory;
949 TFile* fHist = new TFile(fsHistoOutFilename, "RECREATE");
950
951 fHist->cd();
952
953 fhTofPointsPerTrack->Write();
954 fhTofPtsInTrkVsGapInd->Write();
957 for (Int_t iGap = 0; iGap < 10; iGap++)
958 fhTofPtsPosVsGap[iGap]->Write();
959 /*
960 fhTofPointsPerTrackVsPdg->Write();
961 fhMeanDigiPerPoint->Write();
962 fhMeanFiredPerPoint->Write();
963 fhMeanPointPerTrack->Write();
964 fhMeanPointPerTrack2d->Write();
965*/
966 fhEvtProcTime->Write();
967 fhDigiMergeTime->Write();
968 fhDigiNbElecCh->Write();
969 fhProcTimeEvtSize->Write();
970 fhMeanDigiPerTrack->Write();
971 fhMeanFiredPerTrack->Write();
972 fhPtTime->Write();
973 fhDigiTime->Write();
974 fhDigiTimeRes->Write();
975 fhDigiTimeResB->Write();
976 fhToTDist->Write();
977
978 fhElecChOccup->Write();
979 fhMultiDigiEvtElCh->Write();
980 fhNbDigiEvtElCh->Write();
981 fhNbTracksEvtElCh->Write();
982 fhFiredEvtElCh->Write();
984 fhMultiProbElCh->Scale(100.0);
985 fhMultiProbElCh->Write();
986
987 // Uncomment if need to control the Cluster Size and ToT proba
988 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
989 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
990 if (0 == fDigiBdfPar->GetClusterModel()) fh1ClusterSizeProb[iSmType]->Write();
991 fh1ClusterTotProb[iSmType]->Write();
992 }
993
995 gFile = oldFile;
996 gDirectory = oldDir;
997
998 fHist->Close();
999
1000 return kTRUE;
1001}
1003{
1004 if (!fbMonitorHistos) { return kTRUE; }
1005
1006 delete fhTofPointsPerTrack;
1007 delete fhTofPtsInTrkVsGapInd;
1010 for (Int_t iGap = 0; iGap < 10; iGap++)
1011 delete fhTofPtsPosVsGap[iGap];
1012 /*
1013 delete fhTofPointsPerTrackVsPdg;
1014 delete fhMeanDigiPerPoint;
1015 delete fhMeanFiredPerPoint;
1016 delete fhMeanPointPerTrack;
1017 delete fhMeanPointPerTrack2d;
1018*/
1019 delete fhEvtProcTime;
1020 delete fhDigiMergeTime;
1021 delete fhDigiNbElecCh;
1022 delete fhProcTimeEvtSize;
1023 delete fhMeanDigiPerTrack;
1024 delete fhMeanFiredPerTrack;
1025 delete fhPtTime;
1026 delete fhDigiTime;
1027 delete fhDigiTimeRes;
1028 delete fhDigiTimeResB;
1029 delete fhToTDist;
1030
1031 delete fhElecChOccup;
1032 delete fhMultiDigiEvtElCh;
1033 delete fhNbDigiEvtElCh;
1034 delete fhNbTracksEvtElCh;
1035 delete fhFiredEvtElCh;
1036 delete fhMultiProbElCh;
1037
1038 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
1039 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
1040 if (0 == fDigiBdfPar->GetClusterModel()) delete fh1ClusterSizeProb[iSmType];
1041 delete fh1ClusterTotProb[iSmType];
1042 }
1043
1044 return kTRUE;
1045}
1046/************************************************************************************/
1047// Functions for the merging of "gap digis" and "multiple hits digis" into "channel digis"
1048// TODO: FEE double hit discrimination capability (using Time distance between Digis)
1049// TODO: Charge summing up
1051{
1052
1053 if (bFakeBeamCounter) {
1054 UInt_t uChanUId = 0x00002806;
1055 Double_t dHitTime = fCurrentEventTime + gRandom->Gaus(0., 0.04);
1056 const Double_t dHitTot = 2.;
1057 CbmTofDigi* tDigi = new CbmTofDigi(uChanUId, dHitTime, dHitTot);
1058 CbmMatch* tMatch = new CbmMatch();
1059 SendData(tDigi->GetTime(), tDigi, tMatch); // Send digi to DAQ
1060 fiNbDigis++;
1061 LOG(debug) << Form("Add fake diamond digis 0x%08x mode with t = %7.3f", uChanUId, dHitTime);
1062 //delete tDigi;
1063 //delete tMatch;
1064 }
1065
1066 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
1067
1068 // loop over each (Smtype, Sm, Rpc, Channel, Side)
1069 for (Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++) {
1070 Int_t iNbSm = fDigiBdfPar->GetNbSm(iSmType);
1071 Int_t iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
1072
1073 for (Int_t iSm = 0; iSm < iNbSm; iSm++)
1074 for (Int_t iRpc = 0; iRpc < iNbRpc; iRpc++) {
1075 Int_t iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
1076 Int_t iNbSides = 2 - fDigiBdfPar->GetChanType(iSmType, iRpc);
1077
1078 for (Int_t iCh = 0; iCh < iNbCh; iCh++)
1079 for (Int_t iSide = 0; iSide < iNbSides; iSide++) {
1080 Int_t iNbDigis = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].size();
1081
1082 // TOF QA: monitor number of tracks leading to digi before merging them
1083 Int_t iNbTracks = 0;
1084 std::vector<Int_t> vPrevTrackIdList;
1085 if (0 < iNbDigis) {
1086 CbmMatch* digiMatch;
1087 for (Int_t iDigi = 0; iDigi < iNbDigis; iDigi++) { //store matches with digis
1088 LOG(debug) << Form(
1089 " Create match for Digi %d(%d), addr 0x%08x; %d", iDigi, iNbDigis,
1090 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].first->GetAddress(),
1091 fStorDigiMatch[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi]);
1092
1093 digiMatch = new CbmMatch();
1094 digiMatch->AddLink(CbmLink(1.,
1095 fStorDigiMatch[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi],
1097
1098 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].second = digiMatch;
1099 }
1100 if (1 < iNbDigis) { // time sort digis
1101 std::sort(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].begin(),
1102 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].end(), CompTExp);
1103 }
1104
1105 if (fbMonitorHistos) {
1106 fhNbDigiEvtElCh->Fill(fvRpcChOffs[iSmType][iSm][iRpc] + iNbSides * iCh + iSide, iNbDigis);
1107 fhDigiNbElecCh->Fill(iNbDigis);
1108 fhFiredEvtElCh->Fill(fvRpcChOffs[iSmType][iSm][iRpc] + iNbSides * iCh + iSide);
1109 if (1 < iNbDigis) fhMultiDigiEvtElCh->Fill(fvRpcChOffs[iSmType][iSm][iRpc] + iNbSides * iCh + iSide);
1110 }
1111
1112 if (0 == fStorDigiMatch[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].size()) {
1113 LOG(error) << Form(" cannot add digiMatch for (%d,%d,%d,%d,%d) at pos %d", iSmType, iSm, iRpc, iCh,
1114 iSide, fiNbDigis);
1115 break;
1116 }
1117
1118 Int_t iDigi0 = 0;
1119 digiMatch = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].second;
1120 if (iNbDigis > 1) {
1121 LOG(debug) << Form(
1122 "Now apply deadtime %f for %d digis, "
1123 "digi0=%d for adress 0x%08x ",
1124 fDigiBdfPar->GetDeadtime(), iNbDigis, iDigi0,
1125 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].first->GetAddress());
1126 Double_t fdDeadtime = fDigiBdfPar->GetDeadtime();
1127 for (Int_t iDigi = 1; iDigi < iNbDigis; iDigi++) {
1128 // find Digis in deadtime of first Digi
1129 if ((fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].first->GetTime()
1130 - fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].first->GetTime())
1131 < fdDeadtime) { // Store Link with weight 0 to have a trace of MC tracks firing the channel
1132 // but whose Digi is not propagated to next stage
1133 digiMatch = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].second;
1134 Int_t nL =
1135 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].second->GetNofLinks();
1136 if (nL != 1) LOG(fatal) << "Invalid number of Links " << nL;
1137
1138 CbmLink L0 =
1139 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].second->GetLink(0);
1140 digiMatch->AddLink(CbmLink(0., L0.GetIndex(), fCurrentMCEntry, fCurrentInput));
1141
1142 // cleanup of obsolete digis, matches and links done below
1143 }
1144 else { // new digi found
1145 // new digi will be created and later deleted by CbmDaq.
1146 // The original digi will be deleted below, together with the unused digis from the buffer.
1147 CbmTofDigi* digi =
1148 new CbmTofDigi(*(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].first));
1149 CbmMatch* match =
1150 new CbmMatch(*(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].second));
1151
1152 digi->SetTime(digi->GetTime() * fdDigiTimeConvFactor + fCurrentEventTime); // ns->ps
1153 SendData(digi->GetTime(), digi, match); // Send digi to DAQ
1154 fiNbDigis++;
1155
1156 // TOF QA
1157 if (fbMonitorHistos && NULL != digiMatch) {
1158 Int_t nL = digiMatch->GetNofLinks();
1159 for (Int_t iL = 0; iL < nL; iL++) {
1160 // TOF QA: monitor number of tracks leading to digi before merging them
1161 CbmLink L = digiMatch->GetLink(iL);
1162 Bool_t bTrackFound = kFALSE;
1163 for (UInt_t uTrkId = 0; uTrkId < vPrevTrackIdList.size(); uTrkId++)
1164 if (vPrevTrackIdList[uTrkId]
1165 == ((CbmTofPoint*) fTofPointsColl->At(L.GetIndex()))->GetTrackID()) {
1166 bTrackFound = kTRUE;
1167 break;
1168 } // If TrackId already found for this Elec. Chan in this event
1169 if (kFALSE == bTrackFound) {
1170 // New track or first track
1171 iNbTracks++;
1172 vPrevTrackIdList.push_back(((CbmTofPoint*) fTofPointsColl->At(L.GetIndex()))->GetTrackID());
1173 } // if( kFALSE == bTrackFound )
1174 } // for( Int_t iL = 0; iL < nL; iL++
1175 vPrevTrackIdList.clear();
1176 // TOF QA: monitor number of tracks leading to digi before merging them
1177 fhNbTracksEvtElCh->Fill(fvRpcChOffs[iSmType][iSm][iRpc] + iNbSides * iCh + iSide, iNbTracks);
1178 } // if(fbMonitorHistos)
1179
1180 iDigi0 = iDigi;
1181 }
1182 }
1183 } // if( iNbDigis > 1) end
1184 // assemble and send last digi
1185 // new digi will be created and later deleted by CbmDaq.
1186 // The original digi will be deleted below, together with the unused digis from the buffer.
1187 CbmTofDigi* digi =
1188 new CbmTofDigi(*(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].first));
1189 CbmMatch* match =
1190 new CbmMatch(*(fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi0].second));
1191 digi->SetTime(digi->GetTime() * fdDigiTimeConvFactor + fCurrentEventTime); // ns->ps
1192 SendData(digi->GetTime(), digi, match); // Send digi to DAQ
1193 fiNbDigis++;
1194
1195 if (fbMonitorHistos) {
1196 Int_t nL = digiMatch->GetNofLinks();
1197 for (Int_t iL = 0; iL < nL; iL++) {
1198 // TOF QA: monitor number of tracks leading to digi before merging them
1199 CbmLink L = digiMatch->GetLink(iL);
1200 Bool_t bTrackFound = kFALSE;
1201 for (UInt_t uTrkId = 0; uTrkId < vPrevTrackIdList.size(); uTrkId++)
1202 if (vPrevTrackIdList[uTrkId] == ((CbmTofPoint*) fTofPointsColl->At(L.GetIndex()))->GetTrackID()) {
1203 bTrackFound = kTRUE;
1204 break;
1205 } // If TrackId already found for this Elec. Chan in this event
1206 if (kFALSE == bTrackFound) {
1207 // New track or first track
1208 iNbTracks++;
1209 vPrevTrackIdList.push_back(((CbmTofPoint*) fTofPointsColl->At(L.GetIndex()))->GetTrackID());
1210 } // if( kFALSE == bTrackFound )
1211 } // for( Int_t iL = 0; iL < nL; iL++
1212 vPrevTrackIdList.clear();
1213 // TOF QA: monitor number of tracks leading to digi before merging them
1214 fhNbTracksEvtElCh->Fill(fvRpcChOffs[iSmType][iSm][iRpc] + iNbSides * iCh + iSide, iNbTracks);
1215 } // if(fbMonitorHistos)
1216
1217 for (Int_t iDigi = 0; iDigi < iNbDigis; iDigi++) {
1218 CbmTofDigi* tmpDigi = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].first;
1219 CbmMatch* tmpMatch = fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide][iDigi].second;
1220 if (tmpDigi) delete tmpDigi;
1221 if (tmpMatch) delete tmpMatch;
1222 // delete fStorDigiMatch[iSmType][iSm*iNbRpc + iRpc][iNbSides*iCh+iSide][iDigi];
1223 } //
1224
1225 fStorDigi[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].clear();
1226 fStorDigiMatch[iSmType][iSm * iNbRpc + iRpc][iNbSides * iCh + iSide].clear();
1227 } // if( 0 < iNbDigis )
1228 } // for each (Ch, Side) pair
1229 } // for each (Sm, rpc) pair
1230 } // for( Int_t iSmType = 0; iSmType < iNbSmTypes; iSmType++ )
1231
1232 return kTRUE;
1233}
1234/************************************************************************************/
1235// Functions for the Cluster Radius generation
1236Double_t CbmTofDigitize::GenerateClusterRadius(Int_t iSmType, Int_t iRpc)
1237{
1238 Double_t dClusterRadius = 0;
1239 Int_t iChType = fDigiBdfPar->GetChanType(iSmType, iRpc);
1240
1242 case -1: {
1243 // Fixed value at 0.0002 to get a cluster size as close to 1 as possible
1244 dClusterRadius = 0.0002;
1245 break;
1246 }
1247 case 0: {
1248 // Single value using the beamtime cluster size distribution mean
1249 if (0 == iChType) {
1250 // Simple linear relation mean cluster size = 2* radius +1 in [strips]
1251 // Cf "RadiusToMeanClusterAll" histogram
1252 // Come from simple geometry of cluster center position if one
1253 // neglect RPC and extremities edge effects
1254 dClusterRadius = (fh1ClusterSizeProb[iSmType]->GetMean() - 1.0) / 2.0;
1255 // Convert to [cm]
1256 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
1257 // Horizontal channel => strip width along Y
1258 dClusterRadius *= fChannelInfo->GetSizey();
1259 // Vertical channel => strip width along X
1260 else
1261 dClusterRadius *= fChannelInfo->GetSizex();
1262 } // if( 0 == iChType)
1263 else {
1264 LOG(error) << "CbmTofDigitize::GenerateClusterRadius => Cluster Radius "
1265 << "obtention from cluster size not implemented for pads, Sm type " << iSmType << " Rpc " << iRpc;
1266 LOG(error) << "CbmTofDigitize::GenerateClusterRadius => Test "
1267 << " Sm type " << iSmType << " Rpc " << iRpc << " Type " << iChType << " Type " << (Int_t) iChType;
1268 return kFALSE;
1269 } // else of if( 0 == iChType)
1270 break;
1271 } // case 0:
1272 case 1:
1273 case 2: {
1274 if (0 == iChType) {
1275 // from beamtime cluster size distribution
1276 Double_t dStripSize = 0;
1277 // Convert to [cm]
1278 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
1279 // Horizontal channel => strip width along Y
1280 dStripSize = fChannelInfo->GetSizey();
1281 // Vertical channel => strip width along X
1282 else
1283 dStripSize = fChannelInfo->GetSizex();
1284
1285 // Obtain the Landau peak position and sigma scale factor
1286 // from the parameter object. It should take care of getting the values
1287 // either from the ASCII parameter file or from a fit on the beam data
1288 // TODO: cross-check the exact value of the second parameter, here it is set so that probability of
1289 // negative radius is really low
1290 Double_t dPeakPos = fDigiBdfPar->GetLandauMpv(iSmType);
1291 Double_t dSigmScal = fDigiBdfPar->GetLandauSigma(iSmType); // empirical best
1292
1293 // Get the actual Cluster radius
1294 dClusterRadius = dStripSize * gRandom->Landau(dPeakPos, dSigmScal);
1295 if (dClusterRadius < 0) dClusterRadius = 0;
1296 } // if( 0 == iChType)
1297 else {
1298 LOG(error) << "CbmTofDigitize::GenerateClusterRadius => Cluster Radius "
1299 << "obtention from cluster size not implemented for pads, Sm type " << iSmType << " Rpc " << iRpc;
1300 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc => Test 2"
1301 << " Sm type " << iSmType << " Rpc " << iRpc << " Type " << iChType;
1302 return kFALSE;
1303 } // else of if( 0 == iChType)
1304 break;
1305 } // case 1:
1306 default: {
1307 LOG(error) << "CbmTofDigitize::GenerateClusterRadius => Wrong Cluster "
1308 "Radius method , Sm type "
1309 << iSmType << " Rpc " << iRpc;
1310 dClusterRadius = 0;
1311 break;
1312 } // default:
1313 } // switch( fDigiBdfPar->GetClusterRadiusModel() )
1314 return dClusterRadius;
1315}
1316/************************************************************************************/
1317// Functions for a direct use of the cluster size
1319{
1320 // Uniform distribution in ]0;x]
1321 // gRandom->Uniform(x);
1322 // Gauss distribution in of mean m, sigma s
1323 // gRandom->Gauss(m, s);
1324
1325 CbmTofPoint* pPoint;
1326 CbmMCTrack* pMcTrk;
1327
1328 Int_t nTofPoint = fTofPointsColl->GetEntriesFast();
1329 Int_t nMcTracks = fMcTracksColl->GetEntriesFast();
1330
1331 // Prepare the temporary storing of the Track/Point/Digi info
1332 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1333 fvlTrckChAddr.resize(nMcTracks);
1334 fvlTrckRpcAddr.resize(nMcTracks);
1335 fvlTrckRpcTime.resize(nMcTracks);
1336 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1337 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
1338 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1339 fvlTrckChAddr[iTrkInd].clear();
1340 fvlTrckRpcAddr[iTrkInd].clear();
1341 fvlTrckRpcTime[iTrkInd].clear();
1342 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1343 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
1344
1345 if (fbMcTrkMonitor) {
1346 // Debug Info printout
1347 Int_t iNbTofTracks = 0;
1348 Int_t iNbTofTracksPrim = 0;
1349
1350 LOG(debug1) << "CbmTofDigitize::DigitizeDirectClusterSize: " << nTofPoint << " points in Tof for this event with "
1351 << nMcTracks << " MC tracks ";
1352 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
1353 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkInd);
1354 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof)) iNbTofTracks++;
1355 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof) && -1 == pMcTrk->GetMotherId()) iNbTofTracksPrim++;
1356 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
1357
1358 //Some numbers on TOF distributions
1359 LOG(debug1) << "CbmTofDigitize::DigitizeDirectClusterSize: " << iNbTofTracks << " tracks in Tof ";
1360 LOG(debug1) << "CbmTofDigitize::DigitizeDirectClusterSize: " << iNbTofTracksPrim << " tracks in Tof from vertex";
1361 } // if( fbMcTrkMonitor )
1362
1363 // Tof Point Info
1364 Int_t iDetId, iSmType, iSM, iRpc, iChannel, iGap;
1365 Int_t iTrackID, iChanId;
1366 TVector3 vPntPos;
1367 // Cluster Info
1368 Int_t iClusterSize;
1369 Double_t dClustCharge;
1370 // Digi
1371 // CbmTofDigi * pTofDigi; // <- Compressed digi (64 bits)
1372 // CbmTofDigi * pTofDigiExp; // <- Expanded digi
1373 // General geometry info
1374 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
1375 Int_t iNbSm, iNbRpc, iNbCh;
1376 Int_t iChType;
1377
1378 // Start jitter: Same contrib. for all points in same event
1379 // FIXME
1380 // Actually, event start time reconstruction should not be done in the ToF
1381 // digitizer, neither in event-based nor in time-based mode. The timestamp
1382 // of a CbmTofDigi object is not the time difference between signals in a
1383 // (hypothetical) start detector system and the MRPC wall but rather
1384 // represents the detection point in time in an MRPC measured with respect to
1385 // the start of the run.
1386 // For compatibility reasons, we continue adding a start detector jitter to
1387 // digi timestamps in event-based mode. In time-based mode, event start time
1388 // reconstruction is not considered here.
1389 Double_t dStartJitter = 0.;
1390 if (fEventMode) { dStartJitter = gRandom->Gaus(0.0, fDigiBdfPar->GetStartTimeRes()); }
1391
1392 for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++) {
1393 // Get a pointer to the TOF point
1394 pPoint = (CbmTofPoint*) fTofPointsColl->At(iPntInd);
1395 if (NULL == pPoint) {
1396 LOG(warning) << "CbmTofDigitize::DigitizeDirectClusterSize => Be "
1397 "careful: hole in the CbmTofPoint TClonesArray!";
1398 continue;
1399 } // if( pPoint )
1400
1401 // Get all channel info
1402 iDetId = pPoint->GetDetectorID();
1403 iSmType = fGeoHandler->GetSMType(iDetId);
1404 iRpc = fGeoHandler->GetCounter(iDetId);
1405
1406 iChannel = fGeoHandler->GetCell(iDetId);
1408 iChannel--; // Again, channel going from 1 to nbCh instead of 0 to nbCh - 1 ?!?!?
1409 iGap = fGeoHandler->GetGap(iDetId);
1410 iSM = fGeoHandler->GetSModule(iDetId);
1411 iChanId = fGeoHandler->GetCellId(iDetId);
1412 iTrackID = pPoint->GetTrackID();
1413
1414 iNbSm = fDigiBdfPar->GetNbSm(iSmType);
1415 iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
1416 iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
1417 iChType = fDigiBdfPar->GetChanType(iSmType, iRpc);
1418 Int_t iTrkId = pPoint->GetTrackID();
1419
1420 // Catch case where the MC track was removed from the transport stack
1421 if (iTrkId < 0) {
1422 if (fbAllowPointsWithoutTrack) continue;
1423 else
1424 LOG(fatal) << "CbmTofDigitize::DigitizeDirectClusterSize => TofPoint without "
1425 "valid MC track Index, "
1426 << " track was probably cut at the transport level! "
1427 << " Pnt Idx: " << iPntInd << " Trk Idx: " << iTrkId << "\n"
1428 << "=============> To allow this kind of points and simply jump "
1429 "them, "
1430 << "call CbmTofDigitize::AllowPointsWithoutTrack() in your macro!!";
1431 } // if( iTrkId < 0 )
1432
1433 if (fbMcTrkMonitor) {
1434 // Get pointer to the MC-Track info
1435 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkId);
1436
1437 // Keep only primaries
1438 if (kTRUE == fDigiBdfPar->UseOnlyPrimaries())
1439 if (-1 != pMcTrk->GetMotherId()) continue;
1440 } // if( fbMcTrkMonitor )
1441
1442 if (iSmType < 0. || iNbSmTypes <= iSmType || iSM < 0. || iNbSm <= iSM || iRpc < 0. || iNbRpc <= iRpc
1443 || iChannel < 0. || iNbCh <= iChannel) {
1444 LOG(error) << Form("CbmTofDigitize => det ID 0x%08x", iDetId) << " SMType: " << iSmType;
1445 LOG(error) << " SModule: " << iSM << " of " << iNbSm + 1;
1446 LOG(error) << " Module: " << iRpc << " of " << iNbRpc + 1;
1447 LOG(error) << " Gap: " << iGap;
1448 LOG(fatal) << " Cell: " << iChannel << " of " << iNbCh + 1;
1449 continue;
1450 } // if error on channel data
1451
1452 // Check if there was already a Digi from the same track created
1453 // with this channel as main channel
1454 ULong64_t uAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, iChannel, 0, iSmType);
1455 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1456 Bool_t bFoundIt = kFALSE;
1457 // Check if this track ID is bigger than size of McTracks TClonesArray (maybe happen with PSD cut!!)
1458 // If yes, resize the array to reach the appropriate number of fields
1459 // Cast of TrackId is safe as we already check for "< 0" case
1460 // TODO: Is this check still required when Id < 0 are jumped?
1461 if (fvlTrckChAddr.size() <= static_cast<UInt_t>(iTrkId)) fvlTrckChAddr.resize(iTrkId + 1);
1462
1463 for (UInt_t uTrkMainCh = 0; uTrkMainCh < fvlTrckChAddr[iTrkId].size(); uTrkMainCh++)
1464 if (uAddr == fvlTrckChAddr[iTrkId][uTrkMainCh]) {
1465 bFoundIt = kTRUE;
1466 break;
1467 }
1468 // If it is the case, no need to redo the full stuff for this gap
1469 if (kTRUE == bFoundIt) continue;
1470 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1471
1472 // Probability that the RPC detect the hit
1473 // if( fDigiBdfPar->GetEfficiency(iSmType) < gRandom->Uniform(1) )
1474 // continue;
1475
1476 // Probability that the gap detect the hit
1477 // For now use a simple gap treatment (cf CbmTofDigiBdfPar):
1478 // - a single fired gap fires the channel
1479 // - all gaps have exactly equivalent efficiency/firing probability
1480 // - independent gap firing (no charge accumulation or such)
1481 // The probability for a hit not to fire at all is then
1482 // (1-p)^NGaps with p = gap efficiency and Ngaps the number of gaps in this RPC
1483 // This results in the relation: p = 1 - (1 - P)^(1/Ngaps)
1484 // with P = RPC efficiency from beamtime
1485 if (fDigiBdfPar->GetGapEfficiency(iSmType, iRpc) < gRandom->Uniform(1)) continue;
1486
1487 // Save the address in vector so that this channel is not redone later for the
1488 // eventual other gaps TofPoint
1489 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) fvlTrckChAddr[iTrkId].push_back(uAddr);
1490
1491 // Get TofPoint Position
1492 pPoint->Position(vPntPos);
1493 fChannelInfo = fDigiPar->GetCell(iChanId);
1494 TGeoNode* fNode = // prepare global->local trafo
1495 gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
1496 LOG(debug1) << Form(" TofDigitizerBDF:: (%3d,%3d,%3d,%3d) - node at "
1497 "(%6.1f,%6.1f,%6.1f) : 0x%p Pos(%6.1f,%6.1f,%6.1f)",
1498 iSmType, iSM, iRpc, iChannel, fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ(),
1499 fNode, vPntPos.X(), vPntPos.Y(), vPntPos.Z());
1500 gGeoManager->GetCurrentNode();
1501 gGeoManager->GetCurrentMatrix();
1502
1503 Double_t poipos[3] = {vPntPos.X(), vPntPos.Y(), vPntPos.Z()};
1504 Double_t poipos_local[3];
1505 Double_t poipos_local_man[3];
1506 gGeoManager->MasterToLocal(poipos, poipos_local_man);
1507 fDigiPar->GetNode(iChanId)->MasterToLocal(poipos, poipos_local);
1508 for (Int_t i = 0; i < 3; i++)
1509 if (poipos_local[i] != poipos_local_man[i])
1510 LOG(fatal) << "Inconsistent M2L result " << i << ": " << poipos_local[i] << " != " << poipos_local_man[i];
1511
1512 if (1 == iChType) {
1513 LOG(error) << "CbmTofDigitize::DigitizeDirectClusterSize => This method "
1514 << "is not available for pads!!";
1515 return kFALSE;
1516 } // if( 1 == iChType)
1517
1518 // Cluster size from beamtime distribution in [strips]
1519 iClusterSize =
1520 fh1ClusterSizeProb[iSmType]->GetBinContent(fh1ClusterSizeProb[iSmType]->FindBin(gRandom->Uniform(1)));
1521
1522 Int_t iNbStripsSideA;
1523 Int_t iNbStripsSideB;
1524 if (1 == iClusterSize % 2) {
1525 // odd => a center strip and symetric side strips
1526 iNbStripsSideA = (iClusterSize - 1) / 2;
1527 iNbStripsSideB = (iClusterSize - 1) / 2;
1528 } // if odd cluster size
1529 else {
1530 // even => asymetric, the side getting more strips depends
1531 // on the cluster center position
1532 iNbStripsSideA = iClusterSize / 2; // left/bottom
1533 iNbStripsSideB = iClusterSize / 2; // right/top
1534
1535 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
1536 // Horizontal strips
1537 if (poipos_local[1] < fChannelInfo->GetSizey() / 2.0) //FIXME, needs posiion in rotated counter frame
1538 iNbStripsSideB--; // less strips on top
1539 else
1540 iNbStripsSideA--; // less strips on bottom
1541 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
1542 else if (poipos_local[0] < fChannelInfo->GetSizex() / 2.0) //FIXME
1543 iNbStripsSideB--; // less strips on right
1544 else
1545 iNbStripsSideA--; // less strips on left
1546 } // if even cluster size
1547
1548 // Generate Cluster charge as ToT[ps]
1549 dClustCharge = fh1ClusterTotProb[iSmType]->GetBinContent(fh1ClusterTotProb[iSmType]->FindBin(gRandom->Uniform(1)));
1550
1551 // Calculate the time for the central channel
1552 Double_t dCentralTime;
1553 // Check if there was already a Digi from the same track created in this RPC
1554 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1555 ULong64_t uRpcAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, 0, 0, iSmType);
1556 Bool_t bFoundIt = kFALSE;
1557 UInt_t uTrkRpcPair = 0;
1558 for (uTrkRpcPair = 0; uTrkRpcPair < fvlTrckRpcAddr[iTrkId].size(); uTrkRpcPair++)
1559 if (uRpcAddr == fvlTrckRpcAddr[iTrkId][uTrkRpcPair]) {
1560 bFoundIt = kTRUE;
1561 break;
1562 }
1563 // If it is the case, we should reuse the timing already assigned to this track
1564 if (kTRUE == bFoundIt) dCentralTime = fvlTrckRpcTime[iTrkId][uTrkRpcPair];
1565 else {
1566 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
1567 + dStartJitter; // Same contrib. for all points in same event
1568 fvlTrckRpcAddr[iTrkId].push_back(uRpcAddr);
1569 fvlTrckRpcTime[iTrkId].push_back(dCentralTime);
1570 } // No Digi yet in this RPC for this Track
1571 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1572 else
1573 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
1574 + dStartJitter; // Same contrib. for all points in same event
1575
1576 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
1577 // Horizontal channel: A = Right and B = Left of the channel
1578
1579 // Assume the width (sigma) of the gaussian is 0.5*dClusterSize/3
1580 // => 99% of the charge is in "dClusterSize"
1581 TF1* f1ChargeGauss = new TF1("f1ChargeDist", "[0]*TMath::Gaus(x,[1],[2])", poipos_local[1] - 2 * iClusterSize,
1582 poipos_local[1] + 2 * iClusterSize);
1583 // TofChargeDistributions * fptr = new TofChargeDistributions();
1584 // TF1 * f1ChargeGauss = new TF1( "f1ChargeDist", fptr,
1585 // &TofChargeDistributions::Gauss1D,
1586 // poipos_local[1] - 2*iClusterSize,
1587 // poipos_local[1] + 2*iClusterSize,
1588 // 3
1589 // );
1590 // FIXME: wrong normalization
1591 // why is there a coefficient of 1/2 for the standard deviation?
1592 // why is the mean given in [cm] and the standard deviation dimensionless?
1593 f1ChargeGauss->SetParameters(dClustCharge / (TMath::Sqrt(2.0 * TMath::Pi() * iClusterSize / 6.0)),
1594 poipos_local[1], 0.5 * iClusterSize / 3.0);
1595
1596 double* x = new double[kiNbIntPts];
1597 double* w = new double[kiNbIntPts];
1598 f1ChargeGauss->CalcGaussLegendreSamplingPoints(kiNbIntPts, x, w, 1e-12);
1599 // Loop over strips, get the share of the charge each get, compute
1600 // the times it measure and create the digis
1601 for (Int_t iStripInd = iChannel - iNbStripsSideA; iStripInd <= iChannel + iNbStripsSideB; iStripInd++)
1602 if (0 <= iStripInd && iStripInd < iNbCh) {
1603 Int_t iCh1 = iStripInd;
1604 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
1605 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
1606 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
1607 fChannelInfo = fDigiPar->GetCell(iSideChId);
1608
1609 Double_t dStripCharge =
1610 f1ChargeGauss->IntegralFast(kiNbIntPts, x, w, fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
1611 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
1612
1613 // Fee Threshold on charge, each side gets half, each side has a gain
1615 < dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd + 1] / 2.0) {
1616 Double_t dTimeA = dCentralTime;
1617 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
1618#ifdef FULL_PROPAGATION_TIME
1619 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
1620#else
1621 + (poipos_local[0])
1622#endif
1623 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
1624 CbmTofDigi* tofDigi = new CbmTofDigi(
1625 iSM, iRpc, iChannel, dTimeA,
1626 dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0, 1, iSmType);
1627 // tofDigi->GetMatch()->AddLink(1., iPntInd);
1628 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
1629 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(data);
1630 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(iPntInd);
1631
1632 LOG(debug) << Form("Digimatch (%d,%d,%d,%d): size %zu, valA %d, MCt %d", iSmType, iSM, iRpc, iChannel,
1633 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
1634 iTrackID);
1635 } // if Side A above threshold
1637 < dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd] / 2.0) {
1638 Double_t dTimeB = dCentralTime;
1639 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
1640#ifdef FULL_PROPAGATION_TIME
1641 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
1642#else
1643 - (poipos_local[0])
1644#endif
1645 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
1646 CbmTofDigi* tofDigi = new CbmTofDigi(
1647 iSM, iRpc, iChannel, dTimeB,
1648 dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel] / 2.0, 0, iSmType);
1649 // tofDigi->GetMatch()->AddLink(1., iPntInd);
1650 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
1651 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(data);
1652 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(iPntInd);
1653 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, valB %d, MCt %d", iSmType, iSM, iRpc, iChannel,
1654 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
1655 iTrackID);
1656
1657 } // if Side B above threshold
1658 } // if( 0 <= iStripInd && iStripInd < iNbCh )
1659 delete f1ChargeGauss;
1660 // delete []x;
1661 // delete []w;
1662 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
1663 else {
1664 // Vertical channel: A = Top and B = Bottom of the channel
1665
1666 // Assume the width (sigma) of the gaussian is 0.5*dClusterSize/3
1667 // => 99% of the charge is in "dClusterSize"
1668 TF1* f1ChargeGauss = new TF1("f1ChargeDist", "[0]*TMath::Gaus(x,[1],[2])", poipos_local[0] - 2 * iClusterSize,
1669 poipos_local[0] + 2 * iClusterSize);
1670
1671 // TofChargeDistributions * fptr = new TofChargeDistributions();
1672 // TF1 * f1ChargeGauss = new TF1( "f1ChargeDist", fptr,
1673 // &TofChargeDistributions::Gauss1D,
1674 // poipos_local[1] - 2*iClusterSize,
1675 // poipos_local[1] + 2*iClusterSize,
1676 // 3
1677 // );
1678 f1ChargeGauss->SetParameters(dClustCharge / (TMath::Sqrt(2.0 * TMath::Pi()) * iClusterSize / 6.0),
1679 poipos_local[0], 0.5 * iClusterSize / 3.0);
1680
1681 double* x = new double[kiNbIntPts];
1682 double* w = new double[kiNbIntPts];
1683 f1ChargeGauss->CalcGaussLegendreSamplingPoints(kiNbIntPts, x, w, 1e-12);
1684 // Loop over strips, get the share of the charge each get, compute
1685 // the times it measure and create the digis
1686 for (Int_t iStripInd = iChannel - iNbStripsSideA; iStripInd <= iChannel + iNbStripsSideB; iStripInd++)
1687 if (0 <= iStripInd && iStripInd < iNbCh) {
1688 Int_t iCh1 = iStripInd;
1689 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
1690 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
1691 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
1692 fChannelInfo = fDigiPar->GetCell(iSideChId);
1693
1694 Double_t dStripCharge =
1695 f1ChargeGauss->IntegralFast(kiNbIntPts, x, w, fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
1696 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0);
1697
1698 // Fee Threshold on charge, each side gets half, each side has a gain
1700 < dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd + 1] / 2.0) {
1701 Double_t dTimeA = dCentralTime;
1702 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
1703#ifdef FULL_PROPAGATION_TIME
1704 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
1705#else
1706 + (poipos_local[1])
1707#endif
1708 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
1709 LOG(debug) << "Create DigiA TSRC " << iSmType << iSM << iRpc << iStripInd
1710 << Form("at %f, ypos %f", dTimeA, poipos_local[1]);
1711 CbmTofDigi* tofDigi = new CbmTofDigi(
1712 iSM, iRpc, iStripInd, dTimeA,
1713 dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd + 1] / 2.0, 1, iSmType);
1714 // tofDigi->GetMatch()->AddLink(1., iPntInd);
1715 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
1716 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd + 1].push_back(data);
1717 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd + 1].push_back(iPntInd);
1718 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, valC %d, MCt %d", iSmType, iSM, iRpc, iChannel,
1719 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
1720 iTrackID);
1721 } // if Side A above threshold
1723 < dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd] / 2.0) {
1724 Double_t dTimeB = dCentralTime;
1725 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
1726#ifdef FULL_PROPAGATION_TIME
1727 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
1728#else
1729 - (poipos_local[1])
1730#endif
1731 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
1732 LOG(debug) << "Create DigiB TSRC " << iSmType << iSM << iRpc << iStripInd
1733 << Form("at %f, ypos %f", dTimeB, poipos_local[1]);
1734 CbmTofDigi* tofDigi = new CbmTofDigi(
1735 iSM, iRpc, iStripInd, dTimeB,
1736 dStripCharge * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd] / 2.0, 0, iSmType);
1737 // tofDigi->GetMatch()->AddLink(1., iPntInd);
1738 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
1739 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd].push_back(data);
1740 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iStripInd].push_back(iPntInd);
1741 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, valE %d, MCt %d", iSmType, iSM, iRpc, iChannel,
1742 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
1743 iTrackID);
1744 } // if Side B above threshold
1745 } // if( 0 <= iStripInd && iStripInd < iNbCh )
1746 delete f1ChargeGauss;
1747 delete[] x;
1748 delete[] w;
1749 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
1750 } // for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++ )
1751
1752 // Clear the Track to channel temporary storage
1753 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1754 for (UInt_t uTrkInd = 0; uTrkInd < fvlTrckChAddr.size(); uTrkInd++) {
1755 fvlTrckChAddr[uTrkInd].clear();
1756 fvlTrckRpcAddr[uTrkInd].clear();
1757 fvlTrckRpcTime[uTrkInd].clear();
1758 }
1759 fvlTrckChAddr.clear();
1760 fvlTrckRpcAddr.clear();
1761 fvlTrckRpcTime.clear();
1762 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1763
1764 return kTRUE;
1765}
1766/************************************************************************************/
1767// Functions for a simple "Flat disc" cluster approximation
1769{
1770 // Uniform distribution in ]0;x]
1771 // gRandom->Uniform(x);
1772 // Gauss distribution in of mean m, sigma s
1773 // gRandom->Gauss(m, s);
1774
1775 CbmTofPoint* pPoint;
1776 CbmMCTrack* pMcTrk;
1777
1778 Int_t nTofPoint = fTofPointsColl->GetEntriesFast();
1779 Int_t nMcTracks = fMcTracksColl->GetEntriesFast();
1780
1781 // Prepare the temporary storing of the Track/Point/Digi info
1782 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1783 fvlTrckChAddr.resize(nMcTracks);
1784 fvlTrckRpcAddr.resize(nMcTracks);
1785 fvlTrckRpcTime.resize(nMcTracks);
1786 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1787 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
1788 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1789 fvlTrckChAddr[iTrkInd].clear();
1790 fvlTrckRpcAddr[iTrkInd].clear();
1791 fvlTrckRpcTime[iTrkInd].clear();
1792 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1793 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
1794
1795 if (fbMcTrkMonitor) {
1796 // Debug Info printout
1797 Int_t iNbTofTracks = 0;
1798 Int_t iNbTofTracksPrim = 0;
1799
1800 LOG(debug1) << "CbmTofDigitize::DigitizeFlatDisc: " << nTofPoint << " points in Tof for this event with "
1801 << nMcTracks << " MC tracks ";
1802 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
1803 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkInd);
1804 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof)) iNbTofTracks++;
1805 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof) && -1 == pMcTrk->GetMotherId()) iNbTofTracksPrim++;
1806 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
1807
1808 //Some numbers on TOF distributions
1809 LOG(debug1) << "CbmTofDigitize::DigitizeFlatDisc: " << iNbTofTracks << " tracks in Tof ";
1810 LOG(debug1) << "CbmTofDigitize::DigitizeFlatDisc: " << iNbTofTracksPrim << " tracks in Tof from vertex";
1811 } // if( fbMcTrkMonitor )
1812
1813 // Tof Point Info
1814 Int_t iDetId, iSmType, iSM, iRpc, iChannel, iGap;
1815 Int_t iTrackID, iChanId;
1816 TVector3 vPntPos;
1817 // Cluster Info
1818 Double_t dClusterSize;
1819 Double_t dClustCharge;
1820 // Digi
1821 // CbmTofDigi * pTofDigi; // <- Compressed digi (64 bits)
1822 // CbmTofDigi * pTofDigiExp; // <- Expanded digi
1823 // General geometry info
1824 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
1825 Int_t iNbSm, iNbRpc, iNbCh;
1826 Int_t iChType;
1827
1828 // Start jitter: Same contrib. for all points in same event
1829 // FIXME
1830 // Actually, event start time reconstruction should not be done in the ToF
1831 // digitizer, neither in event-based nor in time-based mode. The timestamp
1832 // of a CbmTofDigi object is not the time difference between signals in a
1833 // (hypothetical) start detector system and the MRPC wall but rather
1834 // represents the detection point in time in an MRPC measured with respect to
1835 // the start of the run.
1836 // For compatibility reasons, we continue adding a start detector jitter to
1837 // digi timestamps in event-based mode. In time-based mode, event start time
1838 // reconstruction is not considered here.
1839 Double_t dStartJitter = 0.;
1840 if (!fbTimeBasedOutput) { dStartJitter = gRandom->Gaus(0.0, fDigiBdfPar->GetStartTimeRes()); }
1841
1842 for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++) {
1843 // Get a pointer to the TOF point
1844 pPoint = (CbmTofPoint*) fTofPointsColl->At(iPntInd);
1845 if (NULL == pPoint) {
1846 LOG(warning) << "CbmTofDigitize::DigitizeFlatDisc => Be careful: hole in "
1847 "the CbmTofPoint TClonesArray!"
1848 << endl;
1849 continue;
1850 } // if( pPoint )
1851
1852 // Get all channel info
1853 iDetId = pPoint->GetDetectorID();
1854 iSmType = fGeoHandler->GetSMType(iDetId);
1855 iRpc = fGeoHandler->GetCounter(iDetId);
1856 iChannel = fGeoHandler->GetCell(iDetId);
1858 iChannel--; // Again, channel going from 1 to nbCh instead of 0 to nbCh - 1 ?!?!?
1859 iGap = fGeoHandler->GetGap(iDetId);
1860 iSM = fGeoHandler->GetSModule(iDetId);
1861 iChanId = fGeoHandler->GetCellId(iDetId);
1862 iTrackID = pPoint->GetTrackID();
1863
1864 iNbSm = fDigiBdfPar->GetNbSm(iSmType);
1865 iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
1866 iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
1867 iChType = fDigiBdfPar->GetChanType(iSmType, iRpc);
1868 Int_t iTrkId = pPoint->GetTrackID();
1869
1870 // Catch case where the MC track was removed from the transport stack
1871 if (iTrkId < 0) {
1872 if (fbAllowPointsWithoutTrack) continue;
1873 else
1874 LOG(fatal) << "CbmTofDigitize::DigitizeDirectClusterSize => TofPoint without "
1875 "valid MC track Index, "
1876 << " track was probably cut at the transport level! "
1877 << " Pnt Idx: " << iPntInd << " Trk Idx: " << iTrkId << "\n"
1878 << "=============> To allow this kind of points and simply jump "
1879 "them, "
1880 << "call CbmTofDigitize::AllowPointsWithoutTrack() in your macro!!";
1881 } // if( iTrkId < 0 )
1882
1883 if (fbMcTrkMonitor) {
1884 // Get pointer to the MC-Track info
1885 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkId);
1886
1887 LOG(debug1) << Form("CbmTofDigitize => det ID 0x%08x", iDetId) << ", GeoVersion " << fGeoHandler->GetGeoVersion()
1888 << ", SMType: " << iSmType << " SModule: " << iSM << " of " << iNbSm + 1 << " Module: " << iRpc
1889 << " of " << iNbRpc + 1 << " Gap: " << iGap << " Cell: " << iChannel << " of " << iNbCh + 1;
1890
1891 // Jump all tracks not making 8 points for test
1892 // if( 8 != pMcTrk->GetNPoints(ECbmModuleId::kTof) )
1893 // continue;
1894
1895 // Keep only primaries
1896 if (kTRUE == fDigiBdfPar->UseOnlyPrimaries())
1897 if (-1 != pMcTrk->GetMotherId()) continue;
1898 } // if( fbMcTrkMonitor )
1899
1900 if (iSmType < 0. || iNbSmTypes <= iSmType || iSM < 0. || iNbSm <= iSM || iRpc < 0. || iNbRpc <= iRpc
1901 || iChannel < 0. || iNbCh <= iChannel) {
1902 LOG(error) << Form("CbmTofDigitize => det ID 0x%08x", iDetId) << ", GeoVersion " << fGeoHandler->GetGeoVersion()
1903 << ", SMType: " << iSmType;
1904 LOG(error) << " SModule: " << iSM << " of " << iNbSm + 1;
1905 LOG(error) << " Module: " << iRpc << " of " << iNbRpc + 1;
1906 LOG(error) << " Gap: " << iGap;
1907 LOG(fatal) << " Cell: " << iChannel << " of " << iNbCh + 1;
1908 continue;
1909 } // if error on channel data
1910 LOG(debug2) << "CbmTofDigitize::DigitizeFlatDisc => Check Point " << iPntInd << " Sm type " << iSmType << " SM "
1911 << iSM << " Rpc " << iRpc << " Channel " << iChannel << " Type " << iChType << " Orient. "
1912 << fDigiBdfPar->GetChanOrient(iSmType, iRpc);
1913
1914 // Check if there was already a Digi from the same track created
1915 // with this channel as main channel
1916 ULong64_t uAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, iChannel, 0, iSmType);
1917 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
1918 Bool_t bFoundIt = kFALSE;
1919 // Check if this track ID is bigger than size of McTracks TClonesArray (maybe happen with PSD cut!!)
1920 // If yes, resize the array to reach the appropriate number of fields
1921 // Cast of TrackId is safe as we already check for "< 0" case
1922 // TODO: Is this check still required when Id < 0 are jumped?
1923 if (fvlTrckChAddr.size() <= static_cast<UInt_t>(iTrkId)) fvlTrckChAddr.resize(iTrkId + 1);
1924
1925 for (UInt_t uTrkMainCh = 0; uTrkMainCh < fvlTrckChAddr[iTrkId].size(); uTrkMainCh++)
1926 if (uAddr == fvlTrckChAddr[iTrkId][uTrkMainCh]) {
1927 bFoundIt = kTRUE;
1928 break;
1929 }
1930 // If it is the case, no need to redo the full stuff for this gap
1931 if (kTRUE == bFoundIt) continue;
1932 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
1933
1934 // Probability that the RPC detect the hit
1935 // if( fDigiBdfPar->GetEfficiency(iSmType) < gRandom->Uniform(1) )
1936 // continue;
1937
1938 // Probability that the gap detect the hit
1939 // For now use a simple gap treatment (cf CbmTofDigiBdfPar):
1940 // - a single fired gap fires the channel
1941 // - all gaps have exactly equivalent efficiency/firing probability
1942 // - independent gap firing (no charge accumulation or such)
1943 // The probability for a hit not to fire at all is then
1944 // (1-p)^NGaps with p = gap efficiency and Ngaps the number of gaps in this RPC
1945 // This results in the relation: p = 1 - (1 - P)^(1/Ngaps)
1946 // with P = RPC efficiency from beamtime
1947 LOG(debug2) << "CbmTofDigitize::DigitizeFlatDisc => Eff = " << fDigiBdfPar->GetGapEfficiency(iSmType, iRpc);
1948
1949 if (fDigiBdfPar->GetGapEfficiency(iSmType, iRpc) < gRandom->Uniform(1)) continue;
1950
1951 // Save the address in vector so that this channel is not redone later for the
1952 // eventual other gaps TofPoint
1953 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) fvlTrckChAddr[iTrkId].push_back(uAddr);
1954
1955 // Get TofPoint Position
1956 pPoint->Position(vPntPos);
1957 fChannelInfo = fDigiPar->GetCell(iChanId);
1958 if (NULL == fChannelInfo) {
1959 LOG(warning) << "CbmTofDigitize::DigitizeFlatDisc: No DigPar for iChanId = "
1960 << Form("0x%08x, addr 0x%08x", iChanId, (unsigned int) iDetId);
1961 continue;
1962 }
1963 // Master -> Local
1964 TGeoNode* fNode = // prepare global->local trafo
1965 gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
1966 LOG(debug1) << Form(" TofDigitizerBDF:: (%3d,%3d,%3d,%3d) - node at "
1967 "(%6.1f,%6.1f,%6.1f) : %p Pos(%6.1f,%6.1f,%6.1f)",
1968 iSmType, iSM, iRpc, iChannel, fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ(),
1969 fNode, vPntPos.X(), vPntPos.Y(), vPntPos.Z());
1970 gGeoManager->GetCurrentNode();
1971 gGeoManager->GetCurrentMatrix();
1972
1973 Double_t refpos[3] = {fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ()};
1974 Double_t refpos_local[3];
1975 gGeoManager->MasterToLocal(refpos, refpos_local);
1976 Double_t poipos[3] = {vPntPos.X(), vPntPos.Y(), vPntPos.Z()};
1977 Double_t poipos_local[3];
1978 gGeoManager->MasterToLocal(poipos, poipos_local);
1979 LOG(debug1) << Form(" TofDigitizerBDF:: DetId 0x%08x, ChanId 0x%08x, local "
1980 "pos (%5.1f,%5.1f,%5.1f) refpos (%5.1f,%5.1f,%5.1f) ",
1981 iDetId, iChanId, poipos_local[0], poipos_local[1], poipos_local[2], refpos_local[0],
1982 refpos_local[1], refpos_local[2]);
1983 for (Int_t i = 0; i < 3; i++)
1984 poipos_local[i] -= refpos_local[i]; // correct for transformation failure, FIXME!
1985
1986 // Generate a Cluster radius in [cm]
1987 dClusterSize = GenerateClusterRadius(iSmType, iRpc);
1988 // Cut on the higher radius because otherwise the big clusters at the edge
1989 // of the counter generate hits totally off (because the main strip do not get
1990 // more charge than the side strips anymore). Cut value fully empirical.
1991 while (dClusterSize < 0.0001 || 3.0 < dClusterSize)
1992 // Should not happen without error message
1993 // But Landau can give really small values
1994 dClusterSize = GenerateClusterRadius(iSmType, iRpc);
1995
1996 // Generate Cluster charge as ToT[ps]
1997 dClustCharge = fh1ClusterTotProb[iSmType]->GetBinContent(fh1ClusterTotProb[iSmType]->FindBin(gRandom->Uniform(1)));
1998
1999 //Total cluster area (used to calculate the charge fraction in each channel)
2000 Double_t dClustArea = dClusterSize * dClusterSize * TMath::Pi();
2001
2002 // Calculate the fraction of the charge in central channel
2003 Double_t dChargeCentral =
2004 dClustCharge * ComputeClusterAreaOnChannel(iChanId, dClusterSize, poipos_local[0], poipos_local[1]);
2005 LOG(debug2) << "CbmTofDigitize::DigitizeFlatDisc: ChargeCentral " << dChargeCentral << ", " << dClustCharge
2006 << Form(", 0x%08x", iChanId) << ", " << dClusterSize << ", " << poipos_local[0] << ", "
2007 << poipos_local[1] << ", " << poipos_local[2];
2008
2009 dChargeCentral /= dClustArea;
2010 if (dClustCharge + 0.0000001 < dChargeCentral) {
2011 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc => Central Charge " << dChargeCentral << " " << dClustCharge
2012 << " " << dClustCharge - dChargeCentral << " "
2013 << (ComputeClusterAreaOnChannel(iChanId, dClusterSize, poipos_local[0], poipos_local[1])) << " "
2014 << dClustArea;
2015 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc => Check Point " << iPntInd << " Sm type " << iSmType << " SM "
2016 << iSM << " Rpc " << iRpc << " Channel " << iChannel << " Type " << iChType << " Orient. "
2017 << fDigiBdfPar->GetChanOrient(iSmType, iRpc);
2018 } // if( dClustCharge +0.0000001 < dChargeCentral )
2019
2020 // Calculate the time for the central channel
2021 Double_t dCentralTime;
2022 // Check if there was already a Digi from the same track created in this RPC
2023 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2024 ULong64_t uRpcAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, 0, 0, iSmType);
2025 Bool_t bFoundIt = kFALSE;
2026 UInt_t uTrkRpcPair = 0;
2027 for (uTrkRpcPair = 0; uTrkRpcPair < fvlTrckRpcAddr[iTrkId].size(); uTrkRpcPair++)
2028 if (uRpcAddr == fvlTrckRpcAddr[iTrkId][uTrkRpcPair]) {
2029 bFoundIt = kTRUE;
2030 break;
2031 }
2032 // If it is the case, we should reuse the timing already assigned to this track
2033 if (kTRUE == bFoundIt) dCentralTime = fvlTrckRpcTime[iTrkId][uTrkRpcPair];
2034 else {
2035 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
2036 + dStartJitter; // Same contrib. for all points in same event
2037 fvlTrckRpcAddr[iTrkId].push_back(uRpcAddr);
2038 fvlTrckRpcTime[iTrkId].push_back(dCentralTime);
2039 } // No Digi yet in this RPC for this Track
2040 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2041 else
2042 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
2043 + dStartJitter; // Same contrib. for all points in same event
2044
2045 // FIXME: not sure if this limit does not destroy rate estimates and such
2046 // if( 1e6 < dCentralTime )
2047 // continue;
2048
2049 // Calculate propagation time(s) to the readout point(s)
2050 if (0 == iChType) {
2051 // Strips (readout on both side)
2052 // Assume that the bottom/left strip have lower channel index
2053 // E.g: ... | i | i+1 | ...
2054 // or ... y
2055 // ----- ^
2056 // i+1 |
2057 // ----- --> x
2058 // i
2059 // -----
2060 // ...
2061
2062 Double_t dTimeA = dCentralTime;
2063 Double_t dTimeB = dCentralTime;
2064 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2065 // Horizontal channel: A = Right and B = Left of the channel
2066 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2067#ifdef FULL_PROPAGATION_TIME
2068 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
2069#else
2070 + (poipos_local[0])
2071#endif
2072 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2073 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2074#ifdef FULL_PROPAGATION_TIME
2075 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
2076#else
2077 - (poipos_local[0])
2078#endif
2079 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2080 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2081 else {
2082 // Vertical channel: A = Top and B = Bottom of the channel
2083 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2084#ifdef FULL_PROPAGATION_TIME
2085 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
2086#else
2087 // + ( poipos_local[1] - fChannelInfo->GetY() )
2088 + poipos_local[1]
2089#endif
2090 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2091 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2092#ifdef FULL_PROPAGATION_TIME
2093 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
2094#else
2095 // - ( poipos_local[1] - fChannelInfo->GetY() )
2096 - poipos_local[1]
2097#endif
2098 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2099 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2101 <= dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0) {
2102 CbmTofDigi* tofDigi = new CbmTofDigi(
2103 iSM, iRpc, iChannel, dTimeA,
2104 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0, 1, iSmType);
2105 //nh,crashes
2106 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2107 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2108 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(data);
2109 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(iPntInd);
2110 LOG(debug1) << Form(
2111 "Digimatch (%d,%d,%d,%d): size %zu, MCp %d, MCt %d, TA %6.2f, TotA "
2112 "%6.1f, Ypos %6.1f, Vsig %6.1f ",
2113 iSmType, iSM, iRpc, iChannel, fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
2114 iTrackID, dTimeA, dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0,
2115 poipos_local[1], fvdSignalVelocityRpc[iSmType][iSM][iRpc]);
2116
2117 } // charge ok, TimeA
2119 <= dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel] / 2.0) {
2120 CbmTofDigi* tofDigi =
2121 new CbmTofDigi(iSM, iRpc, iChannel, dTimeB,
2122 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel] / 2.0, 0, iSmType);
2123 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2124 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2125 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(data);
2126 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(iPntInd);
2127 LOG(debug1) << Form(
2128 "Digimatch (%d,%d,%d,%d): size %zu, MCp %d, MCt %d, TB %6.2f, TotB "
2129 "%6.1f",
2130 iSmType, iSM, iRpc, iChannel, fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd,
2131 iTrackID, dTimeB, dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0);
2132 } // charge ok, TimeB
2133 } // if( 0 == iChType)
2134 else {
2135 // Pad (Single side readout)
2136 // Assume that the bottom/left pads have lower channel index
2137 // E.g: for a 2*4 pads counter, pads 0-3 are the bottom/left ones and 4-7 the
2138 // top/right one with reversed numbering:
2139 // -----------------
2140 // row 1 | 7 | 6 | 5 | 4 | y
2141 // ----------------- ^
2142 // row 0 | 0 | 1 | 2 | 3 | |
2143 // ----------------- --> x
2144 // or ---------
2145 // | 4 | 3 |
2146 // ---------
2147 // | 5 | 2 |
2148 // ---------
2149 // | 6 | 1 |
2150 // ---------
2151 // | 7 | 0 |
2152 // ---------
2153 // row 1 0
2154 // Also assume that the readout happens at the middle of the readout edge
2155
2156 Double_t dClustToReadout = 0.0;
2157 Double_t dPadTime = dCentralTime;
2158 // First calculate the propagation time to the center of the pad base
2159 if (iChannel < iNbCh / 2.0) {
2160 // First row
2161 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2162 // Vertical => base = right edge
2163 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2164 + TMath::Power(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0), 2));
2165 else // Horizontal => base = bottom edge
2166 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2167 + TMath::Power(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0), 2));
2168 } // if( iChannel < iNbCh/2.0 )
2169 else {
2170 // Second row
2171 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2172 // Vertical => base = left edge
2173 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2174 + TMath::Power(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0), 2));
2175 else // Horizontal => base = upper edge
2176 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2177 + TMath::Power(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0), 2));
2178 } // else of if( iChannel < iNbCh/2.0 )
2179
2180 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2181
2182 if (fDigiBdfPar->GetFeeThreshold() <= dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChannel]) {
2183 CbmTofDigi* tofDigi =
2184 new CbmTofDigi(iSM, iRpc, iChannel, dPadTime,
2185 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChannel], 0, iSmType);
2186 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2187 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2188 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iChannel].push_back(data);
2189 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChannel].push_back(iPntInd);
2190 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): MCpi %zu, valE %d, MCti %d", iSmType, iSM, iRpc, iChannel,
2191 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd, iTrackID);
2192
2193 } // charge ok
2194 } // else of if( 0 == iChType)
2195
2196 // Loop over neighboring channel to find if they have overlap with
2197 // the cluster ( and if yes which fraction of the total charge they
2198 // got)
2199 if (0 == iChType) {
2200 // Strips (readout on both side)
2201 // Loop in decreasing channel index until a channel with right/upper edge farther
2202 // from cluster center than cluster radius is found
2203 // Loop in increasing channel index until a channel with left/lower edge farther
2204 // from cluster center than cluster radius is found
2205
2206 Int_t iMinChanInd = iChannel - 1;
2207 Int_t iMaxChanInd = iChannel + 1;
2208
2209 Double_t dClusterDist = 0.0;
2210 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2211 // Horizontal channels: First go down, then up
2212 while (0 <= iMinChanInd) {
2213 dClusterDist = TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() * (iMinChanInd - iChannel + 0.5)));
2214 if (dClusterDist < dClusterSize) iMinChanInd--;
2215 else
2216 break;
2217 }
2218 while (iMaxChanInd < iNbCh) {
2219 dClusterDist = TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() * (iMaxChanInd - iChannel - 0.5)));
2220 if (dClusterDist < dClusterSize) iMaxChanInd++;
2221 else
2222 break;
2223 }
2224 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2225 else {
2226 // Vertical channels: First go to the left, then to the right
2227 while (0 <= iMinChanInd) {
2228 dClusterDist = TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() * (iMinChanInd - iChannel + 0.5)));
2229 if (dClusterDist < dClusterSize) iMinChanInd--;
2230 else
2231 break;
2232 }
2233 while (iMaxChanInd < iNbCh) {
2234 dClusterDist = TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() * (iMaxChanInd - iChannel - 0.5)));
2235 if (dClusterDist < dClusterSize) iMaxChanInd++;
2236 else
2237 break;
2238 }
2239 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2240
2241 // Loop over all channels inside the interval ]iMinChanInd;iMaxChanInd[ except central channel,
2242 // using the overlap area with cluster to get the charge and adding a Digi for all channels
2243 for (Int_t iChanInd = iMinChanInd + 1; iChanInd < iMaxChanInd; iChanInd++) {
2244 if (iChanInd == iChannel) continue;
2245
2246 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
2247 // ... don't ask me why ... Reason found in TofMC and TofGeoHandler
2248 // CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iChanInd + 1);
2249 Int_t iCh1 = iChanInd;
2250 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
2251 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
2252 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
2253
2254 fChannelInfo = fDigiPar->GetCell(iSideChId);
2255
2256 if (NULL == fChannelInfo) {
2257 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc: Invalid channel " << iSideChId << " " << iSmType << " "
2258 << iSM << " " << iRpc << " " << iChanInd + 1;
2259 continue;
2260 }
2261
2262 // Calculate the fraction of the charge in this channel
2263 Double_t dChargeSideCh =
2264 dClustCharge * ComputeClusterAreaOnChannel(iSideChId, dClusterSize, poipos_local[0], poipos_local[1]);
2265 dChargeSideCh /= dClustArea;
2266 if (dClustCharge + 0.0000001 < dChargeSideCh) {
2267 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc => Side Charge " << dChargeSideCh << " " << dClustCharge
2268 << " " << dClustArea;
2269 LOG(error) << "CbmTofDigitize::DigitizeFlatDisc => Check Point " << iPntInd << " Sm type " << iSmType
2270 << " SM " << iSM << " Rpc " << iRpc << " Channel " << iChanInd << " Type " << iChType
2271 << " Orient. " << fDigiBdfPar->GetChanOrient(iSmType, iRpc);
2272 } // if( dClustCharge + 0.0000001 < dChargeSideCh )
2273
2274 // Strips = readout on both side
2275 Double_t dTimeA = dCentralTime;
2276 Double_t dTimeB = dCentralTime;
2277
2278 LOG(debug1) << Form(" TofDigitizerBDF:: chrg %7.1f, times %5.1f,%5.1f, "
2279 "pos %5.1f,%5.1f,%5.1f ",
2280 dChargeCentral, dTimeA, dTimeB, poipos_local[0], poipos_local[1], poipos_local[2]);
2281
2282 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2283 // Horizontal channel: A = Right and B = Left of the channel
2284 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2285#ifdef FULL_PROPAGATION_TIME
2286 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
2287#else
2288 + (poipos_local[0])
2289#endif
2290 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2291 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2292#ifdef FULL_PROPAGATION_TIME
2293 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
2294#else
2295 - (poipos_local[0])
2296#endif
2297 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2298 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2299 else {
2300
2301 // Vertical channel: A = Top and B = Bottom of the channel
2302 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2303#ifdef FULL_PROPAGATION_TIME
2304 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
2305#else
2306 // + ( poipos_local[1] - fChannelInfo->GetY() )
2307 + poipos_local[1]
2308#endif
2309 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2310 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2311#ifdef FULL_PROPAGATION_TIME
2312 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
2313#else
2314 // - ( poipos_local[1] - fChannelInfo->GetY() )
2315 - poipos_local[1]
2316#endif
2317 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2318 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2319 LOG(debug1) << Form(" TofDigitizerBDF:: chrg %7.1f, gain %7.1f, thr %7.1f times "
2320 "%5.1f,%5.1f ",
2321 dChargeCentral, fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1],
2322 fDigiBdfPar->GetFeeThreshold(), dTimeA, dTimeB);
2323 // Fee Threshold on charge
2325 <= dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1] / 2.0) {
2326 CbmTofDigi* tofDigi = new CbmTofDigi(
2327 iSM, iRpc, iChanInd, dTimeA,
2328 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1] / 2.0, 1, iSmType);
2329 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2330 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2331 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1].push_back(data);
2332 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1].push_back(iPntInd);
2333 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, MCpA %d, MCtt %d", iSmType, iSM, iRpc, iChanInd,
2334 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1].size(), iPntInd, iTrackID);
2335
2336 } // if( charge above threshold)
2338 <= dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd] / 2.0) {
2339 CbmTofDigi* tofDigi =
2340 new CbmTofDigi(iSM, iRpc, iChanInd, dTimeB,
2341 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd] / 2.0, 0, iSmType);
2342 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2343 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2344 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd].push_back(data);
2345 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd].push_back(iPntInd);
2346 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, MCpB %d, MCtB %d", iSmType, iSM, iRpc, iChanInd,
2347 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChanInd + 1].size(), iPntInd, iTrackID);
2348
2349 } // if( charge above threshold)
2350 } // for( Int_t iChanInd = iMinChanInd + 1; iChanInd < iMaxChanInd; iChanInd++ )
2351 } // if( 0 == iChType)
2352 else {
2353 // Pad (Single side readout)
2354 // Assume that the bottom/left pads have lower channel index
2355 // E.g: for a 2*4 pads counter, pads 0-3 are the bottom/left ones and 4-7 the
2356 // top/right one with reversed numbering
2357 // -----------------
2358 // row 1 | 7 | 6 | 5 | 4 | y
2359 // ----------------- ^
2360 // row 0 | 0 | 1 | 2 | 3 | |
2361 // ----------------- --> x
2362 // or ---------
2363 // | 4 | 3 |
2364 // ---------
2365 // | 5 | 2 |
2366 // ---------
2367 // | 6 | 1 |
2368 // ---------
2369 // | 7 | 0 |
2370 // ---------
2371 // row 1 0
2372
2373 // Loop in decreasing channel index in same row, find min = 1st 0 channel
2374 // Loop in increasing channel index in same row, find max = 1st 0 channel
2375 Int_t iMinChanInd = iChannel;
2376 Int_t iMaxChanInd = iChannel;
2377
2378 Double_t dClusterDist = 0;
2379 Int_t iRow;
2380 Bool_t bCheckOtherRow = kFALSE;
2381 if (iChannel < iNbCh / 2.0) iRow = 0;
2382 else
2383 iRow = 1;
2384
2385 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2386 // Vertical => base = right edge for row 0 and left edge for row 1
2387 while (dClusterDist < dClusterSize && iRow * iNbCh / 2.0 < iMinChanInd) {
2388 iMinChanInd--;
2389 dClusterDist =
2390 TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() * (iMinChanInd - iChannel + (1 - 2 * iRow) / 2)));
2391 } // while upper/lower edge inside cluster and index not out of rpc
2392 dClusterDist = 0;
2393 while (dClusterDist < dClusterSize && iMaxChanInd < (1 + iRow) * iNbCh / 2.0 - 1) {
2394 iMaxChanInd++;
2395 dClusterDist =
2396 TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() * (iMaxChanInd - iChannel - (1 - 2 * iRow) / 2)));
2397 } // while lower/upper edge inside cluster and index not out of rpc
2398
2399 // Test if Pad in diff row but same column as central pad has cluster overlap
2400 // if Yes => Loop from min+1 to max-1 equivalents in the opposite row
2401 dClusterDist = TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() * (2 * iRow - 1) / 2));
2402 if (dClusterDist < dClusterSize) bCheckOtherRow = kTRUE;
2403 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2404 else {
2405 // Horizontal => base = lower edge for row 0 and upper edge for row 1
2406 while (dClusterDist < dClusterSize && iRow * iNbCh / 2.0 < iMinChanInd) {
2407 iMinChanInd--;
2408 dClusterDist =
2409 TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() * (iMinChanInd - iChannel + (1 - 2 * iRow) / 2)));
2410 } // while right/left edge inside cluster and index not out of rpc
2411 dClusterDist = 0;
2412 while (dClusterDist < dClusterSize && iMaxChanInd < (1 + iRow) * iNbCh / 2.0 - 1) {
2413 iMaxChanInd++;
2414 dClusterDist =
2415 TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() * (iMaxChanInd - iChannel - (1 - 2 * iRow) / 2)));
2416 } // while left/right edge inside cluster and index not out of rpc
2417
2418 // Test if Pad in diff row but same column as central pad has cluster overlap
2419 // if Yes => Loop from min+1 to max-1 equivalents in the opposite row
2420 dClusterDist = TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() * (1 - 2 * iRow) / 2));
2421 if (dClusterDist < dClusterSize) bCheckOtherRow = kTRUE;
2422 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2423
2424 // Loop over all channels inside the interval ]iMinChanInd;iMaxChanInd[ except central channel,
2425 // using the overlap area with cluster to get the charge and adding a Digi for all channels
2426 for (Int_t iChanInd = iMinChanInd + 1; iChanInd < iMaxChanInd; iChanInd++) {
2427 if (iChanInd == iChannel) continue;
2428
2429 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
2430 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
2431 Int_t iCh1 = iChanInd;
2432 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
2433 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
2434
2435 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
2436
2437 fChannelInfo = fDigiPar->GetCell(iSideChId);
2438
2439 // Calculate the fraction of the charge in this channel
2440 Double_t dChargeSideCh =
2441 dClustCharge * ComputeClusterAreaOnChannel(iSideChId, dClusterSize, poipos_local[0], poipos_local[1]);
2442 dChargeSideCh /= dClustArea;
2443
2444 // Fee Threshold on charge
2445 if (dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChanInd] < fDigiBdfPar->GetFeeThreshold())
2446 continue;
2447
2448 Double_t dClustToReadout = 0.0;
2449 Double_t dPadTime = dCentralTime;
2450 // First calculate the propagation time to the center of the pad base
2451 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2452 // Vertical => base = right/left edge
2453 dClustToReadout =
2454 TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2455 + TMath::Power(poipos_local[0] - (+(1 - 2 * iRow) * fChannelInfo->GetSizex() / 2.0), 2));
2456 else // Horizontal => base = bottom/upper edge
2457 dClustToReadout =
2458 TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2459 + TMath::Power(poipos_local[1] - (-(1 - 2 * iRow) * fChannelInfo->GetSizey() / 2.0), 2));
2460
2461 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2462
2463 CbmTofDigi* tofDigi =
2464 new CbmTofDigi(iSM, iRpc, iChanInd, dPadTime,
2465 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChanInd], 0, iSmType);
2466 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2467 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2468 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(data);
2469 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(iPntInd);
2470 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, MCpP %d, MCtP %d", iSmType, iSM, iRpc, iChannel,
2471 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd, iTrackID);
2472 } // for( Int_t iChanInd = iMinChanInd + 1; iChanInd < iMaxChanInd; iChanInd++ )
2473
2474 // Loop over channels on the other row equivalent to the interval ]iMinChanInd;iMaxChanInd[
2475 if (kTRUE == bCheckOtherRow)
2476 for (Int_t iChanInd = iMinChanInd + 1 + (1 - 2 * iRow) * iNbCh / 2.0;
2477 iChanInd < iMaxChanInd + (1 - 2 * iRow) * iNbCh / 2.0; iChanInd++) {
2478 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
2479 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
2480 Int_t iCh1 = iChanInd;
2481 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
2482 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
2483
2484 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
2485
2486 fChannelInfo = fDigiPar->GetCell(iSideChId);
2487
2488 // Calculate the fraction of the charge in this channel
2489 Double_t dChargeSideCh =
2490 dClustCharge * ComputeClusterAreaOnChannel(iSideChId, dClusterSize, poipos_local[0], poipos_local[1]);
2491
2492 // Fee Threshold on charge
2493 if (dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChanInd] < fDigiBdfPar->GetFeeThreshold())
2494 continue;
2495
2496 Double_t dClustToReadout = 0.0;
2497 Double_t dPadTime = dCentralTime;
2498 // First calculate the propagation time to the center of the pad base
2499 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2500 // Vertical => base = right/left edge
2501 dClustToReadout =
2502 TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2503 + TMath::Power(poipos_local[0] - (+(1 - 2 * iRow) * fChannelInfo->GetSizex() / 2.0), 2));
2504 else // Horizontal => base = bottom/upper edge
2505 dClustToReadout =
2506 TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2507 + TMath::Power(poipos_local[1] - (-(1 - 2 * iRow) * fChannelInfo->GetSizey() / 2.0), 2));
2508
2509 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2510
2511 CbmTofDigi* tofDigi =
2512 new CbmTofDigi(iSM, iRpc, iChanInd, dPadTime,
2513 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChanInd], 0, iSmType);
2514 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2515 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2516 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(data);
2517 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(iPntInd);
2518 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, MCpX %d, MCtX %d", iSmType, iSM, iRpc, iChannel,
2519 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd, iTrackID);
2520
2521 } // for( Int_t iChanInd = iMinChanInd + 1; iChanInd < iMaxChanInd; iChanInd++ )
2522 } // else of if( 0 == iChType)
2523
2524 } // for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++ )
2525
2526 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2527 // Clear the Track to channel temporary storage
2528 for (UInt_t uTrkInd = 0; uTrkInd < fvlTrckChAddr.size(); uTrkInd++) {
2529 fvlTrckChAddr[uTrkInd].clear();
2530 fvlTrckRpcAddr[uTrkInd].clear();
2531 fvlTrckRpcTime[uTrkInd].clear();
2532 }
2533 fvlTrckChAddr.clear();
2534 fvlTrckRpcAddr.clear();
2535 fvlTrckRpcTime.clear();
2536 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2537
2538 return kTRUE;
2539}
2540/************************************************************************************/
2541// Functions for a 2D Gauss cluster approximation
2543{
2544 // Uniform distribution in ]0;x]
2545 // gRandom->Uniform(x);
2546 // Gauss distribution in of mean m, sigma s
2547 // gRandom->Gauss(m, s);
2548
2549 CbmTofPoint* pPoint;
2550 CbmMCTrack* pMcTrk;
2551
2552 Int_t nTofPoint = fTofPointsColl->GetEntriesFast();
2553 Int_t nMcTracks = fMcTracksColl->GetEntriesFast();
2554
2555 // Prepare the temporary storing of the Track/Point/Digi info
2556 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2557 fvlTrckChAddr.resize(nMcTracks);
2558 fvlTrckRpcAddr.resize(nMcTracks);
2559 fvlTrckRpcTime.resize(nMcTracks);
2560 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2561 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
2562 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2563 fvlTrckChAddr[iTrkInd].clear();
2564 fvlTrckRpcAddr[iTrkInd].clear();
2565 fvlTrckRpcTime[iTrkInd].clear();
2566 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2567 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
2568
2569 if (fbMcTrkMonitor) {
2570 // Debug Info printout
2571 Int_t iNbTofTracks = 0;
2572 Int_t iNbTofTracksPrim = 0;
2573
2574 LOG(debug1) << "CbmTofDigitize::DigitizeGaussCharge: " << nTofPoint << " points in Tof for this event with "
2575 << nMcTracks << " MC tracks ";
2576 for (Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++) {
2577 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkInd);
2578 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof)) iNbTofTracks++;
2579 if (0 < pMcTrk->GetNPoints(ECbmModuleId::kTof) && -1 == pMcTrk->GetMotherId()) iNbTofTracksPrim++;
2580 } // for(Int_t iTrkInd = 0; iTrkInd < nMcTracks; iTrkInd++)
2581
2582 //Some numbers on TOF distributions
2583 LOG(debug1) << "CbmTofDigitize::DigitizeGaussCharge: " << iNbTofTracks << " tracks in Tof ";
2584 LOG(debug1) << "CbmTofDigitize::DigitizeGaussCharge: " << iNbTofTracksPrim << " tracks in Tof from vertex";
2585 } // if( fbMcTrkMonitor )
2586
2587 // Tof Point Info
2588 Int_t iDetId, iSmType, iSM, iRpc, iChannel, iGap;
2589 Int_t iTrackID, iChanId;
2590 TVector3 vPntPos;
2591 // Cluster Info
2592 Double_t dClusterSize;
2593 Double_t dClustCharge;
2594 // Digi
2595 // CbmTofDigi * pTofDigi; // <- Compressed digi (64 bits)
2596 // CbmTofDigi * pTofDigiExp; // <- Expanded digi
2597 // General geometry info
2598 Int_t iNbSmTypes = fDigiBdfPar->GetNbSmTypes();
2599 Int_t iNbSm, iNbRpc, iNbCh;
2600 Int_t iChType;
2601
2602 // Start jitter: Same contrib. for all points in same event
2603 // FIXME
2604 // Actually, event start time reconstruction should not be done in the ToF
2605 // digitizer, neither in event-based nor in time-based mode. The timestamp
2606 // of a CbmTofDigi object is not the time difference between signals in a
2607 // (hypothetical) start detector system and the MRPC wall but rather
2608 // represents the detection point in time in an MRPC measured with respect to
2609 // the start of the run.
2610 // For compatibility reasons, we continue adding a start detector jitter to
2611 // digi timestamps in event-based mode. In time-based mode, event start time
2612 // reconstruction is not considered here.
2613 Double_t dStartJitter = 0.;
2614 if (!fbTimeBasedOutput) { dStartJitter = gRandom->Gaus(0.0, fDigiBdfPar->GetStartTimeRes()); }
2615
2616 for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++) {
2617 // Get a pointer to the TOF point
2618 pPoint = (CbmTofPoint*) fTofPointsColl->At(iPntInd);
2619 if (NULL == pPoint) {
2620 LOG(warning) << "CbmTofDigitize::DigitizeGaussCharge => Be careful: hole "
2621 "in the CbmTofPoint TClonesArray!"
2622 << endl;
2623 continue;
2624 } // if( pPoint )
2625
2626 // Get all channel info
2627 iDetId = pPoint->GetDetectorID();
2628 iSmType = fGeoHandler->GetSMType(iDetId);
2629 iRpc = fGeoHandler->GetCounter(iDetId);
2630
2631 iChannel = fGeoHandler->GetCell(iDetId);
2632 iGap = fGeoHandler->GetGap(iDetId);
2633 iSM = fGeoHandler->GetSModule(iDetId);
2634 iChanId = fGeoHandler->GetCellId(iDetId);
2635 iTrackID = pPoint->GetTrackID();
2636
2637 iNbSm = fDigiBdfPar->GetNbSm(iSmType);
2638 iNbRpc = fDigiBdfPar->GetNbRpc(iSmType);
2639 iNbCh = fDigiBdfPar->GetNbChan(iSmType, iRpc);
2640 iChType = fDigiBdfPar->GetChanType(iSmType, iRpc);
2641 Int_t iTrkId = pPoint->GetTrackID();
2642
2643 // Catch case where the MC track was removed from the transport stack
2644 if (iTrkId < 0) {
2645 if (fbAllowPointsWithoutTrack) continue;
2646 else
2647 LOG(fatal) << "CbmTofDigitize::DigitizeDirectClusterSize => TofPoint without "
2648 "valid MC track Index, "
2649 << " track was probably cut at the transport level! "
2650 << " Pnt Idx: " << iPntInd << " Trk Idx: " << iTrkId << "\n"
2651 << "=============> To allow this kind of points and simply jump "
2652 "them, "
2653 << "call CbmTofDigitize::AllowPointsWithoutTrack() in your macro!!";
2654 } // if( iTrkId < 0 )
2655
2656 if (fbMcTrkMonitor) {
2657 // Get pointer to the MC-Track info
2658 pMcTrk = (CbmMCTrack*) fMcTracksColl->At(iTrkId);
2659
2660 // Keep only primaries
2661 if (kTRUE == fDigiBdfPar->UseOnlyPrimaries())
2662 if (-1 != pMcTrk->GetMotherId()) continue;
2663 } // if( fbMcTrkMonitor )
2664
2665 if (iSmType < 0. || iNbSmTypes < iSmType || iSM < 0. || iNbSm < iSM || iRpc < 0. || iNbRpc < iRpc || iChannel < 0.
2666 || iNbCh < iChannel) {
2667 LOG(error) << Form("CbmTofDigitize => det ID 0x%08x", iDetId) << " SMType: " << iSmType;
2668 LOG(error) << " SModule: " << iSM << " of " << iNbSm + 1;
2669 LOG(error) << " Module: " << iRpc << " of " << iNbRpc + 1;
2670 LOG(error) << " Gap: " << iGap;
2671 LOG(error) << " Cell: " << iChannel << " of " << iNbCh + 1;
2672 continue;
2673 } // if error on channel data
2674
2675 // Check if there was already a Digi from the same track created
2676 // with this channel as main channel
2677 ULong64_t uAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, iChannel, 0, iSmType);
2678 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2679 Bool_t bFoundIt = kFALSE;
2680 // Check if this track ID is bigger than size of McTracks TClonesArray (maybe happen with PSD cut!!)
2681 // If yes, resize the array to reach the appropriate number of fields
2682 // Cast of TrackId is safe as we already check for "< 0" case
2683 // TODO: Is this check still required when Id < 0 are jumped?
2684 if (fvlTrckChAddr.size() <= static_cast<UInt_t>(iTrkId)) fvlTrckChAddr.resize(iTrkId + 1);
2685
2686 for (UInt_t uTrkMainCh = 0; uTrkMainCh < fvlTrckChAddr[iTrkId].size(); uTrkMainCh++)
2687 if (uAddr == fvlTrckChAddr[iTrkId][uTrkMainCh]) {
2688 bFoundIt = kTRUE;
2689 break;
2690 }
2691 // If it is the case, no need to redo the full stuff for this gap
2692 if (kTRUE == bFoundIt) continue;
2693 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2694
2695 // Probability that the RPC detect the hit
2696 // if( fDigiBdfPar->GetEfficiency(iSmType) < gRandom->Uniform(1) )
2697 // continue;
2698
2699 // Probability that the gap detect the hit
2700 // For now use a simple gap treatment (cf CbmTofDigiBdfPar):
2701 // - a single fired gap fires the channel
2702 // - all gaps have exactly equivalent efficiency/firing probability
2703 // - independent gap firing (no charge accumulation or such)
2704 // The probability for a hit not to fire at all is then
2705 // (1-p)^NGaps with p = gap efficiency and Ngaps the number of gaps in this RPC
2706 // This results in the relation: p = 1 - (1 - P)^(1/Ngaps)
2707 // with P = RPC efficiency from beamtime
2708 if (fDigiBdfPar->GetGapEfficiency(iSmType, iRpc) < gRandom->Uniform(1)) continue;
2709
2710 // Save the address in vector so that this channel is not redone later for the
2711 // eventual other gaps TofPoint
2712 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) fvlTrckChAddr[iTrkId].push_back(uAddr);
2713
2714 // Get TofPoint Position
2715 pPoint->Position(vPntPos);
2716 fChannelInfo = fDigiPar->GetCell(iChanId);
2717 TGeoNode* fNode = // prepare global->local trafo
2718 gGeoManager->FindNode(fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ());
2719 LOG(debug1) << Form(" TofDigitizerBDF:: (%3d,%3d,%3d,%3d) - node at "
2720 "(%6.1f,%6.1f,%6.1f) : 0x%p Pos(%6.1f,%6.1f,%6.1f)",
2721 iSmType, iSM, iRpc, iChannel, fChannelInfo->GetX(), fChannelInfo->GetY(), fChannelInfo->GetZ(),
2722 fNode, vPntPos.X(), vPntPos.Y(), vPntPos.Z());
2723 gGeoManager->GetCurrentNode();
2724 gGeoManager->GetCurrentMatrix();
2725 Double_t poipos[3] = {vPntPos.X(), vPntPos.Y(), vPntPos.Z()};
2726 Double_t poipos_local[3];
2727 gGeoManager->MasterToLocal(poipos, poipos_local);
2728
2729 // Generate a Cluster radius in [cm]
2730 dClusterSize = GenerateClusterRadius(iSmType, iRpc);
2731 while (dClusterSize < 0.0001)
2732 // Should not happen without error message
2733 // But Landau can give really small values
2734 dClusterSize = GenerateClusterRadius(iSmType, iRpc);
2735
2736 // Generate Cluster charge as ToT[ps]
2737 dClustCharge = fh1ClusterTotProb[iSmType]->GetBinContent(fh1ClusterTotProb[iSmType]->FindBin(gRandom->Uniform(1)));
2738
2739 // Assume the width (sigma) of the gaussian in both direction is dClusterSize/3
2740 // => 99% of the charge is in "dClusterSize"
2741 TF2* f2ChargeDist = new TF2("ChargeDist", "[0]*TMath::Gaus(x,[1],[2])*TMath::Gaus(y,[3],[4])", -5.0 * dClusterSize,
2742 5.0 * dClusterSize, -5.0 * dClusterSize, 5.0 * dClusterSize);
2743 f2ChargeDist->SetParameters(dClustCharge / (TMath::Sqrt(2.0 * TMath::Pi()) * dClusterSize / 3.0), poipos_local[0],
2744 dClusterSize / 3.0, poipos_local[1], dClusterSize / 3.0);
2745
2746 // Calculate the fraction of the charge in central channel
2747 Double_t dChargeCentral = f2ChargeDist->Integral(
2750
2751 // Calculate the time for the central channel
2752 Double_t dCentralTime;
2753 // Check if there was already a Digi from the same track created in this RPC
2754 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
2755 ULong64_t uRpcAddr = CbmTofAddress::GetUniqueAddress(iSM, iRpc, 0, 0, iSmType);
2756 Bool_t bFoundIt = kFALSE;
2757 UInt_t uTrkRpcPair = 0;
2758 for (uTrkRpcPair = 0; uTrkRpcPair < fvlTrckRpcAddr[iTrkId].size(); uTrkRpcPair++)
2759 if (uRpcAddr == fvlTrckRpcAddr[iTrkId][uTrkRpcPair]) {
2760 bFoundIt = kTRUE;
2761 break;
2762 }
2763 // If it is the case, we should reuse the timing already assigned to this track
2764 if (kTRUE == bFoundIt) dCentralTime = fvlTrckRpcTime[iTrkId][uTrkRpcPair];
2765 else {
2766 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
2767 + dStartJitter; // Same contrib. for all points in same event
2768 fvlTrckRpcAddr[iTrkId].push_back(uRpcAddr);
2769 fvlTrckRpcTime[iTrkId].push_back(dCentralTime);
2770 } // No Digi yet in this RPC for this Track
2771 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
2772 else
2773 dCentralTime = pPoint->GetTime() + gRandom->Gaus(0.0, fDigiBdfPar->GetResolution(iSmType))
2774 + dStartJitter; // Same contrib. for all points in same event
2775
2776 // Calculate propagation time(s) to the readout point(s)
2777 if (0 == iChType) {
2778 // Strips (readout on both side)
2779 // Assume that the bottom/left strip have lower channel index
2780 // E.g: ... | i | i+1 | ...
2781 // or ... y
2782 // ----- ^
2783 // i+1 |
2784 // ----- --> x
2785 // i
2786 // -----
2787 // ...
2788
2789 Double_t dTimeA = dCentralTime;
2790 Double_t dTimeB = dCentralTime;
2791 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2792 // Horizontal channel: A = Right and B = Left of the channel
2793 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2794#ifdef FULL_PROPAGATION_TIME
2795 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
2796#else
2797 + (poipos_local[0])
2798#endif
2799 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2800 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2801#ifdef FULL_PROPAGATION_TIME
2802 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
2803#else
2804 - (poipos_local[0])
2805#endif
2806 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2807 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2808 else {
2809 // Vertical channel: A = Top and B = Bottom of the channel
2810 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2811#ifdef FULL_PROPAGATION_TIME
2812 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
2813#else
2814 + (poipos_local[1])
2815#endif
2816 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2817 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2818#ifdef FULL_PROPAGATION_TIME
2819 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
2820#else
2821 - (poipos_local[1])
2822#endif
2823 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2824 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2825
2826 CbmTofDigi* tofDigi = new CbmTofDigi(
2827 iSM, iRpc, iChannel, dTimeA,
2828 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1] / 2.0, 1, iSmType);
2829 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2830 std::pair<CbmTofDigi*, CbmMatch*> data1(tofDigi, nullptr);
2831 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(data1);
2832 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].push_back(iPntInd);
2833 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val1 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
2834 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel + 1].size(), iPntInd, iTrackID);
2835
2836 tofDigi =
2837 new CbmTofDigi(iSM, iRpc, iChannel, dTimeB,
2838 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iChannel] / 2.0, 0, iSmType);
2839 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2840 std::pair<CbmTofDigi*, CbmMatch*> data2(tofDigi, nullptr);
2841 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(data2);
2842 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].push_back(iPntInd);
2843 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val2 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
2844 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iChannel].size(), iPntInd, iTrackID);
2845 } // if( 0 == iChType)
2846 else {
2847 // Pad (Single side readout)
2848 // Assume that the bottom/left pads have lower channel index
2849 // E.g: for a 2*4 pads counter, pads 0-3 are the bottom/left ones and 4-7 the
2850 // top/right one with reversed numbering:
2851 // -----------------
2852 // row 1 | 7 | 6 | 5 | 4 | y
2853 // ----------------- ^
2854 // row 0 | 0 | 1 | 2 | 3 | |
2855 // ----------------- --> x
2856 // or ---------
2857 // | 4 | 3 |
2858 // ---------
2859 // | 5 | 2 |
2860 // ---------
2861 // | 6 | 1 |
2862 // ---------
2863 // | 7 | 0 |
2864 // ---------
2865 // row 1 0
2866 // Also assume that the readout happens at the middle of the readout edge
2867
2868 Double_t dClustToReadout = 0.0;
2869 Double_t dPadTime = dCentralTime;
2870 // First calculate the propagation time to the center of the pad base
2871 if (iChannel < iNbCh / 2.0) {
2872 // First row
2873 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2874 // Vertical => base = right edge
2875 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2876 + TMath::Power(poipos_local[0] - (fChannelInfo->GetSizex() / 2.0), 2));
2877 else // Horizontal => base = bottom edge
2878 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2879 + TMath::Power(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0), 2));
2880 } // if( iChannel < iNbCh/2.0 )
2881 else {
2882 // Second row
2883 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
2884 // Vertical => base = left edge
2885 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[1], 2)
2886 + TMath::Power(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0), 2));
2887 else // Horizontal => base = upper edge
2888 dClustToReadout = TMath::Sqrt(TMath::Power(poipos_local[0], 2)
2889 + TMath::Power(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0), 2));
2890 } // else of if( iChannel < iNbCh/2.0 )
2891
2892 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2893
2894 // TODO: Check on fee threshold ?
2895 CbmTofDigi* tofDigi =
2896 new CbmTofDigi(iSM, iRpc, iChannel, dPadTime,
2897 dChargeCentral * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChannel], 0, iSmType);
2898 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2899 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
2900 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iChannel].push_back(data);
2901 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChannel].push_back(iPntInd);
2902 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val3 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
2903 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChannel].size(), iPntInd, iTrackID);
2904 } // else of if( 0 == iChType)
2905
2906 // Loop over neighboring channel and check if they are above threshold
2907 if (0 == iChType) {
2908 // Strips (readout on both side)
2909 // Loop in decreasing channel index until a channel with charge under threshold is found
2910 if (0 < iChannel) {
2911 Int_t iSideChInd = iChannel - 1;
2912
2913 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
2914 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
2915 Int_t iCh1 = iSideChInd;
2916 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
2917 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
2918
2919 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
2920
2921 fChannelInfo = fDigiPar->GetCell(iSideChId);
2922
2923 // Calculate the fraction of the charge in this channel
2924 Double_t dChargeSideCh = f2ChargeDist->Integral(
2927
2928 while (fDigiBdfPar->GetFeeThreshold() <= dChargeSideCh && 0 <= iSideChInd) {
2929 // Strips = readout on both side
2930 Double_t dTimeA = dCentralTime;
2931 Double_t dTimeB = dCentralTime;
2932 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
2933 // Horizontal channel: A = Right and B = Left of the channel
2934 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2935#ifdef FULL_PROPAGATION_TIME
2936 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
2937#else
2938 + (poipos_local[0])
2939#endif
2940 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2941 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2942#ifdef FULL_PROPAGATION_TIME
2943 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
2944#else
2945 - (poipos_local[0])
2946#endif
2947 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2948 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2949 else {
2950 // Vertical channel: A = Top and B = Bottom of the channel
2951 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
2952#ifdef FULL_PROPAGATION_TIME
2953 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
2954#else
2955 + (poipos_local[1])
2956#endif
2957 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2958 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
2959#ifdef FULL_PROPAGATION_TIME
2960 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
2961#else
2962 - (poipos_local[1])
2963#endif
2964 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
2965 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
2966
2967 CbmTofDigi* tofDigi = new CbmTofDigi(
2968 iSM, iRpc, iSideChInd, dTimeA,
2969 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1] / 2.0, 1, iSmType);
2970 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2971 std::pair<CbmTofDigi*, CbmMatch*> data1(tofDigi, nullptr);
2972 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1].push_back(data1);
2973 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1].push_back(iPntInd);
2974 tofDigi = new CbmTofDigi(iSM, iRpc, iSideChInd, dTimeB,
2975 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd] / 2.0, 0,
2976 iSmType);
2977 // tofDigi->GetMatch()->AddLink(1., iPntInd);
2978 std::pair<CbmTofDigi*, CbmMatch*> data2(tofDigi, nullptr);
2979 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].push_back(data2);
2980 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].push_back(iPntInd);
2981 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val4 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
2982 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].size(), iPntInd, iTrackID);
2983
2984
2985 // Check next
2986 iSideChInd--;
2987
2988 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
2989 // ... don't ask me why ...
2990 // FIXME: problem around here => reason found in TofMC and TofGeoHandler!
2991 Int_t iCh2 = iSideChInd;
2992 if (fGeoHandler->GetGeoVersion() < k14a) iCh2 = iCh2 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
2993 xDetInfo.fCell = iCh2;
2994
2995 iSideChId = fTofId->SetDetectorInfo(xDetInfo);
2996
2997 fChannelInfo = fDigiPar->GetCell(iSideChId);
2998
2999 // Calculate the fraction of the charge in this channel
3000 dChargeSideCh = f2ChargeDist->Integral(fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
3001 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0,
3002 fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
3003 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
3004 } // while signal and channel index ok
3005 } // if( 0 < iChannel)
3006 // Loop in increasing channel index until a channel with charge under threshold is found
3007 if (iChannel < iNbCh - 1) {
3008 Int_t iSideChInd = iChannel + 1;
3009
3010 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3011 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
3012 Int_t iCh1 = iSideChInd;
3013 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
3014 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
3015
3016 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3017
3018 fChannelInfo = fDigiPar->GetCell(iSideChId);
3019
3020 // Calculate the fraction of the charge in this channel
3021 Double_t dChargeSideCh = f2ChargeDist->Integral(
3024
3025 while (fDigiBdfPar->GetFeeThreshold() < dChargeSideCh && iSideChInd < iNbCh) {
3026 // Strips = readout on both side
3027 Double_t dTimeA = dCentralTime;
3028 Double_t dTimeB = dCentralTime;
3029 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc)) {
3030 // Horizontal channel: A = Right and B = Left of the channel
3031 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
3032#ifdef FULL_PROPAGATION_TIME
3033 + TMath::Abs(poipos_local[0] - (+fChannelInfo->GetSizex() / 2.0))
3034#else
3035 + (poipos_local[0])
3036#endif
3037 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3038 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
3039#ifdef FULL_PROPAGATION_TIME
3040 + TMath::Abs(poipos_local[0] - (-fChannelInfo->GetSizex() / 2.0))
3041#else
3042 - (poipos_local[0])
3043#endif
3044 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3045 } // if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
3046 else {
3047 // Vertical channel: A = Top and B = Bottom of the channel
3048 dTimeA += gRandom->Gaus(0.0, fdTimeResElec)
3049#ifdef FULL_PROPAGATION_TIME
3050 + TMath::Abs(poipos_local[1] - (+fChannelInfo->GetSizey() / 2.0))
3051#else
3052 + (poipos_local[1])
3053#endif
3054 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3055 dTimeB += gRandom->Gaus(0.0, fdTimeResElec)
3056#ifdef FULL_PROPAGATION_TIME
3057 + TMath::Abs(poipos_local[1] - (-fChannelInfo->GetSizey() / 2.0))
3058#else
3059 - (poipos_local[1])
3060#endif
3061 / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3062 } // else of if( 1 == fDigiBdfPar->GetChanOrient( iSmType, iRpc ) )
3063
3064 CbmTofDigi* tofDigi = new CbmTofDigi(
3065 iSM, iRpc, iSideChInd, dTimeA,
3066 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1] / 2.0, 1, iSmType);
3067 // tofDigi->GetMatch()->AddLink(1., iPntInd);
3068 std::pair<CbmTofDigi*, CbmMatch*> data1(tofDigi, nullptr);
3069 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1].push_back(data1);
3070 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1].push_back(iPntInd);
3071 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val5 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
3072 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd + 1].size(), iPntInd,
3073 iTrackID);
3074
3075 tofDigi = new CbmTofDigi(iSM, iRpc, iSideChInd, dTimeB,
3076 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd] / 2.0, 0,
3077 iSmType);
3078 // tofDigi->GetMatch()->AddLink(1., iPntInd);
3079 std::pair<CbmTofDigi*, CbmMatch*> data2(tofDigi, nullptr);
3080 fStorDigi[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].push_back(data2);
3081 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].push_back(iPntInd);
3082 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val6 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
3083 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].size(), iPntInd, iTrackID);
3084
3085 // Check next
3086 iSideChInd++;
3087
3088 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3089 // ... don't ask me why ...
3090 xDetInfo.fCell = iSideChInd + 1;
3091
3092 iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3093
3094 fChannelInfo = fDigiPar->GetCell(iSideChId);
3095
3096 // Calculate the fraction of the charge in this channel
3097 dChargeSideCh = f2ChargeDist->Integral(fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
3098 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0,
3099 fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
3100 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
3101 } // while signal and channel index ok
3102 } // if( 0 < iChannel)
3103 } // if( 0 == iChType)
3104 else {
3105 // Pad (Single side readout)
3106 // Assume that the bottom/left pads have lower channel index
3107 // E.g: for a 2*4 pads counter, pads 0-3 are the bottom/left ones and 4-7 the
3108 // top/right one with reversed numbering
3109 // -----------------
3110 // row 1 | 7 | 6 | 5 | 4 | y
3111 // ----------------- ^
3112 // row 0 | 0 | 1 | 2 | 3 | |
3113 // ----------------- --> x
3114 // or ---------
3115 // | 4 | 3 |
3116 // ---------
3117 // | 5 | 2 |
3118 // ---------
3119 // | 6 | 1 |
3120 // ---------
3121 // | 7 | 0 |
3122 // ---------
3123 // row 1 0
3124 // Loop in decreasing channel index in same row, find min = 1st 0 channel
3125 // Loop in increasing channel index in same row, find max = 1st 0 channel
3126 Int_t iMinChanInd = iChannel;
3127 Int_t iMaxChanInd = iChannel;
3128
3129 // Double_t dClusterDist = 0;// -> Comment to remove warning because set but never used
3130 Int_t iRow;
3131 // Bool_t bCheckOtherRow = kFALSE; // -> Comment to remove warning because set but never used
3132 if (iChannel < iNbCh / 2.0) iRow = 0;
3133 else
3134 iRow = 1;
3135
3136 // Loop in decreasing channel index until a channel with charge under threshold is found
3137 if (iRow * iNbCh / 2.0 < iChannel) {
3138 Int_t iSideChInd = iChannel - 1;
3139
3140 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3141 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
3142 Int_t iCh1 = iSideChInd;
3143 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
3144 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
3145
3146 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3147
3148 fChannelInfo = fDigiPar->GetCell(iSideChId);
3149
3150 // Calculate the fraction of the charge in this channel
3151 Double_t dChargeSideCh = f2ChargeDist->Integral(
3154
3155 while (fDigiBdfPar->GetFeeThreshold() < dChargeSideCh && iRow * iNbCh / 2.0 <= iSideChInd) {
3156 iMinChanInd = iSideChInd;
3157
3158 Double_t dClustToReadout = 0.0;
3159 Double_t dPadTime = dCentralTime;
3160 // First calculate the propagation time to the center of the pad base
3161 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
3162 // Vertical => base = right/left edge
3163 dClustToReadout =
3164 TMath::Sqrt(TMath::Power(poipos_local[1], 2)
3165 + TMath::Power(poipos_local[0] - ((1 - 2 * iRow) * fChannelInfo->GetSizex() / 2.0), 2));
3166 else // Horizontal => base = bottom/upper edge
3167 dClustToReadout =
3168 TMath::Sqrt(TMath::Power(poipos_local[0], 2)
3169 + TMath::Power(poipos_local[1] - (-(1 - 2 * iRow) * fChannelInfo->GetSizey() / 2.0), 2));
3170
3171 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3172
3173 CbmTofDigi* tofDigi =
3174 new CbmTofDigi(iSM, iRpc, iSideChInd, dPadTime,
3175 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iSideChInd], 0, iSmType);
3176 // tofDigi->GetMatch()->AddLink(1., iPntInd);
3177 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
3178 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iSideChInd].push_back(data);
3179 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iSideChInd].push_back(iPntInd);
3180 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val7 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
3181 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][2 * iSideChInd].size(), iPntInd, iTrackID);
3182
3183
3184 // Check next
3185 iSideChInd--;
3186
3187 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3188 // ... don't ask me why ...
3189 xDetInfo.fCell = iSideChInd + 1;
3190
3191 iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3192
3193 fChannelInfo = fDigiPar->GetCell(iSideChId);
3194
3195 // Calculate the fraction of the charge in this channel
3196 dChargeSideCh = f2ChargeDist->Integral(fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
3197 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0,
3198 fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
3199 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
3200 } // while channel has good charge and is not out
3201 } // if( iRow*iNbCh/2.0 < iChannel )
3202 // Loop in increasing channel index until a channel with charge under threshold is found
3203 if (iChannel < (1 + iRow) * iNbCh / 2.0 - 1) {
3204 Int_t iSideChInd = iChannel + 1;
3205
3206 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3207 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
3208 Int_t iCh1 = iSideChInd;
3209 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
3210 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1);
3211
3212 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3213
3214 fChannelInfo = fDigiPar->GetCell(iSideChId);
3215
3216 // Calculate the fraction of the charge in this channel
3217 Double_t dChargeSideCh = f2ChargeDist->Integral(
3220
3221 while (fDigiBdfPar->GetFeeThreshold() < dChargeSideCh && iSideChInd < (1 + iRow) * iNbCh / 2.0) {
3222 iMaxChanInd = iSideChInd;
3223
3224 Double_t dClustToReadout = 0.0;
3225 Double_t dPadTime = dCentralTime;
3226 // First calculate the propagation time to the center of the pad base
3227 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
3228 // Vertical => base = right/left edge
3229 dClustToReadout =
3230 TMath::Sqrt(TMath::Power(poipos_local[1], 2)
3231 + TMath::Power(poipos_local[0] - (+(1 - 2 * iRow) * fChannelInfo->GetSizex() / 2.0), 2));
3232 else // Horizontal => base = bottom/upper edge
3233 dClustToReadout =
3234 TMath::Sqrt(TMath::Power(poipos_local[0], 2)
3235 + TMath::Power(poipos_local[1] - (-(1 - 2 * iRow) * fChannelInfo->GetSizey() / 2.0), 2));
3236
3237 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3238
3239 CbmTofDigi* tofDigi =
3240 new CbmTofDigi(iSM, iRpc, iSideChInd, dPadTime,
3241 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iSideChInd], 0, iSmType);
3242 // tofDigi->GetMatch()->AddLink(1., iPntInd);
3243 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
3244 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iSideChInd].push_back(data);
3245 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iSideChInd].push_back(iPntInd);
3246 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val8 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
3247 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iSideChInd].size(), iPntInd, iTrackID);
3248
3249 // Check next
3250 iSideChInd++;
3251
3252 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3253 // ... don't ask me why ...
3254 xDetInfo.fCell = iSideChInd + 1;
3255
3256 iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3257
3258 fChannelInfo = fDigiPar->GetCell(iSideChId);
3259
3260 // Calculate the fraction of the charge in this channel
3261 dChargeSideCh = f2ChargeDist->Integral(fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
3262 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0,
3263 fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
3264 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
3265 } // while channel has good charge and is not out
3266 } // if( iChannel < (1+iRow)*iNbCh/2.0 - 1)
3267
3268 // Test if Pad in diff row but same column as central pad has enough charge
3269 // if Yes => Loop from min to max equivalents in the opposite row
3270
3271 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3272 // ... don't ask me why ... reason found in TofMC and TofGeoHandler!
3273 Int_t iCh1 = iChannel;
3274 if (fGeoHandler->GetGeoVersion() < k14a) iCh1 = iCh1 + 1; //FIXME: Reason found in TofMC and TofGeoHandler
3275 CbmTofDetectorInfo xDetInfo(ECbmModuleId::kTof, iSmType, iSM, iRpc, 0, iCh1 + (1 - 2 * iRow) * iNbCh / 2.0);
3276 Int_t iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3277 fChannelInfo = fDigiPar->GetCell(iSideChId);
3278
3279 // Calculate the fraction of the charge in this channel
3280 Double_t dChargeSideCh = f2ChargeDist->Integral(
3283
3284 if (fDigiBdfPar->GetFeeThreshold() < dChargeSideCh) {
3285 // bCheckOtherRow = kTRUE; // -> Comment to remove warning because set but never used
3286
3287 for (Int_t iChanInd = iMinChanInd + (1 - 2 * iRow) * iNbCh / 2.0;
3288 iChanInd <= iMaxChanInd + (1 - 2 * iRow) * iNbCh / 2.0; iChanInd++) {
3289 // Channel index in this UID is in [1,nbCh] instead of [0, nbCh[
3290 // ... don't ask me why ...
3291 xDetInfo.fCell = iChanInd + 1;
3292 iSideChId = fTofId->SetDetectorInfo(xDetInfo);
3293 fChannelInfo = fDigiPar->GetCell(iSideChId);
3294
3295 // Calculate the fraction of the charge in this channel
3296 dChargeSideCh = f2ChargeDist->Integral(fChannelInfo->GetX() - fChannelInfo->GetSizex() / 2.0,
3297 fChannelInfo->GetX() + fChannelInfo->GetSizex() / 2.0,
3298 fChannelInfo->GetY() - fChannelInfo->GetSizey() / 2.0,
3299 fChannelInfo->GetY() + fChannelInfo->GetSizey() / 2.0);
3300
3301 if (fDigiBdfPar->GetFeeThreshold() < dChargeSideCh) {
3302 Double_t dClustToReadout = 0.0;
3303 Double_t dPadTime = dCentralTime;
3304 // First calculate the propagation time to the center of the pad base
3305 if (1 == fDigiBdfPar->GetChanOrient(iSmType, iRpc))
3306 // Vertical => base = right/left edge
3307 dClustToReadout =
3308 TMath::Sqrt(TMath::Power(poipos_local[1], 2)
3309 + TMath::Power(poipos_local[0] - (+(1 - 2 * iRow) * fChannelInfo->GetSizex() / 2.0), 2));
3310 else // Horizontal => base = bottom/upper edge
3311 dClustToReadout =
3312 TMath::Sqrt(TMath::Power(poipos_local[0], 2)
3313 + TMath::Power(poipos_local[1] - (-(1 - 2 * iRow) * fChannelInfo->GetSizey() / 2.0), 2));
3314
3315 dPadTime += gRandom->Gaus(0.0, fdTimeResElec) + dClustToReadout / fvdSignalVelocityRpc[iSmType][iSM][iRpc];
3316
3317 CbmTofDigi* tofDigi =
3318 new CbmTofDigi(iSM, iRpc, iChanInd, dPadTime,
3319 dChargeSideCh * fdChannelGain[iSmType][iSM * iNbRpc + iRpc][iChanInd], 0, iSmType);
3320 // tofDigi->GetMatch()->AddLink(1., iPntInd);
3321 std::pair<CbmTofDigi*, CbmMatch*> data(tofDigi, nullptr);
3322 fStorDigi[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(data);
3323 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChanInd].push_back(iPntInd);
3324 LOG(debug1) << Form("Digimatch (%d,%d,%d,%d): size %zu, val9 %d, MCt %d", iSmType, iSM, iRpc, iChannel,
3325 fStorDigiMatch[iSmType][iSM * iNbRpc + iRpc][iChanInd].size(), iPntInd, iTrackID);
3326
3327 } // if( fDigiBdfPar->GetFeeThreshold() < dChargeSideCh )
3328 } // for channels on other row where same row had signal
3329 } // if( fDigiBdfPar->GetFeeThreshold() < dChargeSideCh )
3330 } // else of if( 0 == iChType)
3331
3332 delete f2ChargeDist;
3333 } // for (Int_t iPntInd = 0; iPntInd < nTofPoint; iPntInd++ )
3334
3335 if (kTRUE == fDigiBdfPar->UseOneGapPerTrk()) {
3336 // Clear the Track to channel temporary storage
3337 for (UInt_t uTrkInd = 0; uTrkInd < fvlTrckChAddr.size(); uTrkInd++) {
3338 fvlTrckChAddr[uTrkInd].clear();
3339 fvlTrckRpcAddr[uTrkInd].clear();
3340 fvlTrckRpcTime[uTrkInd].clear();
3341 }
3342 fvlTrckChAddr.clear();
3343 fvlTrckRpcAddr.clear();
3344 fvlTrckRpcTime.clear();
3345 } // if( kTRUE == fDigiBdfPar->UseOneGapPerTrk() )
3346
3347 return kTRUE;
3348}
3349/************************************************************************************/
3350// Auxiliary functions
3351Double_t CbmTofDigitize::ComputeClusterAreaOnChannel(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX,
3352 Double_t dClustCentY)
3353{
3354 Double_t dCornersX[4]; // Corners X position
3355 Double_t dCornersY[4]; // Corners X position
3356 Double_t dCornersR[4]; // Distance from cluster center to the corners
3357
3358 fChannelInfo = fDigiPar->GetCell(iChanId);
3359 Double_t dChanCentPosX = 0.; //fChannelInfo->GetX();
3360 Double_t dChanCentPosY = 0.; //fChannelInfo->GetY();
3361 Double_t dEdgeCentDistX = fChannelInfo->GetSizex() / 2.0;
3362 Double_t dEdgeCentDistY = fChannelInfo->GetSizey() / 2.0;
3363
3364 // Upper Left
3365 dCornersX[0] = dChanCentPosX - dEdgeCentDistX;
3366 dCornersY[0] = dChanCentPosY + dEdgeCentDistY;
3367 dCornersR[0] = TMath::Sqrt(TMath::Power(dCornersX[0] - dClustCentX, 2) + TMath::Power(dCornersY[0] - dClustCentY, 2));
3368 // Upper Right
3369 dCornersX[1] = dChanCentPosX + dEdgeCentDistX;
3370 dCornersY[1] = dChanCentPosY + dEdgeCentDistY;
3371 dCornersR[1] = TMath::Sqrt(TMath::Power(dCornersX[1] - dClustCentX, 2) + TMath::Power(dCornersY[1] - dClustCentY, 2));
3372 // Bottom Right
3373 dCornersX[2] = dChanCentPosX + dEdgeCentDistX;
3374 dCornersY[2] = dChanCentPosY - dEdgeCentDistY;
3375 dCornersR[2] = TMath::Sqrt(TMath::Power(dCornersX[2] - dClustCentX, 2) + TMath::Power(dCornersY[2] - dClustCentY, 2));
3376 // Bottom Left
3377 dCornersX[3] = dChanCentPosX - dEdgeCentDistX;
3378 dCornersY[3] = dChanCentPosY - dEdgeCentDistY;
3379 dCornersR[3] = TMath::Sqrt(TMath::Power(dCornersX[3] - dClustCentX, 2) + TMath::Power(dCornersY[3] - dClustCentY, 2));
3380
3381 Int_t iNbCornersIn = (dCornersR[0] < dClustRadius ? 1 : 0) + (dCornersR[1] < dClustRadius ? 1 : 0)
3382 + (dCornersR[2] < dClustRadius ? 1 : 0) + (dCornersR[3] < dClustRadius ? 1 : 0);
3383
3384 LOG(debug3) << "CbmTofDigitize::ComputeClusterAreaOnChannel => Check " << iNbCornersIn << " Radius " << dClustRadius
3385 << " " << dCornersR[0] << " " << dCornersR[1] << " " << dCornersR[2] << " " << dCornersR[3];
3386
3387 switch (iNbCornersIn) {
3388 case 0: {
3389 // No corner inside the circle
3390 // => if cluster center inside channel: 0-4 disc sections sticking out
3391 // => if cluster center outside channel: 0-1 disc section sticking in
3392 Double_t dEdgeR[4];
3393 dEdgeR[0] = dChanCentPosX - dEdgeCentDistX - dClustCentX; // Cluster -> Left edge
3394 dEdgeR[1] = dChanCentPosX + dEdgeCentDistX - dClustCentX; // Cluster -> Right edge
3395 dEdgeR[2] = dChanCentPosY - dEdgeCentDistY - dClustCentY; // Cluster -> Lower edge
3396 dEdgeR[3] = dChanCentPosY + dEdgeCentDistY - dClustCentY; // Cluster -> Upper edge
3397 if ((0.0 >= dEdgeR[0]) && (0.0 <= dEdgeR[1]) && (0.0 >= dEdgeR[2]) && (0.0 <= dEdgeR[3])) {
3398 // Cluster center inside channel
3399
3400 // First disc area
3401 Double_t dArea = dClustRadius * dClustRadius * TMath::Pi();
3402
3403 LOG(debug3) << "CbmTofDigitize::ComputeClusterAreaOnChannel => CC in Ch " << dArea;
3404
3405 // Now check for each edge if it cuts the cluster circle
3406 // and remove the corresponding disc section if it does
3407 // (no overlap as no corner inside cluster)
3408 if (TMath::Abs(dEdgeR[0]) < dClustRadius) dArea -= DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[0]));
3409 if (TMath::Abs(dEdgeR[1]) < dClustRadius) dArea -= DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[1]));
3410 if (TMath::Abs(dEdgeR[2]) < dClustRadius) dArea -= DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[2]));
3411 if (TMath::Abs(dEdgeR[3]) < dClustRadius) dArea -= DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[3]));
3412 if (dArea < 0.0)
3413 LOG(error) << "CbmTofDigitize::ComputeClusterAreaOnChannel => Neg. area! " << dArea << " Radius "
3414 << dClustRadius << " " << dEdgeR[0] << " " << dEdgeR[1] << " " << dEdgeR[2] << " " << dEdgeR[3];
3415 return dArea;
3416 } // Cluster center inside channel
3417 else {
3418 // Cluster center outside channel
3419 // At max. one of the edges can cur the cluster circle
3420 // If it is the case, the area on the channel is the disc section area
3421 // If no crossing => no common area of cluster and channel
3422
3423 LOG(debug3) << "CbmTofDigitize::ComputeClusterAreaOnChannel => CC out Ch " << dClustRadius << " " << dEdgeR[0]
3424 << " " << dEdgeR[1] << " " << dEdgeR[2] << " " << dEdgeR[3];
3425
3426 if (TMath::Abs(dEdgeR[0]) < dClustRadius) return DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[0]));
3427 else if (TMath::Abs(dEdgeR[1]) < dClustRadius)
3428 return DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[1]));
3429 else if (TMath::Abs(dEdgeR[2]) < dClustRadius)
3430 return DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[2]));
3431 else if (TMath::Abs(dEdgeR[3]) < dClustRadius)
3432 return DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR[3]));
3433 else
3434 return 0.0;
3435 } // Cluster center outside channel
3436 break;
3437 } // case 0
3438 case 1: {
3439 // 1 corner inside the circle
3440 // => we get a "slice" of the cluster disc
3441 // There are then 2 intersection points with the channel, one on each edge
3442 // starting at the included corner. Those 2 points and the corner form a
3443 // triangle. The cluster/channel intersection area is this triangle area +
3444 // the area of the disc section having the 2 intersections for base
3445 Double_t dIntPtX[2] = {0., 0.};
3446 Double_t dIntPtY[2] = {0., 0.};
3447 Double_t dArea = 0.;
3448
3449 if (dCornersR[0] < dClustRadius) {
3450 // Upper Left corner inside
3451 // Intersection point on left edge
3452 dIntPtX[0] = dCornersX[0];
3453 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3454 // Intersection point on upper edge
3455 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3456 dIntPtY[1] = dCornersY[0];
3457
3458 // First triangle area
3459 dArea = TriangleArea(dCornersX[0], dCornersY[0], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3460 }
3461 else if (dCornersR[1] < dClustRadius) {
3462 // Upper Right corner inside
3463 // Intersection point on Right edge
3464 dIntPtX[0] = dCornersX[1];
3465 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3466 // Intersection point on upper edge
3467 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3468 dIntPtY[1] = dCornersY[1];
3469
3470 // First triangle area
3471 dArea = TriangleArea(dCornersX[1], dCornersY[1], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3472 }
3473 else if (dCornersR[2] < dClustRadius) {
3474 // Bottom Right corner inside
3475 // Intersection point on Right edge
3476 dIntPtX[0] = dCornersX[2];
3477 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3478 // Intersection point on lower edge
3479 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3480 dIntPtY[1] = dCornersY[2];
3481
3482 // First triangle area
3483 dArea = TriangleArea(dCornersX[2], dCornersY[2], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3484 }
3485 else if (dCornersR[3] < dClustRadius) {
3486 // Bottom Left corner inside
3487 // Intersection point on left edge
3488 dIntPtX[0] = dCornersX[3];
3489 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3490 // Intersection point on lower edge
3491 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3492 dIntPtY[1] = dCornersY[3];
3493
3494 // First triangle area
3495 dArea = TriangleArea(dCornersX[3], dCornersY[3], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3496 }
3497
3498 // Then add disc section area
3499 // Compute the distance between base and cluster center
3500 Double_t dSecBaseD = DistanceCircleToBase(dClustRadius, dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3501 // Add computed area
3502 dArea += DiscSectionArea(dClustRadius, dSecBaseD);
3503
3504 return dArea;
3505 break;
3506 } // case 1
3507 case 2: {
3508 // 2 corners inside the circle
3509 // => 1 edge is fully included
3510 // Each of the edges in the other direction has 1 intersection point
3511 // with the circle. The area between the included edge and the line
3512 // they form can be otained by summing the area of 2 triangles, using
3513 // 1 of the corners inside the circle.
3514 // For the disc section having these points for base, there are 2
3515 // cases. Either it is fully contained inside the channel, or it sticks
3516 // out, making 2 intersection points on the edge opposite to the
3517 // included one. In the second case the area of this second disc section
3518 // has to be subtracted.
3519 Bool_t bFirstCorner = kTRUE;
3520 Int_t iCorners[2];
3521
3522 iCorners[0] = -1;
3523 iCorners[1] = -1;
3524 if (dCornersR[0] < dClustRadius) {
3525 // Upper Left corner inside
3526 iCorners[0] = 0;
3527 bFirstCorner = kFALSE;
3528 } // if( dCornersR[0] < dClustRadius )
3529 if (dCornersR[1] < dClustRadius) {
3530 // Upper Right corner inside
3531 if (kTRUE == bFirstCorner) {
3532 iCorners[0] = 1;
3533 bFirstCorner = kFALSE;
3534 } // if( kTRUE == bFirstCorner )
3535 else
3536 iCorners[1] = 1;
3537 } // else if( dCornersR[1] < dClustRadius )
3538 if (dCornersR[2] < dClustRadius) {
3539 // Bottom Right corner inside
3540 if (kTRUE == bFirstCorner) {
3541 iCorners[0] = 2;
3542 bFirstCorner = kFALSE;
3543 } // if( kTRUE == bFirstCorner )
3544 else
3545 iCorners[1] = 2;
3546 } // else if( dCornersR[2] < dClustRadius )
3547 if (dCornersR[3] < dClustRadius) {
3548 // Bottom Left corner inside
3549 // Has to be the 2nd one if there
3550 iCorners[1] = 3;
3551 } // else if( dCornersR[3] < dClustRadius )
3552
3553 LOG(debug3) << "Corners In check " << (iCorners[0]) << " " << (iCorners[1]);
3554 // Get the interesting points info
3555 Double_t dIntPtX[2] = {0., 0.};
3556 Double_t dIntPtY[2] = {0., 0.};
3557 Double_t dEdgeR = 0.;
3558 Int_t iOppCorner = 0;
3559 if (0 == iCorners[0] && 1 == iCorners[1]) {
3560 LOG(debug3) << "Test upper edge";
3561 // Upper edge
3562 // 1st Intersection point on left edge
3563 dIntPtX[0] = dCornersX[0];
3564 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3565 // 2nd Intersection point on right edge
3566 dIntPtX[1] = dCornersX[1];
3567 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3568 // Corner opposed to first intersection
3569 iOppCorner = 1; // <- Upper Right corner
3570 // Distance between out edge and cluster center
3571 dEdgeR = dChanCentPosY - dEdgeCentDistY - dClustCentY; // Cluster -> Lower edge
3572 }
3573 else if (1 == iCorners[0] && 2 == iCorners[1]) {
3574 LOG(debug3) << "Test right edge";
3575 // Right edge
3576 // Intersection point on upper edge
3577 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3578 dIntPtY[0] = dCornersY[1];
3579 // Intersection point on lower edge
3580 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3581 dIntPtY[1] = dCornersY[2];
3582 // Corner opposed to first intersection
3583 iOppCorner = 2; // <- Bottom Right corner
3584 // Distance between out edge and cluster center
3585 dEdgeR = dChanCentPosX - dEdgeCentDistX - dClustCentX; // Cluster -> Left edge
3586 }
3587 else if (2 == iCorners[0] && 3 == iCorners[1]) {
3588 LOG(debug3) << "Test lower edge";
3589 // Lower edge
3590 // 1st Intersection point on right edge
3591 dIntPtX[0] = dCornersX[2];
3592 dIntPtY[0] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3593 // 2nd Intersection point on left edge
3594 dIntPtX[1] = dCornersX[3];
3595 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3596 // Corner opposed to first intersection
3597 iOppCorner = 3; // <- Bottom left corner
3598 // Distance between out edge and cluster center
3599 dEdgeR = dChanCentPosY + dEdgeCentDistY - dClustCentY; // Cluster -> Upper edge
3600 }
3601 else if (0 == iCorners[0] && 3 == iCorners[1]) {
3602 LOG(debug3) << "Test left edge";
3603 // Left edge
3604 // Intersection point on lower edge
3605 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3606 dIntPtY[0] = dCornersY[3];
3607 // Intersection point on upper edge
3608 dIntPtX[1] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3609 dIntPtY[1] = dCornersY[0];
3610 // Corner opposed to first intersection
3611 iOppCorner = 0; // <- Upper left corner
3612 // Distance between out edge and cluster center
3613 dEdgeR = dChanCentPosX + dEdgeCentDistX - dClustCentX; // Cluster -> Right edge
3614 }
3615
3616 // First triangle: The 2 corners and the 1st intersection
3617 Double_t dArea = TriangleArea(dCornersX[iCorners[0]], dCornersY[iCorners[0]], dCornersX[iCorners[1]],
3618 dCornersY[iCorners[1]], dIntPtX[0], dIntPtY[0]);
3619 // Second triangle: The corners opposed to first intersection and the 2 intersections
3620 dArea +=
3621 TriangleArea(dCornersX[iOppCorner], dCornersY[iOppCorner], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3622
3623 // Now add the disc section
3624 // Compute the distance between base and cluster center
3625 Double_t dSecBaseD = DistanceCircleToBase(dClustRadius, dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3626 // Add computed area
3627 dArea += DiscSectionArea(dClustRadius, dSecBaseD);
3628
3629 // Use the distance between the cluster center and the opposite edge to
3630 // check if we need to remove a part sticking out
3631
3632 // Now check for this edge if it cuts the cluster circle
3633 // and remove the corresponding disc section if it does
3634 if (TMath::Abs(dEdgeR) < dClustRadius) dArea -= DiscSectionArea(dClustRadius, TMath::Abs(dEdgeR));
3635
3636 return dArea;
3637 break;
3638 } // case 2
3639 case 3: {
3640 // 3 corners inside the circle
3641 // => 2 edges fully included, 1 intersection on each of the 2 others
3642 // In this case the ovelapped area is equal to the full channel area
3643 // minus the area of the triangle formed by the out corner and the 2
3644 // intersection, plus the area of the disc section having the 2
3645 // intersection points for base.
3646 Int_t iOutCorner = 0;
3647 Double_t dIntPtX[2] = {0., 0.};
3648 Double_t dIntPtY[2] = {0., 0.};
3649
3650 if (dCornersR[0] > dClustRadius) {
3651 // Upper Left corner out
3652 iOutCorner = 0;
3653 // Intersection on upper edge
3654 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3655 dIntPtY[0] = dCornersY[0];
3656 // Intersection on left edge
3657 dIntPtX[1] = dCornersX[0];
3658 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3659 } // if( dCornersR[0] > dClustRadius )
3660 else if (dCornersR[1] > dClustRadius) {
3661 // Upper Right corner out
3662 iOutCorner = 1;
3663 // Intersection on upper edge
3664 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3665 dIntPtY[0] = dCornersY[1];
3666 // Intersection on right edge
3667 dIntPtX[1] = dCornersX[1];
3668 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3669 } // else if( dCornersR[1] > dClustRadius )
3670 else if (dCornersR[2] > dClustRadius) {
3671 // Bottom Right corner out
3672 iOutCorner = 2;
3673 // Intersection on bottom edge
3674 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3675 dIntPtY[0] = dCornersY[2];
3676 // Intersection on right edge
3677 dIntPtX[1] = dCornersX[2];
3678 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kTRUE);
3679 } // else if( dCornersR[2] > dClustRadius )
3680 else if (dCornersR[3] > dClustRadius) {
3681 // Bottom Left corner out
3682 iOutCorner = 3;
3683 // Intersection on bottom edge
3684 dIntPtX[0] = CircleIntersectPosX(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3685 dIntPtY[0] = dCornersY[3];
3686 // Intersection on left edge
3687 dIntPtX[1] = dCornersX[3];
3688 dIntPtY[1] = CircleIntersectPosY(iChanId, dClustRadius, dClustCentX, dClustCentY, kFALSE);
3689 } // else if( dCornersR[3] > dClustRadius )
3690
3691 // First get full channel area
3692 Double_t dArea = (fChannelInfo->GetSizex()) * (fChannelInfo->GetSizey());
3693
3694 // Then subtract the triangle area
3695 dArea -=
3696 TriangleArea(dCornersX[iOutCorner], dCornersY[iOutCorner], dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3697
3698 // Finally add the disc section area
3699 // Compute the distance between base and cluster center
3700 Double_t dSecBaseD = DistanceCircleToBase(dClustRadius, dIntPtX[0], dIntPtY[0], dIntPtX[1], dIntPtY[1]);
3701 // Add computed area
3702 dArea += DiscSectionArea(dClustRadius, dSecBaseD);
3703
3704 return dArea;
3705 break;
3706 } // case 3
3707 case 4: {
3708 // All in circle => channel fully contained!
3709 // => Area of Cluster/channel intersection = channel area
3710 return (fChannelInfo->GetSizex()) * (fChannelInfo->GetSizey());
3711 break;
3712 } // case 4
3713 default:
3714 // Should never happen !!!
3715 return 0;
3716 break;
3717 } // switch( iNbCornersIn )
3718}
3719/************************************************************************************/
3720// Auxiliary functions
3721// Area
3722Double_t CbmTofDigitize::TriangleArea(Double_t dXa, Double_t dYa, Double_t dXb, Double_t dYb, Double_t dXc,
3723 Double_t dYc)
3724{
3725 Double_t dArea = 0.5 * ((dXa - dXc) * (dYb - dYa) - (dXa - dXb) * (dYc - dYa));
3726 return TMath::Abs(dArea);
3727}
3728Double_t CbmTofDigitize::DiscSectionArea(Double_t dDiscRadius, Double_t dDistBaseToCenter)
3729{
3730 if (dDiscRadius < dDistBaseToCenter || dDiscRadius <= 0 || dDistBaseToCenter < 0) {
3731 LOG(error) << "CbmTofDigitize::DiscSectionArea => Invalid Input values!! "
3732 "Disc radius "
3733 << dDiscRadius << " and Base distance " << dDistBaseToCenter;
3734 return 0.0;
3735 }
3736 // First Half disc area
3737 Double_t dArea = dDiscRadius * dDiscRadius * TMath::Pi() / 2.0;
3738
3739 // Then remove the "rectangle" middle part of the area between base and center
3740 dArea -= dDistBaseToCenter * TMath::Sqrt(dDiscRadius * dDiscRadius - dDistBaseToCenter * dDistBaseToCenter);
3741 // Finally remove the "arc like" side parts of the area between base and center
3742 dArea -= dDiscRadius * dDiscRadius * TMath::ASin(dDistBaseToCenter / dDiscRadius);
3743
3744 return dArea;
3745}
3746//----------------------------------------------------------------------------//
3747// Points
3748Double_t CbmTofDigitize::CircleIntersectPosX(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX,
3749 Double_t dClustCentY, Bool_t bUpperSide)
3750{
3751 fChannelInfo = fDigiPar->GetCell(iChanId);
3752 Double_t dChanCentPosX = 0.; //fChannelInfo->GetX();
3753 Double_t dChanCentPosY = 0.; //fChannelInfo->GetY();
3754 Double_t dEdgeCentDistX = fChannelInfo->GetSizex() / 2.0;
3755 Double_t dEdgeCentDistY = fChannelInfo->GetSizey() / 2.0;
3756
3757 Double_t dEdgePosY = dChanCentPosY + (kTRUE == bUpperSide ? 1 : -1) * dEdgeCentDistY;
3758
3759 if (dChanCentPosX == dClustCentX) {
3760 // Clustered centered on channel center
3761 // => a single intersection means that the distance between cluster and edge is exactly
3762 // the radius
3763 if (TMath::Abs(dEdgePosY - dClustCentY) == dClustRadius)
3764 // => Intersection at same X position as channel center
3765 return dChanCentPosX;
3766 // Other values mean 0 or 2 intersections in edge range
3767 // => return 0.0, faulty call to this function
3768 else {
3769 LOG(error) << "CbmTofDigitize::CircleIntersectPosX => Invalid values: "
3770 << " 0 or 2 intersections with cluster aligned on channel ";
3771 return 0.0;
3772 } // else of if( dEdgeCentDistY == dClustRadius )
3773 } // if( dChanCentPosX == dClustCentX )
3774 else {
3775 Double_t dRoot = dClustRadius * dClustRadius - TMath::Power(dClustCentY - dEdgePosY, 2);
3776 if (0.0 <= dRoot) {
3777 // Null root means 1 single solution
3778 // Positive root means 2 solutions
3779 /*
3780 // If the circle center is more to the left than the channel center and
3781 // there are 2 solutions, assuming only 1 intersection exists inside the
3782 // edge boundaries, it will be the rightmost one.
3783 // If the circle center is more to the left than the channel center, it
3784 // will be the leftmost one.
3785 */
3786 Double_t dDistX = TMath::Sqrt(dRoot);
3787 Double_t dSign = ((dClustCentX - dDistX > dChanCentPosX - dEdgeCentDistX)
3788 && (dClustCentX - dDistX < dChanCentPosX + dEdgeCentDistX)
3789 ? -1.0
3790 : 1.0);
3791 return dClustCentX + dSign * dDistX;
3792 } // if( 0.0 <= dRoot )
3793 // Negative root means no intersection at all between
3794 // the circle and the line generated by this edge!!
3795 // => return 0.0, faulty call to this function
3796 else {
3797 LOG(error) << "CbmTofDigitize::CircleIntersectPosX => Invalid values: "
3798 << " 0 intersection at all (negative root = " << dRoot << ") ";
3799 TString sTemp =
3800 Form(" Radius = %5.4f ClustX = %6.3f ClustY = %6.3f Side = %1d EdgeY = "
3801 "%6.3f ChanX = %6.3f ChanY = %6.3f Channel = %6d",
3802 dClustRadius, dClustCentX, dClustCentY, bUpperSide, dEdgePosY, dChanCentPosX, dChanCentPosY, iChanId);
3803 LOG(error) << "CbmTofDigitize::CircleIntersectPosX => Input values: " << sTemp;
3804 return 0.0;
3805 } // else of if( 0.0 <= dRoot )
3806 } // else of if( dChanCentPosX == dClustCentX )
3807}
3808Double_t CbmTofDigitize::CircleIntersectPosY(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX,
3809 Double_t dClustCentY, Bool_t bRightSide)
3810{
3811 fChannelInfo = fDigiPar->GetCell(iChanId);
3812 Double_t dChanCentPosX = 0.; //fChannelInfo->GetX();
3813 Double_t dChanCentPosY = 0.; //fChannelInfo->GetY();
3814 Double_t dEdgeCentDistX = fChannelInfo->GetSizex() / 2.0;
3815 Double_t dEdgeCentDistY = fChannelInfo->GetSizey() / 2.0;
3816
3817 Double_t dEdgePosX = dChanCentPosX + (kTRUE == bRightSide ? 1 : -1) * dEdgeCentDistX;
3818
3819 if (dChanCentPosY == dClustCentY) {
3820 // Clustered centered on channel center
3821 // => a single intersection means that the distance between cluster and edge is exactly
3822 // the radius
3823 if (TMath::Abs(dEdgePosX - dClustCentX) == dClustRadius)
3824 // => Intersection at same X position as channel center
3825 return dChanCentPosY;
3826 // Other values mean 0 or 2 intersections in edge range
3827 // => return 0.0, faulty call to this function
3828 else {
3829 LOG(error) << "CbmTofDigitize::CircleIntersectPosY => Invalid values: "
3830 << " 0 or 2 intersections with cluster aligned on channel ";
3831 return 0.0;
3832 } // else of if( dEdgeCentDistX == dClustRadius )
3833 } // if( dChanCentPosX == dClustCentX )
3834 else {
3835 Double_t dRoot = dClustRadius * dClustRadius - TMath::Power(dClustCentX - dEdgePosX, 2);
3836 if (0.0 <= dRoot) {
3837 // Null root means 1 single solution
3838 // Positive root means 2 solutions
3839 /*
3840 // If the circle center is higher than the channel center and
3841 // there are 2 solutions, assuming only 1 intersection exists inside the
3842 // edge boundaries, it will be lower one.
3843 // If the circle center is more to the left than the channel center, it
3844 // will be the higher one.
3845 Double_t dSign = ( dClustCentY > dChanCentPosY ? -1.0 : 1.0);
3846
3847 return dChanCentPosY + dSign * TMath::Sqrt( dRoot );
3848 */
3849 Double_t dDistY = TMath::Sqrt(dRoot);
3850 Double_t dSign = ((dClustCentY - dDistY > dChanCentPosY - dEdgeCentDistY)
3851 && (dClustCentY - dDistY < dChanCentPosY + dEdgeCentDistY)
3852 ? -1.0
3853 : 1.0);
3854 return dClustCentY + dSign * dDistY;
3855 } // if( 0.0 <= dRoot )
3856 // Negative root means no intersection at all between
3857 // the circle and the line generated by this edge!!
3858 // => return 0.0, faulty call to this function
3859 else {
3860 LOG(error) << "CbmTofDigitize::CircleIntersectPosY => Invalid values: "
3861 << " 0 intersection at all (negative root = " << dRoot << ") ";
3862 TString sTemp =
3863 Form(" Radius = %5.4f ClustX = %6.3f ClustY = %6.3f Side = %1d EdgeX = "
3864 "%6.3f ChanX = %6.3f ChanY = %6.3f Channel = %6d",
3865 dClustRadius, dClustCentX, dClustCentY, bRightSide, dEdgePosX, dChanCentPosX, dChanCentPosY, iChanId);
3866 LOG(error) << "CbmTofDigitize::CircleIntersectPosY => Input values: " << sTemp;
3867 return 0.0;
3868 } // else of if( 0.0 <= dRoot )
3869 } // else of if( dChanCentPosX == dClustCentX )
3870}
3871Double_t CbmTofDigitize::DistanceCircleToBase(Double_t dClustRadius, Double_t dBaseXa, Double_t dBaseYa,
3872 Double_t dBaseXb, Double_t dBaseYb)
3873{
3874 // Both base endpoints should be on the circle, forming an isoscele triangle
3875 // with the circle center.
3876 // The distance to the base is then the height of the isoscele triangle.
3877 Double_t dBaseLength = TMath::Sqrt(TMath::Power(dBaseXb - dBaseXa, 2) + TMath::Power(dBaseYb - dBaseYa, 2));
3878 Double_t dRoot = dClustRadius * dClustRadius - dBaseLength * dBaseLength / 4;
3879 if (0.0 <= dRoot) return TMath::Sqrt(dRoot);
3880 else {
3881 LOG(error) << "CbmTofDigitize::DistanceCircleToBase => Invalid values: "
3882 << " base end-points not on circle (negative root" << dRoot << ") ";
3883 TString sTemp = Form(" Radius = %5.4f Xa = %6.3f Ya = %6.3f Xb = %6.3f Yb = %6.3f ", dClustRadius, dBaseXa, dBaseYa,
3884 dBaseXb, dBaseYb);
3885 LOG(error) << "CbmTofDigitize::DistanceCircleToBase => Input values: " << sTemp;
3886 return 0.0;
3887 } // else of if( 0.0 <= dRoot )
3888}
3889
3891{
3892 return (pDigi1->GetTime() < pDigi2->GetTime());
3893}
3894
3895
3922/************************************************************************************/
@ kTof
Time-of-flight Detector.
static TFile * fHist
Bool_t bFakeBeamCounter
const Int_t kiNbIntPts
struct CompTimesExp CompTExp
Int_t fCurrentMCEntry
@ k12b
@ k21a
@ k14a
static constexpr size_t size()
Definition KfSimdPseudo.h:2
bool first
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.
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.
Base class template for CBM digitisation tasks.
Definition CbmDigitize.h:44
void SendData(Double_t time, CbmTofDigi *digi, CbmMatch *match=nullptr)
int32_t GetMotherId() const
Definition CbmMCTrack.h:69
int32_t GetNPoints(ECbmModuleId detId) const
const CbmLink & GetLink(int32_t i) const
Definition CbmMatch.h:39
int32_t GetNofLinks() const
Definition CbmMatch.h:42
void AddLink(const CbmLink &newLink)
Definition CbmMatch.cxx:47
static uint32_t GetUniqueAddress(uint32_t Sm, uint32_t Rpc, uint32_t Channel, uint32_t Side=0, uint32_t SmType=0, uint32_t RpcType=0)
Double_t GetSizey() const
Definition CbmTofCell.h:40
Double_t GetY() const
Definition CbmTofCell.h:36
Double_t GetSizex() const
Definition CbmTofCell.h:39
Double_t GetX() const
Definition CbmTofCell.h:35
Double_t GetZ() const
Definition CbmTofCell.h:37
virtual InitStatus Init()
virtual int32_t GetSModule(const int32_t detectorId)=0
virtual int32_t SetDetectorInfo(const CbmTofDetectorInfo detectorInfo)=0
virtual int32_t GetGap(const int32_t detectorId)=0
virtual int32_t GetCounter(const int32_t detectorId)=0
virtual int32_t GetCell(const int32_t detectorId)=0
virtual int32_t GetSMType(const int32_t detectorId)=0
Parameters class for the CBM ToF digitizer using beam data distributions.
Int_t GetClusterModel() const
Double_t GetFeeTimeRes() const
Int_t GetNbSmTypes() const
Double_t GetResolution(Int_t iSmType) const
Int_t GetClusterRadiusModel() const
Bool_t UseOnlyPrimaries() const
Double_t GetFeeGainSigma() const
Int_t GetNbSm(Int_t iSmType) const
Int_t GetNbChan(Int_t iSmType, Int_t iRpc) const
void SetInputFile(TString FileName)
Bool_t UseOneGapPerTrk() const
Double_t GetGapEfficiency(Int_t iSmType, Int_t iRpc) const
Double_t GetFeeThreshold() const
TH1 * GetClustSizeHist(Int_t iSmType) const
Int_t GetChanType(Int_t iSmType, Int_t iRpc) const
Int_t GetNbRpc(Int_t iSmType) const
Double_t GetLandauMpv(Int_t iSmType) const
Double_t GetDeadtime() const
Int_t GetChanOrient(Int_t iSmType, Int_t iRpc) const
Double_t GetLandauSigma(Int_t iSmType) const
Double_t GetSignalSpeed() const
Double_t GetSigVel(Int_t iSmType, Int_t iSm, Int_t iRpc) const
TH1 * GetClustTotHist(Int_t iSmType) const
Double_t GetStartTimeRes() const
CbmTofCell * GetCell(Int_t i)
TGeoNode * GetNode(Int_t iCell)
Int_t GetNrOfModules()
Int_t GetCellId(Int_t i)
Data class for expanded digital TOF information.
Definition CbmTofDigi.h:47
double GetTime() const
Inherited from CbmDigi.
Definition CbmTofDigi.h:131
void SetTime(double time)
Definition CbmTofDigi.h:165
virtual void Exec(Option_t *option)
Inherited from FairTask.
TString fsBeamInputFile
TH2 * fhTofPtsInTrkVsGapIndPrm
CbmTofDetectorId * fTofId
Bool_t LoadBeamtimeValues()
Load the beamtime values designed in the parameters: histograms or single values.
Double_t CircleIntersectPosY(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX, Double_t dClustCentY, Bool_t bRightSide)
Compute the y position of the intersection of a circle with the left or right edge of a channel....
std::vector< TH1 * > fh1ClusterTotProb
CbmTofDigitize()
Constructor.
TStopwatch fTimer
ROOT timer.
std::vector< std::vector< std::vector< Double_t > > > fvdSignalVelocityRpc
Double_t GenerateClusterRadius(Int_t iSmType, Int_t iRpc)
Generate a value for the cluster radius from the beamtime data corresponding.
TH2 * fhTofPtsPosVsGap[10]
std::vector< std::vector< std::vector< std::vector< Int_t > > > > fStorDigiMatch
Double_t fdTimeTot
Total execution time.
std::vector< std::vector< ULong64_t > > fvlTrckChAddr
TString fsHistoOutFilename
std::vector< std::vector< std::vector< std::vector< std::pair< CbmTofDigi *, CbmMatch * > > > > > fStorDigi
Double_t DiscSectionArea(Double_t dDiscRadius, Double_t dDistBaseToCenter)
Compute area of a disc section from the disc radius and the distance of the.
std::vector< std::vector< std::vector< Double_t > > > fdChannelGain
virtual void Finish()
Inherited from FairTask.
std::vector< TH1 * > fh1ClusterSizeProb
Bool_t DigitizeDirectClusterSize()
Convert TofPoints in input TClonesArray to Tof Digis using directly the.
void SetInputFileName(TString FileName)
Double_t fdNofDigisTot
Total number of digis created.
Double_t fdDigiTimeConvFactor
Bool_t DigitizeFlatDisc()
Convert TofPoints in input TClonesArray to Tof Digis using an approximation of the.
Bool_t RegisterInputs()
Recover pointer on input TClonesArray: TofPoints, ...
std::vector< std::vector< ULong64_t > > fvlTrckRpcAddr
TClonesArray * fTofPointsColl
Bool_t CompareTimes(CbmTofDigi *p1, CbmTofDigi *p2)
CbmTofDigiBdfPar * fDigiBdfPar
Bool_t MergeSameChanDigis()
Merge the digis on he same readout channel.
Double_t ComputeClusterAreaOnChannel(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX, Double_t dClustCentY)
Compute geometrical intersection area of a cluster and a channel.
Bool_t SetHistoFileName(TString sFilenameIn="./tofDigiBdf.hst.root")
Double_t fdNofPointsTot
Total number of points processed.
Bool_t fbAllowPointsWithoutTrack
TTimeStamp fStart
Double_t fdNofTofMcTrkTot
Total number of MC tracks with TOF points.
Bool_t InitParameters()
Initialize other parameters not included in parameter classes.
virtual void SetParContainers()
Inherited from FairTask.
Double_t fdDigitizeTime
Bool_t DigitizeGaussCharge()
Convert TofPoints in input TClonesArray to Tof Digis using an approximation of the.
Double_t fdSignalPropSpeed
TH2 * fhTofPtsInTrkVsGapIndSec
virtual ~CbmTofDigitize()
Destructor.
Double_t CircleIntersectPosX(Int_t iChanId, Double_t dClustRadius, Double_t dClustCentX, Double_t dClustCentY, Bool_t bUpperSide)
Compute the x position of the intersection of a circle with the upper or.
CbmTofGeoHandler * fGeoHandler
virtual InitStatus Init()
Inherited from FairTask.
Int_t fiNofEvents
Total number of events processed.
Double_t TriangleArea(Double_t dXa, Double_t dYa, Double_t dXb, Double_t dYb, Double_t dXc, Double_t dYc)
Compute triangle area from its corners.
Double_t fdFeeGainSigma
std::vector< std::vector< Double_t > > fvlTrckRpcTime
Double_t DistanceCircleToBase(Double_t dClustRadius, Double_t dBaseXa, Double_t dBaseYa, Double_t dBaseXb, Double_t dBaseYb)
Compute the distance from the cluster center to the base of a disc.
Double_t fdTimeResElec
TClonesArray * fMcTracksColl
std::vector< std::vector< std::vector< Int_t > > > fvRpcChOffs
CbmTofDigiPar * fDigiPar
CbmTofCell * fChannelInfo
TH2 * fhTofPtsInTrkVsGapInd
Int_t GetCell(Int_t uniqueId)
Int_t Init(Bool_t isSimulation=kFALSE)
Int_t GetSModule(Int_t uniqueId)
Int_t GetCounter(Int_t uniqueId)
Int_t GetSMType(Int_t uniqueId)
Int_t GetCellId(Int_t uniqueId)
Int_t GetGap(Int_t uniqueId)
Geometric intersection of a MC track with a TOFb detector.
Definition CbmTofPoint.h:44
std::pair< CbmTofDigi *, CbmMatch * > data
bool operator()(data pair1, data pair2)