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