Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 65 additions & 55 deletions PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,21 @@ struct MeanPtFlucId {
Configurable<float> cfgCutNSig3{"cfgCutNSig3", 3.0, "nSigma cut: 3"};
Configurable<float> cfgCutNSig5{"cfgCutNSig5", 5.0, "nSigma cut: 5"};
Configurable<float> cfgCutNSigTpcTof{"cfgCutNSigTpcTof", 3.0, "nSigma TPC cut when TPC + TOF "};
Configurable<float> cfgSelCutNSigTpcPi{"cfgSelCutNSigTpcPi", 2.0, "nSigma TPC cut for pion selection"};
Configurable<float> cfgSelCutNSigTpcKa{"cfgSelCutNSigTpcKa", 2.0, "nSigma TPC cut for kaon selection"};
Configurable<float> cfgSelCutNSigTpcPr{"cfgSelCutNSigTpcPr", 2.0, "nSigma TPC cut for proton selection"};
Configurable<float> cfgSelCutNSigTofPi{"cfgSelCutNSigTofPi", 2.0, "nSigma TOF cut for pion selection"};
Configurable<float> cfgSelCutNSigTofKa{"cfgSelCutNSigTofKa", 2.0, "nSigma TOF cut for kaon selection"};
Configurable<float> cfgSelCutNSigTofPr{"cfgSelCutNSigTofPr", 2.0, "nSigma TOF cut for proton selection"};
Configurable<float> cfgSelCutNSigTpcPi{"cfgSelCutNSigTpcPi", 3.0, "nSigma TPC cut for pion selection"};
Configurable<float> cfgSelCutNSigTpcKa{"cfgSelCutNSigTpcKa", 3.0, "nSigma TPC cut for kaon selection"};
Configurable<float> cfgSelCutNSigTpcPr{"cfgSelCutNSigTpcPr", 3.0, "nSigma TPC cut for proton selection"};
Configurable<float> cfgSelCutNSigTofPi{"cfgSelCutNSigTofPi", 3.0, "nSigma TOF cut for pion selection"};
Configurable<float> cfgSelCutNSigTofKa{"cfgSelCutNSigTofKa", 3.0, "nSigma TOF cut for kaon selection"};
Configurable<float> cfgSelCutNSigTofPr{"cfgSelCutNSigTofPr", 3.0, "nSigma TOF cut for proton selection"};
// Signed TOF nSigma offsets: corrected = raw - shift. Zero preserves the original PID.
Configurable<float> cfgTofShiftPi{"cfgTofShiftPi", 0.f, "Pion TOF nSigma offset to subtract (not a time shift in ps)"};
Configurable<float> cfgTofShiftKa{"cfgTofShiftKa", 0.f, "Kaon TOF nSigma offset to subtract (not a time shift in ps)"};
Configurable<float> cfgTofShiftPr{"cfgTofShiftPr", 0.f, "Proton TOF nSigma offset to subtract (not a time shift in ps)"};
Configurable<float> cfgCutPiPtMin{"cfgCutPiPtMin", 0.2, "Minimum pion p_{T} cut"};
Configurable<float> cfgCutKaPtMin{"cfgCutKaPtMin", 0.3, "Minimum kaon p_{T} cut"};
Configurable<float> cfgCutPrPtMin{"cfgCutPrPtMin", 0.5, "Minimum proton p_{T} cut"};
Configurable<float> cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.7, "Momentum threshold for requiring pion TOF PID"};
Configurable<float> cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.8, "Momentum threshold for requiring kaon TOF PID"};
Configurable<float> cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.55, "Momentum threshold for requiring kaon TOF PID"};
Configurable<float> cfgCutPrThrsldP{"cfgCutPrThrsldP", 0.8, "Momentum threshold for requiring proton TOF PID"};
Configurable<float> cfgP0U{"cfgP0U", 6.36269, "p_{0} for upper cut for N_{TPC} vs N{sim}"};
Configurable<float> cfgP1U{"cfgP1U", 2.22108, "p_{1} for upper cut for N_{TPC} vs N{sim}"};
Expand Down Expand Up @@ -240,6 +244,10 @@ struct MeanPtFlucId {

void init(InitContext const&)
{
if (!std::isfinite(cfgTofShiftPi.value) || !std::isfinite(cfgTofShiftKa.value) || !std::isfinite(cfgTofShiftPr.value)) {
LOGF(fatal, "TOF nSigma shifts must be finite: pion=%g, kaon=%g, proton=%g",
cfgTofShiftPi.value, cfgTofShiftKa.value, cfgTofShiftPr.value);
}

if (nPtBins <= 0 || cfgCutPtMin >= cfgCutPtMax || cfgCutPiPtMin >= cfgCutPtMax ||
cfgCutKaPtMin >= cfgCutPtMax || cfgCutPrPtMin >= cfgCutPtMax) {
Expand Down Expand Up @@ -418,7 +426,7 @@ struct MeanPtFlucId {
hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtCh}});
hist.add("QA/Charged/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}});
hist.add("QA/Charged/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}});
hist.add("QA/Charged/h3_Pt_EtaMC_primary_centFT0M", "Selected primary MC particles;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}});
hist.add("QA/Charged/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}});
hist.add("QA/Charged/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtCh}});
};
addTrackQAHistograms();
Expand All @@ -429,7 +437,7 @@ struct MeanPtFlucId {
hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPi}});
hist.add("QA/Pion/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}});
hist.add("QA/Pion/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}});
hist.add("QA/Pion/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary pions;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}});
hist.add("QA/Pion/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}});
hist.add("QA/Pion/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPi}});
hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPi});
hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPi});
Expand All @@ -446,7 +454,7 @@ struct MeanPtFlucId {
hist.add("QA/Kaon/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtKa}});
hist.add("QA/Kaon/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}});
hist.add("QA/Kaon/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}});
hist.add("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary kaons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}});
hist.add("QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}});
hist.add("QA/Kaon/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtKa}});
hist.add("QA/Kaon/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtKa});
hist.add("QA/Kaon/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtKa});
Expand All @@ -463,7 +471,7 @@ struct MeanPtFlucId {
hist.add("QA/Proton/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPr}});
hist.add("QA/Proton/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}});
hist.add("QA/Proton/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}});
hist.add("QA/Proton/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary protons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}});
hist.add("QA/Proton/h3_Pt_EtaTruth_primary_centFT0M", "Selected truth primary tracks in reconstructed coordinates;#eta;p_{T};FT0M (%)", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}});
hist.add("QA/Proton/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPr}});
hist.add("QA/Proton/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPr});
hist.add("QA/Proton/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPr});
Expand Down Expand Up @@ -689,12 +697,25 @@ struct MeanPtFlucId {
std::fabs(track.tpcNSigmaPr()) > cfgCutNSig3);
}

// Share the corrected hypotheses between PID selection and selected-particle QA.
// The before-PID histograms intentionally retain raw values for calibration.
template <typename T>
std::array<float, 4> getTofNSigmaForPid(T const& track) const
{
std::array<float, 4> values = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()};
if (track.hasTOF()) {
values[static_cast<int>(PIDType::kPions)] -= cfgTofShiftPi.value;
values[static_cast<int>(PIDType::kKaons)] -= cfgTofShiftKa.value;
values[static_cast<int>(PIDType::kProtons)] -= cfgTofShiftPr.value;
}
return values;
}

// PID cuts for identified particles
template <typename T>
bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold)
bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold, const std::array<float, 4>& tofNSigma)
{
const std::array<float, 4> tpcNSigma = {-999.f, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()};
const std::array<float, 4> tofNSigma = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()};

const int selSpecies = static_cast<int>(species);
const int rejSpecies1 = static_cast<int>(reject1);
Expand Down Expand Up @@ -1092,9 +1113,10 @@ struct MeanPtFlucId {
float nSigmaTPCPi = track.tpcNSigmaPi();
float nSigmaTPCKa = track.tpcNSigmaKa();
float nSigmaTPCPr = track.tpcNSigmaPr();
float nSigmaTOFPi = track.tofNSigmaPi();
float nSigmaTOFKa = track.tofNSigmaKa();
float nSigmaTOFPr = track.tofNSigmaPr();
const auto tofNSigma = getTofNSigmaForPid(track);
const float nSigmaTOFPi = tofNSigma[static_cast<int>(PIDType::kPions)];
const float nSigmaTOFKa = tofNSigma[static_cast<int>(PIDType::kKaons)];
const float nSigmaTOFPr = tofNSigma[static_cast<int>(PIDType::kProtons)];
float rapPi = track.rapidity(MassPiPlus);
float rapKa = track.rapidity(MassKPlus);
float rapPr = track.rapidity(MassProton);
Expand Down Expand Up @@ -1129,16 +1151,13 @@ struct MeanPtFlucId {
hist.fill(HIST("QA/after/h_DCAxy_primary"), track.dcaXY());
hist.fill(HIST("QA/after/h_DCAz_primary"), track.dcaZ());
hist.fill(HIST("QA/Charged/h_PtTruth_primary"), track.pt());
const bool mcInChargedAcceptance = ptMC >= cfgCutPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta;
if (mcInChargedAcceptance) {
hist.fill(HIST("QA/Charged/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M);
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kNone, ptMC, etaMC, weight)) {
LOGF(fatal, "Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M);
}
chargedTracksTruthMatchedCorrected.push_back({ptMC, weight});
hist.fill(HIST("QA/Charged/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M);
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kNone, pt, eta, weight)) {
LOGF(fatal, "Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M);
}
chargedTracksTruthMatchedCorrected.push_back({pt, weight});
}
} else {
hist.fill(HIST("QA/after/h_DCAxy_secondary"), track.dcaXY());
Expand Down Expand Up @@ -1169,9 +1188,9 @@ struct MeanPtFlucId {
if (cfgRejTrk && rejectTracks(track)) {
continue;
}
auto selIDPion = identifyParticle(track, PIDType::kPions, PIDType::kKaons, PIDType::kProtons, p, cfgCutPiThrsldP);
auto selIDKaon = identifyParticle(track, PIDType::kKaons, PIDType::kPions, PIDType::kProtons, p, cfgCutKaThrsldP);
auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP);
auto selIDPion = identifyParticle(track, PIDType::kPions, PIDType::kKaons, PIDType::kProtons, p, cfgCutPiThrsldP, tofNSigma);
auto selIDKaon = identifyParticle(track, PIDType::kKaons, PIDType::kPions, PIDType::kProtons, p, cfgCutKaThrsldP, tofNSigma);
auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP, tofNSigma);

if (selIDPion && track.pt() >= cfgCutPiPtMin) {
if (cfgApplyEfficiencyCorrection) {
Expand Down Expand Up @@ -1213,17 +1232,14 @@ struct MeanPtFlucId {
fillPtMCHist<QA_Pion>(false, pt, eta, rapPi, phi, pid, kPiPlus, kPiMinus);
if (mc.isPhysicalPrimary()) {
hist.fill(HIST("QA/Pion/h_PtTruth_primary"), track.pt());
hist.fill(HIST("QA/Pion/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M);
hist.fill(HIST("QA/Pion/h2_Pt_EtaTruth_primary"), track.eta(), track.pt());
const bool mcInPionAcceptance = ptMC >= cfgCutPiPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta;
if (mcInPionAcceptance) {
hist.fill(HIST("QA/Pion/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M);
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kPions, ptMC, etaMC, weight)) {
LOGF(fatal, "Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M);
}
pionTracksTruthMatchedCorrected.push_back({ptMC, weight});
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kPions, pt, eta, weight)) {
LOGF(fatal, "Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M);
}
pionTracksTruthMatchedCorrected.push_back({pt, weight});
}
} else {
hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), track.pt());
Expand All @@ -1236,17 +1252,14 @@ struct MeanPtFlucId {
fillPtMCHist<QA_Kaon>(false, pt, eta, rapKa, phi, pid, kKPlus, kKMinus);
if (mc.isPhysicalPrimary()) {
hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), track.pt());
hist.fill(HIST("QA/Kaon/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M);
hist.fill(HIST("QA/Kaon/h2_Pt_EtaTruth_primary"), track.eta(), track.pt());
const bool mcInKaonAcceptance = ptMC >= cfgCutKaPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta;
if (mcInKaonAcceptance) {
hist.fill(HIST("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M);
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kKaons, ptMC, etaMC, weight)) {
LOGF(fatal, "Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M);
}
kaonTracksTruthMatchedCorrected.push_back({ptMC, weight});
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kKaons, pt, eta, weight)) {
LOGF(fatal, "Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M);
}
kaonTracksTruthMatchedCorrected.push_back({pt, weight});
}
} else {
hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), track.pt());
Expand All @@ -1259,17 +1272,14 @@ struct MeanPtFlucId {
fillPtMCHist<QA_Proton>(false, pt, eta, rapPr, phi, pid, kProton, kProtonBar);
if (mc.isPhysicalPrimary()) {
hist.fill(HIST("QA/Proton/h_PtTruth_primary"), track.pt());
hist.fill(HIST("QA/Proton/h3_Pt_EtaTruth_primary_centFT0M"), track.eta(), track.pt(), centFT0M);
hist.fill(HIST("QA/Proton/h2_Pt_EtaTruth_primary"), track.eta(), track.pt());
const bool mcInProtonAcceptance = ptMC >= cfgCutPrPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta;
if (mcInProtonAcceptance) {
hist.fill(HIST("QA/Proton/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M);
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kProtons, ptMC, etaMC, weight)) {
LOGF(fatal, "Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M);
}
protonTracksTruthMatchedCorrected.push_back({ptMC, weight});
if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) {
double weight = 0.;
if (!getEfficiencyWeight(PIDType::kProtons, pt, eta, weight)) {
LOGF(fatal, "Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M);
}
protonTracksTruthMatchedCorrected.push_back({pt, weight});
}
} else {
hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), track.pt());
Expand Down
Loading