From dc840db09a50422c3acc1397917f61ec9589f61b Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Tue, 28 Oct 2025 21:03:49 +0800 Subject: [PATCH 01/17] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 80 +++++++++- PWGDQ/Core/MCSignalLibrary.cxx | 58 +++++++- PWGDQ/Core/VarManager.cxx | 59 +++++++- PWGDQ/Core/VarManager.h | 242 +++++++++++++++++++++++++++++-- 4 files changed, 419 insertions(+), 20 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index c103d576840..f8a9488ee58 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -11,12 +11,15 @@ // // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // -#include -#include #include "PWGDQ/Core/HistogramsLibrary.h" + #include "VarManager.h" + #include "CommonConstants/MathConstants.h" +#include +#include + void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* histClass, const char* groupName, const char* subGroupName) { // @@ -959,7 +962,54 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Weight", "", false, 50, 0.0, 5.0, VarManager::kMCParticleWeight); hm->AddHistogram(histClass, "MCImpPar_CentFT0CMC", "MC impact param vs MC Cent. FT0C", false, 20, 0.0, 20.0, VarManager::kMCEventImpParam, 100, 0.0, 100.0, VarManager::kMCEventCentrFT0C); } + if (!groupStr.CompareTo("energy_correlator_gen")) { + hm->AddHistogram(histClass, "MCCostheta", "Cos#theta", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); //// + hm->AddHistogram(histClass, "MCHadronPdgCode", "MCHadronPdgCode", false, 6000, -3000, 3000, VarManager::kMCHadronPdgCode); //// + hm->AddHistogram(histClass, "MCMotherPdgCode", "MCMotherPdgCode", false, 6000, -3000, 3000, VarManager::kMCMotherPdgCode); //// + hm->AddHistogram(histClass, "MCPdgCode", "MCPdgCode", false, 1000, -1000, 1000, VarManager::kMCPdgCode); //// + hm->AddHistogram(histClass, "Coschi_pion", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_pion, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_pion); + hm->AddHistogram(histClass, "Coschi_hadron", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_hadron, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_hadron); + hm->AddHistogram(histClass, "Pt_Hadron", "", false, 120, 0.0, 30.0, VarManager::kMCHadronPt); + hm->AddHistogram(histClass, "Eta_Hadron", "", false, 120, -2.0, 2.0, VarManager::kMCHadronEta); + hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta); + hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi); + hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta, 50, -8.0, 8.0, VarManager::kMCdeltaphi); + hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_hadron, 50, -8.0, 8.0, VarManager::kMCdeltaeta, 120, 0.0, 50, VarManager::kMCWeight_hadron); + hm->AddHistogram(histClass, "Costheta_hadron_kMCWeight_before_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 50, -8.0, 8.0, VarManager::kMCdeltaeta, 120, 0.0, 50, VarManager::kMCWeight_before); + // for bkg + + hm->AddHistogram(histClass, "DeltaPhi_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_minus); + hm->AddHistogram(histClass, "DeltaPhi_toward_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_toward_minus); + hm->AddHistogram(histClass, "DeltaPhi_away_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_away_minus); + hm->AddHistogram(histClass, "DeltaPhi_trans_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_trans_minus); + + hm->AddHistogram(histClass, "Coschi_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_minus); + hm->AddHistogram(histClass, "Coschi_toward_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_toward_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_toward_minus); + hm->AddHistogram(histClass, "Coschi_away_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_away_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_away_minus); + hm->AddHistogram(histClass, "Coschi_trans_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_trans_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_trans_minus); + + hm->AddHistogram(histClass, "Costheta_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_toward_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_toward_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_away_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_away_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_trans_minus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_trans_minus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + + hm->AddHistogram(histClass, "DeltaPhi_plus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_plus); + hm->AddHistogram(histClass, "DeltaPhi_toward_plus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_toward_plus); + hm->AddHistogram(histClass, "DeltaPhi_away_plus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_away_plus); + hm->AddHistogram(histClass, "DeltaPhi_trans_plus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_trans_plus); + + hm->AddHistogram(histClass, "Coschi_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_plus); + hm->AddHistogram(histClass, "Coschi_toward_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_toward_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_toward_plus); + hm->AddHistogram(histClass, "Coschi_away_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_away_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_away_plus); + hm->AddHistogram(histClass, "Coschi_trans_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_trans_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_trans_plus); + + hm->AddHistogram(histClass, "Costheta_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_toward_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_toward_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_away_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_away_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "Costheta_trans_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_trans_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + } + // } if (!groupStr.CompareTo("pair")) { if (subGroupStr.Contains("cepf")) { hm->AddHistogram(histClass, "Mass", "", false, 300, 0.0, 12.0, VarManager::kMass); @@ -999,6 +1049,8 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Y_Pt", "", false, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 500, 0.0, 5.0, VarManager::kMass); + hm->AddHistogram(histClass, "Mass_Y_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Y", ";y", false, 40, -2.0, 2.0, VarManager::kRap); if (subGroupStr.Contains("pbpb")) { hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCentFT0C); hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 100, 0.0, 10.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); @@ -1799,6 +1851,18 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kPairMass); hm->AddHistogram(histClass, "Pt", "", false, 750, 0.0, 30.0, VarManager::kPairPt); } + if (subGroupStr.Contains("mixedevent_energy_correlator")) { // for mixed event energy_correlator + hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); + hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); + hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); + hm->AddHistogram(histClass, "Eta_Hadron", ";#eta", false, 120, -2.0, 2.0, VarManager::kEtaDau); + hm->AddHistogram(histClass, "Phi_Hadron", ";#phi", false, 120, -8, 8, VarManager::kPhiDau); + hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); + hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta); + hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kDeltaPhi); + hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kECWeight); + hm->AddHistogram(histClass, "Costheta_hadron_kMCWeight_before_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kEWeight_before); + } if (subGroupStr.Contains("invmass")) { hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 125, 0.0, 5.0, VarManager::kPairMassDau); hm->AddHistogram(histClass, "Mass_Hadron", "", false, 125, 0.0, 5.0, VarManager::kMassDau); @@ -1898,6 +1962,18 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h if (subGroupStr.Contains("opencharm")) { hm->AddHistogram(histClass, "Delta_Mass_DstarD0region", "", false, 50, 0.14, 0.16, VarManager::kDeltaMass); } + if (subGroupStr.Contains("energy_correlator")) { + hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); + hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); + hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); + hm->AddHistogram(histClass, "Eta_Hadron", ";#eta", false, 120, -2.0, 2.0, VarManager::kEtaDau); + hm->AddHistogram(histClass, "Phi_Hadron", ";#phi", false, 120, -8, 8, VarManager::kPhiDau); + hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); + hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta); + hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kDeltaPhi); + hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kECWeight); + hm->AddHistogram(histClass, "Costheta_hadron_kMCWeight_before_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kEWeight_before); + } } if (!groupStr.CompareTo("dilepton-charmhadron")) { diff --git a/PWGDQ/Core/MCSignalLibrary.cxx b/PWGDQ/Core/MCSignalLibrary.cxx index d32054afb5a..28dba386726 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -15,11 +15,13 @@ #include // #include -#include -#include "CommonConstants/PhysicsConstants.h" #include "PWGDQ/Core/MCSignalLibrary.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/Logger.h" +#include + using namespace o2::constants::physics; // using std::cout; // using std::endl; @@ -882,6 +884,22 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + ///// + if (!nameStr.compare("eeFrompromptJpsi")) { + MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from prompt j/psi decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } + + if (!nameStr.compare("eeFromnonpromptJpsi")) { + MCProng prong(3, {11, 443, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "ee pairs from nonprompt j/psi decays", {prong, prong}, {2, 2}); // signal at pair level + return signal; + } + + ////// if (!nameStr.compare("eeFromJpsiExclusive")) { MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -1885,6 +1903,42 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electron pair and pion pair from Psi2S", {pronge, pronge, prongPi, prongPi}, {2, 2, 1, 1}); return signal; } + + if (!nameStr.compare("eeFromPromptJpsiAnyPrimary")) { + MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); + return signal; + } + + if (!nameStr.compare("eeFromJpsiAnyPrimary")) { + MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); + return signal; + } + + if (!nameStr.compare("eeFromNonPromptJpsiAnyPrimary")) { + MCProng pronge(3, {11, 443, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); + pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + MCProng prongPrimary(1); + prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {2, 2, -1}); + return signal; + } + + // if (!nameStr.compare("eeFromNonPromptJpsiAnyPrimary")) { + // MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); + // pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); + // MCProng prongPrimary(1); + // prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); + // signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {-1, -1, -1}); + // return signal; + //} return nullptr; } diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 496a6ca18ae..b5b2ad5d212 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -8,12 +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. +#include "PWGDQ/Core/VarManager.h" + +#include "Tools/KFparticle/KFUtilities.h" + #include #include -#include #include -#include "PWGDQ/Core/VarManager.h" -#include "Tools/KFparticle/KFUtilities.h" +#include using std::cout; using std::endl; @@ -29,7 +31,7 @@ bool VarManager::fgUsedKF = false; float VarManager::fgMagField = 0.5; float VarManager::fgzMatching = -77.5; float VarManager::fgValues[VarManager::kNVars] = {0.0f}; -float VarManager::fgTPCInterSectorBoundary = 1.0; // cm +float VarManager::fgTPCInterSectorBoundary = 1.0; // cm int VarManager::fgITSROFbias = 0; int VarManager::fgITSROFlength = 100; int VarManager::fgITSROFBorderMarginLow = 0; @@ -728,6 +730,28 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMuonTimeRes] = "ns"; fgVariableNames[kMCPdgCode] = "MC PDG code"; fgVariableUnits[kMCPdgCode] = ""; + ///// + fgVariableNames[kMCCosTheta] = "Cos#theta"; + fgVariableUnits[kMCCosTheta] = ""; + fgVariableNames[kMCHadronPdgCode] = "HadronPdgCode"; + fgVariableUnits[kMCHadronPdgCode] = ""; + fgVariableNames[kMCCosChi_pion] = "Cos#chi"; + fgVariableUnits[kMCCosChi_pion] = ""; + fgVariableNames[kMCCosChi_hadron] = "Cos#chi"; + fgVariableUnits[kMCCosChi_hadron] = ""; + fgVariableNames[kMCJpsiPt] = "Jpsi p_{T}"; + fgVariableUnits[kMCJpsiPt] = "GeV/c"; + fgVariableNames[kMCHadronPt] = "Hadron p_{T}"; + fgVariableUnits[kMCHadronPt] = "GeV/c"; + fgVariableNames[kMCHadronEta] = "Hadron #eta"; + fgVariableUnits[kMCHadronEta] = ""; + fgVariableNames[kMCdeltaphi] = "#Delta#phi"; + fgVariableUnits[kMCdeltaphi] = ""; + fgVariableNames[kMCdeltaeta] = "#Delta#eta"; + fgVariableUnits[kMCdeltaeta] = ""; + fgVariableNames[kNhadron] = "N_{hadron}"; + fgVariableUnits[kNhadron] = ""; + ///// fgVariableNames[kMCParticleWeight] = "MC particle weight"; fgVariableUnits[kMCParticleWeight] = ""; fgVariableNames[kMCPx] = "MC px"; @@ -1156,6 +1180,16 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kDeltaPhi] = "rad."; fgVariableNames[kDeltaPhiSym] = "#Delta#phi"; fgVariableUnits[kDeltaPhiSym] = "rad."; + fgVariableNames[kCosChi] = "Cos#chi"; + fgVariableUnits[kCosChi] = ""; + fgVariableNames[kCosTheta] = "Cos#theta"; + fgVariableUnits[kCosTheta] = ""; + fgVariableNames[kPtDau] = "hadron P_{T}"; + fgVariableUnits[kPtDau] = "GeV/c"; + fgVariableNames[kEtaDau] = "hadron #eta"; + fgVariableUnits[kEtaDau] = ""; + fgVariableNames[kPhiDau] = "hadron #phi"; + fgVariableUnits[kPhiDau] = ""; fgVariableNames[kCosThetaHE] = "cos#it{#theta}"; fgVariableUnits[kCosThetaHE] = ""; fgVariableNames[kPhiHE] = "#varphi_{HE}"; @@ -1685,6 +1719,16 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kMuonNAssocsOutOfBunch"] = kMuonNAssocsOutOfBunch; fgVarNamesMap["kNMuonTrackVariables"] = kNMuonTrackVariables; fgVarNamesMap["kMCPdgCode"] = kMCPdgCode; + ////// + fgVarNamesMap["kMCCosTheta"] = kMCCosTheta; + fgVarNamesMap["kMCHadronPdgCode"] = kMCHadronPdgCode; + fgVarNamesMap["kMCCosChi_pion"] = kMCCosChi_pion; + fgVarNamesMap["kMCCosChi_hadron"] = kMCCosChi_hadron; + fgVarNamesMap["kMCHadronPt"] = kMCHadronPt; + fgVarNamesMap["kMCCosChi_minus"] = kMCCosChi_minus; + fgVarNamesMap["kMCWeight_before"] = kMCWeight_before; + + ///// fgVarNamesMap["kMCParticleWeight"] = kMCParticleWeight; fgVarNamesMap["kMCPx"] = kMCPx; fgVarNamesMap["kMCPy"] = kMCPy; @@ -1890,6 +1934,13 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kDeltaEta"] = kDeltaEta; fgVarNamesMap["kDeltaPhi"] = kDeltaPhi; fgVarNamesMap["kDeltaPhiSym"] = kDeltaPhiSym; + fgVarNamesMap["kCosTheta"] = kCosTheta; + fgVarNamesMap["kCosChi"] = kCosChi; + fgVarNamesMap["kECWeight"] = kECWeight; + fgVarNamesMap["kEWeight_before"] = kEWeight_before; + fgVarNamesMap["kPtDau"] = kPtDau; + fgVarNamesMap["kEtaDau"] = kEtaDau; + fgVarNamesMap["kPhiDau"] = kPhiDau; fgVarNamesMap["kNCorrelationVariables"] = kNCorrelationVariables; fgVarNamesMap["kQuadMass"] = kQuadMass; fgVarNamesMap["kQuadDefaultDileptonMass"] = kQuadDefaultDileptonMass; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 42531168bad..d47e8bf54fe 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -614,6 +614,51 @@ class VarManager : public TObject kMCY, kMCParticleGeneratorId, kNMCParticleVariables, + kMCHadronPdgCode, //// + kMCCosTheta, + kMCJpsiPt, /// + kMCCosChi_pion, + kMCCosChi_hadron, + kMCdeltaphi, + kMCdeltaeta, + kMCHadronPt, + kMCHadronEta, + kMCWeight_pion, + kMCWeight_hadron, + kNhadron, + kMCCosChi_minus, ///// + kMCCosTheta_minus, + kMCWeight_minus, + kMCCosChi_toward_minus, + kMCCosTheta_toward_minus, + kMCWeight_toward_minus, + kMCCosChi_away_minus, + kMCCosTheta_away_minus, + kMCWeight_away_minus, + kMCCosChi_trans_minus, + kMCCosTheta_trans_minus, + kMCWeight_trans_minus, + kMCdeltaphi_minus, + kMCdeltaphi_toward_minus, + kMCdeltaphi_away_minus, + kMCdeltaphi_trans_minus, + kMCCosChi_plus, + kMCCosTheta_plus, + kMCWeight_plus, + kMCCosChi_toward_plus, + kMCCosTheta_toward_plus, + kMCWeight_toward_plus, + kMCCosChi_away_plus, + kMCCosTheta_away_plus, + kMCWeight_away_plus, + kMCCosChi_trans_plus, + kMCCosTheta_trans_plus, + kMCWeight_trans_plus, + kMCdeltaphi_plus, + kMCdeltaphi_toward_plus, + kMCdeltaphi_away_plus, + kMCdeltaphi_trans_plus, + kMCWeight_before, // MC mother particle variables kMCMotherPdgCode, @@ -822,6 +867,13 @@ class VarManager : public TObject kDeltaPhiSym, kNCorrelationVariables, kDileptonHadronKstar, + kCosChi, + kEtaDau, + kPhiDau, + kECWeight, + kPtDau, + kCosTheta, + kEWeight_before, // Dilepton-track-track variables kQuadMass, @@ -1097,6 +1149,8 @@ class VarManager : public TObject static void FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values = nullptr); template static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); + template + static void FillEnergyCorrelators(T const& track, T1 const& t1, float* values = nullptr); template static void FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values = nullptr); template @@ -1227,15 +1281,15 @@ class VarManager : public TObject static float fgMagField; static float fgzMatching; - static float fgCenterOfMassEnergy; // collision energy - static float fgMassofCollidingParticle; // mass of the colliding particle - static float fgTPCInterSectorBoundary; // TPC inter-sector border size at the TPC outer radius, in cm - static int fgITSROFbias; // ITS ROF bias (from ALPIDE parameters) - static int fgITSROFlength; // ITS ROF length (from ALPIDE parameters) - static int fgITSROFBorderMarginLow; // ITS ROF border low margin - static int fgITSROFBorderMarginHigh; // ITS ROF border high margin - static uint64_t fgSOR; // Timestamp for start of run - static uint64_t fgEOR; // Timestamp for end of run + static float fgCenterOfMassEnergy; // collision energy + static float fgMassofCollidingParticle; // mass of the colliding particle + static float fgTPCInterSectorBoundary; // TPC inter-sector border size at the TPC outer radius, in cm + static int fgITSROFbias; // ITS ROF bias (from ALPIDE parameters) + static int fgITSROFlength; // ITS ROF length (from ALPIDE parameters) + static int fgITSROFBorderMarginLow; // ITS ROF border low margin + static int fgITSROFBorderMarginHigh; // ITS ROF border high margin + static uint64_t fgSOR; // Timestamp for start of run + static uint64_t fgEOR; // Timestamp for end of run static ROOT::Math::PxPyPzEVector fgBeamA; // beam from A-side 4-momentum vector static ROOT::Math::PxPyPzEVector fgBeamC; // beam from C-side 4-momentum vector @@ -1252,6 +1306,19 @@ class VarManager : public TObject static float calculateCosPA(KFParticle kfp, KFParticle PV); template static float calculatePhiV(const T1& t1, const T2& t2); + template + // static float LorentzTransformJpsihadroncosChi(const T1& t1, const T2& t2 ,float hadronMass); + static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); + static float RotationDeltaPhi(float deltaphi) + { + if (deltaphi > 3.0 / 2.0 * TMath::Pi()) { + deltaphi -= 2.0 * TMath::Pi(); + } + if (deltaphi < -0.5 * TMath::Pi()) { + deltaphi += 2.0 * TMath::Pi(); + } + return deltaphi; + } static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; @@ -2723,7 +2790,6 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) if (!values) { values = fgValues; } - // Quantities based on the mc particle table values[kMCPdgCode] = track.pdgCode(); values[kMCParticleWeight] = track.weight(); @@ -2746,10 +2812,118 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) values[kMCMotherPdgCode] = mother.pdgCode(); } } - FillTrackDerived(values); } +template +void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* values) +{ + // energy correlators + float p2 = t1.p(); + float E_hadron = t1.e(); + float MassPion = o2::constants::physics::MassPionCharged; + float MassHadron = TMath::Sqrt(E_hadron * E_hadron - p2 * p2); + ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); + float deltaphi = RotationDeltaPhi(track.phi() - t1.phi()); + float deltaeta = t1.eta() - track.eta(); + ROOT::Math::PtEtaPhiMVector v2_pion(t1.pt(), t1.eta(), t1.phi(), MassPion); + ROOT::Math::PtEtaPhiMVector v2_hadron(t1.pt(), t1.eta(), t1.phi(), MassHadron); + float E_boost_pion = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_pion); + float E_boost_hadron = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron); + float CosChi_pion = LorentzTransformJpsihadroncosChi("coschi", v1, v2_pion); + float CosChi_hadron = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron); + float CosTheta = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron); + values[kMCCosChi_pion] = CosChi_pion; + values[kMCCosChi_hadron] = CosChi_hadron; + values[kMCWeight_before] = t1.pt() / o2::constants::physics::MassJPsi; + values[kMCCosTheta] = CosTheta; + values[kMCdeltaphi] = deltaphi; + values[kMCdeltaeta] = deltaeta; + values[kMCHadronPt] = t1.pt(); + values[kMCHadronEta] = t1.eta(); + values[kMCHadronPdgCode] = t1.pdgCode(); + values[kMCWeight_pion] = E_boost_pion / o2::constants::physics::MassJPsi; + values[kMCWeight_hadron] = E_boost_hadron / o2::constants::physics::MassJPsi; + values[kMCCosChi_minus] = -999.9f; + values[kMCCosTheta_minus] = -999.9f; + values[kMCCosChi_toward_minus] = -999.9f; + values[kMCCosTheta_toward_minus] = -999.9f; + values[kMCCosChi_away_minus] = -999.9f; + values[kMCCosTheta_away_minus] = -999.9f; + values[kMCCosChi_trans_minus] = -999.9f; + values[kMCCosTheta_trans_minus] = -999.9f; + values[kMCdeltaphi_minus] = -999.9f; + values[kMCdeltaphi_toward_minus] = -999.9f; + values[kMCdeltaphi_away_minus] = -999.9f; + values[kMCdeltaphi_trans_minus] = -999.9f; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -0.25 * TMath::Pi()) || (deltaphi > 1.25 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi())) { + + values[kMCCosChi_minus] = CosChi_hadron; + values[kMCCosTheta_minus] = CosTheta; + values[kMCWeight_minus] = E_boost_hadron / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_toward_minus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_toward_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_toward_minus); + values[kMCCosTheta_toward_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_toward_minus); + values[kMCWeight_toward_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_toward_minus) / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_away_minus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_away_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_away_minus); + values[kMCCosTheta_away_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_away_minus); + values[kMCWeight_away_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_away_minus) / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_trans_minus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); + values[kMCCosChi_trans_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_trans_minus); + values[kMCCosTheta_trans_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_trans_minus); + values[kMCWeight_trans_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_trans_minus) / o2::constants::physics::MassJPsi; + + values[kMCdeltaphi_minus] = deltaphi; + values[kMCdeltaphi_toward_minus] = RotationDeltaPhi(track.phi() - (t1.phi() - 0.5 * TMath::Pi())); + values[kMCdeltaphi_away_minus] = RotationDeltaPhi(track.phi() - (t1.phi() + 0.5 * TMath::Pi())); + values[kMCdeltaphi_trans_minus] = RotationDeltaPhi(track.phi() - t1.phi() + TMath::Pi()); + } + + values[kMCCosChi_plus] = -999.9f; + values[kMCCosTheta_plus] = -999.9f; + values[kMCCosChi_toward_plus] = -999.9f; + values[kMCCosTheta_toward_plus] = -999.9f; + values[kMCCosChi_away_plus] = -999.9f; + values[kMCCosTheta_away_plus] = -999.9f; + values[kMCCosChi_trans_plus] = -999.9f; + values[kMCCosTheta_trans_plus] = -999.9f; + values[kMCdeltaphi_plus] = -999.9f; + values[kMCdeltaphi_toward_plus] = -999.9f; + values[kMCdeltaphi_away_plus] = -999.9f; + values[kMCdeltaphi_trans_plus] = -999.9f; + + if (deltaphi > 0.25 * TMath::Pi() && deltaphi < 0.75 * TMath::Pi()) { + values[kMCCosChi_plus] = CosChi_hadron; + values[kMCCosTheta_plus] = CosTheta; + values[kMCWeight_plus] = E_boost_hadron / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_toward_plus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_toward_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_toward_plus); + values[kMCCosTheta_toward_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_toward_plus); + values[kMCWeight_toward_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_toward_plus) / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_away_plus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_away_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_away_plus); + values[kMCCosTheta_away_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_away_plus); + values[kMCWeight_away_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_away_plus) / o2::constants::physics::MassJPsi; + + ROOT::Math::PtEtaPhiMVector v2_hadron_trans_plus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); + values[kMCCosChi_trans_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_trans_plus); + values[kMCCosTheta_trans_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_trans_plus); + values[kMCWeight_trans_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_trans_plus) / o2::constants::physics::MassJPsi; + + values[kMCdeltaphi_plus] = deltaphi; + values[kMCdeltaphi_toward_plus] = RotationDeltaPhi(track.phi() - (t1.phi() + 0.5 * TMath::Pi())); + values[kMCdeltaphi_away_plus] = RotationDeltaPhi(track.phi() - (t1.phi() - 0.5 * TMath::Pi())); + values[kMCdeltaphi_trans_plus] = RotationDeltaPhi(track.phi() - t1.phi() + TMath::Pi()); + } +} + template void VarManager::FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values) { @@ -4343,6 +4517,16 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[VarManager::kPairMassDau] = v12.M(); values[VarManager::kPairPtDau] = v12.Pt(); } + if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kPhiDau] || fgUsedVars[kEtaDau]) { + values[VarManager::kCosTheta] = LorentzTransformJpsihadroncosChi("costheta", v12, v3); + values[VarManager::kEWeight_before] = v3.Pt() / v12.M(); + values[VarManager::kPtDau] = v3.Pt(); + values[VarManager::kEtaDau] = v3.Eta(); + values[VarManager::kPhiDau] = v3.Phi(); + float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v12, v3); + values[VarManager::kCosChi] = LorentzTransformJpsihadroncosChi("coschi", v12, v3); + values[VarManager::kECWeight] = E_boost / v12.M(); + } values[VarManager::kPt] = track.pt(); values[kS12] = (v1 + v2).M2(); values[kS13] = (v1 + v3).M2(); @@ -5031,7 +5215,7 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = fgValues; } - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau] || fgUsedVars[kDileptonHadronKstar]) { + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau] || fgUsedVars[kDileptonHadronKstar] || fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau]) { ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; @@ -5048,6 +5232,11 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* double Pinv = v12.M(); double Q1 = (dilepton.mass() * dilepton.mass() - hadronMass * hadronMass) / Pinv; values[kDileptonHadronKstar] = sqrt(Q1 * Q1 - v12_Qvect.M2()) / 2.0; + values[kCosChi] = LorentzTransformJpsihadroncosChi("coschi", v1, v2); + float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); + values[kECWeight] = E_boost / v1.M(); + values[kCosTheta] = LorentzTransformJpsihadroncosChi("costheta", v1, v2); + values[kEWeight_before] = v2.Pt() / v1.M(); } if (fgUsedVars[kDeltaPhi]) { double delta = dilepton.phi() - hadron.phi(); @@ -5632,5 +5821,34 @@ void VarManager::FillBdtScore(T1 const& bdtScore, float* values) LOG(warning) << "Unexpected number of BDT outputs: " << bdtScore.size(); } } +//__________________________________________________________________ +template +float VarManager::LorentzTransformJpsihadroncosChi(TString Option, T1 const& v1, T2 const& v2) +{ + float value = -999; + float p1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); + float p2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); + float beta = p1 / v1.E(); + float gamma = 1.0 / TMath::Sqrt(1 - beta * beta); + float nx = v1.Px() / p1; + float ny = v1.Py() / p1; + float nz = v1.Pz() / p1; + float px_boost = (-gamma * beta * nx) * v2.E() + (1 + (gamma - 1) * nx * nx) * v2.Px() + ((gamma - 1) * nx * ny) * v2.Py() + ((gamma - 1) * nx * nz) * v2.Pz(); + float py_boost = (-gamma * beta * ny) * v2.E() + ((gamma - 1) * ny * nx) * v2.Px() + (1 + (gamma - 1) * ny * ny) * v2.Py() + ((gamma - 1) * ny * nz) * v2.Pz(); + float pz_boost = (-gamma * beta * nz) * v2.E() + ((gamma - 1) * nz * nx) * v2.Px() + ((gamma - 1) * nz * ny) * v2.Py() + (1 + (gamma - 1) * nz * nz) * v2.Pz(); + float p_boost = TMath::Sqrt(px_boost * px_boost + py_boost * py_boost + pz_boost * pz_boost); + + if (Option == "coschi") { + value = (px_boost * v1.Px() + py_boost * v1.Py() + pz_boost * v1.Pz()) / (p1 * p_boost); + } + if (Option == "costheta") { + value = (v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / (p1 * p2); + } + if (Option == "weight_boost") { + value = gamma * (v2.E() - v1.Px() / v1.E() * v2.Px() - v1.Py() / v1.E() * v2.Py() - v1.Pz() / v1.E() * v2.Pz()); + } + + return value; +} #endif // PWGDQ_CORE_VARMANAGER_H_ From e31d90a06a3011c1b31c69844f6d60228a0869e5 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Tue, 28 Oct 2025 21:04:15 +0800 Subject: [PATCH 02/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 71 +++++++++++++++++++++----- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 552dd2b4e93..1352e448722 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -1721,10 +1721,10 @@ struct AnalysisSameEventPairing { template void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) { - // if (events.size() == 0) { - // LOG(warning) << "No events in this TF, going to the next one ..."; - // return; - // } + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } if (fCurrentRun != events.begin().runNumber()) { initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); fCurrentRun = events.begin().runNumber(); @@ -3452,9 +3452,15 @@ struct AnalysisDileptonTrack { Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of track cuts to be correlated with the dileptons"}; Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; - Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseMCGenpTcut{"cfgUseMCGenpTcut", false, "Use pT cut for dileptons used in the triplet vertexing(generated)"}; + Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(generated and reconstructed)"}; + Configurable fConfigCaculateEC{"cfgCaculateEC", false, "the switch for caculate the energy correlators"}; + Configurable fConfigCaculateRE{"cfgCaculateRE", true, "the switch for caculate the RE"}; Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; @@ -3497,7 +3503,7 @@ struct AnalysisDileptonTrack { // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonpTCut&& aod::reducedpair::mass > fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; + Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonLowpTCut&& aod::reducedpair::pt fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); @@ -3505,6 +3511,8 @@ struct AnalysisDileptonTrack { // use two values array to avoid mixing up the quantities float* fValuesDilepton; + float* fValuesSignal; + float* fValuesEC; float* fValuesHadron; HistogramManager* fHistMan; @@ -3540,6 +3548,9 @@ struct AnalysisDileptonTrack { fValuesDilepton = new float[VarManager::kNVars]; fValuesHadron = new float[VarManager::kNVars]; + fValuesSignal = new float[VarManager::kNVars]; + fValuesEC = new float[VarManager::kNVars]; + fTrackCutBitMap = 0; VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -3799,9 +3810,11 @@ struct AnalysisDileptonTrack { DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); } - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); - DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); + if (fConfigCaculateRE) { + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); + } } } @@ -3866,6 +3879,11 @@ struct AnalysisDileptonTrack { continue; } + // dilepton rap cut + float rap = dilepton.rap(); + if (fConfigUseMCRapcut && abs(rap) > fConfigDileptonRapCutAbs) + continue; + VarManager::FillTrack(dilepton, fValuesDilepton); // fill selected dilepton histograms for each specified selection @@ -4185,6 +4203,8 @@ struct AnalysisDileptonTrack { void processMCGenWithEventSelection(soa::Filtered const& events, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) { + VarManager::ResetValues(0, VarManager::kNVars, fValuesSignal); + VarManager::ResetValues(0, VarManager::kNVars, fValuesEC); for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -4196,17 +4216,39 @@ struct AnalysisDileptonTrack { auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (auto& track : groupedMCTracks) { - - VarManager::FillTrackMC(mcTracks, track); - - auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + // apply kinematic cuts for signal + if (fConfigUseMCGenpTcut && (track_raw.pt() < fConfigDileptonLowpTCut || track_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (fConfigUseMCRapcut && abs(track_raw.y()) > fConfigDileptonRapCutAbs) + continue; + VarManager::FillTrackMC(mcTracks, track_raw, fValuesSignal); for (auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), fValuesSignal); + } + } + // for the energy correlators + if (!fConfigCaculateEC) + continue; + for (auto& mctrack1 : groupedMCTracks) { + if (TMath::Abs(mctrack1.pdgCode()) == 443 || TMath::Abs(mctrack1.pdgCode()) == 11 || TMath::Abs(mctrack1.pdgCode()) == 22) + continue; + if (mctrack1.pt() < fConfigMCGenHadronPtMin.value || std::abs(mctrack1.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (mctrack1.getGenStatusCode() <= 0) + continue; + for (auto& sig : fGenMCSignals) { + VarManager::FillEnergyCorrelators(track_raw, mctrack1, fValuesEC); + if (sig->CheckSignal(true, track_raw)) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), fValuesEC); + } } } } + if (!fConfigCaculateRE) + continue; // make a list of all MC tracks in the MC collision corresponding to the current reconstructed event std::vector mcTrackIndices; for (auto& t : groupedMCTracks) { @@ -4334,6 +4376,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy_correlator_gen"); } if (classStr.Contains("DileptonsSelected")) { From 0e2dfee7a257d50ed0007fc596fe69582727c504 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 31 Oct 2025 19:22:32 +0800 Subject: [PATCH 03/17] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 23 ++--- PWGDQ/Core/MCSignalLibrary.cxx | 27 +---- PWGDQ/Core/VarManager.cxx | 14 +-- PWGDQ/Core/VarManager.h | 163 +++++++++++++++---------------- 4 files changed, 92 insertions(+), 135 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 8f3f9a72e21..84709dbb757 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -968,22 +968,21 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Weight", "", false, 50, 0.0, 5.0, VarManager::kMCParticleWeight); hm->AddHistogram(histClass, "MCImpPar_CentFT0CMC", "MC impact param vs MC Cent. FT0C", false, 20, 0.0, 20.0, VarManager::kMCEventImpParam, 100, 0.0, 100.0, VarManager::kMCEventCentrFT0C); } - if (!groupStr.CompareTo("energy_correlator_gen")) { - hm->AddHistogram(histClass, "MCCostheta", "Cos#theta", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); //// - hm->AddHistogram(histClass, "MCHadronPdgCode", "MCHadronPdgCode", false, 6000, -3000, 3000, VarManager::kMCHadronPdgCode); //// - hm->AddHistogram(histClass, "MCMotherPdgCode", "MCMotherPdgCode", false, 6000, -3000, 3000, VarManager::kMCMotherPdgCode); //// - hm->AddHistogram(histClass, "MCPdgCode", "MCPdgCode", false, 1000, -1000, 1000, VarManager::kMCPdgCode); //// - hm->AddHistogram(histClass, "Coschi_pion", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_pion, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_pion); - hm->AddHistogram(histClass, "Coschi_hadron", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_hadron, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_hadron); + + if (!groupStr.CompareTo("energy-correlator-gen")) { + hm->AddHistogram(histClass, "MCCostheta", "Cos#theta", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); + hm->AddHistogram(histClass, "MCHadronPdgCode", "MCHadronPdgCode", false, 6000, -3000, 3000, VarManager::kMCHadronPdgCode); + hm->AddHistogram(histClass, "MCMotherPdgCode", "MCMotherPdgCode", false, 6000, -3000, 3000, VarManager::kMCMotherPdgCode); + hm->AddHistogram(histClass, "MCPdgCode", "MCPdgCode", false, 1000, -1000, 1000, VarManager::kMCPdgCode); + hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight); hm->AddHistogram(histClass, "Pt_Hadron", "", false, 120, 0.0, 30.0, VarManager::kMCHadronPt); hm->AddHistogram(histClass, "Eta_Hadron", "", false, 120, -2.0, 2.0, VarManager::kMCHadronEta); hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta); hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi); hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kMCdeltaeta, 50, -8.0, 8.0, VarManager::kMCdeltaphi); - hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_hadron, 50, -8.0, 8.0, VarManager::kMCdeltaeta, 120, 0.0, 50, VarManager::kMCWeight_hadron); + hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi, 50, -8.0, 8.0, VarManager::kMCdeltaeta, 120, 0.0, 50, VarManager::kMCWeight); hm->AddHistogram(histClass, "Costheta_hadron_kMCWeight_before_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta, 50, -8.0, 8.0, VarManager::kMCdeltaeta, 120, 0.0, 50, VarManager::kMCWeight_before); // for bkg - hm->AddHistogram(histClass, "DeltaPhi_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_minus); hm->AddHistogram(histClass, "DeltaPhi_toward_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_toward_minus); hm->AddHistogram(histClass, "DeltaPhi_away_minus", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_away_minus); @@ -1014,8 +1013,6 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Costheta_away_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_away_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); hm->AddHistogram(histClass, "Costheta_trans_plus", "", false, 40, -1.0, 1.0, VarManager::kMCCosTheta_trans_plus, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_before); } - - // } if (!groupStr.CompareTo("pair")) { if (subGroupStr.Contains("cepf")) { hm->AddHistogram(histClass, "Mass", "", false, 300, 0.0, 12.0, VarManager::kMass); @@ -1857,7 +1854,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kPairMass); hm->AddHistogram(histClass, "Pt", "", false, 750, 0.0, 30.0, VarManager::kPairPt); } - if (subGroupStr.Contains("mixedevent_energy_correlator")) { // for mixed event energy_correlator + if (subGroupStr.Contains("mixedevent-energy-correlator")) { // for mixed event_correnergyelator hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); @@ -1968,7 +1965,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h if (subGroupStr.Contains("opencharm")) { hm->AddHistogram(histClass, "Delta_Mass_DstarD0region", "", false, 50, 0.14, 0.16, VarManager::kDeltaMass); } - if (subGroupStr.Contains("energy_correlator")) { + if (subGroupStr.Contains("energy-correlator")) { hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); diff --git a/PWGDQ/Core/MCSignalLibrary.cxx b/PWGDQ/Core/MCSignalLibrary.cxx index 28dba386726..161145dda25 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -884,22 +884,6 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from j/psi decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } - ///// - if (!nameStr.compare("eeFrompromptJpsi")) { - MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {true}); - prong.SetSourceBit(0, MCProng::kPhysicalPrimary); - signal = new MCSignal(name, "ee pairs from prompt j/psi decays", {prong, prong}, {1, 1}); // signal at pair level - return signal; - } - - if (!nameStr.compare("eeFromnonpromptJpsi")) { - MCProng prong(3, {11, 443, 503}, {true, true, true}, {false, false, false}, {0, 0, 0}, {0, 0, 0}, {false, false, false}); - prong.SetSourceBit(0, MCProng::kPhysicalPrimary); - signal = new MCSignal(name, "ee pairs from nonprompt j/psi decays", {prong, prong}, {2, 2}); // signal at pair level - return signal; - } - - ////// if (!nameStr.compare("eeFromJpsiExclusive")) { MCProng prong(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -1927,18 +1911,9 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); MCProng prongPrimary(1); prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); - signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {2, 2, -1}); + signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); return signal; } - - // if (!nameStr.compare("eeFromNonPromptJpsiAnyPrimary")) { - // MCProng pronge(2, {11, 443}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {503}, {false}); - // pronge.SetSourceBit(0, MCProng::kPhysicalPrimary); - // MCProng prongPrimary(1); - // prongPrimary.SetSourceBit(0, MCProng::kPhysicalPrimary); - // signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {-1, -1, -1}); - // return signal; - //} return nullptr; } diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 1e77521821d..04445304d56 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -736,15 +736,12 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMuonTimeRes] = "ns"; fgVariableNames[kMCPdgCode] = "MC PDG code"; fgVariableUnits[kMCPdgCode] = ""; - ///// fgVariableNames[kMCCosTheta] = "Cos#theta"; fgVariableUnits[kMCCosTheta] = ""; fgVariableNames[kMCHadronPdgCode] = "HadronPdgCode"; fgVariableUnits[kMCHadronPdgCode] = ""; - fgVariableNames[kMCCosChi_pion] = "Cos#chi"; - fgVariableUnits[kMCCosChi_pion] = ""; - fgVariableNames[kMCCosChi_hadron] = "Cos#chi"; - fgVariableUnits[kMCCosChi_hadron] = ""; + fgVariableNames[kMCCosChi] = "Cos#chi"; + fgVariableUnits[kMCCosChi] = ""; fgVariableNames[kMCJpsiPt] = "Jpsi p_{T}"; fgVariableUnits[kMCJpsiPt] = "GeV/c"; fgVariableNames[kMCHadronPt] = "Hadron p_{T}"; @@ -757,7 +754,6 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kMCdeltaeta] = ""; fgVariableNames[kNhadron] = "N_{hadron}"; fgVariableUnits[kNhadron] = ""; - ///// fgVariableNames[kMCParticleWeight] = "MC particle weight"; fgVariableUnits[kMCParticleWeight] = ""; fgVariableNames[kMCPx] = "MC px"; @@ -1725,16 +1721,12 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kMuonNAssocsOutOfBunch"] = kMuonNAssocsOutOfBunch; fgVarNamesMap["kNMuonTrackVariables"] = kNMuonTrackVariables; fgVarNamesMap["kMCPdgCode"] = kMCPdgCode; - ////// fgVarNamesMap["kMCCosTheta"] = kMCCosTheta; fgVarNamesMap["kMCHadronPdgCode"] = kMCHadronPdgCode; - fgVarNamesMap["kMCCosChi_pion"] = kMCCosChi_pion; - fgVarNamesMap["kMCCosChi_hadron"] = kMCCosChi_hadron; + fgVarNamesMap["kMCCosChi"] = kMCCosChi; fgVarNamesMap["kMCHadronPt"] = kMCHadronPt; fgVarNamesMap["kMCCosChi_minus"] = kMCCosChi_minus; fgVarNamesMap["kMCWeight_before"] = kMCWeight_before; - - ///// fgVarNamesMap["kMCParticleWeight"] = kMCParticleWeight; fgVarNamesMap["kMCPx"] = kMCPx; fgVarNamesMap["kMCPy"] = kMCPy; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index c813fed0fe8..149824b0f6b 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -159,6 +159,12 @@ class VarManager : public TObject kNMaxCandidateTypes }; + enum HadronMassCandidateType { + // The mass of the associated hadron + kRealHadronMass = 0, // using the real hadron mass + kTreatAsPion // treat the hadron as pion + }; + enum BarrelTrackFilteringBits { kIsConversionLeg = 0, // electron from conversions kIsK0sLeg, // pion from K0s @@ -617,19 +623,17 @@ class VarManager : public TObject kMCY, kMCParticleGeneratorId, kNMCParticleVariables, - kMCHadronPdgCode, //// + kMCHadronPdgCode, kMCCosTheta, - kMCJpsiPt, /// - kMCCosChi_pion, - kMCCosChi_hadron, + kMCJpsiPt, + kMCCosChi, kMCdeltaphi, kMCdeltaeta, kMCHadronPt, kMCHadronEta, - kMCWeight_pion, - kMCWeight_hadron, + kMCWeight, kNhadron, - kMCCosChi_minus, ///// + kMCCosChi_minus, kMCCosTheta_minus, kMCWeight_minus, kMCCosChi_toward_minus, @@ -1152,7 +1156,7 @@ class VarManager : public TObject static void FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values = nullptr); template static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); - template + template static void FillEnergyCorrelators(T const& track, T1 const& t1, float* values = nullptr); template static void FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values = nullptr); @@ -2074,7 +2078,6 @@ void VarManager::FillEvent(T const& event, float* values) values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); - values[kMCEventCentrFT0C] = event.centFT0C(); } if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { @@ -2822,26 +2825,26 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) FillTrackDerived(values); } -template +template void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* values) { // energy correlators - float p2 = t1.p(); - float E_hadron = t1.e(); - float MassPion = o2::constants::physics::MassPionCharged; - float MassHadron = TMath::Sqrt(E_hadron * E_hadron - p2 * p2); + float MassHadron; + if constexpr (massType == kRealHadronMass) { + MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); + ; + } + if constexpr (massType == kTreatAsPion) { + MassHadron = o2::constants::physics::MassPionCharged; + } ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); float deltaphi = RotationDeltaPhi(track.phi() - t1.phi()); float deltaeta = t1.eta() - track.eta(); - ROOT::Math::PtEtaPhiMVector v2_pion(t1.pt(), t1.eta(), t1.phi(), MassPion); - ROOT::Math::PtEtaPhiMVector v2_hadron(t1.pt(), t1.eta(), t1.phi(), MassHadron); - float E_boost_pion = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_pion); - float E_boost_hadron = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron); - float CosChi_pion = LorentzTransformJpsihadroncosChi("coschi", v1, v2_pion); - float CosChi_hadron = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron); - float CosTheta = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron); - values[kMCCosChi_pion] = CosChi_pion; - values[kMCCosChi_hadron] = CosChi_hadron; + ROOT::Math::PtEtaPhiMVector v2(t1.pt(), t1.eta(), t1.phi(), MassHadron); + float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); + float CosChi = LorentzTransformJpsihadroncosChi("coschi", v1, v2); + float CosTheta = LorentzTransformJpsihadroncosChi("costheta", v1, v2); + values[kMCCosChi] = CosChi; values[kMCWeight_before] = t1.pt() / o2::constants::physics::MassJPsi; values[kMCCosTheta] = CosTheta; values[kMCdeltaphi] = deltaphi; @@ -2849,8 +2852,7 @@ void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* valu values[kMCHadronPt] = t1.pt(); values[kMCHadronEta] = t1.eta(); values[kMCHadronPdgCode] = t1.pdgCode(); - values[kMCWeight_pion] = E_boost_pion / o2::constants::physics::MassJPsi; - values[kMCWeight_hadron] = E_boost_hadron / o2::constants::physics::MassJPsi; + values[kMCWeight] = E_boost / o2::constants::physics::MassJPsi; values[kMCCosChi_minus] = -999.9f; values[kMCCosTheta_minus] = -999.9f; values[kMCCosChi_toward_minus] = -999.9f; @@ -2866,24 +2868,24 @@ void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* valu if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -0.25 * TMath::Pi()) || (deltaphi > 1.25 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi())) { - values[kMCCosChi_minus] = CosChi_hadron; + values[kMCCosChi_minus] = CosChi; values[kMCCosTheta_minus] = CosTheta; - values[kMCWeight_minus] = E_boost_hadron / o2::constants::physics::MassJPsi; + values[kMCWeight_minus] = E_boost / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_toward_minus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); - values[kMCCosChi_toward_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_toward_minus); - values[kMCCosTheta_toward_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_toward_minus); - values[kMCWeight_toward_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_toward_minus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_toward_minus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_toward_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_toward_minus); + values[kMCCosTheta_toward_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_toward_minus); + values[kMCWeight_toward_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_toward_minus) / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_away_minus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); - values[kMCCosChi_away_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_away_minus); - values[kMCCosTheta_away_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_away_minus); - values[kMCWeight_away_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_away_minus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_away_minus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_away_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_away_minus); + values[kMCCosTheta_away_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_away_minus); + values[kMCWeight_away_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_away_minus) / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_trans_minus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); - values[kMCCosChi_trans_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_trans_minus); - values[kMCCosTheta_trans_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_trans_minus); - values[kMCWeight_trans_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_trans_minus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_trans_minus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); + values[kMCCosChi_trans_minus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_trans_minus); + values[kMCCosTheta_trans_minus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_trans_minus); + values[kMCWeight_trans_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_trans_minus) / o2::constants::physics::MassJPsi; values[kMCdeltaphi_minus] = deltaphi; values[kMCdeltaphi_toward_minus] = RotationDeltaPhi(track.phi() - (t1.phi() - 0.5 * TMath::Pi())); @@ -2905,24 +2907,24 @@ void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* valu values[kMCdeltaphi_trans_plus] = -999.9f; if (deltaphi > 0.25 * TMath::Pi() && deltaphi < 0.75 * TMath::Pi()) { - values[kMCCosChi_plus] = CosChi_hadron; + values[kMCCosChi_plus] = CosChi; values[kMCCosTheta_plus] = CosTheta; - values[kMCWeight_plus] = E_boost_hadron / o2::constants::physics::MassJPsi; + values[kMCWeight_plus] = E_boost / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_toward_plus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); - values[kMCCosChi_toward_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_toward_plus); - values[kMCCosTheta_toward_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_toward_plus); - values[kMCWeight_toward_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_toward_plus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_toward_plus(t1.pt(), t1.eta(), t1.phi() + 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_toward_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_toward_plus); + values[kMCCosTheta_toward_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_toward_plus); + values[kMCWeight_toward_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_toward_plus) / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_away_plus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); - values[kMCCosChi_away_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_away_plus); - values[kMCCosTheta_away_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_away_plus); - values[kMCWeight_away_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_away_plus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_away_plus(t1.pt(), t1.eta(), t1.phi() - 0.5 * TMath::Pi(), MassHadron); + values[kMCCosChi_away_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_away_plus); + values[kMCCosTheta_away_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_away_plus); + values[kMCWeight_away_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_away_plus) / o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v2_hadron_trans_plus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); - values[kMCCosChi_trans_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_hadron_trans_plus); - values[kMCCosTheta_trans_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_hadron_trans_plus); - values[kMCWeight_trans_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_hadron_trans_plus) / o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v2_trans_plus(t1.pt(), t1.eta(), t1.phi() + TMath::Pi(), MassHadron); + values[kMCCosChi_trans_plus] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_trans_plus); + values[kMCCosTheta_trans_plus] = LorentzTransformJpsihadroncosChi("costheta", v1, v2_trans_plus); + values[kMCWeight_trans_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_trans_plus) / o2::constants::physics::MassJPsi; values[kMCdeltaphi_plus] = deltaphi; values[kMCdeltaphi_toward_plus] = RotationDeltaPhi(track.phi() - (t1.phi() + 0.5 * TMath::Pi())); @@ -4524,16 +4526,6 @@ void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton values[VarManager::kPairMassDau] = v12.M(); values[VarManager::kPairPtDau] = v12.Pt(); } - if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kPhiDau] || fgUsedVars[kEtaDau]) { - values[VarManager::kCosTheta] = LorentzTransformJpsihadroncosChi("costheta", v12, v3); - values[VarManager::kEWeight_before] = v3.Pt() / v12.M(); - values[VarManager::kPtDau] = v3.Pt(); - values[VarManager::kEtaDau] = v3.Eta(); - values[VarManager::kPhiDau] = v3.Phi(); - float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v12, v3); - values[VarManager::kCosChi] = LorentzTransformJpsihadroncosChi("coschi", v12, v3); - values[VarManager::kECWeight] = E_boost / v12.M(); - } values[VarManager::kPt] = track.pt(); values[kS12] = (v1 + v2).M2(); values[kS13] = (v1 + v3).M2(); @@ -5222,7 +5214,7 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = fgValues; } - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau] || fgUsedVars[kDileptonHadronKstar] || fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau]) { + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi] || fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau] || fgUsedVars[kDileptonHadronKstar]) { ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; @@ -5239,11 +5231,18 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* double Pinv = v12.M(); double Q1 = (dilepton.mass() * dilepton.mass() - hadronMass * hadronMass) / Pinv; values[kDileptonHadronKstar] = sqrt(Q1 * Q1 - v12_Qvect.M2()) / 2.0; + } + if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau]) { + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); + ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), o2::constants::physics::MassPionCharged); values[kCosChi] = LorentzTransformJpsihadroncosChi("coschi", v1, v2); float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); values[kECWeight] = E_boost / v1.M(); values[kCosTheta] = LorentzTransformJpsihadroncosChi("costheta", v1, v2); values[kEWeight_before] = v2.Pt() / v1.M(); + values[kPtDau] = v2.pt(); + values[kEtaDau] = v2.eta(); + values[kPhiDau] = v2.phi(); } if (fgUsedVars[kDeltaPhi]) { double delta = dilepton.phi() - hadron.phi(); @@ -5832,29 +5831,23 @@ void VarManager::FillBdtScore(T1 const& bdtScore, float* values) template float VarManager::LorentzTransformJpsihadroncosChi(TString Option, T1 const& v1, T2 const& v2) { - float value = -999; - float p1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); - float p2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); - float beta = p1 / v1.E(); - float gamma = 1.0 / TMath::Sqrt(1 - beta * beta); - float nx = v1.Px() / p1; - float ny = v1.Py() / p1; - float nz = v1.Pz() / p1; - float px_boost = (-gamma * beta * nx) * v2.E() + (1 + (gamma - 1) * nx * nx) * v2.Px() + ((gamma - 1) * nx * ny) * v2.Py() + ((gamma - 1) * nx * nz) * v2.Pz(); - float py_boost = (-gamma * beta * ny) * v2.E() + ((gamma - 1) * ny * nx) * v2.Px() + (1 + (gamma - 1) * ny * ny) * v2.Py() + ((gamma - 1) * ny * nz) * v2.Pz(); - float pz_boost = (-gamma * beta * nz) * v2.E() + ((gamma - 1) * nz * nx) * v2.Px() + ((gamma - 1) * nz * ny) * v2.Py() + (1 + (gamma - 1) * nz * nz) * v2.Pz(); - float p_boost = TMath::Sqrt(px_boost * px_boost + py_boost * py_boost + pz_boost * pz_boost); - + float value = -999.0f; + auto beta_v1 = v1.BoostToCM(); + ROOT::Math::Boost boostv1{beta_v1}; + auto v2_boost = boostv1(v2); + auto p_v1_lab = v1.Vect(); + float p1_lab = p_v1_lab.R(); if (Option == "coschi") { - value = (px_boost * v1.Px() + py_boost * v1.Py() + pz_boost * v1.Pz()) / (p1 * p_boost); + auto p_v2_boost = v2_boost.Vect(); + float p_boost = p_v2_boost.R(); + value = p_v2_boost.Dot(p_v1_lab) / (p1_lab * p_boost); + } else if (Option == "costheta") { + auto p_v2_lab = v2.Vect(); + float p2_lab = p_v2_lab.R(); + value = p_v1_lab.Dot(p_v2_lab) / (p1_lab * p2_lab); + } else if (Option == "weight_boost") { + value = v2_boost.E(); } - if (Option == "costheta") { - value = (v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / (p1 * p2); - } - if (Option == "weight_boost") { - value = gamma * (v2.E() - v1.Px() / v1.E() * v2.Px() - v1.Py() / v1.E() * v2.Py() - v1.Pz() / v1.E() * v2.Pz()); - } - return value; } From e7ac315a6eda504d263dc8592a8ff873304181f7 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 31 Oct 2025 19:23:01 +0800 Subject: [PATCH 04/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 145 +++++++++++++++++-------- 1 file changed, 97 insertions(+), 48 deletions(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 1352e448722..5b4f433a0a7 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -3452,16 +3452,12 @@ struct AnalysisDileptonTrack { Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of track cuts to be correlated with the dileptons"}; Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; + Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseMCGenpTcut{"cfgUseMCGenpTcut", false, "Use pT cut for dileptons used in the triplet vertexing(generated)"}; - Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(generated and reconstructed)"}; - Configurable fConfigCaculateEC{"cfgCaculateEC", false, "the switch for caculate the energy correlators"}; - Configurable fConfigCaculateRE{"cfgCaculateRE", true, "the switch for caculate the RE"}; - Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; @@ -3484,6 +3480,7 @@ struct AnalysisDileptonTrack { Configurable fConfigMCGenHadronPtMin{"cfgMCGenHadronPtMin", 1.0f, "minimum pt for the hadron"}; Configurable fConfigMCGenDileptonLegEtaAbs{"cfgMCGenDileptonLegEtaAbs", 0.9f, "eta abs range for the dilepton leg"}; Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; + Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(reconstructed)"}; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. int fNCuts; @@ -3511,8 +3508,6 @@ struct AnalysisDileptonTrack { // use two values array to avoid mixing up the quantities float* fValuesDilepton; - float* fValuesSignal; - float* fValuesEC; float* fValuesHadron; HistogramManager* fHistMan; @@ -3526,6 +3521,7 @@ struct AnalysisDileptonTrack { bool isMuon = context.mOptions.get("processMuonSkimmed"); bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); bool isDummy = context.mOptions.get("processDummy"); + bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); if (isDummy) { if (isBarrel || isMuon || isBarrelAsymmetric || isMCGen) { @@ -3548,9 +3544,6 @@ struct AnalysisDileptonTrack { fValuesDilepton = new float[VarManager::kNVars]; fValuesHadron = new float[VarManager::kNVars]; - fValuesSignal = new float[VarManager::kNVars]; - fValuesEC = new float[VarManager::kNVars]; - fTrackCutBitMap = 0; VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); @@ -3810,11 +3803,16 @@ struct AnalysisDileptonTrack { DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); } - if (fConfigCaculateRE) { - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); - DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); - } + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelators) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthECDilepton_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthECHadron_%s", sig->GetName()), ""); } } @@ -3878,7 +3876,6 @@ struct AnalysisDileptonTrack { if (dilepton.sign() != 0) { continue; } - // dilepton rap cut float rap = dilepton.rap(); if (fConfigUseMCRapcut && abs(rap) > fConfigDileptonRapCutAbs) @@ -4203,8 +4200,6 @@ struct AnalysisDileptonTrack { void processMCGenWithEventSelection(soa::Filtered const& events, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) { - VarManager::ResetValues(0, VarManager::kNVars, fValuesSignal); - VarManager::ResetValues(0, VarManager::kNVars, fValuesEC); for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -4216,39 +4211,17 @@ struct AnalysisDileptonTrack { auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (auto& track : groupedMCTracks) { - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - // apply kinematic cuts for signal - if (fConfigUseMCGenpTcut && (track_raw.pt() < fConfigDileptonLowpTCut || track_raw.pt() > fConfigDileptonHighpTCut)) - continue; - if (fConfigUseMCRapcut && abs(track_raw.y()) > fConfigDileptonRapCutAbs) - continue; - VarManager::FillTrackMC(mcTracks, track_raw, fValuesSignal); + + VarManager::FillTrackMC(mcTracks, track); + + auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); for (auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), fValuesSignal); - } - } - // for the energy correlators - if (!fConfigCaculateEC) - continue; - for (auto& mctrack1 : groupedMCTracks) { - if (TMath::Abs(mctrack1.pdgCode()) == 443 || TMath::Abs(mctrack1.pdgCode()) == 11 || TMath::Abs(mctrack1.pdgCode()) == 22) - continue; - if (mctrack1.pt() < fConfigMCGenHadronPtMin.value || std::abs(mctrack1.eta()) > fConfigMCGenHadronEtaAbs.value) - continue; - if (mctrack1.getGenStatusCode() <= 0) - continue; - for (auto& sig : fGenMCSignals) { - VarManager::FillEnergyCorrelators(track_raw, mctrack1, fValuesEC); - if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), fValuesEC); - } + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); } } } - if (!fConfigCaculateRE) - continue; // make a list of all MC tracks in the MC collision corresponding to the current reconstructed event std::vector mcTrackIndices; for (auto& t : groupedMCTracks) { @@ -4290,6 +4263,72 @@ struct AnalysisDileptonTrack { } // end loop over reconstructed events } + template + void runEnergyCorrelators(TEvent const& event, TMCTracks const& mcTracks) + { + VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks) { + auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + VarManager::FillTrackMC(mcTracks, t1_raw, fValuesDilepton); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthECDilepton_%s", sig->GetName()), fValuesDilepton); + } + } + // for the energy correlators + for (auto& t2 : groupedMCTracks) { + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelators(t1_raw, t2_raw, fValuesHadron); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthECHadron_%s", sig->GetName()), fValuesHadron); + } + } + } + } + } + void processMCGenEnergyCorrelators(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + void processDummy(MyEvents&) { // do nothing @@ -4300,6 +4339,8 @@ struct AnalysisDileptonTrack { PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); }; @@ -4376,7 +4417,6 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy_correlator_gen"); } if (classStr.Contains("DileptonsSelected")) { @@ -4402,5 +4442,14 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char if (classStr.Contains("DileptonHadronCorrelation")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } + + if (classStr.Contains("MCTruthECDilepton")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + } + + if (classStr.Contains("MCTruthECHadron")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); + } + } // end loop over histogram classes } From 2696e59a17b8b4c183268c8c0d2b4eafe4af50f4 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Tue, 4 Nov 2025 09:42:47 +0800 Subject: [PATCH 05/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 5b4f433a0a7..6f2eb75153e 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -4271,7 +4271,7 @@ struct AnalysisDileptonTrack { auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (auto& t1 : groupedMCTracks) { - auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); // apply kinematic cuts for signal if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) continue; @@ -4304,6 +4304,10 @@ struct AnalysisDileptonTrack { void processMCGenEnergyCorrelators(soa::Filtered const& events, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -4318,6 +4322,10 @@ struct AnalysisDileptonTrack { void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } for (auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; From 6d1f0857ca3ec2b0e4184ebb32f6fb54795790ec Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 7 Nov 2025 17:41:38 +0800 Subject: [PATCH 06/17] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 72 +++++++++++++++++++------------- PWGDQ/Core/VarManager.h | 63 +++++++--------------------- 2 files changed, 57 insertions(+), 78 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 1c12d0aaaef..d378bf9f559 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -906,42 +906,42 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (!groupStr.CompareTo("mctruth_triple")) { - hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 30.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 30.0, VarManager::kPt1); - hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 30.0, VarManager::kPt2); - hm->AddHistogram(histClass, "Eta_Pt_Assoc", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 30.0, VarManager::kPt); + hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 20.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); + hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); + hm->AddHistogram(histClass, "Eta_Pt_Photon", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kPairEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPairPhi); hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 4500, 0.0, 4.5, VarManager::kPairMassDau); - hm->AddHistogram(histClass, "Mass_Assoc", "", false, 500, 0.0, 1.0, VarManager::kMassDau); - hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Assoc", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); - hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 30.0, VarManager::kPairPtDau); - hm->AddHistogram(histClass, "Pt_Assoc", "", false, 500, 0.0, 10.0, VarManager::kPt); - hm->AddHistogram(histClass, "Mass_DileptonAssoc", "", false, 4500, 0.0, 30.0, VarManager::kPairMass); - hm->AddHistogram(histClass, "Pt_DileptonAssoc", "", false, 2000, 0.0, 30.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Mass_Pt_DileptonAssoc", "", false, 500, 0.0, 30.0, VarManager::kPairMass, 200, 0.0, 30.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Pt_Rap_DileptonAssoc", "", false, 5120, 0.0, 30.0, VarManager::kPairPt, 1000, -5.0, 5.0, VarManager::kRap); - hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 5.5, VarManager::kDeltaMass); - hm->AddHistogram(histClass, "DeltaMass_ptdileptonassoc", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Photon", "", false, 500, 0.0, 0.1, VarManager::kMassDau); + hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Photon", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 20.0, VarManager::kPairPtDau); + hm->AddHistogram(histClass, "Pt_Photon", "", false, 500, 0.0, 5.0, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_DileptonPhoton", "", false, 4500, 0.0, 4.5, VarManager::kPairMass); + hm->AddHistogram(histClass, "Pt_DileptonPhoton", "", false, 2000, 0.0, 20.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Pt_DileptonPhoton", "", false, 500, 0.0, 5.0, VarManager::kPairMass, 200, 0.0, 20.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 1.5, VarManager::kDeltaMass); + hm->AddHistogram(histClass, "DeltaMass_ptdileptonphoton", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); hm->AddHistogram(histClass, "DeltaMass_Jpsi", "", false, 1500, 3, 4.5, (VarManager::kDeltaMass_jpsi)); - hm->AddHistogram(histClass, "Rapidity", "", false, 400, -5.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); } if (!groupStr.CompareTo("mctruth_pair")) { - hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 15.0, VarManager::kMCMass, 40, 0.0, 20.0, VarManager::kMCPt); - hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 15.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 200, 0.0, 20.0, VarManager::kPairPtDau); - hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 15.0, VarManager::kMCMass); - hm->AddHistogram(histClass, "Rapidity", "", false, 100, -5.0, 5.0, VarManager::kMCY); - hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kMCEta, 200, 0.0, 20.0, VarManager::kMCPt); - hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kMCEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kMCPhi); - if (subGroupStr.Contains("polarization")) { - int varspTHE[4] = {VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE, VarManager::kMCPhiTildeHE}; - int varspTCS[4] = {VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS, VarManager::kMCPhiTildeCS}; - int bins[4] = {20, 20, 20, 20}; - double xmin[4] = {0., -1., 0., 0.}; - double xmax[4] = {20., 1., 2. * o2::constants::math::PI, 2. * o2::constants::math::PI}; - hm->AddHistogram(histClass, "Pt_cosThetaHE_phiHE_phiTildeHE", "", 4, varspTHE, bins, xmin, xmax, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Pt_cosThetaCS_phiCS_phiTildeCS", "", 4, varspTCS, bins, xmin, xmax, 0, -1, kFALSE); - } + hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); + hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); + hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 15.0, VarManager::kMass); + hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); + int varspTHE[3] = {VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE}; + int varspTCS[3] = {VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS}; + int varspTPP[3] = {VarManager::kMCPt, VarManager::kMCCosThetaPP, VarManager::kMCPhiPP}; + int binspT[3] = {40, 20, 20}; + double xminpT[3] = {0., -1., -3.14}; + double xmaxpT[3] = {20., 1., +3.14}; + hm->AddHistogram(histClass, "Pt_cosThetaHE_phiHE", "", 3, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Pt_cosThetaCS_phiCS", "", 3, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Pt_cosThetaPP_phiPP", "", 3, varspTPP, binspT, xminpT, xmaxpT, 0, -1, kFALSE); } if (!groupStr.CompareTo("mctruth_quad")) { hm->AddHistogram(histClass, "hMass_defaultDileptonMass", "", false, 1000, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass); @@ -1052,8 +1052,10 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Y_Pt", "", false, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 500, 0.0, 5.0, VarManager::kMass); + if (subGroupStr.Contains("energy-correlator")) { hm->AddHistogram(histClass, "Mass_Y_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Y", ";y", false, 40, -2.0, 2.0, VarManager::kRap); + } if (subGroupStr.Contains("pbpb")) { hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCentFT0C); hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 100, 0.0, 10.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); @@ -1082,21 +1084,31 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (subGroupStr.Contains("polarization")) { if (subGroupStr.Contains("helicity")) { + hm->AddHistogram(histClass, "cosThetaHE", "", false, 100, -1., 1., VarManager::kCosThetaHE); + hm->AddHistogram(histClass, "phiHE", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiHE); + hm->AddHistogram(histClass, "phitildeHE", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildeHE); hm->AddHistogram(histClass, "Mass_Pt_CosThetaHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaHE); hm->AddHistogram(histClass, "Mass_Pt_PhiHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiHE); hm->AddHistogram(histClass, "Mass_Pt_PhiTildeHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeHE); } if (subGroupStr.Contains("collins-soper")) { + hm->AddHistogram(histClass, "cosThetaCS", "", false, 100, -1., 1., VarManager::kCosThetaCS); + hm->AddHistogram(histClass, "phiCS", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiCS); + hm->AddHistogram(histClass, "phitildeCS", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildeCS); hm->AddHistogram(histClass, "Mass_Pt_CosThetaCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaCS); hm->AddHistogram(histClass, "Mass_Pt_PhiCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiCS); hm->AddHistogram(histClass, "Mass_Pt_PhiTildeCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeCS); } if (subGroupStr.Contains("production")) { + hm->AddHistogram(histClass, "cosThetaPP", "", false, 100, -1., 1., VarManager::kCosThetaPP); + hm->AddHistogram(histClass, "phiPP", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiPP); + hm->AddHistogram(histClass, "phitildePP", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildePP); hm->AddHistogram(histClass, "Mass_Pt_CosThetaPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaPP); hm->AddHistogram(histClass, "Mass_Pt_PhiPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiPP); hm->AddHistogram(histClass, "Mass_Pt_PhiTildePP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildePP); } if (subGroupStr.Contains("random")) { + hm->AddHistogram(histClass, "cosThetaRM", "", false, 100, -1., 1., VarManager::kCosThetaRM); hm->AddHistogram(histClass, "Mass_Pt_CosThetaRM", "", false, 200, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaRM); } } diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index b12efea788b..6f959e600ec 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -156,13 +156,9 @@ class VarManager : public TObject kDecayToKPi, // e.g. D0 -> K+ pi- or cc. kTripleCandidateToKPiPi, // e.g. D+ -> K- pi+ pi+ kTripleCandidateToPKPi, // e.g. Lambda_c -> p K- pi+ - kNMaxCandidateTypes - }; - - enum HadronMassCandidateType { - // The mass of the associated hadron - kRealHadronMass = 0, // using the real hadron mass - kTreatAsPion // treat the hadron as pion + kNMaxCandidateTypes, + kJpsiHadronMass, // using the real hadron mass + kJpsiPionMass // treat the hadron as pion }; enum BarrelTrackFilteringBits { @@ -1156,8 +1152,8 @@ class VarManager : public TObject static void FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values = nullptr); template static void FillTrackMC(const U& mcStack, T const& track, float* values = nullptr); - template - static void FillEnergyCorrelators(T const& track, T1 const& t1, float* values = nullptr); + template + static void FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values = nullptr); template static void FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values = nullptr); template @@ -1176,8 +1172,8 @@ class VarManager : public TObject static void FillPairME(T1 const& t1, T2 const& t2, float* values = nullptr); template static void FillPairMC(T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr); + template + static void FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); template static void FillQuadMC(T1 const& t1, T2 const& t2, T2 const& t3, float* values = nullptr); template @@ -2825,16 +2821,16 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) FillTrackDerived(values); } -template -void VarManager::FillEnergyCorrelators(T const& track, T1 const& t1, float* values) +template +void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values) { // energy correlators float MassHadron; - if constexpr (massType == kRealHadronMass) { + if constexpr (pairType == kJpsiHadronMass) { MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); ; } - if constexpr (massType == kTreatAsPion) { + if constexpr (pairType == kJpsiPionMass) { MassHadron = o2::constants::physics::MassPionCharged; } ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); @@ -3797,14 +3793,14 @@ void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values) } } -template -void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values) +template +void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) { if (!values) { values = fgValues; } - if constexpr (candidateType == kTripleCandidateToEEPhoton) { + if (pairType == kTripleCandidateToEEPhoton) { float m1 = o2::constants::physics::MassElectron; float m2 = o2::constants::physics::MassElectron; float m3 = o2::constants::physics::MassPhoton; @@ -3833,7 +3829,7 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kPt2] = t2.pt(); } - if constexpr (candidateType == kTripleCandidateToKPiPi) { + if (pairType == kTripleCandidateToKPiPi) { float m1 = o2::constants::physics::MassKaonCharged; float m2 = o2::constants::physics::MassPionCharged; @@ -3851,35 +3847,6 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kS13] = (v1 + v3).M2(); values[kS23] = (v2 + v3).M2(); } - if constexpr (candidateType == kBtoJpsiEEK) { - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - float m3 = o2::constants::physics::MassKaonCharged; - float m4 = o2::constants::physics::MassJPsi; - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); - ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; - values[kPairMass] = v123.M(); - values[kPairPt] = v123.Pt(); - values[kPairEta] = v123.Eta(); - values[kPhi] = v123.Phi(); - values[kMCY] = -v123.Rapidity(); - values[kPairMassDau] = v12.M(); - values[kPairPtDau] = v12.Pt(); - values[kRap] = -v123.Rapidity(); - values[kMassDau] = m3; - values[VarManager::kDeltaMass] = v123.M() - v12.M(); - values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; - values[kPt] = t3.pt(); - values[kEta] = t3.eta(); - values[kEta1] = t1.eta(); - values[kEta2] = t2.eta(); - values[kDeltaEta] = v12.Eta(); - values[kPt1] = t1.pt(); - values[kPt2] = t2.pt(); - } } template From d2c626133a089ecc571d56eb1bee78a595e87b40 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 7 Nov 2025 17:49:32 +0800 Subject: [PATCH 07/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 294 +++++++++++++------------ 1 file changed, 149 insertions(+), 145 deletions(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 8c56884f67a..71b8ea24b21 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -68,6 +68,7 @@ namespace o2::aod { namespace dqanalysisflags { +DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing //need to understand DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity @@ -162,7 +163,8 @@ DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); } // namespace dqanalysisflags -DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); +DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc @@ -201,6 +203,7 @@ using MyEventsVtxCovSelected = soa::Join; using MyEventsVtxCovSelectedQvector = soa::Join; using MyEventsQvector = soa::Join; +using MyEventsVtxCovHashSelected = soa::Join; using MyBarrelTracks = soa::Join; using MyBarrelTracksWithAmbiguities = soa::Join; @@ -244,8 +247,9 @@ void PrintBitMap(TMap map, int nbits) // Analysis task that produces event decisions and the Hash table used in event mixing struct AnalysisEventSelection { Produces eventSel; + Produces hash; OutputObj fOutputList{"output"}; - + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; @@ -261,6 +265,8 @@ struct AnalysisEventSelection { Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; HistogramManager* fHistMan = nullptr; + MixingHandler* fMixHandler = nullptr; + AnalysisCompositeCut* fEventCut; Service fCCDB; @@ -311,6 +317,16 @@ struct AnalysisEventSelection { fOutputList.setObject(fHistMan->GetMainHistogramList()); } + TString mixVarsString = fConfigMixingVariables.value; + std::unique_ptr objArray(mixVarsString.Tokenize(",")); + if (objArray->GetEntries() > 0) { + fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); + fMixHandler->Init(); + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + fCurrentRun = -1; fCCDB->setURL(fConfigCcdbUrl.value); fCCDB->setCaching(true); @@ -359,6 +375,10 @@ struct AnalysisEventSelection { auto& evIndices = fBCCollMap[event.globalBC()]; evIndices.push_back(event.globalIndex()); } + if (fMixHandler != nullptr) { + int hh = fMixHandler->FindEventCategory(VarManager::fgValues); + hash(hh); + } } for (auto& event : mcEvents) { @@ -1302,7 +1322,6 @@ struct AnalysisSameEventPairing { Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; - Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; // TODO: Add pair cuts via JSON } fConfigCuts; @@ -1336,6 +1355,7 @@ struct AnalysisSameEventPairing { Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; + // Configurable runMCGenPair{"cfgRunMCGenPair", false, "Do pairing of true MC particles"}; } fConfigMC; struct : ConfigurableGroup { @@ -1363,8 +1383,6 @@ struct AnalysisSameEventPairing { std::vector fGenMCSignals; std::vector fPairCuts; - AnalysisCompositeCut fMCGenAccCut; - bool fUseMCGenAccCut = false; uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream @@ -1384,7 +1402,7 @@ struct AnalysisSameEventPairing { if (context.mOptions.get("processDummy")) { return; } - bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping") || context.mOptions.get("processBarrelOnlySkimmed"); + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping"); VarManager::SetDefaultVarNames(); fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); @@ -1452,16 +1470,6 @@ struct AnalysisSameEventPairing { } } - // get the mc generated acceptance cut - TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; - if (mcGenAccCutStr != "") { - AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); - if (cut != nullptr) { - fMCGenAccCut.AddCut(cut); - } - fUseMCGenAccCut = true; - } - // check that the barrel track cuts array required in this task is not empty if (!trackCutsStr.IsNull()) { // tokenize and loop over the barrel cuts produced by the barrel track selection task @@ -2104,69 +2112,44 @@ struct AnalysisSameEventPairing { } // end loop over events } + // Preslice perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; template - void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + void runMCGen(ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); uint32_t mcDecision = 0; int isig = 0; - for (auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); - // if we have a mc generated acceptance cut, apply it here - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. // TODO: Use the mcReducedFlags to select signals for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - // Fill Generated histograms taking into account selected collisions - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - for (auto& track : mcTracks) { - if (track.reducedMCeventId() != event.reducedMCeventId()) { + if (sig->GetNProngs() != 1) { // NOTE: 1-prong signals required here continue; } - VarManager::FillTrackMC(mcTracks, track); - // if we have a mc generated acceptance cut, apply it here - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); - - if (useMiniTree.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); - } + bool checked = false; + /*if constexpr (soa::is_soa_filtered_v) { + auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); + checked = sig.CheckSignal(true, mctrack_raw); + } else {*/ + checked = sig->CheckSignal(true, mctrack); + //} + if (checked) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(mctrack.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), mctrack.pt(), mctrack.eta(), mctrack.phi(), -999, -999, -999); } - isig++; } } - } // end loop over reconstructed events + isig++; + } if (fHasTwoProngGenMCsignals) { for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { @@ -2178,60 +2161,20 @@ struct AnalysisSameEventPairing { continue; } if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); VarManager::FillPairMC(t1, t2); - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS - if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - VarManager::FillPairMC(t1, t2); - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - // WARNING! To be checked - dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); - } + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); } - isig++; } + isig++; } } - } // end loop over reconstructed events + } } - } + } // end runMCGen void processAllSkimmed(MyEventsVtxCovSelected const& events, soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, @@ -2252,7 +2195,10 @@ struct AnalysisSameEventPairing { MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - runMCGenWithGrouping(events, mcEvents, mcTracks); + // Feature replaced by processMCGen + /*if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ } void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, @@ -3555,6 +3501,7 @@ struct AnalysisDileptonTrack { Configurable fConfigMCGenDileptonLegEtaAbs{"cfgMCGenDileptonLegEtaAbs", 0.9f, "eta abs range for the dilepton leg"}; Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(reconstructed)"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. int fNCuts; @@ -3588,6 +3535,8 @@ struct AnalysisDileptonTrack { std::vector fRecMCSignals; std::vector fGenMCSignals; + NoBinningPolicy fHashBin; + void init(o2::framework::InitContext& context) { bool isBarrel = context.mOptions.get("processBarrelSkimmed"); @@ -3596,6 +3545,7 @@ struct AnalysisDileptonTrack { bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); bool isDummy = context.mOptions.get("processDummy"); bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); + bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); if (isDummy) { if (isBarrel || isMuon || isBarrelAsymmetric || isMCGen) { @@ -3885,8 +3835,13 @@ struct AnalysisDileptonTrack { if (isMCGen_energycorrelators) { for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthECDilepton_%s", sig->GetName()), ""); - DefineHistograms(fHistMan, Form("MCTruthECHadron_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelatorsME) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); } } @@ -4306,22 +4261,16 @@ struct AnalysisDileptonTrack { for (auto t1 : mcTrackIndices) { auto track1 = mcTracks.rawIteratorAt(*(&t1)); for (auto t2 : mcTrackIndices) { - if (t1 == t2) + if (t1 == t2 || t2 < t1) continue; - // if (t2 < t1) continue; auto track2 = mcTracks.rawIteratorAt(*(&t2)); for (auto t3 : mcTrackIndices) { - if (t3 == t1) - continue; - if (t3 == t2) + if (t3 == t1 || t3 == t2) continue; auto track3 = mcTracks.rawIteratorAt(*(&t3)); for (auto& sig : fRecMCSignals) { if (sig->CheckSignal(true, track1, track2, track3)) { - - VarManager::FillTripleMC(track1, track2, track3, VarManager::fgValues); // nb! hardcoded for jpsiK - fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); // apply kinematic cuts @@ -4346,8 +4295,6 @@ struct AnalysisDileptonTrack { template void runEnergyCorrelators(TEvent const& event, TMCTracks const& mcTracks) { - VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); for (auto& t1 : groupedMCTracks) { @@ -4357,12 +4304,6 @@ struct AnalysisDileptonTrack { continue; if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) continue; - VarManager::FillTrackMC(mcTracks, t1_raw, fValuesDilepton); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, t1_raw)) { - fHistMan->FillHistClass(Form("MCTruthECDilepton_%s", sig->GetName()), fValuesDilepton); - } - } // for the energy correlators for (auto& t2 : groupedMCTracks) { auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); @@ -4372,10 +4313,10 @@ struct AnalysisDileptonTrack { continue; if (t2_raw.getGenStatusCode() <= 0) continue; - VarManager::FillEnergyCorrelators(t1_raw, t2_raw, fValuesHadron); + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); for (auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, t1_raw)) { - fHistMan->FillHistClass(Form("MCTruthECHadron_%s", sig->GetName()), fValuesHadron); + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); } } } @@ -4395,7 +4336,7 @@ struct AnalysisDileptonTrack { if (!event.has_reducedMCevent()) { continue; } - runEnergyCorrelators(event, mcTracks); + runEnergyCorrelators(event, mcTracks); } } @@ -4413,7 +4354,78 @@ struct AnalysisDileptonTrack { if (!event.has_reducedMCevent()) { continue; } - runEnergyCorrelators(event, mcTracks); + runEnergyCorrelators(event, mcTracks); + } + } + + template + void runEnergyCorrelatorsMixedEvent(TEvent const& event1, TEvent const& event2, TMCTracks const& mcTracks) + { + auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.reducedMCeventId()); + auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.reducedMCeventId()); + groupedMCTracks1.bindInternalIndicesTo(&mcTracks); + groupedMCTracks2.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks1) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks2) { + auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + + void processMCGenEnergyCorrelatorsME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPionME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); } } @@ -4429,6 +4441,8 @@ struct AnalysisDileptonTrack { PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); }; @@ -4500,19 +4514,13 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char } if (classStr.Contains("MCTruthGenPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); } - if (classStr.Contains("MCTruthGenSelBR")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); - } else if (classStr.Contains("MCTruthGen")) { + if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); } - // if (classStr.Contains("MCTruthGen")) { - // dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); - // } - if (classStr.Contains("DileptonsSelected")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); } @@ -4537,11 +4545,7 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } - if (classStr.Contains("MCTruthECDilepton")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); - } - - if (classStr.Contains("MCTruthECHadron")) { + if (classStr.Contains("MCTruthEenergyCorrelators")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); } From c4660789034330c891679969bdbb64a363cb4955 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 7 Nov 2025 20:22:33 +0800 Subject: [PATCH 08/17] Add files via upload From f962599d4faef0fb40ce723645e4653f648e0315 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Fri, 7 Nov 2025 20:23:52 +0800 Subject: [PATCH 09/17] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index d378bf9f559..307b800f74f 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -1052,10 +1052,10 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Y_Pt", "", false, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); hm->AddHistogram(histClass, "Mass_VtxZ", "", true, 30, -15.0, 15.0, VarManager::kVtxZ, 500, 0.0, 5.0, VarManager::kMass); - if (subGroupStr.Contains("energy-correlator")) { - hm->AddHistogram(histClass, "Mass_Y_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Y", ";y", false, 40, -2.0, 2.0, VarManager::kRap); - } + if (subGroupStr.Contains("energy-correlator")) { + hm->AddHistogram(histClass, "Mass_Y_Pt", "", false, 125, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Y", ";y", false, 40, -2.0, 2.0, VarManager::kRap); + } if (subGroupStr.Contains("pbpb")) { hm->AddHistogram(histClass, "Mass_CentFT0C", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCentFT0C); hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 100, 0.0, 10.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCentFT0C); From 024c19adbbaa02141281b02278b3f5f96e92ef8f Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 17:56:16 +0800 Subject: [PATCH 10/17] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 82 ++++++++++++-------------------- PWGDQ/Core/VarManager.h | 45 +++++++++++++++--- 2 files changed, 68 insertions(+), 59 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 307b800f74f..4cc9f07a0bf 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -906,42 +906,42 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (!groupStr.CompareTo("mctruth_triple")) { - hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 20.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); - hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); - hm->AddHistogram(histClass, "Eta_Pt_Photon", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Eta_Pt", "", false, 100, -2.0, 2.0, VarManager::kPairEta, 200, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 30.0, VarManager::kPt1); + hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 30.0, VarManager::kPt2); + hm->AddHistogram(histClass, "Eta_Pt_Assoc", "", false, 100, -2.0, 2.0, VarManager::kEta, 200, 0.0, 30.0, VarManager::kPt); hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kPairEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPairPhi); hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 4500, 0.0, 4.5, VarManager::kPairMassDau); - hm->AddHistogram(histClass, "Mass_Photon", "", false, 500, 0.0, 0.1, VarManager::kMassDau); - hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Photon", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); - hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 20.0, VarManager::kPairPtDau); - hm->AddHistogram(histClass, "Pt_Photon", "", false, 500, 0.0, 5.0, VarManager::kPt); - hm->AddHistogram(histClass, "Mass_DileptonPhoton", "", false, 4500, 0.0, 4.5, VarManager::kPairMass); - hm->AddHistogram(histClass, "Pt_DileptonPhoton", "", false, 2000, 0.0, 20.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "Mass_Pt_DileptonPhoton", "", false, 500, 0.0, 5.0, VarManager::kPairMass, 200, 0.0, 20.0, VarManager::kPairPt); - hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 1.5, VarManager::kDeltaMass); - hm->AddHistogram(histClass, "DeltaMass_ptdileptonphoton", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Assoc", "", false, 500, 0.0, 1.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Mass_Dilepton_Mass_Assoc", "", false, 500, 0.0, 5.0, VarManager::kPairMassDau, 500, 0.0, 5.0, VarManager::kMassDau); + hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 2000, 0.0, 30.0, VarManager::kPairPtDau); + hm->AddHistogram(histClass, "Pt_Assoc", "", false, 500, 0.0, 10.0, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_DileptonAssoc", "", false, 4500, 0.0, 30.0, VarManager::kPairMass); + hm->AddHistogram(histClass, "Pt_DileptonAssoc", "", false, 2000, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Mass_Pt_DileptonAssoc", "", false, 500, 0.0, 30.0, VarManager::kPairMass, 200, 0.0, 30.0, VarManager::kPairPt); + hm->AddHistogram(histClass, "Pt_Rap_DileptonAssoc", "", false, 5120, 0.0, 30.0, VarManager::kPairPt, 1000, -5.0, 5.0, VarManager::kRap); + hm->AddHistogram(histClass, "DeltaMass", "", false, 1500, 0.0, 5.5, VarManager::kDeltaMass); + hm->AddHistogram(histClass, "DeltaMass_ptdileptonassoc", "", false, 1000, 0.0, 1.0, VarManager::kDeltaMass, 3000, 0.0, 30.0, VarManager::kPairPt); hm->AddHistogram(histClass, "DeltaMass_Jpsi", "", false, 1500, 3, 4.5, (VarManager::kDeltaMass_jpsi)); - hm->AddHistogram(histClass, "Rapidity", "", false, 400, -4.0, 4.0, VarManager::kRap); + hm->AddHistogram(histClass, "Rapidity", "", false, 400, -5.0, 5.0, VarManager::kRap); } if (!groupStr.CompareTo("mctruth_pair")) { - hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 15.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kPt); + hm->AddHistogram(histClass, "Mass_Pt", "", false, 500, 0.0, 15.0, VarManager::kMCMass, 40, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "Pt", "", false, 200, 0.0, 20.0, VarManager::kMCPt); hm->AddHistogram(histClass, "Pt_Dilepton", "", false, 200, 0.0, 20.0, VarManager::kPairPtDau); - hm->AddHistogram(histClass, "Eta_Pt_lepton1", "", false, 100, -2.0, 2.0, VarManager::kEta1, 200, 0.0, 20.0, VarManager::kPt1); - hm->AddHistogram(histClass, "Eta_Pt_lepton2", "", false, 100, -2.0, 2.0, VarManager::kEta2, 200, 0.0, 20.0, VarManager::kPt2); - hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 15.0, VarManager::kMass); - hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kEta, 200, 0.0, 20.0, VarManager::kPt); - hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kPhi); - int varspTHE[3] = {VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE}; - int varspTCS[3] = {VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS}; - int varspTPP[3] = {VarManager::kMCPt, VarManager::kMCCosThetaPP, VarManager::kMCPhiPP}; - int binspT[3] = {40, 20, 20}; - double xminpT[3] = {0., -1., -3.14}; - double xmaxpT[3] = {20., 1., +3.14}; - hm->AddHistogram(histClass, "Pt_cosThetaHE_phiHE", "", 3, varspTHE, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Pt_cosThetaCS_phiCS", "", 3, varspTCS, binspT, xminpT, xmaxpT, 0, -1, kFALSE); - hm->AddHistogram(histClass, "Pt_cosThetaPP_phiPP", "", 3, varspTPP, binspT, xminpT, xmaxpT, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Mass", "", false, 500, 0.0, 15.0, VarManager::kMCMass); + hm->AddHistogram(histClass, "Rapidity", "", false, 100, -5.0, 5.0, VarManager::kMCY); + hm->AddHistogram(histClass, "Eta_Pt", "", false, 40, -2.0, 2.0, VarManager::kMCEta, 200, 0.0, 20.0, VarManager::kMCPt); + hm->AddHistogram(histClass, "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kMCEta, 200, -2. * o2::constants::math::PI, 2. * o2::constants::math::PI, VarManager::kMCPhi); + if (subGroupStr.Contains("polarization")) { + int varspTHE[4] = {VarManager::kMCPt, VarManager::kMCCosThetaHE, VarManager::kMCPhiHE, VarManager::kMCPhiTildeHE}; + int varspTCS[4] = {VarManager::kMCPt, VarManager::kMCCosThetaCS, VarManager::kMCPhiCS, VarManager::kMCPhiTildeCS}; + int bins[4] = {20, 20, 20, 20}; + double xmin[4] = {0., -1., 0., 0.}; + double xmax[4] = {20., 1., 2. * o2::constants::math::PI, 2. * o2::constants::math::PI}; + hm->AddHistogram(histClass, "Pt_cosThetaHE_phiHE_phiTildeHE", "", 4, varspTHE, bins, xmin, xmax, 0, -1, kFALSE); + hm->AddHistogram(histClass, "Pt_cosThetaCS_phiCS_phiTildeCS", "", 4, varspTCS, bins, xmin, xmax, 0, -1, kFALSE); + } } if (!groupStr.CompareTo("mctruth_quad")) { hm->AddHistogram(histClass, "hMass_defaultDileptonMass", "", false, 1000, 3.0, 5.0, VarManager::kQuadDefaultDileptonMass); @@ -1084,31 +1084,21 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } if (subGroupStr.Contains("polarization")) { if (subGroupStr.Contains("helicity")) { - hm->AddHistogram(histClass, "cosThetaHE", "", false, 100, -1., 1., VarManager::kCosThetaHE); - hm->AddHistogram(histClass, "phiHE", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiHE); - hm->AddHistogram(histClass, "phitildeHE", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildeHE); hm->AddHistogram(histClass, "Mass_Pt_CosThetaHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaHE); hm->AddHistogram(histClass, "Mass_Pt_PhiHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiHE); hm->AddHistogram(histClass, "Mass_Pt_PhiTildeHE", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeHE); } if (subGroupStr.Contains("collins-soper")) { - hm->AddHistogram(histClass, "cosThetaCS", "", false, 100, -1., 1., VarManager::kCosThetaCS); - hm->AddHistogram(histClass, "phiCS", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiCS); - hm->AddHistogram(histClass, "phitildeCS", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildeCS); hm->AddHistogram(histClass, "Mass_Pt_CosThetaCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaCS); hm->AddHistogram(histClass, "Mass_Pt_PhiCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiCS); hm->AddHistogram(histClass, "Mass_Pt_PhiTildeCS", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildeCS); } if (subGroupStr.Contains("production")) { - hm->AddHistogram(histClass, "cosThetaPP", "", false, 100, -1., 1., VarManager::kCosThetaPP); - hm->AddHistogram(histClass, "phiPP", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiPP); - hm->AddHistogram(histClass, "phitildePP", "", false, 100, 0, 2 * o2::constants::math::PI, VarManager::kPhiTildePP); hm->AddHistogram(histClass, "Mass_Pt_CosThetaPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaPP); hm->AddHistogram(histClass, "Mass_Pt_PhiPP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiPP); hm->AddHistogram(histClass, "Mass_Pt_PhiTildePP", "", false, 100, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, 0., 2 * o2::constants::math::PI, VarManager::kPhiTildePP); } if (subGroupStr.Contains("random")) { - hm->AddHistogram(histClass, "cosThetaRM", "", false, 100, -1., 1., VarManager::kCosThetaRM); hm->AddHistogram(histClass, "Mass_Pt_CosThetaRM", "", false, 200, 1.0, 5.0, VarManager::kMass, 40, 0.0, 20.0, VarManager::kPt, 20, -1., 1., VarManager::kCosThetaRM); } } @@ -1856,18 +1846,6 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "Mass", "", false, 750, 0.0, 30.0, VarManager::kPairMass); hm->AddHistogram(histClass, "Pt", "", false, 750, 0.0, 30.0, VarManager::kPairPt); } - if (subGroupStr.Contains("mixedevent-energy-correlator")) { // for mixed event_correnergyelator - hm->AddHistogram(histClass, "Coschi", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kECWeight); - hm->AddHistogram(histClass, "CosTheta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kEWeight_before); - hm->AddHistogram(histClass, "Pt_Hadron", ";P_{T}", false, 120, 0.0, 30.0, VarManager::kPtDau); - hm->AddHistogram(histClass, "Eta_Hadron", ";#eta", false, 120, -2.0, 2.0, VarManager::kEtaDau); - hm->AddHistogram(histClass, "Phi_Hadron", ";#phi", false, 120, -8, 8, VarManager::kPhiDau); - hm->AddHistogram(histClass, "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); - hm->AddHistogram(histClass, "DeltaEta", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta); - hm->AddHistogram(histClass, "DeltaPhi", "", false, 50, -8.0, 8.0, VarManager::kDeltaPhi); - hm->AddHistogram(histClass, "Coschi_hadron_kMCWeight_hadron_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosChi, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kECWeight); - hm->AddHistogram(histClass, "Costheta_hadron_kMCWeight_before_DeltaEta", "", false, 40, -1.0, 1.0, VarManager::kCosTheta, 50, -8.0, 8.0, VarManager::kDeltaEta, 120, 0.0, 50, VarManager::kEWeight_before); - } if (subGroupStr.Contains("invmass")) { hm->AddHistogram(histClass, "Mass_Dilepton", "", false, 125, 0.0, 5.0, VarManager::kPairMassDau); hm->AddHistogram(histClass, "Mass_Hadron", "", false, 125, 0.0, 5.0, VarManager::kMassDau); diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 6f959e600ec..a0ccaccbc3f 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -1172,8 +1172,8 @@ class VarManager : public TObject static void FillPairME(T1 const& t1, T2 const& t2, float* values = nullptr); template static void FillPairMC(T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); + template + static void FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr); template static void FillQuadMC(T1 const& t1, T2 const& t2, T2 const& t3, float* values = nullptr); template @@ -1310,7 +1310,6 @@ class VarManager : public TObject template static float calculatePhiV(const T1& t1, const T2& t2); template - // static float LorentzTransformJpsihadroncosChi(const T1& t1, const T2& t2 ,float hadronMass); static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); static float RotationDeltaPhi(float deltaphi) { @@ -2074,6 +2073,7 @@ void VarManager::FillEvent(T const& event, float* values) values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); + values[kMCEventCentrFT0C] = event.centFT0C(); } if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { @@ -2796,6 +2796,7 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) if (!values) { values = fgValues; } + // Quantities based on the mc particle table values[kMCPdgCode] = track.pdgCode(); values[kMCParticleWeight] = track.weight(); @@ -2818,6 +2819,7 @@ void VarManager::FillTrackMC(const U& mcStack, T const& track, float* values) values[kMCMotherPdgCode] = mother.pdgCode(); } } + FillTrackDerived(values); } @@ -3793,14 +3795,14 @@ void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values) } } -template -void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) +template +void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values) { if (!values) { values = fgValues; } - if (pairType == kTripleCandidateToEEPhoton) { + if constexpr (candidateType == kTripleCandidateToEEPhoton) { float m1 = o2::constants::physics::MassElectron; float m2 = o2::constants::physics::MassElectron; float m3 = o2::constants::physics::MassPhoton; @@ -3829,7 +3831,7 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kPt2] = t2.pt(); } - if (pairType == kTripleCandidateToKPiPi) { + if constexpr (candidateType == kTripleCandidateToKPiPi) { float m1 = o2::constants::physics::MassKaonCharged; float m2 = o2::constants::physics::MassPionCharged; @@ -3847,6 +3849,35 @@ void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* v values[kS13] = (v1 + v3).M2(); values[kS23] = (v2 + v3).M2(); } + if constexpr (candidateType == kBtoJpsiEEK) { + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + float m3 = o2::constants::physics::MassKaonCharged; + float m4 = o2::constants::physics::MassJPsi; + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), m1); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), m2); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; + values[kPairMass] = v123.M(); + values[kPairPt] = v123.Pt(); + values[kPairEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kMCY] = -v123.Rapidity(); + values[kPairMassDau] = v12.M(); + values[kPairPtDau] = v12.Pt(); + values[kRap] = -v123.Rapidity(); + values[kMassDau] = m3; + values[VarManager::kDeltaMass] = v123.M() - v12.M(); + values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; + values[kPt] = t3.pt(); + values[kEta] = t3.eta(); + values[kEta1] = t1.eta(); + values[kEta2] = t2.eta(); + values[kDeltaEta] = v12.Eta(); + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); + } } template From f2d38cf3780d29ad3c4d7c9ea5143a18b7a043bb Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 17:57:52 +0800 Subject: [PATCH 11/17] Add files via upload From 6635ecce7db3e7df80f51b4da795b160b5e74435 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 18:01:48 +0800 Subject: [PATCH 12/17] Add files via upload --- dqEfficiency_withAssoc.cxx | 4639 ++++++++++++++++++++++++++++++++++++ 1 file changed, 4639 insertions(+) create mode 100644 dqEfficiency_withAssoc.cxx diff --git a/dqEfficiency_withAssoc.cxx b/dqEfficiency_withAssoc.cxx new file mode 100644 index 00000000000..76e81dd5a8d --- /dev/null +++ b/dqEfficiency_withAssoc.cxx @@ -0,0 +1,4639 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// Configurable workflow for running several DQ or other PWG analyses + +#include "PWGDQ/Core/AnalysisCompositeCut.h" +#include "PWGDQ/Core/AnalysisCut.h" +#include "PWGDQ/Core/CutsLibrary.h" +#include "PWGDQ/Core/HistogramManager.h" +#include "PWGDQ/Core/HistogramsLibrary.h" +#include "PWGDQ/Core/MCSignal.h" +#include "PWGDQ/Core/MCSignalLibrary.h" +#include "PWGDQ/Core/MixingHandler.h" +#include "PWGDQ/Core/MixingLibrary.h" +#include "PWGDQ/Core/VarManager.h" +#include "PWGDQ/DataModel/ReducedInfoTables.h" + +#include "Common/Core/TableHelper.h" + +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/Propagator.h" +#include "Field/MagneticField.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisHelpers.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" + +#include "TGeoGlobalMagField.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; +using std::string; + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod; + +// Some definitions +namespace o2::aod +{ +namespace dqanalysisflags +{ +DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing //need to understand +DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision +DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions +DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity +DECLARE_SOA_COLUMN(BarrelAmbiguityOutOfBunch, barrelAmbiguityOutOfBunch, int8_t); //! Barrel track out of bunch ambiguity +DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) +DECLARE_SOA_COLUMN(MuonAmbiguityInBunch, muonAmbiguityInBunch, int8_t); //! Muon track in-bunch ambiguity +DECLARE_SOA_COLUMN(MuonAmbiguityOutOfBunch, muonAmbiguityOutOfBunch, int8_t); //! Muon track out of bunch ambiguity +DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to ReducedTracksAssoc) +// Bcandidate columns for ML analysis of B->Jpsi+K +DECLARE_SOA_COLUMN(RunNumber, runNumber, uint64_t); +DECLARE_SOA_COLUMN(EventIdx, eventIdx, uint64_t); +DECLARE_SOA_COLUMN(EventTimestamp, eventTimestamp, uint64_t); +DECLARE_SOA_COLUMN(massBcandidate, MBcandidate, float); +DECLARE_SOA_COLUMN(MassDileptonCandidate, massDileptonCandidate, float); +DECLARE_SOA_COLUMN(deltaMassBcandidate, deltaMBcandidate, float); +DECLARE_SOA_COLUMN(pTBcandidate, PtBcandidate, float); +DECLARE_SOA_COLUMN(EtaBcandidate, etaBcandidate, float); +DECLARE_SOA_COLUMN(PhiBcandidate, phiBcandidate, float); +DECLARE_SOA_COLUMN(RapBcandidate, rapBcandidate, float); +DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); +DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); +DECLARE_SOA_COLUMN(LzBcandidate, lzBcandidate, float); +DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); +DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); +DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); +DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); +DECLARE_SOA_COLUMN(GlobalIndexassoc, globalIndexassoc, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg1, globalIndexleg1, uint64_t); +DECLARE_SOA_COLUMN(GlobalIndexleg2, globalIndexleg2, uint64_t); +DECLARE_SOA_COLUMN(Ptassoc, ptassoc, float); +DECLARE_SOA_COLUMN(PINassoc, pINassoc, float); +DECLARE_SOA_COLUMN(Etaassoc, etaassoc, float); +DECLARE_SOA_COLUMN(Phiassoc, phiassoc, float); +DECLARE_SOA_COLUMN(Ptpair, ptpair, float); +DECLARE_SOA_COLUMN(Etapair, etapair, float); +DECLARE_SOA_COLUMN(Ptleg1, ptleg1, float); +DECLARE_SOA_COLUMN(PINleg1, pINleg1, float); +DECLARE_SOA_COLUMN(Etaleg1, etaleg1, float); +DECLARE_SOA_COLUMN(Phileg1, phileg1, float); +DECLARE_SOA_COLUMN(Ptleg2, ptleg2, float); +DECLARE_SOA_COLUMN(PINleg2, pINleg2, float); +DECLARE_SOA_COLUMN(Etaleg2, etaleg2, float); +DECLARE_SOA_COLUMN(Phileg2, phileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaKaassoc, tpcnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPiassoc, tpcnsigmaPiassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrassoc, tpcnsigmaPrassoc, float); +DECLARE_SOA_COLUMN(TOFnsigmaKaassoc, tofnsigmaKaassoc, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg1, tpcnsigmaElleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg1, tpcnsigmaPileg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg1, tpcnsigmaPrleg1, float); +DECLARE_SOA_COLUMN(TPCnsigmaElleg2, tpcnsigmaElleg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPileg2, tpcnsigmaPileg2, float); +DECLARE_SOA_COLUMN(TPCnsigmaPrleg2, tpcnsigmaPrleg2, float); +DECLARE_SOA_COLUMN(ITSClusterMapassoc, itsClusterMapassoc, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg1, itsClusterMapleg1, uint8_t); +DECLARE_SOA_COLUMN(ITSClusterMapleg2, itsClusterMapleg2, uint8_t); +DECLARE_SOA_COLUMN(ITSChi2assoc, itsChi2assoc, float); +DECLARE_SOA_COLUMN(ITSChi2leg1, itsChi2leg1, float); +DECLARE_SOA_COLUMN(ITSChi2leg2, itsChi2leg2, float); +DECLARE_SOA_COLUMN(TPCNclsassoc, tpcNclsassoc, float); +DECLARE_SOA_COLUMN(TPCNclsleg1, tpcNclsleg1, float); +DECLARE_SOA_COLUMN(TPCNclsleg2, tpcNclsleg2, float); +DECLARE_SOA_COLUMN(TPCChi2assoc, tpcChi2assoc, float); +DECLARE_SOA_COLUMN(TPCChi2leg1, tpcChi2leg1, float); +DECLARE_SOA_COLUMN(TPCChi2leg2, tpcChi2leg2, float); +DECLARE_SOA_COLUMN(McFlag, mcFlag, int8_t); +DECLARE_SOA_BITMAP_COLUMN(IsJpsiFromBSelected, isJpsiFromBSelected, 32); +// Candidate columns for prompt-non-prompt JPsi separation +DECLARE_SOA_COLUMN(Massee, massee, float); +DECLARE_SOA_COLUMN(Etaee, etaee, float); +DECLARE_SOA_COLUMN(Rapee, rapee, float); +DECLARE_SOA_COLUMN(Phiee, phiee, float); +DECLARE_SOA_COLUMN(Ptee, ptee, float); +DECLARE_SOA_COLUMN(Lxyee, lxyee, float); +DECLARE_SOA_COLUMN(LxyeePoleMass, lxyeepolemass, float); +DECLARE_SOA_COLUMN(Lzee, lzee, float); +DECLARE_SOA_COLUMN(MultiplicityFT0A, multiplicityFT0AJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0CJPsi2ee, float); +DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0MJPsi2ee, float); +DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContribJPsi2ee, float); +DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); +DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); +DECLARE_SOA_COLUMN(Corrassoc, corrassoc, bool); +DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); +DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); +// Candidate columns efficiency calculation for prompt-non-prompt JPsi separation +DECLARE_SOA_COLUMN(OniaPt, oniaPt, float); +DECLARE_SOA_COLUMN(OniaY, oniaY, float); +DECLARE_SOA_COLUMN(OniaEta, oniaEta, float); +DECLARE_SOA_COLUMN(OniaPhi, oniaPhi, float); +DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); +DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); +} // namespace dqanalysisflags + +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); +DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc +DECLARE_SOA_TABLE(MuonAmbiguities, "AOD", "DQMUONAMB", dqanalysisflags::MuonAmbiguityInBunch, dqanalysisflags::MuonAmbiguityOutOfBunch); //! joinable to ReducedMuonTracks +DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", + dqanalysisflags::RunNumber, dqanalysisflags::EventIdx, dqanalysisflags::EventTimestamp, + dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltaMassBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::EtaBcandidate, dqanalysisflags::PhiBcandidate, dqanalysisflags::RapBcandidate, + dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, + dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, + dqanalysisflags::GlobalIndexassoc, dqanalysisflags::GlobalIndexleg1, dqanalysisflags::GlobalIndexleg2, + dqanalysisflags::PINassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, + dqanalysisflags::PINleg1, dqanalysisflags::Etaleg1, dqanalysisflags::PINleg2, dqanalysisflags::Etaleg2, + dqanalysisflags::TPCnsigmaKaassoc, dqanalysisflags::TPCnsigmaPiassoc, dqanalysisflags::TPCnsigmaPrassoc, dqanalysisflags::TOFnsigmaKaassoc, + dqanalysisflags::TPCnsigmaElleg1, dqanalysisflags::TPCnsigmaPileg1, dqanalysisflags::TPCnsigmaPrleg1, + dqanalysisflags::TPCnsigmaElleg2, dqanalysisflags::TPCnsigmaPileg2, dqanalysisflags::TPCnsigmaPrleg2, + dqanalysisflags::ITSClusterMapassoc, dqanalysisflags::ITSClusterMapleg1, dqanalysisflags::ITSClusterMapleg2, + dqanalysisflags::ITSChi2assoc, dqanalysisflags::ITSChi2leg1, dqanalysisflags::ITSChi2leg2, + dqanalysisflags::TPCNclsassoc, dqanalysisflags::TPCNclsleg1, dqanalysisflags::TPCNclsleg2, + dqanalysisflags::TPCChi2assoc, dqanalysisflags::TPCChi2leg1, dqanalysisflags::TPCChi2leg2, + dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected, dqanalysisflags::McFlag); +DECLARE_SOA_TABLE(JPsiMuonCandidates, "AOD", "DQJPSIMUONA", + dqanalysisflags::DeltaEta, dqanalysisflags::DeltaPhi, + dqanalysisflags::MassDileptonCandidate, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, dqanalysisflags::Ptassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Phiassoc, + dqanalysisflags::Ptleg1, dqanalysisflags::Etaleg1, dqanalysisflags::Phileg1, dqanalysisflags::Ptleg2, dqanalysisflags::Etaleg2, dqanalysisflags::Phileg2, + dqanalysisflags::McFlag); +DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Etaee, dqanalysisflags::Rapee, dqanalysisflags::Phiee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs, dqanalysisflags::Corrassoc, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); +DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dqanalysisflags::OniaEta, dqanalysisflags::OniaY, dqanalysisflags::OniaPhi, dqanalysisflags::OniaVz, dqanalysisflags::OniaVtxZ, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); +} // namespace o2::aod + +// Declarations of various short names +using MyEvents = soa::Join; +using MyEventsSelected = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; +using MyEventsVtxCovSelectedMultExtra = soa::Join; +using MyEventsVtxCovSelectedQvector = soa::Join; +using MyEventsQvector = soa::Join; +using MyEventsVtxCovHashSelected = soa::Join; + +using MyBarrelTracks = soa::Join; +using MyBarrelTracksWithAmbiguities = soa::Join; +using MyBarrelTracksWithCov = soa::Join; +using MyBarrelTracksWithCovWithAmbiguities = soa::Join; +using MyBarrelTracksWithCovWithAmbiguitiesWithColl = soa::Join; +using MyDielectronCandidates = soa::Join; +using MyDitrackCandidates = soa::Join; +using MyDimuonCandidates = soa::Join; +using MyMuonTracks = soa::Join; +using MyMuonTracksWithCov = soa::Join; +using MyMuonTracksWithCovWithAmbiguities = soa::Join; +// using MyMuonTracksSelectedWithColl = soa::Join; + +// bit maps used for the Fill functions of the VarManager +constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; +constexpr static uint32_t gkEventFillMapWithCovMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventMultExtra; +// constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; +// constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; +constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t gkTrackFillMapWithCovWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; +// constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; + +constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; +constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; +// constexpr static uint32_t gkMuonFillMapWithColl = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCollInfo; + +// Global function used to define needed histogram classes +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks + +template +void PrintBitMap(TMap map, int nbits) +{ + for (int i = 0; i < nbits; i++) { + cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + } +} + +// Analysis task that produces event decisions and the Hash table used in event mixing +struct AnalysisEventSelection { + Produces eventSel; + Produces hash; + OutputObj fOutputList{"output"}; + Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; + + Configurable fConfigSplitCollisionsDeltaZ{"splitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; + Configurable fConfigSplitCollisionsDeltaBC{"splitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; + Configurable fConfigCheckSplitCollisions{"checkSplitCollisions", false, "If true, run the split collision check and fill histograms"}; + + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + + HistogramManager* fHistMan = nullptr; + MixingHandler* fMixHandler = nullptr; + + AnalysisCompositeCut* fEventCut; + + Service fCCDB; + o2::ccdb::CcdbApi fCCDBApi; + + std::map fSelMap; // key: reduced event global index, value: event selection decision + std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices + std::map fMetadataRCT, fHeader; + int fCurrentRun; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fEventCut = new AnalysisCompositeCut(true); + TString eventCutStr = fConfigEventCuts.value; + if (eventCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); + if (cut != nullptr) { + fEventCut->AddCut(cut); + } + } + // Additional cuts via JSON + TString eventCutJSONStr = fConfigEventCutsJSON.value; + if (eventCutJSONStr != "") { + std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); + for (auto& cutIt : jsonCuts) { + fEventCut->AddCut(cutIt); + } + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); + if (fConfigCheckSplitCollisions) { + DefineHistograms(fHistMan, "OutOfBunchCorrelations;SameBunchCorrelations;", ""); + } + DefineHistograms(fHistMan, "EventsMC", fConfigAddEventMCHistogram.value.data()); + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // aditional histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + TString mixVarsString = fConfigMixingVariables.value; + std::unique_ptr objArray(mixVarsString.Tokenize(",")); + if (objArray->GetEntries() > 0) { + fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); + fMixHandler->Init(); + for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { + dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + } + } + + fCurrentRun = -1; + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + fCCDBApi.init(fConfigCcdbUrl.value); + } + + template + void runEventSelection(TEvents const& events, TEventsMC const& mcEvents) + { + if (events.size() > 0 && events.begin().runNumber() != fCurrentRun) { + fHeader = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), fMetadataRCT, -1); + uint64_t sor = std::atol(fHeader["SOR"].c_str()); + uint64_t eor = std::atol(fHeader["EOR"].c_str()); + VarManager::SetSORandEOR(sor, eor); + } + + fSelMap.clear(); + fBCCollMap.clear(); + + for (auto& event : events) { + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(event); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } + + bool decision = false; + // if QA is requested fill histograms before event selections + if (fConfigQA) { + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + } + if (fEventCut->IsSelected(VarManager::fgValues)) { + if (fConfigQA) { + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + } + decision = true; + } + fSelMap[event.globalIndex()] = decision; + if (fBCCollMap.find(event.globalBC()) == fBCCollMap.end()) { + std::vector evIndices = {event.globalIndex()}; + fBCCollMap[event.globalBC()] = evIndices; + } else { + auto& evIndices = fBCCollMap[event.globalBC()]; + evIndices.push_back(event.globalIndex()); + } + if (fMixHandler != nullptr) { + int hh = fMixHandler->FindEventCategory(VarManager::fgValues); + hash(hh); + } + } + + for (auto& event : mcEvents) { + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + VarManager::FillEvent(event); + if (fConfigQA) { + fHistMan->FillHistClass("EventsMC", VarManager::fgValues); + } + } + } + + template + void publishSelections(TEvents const& events) + { + std::map collisionSplittingMap; // key: event global index, value: whether pileup event is a possible splitting + + // Reset the fValues array and fill event observables + VarManager::ResetValues(0, VarManager::kNEventWiseVariables); + // loop over the BC map, get the collision vectors and make in-bunch and out of bunch 2-event correlations + for (auto bc1It = fBCCollMap.begin(); bc1It != fBCCollMap.end(); ++bc1It) { + uint64_t bc1 = bc1It->first; + auto const& bc1Events = bc1It->second; + + // same bunch event correlations, if more than 1 collisions in this bunch + if (bc1Events.size() > 1) { + for (auto ev1It = bc1Events.begin(); ev1It != bc1Events.end(); ++ev1It) { + auto ev1 = events.rawIteratorAt(*ev1It); + for (auto ev2It = std::next(ev1It); ev2It != bc1Events.end(); ++ev2It) { + auto ev2 = events.rawIteratorAt(*ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[*ev1It] = true; + collisionSplittingMap[*ev2It] = true; + } + fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); + } // end second event loop + } // end first event loop + } // end if BC1 events > 1 + + // loop over the following BCs in the TF + for (auto bc2It = std::next(bc1It); bc2It != fBCCollMap.end(); ++bc2It) { + uint64_t bc2 = bc2It->first; + if ((bc2 > bc1 ? bc2 - bc1 : bc1 - bc2) > fConfigSplitCollisionsDeltaBC) { + break; + } + auto const& bc2Events = bc2It->second; + + // loop over events in the first BC + for (auto ev1It : bc1Events) { + auto ev1 = events.rawIteratorAt(ev1It); + // loop over events in the second BC + for (auto ev2It : bc2Events) { + auto ev2 = events.rawIteratorAt(ev2It); + // compute 2-event quantities and mark the candidate split collisions + VarManager::FillTwoEvents(ev1, ev2); + if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + collisionSplittingMap[ev1It] = true; + collisionSplittingMap[ev2It] = true; + } + fHistMan->FillHistClass("OutOfBunchCorrelations", VarManager::fgValues); + } + } + } + } + + // publish the table + uint32_t evSel = static_cast(0); + for (auto& event : events) { + evSel = 0; + if (fSelMap[event.globalIndex()]) { // event passed the user cuts + evSel |= (static_cast(1) << 0); + } + std::vector sameBunchEvents = fBCCollMap[event.globalBC()]; + if (sameBunchEvents.size() > 1) { // event with in-bunch pileup + evSel |= (static_cast(1) << 1); + } + if (collisionSplittingMap.find(event.globalIndex()) != collisionSplittingMap.end()) { // event with possible fake in-bunch pileup (collision splitting) + evSel |= (static_cast(1) << 2); + } + eventSel(evSel); + } + } + + void processSkimmed(MyEvents const& events, aod::ReducedMCEvents const& mcEvents) + { + runEventSelection(events, mcEvents); + publishSelections(events); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); + PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); +}; + +// Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) +// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-even pairing, electron prefiltering, track for dilepton-track correlations) +struct AnalysisTrackSelection { + Produces trackSel; + Produces trackAmbiguities; + OutputObj fOutputList{"output"}; + + Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + + Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + std::vector fTrackCuts; + std::vector fMCSignals; // list of signals to be checked + std::vector fHistNamesReco; + std::vector fHistNamesMCMatched; + + int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) + + std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) + std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString cutNamesStr = fConfigCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // add extra cuts from JSON + TString addTrackCutsStr = fConfigCutsJSON.value; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + fTrackCuts.push_back(reinterpret_cast(t)); + } + } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + // Setting the MC signals + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Configure histogram classes for each track cut; + // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = "AssocsBarrel_BeforeCuts;"; + for (auto& cut : fTrackCuts) { + TString nameStr = Form("AssocsBarrel_%s", cut->GetName()); + fHistNamesReco.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto& sig : fMCSignals) { + TString nameStr2 = Form("AssocsCorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("AssocsIncorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); + if (fConfigPublishAmbiguity) { + DefineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); + } + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + if (fConfigComputeTPCpostCalib) { + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + } + } + + template + void runTrackSelection(ReducedTracksAssoc const& assocs, TEvents const& events, TTracks const& tracks, TEventsMC const& /*eventsMC*/, TTracksMC const& tracksMC) + { + fNAssocsInBunch.clear(); + fNAssocsOutOfBunch.clear(); + + // TODO: Check if postcalibration needed for MC + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + if (fConfigComputeTPCpostCalib) { + auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, events.begin().timestamp()); + VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); + VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); + VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); + } + + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + } + + fCurrentRun = events.begin().runNumber(); + } + + trackSel.reserve(assocs.size()); + trackAmbiguities.reserve(tracks.size()); + + // Loop over associations + for (auto& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + trackSel(0); + continue; + } + + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + // fill event information which might be needed in histograms/cuts that combine track and event properties + VarManager::FillEvent(event); + if (event.has_reducedMCevent()) { + VarManager::FillEvent(event.reducedMCevent()); + } + + auto track = assoc.template reducedtrack_as(); + VarManager::FillTrack(track); + // compute quantities which depend on the associated collision, such as DCA + VarManager::FillTrackCollision(track, event); + + bool isCorrectAssoc = false; + if (track.has_reducedMCTrack()) { + auto trackMC = track.reducedMCTrack(); + auto eventMCfromTrack = trackMC.reducedMCevent(); + if (event.has_reducedMCevent()) { + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); + } + VarManager::FillTrackMC(tracksMC, trackMC); + } + + if (fConfigQA) { + fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); + } + + int iCut = 0; + uint32_t filterMap = static_cast(0); + for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); + if (fConfigQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut], VarManager::fgValues); + } + } + } // end loop over cuts + trackSel(filterMap); + + // compute MC matching decisions and fill histograms for matched associations + int isig = 0; + if (filterMap > 0 && track.has_reducedMCTrack()) { + // loop over all MC signals + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + // check if this MC signal is matched + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + // mcDecision |= (static_cast(1) << isig); + // loop over cuts and fill histograms for the cuts that are fulfilled + for (unsigned int icut = 0; icut < fTrackCuts.size(); icut++) { + if (filterMap & (static_cast(1) << icut)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } + } + + // fill histograms + /*for (unsigned int i = 0; i < fMCSignals.size(); i++) { + if (!(mcDecision & (static_cast(1) << i))) { + continue; + } + for (unsigned int j = 0; j < fTrackCuts.size(); j++) { + if (filterMap & (static_cast(1) << j)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } // end loop over MC signals + */ + } // end if (filterMap > 0) + + // count the number of associations per track + if (fConfigPublishAmbiguity && filterMap > 0) { + if (event.isEventSelected_bit(1)) { + // for this track, count the number of associated collisions with in-bunch pileup and out of bunch associations + if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsInBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsInBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } else { + if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsOutOfBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } + } + } // end loop over associations + + // QA the collision-track associations + // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches + // So one could QA these tracks separately + if (fConfigPublishAmbiguity) { + if (fConfigQA) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = tracks.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks + } + + // publish the ambiguity table + for (auto& track : tracks) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + trackAmbiguities(nInBunch, nOutOfBunch); + } + } + } // end runTrackSelection() + + void processSkimmed(ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); + } + void processSkimmedWithCov(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); + } + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed track associations", false); + PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); + PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); +}; + +// Produces a table with muon decisions (joinable to the ReducedMuonsAssociations) +// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-event pairing, track for dilepton-track correlations) +struct AnalysisMuonSelection { + Produces muonSel; + Produces muonAmbiguities; + OutputObj fOutputList{"output"}; + + Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + Configurable fConfigCcdbUrl{"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 fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + Configurable fConfigMCSignals{"cfgMuonMCSignals", "", "Comma separated list of MC signals"}; + Configurable fConfigMCSignalsJSON{"cfgMuonMCsignalsJSON", "", "Additional list of MC signals via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + std::vector fMuonCuts; + std::vector fHistNamesReco; + std::vector fHistNamesMCMatched; + std::vector fMCSignals; // list of signals to be checked + + int fCurrentRun; // current run kept to detect run changes and trigger loading params from CCDB + + std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) + std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + VarManager::SetDefaultVarNames(); + + fCurrentRun = 0; + TString cutNamesStr = fConfigCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Add cuts configured via JSON + TString addCutsStr = fConfigCutsJSON.value; + if (addCutsStr != "") { + std::vector addCuts = dqcuts::GetCutsFromJSON(addCutsStr.Data()); + for (auto& t : addCuts) { + fMuonCuts.push_back(reinterpret_cast(t)); + } + } + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + + TString configSigNamesStr = fConfigMCSignals.value; + std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); + // Setting the MC signals + for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(sig); + } + } + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals + continue; + } + fMCSignals.push_back(mcIt); + } + } + + if (fConfigQA) { + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Configure histogram classes for each track cut; + // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) + TString histClasses = "AssocsMuon_BeforeCuts;"; + for (auto& cut : fMuonCuts) { + TString nameStr = Form("AssocsMuon_%s", cut->GetName()); + fHistNamesReco.push_back(nameStr); + histClasses += Form("%s;", nameStr.Data()); + for (auto& sig : fMCSignals) { + TString nameStr2 = Form("AssocsCorrectMuon_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + nameStr2 = Form("AssocsIncorrectMuon_%s_%s", cut->GetName(), sig->GetName()); + fHistNamesMCMatched.push_back(nameStr2); + histClasses += Form("%s;", nameStr2.Data()); + } + } + if (fConfigPublishAmbiguity) { + histClasses += "Muon_AmbiguityInBunch;Muon_AmbiguityOutOfBunch;"; + } + + DefineHistograms(fHistMan, histClasses.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigGeoPath); + } + } + + template + void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& muonsMC) + { + if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); + if (grpmag != nullptr) { + o2::base::Propagator::initFieldFromGRP(grpmag); + VarManager::SetMagneticField(grpmag->getNominalL3Field()); + } else { + // LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); + // If the magnetic field is not found it is configured by had by the user + VarManager::SetMagneticField(fConfigMagField.value); + } + fCurrentRun = events.begin().runNumber(); + } + + fNAssocsInBunch.clear(); + fNAssocsOutOfBunch.clear(); + muonSel.reserve(assocs.size()); + + for (auto& assoc : assocs) { + auto event = assoc.template reducedevent_as(); + if (!event.isEventSelected_bit(0)) { + muonSel(0); + continue; + } + VarManager::ResetValues(0, VarManager::kNVars); + // fill event information which might be needed in histograms/cuts that combine track and event properties + VarManager::FillEvent(event); + VarManager::FillEvent(event.reducedMCevent()); + + auto track = assoc.template reducedmuon_as(); + VarManager::FillTrack(track); + + bool isCorrectAssoc = false; + if (track.has_reducedMCTrack()) { + auto trackMC = track.reducedMCTrack(); + auto eventMCfromTrack = trackMC.reducedMCevent(); + isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); + VarManager::FillTrackMC(muonsMC, trackMC); + } + + if (fConfigQA) { + fHistMan->FillHistClass("AssocsMuon_BeforeCuts", VarManager::fgValues); + } + + int iCut = 0; + uint32_t filterMap = static_cast(0); + for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { + if ((*cut)->IsSelected(VarManager::fgValues)) { + filterMap |= (static_cast(1) << iCut); + if (fConfigQA) { + fHistMan->FillHistClass(fHistNamesReco[iCut].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + muonSel(filterMap); + muonAmbiguities.reserve(muons.size()); + + // if no filter fulfilled, continue + if (!filterMap) { + continue; + } + + // everything below is related to filling QA histograms + if (!fConfigQA) { + continue; + } + + // compute MC matching decisions + uint32_t mcDecision = static_cast(0); + int isig = 0; + for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { + if constexpr ((TMuonFillMap & VarManager::ObjTypes::ReducedMuon) > 0) { + if (track.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } + } + + // fill histograms + for (unsigned int i = 0; i < fMCSignals.size(); i++) { + if (!(mcDecision & (static_cast(1) << i))) { + continue; + } + for (unsigned int j = 0; j < fMuonCuts.size(); j++) { + if (filterMap & (static_cast(1) << j)) { + if (isCorrectAssoc) { + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); + } + } + } // end loop over cuts + } // end loop over MC signals + + // count the number of associations per track + if (fConfigPublishAmbiguity && filterMap > 0) { + if (event.isEventSelected_bit(1)) { + if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsInBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsInBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } else { + if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { + std::vector evVector = {event.globalIndex()}; + fNAssocsOutOfBunch[track.globalIndex()] = evVector; + } else { + auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; + evVector.push_back(event.globalIndex()); + } + } + } + } // end loop over assocs + + // QA the collision-track associations + // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches + // So one could QA these tracks separately + if (fConfigPublishAmbiguity) { + for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsInBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("Muon_AmbiguityInBunch", VarManager::fgValues); + } // end loop over in-bunch ambiguous tracks + + for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + if (evIndices.size() == 1) { + continue; + } + auto track = muons.rawIteratorAt(trackIdx); + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillTrack(track); + VarManager::fgValues[VarManager::kMuonNAssocsOutOfBunch] = static_cast(evIndices.size()); + fHistMan->FillHistClass("Muon_AmbiguityOutOfBunch", VarManager::fgValues); + } // end loop over out-of-bunch ambiguous tracks + + // publish the ambiguity table + for (auto& track : muons) { + int8_t nInBunch = 0; + if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { + nInBunch = fNAssocsInBunch[track.globalIndex()].size(); + } + int8_t nOutOfBunch = 0; + if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { + nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); + } + muonAmbiguities(nInBunch, nOutOfBunch); + } + } + } + + void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsSelected const& events, MyMuonTracks const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runMuonSelection(assocs, events, muons, eventsMC, tracksMC); + } + void processSkimmedWithCov(ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) + { + runMuonSelection(assocs, events, muons, eventsMC, tracksMC); + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisMuonSelection, processSkimmed, "Run muon selection on DQ skimmed muons", false); + PROCESS_SWITCH(AnalysisMuonSelection, processSkimmedWithCov, "Run muon selection on DQ skimmed muons, with event and track covariances", false); + PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", true); +}; + +// Run the prefilter selection (e.g. electron prefiltering for photon conversions) +// This takes uses a sample of tracks selected with loose cuts (fConfigPrefilterTrackCut) and combines them +// with the sample of tracks to be used in downstream analysis (fConfigTrackCuts). If a pair is found to pass +// the pair prefilter cut (cfgPrefilterPairCut), the analysis track is tagged to be removed from analysis. +// TODO: Add optional QA histograms +struct AnalysisPrefilterSelection { + Produces prefilter; // joinable with ReducedTracksAssoc + + // Configurables + Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; + Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; + Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; + // Track related options + Configurable fPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + + std::map fPrefilterMap; + AnalysisCompositeCut* fPairCut; + uint32_t fPrefilterMask; + int fPrefilterCutBit; + + Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + + bool runPrefilter = true; + // get the list of track cuts to be prefiltered + TString trackCutsStr = fConfigTrackCuts.value; + TObjArray* objArrayTrackCuts = nullptr; + if (!trackCutsStr.IsNull()) { + objArrayTrackCuts = trackCutsStr.Tokenize(","); + if (objArrayTrackCuts == nullptr) { + runPrefilter = false; + } + } else { + LOG(warn) << " No track cuts to prefilter! Prefilter will not be run"; + runPrefilter = false; + } + // get the cut to be used as loose selection + TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; + if (prefilterTrackCutStr.IsNull()) { + LOG(warn) << " No prefilter loose selection specified! Prefilter will not be run"; + runPrefilter = false; + } + + fPrefilterMask = 0; + fPrefilterCutBit = -1; + if (runPrefilter) { + // get the list of cuts that were computed in the barrel track-selection task and create a bit mask + // to mark just the ones we want to apply a prefilter on + string trackCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + TString allTrackCutsStr = trackCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + TString addTrackCutsStr = trackCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + allTrackCutsStr += Form(",%s", t->GetName()); + } + } + + std::unique_ptr objArray(allTrackCutsStr.Tokenize(",")); + if (objArray == nullptr) { + LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; + } + if (objArray->FindObject(prefilterTrackCutStr.Data()) == nullptr) { + LOG(fatal) << " Prefilter track cut not among the cuts calculated by the track-selection task! "; + } + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { + fPrefilterMask |= (static_cast(1) << icut); + } + if (tempStr.CompareTo(fConfigPrefilterTrackCut.value) == 0) { + fPrefilterCutBit = icut; + } + } + // setup the prefilter pair cut + fPairCut = new AnalysisCompositeCut(true); + TString pairCutStr = fConfigPrefilterPairCut.value; + if (!pairCutStr.IsNull()) { + fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); + } + } + if (fPrefilterMask == static_cast(0) || fPrefilterCutBit < 0) { + LOG(warn) << "No specified loose cut or track cuts for prefiltering. This task will do nothing."; + } + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + VarManager::SetDefaultVarNames(); + + VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); + } + + template + void runPrefilter(TEvent const& event, soa::Join const& assocs, TTracks const& /*tracks*/) + { + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + return; + } + + for (auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { + auto track1 = assoc1.template reducedtrack_as(); + auto track2 = assoc2.template reducedtrack_as(); + + // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made + // a configurable and check also same-sign pairs (track splitting) + if (track1.sign() * track2.sign() > 0) { + continue; + } + + // here we check the cuts fulfilled by both tracks, for both the tight and loose selections + uint32_t track1Candidate = (assoc1.isBarrelSelected_raw() & fPrefilterMask); + uint32_t track2Candidate = (assoc2.isBarrelSelected_raw() & fPrefilterMask); + bool track1Loose = assoc1.isBarrelSelected_bit(fPrefilterCutBit); + bool track2Loose = assoc2.isBarrelSelected_bit(fPrefilterCutBit); + + if (!((track1Candidate > 0 && track2Loose) || (track2Candidate > 0 && track1Loose))) { + continue; + } + + // compute pair quantities + VarManager::FillPair(track1, track2); + if (fPropTrack) { + VarManager::FillPairCollision(event, track1, track2); + } + // if the pair fullfils the criteria, add an entry into the prefilter map for the two tracks + if (fPairCut->IsSelected(VarManager::fgValues)) { + if (fPrefilterMap.find(track1.globalIndex()) == fPrefilterMap.end() && track1Candidate > 0) { + fPrefilterMap[track1.globalIndex()] = track1Candidate; + } + if (fPrefilterMap.find(track2.globalIndex()) == fPrefilterMap.end() && track2Candidate > 0) { + fPrefilterMap[track2.globalIndex()] = track2Candidate; + } + } + } // end loop over combinations + } + + void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) + { + + fPrefilterMap.clear(); + + for (auto& event : events) { + auto groupedAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + if (groupedAssocs.size() > 1) { + runPrefilter(event, groupedAssocs, tracks); + } + } + + uint32_t mymap = -1; + // If cuts were not configured, then produce a map with all 1's and publish it for all associations + if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { + for (int i = 0; i < assocs.size(); ++i) { + prefilter(mymap); + } + } else { + for (auto& assoc : assocs) { + // TODO: just use the index from the assoc (no need to cast the whole track) + auto track = assoc.template reducedtrack_as(); + mymap = -1; + if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { + // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else + mymap = ~fPrefilterMap[track.globalIndex()]; + prefilter(mymap); + } else { + prefilter(mymap); // track did not pass the prefilter selections, so publish just 1's + } + } + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); + PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); +}; + +// Run the same-event pairing +// This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) +// Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations +// TODO: implement properly the barrel-muon combinations +// The task implements also process functions for running event mixing +struct AnalysisSameEventPairing { + + Produces dielectronList; + Produces dimuonList; + Produces dielectronsExtraList; + Produces dielectronInfoList; + Produces dielectronAllList; + Produces dimuonsExtraList; + Produces dimuonAllList; + Produces dileptonMiniTreeGen; + Produces dileptonMiniTreeRec; + Produces dileptonInfoList; + Produces PromptNonPromptSepTable; + Produces MCTruthTableEffi; + + o2::base::MatLayerCylSet* fLUT = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + OutputObj fOutputList{"output"}; + + struct : ConfigurableGroup { + Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; + Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; + // TODO: Add pair cuts via JSON + } fConfigCuts; + + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + struct : ConfigurableGroup { + Configurable url{"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 lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + } fConfigCCDB; + + struct : ConfigurableGroup { + Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; + Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; + Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; + Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; + Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + } fConfigOptions; + + struct : ConfigurableGroup { + Configurable genSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable genSignalsJSON{"cfgMCGenSignalsJSON", "", "Additional list of MC signals (generated) via JSON"}; + Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; + Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; + } fConfigMC; + + struct : ConfigurableGroup { + Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; + Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; + Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; + } useMiniTree; + + // Track related options + Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + + Service fCCDB; + + // Filter filterEventSelected = aod::dqanalysisflags::isEventSelected & uint32_t(1); + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + + HistogramManager* fHistMan; + + // keep histogram class names in maps, so we don't have to buld their names in the pair loops + std::map> fTrackHistNames; + std::map> fBarrelHistNamesMCmatched; + std::map> fMuonHistNames; + std::map> fMuonHistNamesMCmatched; + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + std::vector fPairCuts; + AnalysisCompositeCut fMCGenAccCut; + bool fUseMCGenAccCut = false; + + uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream + uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream + int fNCutsBarrel; + int fNCutsMuon; + int fNPairCuts; + bool fHasTwoProngGenMCsignals = false; + + bool fEnableBarrelHistos; + bool fEnableMuonHistos; + + Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice> muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + void init(o2::framework::InitContext& context) + { + if (context.mOptions.get("processDummy")) { + return; + } + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping") || context.mOptions.get("processBarrelOnlySkimmed"); + VarManager::SetDefaultVarNames(); + + fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); + fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed"); + + // Keep track of all the histogram class names to avoid composing strings in the pairing loop + TString histNames = ""; + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + + // get the list of cuts for tracks/muons, check that they were played by the barrel/muon selection tasks + // and make a mask for active cuts (barrel and muon selection tasks may run more cuts, needed for other analyses) + TString trackCutsStr = fConfigCuts.track.value; + TObjArray* objArrayTrackCuts = nullptr; + if (!trackCutsStr.IsNull()) { + objArrayTrackCuts = trackCutsStr.Tokenize(","); + } + TString muonCutsStr = fConfigCuts.muon.value; + TObjArray* objArrayMuonCuts = nullptr; + if (!muonCutsStr.IsNull()) { + objArrayMuonCuts = muonCutsStr.Tokenize(","); + } + + // Setting the MC rec signal names + TString sigNamesStr = fConfigMC.recSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required + continue; + } + fRecMCSignals.push_back(sig); + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsStr = fConfigMC.recSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 2) { // NOTE: only 2 prong signals + continue; + } + fRecMCSignals.push_back(mcIt); + } + } + + // get the barrel track selection cuts + string tempCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + + // get the mc generated acceptance cut + TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; + if (mcGenAccCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); + if (cut != nullptr) { + fMCGenAccCut.AddCut(cut); + } + fUseMCGenAccCut = true; + } + + // check that the barrel track cuts array required in this task is not empty + if (!trackCutsStr.IsNull()) { + // tokenize and loop over the barrel cuts produced by the barrel track selection task + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + fNCutsBarrel = objArray->GetEntries(); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + // if the current barrel selection cut is required in this task, then switch on the corresponding bit in the mask + // and assign histogram directories + if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { + fTrackFilterMask |= (static_cast(1) << icut); + + if (fEnableBarrelHistos) { + // assign the pair hist directories for the current cut + std::vector names = { + Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), + Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; + if (fConfigQA) { + // assign separate hist directories for ambiguous tracks + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsBarrelSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fTrackHistNames[icut] = names; + + // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination + // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only + // if you know what you are doing. + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = { + Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + // NOTE: In the numbering scheme for the map key, we use the number of barrel cuts in the barrel-track selection task + fTrackHistNames[fNCutsBarrel + icut * fNPairCuts + iPairCut] = names; + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for the MC matched pairs for each (track cut,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + names = { + Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName())}; + if (fConfigQA) { + names.push_back(Form("PairsBarrelSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fBarrelHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); + } // end loop over MC signals + } + } // end if enableBarrelHistos + } + } + } + + // get the muon track selection cuts + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); + tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); + TString addMuonCutsStr = tempCuts; + if (addMuonCutsStr != "") { + std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + for (auto& t : addMuonCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + + // check that in this task we have specified muon cuts + if (!muonCutsStr.IsNull()) { + // loop over the muon cuts computed by the muon selection task and build a filter mask for those required in this task + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + fNCutsMuon = objArray->GetEntries(); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + TString tempStr = objArray->At(icut)->GetName(); + if (objArrayMuonCuts->FindObject(tempStr.Data()) != nullptr) { + // update the filter mask + fMuonFilterMask |= (static_cast(1) << icut); + + if (fEnableMuonHistos) { + // assign pair hist directories for each required muon cut + std::vector names = { + Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), + Form("PairsMuonSEPP_%s", objArray->At(icut)->GetName()), + Form("PairsMuonSEMM_%s", objArray->At(icut)->GetName())}; + if (fConfigQA) { + // assign separate hist directories for ambiguous tracks + names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + names.push_back(Form("PairsMuonSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fMuonHistNames[icut] = names; + + // if there are specified pair cuts, assign hist dirs for each muon cut - pair cut combination + TString cutNamesStr = fConfigCuts.pair.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + names = { + Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), + Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; + histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); + fMuonHistNames[fNCutsMuon + icut * fNCutsMuon + iPairCut] = names; + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for pairs matched to MC signals for each (muon cut, MCrec signal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + names = { + Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), + }; + if (fConfigQA) { + names.push_back(Form("PairsMuonSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); + } + for (auto& n : names) { + histNames += Form("%s;", n.Data()); + } + fMuonHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); + } // end loop over MC signals + } + } + } + } // end loop over cuts + } // end if (muonCutsStr) + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMC.genSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + fGenMCSignals.push_back(sig); + } + } + + // Add the MCSignals from the JSON config + TString addMCSignalsGenStr = fConfigMC.genSignalsJSON.value; + if (addMCSignalsGenStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() > 2) { // NOTE: only 2 prong signals + continue; + } + fGenMCSignals.push_back(mcIt); + } + } + + if (isMCGen) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() == 1) { + histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function + histNames += Form("MCTruthGenSel_%s;", sig->GetName()); + } else if (sig->GetNProngs() == 2) { + histNames += Form("MCTruthGenPair_%s;", sig->GetName()); + histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); + fHasTwoProngGenMCsignals = true; + } + } + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCCDB.url.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + if (fConfigOptions.noCorr) { + VarManager::SetupFwdDCAFitterNoCorr(); + } else if (fConfigOptions.corrFullGeo || (fConfigOptions.useKFVertexing && fConfigOptions.propToPCA)) { + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigCCDB.geoPath); + } + } else { + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigCCDB.lutPath)); + VarManager::SetupMatLUTFwdDCAFitter(fLUT); + } + + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy + + DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + void initParamsFromCCDB(uint64_t timestamp, bool withTwoProngFitter = true) + { + if (fConfigOptions.useRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (withTwoProngFitter) { + if (fConfigOptions.useKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(magField); + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(magField, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); + } + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + } + } else { + if (withTwoProngFitter) { + if (fConfigOptions.useKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigOptions.magField.value); + } else { + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables + VarManager::SetupTwoProngFwdDCAFitter(fConfigOptions.magField.value, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); + } + } else { + VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations + } + } + } + + // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) + template + void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); + fCurrentRun = events.begin().runNumber(); + } + + TString cutNames = fConfigCuts.track.value; + std::map> histNames = fTrackHistNames; + std::map> histNamesMC = fBarrelHistNamesMCmatched; + int ncuts = fNCutsBarrel; + if constexpr (TPairType == VarManager::kDecayToMuMu) { + cutNames = fConfigCuts.muon.value; + histNames = fMuonHistNames; + histNamesMC = fMuonHistNamesMCmatched; + ncuts = fNCutsMuon; + } + + uint32_t twoTrackFilter = static_cast(0); + int sign1 = 0; + int sign2 = 0; + uint32_t mcDecision = static_cast(0); + bool isCorrectAssoc_leg1 = false; + bool isCorrectAssoc_leg2 = false; + dielectronList.reserve(1); + dimuonList.reserve(1); + dielectronsExtraList.reserve(1); + dimuonsExtraList.reserve(1); + dielectronInfoList.reserve(1); + dileptonInfoList.reserve(1); + if (fConfigOptions.flatTables.value) { + dielectronAllList.reserve(1); + dimuonAllList.reserve(1); + } + if (useMiniTree.fConfigMiniTree) { + dileptonMiniTreeGen.reserve(1); + dileptonMiniTreeRec.reserve(1); + } + constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0); + constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + uint8_t evSel = event.isEventSelected_raw(); + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); + + auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); + if (groupedAssocs.size() == 0) { + continue; + } + + for (auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { + + if constexpr (TPairType == VarManager::kDecayToEE) { + twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; + + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.barrelAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + } + + VarManager::FillPair(t1, t2); + if (fPropTrack) { + VarManager::FillPairCollision(event, t1, t2); + } + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); + } + if constexpr (eventHasQvector) { + VarManager::FillPairVn(t1, t2); + } + if (!fConfigMC.skimSignalOnly || (fConfigMC.skimSignalOnly && mcDecision > 0)) { + dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, mcDecision); + + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); + dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); + } + if constexpr (trackHasCov && TTwoProngFitter) { + dielectronsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { + if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), twoTrackFilter, mcDecision, + t1.pt(), t1.eta(), t1.phi(), t1.itsClusterMap(), t1.itsChi2NCl(), t1.tpcNClsCrossedRows(), t1.tpcNClsFound(), t1.tpcChi2NCl(), t1.dcaXY(), t1.dcaZ(), t1.tpcSignal(), t1.tpcNSigmaEl(), t1.tpcNSigmaPi(), t1.tpcNSigmaPr(), t1.beta(), t1.tofNSigmaEl(), t1.tofNSigmaPi(), t1.tofNSigmaPr(), + t2.pt(), t2.eta(), t2.phi(), t2.itsClusterMap(), t2.itsChi2NCl(), t2.tpcNClsCrossedRows(), t2.tpcNClsFound(), t2.tpcChi2NCl(), t2.dcaXY(), t2.dcaZ(), t2.tpcSignal(), t2.tpcNSigmaEl(), t2.tpcNSigmaPi(), t2.tpcNSigmaPr(), t2.beta(), t2.tofNSigmaEl(), t2.tofNSigmaPi(), t2.tofNSigmaPr(), + VarManager::fgValues[VarManager::kKFTrack0DCAxyz], VarManager::fgValues[VarManager::kKFTrack1DCAxyz], VarManager::fgValues[VarManager::kKFDCAxyzBetweenProngs], VarManager::fgValues[VarManager::kKFTrack0DCAxy], VarManager::fgValues[VarManager::kKFTrack1DCAxy], VarManager::fgValues[VarManager::kKFDCAxyBetweenProngs], + VarManager::fgValues[VarManager::kKFTrack0DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack0DeviationxyFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMass], VarManager::fgValues[VarManager::kKFChi2OverNDFGeo], VarManager::fgValues[VarManager::kVertexingLxyz], VarManager::fgValues[VarManager::kVertexingLxyzOverErr], VarManager::fgValues[VarManager::kVertexingLxy], VarManager::fgValues[VarManager::kVertexingLxyOverErr], VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], VarManager::fgValues[VarManager::kKFCosPA], VarManager::fgValues[VarManager::kKFJpsiDCAxyz], VarManager::fgValues[VarManager::kKFJpsiDCAxy], + VarManager::fgValues[VarManager::kKFPairDeviationFromPV], VarManager::fgValues[VarManager::kKFPairDeviationxyFromPV], + VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop], + VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], + VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } + } + } + } + + if constexpr (TPairType == VarManager::kDecayToMuMu) { + twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + auto t1 = a1.template reducedmuon_as(); + auto t2 = a2.template reducedmuon_as(); + if (t1.matchMCHTrackId() == t2.matchMCHTrackId() && t1.matchMCHTrackId() >= 0) + continue; + if (t1.matchMFTTrackId() == t2.matchMFTTrackId() && t1.matchMFTTrackId() >= 0) + continue; + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 28); + } + if (t2.muonAmbiguityInBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 29); + } + if (t1.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 30); + } + if (t2.muonAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); + } + + VarManager::FillPair(t1, t2); + if (fPropTrack) { + VarManager::FillPairCollision(event, t1, t2); + } + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); + } + if constexpr (eventHasQvector) { + VarManager::FillPairVn(t1, t2); + } + + dimuonList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, mcDecision); + if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedMuonCollInfo) > 0) { + dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); + } + + if constexpr (TTwoProngFitter) { + dimuonsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); + if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), + event.selection_raw(), evSel, + event.reducedMCevent().mcPosX(), event.reducedMCevent().mcPosY(), event.reducedMCevent().mcPosZ(), + VarManager::fgValues[VarManager::kMass], + mcDecision, + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), VarManager::fgValues[VarManager::kVertexingChi2PCA], + VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingTauzErr], + VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], + VarManager::fgValues[VarManager::kCosPointingAngle], + VarManager::fgValues[VarManager::kPt1], VarManager::fgValues[VarManager::kEta1], VarManager::fgValues[VarManager::kPhi1], t1.sign(), + VarManager::fgValues[VarManager::kPt2], VarManager::fgValues[VarManager::kEta2], VarManager::fgValues[VarManager::kPhi2], t2.sign(), + t1.fwdDcaX(), t1.fwdDcaY(), t2.fwdDcaX(), t2.fwdDcaY(), + t1.mcMask(), t2.mcMask(), + t1.chi2MatchMCHMID(), t2.chi2MatchMCHMID(), + t1.chi2MatchMCHMFT(), t2.chi2MatchMCHMFT(), + t1.chi2(), t2.chi2(), + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), t1.reducedMCTrack().e(), + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), t2.reducedMCTrack().e(), + t1.reducedMCTrack().vx(), t1.reducedMCTrack().vy(), t1.reducedMCTrack().vz(), t1.reducedMCTrack().vt(), + t2.reducedMCTrack().vx(), t2.reducedMCTrack().vy(), t2.reducedMCTrack().vz(), t2.reducedMCTrack().vt(), + (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)), (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)), + -999.0, -999.0, -999.0, -999.0, -999.0, + -999.0, -999.0, -999.0, -999.0, -999.0, + -999.0, VarManager::fgValues[VarManager::kMultDimuons], + VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); + } + } + } + // TODO: the model for the electron-muon combination has to be thought through + /*if constexpr (TPairType == VarManager::kElectronMuon) { + twoTrackFilter = a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isMuonSelected_raw() & fTwoTrackFilterMask; + }*/ + + // Fill histograms + bool isAmbiInBunch = false; + bool isAmbiOutOfBunch = false; + bool isCorrect_pair = false; + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) + isCorrect_pair = true; + + for (int icut = 0; icut < ncuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); + isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kRap], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], isAmbiInBunch, isAmbiOutOfBunch, isCorrect_pair, VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][0].Data(), VarManager::fgValues); // matched signal + if (useMiniTree.fConfigMiniTree) { + if constexpr (TPairType == VarManager::kDecayToMuMu) { + twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; + if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue + continue; + } + auto t1 = a1.template reducedmuon_as(); + auto t2 = a2.template reducedmuon_as(); + + float dileptonMass = VarManager::fgValues[VarManager::kMass]; + if (dileptonMass > useMiniTree.fConfigMiniTreeMinMass && dileptonMass < useMiniTree.fConfigMiniTreeMaxMass) { + // In the miniTree the positive daughter is positioned as first + if (t1.sign() > 0) { + dileptonMiniTreeRec(mcDecision, + VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), + t1.pt(), t1.eta(), t1.phi(), + t2.pt(), t2.eta(), t2.phi()); + } else { + dileptonMiniTreeRec(mcDecision, + VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], + t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), + t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), + t2.pt(), t2.eta(), t2.phi(), + t1.pt(), t1.eta(), t1.phi()); + } + } + } + } + if (fConfigQA) { + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), VarManager::fgValues); + } else { // incorrect track-collision association + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), VarManager::fgValues); + } + if (isAmbiInBunch) { // ambiguous in bunch + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), VarManager::fgValues); + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), VarManager::fgValues); + } + } + if (isAmbiOutOfBunch) { // ambiguous out of bunch + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), VarManager::fgValues); + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), VarManager::fgValues); + } + } + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), VarManager::fgValues); + } + } + } + } else { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), VarManager::fgValues); + } + } + } else { // -- pairs + fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); + } + } + if (fConfigQA) { + if (isAmbiInBunch) { + fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + } + if (isAmbiOutOfBunch) { + fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), VarManager::fgValues); + } + } + } + } + for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { + AnalysisCompositeCut cut = fPairCuts.at(iPairCut); + if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), VarManager::fgValues); + } else { + if (sign1 > 0) { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), VarManager::fgValues); + } else { + fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), VarManager::fgValues); + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } // end loop over pairs of track associations + } // end loop over events + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + template + void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + uint32_t mcDecision = 0; + int isig = 0; + + for (auto& mctrack : mcTracks) { + VarManager::FillTrackMC(mcTracks, mctrack); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + VarManager::FillTrackMC(mcTracks, track); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; + } + } + } // end loop over reconstructed events + + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS + if (fHasTwoProngGenMCsignals) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); + VarManager::FillPairMC(t1, t2); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } // end loop over reconstructed events + } + } + + void processAllSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); + // Feature replaced by processMCGen + /*if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ + // runSameEventPairing(event, tracks, muons); + } + + void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + runMCGenWithGrouping(events, mcEvents, mcTracks); + } + + void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + // Feature replaced by processMCGen + /* if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ + } + + void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); + // Feature replaced by processMCGen + /* if (fConfigMC.runMCGenPair) { + runMCGen(mcEvents, mcTracks); + }*/ + } + + PresliceUnsorted perReducedMcGenEvent = aod::reducedtrackMC::reducedMCeventId; + + void processMCGen(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // Fill Generated histograms taking into account all generated tracks + uint32_t mcDecision = 0; + int isig = 0; + + for (auto& mctrack : mcTracks) { + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); + // auto groupedMCTracks = mcTracks.sliceBy(perReducedMcGenEvent, event.reducedMCeventId()); + // groupedMCTracks.bindInternalIndicesTo(&mcTracks); + // for (auto& track : groupedMCTracks) { + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + VarManager::FillTrackMC(mcTracks, track); + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + // auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; + } + } + } // end loop over reconstructed events + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + // Fill Generated PAIR histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + if (t1.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + if (t2.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } + } // end loop over reconstructed events + } + + void processMCGenWithGrouping(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + uint32_t mcDecision = 0; + int isig = 0; + + for (auto& mctrack : mcTracks) { + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { + continue; + } + VarManager::FillTrackMC(mcTracks, track); + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; + } + } + } // end loop over reconstructed events + if (fHasTwoProngGenMCsignals) { + for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS + if (fHasTwoProngGenMCsignals) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); + VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } // end loop over reconstructed events + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisSameEventPairing, processAllSkimmed, "Run all types of pairing, with skimmed tracks/muons", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlyWithCollSkimmed, "Run barrel only pairing, with skimmed tracks and with collision information", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMuonOnlySkimmed, "Run muon only pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processMCGenWithGrouping, "Loop over MC particle stack (grouped MCTracks) and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); +}; + +// Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) +struct AnalysisAsymmetricPairing { + + Produces ditrackList; + Produces ditrackExtraList; + + o2::base::MatLayerCylSet* fLUT = nullptr; + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + + // Output objects + OutputObj fOutputList{"output"}; + + // Configurables + Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; + Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; + Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; + Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; + Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; + + Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; + Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; + // Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; + Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; + Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + + Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + + Service fCCDB; + + HistogramManager* fHistMan; + + std::vector fPairCuts; + int fNPairHistPrefixes; + + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + // Filter masks to find legs in BarrelTrackCuts table + uint32_t fLegAFilterMask; + uint32_t fLegBFilterMask; + uint32_t fLegCFilterMask; + // Maps tracking which combination of leg cuts the track cuts participate in + std::map fConstructedLegAFilterMasksMap; + std::map fConstructedLegBFilterMasksMap; + std::map fConstructedLegCFilterMasksMap; + // Filter map for common track cuts + uint32_t fCommonTrackCutMask; + // Map tracking which common track cut the track cuts correspond to + std::map fCommonTrackCutFilterMasks; + + int fNLegCuts; + int fNPairCuts = 0; + int fNCommonTrackCuts; + // vectors for cut names and signal names, for easy access when calling FillHistogramList() + std::vector fLegCutNames; + std::vector fPairCutNames; + std::vector fCommonCutNames; + std::vector fRecMCSignalNames; + + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + + Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + + // Partitions for triplets and asymmetric pairs + Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); + Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); + Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); + + // Map to track how many times a pair of tracks has been encountered + std::map, int8_t> fPairCount; + + void init(o2::framework::InitContext& context) + { + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); + if (context.mOptions.get("processDummy")) { + return; + } + + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + // Get the leg cut filter masks + fLegAFilterMask = fConfigLegAFilterMask.value; + fLegBFilterMask = fConfigLegBFilterMask.value; + fLegCFilterMask = fConfigLegCFilterMask.value; + + // Get the pair cuts + TString cutNamesStr = fConfigPairCuts.value; + if (!cutNamesStr.IsNull()) { + std::unique_ptr objArray(cutNamesStr.Tokenize(",")); + for (int icut = 0; icut < objArray->GetEntries(); ++icut) { + fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + } + } + // Extra pair cuts via JSON + TString addPairCutsStr = fConfigPairCutsJSON.value; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + fPairCuts.push_back(reinterpret_cast(t)); + cutNamesStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); + } + + // Setting the MC rec signal names + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + fRecMCSignals.push_back(sig); + } + } + // Add the reco MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 2 && mcIt->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 2 or 3 prongs! Fix it"; + } + fRecMCSignals.push_back(mcIt); + sigNamesStr += Form(",%s", mcIt->GetName()); + } + } + // Put all the reco MCSignal names in the vector for histogram naming + std::unique_ptr objArrayRecMCSignals(sigNamesStr.Tokenize(",")); + for (int i = 0; i < objArrayRecMCSignals->GetEntries(); i++) { + fRecMCSignalNames.push_back(objArrayRecMCSignals->At(i)->GetName()); + } + + // Get the barrel track selection cuts + string tempCuts; + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + TString tempCutsStr = tempCuts; + // check also the cuts added via JSON and add them to the string of cuts + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + TString addTrackCutsStr = tempCuts; + if (addTrackCutsStr != "") { + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + for (auto& t : addTrackCuts) { + tempCutsStr += Form(",%s", t->GetName()); + } + } + std::unique_ptr objArray(tempCutsStr.Tokenize(",")); + // Get the common leg cuts + int commonCutIdx; + TString commonNamesStr = fConfigCommonTrackCuts.value; + if (!commonNamesStr.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + commonCutIdx = objArray->IndexOf(objArrayCommon->At(icut)); + if (commonCutIdx >= 0) { + fCommonTrackCutMask |= static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonTrackCutFilterMasks[icut] = static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); + fCommonCutNames.push_back(objArrayCommon->At(icut)->GetName()); + } else { + LOGF(fatal, "Common track cut %s was not calculated upstream. Check the config!", objArrayCommon->At(icut)->GetName()); + } + } + } + // Check that the leg cut masks make sense + if (static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1, objArray->GetEntries()); + } + if (static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1 > objArray->GetEntries()) { + LOGF(fatal, "fConfigLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1, objArray->GetEntries()); + } + + // Get the cuts defining the legs + uint32_t fConstructedLegAFilterMask = 0; + uint32_t fConstructedLegBFilterMask = 0; + uint32_t fConstructedLegCFilterMask = 0; + TString legCutsStr = fConfigLegCuts.value; + std::unique_ptr objArrayLegs(legCutsStr.Tokenize(",")); + if (objArrayLegs->GetEntries() == 0 && !isMCGen) { + LOG(fatal) << "No cuts defining legs. Check the config!"; + } + fNLegCuts = objArrayLegs->GetEntries(); + std::vector isThreeProng; + int legAIdx; + int legBIdx; + int legCIdx; + // Loop over leg defining cuts + for (int icut = 0; icut < fNLegCuts; ++icut) { + TString legsStr = objArrayLegs->At(icut)->GetName(); + std::unique_ptr legs(legsStr.Tokenize(":")); + if (legs->GetEntries() == 3) { + isThreeProng.push_back(true); + } else if (legs->GetEntries() == 2) { + isThreeProng.push_back(false); + } else { + LOGF(fatal, "Leg cuts %s has the wrong format and could not be parsed!", legsStr.Data()); + continue; + } + // Find leg cuts in the track selection cuts + legAIdx = objArray->IndexOf(legs->At(0)); + if (legAIdx >= 0) { + fConstructedLegAFilterMask |= static_cast(1) << legAIdx; + fConstructedLegAFilterMasksMap[icut] |= static_cast(1) << legAIdx; + } else { + LOGF(fatal, "Leg A cut %s was not calculated upstream. Check the config!", legs->At(0)->GetName()); + continue; + } + legBIdx = objArray->IndexOf(legs->At(1)); + if (legBIdx >= 0) { + fConstructedLegBFilterMask |= static_cast(1) << legBIdx; + fConstructedLegBFilterMasksMap[icut] |= static_cast(1) << legBIdx; + } else { + LOGF(fatal, "Leg B cut %s was not calculated upstream. Check the config!", legs->At(1)->GetName()); + continue; + } + if (isThreeProng[icut]) { + legCIdx = objArray->IndexOf(legs->At(2)); + if (legCIdx >= 0) { + fConstructedLegCFilterMask |= static_cast(1) << legCIdx; + fConstructedLegCFilterMasksMap[icut] |= static_cast(1) << legCIdx; + } else { + LOGF(fatal, "Leg C cut %s was not calculated upstream. Check the config!", legs->At(2)->GetName()); + continue; + } + } + // Leg cut config is fine, store the leg cut name in a vector + fLegCutNames.push_back(legsStr); + + // Define histogram and histogram directory names + if (isThreeProng[icut]) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); + if (fConfigQA) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + + TString cutNamesStr = fConfigPairCuts.value; + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + + // TODO: assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } // end loop over MC signals + } // end if (MC signals) + } else { + std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; + if (fConfigSameSignHistograms.value) { + pairHistPrefixes.push_back("PairsBarrelSEPP"); + pairHistPrefixes.push_back("PairsBarrelSEMM"); + } + fNPairHistPrefixes = pairHistPrefixes.size(); + + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + if (fConfigQA) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); + } + } + + std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + fNPairCuts = objArrayPair->GetEntries(); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); + } + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + + // assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination + if (!sigNamesStr.IsNull()) { + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { + auto sig = fRecMCSignals.at(isig); + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + if (fConfigReflectedHistograms.value) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + + if (!cutNamesStr.IsNull()) { // if pair cuts + std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { + DefineHistograms(fHistMan, Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } // end loop (common cuts) + } // end loop (pair cuts) + } // end if (pair cuts) + } // end loop over MC signals + } // end if (MC signals) + } + } + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(sig); + DefineHistograms(fHistMan, Form("MCTruthGen_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + // Add the gen MCSignals from the JSON config + addMCSignalsStr = fConfigMCGenSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() == 1) { + fGenMCSignals.push_back(mcIt); + DefineHistograms(fHistMan, Form("MCTruthGen_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function + } + } + } + + // Make sure the leg cuts are covered by the configured filter masks + if (fLegAFilterMask != fConstructedLegAFilterMask) { + LOGF(fatal, "cfgLegAFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegAFilterMask, fConstructedLegAFilterMask); + } + if (fLegBFilterMask != fConstructedLegBFilterMask) { + LOGF(fatal, "cfgLegBFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegBFilterMask, fConstructedLegBFilterMask); + } + if (fLegCFilterMask != fConstructedLegCFilterMask) { + LOGF(fatal, "cfgLegCFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegCFilterMask, fConstructedLegCFilterMask); + } + // Make sure only pairs or only triplets of leg cuts were given + int tripletCheckSum = std::count(isThreeProng.begin(), isThreeProng.end(), true); + if (tripletCheckSum != 0 && tripletCheckSum != fNLegCuts) { + LOGF(fatal, "A mix of pairs and triplets was given as leg cuts. Check your config!"); + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + + fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); + VarManager::SetupMatLUTFwdDCAFitter(fLUT); + + dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + void initParamsFromCCDB(uint64_t timestamp, bool isTriplets) + { + if (fConfigUseRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPMagPath, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(magField); + } else { + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(magField); + } else { + VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } else { + if (isTriplets) { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupTwoProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables + } + } + } + } + + // Template function to run same event pairing with asymmetric pairs (e.g. kaon-pion) + template + void runAsymmetricPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + fPairCount.clear(); + + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), false); + fCurrentRun = events.begin().runNumber(); + } + } + + int sign1 = 0; + int sign2 = 0; + uint32_t mcDecision = 0; + ditrackList.reserve(1); + ditrackExtraList.reserve(1); + + constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + + for (auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { + + uint32_t twoTrackFilter = 0; + uint32_t twoTrackCommonFilter = 0; + uint32_t pairFilter = 0; + bool isPairIdWrong = false; + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find leg pair definitions both candidates participate in + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { + twoTrackFilter |= static_cast(1) << icut; + // If the supposed pion passes a kaon cut, this is a K+K-. Skip it. + if (TPairType == VarManager::kDecayToKPi && fConfigSkipAmbiguousIdCombinations.value) { + if (a2.isBarrelSelected_raw() & fLegAFilterMask) { + isPairIdWrong = true; + } + } + } + } + + if (!twoTrackFilter || isPairIdWrong) { + continue; + } + + // Find common track cuts both candidates pass + twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + + // Avoid self-pairs + if (t1.globalIndex() == t2.globalIndex()) { + continue; + } + + bool isReflected = false; + std::pair trackIds(t1.globalIndex(), t2.globalIndex()); + if (fPairCount.find(trackIds) != fPairCount.end()) { + // Double counting is possible due to track-collision ambiguity. Skip pairs which were counted before + fPairCount[trackIds] += 1; + continue; + } + if (fPairCount.find(std::pair(trackIds.second, trackIds.first)) != fPairCount.end()) { + isReflected = true; + } + fPairCount[trackIds] += 1; + + sign1 = t1.sign(); + sign2 = t2.sign(); + // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= static_cast(1) << 30; + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + twoTrackFilter |= static_cast(1) << 31; + } + + // run MC matching for this pair + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { + VarManager::FillPairMC(t1.reducedMCTrack(), t2.reducedMCTrack()); + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { + mcDecision |= static_cast(1) << isig; + } + } + } // end loop over MC signals + + VarManager::FillPair(t1, t2); + if constexpr (TTwoProngFitter) { + VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); + } + + // Fill histograms + bool isAmbi = false; + for (int icut = 0; icut < fNLegCuts; icut++) { + if (twoTrackFilter & (static_cast(1) << icut)) { + isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); + if (sign1 * sign2 < 0) { // +- pairs + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); // reconstructed, unmatched + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { // ++ pairs + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } else { // -- pairs + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + if (isAmbi && fConfigQA) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + if (isReflected && fConfigReflectedHistograms) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + if (isReflected && fConfigReflectedHistograms.value) { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } + } + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } + } + } + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + pairFilter |= (static_cast(1) << iPairCut); + // Histograms with pair cuts + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } + } + } + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + } + } + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + if (sign1 * sign2 < 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else if (fConfigSameSignHistograms.value) { + if (sign1 > 0) { + fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } else { + fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); + } + } + } + } + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], + VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], + t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); + if constexpr (trackHasCov && TTwoProngFitter) { + ditrackExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); + } + } // end inner assoc loop (leg A) + } // end event loop + } + + // Template function to run same event triplets (e.g. D+->K-pi+pi+) + template + void runThreeProng(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) + { + if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() + if (fCurrentRun != events.begin().runNumber()) { + initParamsFromCCDB(events.begin().timestamp(), true); + fCurrentRun = events.begin().runNumber(); + } + } + + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + // Reset the fValues array + VarManager::ResetValues(0, VarManager::kNVars); + VarManager::FillEvent(event, VarManager::fgValues); + + auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegAAssocs.size() == 0) { + continue; + } + auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegBAssocs.size() == 0) { + continue; + } + auto groupedLegCAssocs = legCCandidateAssocs.sliceBy(preslice, event.globalIndex()); + if (groupedLegCAssocs.size() == 0) { + continue; + } + + // Based on triplet type, make suitable combinations of the partitions + if (tripletType == VarManager::kTripleCandidateToPKPi) { + for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { + readTriplet(a1, a2, a3, tracks, event, tripletType); + } + } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { + for (auto& a1 : groupedLegAAssocs) { + for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { + readTriplet(a1, a2, a3, tracks, event, tripletType); + } + } + } else { + LOG(fatal) << "Given tripletType not recognized. Don't know how to make combinations!" << endl; + } + } // end event loop + } + + // Helper function to process triplet + template + void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType) + { + uint32_t mcDecision = 0; + + uint32_t threeTrackFilter = 0; + uint32_t threeTrackCommonFilter = 0; + for (int icut = 0; icut < fNLegCuts; ++icut) { + // Find out which leg cut combinations the triplet passes + if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) && (a3.isBarrelSelected_raw() & fConstructedLegCFilterMasksMap[icut])) { + threeTrackFilter |= (static_cast(1) << icut); + if (tripletType == VarManager::kTripleCandidateToPKPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if the supposed pion passes as a proton or kaon, if so, skip this triplet. It is pKp or pKK. + if ((a3.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegBFilterMask)) { + return; + } + // Check if the supposed kaon passes as a proton, if so, skip this triplet. It is ppPi. + if (a2.isBarrelSelected_raw() & fLegAFilterMask) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToKPiPi && fConfigSkipAmbiguousIdCombinations.value) { + // Check if one of the supposed pions pass as a kaon, if so, skip this triplet. It is KKPi. + if ((a2.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegAFilterMask)) { + return; + } + } + } + } + if (!threeTrackFilter) { + return; + } + + // Find common track cuts all candidates pass + threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; + + auto t1 = a1.template reducedtrack_as(); + auto t2 = a2.template reducedtrack_as(); + auto t3 = a3.template reducedtrack_as(); + + // Avoid self-pairs + if (t1 == t2 || t1 == t3 || t2 == t3) { + return; + } + // Check charge + if (tripletType == VarManager::kTripleCandidateToKPiPi) { + if (!((t1.sign() == -1 && t2.sign() == 1 && t3.sign() == 1) || (t1.sign() == 1 && t2.sign() == -1 && t3.sign() == -1))) { + return; + } + } + if (tripletType == VarManager::kTripleCandidateToPKPi) { + if (!((t1.sign() == 1 && t2.sign() == -1 && t3.sign() == 1) || (t1.sign() == -1 && t2.sign() == 1 && t3.sign() == -1))) { + return; + } + } + + // store the ambiguity of the three legs in the last 3 digits of the two-track filter + if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 29); + } + if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 30); + } + if (t3.barrelAmbiguityInBunch() > 1 || t3.barrelAmbiguityOutOfBunch() > 1) { + threeTrackFilter |= (static_cast(1) << 31); + } + + // run MC matching for this triplet + int isig = 0; + mcDecision = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack() && t3.has_reducedMCTrack()) { + if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack(), t3.reducedMCTrack())) { + mcDecision |= (static_cast(1) << isig); + } + } + } // end loop over MC signals + + VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); + if constexpr (TThreeProngFitter) { + VarManager::FillTripletVertexing(event, t1, t2, t3, tripletType); + } + + // Fill histograms + bool isAmbi = false; + for (int icut = 0; icut < fNLegCuts; icut++) { + isAmbi = (threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)); + if (threeTrackFilter & (static_cast(1) << icut)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + if (fConfigQA && isAmbi) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + } + } // end loop (common cuts) + int iPairCut = 0; + for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { + if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts + continue; + // Histograms with pair cuts + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + // Histograms with pair cuts and common track cuts + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal + } + } // end loop (MC signals) + } + } + } // end loop (pair cuts) + } + } // end loop (cuts) + } + + void processKaonPionSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + } + + void processKaonPionSkimmedMultExtra(MyEventsVtxCovSelectedMultExtra const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); + } + + void processKaonPionPionSkimmed(MyEventsVtxCovSelected const& events, + soa::Join const& barrelAssocs, + MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); + } + + void processMCGen(ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); + for (auto& mctrack : mcTracks) { + + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void processMCGenWithEventSelection(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& track : groupedMCTracks) { + + VarManager::FillTrackMC(mcTracks, track); + + auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } // end loop over reconstructed events + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmedMultExtra, "Run kaon pion pairing, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); +}; + +// Combines dileptons with barrel or muon tracks for either resonance or correlation analyses +// Dileptons produced with all the selection cuts specified in the same-event pairing task are combined with the +// tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected +struct AnalysisDileptonTrack { + Produces BmesonsTable; + Produces DileptonTrackTable; + OutputObj fOutputList{"output"}; + + Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of track cuts to be correlated with the dileptons"}; + Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; + Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; + Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; + Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; + Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; + Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; + Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + Configurable fConfigCcdbUrl{"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 fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + Configurable fConfigMCRecSignals{"cfgMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; + Configurable fConfigMCGenSignals{"cfgMCGenSignals", "", "Comma separated list of MC signals (generated)"}; + Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; + Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; + Configurable fConfigMCGenSignalDileptonLegPos{"cfgMCGenSignalDileptonLegPos", 0, "generator level positive dilepton leg signal (bit number according to table-maker)"}; + Configurable fConfigMCGenSignalDileptonLegNeg{"cfgMCGenSignalDileptonLegNeg", 0, "generator level negative dilepton leg signal (bit number according to table-maker)"}; + Configurable fConfigMCGenSignalHadron{"cfgMCGenSignalHadron", 0, "generator level associated hadron signal (bit number according to table-maker)"}; + Configurable fConfigMCGenDileptonLegPtMin{"cfgMCGenDileptonLegPtMin", 1.0f, "minimum pt for the dilepton leg"}; + Configurable fConfigMCGenHadronPtMin{"cfgMCGenHadronPtMin", 1.0f, "minimum pt for the hadron"}; + Configurable fConfigMCGenDileptonLegEtaAbs{"cfgMCGenDileptonLegEtaAbs", 0.9f, "eta abs range for the dilepton leg"}; + Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; + Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(reconstructed)"}; + Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; + + int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + int fNCuts; + int fNLegCuts; + int fNPairCuts; + int fNCommonTrackCuts; + std::map fCommonTrackCutMap; + uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons + // vector for single-lepton and track cut names for easy access when calling FillHistogramList() + std::vector fTrackCutNames; + std::vector fLegCutNames; + // vector for pair cut names, used mainly for pairs built via the asymmetric pairing task + std::vector fPairCutNames; + std::vector fCommonPairCutNames; + + Service fCCDB; + + // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file + Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); + Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonLowpTCut&& aod::reducedpair::pt fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; + Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); + Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); + + constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map + + // use two values array to avoid mixing up the quantities + float* fValuesDilepton; + float* fValuesHadron; + HistogramManager* fHistMan; + + std::vector fRecMCSignals; + std::vector fGenMCSignals; + + NoBinningPolicy fHashBin; + + void init(o2::framework::InitContext& context) + { + bool isBarrel = context.mOptions.get("processBarrelSkimmed"); + bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); + bool isMuon = context.mOptions.get("processMuonSkimmed"); + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); + bool isDummy = context.mOptions.get("processDummy"); + bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); + bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); + + if (isDummy) { + if (isBarrel || isMuon || isBarrelAsymmetric || isMCGen) { + LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; + } else { + LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; + return; + } + } + + fCurrentRun = 0; + + fCCDB->setURL(fConfigCcdbUrl.value); + fCCDB->setCaching(true); + fCCDB->setLocalObjectValidityChecking(); + fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + fCCDB->get(fConfigGeoPath); + } + + fValuesDilepton = new float[VarManager::kNVars]; + fValuesHadron = new float[VarManager::kNVars]; + fTrackCutBitMap = 0; + VarManager::SetDefaultVarNames(); + fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); + fHistMan->SetUseDefaultVariableNames(true); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + TString sigNamesStr = fConfigMCRecSignals.value; + std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); + if (!sigNamesStr.IsNull()) { + for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << sig->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCSignals.push_back(sig); + } else { + LOG(fatal) << "Signal at reconstructed level requested (" << objRecSigArray->At(isig)->GetName() << ") " << "could not be retrieved from the library! -> skipped"; + } + } + } + + // Add the reco MCSignals from the JSON config + TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() != 3) { + LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 3 prongs! Fix it"; + } + fRecMCSignals.push_back(mcIt); + } + } + + // Add histogram classes for each specified MCsignal at the generator level + // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function + TString sigGenNamesStr = fConfigMCGenSignals.value; + std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); + for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { + MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); + if (sig) { + if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required + fGenMCSignals.push_back(sig); + } + } + } + + // Add the gen MCSignals from the JSON config + addMCSignalsStr = fConfigMCGenSignalsJSON.value; + if (addMCSignalsStr != "") { + std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); + for (auto& mcIt : addMCSignals) { + if (mcIt->GetNProngs() == 1) { + fGenMCSignals.push_back(mcIt); + } + } + } + + // For each track/muon selection used to produce dileptons, create a separate histogram directory using the + // name of the track/muon cut. + + // Get the list of single track and muon cuts computed in the dedicated tasks upstream + // We need this to know the order in which they were computed, and also to make sure that in this task we do not ask + // for cuts which were not computed (in which case this will trigger a fatal) + string cfgTrackSelection_TrackCuts; + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); + } + TObjArray* cfgTrackSelection_objArrayTrackCuts = nullptr; + if (!cfgTrackSelection_TrackCuts.empty()) { + cfgTrackSelection_objArrayTrackCuts = TString(cfgTrackSelection_TrackCuts).Tokenize(","); + } + // get also the list of cuts specified via the JSON parameters + if (isBarrel || isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); + } else { + getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); + } + if (!cfgTrackSelection_TrackCuts.empty()) { + if (cfgTrackSelection_objArrayTrackCuts == nullptr) { + cfgTrackSelection_objArrayTrackCuts = new TObjArray(); + } + std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); + for (auto& t : addTrackCuts) { + TObjString* tempObjStr = new TObjString(t->GetName()); + cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); + } + } + if (cfgTrackSelection_objArrayTrackCuts->GetEntries() == 0) { + LOG(fatal) << " No track cuts found in the barrel or muon upstream tasks"; + } + // store all the computed track cut names in a vector + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + fTrackCutNames.push_back(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName()); + } + // get the list of associated track cuts to be combined with the dileptons, + // check that these were computed upstream, and create a bit mask + TObjArray* cfgDileptonTrack_objArrayTrackCuts = nullptr; + if (!fConfigTrackCuts.value.empty()) { + cfgDileptonTrack_objArrayTrackCuts = TString(fConfigTrackCuts.value).Tokenize(","); + } else { + LOG(fatal) << " No track cuts specified! Check it out!"; + } + // loop over these cuts and check they were computed upstream (otherwise trigger a fatal) + for (int icut = 0; icut < cfgDileptonTrack_objArrayTrackCuts->GetEntries(); icut++) { + if (!cfgTrackSelection_objArrayTrackCuts->FindObject(cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName())) { + LOG(fatal) << "Specified track cut (" << cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName() << ") not found in the list of computed cuts by the single barrel / muon selection tasks"; + } + } + // loop over all the upstream cuts and make a bit mask for the track cuts specified in this task + for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { + if (cfgDileptonTrack_objArrayTrackCuts->FindObject(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName())) { + fTrackCutBitMap |= (static_cast(1) << icut); + } + } + // finally, store the total number of upstream tasks, for easy access + fNCuts = fTrackCutNames.size(); + + // get the cuts employed for same-event pairing + // NOTE: The track/muon cuts in analysis-same-event-pairing are used to select electrons/muons to build dielectrons/dimuons + // NOTE: The cfgPairCuts in analysis-same-event-pairing are used to apply an additional selection on top of the already produced dileptons + // but this is only used for histograms, not for the produced dilepton tables + string cfgPairing_TrackCuts; + string cfgPairing_PairCuts; + string cfgPairing_PairCutsJSON; + string cfgPairing_CommonTrackCuts; + if (isBarrel) { + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isMuon) { + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + } else if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); + } + if (cfgPairing_TrackCuts.empty()) { + LOG(fatal) << "There are no dilepton cuts specified in the upstream in the same-event-pairing or asymmetric-pairing"; + } + + // If asymmetric pair is used, it may have common track cuts + TString cfgPairing_strCommonTrackCuts = cfgPairing_CommonTrackCuts; + if (!cfgPairing_strCommonTrackCuts.IsNull()) { // if common track cuts + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + fNCommonTrackCuts = objArrayCommon->GetEntries(); + for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { + for (int iicut = 0; iicut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); iicut++) { + if (std::strcmp(cfgTrackSelection_objArrayTrackCuts->At(iicut)->GetName(), objArrayCommon->At(icut)->GetName()) == 0) { + fCommonTrackCutMap[icut] = iicut; + fCommonPairCutNames.push_back(objArrayCommon->At(icut)->GetName()); + } + } + } + } // end if (common cuts) + + // Get also the pair cuts specified via the JSON parameters + if (isBarrelAsymmetric) { + getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); + TString addPairCutsStr = cfgPairing_PairCutsJSON; + if (addPairCutsStr != "") { + std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + for (auto& t : addPairCuts) { + cfgPairing_PairCuts += Form(",%s", t->GetName()); + } + } + } + + std::unique_ptr objArrayPairCuts(TString(cfgPairing_PairCuts).Tokenize(",")); + fNPairCuts = objArrayPairCuts->GetEntries(); + for (int j = 0; j < fNPairCuts; j++) { + fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); + } + + // array of single lepton cuts specified in the same-analysis-pairing task + std::unique_ptr cfgPairing_objArrayTrackCuts(TString(cfgPairing_TrackCuts).Tokenize(",")); + // If asymmetric pairs are used, the number of cuts should come from the asymmetric-pairing task + if (isBarrelAsymmetric) { + fNLegCuts = cfgPairing_objArrayTrackCuts->GetEntries(); + } else { + fNLegCuts = fNCuts; + } + + // loop over single lepton cuts + if (isBarrel || isBarrelAsymmetric || isMuon) { + for (int icut = 0; icut < fNLegCuts; ++icut) { + + TString pairLegCutName; + + // here we check that this cut is one of those used for building the dileptons + if (!isBarrelAsymmetric) { + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; + } + pairLegCutName = fTrackCutNames[icut].Data(); + } else { + // For asymmetric pairs we access the leg cuts instead + pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); + } + fLegCutNames.push_back(pairLegCutName); + + // define dilepton histograms + DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); + // loop over track cuts and create dilepton - track histogram directories + for (int iCutTrack = 0; iCutTrack < fNCuts; iCutTrack++) { + + // here we check that this track cut is one of those required to associate with the dileptons + if (!(fTrackCutBitMap & (static_cast(1) << iCutTrack))) { + continue; + } + + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + } + + if (fNPairCuts != 0) { + + for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + + if (!cfgPairing_strCommonTrackCuts.IsNull()) { + std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { + DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); + } + } + } + } + } + } // end loop over track cuts to be combined with dileptons / di-tracks + } // end loop over pair leg track cuts + } // end if (isBarrel || isBarrelAsymmetric || isMuon) + + if (isMCGen) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); + } + for (auto& sig : fRecMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); + DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelators) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); + } + } + + if (isMCGen_energycorrelatorsME) { + for (auto& sig : fGenMCSignals) { + DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); + } + } + + TString addHistsStr = fConfigAddJSONHistograms.value; + if (addHistsStr != "") { + dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); + } + VarManager::SetUseVars(fHistMan->GetUsedVars()); + fOutputList.setObject(fHistMan->GetMainHistogramList()); + } + + // init parameters from CCDB + void initParamsFromCCDB(uint64_t timestamp) + { + if (fConfigUseRemoteField.value) { + o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPmagPath.value, timestamp); + float magField = 0.0; + if (grpmag != nullptr) { + magField = grpmag->getNominalL3Field(); + } else { + LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); + } + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(magField); + } else { + VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } + } else { + if (fConfigUseKFVertexing.value) { + VarManager::SetupThreeProngKFParticle(fConfigMagField.value); + } else { + VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables + } + } + } + + // Template function to run pair - hadron combinations + template + void runDileptonHadron(TEvent const& event, TTrackAssocs const& assocs, TTracks const& tracks, TDileptons const& dileptons, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) + { + VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); + VarManager::FillEvent(event, fValuesHadron); + VarManager::FillEvent(event.reducedMCevent(), fValuesHadron); + VarManager::FillEvent(event, fValuesDilepton); + VarManager::FillEvent(event.reducedMCevent(), fValuesDilepton); + + uint32_t mcDecision = static_cast(0); + size_t isig = 0; + + for (auto dilepton : dileptons) { + // get full track info of tracks based on the index + auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); + auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); + if (!lepton1.has_reducedMCTrack() || !lepton2.has_reducedMCTrack()) { + continue; + } + auto lepton1MC = lepton1.reducedMCTrack(); + auto lepton2MC = lepton2.reducedMCTrack(); + // Check that the dilepton has zero charge + if (dilepton.sign() != 0) { + continue; + } + // dilepton rap cut + float rap = dilepton.rap(); + if (fConfigUseMCRapcut && abs(rap) > fConfigDileptonRapCutAbs) + continue; + + VarManager::FillTrack(dilepton, fValuesDilepton); + + // fill selected dilepton histograms for each specified selection + for (int icut = 0; icut < fNLegCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // regular dileptons + fHistMan->FillHistClass(Form("DileptonsSelected_%s", fLegCutNames[icut].Data()), fValuesDilepton); + + // other pairs, e.g.: D0s + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); + } + } + } + } + } + } + + // loop over track associations + for (auto& assoc : assocs) { + + uint32_t trackSelection = 0; + if constexpr (TCandidateType == VarManager::kBtoJpsiEEK) { + // check the cuts fulfilled by this candidate track; if none just continue + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + // get the track from this association + auto track = assoc.template reducedtrack_as(); + // check that this track is not included in the current dilepton + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + // compute needed quantities + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + // table to be written out for ML analysis + BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), + fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], + fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], + fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kCosPointingAngle], + fValuesHadron[VarManager::kVertexingChi2PCA], + track.globalIndex(), lepton1.globalIndex(), lepton2.globalIndex(), + track.tpcInnerParam(), track.eta(), dilepton.pt(), dilepton.eta(), lepton1.tpcInnerParam(), lepton1.eta(), lepton2.tpcInnerParam(), lepton2.eta(), + track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tpcNSigmaPr(), track.tofNSigmaKa(), + lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), + lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), + track.itsClusterMap(), lepton1.itsClusterMap(), lepton2.itsClusterMap(), + track.itsChi2NCl(), lepton1.itsChi2NCl(), lepton2.itsChi2NCl(), + track.tpcNClsFound(), lepton1.tpcNClsFound(), lepton2.tpcNClsFound(), + track.tpcChi2NCl(), lepton1.tpcChi2NCl(), lepton2.tpcChi2NCl(), + dilepton.filterMap_raw(), trackSelection, mcDecision); + } + + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { + trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + + auto track = assoc.template reducedtrack_as(); + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + // Check that the charge combination makes sense for D*+ -> D0 pi+ or D*- -> D0bar pi- + if (!((track.sign() == 1 && lepton1.sign() == -1 && lepton2.sign() == 1) || (track.sign() == -1 && lepton1.sign() == 1 && lepton2.sign() == -1))) { + continue; + } + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + } + + if constexpr (TCandidateType == VarManager::kBcToThreeMuons) { + trackSelection = (assoc.isMuonSelected_raw() & fTrackCutBitMap); + if (!trackSelection) { + continue; + } + + auto track = assoc.template reducedmuon_as(); + if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { + continue; + } + + VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); + VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); + + if (!track.has_reducedMCTrack()) { + continue; + } + auto trackMC = track.reducedMCTrack(); + mcDecision = 0; + isig = 0; + for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { + if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { + mcDecision |= (static_cast(1) << isig); + } + } + // Fill table for correlation analysis + DileptonTrackTable(fValuesHadron[VarManager::kDeltaEta], fValuesHadron[VarManager::kDeltaPhi], + dilepton.mass(), dilepton.pt(), dilepton.eta(), track.pt(), track.eta(), track.phi(), + lepton1.pt(), lepton1.eta(), lepton1.phi(), lepton2.pt(), lepton2.eta(), lepton2.phi(), + mcDecision); + } + + // Fill histograms for the triplets + // loop over dilepton / ditrack cuts and MC signals + for (int icut = 0; icut < fNCuts; icut++) { + + if (!dilepton.filterMap_bit(icut)) { + continue; + } + + // loop over specified track cuts (the tracks to be combined with the dileptons) + for (int iTrackCut = 0; iTrackCut < fNCuts; iTrackCut++) { + + if (!(trackSelection & (static_cast(1) << iTrackCut))) { + continue; + } + + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + + if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + } + } + for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { + if (dilepton.pairFilterMap_bit(iPairCut)) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { + if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { + fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); + for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { + if (mcDecision & (static_cast(1) << isig)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + } + } + } + } + } + } + } + } // end loop over track cuts + } // end loop over dilepton cuts + } // end loop over associations + } // end loop over dileptons + } + + Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; + Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; + + void processBarrelSkimmed(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + auto groupedDielectrons = dileptons.sliceBy(dielectronsPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDielectrons, mcEvents, mcTracks); + } + } + + void processDstarToD0Pi(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); + auto groupedDitracks = ditracks.sliceBy(ditracksPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDitracks, mcEvents, mcTracks); + } + } + + Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + Preslice dimuonsPerCollision = aod::reducedpair::reducedeventId; + + void processMuonSkimmed(soa::Filtered const& events, + soa::Filtered> const& assocs, + MyMuonTracksWithCov const& tracks, soa::Filtered const& dileptons, + ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + { + // set up KF or DCAfitter + if (events.size() == 0) { + return; + } + if (fCurrentRun != events.begin().runNumber()) { // start: runNumber + initParamsFromCCDB(events.begin().timestamp()); + fCurrentRun = events.begin().runNumber(); + } // end: runNumber + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + auto groupedMuonAssocs = assocs.sliceBy(muonAssocsPerCollision, event.globalIndex()); + auto groupedDimuons = dileptons.sliceBy(dimuonsPerCollision, event.globalIndex()); + runDileptonHadron(event, groupedMuonAssocs, tracks, groupedDimuons, mcEvents, mcTracks); + } + } + + void processMCGen(ReducedMCTracks const& mcTracks) + { + // loop over mc stack and fill histograms for pure MC truth signals + // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event + // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); + for (auto& mctrack : mcTracks) { + + if ((std::abs(mctrack.pdgCode()) > 400 && std::abs(mctrack.pdgCode()) < 599) || + (std::abs(mctrack.pdgCode()) > 4000 && std::abs(mctrack.pdgCode()) < 5999) || + mctrack.mcReducedFlags() > 0) { + /*cout << ">>>>>>>>>>>>>>>>>>>>>>> track idx / pdg / selections: " << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / "; + PrintBitMap(mctrack.mcReducedFlags(), 16); + cout << endl; + if (mctrack.has_mothers()) { + for (auto& m : mctrack.mothersIds()) { + if (m < mcTracks.size()) { // protect against bad mother indices + auto aMother = mcTracks.rawIteratorAt(m); + cout << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode() << endl; + } + } + } + + if (mctrack.has_daughters()) { + for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { + if (d < mcTracks.size()) { // protect against bad daughter indices + auto aDaughter = mcTracks.rawIteratorAt(d); + cout << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode() << endl; + } + } + }*/ + } + + VarManager::FillTrackMC(mcTracks, mctrack); + // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. + // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. + // TODO: Use the mcReducedFlags to select signals + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + + PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; + + void processMCGenWithEventSelection(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& track : groupedMCTracks) { + + VarManager::FillTrackMC(mcTracks, track); + + auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + } + } + } + + // make a list of all MC tracks in the MC collision corresponding to the current reconstructed event + std::vector mcTrackIndices; + for (auto& t : groupedMCTracks) { + mcTrackIndices.push_back(t.globalIndex()); + } + + // make a three nested for loop over all MC tracks in the vector + for (auto t1 : mcTrackIndices) { + auto track1 = mcTracks.rawIteratorAt(*(&t1)); + for (auto t2 : mcTrackIndices) { + if (t1 == t2) + continue; + // if (t2 < t1) continue; + auto track2 = mcTracks.rawIteratorAt(*(&t2)); + for (auto t3 : mcTrackIndices) { + if (t3 == t1) + continue; + if (t3 == t2) + continue; + auto track3 = mcTracks.rawIteratorAt(*(&t3)); + + for (auto& sig : fRecMCSignals) { + if (sig->CheckSignal(true, track1, track2, track3)) { + + VarManager::FillTripleMC(track1, track2, track3, VarManager::fgValues); // nb! hardcoded for jpsiK + + fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); + + // apply kinematic cuts + if (track1.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track1.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + if (track2.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track2.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { + continue; + } + if (track3.pt() < fConfigMCGenHadronPtMin.value || std::abs(track3.eta()) > fConfigMCGenHadronEtaAbs.value) { + continue; + } + fHistMan->FillHistClass(Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + } // end loop over reconstructed events + } + + template + void runEnergyCorrelators(TEvent const& event, TMCTracks const& mcTracks) + { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks) { + auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + void processMCGenEnergyCorrelators(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + runEnergyCorrelators(event, mcTracks); + } + } + + template + void runEnergyCorrelatorsMixedEvent(TEvent const& event1, TEvent const& event2, TMCTracks const& mcTracks) + { + auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.reducedMCeventId()); + auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.reducedMCeventId()); + groupedMCTracks1.bindInternalIndicesTo(&mcTracks); + groupedMCTracks2.bindInternalIndicesTo(&mcTracks); + for (auto& t1 : groupedMCTracks1) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + // apply kinematic cuts for signal + if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) + continue; + if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) + continue; + // for the energy correlators + for (auto& t2 : groupedMCTracks2) { + auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); + if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) + continue; + if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) + continue; + if (t2_raw.getGenStatusCode() <= 0) + continue; + VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, t1_raw)) { + fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); + } + } + } + } + } + + void processMCGenEnergyCorrelatorsME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); + } + } + + void processMCGenEnergyCorrelatorsPionME(soa::Filtered const& events, + ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) + { + if (events.size() == 0) { + LOG(warning) << "No events in this TF, going to the next one ..."; + return; + } + // loop over two event comibnations + for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { + if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { + continue; + } + if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { + continue; + } + runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); + } + } + + void processDummy(MyEvents&) + { + // do nothing + } + + PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelSkimmed, "Run barrel dilepton-track pairing, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDstarToD0Pi, "Run barrel pairing of D0 daughters with pion candidate, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); + PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} + +void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +{ + // + // Define here the histograms for all the classes required in analysis. + // The histogram classes are provided in the histClasses string, separated by semicolon ";" + // The histogram classes and their components histograms are defined below depending on the name of the histogram class + // + std::unique_ptr objArray(histClasses.Tokenize(";")); + for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { + TString classStr = objArray->At(iclass)->GetName(); + histMan->AddHistClass(classStr.Data()); + + TString histName = histGroups; + // NOTE: The level of detail for histogramming can be controlled via configurables + if (classStr.Contains("Event")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + } + + if (classStr.Contains("SameBunchCorrelations") || classStr.Contains("OutOfBunchCorrelations")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); + } + + if ((classStr.Contains("Track") || classStr.Contains("Assoc")) && !classStr.Contains("Pairs")) { + if (classStr.Contains("Barrel")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + if (classStr.Contains("PIDCalibElectron")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); + } + if (classStr.Contains("PIDCalibPion")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_pion"); + } + if (classStr.Contains("PIDCalibProton")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); + } + if (classStr.Contains("Ambiguity")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); + } + } + } + if (classStr.Contains("Muon") && !classStr.Contains("Pairs")) { + if (!classStr.Contains("Ambiguity")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } else { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "muon-ambiguity"); + } + } + + if (classStr.Contains("Pairs")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + + if (classStr.Contains("Triplets")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + } + + if (classStr.Contains("MCTruthGenPair")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); + } + + if (classStr.Contains("MCTruthGenSelBR")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); + } else if (classStr.Contains("MCTruthGen")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + } + + // if (classStr.Contains("MCTruthGen")) { + // dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + // } + + if (classStr.Contains("DileptonsSelected")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); + } + + if (classStr.Contains("DileptonTrack") && !classStr.Contains("ME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); + } + + if (classStr.Contains("DileptonTrackME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "mixedevent"); + } + + if (classStr.Contains("HadronsSelected")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + } + + if (classStr.Contains("DileptonHadronInvMass")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); + } + + if (classStr.Contains("DileptonHadronCorrelation")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); + } + + if (classStr.Contains("MCTruthEenergyCorrelators")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); + } + + } // end loop over histogram classes +} From d3935f2b96dae1866b77c9dfad5c8e8b9515b535 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 18:06:20 +0800 Subject: [PATCH 13/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 162 +++++++++++++++++++------ 1 file changed, 124 insertions(+), 38 deletions(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 71b8ea24b21..76e81dd5a8d 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -1322,6 +1322,7 @@ struct AnalysisSameEventPairing { Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; + Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; // TODO: Add pair cuts via JSON } fConfigCuts; @@ -1355,7 +1356,6 @@ struct AnalysisSameEventPairing { Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; - // Configurable runMCGenPair{"cfgRunMCGenPair", false, "Do pairing of true MC particles"}; } fConfigMC; struct : ConfigurableGroup { @@ -1383,6 +1383,8 @@ struct AnalysisSameEventPairing { std::vector fGenMCSignals; std::vector fPairCuts; + AnalysisCompositeCut fMCGenAccCut; + bool fUseMCGenAccCut = false; uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream @@ -1402,7 +1404,7 @@ struct AnalysisSameEventPairing { if (context.mOptions.get("processDummy")) { return; } - bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping"); + bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping") || context.mOptions.get("processBarrelOnlySkimmed"); VarManager::SetDefaultVarNames(); fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); @@ -1470,6 +1472,16 @@ struct AnalysisSameEventPairing { } } + // get the mc generated acceptance cut + TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; + if (mcGenAccCutStr != "") { + AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); + if (cut != nullptr) { + fMCGenAccCut.AddCut(cut); + } + fUseMCGenAccCut = true; + } + // check that the barrel track cuts array required in this task is not empty if (!trackCutsStr.IsNull()) { // tokenize and loop over the barrel cuts produced by the barrel track selection task @@ -2112,44 +2124,69 @@ struct AnalysisSameEventPairing { } // end loop over events } - // Preslice perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; template - void runMCGen(ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) + void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { - // loop over mc stack and fill histograms for pure MC truth signals - // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); uint32_t mcDecision = 0; int isig = 0; + for (auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. // TODO: Use the mcReducedFlags to select signals for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 1) { // NOTE: 1-prong signals required here + if (sig->CheckSignal(true, mctrack)) { + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + } + } + } + // Fill Generated histograms taking into account selected collisions + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + + for (auto& track : mcTracks) { + if (track.reducedMCeventId() != event.reducedMCeventId()) { continue; } - bool checked = false; - /*if constexpr (soa::is_soa_filtered_v) { - auto mctrack_raw = groupedMCTracks.rawIteratorAt(mctrack.globalIndex()); - checked = sig.CheckSignal(true, mctrack_raw); - } else {*/ - checked = sig->CheckSignal(true, mctrack); - //} - if (checked) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(mctrack.reducedMCeventId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), mctrack.pt(), mctrack.eta(), mctrack.phi(), -999, -999, -999); + VarManager::FillTrackMC(mcTracks, track); + // if we have a mc generated acceptance cut, apply it here + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; } } + auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->CheckSignal(true, track_raw)) { + mcDecision |= (static_cast(1) << isig); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); + + if (useMiniTree.fConfigMiniTree) { + auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); + dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + } + } + isig++; + } } - isig++; - } + } // end loop over reconstructed events if (fHasTwoProngGenMCsignals) { for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { @@ -2161,20 +2198,60 @@ struct AnalysisSameEventPairing { continue; } if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); VarManager::FillPairMC(t1, t2); - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - // WARNING! To be checked - dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } } + fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); } - isig++; } } } } - } // end runMCGen + for (auto& event : events) { + if (!event.isEventSelected_bit(0)) { + continue; + } + if (!event.has_reducedMCevent()) { + continue; + } + // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS + if (fHasTwoProngGenMCsignals) { + auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); + groupedMCTracks.bindInternalIndicesTo(&mcTracks); + for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { + auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); + auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); + if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { + mcDecision = 0; + isig = 0; + for (auto& sig : fGenMCSignals) { + if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here + continue; + } + if (sig->CheckSignal(true, t1_raw, t2_raw)) { + mcDecision |= (static_cast(1) << isig); + VarManager::FillPairMC(t1, t2); + if (fUseMCGenAccCut) { + if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { + continue; + } + } + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + if (useMiniTree.fConfigMiniTree) { + // WARNING! To be checked + dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); + } + } + isig++; + } + } + } + } // end loop over reconstructed events + } + } void processAllSkimmed(MyEventsVtxCovSelected const& events, soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, @@ -2195,10 +2272,7 @@ struct AnalysisSameEventPairing { MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - // Feature replaced by processMCGen - /*if (fConfigMC.runMCGenPair) { - runMCGen(mcEvents, mcTracks); - }*/ + runMCGenWithGrouping(events, mcEvents, mcTracks); } void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, @@ -4261,16 +4335,22 @@ struct AnalysisDileptonTrack { for (auto t1 : mcTrackIndices) { auto track1 = mcTracks.rawIteratorAt(*(&t1)); for (auto t2 : mcTrackIndices) { - if (t1 == t2 || t2 < t1) + if (t1 == t2) continue; + // if (t2 < t1) continue; auto track2 = mcTracks.rawIteratorAt(*(&t2)); for (auto t3 : mcTrackIndices) { - if (t3 == t1 || t3 == t2) + if (t3 == t1) + continue; + if (t3 == t2) continue; auto track3 = mcTracks.rawIteratorAt(*(&t3)); for (auto& sig : fRecMCSignals) { if (sig->CheckSignal(true, track1, track2, track3)) { + + VarManager::FillTripleMC(track1, track2, track3, VarManager::fgValues); // nb! hardcoded for jpsiK + fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); // apply kinematic cuts @@ -4514,13 +4594,19 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char } if (classStr.Contains("MCTruthGenPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair"); + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); } - if (classStr.Contains("MCTruthGen")) { + if (classStr.Contains("MCTruthGenSelBR")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); + } else if (classStr.Contains("MCTruthGen")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); } + // if (classStr.Contains("MCTruthGen")) { + // dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); + // } + if (classStr.Contains("DileptonsSelected")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); } From 42b35a5f6f357f5783236b930b61dc107ca47ed5 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 18:14:45 +0800 Subject: [PATCH 14/17] Delete dqEfficiency_withAssoc.cxx --- dqEfficiency_withAssoc.cxx | 4639 ------------------------------------ 1 file changed, 4639 deletions(-) delete mode 100644 dqEfficiency_withAssoc.cxx diff --git a/dqEfficiency_withAssoc.cxx b/dqEfficiency_withAssoc.cxx deleted file mode 100644 index 76e81dd5a8d..00000000000 --- a/dqEfficiency_withAssoc.cxx +++ /dev/null @@ -1,4639 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// 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. -// -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// Configurable workflow for running several DQ or other PWG analyses - -#include "PWGDQ/Core/AnalysisCompositeCut.h" -#include "PWGDQ/Core/AnalysisCut.h" -#include "PWGDQ/Core/CutsLibrary.h" -#include "PWGDQ/Core/HistogramManager.h" -#include "PWGDQ/Core/HistogramsLibrary.h" -#include "PWGDQ/Core/MCSignal.h" -#include "PWGDQ/Core/MCSignalLibrary.h" -#include "PWGDQ/Core/MixingHandler.h" -#include "PWGDQ/Core/MixingLibrary.h" -#include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" - -#include "Common/Core/TableHelper.h" - -#include "CCDB/BasicCCDBManager.h" -#include "DataFormatsParameters/GRPMagField.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisHelpers.h" -#include "Framework/AnalysisTask.h" -#include "Framework/runDataProcessing.h" - -#include "TGeoGlobalMagField.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using std::cout; -using std::endl; -using std::string; - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::aod; - -// Some definitions -namespace o2::aod -{ -namespace dqanalysisflags -{ -DECLARE_SOA_COLUMN(MixingHash, mixingHash, int); //! Hash used in event mixing //need to understand -DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 32); //! Event decision -DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions -DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity -DECLARE_SOA_COLUMN(BarrelAmbiguityOutOfBunch, barrelAmbiguityOutOfBunch, int8_t); //! Barrel track out of bunch ambiguity -DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) -DECLARE_SOA_COLUMN(MuonAmbiguityInBunch, muonAmbiguityInBunch, int8_t); //! Muon track in-bunch ambiguity -DECLARE_SOA_COLUMN(MuonAmbiguityOutOfBunch, muonAmbiguityOutOfBunch, int8_t); //! Muon track out of bunch ambiguity -DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to ReducedTracksAssoc) -// Bcandidate columns for ML analysis of B->Jpsi+K -DECLARE_SOA_COLUMN(RunNumber, runNumber, uint64_t); -DECLARE_SOA_COLUMN(EventIdx, eventIdx, uint64_t); -DECLARE_SOA_COLUMN(EventTimestamp, eventTimestamp, uint64_t); -DECLARE_SOA_COLUMN(massBcandidate, MBcandidate, float); -DECLARE_SOA_COLUMN(MassDileptonCandidate, massDileptonCandidate, float); -DECLARE_SOA_COLUMN(deltaMassBcandidate, deltaMBcandidate, float); -DECLARE_SOA_COLUMN(pTBcandidate, PtBcandidate, float); -DECLARE_SOA_COLUMN(EtaBcandidate, etaBcandidate, float); -DECLARE_SOA_COLUMN(PhiBcandidate, phiBcandidate, float); -DECLARE_SOA_COLUMN(RapBcandidate, rapBcandidate, float); -DECLARE_SOA_COLUMN(LxyBcandidate, lxyBcandidate, float); -DECLARE_SOA_COLUMN(LxyzBcandidate, lxyzBcandidate, float); -DECLARE_SOA_COLUMN(LzBcandidate, lzBcandidate, float); -DECLARE_SOA_COLUMN(TauxyBcandidate, tauxyBcandidate, float); -DECLARE_SOA_COLUMN(TauzBcandidate, tauzBcandidate, float); -DECLARE_SOA_COLUMN(CosPBcandidate, cosPBcandidate, float); -DECLARE_SOA_COLUMN(Chi2Bcandidate, chi2Bcandidate, float); -DECLARE_SOA_COLUMN(GlobalIndexassoc, globalIndexassoc, uint64_t); -DECLARE_SOA_COLUMN(GlobalIndexleg1, globalIndexleg1, uint64_t); -DECLARE_SOA_COLUMN(GlobalIndexleg2, globalIndexleg2, uint64_t); -DECLARE_SOA_COLUMN(Ptassoc, ptassoc, float); -DECLARE_SOA_COLUMN(PINassoc, pINassoc, float); -DECLARE_SOA_COLUMN(Etaassoc, etaassoc, float); -DECLARE_SOA_COLUMN(Phiassoc, phiassoc, float); -DECLARE_SOA_COLUMN(Ptpair, ptpair, float); -DECLARE_SOA_COLUMN(Etapair, etapair, float); -DECLARE_SOA_COLUMN(Ptleg1, ptleg1, float); -DECLARE_SOA_COLUMN(PINleg1, pINleg1, float); -DECLARE_SOA_COLUMN(Etaleg1, etaleg1, float); -DECLARE_SOA_COLUMN(Phileg1, phileg1, float); -DECLARE_SOA_COLUMN(Ptleg2, ptleg2, float); -DECLARE_SOA_COLUMN(PINleg2, pINleg2, float); -DECLARE_SOA_COLUMN(Etaleg2, etaleg2, float); -DECLARE_SOA_COLUMN(Phileg2, phileg2, float); -DECLARE_SOA_COLUMN(TPCnsigmaKaassoc, tpcnsigmaKaassoc, float); -DECLARE_SOA_COLUMN(TPCnsigmaPiassoc, tpcnsigmaPiassoc, float); -DECLARE_SOA_COLUMN(TPCnsigmaPrassoc, tpcnsigmaPrassoc, float); -DECLARE_SOA_COLUMN(TOFnsigmaKaassoc, tofnsigmaKaassoc, float); -DECLARE_SOA_COLUMN(TPCnsigmaElleg1, tpcnsigmaElleg1, float); -DECLARE_SOA_COLUMN(TPCnsigmaPileg1, tpcnsigmaPileg1, float); -DECLARE_SOA_COLUMN(TPCnsigmaPrleg1, tpcnsigmaPrleg1, float); -DECLARE_SOA_COLUMN(TPCnsigmaElleg2, tpcnsigmaElleg2, float); -DECLARE_SOA_COLUMN(TPCnsigmaPileg2, tpcnsigmaPileg2, float); -DECLARE_SOA_COLUMN(TPCnsigmaPrleg2, tpcnsigmaPrleg2, float); -DECLARE_SOA_COLUMN(ITSClusterMapassoc, itsClusterMapassoc, uint8_t); -DECLARE_SOA_COLUMN(ITSClusterMapleg1, itsClusterMapleg1, uint8_t); -DECLARE_SOA_COLUMN(ITSClusterMapleg2, itsClusterMapleg2, uint8_t); -DECLARE_SOA_COLUMN(ITSChi2assoc, itsChi2assoc, float); -DECLARE_SOA_COLUMN(ITSChi2leg1, itsChi2leg1, float); -DECLARE_SOA_COLUMN(ITSChi2leg2, itsChi2leg2, float); -DECLARE_SOA_COLUMN(TPCNclsassoc, tpcNclsassoc, float); -DECLARE_SOA_COLUMN(TPCNclsleg1, tpcNclsleg1, float); -DECLARE_SOA_COLUMN(TPCNclsleg2, tpcNclsleg2, float); -DECLARE_SOA_COLUMN(TPCChi2assoc, tpcChi2assoc, float); -DECLARE_SOA_COLUMN(TPCChi2leg1, tpcChi2leg1, float); -DECLARE_SOA_COLUMN(TPCChi2leg2, tpcChi2leg2, float); -DECLARE_SOA_COLUMN(McFlag, mcFlag, int8_t); -DECLARE_SOA_BITMAP_COLUMN(IsJpsiFromBSelected, isJpsiFromBSelected, 32); -// Candidate columns for prompt-non-prompt JPsi separation -DECLARE_SOA_COLUMN(Massee, massee, float); -DECLARE_SOA_COLUMN(Etaee, etaee, float); -DECLARE_SOA_COLUMN(Rapee, rapee, float); -DECLARE_SOA_COLUMN(Phiee, phiee, float); -DECLARE_SOA_COLUMN(Ptee, ptee, float); -DECLARE_SOA_COLUMN(Lxyee, lxyee, float); -DECLARE_SOA_COLUMN(LxyeePoleMass, lxyeepolemass, float); -DECLARE_SOA_COLUMN(Lzee, lzee, float); -DECLARE_SOA_COLUMN(MultiplicityFT0A, multiplicityFT0AJPsi2ee, float); -DECLARE_SOA_COLUMN(MultiplicityFT0C, multiplicityFT0CJPsi2ee, float); -DECLARE_SOA_COLUMN(PercentileFT0M, percentileFT0MJPsi2ee, float); -DECLARE_SOA_COLUMN(MultiplicityNContrib, multiplicityNContribJPsi2ee, float); -DECLARE_SOA_COLUMN(AmbiguousInBunchPairs, AmbiguousJpsiPairsInBunch, bool); -DECLARE_SOA_COLUMN(AmbiguousOutOfBunchPairs, AmbiguousJpsiPairsOutOfBunch, bool); -DECLARE_SOA_COLUMN(Corrassoc, corrassoc, bool); -DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); -DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); -// Candidate columns efficiency calculation for prompt-non-prompt JPsi separation -DECLARE_SOA_COLUMN(OniaPt, oniaPt, float); -DECLARE_SOA_COLUMN(OniaY, oniaY, float); -DECLARE_SOA_COLUMN(OniaEta, oniaEta, float); -DECLARE_SOA_COLUMN(OniaPhi, oniaPhi, float); -DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); -DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); -} // namespace dqanalysisflags - -DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); -DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents -DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc -DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks -DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTS", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc -DECLARE_SOA_TABLE(MuonAmbiguities, "AOD", "DQMUONAMB", dqanalysisflags::MuonAmbiguityInBunch, dqanalysisflags::MuonAmbiguityOutOfBunch); //! joinable to ReducedMuonTracks -DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTER", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc -DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONS", - dqanalysisflags::RunNumber, dqanalysisflags::EventIdx, dqanalysisflags::EventTimestamp, - dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltaMassBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::EtaBcandidate, dqanalysisflags::PhiBcandidate, dqanalysisflags::RapBcandidate, - dqanalysisflags::LxyBcandidate, dqanalysisflags::LxyzBcandidate, dqanalysisflags::LzBcandidate, - dqanalysisflags::TauxyBcandidate, dqanalysisflags::TauzBcandidate, dqanalysisflags::CosPBcandidate, dqanalysisflags::Chi2Bcandidate, - dqanalysisflags::GlobalIndexassoc, dqanalysisflags::GlobalIndexleg1, dqanalysisflags::GlobalIndexleg2, - dqanalysisflags::PINassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, - dqanalysisflags::PINleg1, dqanalysisflags::Etaleg1, dqanalysisflags::PINleg2, dqanalysisflags::Etaleg2, - dqanalysisflags::TPCnsigmaKaassoc, dqanalysisflags::TPCnsigmaPiassoc, dqanalysisflags::TPCnsigmaPrassoc, dqanalysisflags::TOFnsigmaKaassoc, - dqanalysisflags::TPCnsigmaElleg1, dqanalysisflags::TPCnsigmaPileg1, dqanalysisflags::TPCnsigmaPrleg1, - dqanalysisflags::TPCnsigmaElleg2, dqanalysisflags::TPCnsigmaPileg2, dqanalysisflags::TPCnsigmaPrleg2, - dqanalysisflags::ITSClusterMapassoc, dqanalysisflags::ITSClusterMapleg1, dqanalysisflags::ITSClusterMapleg2, - dqanalysisflags::ITSChi2assoc, dqanalysisflags::ITSChi2leg1, dqanalysisflags::ITSChi2leg2, - dqanalysisflags::TPCNclsassoc, dqanalysisflags::TPCNclsleg1, dqanalysisflags::TPCNclsleg2, - dqanalysisflags::TPCChi2assoc, dqanalysisflags::TPCChi2leg1, dqanalysisflags::TPCChi2leg2, - dqanalysisflags::IsJpsiFromBSelected, dqanalysisflags::IsBarrelSelected, dqanalysisflags::McFlag); -DECLARE_SOA_TABLE(JPsiMuonCandidates, "AOD", "DQJPSIMUONA", - dqanalysisflags::DeltaEta, dqanalysisflags::DeltaPhi, - dqanalysisflags::MassDileptonCandidate, dqanalysisflags::Ptpair, dqanalysisflags::Etapair, dqanalysisflags::Ptassoc, dqanalysisflags::Etaassoc, dqanalysisflags::Phiassoc, - dqanalysisflags::Ptleg1, dqanalysisflags::Etaleg1, dqanalysisflags::Phileg1, dqanalysisflags::Ptleg2, dqanalysisflags::Etaleg2, dqanalysisflags::Phileg2, - dqanalysisflags::McFlag); -DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", dqanalysisflags::Massee, dqanalysisflags::Ptee, dqanalysisflags::Etaee, dqanalysisflags::Rapee, dqanalysisflags::Phiee, dqanalysisflags::Lxyee, dqanalysisflags::LxyeePoleMass, dqanalysisflags::Lzee, dqanalysisflags::AmbiguousInBunchPairs, dqanalysisflags::AmbiguousOutOfBunchPairs, dqanalysisflags::Corrassoc, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); -DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dqanalysisflags::OniaEta, dqanalysisflags::OniaY, dqanalysisflags::OniaPhi, dqanalysisflags::OniaVz, dqanalysisflags::OniaVtxZ, dqanalysisflags::MultiplicityFT0A, dqanalysisflags::MultiplicityFT0C, dqanalysisflags::PercentileFT0M, dqanalysisflags::MultiplicityNContrib); -} // namespace o2::aod - -// Declarations of various short names -using MyEvents = soa::Join; -using MyEventsSelected = soa::Join; -using MyEventsVtxCov = soa::Join; -using MyEventsVtxCovSelected = soa::Join; -using MyEventsVtxCovSelectedMultExtra = soa::Join; -using MyEventsVtxCovSelectedQvector = soa::Join; -using MyEventsQvector = soa::Join; -using MyEventsVtxCovHashSelected = soa::Join; - -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithAmbiguities = soa::Join; -using MyBarrelTracksWithCov = soa::Join; -using MyBarrelTracksWithCovWithAmbiguities = soa::Join; -using MyBarrelTracksWithCovWithAmbiguitiesWithColl = soa::Join; -using MyDielectronCandidates = soa::Join; -using MyDitrackCandidates = soa::Join; -using MyDimuonCandidates = soa::Join; -using MyMuonTracks = soa::Join; -using MyMuonTracksWithCov = soa::Join; -using MyMuonTracksWithCovWithAmbiguities = soa::Join; -// using MyMuonTracksSelectedWithColl = soa::Join; - -// bit maps used for the Fill functions of the VarManager -constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; -constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; -constexpr static uint32_t gkEventFillMapWithCovMultExtra = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventMultExtra; -// constexpr static uint32_t gkEventFillMapWithQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventQvector; -// constexpr static uint32_t gkEventFillMapWithCovQvector = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov | VarManager::ObjTypes::ReducedEventQvector; -constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID; -constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; -constexpr static uint32_t gkTrackFillMapWithCovWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; -// constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; - -constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; -constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; -// constexpr static uint32_t gkMuonFillMapWithColl = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCollInfo; - -// Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks - -template -void PrintBitMap(TMap map, int nbits) -{ - for (int i = 0; i < nbits; i++) { - cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); - } -} - -// Analysis task that produces event decisions and the Hash table used in event mixing -struct AnalysisEventSelection { - Produces eventSel; - Produces hash; - OutputObj fOutputList{"output"}; - Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddEventMCHistogram{"cfgAddEventMCHistogram", "generator", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; - - Configurable fConfigSplitCollisionsDeltaZ{"splitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; - Configurable fConfigSplitCollisionsDeltaBC{"splitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; - Configurable fConfigCheckSplitCollisions{"checkSplitCollisions", false, "If true, run the split collision check and fill histograms"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - - HistogramManager* fHistMan = nullptr; - MixingHandler* fMixHandler = nullptr; - - AnalysisCompositeCut* fEventCut; - - Service fCCDB; - o2::ccdb::CcdbApi fCCDBApi; - - std::map fSelMap; // key: reduced event global index, value: event selection decision - std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices - std::map fMetadataRCT, fHeader; - int fCurrentRun; - - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processDummy")) { - return; - } - VarManager::SetDefaultVarNames(); - - fEventCut = new AnalysisCompositeCut(true); - TString eventCutStr = fConfigEventCuts.value; - if (eventCutStr != "") { - AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); - if (cut != nullptr) { - fEventCut->AddCut(cut); - } - } - // Additional cuts via JSON - TString eventCutJSONStr = fConfigEventCutsJSON.value; - if (eventCutJSONStr != "") { - std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); - for (auto& cutIt : jsonCuts) { - fEventCut->AddCut(cutIt); - } - } - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - - if (fConfigQA) { - fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); - if (fConfigCheckSplitCollisions) { - DefineHistograms(fHistMan, "OutOfBunchCorrelations;SameBunchCorrelations;", ""); - } - DefineHistograms(fHistMan, "EventsMC", fConfigAddEventMCHistogram.value.data()); - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // aditional histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - TString mixVarsString = fConfigMixingVariables.value; - std::unique_ptr objArray(mixVarsString.Tokenize(",")); - if (objArray->GetEntries() > 0) { - fMixHandler = new MixingHandler("mixingHandler", "mixing handler"); - fMixHandler->Init(); - for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); - } - } - - fCurrentRun = -1; - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - fCCDBApi.init(fConfigCcdbUrl.value); - } - - template - void runEventSelection(TEvents const& events, TEventsMC const& mcEvents) - { - if (events.size() > 0 && events.begin().runNumber() != fCurrentRun) { - fHeader = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", events.begin().runNumber()), fMetadataRCT, -1); - uint64_t sor = std::atol(fHeader["SOR"].c_str()); - uint64_t eor = std::atol(fHeader["EOR"].c_str()); - VarManager::SetSORandEOR(sor, eor); - } - - fSelMap.clear(); - fBCCollMap.clear(); - - for (auto& event : events) { - // Reset the fValues array and fill event observables - VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - VarManager::FillEvent(event); - if (event.has_reducedMCevent()) { - VarManager::FillEvent(event.reducedMCevent()); - } - - bool decision = false; - // if QA is requested fill histograms before event selections - if (fConfigQA) { - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event - } - if (fEventCut->IsSelected(VarManager::fgValues)) { - if (fConfigQA) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); - } - decision = true; - } - fSelMap[event.globalIndex()] = decision; - if (fBCCollMap.find(event.globalBC()) == fBCCollMap.end()) { - std::vector evIndices = {event.globalIndex()}; - fBCCollMap[event.globalBC()] = evIndices; - } else { - auto& evIndices = fBCCollMap[event.globalBC()]; - evIndices.push_back(event.globalIndex()); - } - if (fMixHandler != nullptr) { - int hh = fMixHandler->FindEventCategory(VarManager::fgValues); - hash(hh); - } - } - - for (auto& event : mcEvents) { - // Reset the fValues array and fill event observables - VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - VarManager::FillEvent(event); - if (fConfigQA) { - fHistMan->FillHistClass("EventsMC", VarManager::fgValues); - } - } - } - - template - void publishSelections(TEvents const& events) - { - std::map collisionSplittingMap; // key: event global index, value: whether pileup event is a possible splitting - - // Reset the fValues array and fill event observables - VarManager::ResetValues(0, VarManager::kNEventWiseVariables); - // loop over the BC map, get the collision vectors and make in-bunch and out of bunch 2-event correlations - for (auto bc1It = fBCCollMap.begin(); bc1It != fBCCollMap.end(); ++bc1It) { - uint64_t bc1 = bc1It->first; - auto const& bc1Events = bc1It->second; - - // same bunch event correlations, if more than 1 collisions in this bunch - if (bc1Events.size() > 1) { - for (auto ev1It = bc1Events.begin(); ev1It != bc1Events.end(); ++ev1It) { - auto ev1 = events.rawIteratorAt(*ev1It); - for (auto ev2It = std::next(ev1It); ev2It != bc1Events.end(); ++ev2It) { - auto ev2 = events.rawIteratorAt(*ev2It); - // compute 2-event quantities and mark the candidate split collisions - VarManager::FillTwoEvents(ev1, ev2); - if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split - collisionSplittingMap[*ev1It] = true; - collisionSplittingMap[*ev2It] = true; - } - fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); - } // end second event loop - } // end first event loop - } // end if BC1 events > 1 - - // loop over the following BCs in the TF - for (auto bc2It = std::next(bc1It); bc2It != fBCCollMap.end(); ++bc2It) { - uint64_t bc2 = bc2It->first; - if ((bc2 > bc1 ? bc2 - bc1 : bc1 - bc2) > fConfigSplitCollisionsDeltaBC) { - break; - } - auto const& bc2Events = bc2It->second; - - // loop over events in the first BC - for (auto ev1It : bc1Events) { - auto ev1 = events.rawIteratorAt(ev1It); - // loop over events in the second BC - for (auto ev2It : bc2Events) { - auto ev2 = events.rawIteratorAt(ev2It); - // compute 2-event quantities and mark the candidate split collisions - VarManager::FillTwoEvents(ev1, ev2); - if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split - collisionSplittingMap[ev1It] = true; - collisionSplittingMap[ev2It] = true; - } - fHistMan->FillHistClass("OutOfBunchCorrelations", VarManager::fgValues); - } - } - } - } - - // publish the table - uint32_t evSel = static_cast(0); - for (auto& event : events) { - evSel = 0; - if (fSelMap[event.globalIndex()]) { // event passed the user cuts - evSel |= (static_cast(1) << 0); - } - std::vector sameBunchEvents = fBCCollMap[event.globalBC()]; - if (sameBunchEvents.size() > 1) { // event with in-bunch pileup - evSel |= (static_cast(1) << 1); - } - if (collisionSplittingMap.find(event.globalIndex()) != collisionSplittingMap.end()) { // event with possible fake in-bunch pileup (collision splitting) - evSel |= (static_cast(1) << 2); - } - eventSel(evSel); - } - } - - void processSkimmed(MyEvents const& events, aod::ReducedMCEvents const& mcEvents) - { - runEventSelection(events, mcEvents); - publishSelections(events); - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisEventSelection, processSkimmed, "Run event selection on DQ skimmed events", false); - PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); -}; - -// Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) -// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-even pairing, electron prefiltering, track for dilepton-track correlations) -struct AnalysisTrackSelection { - Produces trackSel; - Produces trackAmbiguities; - OutputObj fOutputList{"output"}; - - Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; - Configurable fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - - Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; - Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; - - Service fCCDB; - - HistogramManager* fHistMan; - std::vector fTrackCuts; - std::vector fMCSignals; // list of signals to be checked - std::vector fHistNamesReco; - std::vector fHistNamesMCMatched; - - int fCurrentRun; // current run (needed to detect run changes for loading CCDB parameters) - - std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) - std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) - - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processDummy")) { - return; - } - VarManager::SetDefaultVarNames(); - - fCurrentRun = 0; - TString cutNamesStr = fConfigCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); - } - } - // add extra cuts from JSON - TString addTrackCutsStr = fConfigCutsJSON.value; - if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { - fTrackCuts.push_back(reinterpret_cast(t)); - } - } - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - - TString configSigNamesStr = fConfigMCSignals.value; - std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); - // Setting the MC signals - for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals - continue; - } - fMCSignals.push_back(sig); - } - } - // Add the MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals - continue; - } - fMCSignals.push_back(mcIt); - } - } - - if (fConfigQA) { - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - // Configure histogram classes for each track cut; - // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) - TString histClasses = "AssocsBarrel_BeforeCuts;"; - for (auto& cut : fTrackCuts) { - TString nameStr = Form("AssocsBarrel_%s", cut->GetName()); - fHistNamesReco.push_back(nameStr); - histClasses += Form("%s;", nameStr.Data()); - for (auto& sig : fMCSignals) { - TString nameStr2 = Form("AssocsCorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); - fHistNamesMCMatched.push_back(nameStr2); - histClasses += Form("%s;", nameStr2.Data()); - nameStr2 = Form("AssocsIncorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); - fHistNamesMCMatched.push_back(nameStr2); - histClasses += Form("%s;", nameStr2.Data()); - } - } - - DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data()); - if (fConfigPublishAmbiguity) { - DefineHistograms(fHistMan, "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;", "ambiguity"); - } - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - if (fConfigComputeTPCpostCalib) { - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - } - } - - template - void runTrackSelection(ReducedTracksAssoc const& assocs, TEvents const& events, TTracks const& tracks, TEventsMC const& /*eventsMC*/, TTracksMC const& tracksMC) - { - fNAssocsInBunch.clear(); - fNAssocsOutOfBunch.clear(); - - // TODO: Check if postcalibration needed for MC - if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { - if (fConfigComputeTPCpostCalib) { - auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, events.begin().timestamp()); - VarManager::SetCalibrationObject(VarManager::kTPCElectronMean, calibList->FindObject("mean_map_electron")); - VarManager::SetCalibrationObject(VarManager::kTPCElectronSigma, calibList->FindObject("sigma_map_electron")); - VarManager::SetCalibrationObject(VarManager::kTPCPionMean, calibList->FindObject("mean_map_pion")); - VarManager::SetCalibrationObject(VarManager::kTPCPionSigma, calibList->FindObject("sigma_map_pion")); - VarManager::SetCalibrationObject(VarManager::kTPCProtonMean, calibList->FindObject("mean_map_proton")); - VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); - } - - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); - if (grpmag != nullptr) { - VarManager::SetMagneticField(grpmag->getNominalL3Field()); - } else { - LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); - } - - fCurrentRun = events.begin().runNumber(); - } - - trackSel.reserve(assocs.size()); - trackAmbiguities.reserve(tracks.size()); - - // Loop over associations - for (auto& assoc : assocs) { - auto event = assoc.template reducedevent_as(); - if (!event.isEventSelected_bit(0)) { - trackSel(0); - continue; - } - - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - // fill event information which might be needed in histograms/cuts that combine track and event properties - VarManager::FillEvent(event); - if (event.has_reducedMCevent()) { - VarManager::FillEvent(event.reducedMCevent()); - } - - auto track = assoc.template reducedtrack_as(); - VarManager::FillTrack(track); - // compute quantities which depend on the associated collision, such as DCA - VarManager::FillTrackCollision(track, event); - - bool isCorrectAssoc = false; - if (track.has_reducedMCTrack()) { - auto trackMC = track.reducedMCTrack(); - auto eventMCfromTrack = trackMC.reducedMCevent(); - if (event.has_reducedMCevent()) { - isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); - } - VarManager::FillTrackMC(tracksMC, trackMC); - } - - if (fConfigQA) { - fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); - } - - int iCut = 0; - uint32_t filterMap = static_cast(0); - for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { - if ((*cut)->IsSelected(VarManager::fgValues)) { - filterMap |= (static_cast(1) << iCut); - if (fConfigQA) { - fHistMan->FillHistClass(fHistNamesReco[iCut], VarManager::fgValues); - } - } - } // end loop over cuts - trackSel(filterMap); - - // compute MC matching decisions and fill histograms for matched associations - int isig = 0; - if (filterMap > 0 && track.has_reducedMCTrack()) { - // loop over all MC signals - for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { - // check if this MC signal is matched - if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { - // mcDecision |= (static_cast(1) << isig); - // loop over cuts and fill histograms for the cuts that are fulfilled - for (unsigned int icut = 0; icut < fTrackCuts.size(); icut++) { - if (filterMap & (static_cast(1) << icut)) { - if (isCorrectAssoc) { - fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(fHistNamesMCMatched[icut * 2 * fMCSignals.size() + 2 * isig + 1].Data(), VarManager::fgValues); - } - } - } // end loop over cuts - } - } - - // fill histograms - /*for (unsigned int i = 0; i < fMCSignals.size(); i++) { - if (!(mcDecision & (static_cast(1) << i))) { - continue; - } - for (unsigned int j = 0; j < fTrackCuts.size(); j++) { - if (filterMap & (static_cast(1) << j)) { - if (isCorrectAssoc) { - fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(fHistNamesMCMatched[j * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); - } - } - } // end loop over cuts - } // end loop over MC signals - */ - } // end if (filterMap > 0) - - // count the number of associations per track - if (fConfigPublishAmbiguity && filterMap > 0) { - if (event.isEventSelected_bit(1)) { - // for this track, count the number of associated collisions with in-bunch pileup and out of bunch associations - if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { - std::vector evVector = {event.globalIndex()}; - fNAssocsInBunch[track.globalIndex()] = evVector; - } else { - auto& evVector = fNAssocsInBunch[track.globalIndex()]; - evVector.push_back(event.globalIndex()); - } - } else { - if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { - std::vector evVector = {event.globalIndex()}; - fNAssocsOutOfBunch[track.globalIndex()] = evVector; - } else { - auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; - evVector.push_back(event.globalIndex()); - } - } - } - } // end loop over associations - - // QA the collision-track associations - // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches - // So one could QA these tracks separately - if (fConfigPublishAmbiguity) { - if (fConfigQA) { - for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { - if (evIndices.size() == 1) { - continue; - } - auto track = tracks.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); - } // end loop over in-bunch ambiguous tracks - - for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { - if (evIndices.size() == 1) { - continue; - } - auto track = tracks.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); - } // end loop over out-of-bunch ambiguous tracks - } - - // publish the ambiguity table - for (auto& track : tracks) { - int8_t nInBunch = 0; - if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { - nInBunch = fNAssocsInBunch[track.globalIndex()].size(); - } - int8_t nOutOfBunch = 0; - if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { - nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); - } - trackAmbiguities(nInBunch, nOutOfBunch); - } - } - } // end runTrackSelection() - - void processSkimmed(ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) - { - runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); - } - void processSkimmedWithCov(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) - { - runTrackSelection(assocs, events, tracks, eventsMC, tracksMC); - } - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisTrackSelection, processSkimmed, "Run barrel track selection on DQ skimmed track associations", false); - PROCESS_SWITCH(AnalysisTrackSelection, processSkimmedWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); - PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); -}; - -// Produces a table with muon decisions (joinable to the ReducedMuonsAssociations) -// Here one should add all the track cuts needed through the workflow (e.g. cuts for same-event pairing, track for dilepton-track correlations) -struct AnalysisMuonSelection { - Produces muonSel; - Produces muonAmbiguities; - OutputObj fOutputList{"output"}; - - Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; - Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; - Configurable fConfigCcdbUrl{"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 fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - - Configurable fConfigMCSignals{"cfgMuonMCSignals", "", "Comma separated list of MC signals"}; - Configurable fConfigMCSignalsJSON{"cfgMuonMCsignalsJSON", "", "Additional list of MC signals via JSON"}; - - Service fCCDB; - - HistogramManager* fHistMan; - std::vector fMuonCuts; - std::vector fHistNamesReco; - std::vector fHistNamesMCMatched; - std::vector fMCSignals; // list of signals to be checked - - int fCurrentRun; // current run kept to detect run changes and trigger loading params from CCDB - - std::map> fNAssocsInBunch; // key: track global index, value: vector of global index for events associated in-bunch (events that have in-bunch pileup or splitting) - std::map> fNAssocsOutOfBunch; // key: track global index, value: vector of global index for events associated out-of-bunch (events that have no in-bunch pileup) - - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processDummy")) { - return; - } - VarManager::SetDefaultVarNames(); - - fCurrentRun = 0; - TString cutNamesStr = fConfigCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); - } - } - // Add cuts configured via JSON - TString addCutsStr = fConfigCutsJSON.value; - if (addCutsStr != "") { - std::vector addCuts = dqcuts::GetCutsFromJSON(addCutsStr.Data()); - for (auto& t : addCuts) { - fMuonCuts.push_back(reinterpret_cast(t)); - } - } - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - - TString configSigNamesStr = fConfigMCSignals.value; - std::unique_ptr sigNamesArray(configSigNamesStr.Tokenize(",")); - // Setting the MC signals - for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals - continue; - } - fMCSignals.push_back(sig); - } - } - // Add the MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals - continue; - } - fMCSignals.push_back(mcIt); - } - } - - if (fConfigQA) { - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - // Configure histogram classes for each track cut; - // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) - TString histClasses = "AssocsMuon_BeforeCuts;"; - for (auto& cut : fMuonCuts) { - TString nameStr = Form("AssocsMuon_%s", cut->GetName()); - fHistNamesReco.push_back(nameStr); - histClasses += Form("%s;", nameStr.Data()); - for (auto& sig : fMCSignals) { - TString nameStr2 = Form("AssocsCorrectMuon_%s_%s", cut->GetName(), sig->GetName()); - fHistNamesMCMatched.push_back(nameStr2); - histClasses += Form("%s;", nameStr2.Data()); - nameStr2 = Form("AssocsIncorrectMuon_%s_%s", cut->GetName(), sig->GetName()); - fHistNamesMCMatched.push_back(nameStr2); - histClasses += Form("%s;", nameStr2.Data()); - } - } - if (fConfigPublishAmbiguity) { - histClasses += "Muon_AmbiguityInBunch;Muon_AmbiguityOutOfBunch;"; - } - - DefineHistograms(fHistMan, histClasses.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(fConfigGeoPath); - } - } - - template - void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& muonsMC) - { - if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, events.begin().timestamp()); - if (grpmag != nullptr) { - o2::base::Propagator::initFieldFromGRP(grpmag); - VarManager::SetMagneticField(grpmag->getNominalL3Field()); - } else { - // LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp()); - // If the magnetic field is not found it is configured by had by the user - VarManager::SetMagneticField(fConfigMagField.value); - } - fCurrentRun = events.begin().runNumber(); - } - - fNAssocsInBunch.clear(); - fNAssocsOutOfBunch.clear(); - muonSel.reserve(assocs.size()); - - for (auto& assoc : assocs) { - auto event = assoc.template reducedevent_as(); - if (!event.isEventSelected_bit(0)) { - muonSel(0); - continue; - } - VarManager::ResetValues(0, VarManager::kNVars); - // fill event information which might be needed in histograms/cuts that combine track and event properties - VarManager::FillEvent(event); - VarManager::FillEvent(event.reducedMCevent()); - - auto track = assoc.template reducedmuon_as(); - VarManager::FillTrack(track); - - bool isCorrectAssoc = false; - if (track.has_reducedMCTrack()) { - auto trackMC = track.reducedMCTrack(); - auto eventMCfromTrack = trackMC.reducedMCevent(); - isCorrectAssoc = (eventMCfromTrack.globalIndex() == event.reducedMCevent().globalIndex()); - VarManager::FillTrackMC(muonsMC, trackMC); - } - - if (fConfigQA) { - fHistMan->FillHistClass("AssocsMuon_BeforeCuts", VarManager::fgValues); - } - - int iCut = 0; - uint32_t filterMap = static_cast(0); - for (auto cut = fMuonCuts.begin(); cut != fMuonCuts.end(); cut++, iCut++) { - if ((*cut)->IsSelected(VarManager::fgValues)) { - filterMap |= (static_cast(1) << iCut); - if (fConfigQA) { - fHistMan->FillHistClass(fHistNamesReco[iCut].Data(), VarManager::fgValues); - } - } - } // end loop over cuts - muonSel(filterMap); - muonAmbiguities.reserve(muons.size()); - - // if no filter fulfilled, continue - if (!filterMap) { - continue; - } - - // everything below is related to filling QA histograms - if (!fConfigQA) { - continue; - } - - // compute MC matching decisions - uint32_t mcDecision = static_cast(0); - int isig = 0; - for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) { - if constexpr ((TMuonFillMap & VarManager::ObjTypes::ReducedMuon) > 0) { - if (track.has_reducedMCTrack()) { - if ((*sig)->CheckSignal(true, track.reducedMCTrack())) { - mcDecision |= (static_cast(1) << isig); - } - } - } - } - - // fill histograms - for (unsigned int i = 0; i < fMCSignals.size(); i++) { - if (!(mcDecision & (static_cast(1) << i))) { - continue; - } - for (unsigned int j = 0; j < fMuonCuts.size(); j++) { - if (filterMap & (static_cast(1) << j)) { - if (isCorrectAssoc) { - fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(fHistNamesMCMatched[j * 2 * fMCSignals.size() + 2 * i + 1].Data(), VarManager::fgValues); - } - } - } // end loop over cuts - } // end loop over MC signals - - // count the number of associations per track - if (fConfigPublishAmbiguity && filterMap > 0) { - if (event.isEventSelected_bit(1)) { - if (fNAssocsInBunch.find(track.globalIndex()) == fNAssocsInBunch.end()) { - std::vector evVector = {event.globalIndex()}; - fNAssocsInBunch[track.globalIndex()] = evVector; - } else { - auto& evVector = fNAssocsInBunch[track.globalIndex()]; - evVector.push_back(event.globalIndex()); - } - } else { - if (fNAssocsOutOfBunch.find(track.globalIndex()) == fNAssocsOutOfBunch.end()) { - std::vector evVector = {event.globalIndex()}; - fNAssocsOutOfBunch[track.globalIndex()] = evVector; - } else { - auto& evVector = fNAssocsOutOfBunch[track.globalIndex()]; - evVector.push_back(event.globalIndex()); - } - } - } - } // end loop over assocs - - // QA the collision-track associations - // TODO: some tracks can be associated to both collisions that have in bunch pileup and collisions from different bunches - // So one could QA these tracks separately - if (fConfigPublishAmbiguity) { - for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { - if (evIndices.size() == 1) { - continue; - } - auto track = muons.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kMuonNAssocsInBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("Muon_AmbiguityInBunch", VarManager::fgValues); - } // end loop over in-bunch ambiguous tracks - - for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { - if (evIndices.size() == 1) { - continue; - } - auto track = muons.rawIteratorAt(trackIdx); - VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillTrack(track); - VarManager::fgValues[VarManager::kMuonNAssocsOutOfBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("Muon_AmbiguityOutOfBunch", VarManager::fgValues); - } // end loop over out-of-bunch ambiguous tracks - - // publish the ambiguity table - for (auto& track : muons) { - int8_t nInBunch = 0; - if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { - nInBunch = fNAssocsInBunch[track.globalIndex()].size(); - } - int8_t nOutOfBunch = 0; - if (fNAssocsOutOfBunch.find(track.globalIndex()) != fNAssocsOutOfBunch.end()) { - nOutOfBunch = fNAssocsOutOfBunch[track.globalIndex()].size(); - } - muonAmbiguities(nInBunch, nOutOfBunch); - } - } - } - - void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsSelected const& events, MyMuonTracks const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) - { - runMuonSelection(assocs, events, muons, eventsMC, tracksMC); - } - void processSkimmedWithCov(ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons, ReducedMCEvents const& eventsMC, ReducedMCTracks const& tracksMC) - { - runMuonSelection(assocs, events, muons, eventsMC, tracksMC); - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisMuonSelection, processSkimmed, "Run muon selection on DQ skimmed muons", false); - PROCESS_SWITCH(AnalysisMuonSelection, processSkimmedWithCov, "Run muon selection on DQ skimmed muons, with event and track covariances", false); - PROCESS_SWITCH(AnalysisMuonSelection, processDummy, "Dummy function", true); -}; - -// Run the prefilter selection (e.g. electron prefiltering for photon conversions) -// This takes uses a sample of tracks selected with loose cuts (fConfigPrefilterTrackCut) and combines them -// with the sample of tracks to be used in downstream analysis (fConfigTrackCuts). If a pair is found to pass -// the pair prefilter cut (cfgPrefilterPairCut), the analysis track is tagged to be removed from analysis. -// TODO: Add optional QA histograms -struct AnalysisPrefilterSelection { - Produces prefilter; // joinable with ReducedTracksAssoc - - // Configurables - Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; - Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; - // Track related options - Configurable fPropTrack{"cfgPropTrack", false, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; - - std::map fPrefilterMap; - AnalysisCompositeCut* fPairCut; - uint32_t fPrefilterMask; - int fPrefilterCutBit; - - Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processDummy")) { - return; - } - - bool runPrefilter = true; - // get the list of track cuts to be prefiltered - TString trackCutsStr = fConfigTrackCuts.value; - TObjArray* objArrayTrackCuts = nullptr; - if (!trackCutsStr.IsNull()) { - objArrayTrackCuts = trackCutsStr.Tokenize(","); - if (objArrayTrackCuts == nullptr) { - runPrefilter = false; - } - } else { - LOG(warn) << " No track cuts to prefilter! Prefilter will not be run"; - runPrefilter = false; - } - // get the cut to be used as loose selection - TString prefilterTrackCutStr = fConfigPrefilterTrackCut.value; - if (prefilterTrackCutStr.IsNull()) { - LOG(warn) << " No prefilter loose selection specified! Prefilter will not be run"; - runPrefilter = false; - } - - fPrefilterMask = 0; - fPrefilterCutBit = -1; - if (runPrefilter) { - // get the list of cuts that were computed in the barrel track-selection task and create a bit mask - // to mark just the ones we want to apply a prefilter on - string trackCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); - TString allTrackCutsStr = trackCuts; - // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); - TString addTrackCutsStr = trackCuts; - if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { - allTrackCutsStr += Form(",%s", t->GetName()); - } - } - - std::unique_ptr objArray(allTrackCutsStr.Tokenize(",")); - if (objArray == nullptr) { - LOG(fatal) << " Not getting any track cuts from the barrel-track-selection "; - } - if (objArray->FindObject(prefilterTrackCutStr.Data()) == nullptr) { - LOG(fatal) << " Prefilter track cut not among the cuts calculated by the track-selection task! "; - } - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - TString tempStr = objArray->At(icut)->GetName(); - if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { - fPrefilterMask |= (static_cast(1) << icut); - } - if (tempStr.CompareTo(fConfigPrefilterTrackCut.value) == 0) { - fPrefilterCutBit = icut; - } - } - // setup the prefilter pair cut - fPairCut = new AnalysisCompositeCut(true); - TString pairCutStr = fConfigPrefilterPairCut.value; - if (!pairCutStr.IsNull()) { - fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); - } - } - if (fPrefilterMask == static_cast(0) || fPrefilterCutBit < 0) { - LOG(warn) << "No specified loose cut or track cuts for prefiltering. This task will do nothing."; - } - - VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill - VarManager::SetDefaultVarNames(); - - VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); - } - - template - void runPrefilter(TEvent const& event, soa::Join const& assocs, TTracks const& /*tracks*/) - { - if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { - return; - } - - for (auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { - auto track1 = assoc1.template reducedtrack_as(); - auto track2 = assoc2.template reducedtrack_as(); - - // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made - // a configurable and check also same-sign pairs (track splitting) - if (track1.sign() * track2.sign() > 0) { - continue; - } - - // here we check the cuts fulfilled by both tracks, for both the tight and loose selections - uint32_t track1Candidate = (assoc1.isBarrelSelected_raw() & fPrefilterMask); - uint32_t track2Candidate = (assoc2.isBarrelSelected_raw() & fPrefilterMask); - bool track1Loose = assoc1.isBarrelSelected_bit(fPrefilterCutBit); - bool track2Loose = assoc2.isBarrelSelected_bit(fPrefilterCutBit); - - if (!((track1Candidate > 0 && track2Loose) || (track2Candidate > 0 && track1Loose))) { - continue; - } - - // compute pair quantities - VarManager::FillPair(track1, track2); - if (fPropTrack) { - VarManager::FillPairCollision(event, track1, track2); - } - // if the pair fullfils the criteria, add an entry into the prefilter map for the two tracks - if (fPairCut->IsSelected(VarManager::fgValues)) { - if (fPrefilterMap.find(track1.globalIndex()) == fPrefilterMap.end() && track1Candidate > 0) { - fPrefilterMap[track1.globalIndex()] = track1Candidate; - } - if (fPrefilterMap.find(track2.globalIndex()) == fPrefilterMap.end() && track2Candidate > 0) { - fPrefilterMap[track2.globalIndex()] = track2Candidate; - } - } - } // end loop over combinations - } - - void processBarrelSkimmed(MyEvents const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) - { - - fPrefilterMap.clear(); - - for (auto& event : events) { - auto groupedAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); - if (groupedAssocs.size() > 1) { - runPrefilter(event, groupedAssocs, tracks); - } - } - - uint32_t mymap = -1; - // If cuts were not configured, then produce a map with all 1's and publish it for all associations - if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { - for (int i = 0; i < assocs.size(); ++i) { - prefilter(mymap); - } - } else { - for (auto& assoc : assocs) { - // TODO: just use the index from the assoc (no need to cast the whole track) - auto track = assoc.template reducedtrack_as(); - mymap = -1; - if (fPrefilterMap.find(track.globalIndex()) != fPrefilterMap.end()) { - // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else - mymap = ~fPrefilterMap[track.globalIndex()]; - prefilter(mymap); - } else { - prefilter(mymap); // track did not pass the prefilter selections, so publish just 1's - } - } - } - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisPrefilterSelection, processBarrelSkimmed, "Run Prefilter selection on reduced tracks", false); - PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true); -}; - -// Run the same-event pairing -// This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel) -// Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations -// TODO: implement properly the barrel-muon combinations -// The task implements also process functions for running event mixing -struct AnalysisSameEventPairing { - - Produces dielectronList; - Produces dimuonList; - Produces dielectronsExtraList; - Produces dielectronInfoList; - Produces dielectronAllList; - Produces dimuonsExtraList; - Produces dimuonAllList; - Produces dileptonMiniTreeGen; - Produces dileptonMiniTreeRec; - Produces dileptonInfoList; - Produces PromptNonPromptSepTable; - Produces MCTruthTableEffi; - - o2::base::MatLayerCylSet* fLUT = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - - OutputObj fOutputList{"output"}; - - struct : ConfigurableGroup { - Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; - Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts, !!! Use only if you know what you are doing, otherwise leave empty"}; - Configurable MCgenAcc{"cfgMCGenAccCut", "", "cut for MC generated particles acceptance"}; - // TODO: Add pair cuts via JSON - } fConfigCuts; - - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - - struct : ConfigurableGroup { - Configurable url{"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 lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - } fConfigCCDB; - - struct : ConfigurableGroup { - Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; - Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; - Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; - Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; - Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; - Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; - } fConfigOptions; - - struct : ConfigurableGroup { - Configurable genSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable genSignalsJSON{"cfgMCGenSignalsJSON", "", "Additional list of MC signals (generated) via JSON"}; - Configurable recSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable recSignalsJSON{"cfgMCRecSignalsJSON", "", "Comma separated list of MC signals (reconstructed) via JSON"}; - Configurable skimSignalOnly{"cfgSkimSignalOnly", false, "Configurable to select only matched candidates"}; - } fConfigMC; - - struct : ConfigurableGroup { - Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; - Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; - Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; - } useMiniTree; - - // Track related options - Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; - - Service fCCDB; - - // Filter filterEventSelected = aod::dqanalysisflags::isEventSelected & uint32_t(1); - Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - - HistogramManager* fHistMan; - - // keep histogram class names in maps, so we don't have to buld their names in the pair loops - std::map> fTrackHistNames; - std::map> fBarrelHistNamesMCmatched; - std::map> fMuonHistNames; - std::map> fMuonHistNamesMCmatched; - std::vector fRecMCSignals; - std::vector fGenMCSignals; - - std::vector fPairCuts; - AnalysisCompositeCut fMCGenAccCut; - bool fUseMCGenAccCut = false; - - uint32_t fTrackFilterMask; // mask for the track cuts required in this task to be applied on the barrel cuts produced upstream - uint32_t fMuonFilterMask; // mask for the muon cuts required in this task to be applied on the muon cuts produced upstream - int fNCutsBarrel; - int fNCutsMuon; - int fNPairCuts; - bool fHasTwoProngGenMCsignals = false; - - bool fEnableBarrelHistos; - bool fEnableMuonHistos; - - Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice> muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - - void init(o2::framework::InitContext& context) - { - if (context.mOptions.get("processDummy")) { - return; - } - bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithGrouping") || context.mOptions.get("processBarrelOnlySkimmed"); - VarManager::SetDefaultVarNames(); - - fEnableBarrelHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processBarrelOnlySkimmed") || context.mOptions.get("processBarrelOnlyWithCollSkimmed"); - fEnableMuonHistos = context.mOptions.get("processAllSkimmed") || context.mOptions.get("processMuonOnlySkimmed"); - - // Keep track of all the histogram class names to avoid composing strings in the pairing loop - TString histNames = ""; - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); - } - } - - // get the list of cuts for tracks/muons, check that they were played by the barrel/muon selection tasks - // and make a mask for active cuts (barrel and muon selection tasks may run more cuts, needed for other analyses) - TString trackCutsStr = fConfigCuts.track.value; - TObjArray* objArrayTrackCuts = nullptr; - if (!trackCutsStr.IsNull()) { - objArrayTrackCuts = trackCutsStr.Tokenize(","); - } - TString muonCutsStr = fConfigCuts.muon.value; - TObjArray* objArrayMuonCuts = nullptr; - if (!muonCutsStr.IsNull()) { - objArrayMuonCuts = muonCutsStr.Tokenize(","); - } - - // Setting the MC rec signal names - TString sigNamesStr = fConfigMC.recSignals.value; - std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); - for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required - continue; - } - fRecMCSignals.push_back(sig); - } - } - - // Add the MCSignals from the JSON config - TString addMCSignalsStr = fConfigMC.recSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != 2) { // NOTE: only 2 prong signals - continue; - } - fRecMCSignals.push_back(mcIt); - } - } - - // get the barrel track selection cuts - string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); - TString tempCutsStr = tempCuts; - // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); - TString addTrackCutsStr = tempCuts; - if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { - tempCutsStr += Form(",%s", t->GetName()); - } - } - - // get the mc generated acceptance cut - TString mcGenAccCutStr = fConfigCuts.MCgenAcc.value; - if (mcGenAccCutStr != "") { - AnalysisCut* cut = dqcuts::GetAnalysisCut(mcGenAccCutStr.Data()); - if (cut != nullptr) { - fMCGenAccCut.AddCut(cut); - } - fUseMCGenAccCut = true; - } - - // check that the barrel track cuts array required in this task is not empty - if (!trackCutsStr.IsNull()) { - // tokenize and loop over the barrel cuts produced by the barrel track selection task - std::unique_ptr objArray(tempCutsStr.Tokenize(",")); - fNCutsBarrel = objArray->GetEntries(); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - TString tempStr = objArray->At(icut)->GetName(); - // if the current barrel selection cut is required in this task, then switch on the corresponding bit in the mask - // and assign histogram directories - if (objArrayTrackCuts->FindObject(tempStr.Data()) != nullptr) { - fTrackFilterMask |= (static_cast(1) << icut); - - if (fEnableBarrelHistos) { - // assign the pair hist directories for the current cut - std::vector names = { - Form("PairsBarrelSEPM_%s", objArray->At(icut)->GetName()), - Form("PairsBarrelSEPP_%s", objArray->At(icut)->GetName()), - Form("PairsBarrelSEMM_%s", objArray->At(icut)->GetName())}; - if (fConfigQA) { - // assign separate hist directories for ambiguous tracks - names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsBarrelSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsBarrelSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsBarrelSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsBarrelSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - } - for (auto& n : names) { - histNames += Form("%s;", n.Data()); - } - fTrackHistNames[icut] = names; - - // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination - // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only - // if you know what you are doing. - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - fNPairCuts = objArrayPair->GetEntries(); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - names = { - Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), - Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), - Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; - histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); - // NOTE: In the numbering scheme for the map key, we use the number of barrel cuts in the barrel-track selection task - fTrackHistNames[fNCutsBarrel + icut * fNPairCuts + iPairCut] = names; - } // end loop (pair cuts) - } // end if (pair cuts) - - // assign hist directories for the MC matched pairs for each (track cut,MCsignal) combination - if (!sigNamesStr.IsNull()) { - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - auto sig = fRecMCSignals.at(isig); - names = { - Form("PairsBarrelSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), - Form("PairsBarrelSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), - Form("PairsBarrelSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName())}; - if (fConfigQA) { - names.push_back(Form("PairsBarrelSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - } - for (auto& n : names) { - histNames += Form("%s;", n.Data()); - } - fBarrelHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); - } // end loop over MC signals - } - } // end if enableBarrelHistos - } - } - } - - // get the muon track selection cuts - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); - tempCutsStr = tempCuts; - // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); - TString addMuonCutsStr = tempCuts; - if (addMuonCutsStr != "") { - std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); - for (auto& t : addMuonCuts) { - tempCutsStr += Form(",%s", t->GetName()); - } - } - - // check that in this task we have specified muon cuts - if (!muonCutsStr.IsNull()) { - // loop over the muon cuts computed by the muon selection task and build a filter mask for those required in this task - std::unique_ptr objArray(tempCutsStr.Tokenize(",")); - fNCutsMuon = objArray->GetEntries(); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - TString tempStr = objArray->At(icut)->GetName(); - if (objArrayMuonCuts->FindObject(tempStr.Data()) != nullptr) { - // update the filter mask - fMuonFilterMask |= (static_cast(1) << icut); - - if (fEnableMuonHistos) { - // assign pair hist directories for each required muon cut - std::vector names = { - Form("PairsMuonSEPM_%s", objArray->At(icut)->GetName()), - Form("PairsMuonSEPP_%s", objArray->At(icut)->GetName()), - Form("PairsMuonSEMM_%s", objArray->At(icut)->GetName())}; - if (fConfigQA) { - // assign separate hist directories for ambiguous tracks - names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsMuonSEPP_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsMuonSEMM_ambiguousInBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsMuonSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - names.push_back(Form("PairsMuonSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); - } - for (auto& n : names) { - histNames += Form("%s;", n.Data()); - } - fMuonHistNames[icut] = names; - - // if there are specified pair cuts, assign hist dirs for each muon cut - pair cut combination - TString cutNamesStr = fConfigCuts.pair.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - fNPairCuts = objArrayPair->GetEntries(); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - names = { - Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), - Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName()), - Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), objArrayPair->At(iPairCut)->GetName())}; - histNames += Form("%s;%s;%s;", names[0].Data(), names[1].Data(), names[2].Data()); - fMuonHistNames[fNCutsMuon + icut * fNCutsMuon + iPairCut] = names; - } // end loop (pair cuts) - } // end if (pair cuts) - - // assign hist directories for pairs matched to MC signals for each (muon cut, MCrec signal) combination - if (!sigNamesStr.IsNull()) { - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - auto sig = fRecMCSignals.at(isig); - names = { - Form("PairsMuonSEPM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), - Form("PairsMuonSEPP_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), - Form("PairsMuonSEMM_%s_%s", objArray->At(icut)->GetName(), sig->GetName()), - }; - if (fConfigQA) { - names.push_back(Form("PairsMuonSEPMCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPMIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousInBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousInBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousInBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunch_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - names.push_back(Form("PairsMuonSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); - } - for (auto& n : names) { - histNames += Form("%s;", n.Data()); - } - fMuonHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); - } // end loop over MC signals - } - } - } - } // end loop over cuts - } // end if (muonCutsStr) - - // Add histogram classes for each specified MCsignal at the generator level - // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function - TString sigGenNamesStr = fConfigMC.genSignals.value; - std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); - for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); - if (sig) { - fGenMCSignals.push_back(sig); - } - } - - // Add the MCSignals from the JSON config - TString addMCSignalsGenStr = fConfigMC.genSignalsJSON.value; - if (addMCSignalsGenStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() > 2) { // NOTE: only 2 prong signals - continue; - } - fGenMCSignals.push_back(mcIt); - } - } - - if (isMCGen) { - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() == 1) { - histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function - histNames += Form("MCTruthGenSel_%s;", sig->GetName()); - } else if (sig->GetNProngs() == 2) { - histNames += Form("MCTruthGenPair_%s;", sig->GetName()); - histNames += Form("MCTruthGenPairSel_%s;", sig->GetName()); - fHasTwoProngGenMCsignals = true; - } - } - } - - fCurrentRun = 0; - - fCCDB->setURL(fConfigCCDB.url.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - - if (fConfigOptions.noCorr) { - VarManager::SetupFwdDCAFitterNoCorr(); - } else if (fConfigOptions.corrFullGeo || (fConfigOptions.useKFVertexing && fConfigOptions.propToPCA)) { - if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(fConfigCCDB.geoPath); - } - } else { - fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigCCDB.lutPath)); - VarManager::SetupMatLUTFwdDCAFitter(fLUT); - } - - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy - - DefineHistograms(fHistMan, histNames.Data(), fConfigAddSEPHistogram.value.data()); // define all histograms - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - void initParamsFromCCDB(uint64_t timestamp, bool withTwoProngFitter = true) - { - if (fConfigOptions.useRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); - float magField = 0.0; - if (grpmag != nullptr) { - magField = grpmag->getNominalL3Field(); - } else { - LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); - } - if (withTwoProngFitter) { - if (fConfigOptions.useKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(magField); - } else { - VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(magField, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); - } - } else { - VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations - } - } else { - if (withTwoProngFitter) { - if (fConfigOptions.useKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(fConfigOptions.magField.value); - } else { - VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // TODO: get these parameters from Configurables - VarManager::SetupTwoProngFwdDCAFitter(fConfigOptions.magField.value, true, 200.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); - } - } else { - VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations - } - } - } - - // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) - template - void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - if (fCurrentRun != events.begin().runNumber()) { - initParamsFromCCDB(events.begin().timestamp(), TTwoProngFitter); - fCurrentRun = events.begin().runNumber(); - } - - TString cutNames = fConfigCuts.track.value; - std::map> histNames = fTrackHistNames; - std::map> histNamesMC = fBarrelHistNamesMCmatched; - int ncuts = fNCutsBarrel; - if constexpr (TPairType == VarManager::kDecayToMuMu) { - cutNames = fConfigCuts.muon.value; - histNames = fMuonHistNames; - histNamesMC = fMuonHistNamesMCmatched; - ncuts = fNCutsMuon; - } - - uint32_t twoTrackFilter = static_cast(0); - int sign1 = 0; - int sign2 = 0; - uint32_t mcDecision = static_cast(0); - bool isCorrectAssoc_leg1 = false; - bool isCorrectAssoc_leg2 = false; - dielectronList.reserve(1); - dimuonList.reserve(1); - dielectronsExtraList.reserve(1); - dimuonsExtraList.reserve(1); - dielectronInfoList.reserve(1); - dileptonInfoList.reserve(1); - if (fConfigOptions.flatTables.value) { - dielectronAllList.reserve(1); - dimuonAllList.reserve(1); - } - if (useMiniTree.fConfigMiniTree) { - dileptonMiniTreeGen.reserve(1); - dileptonMiniTreeRec.reserve(1); - } - constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::ReducedEventQvector) > 0); - constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); - - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - uint8_t evSel = event.isEventSelected_raw(); - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); - VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); - - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - if (groupedAssocs.size() == 0) { - continue; - } - - for (auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { - - if constexpr (TPairType == VarManager::kDecayToEE) { - twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; - - if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue - continue; - } - - auto t1 = a1.template reducedtrack_as(); - auto t2 = a2.template reducedtrack_as(); - sign1 = t1.sign(); - sign2 = t2.sign(); - // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter - if (t1.barrelAmbiguityInBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 28); - } - if (t2.barrelAmbiguityInBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 29); - } - if (t1.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 30); - } - if (t2.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 31); - } - - // run MC matching for this pair - int isig = 0; - mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= (static_cast(1) << isig); - } - } - } // end loop over MC signals - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); - isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); - } - - VarManager::FillPair(t1, t2); - if (fPropTrack) { - VarManager::FillPairCollision(event, t1, t2); - } - if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); - } - if constexpr (eventHasQvector) { - VarManager::FillPairVn(t1, t2); - } - if (!fConfigMC.skimSignalOnly || (fConfigMC.skimSignalOnly && mcDecision > 0)) { - dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, mcDecision); - - if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { - dielectronInfoList(t1.collisionId(), t1.trackId(), t2.trackId()); - dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); - } - if constexpr (trackHasCov && TTwoProngFitter) { - dielectronsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); - if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedTrackCollInfo) > 0) { - if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - dielectronAllList(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), twoTrackFilter, mcDecision, - t1.pt(), t1.eta(), t1.phi(), t1.itsClusterMap(), t1.itsChi2NCl(), t1.tpcNClsCrossedRows(), t1.tpcNClsFound(), t1.tpcChi2NCl(), t1.dcaXY(), t1.dcaZ(), t1.tpcSignal(), t1.tpcNSigmaEl(), t1.tpcNSigmaPi(), t1.tpcNSigmaPr(), t1.beta(), t1.tofNSigmaEl(), t1.tofNSigmaPi(), t1.tofNSigmaPr(), - t2.pt(), t2.eta(), t2.phi(), t2.itsClusterMap(), t2.itsChi2NCl(), t2.tpcNClsCrossedRows(), t2.tpcNClsFound(), t2.tpcChi2NCl(), t2.dcaXY(), t2.dcaZ(), t2.tpcSignal(), t2.tpcNSigmaEl(), t2.tpcNSigmaPi(), t2.tpcNSigmaPr(), t2.beta(), t2.tofNSigmaEl(), t2.tofNSigmaPi(), t2.tofNSigmaPr(), - VarManager::fgValues[VarManager::kKFTrack0DCAxyz], VarManager::fgValues[VarManager::kKFTrack1DCAxyz], VarManager::fgValues[VarManager::kKFDCAxyzBetweenProngs], VarManager::fgValues[VarManager::kKFTrack0DCAxy], VarManager::fgValues[VarManager::kKFTrack1DCAxy], VarManager::fgValues[VarManager::kKFDCAxyBetweenProngs], - VarManager::fgValues[VarManager::kKFTrack0DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationFromPV], VarManager::fgValues[VarManager::kKFTrack0DeviationxyFromPV], VarManager::fgValues[VarManager::kKFTrack1DeviationxyFromPV], - VarManager::fgValues[VarManager::kKFMass], VarManager::fgValues[VarManager::kKFChi2OverNDFGeo], VarManager::fgValues[VarManager::kVertexingLxyz], VarManager::fgValues[VarManager::kVertexingLxyzOverErr], VarManager::fgValues[VarManager::kVertexingLxy], VarManager::fgValues[VarManager::kVertexingLxyOverErr], VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], VarManager::fgValues[VarManager::kKFCosPA], VarManager::fgValues[VarManager::kKFJpsiDCAxyz], VarManager::fgValues[VarManager::kKFJpsiDCAxy], - VarManager::fgValues[VarManager::kKFPairDeviationFromPV], VarManager::fgValues[VarManager::kKFPairDeviationxyFromPV], - VarManager::fgValues[VarManager::kKFMassGeoTop], VarManager::fgValues[VarManager::kKFChi2OverNDFGeoTop], - VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjected], - VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); - } - } - } - } - } - - if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; - if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue - continue; - } - auto t1 = a1.template reducedmuon_as(); - auto t2 = a2.template reducedmuon_as(); - if (t1.matchMCHTrackId() == t2.matchMCHTrackId() && t1.matchMCHTrackId() >= 0) - continue; - if (t1.matchMFTTrackId() == t2.matchMFTTrackId() && t1.matchMFTTrackId() >= 0) - continue; - sign1 = t1.sign(); - sign2 = t2.sign(); - // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter - if (t1.muonAmbiguityInBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 28); - } - if (t2.muonAmbiguityInBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 29); - } - if (t1.muonAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 30); - } - if (t2.muonAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= (static_cast(1) << 31); - } - - // run MC matching for this pair - int isig = 0; - mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= (static_cast(1) << isig); - } - } - } // end loop over MC signals - - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - isCorrectAssoc_leg1 = (t1.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); - isCorrectAssoc_leg2 = (t2.reducedMCTrack().reducedMCevent() == event.reducedMCevent()); - } - - VarManager::FillPair(t1, t2); - if (fPropTrack) { - VarManager::FillPairCollision(event, t1, t2); - } - if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigOptions.propToPCA); - } - if constexpr (eventHasQvector) { - VarManager::FillPairVn(t1, t2); - } - - dimuonList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, mcDecision); - if constexpr ((TTrackFillMap & VarManager::ObjTypes::ReducedMuonCollInfo) > 0) { - dileptonInfoList(t1.collisionId(), event.posX(), event.posY(), event.posZ()); - } - - if constexpr (TTwoProngFitter) { - dimuonsExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingLz], VarManager::fgValues[VarManager::kVertexingLxy]); - if (fConfigOptions.flatTables.value && t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - dimuonAllList(event.posX(), event.posY(), event.posZ(), event.numContrib(), - event.selection_raw(), evSel, - event.reducedMCevent().mcPosX(), event.reducedMCevent().mcPosY(), event.reducedMCevent().mcPosZ(), - VarManager::fgValues[VarManager::kMass], - mcDecision, - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), VarManager::fgValues[VarManager::kVertexingChi2PCA], - VarManager::fgValues[VarManager::kVertexingTauz], VarManager::fgValues[VarManager::kVertexingTauzErr], - VarManager::fgValues[VarManager::kVertexingTauxy], VarManager::fgValues[VarManager::kVertexingTauxyErr], - VarManager::fgValues[VarManager::kCosPointingAngle], - VarManager::fgValues[VarManager::kPt1], VarManager::fgValues[VarManager::kEta1], VarManager::fgValues[VarManager::kPhi1], t1.sign(), - VarManager::fgValues[VarManager::kPt2], VarManager::fgValues[VarManager::kEta2], VarManager::fgValues[VarManager::kPhi2], t2.sign(), - t1.fwdDcaX(), t1.fwdDcaY(), t2.fwdDcaX(), t2.fwdDcaY(), - t1.mcMask(), t2.mcMask(), - t1.chi2MatchMCHMID(), t2.chi2MatchMCHMID(), - t1.chi2MatchMCHMFT(), t2.chi2MatchMCHMFT(), - t1.chi2(), t2.chi2(), - t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), t1.reducedMCTrack().e(), - t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), t2.reducedMCTrack().e(), - t1.reducedMCTrack().vx(), t1.reducedMCTrack().vy(), t1.reducedMCTrack().vz(), t1.reducedMCTrack().vt(), - t2.reducedMCTrack().vx(), t2.reducedMCTrack().vy(), t2.reducedMCTrack().vz(), t2.reducedMCTrack().vt(), - (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)), (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)), - -999.0, -999.0, -999.0, -999.0, -999.0, - -999.0, -999.0, -999.0, -999.0, -999.0, - -999.0, VarManager::fgValues[VarManager::kMultDimuons], - VarManager::fgValues[VarManager::kVertexingPz], VarManager::fgValues[VarManager::kVertexingSV]); - } - } - } - // TODO: the model for the electron-muon combination has to be thought through - /*if constexpr (TPairType == VarManager::kElectronMuon) { - twoTrackFilter = a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isMuonSelected_raw() & fTwoTrackFilterMask; - }*/ - - // Fill histograms - bool isAmbiInBunch = false; - bool isAmbiOutOfBunch = false; - bool isCorrect_pair = false; - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) - isCorrect_pair = true; - - for (int icut = 0; icut < ncuts; icut++) { - if (twoTrackFilter & (static_cast(1) << icut)) { - isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); - isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kRap], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], isAmbiInBunch, isAmbiOutOfBunch, isCorrect_pair, VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][0].Data(), VarManager::fgValues); // matched signal - if (useMiniTree.fConfigMiniTree) { - if constexpr (TPairType == VarManager::kDecayToMuMu) { - twoTrackFilter = a1.isMuonSelected_raw() & a2.isMuonSelected_raw() & fMuonFilterMask; - if (!twoTrackFilter) { // the tracks must have at least one filter bit in common to continue - continue; - } - auto t1 = a1.template reducedmuon_as(); - auto t2 = a2.template reducedmuon_as(); - - float dileptonMass = VarManager::fgValues[VarManager::kMass]; - if (dileptonMass > useMiniTree.fConfigMiniTreeMinMass && dileptonMass < useMiniTree.fConfigMiniTreeMaxMass) { - // In the miniTree the positive daughter is positioned as first - if (t1.sign() > 0) { - dileptonMiniTreeRec(mcDecision, - VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], - t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), - t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), - t1.pt(), t1.eta(), t1.phi(), - t2.pt(), t2.eta(), t2.phi()); - } else { - dileptonMiniTreeRec(mcDecision, - VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kCentFT0C], - t2.reducedMCTrack().pt(), t2.reducedMCTrack().eta(), t2.reducedMCTrack().phi(), - t1.reducedMCTrack().pt(), t1.reducedMCTrack().eta(), t1.reducedMCTrack().phi(), - t2.pt(), t2.eta(), t2.phi(), - t1.pt(), t1.eta(), t1.phi()); - } - } - } - } - if (fConfigQA) { - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), VarManager::fgValues); - } else { // incorrect track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), VarManager::fgValues); - } - if (isAmbiInBunch) { // ambiguous in bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), VarManager::fgValues); - } - } - if (isAmbiOutOfBunch) { // ambiguous out of bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), VarManager::fgValues); - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), VarManager::fgValues); - } - } - } - } - if (fConfigQA) { - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); - } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), VarManager::fgValues); - } - } - } - } else { - if (sign1 > 0) { // ++ pairs - fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); - } - } - if (fConfigQA) { - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); - } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), VarManager::fgValues); - } - } - } else { // -- pairs - fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); - } - } - if (fConfigQA) { - if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); - } - if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), VarManager::fgValues); - } - } - } - } - for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { - AnalysisCompositeCut cut = fPairCuts.at(iPairCut); - if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts - continue; - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][0].Data(), VarManager::fgValues); - } else { - if (sign1 > 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][1].Data(), VarManager::fgValues); - } else { - fHistMan->FillHistClass(histNames[ncuts + icut * ncuts + iPairCut][2].Data(), VarManager::fgValues); - } - } - } // end loop (pair cuts) - } - } // end loop (cuts) - } // end loop over pairs of track associations - } // end loop over events - } - - PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; - - template - void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - uint32_t mcDecision = 0; - int isig = 0; - - for (auto& mctrack : mcTracks) { - VarManager::FillTrackMC(mcTracks, mctrack); - // if we have a mc generated acceptance cut, apply it here - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - // Fill Generated histograms taking into account selected collisions - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - for (auto& track : mcTracks) { - if (track.reducedMCeventId() != event.reducedMCeventId()) { - continue; - } - VarManager::FillTrackMC(mcTracks, track); - // if we have a mc generated acceptance cut, apply it here - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); - - if (useMiniTree.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); - } - } - isig++; - } - } - } // end loop over reconstructed events - - if (fHasTwoProngGenMCsignals) { - for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - VarManager::FillPairMC(t1, t2); - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS - if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - VarManager::FillPairMC(t1, t2); - if (fUseMCGenAccCut) { - if (!fMCGenAccCut.IsSelected(VarManager::fgValues)) { - continue; - } - } - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - // WARNING! To be checked - dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); - } - } - isig++; - } - } - } - } // end loop over reconstructed events - } - } - - void processAllSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); - // Feature replaced by processMCGen - /*if (fConfigMC.runMCGenPair) { - runMCGen(mcEvents, mcTracks); - }*/ - // runSameEventPairing(event, tracks, muons); - } - - void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - runMCGenWithGrouping(events, mcEvents, mcTracks); - } - - void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - // Feature replaced by processMCGen - /* if (fConfigMC.runMCGenPair) { - runMCGen(mcEvents, mcTracks); - }*/ - } - - void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons, mcEvents, mcTracks); - // Feature replaced by processMCGen - /* if (fConfigMC.runMCGenPair) { - runMCGen(mcEvents, mcTracks); - }*/ - } - - PresliceUnsorted perReducedMcGenEvent = aod::reducedtrackMC::reducedMCeventId; - - void processMCGen(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - // Fill Generated histograms taking into account all generated tracks - uint32_t mcDecision = 0; - int isig = 0; - - for (auto& mctrack : mcTracks) { - VarManager::FillTrackMC(mcTracks, mctrack); - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - - // Fill Generated histograms taking into account selected collisions - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - VarManager::FillEvent(event, VarManager::fgValues); - VarManager::FillEvent(event.reducedMCevent(), VarManager::fgValues); - // auto groupedMCTracks = mcTracks.sliceBy(perReducedMcGenEvent, event.reducedMCeventId()); - // groupedMCTracks.bindInternalIndicesTo(&mcTracks); - // for (auto& track : groupedMCTracks) { - for (auto& track : mcTracks) { - if (track.reducedMCeventId() != event.reducedMCeventId()) { - continue; - } - VarManager::FillTrackMC(mcTracks, track); - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - // auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); - - if (useMiniTree.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); - } - } - isig++; - } - } - } // end loop over reconstructed events - if (fHasTwoProngGenMCsignals) { - for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - // Fill Generated PAIR histograms taking into account selected collisions - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - if (fHasTwoProngGenMCsignals) { - for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - if (t1.reducedMCeventId() != event.reducedMCeventId()) { - continue; - } - if (t2.reducedMCeventId() != event.reducedMCeventId()) { - continue; - } - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - // WARNING! To be checked - dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); - } - } - isig++; - } - } - } - } - } // end loop over reconstructed events - } - - void processMCGenWithGrouping(soa::Filtered const& events, ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - uint32_t mcDecision = 0; - int isig = 0; - - for (auto& mctrack : mcTracks) { - VarManager::FillTrackMC(mcTracks, mctrack); - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - // Fill Generated histograms taking into account selected collisions - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - for (auto& track : mcTracks) { - if (track.reducedMCeventId() != event.reducedMCeventId()) { - continue; - } - VarManager::FillTrackMC(mcTracks, track); - auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); - - if (useMiniTree.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(track_raw.reducedMCeventId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); - } - } - isig++; - } - } - } // end loop over reconstructed events - if (fHasTwoProngGenMCsignals) { - for (auto& [t1, t2] : combinations(mcTracks, mcTracks)) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = mcTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons - fHistMan->FillHistClass(Form("MCTruthGenPair_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - // CURRENTLY ONLY FOR 1-GENERATION 2-PRONG SIGNALS - if (fHasTwoProngGenMCsignals) { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& [t1, t2] : combinations(groupedMCTracks, groupedMCTracks)) { - auto t1_raw = groupedMCTracks.rawIteratorAt(t1.globalIndex()); - auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); - if (t1_raw.reducedMCeventId() == t2_raw.reducedMCeventId()) { - mcDecision = 0; - isig = 0; - for (auto& sig : fGenMCSignals) { - if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here - continue; - } - if (sig->CheckSignal(true, t1_raw, t2_raw)) { - mcDecision |= (static_cast(1) << isig); - VarManager::FillPairMC(t1, t2); // NOTE: This feature will only work for muons - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); - if (useMiniTree.fConfigMiniTree) { - // WARNING! To be checked - dileptonMiniTreeGen(mcDecision, -999, t1.pt(), t1.eta(), t1.phi(), t2.pt(), t2.eta(), t2.phi()); - } - } - isig++; - } - } - } - } // end loop over reconstructed events - } - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisSameEventPairing, processAllSkimmed, "Run all types of pairing, with skimmed tracks/muons", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlySkimmed, "Run barrel only pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processBarrelOnlyWithCollSkimmed, "Run barrel only pairing, with skimmed tracks and with collision information", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processMuonOnlySkimmed, "Run muon only pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processMCGenWithGrouping, "Loop over MC particle stack (grouped MCTracks) and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisSameEventPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); -}; - -// Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) -struct AnalysisAsymmetricPairing { - - Produces ditrackList; - Produces ditrackExtraList; - - o2::base::MatLayerCylSet* fLUT = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - - // Output objects - OutputObj fOutputList{"output"}; - - // Configurables - Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; - Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in event-selection"}; - Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; - Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; - Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; - Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; - - Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; - Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; - // Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; - Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; - Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - - Configurable fConfigMCGenSignals{"cfgBarrelMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable fConfigMCRecSignals{"cfgBarrelMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; - Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; - - Service fCCDB; - - HistogramManager* fHistMan; - - std::vector fPairCuts; - int fNPairHistPrefixes; - - std::vector fRecMCSignals; - std::vector fGenMCSignals; - - // Filter masks to find legs in BarrelTrackCuts table - uint32_t fLegAFilterMask; - uint32_t fLegBFilterMask; - uint32_t fLegCFilterMask; - // Maps tracking which combination of leg cuts the track cuts participate in - std::map fConstructedLegAFilterMasksMap; - std::map fConstructedLegBFilterMasksMap; - std::map fConstructedLegCFilterMasksMap; - // Filter map for common track cuts - uint32_t fCommonTrackCutMask; - // Map tracking which common track cut the track cuts correspond to - std::map fCommonTrackCutFilterMasks; - - int fNLegCuts; - int fNPairCuts = 0; - int fNCommonTrackCuts; - // vectors for cut names and signal names, for easy access when calling FillHistogramList() - std::vector fLegCutNames; - std::vector fPairCutNames; - std::vector fCommonCutNames; - std::vector fRecMCSignalNames; - - Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - - Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - - // Partitions for triplets and asymmetric pairs - Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); - Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); - Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); - - // Map to track how many times a pair of tracks has been encountered - std::map, int8_t> fPairCount; - - void init(o2::framework::InitContext& context) - { - bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); - if (context.mOptions.get("processDummy")) { - return; - } - - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - // Get the leg cut filter masks - fLegAFilterMask = fConfigLegAFilterMask.value; - fLegBFilterMask = fConfigLegBFilterMask.value; - fLegCFilterMask = fConfigLegCFilterMask.value; - - // Get the pair cuts - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { - std::unique_ptr objArray(cutNamesStr.Tokenize(",")); - for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); - } - } - // Extra pair cuts via JSON - TString addPairCutsStr = fConfigPairCutsJSON.value; - if (addPairCutsStr != "") { - std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); - for (auto& t : addPairCuts) { - fPairCuts.push_back(reinterpret_cast(t)); - cutNamesStr += Form(",%s", t->GetName()); - } - } - std::unique_ptr objArrayPairCuts(cutNamesStr.Tokenize(",")); - fNPairCuts = objArrayPairCuts->GetEntries(); - for (int j = 0; j < fNPairCuts; j++) { - fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); - } - - // Setting the MC rec signal names - TString sigNamesStr = fConfigMCRecSignals.value; - std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); - for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); - if (sig) { - fRecMCSignals.push_back(sig); - } - } - // Add the reco MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != 2 && mcIt->GetNProngs() != 3) { - LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 2 or 3 prongs! Fix it"; - } - fRecMCSignals.push_back(mcIt); - sigNamesStr += Form(",%s", mcIt->GetName()); - } - } - // Put all the reco MCSignal names in the vector for histogram naming - std::unique_ptr objArrayRecMCSignals(sigNamesStr.Tokenize(",")); - for (int i = 0; i < objArrayRecMCSignals->GetEntries(); i++) { - fRecMCSignalNames.push_back(objArrayRecMCSignals->At(i)->GetName()); - } - - // Get the barrel track selection cuts - string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); - TString tempCutsStr = tempCuts; - // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); - TString addTrackCutsStr = tempCuts; - if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { - tempCutsStr += Form(",%s", t->GetName()); - } - } - std::unique_ptr objArray(tempCutsStr.Tokenize(",")); - // Get the common leg cuts - int commonCutIdx; - TString commonNamesStr = fConfigCommonTrackCuts.value; - if (!commonNamesStr.IsNull()) { // if common track cuts - std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); - fNCommonTrackCuts = objArrayCommon->GetEntries(); - for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { - commonCutIdx = objArray->IndexOf(objArrayCommon->At(icut)); - if (commonCutIdx >= 0) { - fCommonTrackCutMask |= static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); - fCommonTrackCutFilterMasks[icut] = static_cast(1) << objArray->IndexOf(objArrayCommon->At(icut)); - fCommonCutNames.push_back(objArrayCommon->At(icut)->GetName()); - } else { - LOGF(fatal, "Common track cut %s was not calculated upstream. Check the config!", objArrayCommon->At(icut)->GetName()); - } - } - } - // Check that the leg cut masks make sense - if (static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegAFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegAFilterMask))) + 1, objArray->GetEntries()); - } - if (static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegBFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegBFilterMask))) + 1, objArray->GetEntries()); - } - if (static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1 > objArray->GetEntries()) { - LOGF(fatal, "fConfigLegCFilterMask has highest bit at position %d, but track-selection only has %d cuts!", static_cast(std::floor(TMath::Log2(fLegCFilterMask))) + 1, objArray->GetEntries()); - } - - // Get the cuts defining the legs - uint32_t fConstructedLegAFilterMask = 0; - uint32_t fConstructedLegBFilterMask = 0; - uint32_t fConstructedLegCFilterMask = 0; - TString legCutsStr = fConfigLegCuts.value; - std::unique_ptr objArrayLegs(legCutsStr.Tokenize(",")); - if (objArrayLegs->GetEntries() == 0 && !isMCGen) { - LOG(fatal) << "No cuts defining legs. Check the config!"; - } - fNLegCuts = objArrayLegs->GetEntries(); - std::vector isThreeProng; - int legAIdx; - int legBIdx; - int legCIdx; - // Loop over leg defining cuts - for (int icut = 0; icut < fNLegCuts; ++icut) { - TString legsStr = objArrayLegs->At(icut)->GetName(); - std::unique_ptr legs(legsStr.Tokenize(":")); - if (legs->GetEntries() == 3) { - isThreeProng.push_back(true); - } else if (legs->GetEntries() == 2) { - isThreeProng.push_back(false); - } else { - LOGF(fatal, "Leg cuts %s has the wrong format and could not be parsed!", legsStr.Data()); - continue; - } - // Find leg cuts in the track selection cuts - legAIdx = objArray->IndexOf(legs->At(0)); - if (legAIdx >= 0) { - fConstructedLegAFilterMask |= static_cast(1) << legAIdx; - fConstructedLegAFilterMasksMap[icut] |= static_cast(1) << legAIdx; - } else { - LOGF(fatal, "Leg A cut %s was not calculated upstream. Check the config!", legs->At(0)->GetName()); - continue; - } - legBIdx = objArray->IndexOf(legs->At(1)); - if (legBIdx >= 0) { - fConstructedLegBFilterMask |= static_cast(1) << legBIdx; - fConstructedLegBFilterMasksMap[icut] |= static_cast(1) << legBIdx; - } else { - LOGF(fatal, "Leg B cut %s was not calculated upstream. Check the config!", legs->At(1)->GetName()); - continue; - } - if (isThreeProng[icut]) { - legCIdx = objArray->IndexOf(legs->At(2)); - if (legCIdx >= 0) { - fConstructedLegCFilterMask |= static_cast(1) << legCIdx; - fConstructedLegCFilterMasksMap[icut] |= static_cast(1) << legCIdx; - } else { - LOGF(fatal, "Leg C cut %s was not calculated upstream. Check the config!", legs->At(2)->GetName()); - continue; - } - } - // Leg cut config is fine, store the leg cut name in a vector - fLegCutNames.push_back(legsStr); - - // Define histogram and histogram directory names - if (isThreeProng[icut]) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); - if (fConfigQA) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_ambiguous_%s", legsStr.Data()), fConfigHistogramSubgroups.value.data()); - } - - std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); - } - - TString cutNamesStr = fConfigPairCuts.value; - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - fNPairCuts = objArrayPair->GetEntries(); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); - } // end loop (common cuts) - } // end loop (pair cuts) - } // end if (pair cuts) - - // TODO: assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination - if (!sigNamesStr.IsNull()) { - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - auto sig = fRecMCSignals.at(isig); - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s", legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s", legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("TripletsBarrelSE_%s_%s_%s_%s", legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } // end loop (common cuts) - } // end loop (pair cuts) - } // end if (pair cuts) - } // end loop over MC signals - } // end if (MC signals) - } else { - std::vector pairHistPrefixes = {"PairsBarrelSEPM"}; - if (fConfigSameSignHistograms.value) { - pairHistPrefixes.push_back("PairsBarrelSEPP"); - pairHistPrefixes.push_back("PairsBarrelSEMM"); - } - fNPairHistPrefixes = pairHistPrefixes.size(); - - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); - } - if (fConfigQA) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_ambiguous_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); - } - } - if (fConfigReflectedHistograms.value) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_reflected_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data()), fConfigHistogramSubgroups.value.data()); - } - } - - std::unique_ptr objArrayCommon(commonNamesStr.Tokenize(",")); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName()), fConfigHistogramSubgroups.value.data()); - } - } - - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - fNPairCuts = objArrayPair->GetEntries(); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); - } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName()), fConfigHistogramSubgroups.value.data()); - } - } // end loop (common cuts) - } // end loop (pair cuts) - } // end if (pair cuts) - - // assign hist directories for the MC matched triplets for each (leg cut combo,MCsignal) combination - if (!sigNamesStr.IsNull()) { - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { - auto sig = fRecMCSignals.at(isig); - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - if (fConfigReflectedHistograms.value) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_reflected_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - } - - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - } - - if (!cutNamesStr.IsNull()) { // if pair cuts - std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { // loop over pair cuts - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - for (int iPrefix = 0; iPrefix < fNPairHistPrefixes; ++iPrefix) { - DefineHistograms(fHistMan, Form("%s_%s_%s_%s_%s", pairHistPrefixes[iPrefix].Data(), legsStr.Data(), objArrayCommon->At(iCommonCut)->GetName(), objArrayPair->At(iPairCut)->GetName(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - } // end loop (common cuts) - } // end loop (pair cuts) - } // end if (pair cuts) - } // end loop over MC signals - } // end if (MC signals) - } - } - - // Add histogram classes for each specified MCsignal at the generator level - // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function - TString sigGenNamesStr = fConfigMCGenSignals.value; - std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); - for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required - fGenMCSignals.push_back(sig); - DefineHistograms(fHistMan, Form("MCTruthGen_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", sig->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - } - } - } - - // Add the gen MCSignals from the JSON config - addMCSignalsStr = fConfigMCGenSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() == 1) { - fGenMCSignals.push_back(mcIt); - DefineHistograms(fHistMan, Form("MCTruthGen_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - DefineHistograms(fHistMan, Form("MCTruthGenSel_%s;", mcIt->GetName()), fConfigHistogramSubgroups.value.data()); // TODO: Add these names to a std::vector to avoid using Form in the process function - } - } - } - - // Make sure the leg cuts are covered by the configured filter masks - if (fLegAFilterMask != fConstructedLegAFilterMask) { - LOGF(fatal, "cfgLegAFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegAFilterMask, fConstructedLegAFilterMask); - } - if (fLegBFilterMask != fConstructedLegBFilterMask) { - LOGF(fatal, "cfgLegBFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegBFilterMask, fConstructedLegBFilterMask); - } - if (fLegCFilterMask != fConstructedLegCFilterMask) { - LOGF(fatal, "cfgLegCFilterMask (%d) is not equal to the mask constructed by the cuts specified in cfgLegCuts (%d)!", fLegCFilterMask, fConstructedLegCFilterMask); - } - // Make sure only pairs or only triplets of leg cuts were given - int tripletCheckSum = std::count(isThreeProng.begin(), isThreeProng.end(), true); - if (tripletCheckSum != 0 && tripletCheckSum != fNLegCuts) { - LOGF(fatal, "A mix of pairs and triplets was given as leg cuts. Check your config!"); - } - - fCurrentRun = 0; - - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - - fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); - VarManager::SetupMatLUTFwdDCAFitter(fLUT); - - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - void initParamsFromCCDB(uint64_t timestamp, bool isTriplets) - { - if (fConfigUseRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPMagPath, timestamp); - float magField = 0.0; - if (grpmag != nullptr) { - magField = grpmag->getNominalL3Field(); - } else { - LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); - } - if (isTriplets) { - if (fConfigUseKFVertexing.value) { - VarManager::SetupThreeProngKFParticle(magField); - } else { - VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); - } - } else { - if (fConfigUseKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(magField); - } else { - VarManager::SetupTwoProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables - } - } - } else { - if (isTriplets) { - if (fConfigUseKFVertexing.value) { - VarManager::SetupThreeProngKFParticle(fConfigMagField.value); - } else { - VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); - } - } else { - if (fConfigUseKFVertexing.value) { - VarManager::SetupTwoProngKFParticle(fConfigMagField.value); - } else { - VarManager::SetupTwoProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigUseAbsDCA.value); // TODO: get these parameters from Configurables - } - } - } - } - - // Template function to run same event pairing with asymmetric pairs (e.g. kaon-pion) - template - void runAsymmetricPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) - { - fPairCount.clear(); - - if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() - if (fCurrentRun != events.begin().runNumber()) { - initParamsFromCCDB(events.begin().timestamp(), false); - fCurrentRun = events.begin().runNumber(); - } - } - - int sign1 = 0; - int sign2 = 0; - uint32_t mcDecision = 0; - ditrackList.reserve(1); - ditrackExtraList.reserve(1); - - constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0 || (TTrackFillMap & VarManager::ObjTypes::ReducedTrackBarrelCov) > 0); - - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); - - auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); - if (groupedLegAAssocs.size() == 0) { - continue; - } - auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); - if (groupedLegBAssocs.size() == 0) { - continue; - } - - for (auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { - - uint32_t twoTrackFilter = 0; - uint32_t twoTrackCommonFilter = 0; - uint32_t pairFilter = 0; - bool isPairIdWrong = false; - for (int icut = 0; icut < fNLegCuts; ++icut) { - // Find leg pair definitions both candidates participate in - if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut])) { - twoTrackFilter |= static_cast(1) << icut; - // If the supposed pion passes a kaon cut, this is a K+K-. Skip it. - if (TPairType == VarManager::kDecayToKPi && fConfigSkipAmbiguousIdCombinations.value) { - if (a2.isBarrelSelected_raw() & fLegAFilterMask) { - isPairIdWrong = true; - } - } - } - } - - if (!twoTrackFilter || isPairIdWrong) { - continue; - } - - // Find common track cuts both candidates pass - twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; - - auto t1 = a1.template reducedtrack_as(); - auto t2 = a2.template reducedtrack_as(); - - // Avoid self-pairs - if (t1.globalIndex() == t2.globalIndex()) { - continue; - } - - bool isReflected = false; - std::pair trackIds(t1.globalIndex(), t2.globalIndex()); - if (fPairCount.find(trackIds) != fPairCount.end()) { - // Double counting is possible due to track-collision ambiguity. Skip pairs which were counted before - fPairCount[trackIds] += 1; - continue; - } - if (fPairCount.find(std::pair(trackIds.second, trackIds.first)) != fPairCount.end()) { - isReflected = true; - } - fPairCount[trackIds] += 1; - - sign1 = t1.sign(); - sign2 = t2.sign(); - // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter - if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= static_cast(1) << 30; - } - if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { - twoTrackFilter |= static_cast(1) << 31; - } - - // run MC matching for this pair - int isig = 0; - mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack()) { - VarManager::FillPairMC(t1.reducedMCTrack(), t2.reducedMCTrack()); - if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack())) { - mcDecision |= static_cast(1) << isig; - } - } - } // end loop over MC signals - - VarManager::FillPair(t1, t2); - if constexpr (TTwoProngFitter) { - VarManager::FillPairVertexing(event, t1, t2, fConfigPropToPCA); - } - - // Fill histograms - bool isAmbi = false; - for (int icut = 0; icut < fNLegCuts; icut++) { - if (twoTrackFilter & (static_cast(1) << icut)) { - isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); // reconstructed, unmatched - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { // ++ pairs - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - } else { // -- pairs - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - if (isAmbi && fConfigQA) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - if (isReflected && fConfigReflectedHistograms) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - } - } - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - if (isReflected && fConfigReflectedHistograms.value) { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_reflected_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } - } - } - } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); - } - } - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } - } - } - } - } // end loop (common cuts) - int iPairCut = 0; - for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { - if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts - continue; - pairFilter |= (static_cast(1) << iPairCut); - // Histograms with pair cuts - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } - } - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } - } - } - // Histograms with pair cuts and common track cuts - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - if (twoTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - } - } - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else if (fConfigSameSignHistograms.value) { - if (sign1 > 0) { - fHistMan->FillHistClass(Form("PairsBarrelSEPP_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } else { - fHistMan->FillHistClass(Form("PairsBarrelSEMM_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); - } - } - } - } - } - } - } // end loop (pair cuts) - } - } // end loop (cuts) - ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); - if constexpr (trackHasCov && TTwoProngFitter) { - ditrackExtraList(t1.globalIndex(), t2.globalIndex(), VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingLzProjected], VarManager::fgValues[VarManager::kVertexingLxyProjected]); - } - } // end inner assoc loop (leg A) - } // end event loop - } - - // Template function to run same event triplets (e.g. D+->K-pi+pi+) - template - void runThreeProng(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/, VarManager::PairCandidateType tripletType) - { - if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() - if (fCurrentRun != events.begin().runNumber()) { - initParamsFromCCDB(events.begin().timestamp(), true); - fCurrentRun = events.begin().runNumber(); - } - } - - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - // Reset the fValues array - VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); - - auto groupedLegAAssocs = legACandidateAssocs.sliceBy(preslice, event.globalIndex()); - if (groupedLegAAssocs.size() == 0) { - continue; - } - auto groupedLegBAssocs = legBCandidateAssocs.sliceBy(preslice, event.globalIndex()); - if (groupedLegBAssocs.size() == 0) { - continue; - } - auto groupedLegCAssocs = legCCandidateAssocs.sliceBy(preslice, event.globalIndex()); - if (groupedLegCAssocs.size() == 0) { - continue; - } - - // Based on triplet type, make suitable combinations of the partitions - if (tripletType == VarManager::kTripleCandidateToPKPi) { - for (auto& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { - readTriplet(a1, a2, a3, tracks, event, tripletType); - } - } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { - for (auto& a1 : groupedLegAAssocs) { - for (auto& [a2, a3] : combinations(groupedLegBAssocs, groupedLegCAssocs)) { - readTriplet(a1, a2, a3, tracks, event, tripletType); - } - } - } else { - LOG(fatal) << "Given tripletType not recognized. Don't know how to make combinations!" << endl; - } - } // end event loop - } - - // Helper function to process triplet - template - void readTriplet(TTrackAssoc const& a1, TTrackAssoc const& a2, TTrackAssoc const& a3, TTracks const& /*tracks*/, TEvent const& event, VarManager::PairCandidateType tripletType) - { - uint32_t mcDecision = 0; - - uint32_t threeTrackFilter = 0; - uint32_t threeTrackCommonFilter = 0; - for (int icut = 0; icut < fNLegCuts; ++icut) { - // Find out which leg cut combinations the triplet passes - if ((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) && (a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) && (a3.isBarrelSelected_raw() & fConstructedLegCFilterMasksMap[icut])) { - threeTrackFilter |= (static_cast(1) << icut); - if (tripletType == VarManager::kTripleCandidateToPKPi && fConfigSkipAmbiguousIdCombinations.value) { - // Check if the supposed pion passes as a proton or kaon, if so, skip this triplet. It is pKp or pKK. - if ((a3.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegBFilterMask)) { - return; - } - // Check if the supposed kaon passes as a proton, if so, skip this triplet. It is ppPi. - if (a2.isBarrelSelected_raw() & fLegAFilterMask) { - return; - } - } - if (tripletType == VarManager::kTripleCandidateToKPiPi && fConfigSkipAmbiguousIdCombinations.value) { - // Check if one of the supposed pions pass as a kaon, if so, skip this triplet. It is KKPi. - if ((a2.isBarrelSelected_raw() & fLegAFilterMask) || (a3.isBarrelSelected_raw() & fLegAFilterMask)) { - return; - } - } - } - } - if (!threeTrackFilter) { - return; - } - - // Find common track cuts all candidates pass - threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - - auto t1 = a1.template reducedtrack_as(); - auto t2 = a2.template reducedtrack_as(); - auto t3 = a3.template reducedtrack_as(); - - // Avoid self-pairs - if (t1 == t2 || t1 == t3 || t2 == t3) { - return; - } - // Check charge - if (tripletType == VarManager::kTripleCandidateToKPiPi) { - if (!((t1.sign() == -1 && t2.sign() == 1 && t3.sign() == 1) || (t1.sign() == 1 && t2.sign() == -1 && t3.sign() == -1))) { - return; - } - } - if (tripletType == VarManager::kTripleCandidateToPKPi) { - if (!((t1.sign() == 1 && t2.sign() == -1 && t3.sign() == 1) || (t1.sign() == -1 && t2.sign() == 1 && t3.sign() == -1))) { - return; - } - } - - // store the ambiguity of the three legs in the last 3 digits of the two-track filter - if (t1.barrelAmbiguityInBunch() > 1 || t1.barrelAmbiguityOutOfBunch() > 1) { - threeTrackFilter |= (static_cast(1) << 29); - } - if (t2.barrelAmbiguityInBunch() > 1 || t2.barrelAmbiguityOutOfBunch() > 1) { - threeTrackFilter |= (static_cast(1) << 30); - } - if (t3.barrelAmbiguityInBunch() > 1 || t3.barrelAmbiguityOutOfBunch() > 1) { - threeTrackFilter |= (static_cast(1) << 31); - } - - // run MC matching for this triplet - int isig = 0; - mcDecision = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if (t1.has_reducedMCTrack() && t2.has_reducedMCTrack() && t3.has_reducedMCTrack()) { - if ((*sig)->CheckSignal(true, t1.reducedMCTrack(), t2.reducedMCTrack(), t3.reducedMCTrack())) { - mcDecision |= (static_cast(1) << isig); - } - } - } // end loop over MC signals - - VarManager::FillTriple(t1, t2, t3, VarManager::fgValues, tripletType); - if constexpr (TThreeProngFitter) { - VarManager::FillTripletVertexing(event, t1, t2, t3, tripletType); - } - - // Fill histograms - bool isAmbi = false; - for (int icut = 0; icut < fNLegCuts; icut++) { - isAmbi = (threeTrackFilter & (static_cast(1) << 29)) || (threeTrackFilter & (static_cast(1) << 30)) || (threeTrackFilter & (static_cast(1) << 31)); - if (threeTrackFilter & (static_cast(1) << icut)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal - } - } // end loop (MC signals) - if (fConfigQA && isAmbi) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_ambiguous_%s", fLegCutNames[icut].Data()), VarManager::fgValues); - } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data()), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal - } - } // end loop (MC signals) - } - } // end loop (common cuts) - int iPairCut = 0; - for (auto cut = fPairCuts.begin(); cut != fPairCuts.end(); cut++, iPairCut++) { - if (!((*cut)->IsSelected(VarManager::fgValues))) // apply pair cuts - continue; - // Histograms with pair cuts - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal - } - } // end loop (MC signals) - // Histograms with pair cuts and common track cuts - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - if (threeTrackCommonFilter & fCommonTrackCutFilterMasks[iCommonCut]) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), VarManager::fgValues); - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("TripletsBarrelSE_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fRecMCSignalNames[isig].Data()), VarManager::fgValues); // matched signal - } - } // end loop (MC signals) - } - } - } // end loop (pair cuts) - } - } // end loop (cuts) - } - - void processKaonPionSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - } - - void processKaonPionSkimmedMultExtra(MyEventsVtxCovSelectedMultExtra const& events, - soa::Join const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); - } - - void processKaonPionPionSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, - MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks, VarManager::kTripleCandidateToKPiPi); - } - - void processMCGen(ReducedMCTracks const& mcTracks) - { - // loop over mc stack and fill histograms for pure MC truth signals - // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); - for (auto& mctrack : mcTracks) { - - VarManager::FillTrackMC(mcTracks, mctrack); - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - - PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; - - void processMCGenWithEventSelection(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& track : groupedMCTracks) { - - VarManager::FillTrackMC(mcTracks, track); - - auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } // end loop over reconstructed events - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmed, "Run kaon pion pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionSkimmedMultExtra, "Run kaon pion pairing, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processKaonPionPionSkimmed, "Run kaon pion pion triplets, with skimmed tracks", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisAsymmetricPairing, processDummy, "Dummy function, enabled only if none of the others are enabled", true); -}; - -// Combines dileptons with barrel or muon tracks for either resonance or correlation analyses -// Dileptons produced with all the selection cuts specified in the same-event pairing task are combined with the -// tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected -struct AnalysisDileptonTrack { - Produces BmesonsTable; - Produces DileptonTrackTable; - OutputObj fOutputList{"output"}; - - Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of track cuts to be correlated with the dileptons"}; - Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; - Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; - Configurable fConfigDileptonpTCut{"cfgDileptonpTCut", 0.0, "pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; - Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - Configurable fConfigCcdbUrl{"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 fConfigNoLaterThan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; - Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - - Configurable fConfigMCRecSignals{"cfgMCRecSignals", "", "Comma separated list of MC signals (reconstructed)"}; - Configurable fConfigMCGenSignals{"cfgMCGenSignals", "", "Comma separated list of MC signals (generated)"}; - Configurable fConfigMCRecSignalsJSON{"cfgMCRecSignalsJSON", "", "Additional list of MC signals (reconstructed) via JSON"}; - Configurable fConfigMCGenSignalsJSON{"cfgMCGenSignalsJSON", "", "Comma separated list of MC signals (generated) via JSON"}; - Configurable fConfigMCGenSignalDileptonLegPos{"cfgMCGenSignalDileptonLegPos", 0, "generator level positive dilepton leg signal (bit number according to table-maker)"}; - Configurable fConfigMCGenSignalDileptonLegNeg{"cfgMCGenSignalDileptonLegNeg", 0, "generator level negative dilepton leg signal (bit number according to table-maker)"}; - Configurable fConfigMCGenSignalHadron{"cfgMCGenSignalHadron", 0, "generator level associated hadron signal (bit number according to table-maker)"}; - Configurable fConfigMCGenDileptonLegPtMin{"cfgMCGenDileptonLegPtMin", 1.0f, "minimum pt for the dilepton leg"}; - Configurable fConfigMCGenHadronPtMin{"cfgMCGenHadronPtMin", 1.0f, "minimum pt for the hadron"}; - Configurable fConfigMCGenDileptonLegEtaAbs{"cfgMCGenDileptonLegEtaAbs", 0.9f, "eta abs range for the dilepton leg"}; - Configurable fConfigMCGenHadronEtaAbs{"cfgMCGenHadronEtaAbs", 0.9f, "eta abs range for the hadron"}; - Configurable fConfigUseMCRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing(reconstructed)"}; - Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; - - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. - int fNCuts; - int fNLegCuts; - int fNPairCuts; - int fNCommonTrackCuts; - std::map fCommonTrackCutMap; - uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons - // vector for single-lepton and track cut names for easy access when calling FillHistogramList() - std::vector fTrackCutNames; - std::vector fLegCutNames; - // vector for pair cut names, used mainly for pairs built via the asymmetric pairing task - std::vector fPairCutNames; - std::vector fCommonPairCutNames; - - Service fCCDB; - - // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file - Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonLowpTCut&& aod::reducedpair::pt fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut; - Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); - Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); - - constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map - - // use two values array to avoid mixing up the quantities - float* fValuesDilepton; - float* fValuesHadron; - HistogramManager* fHistMan; - - std::vector fRecMCSignals; - std::vector fGenMCSignals; - - NoBinningPolicy fHashBin; - - void init(o2::framework::InitContext& context) - { - bool isBarrel = context.mOptions.get("processBarrelSkimmed"); - bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); - bool isMuon = context.mOptions.get("processMuonSkimmed"); - bool isMCGen = context.mOptions.get("processMCGen") || context.mOptions.get("processMCGenWithEventSelection"); - bool isDummy = context.mOptions.get("processDummy"); - bool isMCGen_energycorrelators = context.mOptions.get("processMCGenEnergyCorrelators") || context.mOptions.get("processMCGenEnergyCorrelatorsPion"); - bool isMCGen_energycorrelatorsME = context.mOptions.get("processMCGenEnergyCorrelatorsME") || context.mOptions.get("processMCGenEnergyCorrelatorsPionME"); - - if (isDummy) { - if (isBarrel || isMuon || isBarrelAsymmetric || isMCGen) { - LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; - } else { - LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; - return; - } - } - - fCurrentRun = 0; - - fCCDB->setURL(fConfigCcdbUrl.value); - fCCDB->setCaching(true); - fCCDB->setLocalObjectValidityChecking(); - fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - fCCDB->get(fConfigGeoPath); - } - - fValuesDilepton = new float[VarManager::kNVars]; - fValuesHadron = new float[VarManager::kNVars]; - fTrackCutBitMap = 0; - VarManager::SetDefaultVarNames(); - fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); - fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - - TString sigNamesStr = fConfigMCRecSignals.value; - std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); - if (!sigNamesStr.IsNull()) { - for (int isig = 0; isig < objRecSigArray->GetEntries(); ++isig) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objRecSigArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() != 3) { - LOG(fatal) << "Signal at reconstructed level requested (" << sig->GetName() << ") " << "does not have 3 prongs! Fix it"; - } - fRecMCSignals.push_back(sig); - } else { - LOG(fatal) << "Signal at reconstructed level requested (" << objRecSigArray->At(isig)->GetName() << ") " << "could not be retrieved from the library! -> skipped"; - } - } - } - - // Add the reco MCSignals from the JSON config - TString addMCSignalsStr = fConfigMCRecSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() != 3) { - LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 3 prongs! Fix it"; - } - fRecMCSignals.push_back(mcIt); - } - } - - // Add histogram classes for each specified MCsignal at the generator level - // TODO: create a std::vector of hist classes to be used at Fill time, to avoid using Form in the process function - TString sigGenNamesStr = fConfigMCGenSignals.value; - std::unique_ptr objGenSigArray(sigGenNamesStr.Tokenize(",")); - for (int isig = 0; isig < objGenSigArray->GetEntries(); isig++) { - MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(objGenSigArray->At(isig)->GetName()); - if (sig) { - if (sig->GetNProngs() == 1) { // NOTE: 1-prong signals required - fGenMCSignals.push_back(sig); - } - } - } - - // Add the gen MCSignals from the JSON config - addMCSignalsStr = fConfigMCGenSignalsJSON.value; - if (addMCSignalsStr != "") { - std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { - if (mcIt->GetNProngs() == 1) { - fGenMCSignals.push_back(mcIt); - } - } - } - - // For each track/muon selection used to produce dileptons, create a separate histogram directory using the - // name of the track/muon cut. - - // Get the list of single track and muon cuts computed in the dedicated tasks upstream - // We need this to know the order in which they were computed, and also to make sure that in this task we do not ask - // for cuts which were not computed (in which case this will trigger a fatal) - string cfgTrackSelection_TrackCuts; - if (isBarrel || isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); - } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); - } - TObjArray* cfgTrackSelection_objArrayTrackCuts = nullptr; - if (!cfgTrackSelection_TrackCuts.empty()) { - cfgTrackSelection_objArrayTrackCuts = TString(cfgTrackSelection_TrackCuts).Tokenize(","); - } - // get also the list of cuts specified via the JSON parameters - if (isBarrel || isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); - } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); - } - if (!cfgTrackSelection_TrackCuts.empty()) { - if (cfgTrackSelection_objArrayTrackCuts == nullptr) { - cfgTrackSelection_objArrayTrackCuts = new TObjArray(); - } - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); - for (auto& t : addTrackCuts) { - TObjString* tempObjStr = new TObjString(t->GetName()); - cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); - } - } - if (cfgTrackSelection_objArrayTrackCuts->GetEntries() == 0) { - LOG(fatal) << " No track cuts found in the barrel or muon upstream tasks"; - } - // store all the computed track cut names in a vector - for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { - fTrackCutNames.push_back(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName()); - } - // get the list of associated track cuts to be combined with the dileptons, - // check that these were computed upstream, and create a bit mask - TObjArray* cfgDileptonTrack_objArrayTrackCuts = nullptr; - if (!fConfigTrackCuts.value.empty()) { - cfgDileptonTrack_objArrayTrackCuts = TString(fConfigTrackCuts.value).Tokenize(","); - } else { - LOG(fatal) << " No track cuts specified! Check it out!"; - } - // loop over these cuts and check they were computed upstream (otherwise trigger a fatal) - for (int icut = 0; icut < cfgDileptonTrack_objArrayTrackCuts->GetEntries(); icut++) { - if (!cfgTrackSelection_objArrayTrackCuts->FindObject(cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName())) { - LOG(fatal) << "Specified track cut (" << cfgDileptonTrack_objArrayTrackCuts->At(icut)->GetName() << ") not found in the list of computed cuts by the single barrel / muon selection tasks"; - } - } - // loop over all the upstream cuts and make a bit mask for the track cuts specified in this task - for (int icut = 0; icut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); icut++) { - if (cfgDileptonTrack_objArrayTrackCuts->FindObject(cfgTrackSelection_objArrayTrackCuts->At(icut)->GetName())) { - fTrackCutBitMap |= (static_cast(1) << icut); - } - } - // finally, store the total number of upstream tasks, for easy access - fNCuts = fTrackCutNames.size(); - - // get the cuts employed for same-event pairing - // NOTE: The track/muon cuts in analysis-same-event-pairing are used to select electrons/muons to build dielectrons/dimuons - // NOTE: The cfgPairCuts in analysis-same-event-pairing are used to apply an additional selection on top of the already produced dileptons - // but this is only used for histograms, not for the produced dilepton tables - string cfgPairing_TrackCuts; - string cfgPairing_PairCuts; - string cfgPairing_PairCutsJSON; - string cfgPairing_CommonTrackCuts; - if (isBarrel) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); - } else if (isMuon) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); - } else if (isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); - } - if (cfgPairing_TrackCuts.empty()) { - LOG(fatal) << "There are no dilepton cuts specified in the upstream in the same-event-pairing or asymmetric-pairing"; - } - - // If asymmetric pair is used, it may have common track cuts - TString cfgPairing_strCommonTrackCuts = cfgPairing_CommonTrackCuts; - if (!cfgPairing_strCommonTrackCuts.IsNull()) { // if common track cuts - std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); - fNCommonTrackCuts = objArrayCommon->GetEntries(); - for (int icut = 0; icut < fNCommonTrackCuts; ++icut) { - for (int iicut = 0; iicut < cfgTrackSelection_objArrayTrackCuts->GetEntries(); iicut++) { - if (std::strcmp(cfgTrackSelection_objArrayTrackCuts->At(iicut)->GetName(), objArrayCommon->At(icut)->GetName()) == 0) { - fCommonTrackCutMap[icut] = iicut; - fCommonPairCutNames.push_back(objArrayCommon->At(icut)->GetName()); - } - } - } - } // end if (common cuts) - - // Get also the pair cuts specified via the JSON parameters - if (isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); - TString addPairCutsStr = cfgPairing_PairCutsJSON; - if (addPairCutsStr != "") { - std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); - for (auto& t : addPairCuts) { - cfgPairing_PairCuts += Form(",%s", t->GetName()); - } - } - } - - std::unique_ptr objArrayPairCuts(TString(cfgPairing_PairCuts).Tokenize(",")); - fNPairCuts = objArrayPairCuts->GetEntries(); - for (int j = 0; j < fNPairCuts; j++) { - fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); - } - - // array of single lepton cuts specified in the same-analysis-pairing task - std::unique_ptr cfgPairing_objArrayTrackCuts(TString(cfgPairing_TrackCuts).Tokenize(",")); - // If asymmetric pairs are used, the number of cuts should come from the asymmetric-pairing task - if (isBarrelAsymmetric) { - fNLegCuts = cfgPairing_objArrayTrackCuts->GetEntries(); - } else { - fNLegCuts = fNCuts; - } - - // loop over single lepton cuts - if (isBarrel || isBarrelAsymmetric || isMuon) { - for (int icut = 0; icut < fNLegCuts; ++icut) { - - TString pairLegCutName; - - // here we check that this cut is one of those used for building the dileptons - if (!isBarrelAsymmetric) { - if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { - continue; - } - pairLegCutName = fTrackCutNames[icut].Data(); - } else { - // For asymmetric pairs we access the leg cuts instead - pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); - } - fLegCutNames.push_back(pairLegCutName); - - // define dilepton histograms - DefineHistograms(fHistMan, Form("DileptonsSelected_%s", pairLegCutName.Data()), "barrel,vertexing"); - // loop over track cuts and create dilepton - track histogram directories - for (int iCutTrack = 0; iCutTrack < fNCuts; iCutTrack++) { - - // here we check that this track cut is one of those required to associate with the dileptons - if (!(fTrackCutBitMap & (static_cast(1) << iCutTrack))) { - continue; - } - - DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - - if (!cfgPairing_strCommonTrackCuts.IsNull()) { - std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); - DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - } - } - - if (fNPairCuts != 0) { - - for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { - DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); - DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - - if (!cfgPairing_strCommonTrackCuts.IsNull()) { - std::unique_ptr objArrayCommon(cfgPairing_strCommonTrackCuts.Tokenize(",")); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { - DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); - DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigHistogramSubgroups.value.data()); - } - } - } - } - } - } // end loop over track cuts to be combined with dileptons / di-tracks - } // end loop over pair leg track cuts - } // end if (isBarrel || isBarrelAsymmetric || isMuon) - - if (isMCGen) { - for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); - DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); - } - for (auto& sig : fRecMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); - DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); - } - } - - if (isMCGen_energycorrelators) { - for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelators_%s", sig->GetName()), ""); - } - } - - if (isMCGen_energycorrelatorsME) { - for (auto& sig : fGenMCSignals) { - DefineHistograms(fHistMan, Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), ""); - } - } - - TString addHistsStr = fConfigAddJSONHistograms.value; - if (addHistsStr != "") { - dqhistograms::AddHistogramsFromJSON(fHistMan, addHistsStr.Data()); - } - VarManager::SetUseVars(fHistMan->GetUsedVars()); - fOutputList.setObject(fHistMan->GetMainHistogramList()); - } - - // init parameters from CCDB - void initParamsFromCCDB(uint64_t timestamp) - { - if (fConfigUseRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigGRPmagPath.value, timestamp); - float magField = 0.0; - if (grpmag != nullptr) { - magField = grpmag->getNominalL3Field(); - } else { - LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", timestamp); - } - if (fConfigUseKFVertexing.value) { - VarManager::SetupThreeProngKFParticle(magField); - } else { - VarManager::SetupThreeProngDCAFitter(magField, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables - } - } else { - if (fConfigUseKFVertexing.value) { - VarManager::SetupThreeProngKFParticle(fConfigMagField.value); - } else { - VarManager::SetupThreeProngDCAFitter(fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables - } - } - } - - // Template function to run pair - hadron combinations - template - void runDileptonHadron(TEvent const& event, TTrackAssocs const& assocs, TTracks const& tracks, TDileptons const& dileptons, ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& /*mcTracks*/) - { - VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); - VarManager::FillEvent(event, fValuesHadron); - VarManager::FillEvent(event.reducedMCevent(), fValuesHadron); - VarManager::FillEvent(event, fValuesDilepton); - VarManager::FillEvent(event.reducedMCevent(), fValuesDilepton); - - uint32_t mcDecision = static_cast(0); - size_t isig = 0; - - for (auto dilepton : dileptons) { - // get full track info of tracks based on the index - auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); - auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); - if (!lepton1.has_reducedMCTrack() || !lepton2.has_reducedMCTrack()) { - continue; - } - auto lepton1MC = lepton1.reducedMCTrack(); - auto lepton2MC = lepton2.reducedMCTrack(); - // Check that the dilepton has zero charge - if (dilepton.sign() != 0) { - continue; - } - // dilepton rap cut - float rap = dilepton.rap(); - if (fConfigUseMCRapcut && abs(rap) > fConfigDileptonRapCutAbs) - continue; - - VarManager::FillTrack(dilepton, fValuesDilepton); - - // fill selected dilepton histograms for each specified selection - for (int icut = 0; icut < fNLegCuts; icut++) { - - if (!dilepton.filterMap_bit(icut)) { - continue; - } - - // regular dileptons - fHistMan->FillHistClass(Form("DileptonsSelected_%s", fLegCutNames[icut].Data()), fValuesDilepton); - - // other pairs, e.g.: D0s - if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { - fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data()), fValuesDilepton); - } - } - for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { - if (dilepton.pairFilterMap_bit(iPairCut)) { - fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { - fHistMan->FillHistClass(Form("DileptonsSelected_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[icut].Data()), fValuesDilepton); - } - } - } - } - } - } - - // loop over track associations - for (auto& assoc : assocs) { - - uint32_t trackSelection = 0; - if constexpr (TCandidateType == VarManager::kBtoJpsiEEK) { - // check the cuts fulfilled by this candidate track; if none just continue - trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); - if (!trackSelection) { - continue; - } - // get the track from this association - auto track = assoc.template reducedtrack_as(); - // check that this track is not included in the current dilepton - if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { - continue; - } - // compute needed quantities - VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); - VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); - - auto trackMC = track.reducedMCTrack(); - mcDecision = 0; - isig = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (static_cast(1) << isig); - } - } - // table to be written out for ML analysis - BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), - fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], - fValuesHadron[VarManager::kVertexingLxy], fValuesHadron[VarManager::kVertexingLxyz], fValuesHadron[VarManager::kVertexingLz], - fValuesHadron[VarManager::kVertexingTauxy], fValuesHadron[VarManager::kVertexingTauz], fValuesHadron[VarManager::kCosPointingAngle], - fValuesHadron[VarManager::kVertexingChi2PCA], - track.globalIndex(), lepton1.globalIndex(), lepton2.globalIndex(), - track.tpcInnerParam(), track.eta(), dilepton.pt(), dilepton.eta(), lepton1.tpcInnerParam(), lepton1.eta(), lepton2.tpcInnerParam(), lepton2.eta(), - track.tpcNSigmaKa(), track.tpcNSigmaPi(), track.tpcNSigmaPr(), track.tofNSigmaKa(), - lepton1.tpcNSigmaEl(), lepton1.tpcNSigmaPi(), lepton1.tpcNSigmaPr(), - lepton2.tpcNSigmaEl(), lepton2.tpcNSigmaPi(), lepton2.tpcNSigmaPr(), - track.itsClusterMap(), lepton1.itsClusterMap(), lepton2.itsClusterMap(), - track.itsChi2NCl(), lepton1.itsChi2NCl(), lepton2.itsChi2NCl(), - track.tpcNClsFound(), lepton1.tpcNClsFound(), lepton2.tpcNClsFound(), - track.tpcChi2NCl(), lepton1.tpcChi2NCl(), lepton2.tpcChi2NCl(), - dilepton.filterMap_raw(), trackSelection, mcDecision); - } - - if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { - trackSelection = (assoc.isBarrelSelected_raw() & fTrackCutBitMap); - if (!trackSelection) { - continue; - } - - auto track = assoc.template reducedtrack_as(); - if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { - continue; - } - // Check that the charge combination makes sense for D*+ -> D0 pi+ or D*- -> D0bar pi- - if (!((track.sign() == 1 && lepton1.sign() == -1 && lepton2.sign() == 1) || (track.sign() == -1 && lepton1.sign() == 1 && lepton2.sign() == -1))) { - continue; - } - VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); - VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); - - auto trackMC = track.reducedMCTrack(); - mcDecision = 0; - isig = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (static_cast(1) << isig); - } - } - } - - if constexpr (TCandidateType == VarManager::kBcToThreeMuons) { - trackSelection = (assoc.isMuonSelected_raw() & fTrackCutBitMap); - if (!trackSelection) { - continue; - } - - auto track = assoc.template reducedmuon_as(); - if (track.globalIndex() == dilepton.index0Id() || track.globalIndex() == dilepton.index1Id()) { - continue; - } - - VarManager::FillDileptonHadron(dilepton, track, fValuesHadron); - VarManager::FillDileptonTrackVertexing(event, lepton1, lepton2, track, fValuesHadron); - - if (!track.has_reducedMCTrack()) { - continue; - } - auto trackMC = track.reducedMCTrack(); - mcDecision = 0; - isig = 0; - for (auto sig = fRecMCSignals.begin(); sig != fRecMCSignals.end(); sig++, isig++) { - if ((*sig)->CheckSignal(true, lepton1MC, lepton2MC, trackMC)) { - mcDecision |= (static_cast(1) << isig); - } - } - // Fill table for correlation analysis - DileptonTrackTable(fValuesHadron[VarManager::kDeltaEta], fValuesHadron[VarManager::kDeltaPhi], - dilepton.mass(), dilepton.pt(), dilepton.eta(), track.pt(), track.eta(), track.phi(), - lepton1.pt(), lepton1.eta(), lepton1.phi(), lepton2.pt(), lepton2.eta(), lepton2.phi(), - mcDecision); - } - - // Fill histograms for the triplets - // loop over dilepton / ditrack cuts and MC signals - for (int icut = 0; icut < fNCuts; icut++) { - - if (!dilepton.filterMap_bit(icut)) { - continue; - } - - // loop over specified track cuts (the tracks to be combined with the dileptons) - for (int iTrackCut = 0; iTrackCut < fNCuts; iTrackCut++) { - - if (!(trackSelection & (static_cast(1) << iTrackCut))) { - continue; - } - - fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); - } - } - - if constexpr (TCandidateType == VarManager::kDstarToD0KPiPi) { // Dielectrons and Dimuons don't have the PairFilterMap column - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { - fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); - } - } - } - } - for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { - if (dilepton.pairFilterMap_bit(iPairCut)) { - fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); - } - } - for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { - if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { - fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); - } - } - } - } - } - } - } - } // end loop over track cuts - } // end loop over dilepton cuts - } // end loop over associations - } // end loop over dileptons - } - - Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; - Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; - - void processBarrelSkimmed(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - // set up KF or DCAfitter - if (events.size() == 0) { - return; - } - if (fCurrentRun != events.begin().runNumber()) { // start: runNumber - initParamsFromCCDB(events.begin().timestamp()); - fCurrentRun = events.begin().runNumber(); - } // end: runNumber - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); - auto groupedDielectrons = dileptons.sliceBy(dielectronsPerCollision, event.globalIndex()); - runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDielectrons, mcEvents, mcTracks); - } - } - - void processDstarToD0Pi(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - // set up KF or DCAfitter - if (events.size() == 0) { - return; - } - if (fCurrentRun != events.begin().runNumber()) { // start: runNumber - initParamsFromCCDB(events.begin().timestamp()); - fCurrentRun = events.begin().runNumber(); - } // end: runNumber - for (auto& event : events) { - auto groupedBarrelAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); - auto groupedDitracks = ditracks.sliceBy(ditracksPerCollision, event.globalIndex()); - runDileptonHadron(event, groupedBarrelAssocs, tracks, groupedDitracks, mcEvents, mcTracks); - } - } - - Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice dimuonsPerCollision = aod::reducedpair::reducedeventId; - - void processMuonSkimmed(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyMuonTracksWithCov const& tracks, soa::Filtered const& dileptons, - ReducedMCEvents const& mcEvents, ReducedMCTracks const& mcTracks) - { - // set up KF or DCAfitter - if (events.size() == 0) { - return; - } - if (fCurrentRun != events.begin().runNumber()) { // start: runNumber - initParamsFromCCDB(events.begin().timestamp()); - fCurrentRun = events.begin().runNumber(); - } // end: runNumber - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - auto groupedMuonAssocs = assocs.sliceBy(muonAssocsPerCollision, event.globalIndex()); - auto groupedDimuons = dileptons.sliceBy(dimuonsPerCollision, event.globalIndex()); - runDileptonHadron(event, groupedMuonAssocs, tracks, groupedDimuons, mcEvents, mcTracks); - } - } - - void processMCGen(ReducedMCTracks const& mcTracks) - { - // loop over mc stack and fill histograms for pure MC truth signals - // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedtrackMC::reducedMCeventId, event.reducedMCevent().globalIndex()); - for (auto& mctrack : mcTracks) { - - if ((std::abs(mctrack.pdgCode()) > 400 && std::abs(mctrack.pdgCode()) < 599) || - (std::abs(mctrack.pdgCode()) > 4000 && std::abs(mctrack.pdgCode()) < 5999) || - mctrack.mcReducedFlags() > 0) { - /*cout << ">>>>>>>>>>>>>>>>>>>>>>> track idx / pdg / selections: " << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / "; - PrintBitMap(mctrack.mcReducedFlags(), 16); - cout << endl; - if (mctrack.has_mothers()) { - for (auto& m : mctrack.mothersIds()) { - if (m < mcTracks.size()) { // protect against bad mother indices - auto aMother = mcTracks.rawIteratorAt(m); - cout << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode() << endl; - } - } - } - - if (mctrack.has_daughters()) { - for (int d = mctrack.daughtersIds()[0]; d <= mctrack.daughtersIds()[1]; ++d) { - if (d < mcTracks.size()) { // protect against bad daughter indices - auto aDaughter = mcTracks.rawIteratorAt(d); - cout << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode() << endl; - } - } - }*/ - } - - VarManager::FillTrackMC(mcTracks, mctrack); - // NOTE: Signals are checked here mostly based on the skimmed MC stack, so depending on the requested signal, the stack could be incomplete. - // NOTE: However, the working model is that the decisions on MC signals are precomputed during skimming and are stored in the mcReducedFlags member. - // TODO: Use the mcReducedFlags to select signals - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, mctrack)) { - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - - PresliceUnsorted perReducedMcEvent = aod::reducedtrackMC::reducedMCeventId; - - void processMCGenWithEventSelection(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& track : groupedMCTracks) { - - VarManager::FillTrackMC(mcTracks, track); - - auto track_raw = groupedMCTracks.rawIteratorAt(track.globalIndex()); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, track_raw)) { - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); - } - } - } - - // make a list of all MC tracks in the MC collision corresponding to the current reconstructed event - std::vector mcTrackIndices; - for (auto& t : groupedMCTracks) { - mcTrackIndices.push_back(t.globalIndex()); - } - - // make a three nested for loop over all MC tracks in the vector - for (auto t1 : mcTrackIndices) { - auto track1 = mcTracks.rawIteratorAt(*(&t1)); - for (auto t2 : mcTrackIndices) { - if (t1 == t2) - continue; - // if (t2 < t1) continue; - auto track2 = mcTracks.rawIteratorAt(*(&t2)); - for (auto t3 : mcTrackIndices) { - if (t3 == t1) - continue; - if (t3 == t2) - continue; - auto track3 = mcTracks.rawIteratorAt(*(&t3)); - - for (auto& sig : fRecMCSignals) { - if (sig->CheckSignal(true, track1, track2, track3)) { - - VarManager::FillTripleMC(track1, track2, track3, VarManager::fgValues); // nb! hardcoded for jpsiK - - fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); - - // apply kinematic cuts - if (track1.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track1.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { - continue; - } - if (track2.pt() < fConfigMCGenDileptonLegPtMin.value || std::abs(track2.eta()) > fConfigMCGenDileptonLegEtaAbs.value) { - continue; - } - if (track3.pt() < fConfigMCGenHadronPtMin.value || std::abs(track3.eta()) > fConfigMCGenHadronEtaAbs.value) { - continue; - } - fHistMan->FillHistClass(Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - } // end loop over reconstructed events - } - - template - void runEnergyCorrelators(TEvent const& event, TMCTracks const& mcTracks) - { - auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.reducedMCeventId()); - groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& t1 : groupedMCTracks) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - // apply kinematic cuts for signal - if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) - continue; - if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) - continue; - // for the energy correlators - for (auto& t2 : groupedMCTracks) { - auto t2_raw = groupedMCTracks.rawIteratorAt(t2.globalIndex()); - if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) - continue; - if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) - continue; - if (t2_raw.getGenStatusCode() <= 0) - continue; - VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, t1_raw)) { - fHistMan->FillHistClass(Form("MCTruthEenergyCorrelators_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - void processMCGenEnergyCorrelators(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - runEnergyCorrelators(event, mcTracks); - } - } - - void processMCGenEnergyCorrelatorsPion(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - for (auto& event : events) { - if (!event.isEventSelected_bit(0)) { - continue; - } - if (!event.has_reducedMCevent()) { - continue; - } - runEnergyCorrelators(event, mcTracks); - } - } - - template - void runEnergyCorrelatorsMixedEvent(TEvent const& event1, TEvent const& event2, TMCTracks const& mcTracks) - { - auto groupedMCTracks1 = mcTracks.sliceBy(perReducedMcEvent, event1.reducedMCeventId()); - auto groupedMCTracks2 = mcTracks.sliceBy(perReducedMcEvent, event2.reducedMCeventId()); - groupedMCTracks1.bindInternalIndicesTo(&mcTracks); - groupedMCTracks2.bindInternalIndicesTo(&mcTracks); - for (auto& t1 : groupedMCTracks1) { - auto t1_raw = mcTracks.rawIteratorAt(t1.globalIndex()); - // apply kinematic cuts for signal - if ((t1_raw.pt() < fConfigDileptonLowpTCut || t1_raw.pt() > fConfigDileptonHighpTCut)) - continue; - if (abs(t1_raw.y()) > fConfigDileptonRapCutAbs) - continue; - // for the energy correlators - for (auto& t2 : groupedMCTracks2) { - auto t2_raw = groupedMCTracks2.rawIteratorAt(t2.globalIndex()); - if (TMath::Abs(t2_raw.pdgCode()) == 443 || TMath::Abs(t2_raw.pdgCode()) == 11 || TMath::Abs(t2_raw.pdgCode()) == 22) - continue; - if (t2_raw.pt() < fConfigMCGenHadronPtMin.value || std::abs(t2_raw.eta()) > fConfigMCGenHadronEtaAbs.value) - continue; - if (t2_raw.getGenStatusCode() <= 0) - continue; - VarManager::FillEnergyCorrelatorsMC(t1_raw, t2_raw, VarManager::fgValues); - for (auto& sig : fGenMCSignals) { - if (sig->CheckSignal(true, t1_raw)) { - fHistMan->FillHistClass(Form("MCTruthEenergyCorrelatorsME_%s", sig->GetName()), VarManager::fgValues); - } - } - } - } - } - - void processMCGenEnergyCorrelatorsME(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - // loop over two event comibnations - for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { - if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { - continue; - } - if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { - continue; - } - runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); - } - } - - void processMCGenEnergyCorrelatorsPionME(soa::Filtered const& events, - ReducedMCEvents const& /*mcEvents*/, ReducedMCTracks const& mcTracks) - { - if (events.size() == 0) { - LOG(warning) << "No events in this TF, going to the next one ..."; - return; - } - // loop over two event comibnations - for (auto& [event1, event2] : selfCombinations(fHashBin, fConfigMixingDepth.value, -1, events, events)) { - if (!event1.isEventSelected_bit(0) || !event2.isEventSelected_bit(0)) { - continue; - } - if (!event1.has_reducedMCevent() || !event2.has_reducedMCevent()) { - continue; - } - runEnergyCorrelatorsMixedEvent(event1, event2, mcTracks); - } - } - - void processDummy(MyEvents&) - { - // do nothing - } - - PROCESS_SWITCH(AnalysisDileptonTrack, processBarrelSkimmed, "Run barrel dilepton-track pairing, using skimmed data", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processDstarToD0Pi, "Run barrel pairing of D0 daughters with pion candidate, using skimmed data", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMuonSkimmed, "Run muon dilepton-track pairing, using skimmed data", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGen, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenWithEventSelection, "Loop over MC particle stack and fill generator level histograms", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelators, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPion, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processMCGenEnergyCorrelatorsPionME, "Loop over MC particle stack and fill generator level histograms(energy correlators)", false); - PROCESS_SWITCH(AnalysisDileptonTrack, processDummy, "Dummy function", true); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; -} - -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) -{ - // - // Define here the histograms for all the classes required in analysis. - // The histogram classes are provided in the histClasses string, separated by semicolon ";" - // The histogram classes and their components histograms are defined below depending on the name of the histogram class - // - std::unique_ptr objArray(histClasses.Tokenize(";")); - for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { - TString classStr = objArray->At(iclass)->GetName(); - histMan->AddHistClass(classStr.Data()); - - TString histName = histGroups; - // NOTE: The level of detail for histogramming can be controlled via configurables - if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); - } - - if (classStr.Contains("SameBunchCorrelations") || classStr.Contains("OutOfBunchCorrelations")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); - } - - if ((classStr.Contains("Track") || classStr.Contains("Assoc")) && !classStr.Contains("Pairs")) { - if (classStr.Contains("Barrel")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); - if (classStr.Contains("PIDCalibElectron")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); - } - if (classStr.Contains("PIDCalibPion")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_pion"); - } - if (classStr.Contains("PIDCalibProton")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); - } - if (classStr.Contains("Ambiguity")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); - } - } - } - if (classStr.Contains("Muon") && !classStr.Contains("Pairs")) { - if (!classStr.Contains("Ambiguity")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); - } else { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "muon-ambiguity"); - } - } - - if (classStr.Contains("Pairs")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); - } - - if (classStr.Contains("Triplets")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); - } - - if (classStr.Contains("MCTruthGenPair")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_pair", histName); - } - - if (classStr.Contains("MCTruthGenSelBR")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_triple"); - } else if (classStr.Contains("MCTruthGen")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); - } - - // if (classStr.Contains("MCTruthGen")) { - // dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "mctruth_track"); - // } - - if (classStr.Contains("DileptonsSelected")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); - } - - if (classStr.Contains("DileptonTrack") && !classStr.Contains("ME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); - } - - if (classStr.Contains("DileptonTrackME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "mixedevent"); - } - - if (classStr.Contains("HadronsSelected")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); - } - - if (classStr.Contains("DileptonHadronInvMass")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); - } - - if (classStr.Contains("DileptonHadronCorrelation")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); - } - - if (classStr.Contains("MCTruthEenergyCorrelators")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "energy-correlator-gen"); - } - - } // end loop over histogram classes -} From 8cf0697a2fa72b947971fd53544cf8575f3b180b Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Sun, 9 Nov 2025 18:26:50 +0800 Subject: [PATCH 15/17] Add files via upload --- PWGDQ/Tasks/dqEfficiency_withAssoc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index 76e81dd5a8d..470d32513bd 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -163,7 +163,7 @@ DECLARE_SOA_COLUMN(OniaVz, oniaVz, float); DECLARE_SOA_COLUMN(OniaVtxZ, oniaVtxZ, float); } // namespace dqanalysisflags -DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); +DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTS", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTS", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMB", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks From 32ffdfd57b2139484f0dfb6c380b31fb587c7f67 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Mon, 10 Nov 2025 11:17:25 +0800 Subject: [PATCH 16/17] Add files via upload --- PWGDQ/Core/VarManager.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index a0ccaccbc3f..63a198dccd4 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -156,9 +156,9 @@ class VarManager : public TObject kDecayToKPi, // e.g. D0 -> K+ pi- or cc. kTripleCandidateToKPiPi, // e.g. D+ -> K- pi+ pi+ kTripleCandidateToPKPi, // e.g. Lambda_c -> p K- pi+ - kNMaxCandidateTypes, - kJpsiHadronMass, // using the real hadron mass - kJpsiPionMass // treat the hadron as pion + kJpsiHadronMass, // using the real hadron mass + kJpsiPionMass, // treat the hadron as pion + kNMaxCandidateTypes }; enum BarrelTrackFilteringBits { @@ -1311,7 +1311,7 @@ class VarManager : public TObject static float calculatePhiV(const T1& t1, const T2& t2); template static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); - static float RotationDeltaPhi(float deltaphi) + static float RotationDeltaPhi(float deltaphi) // rotate deltaphi to the range -0.5*pi < deltaphi < 1.5*pi { if (deltaphi > 3.0 / 2.0 * TMath::Pi()) { deltaphi -= 2.0 * TMath::Pi(); From 971f0630b1f8ad84c08faa49b042420277f7d380 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Mon, 10 Nov 2025 11:47:44 +0800 Subject: [PATCH 17/17] Add files via upload --- PWGDQ/Core/VarManager.h | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 63a198dccd4..675f2971554 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -1311,16 +1311,6 @@ class VarManager : public TObject static float calculatePhiV(const T1& t1, const T2& t2); template static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); - static float RotationDeltaPhi(float deltaphi) // rotate deltaphi to the range -0.5*pi < deltaphi < 1.5*pi - { - if (deltaphi > 3.0 / 2.0 * TMath::Pi()) { - deltaphi -= 2.0 * TMath::Pi(); - } - if (deltaphi < -0.5 * TMath::Pi()) { - deltaphi += 2.0 * TMath::Pi(); - } - return deltaphi; - } static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; @@ -2836,7 +2826,7 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va MassHadron = o2::constants::physics::MassPionCharged; } ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); - float deltaphi = RotationDeltaPhi(track.phi() - t1.phi()); + float deltaphi = RecoDecay::constrainAngle(track.phi() - t1.phi(), -o2::constants::math::PIHalf); float deltaeta = t1.eta() - track.eta(); ROOT::Math::PtEtaPhiMVector v2(t1.pt(), t1.eta(), t1.phi(), MassHadron); float E_boost = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2); @@ -2886,9 +2876,9 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va values[kMCWeight_trans_minus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_trans_minus) / o2::constants::physics::MassJPsi; values[kMCdeltaphi_minus] = deltaphi; - values[kMCdeltaphi_toward_minus] = RotationDeltaPhi(track.phi() - (t1.phi() - 0.5 * TMath::Pi())); - values[kMCdeltaphi_away_minus] = RotationDeltaPhi(track.phi() - (t1.phi() + 0.5 * TMath::Pi())); - values[kMCdeltaphi_trans_minus] = RotationDeltaPhi(track.phi() - t1.phi() + TMath::Pi()); + values[kMCdeltaphi_toward_minus] = RecoDecay::constrainAngle(track.phi() - (t1.phi() - 0.5 * TMath::Pi()), -o2::constants::math::PIHalf); + values[kMCdeltaphi_away_minus] = RecoDecay::constrainAngle(track.phi() - (t1.phi() + 0.5 * TMath::Pi()), -o2::constants::math::PIHalf); + values[kMCdeltaphi_trans_minus] = RecoDecay::constrainAngle(track.phi() - t1.phi() + TMath::Pi(), -o2::constants::math::PIHalf); } values[kMCCosChi_plus] = -999.9f; @@ -2925,9 +2915,9 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va values[kMCWeight_trans_plus] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_trans_plus) / o2::constants::physics::MassJPsi; values[kMCdeltaphi_plus] = deltaphi; - values[kMCdeltaphi_toward_plus] = RotationDeltaPhi(track.phi() - (t1.phi() + 0.5 * TMath::Pi())); - values[kMCdeltaphi_away_plus] = RotationDeltaPhi(track.phi() - (t1.phi() - 0.5 * TMath::Pi())); - values[kMCdeltaphi_trans_plus] = RotationDeltaPhi(track.phi() - t1.phi() + TMath::Pi()); + values[kMCdeltaphi_toward_plus] = RecoDecay::constrainAngle(track.phi() - (t1.phi() + 0.5 * TMath::Pi()), -o2::constants::math::PIHalf); + values[kMCdeltaphi_away_plus] = RecoDecay::constrainAngle(track.phi() - (t1.phi() - 0.5 * TMath::Pi()), -o2::constants::math::PIHalf); + values[kMCdeltaphi_trans_plus] = RecoDecay::constrainAngle(track.phi() - (t1.phi() - 0.5 * TMath::Pi()), -o2::constants::math::PIHalf); } }