CbmRoot
Loading...
Searching...
No Matches
CbmRichRingRecoQa.cxx
Go to the documentation of this file.
1/* Copyright (C) 2025 Justus-Liebig-Universitaet Giessen, Giessen
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Martin Beyer [committer] */
4
11
12#include "CbmRichRingRecoQa.h"
13
14#include "CbmDigiManager.h"
15#include "CbmEvent.h"
16#include "CbmMCDataArray.h"
17#include "CbmMCDataManager.h"
18#include "CbmMCTrack.h"
19#include "CbmMatch.h"
20#include "CbmMatchRecoToMC.h"
21#include "CbmQaTable.h"
22#include "CbmRichHit.h"
23#include "CbmRichRing.h"
24#include "CbmTrackMatchNew.h"
25
26#include <FairRootManager.h>
27
28#include <TClonesArray.h>
29#include <TMCProcess.h>
30
31#include <array>
32#include <vector>
33
34
36{
37 FairRootManager* manager = FairRootManager::Instance();
38 if (!manager) LOG(fatal) << GetName() << ": No FairRootManager!";
39
41 fDigiManager->Init();
42 if (!fDigiManager->IsPresent(ECbmModuleId::kRich)) {
43 LOG(fatal) << GetName() << ": No RichDigi array found in CbmDigiManager!";
44 }
45
46 fCbmEvents = dynamic_cast<TClonesArray*>(manager->GetObject("CbmEvent"));
47 LOG(info) << GetName() << ": CbmEvent" << (fCbmEvents ? " " : " NOT ") << "found.\n";
48
49 fRichHits = dynamic_cast<TClonesArray*>(manager->GetObject("RichHit"));
50 if (!fRichHits) LOG(fatal) << GetName() << ": No RichHit array found in FairRootManager!";
51
52 fRichRings = dynamic_cast<TClonesArray*>(manager->GetObject("RichRing"));
53 if (!fRichRings) LOG(fatal) << GetName() << ": No RichRing array found in FairRootManager!";
54
55 fRichProjections = dynamic_cast<TClonesArray*>(manager->GetObject("RichProjection"));
56 if (!fRichProjections) LOG(fatal) << GetName() << ": No RichProjection array found in FairRootManager!";
57
58
59 if (IsMCUsed()) {
60 auto* mcManager = static_cast<CbmMCDataManager*>(manager->GetObject("MCDataManager"));
61 if (!mcManager) LOG(fatal) << GetName() << ": No MCDataManager!";
62
63 fMcTracks = mcManager->InitBranch("MCTrack");
64 if (!fMcTracks) LOG(fatal) << GetName() << ": No MCTrack array found in CbmMCDataManager!";
65
66 fRichPoints = mcManager->InitBranch("RichPoint");
67 if (!fRichPoints) LOG(fatal) << GetName() << ": No RichPoint array found in CbmMCDataManager!";
68
69 fRichRingMatches = dynamic_cast<TClonesArray*>(manager->GetObject("RichRingMatch"));
70 if (!fRichRingMatches) LOG(fatal) << GetName() << ": No RichRingMatch array found in FairRootManager!";
71 }
72
74
75 return kSUCCESS;
76}
77
79{
80 // clang-format off
82 MakeQaObject<TH1D>("RichRingsPerEvent", "RichRings per event; #RichRings / Event; Entries", 71, -0.5, 70.5);
84 MakeQaObject<TH1D>("RichRingTimeEvent", "Rich ring time in event; Ring time - Event time [ns]; Entires", 30, 12., 24.);
86 MakeQaObject<TH1D>("RingHitsTime", "Rich ring time - Hit times; Ring time - Hit time [ns]; Entires", 100, -5., 5.);
88 MakeQaObject<TH2D>("RingXY", "Rich ring positions; x [cm]; y [cm]; Entries", 50, -130., 130.0, 20, 110., 200.);
89
90 // 1D feature histograms
92 MakeQaObject<TH1D>("RingRadius", "Rich ring radius; Radius [cm]; Entries", 50, 0., 10.);
94 MakeQaObject<TH1D>("RingNumHits", "Rich ring number of hits; #Ring hits; Entries", 51, -0.5, 50.5);
96 MakeQaObject<TH1D>("RingCenterX", "Rich ring center x position; Center x [cm]; Entries", 100, -130., 130.0);
98 MakeQaObject<TH1D>("RingCenterY", "Rich ring center y position; |Center y| [cm]; Entries", 50, 110., 200.);
100 MakeQaObject<TH1D>("RingAaxis", "Rich ring A axis; A axis [cm]; Entries", 50, 0., 10.);
102 MakeQaObject<TH1D>("RingBaxis", "Rich ring B axis; B axis [cm]; Entries", 50, 0., 10.);
104 MakeQaObject<TH1D>("RingBoA", "Rich ring B over A axis; B/A; Entries", 50, 0., 1.1);
106 MakeQaObject<TH1D>("RingPhi", "Rich ring phi; Phi [rad]; Entries", 40, -2., 2.);
108 MakeQaObject<TH1D>("RingChi2oNDF", "Rich ring Chi2 over NDF; Chi2 / NDF; Entries", 40, -0.5, 3.);
109 // ! Angle histograms current no filled, since angle value is not passed to CbmRichRing objects
110 // fhRingFeatures.at(ERingFeature::Angle) =
111 // MakeQaObject<TH1D>("RingAngle", "Rich ring sum of 3 consecutive angles between hits in ring; Angle [rad]; Entries", 50, 0., 3.1415);
113 MakeQaObject<TH1D>("RingRadialPosition", "Rich ring radial position; RadialPosition [cm]; Entries", 50, 0., 150);
115 MakeQaObject<TH1D>("RingRadialAngle", "Rich ring radial angle; RadialAngle [rad]; Entries", 50, 0., 3.1415);
116
117 // * MC part starting here
118 if (!IsMCUsed()) return;
120 MakeQaObject<TH1D>("RingTypes", "Reconstructed rings for types; Ring types; Entries", 8, -1.5, 6.5);
121 const std::array<std::string, 8> tickLabels{"Reco", "TrueReco", "PrimEl", "SecEl", "Pion", "Other", "Fake", "Clone"};
122 for (std::size_t i = 0; i < tickLabels.size(); ++i) {
123 fhRingTypeCounts->GetXaxis()->SetBinLabel(i + 1, tickLabels[i].c_str());
124 }
125
128 "RingRecoPurityXY",
129 "Rich ring reconstruction purity; x [cm]; y [cm]; Purity",
130 50, -130., 130.0, 20, 110., 200.);
131
132 const std::array<TString, 6> typesStr{"TrueReco", "PrimEl", "SecEl", "Pion", "Other", "Fake"};
133 const std::array<TString, 6> typesStrFull{"all correct reconstructed rings", "primary electrons",
134 "seconday electrons", "pions", "others", "fakes"};
135
136 // Efficiency vs MC momentum Profile histograms
137 for (int type = ERecoRingType::TrueReco; type <= ERecoRingType::Other; type++) {
138 fhRingRecoEff.at(type) =
140 "RingRecoEff" + typesStr.at(type),
141 "Rich ring reconstruction efficiency" + typesStrFull.at(type) +"; p_{MC} [GeV/c]; Ring reconstruction efficiency",
142 60, 0., 12.);
143 }
144
145 // 1D feature histograms MC
146 for (int type = ERecoRingType::TrueReco; type <= ERecoRingType::Fake; type++) {
147 auto& featureHists = fhRingTypeFeatures.at(type);
148 featureHists.at(ERingFeature::Radius) =
150 "RingFeatures" + typesStr.at(type) + "/RingRadius" + typesStr.at(type),
151 "Rich ring radius " + typesStrFull.at(type) + "; Radius [cm]; Entries",
152 50, 0., 10.);
153 featureHists.at(ERingFeature::NHits) =
155 "RingFeatures" + typesStr.at(type) + "/RingNumHits" + typesStr.at(type),
156 "Rich ring number of hits " + typesStrFull.at(type) + "; #Ring hits; Entries",
157 51, -0.5, 50.5);
158 featureHists.at(ERingFeature::CenterX) =
160 "RingFeatures" + typesStr.at(type) + "/RingCenterX" + typesStr.at(type),
161 "Rich ring center x position " + typesStrFull.at(type) + "; Center x [cm]; Entries",
162 100, -130., 130.0);
163 featureHists.at(ERingFeature::CenterY) =
165 "RingFeatures" + typesStr.at(type) + "/RingCenterY" + typesStr.at(type),
166 "Rich ring center y position " + typesStrFull.at(type) + "; |Center y| [cm]; Entries",
167 50, 110., 200.);
168 featureHists.at(ERingFeature::Aaxis) =
170 "RingFeatures" + typesStr.at(type) + "/RingAaxis" + typesStr.at(type),
171 "Rich ring A axis " + typesStrFull.at(type) + "; A axis [cm]; Entries",
172 50, 0., 10.);
173 featureHists.at(ERingFeature::Baxis) =
175 "RingFeatures" + typesStr.at(type) + "/RingBaxis" + typesStr.at(type),
176 "Rich ring B axis " + typesStrFull.at(type) + "; B axis [cm]; Entries",
177 50, 0., 10.);
178 featureHists.at(ERingFeature::BoA) =
180 "RingFeatures" + typesStr.at(type) + "/RingBoA" + typesStr.at(type),
181 "Rich ring B over A axis " + typesStrFull.at(type) + "; B/A; Entries",
182 50, 0., 1.1);
183 featureHists.at(ERingFeature::Phi) =
185 "RingFeatures" + typesStr.at(type) + "/RingPhi" + typesStr.at(type),
186 "Rich ring phi " + typesStrFull.at(type) + "; Phi [rad]; Entries",
187 40, -2., 2.);
188 featureHists.at(ERingFeature::Chi2oNDF) =
190 "RingFeatures" + typesStr.at(type) + "/RingChi2oNDF" + typesStr.at(type),
191 "Rich ring Chi2 over NDF " + typesStrFull.at(type) + "; Chi2 / NDF; Entries",
192 40, -0.5, 3.);
193 // featureHists.at(ERingFeature::Angle) =
194 // MakeQaObject<TH1D>(
195 // "RingFeatures" + typesStr.at(type) + "/RingAngle" + typesStr.at(type),
196 // "Rich ring sum of 3 consecutive angles between hits in ring " + typesStrFull.at(type) + "; Angle [rad]; Entries",
197 // 50, 0., 3.1415);
198 featureHists.at(ERingFeature::RadialPosition) =
200 "RingFeatures" + typesStr.at(type) + "/RingRadialPosition" + typesStr.at(type),
201 "Rich ring radial position " + typesStrFull.at(type) + "; RadialPosition [cm]; Entries",
202 50, 0., 150);
203 featureHists.at(ERingFeature::RadialAngle) =
205 "RingFeatures" + typesStr.at(type) + "/RingRadialAngle" + typesStr.at(type),
206 "Rich ring radial angle " + typesStrFull.at(type) + "; RadialAngle [rad]; Entries",
207 50, 0., 3.1415);
208 }
209
210 // 2D feature vs MC momentum histograms (no fakes here!)
211 for (int type = ERecoRingType::TrueReco; type <= ERecoRingType::Other; type++) {
212 auto& featureHists = fhRingTypeFeaturesMomentum.at(type);
213 featureHists.at(ERingFeature::Radius) =
215 "RingFeatures" + typesStr.at(type) + "/RingRadiusMomentum" + typesStr.at(type),
216 "Rich ring radius vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; Radius [cm]; Entries",
217 60, 0., 12., 50, 0., 10.);
218 featureHists.at(ERingFeature::NHits) =
220 "RingFeatures" + typesStr.at(type) + "/RingNumHitsMomentum" + typesStr.at(type),
221 "Rich ring number of hits vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; #Ring hits; Entries",
222 60, 0., 12., 51, -0.5, 50.5);
223 featureHists.at(ERingFeature::CenterX) =
225 "RingFeatures" + typesStr.at(type) + "/RingCenterXMomentum" + typesStr.at(type),
226 "Rich ring center x position vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; Center x [cm]; Entries",
227 60, 0., 12., 100, -130., 130.0);
228 featureHists.at(ERingFeature::CenterY) =
230 "RingFeatures" + typesStr.at(type) + "/RingCenterYMomentum" + typesStr.at(type),
231 "Rich ring center y position vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; |Center y| [cm]; Entries",
232 60, 0., 12., 50, 110., 200.);
233 featureHists.at(ERingFeature::Aaxis) =
235 "RingFeatures" + typesStr.at(type) + "/RingAaxisMomentum" + typesStr.at(type),
236 "Rich ring A axis vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; A axis [cm]; Entries",
237 60, 0., 12., 50, 0., 10.);
238 featureHists.at(ERingFeature::Baxis) =
240 "RingFeatures" + typesStr.at(type) + "/RingBaxisMomentum" + typesStr.at(type),
241 "Rich ring B axis vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; B axis [cm]; Entries",
242 60, 0., 12., 50, 0., 10.);
243 featureHists.at(ERingFeature::BoA) =
245 "RingFeatures" + typesStr.at(type) + "/RingBoAMomentum" + typesStr.at(type),
246 "Rich ring B over A axis vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; B/A; Entries",
247 60, 0., 12., 50, 0., 1.1);
248 featureHists.at(ERingFeature::Phi) =
250 "RingFeatures" + typesStr.at(type) + "/RingPhiMomentum" + typesStr.at(type),
251 "Rich ring phi vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; Phi [rad]; Entries",
252 60, 0., 12., 40, -2., 2.);
253 featureHists.at(ERingFeature::Chi2oNDF) =
255 "RingFeatures" + typesStr.at(type) + "/RingChi2oNDFMomentum" + typesStr.at(type),
256 "Rich ring Chi2 over NDF vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; Chi2 / NDF; Entries",
257 60, 0., 12., 40, -0.5, 3.);
258 // featureHists.at(ERingFeature::Angle) =
259 // MakeQaObject<TH2D>(
260 // "RingFeatures" + typesStr.at(type) + "/RingAngleMomentum" + typesStr.at(type),
261 // "Rich ring sum of 3 consecutive angles between hits in ring vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; Angle [rad]; Entries",
262 // 60, 0., 12., 50, 0., 3.1415);
263 featureHists.at(ERingFeature::RadialPosition) =
265 "RingFeatures" + typesStr.at(type) + "/RingRadialPositionMomentum" + typesStr.at(type),
266 "Rich ring radial position vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; RadialPosition [cm]; Entries",
267 60, 0., 12., 50, 0., 150);
268 featureHists.at(ERingFeature::RadialAngle) =
270 "RingFeatures" + typesStr.at(type) + "/RingRadialAngleMomentum" + typesStr.at(type),
271 "Rich ring radial angle vs momentum " + typesStrFull.at(type) + "; p_{MC} [GeV/c]; RadialAngle [rad]; Entries",
272 60, 0., 12., 50, 0., 3.1415);
273 }
274 // clang-format on
275}
276
278{
279 const CbmEvent* event = GetCurrentEvent();
280
281 const int nRichRings = event ? event->GetNofData(ECbmDataType::kRichRing) : fRichRings->GetEntriesFast();
282 if (event) fhRichRingsPerEvent->Fill(nRichRings);
283 for (int iRing = 0; iRing < nRichRings; ++iRing) {
284 const int iRingIndex = event ? event->GetIndex(ECbmDataType::kRichRing, iRing) : iRing;
285 const auto* ring = static_cast<CbmRichRing*>(fRichRings->At(iRingIndex));
286 if (!ring) continue;
287
288 if (event) fhRingTimeInEvent->Fill(ring->GetTime() - event->GetTzero());
289 fhRingCenterXY->Fill(ring->GetCenterX(), ring->GetCenterY());
290 const int nHits = ring->GetNofHits();
291 for (int iHit = 0; iHit < nHits; ++iHit) {
292 const auto* hit = static_cast<CbmRichHit*>(fRichHits->At(ring->GetHit(iHit)));
293 if (!hit) continue;
294 fhRingHitsTime->Fill(ring->GetTime() - hit->GetTime());
295 }
296
297 fhRingFeatures.at(ERingFeature::Radius)->Fill(ring->GetRadius());
298 fhRingFeatures.at(ERingFeature::NHits)->Fill(ring->GetNofHits());
299 fhRingFeatures.at(ERingFeature::CenterX)->Fill(ring->GetCenterX());
300 fhRingFeatures.at(ERingFeature::CenterY)->Fill(ring->GetCenterY());
301 fhRingFeatures.at(ERingFeature::Aaxis)->Fill(ring->GetAaxis());
302 fhRingFeatures.at(ERingFeature::Baxis)->Fill(ring->GetBaxis());
303 fhRingFeatures.at(ERingFeature::BoA)->Fill(ring->GetBaxis() / ring->GetAaxis());
304 fhRingFeatures.at(ERingFeature::Phi)->Fill(ring->GetPhi());
305 fhRingFeatures.at(ERingFeature::Chi2oNDF)->Fill(ring->GetChi2() / static_cast<double>(ring->GetNDF()));
306 // fhRingFeatures.at(ERingFeature::Angle)->Fill(ring->GetAngle());
307 fhRingFeatures.at(ERingFeature::RadialPosition)->Fill(ring->GetRadialPosition());
308 fhRingFeatures.at(ERingFeature::RadialAngle)->Fill(ring->GetRadialAngle());
309 }
310
311 // * MC part starting here
312 if (!IsMCUsed()) return;
313
314 // ! Accepted rings are searched for in each camera seperately.
315 // Reason: It happens that Cherenkov cones are split due to the 2 segment mirror.
316 // Accepted rings for upper [0] and lower [1] RICH camera
317 std::array<std::map<CbmLink, int>, 2> accRingsCam{};
318
319 // Count RichHits for each Cherenkov mother particle
320 const int nRichHits = event ? event->GetNofData(ECbmDataType::kRichHit) : fRichHits->GetEntriesFast();
321 for (int iHit = 0; iHit < nRichHits; iHit++) {
322 const int iHitIndex = event ? event->GetIndex(ECbmDataType::kRichHit, iHit) : iHit;
323 const auto* hit = static_cast<CbmRichHit*>(fRichHits->At(iHitIndex));
324 if (!hit) continue;
325 const std::vector<CbmLink> motherIds =
327 const bool isUpperCamera = hit->GetY() > 0.;
328 for (const auto& motherId : motherIds)
329 (isUpperCamera ? accRingsCam[0] : accRingsCam[1])[motherId]++;
330 }
331
332 // Remove mother particles below minimum amount of hits for accepted ring.
333 // Set counters to 0 and reuse them later to count how many reco rings match with a specific acc ring.
334 for (auto& accRings : accRingsCam) {
335 for (auto it = accRings.begin(); it != accRings.end();) {
336 auto& [link, nHits] = *it;
337 if (nHits < fAccRingMinNumHits) {
338 it = accRings.erase(it);
339 continue;
340 }
341 const auto* mcTrack = static_cast<const CbmMCTrack*>(fMcTracks->Get(link));
342 if (!mcTrack) {
343 it = accRings.erase(it);
344 continue;
345 }
346 // TODO: implement FillHistsAccRing(mcTrack), e.g. count split Cherenkov cones
347 nHits = 0;
348 ++it;
349 }
350 }
351
352 // Loop reconstruced rings, fill histograms for specific ring types (E.g. primary, pion, fake, etc.)
353 fhRingTypeCounts->Fill(-1., static_cast<double>(nRichRings));
354 for (Int_t iRing = 0; iRing < nRichRings; ++iRing) {
355 const int iRingIndex = event ? event->GetIndex(ECbmDataType::kRichRing, iRing) : iRing;
356 const auto* ring = static_cast<CbmRichRing*>(fRichRings->At(iRingIndex));
357 if (!ring) continue;
358
359 const auto* ringMatch = static_cast<CbmTrackMatchNew*>(fRichRingMatches->At(iRingIndex));
360 if (!ringMatch) {
361 LOG(warn) << GetName() << ": ringMatch not found for ring index " << iRingIndex << " !";
362 FillHistsFakeRing(ring);
363 continue;
364 }
365
366 // Full digitizer noise ring
367 if (ringMatch->GetNofLinks() <= 0) {
368 LOG(warn) << GetName() << ": Full digitizer noise ring for index " << iRingIndex
369 << " , this should be extremely rare!";
370 FillHistsFakeRing(ring);
371 continue;
372 }
373
374 const CbmLink matchedLink{ringMatch->GetMatchedLink()};
375 const auto* mcTrack = static_cast<const CbmMCTrack*>(fMcTracks->Get(matchedLink));
376 if (!mcTrack) {
377 LOG(warn) << GetName() << ": mcTrack not found for matched link " << matchedLink.ToString() << " !";
378 FillHistsFakeRing(ring);
379 continue;
380 }
381
382 // Normal fake rings
383 const double quota{ringMatch->GetTrueOverAllHitsRatio()};
384 if (quota < fQuotaRich) {
385 FillHistsFakeRing(ring);
386 continue;
387 }
388
389 const bool isUpperCamera{ring->GetCenterY() > 0.};
390 std::map<CbmLink, int>& accRings = isUpperCamera ? accRingsCam[0] : accRingsCam[1];
391 if (accRings.count(matchedLink) > 0) {
392 accRings[matchedLink]++;
393 if (accRings[matchedLink] > 1) {
394 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::Clone));
395 }
396 else {
397 FillHistsTrueRecoRing(ring, mcTrack);
398 }
399 }
400 else {
401 // True reco, but no accepted, example for this case:
402 // 5 Hits from one MC mother particle. A ring is reconstruced
403 // from those 5 Hits + 2 other. The quota will be above threshold,
404 // hence a true ring. But no acc ring counterpart exists,
405 // because we require >= 7 hits for a accepted ring usually.
406 FillHistsFakeRing(ring);
407 continue;
408 }
409 }
410
411 for (const auto& accRings : accRingsCam) {
412 for (const auto& [link, nMatchedRings] : accRings) {
413 const auto* mcTrack = static_cast<const CbmMCTrack*>(fMcTracks->Get(link));
414 if (!mcTrack) continue;
415
416 fhRingRecoEff.at(ERecoRingType::TrueReco)->Fill(mcTrack->GetP(), static_cast<double>(nMatchedRings > 0), 1.);
417
418 if (IsMcPrimaryElectron(mcTrack)) {
419 fhRingRecoEff.at(ERecoRingType::PrimEl)->Fill(mcTrack->GetP(), static_cast<double>(nMatchedRings > 0), 1.);
420 }
421 else if (IsMcSecondaryElectron(mcTrack)) {
422 fhRingRecoEff.at(ERecoRingType::SecEl)->Fill(mcTrack->GetP(), static_cast<double>(nMatchedRings > 0), 1.);
423 }
424 else if (IsMcPion(mcTrack)) {
425 fhRingRecoEff.at(ERecoRingType::Pion)->Fill(mcTrack->GetP(), static_cast<double>(nMatchedRings > 0), 1.);
426 }
427 else {
428 fhRingRecoEff.at(ERecoRingType::Other)->Fill(mcTrack->GetP(), static_cast<double>(nMatchedRings > 0), 1.);
429 }
430 }
431 }
432}
433
435{
436 // * MC part starting here
437 if (!IsMCUsed()) return;
438 // Sanity check for amount of ringTypes
439 const double nRecoRings{fhRingTypeCounts->GetBinContent(ERecoRingType::Reco + 2)};
440 const double nTrueRecoRings{fhRingTypeCounts->GetBinContent(ERecoRingType::TrueReco + 2)};
441 const double nSumParticleTypes{fhRingTypeCounts->GetBinContent(ERecoRingType::PrimEl + 2)
442 + fhRingTypeCounts->GetBinContent(ERecoRingType::SecEl + 2)
443 + fhRingTypeCounts->GetBinContent(ERecoRingType::Pion + 2)
444 + fhRingTypeCounts->GetBinContent(ERecoRingType::Other + 2)};
445 const double nSumFakeClone{fhRingTypeCounts->GetBinContent(ERecoRingType::Fake + 2)
446 + fhRingTypeCounts->GetBinContent(ERecoRingType::Clone + 2)};
447 if (static_cast<int>(std::round(nTrueRecoRings)) != static_cast<int>(std::round(nSumParticleTypes))) {
448 LOG(error) << "nTrueRecoRings != nSumParticleTypes. This should never happen!";
449 }
450 if (static_cast<int>(std::round(nRecoRings)) != static_cast<int>(std::round(nTrueRecoRings + nSumFakeClone))) {
451 LOG(error) << "nRecoRingsTotal != nTrueRecoRingsTotal + nSumFakeClone. This should never happen!";
452 }
453
454 const std::array<std::string, 4> flagNames{"Mean efficiency all", "Mean efficiency primary electrons",
455 "Mean efficiency secondary electrons", "Mean efficiency pions"};
456 for (int type = ERecoRingType::TrueReco; type <= ERecoRingType::Pion; type++) {
457 double val = fhRingRecoEff.at(type)->GetMean(2);
458 bool status = val >= fRingRecoEffsMin.at(type);
459 std::string msg = status ? "" : Form("value %f < %f", val, fRingRecoEffsMin.at(type));
460 StoreCheckResult(flagNames.at(type), status, msg);
461 }
462 {
463 double purity = fhRingTypeCounts->GetBinContent(ERecoRingType::TrueReco + 2)
464 / fhRingTypeCounts->GetBinContent(ERecoRingType::Reco + 2);
465 bool status = purity >= fRingPurityMin;
466 std::string msg = status ? "" : Form("value %f < %f", purity, fRingPurityMin);
467 StoreCheckResult("Mean ring reco purity", status, msg);
468 }
469
470 // Efficiency and purity summary
471 auto GetErrorFraction = [&](const double meanNom, const double errNom, const double meanDenom,
472 const double errDenom) {
473 const double sqrtFactor =
474 std::sqrt((errNom / meanNom) * (errNom / meanNom) + (errDenom / meanDenom) * (errDenom / meanDenom));
475 return (meanNom / meanDenom) * sqrtFactor;
476 };
477
478 auto* pTable = MakeQaObject<CbmQaTable>("table_efficiency", "RICH ring reconstruction efficiencies and purity", 8, 1);
479 pTable->SetColWidth(30);
480 pTable->SetNamesOfCols({" mean +/- error"});
481 pTable->SetNamesOfRows({{"All particle efficiency"},
482 {"Primary electron efficiency"},
483 {"Secondary electron efficiency"},
484 {"Pion efficiency"},
485 {"Other efficiency"},
486 {"Fake rate"},
487 {"Clone rate"},
488 {"Purity"}});
489 for (int type = ERecoRingType::TrueReco; type <= ERecoRingType::Other; type++) {
490 pTable->SetCell(type, 0, fhRingRecoEff.at(type)->GetMean(2), fhRingRecoEff.at(type)->GetMeanError(2));
491 }
492 const std::array<ERecoRingType, 3> ringTypes{ERecoRingType::Fake, ERecoRingType::Clone, ERecoRingType::TrueReco};
493 const std::array<int, 3> rowIndex{5, 6, 7};
494 for (int i = 0; i < 3; ++i) {
495 pTable->SetCell(rowIndex.at(i), 0,
496 fhRingTypeCounts->GetBinContent(ringTypes.at(i) + 2)
497 / fhRingTypeCounts->GetBinContent(ERecoRingType::Reco + 2),
498 GetErrorFraction(fhRingTypeCounts->GetBinContent(ringTypes.at(i) + 2),
499 fhRingTypeCounts->GetBinError(ringTypes.at(i) + 2),
500 fhRingTypeCounts->GetBinContent(ERecoRingType::Reco + 2),
501 fhRingTypeCounts->GetBinError(ERecoRingType::Reco + 2)));
502 }
503 LOG(info) << '\n' << pTable->ToString(4, true);
504}
505
507{
508 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::TrueReco));
510
511 if (IsMcPrimaryElectron(mcTrack)) {
512 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::PrimEl));
514 }
515 else if (IsMcSecondaryElectron(mcTrack)) {
516 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::SecEl));
518 }
519 else if (IsMcPion(mcTrack)) {
520 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::Pion));
522 }
523 else {
524 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::Other));
526 }
527}
528
530{
531 fhRingTypeCounts->Fill(static_cast<double>(ERecoRingType::Fake));
533}
534
536 const ERecoRingType ringType)
537{
538 fhRingRecoPurityXY->Fill(ring->GetCenterX(), std::abs(ring->GetCenterY()), ringType == ERecoRingType::Fake ? 0. : 1.);
539
540 // Fill 1D ring feature histograms
541 auto& featureHists = fhRingTypeFeatures.at(ringType);
542 featureHists.at(ERingFeature::Radius)->Fill(ring->GetRadius());
543 featureHists.at(ERingFeature::NHits)->Fill(ring->GetNofHits());
544 featureHists.at(ERingFeature::CenterX)->Fill(ring->GetCenterX());
545 featureHists.at(ERingFeature::CenterY)->Fill(ring->GetCenterY());
546 featureHists.at(ERingFeature::Aaxis)->Fill(ring->GetAaxis());
547 featureHists.at(ERingFeature::Baxis)->Fill(ring->GetBaxis());
548 featureHists.at(ERingFeature::BoA)->Fill(ring->GetBaxis() / ring->GetAaxis());
549 featureHists.at(ERingFeature::Phi)->Fill(ring->GetPhi());
550 featureHists.at(ERingFeature::Chi2oNDF)->Fill(ring->GetChi2() / static_cast<double>(ring->GetNDF()));
551 // featureHists.at(ERingFeature::Angle)->Fill(ring->GetAngle());
552 featureHists.at(ERingFeature::RadialPosition)->Fill(ring->GetRadialPosition());
553 featureHists.at(ERingFeature::RadialAngle)->Fill(ring->GetRadialAngle());
554
555 // Fill 2D ring feature vs MC momentum histograms
556 if (ringType == ERecoRingType::Fake || !mcTrack) return; // Skip ring feature vs momentum for fake rings
557 auto& featureHistsMomentum = fhRingTypeFeaturesMomentum.at(ringType);
558 featureHistsMomentum.at(ERingFeature::Radius)->Fill(mcTrack->GetP(), ring->GetRadius());
559 featureHistsMomentum.at(ERingFeature::NHits)->Fill(mcTrack->GetP(), ring->GetNofHits());
560 featureHistsMomentum.at(ERingFeature::CenterX)->Fill(mcTrack->GetP(), ring->GetCenterX());
561 featureHistsMomentum.at(ERingFeature::CenterY)->Fill(mcTrack->GetP(), ring->GetCenterY());
562 featureHistsMomentum.at(ERingFeature::Aaxis)->Fill(mcTrack->GetP(), ring->GetAaxis());
563 featureHistsMomentum.at(ERingFeature::Baxis)->Fill(mcTrack->GetP(), ring->GetBaxis());
564 featureHistsMomentum.at(ERingFeature::BoA)->Fill(mcTrack->GetP(), ring->GetBaxis() / ring->GetAaxis());
565 featureHistsMomentum.at(ERingFeature::Phi)->Fill(mcTrack->GetP(), ring->GetPhi());
566 featureHistsMomentum.at(ERingFeature::Chi2oNDF)
567 ->Fill(mcTrack->GetP(), ring->GetChi2() / static_cast<double>(ring->GetNDF()));
568 // featureHistsMomentum.at(ERingFeature::Angle)->Fill(mcTrack->GetP(), ring->GetAngle());
569 featureHistsMomentum.at(ERingFeature::RadialPosition)->Fill(mcTrack->GetP(), ring->GetRadialPosition());
570 featureHistsMomentum.at(ERingFeature::RadialAngle)->Fill(mcTrack->GetP(), ring->GetRadialAngle());
571}
572
573
575{
576 if (!mcTrack) return false;
577 return (std::abs(mcTrack->GetPdgCode()) == 11
578 && (mcTrack->GetMotherId() == -1 || mcTrack->GetGeantProcessId() == kPPrimary));
579}
580
582{
583 if (!mcTrack) return false;
584 return (std::abs(mcTrack->GetPdgCode()) == 11 && !IsMcPrimaryElectron(mcTrack));
585}
586
588{
589 if (!mcTrack) return false;
590 return std::abs(mcTrack->GetPdgCode()) == 211;
591}
@ kRich
Ring-Imaging Cherenkov Detector.
Definition CbmDefs.h:49
FairTask for matching RECO data to MC.
Definition of CbmQaTable class.
QA-task for RICH ring reconstruction.
int Int_t
static CbmDigiManager * Instance()
Static instance.
Class characterising one event by a collection of links (indices) to data objects,...
Definition CbmEvent.h:34
Task class creating and managing CbmMCDataArray objects.
double GetP() const
Definition CbmMCTrack.h:97
uint32_t GetGeantProcessId() const
Definition CbmMCTrack.h:66
int32_t GetMotherId() const
Definition CbmMCTrack.h:68
int32_t GetPdgCode() const
Definition CbmMCTrack.h:67
static std::vector< CbmLink > GetMcTrackMotherIdsForRichHit(CbmDigiManager *digiMan, const CbmRichHit *hit, CbmMCDataArray *richPoints, CbmMCDataArray *mcTracks)
Get CbmLinks of Mother MC Tracks for RICH hit.
T * MakeQaObject(TString sName, TString sTitle, Args... args)
Definition CbmQaIO.h:260
CbmEvent * GetCurrentEvent()
Gets pointer to current event.
Definition CbmQaTask.h:216
void StoreCheckResult(const std::string &tag, bool result, const std::string &msg="")
Stores check flag to the check-list.
bool IsMCUsed() const
Returns flag, whether MC information is used or not in the task.
Definition CbmQaTask.h:126
void FillHistsFakeRing(const CbmRichRing *ring)
void FillHistsTrueRecoRing(const CbmRichRing *ring, const CbmMCTrack *mcTrack)
TClonesArray * fRichRingMatches
bool IsMcPion(const CbmMCTrack *mcTrack)
TClonesArray * fRichHits
CbmMCDataArray * fMcTracks
std::array< std::array< TH2D *, 12 >, 5 > fhRingTypeFeaturesMomentum
TClonesArray * fRichRings
void FillHistsRingFeatures(const CbmRichRing *ring, const CbmMCTrack *mcTrack, const ERecoRingType ringType)
bool IsMcSecondaryElectron(const CbmMCTrack *mcTrack)
CbmMCDataArray * fRichPoints
static constexpr double fQuotaRich
static constexpr int fAccRingMinNumHits
TClonesArray * fCbmEvents
std::array< std::array< TH1D *, 12 >, 6 > fhRingTypeFeatures
static constexpr double fRingPurityMin
CbmDigiManager * fDigiManager
void ExecQa() override
Method to fill histograms per event or time-slice.
std::array< TH1D *, 12 > fhRingFeatures
void Check() override
Function to check, if the QA results are acceptable.
std::array< TProfile *, 5 > fhRingRecoEff
TProfile2D * fhRingRecoPurityXY
static constexpr std::array< double, 4 > fRingRecoEffsMin
TClonesArray * fRichProjections
bool IsMcPrimaryElectron(const CbmMCTrack *mcTrack)
InitStatus InitQa() override
Initializes the task.
double GetRadialAngle() const
float GetRadius() const
Definition CbmRichRing.h:79
double GetAaxis() const
Definition CbmRichRing.h:80
int32_t GetNofHits() const
Definition CbmRichRing.h:37
float GetCenterX() const
Definition CbmRichRing.h:77
double GetChi2() const
Definition CbmRichRing.h:92
double GetPhi() const
Definition CbmRichRing.h:84
double GetNDF() const
Definition CbmRichRing.h:93
float GetCenterY() const
Definition CbmRichRing.h:78
float GetRadialPosition() const
double GetBaxis() const
Definition CbmRichRing.h:81