CbmRoot
Loading...
Searching...
No Matches
CbmTrdClusterFinder.cxx
Go to the documentation of this file.
1/* Copyright (C) 2010-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Florian Uhlig [committer], Pascal Raisig, Alexandru Bercuci */
4
6
7#include "CbmDefs.h"
8#include "CbmDigiManager.h"
9#include "CbmTimeSlice.h"
10#include "CbmTrdCluster.h"
11#include "CbmTrdDigi.h"
12#include "CbmTrdGeoHandler.h"
13#include "CbmTrdModuleRec2D.h"
14#include "CbmTrdModuleRecR.h"
15#include "CbmTrdParAsic.h"
16#include "CbmTrdParModDigi.h"
17#include "CbmTrdParModGain.h"
18#include "CbmTrdParModGas.h"
19#include "CbmTrdParSetAsic.h"
20#include "CbmTrdParSetDigi.h"
21#include "CbmTrdParSetGain.h"
22#include "CbmTrdParSetGas.h"
23#include "CbmTrdParSetGeo.h"
24
25#include <FairRootManager.h>
26#include <FairRunAna.h>
27#include <FairRuntimeDb.h>
28#include <Logger.h>
29
30#include <RtypesCore.h>
31#include <TArray.h>
32#include <TClonesArray.h>
33#include <TGeoPhysicalNode.h>
34#include <TStopwatch.h>
35// #include "TCanvas.h"
36// #include "TImage.h"
37
38#include <cmath>
39#include <iomanip>
40#include <iostream>
41
42using std::fixed;
43using std::left;
44using std::right;
45using std::setprecision;
46using std::setw;
47using std::stringstream;
48
49
52//_____________________________________________________________________
53CbmTrdClusterFinder::CbmTrdClusterFinder() : FairTask("TrdClusterFinder", 1)
54{
56 SetTimeBased(true);
57}
58// --------------------------------------------------------------------
59
60// ---- Destructor ----------------------------------------------------
62{
63
64 if (fClusters) {
65 fClusters->Clear("C");
66 fClusters->Delete();
67 delete fClusters;
68 }
69 // if (fGeoPar) { delete fGeoPar; }
70 // if(fModuleInfo){
71 // delete fModuleInfo;
72 // }
73}
74
75//_____________________________________________________________________
77{
78 Int_t ncl(fClusters->GetEntriesFast());
79 new ((*fClusters)[ncl++]) CbmTrdCluster(*c);
80 return kTRUE;
81}
82
83// ---- addDigisToModules ----
85{
86 const int NDIGICHUNK = 1000; // force flush of cluster buffer once every NDIGICHUNK digi to avoid memory exhaustion
87
88 UInt_t ndigis = static_cast<UInt_t>(std::abs(CbmDigiManager::Instance()->GetNofDigis(ECbmModuleId::kTrd)));
89 if (ndigis == 0) return 0;
90
91 int jdigi(0);
92 for (size_t idigi(0); idigi < ndigis; idigi++) {
93 addDigiToModule(idigi);
94 jdigi++;
95 // once in a while dump finished clusters
96 // TODO ad hoc condition. Maybe a find a better one
97 if (IsTimeBased() && jdigi >= NDIGICHUNK) {
98 processDigisInModules(jdigi, nullptr, false);
99 jdigi = 0;
100 }
101 }
102 return ndigis;
103}
104
105// ---- addDigisToModules ----
107{
108 UInt_t ndigis = static_cast<UInt_t>(event->GetNofData(ECbmDataType::kTrdDigi));
109 if (ndigis == 0) return 0;
110 for (size_t idigi = 0; idigi < ndigis; idigi++) {
111 auto digiindex = event->GetIndex(ECbmDataType::kTrdDigi, idigi);
112 addDigiToModule(digiindex);
113 }
114 return ndigis;
115}
116
117
118// ---- addDigiToModule ----
120{
121 CbmTrdModuleRec* mod = nullptr;
122
123 const CbmTrdDigi* digi = CbmDigiManager::Instance()->Get<CbmTrdDigi>(digiIdx);
124 if (!digi) return;
125 Int_t moduleAddress = digi->GetAddressModule();
126
127 std::map<Int_t, CbmTrdModuleRec*>::iterator imod = fModules.find(moduleAddress);
128 if (imod == fModules.end())
129 mod = AddModule(digi);
130 else
131 mod = imod->second;
132
133 mod->AddDigi(digi, digiIdx);
134}
135
136// ---- processDigisInModules ----
137void CbmTrdClusterFinder::processDigisInModules(UInt_t ndigis, CbmEvent* event, bool clr)
138{
139 CbmTrdModuleRec* mod(NULL);
140 Int_t digiCounter(0), clsCounter(0);
141 for (std::map<Int_t, CbmTrdModuleRec*>::iterator imod = fModules.begin(); imod != fModules.end(); imod++) {
142 mod = imod->second;
143 digiCounter += mod->GetOverThreshold();
144 clsCounter += mod->FindClusters(event || clr);
145 AddClusters(mod->GetClusters(), event, kTRUE);
146 }
147
148 // remove local data from all modules
149 for (std::map<Int_t, CbmTrdModuleRec*>::iterator imod = fModules.begin(); imod != fModules.end(); imod++)
150 imod->second->Clear("cls");
151
152 fNrDigis += ndigis;
153 fNrClusters += clsCounter;
154
155 if (DoDebugPrintouts()) {
156 LOG(info) << GetName() << "::Exec : Digis : " << ndigis << " / " << digiCounter << " above threshold ("
157 << 1e6 * fgMinimumChargeTH << " keV)";
158 LOG(info) << GetName() << "::Exec : Clusters : " << clsCounter;
159 }
160}
161
162//____________________________________________________________________________________
164{
165 Int_t address = digi->GetAddressModule();
166 CbmTrdModuleRec* module(NULL);
168 module = fModules[address] = new CbmTrdModuleRec2D(address);
169 else
170 module = fModules[address] = new CbmTrdModuleRecR(address);
171 LOG(debug) << GetName() << "::AddModule : " << module->GetName();
172
173 // try to load Geometry parameters for module
174 const CbmTrdParModGeo* pGeo(NULL);
175 if (!fGeoPar || !(pGeo = (const CbmTrdParModGeo*) fGeoPar->GetModulePar(address))) {
176 LOG(fatal) << GetName() << "::AddModule : No Geo params for module " << address << ". Using default.";
177 }
178 else
179 module->SetGeoPar(pGeo);
180
181 // try to load read-out parameters for module
182 const CbmTrdParModDigi* pDigi(NULL);
183 if (!fDigiPar || !(pDigi = (const CbmTrdParModDigi*) fDigiPar->GetModulePar(address))) {
184 LOG(warn) << GetName() << "::AddModule : No Read-Out params for modAddress " << address << ". Using default.";
185 }
186 else
187 module->SetDigiPar(pDigi);
188
189 // try to load ASIC parameters for module
190 CbmTrdParModAsic* pAsic(NULL);
191 if (!fAsicPar || !(pAsic = (CbmTrdParModAsic*) fAsicPar->GetModulePar(address))) {
192 LOG(warn) << GetName() << "::AddModule : No ASIC params for modAddress " << address << ". Using default.";
193 // module->SetAsicPar(); // map ASIC channels to read-out channels - need ParModDigi already loaded
194 }
195 else
196 module->SetAsicPar(pAsic);
197
198 // try to load Chamber parameters for module
199 const CbmTrdParModGas* pChmb(NULL);
200 if (!fGasPar || !(pChmb = (const CbmTrdParModGas*) fGasPar->GetModulePar(address))) {
201 LOG(warn) << GetName() << "::AddModule : No Gas params for modAddress " << address << ". Using default.";
202 }
203 else
204 module->SetChmbPar(pChmb);
205
206 // try to load Gain parameters for module
208 const CbmTrdParModGain* pGain(NULL);
209 if (!fGainPar || !(pGain = (const CbmTrdParModGain*) fGainPar->GetModulePar(address))) {
210 //LOG(warn) << GetName() << "::AddModule : No Gain params for modAddress "<< address <<". Using default.";
211 }
212 else
213 module->SetGainPar(pGain);
214 }
215 return module;
216}
217
218//_____________________________________________________________________
220{
221 FairRuntimeDb* rtdb = FairRunAna::Instance()->GetRuntimeDb();
222 fAsicPar = static_cast<CbmTrdParSetAsic*>(rtdb->getContainer("CbmTrdParSetAsic"));
223 fGasPar = static_cast<CbmTrdParSetGas*>(rtdb->getContainer("CbmTrdParSetGas"));
224 fDigiPar = static_cast<CbmTrdParSetDigi*>(rtdb->getContainer("CbmTrdParSetDigi"));
225 fGainPar = static_cast<CbmTrdParSetGain*>(rtdb->getContainer("CbmTrdParSetGain"));
226 fGeoPar = static_cast<CbmTrdParSetGeo*>(rtdb->getContainer("CbmTrdParSetGeo"));
227}
228
229//_____________________________________________________________________
231{
232
234 if (!CbmDigiManager::Instance()->IsPresent(ECbmModuleId::kTrd)) LOG(fatal) << GetName() << "Missing Trd digi branch.";
235
236 FairRootManager* ioman = FairRootManager::Instance();
237
238 fClusters = new TClonesArray("CbmTrdCluster", 100);
239 ioman->Register("TrdCluster", "TRD", fClusters, IsOutputBranchPersistent("TrdCluster"));
240
241 // Identify the time order of events based on the following conditions :
242 // 1. Existence of "CbmEvent" branch means that a form of DigiEventBuilder was run before (for
243 // both data and simulations) and it should be used UNLESS the user EXPLICITELY specify NOT TO.
244 // 2. Existence of "TimeSlice" branch "IsEvent() == true" for simulations
245 fEvents = dynamic_cast<TClonesArray*>(ioman->GetObject("CbmEvent"));
246 bool digiEvent(false);
247 CbmTimeSlice* ts = dynamic_cast<CbmTimeSlice*>(ioman->GetObject("TimeSlice."));
248 if (ts != nullptr) {
249 digiEvent = ts->IsEvent();
250 }
251 LOG(info) << GetName() << ": Event trigger " << (fEvents ? "found" : "miss") << "; digi organized "
252 << (digiEvent ? "EbyE" : "Timebased") << ".";
253
254 // If activated by the user, the clusterizer will look for the CbmEvent branch, to only use Digis connected to a CbmEvent. If no CbmEvent branch is found all digis in the TrdDigi branch are automatically used.
255 if (UseOnlyEventDigis()) {
256 if (fEvents == nullptr) {
257 LOG(warn) << GetName()
258 << ": Event mode selected but no CbmEvent branch found ! Processing all digi from the list.";
260 }
261 }
262 else {
263 if (fEvents) {
264 LOG(warn) << GetName()
265 << ": CbmEvent branch found but full digi stream asked by user ! Processing all digi from the list.";
266 fEvents = nullptr;
267 }
268 }
269
270 if (IsTimeBased() && digiEvent) {
271 LOG(warn) << GetName() << ": Timebased mode selected but digi EbyE ! Processing digi from event (simulation EbyE).";
272 SetTimeBased(false);
273 }
274
275 // // Get the full geometry information of the detector gas layers and store
276 // // them with the CbmTrdModuleRec. This information can then be used for
277 // // transformation calculations
278 // std::map<Int_t, TGeoPhysicalNode*> moduleMap = fGeoHandler->FillModuleMap();
279 //
280 // Int_t nrModules = fDigiPar->GetNrOfModules();
281 // Int_t nrNodes = moduleMap.size();
282 // if (nrModules != nrNodes) LOG(fatal) << "Geometry and parameter files have different number of modules.";
283 // for (Int_t loop=0; loop< nrModules; ++loop) {
284 // Int_t address = fDigiPar->GetModuleId(loop);
285 // std::map<Int_t, TGeoPhysicalNode*>::iterator it = moduleMap.find(address);
286 // if ( it == moduleMap.end() ) {
287 // LOG(fatal) << "Expected module with address " << address << " wasn't found in the map with TGeoNode information.";
288 // }
289 // AddModule(address, it->second);
290 // }
291
292 // // new call needed when parameters are initialized from ROOT file
293 // fDigiPar->Initialize();
294
295 LOG(info) << "================ TRD Cluster Finder ===============";
296 LOG(info) << " Free streaming : " << (IsTimeBased() ? "yes" : "no");
297 LOG(info) << " Multi hit detect : " << (HasMultiHit() ? "yes" : "no");
298 LOG(info) << " Row merger : " << (HasRowMerger() ? "yes" : "no");
299 LOG(info) << " c-Neighbour enable : " << (HasNeighbourCol() ? "yes" : "no");
300 LOG(info) << " r-Neighbour enable : " << (HasNeighbourRow() ? "yes" : "no");
301 LOG(info) << " Write clusters : " << (HasDumpClusters() ? "yes" : "no");
302 LOG(info) << " Use only event digis : " << (UseOnlyEventDigis() ? "yes" : "no");
303
304 return kSUCCESS;
305}
306
307//_____________________________________________________________________
308void CbmTrdClusterFinder::Exec(Option_t* /*option*/)
309{
323 fClusters->Delete();
324
325 TStopwatch timer;
326 TStopwatch timerTs;
327 timerTs.Start();
329 Long64_t nDigisUsed = 0;
330 UInt_t nDigis = 0;
331 UInt_t nEvents = 0;
332
333 if (UseOnlyEventDigis()) {
334 for (auto eventobj : *fEvents) {
335 timer.Start();
336 auto event = static_cast<CbmEvent*>(eventobj);
337 nDigis = addDigisToModules(event);
338 processDigisInModules(nDigis, event);
339 fNrEvents++;
340 nEvents++;
341 nDigisUsed += nDigis;
342 timer.Stop();
343 if (DoDebugPrintouts()) {
344 LOG(info) << GetName() << "::Exec : Event Nr: " << fNrEvents;
345 LOG(info) << GetName() << "::Exec : real time=" << timer.RealTime() << " CPU time=" << timer.CpuTime();
346 }
347 fProcessTime += timer.RealTime();
348 timer.Reset();
349 }
350 }
351
352 if (!UseOnlyEventDigis()) {
353 timer.Start();
354 nDigis = addDigisToModules();
355 processDigisInModules(nDigis);
356 fNrEvents++;
357 nDigisUsed = nDigis;
358 timer.Stop();
359 if (DoDebugPrintouts()) {
360 LOG(info) << GetName() << "::Exec : Event Nr: " << fNrEvents;
361 LOG(info) << GetName() << "::Exec : real time=" << timer.RealTime() << " CPU time=" << timer.CpuTime();
362 }
363 fProcessTime += timer.RealTime();
364 timer.Reset();
365 }
366
367 timerTs.Stop();
368 stringstream logOut;
369 logOut << setw(20) << left << GetName() << " [";
370 logOut << fixed << setw(8) << setprecision(1) << right << timerTs.RealTime() * 1000. << " ms] ";
371 logOut << "TS " << fNrTs;
372 if (UseOnlyEventDigis()) logOut << ", events " << nEvents;
373 logOut << ", digis " << nDigisUsed << " / " << nDigisAll << " clusters "
374 << (fClusters ? fClusters->GetEntriesFast() : 0);
375 LOG(info) << logOut.str();
376 fNrTs++;
377}
378
379//_____________________________________________________________________
380Int_t CbmTrdClusterFinder::AddClusters(TClonesArray* clusters, CbmEvent* event, Bool_t /* move*/)
381{
382 if (!clusters) return 0;
383 CbmTrdCluster *cls(NULL), *clsSave(NULL);
384 const CbmTrdDigi* digi(NULL);
385 CbmTrdParModDigi* digiPar(NULL);
386 TBits cols, rows;
387 Int_t ncl(fClusters->GetEntriesFast()), mcl(0), ncols(0);
388
389 for (Int_t ic(0); ic < clusters->GetEntriesFast(); ic++) {
390 if (!(cls = (CbmTrdCluster*) (*clusters)[ic])) continue;
391
392 if (!cls->HasFaspDigis()) { // only for rectangular/SPADIC clusters
393 if (!ncols) {
394 digiPar = (CbmTrdParModDigi*) fDigiPar->GetModulePar(cls->GetAddress());
395 if (!digiPar) {
396 LOG(error) << "CbmTrdClusterFinder::AddClusters : Can't find "
397 "ParModDigi for address"
398 << cls->GetAddress();
399 continue;
400 }
401 ncols = digiPar->GetNofColumns();
402 }
403 cols.Clear();
404 rows.Clear();
405 for (Int_t id = 0; id < cls->GetNofDigis(); id++) {
406 digi = CbmDigiManager::Instance()->Get<CbmTrdDigi>(cls->GetDigi(id));
407 Int_t digiChannel = digi->GetAddressChannel();
408 Int_t colId = digiChannel % ncols;
409 Int_t globalRow = digiChannel / ncols;
410
411 Int_t combiId = globalRow * ncols + colId;
412 cols.SetBitNumber(combiId);
413 rows.SetBitNumber(globalRow);
414 }
415 // store information in cluster
416 cls->SetNCols(cols.CountBits());
417 cls->SetNRows(rows.CountBits());
418 }
419 clsSave = new ((*fClusters)[ncl]) CbmTrdCluster(*cls); // TODO implement copy constructor
420 // In case we have an event branch and we did only use digis from within the event, add the cluster to the event. This allows the hit producer to identify wether or not to add the corresponding hit to the event.
421 if (event) event->AddData(ECbmDataType::kTrdCluster, ncl);
422 ncl++;
423 clsSave->SetFaspDigis(cls->HasFaspDigis());
424 if (cls->GetMatch() != NULL)
425 delete cls; //only the matches have pointers to allocated memory, so otherwise the clear does the trick
426 mcl++;
427 }
428 //clusters->Clear();
429 return mcl;
430}
431
432//_____________________________________________________________________
434{
435 std::cout << std::endl;
436 LOG(info) << "=====================================";
437 LOG(info) << GetName() << ": Finish run";
438 LOG(info) << GetName() << ": Run summary ";
439 LOG(info) << GetName() << ": Processing time : " << std::fixed << std::setprecision(3) << fProcessTime;
440 LOG(info) << GetName() << ": Nr of events : " << fNrEvents;
441 LOG(info) << GetName() << ": Nr of input digis : " << fNrDigis;
442 LOG(info) << GetName() << ": Nr of produced clusters : " << fNrClusters;
443 LOG(info) << GetName() << ": Nr of clusters / event : " << std::fixed << std::setprecision(2)
444 << (fNrEvents > 0 ? fNrClusters / (Double_t) fNrEvents : 0);
445 LOG(info) << GetName() << ": Nr of digis / cluster : " << std::fixed << std::setprecision(2)
446 << (fNrClusters > 0 ? fNrDigis / (Double_t) fNrClusters : 0);
447 LOG(info) << "=====================================";
448 std::cout << std::endl;
449}
450
ClassImp(CbmConverterManager)
@ kTrd
Transition Radiation Detector.
FairTask to produce TrdCluster objects from TrdHit objects.
Data Container for TRD clusters.
Helper class to extract information from the GeoManager.
static Int_t GetNofDigis(ECbmModuleId systemId)
InitStatus Init()
Initialisation.
const Digi * Get(Int_t index) const
Get a digi object.
static CbmDigiManager * Instance()
Static instance.
Class characterising one event by a collection of links (indices) to data objects,...
Definition CbmEvent.h:34
Bookkeeping of time-slice content.
bool IsEvent() const
static void SetUseOnlyEventDigis(Bool_t set=kTRUE)
Set the Use Only Event Digis Per default this is activated on construction, such that the user can tu...
static void SetTimeBased(Bool_t set=kTRUE)
TClonesArray * fEvents
Array connected to the CbmEvent branch.
std::map< Int_t, CbmTrdModuleRec * > fModules
list of modules being processed
CbmTrdParSetGas * fGasPar
parameter list for HV status
static Bool_t HasDumpClusters()
static Int_t fgConfig
Configuration map for the clusterizer. See CbmTrdRecDef for details.
UInt_t fNrDigis
Number of digis as input for the hit production.
virtual InitStatus Init()
static Bool_t HasNeighbourCol()
Bool_t AddCluster(CbmTrdCluster *c)
Save one finished cluster to the output.
CbmTrdParSetDigi * fDigiPar
parameter list for read-out geometry
CbmTrdClusterFinder()
Default constructor.
static Bool_t HasRowMerger()
UInt_t fNrTs
Number of processed time slices.
~CbmTrdClusterFinder()
Default destructor.
CbmTrdModuleRec * AddModule(const CbmTrdDigi *digi)
Adds the module corresponding to the address of the passed digi to the ModuleMap (fModules)
virtual void Exec(Option_t *option)
Executed task.
UInt_t fNrClusters
Number of produced clusters.
CbmTrdParSetGeo * fGeoPar
parameter list for modules geometry
static Bool_t HasNeighbourRow()
static Bool_t UseOnlyEventDigis()
If true only digis connected ro a CbmEvent are processed Per default this is activated on constructio...
CbmTrdParSetGain * fGainPar
parameter list for keV->ADC gain conversion
void processDigisInModules(UInt_t ndigis, CbmEvent *event=nullptr, bool clr=true)
Call the clusterizer function of each module.
static Bool_t HasMultiHit()
static Bool_t IsTimeBased()
UInt_t addDigisToModules()
Add all digis available from CbmDigiManager to the corresponding modules.
static Float_t fgMinimumChargeTH
Int_t AddClusters(TClonesArray *clusters, CbmEvent *event, Bool_t moveOwner=kTRUE)
void addDigiToModule(UInt_t digiIdx)
Add the digi in the TrdDigi branch at the passed digiIdx to its corresponding module.
CbmTrdParSetAsic * fAsicPar
parameter list for ASIC characterization
UInt_t fNrEvents
Number of processed events (without CbmEvent corresponds to nr of exec calls)
Float_t fProcessTime
Total processing time [RealTime].
static Bool_t DoDebugPrintouts()
Data Container for TRD clusters.
void SetFaspDigis(bool set=true)
int32_t GetAddressModule() const
Getter module address in the experiment.
int32_t GetAddressChannel() const
Getter read-out id.
eCbmTrdAsicType GetType() const
Channel FEE SPADIC/FASP according to CbmTrdAsicType.
Definition CbmTrdDigi.h:173
Abstract class for module wise cluster finding and hit reconstruction.
virtual Int_t GetOverThreshold() const
virtual TClonesArray * GetClusters()
virtual Bool_t AddDigi(const CbmTrdDigi *, Int_t)
Add digi to local module.
virtual Int_t FindClusters(bool clr=true)=0
Steering routine for finding digits clusters.
Describe TRD module ASIC settings (electronic gain, delays, etc)
Definition of chamber gain conversion for one TRD module.
Int_t GetNofColumns() const
Definition of gain parameters for one TRD module.
Definition of gas parameters for one TRD module.
Definition of geometry for one TRD module.
Describe TRD module ASIC settings (electronic gain, delays, etc)
Describe TRD module working settings (HV, etc)
virtual const CbmTrdParMod * GetModulePar(Int_t detId) const