2020#include "PWGEM/PhotonMeson/DataModel/gammaTables.h"
2121
2222#include <Framework/ASoA.h>
23+ #include <Framework/HistogramRegistry.h>
2324
2425#include <TNamed.h>
2526
@@ -92,7 +93,7 @@ class EMCPhotonCut : public TNamed
9293 EMCPhotonCut() = default;
9394 EMCPhotonCut(const char* name, const char* title) : TNamed(name, title) {}
9495
95- enum class EMCPhotonCuts : int {
96+ enum class EMCPhotonCuts : std::uint8_t {
9697 // cluster cut
9798 kDefinition = 0,
9899 kEnergy,
@@ -105,6 +106,12 @@ class EMCPhotonCut : public TNamed
105106 kNCuts
106107 };
107108
109+ enum class TrackType : std::uint8_t {
110+ // cluster cut
111+ kPrimary = 0,
112+ kSecondary,
113+ };
114+
108115 static const char* mCutNames[static_cast<int>(EMCPhotonCuts::kNCuts)];
109116
110117 constexpr auto getClusterId(o2::soa::is_iterator auto const& t) const
@@ -126,7 +133,7 @@ class EMCPhotonCut : public TNamed
126133 /// \param GetPhiCut lambda to get the phi cut value
127134 /// \param applyEoverP bool to check if E/p should be checked (for secondaries we do not check this!)
128135 bool checkTrackMatching(o2::soa::is_iterator auto const& cluster, IsTrackIterator auto& emcmatchedtrack, o2::soa::RowViewSentinel const emcmatchedtrackEnd,
129- bool applyEoverP, auto GetEtaCut, auto GetPhiCut) const
136+ bool applyEoverP, auto GetEtaCut, auto GetPhiCut, o2::framework::HistogramRegistry* fRegistry = nullptr, TrackType trackType = TrackType::kPrimary ) const
130137 {
131138 // advance to cluster
132139 while (emcmatchedtrack != emcmatchedtrackEnd && getClusterId(emcmatchedtrack) < cluster.globalIndex()) {
@@ -150,29 +157,137 @@ class EMCPhotonCut : public TNamed
150157 (dPhi > GetPhiCut(trackpt)) ||
151158 (applyEoverP && cluster.e() / trackp >= mMinEoverP);
152159 if (!fail) {
160+ if (mDoQA && fRegistry != nullptr) {
161+ switch (trackType) {
162+ case TrackType::kPrimary:
163+ fRegistry->fill(HIST("Cluster/hTrackdEtadPhi"), dEta, dPhi);
164+ fRegistry->fill(HIST("Cluster/hTrackdEtaPt"), dEta, trackpt);
165+ fRegistry->fill(HIST("Cluster/hTrackdPhiPt"), dPhi, trackpt);
166+ break;
167+ case TrackType::kSecondary:
168+ fRegistry->fill(HIST("Cluster/hSecTrackdEtadPhi"), dEta, dPhi);
169+ fRegistry->fill(HIST("Cluster/hSecTrackdEtaPt"), dEta, trackpt);
170+ fRegistry->fill(HIST("Cluster/hSecTrackdPhiPt"), dPhi, trackpt);
171+ break;
172+ default:
173+ break;
174+ }
175+ }
153176 return false; // cluster got a track matche to it
154177 }
155178 ++emcmatchedtrack;
156179 }
157180 return true; // all tracks checked, cluster survives
158181 }
159182
183+ void fillBeforeClusterHistogram(o2::soa::is_iterator auto const& cluster, o2::framework::HistogramRegistry* fRegistry = nullptr)
184+ {
185+
186+ if (mDoQA == false || fRegistry == nullptr) {
187+ return;
188+ }
189+
190+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), 0, cluster.e());
191+ fRegistry->fill(HIST("Cluster/before/hE"), 0, cluster.e());
192+ fRegistry->fill(HIST("Cluster/before/hPt"), 0, cluster.pt());
193+ fRegistry->fill(HIST("Cluster/before/hEtaPhi"), 0, cluster.eta(), cluster.phi());
194+ fRegistry->fill(HIST("Cluster/before/hNCell"), 0, cluster.nCells(), cluster.e());
195+ fRegistry->fill(HIST("Cluster/before/hM02"), 0, cluster.m02(), cluster.e());
196+ fRegistry->fill(HIST("Cluster/before/hTime"), 0, cluster.time(), cluster.e());
197+ }
198+
199+ void fillAfterClusterHistogram(o2::soa::is_iterator auto const& cluster, o2::framework::HistogramRegistry* fRegistry = nullptr)
200+ {
201+
202+ if (mDoQA == false || fRegistry == nullptr) {
203+ return;
204+ }
205+
206+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), 0, cluster.e());
207+ fRegistry->fill(HIST("Cluster/before/hE"), 0, cluster.e());
208+ fRegistry->fill(HIST("Cluster/before/hPt"), 0, cluster.pt());
209+ fRegistry->fill(HIST("Cluster/before/hEtaPhi"), 0, cluster.eta(), cluster.phi());
210+ fRegistry->fill(HIST("Cluster/before/hNCell"), 0, cluster.nCells(), cluster.e());
211+ fRegistry->fill(HIST("Cluster/before/hM02"), 0, cluster.m02(), cluster.e());
212+ fRegistry->fill(HIST("Cluster/before/hTime"), 0, cluster.time(), cluster.e());
213+ }
214+
160215 /// \brief check if given clusters survives all cuts
161216 /// \param flags EMBitFlags where results will be stored
162217 /// \param cluster cluster table to check
163218 /// \param matchedTracks matched primary tracks table
164219 /// \param matchedSecondaries matched secondary tracks table
165- void AreSelectedRunning(EMBitFlags& flags, o2::soa::is_table auto const& clusters, IsTrackContainer auto const& emcmatchedtracks, IsTrackContainer auto const& secondaries) const
220+ /// \param fRegistry HistogramRegistry pointer of the main task
221+ void AreSelectedRunning(EMBitFlags& flags, o2::soa::is_table auto const& clusters, IsTrackContainer auto const& emcmatchedtracks, IsTrackContainer auto const& secondaries, o2::framework::HistogramRegistry* fRegistry = nullptr)
166222 {
167223 auto emcmatchedtrackIter = emcmatchedtracks.begin();
168224 auto emcmatchedtrackEnd = emcmatchedtracks.end();
169225 auto secondaryIter = secondaries.begin();
170226 auto secondaryEnd = secondaries.end();
171227 size_t iCluster = 0;
228+
229+ // Check if we want to do QA and provided proper histogram registry
230+ if (mDoQA && fRegistry != nullptr) {
231+ const o2::framework::AxisSpec thAxisClusterEnergy{500, 0, 50, "#it{E}_{cls} (GeV)"};
232+ const o2::framework::AxisSpec thAxisMomentum{250, 0., 25., "#it{p}_{T} (GeV/#it{c})"};
233+ const o2::framework::AxisSpec thAxisDEta{200, -0.1, 0.1, "#Delta#eta"};
234+ const o2::framework::AxisSpec thAxisDPhi{200, -0.1, 0.1, "#Delta#varphi (rad)"};
235+ const o2::framework::AxisSpec thAxisEnergy{500, 0., 50., "#it{E} (GeV)"};
236+ const o2::framework::AxisSpec thAxisEta{320, -0.8, 0.8, "#eta"};
237+ const o2::framework::AxisSpec thAxisPhi{500, 0, o2::constants::math::TwoPI, "#varphi (rad)"};
238+ const o2::framework::AxisSpec thAxisNCell{51, -0.5, 50.5, "#it{N}_{cell}"};
239+ const o2::framework::AxisSpec thAxisM02{200, 0, 2.0, "#it{M}_{02}"};
240+ const o2::framework::AxisSpec thAxisTime{300, -150, +150, "#it{t}_{cls} (ns)"};
241+ const o2::framework::AxisSpec thAxisEoverP{400, 0, 10., "#it{E}_{cls}/#it{p}_{track} (#it{c})"};
242+
243+ fRegistry->add("Cluster/before/hE", "E_{cluster};#it{E}_{cluster} (GeV);#it{N}_{cluster}", o2::framework::kTH1F, {thAxisClusterEnergy}, true);
244+ fRegistry->add("Cluster/before/hPt", "Transverse momenta of clusters;#it{p}_{T} (GeV/c);#it{N}_{cluster}", o2::framework::kTH1F, {thAxisClusterEnergy}, true);
245+ fRegistry->add("Cluster/before/hNgamma", "Number of #gamma candidates per collision;#it{N}_{#gamma} per collision;#it{N}_{collisions}", o2::framework::kTH1F, {{1001, -0.5f, 1000.5f}}, true);
246+ fRegistry->add("Cluster/before/hEtaPhi", "#eta vs #varphi;#eta;#varphi (rad.)", o2::framework::kTH2F, {thAxisEta, thAxisPhi}, true);
247+ fRegistry->add("Cluster/before/hNCell", "#it{N}_{cells};N_{cells} (GeV);#it{E}_{cluster} (GeV)", o2::framework::kTH2F, {thAxisNCell, thAxisClusterEnergy}, true);
248+ fRegistry->add("Cluster/before/hM02", "Long ellipse axis;#it{M}_{02} (cm);#it{E}_{cluster} (GeV)", o2::framework::kTH2F, {thAxisM02, thAxisClusterEnergy}, true);
249+ fRegistry->add("Cluster/before/hTime", "Cluster time;#it{t}_{cls} (ns);#it{E}_{cluster} (GeV)", o2::framework::kTH2F, {thAxisTime, thAxisClusterEnergy}, true);
250+
251+ fRegistry->addClone("Cluster/before/", "Cluster/after/");
252+
253+ auto hClusterQualityCuts = fRegistry->add<TH2>("Cluster/hClusterQualityCuts", "Energy at which clusters are removed by a given cut;;#it{E} (GeV)", o2::framework::kTH2F, {{static_cast<int>(EMCPhotonCut::EMCPhotonCuts::kNCuts) + 2, -0.5, static_cast<double>(EMCPhotonCut::EMCPhotonCuts::kNCuts) + 1.5}, thAxisClusterEnergy}, true);
254+ hClusterQualityCuts->GetXaxis()->SetBinLabel(1, "In");
255+ hClusterQualityCuts->GetXaxis()->SetBinLabel(2, "Definition");
256+ hClusterQualityCuts->GetXaxis()->SetBinLabel(3, "Energy");
257+ hClusterQualityCuts->GetXaxis()->SetBinLabel(4, "NCell");
258+ hClusterQualityCuts->GetXaxis()->SetBinLabel(5, "M02");
259+ hClusterQualityCuts->GetXaxis()->SetBinLabel(6, "Timing");
260+ hClusterQualityCuts->GetXaxis()->SetBinLabel(7, "TM");
261+ hClusterQualityCuts->GetXaxis()->SetBinLabel(8, "Sec. TM");
262+ hClusterQualityCuts->GetXaxis()->SetBinLabel(9, "Exotic");
263+ hClusterQualityCuts->GetXaxis()->SetBinLabel(10, "Out");
264+
265+ fRegistry->add("Cluster/hTrackdEtadPhi", "d#eta vs. d#varphi of matched tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDEta, thAxisDPhi}, true);
266+ fRegistry->add("Cluster/hTrackdEtaPt", "d#eta vs. track pT of matched tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDEta, thAxisMomentum}, true);
267+ fRegistry->add("Cluster/hTrackdPhiPt", "d#varphi vs. track pT of matched tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDPhi, thAxisMomentum}, true);
268+ fRegistry->add("Cluster/hSecTrackdEtadPhi", "d#eta vs. d#varphi of matched secondary tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDEta, thAxisDPhi}, true);
269+ fRegistry->add("Cluster/hSecTrackdEtaPt", "d#eta vs. track pT of matched secondary tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDEta, thAxisMomentum}, true);
270+ fRegistry->add("Cluster/hSecTrackdPhiPt", "d#varphi vs. track pT of matched secondary tracks;d#eta;d#varphi (rad.)", o2::framework::kTH2F, {thAxisDPhi, thAxisMomentum}, true);
271+ }
272+
273+ nTotClusterPerColl = 0;
274+ currentCollID = clusters.iteratorAt(0).emeventId();
172275 for (const auto& cluster : clusters) {
276+ if (currentCollID == cluster.emeventId()) {
277+ ++nTotClusterPerColl;
278+ } else {
279+ fRegistry->fill(HIST("Cluster/before/hNgamma"), nTotClusterPerColl);
280+ nTotClusterPerColl = 0;
281+ }
282+ if (mDoQA == true || fRegistry != nullptr) {
283+ fillBeforeClusterHistogram(cluster, fRegistry);
284+ }
173285 if (!IsSelectedRunning(cluster, emcmatchedtrackIter, emcmatchedtrackEnd, secondaryIter, secondaryEnd)) {
174286 flags.set(iCluster);
287+ } else if (mDoQA == true || fRegistry != nullptr) {
288+ fillAfterClusterHistogram(cluster, fRegistry);
175289 }
290+ currentCollID = cluster.emeventId();
176291 ++iCluster;
177292 }
178293 }
@@ -184,32 +299,47 @@ class EMCPhotonCut : public TNamed
184299 /// \param secondaryIter current iterator of matched secondary tracks
185300 /// \param secondaryEnd end iterator of matched secondary tracks
186301 /// \return true if cluster survives all cuts else false
187- bool IsSelectedRunning(o2::soa::is_iterator auto const& cluster, IsTrackIterator auto& emcmatchedtrackIter, o2::soa::RowViewSentinel const emcmatchedtrackEnd, IsTrackIterator auto& secondaryIter, o2::soa::RowViewSentinel const secondaryEnd) const
302+ bool IsSelectedRunning(o2::soa::is_iterator auto const& cluster, IsTrackIterator auto& emcmatchedtrackIter, o2::soa::RowViewSentinel const emcmatchedtrackEnd, IsTrackIterator auto& secondaryIter, o2::soa::RowViewSentinel const secondaryEnd, o2::framework::HistogramRegistry* fRegistry = nullptr)
188303 {
189304 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kDefinition, cluster)) {
305+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kDefinition) + 1, cluster.e());
190306 return false;
191307 }
192308 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kEnergy, cluster)) {
309+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kEnergy) + 1, cluster.e());
193310 return false;
194311 }
195312 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kNCell, cluster)) {
313+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kNCell) + 1, cluster.e());
196314 return false;
197315 }
198316 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kM02, cluster)) {
317+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kM02) + 1, cluster.e());
199318 return false;
200319 }
201320 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kTiming, cluster)) {
321+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kTiming) + 1, cluster.e());
202322 return false;
203323 }
204324 if (mUseTM && (!IsSelectedEMCalRunning(EMCPhotonCuts::kTM, cluster, emcmatchedtrackIter, emcmatchedtrackEnd))) {
325+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kTM) + 1, cluster.e());
205326 return false;
206327 }
207328 if (mUseSecondaryTM && (!IsSelectedEMCalRunning(EMCPhotonCuts::kSecondaryTM, cluster, secondaryIter, secondaryEnd))) {
329+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kSecondaryTM) + 1, cluster.e());
208330 return false;
209331 }
210332 if (!IsSelectedEMCalRunning(EMCPhotonCuts::kExotic, cluster)) {
333+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kExotic) + 1, cluster.e());
211334 return false;
212335 }
336+ fRegistry->fill(HIST("Cluster/hClusterQualityCuts"), static_cast<int>(EMCPhotonCuts::kNCuts) + 1, cluster.e());
337+ if (currentCollID == cluster.emeventId()) {
338+ ++nAccClusterPerColl;
339+ } else {
340+ fRegistry->fill(HIST("Cluster/before/hNgamma"), nAccClusterPerColl);
341+ nAccClusterPerColl = 0;
342+ }
213343 return true;
214344 }
215345
@@ -439,6 +569,10 @@ class EMCPhotonCut : public TNamed
439569 /// \param flag flag to use secondary track matching
440570 void SetUseSecondaryTM(bool flag = false);
441571
572+ /// \brief Set flag to do QA
573+ /// \param flag flag to do QA
574+ void SetDoQA(bool flag = false);
575+
442576 /// \brief Set parameters for track matching delta eta = a + (pT + b)^c
443577 /// \param a a in a + (pT + b)^c
444578 /// \param b b in a + (pT + b)^c
@@ -517,8 +651,13 @@ class EMCPhotonCut : public TNamed
517651 float mMaxTime{25.f}; ///< maximum cluster timing
518652 float mMinEoverP{1.75f}; ///< minimum cluster energy over track momentum ratio needed for the pair to be considered matched
519653 bool mUseExoticCut{true}; ///< flag to decide if the exotic cluster cut is to be checked or not
520- bool mUseTM{true}; ///< flag to decide if track matching cut is to be checek or not
521- bool mUseSecondaryTM{false}; ///< flag to decide if seconary track matching cut is to be checek or not
654+ bool mUseTM{true}; ///< flag to decide if track matching cut is to be check or not
655+ bool mUseSecondaryTM{false}; ///< flag to decide if seconary track matching cut is to be check or not
656+ bool mDoQA{false}; ///< flag to decide if QA should be done or not
657+
658+ uint nTotClusterPerColl{0}; ///< running number of all cluster per collision used for QA
659+ uint nAccClusterPerColl{0}; ///< running number of accepted cluster per collision used for QA
660+ int currentCollID{-1}; ///< running collision ID of clusters used for QA
522661
523662 TrackMatchingParams mTrackMatchingEtaParams = {-1.f, 0.f, 0.f};
524663 TrackMatchingParams mTrackMatchingPhiParams = {-1.f, 0.f, 0.f};
0 commit comments