CbmRoot
Loading...
Searching...
No Matches
CbmRecoQaTask.cxx
Go to the documentation of this file.
1/* Copyright (C) 2024 Hulubei National Institute of Physics and Nuclear Engineering - Horia Hulubei, Bucharest
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Alexandru Bercuci [committer], Omveer Singh */
4
5//CBM headers
6#include "CbmRecoQaTask.h"
7
9#include "CbmDefs.h"
10#include "CbmEvent.h"
11#include "CbmFsdHit.h"
12#include "CbmGlobalTrack.h"
13#include "CbmMCDataArray.h"
14#include "CbmMCDataManager.h"
15#include "CbmMvdHit.h"
16#include "CbmPsdHit.h"
17#include "CbmRichHit.h"
18#include "CbmSetup.h"
19#include "CbmStsAddress.h"
20#include "CbmStsHit.h"
21#include "CbmStsSetup.h"
22#include "CbmTimeSlice.h"
23#include "CbmTofAddress.h"
24#include "CbmTofHit.h"
25#include "CbmTrdAddress.h"
26#include "CbmTrdHit.h"
27// FAIR headers
28#include "FairMCPoint.h"
29
30#include <FairRootManager.h>
31#include <FairSink.h>
32// ROOT headers
33#include <TClonesArray.h>
34#include <TGeoManager.h>
35#include <TGeoNode.h>
36#include <TH2D.h>
37
38#include <iterator>
39#include <regex>
40
41using namespace std;
42using namespace cbm::algo;
43std::bitset<CbmRecoQaTask::eRecoConfig::kRecoQaNConfigs> CbmRecoQaTask::fuRecoConfig = {};
44
45//_____________________________________________________________________
46CbmRecoQaTask::CbmRecoQaTask() : FairTask("RecoQA", 0) {}
47
48//_____________________________________________________________________
50{
51 /* Interface to the user. Check that the det defined in the outside world
52 * fulfills the quality criteria.
53 */
54 if (GetDetector(id)) {
55 LOG(warn) << GetName() << "::AddDetector(" << ToString(id) << ")."
56 << " already registered. Using "
57 << "\"CbmRecoQaTask::GetDetector(ECbmModuleId).\"";
58 return GetDetector(id);
59 }
60 switch (id) {
70 LOG(debug) << GetName() << "::AddDetector(" << ToString(id) << ").";
71 fDetQa.emplace(id, id);
72 break;
73 default: LOG(warn) << GetName() << "::AddDetector : unsupported det " << ToString(id); return nullptr;
74 }
75
76 return &fDetQa[id];
77}
78
79//_____________________________________________________________________
81{
82 if (fDetQa.find(id) == fDetQa.end()) return nullptr;
83 return &fDetQa[id];
84}
85
86//_____________________________________________________________________
88{
89 if (fTracks.find(did) == fTracks.end()) {
90 LOG(warning) << GetName() << " missing tracks for " << ToString(did);
91 return nullptr;
92 }
93 if (id < 0) {
94 LOG(warning) << GetName() << " negative trk idx for " << ToString(did);
95 return nullptr;
96 }
97 const CbmTrack* trk = (const CbmTrack*) (fTracks.at(did))->At(id);
98 if (!trk) {
99 LOG(debug1) << GetName() << " missing trk_" << id << " for " << ToString(did);
100 return nullptr;
101 }
102 return trk;
103}
104
105//_____________________________________________________________________
107{
108 fFitter.Init();
110
111 // Get ROOT Manager
112 FairRootManager* ioman = FairRootManager::Instance();
113
114 if (!ioman) {
115 LOG(fatal) << GetName() << "::Init :: RootManager not instantiated!";
116 return kERROR;
117 }
118
119 fGTracks = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrack"));
120 if (!fGTracks)
121 LOG(warn) << GetName() << "::Init: Global track array not found!";
122 else
124
125 fEvents = static_cast<TClonesArray*>(ioman->GetObject("CbmEvent"));
126 if (!fEvents)
127 LOG(warn) << GetName() << "::Init: No event found. Some results will be missing.";
128 else
130
131 switch (fSetupClass) {
132 case kMcbm22:
133 LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2022\".";
134 InitMcbm22();
135 break;
136 case kMcbm24:
137 LOG(info) << GetName() << "::Init: Setup config for \"mCBM 2024\". ";
138 InitMcbm24();
139 break;
140 case kDefault:
141 LOG(info) << GetName() << "::Init: Setup config for \"Default\". ";
142 InitDefault();
143 break;
144 }
145
146 if (fuRecoConfig[kUseMC]) {
147 cbm_mc_manager = dynamic_cast<CbmMCDataManager*>(ioman->GetObject("MCDataManager"));
148 if (!cbm_mc_manager) {
149 LOG(warn) << GetName() << "::Init: MC data manager not available even though asked by user !";
150 fuRecoConfig.reset(kUseMC);
151 }
152 else {
153 fTrackMatches = static_cast<TClonesArray*>(ioman->GetObject("GlobalTrackMatch"));
154 if (!fTrackMatches) {
155 LOG(warn) << GetName() << "::Init: MC info for Global track not available !";
156 }
157 }
158 }
159
160 fOutFolder.Clear();
161 for (auto& detp : fDetQa) { // SYSTEM LOOP
162 auto& det = detp.second;
163
164 if (cbm_mc_manager) {
165 fPoints[det.id] = cbm_mc_manager->InitBranch(det.point.name.data());
166 if (!fPoints[det.id])
167 LOG(warn) << GetName() << "::Init: MC Point array for " << ToString(det.id) << " not found!";
168 fHitMatch[det.id] = static_cast<TClonesArray*>(ioman->GetObject((det.hit.name + "Match").c_str()));
169
170 if (!fHitMatch[det.id])
171 LOG(warn) << GetName() << "::Init: Hit Match array for " << ToString(det.id) << " not found!";
172 }
173
174 fHits[det.id] = static_cast<TClonesArray*>(ioman->GetObject(det.hit.name.data()));
175 if (!fHits[det.id]) {
176 LOG(warn) << GetName() << "::Init: Hit array for " << ToString(det.id) << " not found!";
177 continue;
178 }
179
180 if (fGTracks && det.trk.id != ECbmDataType::kUnknown) {
181 fTracks[det.id] = static_cast<TClonesArray*>(ioman->GetObject(det.trk.name.data()));
182 if (!fTracks[det.id]) LOG(warn) << GetName() << "::Init: Track array for " << ToString(det.id) << " not found!";
183 }
184 if (!det.Init(&fOutFolder, (bool) fuRecoConfig[kUseMC])) continue;
185 }
186
187 TDirectoryFile* trgDir = (fuRecoConfig[kRecoEvents] || GetNviews(eViewType::kTrkProj))
188 ? (TDirectoryFile*) fOutFolder.mkdir("TRG", "Target tomography with CA")
189 : nullptr;
190
191 // register track projection on z planes
192 if (fPrjPlanes.size() && trgDir) {
193 fViews.emplace("prj", View("TrkProj", "", {}));
194 fViews["prj"].fType = eViewType::kTrkProj;
195 int i(0);
196 for (auto plane : fPrjPlanes) { // add projection planes according to user request
197 if (i >= kNtrkProjections) {
198 LOG(warn) << GetName() << "::Init: Only " << kNtrkProjections << " are supported. Skipping the rest.";
199 fPrjPlanes.erase(fPrjPlanes.begin() + int(kNtrkProjections), fPrjPlanes.end());
200 break;
201 }
202
204 plane.Z());
205 i++;
206 }
207 fViews["prj"].Init("");
208 fViews["prj"].Register(trgDir);
209 }
210
211 // register primary vertex QA
212 if (fuRecoConfig[kRecoEvents] && trgDir) {
213 fViews.emplace("vx", View("Vx", "", {}));
214 fViews["vx"].fType = eViewType::kPV;
219 fViews["vx"].Init("Prim");
220 fViews["vx"].Register(trgDir);
221 }
222 return kSUCCESS;
223}
224
226template<class Hit>
227bool CbmRecoQaTask::View::HasAddress(const CbmHit* h, double&, double&, double&, double&) const
228{
229 LOG(error) << "Unprocessed hit in view " << name;
230 cout << h->ToString();
231
232 return false;
233}
234// STS specialization
235template<>
236bool CbmRecoQaTask::View::HasAddress<CbmStsHit>(const CbmHit* h, double& x, double& y, double& dx, double& dy) const
237{
238 int32_t a = h->GetAddress();
242 uint idx(0);
243 for (auto ii : fSelector) {
244 if (uint(ii) != sel[idx]) break;
245 idx++;
246 }
247 if (fSetup == eSetup::kDefault && sel[0] != uint(fSelector[0])) {
248 return false;
249 }
250 else if (fSetup != eSetup::kDefault && idx != fSelector.size()) {
251 return false;
252 }
253 else
254 LOG(debug4) << "Accept Sts hit for " << sel[0] << " " << sel[1] << " " << sel[2];
255
256 const CbmStsHit* h0 = dynamic_cast<const CbmStsHit*>(h);
257 if (!h0) {
258 LOG(error) << "Failed loading STS hit in view " << name;
259 return false;
260 }
261 x = h0->GetX();
262 dx = h0->GetDx();
263 y = h0->GetY();
264 dy = h0->GetDy();
265 return true;
266}
267// Rich specialization
268template<>
269bool CbmRecoQaTask::View::HasAddress<CbmRichHit>(const CbmHit* h, double& x, double& y, double& dx, double& dy) const
270{
271 int16_t uId = CbmRichUtil::GetDirichId(h->GetAddress());
272 // TODO implement at RichUtil level
273 int8_t modId = (uId >> 8) & 0xF;
274
275 if (fSetup != eSetup::kDefault) {
276 if (modId >= fSelector[0]) return false;
277 }
278
279 const CbmRichHit* h0 = dynamic_cast<const CbmRichHit*>(h);
280 if (!h0) {
281 LOG(error) << "Failed loading RICH hit in view " << name;
282 return false;
283 }
284 x = h0->GetX();
285 dx = h0->GetDx();
286 y = h0->GetY();
287 dy = h0->GetDy();
288 return true;
289}
290// TRD specialization
291template<>
292bool CbmRecoQaTask::View::HasAddress<CbmTrdHit>(const CbmHit* h, double& x, double& y, double& dx, double& dy) const
293{
294 std::vector<int> sel;
295
296 if (fSetup == eSetup::kDefault) {
297 sel = {static_cast<int>(CbmTrdAddress::GetLayerId(CbmTrdAddress::GetModuleAddress(h->GetAddress()))),
298 static_cast<int>(CbmTrdAddress::GetModuleId(h->GetAddress())), -1};
299 }
300 else {
301 sel = {static_cast<int>(CbmTrdAddress::GetModuleAddress(h->GetAddress())), -1, -1};
302 }
303
304 uint idx = 0;
305 for (auto ii : fSelector) {
306 if (ii != sel[idx]) break;
307 idx++;
308 }
309
310 if (idx != fSelector.size()) {
311 return false;
312 }
313
314 LOG(debug4) << "Accept Sts hit for " << sel[0] << " " << sel[1] << " " << sel[2];
315
316 const CbmTrdHit* h0 = dynamic_cast<const CbmTrdHit*>(h);
317 if (!h0) {
318 LOG(error) << "Failed loading TRD hit in view " << name;
319 return false;
320 }
321 x = h0->GetX();
322 dx = h0->GetDx();
323 y = h0->GetY();
324 dy = h0->GetDy();
325 return true;
326}
327// ToF specialization
328template<>
329bool CbmRecoQaTask::View::HasAddress<CbmTofHit>(const CbmHit* h, double& x, double& y, double& dx, double& dy) const
330{
331 int32_t a = h->GetAddress();
333 uint idx(0);
334 for (auto ii : fSelector) {
335 if (ii != sel[idx]) break;
336 idx++;
337 }
338 if (fSetup == eSetup::kDefault && idx != 2) {
339 return false;
340 }
341 else if (fSetup != eSetup::kDefault && idx != fSelector.size()) {
342 return false;
343 }
344 else
345 LOG(debug4) << "Accept Tof hit for " << sel[0] << " " << sel[1] << " " << sel[2];
346
347 const CbmTofHit* h0 = dynamic_cast<const CbmTofHit*>(h);
348 if (!h0) {
349 LOG(error) << "Failed loading ToF hit in view " << name;
350 return false;
351 }
352 x = h0->GetX();
353 dx = h0->GetDx();
354 y = h0->GetY();
355 dy = h0->GetDy();
356 return true;
357}
358template<class Hit>
359bool CbmRecoQaTask::View::Load(const CbmHit* h, const FairMCPoint* point, const CbmEvent* ev)
360{
361 double x(0), y(0), dx(0), dy(0);
362 if (!HasAddress<Hit>(h, x, y, dx, dy)) {
363 LOG(debug1) << "view " << name << " does not own hit " << h->ToString();
364 return false;
365 }
366
367 // printf("View[%s] z(%d)[%f]\n", name.data(), (int)h->GetType(), h->GetZ());
368 int scale(0);
369 TH2* hh(nullptr);
370 auto fillView = [&](eProjectionType proj, double xx, double yy, bool scaleY = true) {
371 auto it = fProjection.find(proj);
372 if (it != fProjection.end()) {
373 scale = std::get<0>(it->second);
374 hh = std::get<2>(it->second);
375 if (hh) hh->Fill(xx, scaleY ? yy * scale : yy);
376 }
377 };
378
379 if (ev) {
380 fillView(eProjectionType::kChdT, x, h->GetTime() - ev->GetStartTime());
381 //fillView(eProjectionType::kXYh, x, y, false);
382 }
383
384 fillView(eProjectionType::kXYh, x, y, false);
385
386 double event_time = ev ? ev->GetStartTime() : 1000;
387
388 if (point) {
389 fillView(eProjectionType::kXYhMC, point->GetX(), point->GetY(), false);
390 fillView(eProjectionType::kResidualX, point->GetX(), x - point->GetX());
391 fillView(eProjectionType::kResidualY, point->GetY(), y - point->GetY());
392 fillView(eProjectionType::kResidualTX, point->GetX(), h->GetTime() - event_time - point->GetTime());
393 fillView(eProjectionType::kResidualTY, point->GetY(), h->GetTime() - event_time - point->GetTime());
394 fillView(eProjectionType::kPullX, point->GetX(), (x - point->GetX()) / dx);
395 fillView(eProjectionType::kPullY, point->GetY(), (y - point->GetY()) / dy);
396 }
397 fMult++; // register hit/point multiplicity
398 return true;
399}
400
401bool CbmRecoQaTask::View::Load(const CbmKfTrackFitter::TrajectoryNode* n, const FairMCPoint* point)
402{
403 const kf::TrackParamD& t = n->fParamUp;
404 double dx = n->fMxy.X() - t.X(), dy = n->fMxy.Y() - t.Y(), dt = n->fMt.T() - t.Time(),
405 pullx = dx / sqrt(n->fMxy.Dx2() + t.GetCovariance(0, 0)),
406 pully = dy / sqrt(n->fMxy.Dy2() + t.GetCovariance(1, 1));
407 // pullt = dt / sqrt(n->fMt.Dt2() + n->fTrack.GetCovariance(5, 5));
408
409 for (auto& projection : fProjection) {
410 int scale = get<0>(projection.second);
411 TH2* hh = get<2>(projection.second);
412 if (!hh) continue;
413
414 switch (projection.first) {
415 case eProjectionType::kXYa: hh->Fill(n->fMxy.X(), n->fMxy.Y()); break;
416 case eProjectionType::kXYp: hh->Fill(t.X(), t.Y()); break;
417 case eProjectionType::kXdX: hh->Fill(n->fMxy.X(), scale * dx); break;
418 case eProjectionType::kYdY: hh->Fill(n->fMxy.Y(), scale * dy); break;
419 case eProjectionType::kWdT: hh->Fill(n->fMxy.X(), scale * dt); break;
420 case eProjectionType::kXpX: hh->Fill(n->fMxy.X(), pullx); break;
421 case eProjectionType::kYpY: hh->Fill(n->fMxy.Y(), pully); break;
422
423 default: break;
424 }
425
426 if (point) {
427 double dxMC = point->GetX() - t.X(), dyMC = point->GetY() - t.Y();
428
429 switch (projection.first) {
430 case eProjectionType::kXdXMC: hh->Fill(point->GetX(), scale * dxMC); break;
431 case eProjectionType::kYdYMC: hh->Fill(point->GetY(), scale * dyMC); break;
432 default: break;
433 }
434 }
435 }
436 return true;
437}
438
440{
441 for (auto& projection : fProjection) {
442 int scale = get<0>(projection.second);
443 TH2* hh = get<2>(projection.second);
444 if (!hh) continue;
445 switch (projection.first) {
447 if (int(p->Z()) == -124) hh->Fill(p->X(), p->Y());
448 break;
450 if (int(p->Z()) == 0) hh->Fill(scale * p->X(), scale * p->Y());
451 break;
452 // fall through
454 if (int(p->Z()) == 1) hh->Fill(scale * p->X(), scale * p->Y());
455 break;
456 // fall through
458 if (int(p->Z()) == 2) hh->Fill(scale * p->X(), scale * p->Y());
459 break;
460 // fall through
462 if (int(p->Z()) == 3) hh->Fill(scale * p->X(), scale * p->Y());
463 break;
464 // fall through
466 if (int(p->Z()) == 4) hh->Fill(scale * p->X(), scale * p->Y());
467 break;
468 // fall through
470 if (int(p->Z()) == 5) hh->Fill(scale * p->X(), scale * p->Y());
471 break;
472 // fall through
473 case eProjectionType::kPVxy: hh->Fill(scale * p->X(), scale * p->Y()); break;
474 case eProjectionType::kPVxz: hh->Fill(p->Z(), scale * p->X()); break;
475 case eProjectionType::kPVyz: hh->Fill(p->Z(), scale * p->Y()); break;
477 if (int(p->Z()) == -123) hh->Fill(scale * p->X(), scale * p->Y());
478 break;
479 default: break;
480 }
481 }
482 return true;
483}
484
485//_____________________________________________________________________
486
487void CbmRecoQaTask::Exec(Option_t*)
488{
489 LOG(info) << GetName() << "::Exec : Evs[" << (fEvents ? fEvents->GetEntriesFast() : 0) << "] Trks["
490 << (fGTracks ? fGTracks->GetEntriesFast() : 0) << "] Hits["
491 << (fHits[ECbmModuleId::kSts] ? fHits[ECbmModuleId::kSts]->GetEntriesFast() : 0) << " "
492 << (fHits[ECbmModuleId::kTrd] ? fHits[ECbmModuleId::kTrd]->GetEntriesFast() : 0) << " "
493 << (fHits[ECbmModuleId::kTof] ? fHits[ECbmModuleId::kTof]->GetEntriesFast() : 0) << "]";
494
495 // fixed momentum no magentic field for mCBM
498 int iev = 0, itrack = 0, nnodes = 0;
499 auto processHits = [&](CbmEvent* ev) {
500 for (auto& detp : fDetQa) {
501 auto& det = detp.second;
502 if (!fHits[det.id]) {
503 LOG(error) << GetName() << "::Exec() : Hits for " << ToString(det.id) << " not available. Skip.";
504 continue;
505 }
506
507 const int nh = (ev) ? max(int(0), int(ev->GetNofData(det.hit.id))) : fHits[det.id]->GetEntriesFast();
508 for (int ih = 0; ih < nh; ++ih) {
509 const int jh = (ev) ? ev->GetIndex(det.hit.id, ih) : ih;
510
511 const FairMCPoint* mcpoint = nullptr;
512 const CbmHit* hit = dynamic_cast<CbmHit*>(fHits[det.id]->At(jh));
513 if (!hit) {
514 LOG(warning) << GetName() << "::Exec() : Hit " << jh << " for " << ToString(det.id)
515 << " not available. Skip.";
516 continue;
517 }
518
519 if (fHitMatch[det.id] && fPoints[det.id]) {
520 if (det.id == ECbmModuleId::kRich) {
521 Int_t pointID = hit->GetRefId();
522 if (pointID >= 0) {
523 // mcpoint = dynamic_cast<FairMCPoint*>(fPoints[det.id]->At(pointID));
524 if (!mcpoint) continue;
525 }
526 }
527 else {
528 const CbmMatch* match = dynamic_cast<CbmMatch*>(fHitMatch[det.id]->At(jh));
529 if (match && match->GetNofLinks() > 0) {
530 const auto& link = match->GetMatchedLink();
531 if (ev) {
532 int file_id{0}, event_id{0};
533 if (ev && ev->GetMatch() && ev->GetMatch()->GetNofLinks() > 0) {
534 file_id = ev->GetMatch()->GetMatchedLink().GetFile();
535 event_id = ev->GetMatch()->GetMatchedLink().GetEntry();
536 }
537 else {
538 event_id = FairRootManager::Instance()->GetEntryNr();
539 }
540 if (link.GetFile() != file_id || link.GetEntry() != event_id) {
541 LOG(warn) << "match from different event";
542 }
543 }
544 mcpoint = dynamic_cast<FairMCPoint*>(fPoints[det.id]->Get(link));
545 }
546 }
547 }
548
549 bool ret(false);
550 for (auto& view : det.fViews) {
551 switch (det.id) {
552 case ECbmModuleId::kMvd: ret = view.Load<CbmMvdHit>(hit, mcpoint, ev); break;
553 case ECbmModuleId::kSts: ret = view.Load<CbmStsHit>(hit, mcpoint, ev); break;
554 case ECbmModuleId::kMuch: ret = view.Load<CbmMuchPixelHit>(hit, mcpoint, ev); break;
555 case ECbmModuleId::kRich: ret = view.Load<CbmRichHit>(hit, mcpoint, ev); break;
556 case ECbmModuleId::kTrd: ret = view.Load<CbmTrdHit>(hit, mcpoint, ev); break;
557 case ECbmModuleId::kTrd2d: ret = view.Load<CbmTrdHit>(hit, mcpoint, ev); break;
558 case ECbmModuleId::kTof: ret = view.Load<CbmTofHit>(hit, mcpoint, ev); break;
559 case ECbmModuleId::kFsd: ret = view.Load<CbmFsdHit>(hit, mcpoint, ev); break;
560 case ECbmModuleId::kPsd: ret = view.Load<CbmPsdHit>(hit, mcpoint, ev); break;
561 default: LOG(fatal) << GetName() << "::Exec : unsupported det " << ToString(det.id); break;
562 }
563 if (ret) break;
564 }
565 }
566 TVector3 mult;
567 for (auto& v : det.fViews) {
568 mult.SetXYZ(nh, double(v.fMult) / nh, -124);
569 v.Load(&mult);
570 v.fMult = 0;
571 }
572 }
573 };
574
575 auto processTracks = [&](CbmEvent* ev) {
576 const int ntrk = (ev) ? ev->GetNofData(ECbmDataType::kGlobalTrack) : fGTracks->GetEntriesFast();
577 // read in the vertex and the list of tracks used for its definition
578 TVector3 pvx, evx;
579 int ntrkDet[3] = {0};
580
581 CbmVertex* vx(nullptr);
582 int nTrkVx(0);
583 if (ev && fViews.find("vx") != fViews.end()) {
584 vx = ev->GetVertex();
585 nTrkVx = vx->GetNTracks();
586 auto& v = fViews["vx"];
587 if (nTrkVx >= 2) {
588 vx->Position(pvx);
589 for (int i(0); i < 3; i++) {
590 evx[i] = vx->GetCovariance(i, i);
591 if (evx[i] > 0.) evx[i] = sqrt(evx[i]);
592 }
593 v.Load(&pvx);
594 }
595 pvx.SetXYZ(ntrk, nTrkVx, -123);
596 v.Load(&pvx);
597 }
598 for (int itrk = 0; itrk < ntrk; ++itrk) {
599 int trkIdx = ev ? ev->GetIndex(ECbmDataType::kGlobalTrack, itrk) : itrk;
600 auto track = dynamic_cast<const CbmGlobalTrack*>((*fGTracks)[trkIdx]);
601 // track QA filtering
602 if (!FilterTrack(track)) continue;
603
604 if (nTrkVx >= 2) {
605 if (vx->FindTrackByIndex(trkIdx)) {
606 if (track->GetStsTrackIndex() >= 0) ntrkDet[0]++;
607 if (track->GetTrdTrackIndex() >= 0) ntrkDet[1]++;
608 if (track->GetTofTrackIndex() >= 0) ntrkDet[2]++;
609 }
610 }
611
613 if (!fFitter.CreateGlobalTrack(trkKf, *track)) {
614 LOG(fatal) << GetName() << "::Exec: can not create the track for the fit!";
615 break;
616 }
617 if (!nnodes) nnodes = trkKf.fNodes.size();
618 // minimalistic QA tool for tracks used for target projection
619 int nhit[(size_t) ECbmModuleId::kLastModule] = {0};
620 for (auto& n : trkKf.fNodes) {
621 // check if hit is well defined and detector is registered
622 if (n.fHitSystemId == ECbmModuleId::kNotExist || fDetQa.find(n.fHitSystemId) == fDetQa.end()) continue;
623 auto& det = fDetQa[n.fHitSystemId];
624 // det.Print();
625 auto view = det.FindView(n.fMxy.X(), n.fMxy.Y(), n.fZ);
626 if (!view) {
627 LOG(debug) << GetName() << "::Exec: view for tracking layer " << ToString(det.id) << " not defined.";
628 continue;
629 }
630 n.fIsTimeSet = n.fIsXySet = false;
631 fFitter.FitTrajectory(trkKf);
632
633 // match to MC
634 const CbmHit* hit = dynamic_cast<CbmHit*>(fHits[n.fHitSystemId]->At(n.fHitIndex));
635 if (!hit) continue;
636 const FairMCPoint* mcpoint = nullptr;
637
638 if (fHitMatch[n.fHitSystemId] && fPoints[n.fHitSystemId]) {
639 if (n.fHitSystemId == ECbmModuleId::kRich) {
640 Int_t pointID = hit->GetRefId();
641 if (pointID >= 0) {
642 // mcpoint = dynamic_cast<FairMCPoint*>(fPoints[n.fHitSystemId]->At(pointID));
643 }
644 }
645 else {
646 const CbmMatch* match = dynamic_cast<CbmMatch*>(fHitMatch[n.fHitSystemId]->At(n.fHitIndex));
647 if (match && match->GetNofLinks() > 0) {
648 const auto& link = match->GetMatchedLink();
649 mcpoint = dynamic_cast<FairMCPoint*>(fPoints[n.fHitSystemId]->Get(link));
650 }
651 }
652 }
653
654 view->Load(&n, mcpoint);
655 nhit[(int) n.fHitSystemId]++;
656 n.fIsTimeSet = n.fIsXySet = true;
657 }
658
659 // Fit track with all hits ON for track projections
660 if (!nnodes) nnodes = (int) trkKf.fNodes.size();
661 if (fViews.find("prj") != fViews.end()) {
662 auto v = fViews["prj"];
663 if (v.fType != eViewType::kTrkProj)
664 LOG(error) << GetName() << "::Exec: view for track projection with wrong type. Skipping.";
665 else {
666 int iprj(0);
667 for (auto plane : fPrjPlanes) {
669 n.fZ = plane.Z();
670 n.fIsXySet = true;
671 n.fReference1 = iprj++;
672 trkKf.fNodes.push_back(n);
673 }
674 trkKf.OrderNodesInZ();
675 fFitter.FitTrajectory(trkKf);
676
677 TVector3 xyz;
678 for (auto& n : trkKf.fNodes) {
679 if (n.fReference1 < 0) continue;
680 xyz.SetXYZ(n.fParamUp.X(), n.fParamUp.Y(), n.fReference1); // to communicate to the Load function
681 v.Load(&xyz);
682 }
683 }
684 // if (mod->hdYy.second) mod->hdYy.second->Fill(mod->hdYy.first *
685 // n.fTrack.X()[0], n.fTrack.Time()[0]);
686 }
687 itrack++;
688 }
689 };
690
691 if (fEvents) {
692 for (auto evObj : *fEvents) {
693 auto ev = dynamic_cast<CbmEvent*>(evObj);
694 if (!FilterEvent(ev)) continue;
695 processHits(ev);
696 if (fGTracks) processTracks(ev);
697 iev++;
698 }
699 LOG(info) << GetName() << "::Exec : Evs(%)["
700 << (fEvents->GetEntriesFast() ? 1.e2 * iev / fEvents->GetEntriesFast() : 0) << "] Trks(%)["
701 << (fGTracks && fGTracks->GetEntriesFast() ? 1.e2 * itrack / fGTracks->GetEntriesFast() : 0) << "]";
702 return; // END EbyE QA
703 }
704 else {
705
706 processHits(nullptr);
707
708 if (!fGTracks) {
709 LOG(info) << GetName() << "::Exec : TS local reco only.";
710 return; // END TS QA (no tracking)
711 }
712
713 processTracks(nullptr);
714 }
715 LOG(info) << GetName() << "::Exec : Trks(%)["
716 << (fGTracks && fGTracks->GetEntriesFast() ? 1.e2 * itrack / fGTracks->GetEntriesFast() : 0) << "]";
717 return;
718}
719
720//_____________________________________________________________________
722{
723 int n(0);
724 for (auto v : fViews) {
725 if (v.second.fType != type) continue;
726 n++;
727 }
728 return n;
729}
730
731
732//_____________________________________________________________________
734{
735 FairSink* sink = FairRootManager::Instance()->GetSink();
736 sink->WriteObject(&fOutFolder, nullptr);
737}
738
739//_____________________________________________________________________
741{
742 // sanity checks
743 if (ptr->GetStartTime() < 0) return false; // this is found in MC
744
745 for (auto evCut : fFilterEv) {
746 if (!evCut.Accept(ptr, this)) return false;
747 }
748 return true;
749}
750
751//_____________________________________________________________________
753{
754 for (auto trkCut : fFilterTrk) {
755 if (!trkCut.Accept(ptr, this)) return false;
756 }
757 return true;
758}
759
760//_____________________________________________________________________
761TString CbmRecoQaTask::GetGeoTagForDetector(const TString& detector)
762{
763 gGeoManager->CdTop();
764 TGeoNode* cave = gGeoManager->GetCurrentNode();
765 if (!cave) {
766 LOG(error) << "Error: Could not get the top node in the geometry manager." << std::endl;
767 return "";
768 }
769
770 for (Int_t iNode = 0; iNode < cave->GetNdaughters(); iNode++) {
771 TString name = cave->GetDaughter(iNode)->GetVolume()->GetName();
772 if (name.Contains(detector, TString::kIgnoreCase)) {
773 return name.Contains("mcbm", TString::kIgnoreCase) ? TString(name(5, name.Length()))
774 : TString(name(5, name.Length() - 5));
775 }
776 }
777 return "";
778}
779
780//_____________________________________________________________________
781std::vector<TString> CbmRecoQaTask::GetPath(TGeoNode* node, TString detector, TString activeNodeName, int depth,
782 const TString& path)
783{
784 std::vector<TString> nodePaths;
785
786 if (!node) {
787 return nodePaths;
788 }
789
790 TString nodePath = path;
791 if (!nodePath.IsNull()) {
792 nodePath += "/";
793 }
794 nodePath += node->GetName();
795
796 if (TString(node->GetName()).Contains(activeNodeName)) {
797 if (nodePath.Contains(detector)) nodePaths.push_back(nodePath);
798 }
799
800 // Recursively traverse the daughters
801 Int_t numDaughters = node->GetNdaughters();
802 for (Int_t i = 0; i < numDaughters; ++i) {
803 TGeoNode* daughterNode = node->GetDaughter(i);
804
805 std::vector<TString> result = GetPath(daughterNode, detector, activeNodeName, depth + 1, nodePath);
806 nodePaths.insert(nodePaths.end(), result.begin(), result.end());
807 }
808
809 return nodePaths;
810}
811//_____________________________________________________________________
813{
814 CbmSetup* setup = CbmSetup::Instance();
815 if (!setup) {
816 LOG(fatal) << GetName() << "::InitMcbm22() : Missing setup definition.";
817 return;
818 }
819 // fixed momentum no magentic field for mCBM
822
823 View* v = nullptr;
824
825 std::vector<TString> path;
826 TGeoNode* topNode = gGeoManager->GetTopNode();
827 if (!topNode) {
828 LOG(error) << "Error: Top node not found.";
829 return;
830 }
831
832 auto processDetector = [&](const std::string& detector, const std::string& component) {
833 TString geoTag = GetGeoTagForDetector(detector);
834
835 if (geoTag.Length() > 0) {
836 LOG(info) << detector << ": geometry tag is " << geoTag;
837 }
838 else {
839 LOG(warn) << "Warning: No geometry tag found for detector " << detector;
840 }
841
842 path = GetPath(topNode, detector, component, 0);
843 };
844
845 if (setup->IsActive(ECbmModuleId::kSts)) {
846
847 processDetector("sts", "Sensor");
848
849 std::regex pattern("/Station(\\d+)_(\\d+)/Ladder(\\d+)_(\\d+)/HalfLadder\\d+d_(\\d+)/"
850 "HalfLadder\\d+d_Module(\\d+)_(\\d+)/Sensor(\\d+)_(\\d+)");
851
853 for (const auto& str : path) {
854 std::string Str(str.Data());
855 std::smatch match;
856 if (std::regex_search(Str, match, pattern)) {
857 int station = std::stoi(match[2]);
858 int ladder = std::stoi(match[4]);
859 int module = std::stoi(match[7]);
860
861 const char* fType = Form("U%dL%dM%d", station - 1, ladder - 1, module - 1);
862
863 v = sts->AddView(fType, str.Data(), {station - 1, ladder - 1, module - 1});
864 v->SetProjection(eProjectionType::kXdX, (station == 1) ? 1 : 0.75, "mm");
865 v->SetProjection(eProjectionType::kYdY, (station == 1) ? 4 : 3, "mm");
866 if (fuRecoConfig[kUseMC]) {
867 v->SetProjection(eProjectionType::kXdXMC, 1, "mm");
868 v->SetProjection(eProjectionType::kYdYMC, 3, "mm");
869 v->SetProjection(eProjectionType::kResidualX, 200, "um");
870 v->SetProjection(eProjectionType::kResidualY, 500, "um");
871 }
872 }
873 else {
874 std::cout << "No match found in string: " << str << std::endl;
875 }
876 }
877 }
878
879 if (setup->IsActive(ECbmModuleId::kTrd)) {
880 processDetector("trd", "module");
881
882 // Trd2d
884
885 for (const auto& str : path) {
886 if (!str.Contains("module9")) continue;
887 v = trd->AddView("2D", str.Data(), {5});
889 v->SetProjection(eProjectionType::kXdX, 10, "mm");
890 v->SetProjection(eProjectionType::kYdY, 20, "mm");
891 if (fuRecoConfig[kUseMC]) {
892 v->SetProjection(eProjectionType::kXdXMC, 10, "mm");
893 v->SetProjection(eProjectionType::kYdYMC, 20, "mm");
894 v->SetProjection(eProjectionType::kResidualX, 1.5, "mm");
895 v->SetProjection(eProjectionType::kResidualY, 5.0, "mm");
896 }
897 }
898 // Trd1DxDy
900 for (const auto& str : path) {
901 LOG(info) << str;
902 if (str.Contains("layer02")) {
903 v = trd->AddView("1Dx", str.Data(), {21});
905 v->SetProjection(eProjectionType::kXdX, 1.5, "cm");
906 if (fuRecoConfig[kUseMC]) {
907 v->SetProjection(eProjectionType::kXdXMC, 1.5, "cm");
908 v->SetProjection(eProjectionType::kResidualX, 1.5, "mm");
909 }
910 }
911 if (str.Contains("layer03")) {
912 v = trd->AddView("1Dy", str.Data(), {37});
914 v->SetProjection(eProjectionType::kYdY, 1.5, "cm");
915 if (fuRecoConfig[kUseMC]) {
916 v->SetProjection(eProjectionType::kYdYMC, 1.5, "cm");
917 v->SetProjection(eProjectionType::kResidualY, 1.5, "mm");
918 }
919 }
920 }
921 }
922
923
924 if (setup->IsActive(ECbmModuleId::kTof)) {
925 processDetector("tof", "counter");
926
928 tof->hit.name = "TofHit";
929 std::regex pattern("module_(\\d+)_(\\d+)/gas_box_(\\d+)/counter_(\\d+)");
930
931 for (const auto& str : path) {
932 std::string Str(str.Data());
933 std::smatch match;
934 if (std::regex_search(Str, match, pattern)) {
935 int type = std::stoi(match[1]);
936 int smid = std::stoi(match[2]);
937 int rpc = std::stoi(match[4]);
938 const char* name = Form("Sm%d_%dRpc%d", type, smid, rpc);
939 if (type == 0) {
940 v = tof->AddView(name, str.Data(), {smid, type, rpc});
942 }
943 else {
944 v = tof->AddView(name, str.Data(), {smid, type, rpc});
945 }
946 }
947 else {
948 std::cout << "No match found in string: " << str << std::endl;
949 }
950 }
951 }
952 // ===============================================================================
953 // TRG - upstream projections
954 float angle = 25., L[] = {14.3, 0, -20, -38 /*-1*/, -50.5 /*-4.1*/};
955 //R[]= {2.5, 3, 0.5, 0.6, 0.6}, dx[5], dz[5];
956 for (int i(0); i < 5; i++) {
957 fPrjPlanes.emplace_back(L[i] * TMath::Sin(angle * TMath::DegToRad()), 0.,
958 L[i] * TMath::Cos(angle * TMath::DegToRad()));
959 }
960 // (cm); T_{trk} - T_{ev} (ns)", prj.first),
961}
962
963//_____________________________________________________________________
965{
966 CbmSetup* setup = CbmSetup::Instance();
967 if (!setup) {
968 LOG(fatal) << GetName() << "::InitMcbm24() : Missing setup definition.";
969 return;
970 }
971 // fixed momentum no magentic field for mCBM
974
975 TString dtag;
976 View* v(nullptr);
977 if (setup->IsActive(ECbmModuleId::kSts)) {
978 // setup->GetGeoTag(ECbmModuleId::kSts, dtag);
979 // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag;
980 dtag = "v24c_mcbm";
982 // U0 L0 M0
983 v = sts->AddView("U0L0M0",
984 Form("/cave_1/sts_%s_0/Station01_1/Ladder13_1/"
985 "HalfLadder13u_1/HalfLadder13u_Module03_1/Sensor03_1",
986 dtag.Data()),
987 {0, 0, 0});
989 v->SetProjection(eProjectionType::kXdX, 500, "um");
990 // U1 L0 M0
991 v = sts->AddView("U1L0M0",
992 Form("/cave_1/sts_%s_0/Station02_2/Ladder09_1/"
993 "HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1",
994 dtag.Data()),
995 {1, 0, 0});
997 v->SetProjection(eProjectionType::kXdX, 500, "um");
998 v = sts->AddView("U1L0M1",
999 Form("/cave_1/sts_%s_0/Station02_2/Ladder09_1/"
1000 "HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1",
1001 dtag.Data()),
1002 {1, 0, 1});
1004 v->SetProjection(eProjectionType::kXdX, 500, "um");
1005 // U1 L1
1006 v = sts->AddView("U1L1M0",
1007 Form("/cave_1/sts_%s_0/Station02_2/Ladder09_2/"
1008 "HalfLadder09d_2/HalfLadder09d_Module03_1/Sensor03_1",
1009 dtag.Data()),
1010 {1, 1, 0});
1012 v->SetProjection(eProjectionType::kXdX, 500, "um");
1013 v = sts->AddView("U1L1M1",
1014 Form("/cave_1/sts_%s_0/Station02_2/Ladder09_2/"
1015 "HalfLadder09d_2/HalfLadder09d_Module03_2/Sensor03_1",
1016 dtag.Data()),
1017 {1, 1, 1});
1019 v->SetProjection(eProjectionType::kXdX, 500, "um");
1020 // U2 L0
1021 v = sts->AddView("U2L0M0",
1022 Form("/cave_1/sts_%s_0/Station03_3/Ladder10_1/"
1023 "HalfLadder10d_2/HalfLadder10d_Module03_1/Sensor03_1",
1024 dtag.Data()),
1025 {2, 0, 0});
1027 v->SetProjection(eProjectionType::kXdX, 500, "um");
1028 v = sts->AddView("U2L0M1",
1029 Form("/cave_1/sts_%s_0/Station03_3/Ladder10_1/"
1030 "HalfLadder10d_2/HalfLadder10d_Module04_2/Sensor04_1",
1031 dtag.Data()),
1032 {2, 0, 1});
1034 v->SetProjection(eProjectionType::kXdX, 500, "um");
1035 // U2 L1
1036 v = sts->AddView("U2L1M0",
1037 Form("/cave_1/sts_%s_0/Station03_3/Ladder12_2/"
1038 "HalfLadder12d_2/HalfLadder12d_Module03_1/Sensor03_1",
1039 dtag.Data()),
1040 {2, 1, 0});
1042 v->SetProjection(eProjectionType::kXdX, 500, "um");
1043 v = sts->AddView("U2L1M1",
1044 Form("/cave_1/sts_%s_0/Station03_3/Ladder12_2/"
1045 "HalfLadder12d_2/HalfLadder12d_Module04_2/Sensor04_1",
1046 dtag.Data()),
1047 {2, 1, 1});
1049 v->SetProjection(eProjectionType::kXdX, 500, "um");
1050 // U2 L2
1051 v = sts->AddView("U2L2M0",
1052 Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/"
1053 "HalfLadder11d_2/HalfLadder11d_Module03_1/Sensor03_1",
1054 dtag.Data()),
1055 {2, 2, 0});
1057 v->SetProjection(eProjectionType::kXdX, 500, "um");
1058 v = sts->AddView("U2L2M1",
1059 Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/"
1060 "HalfLadder11d_2/HalfLadder11d_Module03_2/Sensor03_1",
1061 dtag.Data()),
1062 {2, 2, 1});
1063 v = sts->AddView("U2L2M2",
1064 Form("/cave_1/sts_%s_0/Station03_3/Ladder11_3/"
1065 "HalfLadder11d_2/HalfLadder11d_Module03_3/Sensor03_1",
1066 dtag.Data()),
1067 {2, 2, 2});
1069 v->SetProjection(eProjectionType::kXdX, 500, "um");
1070 }
1071 if (setup->IsActive(ECbmModuleId::kTrd)) {
1072 // setup->GetGeoTag(ECbmModuleId::kTrd, dtag);
1073 // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag;
1074 dtag = "v24e_mcbm";
1076 // Trd2D
1077 v = trd->AddView("2D", Form("/cave_1/trd_%s_0/layer01_20101/module9_101001001/gas_0", dtag.Data()), {5});
1079 // Trd1Dx
1081 v = trd->AddView("1Dx", Form("/cave_1/trd_%s_0/layer02_10202/module5_101002001", dtag.Data()), {21});
1083 v->SetProjection(eProjectionType::kXdX, 1.5, "cm");
1084 v->SetProjection(eProjectionType::kYdY, 3.0, "cm");
1085 // Trd1Dy
1086 v = trd->AddView("1Dy", Form("/cave_1/trd_%s_0/layer03_11303/module5_101103001", dtag.Data()), {37});
1088 v->SetProjection(eProjectionType::kXdX, 1.5, "cm");
1089 v->SetProjection(eProjectionType::kYdY, 3.0, "cm");
1090 }
1091 if (setup->IsActive(ECbmModuleId::kTof)) {
1092 // setup->GetGeoTag(ECbmModuleId::kTof, dtag);
1093 // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag;
1094 dtag = "v24d_mcbm";
1096 vector<int> tofSelect(3);
1097 // add type 0
1098 for (int ism(0); ism < 6; ism++) {
1099 tofSelect[0] = ism;
1100 for (int irpc(0); irpc < 5; irpc++) {
1101 tofSelect[2] = irpc;
1102 v = tof->AddView(Form("Sm%dRpc%d", ism, irpc),
1103 Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/"
1104 "gas_box_0/counter_%d",
1105 dtag.Data(), dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]),
1106 tofSelect);
1108 v->SetProjection(eProjectionType::kYdY, 1, "cm");
1109 }
1110 }
1111 // add type 6 (Buch)
1112 tofSelect[0] = 0;
1113 tofSelect[1] = 6;
1114 for (int irpc(0); irpc < 2; irpc++) {
1115 tofSelect[2] = irpc;
1116 tof->AddView(Form("BuchRpc%d", irpc),
1117 Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/gas_box_0/"
1118 "counter_%d",
1119 dtag.Data(), dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]),
1120 tofSelect);
1121 }
1122 // add type 9
1123 tofSelect[1] = 9;
1124 for (int ism(0); ism < 2; ism++) {
1125 tofSelect[0] = ism;
1126 for (int irpc(0); irpc < 2; irpc++) {
1127 tofSelect[2] = irpc;
1128 tof->AddView(Form("Test%dRpc%d", ism, irpc),
1129 Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/"
1130 "gas_box_0/counter_%d",
1131 dtag.Data(), dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]),
1132 tofSelect);
1133 }
1134 }
1135 // add type 2
1136 tofSelect[1] = 2;
1137 for (int ism(0); ism < 2; ism++) {
1138 tofSelect[0] = ism;
1139 for (int irpc(0); irpc < 5; irpc++) {
1140 tofSelect[2] = irpc;
1141 tof->AddView(Form("Sm2%dRpc%d", ism, irpc),
1142 Form("/cave_1/tof_%s_0/tof_%sStand_1/module_%d_%d/"
1143 "gas_box_0/counter_%d",
1144 dtag.Data(), dtag.Data(), tofSelect[1], tofSelect[0], tofSelect[2]),
1145 tofSelect);
1146 }
1147 }
1148 }
1149 if (setup->IsActive(ECbmModuleId::kRich)) {
1150 // setup->GetGeoTag(ECbmModuleId::kRich, dtag);
1151 // LOG(debug) << GetName() << "::InitMcbm24() : found " << dtag;
1152 dtag = "v24a_mcbm";
1154 // Aerogel 1
1155 rich->AddView("Aerogel", Form("/cave_1/rich_%s_0/box_1/Gas_1", dtag.Data()), {4});
1156 }
1157 // ===============================================================================
1158 // TRG - upstream projections
1159 float angle = 25., L[] = {14.3, 0, -20, -38, -50.5};
1160 //R[]= {2.5, 3, 0.5, 0.6, 0.6}, dx[5], dz[5];
1161 for (int i(0); i < 5; i++) {
1162 fPrjPlanes.emplace_back(L[i] * TMath::Sin(angle * TMath::DegToRad()), 0.,
1163 L[i] * TMath::Cos(angle * TMath::DegToRad()));
1164 }
1165}
1166//_____________________________________________________________________
1168{
1169 LOG(info) << "Init Default ....";
1170 CbmSetup* setup = CbmSetup::Instance();
1171 if (!setup) {
1172 LOG(fatal) << GetName() << "::InitDefault() : Missing setup definition.";
1173 return;
1174 }
1175
1176 View* v = nullptr;
1177 std::vector<TString> path;
1178 TGeoNode* topNode = gGeoManager->GetTopNode();
1179 if (!topNode) {
1180 LOG(error) << "Error: Top node not found.";
1181 return;
1182 }
1183
1184 TString geoTag;
1185 auto processDetector = [&](const std::string& detector, const std::string& component) {
1186 geoTag = GetGeoTagForDetector(detector);
1187
1188 if (geoTag.Length() > 0) {
1189 LOG(info) << detector << ": geometry tag is " << geoTag;
1190 }
1191 else {
1192 LOG(warn) << "Warning: No geometry tag found for detector " << detector;
1193 }
1194 path = GetPath(topNode, detector, component, 0);
1195 };
1196
1197 if (setup->IsActive(ECbmModuleId::kSts)) {
1198 processDetector("sts", "Unit");
1199
1200 // std::regex pattern("Unit\\d{2}[LR]_\\d+");
1201 std::regex pattern(R"(Unit(\d{2}[LR])_(\d+))");
1202
1204
1205 for (const auto& str : path) {
1206 std::string Str(str.Data());
1207 std::smatch match;
1208
1209 if (std::regex_search(Str, match, pattern)) {
1210 int unitid = std::stoi(match[2].str());
1211 std::string unitname = (Str.find("Unit") != std::string::npos) ? Str.substr(Str.find("Unit")) : "";
1212
1213 v = sts->AddView(unitname.c_str(), str.Data(), {unitid - 1, -1, -1});
1215 }
1216 else {
1217 std::cout << "No match found in string: " << str << std::endl;
1218 }
1219 }
1220 }
1221
1222 if (setup->IsActive(ECbmModuleId::kTrd)) {
1223 processDetector("trd", "module");
1224 std::regex pattern("layer(\\d+)_(\\d+)/module(\\d+)_(\\d+)");
1226 char name[256];
1227 for (const auto& str : path) {
1228 std::string Str(str.Data());
1229 std::smatch match;
1230 if (std::regex_search(Str, match, pattern)) {
1231 int layer = std::stoi(match[1]);
1232 int layercopyNr = std::stoi(match[2]);
1233
1234 int module = std::stoi(match[3]);
1235 int modulecopyNr = std::stoi(match[4]);
1236
1237 int fLayer = ((layercopyNr / 100) % 10);
1238 int fModuleCopy = (modulecopyNr % 100);
1239
1240 sprintf(name, "layer%d_%d_module_%d_%d", layer, layercopyNr, module, modulecopyNr);
1241
1242 v = trd->AddView(name, str.Data(), {fLayer - 1, fModuleCopy - 1, -1});
1244 }
1245 else {
1246 std::cout << "No match found in string: " << str << std::endl;
1247 }
1248 }
1249 }
1250
1251 if (setup->IsActive(ECbmModuleId::kRich)) {
1252 processDetector("rich", "sens");
1254 for (const auto& str : path) {
1255 v = rich->AddView("rich", str.Data(), {-1, -1, -1});
1257 }
1258 }
1259
1260 if (setup->IsActive(ECbmModuleId::kTof)) {
1261 processDetector("tof", "module");
1262
1264 tof->hit.name = "TofHit";
1265 std::regex pattern("module_(\\d+)_(\\d+)");
1266 for (const auto& str : path) {
1267 std::string Str(str.Data());
1268 std::smatch match;
1269 if (std::regex_search(Str, match, pattern)) {
1270 int type = std::stoi(match[1]);
1271 int smid = std::stoi(match[2]);
1272
1273 std::string modulename = (Str.find("module") != std::string::npos) ? Str.substr(Str.find("module")) : "";
1274
1275 v = tof->AddView(modulename.c_str(), str.Data(), {smid, type, -1});
1277 }
1278 else {
1279 std::cout << "No match found in string: " << str << std::endl;
1280 }
1281 }
1282 }
1283}
1284
1285//========= DETECTOR ======================
1287{
1288 id = did;
1289 switch (id) {
1290 case ECbmModuleId::kMvd:
1291 new (&hit) Data(ECbmDataType::kMvdHit, "MvdHit");
1292 new (&point) Data(ECbmDataType::kMvdPoint, "MvdPoint");
1293 break;
1294 case ECbmModuleId::kSts:
1295 new (&hit) Data(ECbmDataType::kStsHit, "StsHit");
1296 new (&point) Data(ECbmDataType::kStsPoint, "StsPoint");
1297 new (&trk) Data(ECbmDataType::kStsTrack, "StsTrack");
1298 break;
1300 new (&hit) Data(ECbmDataType::kMuchPixelHit, "MuchHit");
1301 new (&point) Data(ECbmDataType::kMuchPoint, "MuchPoint");
1302 break;
1304 new (&hit) Data(ECbmDataType::kRichHit, "RichHit");
1305 new (&point) Data(ECbmDataType::kRichPoint, "RichPoint");
1306 break;
1307 case ECbmModuleId::kTrd:
1309 new (&hit) Data(ECbmDataType::kTrdHit, "TrdHit");
1310 new (&point) Data(ECbmDataType::kTrdPoint, "TrdPoint");
1311 new (&trk) Data(ECbmDataType::kTrdTrack, "TrdTrack");
1312 break;
1313 case ECbmModuleId::kTof:
1314 new (&hit) Data(ECbmDataType::kTofHit, "TofHit");
1315 new (&point) Data(ECbmDataType::kTofPoint, "TofPoint");
1316 new (&trk) Data(ECbmDataType::kTofTrack, "TofTrack");
1317 break;
1318 case ECbmModuleId::kFsd:
1319 new (&hit) Data(ECbmDataType::kFsdHit, "FsdHit");
1320 new (&point) Data(ECbmDataType::kFsdHit, "FsdPoint");
1321 break;
1322 case ECbmModuleId::kPsd:
1323 new (&hit) Data(ECbmDataType::kPsdHit, "PsdHit");
1324 new (&point) Data(ECbmDataType::kPsdPoint, "PsdPoint");
1325 break;
1326 default:
1327 LOG(warn) << "QA unsupported for Detector=" << ToString(did);
1329 break;
1330 }
1331}
1332
1333//+++++++++++++++++++++ Detector ++++++++++++++++++++++++++++++++
1334//_________________________________________________________________
1335CbmRecoQaTask::View* CbmRecoQaTask::Detector::AddView(const char* n, const char* p, std::vector<int> set)
1336{
1337 View* v(nullptr);
1338 fViews.emplace_back(n, p, set);
1339 v = &fViews.back();
1351
1361
1362 return v;
1363}
1364
1366{
1367 for (auto& view : fViews)
1368 if (view.name.compare(n) == 0) return &view;
1369
1370 return nullptr;
1371}
1372
1374{
1375 for (auto& v : fViews) {
1376 // printf("Looking for p[%f %f %f] in V[%s-%s] @ %f %f %f (%f %f %f)\n", x,
1377 // y, z, ToString(id).data(), v.name.data(), v.pos[0], v.pos[1], v.pos[2],
1378 // v.size[0], v.size[1], v.size[2]);
1379 if (abs(v.pos[0] - x) > 0.5 * v.size[0]) continue;
1380 if (abs(v.pos[1] - y) > 0.5 * v.size[1]) continue;
1381 if (abs(v.pos[2] - z) > 0.5 * v.size[2]) continue;
1382 return &v;
1383 }
1384
1385 return nullptr;
1386}
1387
1388bool CbmRecoQaTask::Detector::Init(TDirectoryFile* fOut, bool mc)
1389{
1390 /* Query the geometry and trigger detector views init
1391 */
1392 if (!gGeoManager) {
1393 LOG(fatal) << "CbmRecoQaTask::Detector::Init() " << ToString(id) << " missing geometry.";
1394 return false;
1395 }
1396 //LOG(debug) << "CbmRecoQaTask::Detector::Init() : " << ToString(id);
1397 LOG(info) << "CbmRecoQaTask::Detector::Init() : " << ToString(id) << " MC = " << mc;
1398
1399 TDirectoryFile* modDir =
1400 (TDirectoryFile*) fOut->mkdir(ToString(id).data(), Form("Reco QA for %s", ToString(id).data()));
1401 bool ret(true);
1402 for (auto& view : fViews) {
1403 bool vret = view.Init(ToString(id).data(), mc);
1404 view.Register(modDir);
1405 ret = ret && vret;
1406 }
1407 return ret;
1408}
1409
1411{
1412 stringstream s;
1413 s << "D[" << ToString(id) << "] views[" << fViews.size() << "]\n";
1414 for (auto v : fViews)
1415 s << v.ToString();
1416 cout << s.str();
1417}
1418
1419//+++++++++++++++++++++ View ++++++++++++++++++++++++++++++++
1420//_______________________________________________________________________
1421bool CbmRecoQaTask::View::AddProjection(eProjectionType prj, float range, const char* unit)
1422{
1423 if (fProjection.find(prj) != fProjection.end()) {
1424 LOG(warn) << "Projection " << ToString(prj) << " already registered";
1425 return false;
1426 }
1427 int scale(1);
1428 if (strcmp(unit, "mm") == 0)
1429 scale = 10;
1430 else if (strcmp(unit, "um") == 0)
1431 scale = 10000;
1432 else if (strcmp(unit, "ps") == 0)
1433 scale = 1000;
1434 else if (strcmp(unit, "eV") == 0)
1435 scale = 1000;
1436 else if (strcmp(unit, "cm") == 0)
1437 scale = 1;
1438 else if (strcmp(unit, "ns") == 0)
1439 scale = 1;
1440 else if (strcmp(unit, "keV") == 0)
1441 scale = 1;
1442 else if (strcmp(unit, "a.u.") == 0)
1443 scale = 1;
1444 else
1445 LOG(warn) << "Projection units " << unit << " not registered. Natural units will be used.";
1446
1447 fProjection[prj] = make_tuple(scale, range, nullptr);
1448 return true;
1449}
1450
1451bool CbmRecoQaTask::View::SetProjection(eProjectionType prj, float range, const char* unit)
1452{
1453 if (fProjection.find(prj) == fProjection.end()) {
1454 LOG(warn) << "Projection " << ToString(prj)
1455 << " not initialized. Calling "
1456 "\"CbmRecoQaTask::View::AddProjection()\"";
1457 return AddProjection(prj, range, unit);
1458 }
1459 int scale(1);
1460 if (strcmp(unit, "mm") == 0)
1461 scale = 10;
1462 else if (strcmp(unit, "um") == 0)
1463 scale = 10000;
1464 else if (strcmp(unit, "ps") == 0)
1465 scale = 1000;
1466 else if (strcmp(unit, "eV") == 0)
1467 scale = 1000;
1468 else if (strcmp(unit, "cm") == 0)
1469 scale = 1;
1470 else if (strcmp(unit, "ns") == 0)
1471 scale = 1;
1472 else if (strcmp(unit, "keV") == 0)
1473 scale = 1;
1474 else if (strcmp(unit, "a.u.") == 0)
1475 scale = 1;
1476 else
1477 LOG(warn) << "Projection units " << unit << " not registered. Natural units will be used.";
1478
1479 get<0>(fProjection[prj]) = scale;
1480 get<1>(fProjection[prj]) = range;
1481 return true;
1482}
1483
1484bool CbmRecoQaTask::View::Init(const char* dname, bool mc)
1485{
1490 if (path.size() && fType == eViewType::kDetUnit) { // applies only for detection units
1491 if (!gGeoManager->cd(path.data())) return false;
1492 TGeoHMatrix* m = gGeoManager->GetCurrentMatrix();
1493 const double* tr(m->GetTranslation());
1494 TGeoVolume* v = gGeoManager->GetCurrentVolume();
1495 TGeoShape* bb = v->GetShape();
1496 double w_lo, w_hi;
1497 for (int i(0); i < 3; i++) { // loop over the spatial dimensions
1498 size[i] = bb->GetAxisRange(i + 1, w_lo, w_hi);
1499 pos[i] = 0.5 * (w_lo + w_hi) + tr[i];
1500 }
1501
1502 LOG(info) << "CbmRecoQaTask::Detector(" << dname << ")::View(" << name << ")::Init() : size [" << size[0] << " x "
1503 << size[1] << " x " << size[2] << "]. mc[" << mc << "].";
1504 }
1505 else
1506 LOG(info) << "CbmRecoQaTask::Detector(" << dname << ")::View(" << name << ")::Init() : mc[" << mc << "].";
1507
1508
1509 // TODO short-hand for XY display resolution
1510 int dscale = 10;
1511 if (strcmp(dname, "Tof") == 0 || strcmp(dname, "Rich") == 0) dscale = 1;
1512
1513 int nbinsx, nbinsy;
1514 string unit;
1515 for (auto& projection : fProjection) {
1516 int scale = get<0>(projection.second);
1517 float yrange = get<1>(projection.second);
1518 char xy_id = 0;
1519 char mc_id[2] = {' ', ' '};
1520 double xlo = pos[0] - 0.5 * size[0], xhi = pos[0] + 0.5 * size[0], ylo = pos[1] - 0.5 * size[1],
1521 yhi = pos[1] + 0.5 * size[1];
1522 switch (projection.first) {
1524 if (!mc) break;
1525 xy_id = 'M';
1526 mc_id[0] = 'M';
1527 mc_id[1] = 'C';
1528 // fall through
1530 if (!xy_id) xy_id = 't';
1531 nbinsx = 10 * ceil(size[0]); // mm binning
1532 unit = makeYrange(scale, yrange);
1533 nbinsy = 200; //* ceil(yrange);
1534 get<2>(projection.second) =
1535 new TH2D(Form("hxx%s_%s%s", (xy_id == 'M' ? "MC" : ""), dname, name.data()),
1536 Form("X resolution %s %s [%s]; X^{%s}_{%s-%s} (cm); #Delta X (%s)", (xy_id == 'M' ? "MC" : ""),
1537 name.data(), dname, mc_id, dname, name.data(), unit.data()),
1538 nbinsx, xlo, xhi, nbinsy, -yrange, yrange);
1539 break;
1540
1542 if (!mc) break;
1543 xy_id = 'M';
1544 mc_id[0] = 'M';
1545 mc_id[1] = 'C';
1546 // fall through
1548 if (!xy_id) xy_id = 't';
1549 nbinsx = 10 * ceil(size[1]); // mm binning
1550 unit = makeYrange(scale, yrange);
1551 nbinsy = 200; //* ceil(yrange);
1552 get<2>(projection.second) =
1553 new TH2D(Form("hyy%s_%s%s", (xy_id == 'M' ? "MC" : ""), dname, name.data()),
1554 Form("Y resolution %s %s [%s]; Y^{%s}_{%s-%s} (cm); #Delta Y (%s)", (xy_id == 'M' ? "MC" : ""),
1555 name.data(), dname, mc_id, dname, name.data(), unit.data()),
1556 nbinsx, ylo, yhi, nbinsy, -yrange, yrange);
1557 break;
1558
1560 nbinsx = 10 * ceil(size[0]); // mm binning
1561 if (yrange < 0) {
1562 LOG(debug) << "ProjectionP[" << name << "] using default range.";
1563 yrange = 5; // +- 5 sigma range
1564 }
1565 nbinsy = 200; //* ceil(yrange);
1566 get<2>(projection.second) =
1567 new TH2D(Form("hpx_%s%s", dname, name.data()),
1568 Form("X pulls %s [%s]; X^{%s}_{%s-%s} (cm); pull(X)", name.data(), dname, mc_id, dname, name.data()),
1569 nbinsx, xlo, xhi, nbinsy, -yrange, yrange);
1570 break;
1571
1573 nbinsx = 10 * ceil(size[1]); // mm binning
1574 if (yrange < 0) {
1575 LOG(debug) << "ProjectionP[" << name << "] using default range.";
1576 yrange = 5; // +- 5 sigma range
1577 }
1578 nbinsy = 200; //* ceil(yrange);
1579 get<2>(projection.second) =
1580 new TH2D(Form("hpy_%s%s", dname, name.data()),
1581 Form("Y pulls %s [%s]; Y^{%s}_{%s-%s} (cm); pull(Y)", name.data(), dname, mc_id, dname, name.data()),
1582 nbinsx, ylo, yhi, nbinsy, -yrange, yrange);
1583 break;
1584
1586 nbinsx = 10 * ceil(size[0]); // mm binning
1587 unit = makeTrange(scale, yrange);
1588 nbinsy = 2 * ceil(yrange);
1589 get<2>(projection.second) = new TH2D(Form("hxt_%s%s", dname, name.data()),
1590 Form("Hit_Trk %s [%s]; X_{%s-%s} (cm); #Delta time_{TRK} (%s)",
1591 name.data(), dname, dname, name.data(), unit.data()),
1592 nbinsx, xlo, xhi, nbinsy, -yrange, yrange);
1593 break;
1594
1596 nbinsx = dscale * ceil(size[0]); // mm binning
1597 unit = makeTrange(scale, yrange);
1598 nbinsy = 10 * ceil(yrange);
1599 get<2>(projection.second) = new TH2D(Form("hct_%s%s", dname, name.data()),
1600 Form("Hit Event %s [%s]; X_{%s-%s} (cm); #Delta time_{EV} (%s)",
1601 name.data(), dname, dname, name.data(), unit.data()),
1602 nbinsx, xlo, xhi, nbinsy, -yrange, yrange);
1603 break;
1605 if (!mc) break;
1606 xy_id = 'm';
1607 // fall through
1609 nbinsx = 100;
1610 xlo = -0.5;
1611 xhi = xlo + nbinsx;
1612 get<2>(projection.second) = new TH2D(
1613 Form("hdm_%s%s", dname, name.data()),
1614 Form("%s multiplicity [EbyE] %s [%s]; N_{%s}^{%s}; N_{%s-%s}^{%s} (%%)", (xy_id ? "point" : "hit"),
1615 name.data(), dname, dname, (xy_id ? "point" : "hit"), dname, name.data(), (xy_id ? "point" : "hit")),
1616 nbinsx, xlo, xhi, 200, 0, 1);
1617 break;
1618
1620 xy_id = 'a';
1621 // fall through
1623 if (!xy_id) xy_id = 'h';
1624 nbinsx = dscale * ceil(size[0]); // mm binning
1625 nbinsy = dscale * ceil(size[1]);
1626 get<2>(projection.second) =
1627 new TH2D(Form("hxy%c_%s%s", xy_id, dname, name.data()),
1628 Form("Hit_{%s} %s [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", (xy_id == 'h' ? "reco" : "attach"),
1629 name.data(), dname, dname, name.data(), dname, name.data()),
1630 nbinsx, xlo, xhi, nbinsy, ylo, yhi);
1631 break;
1632
1634 if (!mc) break;
1635 if (!xy_id) xy_id = 'h';
1636 mc_id[0] = 'M';
1637 mc_id[1] = 'C';
1638 nbinsx = dscale * ceil(size[0]); // mm binning
1639 nbinsy = dscale * ceil(size[1]);
1640 get<2>(projection.second) =
1641 new TH2D(Form("hxymc%c_%s%s", xy_id, dname, name.data()),
1642 Form("Hit_{%s} %s [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", (xy_id == 'h' ? "mc" : "attach"),
1643 name.data(), dname, dname, name.data(), dname, name.data()),
1644 nbinsx, xlo, xhi, nbinsy, ylo, yhi);
1645 break;
1646
1648 // fall through
1650 if (!mc) break;
1651 mc_id[0] = 'M';
1652 mc_id[1] = 'C';
1653 {
1654 bool isResidualX = (projection.first == eProjectionType::kResidualX);
1655
1656 nbinsx = dscale * ceil(size[0]); // mm binning
1657 nbinsy = dscale * ceil(size[1]);
1658 unit = makeYrange(scale, yrange);
1659
1660 get<2>(projection.second) = new TH2D(
1661 Form("h%sR_%s%s", (isResidualX ? "xx" : "yy"), dname, name.data()),
1662 Form("%s resolution %s [%s]; %s_{%s-%s} (cm); #Delta %s (%s)", (isResidualX ? "X" : "Y"), name.data(),
1663 dname, (isResidualX ? "X" : "Y"), dname, name.data(), (isResidualX ? "X" : "Y"), unit.data()),
1664 nbinsx, (isResidualX ? xlo : ylo), (isResidualX ? xhi : yhi), nbinsy, -yrange, yrange);
1665 break;
1666 }
1667
1669 // fall through
1671 if (!mc) break;
1672 {
1673 bool isResidualTX = (projection.first == eProjectionType::kResidualTX);
1674
1675 nbinsx = dscale * ceil(size[0]); // mm binning
1676 nbinsy = dscale * ceil(size[1]);
1677
1678 get<2>(projection.second) = new TH2D(
1679 Form("h%sR_%s%s", (isResidualTX ? "tx" : "ty"), dname, name.data()),
1680 Form("%s resolution %s [%s]; %s_{%s-%s} (cm); #Delta %s (ns)", (isResidualTX ? "T" : "T"), name.data(),
1681 dname, (isResidualTX ? "X" : "Y"), dname, name.data(), (isResidualTX ? "T" : "T")),
1682 nbinsx, (isResidualTX ? xlo : ylo), (isResidualTX ? xhi : yhi), nbinsy, -yrange, yrange);
1683 break;
1684 }
1685
1687 // fall through
1689 if (!mc) break;
1690 {
1691 bool isPullX = (projection.first == eProjectionType::kPullX);
1692
1693 nbinsx = dscale * ceil(size[0]); // mm binning
1694 nbinsy = dscale * ceil(size[1]);
1695 unit = makeYrange(scale, yrange);
1696
1697 get<2>(projection.second) =
1698 new TH2D(Form("h%sP_%s%s", (isPullX ? "xx" : "yy"), dname, name.data()),
1699 Form("%s pull %s [%s]; %s_{%s-%s} (cm); pull(%s)", (isPullX ? "X" : "Y"), name.data(), dname,
1700 (isPullX ? "X" : "Y"), dname, name.data(), (isPullX ? "X" : "Y")),
1701 nbinsx, (isPullX ? xlo : ylo), (isPullX ? xhi : yhi), nbinsy, -yrange, yrange);
1702 break;
1703 }
1704
1706 nbinsx = dscale * ceil(size[0] * 2.); // mm binning
1707 nbinsy = dscale * ceil(size[1] * 2.);
1708 xlo = pos[0] - size[0];
1709 xhi = pos[0] + size[0];
1710 ylo = pos[1] - size[1];
1711 yhi = pos[1] + size[1];
1712
1713 get<2>(projection.second) = new TH2D(Form("hxyp_%s%s", dname, name.data()),
1714 Form("Trk_{proj} %s [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", name.data(),
1715 dname, dname, name.data(), dname, name.data()),
1716 nbinsx, xlo, xhi, nbinsy, ylo, yhi);
1717 break;
1718 case eProjectionType::kXYt0: xy_id = '0';
1719 // fall through
1721 if (!xy_id) xy_id = '1';
1722 // fall through
1724 if (!xy_id) xy_id = '2';
1725 // fall through
1727 if (!xy_id) xy_id = '3';
1728 // fall through
1730 if (!xy_id) xy_id = '4';
1731 // fall through
1733 if (!xy_id) xy_id = '5';
1734 nbinsx = 4500; // mm binning
1735 nbinsy = 1000;
1736 xlo = -25;
1737 xhi = +20;
1738 ylo = -5;
1739 yhi = +5;
1740
1741 get<2>(projection.second) = new TH2D(Form("hxyt%c_%s%s", xy_id, dname, name.data()),
1742 Form("Trk_{proj} z = %+.2f [%s]; X_{%s-%s} (cm); Y_{%s-%s} (cm)", yrange,
1743 dname, dname, name.data(), dname, name.data()),
1744 nbinsx, xlo, xhi, nbinsy, ylo, yhi);
1745 break;
1746
1747 // Primary vertex plots
1748 case eProjectionType::kPVmult: // define primary vertex multiplicity
1749 nbinsx = 50;
1750 nbinsy = 20;
1751 xlo = -0.5;
1752 xhi = xlo + nbinsx;
1753 ylo = -0.5;
1754 yhi = ylo + nbinsy;
1755
1756 get<2>(projection.second) =
1757 new TH2D(Form("hMult_%s%s", dname, name.data()), "Vertex multiplicity; N_{trk}^{event}; N_{trk}^{PV}",
1758 nbinsx, xlo, xhi, nbinsy, ylo, yhi);
1759 break;
1760 case eProjectionType::kPVxz: // define X-Z vertex projection
1761 xy_id = 'y';
1762 mc_id[0] = 'z'; // use to store x-axis title
1763 mc_id[1] = 'x'; // use to store y-axis title
1764 nbinsx = 100;
1765 nbinsy = 200;
1766 xlo = -10;
1767 xhi = +10;
1768 ylo = -2;
1769 yhi = +2;
1770 // fall through
1771 case eProjectionType::kPVyz: // define Y-Z vertex projection
1772 if (!xy_id) {
1773 xy_id = 'x';
1774 mc_id[0] = 'z'; // use to store x-axis title
1775 mc_id[1] = 'y'; // use to store y-axis title
1776 nbinsx = 100;
1777 nbinsy = 200;
1778 xlo = -10;
1779 xhi = +10;
1780 ylo = -2;
1781 yhi = +2;
1782 }
1783 // fall through
1784 case eProjectionType::kPVxy: // define X-Y vertex projection
1785 if (!xy_id) {
1786 xy_id = 'z';
1787 mc_id[0] = 'x'; // use to store x-axis title
1788 mc_id[1] = 'y'; // use to store y-axis title
1789 nbinsx = 200;
1790 nbinsy = 200;
1791 xlo = -2;
1792 xhi = +2;
1793 ylo = -2;
1794 yhi = +2;
1795 }
1796 get<2>(projection.second) =
1797 new TH2D(Form("h%c_%s%s", xy_id, dname, name.data()),
1798 Form("Vertex_{%c%c}; %c (cm); %c (cm)", mc_id[0], mc_id[1], mc_id[0], mc_id[1]), nbinsx, xlo, xhi,
1799 nbinsy, ylo, yhi);
1800 break;
1801 }
1802 }
1803 return true;
1804}
1805
1807{
1808 stringstream s;
1809 s << "V[" << name << "] path[" << path << "] @ [" << pos[0] << ", " << pos[1] << ", " << pos[2] << "] size["
1810 << size[0] << ", " << size[1] << ", " << size[2] << "] projections[" << fProjection.size() << "] sel[";
1811 for (auto ii : fSelector)
1812 s << ii << " ";
1813 s << "]\n";
1814 return s.str();
1815}
1816
1817uint CbmRecoQaTask::View::Register(TDirectoryFile* fOut)
1818{
1819 uint n(0);
1820 TDirectoryFile* lDir = (TDirectoryFile*) fOut->mkdir(name.data(), Form("QA for vol[%s]", path.data()));
1821 TDirectoryFile *sDir(nullptr), *tDir(nullptr);
1822 // run extra directory structure for the case of detector view
1823 if (fType == eViewType::kDetUnit) {
1825 sDir = (TDirectoryFile*) lDir->mkdir("event", "Local Reco QA");
1826 else
1827 sDir = (TDirectoryFile*) lDir->mkdir("TS", "TimeSlice QA");
1828 tDir = (CbmRecoQaTask::fuRecoConfig[kRecoTracks] ? (TDirectoryFile*) lDir->mkdir("track", "CA QA") : nullptr);
1829 }
1830
1831 for (auto& projection : fProjection) {
1832 TH2* hh = get<2>(projection.second);
1833 if (!hh) continue;
1834 switch (projection.first) {
1844 if (tDir) tDir->Add(hh);
1845 break;
1857 if (sDir) sDir->Add(hh);
1858 break;
1869 if (lDir) lDir->Add(hh);
1870 break;
1871 }
1872 n++;
1873 }
1874 LOG(debug) << "CbmRecoQaTask::View[" << name << "]::Register() : " << n << " projections for " << fOut->GetName();
1875 return n;
1876}
1877
1879{
1880 string s;
1881 switch (prj) {
1882 case eProjectionType::kXYa: s = "x-y (attach)"; break;
1889 case eProjectionType::kXYt5: s = "x-y (track)"; break;
1890 case eProjectionType::kXdX: s = "dx-x"; break;
1891 case eProjectionType::kXdXMC: s = "dx-x (MC)"; break;
1892 case eProjectionType::kResidualX: s = "residual(x)-x:MC"; break;
1893 case eProjectionType::kResidualY: s = "residual(y)-y:MC"; break;
1894 case eProjectionType::kResidualTX: s = "residual(t)-x:MC"; break;
1895 case eProjectionType::kResidualTY: s = "residual(t)-y:MC"; break;
1896 case eProjectionType::kPullX: s = "pull(x)-x:MC"; break;
1897 case eProjectionType::kPullY: s = "pull(y)-y:MC"; break;
1898 case eProjectionType::kYdY: s = "dy-y"; break;
1899 case eProjectionType::kYdYMC: s = "dy-y (MC)"; break;
1900 case eProjectionType::kXpX: s = "pull(x)-x"; break;
1901 case eProjectionType::kYpY: s = "pull(y)-y"; break;
1902 case eProjectionType::kWdT: s = "dt(trk)-w"; break;
1903 case eProjectionType::kChdT: s = "dt(ev)-w"; break;
1904 case eProjectionType::kXYh: s = "x-y (hit)"; break;
1905 case eProjectionType::kXYhMC: s = "x-y (point)"; break;
1906 default: LOG(error) << "View::ToString() : Unknown projection " << int(prj); break;
1907 }
1908 return s;
1909}
1910
1911string CbmRecoQaTask::View::makeYrange(const int scale, float& yrange)
1912{
1913 bool kDefaultRange = false;
1914 string unit = "cm";
1915 if (yrange < 0) {
1916 LOG(debug) << "ProjectionY[" << name << "] using default range.";
1917 kDefaultRange = true;
1918 yrange = 3; // +- 6 cm default range
1919 }
1920 if (scale == 10) { // mm resolution
1921 unit = "mm";
1922 if (kDefaultRange) yrange = 10; // +- 20 mm default range
1923 }
1924 else if (scale == 10000) { // micron resolution
1925 unit = "#mu m";
1926 if (kDefaultRange) yrange = 150; // +- 300 um default range
1927 }
1928 return unit;
1929}
1930
1931string CbmRecoQaTask::View::makeTrange(const int scale, float& yrange)
1932{
1933 bool kDefaultRange = false;
1934 string unit = "ns";
1935 if (yrange < 0) {
1936 LOG(debug) << "ProjectionT[" << name << "] using default range.";
1937 kDefaultRange = true;
1938 yrange = 40; // +- 80 ns default range
1939 }
1940 if (scale == 1000) { // ps resolution
1941 unit = "ps";
1942 if (kDefaultRange) yrange = 300; // +- 600 ps default range
1943 }
1944 return unit;
1945}
1946
1948{
1949 for (auto cut : fFilterEv) {
1950 if (cut.fType == type) {
1951 LOG(warning) << GetName() << "::AddEventFilter event filter : " << cut.ToString() << " already on the list.";
1952 return nullptr;
1953 }
1954 }
1955 fFilterEv.emplace_back(type);
1956 return &fFilterEv.back();
1957}
1958
1960{
1961 for (auto cut : fFilterTrk) {
1962 if (cut.fType == type) {
1963 LOG(warning) << GetName() << "::AddTrackFilter track filter : " << cut.ToString() << " already on the list.";
1964 return nullptr;
1965 }
1966 }
1967 fFilterTrk.emplace_back(type);
1968 return &fFilterTrk.back();
1969}
1970
1971//+++++++++++++++++++++ EventFilter ++++++++++++++++++++++++++++++++
1972//____________________________________________________________________
1974{
1975 stringstream ss;
1976 bool ret(true);
1977 size_t val(0);
1978 switch (fType) {
1979 case eEventCut::kMultTrk:
1981 if (fMinTrack > 0 && val < size_t(fMinTrack)) {
1982 ss << "NofTrack[" << val << "] < min[" << fMinTrack << "].";
1983 ret = false;
1984 break;
1985 }
1986 if (ret && fMaxTrack > 0 && val > size_t(fMaxTrack)) {
1987 ss << "NofTrack[" << val << "] > max[" << fMaxTrack << "].";
1988 ret = false;
1989 }
1990 break;
1991 case eEventCut::kMultHit:
1993 if (fMultHit[0] > 0 && val > size_t(fMultHit[0])) {
1994 ss << "Sts hits [" << val << "] > max[" << fMultHit[0] << "].";
1995 ret = false;
1996 break;
1997 }
1999 if (fMultHit[1] > 0 && val > size_t(fMultHit[1])) {
2000 ss << "Trd hits [" << val << "] > max[" << fMultHit[1] << "].";
2001 ret = false;
2002 break;
2003 }
2005 if (fMultHit[2] > 0 && val > size_t(fMultHit[2])) {
2006 ss << "Tof hits [" << val << "] > max[" << fMultHit[2] << "].";
2007 ret = false;
2008 }
2009 break;
2010 default: break;
2011 }
2012 if (!ret) LOG(debug2) << "Event reject for : " << ss.str();
2013 return ret;
2014}
2015bool CbmRecoQaTask::EventFilter::SetFilter(std::vector<float> cuts)
2016{
2017 switch (fType) {
2018 case eEventCut::kMultTrk:
2019 if (cuts.size() < 2 || cuts[1] < cuts[0]) {
2020 LOG(warning) << "Improper definition for event filter :\n\t" << ToString() << endl;
2021 HelpMess();
2022 return false;
2023 }
2024 fMinTrack = int(cuts[0]);
2025 fMaxTrack = int(cuts[1]);
2026 break;
2027 case eEventCut::kMultHit:
2028 if (cuts.size() < 3) {
2029 LOG(warning) << "Improper definition for event filter :\n\t" << ToString() << endl;
2030 HelpMess();
2031 return false;
2032 }
2033 for (int i(0); i < int(CbmRecoQaTask::EventFilter::eEventDef::kNofDetHit); i++)
2034 fMultHit[i] = int(cuts[i]);
2035 break;
2036 case eEventCut::kTrigger: break;
2037 case eEventCut::kVertex: break;
2038 default: break;
2039 }
2040 return true;
2041}
2043{
2044 stringstream ss;
2045 switch (fType) {
2046 case eEventCut::kMultTrk: ss << "kMultTrk : \"cut on track multiplicity"; break;
2047 case eEventCut::kMultHit: ss << "kMultHit : \"cut on hit multiplicity"; break;
2048 case eEventCut::kTrigger: ss << "kTrigger : \"cut on trigger conditions"; break;
2049 case eEventCut::kVertex: ss << "kVertex : \"cut on vertex definition"; break;
2050 default: break;
2051 }
2052 return ss.str();
2053}
2055{
2056 LOG(info) << "CbmRecoQaTask::EventFilter : Usage";
2057 switch (fType) {
2058 case eEventCut::kMultTrk:
2059 LOG(info) << ToString();
2060 LOG(info) << "\tDepends one two values : min and max of the no of global "
2061 "tracks / event.";
2062 LOG(info) << "\tValue should follow the relation max >= min.";
2063 break;
2064 case eEventCut::kMultHit:
2065 LOG(info) << ToString();
2066 LOG(info) << "\tDepends one three values : total hits in the following "
2067 "systems (in this order) : STS TRD TOF.";
2068 LOG(info) << "\tNegative values are interpreted as no-cut.";
2069 break;
2070 default:
2071 LOG(info) << ToString();
2072 LOG(info) << "\tNo user info.";
2073 break;
2074 }
2075}
2076//+++++++++++++++++++++ TrackFilter ++++++++++++++++++++++++++++++++
2077//____________________________________________________________________
2079{
2080 bool ret(true);
2081 stringstream ss;
2082 int idx(-1);
2083 const CbmTrack* trk(nullptr);
2084 switch (fType) {
2085 case eTrackCut::kSts:
2086 if (fNSts <= 0 && !fStsHits.size()) break;
2087 if ((idx = ptr->GetStsTrackIndex()) < 0) {
2088 ss << "Sts trk index missing";
2089 ret = false;
2090 break;
2091 }
2092 if (!(trk = lnk->GetTrack(ECbmModuleId::kSts, idx))) {
2093 ss << "Sts trk nullptr";
2094 ret = false;
2095 break;
2096 }
2097 // cut on the total no of STS hits/trk
2098 if (trk->GetNofHits() < fNSts) {
2099 ss << "Sts hits/trk [" << trk->GetNofHits() << "] < min[" << fNSts << "].";
2100 ret = false;
2101 break;
2102 }
2103 // cut on the distribution of STS hits/trk/station
2104 for (auto stsStation : fStsHits) {
2105 if (!stsStation) continue;
2106 // check hit in this particular station
2107 }
2108 break;
2109 case eTrackCut::kTrd:
2110 if (fNTrd <= 0) break;
2111 if ((idx = ptr->GetTrdTrackIndex()) < 0) {
2112 ss << "Trd trk index missing";
2113 ret = false;
2114 break;
2115 }
2116 if (!(trk = lnk->GetTrack(ECbmModuleId::kTrd, idx))) {
2117 ss << "Trd trk nullptr";
2118 ret = false;
2119 break;
2120 }
2121 // cut on the total no of TRD hits/trk
2122 if (trk->GetNofHits() < fNTrd) {
2123 ss << "Trd` hits/trk [" << trk->GetNofHits() << "] < min[" << fNTrd << "].";
2124 ret = false;
2125 break;
2126 }
2127 break;
2128 case eTrackCut::kTof:
2129 if (fNTof <= 0) break;
2130 if ((idx = ptr->GetTofTrackIndex()) < 0) {
2131 ss << "Tof trk index missing";
2132 ret = false;
2133 break;
2134 }
2135 if (!(trk = lnk->GetTrack(ECbmModuleId::kTof, idx))) {
2136 ss << "Tof trk nullptr";
2137 ret = false;
2138 break;
2139 }
2140 // cut on the total no of ToF hits/trk
2141 if (trk->GetNofHits() < fNTof) {
2142 ss << "Tof` hits/trk [" << trk->GetNofHits() << "] < min[" << fNTof << "].";
2143 ret = false;
2144 break;
2145 }
2146 break;
2147 default: break;
2148 }
2149
2150 if (!ret) LOG(debug2) << "Track reject for : " << ss.str();
2151 return ret;
2152}
2153bool CbmRecoQaTask::TrackFilter::SetFilter(std::vector<float> cuts)
2154{
2155 switch (fType) {
2156 case eTrackCut::kSts:
2157 if (cuts.size() < 1) {
2158 LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl;
2159 // HelpMess();
2160 return false;
2161 }
2162 fNSts = int(cuts[0]);
2163 break;
2164 case eTrackCut::kTrd:
2165 if (cuts.size() < 1) {
2166 LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl;
2167 // HelpMess();
2168 return false;
2169 }
2170 fNTrd = int(cuts[0]);
2171 break;
2172 case eTrackCut::kTof:
2173 if (cuts.size() < 1) {
2174 LOG(warning) << "Improper definition for track filter :\n\t" << ToString() << endl;
2175 // HelpMess();
2176 return false;
2177 }
2178 fNTof = int(cuts[0]);
2179 break;
2180 default: break;
2181 }
2182 return true;
2183}
2185{
2186 stringstream ss;
2187 switch (fType) {
2188 case eTrackCut::kSts: ss << "kSts : \"cut on no of STS hits / track\""; break;
2189 case eTrackCut::kMuch: ss << "kMuch : \"cut on no of Much hits / track\""; break;
2190 case eTrackCut::kRich: ss << "kRich : \"cut on no of Rich hits / track\""; break;
2191 case eTrackCut::kTrd: ss << "kTrd : \"cut on no of TRD hits / track\""; break;
2192 case eTrackCut::kTof: ss << "kTof : \"cut on no of Tof hits / track\""; break;
2193 default: break;
2194 }
2195 return ss.str();
2196}
2197/* clang-format off */
2203 /* clang-format on */
ClassImp(CbmConverterManager)
ECbmModuleId
Definition CbmDefs.h:39
@ kMvd
Micro-Vertex Detector.
@ kTrd
Transition Radiation Detector.
@ kTof
Time-of-flight Detector.
@ kNotExist
If not found.
@ kPsd
Projectile spectator detector.
@ kSts
Silicon Tracking System.
@ kTrd2d
TRD-FASP Detector (FIXME)
@ kLastModule
For loops over all modules.
@ kMuch
Muon detection system.
@ kFsd
Forward spectator detector.
@ kRich
Ring-Imaging Cherenkov Detector.
#define kNtrkProjections
@ kStsModule
@ kStsLadder
@ kStsUnit
Data class for a reconstructed hit in the STS.
Helper class to convert unique channel ID back and forth.
Class for hits in TRD detector.
friend fvec sqrt(const fvec &a)
friend fscal max(fscal x, fscal y)
static constexpr size_t size()
Definition KfSimdPseudo.h:2
fscal v[fmask::Size]
Definition KfSimdPseudo.h:4
Generates beam ions for transport simulation.
Class characterising one event by a collection of links (indices) to data objects,...
Definition CbmEvent.h:34
size_t GetNofData() const
Definition CbmEvent.cxx:58
double GetStartTime() const
Definition CbmEvent.h:140
int32_t GetStsTrackIndex() const
int32_t GetTofTrackIndex() const
int32_t GetTrdTrackIndex() const
int32_t GetRefId() const
Definition CbmHit.h:73
void SetSkipUnmeasuredCoordinates(bool skip=true)
skip unmeasured coordinates
bool CreateGlobalTrack(Trajectory &kfTrack, int globalTrackIndex)
void FixMomentumForMs(bool fix=true)
fix the inverse momentum for the Multiple Scattering calculation
void SetDefaultMomentumForMs(double p)
set the default inverse momentum for the Multiple Scattering calculation
bool FitTrajectory(CbmKfTrackFitter::Trajectory &t)
fit the track
Task class creating and managing CbmMCDataArray objects.
CbmMCDataArray * InitBranch(const char *name)
int32_t GetNofLinks() const
Definition CbmMatch.h:42
const CbmLink & GetMatchedLink() const
Definition CbmMatch.h:41
double GetDy() const
Definition CbmPixelHit.h:76
double GetDx() const
Definition CbmPixelHit.h:75
double GetY() const
Definition CbmPixelHit.h:74
double GetX() const
Definition CbmPixelHit.h:73
CbmMCDataManager * cbm_mc_manager
std::vector< TVector3 > fPrjPlanes
list of QA views
virtual bool FilterEvent(const CbmEvent *ptr)
Filter events for QA use (e.g. event multiplicity)
std::map< ECbmModuleId, TClonesArray * > fHitMatch
mc points
int GetNviews(eViewType type) const
count views types registered with the task
virtual EventFilter * AddEventFilter(EventFilter::eEventCut cut)
virtual Detector * GetDetector(ECbmModuleId did)
std::map< ECbmModuleId, CbmMCDataArray * > fPoints
reconstructed hits
TClonesArray * fGTracks
TClonesArray * fEvents
MC info for the global tracks.
static std::bitset< kRecoQaNConfigs > fuRecoConfig
std::map< ECbmModuleId, Detector > fDetQa
virtual void Exec(Option_t *option)
Executed task.
std::map< ECbmModuleId, TClonesArray * > fHits
Time slice info.
std::vector< EventFilter > fFilterEv
reconstructed hits
std::vector< TrackFilter > fFilterTrk
@ kPVyz
x-z projection of the primary vertex:
@ kXYh
Time to EV residuals as function of coordinate in view.
@ kPVxy
Residual distribution T:
@ kResidualX
Pull distribution Y:
@ kDmult
X-Y hit coorelation in local view.
@ kXYt3
X-Y track projections on a random plane (value 2)
@ kXYt5
X-Y track projections on a random plane (value 4)
@ kXYhMC
local view MC point multiplicity
@ kYpY
X to TRK pulls as function of local X in view.
@ kXYt1
X-Y track projections on a random plane (value 0)
@ kYdYMC
Y to TRK residuals as function of local Y in view.
@ kResidualY
Residual distribution X: (x_RC - x_MC) in cm.
@ kPullX
X-Y MC point coorelation in local view (using HitMatch)
@ kResidualTX
Residual distribution Y:
@ kXYt0
y-z projection of the primary vertex:
@ kXYt2
X-Y track projections on a random plane (value 1)
@ kResidualTY
Residual distribution T:
@ kXdX
X-Y track projections on detection unit.
@ kPullY
Pull distribution X: (RC - MC) / dx_RC.
@ kXYp
X-Y hit coorelation in track filtered data.
@ kPVmult
y-z projection of the primary vertex:
@ kYdY
X to TRK residuals w.r.t MC points.
@ kXdXMC
X to TRK residuals as function of local X in view.
@ kWdT
Y to TRK residuals w.r.t MC points.
@ kPVxz
x-y projection of the primary vertex:
@ kXYt4
X-Y track projections on a random plane (value 3)
@ kDmultMC
local view hit multiplicity
@ kChdT
Y to TRK pulls as function of local Y in view.
CbmKfTrackFitter fFitter
virtual bool FilterTrack(const CbmGlobalTrack *ptr)
Filter tracks for further use (e.g. track projections)
@ kUseMC
has Much hits (MuchHit branch)
@ kRecoTracks
has events reconstructed (CbmEvent branch)
virtual InitStatus Init()
Perform initialization of data sources and projections.
std::map< ECbmModuleId, TClonesArray * > fTracks
reconstructed global tracks / event
TString GetGeoTagForDetector(const TString &detector)
std::vector< TString > GetPath(TGeoNode *node, TString, TString activeNodeName, int depth=0, const TString &path="")
@ kPV
set of track projection views
@ kTrkProj
detector view
virtual const CbmTrack * GetTrack(ECbmModuleId did, int id) const
Retrieve detector specific track by index.
std::map< const char *, View > fViews
list of detector QA
TClonesArray * fTrackMatches
reconstructed global tracks / event
virtual TrackFilter * AddTrackFilter(TrackFilter::eTrackCut cut)
virtual Detector * AddDetector(ECbmModuleId did)
TDirectoryFile fOutFolder
virtual void Finish()
void InitMcbm22()
build QA plots for particular setups
static uint16_t GetDirichId(int Address)
Definition CbmRichUtil.h:31
Bool_t IsActive(ECbmModuleId moduleId)
Definition CbmSetup.cxx:169
static CbmSetup * Instance()
Definition CbmSetup.cxx:160
data class for a reconstructed 3-d hit in the STS
Definition CbmStsHit.h:35
Data class with information on a STS local track.
static int32_t GetSmId(uint32_t address)
static int32_t GetRpcId(uint32_t address)
static int32_t GetSmType(uint32_t address)
virtual int32_t GetNofHits() const
Definition CbmTrack.h:58
static uint32_t GetModuleId(uint32_t address)
Return module ID from address.
static uint32_t GetLayerId(uint32_t address)
Return layer ID from address.
static uint32_t GetModuleAddress(uint32_t address)
Return unique module ID from address.
data class for a reconstructed Energy-4D measurement in the TRD
Definition CbmTrdHit.h:40
void Position(TVector3 &pos) const
Definition CbmVertex.h:73
bool FindTrackByIndex(uint32_t iTrack) const
Accessors to the Global track array. Check if track with global index iTrack was actually used for ve...
double GetCovariance(int32_t i, int32_t j) const
int32_t GetNTracks() const
Definition CbmVertex.h:72
T X() const
Gets x position [cm].
T Y() const
Gets y position [cm].
T Time() const
Gets time [ns].
T GetCovariance(int i, int j) const
Get covariance matrix element.
uint32_t GetElementId(int32_t address, int32_t level)
Get the index of an element.
std::string_view ToString(T t)
Definition EnumDict.h:64
Hash for CbmL1LinkKey.
cbm::algo::kf::TrackParamD fParamUp
fitted track parameters upstream the node
double fZ
Z coordinate of the node.
cbm::algo::kf::MeasurementXy< double > fMxy
== Hit information ( if present )
int fReference1
some reference can be set by the user
cbm::algo::kf::MeasurementTime< double > fMt
time measurement at fZ
A trajectory to be fitted.
std::vector< TrajectoryNode > fNodes
nodes on the trajectory
View * GetView(const char *n)
Detector(ECbmModuleId did=ECbmModuleId::kNotExist)
View * FindView(double x, double y, double z)
bool Init(TDirectoryFile *f, bool mc=false)
Check geometry and trigger Init() for all registered views. Build main directory outut for the curren...
View * AddView(const char *n, const char *p, std::vector< int > set)
void HelpMess() const
max no of hits/ev for the systems [STS TRD ToF]
std::string ToString() const
bool SetFilter(std::vector< float > cuts)
bool Accept(const CbmEvent *ptr, const CbmRecoQaTask *lnk)
bool Accept(const CbmGlobalTrack *ptr, const CbmRecoQaTask *lnk)
std::string ToString() const
bool SetFilter(std::vector< float > cuts)
bool AddProjection(eProjectionType prj, float range=-1, const char *unit="cm")
bool Init(const char *dname, bool mc=false)
Define all type of QA histo known to the class. In case of detector view type, convert geo address in...
std::string makeYrange(const int scale, float &range)
bool Load(const CbmHit *h, const FairMCPoint *point, const CbmEvent *ev)
void SetSetup(CbmRecoQaTask::eSetup setup)
uint Register(TDirectoryFile *f)
build directory structure for all projections of current view.
std::string makeTrange(const int scale, float &range)
helper functions to estimate the representation (y) axis
bool HasAddress(const CbmHit *h, double &x, double &y, double &dx, double &dy) const
Hit classification on system and view.
bool SetProjection(eProjectionType prj, float range, const char *unit)
std::string ToString() const