Skip to content

Commit dc62da0

Browse files
authored
[PWGLF] Add Best Collision Cut in Response Hist in hStrangeCorrelation.cxx (#18378)
1 parent ae803ec commit dc62da0

1 file changed

Lines changed: 114 additions & 22 deletions

File tree

‎PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx‎

Lines changed: 114 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,23 @@ struct HStrangeCorrelation {
338338
// see runEventRecoEfficiencyStudy
339339
Configurable<bool> doStageDiagnostics{"doStageDiagnostics", true, "part 1: fill the PairLossK0 truth-pair reconstruction ladder and its diagnostics"};
340340
Configurable<bool> doRecComparison{"doRecComparison", false, "part 2: fill the PairLossK0/Comparison cumulative Rec/Truth/Gen/Final ladder (runs the exact reconstructed path internally)"};
341+
Configurable<bool> recComparisonBestCollisionOnly{"recComparisonBestCollisionOnly", false, "part 2: run the Rec path of PairLossK0/Comparison only in the best reconstructed collision (most PV contributors) of each MC collision, the one the Gen, Truth and Final stages are selected on. Set false to run it in every reconstructed collision, as the data path does"};
341342
Configurable<bool> doGenLevelStudy{"doGenLevelStudy", false, "part 3: fill the PairLossK0/GenStudy generated-vs-reconstructed split, using generator-level event selection only"};
342343
Configurable<bool> doEventRecoEfficiencyStudy{"doEventRecoEfficiencyStudy", false, "fill PairLossK0/EventRecoEfficiency: Nch^gen (charged primaries, |eta| < 1) of all, reconstructed and selected MC collisions, Nch^gen vs multNTracksPVeta1 and multNTracksPVeta1 vs FT0M percentile and amplitude"};
344+
Configurable<bool> nchGenResponseBestCollisionOnly{"nchGenResponseBestCollisionOnly", false, "fill PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1 with the best reconstructed collision (most PV contributors) of each MC collision only, instead of with every reconstructed collision; the multNTracksPVeta1 vs FT0M responses stay per reconstructed collision"};
343345
Configurable<bool> applyINELSelectionAtGenLevel{"applyINELSelectionAtGenLevel", false, "part 2 (pp only): replace the reconstructed INEL cuts by Nch^gen >= 1 of the MC collision in the Rec, Gen, Truth and Final stages (selectINELgtN is ignored) and fill only PairLossK0/Comparison/NchGen (Rec and Gen vs Nch^gen, integrated over vertex z and multiplicity); requires doRecComparison and applyNewMCSelection"};
344346
ConfigurableAxis axisComparisonNchGen{"axisComparisonNchGen", {VARIABLE_WIDTH, 0.5f, 4.5f, 9.5f, 19.5f, 1000.5f}, "Nch^gen classes (charged primaries in |eta| < 1) of PairLossK0/Comparison/NchGen"};
347+
// MC-only event quality cut on the Nch^gen vs multNTracksPVeta1 response
348+
// (PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1): a reconstructed collision
349+
// is kept only if |multNTracksPVeta1 - mu(Nch^gen)| <= nSigma * max(sigma(Nch^gen), sigmaMin),
350+
// with mu a polynomial in Nch^gen and sigma a polynomial in sqrt(Nch^gen), e.g. fits of
351+
// the mean and width of each Nch^gen column of that response. It uses the generated
352+
// multiplicity, so it has no data counterpart
353+
Configurable<bool> applyNchResponseBandCut{"applyNchResponseBandCut", false, "part 2 (MC only): keep only reconstructed collisions inside the mu +- nSigma*sigma band of the Nch^gen vs multNTracksPVeta1 response, in the Rec (every collision), Gen, Truth and Final (best collision) stages of PairLossK0/Comparison"};
354+
Configurable<std::vector<double>> nchResponseBandMeanPars{"nchResponseBandMeanPars", {0.0, 0.9}, "mean multNTracksPVeta1 = p0 + p1*x + p2*x^2 + ..., x = Nch^gen"};
355+
Configurable<std::vector<double>> nchResponseBandSigmaPars{"nchResponseBandSigmaPars", {0.0, 0.35}, "multNTracksPVeta1 width = p0 + p1*sqrt(x) + p2*x + p3*x^1.5 + ..., x = Nch^gen"};
356+
Configurable<float> nchResponseBandNSigma{"nchResponseBandNSigma", 3.0f, "half-width of the band in units of sigma"};
357+
Configurable<float> nchResponseBandSigmaMin{"nchResponseBandSigmaMin", 1.0f, "lower bound of sigma, which keeps the band open at low Nch^gen"};
345358
// Generated charged multiplicity of the MC collision, counted in |eta| < 0.8
346359
// by mCounter. Plain ConfigurableAxis: unlike the correlation axes it is NOT
347360
// trimmed by skipUnderOverflowInTHn, so what you configure is what you get.
@@ -2826,6 +2839,10 @@ struct HStrangeCorrelation {
28262839
}
28272840
}
28282841

2842+
if (pairLossK0Configurations.applyNchResponseBandCut && !doprocessPairLossK0MC) {
2843+
LOGF(fatal, "pairLossK0Configurations.applyNchResponseBandCut needs the generated multiplicity; enable processPairLossK0MC");
2844+
}
2845+
28292846
if (doprocessPairLossK0MC && pairLossK0Configurations.doEventRecoEfficiencyStudy) {
28302847
// Per MC collision with |vz_gen| <= zVertexCut, each histogram a subset of
28312848
// the previous one: HasRecoColl/All is the MC-collision reconstruction
@@ -2837,10 +2854,21 @@ struct HStrangeCorrelation {
28372854
histos.add("PairLossK0/EventRecoEfficiency/hNchGenEvSel", "best reconstructed collision passes the Rec event selection with reconstructed-level INEL cuts;#it{N}_{ch}^{gen} (|#eta| < 1);MC collisions", kTH1D, {axesConfigurations.axisNchGen});
28382855
histos.add("PairLossK0/EventRecoEfficiency/hNchGenVsNRecoColl", "all MC collisions;#it{N}_{ch}^{gen} (|#eta| < 1);reconstructed collisions", kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisNRecoCollisions});
28392856
// Per reconstructed collision passing the Rec event selection without INEL
2840-
// cuts, no |vz_gen| cut: the same collisions the Rec path sees before its INEL cut
2841-
histos.add("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1", "reconstructed collisions passing the Rec event selection without INEL cuts;#it{N}_{ch}^{gen} (|#eta| < 1);multNTracksPVeta1", kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisNchGen});
2857+
// cuts, no |vz_gen| cut: the same collisions the Rec path sees before its INEL cut.
2858+
// With nchGenResponseBestCollisionOnly the Nch^gen response takes only the best
2859+
// collision, which drops the split and duplicate vertices of the MC collision
2860+
histos.add("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1",
2861+
pairLossK0Configurations.nchGenResponseBestCollisionOnly ? "best reconstructed collision passing the Rec event selection without INEL cuts;#it{N}_{ch}^{gen} (|#eta| < 1);multNTracksPVeta1"
2862+
: "reconstructed collisions passing the Rec event selection without INEL cuts;#it{N}_{ch}^{gen} (|#eta| < 1);multNTracksPVeta1",
2863+
kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisNchGen});
28422864
histos.add("PairLossK0/EventRecoEfficiency/hNTracksPVeta1VsCentFT0M", "reconstructed collisions passing the Rec event selection without INEL cuts;multNTracksPVeta1;FT0M percentile", kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisCentFT0M});
28432865
histos.add("PairLossK0/EventRecoEfficiency/hNTracksPVeta1VsMultFT0M", "reconstructed collisions passing the Rec event selection without INEL cuts;multNTracksPVeta1;FT0M amplitude", kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisMultFT0M});
2866+
if (pairLossK0Configurations.applyNchResponseBandCut) {
2867+
// Checks of applyNchResponseBandCut: the part of the Nch^gen response it keeps,
2868+
// and hNchGenEvSelNoInelInBand / hNchGenEvSelNoInel, its efficiency vs Nch^gen
2869+
histos.add("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1InBand", "hNchGenVsNTracksPVeta1 inside the Nch^gen vs multNTracksPVeta1 band;#it{N}_{ch}^{gen} (|#eta| < 1);multNTracksPVeta1", kTH2D, {axesConfigurations.axisNchGen, axesConfigurations.axisNchGen});
2870+
histos.add("PairLossK0/EventRecoEfficiency/hNchGenEvSelNoInelInBand", "best reconstructed collision passes the Rec event selection without INEL cuts and lies inside the Nch^gen vs multNTracksPVeta1 band;#it{N}_{ch}^{gen} (|#eta| < 1);MC collisions", kTH1D, {axesConfigurations.axisNchGen});
2871+
}
28442872
}
28452873

