From 160dd31e13ef8da8b786a4d123cc707cdb0560c5 Mon Sep 17 00:00:00 2001 From: romainschotter Date: Mon, 6 Oct 2025 21:57:11 +0200 Subject: [PATCH 1/3] Update DPG K0s QC task --- .../AOTTrack/V0Cascades/perfK0sResolution.cxx | 740 +++++++++++------- 1 file changed, 461 insertions(+), 279 deletions(-) diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index 6d2c5d80df1..1a66277a3a1 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -9,10 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -52,9 +54,17 @@ using namespace o2::track; using namespace o2::framework; using namespace o2::framework::expressions; -using PIDTracks = soa::Join; +using PIDTracksIU = soa::Join; using PIDTracksIUMC = soa::Join; -using SelectedCollisions = soa::Join; +using SelectedCollisions = soa::Join; + +enum CentEstimator { + kCentFT0C = 0, + kCentFT0M, + kCentFT0CVariant1, + kCentMFT, + kCentNGlobal +}; struct perfK0sResolution { // Configurable bins @@ -69,38 +79,89 @@ struct perfK0sResolution { ConfigurableAxis etaBinsDauthers{"etaBinsDauthers", {100, -1.f, 1.f}, "eta binning for daughters"}; ConfigurableAxis phiBins{"phiBins", {100, 0.f, 6.28f}, "phi binning"}; ConfigurableAxis relpTResBins{"relpTResBins", {200, 0.f, 0.5f}, "rel. pT resolution binning"}; - - // Selection criteria - Configurable v0setting_cospa{"v0setting_cospa", 0.995, "V0 CosPA"}; // shoudl be double in future - Configurable v0setting_dcav0dau{"v0setting_dcav0dau", 1., "DCA V0 Daughters"}; - Configurable v0setting_dcapostopv{"v0setting_dcapostopv", 0.1, "DCA Pos To PV"}; - Configurable v0setting_dcanegtopv{"v0setting_dcanegtopv", 0.1, "DCA Neg To PV"}; - Configurable v0setting_radius{"v0setting_radius", 0.9, "V0 Radius"}; - Configurable v0setting_rapidity{"v0setting_rapidity", 0.5, "rapidity"}; - - Configurable nV0lifetime{"nV0lifetime", 3., "n ctau"}; - Configurable nMaxTPCNsigma{"nMaxTPCNsigma", 10., "Maximum TPC nsigma for pions"}; - Configurable itsIbSelectionPos{"itsIbSelectionPos", 0, "Flag for the ITS IB selection on positive daughters: -1 no ITS IB, 0 no selection, 1 ITS IB"}; - Configurable itsIbSelectionNeg{"itsIbSelectionNeg", 0, "Flag for the ITS IB selection on negative daughters: -1 no ITS IB, 0 no selection, 1 ITS IB"}; - Configurable itsAfterburnerPos{"itsAfterburnerPos", 0, "Flag for the ITS afterburner tracks on positive daughters: -1 no AB, 0 no selection, 1 AB"}; - Configurable itsAfterburnerNeg{"itsAfterburnerNeg", 0, "Flag for the ITS afterburner tracks on negative daughters: -1 no AB, 0 no selection, 1 AB"}; - Configurable trdSelectionPos{"trdSelectionPos", 0, "Flag for the TRD selection on positive daughters: -1 no TRD, 0 no selection, 1 TRD"}; - Configurable trdSelectionNeg{"trdSelectionNeg", 0, "Flag for the TRD selection on negative daughters: -1 no TRD, 0 no selection, 1 TRD"}; - Configurable tofSelectionPos{"tofSelectionPos", 0, "Flag for the TOF selection on positive daughters: -1 no TOF, 0 no selection, 1 TOF"}; - Configurable tofSelectionNeg{"tofSelectionNeg", 0, "Flag for the TOF selection on negative daughters: -1 no TOF, 0 no selection, 1 TOF"}; - Configurable pidHypoPos{"pidHypoPos", -1, "Index for the PID hypothesis used in tracking for the positive daughters: -1 no selection, 0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton"}; - Configurable pidHypoNeg{"pidHypoNeg", -1, "Index for the PID hypothesis used in tracking for the negative daughters: -1 no selection, 0 Electron, 1 Muon, 2 Pion, 3 Kaon, 4 Proton"}; - Configurable extraCutTPCClusters{"extraCutTPCClusters", -1.0f, "Extra cut on daugthers for TPC clusters"}; + ConfigurableAxis centralityAxis{"centralityAxis", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 101.f}, "Centrality"}; + ConfigurableAxis occupancyAxis{"occupancyAxis", {VARIABLE_WIDTH, -1.0f, 0.0f, 250.0f, 500.0f, 750.0f, 1000.0f, 1500.0f, 2000.0f, 3000.0f, 4500.0f, 6000.0f, 8000.0f, 10000.0f, 50000.0f}, "Occupancy"}; + + struct : ConfigurableGroup { + std::string prefix = "eventSelections"; // JSON group name + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border (Run 3 only)"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border (Run 3 only)"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "require events with at least one ITS-TPC track (Run 3 only)"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference (Run 3 only)"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF (Run 3 only)"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD (Run 3 only)"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", true, "reject collisions in case of pileup with another collision in the same foundBC (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds (Run 3 only)"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds (Run 3 only)"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold (Run 3 only)"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF (Run 3 only)"}; + Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + + Configurable centralityEstimator{"centralityEstimator", kCentFT0C, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFT0CVariant1, 3:CentMFT, 4:CentNGlobal)"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + } eventSelections; + + static constexpr float DefaultLifetimeCuts[1][2] = {{30., 20.}}; + + struct : ConfigurableGroup { + std::string prefix = "v0Selections"; // JSON group name + Configurable v0TypeSelection{"v0TypeSelection", 1, "select on a certain V0 type (leave negative if no selection desired)"}; + + // Selection criteria: acceptance + Configurable rapidityCut{"rapidityCut", 0.5, "rapidity"}; + Configurable daughterEtaCut{"daughterEtaCut", 0.8, "max eta for daughters"}; + + // Standard 5 topological criteria + Configurable v0cospa{"v0cospa", 0.995, "min V0 CosPA"}; + Configurable dcav0dau{"dcav0dau", 1.0, "max DCA V0 Daughters (cm)"}; + Configurable dcanegtopv{"dcanegtopv", 0.1, "min DCA Neg To PV (cm)"}; + Configurable dcapostopv{"dcapostopv", 0.1, "min DCA Pos To PV (cm)"}; + Configurable v0radius{"v0radius", 1.2, "minimum V0 radius (cm)"}; + Configurable v0radiusMax{"v0radiusMax", 1E5, "maximum V0 radius (cm)"}; + Configurable> lifetimecut{"lifetimecut", {DefaultLifetimeCuts[0], 2, {"lifetimecutLambda", "lifetimecutK0S"}}, "lifetimecut"}; + + // Additional selection on the AP plot (exclusive for K0Short) + // original equation: lArmPt*5>TMath::Abs(lArmAlpha) + Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + + // Track quality + Configurable minTPCrows{"minTPCrows", 70, "minimum TPC crossed rows"}; + Configurable minITSclusters{"minITSclusters", -1, "minimum ITS clusters"}; + Configurable minTPCrowsOverFindableClusters{"minTPCrowsOverFindableClusters", -1, "minimum nbr of TPC crossed rows over findable clusters"}; + Configurable minTPCfoundOverFindableClusters{"minTPCfoundOverFindableClusters", -1, "minimum nbr of found over findable TPC clusters"}; + Configurable maxFractionTPCSharedClusters{"maxFractionTPCSharedClusters", 1e+09, "maximum fraction of TPC shared clusters"}; + Configurable maxITSchi2PerNcls{"maxITSchi2PerNcls", 1e+09, "maximum ITS chi2 per clusters"}; + Configurable maxTPCchi2PerNcls{"maxTPCchi2PerNcls", 1e+09, "maximum TPC chi2 per clusters"}; + Configurable requirePosITSib{"requirePosITSib", 0, "require ITS IB selection on positive daughters? -1: no ITS IB, 0: no selection, 1: ITS IB"}; + Configurable requireNegITSib{"requireNegITSib", 0, "require ITS IB selection on negative daughters? -1: no ITS IB, 0: no selection, 1: ITS IB"}; + Configurable requirePosITSafterburner{"requirePosITSafterburner", 0, "require positive track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; + Configurable requireNegITSafterburner{"requireNegITSafterburner", 0, "require negative track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; + Configurable requirePosTRD{"trdSelectionPos", 0, "require TRD selection on positive daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requireNegTRD{"trdSelectionNeg", 0, "require TRD selection on negative daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requirePosTOF{"tofSelectionPos", 0, "require TOF selection on positive daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requireNegTOF{"tofSelectionNeg", 0, "require TOF selection on negative daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requirePosPIDforTracking{"pidHypoPos", -1, "require specific PID hypothesis used in tracking for the positive daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + Configurable requireNegPIDforTracking{"pidHypoNeg", -1, "require specific PID hypothesis used in tracking for the negative daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + + // PID (TPC/TOF) + Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 10., "tpcPidNsigmaCut"}; + Configurable tofPidNsigmaCut{"tofPidNsigmaCut", 1e+6, "tofPidNsigmaCut"}; + } v0Selections; // Configure plots to enable Configurable useMultidimHisto{"useMultidimHisto", false, "use multidimentional histograms"}; Configurable enableTPCPlot{"enableTPCPlot", false, "Enable the TPC plot"}; - Configurable computeInvMassFromDaughters{"computeInvMassFromDaughters", false, "Compute the invariant mass from the daughters"}; - Configurable requireTrueK0s{"requireTrueK0s", false, "require rec. v0 to be true K0s"}; - - // Configurable for event selection - Configurable cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; - Configurable eventSelection{"eventSelection", true, "event selection"}; + Configurable requireTrueK0s{"requireTrueK0s", true, "require rec. v0 to be true K0s"}; + Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; HistogramRegistry rK0sResolution{"K0sResolution", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rK0sDauResolution{"K0sDauResolution", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -116,11 +177,9 @@ struct perfK0sResolution { Configurable useTrackTuner{"useTrackTuner", false, "Apply Improver/DCA corrections to MC"}; Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackCovMat=0|updateCurvature=1|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|usePvRefitCorrections=0|oneOverPtCurrent=1|oneOverPtUpgr=1.2", "TrackTuner parameter initialization (format: =|=)"}; OutputObj trackTunedTracks{TH1D("trackTunedTracks", "", 4, 0.5, 4.5), OutputObjHandlingPolicy::AnalysisObject}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUTInner", "Path of the Lut parametrization"}; Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable minOccupancyCut{"minOccupancyCut", 1, "Minimum occupancy cut. Enabled if min < max"}; - Configurable maxOccupancyCut{"maxOccupancyCut", -1, "Maximum occupancy cut. Enabled if min < max"}; int runNumber = -1; @@ -141,45 +200,71 @@ struct perfK0sResolution { const AxisSpec phiAxis{phiBins, "#phi"}; const AxisSpec trueK0Axis{2, -0.5, 1.5, "True K0"}; - rK0sResolution.add("h1_stats", "h1_stats", {HistType::kTH1F, {statAxis}}); + // Event Counters + rK0sResolution.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.5f}}); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min occup."); + rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max occup."); + + rK0sResolution.add("hEventCentrality", "hEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + rK0sResolution.add("hEventOccupancy", "hEventOccupancy", kTH1D, {occupancyAxis}); + + rK0sResolution.add("h1_stats", "h1_stats", {HistType::kTH1D, {statAxis}}); TString hStatsLabels[5] = {"Selected Events", "All V0s", "Selected V0s", "Daughters have MC particles", "Daughters corr. rec."}; for (Int_t n = 1; n <= rK0sResolution.get(HIST("h1_stats"))->GetNbinsX(); n++) { rK0sResolution.get(HIST("h1_stats"))->GetXaxis()->SetBinLabel(n, hStatsLabels[n - 1]); } if (doprocessMC) { - rK0sDauResolution.add("h2_massPosPtRes", "h2_massPosPtRes", {HistType::kTH2F, {mAxis, pTResAxis}}); - rK0sDauResolution.add("h2_massNegPtRes", "h2_massNegPtRes", {HistType::kTH2F, {mAxis, pTResAxis}}); - - rK0sDauResolution.add("h2_genPtPosPtResNorm", "h2_genPtPosPtResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxPosPxResNorm", "h2_genPxPosPxResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyPosPyResNorm", "h2_genPyPosPyResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzPosPzResNorm", "h2_genPzPosPzResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtNegPtResNorm", "h2_genPtNegPtResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxNegPxResNorm", "h2_genPxNegPxResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyNegPyResNorm", "h2_genPyNegPyResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzNegPzResNorm", "h2_genPzNegPzResNorm", {HistType::kTH2F, {pTResRelAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtPosPtRes", "h2_genPtPosPtRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxPosPxRes", "h2_genPxPosPxRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyPosPyRes", "h2_genPyPosPyRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzPosPzRes", "h2_genPzPosPzRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtNegPtRes", "h2_genPtNegPtRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPxNegPxRes", "h2_genPxNegPxRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPyNegPyRes", "h2_genPyNegPyRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - rK0sDauResolution.add("h2_genPzNegPzRes", "h2_genPzNegPzRes", {HistType::kTH2F, {pTResAxis, pTAxis}}); - - rK0sDauResolution.add("h2_genPtPosPulls", "h2_GenPtPosPulls", {HistType::kTH2F, {invpTResNormAxis, invpTAxis}}); - rK0sDauResolution.add("h2_genPtNegPulls", "h2_GenPtNegPulls", {HistType::kTH2F, {invpTResNormAxis, invpTAxis}}); - - rK0sDauResolution.add("h2_PosRelPtRes", "h2_PosRelPtRes", {HistType::kTH2F, {pTAxis, relpTResAxis}}); - rK0sDauResolution.add("h2_NegRelPtRes", "h2_NegRelPtRes", {HistType::kTH2F, {pTAxis, relpTResAxis}}); - } - rK0sResolution.add("h2_masspT", "h2_masspT", {HistType::kTH2F, {mAxis, pTAxis}}); - rK0sResolution.add("h2_masseta", "h2_masseta", {HistType::kTH2F, {mAxis, etaAxis}}); - rK0sResolution.add("h2_massphi", "h2_massphi", {HistType::kTH2F, {mAxis, phiAxis}}); + rK0sDauResolution.add("h2_massPosPtRes", "h2_massPosPtRes", {HistType::kTH2D, {mAxis, pTResAxis}}); + rK0sDauResolution.add("h2_massNegPtRes", "h2_massNegPtRes", {HistType::kTH2D, {mAxis, pTResAxis}}); + + rK0sDauResolution.add("h2_genPtPosPtResNorm", "h2_genPtPosPtResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxPosPxResNorm", "h2_genPxPosPxResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyPosPyResNorm", "h2_genPyPosPyResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzPosPzResNorm", "h2_genPzPosPzResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtNegPtResNorm", "h2_genPtNegPtResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxNegPxResNorm", "h2_genPxNegPxResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyNegPyResNorm", "h2_genPyNegPyResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzNegPzResNorm", "h2_genPzNegPzResNorm", {HistType::kTH2D, {pTResRelAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtPosPtRes", "h2_genPtPosPtRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxPosPxRes", "h2_genPxPosPxRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyPosPyRes", "h2_genPyPosPyRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzPosPzRes", "h2_genPzPosPzRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtNegPtRes", "h2_genPtNegPtRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPxNegPxRes", "h2_genPxNegPxRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPyNegPyRes", "h2_genPyNegPyRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + rK0sDauResolution.add("h2_genPzNegPzRes", "h2_genPzNegPzRes", {HistType::kTH2D, {pTResAxis, pTAxis}}); + + rK0sDauResolution.add("h2_genPtPosPulls", "h2_GenPtPosPulls", {HistType::kTH2D, {invpTResNormAxis, invpTAxis}}); + rK0sDauResolution.add("h2_genPtNegPulls", "h2_GenPtNegPulls", {HistType::kTH2D, {invpTResNormAxis, invpTAxis}}); + + rK0sDauResolution.add("h2_PosRelPtRes", "h2_PosRelPtRes", {HistType::kTH2D, {pTAxis, relpTResAxis}}); + rK0sDauResolution.add("h2_NegRelPtRes", "h2_NegRelPtRes", {HistType::kTH2D, {pTAxis, relpTResAxis}}); + } + rK0sResolution.add("h2_masspT", "h2_masspT", {HistType::kTH2D, {mAxis, pTAxis}}); + rK0sResolution.add("h2_masseta", "h2_masseta", {HistType::kTH2D, {mAxis, etaAxis}}); + rK0sResolution.add("h2_massphi", "h2_massphi", {HistType::kTH2D, {mAxis, phiAxis}}); if (useMultidimHisto) { if (doprocessMC) { rK0sResolution.add("thn_mass", "thn_mass", kTHnSparseF, {mAxis, pTAxis, etaAxis, phiAxis, etaAxisPosD, etaAxisNegD, invpTResAxis, invpTResAxis, trueK0Axis}); @@ -187,9 +272,11 @@ struct perfK0sResolution { rK0sResolution.add("thn_mass", "thn_mass", kTHnSparseF, {mAxis, pTAxis, etaAxis, phiAxis, etaAxisPosD, etaAxisNegD}); } } + rK0sResolution.add("h3_centralitypTmass", "h3_centralitypTmass", kTH3D, {centralityAxis, pTAxis, mAxis}); + rK0sResolution.add("h3_occupancypTmass", "h3_occupancypTmass", kTH3D, {occupancyAxis, pTAxis, mAxis}); if (enableTPCPlot) { - rK0sDauResolution.add("h3_tpc_vs_pid_hypothesis", "h3_tpc_vs_pid_hypothesis", {HistType::kTH3F, {{200, -10.f, 10.f, "#it{p}/Z (GeV/#it{c})"}, {1000, 0, 1000.f, "dE/dx (a.u.)"}, {10, -0.5, 9.5f, "PID hypothesis"}}}); + rK0sDauResolution.add("h3_tpc_vs_pid_hypothesis", "h3_tpc_vs_pid_hypothesis", {HistType::kTH3D, {{200, -10.f, 10.f, "#it{p}/Z (GeV/#it{c})"}, {1000, 0, 1000.f, "dE/dx (a.u.)"}, {10, -0.5, 9.5f, "PID hypothesis"}}}); } /// TrackTuner initialization @@ -208,6 +295,10 @@ struct perfK0sResolution { trackTunedTracks->GetXaxis()->SetBinLabel(3, "untouched tracks due to negative detXY"); trackTunedTracks->GetXaxis()->SetBinLabel(4, "original detXY<0"); } + + // inspect histogram sizes, please + rK0sResolution.print(); + rK0sDauResolution.print(); } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -225,250 +316,332 @@ struct perfK0sResolution { runNumber = bc.runNumber(); } + // ______________________________________________________ + // Return slicing output + template + float getCentralityRun3(TCollision const& collision) + { + if (eventSelections.centralityEstimator == kCentFT0C) + return collision.centFT0C(); + else if (eventSelections.centralityEstimator == kCentFT0M) + return collision.centFT0M(); + else if (eventSelections.centralityEstimator == kCentFT0CVariant1) + return collision.centFT0CVariant1(); + else if (eventSelections.centralityEstimator == kCentMFT) + return collision.centMFT(); + else if (eventSelections.centralityEstimator == kCentNGlobal) + return collision.centNGlobal(); + + return -1.f; + } + + template + bool isEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 0. /* all collisions */); + + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 18 /* Below min occupancy */); + + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) + rK0sResolution.fill(HIST("hEventSelection"), 19 /* Above max occupancy */); + + return true; + } + template bool acceptV0(const T1& v0, const T2& ntrack, const T2& ptrack, const C& collision) { // Apply selections on V0 - if (TMath::Abs(v0.yK0Short()) > v0setting_rapidity) { + if (std::abs(v0.yK0Short()) > v0Selections.rapidityCut) { return false; } - if (v0.v0radius() < v0setting_radius) { + + if (std::abs(v0.negativeeta()) > v0Selections.daughterEtaCut || std::abs(v0.positiveeta()) > v0Selections.daughterEtaCut) + return false; + + if (v0Selections.v0TypeSelection > -1 && v0.v0Type() != v0Selections.v0TypeSelection) + return false; // skip V0s that are not standard + + // Base topological variables + if (v0.v0radius() < v0Selections.v0radius) + return false; + if (v0.v0radius() > v0Selections.v0radiusMax) + return false; + if (std::abs(v0.dcapostopv()) < v0Selections.dcapostopv) + return false; + if (std::abs(v0.dcanegtopv()) < v0Selections.dcanegtopv) + return false; + if (v0.v0cosPA() < v0Selections.v0cospa) + return false; + if (v0.dcaV0daughters() > v0Selections.dcav0dau) + return false; + + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short > v0Selections.lifetimecut->get("lifetimecutK0S")) { return false; } - if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * pid_constants::sMasses[PID::K0] > 2.684 * nV0lifetime) { + + if (v0Selections.armPodCut > 1e-4 && v0.qtarm() * v0Selections.armPodCut < std::abs(v0.alpha())) { return false; } // Apply selections on V0 daughters - // ITS selection - switch (itsIbSelectionPos) { - case -1: - if (ptrack.itsNClsInnerBarrel() > 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ptrack.itsNClsInnerBarrel() < 1) { - return false; - } - break; - default: - LOG(fatal) << "Invalid ITS selection for positive daughter"; - break; - } - switch (itsIbSelectionNeg) { - case -1: - if (ntrack.itsNClsInnerBarrel() > 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ntrack.itsNClsInnerBarrel() < 1) { - return false; - } - break; - default: - LOG(fatal) << "Invalid ITS selection for negative daughter"; - break; - } - switch (itsAfterburnerPos) { - case -1: - if (ptrack.itsChi2NCl() >= 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ptrack.itsChi2NCl() < 0) { - return false; - } - break; - default: - LOG(fatal) << "Invalid AB selection for positive daughter"; - break; - } - switch (itsAfterburnerNeg) { - case -1: - if (ntrack.itsChi2NCl() >= 0) { - return false; - } - break; - case 0: - break; - case 1: - if (ntrack.itsChi2NCl() < 0) { - return false; - } - break; - default: - LOG(fatal) << "Invalid AB selection for negative daughter"; - break; + // ITS quality flags + // check minium ITS clusters + if (ptrack.itsNCls() < v0Selections.minITSclusters) + return false; + if (ntrack.itsNCls() < v0Selections.minITSclusters) + return false; + // check maximum ITS chi2 per clusters + if (ptrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls) + return false; + if (ntrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls) + return false; + + // TPC quality flags + // check minimum TPC crossed rows + if (ptrack.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; + if (ntrack.tpcNClsCrossedRows() < v0Selections.minTPCrows) + return false; + // check maximum TPC chi2 per clusters + if (ptrack.tpcChi2NCl() > v0Selections.maxTPCchi2PerNcls) + return false; + if (ntrack.tpcChi2NCl() > v0Selections.maxTPCchi2PerNcls) + return false; + // check minimum fraction of TPC rows over findable + if (ptrack.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; + if (ntrack.tpcCrossedRowsOverFindableCls() < v0Selections.minTPCrowsOverFindableClusters) + return false; + // check minimum fraction of found over findable TPC clusters + if (ptrack.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; + if (ntrack.tpcFoundOverFindableCls() < v0Selections.minTPCfoundOverFindableClusters) + return false; + // check the maximum fraction of allowed shared TPC clusters + if (ptrack.tpcChi2NCl() > v0Selections.maxFractionTPCSharedClusters) + return false; + if (ntrack.tpcChi2NCl() > v0Selections.maxFractionTPCSharedClusters) + return false; + + // ITS Inner Barrel selection + if (std::abs(v0Selections.requirePosITSib) > 0) { + if (v0Selections.requirePosITSib < 0 && ptrack.itsNClsInnerBarrel() > 0) // require no ITS IB + return false; + if (v0Selections.requirePosITSib > 0 && ptrack.itsNClsInnerBarrel() < 1) // require ITS IB + return false; + } + if (std::abs(v0Selections.requireNegITSib) > 0) { + if (v0Selections.requireNegITSib < 0 && ntrack.itsNClsInnerBarrel() > 0) // require no ITS IB + return false; + if (v0Selections.requireNegITSib > 0 && ntrack.itsNClsInnerBarrel() < 1) // require ITS IB + return false; } - // TPC selection - if (!ntrack.hasTPC() || !ptrack.hasTPC()) { + // ITS AfterBurner selection + if (std::abs(v0Selections.requirePosITSafterburner) > 0) { + if (v0Selections.requirePosITSafterburner < 0 && ptrack.isITSAfterburner()) // require no ITS AB + return false; + if (v0Selections.requirePosITSafterburner > 0 && !ptrack.isITSAfterburner()) // require ITS AB + return false; + } + if (std::abs(v0Selections.requireNegITSafterburner) > 0) { + if (v0Selections.requireNegITSafterburner < 0 && ntrack.isITSAfterburner()) // require no ITS AB + return false; + if (v0Selections.requireNegITSafterburner > 0 && !ntrack.isITSAfterburner()) // require ITS AB + return false; + } + + // TPC PID selection + if (std::abs(ptrack.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) { return false; } - if (std::abs(ntrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + if (std::abs(ntrack.tpcNSigmaPi()) > v0Selections.tpcPidNsigmaCut) { return false; } - if (std::abs(ptrack.tpcNSigmaPi()) > nMaxTPCNsigma) { + + // TOF PID selection + if (ptrack.hasTOF() && std::fabs(v0.tofNSigmaK0PiPlus()) > v0Selections.tofPidNsigmaCut) { return false; } - if (ntrack.tpcNClsCrossedRows() < extraCutTPCClusters || ptrack.tpcNClsCrossedRows() < extraCutTPCClusters) { + if (ntrack.hasTOF() && std::fabs(v0.tofNSigmaK0PiMinus()) > v0Selections.tofPidNsigmaCut) { return false; } // TOF selection - switch (tofSelectionPos) { - case -1: - if (ptrack.hasTOF()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ptrack.hasTOF()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TOF selection for positive daughter"; - break; - } - switch (tofSelectionNeg) { - case -1: - if (ntrack.hasTOF()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ntrack.hasTOF()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TOF selection for negative daughter"; - break; + if (std::abs(v0Selections.requirePosTOF) > 0) { + if (v0Selections.requirePosTOF < 0 && ptrack.hasTOF()) // require no TOF + return false; + if (v0Selections.requirePosTOF > 0 && !ptrack.hasTOF()) // require TOF + return false; + } + if (std::abs(v0Selections.requireNegTOF) > 0) { + if (v0Selections.requireNegTOF < 0 && ntrack.hasTOF()) // require no TOF + return false; + if (v0Selections.requireNegTOF > 0 && !ntrack.hasTOF()) // require TOF + return false; } // TRD selection - switch (trdSelectionPos) { - case -1: - if (ptrack.hasTRD()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ptrack.hasTRD()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TRD selection for positive daughter"; - break; - } - switch (trdSelectionNeg) { - case -1: - if (ntrack.hasTRD()) { - return false; - } - break; - case 0: - break; - case 1: - if (!ntrack.hasTRD()) { - return false; - } - break; - default: - LOG(fatal) << "Invalid TRD selection for negative daughter"; - break; - } - - // PID hypothesis selection - switch (pidHypoPos) { - case -1: - break; - case 0: - case 1: - case 2: - case 3: - case 4: - if (ptrack.pidForTracking() != static_cast(pidHypoPos)) { - return false; - } - break; - default: - LOG(fatal) << "Invalid PID selection for positive daughter"; - break; - } - switch (pidHypoNeg) { - case -1: - break; - case 0: - case 1: - case 2: - case 3: - case 4: - if (ntrack.pidForTracking() != static_cast(pidHypoNeg)) { - return false; - } - break; - default: - LOG(fatal) << "Invalid PID selection for negative daughter"; - break; + if (std::abs(v0Selections.requirePosTRD) > 0) { + if (v0Selections.requirePosTRD < 0 && ptrack.hasTRD()) // require no TRD + return false; + if (v0Selections.requirePosTRD > 0 && !ptrack.hasTRD()) // require TRD + return false; + } + if (std::abs(v0Selections.requireNegTRD) > 0) { + if (v0Selections.requireNegTRD < 0 && ntrack.hasTRD()) // require no TRD + return false; + if (v0Selections.requireNegTRD > 0 && !ntrack.hasTRD()) // require TRD + return false; } - return true; - } - // Filters on V0s - Filter v0Filter = (nabs(aod::v0data::dcapostopv) > v0setting_dcapostopv && - nabs(aod::v0data::dcanegtopv) > v0setting_dcanegtopv && - aod::v0data::dcaV0daughters < v0setting_dcav0dau && - aod::v0data::v0cosPA > v0setting_cospa); + // Specific PID for tracking selection + if (v0Selections.requirePosPIDforTracking > -1 && ptrack.pidForTracking() != static_cast(v0Selections.requirePosPIDforTracking)) { + return false; + } + if (v0Selections.requireNegPIDforTracking > -1 && ntrack.pidForTracking() != static_cast(v0Selections.requireNegPIDforTracking)) { + return false; + } - // Event selection - Filter eventFilter = (eventSelection && o2::aod::evsel::sel8 == true); - Filter posZFilter = (nabs(o2::aod::collision::posZ) < cutzvertex); + return true; + } - void processData(soa::Filtered::iterator const& collision, - soa::Filtered const& fullV0s, - PIDTracks const&) + void processData(SelectedCollisions::iterator const& collision, + soa::Join const& fullV0s, + PIDTracksIU const&) { - const int occupancy = collision.trackOccupancyInTimeRange(); - if (minOccupancyCut < maxOccupancyCut) { - if (occupancy < minOccupancyCut || occupancy > maxOccupancyCut) { - return; - } - } + if (!isEventAccepted(collision, true)) + return; + + float centrality = getCentralityRun3(collision); + float occupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + rK0sResolution.fill(HIST("hEventCentrality"), centrality); + rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); rK0sResolution.fill(HIST("h1_stats"), 0.5); for (auto& v0 : fullV0s) { rK0sResolution.fill(HIST("h1_stats"), 1.5); - const auto& posTrack = v0.posTrack_as(); - const auto& negTrack = v0.negTrack_as(); + const auto& posTrack = v0.posTrack_as(); + const auto& negTrack = v0.negTrack_as(); if (!acceptV0(v0, negTrack, posTrack, collision)) continue; rK0sResolution.fill(HIST("h1_stats"), 2.5); float mass = v0.mK0Short(); - if (computeInvMassFromDaughters) { - mass = RecoDecay::m(std::array{std::array{posTrack.px(), posTrack.py(), posTrack.pz()}, - std::array{negTrack.px(), negTrack.py(), negTrack.pz()}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - } rK0sResolution.fill(HIST("h2_masspT"), mass, v0.pt()); rK0sResolution.fill(HIST("h2_masseta"), mass, v0.eta()); @@ -476,6 +649,8 @@ struct perfK0sResolution { if (useMultidimHisto) { rK0sResolution.fill(HIST("thn_mass"), mass, v0.pt(), v0.eta(), v0.phi(), posTrack.eta(), negTrack.eta()); } + rK0sResolution.fill(HIST("h3_centralitypTmass"), centrality, v0.pt(), mass); + rK0sResolution.fill(HIST("h3_occupancypTmass"), occupancy, v0.pt(), mass); if (enableTPCPlot) { rK0sDauResolution.fill(HIST("h3_tpc_vs_pid_hypothesis"), posTrack.tpcInnerParam(), posTrack.tpcSignal(), posTrack.pidForTracking()); rK0sDauResolution.fill(HIST("h3_tpc_vs_pid_hypothesis"), -negTrack.tpcInnerParam(), negTrack.tpcSignal(), negTrack.pidForTracking()); @@ -520,12 +695,20 @@ struct perfK0sResolution { o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCovNeg, 2.f, matCorr, &mDcaInfoCovNeg); } - void processMC(soa::Filtered::iterator const& collision, - soa::Filtered> const& fullV0s, + void processMC(SelectedCollisions::iterator const& collision, + soa::Join const& fullV0s, PIDTracksIUMC const&, aod::McParticles const& mcParticles, aod::BCsWithTimestamps const& bcs) { + if (!isEventAccepted(collision, true)) + return; + + float centrality = getCentralityRun3(collision); + float occupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + rK0sResolution.fill(HIST("hEventCentrality"), centrality); + rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); + rK0sResolution.fill(HIST("h1_stats"), 0.5); for (auto& v0 : fullV0s) { bool daughtersHaveMCParticles = false; @@ -540,7 +723,9 @@ struct perfK0sResolution { if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { daughtersHaveMCParticles = true; rK0sResolution.fill(HIST("h1_stats"), 3.5); - if (posTrack.mcParticle().pdgCode() == 211 && negTrack.mcParticle().pdgCode() == -211) { + bool isPositivePion = posTrack.mcParticle().pdgCode() == 211 || (doTreatPiToMuon && posTrack.mcParticle().pdgCode() == -13); + bool isNegativePion = negTrack.mcParticle().pdgCode() == -211 || (doTreatPiToMuon && negTrack.mcParticle().pdgCode() == 13); + if (isPositivePion && isNegativePion) { daughtersCorrRec = true; rK0sResolution.fill(HIST("h1_stats"), 4.5); } @@ -552,11 +737,6 @@ struct perfK0sResolution { float mass = v0.mK0Short(); - if (computeInvMassFromDaughters) { - mass = RecoDecay::m(std::array{std::array{posTrack.px(), posTrack.py(), posTrack.pz()}, - std::array{negTrack.px(), negTrack.py(), negTrack.pz()}}, - std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); - } if (useTrackTuner && daughtersHaveMCParticles) { std::array pPos{0., 0., 0.}; std::array pNeg{0., 0., 0.}; @@ -567,8 +747,8 @@ struct perfK0sResolution { std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); } - const bool isTrueK0s = (v0.has_mcParticle() && v0.mcParticle().pdgCode() == 310); - if (!isTrueK0s && requireTrueK0s) { + bool isTrueK0s = (v0.has_mcParticle() && std::abs(v0.mcParticle().pdgCode()) == 310 && v0.mcParticle().isPhysicalPrimary() && daughtersCorrRec); + if (requireTrueK0s && !isTrueK0s) { continue; } @@ -614,6 +794,8 @@ struct perfK0sResolution { rK0sResolution.fill(HIST("h2_masspT"), mass, v0.pt()); rK0sResolution.fill(HIST("h2_masseta"), mass, v0.eta()); rK0sResolution.fill(HIST("h2_massphi"), mass, v0.phi()); + rK0sResolution.fill(HIST("h3_centralitypTmass"), centrality, v0.pt(), mass); + rK0sResolution.fill(HIST("h3_occupancypTmass"), occupancy, v0.pt(), mass); } } PROCESS_SWITCH(perfK0sResolution, processMC, "Process MC", false); From 32c7b743f1b07e619cfc0ca01639f9be1555b9dd Mon Sep 17 00:00:00 2001 From: romainschotter Date: Tue, 7 Oct 2025 00:12:27 +0200 Subject: [PATCH 2/3] Fix O2Linter errors --- .../AOTTrack/V0Cascades/perfK0sResolution.cxx | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index 1a66277a3a1..34de1301ab0 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -8,6 +8,14 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// +/// \file perfK0sResolution.cxx +/// \brief V0s (K0s, Lambda and antiLambda) analysis task +/// +/// \author Nicolò Jacazio , Universita del Piemonte Orientale +/// \author Roman Nepeivoda , Lund University +/// \author Romain Schotter , Austrian Academy of Sciences & MBI +// #include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" @@ -145,12 +153,12 @@ struct perfK0sResolution { Configurable requireNegITSib{"requireNegITSib", 0, "require ITS IB selection on negative daughters? -1: no ITS IB, 0: no selection, 1: ITS IB"}; Configurable requirePosITSafterburner{"requirePosITSafterburner", 0, "require positive track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; Configurable requireNegITSafterburner{"requireNegITSafterburner", 0, "require negative track formed out of afterburner ITS tracks? -1: no AB, 0: no selection, 1: AB"}; - Configurable requirePosTRD{"trdSelectionPos", 0, "require TRD selection on positive daughters? -1: no TRD, 0: no selection, 1: TRD"}; - Configurable requireNegTRD{"trdSelectionNeg", 0, "require TRD selection on negative daughters? -1: no TRD, 0: no selection, 1: TRD"}; - Configurable requirePosTOF{"tofSelectionPos", 0, "require TOF selection on positive daughters? -1: no TOF, 0: no selection, 1: TOF"}; - Configurable requireNegTOF{"tofSelectionNeg", 0, "require TOF selection on negative daughters? -1: no TOF, 0: no selection, 1: TOF"}; - Configurable requirePosPIDforTracking{"pidHypoPos", -1, "require specific PID hypothesis used in tracking for the positive daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; - Configurable requireNegPIDforTracking{"pidHypoNeg", -1, "require specific PID hypothesis used in tracking for the negative daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + Configurable requirePosTRD{"requirePosTRD", 0, "require TRD selection on positive daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requireNegTRD{"requireNegTRD", 0, "require TRD selection on negative daughters? -1: no TRD, 0: no selection, 1: TRD"}; + Configurable requirePosTOF{"requirePosTOF", 0, "require TOF selection on positive daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requireNegTOF{"requireNegTOF", 0, "require TOF selection on negative daughters? -1: no TOF, 0: no selection, 1: TOF"}; + Configurable requirePosPIDforTracking{"requirePosPIDforTracking", -1, "require specific PID hypothesis used in tracking for the positive daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; + Configurable requireNegPIDforTracking{"requireNegPIDforTracking", -1, "require specific PID hypothesis used in tracking for the negative daughters? -1: no selection, 0: Electron, 1: Muon, 2: Pion, 3: Kaon, 4: Proton"}; // PID (TPC/TOF) Configurable tpcPidNsigmaCut{"tpcPidNsigmaCut", 10., "tpcPidNsigmaCut"}; @@ -178,7 +186,7 @@ struct perfK0sResolution { Configurable trackTunerParams{"trackTunerParams", "debugInfo=0|updateTrackCovMat=0|updateCurvature=1|updatePulls=0|isInputFileFromCCDB=1|pathInputFile=Users/m/mfaggin/test/inputsTrackTuner/PbPb2022|nameInputFile=trackTuner_DataLHC22sPass5_McLHC22l1b2_run529397.root|usePvRefitCorrections=0|oneOverPtCurrent=1|oneOverPtUpgr=1.2", "TrackTuner parameter initialization (format: =|=)"}; OutputObj trackTunedTracks{TH1D("trackTunedTracks", "", 4, 0.5, 4.5), OutputObjHandlingPolicy::AnalysisObject}; Configurable lutPath{"lutPath", "GLO/Param/MatLUTInner", "Path of the Lut parametrization"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; int runNumber = -1; @@ -228,7 +236,7 @@ struct perfK0sResolution { rK0sResolution.add("h1_stats", "h1_stats", {HistType::kTH1D, {statAxis}}); TString hStatsLabels[5] = {"Selected Events", "All V0s", "Selected V0s", "Daughters have MC particles", "Daughters corr. rec."}; - for (Int_t n = 1; n <= rK0sResolution.get(HIST("h1_stats"))->GetNbinsX(); n++) { + for (int n = 1; n <= rK0sResolution.get(HIST("h1_stats"))->GetNbinsX(); n++) { rK0sResolution.get(HIST("h1_stats"))->GetXaxis()->SetBinLabel(n, hStatsLabels[n - 1]); } @@ -281,7 +289,7 @@ struct perfK0sResolution { /// TrackTuner initialization if (useTrackTuner) { - ccdb->setURL(ccdburl); + ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); @@ -633,7 +641,7 @@ struct perfK0sResolution { rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); rK0sResolution.fill(HIST("h1_stats"), 0.5); - for (auto& v0 : fullV0s) { + for (const auto& v0 : fullV0s) { rK0sResolution.fill(HIST("h1_stats"), 1.5); const auto& posTrack = v0.posTrack_as(); const auto& negTrack = v0.negTrack_as(); @@ -710,7 +718,7 @@ struct perfK0sResolution { rK0sResolution.fill(HIST("hEventOccupancy"), occupancy); rK0sResolution.fill(HIST("h1_stats"), 0.5); - for (auto& v0 : fullV0s) { + for (const auto& v0 : fullV0s) { bool daughtersHaveMCParticles = false; bool daughtersCorrRec = false; rK0sResolution.fill(HIST("h1_stats"), 1.5); @@ -723,8 +731,8 @@ struct perfK0sResolution { if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { daughtersHaveMCParticles = true; rK0sResolution.fill(HIST("h1_stats"), 3.5); - bool isPositivePion = posTrack.mcParticle().pdgCode() == 211 || (doTreatPiToMuon && posTrack.mcParticle().pdgCode() == -13); - bool isNegativePion = negTrack.mcParticle().pdgCode() == -211 || (doTreatPiToMuon && negTrack.mcParticle().pdgCode() == 13); + bool isPositivePion = posTrack.mcParticle().pdgCode() == PDG_t::kPiPlus || (doTreatPiToMuon && posTrack.mcParticle().pdgCode() == PDG_t::kMuonPlus); + bool isNegativePion = negTrack.mcParticle().pdgCode() == PDG_t::kPiMinus || (doTreatPiToMuon && negTrack.mcParticle().pdgCode() == PDG_t::kMuonMinus); if (isPositivePion && isNegativePion) { daughtersCorrRec = true; rK0sResolution.fill(HIST("h1_stats"), 4.5); @@ -747,7 +755,7 @@ struct perfK0sResolution { std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassPionCharged}); } - bool isTrueK0s = (v0.has_mcParticle() && std::abs(v0.mcParticle().pdgCode()) == 310 && v0.mcParticle().isPhysicalPrimary() && daughtersCorrRec); + bool isTrueK0s = (v0.has_mcParticle() && std::abs(v0.mcParticle().pdgCode()) == PDG_t::kK0Short && v0.mcParticle().isPhysicalPrimary() && daughtersCorrRec); if (requireTrueK0s && !isTrueK0s) { continue; } From f5ea1947e2da00ba542cab40ae84cca3c13fbb1b Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Mon, 6 Oct 2025 22:13:18 +0000 Subject: [PATCH 3/3] Please consider the following formatting changes --- DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index 34de1301ab0..1ab36ad9f71 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -230,7 +230,7 @@ struct perfK0sResolution { rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min occup."); rK0sResolution.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max occup."); - + rK0sResolution.add("hEventCentrality", "hEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); rK0sResolution.add("hEventOccupancy", "hEventOccupancy", kTH1D, {occupancyAxis}); @@ -495,7 +495,7 @@ struct perfK0sResolution { return false; if (v0.dcaV0daughters() > v0Selections.dcav0dau) return false; - + if (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short > v0Selections.lifetimecut->get("lifetimecutK0S")) { return false; } @@ -512,7 +512,7 @@ struct perfK0sResolution { return false; if (ntrack.itsNCls() < v0Selections.minITSclusters) return false; - // check maximum ITS chi2 per clusters + // check maximum ITS chi2 per clusters if (ptrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls) return false; if (ntrack.itsChi2NCl() > v0Selections.maxITSchi2PerNcls)