Skip to content

Commit 2071c92

Browse files
authored
[PWGLF] Add More QA hist in HStrangeCorrelation.cxx (#17496)
1 parent d9e13d9 commit 2071c92

1 file changed

Lines changed: 105 additions & 19 deletions

File tree

PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx

Lines changed: 105 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ struct HStrangeCorrelation {
303303
struct : ConfigurableGroup {
304304
std::string prefix = "pairLossK0Configurations";
305305
Configurable<bool> compactComparisonMode{"compactComparisonMode", false, "write only the Rec/Truth/Gen/Final comparison and cumulative Rec control variants; suppress the original PairLoss diagnostic suite"};
306+
Configurable<bool> doClosureTestStages{"doClosureTestStages", true, "create and fill the whole ClosureTest/PairLossK0 folder: the truth and any-reconstructed-object stages of the truth h-K0 pair, mirroring the first processPairLossK0MC stages"};
306307
Configurable<bool> applyRecoEventSelection{"applyRecoEventSelection", true, "apply the standard reconstructed-event selection in the K0 pair-loss diagnostic"};
307308
Configurable<float> daughterPtMin{"daughterPtMin", 0.05f, "minimum generated daughter pT for the findable K0 category"};
308309
Configurable<float> daughterEtaMax{"daughterEtaMax", 0.9f, "maximum absolute generated daughter eta for the findable K0 category"};
@@ -327,6 +328,10 @@ struct HStrangeCorrelation {
327328
Configurable<bool> triggerTracksRequireITS{"triggerTracksRequireITS", true, "must match triggerRequireITS in hStrangeCorrelationFilter.cxx"};
328329
Configurable<int> triggerTracksMaxSharedClusters{"triggerTracksMaxSharedClusters", 200, "must match triggerMaxTPCSharedClusters in hStrangeCorrelationFilter.cxx"};
329330
Configurable<bool> triggerTracksRequireLayer0{"triggerTracksRequireLayer0", false, "must match triggerRequireL0 in hStrangeCorrelationFilter.cxx"};
331+
// Separate from trackSelection.dcaXY*, which is this task's systematic-variation knob: the
332+
// replica must follow the value the filter was run with, not the varied analysis-level one.
333+
Configurable<float> triggerTracksDcaXYconstant{"triggerTracksDcaXYconstant", 0.004f, "must match dcaXYconstant in hStrangeCorrelationFilter.cxx"};
334+
Configurable<float> triggerTracksDcaXYpTdep{"triggerTracksDcaXYpTdep", 0.013f, "must match dcaXYpTdep in hStrangeCorrelationFilter.cxx"};
330335
} pairLossK0Configurations;
331336

332337
struct ValidCollision {
@@ -502,18 +507,26 @@ struct HStrangeCorrelation {
502507
int tpcSharedClusters = 0;
503508
int itsClusters = 0;
504509
bool hasLayer0 = false;
510+
// Needed to replicate the declarative preFilterTracks DCAxy cut of
511+
// hStrangeCorrelationFilter.cxx, which uses exactly these two columns.
512+
float dcaXY = 0.0f;
513+
float signed1Pt = 0.0f;
505514
};
506515

507516
// First-failing-condition breakdown for the stage3->4 gate ("Trigger track, best collision"
508-
// -> "Trigger in TriggerTracks"). Order mirrors the early-return order of isValidTrigger()
509-
// in hStrangeCorrelationFilter.cxx exactly, so "first reason to fail" means the same thing here.
517+
// -> "Trigger in TriggerTracks"). Order mirrors the order in which hStrangeCorrelationFilter.cxx
518+
// applies its conditions -- the declarative preFilterTracks DCAxy cut first, then the early
519+
// returns of isValidTrigger() -- so "first reason to fail" means the same thing here.
510520
//
511521
// Pass/fail itself is decided by the real TriggerTracks table, not by the replica below;
512522
// the replica only attributes a reason once the table has already said "not in". That keeps
513523
// the Passed bin numerically identical to stage 4 even when the replica's configurables have
514524
// drifted away from the filter's, and routes any such drift into the two dedicated bins.
515525
enum PairLossTriggerTracksFailureReason : int {
516526
PairLossTriggerTracksPassed = 0,
527+
// First, because preFilterTracks is applied to the track table before isValidTrigger() ever
528+
// sees the track, so DCAxy is the earliest condition a trigger candidate can fail.
529+
PairLossTriggerTracksFailDcaXY,
517530
PairLossTriggerTracksFailEta,
518531
PairLossTriggerTracksFailPt,
519532
PairLossTriggerTracksFailCrossedRows,
@@ -532,6 +545,7 @@ struct HStrangeCorrelation {
532545

533546
static constexpr std::array<std::string_view, PairLossTriggerTracksNReasons> PairLossTriggerTracksFailureNames = {
534547
"Passed (really in TriggerTracks)",
548+
"Failed DCAxy prefilter",
535549
"Failed eta window",
536550
"Failed pT window",
537551
"Failed min TPC crossed rows",
@@ -674,15 +688,22 @@ struct HStrangeCorrelation {
674688
.tpcCrossedRows = track.tpcNClsCrossedRows(),
675689
.tpcSharedClusters = track.tpcNClsShared(),
676690
.itsClusters = track.itsNCls(),
677-
.hasLayer0 = static_cast<bool>(TESTBIT(track.itsClusterMap(), 0))};
691+
.hasLayer0 = static_cast<bool>(TESTBIT(track.itsClusterMap(), 0)),
692+
.dcaXY = track.dcaXY(),
693+
.signed1Pt = track.signed1Pt()};
678694
}
679695

680-
// Replicates isValidTrigger() from hStrangeCorrelationFilter.cxx condition-by-condition
681-
// (same early-return order) so that, for a trigger already known to exist in the best
696+
// Replicates preFilterTracks and isValidTrigger() from hStrangeCorrelationFilter.cxx
697+
// condition-by-condition (same order) so that, for a trigger already known to exist in the best
682698
// collision (stage 3), we can tell which single cut is responsible for it not making it
683699
// into the TriggerTracks table (stage 4), instead of only knowing that it failed overall.
684700
int classifyTriggerTracksFailure(PairLossTrackInfo const& info)
685701
{
702+
// Negation of "Filter preFilterTracks = nabs(dcaXY) < dcaXYconstant + dcaXYpTdep * nabs(signed1Pt)":
703+
// same columns, same formula, and >= so that the boundary is rejected exactly as the filter does.
704+
if (std::abs(info.dcaXY) >= pairLossK0Configurations.triggerTracksDcaXYconstant + pairLossK0Configurations.triggerTracksDcaXYpTdep * std::abs(info.signed1Pt)) {
705+
return PairLossTriggerTracksFailDcaXY;
706+
}
686707
if (info.eta > pairLossK0Configurations.triggerTracksEtaMax || info.eta < pairLossK0Configurations.triggerTracksEtaMin) {
687708
return PairLossTriggerTracksFailEta;
688709
}
@@ -2876,12 +2897,38 @@ struct HStrangeCorrelation {
28762897
}
28772898
}
28782899
if (doprocessClosureTest) {
2879-
histos.add("ClosureTest/PairLossK0/Truth/sameEvent/K0Short", "truth h-K0 pairs with the processPairLossK0MC selections", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2880-
histos.add("ClosureTest/PairLossK0/AnyTrack/sameEvent/K0Short", "truth h-K0 pairs whose truth trigger has a reconstructed-track match in any associated collision", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2881-
histos.add("ClosureTest/PairLossK0/Truth/hTrigger", "truth triggers with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2882-
histos.add("ClosureTest/PairLossK0/Truth/hK0Short", "truth K0s with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2883-
histos.add("ClosureTest/PairLossK0/AnyTrack/hTrigger", "truth triggers with a reconstructed-track match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2884-
histos.add("ClosureTest/PairLossK0/AnyTrack/hK0Short", "truth K0s; unchanged at the any-track trigger stage;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2900+
if (pairLossK0Configurations.doClosureTestStages) {
2901+
// Naming inside ClosureTest/PairLossK0: each folder is one reconstruction
2902+
// requirement imposed on the same truth h-K0 pair. "Any" means the object
2903+
// must have at least one reconstructed counterpart (a track with a
2904+
// matching MC label for the trigger, a V0 candidate with a matching MC
2905+
// core for the K0) in any reconstructed collision associated with this MC
2906+
// collision, with no quality selection whatsoever.
2907+
// folder trigger K0 processPairLossK0MC stage
2908+
// Truth truth truth PairLossGenPair
2909+
// AnyTrack any truth PairLossTriggerAnyCollision
2910+
// AnyTrackK0 truth any PairLossV0AnyCollision
2911+
// AnyTrackBoth any any both stages at once
2912+
// Every folder has the same three objects -- sameEvent/K0Short, hTrigger,
2913+
// hK0Short -- and each of them is filled at the level its own folder
2914+
// prescribes, so a folder can be normalised without looking at any other.
2915+
// Consequence: the single-particle spectra repeat across folders in pairs
2916+
// (Truth/hTrigger == AnyTrackK0/hTrigger, AnyTrack/hTrigger ==
2917+
// AnyTrackBoth/hTrigger, Truth/hK0Short == AnyTrack/hK0Short,
2918+
// AnyTrackK0/hK0Short == AnyTrackBoth/hK0Short). That is intended.
2919+
histos.add("ClosureTest/PairLossK0/Truth/sameEvent/K0Short", "truth h-K0 pairs with the processPairLossK0MC selections", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2920+
histos.add("ClosureTest/PairLossK0/AnyTrack/sameEvent/K0Short", "truth h-K0 pairs whose truth trigger has a reconstructed-track match in any associated collision", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2921+
histos.add("ClosureTest/PairLossK0/AnyTrackK0/sameEvent/K0Short", "truth h-K0 pairs whose truth K0 has a V0-candidate match in any associated collision", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2922+
histos.add("ClosureTest/PairLossK0/AnyTrackBoth/sameEvent/K0Short", "truth h-K0 pairs with both the trigger track match and the K0 V0-candidate match in any associated collision", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
2923+
histos.add("ClosureTest/PairLossK0/Truth/hTrigger", "truth triggers with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2924+
histos.add("ClosureTest/PairLossK0/Truth/hK0Short", "truth K0s with the processPairLossK0MC selections;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2925+
histos.add("ClosureTest/PairLossK0/AnyTrack/hTrigger", "truth triggers with a reconstructed-track match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2926+
histos.add("ClosureTest/PairLossK0/AnyTrack/hK0Short", "truth K0s; the K0 stays at truth level in this folder;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2927+
histos.add("ClosureTest/PairLossK0/AnyTrackK0/hTrigger", "truth triggers; the trigger stays at truth level in this folder;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2928+
histos.add("ClosureTest/PairLossK0/AnyTrackK0/hK0Short", "truth K0s with a V0-candidate match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2929+
histos.add("ClosureTest/PairLossK0/AnyTrackBoth/hTrigger", "truth triggers with a reconstructed-track match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2930+
histos.add("ClosureTest/PairLossK0/AnyTrackBoth/hK0Short", "truth K0s with a V0-candidate match in any associated collision;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi});
2931+
}
28852932
for (int i = 0; i < AssocParticleTypes; i++) {
28862933
if (TESTBIT(doCorrelation, i)) {
28872934
histos.add(fmt::format("ClosureTest/sameEvent/{}", Particlenames[i]).c_str(), "", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim});
@@ -5055,16 +5102,27 @@ struct HStrangeCorrelation {
50555102
void processClosureTest(aod::McCollision const& /*mcCollision*/,
50565103
soa::SmallGroups<soa::Join<aod::McCollisionLabels, aod::Collisions, aod::EvSels, aod::CentFT0Ms, aod::CentFT0Cs, aod::PVMults>> const& recCollisions,
50575104
aod::McParticles const& mcParticles,
5105+
aod::V0MCCores const& v0MCCores,
5106+
V0DatasWithoutTrackX const& v0Candidates,
50585107
TracksCompleteMC const& tracks)
50595108
{
50605109

5061-
// Reproduce the first two processPairLossK0MC trigger stages without changing
5062-
// the selections or output of the pre-existing closure-test analysis below.
5063-
// Both histograms remain anchored to the same truth h-K0 pair. "AnyTrack"
5064-
// changes only the trigger requirement: at least one reconstructed track in
5065-
// any reconstructed collision associated with this MC collision must point
5066-
// back to the truth trigger through its MC label.
5110+
// Reproduce the first processPairLossK0MC stages without changing the
5111+
// selections or output of the pre-existing closure-test analysis below. All
5112+
// histograms remain anchored to the same truth h-K0 pair; the folders differ
5113+
// only in which reconstruction requirement is imposed:
5114+
// AnyTrack the truth trigger must have at least one reconstructed track
5115+
// pointing back to it through its MC label, in any
5116+
// reconstructed collision associated with this MC collision
5117+
// (stage PairLossTriggerAnyCollision)
5118+
// AnyTrackK0 the truth K0 must have at least one reconstructed V0
5119+
// candidate pointing back to it, in any associated collision
5120+
// (stage PairLossV0AnyCollision)
5121+
// AnyTrackBoth both requirements at the same time
50675122
auto fillPairLossK0TruthAndAnyTrack = [&]() {
5123+
if (!pairLossK0Configurations.doClosureTestStages) {
5124+
return;
5125+
}
50685126
if (recCollisions.size() == 0) {
50695127
return;
50705128
}
@@ -5082,13 +5140,25 @@ struct HStrangeCorrelation {
50825140
}
50835141

50845142
std::unordered_set<int64_t> pairLossAnyTrackMcParticleIds;
5143+
std::unordered_set<int64_t> pairLossAnyV0McParticleIds;
50855144
for (auto const& collision : recCollisions) {
50865145
const auto trackSlice = tracks.sliceBy(pairLossTracksPerCollision, collision.globalIndex());
50875146
for (auto const& track : trackSlice) {
50885147
if (track.has_mcParticle()) {
50895148
pairLossAnyTrackMcParticleIds.insert(track.mcParticleId());
50905149
}
50915150
}
5151+
// Same V0-side bookkeeping as tracksAnyCollision/v0sAnyCollision in
5152+
// processPairLossK0MC: any V0 candidate in any associated collision whose
5153+
// MC core is a true K0 short, with no candidate-quality selection at all.
5154+
const auto v0Slice = v0Candidates.sliceBy(pairLossV0sPerCollision, collision.globalIndex());
5155+
for (auto const& v0 : v0Slice) {
5156+
const auto v0MC = v0MCCores.iteratorAt(v0.globalIndex());
5157+
if (v0MC.particleIdMC() < 0 || v0MC.pdgCode() != PDG_t::kK0Short) {
5158+
continue;
5159+
}
5160+
pairLossAnyV0McParticleIds.insert(v0MC.particleIdMC());
5161+
}
50925162
}
50935163

50945164
for (auto const& collision : recCollisions) {
@@ -5162,17 +5232,25 @@ struct HStrangeCorrelation {
51625232
pairLossTruthTriggers.push_back(leadingTriggerCopy);
51635233
}
51645234

5235+
// One entry per object per folder, at the level that folder prescribes:
5236+
// the trigger is at truth level in Truth/ and AnyTrackK0/, at any level in
5237+
// AnyTrack/ and AnyTrackBoth/; the K0 is at truth level in Truth/ and
5238+
// AnyTrack/, at any level in AnyTrackK0/ and AnyTrackBoth/.
51655239
for (auto const& truthTrigger : pairLossTruthTriggers) {
51665240
histos.fill(HIST("ClosureTest/PairLossK0/Truth/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi);
5241+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackK0/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi);
51675242
if (pairLossAnyTrackMcParticleIds.find(truthTrigger.globalIndex) != pairLossAnyTrackMcParticleIds.end()) {
51685243
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrack/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi);
5244+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackBoth/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi);
51695245
}
51705246
}
51715247
for (auto const& truthK0 : pairLossTruthK0s) {
5172-
// The any-track stage adds no K0 requirement, so its object-level K0
5173-
// spectrum is intentionally identical to the truth-stage spectrum.
51745248
histos.fill(HIST("ClosureTest/PairLossK0/Truth/hK0Short"), truthK0.pt, truthK0.eta, truthK0.phi);
51755249
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrack/hK0Short"), truthK0.pt, truthK0.eta, truthK0.phi);
5250+
if (pairLossAnyV0McParticleIds.find(truthK0.globalIndex) != pairLossAnyV0McParticleIds.end()) {
5251+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackK0/hK0Short"), truthK0.pt, truthK0.eta, truthK0.phi);
5252+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackBoth/hK0Short"), truthK0.pt, truthK0.eta, truthK0.phi);
5253+
}
51765254
}
51775255

51785256
for (auto const& truthTrigger : pairLossTruthTriggers) {
@@ -5191,10 +5269,18 @@ struct HStrangeCorrelation {
51915269
continue;
51925270
}
51935271

5272+
const bool k0HasAnyV0 = pairLossAnyV0McParticleIds.find(truthK0.globalIndex) != pairLossAnyV0McParticleIds.end();
5273+
51945274
histos.fill(HIST("ClosureTest/PairLossK0/Truth/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
51955275
if (triggerHasAnyTrack) {
51965276
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrack/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
51975277
}
5278+
if (k0HasAnyV0) {
5279+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackK0/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
5280+
}
5281+
if (triggerHasAnyTrack && k0HasAnyV0) {
5282+
histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackBoth/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity);
5283+
}
51985284
}
51995285
}
52005286
return;

0 commit comments

Comments
 (0)