28462874
if (doprocessSameEventHV0s && masterConfigurations.doMultEstimatorResponse) {
@@ -3438,6 +3466,29 @@ struct HStrangeCorrelation {
34383466
return nChGen > 0;
34393467
}
34403468

3469+
// MC-only event quality cut of the PairLoss Comparison stages (applyNchResponseBandCut):
3470+
// multNTracksPVeta1 inside mu(Nch^gen) +- nSigma * max(sigma(Nch^gen), sigmaMin), with mu
3471+
// a polynomial in Nch^gen and sigma one in sqrt(Nch^gen). Evaluated here rather than
3472+
// through TF1 members: the task struct is at the StructToTuple member limit
3473+
bool isInNchResponseBand(int nChGen, int nTracksPVeta1)
3474+
{
3475+
const double sqrtNchGen = std::sqrt(static_cast<double>(std::max(nChGen, 0)));
3476+
double mean = 0.0;
3477+
double power = 1.0;
3478+
for (const double par : pairLossK0Configurations.nchResponseBandMeanPars.value) {
3479+
mean += par * power;
3480+
power *= nChGen;
3481+
}
3482+
double sigma = 0.0;
3483+
power = 1.0;
3484+
for (const double par : pairLossK0Configurations.nchResponseBandSigmaPars.value) {
3485+
sigma += par * power;
3486+
power *= sqrtNchGen;
3487+
}
3488+
sigma = std::max(sigma, static_cast<double>(pairLossK0Configurations.nchResponseBandSigmaMin));
3489+
return std::abs(nTracksPVeta1 - mean) <= pairLossK0Configurations.nchResponseBandNSigma * sigma;
3490+
}
3491+
34413492
// this function allows for all event selections to be done in a modular way
34423493
// applyInelSelection = false skips only the reconstructed INEL>0 / INEL>N cuts
34433494
template <typename TCollision>
@@ -4667,9 +4718,11 @@ struct HStrangeCorrelation {
46674718
TracksComplete const& tracks)
46684719
{
46694720
// Nch^gen of this MC collision (charged primaries in |eta| < 1), shared by the
4670-
// event-reconstruction-efficiency study and the generated-level INEL selection
4721+
// event-reconstruction-efficiency study, the generated-level INEL selection and
4722+
// the Nch^gen vs multNTracksPVeta1 band cut
46714723
const bool applyGenInel = pairLossK0Configurations.applyINELSelectionAtGenLevel;
4672-
const int nChGen = (pairLossK0Configurations.doEventRecoEfficiencyStudy || applyGenInel) ? countNchGenEta1(mcParticles) : -1;
4724+
const bool applyBandCut = pairLossK0Configurations.applyNchResponseBandCut;
4725+
const int nChGen = (pairLossK0Configurations.doEventRecoEfficiencyStudy || applyGenInel || applyBandCut) ? countNchGenEta1(mcParticles) : -1;
46734726

46744727
// Part 3: a self-contained generator-level study. It deliberately touches no
46754728
// reconstructed quantity in its event selection or in any of its axes: the
@@ -4887,10 +4940,12 @@ struct HStrangeCorrelation {
48874940
bestCollisionVtxZ = collision.posZ();
48884941
bestCollisionMultiplicity = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C();
48894942
// with applyGenInel (pp only) the reconstructed INEL cuts are replaced by
4890-
// Nch^gen >= 1, as in the Rec and Gen stages
4891-
pairLossEventSelected = !pairLossK0Configurations.applyRecoEventSelection ||
4892-
(masterConfigurations.doPPAnalysis ? isCollisionSelected(collision, !applyGenInel) && (!applyGenInel || isGenInelGt0(nChGen))
4893-
: isCollisionSelectedPbPb(collision, false));
4943+
// Nch^gen >= 1, as in the Rec and Gen stages; the band cut acts on top,
4944+
// independently of applyRecoEventSelection
4945+
pairLossEventSelected = (!pairLossK0Configurations.applyRecoEventSelection ||
4946+
(masterConfigurations.doPPAnalysis ? isCollisionSelected(collision, !applyGenInel) && (!applyGenInel || isGenInelGt0(nChGen))
4947+
: isCollisionSelectedPbPb(collision, false))) &&
4948+
(!applyBandCut || isInNchResponseBand(nChGen, collision.multNTracksPVeta1()));
48944949
}
48954950
if (bestCollisionId < 0) {
48964951
return;
@@ -4999,6 +5054,7 @@ struct HStrangeCorrelation {
49995054
bool genBestCollisionGoodZvtxFT0vsPV = false;
50005055
bool genCollisionSelected = false;
50015056
int genLargestNContributors = -1;
5057+
int genBestCollisionNTracksPVeta1 = -1;
50025058
uint32_t genBestCollisionTriggerPresenceMap = 0;
50035059
for (auto const& recCollision : recCollisions) {
50045060
if (genLargestNContributors >= recCollision.numContrib()) {
@@ -5008,6 +5064,7 @@ struct HStrangeCorrelation {
50085064
genBestCollisionMultiplicity = masterConfigurations.doPPAnalysis ? recCollision.centFT0M() : recCollision.centFT0C();
50095065
// Both branches fill the Gen THn with this vertex position
50105066
genBestCollisionVtxZ = recCollision.posZ();
5067+
genBestCollisionNTracksPVeta1 = recCollision.multNTracksPVeta1();
50115068
if (masterConfigurations.applyNewMCSelection) {
50125069
genCollisionSelected = (masterConfigurations.doPPAnalysis && isCollisionSelected(recCollision, !applyGenInel)) ||
50135070
(!masterConfigurations.doPPAnalysis && isCollisionSelectedPbPb(recCollision, false));
@@ -5034,6 +5091,10 @@ struct HStrangeCorrelation {
50345091
(!masterConfigurations.requireGoodZvtxFT0vsPV || genBestCollisionGoodZvtxFT0vsPV) &&
50355092
genBestCollisionMultiplicity >= axisRanges[5][0] && genBestCollisionMultiplicity <= axisRanges[5][1];
50365093
}
5094+
// the band cut acts on top of either Gen event selection, on the best collision
5095+
if (applyBandCut) {
5096+
genEventSelected = genEventSelected && isInNchResponseBand(nChGen, genBestCollisionNTracksPVeta1);
5097+
}
50375098

50385099
if (genEventSelected && masterConfigurations.doCorrelationK0Short && TESTBIT(doCorrelation, IndexK0)) {
50395100
std::vector<uint32_t> genTriggerIndices;
@@ -5282,6 +5343,16 @@ struct HStrangeCorrelation {
52825343
pairLossComparison.nChGen = applyGenInel ? nChGen : -1;
52835344
pairLossComparison.active = true;
52845345
for (auto const& recCollision : recCollisions) {
5346+
// recComparisonBestCollisionOnly: one reconstructed collision per MC collision,
5347+
// the best one, as in the Gen stage
5348+
if (pairLossK0Configurations.recComparisonBestCollisionOnly && recCollision.globalIndex() != bestCollisionId) {
5349+
continue;
5350+
}
5351+
// The band cut tests every reconstructed collision against the Nch^gen of
5352+
// this MC collision, so it also rejects split and duplicate vertices
5353+
if (applyBandCut && !isInNchResponseBand(nChGen, recCollision.multNTracksPVeta1())) {
5354+
continue;
5355+
}
52855356
const auto recTriggerSlice = triggerTracks.sliceBy(collisionSliceTracks, recCollision.globalIndex());
52865357
const auto recV0Slice = associatedV0s.sliceBy(collisionSliceV0s, recCollision.globalIndex());
52875358
const auto recTrackSlice = tracks.sliceBy(pairLossTracksPerCollision, recCollision.globalIndex());
@@ -5306,14 +5377,44 @@ struct HStrangeCorrelation {
53065377
// responses. The event selection is the one runSameEventHV0s applies before
53075378
// its INEL cut: trigger presence + isCollisionSelected (isCollisionSelectedNoInel)
53085379
auto runEventRecoEfficiencyStudy = [&]() {
5309-
// Responses: one entry per reconstructed collision, as in the Rec path
5380+
// Best collision: the one with the most PV contributors, as in the Rec comparison
5381+
int largestNContributors = -1;
5382+
bool bestCollisionSelectedNoInel = false;
5383+
bool bestCollisionSelected = false;
5384+
int bestCollisionNTracksPVeta1 = -1;
5385+
for (auto const& collision : recCollisions) {
5386+
if (collision.numContrib() <= largestNContributors) {
5387+
continue;
5388+
}
5389+
largestNContributors = collision.numContrib();
5390+
bestCollisionSelectedNoInel = isCollisionSelectedNoInel(collision);
5391+
// reconstructed-level INEL cuts; the Pb-Pb event selection has none
5392+
bestCollisionSelected = bestCollisionSelectedNoInel && (!masterConfigurations.doPPAnalysis || isCollisionInelSelected(collision));
5393+
bestCollisionNTracksPVeta1 = collision.multNTracksPVeta1();
5394+
}
5395+
5396+
// Nch^gen response, and with applyNchResponseBandCut the part of it inside the band
5397+
auto fillNchGenResponse = [&](int nTracksPVeta1) {
5398+
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1"), nChGen, nTracksPVeta1);
5399+
if (applyBandCut && isInNchResponseBand(nChGen, nTracksPVeta1)) {
5400+
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1InBand"), nChGen, nTracksPVeta1);
5401+
}
5402+
};
5403+
5404+
// Responses: one entry per reconstructed collision, as in the Rec path, except
5405+
// the Nch^gen response with nchGenResponseBestCollisionOnly (best collision only)
53105406
for (auto const& collision : recCollisions) {
53115407
if (isCollisionSelectedNoInel(collision)) {
5312-
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenVsNTracksPVeta1"), nChGen, collision.multNTracksPVeta1());
5408+
if (!pairLossK0Configurations.nchGenResponseBestCollisionOnly) {
5409+
fillNchGenResponse(collision.multNTracksPVeta1());
5410+
}
53135411
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNTracksPVeta1VsCentFT0M"), collision.multNTracksPVeta1(), collision.centFT0M());
53145412
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNTracksPVeta1VsMultFT0M"), collision.multNTracksPVeta1(), collision.multFT0M());
53155413
}
53165414
}
5415+
if (pairLossK0Configurations.nchGenResponseBestCollisionOnly && bestCollisionSelectedNoInel) {
5416+
fillNchGenResponse(bestCollisionNTracksPVeta1);
5417+
}
53175418

53185419
// Efficiency: one entry per MC collision, evaluated on the best collision
53195420
if (std::abs(mcCollision.posZ()) > masterConfigurations.zVertexCut) {
@@ -5325,20 +5426,11 @@ struct HStrangeCorrelation {
53255426
return;
53265427
}
53275428
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenHasRecoColl"), nChGen);
5328-
int largestNContributors = -1;
5329-
bool bestCollisionSelectedNoInel = false;
5330-
bool bestCollisionSelected = false;
5331-
for (auto const& collision : recCollisions) {
5332-
if (collision.numContrib() <= largestNContributors) {
5333-
continue;
5334-
}
5335-
largestNContributors = collision.numContrib();
5336-
bestCollisionSelectedNoInel = isCollisionSelectedNoInel(collision);
5337-
// reconstructed-level INEL cuts; the Pb-Pb event selection has none
5338-
bestCollisionSelected = bestCollisionSelectedNoInel && (!masterConfigurations.doPPAnalysis || isCollisionInelSelected(collision));
5339-
}
53405429
if (bestCollisionSelectedNoInel) {
53415430
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenEvSelNoInel"), nChGen);
5431+
if (applyBandCut && isInNchResponseBand(nChGen, bestCollisionNTracksPVeta1)) {
5432+
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenEvSelNoInelInBand"), nChGen);
5433+
}
53425434
}
53435435
if (bestCollisionSelected) {
53445436
histos.fill(HIST("PairLossK0/EventRecoEfficiency/hNchGenEvSel"), nChGen);

0 commit comments

Comments
 (0)