Skip to content

Commit abc2207

Browse files
authored
[PWGEM,PWGJE] EMCal TM monitor: MC truth of the track matching chain (#18443)
1 parent 3315905 commit abc2207

2 files changed

Lines changed: 384 additions & 32 deletions

File tree

‎PWGEM/PhotonMeson/Tasks/twoPhotonMcTask.cxx‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ enum class LegMatchStatus : uint8_t {
119119
kOutsideWindow, // leg found, but outside the track matching window of the analysis
120120
kInsideWindowEoverP, // leg found inside the window, but E/p above the cut (primaries only)
121121
kInsideWindow, // leg found inside the window: the cluster should have been vetoed
122+
kNotGlobalTrack, // primaries only: the leg is not a global track, so it is no candidate of the primary matching
122123
kNStatus
123124
};
124125

@@ -478,12 +479,15 @@ struct TwoPhotonMcTask {
478479
const AxisSpec axisDeltaPhi{100, -0.1, 0.1, "#Delta#varphi (cluster - track)"};
479480
const AxisSpec axisDp{200, -1., 1., "(#it{p}_{match} - #it{p}_{leg}) / #it{p}_{leg}"};
480481
static constexpr std::array<std::string_view, static_cast<int>(SameParticleOrigin::kNOrigins)> OriginLabels = {"leg e^{#pm}", "brems #gamma of leg", "other e^{#pm}", "other"};
481-
static constexpr std::array<std::string_view, static_cast<int>(LegMatchStatus::kNStatus)> StatusLabels = {"no match stored", "no match with leg #it{p}", "outside window", "in window, #it{E}/#it{p} #geq cut", "in window"};
482+
static constexpr std::array<std::string_view, static_cast<int>(LegMatchStatus::kNStatus)> StatusLabels = {"no match stored", "no match with leg #it{p}", "outside window", "in window, #it{E}/#it{p} #geq cut", "in window", "not a global track"};
482483

483484
auto hOrigin = registry.add<TH3>("PCMEMC/SameParticle/hOrigin", "same particle pairs: leading contributor of the cluster", HistType::kTH3F, {thnAxisInvMass, thnAxisPtRec, axisOrigin});
484485
for (std::size_t i = 0; i < OriginLabels.size(); ++i) {
485486
hOrigin->GetZaxis()->SetBinLabel(static_cast<int>(i) + 1, OriginLabels[i].data());
486487
}
488+
// labels make the axis extendable, and TH1Merger::LabelMerge in ROOT 6.36 reads the z labels from the y axis:
489+
// merged TH3 content would end up in a new, unlabelled z bin. With a fixed axis the merge goes bin by bin.
490+
hOrigin->GetZaxis()->SetCanExtend(false);
487491
registry.add("PCMEMC/SameParticle/hLegEoverP", "cluster from a V0 leg: #it{E}_{cls}/#it{p}_{leg}", HistType::kTH2F, {{200, 0., 4., "#it{E}_{cls}/#it{p}_{leg}"}, axisPtLeg});
488492
for (const auto& [type, title] : {std::pair<std::string_view, std::string_view>{"Prim", "primary"}, {"Sec", "secondary"}}) {
489493
auto hStatus = registry.add<TH2>(std::format("PCMEMC/SameParticle/hLeg{}Status", type.data()).data(), std::format("cluster from a V0 leg: leg among the matched {} tracks", title.data()).data(), HistType::kTH2F, {axisStatus, axisPtLeg});
@@ -762,6 +766,30 @@ struct TwoPhotonMcTask {
762766
return PairBucket::kCrossOtherHadron;
763767
}
764768

769+
/// \brief Whether the track of a V0 leg passes the global track selection used by the primary EMCal track matching.
770+
/// Rebuilt from the leg columns of the derived data, following getGlobalTrackSelectionRun3ITSMatch(Run3ITSibAny):
771+
/// the golden chi2 requirement cannot be checked here, and pT/eta are the ones of the leg at the V0 vertex.
772+
/// \param leg V0 leg
773+
template <o2::soa::is_iterator TLeg>
774+
static bool isLikelyGlobalTrack(TLeg const& leg)
775+
{
776+
constexpr float MinPt = 0.1f, MaxEta = 0.8f;
777+
constexpr int MinCrossedRows = 70;
778+
constexpr float MinCrossedRowsOverFindable = 0.8f, MaxChi2TPC = 4.f, MaxChi2ITS = 36.f, MaxDcaZ = 2.f;
779+
const float pt = leg.pt();
780+
if (!leg.hasITS() || !leg.hasTPC() || pt < MinPt || std::fabs(leg.eta()) > MaxEta) {
781+
return false;
782+
}
783+
if (leg.itsNClsInnerBarrel() < 1 || leg.itsChi2NCl() > MaxChi2ITS) { // Run3ITSibAny: at least one hit in ITS layers 0-2
784+
return false;
785+
}
786+
if (leg.tpcNClsCrossedRows() < MinCrossedRows || leg.tpcCrossedRowsOverFindableCls() < MinCrossedRowsOverFindable || leg.tpcChi2NCl() > MaxChi2TPC) {
787+
return false;
788+
}
789+
const float maxDcaXY = 0.0105f + 0.035f / std::pow(pt, 1.1f); // o2-linter: disable=magic-number (global track selection)
790+
return std::fabs(leg.dcaXY()) <= maxDcaXY && std::fabs(leg.dcaZ()) <= MaxDcaZ;
791+
}
792+
765793
/// \brief Look for the V0 leg among the tracks matched to an EMC cluster and classify why it did not veto the cluster.
766794
/// The matched track tables store no track index, so the leg is identified by its momentum.
767795
/// \tparam isSecondary matches are secondaries (V0 legs, no E/p condition) instead of primaries
@@ -865,7 +893,12 @@ struct TwoPhotonMcTask {
865893
return;
866894
}
867895
registry.fill(HIST("PCMEMC/SameParticle/hLegEoverP"), emc.e() / pLeg, ptLeg);
868-
fillLegMatch<false>(matchedPrims.sliceBy(perEMCClusterMT, emc.globalIndex()), emc.e(), pLeg, ptLeg);
896+
// the primary matching only uses global tracks: other legs are no candidate there and get their own status
897+
if (isLikelyGlobalTrack(leg)) {
898+
fillLegMatch<false>(matchedPrims.sliceBy(perEMCClusterMT, emc.globalIndex()), emc.e(), pLeg, ptLeg);
899+
} else {
900+
registry.fill(HIST("PCMEMC/SameParticle/hLegPrimStatus"), static_cast<int>(LegMatchStatus::kNotGlobalTrack), ptLeg);
901+
}
869902
fillLegMatch<true>(matchedSeconds.sliceBy(perEMCClusterMS, emc.globalIndex()), emc.e(), pLeg, ptLeg);
870903
}
871904

0 commit comments

Comments
 (0)