From dc840db09a50422c3acc1397917f61ec9589f61b Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Tue, 28 Oct 2025 21:03:49 +0800 Subject: [PATCH 01/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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/24] 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); } } From c1110d1bc561808f66756fd0d32f4fa9683a4b82 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 17:28:26 +0800 Subject: [PATCH 18/24] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 53 +++---- PWGDQ/Core/VarManager.cxx | 3 - PWGDQ/Core/VarManager.h | 233 ++++++++++++++++--------------- 3 files changed, 141 insertions(+), 148 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 4cc9f07a0bf..6b6afe3122e 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -977,41 +977,20 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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, "Phi_Hadron", "", false, 120, -2.0, 2.0, VarManager::kMCHadronPhi); 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, 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); - 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); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_1", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_1); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_2", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_2); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_3", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_3); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_4", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_4); + + hm->AddHistogram(histClass, "Coschi_randomPhi_1", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_1, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_1); + hm->AddHistogram(histClass, "Coschi_randomPhi_2", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_2, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_2); + hm->AddHistogram(histClass, "Coschi_randomPhi_3", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_3, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_3); + hm->AddHistogram(histClass, "Coschi_randomPhi_4", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_4, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_4); } if (!groupStr.CompareTo("pair")) { if (subGroupStr.Contains("cepf")) { @@ -1052,6 +1031,7 @@ 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, 500, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); 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); @@ -1947,6 +1927,7 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } 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_woweight", "", false, 40, -1.0, 1.0, VarManager::kCosTheta); 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); @@ -1954,8 +1935,14 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); + // for bkg + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_trans", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_trans); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_toward", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_toward); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_away", "", false, 50, -8.0, 8.0, VarManager::kdeltaphi_randomPhi_away); + + hm->AddHistogram(histClass, "Coschi_randomPhi_trans", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_trans, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_trans); + hm->AddHistogram(histClass, "Coschi_randomPhi_toward", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_toward, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_toward); + hm->AddHistogram(histClass, "Coschi_randomPhi_away", "", false, 40, -1.0, 1.0, VarManager::kCosChi_randomPhi_away, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kWeight_randomPhi_away); } } diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index 04445304d56..7ce441f2348 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -752,8 +752,6 @@ void VarManager::SetDefaultVarNames() 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"; @@ -1725,7 +1723,6 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kMCHadronPdgCode"] = kMCHadronPdgCode; fgVarNamesMap["kMCCosChi"] = kMCCosChi; fgVarNamesMap["kMCHadronPt"] = kMCHadronPt; - fgVarNamesMap["kMCCosChi_minus"] = kMCCosChi_minus; fgVarNamesMap["kMCWeight_before"] = kMCWeight_before; fgVarNamesMap["kMCParticleWeight"] = kMCParticleWeight; fgVarNamesMap["kMCPx"] = kMCPx; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index f887b75852d..e06fbd62a3b 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -627,40 +627,20 @@ class VarManager : public TObject kMCdeltaeta, kMCHadronPt, kMCHadronEta, + kMCHadronPhi, kMCWeight, - 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, + kMCCosChi_randomPhi_1, + kMCWeight_randomPhi_1, + kMCCosChi_randomPhi_2, + kMCWeight_randomPhi_2, + kMCCosChi_randomPhi_3, + kMCWeight_randomPhi_3, + kMCCosChi_randomPhi_4, + kMCWeight_randomPhi_4, + kMCdeltaphi_randomPhi_1, + kMCdeltaphi_randomPhi_2, + kMCdeltaphi_randomPhi_3, + kMCdeltaphi_randomPhi_4, kMCWeight_before, // MC mother particle variables @@ -877,6 +857,15 @@ class VarManager : public TObject kPtDau, kCosTheta, kEWeight_before, + kCosChi_randomPhi_trans, + kCosChi_randomPhi_toward, + kCosChi_randomPhi_away, + kWeight_randomPhi_trans, + kWeight_randomPhi_toward, + kWeight_randomPhi_away, + kdeltaphi_randomPhi_trans, + kdeltaphi_randomPhi_toward, + kdeltaphi_randomPhi_away, // Dilepton-track-track variables kQuadMass, @@ -1724,11 +1713,20 @@ void VarManager::FillEvent(T const& event, float* values) } if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { - values[kMultFV0A] = event.multFV0A(); - values[kMultFT0A] = event.multFT0A(); - values[kMultFT0C] = event.multFT0C(); - values[kMultFDDA] = event.multFDDA(); - values[kMultFDDC] = event.multFDDC(); + if constexpr ((fillMap & RapidityGapFilter) > 0) { + // UPC: Use the FIT signals from the nearest BC with FIT amplitude above threshold + values[kMultFV0A] = event.newBcMultFV0A(); + values[kMultFT0A] = event.newBcMultFT0A(); + values[kMultFT0C] = event.newBcMultFT0C(); + values[kMultFDDA] = event.newBcMultFDDA(); + values[kMultFDDC] = event.newBcMultFDDC(); + } else { + values[kMultFV0A] = event.multFV0A(); + values[kMultFT0A] = event.multFT0A(); + values[kMultFT0C] = event.multFT0C(); + values[kMultFDDA] = event.multFDDA(); + values[kMultFDDC] = event.multFDDC(); + } values[kMultTPC] = event.multTPC(); values[kMultFV0C] = event.multFV0C(); values[kMultZNA] = event.multZNA(); @@ -2811,7 +2809,6 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va float MassHadron; if constexpr (pairType == kJpsiHadronMass) { MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); - ; } if constexpr (pairType == kJpsiPionMass) { MassHadron = o2::constants::physics::MassPionCharged; @@ -2830,85 +2827,57 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va values[kMCdeltaeta] = deltaeta; values[kMCHadronPt] = t1.pt(); values[kMCHadronEta] = t1.eta(); + values[kMCHadronPhi] = RecoDecay::constrainAngle(t1.phi(), -o2::constants::math::PIHalf); values[kMCHadronPdgCode] = t1.pdgCode(); values[kMCWeight] = E_boost / 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; + + values[kMCCosChi_randomPhi_1] = -999.9f; + values[kMCCosChi_randomPhi_2] = -999.9f; + values[kMCCosChi_randomPhi_3] = -999.9f; + values[kMCCosChi_randomPhi_4] = -999.9f; + + values[kMCdeltaphi_randomPhi_1] = -999.9f; + values[kMCdeltaphi_randomPhi_2] = -999.9f; + values[kMCdeltaphi_randomPhi_3] = -999.9f; + values[kMCdeltaphi_randomPhi_4] = -999.9f; + + float randomPhi_1 = -o2::constants::math::PIHalf; + float randomPhi_2 = -o2::constants::math::PIHalf; + float randomPhi_3 = -o2::constants::math::PIHalf; + float randomPhi_4 = -o2::constants::math::PIHalf; if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -0.25 * TMath::Pi()) || (deltaphi > 1.25 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi())) { + randomPhi_1 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_2 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - values[kMCCosChi_minus] = CosChi; - values[kMCCosTheta_minus] = CosTheta; - values[kMCWeight_minus] = E_boost / 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_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_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] = 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; - 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; + ROOT::Math::PtEtaPhiMVector v2_randomPhi_1(v2.pt(), v2.eta(), randomPhi_1, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_1] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_1); + values[kMCWeight_randomPhi_1] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_1) / v1.M(); + ; + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_2(v2.pt(), v2.eta(), randomPhi_2, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_2] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_2); + values[kMCWeight_randomPhi_2] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_2) / v1.M(); + + values[kMCdeltaphi_randomPhi_1] = RecoDecay::constrainAngle(v1.phi() - randomPhi_1, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_2] = RecoDecay::constrainAngle(v1.phi() - randomPhi_2, -o2::constants::math::PIHalf); + } if (deltaphi > 0.25 * TMath::Pi() && deltaphi < 0.75 * TMath::Pi()) { - values[kMCCosChi_plus] = CosChi; - values[kMCCosTheta_plus] = CosTheta; - values[kMCWeight_plus] = E_boost / 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_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_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] = 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); + randomPhi_3 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_4 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_3(v2.pt(), v2.eta(), randomPhi_3, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_3] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_3); + values[kMCWeight_randomPhi_3] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_3) / v1.M(); + ; + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_4(v2.pt(), v2.eta(), randomPhi_4, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_4] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_4); + values[kMCWeight_randomPhi_4] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_4) / v1.M(); + + values[kMCdeltaphi_randomPhi_3] = RecoDecay::constrainAngle(v1.phi() - randomPhi_3, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_4] = RecoDecay::constrainAngle(v1.phi() - randomPhi_4, -o2::constants::math::PIHalf); } } @@ -5250,8 +5219,48 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values[kEWeight_before] = v2.Pt() / v1.M(); values[kPtDau] = v2.pt(); values[kEtaDau] = v2.eta(); - values[kPhiDau] = v2.phi(); + values[kPhiDau] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); + + if (fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + + float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); + values[kCosChi_randomPhi_trans] = -999.9f; + values[kCosChi_randomPhi_toward] = -999.9f; + values[kCosChi_randomPhi_away] = -999.9f; + + values[kdeltaphi_randomPhi_trans] = -999.9f; + values[kdeltaphi_randomPhi_toward] = -999.9f; + values[kdeltaphi_randomPhi_away] = -999.9f; + + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); + ; + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); + + values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); + } + } } + if (fgUsedVars[kDeltaPhi]) { double delta = dilepton.phi() - hadron.phi(); if (delta > 3.0 / 2.0 * M_PI) { From 8f392a8b539786e46283bcbc1f4882b015d71d70 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 17:28:54 +0800 Subject: [PATCH 19/24] Add files via upload --- PWGDQ/Tasks/tableReader_withAssoc.cxx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.cxx index 5423591e7d9..6c9297db8bb 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.cxx @@ -3091,7 +3091,9 @@ struct AnalysisDileptonTrack { Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of cuts for the track 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)"}; @@ -3106,6 +3108,8 @@ struct AnalysisDileptonTrack { 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"}; Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + Configurable fConfigUseRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing"}; + Configurable fConfigEnergycorrelator{"cfgEnergycorrelator", false, "Add some hist for energy correlator study"}; int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. int fNCuts; // number of dilepton leg cuts @@ -3125,7 +3129,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); @@ -3341,6 +3345,9 @@ struct AnalysisDileptonTrack { if (isBarrelME || isMuonME) { DefineHistograms(fHistMan, Form("DileptonTrackME_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), "dilepton-hadron-array-correlation"); // define ME histograms + if (fConfigEnergycorrelator) { + DefineHistograms(fHistMan, Form("DileptonTrackECME_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), "energy-correlator"); // define ME histograms + } } } // end loop over track cuts to be combined with dileptons / di-tracks } // end loop over pair leg track cuts @@ -3403,6 +3410,11 @@ struct AnalysisDileptonTrack { if (dilepton.sign() != 0) { continue; } + // dilepton rap cut + float rap = dilepton.rap(); + if (fConfigUseRapcut && abs(rap) > fConfigDileptonRapCutAbs) + continue; + VarManager::FillTrack(dilepton, fValuesDilepton); // loop over existing dilepton leg cuts (e.g. electron1, electron2, etc) @@ -3658,6 +3670,9 @@ struct AnalysisDileptonTrack { for (uint32_t iTrackCut = 0; iTrackCut < fTrackCutNames.size(); iTrackCut++) { if (trackSelection & (static_cast(1) << iTrackCut)) { fHistMan->FillHistClass(Form("DileptonTrackME_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), VarManager::fgValues); + if (fConfigEnergycorrelator) { + fHistMan->FillHistClass(Form("DileptonTrackECME_%s_%s", fTrackCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), VarManager::fgValues); + } } } } @@ -4051,6 +4066,10 @@ void DefineHistograms(HistogramManager* histMan, TString histClasses, const char dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "dilepton-hadron-array-correlation"); } + if (classStr.Contains("DileptonTrackECME")) { + dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "energy-correlator"); + } + if (classStr.Contains("HadronsSelected")) { dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); } From e46c47520b96184e7d3a135db74dcec20200182e Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 17:54:37 +0800 Subject: [PATCH 20/24] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 16 ++-- PWGDQ/Core/VarManager.h | 144 +++++++++++++------------------ 2 files changed, 68 insertions(+), 92 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 6b6afe3122e..74a905ee6c0 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -982,15 +982,13 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h 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); // for bkg - hm->AddHistogram(histClass, "DeltaPhi_randomPhi_1", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_1); - hm->AddHistogram(histClass, "DeltaPhi_randomPhi_2", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_2); - hm->AddHistogram(histClass, "DeltaPhi_randomPhi_3", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_3); - hm->AddHistogram(histClass, "DeltaPhi_randomPhi_4", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_4); - - hm->AddHistogram(histClass, "Coschi_randomPhi_1", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_1, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_1); - hm->AddHistogram(histClass, "Coschi_randomPhi_2", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_2, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_2); - hm->AddHistogram(histClass, "Coschi_randomPhi_3", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_3, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_3); - hm->AddHistogram(histClass, "Coschi_randomPhi_4", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_4, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_4); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_trans", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_trans); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_toward", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_toward); + hm->AddHistogram(histClass, "DeltaPhi_randomPhi_away", "", false, 50, -8.0, 8.0, VarManager::kMCdeltaphi_randomPhi_away); + + hm->AddHistogram(histClass, "Coschi_randomPhi_trans", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_trans, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_trans); + hm->AddHistogram(histClass, "Coschi_randomPhi_toward", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_toward, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_toward); + hm->AddHistogram(histClass, "Coschi_randomPhi_away", "", false, 40, -1.0, 1.0, VarManager::kMCCosChi_randomPhi_away, 0, 0, 0, -1, 0, 0, 0, -1, "", "", "", -1, VarManager::kMCWeight_randomPhi_away); } if (!groupStr.CompareTo("pair")) { if (subGroupStr.Contains("cepf")) { diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index e06fbd62a3b..af9210cab56 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -629,18 +629,15 @@ class VarManager : public TObject kMCHadronEta, kMCHadronPhi, kMCWeight, - kMCCosChi_randomPhi_1, - kMCWeight_randomPhi_1, - kMCCosChi_randomPhi_2, - kMCWeight_randomPhi_2, - kMCCosChi_randomPhi_3, - kMCWeight_randomPhi_3, - kMCCosChi_randomPhi_4, - kMCWeight_randomPhi_4, - kMCdeltaphi_randomPhi_1, - kMCdeltaphi_randomPhi_2, - kMCdeltaphi_randomPhi_3, - kMCdeltaphi_randomPhi_4, + kMCCosChi_randomPhi_toward, + kMCWeight_randomPhi_toward, + kMCCosChi_randomPhi_away, + kMCWeight_randomPhi_away, + kMCCosChi_randomPhi_trans, + kMCWeight_randomPhi_trans, + kMCdeltaphi_randomPhi_toward, + kMCdeltaphi_randomPhi_away, + kMCdeltaphi_randomPhi_trans, kMCWeight_before, // MC mother particle variables @@ -2831,53 +2828,38 @@ void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* va values[kMCHadronPdgCode] = t1.pdgCode(); values[kMCWeight] = E_boost / o2::constants::physics::MassJPsi; - values[kMCCosChi_randomPhi_1] = -999.9f; - values[kMCCosChi_randomPhi_2] = -999.9f; - values[kMCCosChi_randomPhi_3] = -999.9f; - values[kMCCosChi_randomPhi_4] = -999.9f; + values[kMCCosChi_randomPhi_trans] = -999.9f; + values[kMCCosChi_randomPhi_toward] = -999.9f; + values[kMCCosChi_randomPhi_away] = -999.9f; - values[kMCdeltaphi_randomPhi_1] = -999.9f; - values[kMCdeltaphi_randomPhi_2] = -999.9f; - values[kMCdeltaphi_randomPhi_3] = -999.9f; - values[kMCdeltaphi_randomPhi_4] = -999.9f; + values[kMCdeltaphi_randomPhi_trans] = -999.9f; + values[kMCdeltaphi_randomPhi_toward] = -999.9f; + values[kMCdeltaphi_randomPhi_away] = -999.9f; - float randomPhi_1 = -o2::constants::math::PIHalf; - float randomPhi_2 = -o2::constants::math::PIHalf; - float randomPhi_3 = -o2::constants::math::PIHalf; - float randomPhi_4 = -o2::constants::math::PIHalf; + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; - if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -0.25 * TMath::Pi()) || (deltaphi > 1.25 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi())) { - randomPhi_1 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_2 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - ROOT::Math::PtEtaPhiMVector v2_randomPhi_1(v2.pt(), v2.eta(), randomPhi_1, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_1] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_1); - values[kMCWeight_randomPhi_1] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_1) / v1.M(); - ; - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_2(v2.pt(), v2.eta(), randomPhi_2, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_2] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_2); - values[kMCWeight_randomPhi_2] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_2) / v1.M(); - - values[kMCdeltaphi_randomPhi_1] = RecoDecay::constrainAngle(v1.phi() - randomPhi_1, -o2::constants::math::PIHalf); - values[kMCdeltaphi_randomPhi_2] = RecoDecay::constrainAngle(v1.phi() - randomPhi_2, -o2::constants::math::PIHalf); - } + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kMCWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); - if (deltaphi > 0.25 * TMath::Pi() && deltaphi < 0.75 * TMath::Pi()) { - randomPhi_3 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_4 = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kMCWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); - ROOT::Math::PtEtaPhiMVector v2_randomPhi_3(v2.pt(), v2.eta(), randomPhi_3, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_3] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_3); - values[kMCWeight_randomPhi_3] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_3) / v1.M(); - ; - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_4(v2.pt(), v2.eta(), randomPhi_4, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_4] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_4); - values[kMCWeight_randomPhi_4] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_4) / v1.M(); + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kMCWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); - values[kMCdeltaphi_randomPhi_3] = RecoDecay::constrainAngle(v1.phi() - randomPhi_3, -o2::constants::math::PIHalf); - values[kMCdeltaphi_randomPhi_4] = RecoDecay::constrainAngle(v1.phi() - randomPhi_4, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); } } @@ -5209,7 +5191,7 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* 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]) { + if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { 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); @@ -5221,43 +5203,39 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values[kEtaDau] = v2.eta(); values[kPhiDau] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); - if (fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); + values[kCosChi_randomPhi_trans] = -999.9f; + values[kCosChi_randomPhi_toward] = -999.9f; + values[kCosChi_randomPhi_away] = -999.9f; - float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); - values[kCosChi_randomPhi_trans] = -999.9f; - values[kCosChi_randomPhi_toward] = -999.9f; - values[kCosChi_randomPhi_away] = -999.9f; + values[kdeltaphi_randomPhi_trans] = -999.9f; + values[kdeltaphi_randomPhi_toward] = -999.9f; + values[kdeltaphi_randomPhi_away] = -999.9f; - values[kdeltaphi_randomPhi_trans] = -999.9f; - values[kdeltaphi_randomPhi_toward] = -999.9f; - values[kdeltaphi_randomPhi_away] = -999.9f; + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; - float randomPhi_trans = -o2::constants::math::PIHalf; - float randomPhi_toward = -o2::constants::math::PIHalf; - float randomPhi_away = -o2::constants::math::PIHalf; + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { - randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); - ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); - values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); - ; + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); - ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); - values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); - ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); - values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); - - values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); - values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); - values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); - } + values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); } } From 314f30a538843036f4cc204fb4a0dad694203014 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 18:18:13 +0800 Subject: [PATCH 21/24] Add files via upload --- PWGDQ/Core/HistogramsLibrary.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 74a905ee6c0..af13151a630 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -1029,10 +1029,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, 500, 0.0, 5.0, VarManager::kMass, 40, -2.0, 2.0, VarManager::kRap, 40, 0.0, 20.0, VarManager::kPt); 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); From 9395607948252f3d0d485d1ab7e2828a55be5317 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 18:25:39 +0800 Subject: [PATCH 22/24] Add files via upload --- PWGDQ/VarManager.h | 5840 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5840 insertions(+) create mode 100644 PWGDQ/VarManager.h diff --git a/PWGDQ/VarManager.h b/PWGDQ/VarManager.h new file mode 100644 index 00000000000..2056a88416e --- /dev/null +++ b/PWGDQ/VarManager.h @@ -0,0 +1,5840 @@ +// 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 +// +// Class to handle analysis variables +// + +#ifndef PWGDQ_CORE_VARMANAGER_H_ +#define PWGDQ_CORE_VARMANAGER_H_ + +#ifndef HomogeneousField +#define HomogeneousField +#endif + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/CollisionTypeHelper.h" +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/fwdtrackUtilities.h" +#include "Common/Core/trackUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using std::complex; +using std::cout; +using std::endl; + +using SMatrix55 = ROOT::Math::SMatrix>; +using SMatrix5 = ROOT::Math::SVector; +using Vec3D = ROOT::Math::SVector; + +//_________________________________________________________________________ +class VarManager : public TObject +{ + public: + // map the information contained in the objects passed to the Fill functions + enum ObjTypes { + // NOTE: Elements containing "Reduced" in their name refer strictly to skimmed data tables + // and the ones that don't refer to tables from the Framework data model or both models + BC = BIT(0), + Collision = BIT(1), + CollisionCentRun2 = BIT(2), + CollisionTimestamp = BIT(3), + ReducedEvent = BIT(4), + ReducedEventExtended = BIT(5), + ReducedEventVtxCov = BIT(6), + CollisionMC = BIT(7), + ReducedEventMC = BIT(8), + ReducedEventQvector = BIT(9), + CollisionCent = BIT(10), + CollisionMult = BIT(11), + EventFilter = BIT(12), + CollisionQvect = BIT(13), + ReducedEventQvectorExtra = BIT(14), + ReducedEventRefFlow = BIT(15), + Zdc = BIT(16), + ReducedZdc = BIT(17), + CollisionMultExtra = BIT(18), + ReducedEventMultExtra = BIT(19), + CollisionQvectCentr = BIT(20), + RapidityGapFilter = BIT(21), + Track = BIT(0), + TrackCov = BIT(1), + TrackExtra = BIT(2), + TrackPID = BIT(3), // used for basic PID properties (needed such that we can subscribe to a minimal set of PID tables): e,pi,K,p for TPC and TOF + TrackPIDExtra = BIT(4), // extra PID information + TrackDCA = BIT(5), + TrackSelection = BIT(6), + TrackV0Bits = BIT(7), + ReducedTrack = BIT(8), + ReducedTrackBarrel = BIT(9), + ReducedTrackBarrelCov = BIT(10), + ReducedTrackBarrelPID = BIT(11), + Muon = BIT(12), + MuonCov = BIT(13), + ReducedMuon = BIT(14), + ReducedMuonExtra = BIT(15), + ReducedMuonCov = BIT(16), + ParticleMC = BIT(17), + Pair = BIT(18), // TODO: check whether we really need the Pair member here + AmbiTrack = BIT(19), + AmbiMuon = BIT(20), + DalitzBits = BIT(21), + TrackTPCPID = BIT(22), + TrackMFT = BIT(23), + ReducedTrackCollInfo = BIT(24), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo + ReducedMuonCollInfo = BIT(25), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo + MuonRealign = BIT(26), + MuonCovRealign = BIT(27), + MFTCov = BIT(28) + }; + + enum PairCandidateType { + // TODO: need to agree on a scheme to incorporate all various hypotheses (e.g. e - mu, jpsi - K+, Jpsi - pipi,...) + kDecayToEE = 0, // e.g. J/psi -> e+ e- + kDecayToMuMu, // e.g. J/psi -> mu+ mu- + kDecayToPiPi, + kElectronMuon, // e.g. Electron - muon correlations + kBcToThreeMuons, // e.g. Bc -> mu+ mu- mu+ + kBtoJpsiEEK, // e.g. B+ -> e+ e- K+ + kJpsiEEProton, // e.g. Jpsi-proton correlation, Jpsi to e+e- + kXtoJpsiPiPi, // e.g. X(3872) -> J/psi pi+ pi- + kPsi2StoJpsiPiPi, // e.g. Psi(2S) -> J/psi pi+ pi- + kChictoJpsiEE, // e.g. Chi_c1 -> J/psi e+ e- + kDstarToD0KPiPi, // e.g. D*+ -> D0 pi+ -> K- pi+ pi+ + kTripleCandidateToEEPhoton, // e.g. chi_c -> e+ e- photon or pi0 -> e+ e- photon + kDecayToKPi, // e.g. D0 -> K+ pi- or cc. + kTripleCandidateToKPiPi, // e.g. D+ -> K- pi+ pi+ + kTripleCandidateToPKPi, // e.g. Lambda_c -> p K- pi+ + kJpsiHadronMass, // using the real hadron mass + kJpsiPionMass, // treat the hadron as pion + kNMaxCandidateTypes + }; + + enum BarrelTrackFilteringBits { + kIsConversionLeg = 0, // electron from conversions + kIsK0sLeg, // pion from K0s + kIsLambdaLeg, // proton or pion from Lambda + kIsALambdaLeg, // proton or pion from anti-Lambda + kIsOmegaLeg, // kaon from Omega baryon decay + kDalitzBits = 5, // first bit for Dalitz tagged tracks + kBarrelUserCutsBits = 13, // first bit for user track cuts + kIsTPCPostcalibrated = 63 // tracks were postcalibrated for the TPC PID + }; + + enum MuonTrackFilteringBits { + kMuonUserCutsBits = 0, // first bit for user muon cuts + kMuonIsPropagated = 7 // whether the muon was propagated already + }; + + public: + enum Variables { + kNothing = -1, + // Run wise variables + kRunNo = 0, + kNRunWiseVariables, + + // Event wise variables + kTimestamp, + kTimeFromSOR, // Time since Start of Run (SOR) in minutes + kCollisionTime, + kCollisionTimeRes, + kBC, + kBCOrbit, + kIsPhysicsSelection, + kIsNoTFBorder, // No time frame border + kIsNoITSROFBorder, // No ITS read out frame border (from event selection) + kIsNoITSROFBorderRecomputed, // No ITS read out frame border, computed here + kIsNoSameBunch, // No collisions with same T0 BC + kIsGoodZvtxFT0vsPV, // No collisions w/ difference between z_ {PV, tracks} and z_{PV FT0A-C} + kIsVertexITSTPC, // At least one ITS-TPC track + kIsVertexTOFmatched, // At least one TOF-matched track + kIsSel8, // TVX in Run3 && No time frame border && No ITS read out frame border (from event selection) + kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value + kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values + kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values + kIsINT7, + kIsEMC7, + kIsINT7inMUON, + kIsMuonSingleLowPt7, + kIsMuonSingleHighPt7, + kIsMuonUnlikeLowPt7, + kIsMuonLikeLowPt7, + kIsCUP8, + kIsCUP9, + kIsMUP10, + kIsMUP11, + kVtxX, + kVtxY, + kVtxZ, + kVtxNcontrib, + kVtxNcontribReal, + kVtxCovXX, + kVtxCovXY, + kVtxCovXZ, + kVtxCovYY, + kVtxCovYZ, + kVtxCovZZ, + kVtxChi2, + kCentVZERO, + kCentFT0C, + kCentFT0A, + kCentFT0M, + kMultTPC, + kMultFV0A, + kMultFV0C, + kMultFT0A, + kMultFT0C, + kMultFDDA, + kMultFDDC, + kMultZNA, + kMultZNC, + kMultTracklets, + kMultDimuons, + kMultAntiMuons, + kMultMuons, + kMultSingleMuons, + kMultNTracksHasITS, + kMultNTracksHasTPC, + kMultNTracksHasTOF, + kMultNTracksHasTRD, + kMultNTracksITSOnly, + kMultNTracksTPCOnly, + kMultNTracksITSTPC, + kMultNTracksPVeta1, + kMultNTracksPVetaHalf, + kTrackOccupancyInTimeRange, + kFT0COccupancyInTimeRange, + kNoCollInTimeRangeStandard, + kMultAllTracksTPCOnly, + kMultAllTracksITSTPC, + kNTPCpileupContribA, + kNTPCpileupContribC, + kNTPCpileupZA, + kNTPCpileupZC, + kNTPCtracksInPast, + kNTPCtracksInFuture, + kNTPCcontribLongA, + kNTPCcontribLongC, + kNTPCmeanTimeLongA, + kNTPCmeanTimeLongC, + kNTPCmedianTimeLongA, + kNTPCmedianTimeLongC, + kNTPCcontribShortA, + kNTPCcontribShortC, + kNTPCmeanTimeShortA, + kNTPCmeanTimeShortC, + kNTPCmedianTimeShortA, + kNTPCmedianTimeShortC, + kMCEventGeneratorId, + kMCEventSubGeneratorId, + kMCVtxX, + kMCVtxY, + kMCVtxZ, + kMCEventTime, + kMCEventWeight, + kMCEventImpParam, + kMCEventCentrFT0C, + kMultMCNParticlesEta10, + kMultMCNParticlesEta08, + kMultMCNParticlesEta05, + kQ1ZNAX, + kQ1ZNAY, + kQ1ZNCX, + kQ1ZNCY, + KIntercalibZNA, + KIntercalibZNC, + kQ1ZNACXX, + kQ1ZNACYY, + kQ1ZNACYX, + kQ1ZNACXY, + kQ1X0A, // q-vector (e.g. from TPC) with x component (harmonic 1 and power 0), sub-event A + kQ1Y0A, // q-vector (e.g. from TPC) with y component (harmonic 1 and power 0), sub-event A + kQ1X0B, + kQ1Y0B, + kQ1X0C, + kQ1Y0C, + kQ2X0A, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 0), sub-event A + kQ2Y0A, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 0), sub-event A + kQ2X0APOS, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 1), Pos. TPC + kQ2Y0APOS, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 1), Pos. TPC + kQ2X0ANEG, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 1), Neg. TPC + kQ2Y0ANEG, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 1), Neg. TPC + kQ2X0B, + kQ2Y0B, + kQ2X0C, + kQ2Y0C, + kQ2YYAB, + kQ2XXAB, + kQ2XYAB, + kQ2YXAB, + kQ2YYAC, + kQ2XXAC, + kQ2XYAC, + kQ2YXAC, + kQ2YYBC, + kQ2XXBC, + kQ2XYBC, + kQ2YXBC, + kMultA, // Multiplicity of the sub-event A + kMultAPOS, // Multiplicity of the sub-event A + kMultANEG, // Multiplicity of the sub-event A + kMultB, + kMultC, + kQ3X0A, // q-vector (e.g. from TPC) with x component (harmonic 3 and power 0), sub-event A + kQ3Y0A, // q-vector (e.g. from TPC) with y component (harmonic 3 and power 0), sub-event A + kQ3X0B, + kQ3Y0B, + kQ3X0C, + kQ3Y0C, + kQ4X0A, // q-vector (e.g. from TPC) with x component (harmonic 4 and power 0), sub-event A + kQ4Y0A, // q-vector (e.g. from TPC) with y component (harmonic 4 and power 0), sub-event A + kQ4X0B, + kQ4Y0B, + kQ4X0C, + kQ4Y0C, + kR2SP_AB, + kR2SP_AC, + kR2SP_BC, + kWR2SP_AB, + kWR2SP_AC, + kWR2SP_BC, + kR2SP_AB_Im, + kR2SP_AC_Im, + kR2SP_BC_Im, + kWR2SP_AB_Im, + kWR2SP_AC_Im, + kWR2SP_BC_Im, + kR2SP_FT0CTPCPOS, + kR2SP_FT0CTPCNEG, + kR2SP_FT0ATPCPOS, + kR2SP_FT0ATPCNEG, + kR2SP_FT0MTPCPOS, + kR2SP_FT0MTPCNEG, + kR2SP_FV0ATPCPOS, + kR2SP_FV0ATPCNEG, + kR3SP, + kR2EP_AB, + kR2EP_AC, + kR2EP_BC, + kWR2EP_AB, + kWR2EP_AC, + kWR2EP_BC, + kR2EP_AB_Im, + kR2EP_AC_Im, + kR2EP_BC_Im, + kWR2EP_AB_Im, + kWR2EP_AC_Im, + kWR2EP_BC_Im, + kR2EP_FT0CTPCPOS, + kR2EP_FT0CTPCNEG, + kR2EP_FT0ATPCPOS, + kR2EP_FT0ATPCNEG, + kR2EP_FT0MTPCPOS, + kR2EP_FT0MTPCNEG, + kR2EP_FV0ATPCPOS, + kR2EP_FV0ATPCNEG, + kR3EP, + kIsDoubleGap, // Double rapidity gap + kIsSingleGapA, // Rapidity gap on side A + kIsSingleGapC, // Rapidity gap on side C + kIsSingleGap, // Rapidity gap on either side + kIsITSUPCMode, // UPC mode used for event + kTwoEvPosZ1, // vtx-z for collision 1 in two events correlations + kTwoEvPosZ2, // vtx-z for collision 2 in two events correlations + kTwoEvPosR1, // vtx-R for collision 1 in two events correlations + kTwoEvPosR2, + kTwoEvCentFT0C1, + kTwoEvCentFT0C2, + kTwoEvPVcontrib1, // n-contributors for collision 1 in two events correlations + kTwoEvPVcontrib2, + kTwoEvDeltaZ, // distance in z between collisions + kTwoEvDeltaX, // distance in x between collisions + kTwoEvDeltaY, // distance in y between collisions + kTwoEvDeltaR, // distance in (x,y) plane between collisions + kEnergyCommonZNA, + kEnergyCommonZNC, + kEnergyCommonZPA, + kEnergyCommonZPC, + kEnergyZNA1, + kEnergyZNA2, + kEnergyZNA3, + kEnergyZNA4, + kEnergyZNC1, + kEnergyZNC2, + kEnergyZNC3, + kEnergyZNC4, + kTimeZNA, + kTimeZNC, + kTimeZPA, + kTimeZPC, + kQ2X0A1, + kQ2X0A2, + kQ2Y0A1, + kQ2Y0A2, + kU2Q2Ev1, + kU2Q2Ev2, + kCos2DeltaPhiEv1, + kCos2DeltaPhiEv2, + kV2SP1, + kV2SP2, + kV2EP1, + kV2EP2, + kV2ME_SP, + kV2ME_EP, + kWV2ME_SP, + kWV2ME_EP, + kTwoR2SP1, // Scalar product resolution of event1 for ME technique + kTwoR2SP2, // Scalar product resolution of event2 for ME technique + kTwoR2EP1, // Event plane resolution of event2 for ME technique + kTwoR2EP2, // Event plane resolution of event2 for ME technique + kNEventWiseVariables, + + // Variables for event mixing with cumulant + kV22m, + kV24m, + kV22p, + kV24p, + kV22ME, + kV24ME, + kWV22ME, + kWV24ME, + + // Basic track/muon/pair wise variables + kX, + kY, + kZ, + kPt, + kSignedPt, + kInvPt, + kEta, + kTgl, + kPhi, + kP, + kPx, + kPy, + kPz, + kRap, + kMass, + kCharge, + kNBasicTrackVariables, + kUsedKF, + kKFMass, + kKFMassGeoTop, + + kPt1, + kEta1, + kPhi1, + kCharge1, + kPin_leg1, + kTPCnSigmaKa_leg1, + kPt2, + kEta2, + kPhi2, + kCharge2, + + // Barrel track variables + kPin, + kSignedPin, + kTOFExpMom, + kTrackTime, + kTrackTimeRes, + kTrackTimeResRelative, + kDetectorMap, + kHasITS, + kHasTRD, + kHasTOF, + kHasTPC, + kIsGlobalTrack, + kIsGlobalTrackSDD, + kIsITSrefit, + kIsSPDany, + kIsSPDfirst, + kIsSPDboth, + kIsITSibAny, + kIsITSibFirst, + kIsITSibAll, + kITSncls, + kITSchi2, + kITSlayerHit, + kITSmeanClsSize, + kIsTPCrefit, + kTPCncls, + kITSClusterMap, + kTPCnclsCR, + kTPCnCRoverFindCls, + kTPCchi2, + kTPCsignal, + kPhiTPCOuter, + kTrackIsInsideTPCModule, + kTRDsignal, + kTRDPattern, + kTOFbeta, + kTrackLength, + kTrackDCAxy, + kTrackDCAxyProng1, + kTrackDCAxyProng2, + kTrackDCAz, + kTrackDCAzProng1, + kTrackDCAzProng2, + kTrackDCAsigXY, + kTrackDCAsigZ, + kTrackDCAresXY, + kTrackDCAresZ, + kIsGoldenChi2, + kTrackCYY, + kTrackCZZ, + kTrackCSnpSnp, + kTrackCTglTgl, + kTrackC1Pt21Pt2, + kTPCnSigmaEl, + kTPCnSigmaMu, + kTPCnSigmaPi, + kTPCnSigmaKa, + kTPCnSigmaPr, + kTPCnSigmaEl_Corr, + kTPCnSigmaPi_Corr, + kTPCnSigmaKa_Corr, + kTPCnSigmaPr_Corr, + kTOFnSigmaEl, + kTOFnSigmaMu, + kTOFnSigmaPi, + kTOFnSigmaKa, + kTOFnSigmaPr, + kTrackTimeResIsRange, // Gaussian or range (see Framework/DataTypes) + kPVContributor, // This track has contributed to the collision vertex fit (see Framework/DataTypes) + kOrphanTrack, // Track has no association with any collision vertex (see Framework/DataTypes) + kIsAmbiguous, + kIsLegFromGamma, + kIsLegFromK0S, + kIsLegFromLambda, + kIsLegFromAntiLambda, + kIsLegFromOmega, + kIsProtonFromLambdaAndAntiLambda, + kIsDalitzLeg, // Up to 8 dalitz selections + kBarrelNAssocsInBunch = kIsDalitzLeg + 8, // number of in bunch collision associations + kBarrelNAssocsOutOfBunch, // number of out of bunch collision associations + kNBarrelTrackVariables, + + // Muon track variables + kMuonNClusters, + kMuonPDca, + kMuonRAtAbsorberEnd, + kMCHBitMap, + kMuonChi2, + kMuonChi2MatchMCHMID, + kMuonChi2MatchMCHMFT, + kMuonMatchScoreMCHMFT, + kMuonCXX, + kMuonCXY, + kMuonCYY, + kMuonCPhiX, + kMuonCPhiY, + kMuonCPhiPhi, + kMuonCTglX, + kMuonCTglY, + kMuonCTglPhi, + kMuonCTglTgl, + kMuonC1Pt2X, + kMuonC1Pt2Y, + kMuonC1Pt2Phi, + kMuonC1Pt2Tgl, + kMuonC1Pt21Pt2, + kMuonTrackType, + kMuonDCAx, + kMuonDCAy, + kMuonTime, + kMuonTimeRes, + kMftNClusters, + kMftClusterSize, + kMftMeanClusterSize, + kMuonNAssocsInBunch, + kMuonNAssocsOutOfBunch, + kNMuonTrackVariables, + + // MC particle variables + kMCPdgCode, + kMCParticleWeight, + kMCPx, + kMCPy, + kMCPz, + kMCMass, + kMCE, + kMCVx, + kMCVy, + kMCVz, + kMCPt, + kMCPhi, + kMCEta, + kMCY, + kMCParticleGeneratorId, + kNMCParticleVariables, + kMCHadronPdgCode, + kMCCosTheta, + kMCJpsiPt, + kMCCosChi, + kMCdeltaphi, + kMCdeltaeta, + kMCHadronPt, + kMCHadronEta, + kMCHadronPhi, + kMCWeight, + kMCCosChi_randomPhi_toward, + kMCWeight_randomPhi_toward, + kMCCosChi_randomPhi_away, + kMCWeight_randomPhi_away, + kMCCosChi_randomPhi_trans, + kMCWeight_randomPhi_trans, + kMCdeltaphi_randomPhi_toward, + kMCdeltaphi_randomPhi_away, + kMCdeltaphi_randomPhi_trans, + kMCWeight_before, + + // MC mother particle variables + kMCMotherPdgCode, + + // MC pair variables + kMCCosThetaHE, + kMCPhiHE, + kMCPhiTildeHE, + kMCCosThetaCS, + kMCPhiCS, + kMCPhiTildeCS, + kMCCosThetaPP, + kMCPhiPP, + kMCPhiTildePP, + kMCCosThetaRM, + + // Pair variables + kCandidateId, + kPairType, + kVertexingLxy, + kVertexingLxyErr, + kVertexingPseudoCTau, + kVertexingLxyz, + kVertexingLxyzErr, + kVertexingLz, + kVertexingLzErr, + kVertexingTauxy, + kVertexingTauxyErr, + kVertexingLzProjected, + kVertexingLxyProjected, + kVertexingLxyzProjected, + kVertexingTauzProjected, + kVertexingTauxyProjected, + kVertexingTauxyProjectedPoleJPsiMass, + kVertexingTauxyProjectedNs, + kVertexingTauxyzProjected, + kVertexingTauz, + kVertexingTauzErr, + kVertexingPz, + kVertexingSV, + kVertexingProcCode, + kVertexingChi2PCA, + kCosThetaHE, + kPhiHE, + kPhiTildeHE, + kCosThetaCS, + kPhiCS, + kPhiTildeCS, + kCosThetaPP, + kPhiPP, + kPhiTildePP, + kCosThetaRM, + kCosThetaStarTPC, + kCosThetaStarFT0A, + kCosThetaStarFT0C, + kCosPhiVP, + kPhiVP, + kDeltaPhiPair2, + kDeltaEtaPair2, + kPsiPair, + kDeltaPhiPair, + kOpeningAngle, + kQuadDCAabsXY, + kQuadDCAsigXY, + kQuadDCAabsZ, + kQuadDCAsigZ, + kQuadDCAsigXYZ, + kSignQuadDCAsigXY, + kCosPointingAngle, + kImpParXYJpsi, + kImpParXYK, + kDCATrackProd, + kDCATrackVtxProd, + kV2SP, + kV2EP, + kWV2SP, + kWV2EP, + kU2Q2, + kU3Q3, + kQ42XA, + kQ42YA, + kQ23XA, + kQ23YA, + kS11A, + kS12A, + kS13A, + kS31A, + kM11REF, + kM11REFetagap, + kM01POI, + kM1111REF, + kM11M1111REF, + kM11M1111REFoverMp, + kM01M0111POIoverMp, + kM0111POI, + kCORR2REF, + kCORR2REFbydimuons, + kCORR2REFbysinglemu, + kCORR2REFetagap, + kCORR2POI, + kCORR2POICORR4POI, + kCORR2REFCORR4POI, + kCORR2REFCORR2POI, + kM01M0111overMp, + kM11M0111overMp, + kM11M01overMp, + kCORR2CORR4REF, + kCORR4REF, + kCORR4REFbydimuons, + kCORR4REFbysinglemu, + kCORR4POI, + kM11REFoverMp, + kM01POIoverMp, + kM1111REFoverMp, + kM0111POIoverMp, + kCORR2POIMp, + kCORR4POIMp, + kM01POIplus, + kM0111POIplus, + kM01POIminus, + kM0111POIminus, + kM01POIsingle, + kM0111POIsingle, + kM01POIoverMpminus, + kM01POIoverMpplus, + kM01POIoverMpsingle, + kM01POIoverMpmoins, + kM0111POIoverMpminus, + kM0111POIoverMpplus, + kM0111POIoverMpsingle, + kCORR2POIplus, + kCORR2POIminus, + kCORR2POIsingle, + kCORR4POIplus, + kCORR4POIminus, + kCORR4POIsingle, + kM11REFoverMpplus, + kM1111REFoverMpplus, + kM11REFoverMpminus, + kM1111REFoverMpminus, + kM11REFoverMpsingle, + kM1111REFoverMpsingle, + kM01POIME, + kMultDimuonsME, + kM0111POIME, + kCORR2POIME, + kCORR4POIME, + kM01POIoverMpME, + kM0111POIoverMpME, + kM11REFoverMpME, + kM1111REFoverMpME, + kCORR2REFbydimuonsME, + kCORR4REFbydimuonsME, + kR2SP, + kR2EP, + kPsi2A, + kPsi2APOS, + kPsi2ANEG, + kPsi2B, + kPsi2C, + kCos2DeltaPhi, + kCos2DeltaPhiMu1, // cos(phi - phi1) for muon1 + kCos2DeltaPhiMu2, ////cos(phi - phi2) for muon2 + kCos3DeltaPhi, + kDeltaPtotTracks, + kVertexingLxyOverErr, + kVertexingLzOverErr, + kVertexingLxyzOverErr, + kKFTrack0DCAxyz, + kKFTrack1DCAxyz, + kKFTracksDCAxyzMax, + kKFDCAxyzBetweenProngs, + kKFTrack0DCAxy, + kKFTrack1DCAxy, + kKFTracksDCAxyMax, + kKFDCAxyBetweenProngs, + kKFTrack0DeviationFromPV, + kKFTrack1DeviationFromPV, + kKFTrack0DeviationxyFromPV, + kKFTrack1DeviationxyFromPV, + kKFChi2OverNDFGeo, + kKFNContributorsPV, + kKFCosPA, + kKFChi2OverNDFGeoTop, + kKFJpsiDCAxyz, + kKFJpsiDCAxy, + kKFPairDeviationFromPV, + kKFPairDeviationxyFromPV, + kS12, + kS13, + kS23, + kNPairVariables, + + // Candidate-track correlation variables + kPairMass, + kPairMassDau, + kMassDau, + kPairPt, + kPairPtDau, + kPairEta, + kPairRap, + kPairPhi, + kPairPhiv, + kDeltaEta, + kDeltaPhi, + kDeltaPhiSym, + kNCorrelationVariables, + kDileptonHadronKstar, + kCosChi, + kEtaDau, + kPhiDau, + kECWeight, + kPtDau, + kCosTheta, + kEWeight_before, + kCosChi_randomPhi_trans, + kCosChi_randomPhi_toward, + kCosChi_randomPhi_away, + kWeight_randomPhi_trans, + kWeight_randomPhi_toward, + kWeight_randomPhi_away, + kdeltaphi_randomPhi_trans, + kdeltaphi_randomPhi_toward, + kdeltaphi_randomPhi_away, + + // Dilepton-track-track variables + kQuadMass, + kQuadDefaultDileptonMass, + kQuadPt, + kQuadEta, + kQuadPhi, + kCosthetaDileptonDitrack, + kDitrackMass, + kDitrackPt, + kQ, + kDeltaR1, + kDeltaR2, + kDeltaR, + + // DQ-HF correlation variables + kMassCharmHadron, + kPtCharmHadron, + kRapCharmHadron, + kPhiCharmHadron, + kBdtCharmHadron, + + // Index used to scan bit maps + kBitMapIndex, + + // deltaMass = kPairMass - kPairMassDau + kDeltaMass, + // deltaMass_jpsi = kPairMass - kPairMassDau +3.096900 + kDeltaMass_jpsi, + + // BDT score + kBdtBackground, + kBdtPrompt, + kBdtNonprompt, + + kNVars + }; // end of Variables enumeration + + enum CalibObjects { + kTPCElectronMean = 0, + kTPCElectronSigma, + kTPCElectronStatus, + kTPCPionMean, + kTPCPionSigma, + kTPCPionStatus, + kTPCKaonMean, + kTPCKaonSigma, + kTPCKaonStatus, + kTPCProtonMean, + kTPCProtonSigma, + kTPCProtonStatus, + kNCalibObjects + }; + + enum DileptonCharmHadronTypes { + kJPsi = 0, + kD0ToPiK, + kD0barToKPi + }; + + enum EventFilters { + kDoubleGap = 0, + kSingleGapA, + kSingleGapC, + kITSUPCMode + }; + + enum MuonExtrapolation { + // Index used to set different options for Muon propagation + kToVertex = 0, // propagtion to vertex by default + kToDCA, + kToRabs, + kToMatching + }; + + static TString fgVariableNames[kNVars]; // variable names + static TString fgVariableUnits[kNVars]; // variable units + static std::map fgVarNamesMap; // key: variables short name, value: order in the Variables enum + static void SetDefaultVarNames(); + + static void SetUseVariable(int var) + { + if (var >= 0 && var < kNVars) { + fgUsedVars[var] = kTRUE; + } + SetVariableDependencies(); + } + static void SetUseVars(const bool* usedVars) + { + for (int i = 0; i < kNVars; ++i) { + if (usedVars[i]) { + fgUsedVars[i] = true; // overwrite only the variables that are being used since there are more channels to modify the used variables array, independently + } + } + SetVariableDependencies(); + } + static void SetUseVars(const std::vector usedVars) + { + for (auto& var : usedVars) { + fgUsedVars[var] = true; + } + } + static bool GetUsedVar(int var) + { + if (var >= 0 && var < kNVars) { + return fgUsedVars[var]; + } + return false; + } + + // Setup the collision system + static void SetCollisionSystem(TString system, float energy); + static void SetCollisionSystem(o2::parameters::GRPLHCIFData* grplhcif); + + static void SetMagneticField(float magField) + { + fgMagField = magField; + } + + // Setup plane position for MFT-MCH matching + static void SetMatchingPlane(float z) + { + fgzMatching = z; + } + + static float GetMatchingPlane() + { + return fgzMatching; + } + + // Setup the 2 prong KFParticle + static void SetupTwoProngKFParticle(float magField) + { + KFParticle::SetField(magField); + fgUsedKF = true; + } + // Setup magnetic field for muon propagation + static void SetupMuonMagField() + { + o2::mch::TrackExtrap::setField(); + } + + // Setup the 2 prong DCAFitterN + static void SetupTwoProngDCAFitter(float magField, bool propagateToPCA, float maxR, float maxDZIni, float minParamChange, float minRelChi2Change, bool useAbsDCA) + { + fgFitterTwoProngBarrel.setBz(magField); + fgFitterTwoProngBarrel.setPropagateToPCA(propagateToPCA); + fgFitterTwoProngBarrel.setMaxR(maxR); + fgFitterTwoProngBarrel.setMaxDZIni(maxDZIni); + fgFitterTwoProngBarrel.setMinParamChange(minParamChange); + fgFitterTwoProngBarrel.setMinRelChi2Change(minRelChi2Change); + fgFitterTwoProngBarrel.setUseAbsDCA(useAbsDCA); + fgUsedKF = false; + } + + // Setup the 2 prong FwdDCAFitterN + static void SetupTwoProngFwdDCAFitter(float magField, bool propagateToPCA, float maxR, float minParamChange, float minRelChi2Change, bool useAbsDCA) + { + fgFitterTwoProngFwd.setBz(magField); + fgFitterTwoProngFwd.setPropagateToPCA(propagateToPCA); + fgFitterTwoProngFwd.setMaxR(maxR); + fgFitterTwoProngFwd.setMinParamChange(minParamChange); + fgFitterTwoProngFwd.setMinRelChi2Change(minRelChi2Change); + fgFitterTwoProngFwd.setUseAbsDCA(useAbsDCA); + fgUsedKF = false; + } + // Use MatLayerCylSet to correct MCS in fwdtrack propagation + static void SetupMatLUTFwdDCAFitter(o2::base::MatLayerCylSet* m) + { + fgFitterTwoProngFwd.setTGeoMat(false); + fgFitterTwoProngFwd.setMatLUT(m); + } + // Use GeometryManager to correct MCS in fwdtrack propagation + static void SetupTGeoFwdDCAFitter() + { + fgFitterTwoProngFwd.setTGeoMat(true); + } + // No material budget in fwdtrack propagation + static void SetupFwdDCAFitterNoCorr() + { + fgFitterTwoProngFwd.setTGeoMat(false); + } + // Setup the 3 prong KFParticle + static void SetupThreeProngKFParticle(float magField) + { + KFParticle::SetField(magField); + fgUsedKF = true; + } + + // Setup the 3 prong DCAFitterN + static void SetupThreeProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) + { + fgFitterThreeProngBarrel.setBz(magField); + fgFitterThreeProngBarrel.setPropagateToPCA(propagateToPCA); + fgFitterThreeProngBarrel.setMaxR(maxR); + fgFitterThreeProngBarrel.setMinParamChange(minParamChange); + fgFitterThreeProngBarrel.setMinRelChi2Change(minRelChi2Change); + fgFitterThreeProngBarrel.setUseAbsDCA(useAbsDCA); + fgUsedKF = false; + } + + // Setup the 4 prong KFParticle + static void SetupFourProngKFParticle(float magField) + { + KFParticle::SetField(magField); + fgUsedKF = true; + } + + // Setup the 4 prong DCAFitterN + static void SetupFourProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) + { + fgFitterFourProngBarrel.setBz(magField); + fgFitterFourProngBarrel.setPropagateToPCA(propagateToPCA); + fgFitterFourProngBarrel.setMaxR(maxR); + fgFitterFourProngBarrel.setMinParamChange(minParamChange); + fgFitterFourProngBarrel.setMinRelChi2Change(minRelChi2Change); + fgFitterFourProngBarrel.setUseAbsDCA(useAbsDCA); + fgUsedKF = false; + } + + static auto getEventPlane(int harm, float qnxa, float qnya) + { + // Compute event plane angle from qn vector components for the sub-event A + return (1.0 / harm) * TMath::ATan2(qnya, qnxa); + }; + + static float getDeltaPsiInRange(float psi1, float psi2, float harmonic) + { + float deltaPsi = psi1 - psi2; + if (std::abs(deltaPsi) > o2::constants::math::PI / harmonic) { + if (deltaPsi > 0.) { + deltaPsi -= o2::constants::math::TwoPI / harmonic; + } else { + deltaPsi += o2::constants::math::TwoPI / harmonic; + } + } + return deltaPsi; + } + + template + static o2::track::TrackParCovFwd FwdToTrackPar(const T& track, const C& cov); + template + static o2::dataformats::GlobalFwdTrack PropagateMuon(const T& muon, const C& collision, int endPoint = kToVertex); + template + static o2::track::TrackParCovFwd PropagateFwd(const T& track, const C& cov, float z); + template + static void FillMuonPDca(const T& muon, const C& collision, float* values = nullptr); + template + static void FillPropagateMuon(const T& muon, const C& collision, float* values = nullptr); + template + static void FillBC(T const& bc, float* values = nullptr); + template + static void FillEvent(T const& event, float* values = nullptr); + template + static void FillEventTrackEstimators(TEvent const& collision, TAssoc const& groupedTrackIndices, TTracks const& tracks, float* values = nullptr); + template + static void FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); + template + static void FillTwoEvents(T const& event1, T const& event2, float* values = nullptr); + template + static void FillTwoMixEvents(T1 const& event1, T1 const& event2, T2 const& tracks1, T2 const& tracks2, float* values = nullptr); + template + static void FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); + template + static void FillTwoMixEventsCumulants(T const& h_v22m, T const& h_v24m, T const& h_v22p, T const& h_v24p, T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillTrack(T const& track, float* values = nullptr); + template + static void FillPhoton(T const& photon, float* values = nullptr); + template + static void FillTrackCollision(T const& track, C const& collision, float* values = nullptr); + template + 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 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 + static void FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values = nullptr); + template + static void FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, float* values = nullptr); + template + static void FillPair(T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillPairCollision(C const& collision, T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values = nullptr); + template + static void FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); + template + 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 FillQuadMC(T1 const& t1, T2 const& t2, T2 const& t3, float* values = nullptr); + template + static void FillPairVertexing(C const& collision, T const& t1, T const& t2, bool propToSV = false, float* values = nullptr); + template + static void FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, PairCandidateType tripletType, float* values = nullptr); + template + static void FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values); + template + static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); + template + static void FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values = nullptr); + template + static void FillHadron(T const& hadron, float* values = nullptr, float hadronMass = 0.0f); + template + static void FillSingleDileptonCharmHadron(Cand const& candidate, H hfHelper, T& bdtScoreCharmHad, float* values = nullptr); + template + static void FillDileptonCharmHadron(DQ const& dilepton, HF const& charmHadron, H hfHelper, T& bdtScoreCharmHad, float* values = nullptr); + template + static void FillQVectorFromGFW(C const& collision, A const& compA11, A const& compB11, A const& compC11, A const& compA21, A const& compB21, A const& compC21, A const& compA31, A const& compB31, A const& compC31, A const& compA41, A const& compB41, A const& compC41, A const& compA23, A const& compA42, float S10A = 1.0, float S10B = 1.0, float S10C = 1.0, float S11A = 1.0, float S11B = 1.0, float S11C = 1.0, float S12A = 1.0, float S13A = 1.0, float S14A = 1.0, float S21A = 1.0, float S22A = 1.0, float S31A = 1.0, float S41A = 1.0, float* values = nullptr); + template + static void FillQVectorFromCentralFW(C const& collision, float* values = nullptr); + template + static void FillNewQVectorFromCentralFW(C const& collision, float* values = nullptr); + template + static void FillSpectatorPlane(C const& collision, float* values = nullptr); + template + static void FillPairVn(T1 const& t1, T2 const& t2, float* values = nullptr); + template + static void FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T3 const& hadron2, float* values = nullptr); + template + static void FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values); + template + static void FillZDC(const T& zdc, float* values = nullptr); + template + static void FillBdtScore(const T& bdtScore, float* values = nullptr); + + static void SetCalibrationObject(CalibObjects calib, TObject* obj) + { + fgCalibs[calib] = obj; + // Check whether all the needed objects for TPC postcalibration are available + if (fgCalibs.find(kTPCElectronMean) != fgCalibs.end() && fgCalibs.find(kTPCElectronSigma) != fgCalibs.end()) { + fgRunTPCPostCalibration[0] = true; + fgUsedVars[kTPCnSigmaEl_Corr] = true; + } + if (fgCalibs.find(kTPCPionMean) != fgCalibs.end() && fgCalibs.find(kTPCPionSigma) != fgCalibs.end()) { + fgRunTPCPostCalibration[1] = true; + fgUsedVars[kTPCnSigmaPi_Corr] = true; + } + if (fgCalibs.find(kTPCKaonMean) != fgCalibs.end() && fgCalibs.find(kTPCKaonSigma) != fgCalibs.end()) { + fgRunTPCPostCalibration[2] = true; + fgUsedVars[kTPCnSigmaKa_Corr] = true; + } + if (fgCalibs.find(kTPCProtonMean) != fgCalibs.end() && fgCalibs.find(kTPCProtonSigma) != fgCalibs.end()) { + fgRunTPCPostCalibration[3] = true; + fgUsedVars[kTPCnSigmaPr_Corr] = true; + } + } + + static void SetCalibrationType(int type, bool useInterpolation = true) + { + if (type < 0 || type > 2) { + LOG(fatal) << "Invalid calibration type. Must be 0, 1, or 2."; + } + fgCalibrationType = type; + fgUseInterpolatedCalibration = useInterpolation; + } + static double ComputePIDcalibration(int species, double nSigmaValue); + + static TObject* GetCalibrationObject(CalibObjects calib) + { + auto obj = fgCalibs.find(calib); + if (obj == fgCalibs.end()) { + return 0x0; + } else { + return obj->second; + } + } + static void SetTPCInterSectorBoundary(float boundarySize) + { + fgTPCInterSectorBoundary = boundarySize; + } + static void SetITSROFBorderselection(int bias, int length, int marginLow, int marginHigh) + { + fgITSROFbias = bias; + fgITSROFlength = length; + fgITSROFBorderMarginLow = marginLow; + fgITSROFBorderMarginHigh = marginHigh; + } + + static void SetSORandEOR(uint64_t sor, uint64_t eor) + { + fgSOR = sor; + fgEOR = eor; + } + + public: + VarManager(); + ~VarManager() override; + + static float fgValues[kNVars]; // array holding all variables computed during analysis + static void ResetValues(int startValue = 0, int endValue = kNVars, float* values = nullptr); + + private: + static bool fgUsedVars[kNVars]; // holds flags for when the corresponding variable is needed (e.g., in the histogram manager, in cuts, mixing handler, etc.) + static bool fgUsedKF; + static void SetVariableDependencies(); // toggle those variables on which other used variables might depend + + 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 ROOT::Math::PxPyPzEVector fgBeamA; // beam from A-side 4-momentum vector + static ROOT::Math::PxPyPzEVector fgBeamC; // beam from C-side 4-momentum vector + + // static void FillEventDerived(float* values = nullptr); + static void FillTrackDerived(float* values = nullptr); + template + static auto getRotatedCovMatrixXX(const T& matrix, U phi, V theta); + template + static KFPTrack createKFPTrackFromTrack(const T& track); + template + static KFPTrack createKFPFwdTrackFromFwdTrack(const T& muon); + template + static KFPVertex createKFPVertexFromCollision(const T& collision); + static float calculateCosPA(KFParticle kfp, KFParticle PV); + template + static float calculatePhiV(const T1& t1, const T2& t2); + template + static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); + + static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; + static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; + static o2::vertexing::DCAFitterN<4> fgFitterFourProngBarrel; + static o2::vertexing::FwdDCAFitterN<2> fgFitterTwoProngFwd; + static o2::vertexing::FwdDCAFitterN<3> fgFitterThreeProngFwd; + static o2::globaltracking::MatchGlobalFwd mMatching; + + static std::map fgCalibs; // map of calibration histograms + static bool fgRunTPCPostCalibration[4]; // 0-electron, 1-pion, 2-kaon, 3-proton + static int fgCalibrationType; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb + static bool fgUseInterpolatedCalibration; // use interpolated calibration histograms (default: true) + + VarManager& operator=(const VarManager& c); + VarManager(const VarManager& c); + + ClassDef(VarManager, 4); +}; + +template +o2::track::TrackParCovFwd VarManager::FwdToTrackPar(const T& track, const C& cov) +{ + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + return trackparCov; +} + +template +auto VarManager::getRotatedCovMatrixXX(const T& matrix, U phi, V theta) +{ + // + auto cp = std::cos(phi); + auto sp = std::sin(phi); + auto ct = std::cos(theta); + auto st = std::sin(theta); + return matrix[0] * cp * cp * ct * ct // covXX + + matrix[1] * 2. * cp * sp * ct * ct // covXY + + matrix[2] * sp * sp * ct * ct // covYY + + matrix[3] * 2. * cp * ct * st // covXZ + + matrix[4] * 2. * sp * ct * st // covYZ + + matrix[5] * st * st; // covZZ +} + +template +KFPTrack VarManager::createKFPTrackFromTrack(const T& track) +{ + std::array trackpars = {track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt()}; + std::array trackcovs = {track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), + track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), + track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()}; + o2::track::TrackParametrizationWithError trackparCov{track.x(), track.alpha(), std::move(trackpars), std::move(trackcovs)}; + std::array trkpos_par; + std::array trkmom_par; + std::array trk_cov; + trackparCov.getXYZGlo(trkpos_par); + trackparCov.getPxPyPzGlo(trkmom_par); + trackparCov.getCovXYZPxPyPzGlo(trk_cov); + float trkpar_KF[6] = {trkpos_par[0], trkpos_par[1], trkpos_par[2], + trkmom_par[0], trkmom_par[1], trkmom_par[2]}; + float trkcov_KF[21]; + for (int i = 0; i < 21; i++) { + trkcov_KF[i] = trk_cov[i]; + } + KFPTrack kfpTrack; + kfpTrack.SetParameters(trkpar_KF); + kfpTrack.SetCovarianceMatrix(trkcov_KF); + kfpTrack.SetCharge(track.sign()); + kfpTrack.SetNDF(track.tpcNClsFound() - 5); + kfpTrack.SetChi2(track.tpcChi2NCl() * track.tpcNClsFound()); + return kfpTrack; +} + +template +KFPTrack VarManager::createKFPFwdTrackFromFwdTrack(const T& muon) +{ + o2::track::TrackParCovFwd trackparCov = FwdToTrackPar(muon, muon); + + std::array trk_cov; + trackparCov.getCovXYZPxPyPzGlo(trk_cov); + double trkpar_KF[6] = {trackparCov.getX(), trackparCov.getY(), trackparCov.getZ(), + trackparCov.getPx(), trackparCov.getPy(), trackparCov.getPz()}; + float trkcov_KF[21]; + for (int i = 0; i < 21; i++) { + trkcov_KF[i] = trk_cov[i]; + } + KFPTrack kfpTrack; + kfpTrack.SetParameters(trkpar_KF); + kfpTrack.SetCovarianceMatrix(trkcov_KF); + kfpTrack.SetCharge(muon.sign()); + kfpTrack.SetNDF(muon.nClusters() - 5); + kfpTrack.SetChi2(muon.chi2()); + return kfpTrack; +} + +template +KFPVertex VarManager::createKFPVertexFromCollision(const T& collision) +{ + KFPVertex kfpVertex; + kfpVertex.SetXYZ(collision.posX(), collision.posY(), collision.posZ()); + kfpVertex.SetCovarianceMatrix(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + kfpVertex.SetChi2(collision.chi2()); + kfpVertex.SetNDF(2 * collision.numContrib() - 3); + kfpVertex.SetNContributors(collision.numContrib()); + return kfpVertex; +} + +template +o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C& collision, const int endPoint) +{ + o2::track::TrackParCovFwd fwdtrack = FwdToTrackPar(muon, muon); + o2::dataformats::GlobalFwdTrack propmuon; + if (static_cast(muon.trackType()) > 2) { + o2::dataformats::GlobalFwdTrack track; + track.setParameters(fwdtrack.getParameters()); + track.setZ(fwdtrack.getZ()); + track.setCovariances(fwdtrack.getCovariances()); + auto mchTrack = mMatching.FwdtoMCH(track); + + if (endPoint == kToVertex) { + o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); + } + if (endPoint == kToDCA) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.posZ()); + } + if (endPoint == kToRabs) { + o2::mch::TrackExtrap::extrapToZ(mchTrack, -505.); + } + if (endPoint == kToMatching) { + o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, fgzMatching); + } + + auto proptrack = mMatching.MCHtoFwd(mchTrack); + propmuon.setParameters(proptrack.getParameters()); + propmuon.setZ(proptrack.getZ()); + propmuon.setCovariances(proptrack.getCovariances()); + + } else if (static_cast(muon.trackType()) < 2) { + double centerMFT[3] = {0, 0, -61.4}; + o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + auto Bz = field->getBz(centerMFT); // Get field at centre of MFT + auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), collision.posX(), collision.posY(), collision.posZ()); + auto x2x0 = static_cast(geoMan.meanX2X0); + fwdtrack.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, Bz, x2x0); + propmuon.setParameters(fwdtrack.getParameters()); + propmuon.setZ(fwdtrack.getZ()); + propmuon.setCovariances(fwdtrack.getCovariances()); + } + return propmuon; +} + +template +o2::track::TrackParCovFwd VarManager::PropagateFwd(const T& track, const C& cov, float z) +{ + o2::track::TrackParCovFwd fwdtrack = FwdToTrackPar(track, cov); + fwdtrack.propagateToZhelix(z, fgMagField); + return fwdtrack; +} + +template +void VarManager::FillMuonPDca(const T& muon, const C& collision, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { + + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); + o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); + + float dcaX = (propmuonAtDCA.getX() - collision.posX()); + float dcaY = (propmuonAtDCA.getY() - collision.posY()); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + values[kMuonPDca] = muon.p() * dcaXY; + } +} + +template +void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & ReducedMuonCov) > 0) { + if (muon.filteringFlags() & (uint8_t(1) << VarManager::kMuonIsPropagated)) { // the muon is already propagated, so nothing to do + return; + } + } + + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); + values[kPt] = propmuon.getPt(); + values[kX] = propmuon.getX(); + values[kY] = propmuon.getY(); + values[kZ] = propmuon.getZ(); + values[kEta] = propmuon.getEta(); + values[kTgl] = propmuon.getTgl(); + values[kPhi] = propmuon.getPhi(); + + // Redo propagation only for muon tracks + // propagation of MFT tracks alredy done in fwdtrack-extention task + if (static_cast(muon.trackType()) > 2) { + o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); + o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, kToRabs); + float dcaX = (propmuonAtDCA.getX() - collision.posX()); + float dcaY = (propmuonAtDCA.getY() - collision.posY()); + values[kMuonDCAx] = dcaX; + values[kMuonDCAy] = dcaY; + double xAbs = propmuonAtRabs.getX(); + double yAbs = propmuonAtRabs.getY(); + values[kMuonRAtAbsorberEnd] = std::sqrt(xAbs * xAbs + yAbs * yAbs); + } + + SMatrix55 cov = propmuon.getCovariances(); + values[kMuonCXX] = cov(0, 0); + values[kMuonCXY] = cov(1, 0); + values[kMuonCYY] = cov(1, 1); + values[kMuonCPhiX] = cov(2, 0); + values[kMuonCPhiY] = cov(2, 1); + values[kMuonCPhiPhi] = cov(2, 2); + values[kMuonCTglX] = cov(3, 0); + values[kMuonCTglY] = cov(3, 1); + values[kMuonCTglPhi] = cov(3, 2); + values[kMuonCTglTgl] = cov(3, 3); + values[kMuonC1Pt2X] = cov(4, 0); + values[kMuonC1Pt2Y] = cov(4, 1); + values[kMuonC1Pt2Phi] = cov(4, 2); + values[kMuonC1Pt2Tgl] = cov(4, 3); + values[kMuonC1Pt21Pt2] = cov(4, 4); + } +} + +template +void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values) +{ + if (!values) { + values = fgValues; + } + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); + double px = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * cos(mfttrack.phi()); + double py = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * sin(mfttrack.phi()); + double pz = propmuon.getP() * cos(M_PI / 2 - atan(mfttrack.tgl())); + double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); + values[kX] = mfttrack.x(); + values[kY] = mfttrack.y(); + values[kZ] = mfttrack.z(); + values[kTgl] = mfttrack.tgl(); + values[kPt] = pt; + values[kPz] = pz; + values[kEta] = mfttrack.eta(); + values[kPhi] = mfttrack.phi(); + } +} + +template +void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, float* values) +{ + if (!values) { + values = fgValues; + } + if constexpr ((MuonfillMap & MuonCov) > 0) { + if constexpr ((MFTfillMap & MFTCov) > 0) { + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); + o2::track::TrackParCovFwd mft = FwdToTrackPar(mfttrack, mftcov); + + o2::dataformats::GlobalFwdTrack globalRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); + values[kX] = globalRefit.getX(); + values[kY] = globalRefit.getY(); + values[kZ] = globalRefit.getZ(); + values[kTgl] = globalRefit.getTgl(); + values[kPt] = globalRefit.getPt(); + values[kPz] = globalRefit.getPz(); + values[kEta] = globalRefit.getEta(); + values[kPhi] = globalRefit.getPhi(); + } + } +} + +template +void VarManager::FillBC(T const& bc, float* values) +{ + if (!values) { + values = fgValues; + } + values[kRunNo] = bc.runNumber(); + values[kBC] = bc.globalBC(); + values[kBCOrbit] = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; + values[kTimestamp] = bc.timestamp(); + values[kTimeFromSOR] = (fgSOR > 0 ? (bc.timestamp() - fgSOR) / 60000. : -1.0); +} + +template +void VarManager::FillEvent(T const& event, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & CollisionTimestamp) > 0) { + values[kTimestamp] = event.timestamp(); + } + + if constexpr ((fillMap & Collision) > 0) { + // TODO: trigger info from the event selection requires a separate flag + // so that it can be switched off independently of the rest of Collision variables (e.g. if event selection is not available) + + if (fgUsedVars[kIsNoITSROFBorder]) { + values[kIsNoITSROFBorder] = event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); + } + if (fgUsedVars[kTrackOccupancyInTimeRange]) { + values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); + } + if (fgUsedVars[kFT0COccupancyInTimeRange]) { + values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); + } + if (fgUsedVars[kNoCollInTimeRangeStandard]) { + values[kNoCollInTimeRangeStandard] = event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); + } + if (fgUsedVars[kIsNoTFBorder]) { + values[kIsNoTFBorder] = event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); + } + if (fgUsedVars[kIsNoSameBunch]) { + values[kIsNoSameBunch] = event.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + } + if (fgUsedVars[kIsGoodZvtxFT0vsPV]) { + values[kIsGoodZvtxFT0vsPV] = event.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); + } + if (fgUsedVars[kIsVertexITSTPC]) { + values[kIsVertexITSTPC] = event.selection_bit(o2::aod::evsel::kIsVertexITSTPC); + } + if (fgUsedVars[kIsVertexTOFmatched]) { + values[kIsVertexTOFmatched] = event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched); + } + if (fgUsedVars[kIsSel8]) { + values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); + } + if (fgUsedVars[kIsGoodITSLayer3]) { + values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); + } + if (fgUsedVars[kIsGoodITSLayer0123]) { + values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + } + if (fgUsedVars[kIsGoodITSLayersAll]) { + values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + } + if (fgUsedVars[kIsINT7]) { + values[kIsINT7] = (event.alias_bit(kINT7) > 0); + } + if (fgUsedVars[kIsEMC7]) { + values[kIsEMC7] = (event.alias_bit(kEMC7) > 0); + } + if (fgUsedVars[kIsINT7inMUON]) { + values[kIsINT7inMUON] = (event.alias_bit(kINT7inMUON) > 0); + } + if (fgUsedVars[kIsMuonSingleLowPt7]) { + values[kIsMuonSingleLowPt7] = (event.alias_bit(kMuonSingleLowPt7) > 0); + } + if (fgUsedVars[kIsMuonSingleHighPt7]) { + values[kIsMuonSingleHighPt7] = (event.alias_bit(kMuonSingleHighPt7) > 0); + } + if (fgUsedVars[kIsMuonUnlikeLowPt7]) { + values[kIsMuonUnlikeLowPt7] = (event.alias_bit(kMuonUnlikeLowPt7) > 0); + } + if (fgUsedVars[kIsMuonLikeLowPt7]) { + values[kIsMuonLikeLowPt7] = (event.alias_bit(kMuonLikeLowPt7) > 0); + } + if (fgUsedVars[kIsCUP8]) { + values[kIsCUP8] = (event.alias_bit(kCUP8) > 0); + } + if (fgUsedVars[kIsCUP9]) { + values[kIsCUP9] = (event.alias_bit(kCUP9) > 0); + } + if (fgUsedVars[kIsMUP10]) { + values[kIsMUP10] = (event.alias_bit(kMUP10) > 0); + } + if (fgUsedVars[kIsMUP11]) { + values[kIsMUP11] = (event.alias_bit(kMUP11) > 0); + } + values[kVtxX] = event.posX(); + values[kVtxY] = event.posY(); + values[kVtxZ] = event.posZ(); + values[kVtxNcontrib] = event.numContrib(); + values[kVtxCovXX] = event.covXX(); + values[kVtxCovXY] = event.covXY(); + values[kVtxCovXZ] = event.covXZ(); + values[kVtxCovYY] = event.covYY(); + values[kVtxCovYZ] = event.covYZ(); + values[kVtxCovZZ] = event.covZZ(); + values[kVtxChi2] = event.chi2(); + values[kCollisionTime] = event.collisionTime(); + values[kCollisionTimeRes] = event.collisionTimeRes(); + } + + if constexpr ((fillMap & CollisionCentRun2) > 0) { + values[kCentVZERO] = event.centRun2V0M(); + } + + if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { + if constexpr ((fillMap & CollisionMC) == 0) { + values[kCentFT0C] = event.centFT0C(); + values[kCentFT0A] = event.centFT0A(); + values[kCentFT0M] = event.centFT0M(); + } + } + + if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { + values[kMultFV0A] = event.multFV0A(); + values[kMultFT0A] = event.multFT0A(); + values[kMultFT0C] = event.multFT0C(); + values[kMultFDDA] = event.multFDDA(); + values[kMultFDDC] = event.multFDDC(); + values[kMultTPC] = event.multTPC(); + values[kMultFV0C] = event.multFV0C(); + values[kMultZNA] = event.multZNA(); + values[kMultZNC] = event.multZNC(); + values[kMultTracklets] = event.multTracklets(); + values[kVtxNcontribReal] = event.multNTracksPV(); + } + + if constexpr ((fillMap & CollisionMultExtra) > 0 || (fillMap & ReducedEventMultExtra) > 0) { + values[kMultNTracksHasITS] = event.multNTracksHasITS(); + values[kMultNTracksHasTPC] = event.multNTracksHasTPC(); + values[kMultNTracksHasTOF] = event.multNTracksHasTOF(); + values[kMultNTracksHasTRD] = event.multNTracksHasTRD(); + values[kMultNTracksITSOnly] = event.multNTracksITSOnly(); + values[kMultNTracksTPCOnly] = event.multNTracksTPCOnly(); + values[kMultNTracksITSTPC] = event.multNTracksITSTPC(); + values[kMultNTracksPVeta1] = event.multNTracksPVeta1(); + values[kMultNTracksPVetaHalf] = event.multNTracksPVetaHalf(); + values[kMultAllTracksTPCOnly] = event.multAllTracksTPCOnly(); + values[kMultAllTracksITSTPC] = event.multAllTracksITSTPC(); + values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); + values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); + if constexpr ((fillMap & ReducedEventMultExtra) > 0) { + values[kNTPCcontribLongA] = event.nTPCoccupContribLongA(); + values[kNTPCcontribLongC] = event.nTPCoccupContribLongC(); + values[kNTPCcontribShortA] = event.nTPCoccupContribShortA(); + values[kNTPCcontribShortC] = event.nTPCoccupContribShortC(); + values[kNTPCmeanTimeLongA] = event.nTPCoccupMeanTimeLongA(); + values[kNTPCmeanTimeLongC] = event.nTPCoccupMeanTimeLongC(); + values[kNTPCmeanTimeShortA] = event.nTPCoccupMeanTimeShortA(); + values[kNTPCmeanTimeShortC] = event.nTPCoccupMedianTimeShortC(); + values[kNTPCmedianTimeLongA] = event.nTPCoccupMedianTimeLongA(); + values[kNTPCmedianTimeLongC] = event.nTPCoccupMedianTimeLongC(); + values[kNTPCmedianTimeShortA] = event.nTPCoccupMedianTimeShortA(); + values[kNTPCmedianTimeShortC] = event.nTPCoccupMedianTimeShortC(); + } + } + // TODO: need to add EvSels and Cents tables, etc. in case of the central data model + + if constexpr ((fillMap & ReducedEvent) > 0) { + values[kRunNo] = event.runNumber(); + values[kVtxX] = event.posX(); + values[kVtxY] = event.posY(); + values[kVtxZ] = event.posZ(); + values[kVtxNcontrib] = event.numContrib(); + if (fgUsedVars[kIsDoubleGap]) { + values[kIsDoubleGap] = (event.tag_bit(56 + kDoubleGap) > 0); + } + if (fgUsedVars[kIsSingleGap] || fgUsedVars[kIsSingleGapA] || fgUsedVars[kIsSingleGapC]) { + values[kIsSingleGapA] = (event.tag_bit(56 + kSingleGapA) > 0); + values[kIsSingleGapC] = (event.tag_bit(56 + kSingleGapC) > 0); + values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; + } + if (fgUsedVars[kIsITSUPCMode]) { + values[kIsITSUPCMode] = (event.tag_bit(56 + kITSUPCMode) > 0); + } + values[kCollisionTime] = event.collisionTime(); + values[kCollisionTimeRes] = event.collisionTimeRes(); + } + + if constexpr ((fillMap & ReducedEventExtended) > 0) { + values[kBC] = event.globalBC(); + values[kBCOrbit] = event.globalBC() % o2::constants::lhc::LHCMaxBunches; + values[kTimestamp] = event.timestamp(); + values[kTimeFromSOR] = (fgSOR > 0 ? (event.timestamp() - fgSOR) / 60000. : -1.0); + values[kCentVZERO] = event.centRun2V0M(); + values[kCentFT0C] = event.centFT0C(); + if (fgUsedVars[kIsNoITSROFBorderRecomputed]) { + uint16_t bcInITSROF = (event.globalBC() + 3564 - fgITSROFbias) % fgITSROFlength; + values[kIsNoITSROFBorderRecomputed] = bcInITSROF > fgITSROFBorderMarginLow && bcInITSROF < fgITSROFlength - fgITSROFBorderMarginHigh ? 1.0 : 0.0; + } + if (fgUsedVars[kIsNoITSROFBorder]) { + values[kIsNoITSROFBorder] = (event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) > 0); + } + if (fgUsedVars[kIsNoTFBorder]) { + values[kIsNoTFBorder] = (event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) > 0); + } + if (fgUsedVars[kNoCollInTimeRangeStandard]) { + values[kNoCollInTimeRangeStandard] = (event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) > 0); + } + if (fgUsedVars[kIsNoSameBunch]) { + values[kIsNoSameBunch] = (event.selection_bit(o2::aod::evsel::kNoSameBunchPileup) > 0); + } + if (fgUsedVars[kIsGoodZvtxFT0vsPV]) { + values[kIsGoodZvtxFT0vsPV] = (event.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) > 0); + } + if (fgUsedVars[kIsVertexITSTPC]) { + values[kIsVertexITSTPC] = (event.selection_bit(o2::aod::evsel::kIsVertexITSTPC) > 0); + } + if (fgUsedVars[kIsVertexTOFmatched]) { + values[kIsVertexTOFmatched] = (event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched) > 0); + } + if (fgUsedVars[kIsSel8]) { + values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); + } + if (fgUsedVars[kIsGoodITSLayer3]) { + values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); + } + if (fgUsedVars[kIsGoodITSLayer0123]) { + values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); + } + if (fgUsedVars[kIsGoodITSLayersAll]) { + values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); + } + if (fgUsedVars[kIsINT7]) { + values[kIsINT7] = (event.alias_bit(kINT7) > 0); + } + if (fgUsedVars[kIsEMC7]) { + values[kIsEMC7] = (event.alias_bit(kEMC7) > 0); + } + if (fgUsedVars[kIsINT7inMUON]) { + values[kIsINT7inMUON] = (event.alias_bit(kINT7inMUON) > 0); + } + if (fgUsedVars[kIsMuonSingleLowPt7]) { + values[kIsMuonSingleLowPt7] = (event.alias_bit(kMuonSingleLowPt7) > 0); + } + if (fgUsedVars[kIsMuonSingleHighPt7]) { + values[kIsMuonSingleHighPt7] = (event.alias_bit(kMuonSingleHighPt7) > 0); + } + if (fgUsedVars[kIsMuonUnlikeLowPt7]) { + values[kIsMuonUnlikeLowPt7] = (event.alias_bit(kMuonUnlikeLowPt7) > 0); + } + if (fgUsedVars[kIsMuonLikeLowPt7]) { + values[kIsMuonLikeLowPt7] = (event.alias_bit(kMuonLikeLowPt7) > 0); + } + if (fgUsedVars[kIsCUP8]) { + values[kIsCUP8] = (event.alias_bit(kCUP8) > 0); + } + if (fgUsedVars[kIsCUP9]) { + values[kIsCUP9] = (event.alias_bit(kCUP9) > 0); + } + if (fgUsedVars[kIsMUP10]) { + values[kIsMUP10] = (event.alias_bit(kMUP10) > 0); + } + if (fgUsedVars[kIsMUP11]) { + values[kIsMUP11] = (event.alias_bit(kMUP11) > 0); + } + } + + if constexpr ((fillMap & ReducedEventVtxCov) > 0) { + values[kVtxCovXX] = event.covXX(); + values[kVtxCovXY] = event.covXY(); + values[kVtxCovXZ] = event.covXZ(); + values[kVtxCovYY] = event.covYY(); + values[kVtxCovYZ] = event.covYZ(); + values[kVtxCovZZ] = event.covZZ(); + values[kVtxChi2] = event.chi2(); + } + + if constexpr ((fillMap & ReducedEventQvector) > 0) { + values[kQ1X0A] = event.q1x0a(); + values[kQ1Y0A] = event.q1y0a(); + values[kQ1X0B] = event.q1x0b(); + values[kQ1Y0B] = event.q1y0b(); + values[kQ1X0C] = event.q1x0c(); + values[kQ1Y0C] = event.q1y0c(); + values[kQ2X0A] = event.q2x0a(); + values[kQ2Y0A] = event.q2y0a(); + values[kQ2X0B] = event.q2x0b(); + values[kQ2Y0B] = event.q2y0b(); + values[kQ2X0C] = event.q2x0c(); + values[kQ2Y0C] = event.q2y0c(); + values[kMultA] = event.multa(); + values[kMultB] = event.multb(); + values[kMultC] = event.multc(); + values[kQ3X0A] = event.q3x0a(); + values[kQ3Y0A] = event.q3y0a(); + values[kQ3X0B] = event.q3x0b(); + values[kQ3Y0B] = event.q3y0b(); + values[kQ3X0C] = event.q3x0c(); + values[kQ3Y0C] = event.q3y0c(); + values[kQ4X0A] = event.q4x0a(); + values[kQ4Y0A] = event.q4y0a(); + values[kQ4X0B] = event.q4x0b(); + values[kQ4Y0B] = event.q4y0b(); + values[kQ4X0C] = event.q4x0c(); + values[kQ4Y0C] = event.q4y0c(); + + EventPlaneHelper epHelper; + float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); + float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); + + values[VarManager::kPsi2A] = Psi2A; + values[VarManager::kPsi2B] = Psi2B; + values[VarManager::kPsi2C] = Psi2C; + + if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { + values[kQ42XA] = event.q42xa(); + values[kQ42YA] = event.q42ya(); + values[kQ23XA] = event.q23xa(); + values[kQ23YA] = event.q23ya(); + values[kS11A] = event.s11a(); + values[kS12A] = event.s12a(); + values[kS13A] = event.s13a(); + values[kS31A] = event.s31a(); + } + + if constexpr ((fillMap & ReducedEventRefFlow) > 0) { + values[kMultA] = event.multa(); + values[kCORR2REFetagap] = event.corr2refetagap(); + values[kM11REFetagap] = event.m11refetagap(); + values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : event.corr2ref(); + values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : event.corr4ref(); + values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : event.corr2ref() * event.corr4ref(); + values[kM11REF] = !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? event.m11ref() : 0; + values[kM1111REF] = !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? event.m1111ref() : 0; + values[kM11M1111REF] = !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? event.m11ref() * event.m1111ref() : 0; + } + } + + if constexpr ((fillMap & CollisionQvect) > 0) { + values[kQ1X0A] = -999; + values[kQ1Y0A] = -999; + values[kQ1X0B] = -999; + values[kQ1Y0B] = -999; + values[kQ1X0C] = -999; + values[kQ1Y0C] = -999; + values[kQ2X0A] = (event.qvecBPosRe() * event.nTrkBPos() + event.qvecBNegRe() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); + values[kQ2Y0A] = (event.qvecBPosIm() * event.nTrkBPos() + event.qvecBNegIm() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); + values[kQ2X0APOS] = event.qvecBPosRe(); + values[kQ2Y0APOS] = event.qvecBPosIm(); + values[kQ2X0ANEG] = event.qvecBNegRe(); + values[kQ2Y0ANEG] = event.qvecBNegIm(); + values[kQ2X0B] = event.qvecFT0ARe(); + values[kQ2Y0B] = event.qvecFT0AIm(); + values[kQ2X0C] = event.qvecFT0CRe(); + values[kQ2Y0C] = event.qvecFT0CIm(); + values[kMultA] = event.nTrkBPos() + event.nTrkBNeg(); + values[kMultAPOS] = event.nTrkBPos(); + values[kMultANEG] = event.nTrkBNeg(); + values[kMultB] = event.sumAmplFT0A(); + values[kMultC] = event.sumAmplFT0C(); + values[kQ3X0A] = -999; + values[kQ3Y0A] = -999; + values[kQ3X0B] = -999; + values[kQ3Y0B] = -999; + values[kQ3X0C] = -999; + values[kQ3Y0C] = -999; + values[kQ4X0A] = -999; + values[kQ4Y0A] = -999; + values[kQ4X0B] = -999; + values[kQ4Y0B] = -999; + values[kQ4X0C] = -999; + values[kQ4Y0C] = -999; + + EventPlaneHelper epHelper; + float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); + float Psi2ANEG = epHelper.GetEventPlane(values[kQ2X0ANEG], values[kQ2Y0ANEG], 2); + float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); + float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); + + values[kPsi2A] = Psi2A; + values[kPsi2APOS] = Psi2APOS; + values[kPsi2ANEG] = Psi2ANEG; + values[kPsi2B] = Psi2B; + values[kPsi2C] = Psi2C; + + float R2SP_AB = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + float R2SP_AC = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + float R2SP_BC = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + float R2SP_AB_Im = (values[kQ2Y0A] * values[kQ2X0B] - values[kQ2X0A] * values[kQ2Y0B]); + float R2SP_AC_Im = (values[kQ2Y0A] * values[kQ2X0C] - values[kQ2X0A] * values[kQ2Y0C]); + float R2SP_BC_Im = (values[kQ2Y0B] * values[kQ2X0C] - values[kQ2X0B] * values[kQ2Y0C]); + values[kR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : R2SP_AB; + values[kWR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : 1.0; + values[kR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : R2SP_AC; + values[kWR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : 1.0; + values[kR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : R2SP_BC; + values[kWR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : 1.0; + values[kR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : R2SP_AB_Im; + values[kWR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : 1.0; + values[kR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : R2SP_AC_Im; + values[kWR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : 1.0; + values[kR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : R2SP_BC_Im; + values[kWR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : 1.0; + + float R2EP_AB = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Cos(2 * (Psi2A - Psi2B)); + float R2EP_AC = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2A - Psi2C)); + float R2EP_BC = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2B - Psi2C)); + float R2EP_AB_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Sin(2 * (Psi2A - Psi2B)); + float R2EP_AC_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2A - Psi2C)); + float R2EP_BC_Im = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2B - Psi2C)); + values[kR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : R2EP_AB; + values[kWR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : 1.0; + values[kR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : R2EP_AC; + values[kWR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : 1.0; + values[kR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : R2EP_BC; + values[kWR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : 1.0; + values[kR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : R2EP_AB_Im; + values[kWR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : 1.0; + values[kR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : R2EP_AC_Im; + values[kWR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : 1.0; + values[kR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : R2EP_BC_Im; + values[kWR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : 1.0; + } + + if constexpr ((fillMap & CollisionMC) > 0) { + values[kMCEventGeneratorId] = event.generatorsID(); + values[kMCEventSubGeneratorId] = event.getSubGeneratorId(); + values[kMCVtxX] = event.posX(); + values[kMCVtxY] = event.posY(); + values[kMCVtxZ] = event.posZ(); + values[kMCEventTime] = event.t(); + values[kMCEventWeight] = event.weight(); + values[kMCEventImpParam] = event.impactParameter(); + if constexpr ((fillMap & CollisionCent) > 0) { + // WARNING: temporary solution, ongoing work to provide proper MC gen. centrality + values[kMCEventCentrFT0C] = event.bestCollisionCentFT0C(); + values[kMultMCNParticlesEta05] = event.multMCNParticlesEta05(); + values[kMultMCNParticlesEta08] = event.multMCNParticlesEta08(); + values[kMultMCNParticlesEta10] = event.multMCNParticlesEta10(); + } + } + + if constexpr ((fillMap & ReducedEventMC) > 0) { + values[kMCEventGeneratorId] = event.generatorsID(); + values[kMCEventGeneratorId] = -999; // to be added in reduced events + values[kMCVtxX] = event.mcPosX(); + values[kMCVtxY] = event.mcPosY(); + values[kMCVtxZ] = event.mcPosZ(); + values[kMCEventTime] = event.t(); + values[kMCEventWeight] = event.weight(); + values[kMCEventImpParam] = event.impactParameter(); + values[kMCEventCentrFT0C] = event.centFT0C(); + } + + if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { + values[kIsDoubleGap] = (event.eventFilter() & (static_cast(1) << kDoubleGap)) > 0; + values[kIsSingleGapA] = (event.eventFilter() & (static_cast(1) << kSingleGapA)) > 0; + values[kIsSingleGapC] = (event.eventFilter() & (static_cast(1) << kSingleGapC)) > 0; + values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; + values[kIsITSUPCMode] = (event.eventFilter() & (static_cast(1) << kITSUPCMode)) > 0; + } + + if constexpr ((fillMap & ReducedZdc) > 0) { + FillZDC(event, values); + } + + // FillEventDerived(values); +} + +template +void VarManager::FillEventTrackEstimators(TEvent const& collision, TAssoc const& assocs, TTracks const& /*tracks*/, float* values) +{ + // Compute median Z for the large dcaZ tracks in the TPC + // This is for studies of the pileup impact on the TPC + + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & Track) > 0 && (fillMap & TrackDCA) > 0) { + + std::vector tracksP; + std::vector tracksM; + + for (const auto& assoc : assocs) { + auto track = assoc.template track_as(); + // compute the dca of this track wrt the collision + auto trackPar = getTrackPar(track); + std::array dca{1e10f, 1e10f}; + trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + + // if it is a displaced track longitudinally, add it to the track vector + if (abs(dca[0]) < 3.0 && abs(dca[1]) > 4.0) { + if (track.tgl() > 0.1) { + tracksP.push_back(track.z()); + } + if (track.tgl() < -0.1) { + tracksM.push_back(track.z()); + } + } + } // end loop over associations + + // compute the number of pileup contributors and the median z for pileup + if (tracksP.size() > 0) { + std::sort(tracksP.begin(), tracksP.end()); + auto midP = tracksP.size() / 2; + values[kNTPCpileupContribA] = tracksP.size(); + values[kNTPCpileupZA] = (tracksP.size() % 2 ? (tracksP[midP] + tracksP[midP - 1]) / 2 : tracksP[midP]); + } + + if (tracksM.size() > 0) { + std::sort(tracksM.begin(), tracksM.end()); + values[kNTPCpileupContribC] = tracksM.size(); + auto midM = tracksM.size() / 2; + values[kNTPCpileupZC] = (tracksM.size() % 2 ? (tracksM[midM] + tracksM[midM - 1]) / 2 : tracksM[midM]); + } + } +} + +template +void VarManager::FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) +{ + if (!values) { + values = fgValues; + } + + if (values[kCentFT0C] >= 0.) { + int idx_sp = hs_sp->FindBin(values[kCentFT0C]); + int idx_ep = hs_ep->FindBin(values[kCentFT0C]); + + values[kR2SP] = hs_sp->GetBinContent(idx_sp); + values[kR2EP] = hs_ep->GetBinContent(idx_ep); + } +} + +template +void VarManager::FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) +{ + if (!values) { + values = fgValues; + } + + if (values[kTwoEvCentFT0C1] >= 0.) { + int idx_sp1 = hs_sp->FindBin(values[kTwoEvCentFT0C1]); + int idx_ep1 = hs_ep->FindBin(values[kTwoEvCentFT0C1]); + + values[kTwoR2SP1] = hs_sp->GetBinContent(idx_sp1); + values[kTwoR2EP1] = hs_ep->GetBinContent(idx_ep1); + } + + if (values[kTwoEvCentFT0C2] >= 0.) { + int idx_sp2 = hs_sp->FindBin(values[kTwoEvCentFT0C2]); + int idx_ep2 = hs_ep->FindBin(values[kTwoEvCentFT0C2]); + + values[kTwoR2SP2] = hs_sp->GetBinContent(idx_sp2); + values[kTwoR2EP2] = hs_ep->GetBinContent(idx_ep2); + } +} + +template +void VarManager::FillTwoMixEventsCumulants(T const& h_v22ev1, T const& h_v24ev1, T const& h_v22ev2, T const& h_v24ev2, T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + int idx_v22ev1; + int idx_v24ev1; + int idx_v22ev2; + int idx_v24ev2; + + if (values[kTwoEvCentFT0C1] >= 0.) { + if (t1.sign() < 0) { + + idx_v22ev1 = h_v22ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + idx_v24ev1 = h_v24ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + values[kV22m] = h_v22ev1->GetBinContent(idx_v22ev1); + values[kV24m] = h_v24ev1->GetBinContent(idx_v24ev1); + + } else { + + idx_v22ev1 = h_v22ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + idx_v24ev1 = h_v24ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); + values[kV22m] = h_v22ev2->GetBinContent(idx_v22ev1); + values[kV24m] = h_v24ev2->GetBinContent(idx_v24ev1); + } + } + if (values[kTwoEvCentFT0C2] >= 0.) { + if (t2.sign() < 0) { + + idx_v22ev2 = h_v22ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + idx_v24ev2 = h_v24ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + values[kV22p] = h_v22ev1->GetBinContent(idx_v22ev2); + values[kV24p] = h_v24ev1->GetBinContent(idx_v24ev2); + + } else { + + idx_v22ev2 = h_v22ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + idx_v24ev2 = h_v24ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); + values[kV22p] = h_v22ev2->GetBinContent(idx_v22ev2); + values[kV24p] = h_v24ev2->GetBinContent(idx_v24ev2); + } + } +} + +template +void VarManager::FillTwoEvents(T const& ev1, T const& ev2, float* values) +{ + if (!values) { + values = fgValues; + } + + values[kTwoEvPosZ1] = ev1.posZ(); + values[kTwoEvPosZ2] = ev2.posZ(); + values[kTwoEvPosR1] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); + values[kTwoEvPosR2] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); + values[kTwoEvPVcontrib1] = ev1.numContrib(); + values[kTwoEvPVcontrib2] = ev2.numContrib(); + if (ev1.numContrib() < ev2.numContrib()) { + values[kTwoEvPosZ1] = ev2.posZ(); + values[kTwoEvPosZ2] = ev1.posZ(); + values[kTwoEvPVcontrib1] = ev2.numContrib(); + values[kTwoEvPVcontrib2] = ev1.numContrib(); + values[kTwoEvPosR1] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); + ; + values[kTwoEvPosR2] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); + } + values[kTwoEvDeltaZ] = ev1.posZ() - ev2.posZ(); + values[kTwoEvDeltaX] = ev1.posX() - ev2.posX(); + values[kTwoEvDeltaY] = ev1.posY() - ev2.posY(); + values[kTwoEvDeltaR] = std::sqrt(values[kTwoEvDeltaX] * values[kTwoEvDeltaX] + values[kTwoEvDeltaY] * values[kTwoEvDeltaY]); +} + +template +void VarManager::FillTwoMixEvents(T1 const& ev1, T1 const& ev2, T2 const& /*tracks1*/, T2 const& /*tracks2*/, float* values) +{ + if (!values) { + values = fgValues; + } + values[kTwoEvPosZ1] = ev1.posZ(); + values[kTwoEvPosZ2] = ev2.posZ(); + values[kTwoEvPosR1] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); + values[kTwoEvPosR2] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); + values[kTwoEvPVcontrib1] = ev1.numContrib(); + values[kTwoEvPVcontrib2] = ev2.numContrib(); + /* + uint32_t Track1Filter = 0; + uint32_t Track2Filter = 0; + for (auto& track1 : tracks1) { Track1Filter = uint32_t(track1.isMuonSelected());} + for (auto& track2 : tracks2) { Track2Filter = uint32_t(track2.isMuonSelected());} + */ + if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { + values[kTwoEvCentFT0C1] = ev1.centFT0C(); + values[kTwoEvCentFT0C2] = ev2.centFT0C(); + } + if constexpr ((fillMap & ReducedEventQvector) > 0) { + // Tobe used for the calculation of u1q1 and u2q2 + values[kQ2X0A1] = ev1.q2x0a(); + values[kQ2X0A2] = ev2.q2x0a(); + values[kQ2Y0A1] = ev1.q2y0a(); + values[kQ2Y0A2] = ev2.q2y0a(); + } + if constexpr ((fillMap & CollisionQvect) > 0) { + // Tobe used for the calculation of u1q1 and u2q2 + values[kQ2X0A1] = (ev1.qvecBPosRe() * ev1.nTrkBPos() + ev1.qvecBNegRe() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); + values[kQ2X0A2] = (ev2.qvecBPosRe() * ev2.nTrkBPos() + ev2.qvecBNegRe() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); + values[kQ2Y0A1] = (ev1.qvecBPosIm() * ev1.nTrkBPos() + ev1.qvecBNegIm() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); + values[kQ2Y0A2] = (ev2.qvecBPosIm() * ev2.nTrkBPos() + ev2.qvecBNegIm() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); + } +} + +template +void VarManager::FillTrack(T const& track, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((fillMap & TrackMFT) > 0) { + values[kPt] = track.pt(); + values[kEta] = track.eta(); + values[kPhi] = track.phi(); + values[kMftNClusters] = track.nClusters(); + + uint64_t mftClsAndFlgs = track.mftClusterSizesAndTrackFlags(); + double meanClusterSize = 0; + for (int i = 0; i < 10; ++i) { + double size = (mftClsAndFlgs >> (i * 6)) & 0x3fULL; + values[kMftClusterSize + i] = (mftClsAndFlgs >> (i * 6)) & 0x3fULL; + if (size > 0) { + meanClusterSize += size; + } + } + meanClusterSize /= track.nClusters(); + values[kMftMeanClusterSize] = meanClusterSize; + } + + // Quantities based on the basic table (contains just kine information and filter bits) + if constexpr ((fillMap & Track) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0 || (fillMap & ReducedTrack) > 0 || (fillMap & ReducedMuon) > 0) { + values[kPt] = track.pt(); + values[kSignedPt] = track.pt() * track.sign(); + if (fgUsedVars[kP]) { + values[kP] = track.p(); + } + if (fgUsedVars[kPx]) { + values[kPx] = track.px(); + } + if (fgUsedVars[kPy]) { + values[kPy] = track.py(); + } + if (fgUsedVars[kPz]) { + values[kPz] = track.pz(); + } + if (fgUsedVars[kInvPt]) { + values[kInvPt] = 1. / track.pt(); + } + values[kEta] = track.eta(); + values[kPhi] = track.phi(); + values[kCharge] = track.sign(); + if (fgUsedVars[kPhiTPCOuter]) { + values[kPhiTPCOuter] = track.phi() - (track.sign() > 0 ? 1.0 : -1.0) * (TMath::PiOver2() - TMath::ACos(0.22 * fgMagField / track.pt())); + if (values[kPhiTPCOuter] > TMath::TwoPi()) { + values[kPhiTPCOuter] -= TMath::TwoPi(); + } + if (values[kPhiTPCOuter] < 0.0) { + values[kPhiTPCOuter] += TMath::TwoPi(); + } + } + if (fgUsedVars[kTrackIsInsideTPCModule]) { + float localSectorPhi = values[kPhiTPCOuter] - TMath::Floor(18.0 * values[kPhiTPCOuter] / TMath::TwoPi()) * (TMath::TwoPi() / 18.0); + float edge = fgTPCInterSectorBoundary / 2.0 / 246.6; // minimal inter-sector boundary as angle + float curvature = 3.0 * 3.33 * track.pt() / fgMagField * (1.0 - TMath::Sin(TMath::ACos(0.22 * fgMagField / track.pt()))); + if (curvature / 2.466 > edge) { + edge = curvature / 2.466; + } + double min = edge; + double max = TMath::TwoPi() / 18.0 - edge; + values[kTrackIsInsideTPCModule] = (localSectorPhi > min && localSectorPhi < max ? 1.0 : 0.0); + } + + if constexpr ((fillMap & ReducedTrack) > 0 && !((fillMap & Pair) > 0)) { + // values[kIsGlobalTrack] = track.filteringFlags_bit(0); + // values[kIsGlobalTrackSDD] = track.filteringFlags_bit(1); + values[kIsAmbiguous] = track.isAmbiguous(); + + values[kIsLegFromGamma] = track.filteringFlags_bit(VarManager::kIsConversionLeg); + values[kIsLegFromK0S] = track.filteringFlags_bit(VarManager::kIsK0sLeg); + values[kIsLegFromLambda] = track.filteringFlags_bit(VarManager::kIsLambdaLeg); + values[kIsLegFromAntiLambda] = track.filteringFlags_bit(VarManager::kIsALambdaLeg); + values[kIsLegFromOmega] = track.filteringFlags_bit(VarManager::kIsOmegaLeg); + + values[kIsProtonFromLambdaAndAntiLambda] = static_cast((values[kIsLegFromLambda] * track.sign() > 0) || (values[kIsLegFromAntiLambda] * (-track.sign()) > 0)); + + for (int i = 0; i < 8; i++) { + values[kIsDalitzLeg + i] = track.filteringFlags_bit(VarManager::kDalitzBits + i); + } + } + + if (fgUsedVars[kM11REFoverMpsingle]) { + float m = o2::constants::physics::MassMuon; + ROOT::Math::PtEtaPhiMVector v(track.pt(), track.eta(), track.phi(), m); + complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex Q42(values[kQ42XA], values[kQ42YA]); + complex Q23(values[kQ23XA], values[kQ23YA]); + complex P2(TMath::Cos(2 * v.Phi()), TMath::Sin(2 * v.Phi())); + values[kM11REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultSingleMuons] : 0; + values[kM1111REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultSingleMuons] : 0; + values[kCORR2REFbysinglemu] = std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbysinglemu] = std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POI]; + values[kM01POIsingle] = values[kMultSingleMuons] * values[kS11A]; + values[kM0111POIsingle] = values[kMultSingleMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POIsingle]; + values[kCORR4POIsingle] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIsingle]; + values[kM01POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM01POIsingle]; + values[kM0111POIsingle] = std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM0111POIsingle]; + values[kCORR2POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR2POIsingle]; + values[kCORR4POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR4POIsingle]; + values[kM01POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM01POIsingle] / values[kMultSingleMuons] : 0; + values[kM0111POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM0111POIsingle] / values[kMultSingleMuons] : 0; + } + } + + // Quantities based on the barrel tables + if constexpr ((fillMap & TrackExtra) > 0 || (fillMap & ReducedTrackBarrel) > 0) { + values[kPin] = track.tpcInnerParam(); + values[kSignedPin] = track.tpcInnerParam() * track.sign(); + if (fgUsedVars[kIsITSrefit]) { + values[kIsITSrefit] = (track.flags() & o2::aod::track::ITSrefit) > 0; // NOTE: This is just for Run-2 + } + if (fgUsedVars[kTrackTimeResIsRange]) { + values[kTrackTimeResIsRange] = (track.flags() & o2::aod::track::TrackTimeResIsRange) > 0; // NOTE: This is NOT for Run-2 + } + if (fgUsedVars[kIsTPCrefit]) { + values[kIsTPCrefit] = (track.flags() & o2::aod::track::TPCrefit) > 0; // NOTE: This is just for Run-2 + } + if (fgUsedVars[kPVContributor]) { + values[kPVContributor] = (track.flags() & o2::aod::track::PVContributor) > 0; // NOTE: This is NOT for Run-2 + } + if (fgUsedVars[kIsGoldenChi2]) { + values[kIsGoldenChi2] = (track.flags() & o2::aod::track::GoldenChi2) > 0; // NOTE: This is just for Run-2 + } + if (fgUsedVars[kOrphanTrack]) { + values[kOrphanTrack] = (track.flags() & o2::aod::track::OrphanTrack) > 0; // NOTE: This is NOT for Run-2 + } + if (fgUsedVars[kIsSPDfirst]) { + values[kIsSPDfirst] = (track.itsClusterMap() & uint8_t(1)) > 0; + } + if (fgUsedVars[kIsSPDboth]) { + values[kIsSPDboth] = (track.itsClusterMap() & uint8_t(3)) > 0; + } + if (fgUsedVars[kIsSPDany]) { + values[kIsSPDany] = (track.itsClusterMap() & uint8_t(1)) || (track.itsClusterMap() & uint8_t(2)); + } + if (fgUsedVars[kITSClusterMap]) { + values[kITSClusterMap] = track.itsClusterMap(); + } + + if (fgUsedVars[kIsITSibFirst]) { + values[kIsITSibFirst] = (track.itsClusterMap() & uint8_t(1)) > 0; + } + if (fgUsedVars[kIsITSibAny]) { + values[kIsITSibAny] = (track.itsClusterMap() & (1 << uint8_t(0))) > 0 || (track.itsClusterMap() & (1 << uint8_t(1))) > 0 || (track.itsClusterMap() & (1 << uint8_t(2))) > 0; + } + if (fgUsedVars[kIsITSibAll]) { + values[kIsITSibAll] = (track.itsClusterMap() & (1 << uint8_t(0))) > 0 && (track.itsClusterMap() & (1 << uint8_t(1))) > 0 && (track.itsClusterMap() & (1 << uint8_t(2))) > 0; + } + + values[kTrackTime] = track.trackTime(); + values[kTrackTimeRes] = track.trackTimeRes(); + values[kTrackTimeResRelative] = track.trackTimeRes() / track.trackTime(); + values[kTOFExpMom] = track.tofExpMom(); + values[kITSchi2] = track.itsChi2NCl(); + values[kTPCncls] = track.tpcNClsFound(); + values[kTPCchi2] = track.tpcChi2NCl(); + values[kTrackLength] = track.length(); + values[kTPCnclsCR] = track.tpcNClsCrossedRows(); + values[kTRDPattern] = track.trdPattern(); + + values[kTPCsignal] = track.tpcSignal(); + values[kTRDsignal] = track.trdSignal(); + + values[kDetectorMap] = track.detectorMap(); + values[kHasITS] = track.hasITS(); + values[kHasTRD] = track.hasTRD(); + values[kHasTOF] = track.hasTOF(); + values[kHasTPC] = track.hasTPC(); + + if constexpr ((fillMap & TrackExtra) > 0) { + if (fgUsedVars[kTPCnCRoverFindCls]) { + values[kTPCnCRoverFindCls] = track.tpcCrossedRowsOverFindableCls(); + } + if (fgUsedVars[kITSncls]) { + values[kITSncls] = track.itsNCls(); // dynamic column + } + if (fgUsedVars[kITSmeanClsSize]) { + values[kITSmeanClsSize] = 0.0; + uint32_t clsizeflag = track.itsClusterSizes(); + float mcls = 0.; + for (unsigned int layer = 0; layer < 7; layer++) { + mcls += (clsizeflag >> (layer * 4)) & 0xF; + } + if (track.itsNCls() > 0) { + values[kITSmeanClsSize] = mcls / track.itsNCls(); + } + } + } + if constexpr ((fillMap & ReducedTrackBarrel) > 0) { + if (fgUsedVars[kITSncls]) { + values[kITSncls] = 0.0; + for (int i = 0; i < 7; ++i) { + values[kITSncls] += ((track.itsClusterMap() & (1 << i)) ? 1 : 0); + } + } + values[kTrackDCAxy] = track.dcaXY(); + values[kTrackDCAz] = track.dcaZ(); + if constexpr ((fillMap & ReducedTrackBarrelCov) > 0) { + if (fgUsedVars[kTrackDCAsigXY]) { + values[kTrackDCAsigXY] = track.dcaXY() / std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAsigZ]) { + values[kTrackDCAsigZ] = track.dcaZ() / std::sqrt(track.cZZ()); + } + if (fgUsedVars[kTrackDCAresXY]) { + values[kTrackDCAresXY] = std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAresZ]) { + values[kTrackDCAresZ] = std::sqrt(track.cZZ()); + } + } + } + } + + // Quantities based on the barrel track selection table + if constexpr ((fillMap & TrackDCA) > 0) { + values[kTrackDCAxy] = track.dcaXY(); + values[kTrackDCAz] = track.dcaZ(); + if constexpr ((fillMap & TrackCov) > 0) { + if (fgUsedVars[kTrackDCAsigXY]) { + values[kTrackDCAsigXY] = track.dcaXY() / std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAsigZ]) { + values[kTrackDCAsigZ] = track.dcaZ() / std::sqrt(track.cZZ()); + } + if (fgUsedVars[kTrackDCAresXY]) { + values[kTrackDCAresXY] = std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAresZ]) { + values[kTrackDCAresZ] = std::sqrt(track.cZZ()); + } + } + } + + // Quantities based on the barrel track selection table + if constexpr ((fillMap & TrackSelection) > 0) { + values[kIsGlobalTrack] = track.isGlobalTrack(); + values[kIsGlobalTrackSDD] = track.isGlobalTrackSDD(); + } + + // Quantities based on the barrel covariance tables + if constexpr ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0) { + values[kTrackCYY] = track.cYY(); + values[kTrackCZZ] = track.cZZ(); + values[kTrackCSnpSnp] = track.cSnpSnp(); + values[kTrackCTglTgl] = track.cTglTgl(); + values[kTrackC1Pt21Pt2] = track.c1Pt21Pt2(); + } + + // Quantities based on the dalitz selections + if constexpr ((fillMap & DalitzBits) > 0) { + for (int i = 0; i < 8; i++) { + values[kIsDalitzLeg + i] = static_cast(track.dalitzBits() & (uint8_t(1) << i)); + } + } + + // Quantities based on the V0 selections + if constexpr ((fillMap & TrackV0Bits) > 0) { + values[kIsLegFromGamma] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsConversionLeg)); + values[kIsLegFromK0S] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsK0sLeg)); + values[kIsLegFromLambda] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsLambdaLeg)); + values[kIsLegFromAntiLambda] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsALambdaLeg)); + values[kIsLegFromOmega] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsOmegaLeg)); + values[kIsProtonFromLambdaAndAntiLambda] = static_cast((values[kIsLegFromLambda] * track.sign() > 0) || (values[kIsLegFromAntiLambda] * (-track.sign()) > 0)); + } + + // Quantities based on the barrel PID tables + if constexpr ((fillMap & TrackPID) > 0 || (fillMap & TrackTPCPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { + values[kTPCnSigmaEl] = track.tpcNSigmaEl(); + values[kTPCnSigmaPi] = track.tpcNSigmaPi(); + values[kTPCnSigmaKa] = track.tpcNSigmaKa(); + values[kTPCnSigmaPr] = track.tpcNSigmaPr(); + + bool isTPCCalibrated = false; + if constexpr ((fillMap & ReducedTrackBarrelPID) > 0) { + if (track.filteringFlags_bit(kIsTPCPostcalibrated)) { + isTPCCalibrated = true; + } + } + // compute TPC postcalibrated electron nsigma based on calibration histograms from CCDB + if (fgUsedVars[kTPCnSigmaEl_Corr] && fgRunTPCPostCalibration[0]) { + if (!isTPCCalibrated) { + values[kTPCnSigmaEl_Corr] = ComputePIDcalibration(0, values[kTPCnSigmaEl]); + } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; + values[kTPCnSigmaEl_Corr] = track.tpcNSigmaEl(); + } + } + + // compute TPC postcalibrated pion nsigma if required + if (fgUsedVars[kTPCnSigmaPi_Corr] && fgRunTPCPostCalibration[1]) { + if (!isTPCCalibrated) { + values[kTPCnSigmaPi_Corr] = ComputePIDcalibration(1, values[kTPCnSigmaPi]); + } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; + values[kTPCnSigmaPi_Corr] = track.tpcNSigmaPi(); + } + } + if (fgUsedVars[kTPCnSigmaKa_Corr] && fgRunTPCPostCalibration[2]) { + // compute TPC postcalibrated kaon nsigma if required + if (!isTPCCalibrated) { + values[kTPCnSigmaKa_Corr] = ComputePIDcalibration(2, values[kTPCnSigmaKa]); + } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; + values[kTPCnSigmaKa_Corr] = track.tpcNSigmaKa(); + } + } + // compute TPC postcalibrated proton nsigma if required + if (fgUsedVars[kTPCnSigmaPr_Corr] && fgRunTPCPostCalibration[3]) { + if (!isTPCCalibrated) { + values[kTPCnSigmaPr_Corr] = ComputePIDcalibration(3, values[kTPCnSigmaPr]); + } else { + LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; + values[kTPCnSigmaPr_Corr] = track.tpcNSigmaPr(); + } + } + + if constexpr ((fillMap & TrackPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { + values[kTOFnSigmaEl] = track.tofNSigmaEl(); + values[kTOFnSigmaPi] = track.tofNSigmaPi(); + values[kTOFnSigmaKa] = track.tofNSigmaKa(); + values[kTOFnSigmaPr] = track.tofNSigmaPr(); + } + + if constexpr ((fillMap & ReducedTrackBarrelPID) > 0) { + values[kTPCnSigmaMu] = track.tpcNSigmaMu(); + values[kTOFnSigmaMu] = track.tofNSigmaMu(); + values[kTPCsignal] = track.tpcSignal(); + values[kTRDsignal] = track.trdSignal(); + values[kTOFbeta] = track.beta(); + } + } + if constexpr ((fillMap & TrackTPCPID) > 0) { + values[kTPCnSigmaEl] = track.tpcNSigmaEl(); + values[kTPCnSigmaPi] = track.tpcNSigmaPi(); + values[kTPCnSigmaKa] = track.tpcNSigmaKa(); + values[kTPCnSigmaPr] = track.tpcNSigmaPr(); + } + if constexpr ((fillMap & TrackPIDExtra) > 0) { + values[kTPCnSigmaMu] = track.tpcNSigmaMu(); + values[kTOFnSigmaMu] = track.tofNSigmaMu(); + values[kTOFbeta] = track.beta(); + } + + // Quantities based on the muon extra table + if constexpr ((fillMap & ReducedMuonExtra) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0) { + values[kMuonNClusters] = track.nClusters(); + values[kMuonPDca] = track.pDca(); + values[kMCHBitMap] = track.mchBitMap(); + values[kMuonRAtAbsorberEnd] = track.rAtAbsorberEnd(); + values[kMuonChi2] = track.chi2(); + values[kMuonChi2MatchMCHMID] = track.chi2MatchMCHMID(); + values[kMuonChi2MatchMCHMFT] = track.chi2MatchMCHMFT(); + values[kMuonMatchScoreMCHMFT] = track.matchScoreMCHMFT(); + values[kMuonTrackType] = track.trackType(); + values[kMuonDCAx] = track.fwdDcaX(); + values[kMuonDCAy] = track.fwdDcaY(); + values[kMuonTime] = track.trackTime(); + values[kMuonTimeRes] = track.trackTimeRes(); + } + // Quantities based on the muon covariance table + if constexpr ((fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { + values[kX] = track.x(); + values[kY] = track.y(); + values[kZ] = track.z(); + values[kTgl] = track.tgl(); + values[kMuonCXX] = track.cXX(); + values[kMuonCXY] = track.cXY(); + values[kMuonCYY] = track.cYY(); + values[kMuonCPhiX] = track.cPhiX(); + values[kMuonCPhiY] = track.cPhiY(); + values[kMuonCPhiPhi] = track.cPhiPhi(); + values[kMuonCTglX] = track.cTglX(); + values[kMuonCTglY] = track.cTglY(); + values[kMuonCTglPhi] = track.cTglPhi(); + values[kMuonCTglTgl] = track.cTglTgl(); + values[kMuonC1Pt2X] = track.c1PtX(); + values[kMuonC1Pt2Y] = track.c1PtY(); + values[kMuonC1Pt2Phi] = track.c1PtPhi(); + values[kMuonC1Pt2Tgl] = track.c1PtTgl(); + values[kMuonC1Pt21Pt2] = track.c1Pt21Pt2(); + } + + // Quantities based on the pair table(s) + if constexpr ((fillMap & Pair) > 0) { + values[kMass] = track.mass(); + ROOT::Math::PtEtaPhiMVector vpair(track.pt(), track.eta(), track.phi(), track.mass()); + values[kRap] = vpair.Rapidity(); + } + + // Derived quantities which can be computed based on already filled variables + FillTrackDerived(values); +} + +template +void VarManager::FillTrackCollision(T const& track, C const& collision, float* values) +{ + + if (!values) { + values = fgValues; + } + if constexpr ((fillMap & ReducedTrackBarrel) > 0 || (fillMap & TrackDCA) > 0) { + auto trackPar = getTrackPar(track); + std::array dca{1e10f, 1e10f}; + trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + + values[kTrackDCAxy] = dca[0]; + values[kTrackDCAz] = dca[1]; + + if constexpr ((fillMap & ReducedTrackBarrelCov) > 0 || (fillMap & TrackCov) > 0) { + if (fgUsedVars[kTrackDCAsigXY]) { + values[kTrackDCAsigXY] = dca[0] / std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAsigZ]) { + values[kTrackDCAsigZ] = dca[1] / std::sqrt(track.cZZ()); + } + } + } + if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0 || (fillMap & ReducedMuonCov) > 0) { + + o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); + + float dcaX = (propmuonAtDCA.getX() - collision.posX()); + float dcaY = (propmuonAtDCA.getY() - collision.posY()); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + values[kMuonPDca] = track.p() * dcaXY; + } +} + +template +void VarManager::FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values) +{ + if (!values) { + values = fgValues; + } + if constexpr ((fillMap & ReducedTrackBarrel) > 0 || (fillMap & TrackDCA) > 0) { + auto trackPar = getTrackPar(track); + std::array dca{1e10f, 1e10f}; + std::array pVec = {track.px(), track.py(), track.pz()}; + // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, materialCorr, &dca); + getPxPyPz(trackPar, pVec); + + values[kTrackDCAxy] = dca[0]; + values[kTrackDCAz] = dca[1]; + + if constexpr ((fillMap & ReducedTrackBarrelCov) > 0 || (fillMap & TrackCov) > 0) { + if (fgUsedVars[kTrackDCAsigXY]) { + values[kTrackDCAsigXY] = dca[0] / std::sqrt(track.cYY()); + } + if (fgUsedVars[kTrackDCAsigZ]) { + values[kTrackDCAsigZ] = dca[1] / std::sqrt(track.cZZ()); + } + } + } +} + +template +void VarManager::FillPhoton(T const& track, float* values) +{ + if (!values) { + values = fgValues; + } + + // Quantities based on the basic table (contains just kine information and filter bits) + if constexpr ((fillMap & Track) > 0 || (fillMap & ReducedTrack) > 0) { + values[kPt] = track.pt(); + if (fgUsedVars[kP]) { + values[kP] = track.p(); + } + if (fgUsedVars[kPx]) { + values[kPx] = track.px(); + } + if (fgUsedVars[kPy]) { + values[kPy] = track.py(); + } + if (fgUsedVars[kPz]) { + values[kPz] = track.pz(); + } + if (fgUsedVars[kInvPt]) { + values[kInvPt] = 1. / track.pt(); + } + values[kEta] = track.eta(); + values[kPhi] = track.phi(); + values[kRap] = track.eta(); // photon does not know rapidity .y() + values[kMassDau] = track.mGamma(); + } +} + +template +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(); + values[kMCPx] = track.px(); + values[kMCPy] = track.py(); + values[kMCPz] = track.pz(); + values[kMCE] = track.e(); + values[kMCVx] = track.vx(); + values[kMCVy] = track.vy(); + values[kMCVz] = track.vz(); + values[kMCPt] = track.pt(); + values[kMCPhi] = track.phi(); + values[kMCEta] = track.eta(); + values[kMCY] = -track.y(); + values[kMCParticleGeneratorId] = track.producedByGenerator(); + if (fgUsedVars[kMCMotherPdgCode]) { + if (track.has_mothers()) { + auto motherId = track.mothersIds()[0]; + auto mother = mcStack.rawIteratorAt(motherId); + values[kMCMotherPdgCode] = mother.pdgCode(); + } + } + + FillTrackDerived(values); +} + +template +void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values) +{ + // energy correlators + float MassHadron; + if constexpr (pairType == kJpsiHadronMass) { + MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); + } + if constexpr (pairType == kJpsiPionMass) { + MassHadron = o2::constants::physics::MassPionCharged; + } + ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); + 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); + 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; + values[kMCdeltaeta] = deltaeta; + values[kMCHadronPt] = t1.pt(); + values[kMCHadronEta] = t1.eta(); + values[kMCHadronPhi] = RecoDecay::constrainAngle(t1.phi(), -o2::constants::math::PIHalf); + values[kMCHadronPdgCode] = t1.pdgCode(); + values[kMCWeight] = E_boost / o2::constants::physics::MassJPsi; + + values[kMCCosChi_randomPhi_trans] = -999.9f; + values[kMCCosChi_randomPhi_toward] = -999.9f; + values[kMCCosChi_randomPhi_away] = -999.9f; + + values[kMCdeltaphi_randomPhi_trans] = -999.9f; + values[kMCdeltaphi_randomPhi_toward] = -999.9f; + values[kMCdeltaphi_randomPhi_away] = -999.9f; + + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kMCWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kMCWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kMCCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kMCWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); + + values[kMCdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kMCdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); + } +} + +template +void VarManager::FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values) +{ + if (!values) { + values = fgValues; + } + o2::dataformats::GlobalFwdTrack propmuon1 = PropagateMuon(muon1, collision); + o2::dataformats::GlobalFwdTrack propmuon2 = PropagateMuon(muon2, collision); + + float m = o2::constants::physics::MassMuon; + + ROOT::Math::PtEtaPhiMVector v1(propmuon1.getPt(), propmuon1.getEta(), propmuon1.getPhi(), m); + ROOT::Math::PtEtaPhiMVector v2(propmuon2.getPt(), propmuon2.getEta(), propmuon2.getPhi(), m); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + values[kPhi] = v12.Phi(); + values[kRap] = -v12.Rapidity(); + + double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); + double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); + values[kDeltaPtotTracks] = Ptot1 - Ptot2; +} + +template +void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if constexpr (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if constexpr (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + // Make the TPC information of the kaon available for pair histograms + values[kPin_leg1] = t1.tpcInnerParam(); + values[kTPCnSigmaKa_leg1] = t1.tpcNSigmaKa(); + } + + if constexpr (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + values[kCharge] = t1.sign() + t2.sign(); + values[kCharge1] = t1.sign(); + values[kCharge2] = t2.sign(); + 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; + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; + values[kRap] = -v12.Rapidity(); + double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); + double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); + values[kDeltaPtotTracks] = Ptot1 - Ptot2; + + values[kPt1] = t1.pt(); + values[kEta1] = t1.eta(); + values[kPhi1] = t1.phi(); + values[kPt2] = t2.pt(); + values[kEta2] = t2.eta(); + values[kPhi2] = t2.phi(); + + if (fgUsedVars[kDeltaPhiPair2]) { + double phipair2 = v1.Phi() - v2.Phi(); + if (phipair2 > 3 * TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2 - 2 * TMath::Pi(); + } else if (phipair2 < -TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2 + 2 * TMath::Pi(); + } else { + values[kDeltaPhiPair2] = phipair2; + } + } + + if (fgUsedVars[kDeltaEtaPair2]) { + values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); + } + + if (fgUsedVars[kPsiPair]) { + values[kDeltaPhiPair] = (t1.sign() * fgMagField > 0.) ? (v1.Phi() - v2.Phi()) : (v2.Phi() - v1.Phi()); + double xipair = TMath::ACos((v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / v1.P() / v2.P()); + values[kPsiPair] = (t1.sign() * fgMagField > 0.) ? TMath::ASin((v1.Theta() - v2.Theta()) / xipair) : TMath::ASin((v2.Theta() - v1.Theta()) / xipair); + } + + if (fgUsedVars[kOpeningAngle]) { + double scalar = v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz(); + double Ptot12 = Ptot1 * Ptot2; + if (Ptot12 <= 0) { + values[kOpeningAngle] = 0.; + } else { + double arg = scalar / Ptot12; + if (arg > 1.) + arg = 1.; + if (arg < -1) + arg = -1; + values[kOpeningAngle] = TMath::ACos(arg); + } + } + + // polarization parameters + bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame + bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kCosThetaRM]; // Random frame + + if (useHE || useCS || usePP || useRM) { + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kCosThetaHE]) + values[kCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kPhiHE]) { + values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kPhiHE] < 0) { + values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeHE]) { + if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { + if (values[kCosThetaHE] > 0) { + values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeHE] = -999; // not computable + } + } + } + + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kCosThetaCS]) + values[kCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kPhiCS]) { + values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kPhiCS] < 0) { + values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeCS]) { + if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { + if (values[kCosThetaCS] > 0) { + values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeCS] = -999; // not computable + } + } + } + + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kCosThetaPP]) { + values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); + } + if (fgUsedVars[kPhiPP]) { + values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kPhiPP] < 0) { + values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildePP]) { + if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { + if (values[kCosThetaPP] > 0) { + values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildePP] = -999; // not computable + } + } + } + + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kCosThetaRM]) + values[kCosThetaRM] = zaxis_RM.Dot(v_CM); + } + } + + if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { + + if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { + // Quantities based on the barrel tables + double dca1XY = t1.dcaXY(); + double dca2XY = t2.dcaXY(); + double dca1Z = t1.dcaZ(); + double dca2Z = t2.dcaZ(); + double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); + double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); + double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); + double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); + + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); + values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); + values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); + values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + + double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); + double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); + if ((det1 < 0) || (det2 < 0)) { + values[kQuadDCAsigXYZ] = -999; + } else { + double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; + double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; + + double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); + double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); + + values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); + } + } + } + if constexpr ((pairType == kDecayToMuMu) && ((fillMap & Muon) > 0 || (fillMap & ReducedMuon) > 0)) { + if (fgUsedVars[kQuadDCAabsXY]) { + double dca1X = t1.fwdDcaX(); + double dca1Y = t1.fwdDcaY(); + double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); + double dca2X = t2.fwdDcaX(); + double dca2Y = t2.fwdDcaY(); + double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); + } + } + if (fgUsedVars[kPairPhiv]) { + values[kPairPhiv] = calculatePhiV(t1, t2); + } +} + +template +void VarManager::FillPairCollision(const C& collision, T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { + + if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { + + auto trackPart1 = getTrackPar(t1); + std::array dca1{1e10f, 1e10f}; + trackPart1.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca1); + + auto trackPart2 = getTrackPar(t2); + std::array dca2{1e10f, 1e10f}; + trackPart2.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca2); + + // Recalculated quantities + double dca1XY = dca1[0]; + double dca2XY = dca2[0]; + double dca1Z = dca1[1]; + double dca2Z = dca2[1]; + double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); + double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); + double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); + double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); + + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); + values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); + values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); + values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + + double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); + double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); + if ((det1 < 0) || (det2 < 0)) { + values[kQuadDCAsigXYZ] = -999; + } else { + double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; + double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; + + double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); + double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); + + values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); + } + } + } +} + +template +void VarManager::FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { + + if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { + + auto trackPart1 = getTrackPar(t1); + std::array dca1{1e10f, 1e10f}; + std::array pVect1 = {t1.px(), t1.py(), t1.pz()}; + // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart1, 2.f, materialCorr, &dca1); + getPxPyPz(trackPart1, pVect1); + + auto trackPart2 = getTrackPar(t2); + std::array dca2{1e10f, 1e10f}; + std::array pVect2 = {t2.px(), t2.py(), t2.pz()}; + // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); + propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart2, 2.f, materialCorr, &dca2); + getPxPyPz(trackPart2, pVect2); + + // Recalculated quantities + double dca1XY = dca1[0]; + double dca2XY = dca2[0]; + double dca1Z = dca1[1]; + double dca2Z = dca2[1]; + double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); + double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); + double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); + double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); + + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); + values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); + values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); + values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); + + double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); + double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); + if ((det1 < 0) || (det2 < 0)) { + values[kQuadDCAsigXYZ] = -999; + } else { + double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; + double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; + + double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); + double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); + + values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); + } + } + } +} + +template +void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) +{ + + if (!values) { + values = fgValues; + } + if (pairType == kTripleCandidateToEEPhoton) { + float m1 = o2::constants::physics::MassElectron; + float m3 = o2::constants::physics::MassPhoton; + 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(), m1); + ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; + values[kPairMass] = v123.M(); + values[kPairPt] = v123.Pt(); + values[kPairEta] = v123.Eta(); + values[kPairPhi] = v123.Phi(); + values[kPairMassDau] = v12.M(); + values[kMassDau] = m3; + values[kPairPtDau] = v12.Pt(); + values[kPt] = t3.pt(); + values[kEta] = t3.eta(); + values[kEta1] = t1.eta(); + values[kEta2] = t2.eta(); + values[kDeltaEta] = v12.Eta(); + values[VarManager::kDeltaMass] = v123.M() - v12.M(); + values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; + values[kRap] = v123.Rapidity(); + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); + } + + if (pairType == kTripleCandidateToKPiPi) { + float m1 = o2::constants::physics::MassKaonCharged; + float m2 = o2::constants::physics::MassPionCharged; + + 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 v3(t3.pt(), t3.eta(), t3.phi(), m2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + values[kCharge] = t1.sign() + t2.sign() + t3.sign(); + values[kS12] = (v1 + v2).M2(); + values[kS13] = (v1 + v3).M2(); + values[kS23] = (v2 + v3).M2(); + } + + if (pairType == kTripleCandidateToPKPi) { + float m1 = o2::constants::physics::MassProton; + float m2 = o2::constants::physics::MassKaonCharged; + float m3 = o2::constants::physics::MassPionCharged; + + 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 v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + } +} + +template +void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) +{ + // + // Lightweight fill function called from the innermost event mixing loop + // + if (!values) { + values = fgValues; + } + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if constexpr (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if constexpr (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + 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; + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; + values[kRap] = -v12.Rapidity(); + + if (fgUsedVars[kDeltaPhiPair2]) { + double phipair2ME = v1.Phi() - v2.Phi(); + if (phipair2ME > 3 * TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2ME - 2 * TMath::Pi(); + } else if (phipair2ME < -TMath::Pi() / 2) { + values[kDeltaPhiPair2] = phipair2ME + 2 * TMath::Pi(); + } else { + values[kDeltaPhiPair2] = phipair2ME; + } + } + + if (fgUsedVars[kDeltaEtaPair2]) { + values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); + } + + // polarization parameters + bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame + bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kCosThetaRM]; // Random frame + + if (useHE || useCS || usePP || useRM) { + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kCosThetaHE]) + values[kCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kPhiHE]) { + values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kPhiHE] < 0) { + values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeHE]) { + if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { + if (values[kCosThetaHE] > 0) { + values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeHE] < 0) { + values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeHE] = -999; // not computable + } + } + } + + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kCosThetaCS]) + values[kCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kPhiCS]) { + values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kPhiCS] < 0) { + values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildeCS]) { + if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { + if (values[kCosThetaCS] > 0) { + values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildeCS] < 0) { + values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildeCS] = -999; // not computable + } + } + } + + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kCosThetaPP]) { + values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); + } + if (fgUsedVars[kPhiPP]) { + values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kPhiPP] < 0) { + values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kPhiTildePP]) { + if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { + if (values[kCosThetaPP] > 0) { + values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kPhiTildePP] < 0) { + values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kPhiTildePP] = -999; // not computable + } + } + } + + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kCosThetaRM]) + values[kCosThetaRM] = zaxis_RM.Dot(v_CM); + } + } + + if constexpr ((fillMap & ReducedEventQvector) > 0 || (fillMap & CollisionQvect) > 0) { + // TODO: provide different computations for vn + // Compute the scalar product UQ for two muon from different event using Q-vector from A, for second and third harmonic + float Psi2A1 = getEventPlane(2, values[kQ2X0A1], values[kQ2Y0A1]); + float Psi2A2 = getEventPlane(2, values[kQ2X0A2], values[kQ2Y0A2]); + values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A1)); // WARNING: using the first event EP + values[kCos2DeltaPhiEv1] = TMath::Cos(2 * (v1.Phi() - Psi2A1)); + values[kCos2DeltaPhiEv2] = TMath::Cos(2 * (v2.Phi() - Psi2A2)); + values[kU2Q2] = values[kQ2X0A1] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v12.Phi()); // WARNING: using the first event EP + values[kU2Q2Ev1] = values[kQ2X0A1] * TMath::Cos(2 * v1.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v1.Phi()); + values[kU2Q2Ev2] = values[kQ2X0A2] * TMath::Cos(2 * v2.Phi()) + values[kQ2Y0A2] * TMath::Sin(2 * v2.Phi()); + + values[kCos2DeltaPhiMu1] = TMath::Cos(2 * (v1.Phi() - v12.Phi())); + values[kCos2DeltaPhiMu2] = TMath::Cos(2 * (v2.Phi() - v12.Phi())); + + values[kV2SP1] = values[kU2Q2Ev1] / values[kTwoR2SP1]; + values[kV2SP2] = values[kU2Q2Ev2] / values[kTwoR2SP2]; + values[kV2EP1] = values[kCos2DeltaPhiEv1] / values[kTwoR2EP1]; + values[kV2EP2] = values[kCos2DeltaPhiEv2] / values[kTwoR2EP2]; + + float V2ME_SP = values[kV2SP1] * values[kCos2DeltaPhiMu1] + values[kV2SP2] * values[kCos2DeltaPhiMu2]; + float V2ME_EP = values[kV2EP1] * values[kCos2DeltaPhiMu1] + values[kV2EP2] * values[kCos2DeltaPhiMu2]; + values[kV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : V2ME_SP; + values[kWV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : 1.0; + values[kV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : V2ME_EP; + values[kWV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : 1.0; + + // Cumulant part + float V22ME = values[kV22m] * values[kCos2DeltaPhiMu1] + values[kV22p] * values[kCos2DeltaPhiMu2]; + float V24ME = values[kV24m] * values[kCos2DeltaPhiMu1] + values[kV24p] * values[kCos2DeltaPhiMu2]; + values[kV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V22ME; + values[kWV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; + values[kV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V24ME; + values[kWV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; + + if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { + complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex Q42(values[kQ42XA], values[kQ42YA]); + complex Q23(values[kQ23XA], values[kQ23YA]); + complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); + values[kM01POIME] = values[kMultDimuonsME] * values[kS11A]; + values[kM0111POIME] = values[kMultDimuonsME] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIME] = (P2 * conj(Q21)).real() / values[kM01POIME]; + values[kCORR4POIME] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIME]; + values[kM01POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME])) ? values[kM01POIME] / values[kMultDimuonsME] : 0; + values[kM0111POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME])) ? values[kM0111POIME] / values[kMultDimuonsME] : 0; + values[kM11REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuonsME] : 0; + values[kM1111REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuonsME] : 0; + values[kCORR2REFbydimuonsME] = std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbydimuonsME] = std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POIME] = std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) ? 0 : values[kCORR2POIME]; + values[kCORR4POIME] = std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) ? 0 : values[kCORR4POIME]; + } + } + if constexpr (pairType == kDecayToMuMu) { + if (fgUsedVars[kQuadDCAabsXY]) { + double dca1X = t1.fwdDcaX(); + double dca1Y = t1.fwdDcaY(); + double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); + double dca2X = t2.fwdDcaX(); + double dca2Y = t2.fwdDcaY(); + double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); + values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); + } + } + if (fgUsedVars[kPairPhiv]) { + values[kPairPhiv] = calculatePhiV(t1, t2); + } +} + +template +void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values) +{ + if (!values) { + values = fgValues; + } + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + // TODO : implement resolution smearing. + 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; + values[kMCMass] = v12.M(); + values[kMCPt] = v12.Pt(); + values[kMCEta] = v12.Eta(); + values[kMCPhi] = v12.Phi(); + values[kMCY] = -v12.Rapidity(); + + // polarization parameters + bool useHE = fgUsedVars[kMCCosThetaHE] || fgUsedVars[kMCPhiHE]; // helicity frame + bool useCS = fgUsedVars[kMCCosThetaCS] || fgUsedVars[kMCPhiCS]; // Collins-Soper frame + bool usePP = fgUsedVars[kMCCosThetaPP]; // production plane frame + bool useRM = fgUsedVars[kMCCosThetaRM]; // Random frame + + if (useHE || useCS || usePP || useRM) { + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; + ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.pdgCode() > 0 ? v1_CM : v2_CM); + + if (useHE) { + ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; + ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; + if (fgUsedVars[kMCCosThetaHE]) + values[kMCCosThetaHE] = zaxis_HE.Dot(v_CM); + if (fgUsedVars[kMCPhiHE]) { + values[kMCPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); + if (values[kMCPhiHE] < 0) { + values[kMCPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildeHE]) { + if (fgUsedVars[kMCCosThetaHE] && fgUsedVars[kMCPhiHE]) { + if (values[kMCCosThetaHE] > 0) { + values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildeHE] < 0) { + values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildeHE] < 0) { + values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildeHE] = -999; // not computable + } + } + } + + if (useCS) { + ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; + ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; + ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; + if (fgUsedVars[kMCCosThetaCS]) + values[kMCCosThetaCS] = zaxis_CS.Dot(v_CM); + if (fgUsedVars[kMCPhiCS]) { + values[kMCPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); + if (values[kMCPhiCS] < 0) { + values[kMCPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildeCS]) { + if (fgUsedVars[kMCCosThetaCS] && fgUsedVars[kMCPhiCS]) { + if (values[kMCCosThetaCS] > 0) { + values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildeCS] < 0) { + values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildeCS] < 0) { + values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildeCS] = -999; // not computable + } + } + } + + if (usePP) { + ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); + ROOT::Math::XYZVector yaxis_PP{v12.Vect().Unit()}; + ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; + if (fgUsedVars[kMCCosThetaPP]) { + values[kMCCosThetaPP] = zaxis_PP.Dot(v_CM); + } + if (fgUsedVars[kMCPhiPP]) { + values[kMCPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); + if (values[kMCPhiPP] < 0) { + values[kMCPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] + } + } + if (fgUsedVars[kMCPhiTildePP]) { + if (fgUsedVars[kMCCosThetaPP] && fgUsedVars[kMCPhiPP]) { + if (values[kMCCosThetaPP] > 0) { + values[kMCPhiTildePP] = values[kMCPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 + if (values[kMCPhiTildePP] < 0) { + values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } else { + values[kMCPhiTildePP] = values[kMCPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 + if (values[kMCPhiTildePP] < 0) { + values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] + } + } + } else { + values[kMCPhiTildePP] = -999; // not computable + } + } + } + + if (useRM) { + double randomCostheta = gRandom->Uniform(-1., 1.); + double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); + ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); + if (fgUsedVars[kMCCosThetaRM]) + values[kMCCosThetaRM] = zaxis_RM.Dot(v_CM); + } + } +} + +template +void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr (candidateType == kTripleCandidateToEEPhoton) { + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + float m3 = o2::constants::physics::MassPhoton; + 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[kPairMassDau] = v12.M(); + values[kMassDau] = m3; + values[kPairPtDau] = v12.Pt(); + values[kPt] = t3.pt(); + values[kEta] = t3.eta(); + values[kEta1] = t1.eta(); + values[kEta2] = t2.eta(); + values[kDeltaEta] = v12.Eta(); + values[VarManager::kDeltaMass] = v123.M() - v12.M(); + values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; + values[kRap] = -v123.Rapidity(); + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); + } + + if constexpr (candidateType == kTripleCandidateToKPiPi) { + float m1 = o2::constants::physics::MassKaonCharged; + float m2 = o2::constants::physics::MassPionCharged; + + 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 v3(t3.pt(), t3.eta(), t3.phi(), m2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kMass] = v123.M(); + values[kPt] = v123.Pt(); + values[kEta] = v123.Eta(); + values[kPhi] = v123.Phi(); + values[kRap] = -v123.Rapidity(); + values[kCharge] = t1.sign() + t2.sign() + t3.sign(); + values[kS12] = (v1 + v2).M2(); + 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 +void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, bool propToSV, float* values) +{ + // check at compile time that the event and cov matrix have the cov matrix + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); + constexpr bool muonHasCov = ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0); + + if (!values) { + values = fgValues; + } + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToKPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + } + if constexpr (pairType == kDecayToMuMu && muonHasCov) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + 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; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + int procCode = 0; + + // TODO: use trackUtilities functions to initialize the various matrices to avoid code duplication + // auto pars1 = getTrackParCov(t1); + // auto pars2 = getTrackParCov(t2); + // We need to hide the cov data members from the cases when no cov table is provided + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { + std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; + std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), + t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), + t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; + std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; + std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), + t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), + t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; + procCode = fgFitterTwoProngBarrel.process(pars1, pars2); + } else if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { + // Initialize track parameters for forward + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); + procCode = fgFitterTwoProngFwd.process(pars1, pars2); + } else { + return; + } + + values[kVertexingProcCode] = procCode; + if (procCode == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingChi2PCA] = -999.; + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + + values[kVertexingTauxy] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauzErr] = -999.; + values[kVertexingPz] = -999.; + values[kVertexingSV] = -999.; + return; + } + + Vec3D secondaryVertex; + + if constexpr (eventHasVtxCov) { + + std::array covMatrixPCA{}; + // get track impact parameters + // This modifies track momenta! + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; + // auto primaryVertex = getPrimaryVertex(collision); + auto covMatrixPV = primaryVertex.getCov(); + + if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { + secondaryVertex = fgFitterTwoProngBarrel.getPCACandidate(); + covMatrixPCA = fgFitterTwoProngBarrel.calcPCACovMatrixFlat(); + auto chi2PCA = fgFitterTwoProngBarrel.getChi2AtPCACandidate(); + auto trackParVar0 = fgFitterTwoProngBarrel.getTrack(0); + auto trackParVar1 = fgFitterTwoProngBarrel.getTrack(1); + values[kVertexingChi2PCA] = chi2PCA; + v1 = {trackParVar0.getPt(), trackParVar0.getEta(), trackParVar0.getPhi(), m1}; + v2 = {trackParVar1.getPt(), trackParVar1.getEta(), trackParVar1.getPhi(), m2}; + v12 = v1 + v2; + + } else if constexpr (pairType == kDecayToMuMu && muonHasCov) { + // Get pca candidate from forward DCA fitter + secondaryVertex = fgFitterTwoProngFwd.getPCACandidate(); + covMatrixPCA = fgFitterTwoProngFwd.calcPCACovMatrixFlat(); + auto chi2PCA = fgFitterTwoProngFwd.getChi2AtPCACandidate(); + auto trackParVar0 = fgFitterTwoProngFwd.getTrack(0); + auto trackParVar1 = fgFitterTwoProngFwd.getTrack(1); + values[kVertexingChi2PCA] = chi2PCA; + v1 = {trackParVar0.getPt(), trackParVar0.getEta(), trackParVar0.getPhi(), m1}; + v2 = {trackParVar1.getPt(), trackParVar1.getEta(), trackParVar1.getPhi(), m2}; + v12 = v1 + v2; + + values[kPt1] = trackParVar0.getPt(); + values[kEta1] = trackParVar0.getEta(); + values[kPhi1] = trackParVar0.getPhi(); + + values[kPt2] = trackParVar1.getPt(); + values[kEta2] = trackParVar1.getEta(); + values[kPhi2] = trackParVar1.getPhi(); + } + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingPz] = TMath::Abs(v12.Pz()); + values[kVertexingSV] = secondaryVertex[2]; + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v12.Px() + + (collision.posY() - secondaryVertex[1]) * v12.Py() + + (collision.posZ() - secondaryVertex[2]) * v12.Pz()) / + (v12.P() * values[VarManager::kVertexingLxyz]); + // Decay length defined as in Run 2 + values[kVertexingLzProjected] = ((secondaryVertex[2] - collision.posZ()) * v12.Pz()) / TMath::Sqrt(v12.Pz() * v12.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()) + ((secondaryVertex[2] - collision.posZ()) * v12.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py()) + (v12.Pz() * v12.Pz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v12.M() / (v12.Pt()); + values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (v12.Pt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v12.M() / TMath::Abs(v12.Pz()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v12.M() / (v12.P()); + } + } else { + KFParticle trk0KF; + KFParticle trk1KF; + KFParticle KFGeoTwoProng; + if constexpr ((pairType == kDecayToEE) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, -11 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, -11 * t2.sign()); + + KFGeoTwoProng.SetConstructMethod(2); + KFGeoTwoProng.AddDaughter(trk0KF); + KFGeoTwoProng.AddDaughter(trk1KF); + + } else if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { + KFPTrack kfpTrack0 = createKFPFwdTrackFromFwdTrack(t1); + trk0KF = KFParticle(kfpTrack0, -13 * t1.sign()); + KFPTrack kfpTrack1 = createKFPFwdTrackFromFwdTrack(t2); + trk1KF = KFParticle(kfpTrack1, -13 * t2.sign()); + + KFGeoTwoProng.SetConstructMethod(2); + KFGeoTwoProng.AddDaughter(trk0KF); + KFGeoTwoProng.AddDaughter(trk1KF); + + } else if constexpr ((pairType == kDecayToKPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); + + KFGeoTwoProng.SetConstructMethod(2); + KFGeoTwoProng.AddDaughter(trk0KF); + KFGeoTwoProng.AddDaughter(trk1KF); + } + if (fgUsedVars[kKFMass]) { + float mass = 0., massErr = 0.; + if (!KFGeoTwoProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; + } + + if constexpr (eventHasVtxCov) { + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + values[kKFNContributorsPV] = kfpVertex.GetNContributors(); + KFParticle KFPV(kfpVertex); + double dxPair2PV = KFGeoTwoProng.GetX() - KFPV.GetX(); + double dyPair2PV = KFGeoTwoProng.GetY() - KFPV.GetY(); + double dzPair2PV = KFGeoTwoProng.GetZ() - KFPV.GetZ(); + if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr] || fgUsedVars[kVertexingTauxy] || fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr] || fgUsedVars[kCosPointingAngle]) { + values[kVertexingLxy] = std::sqrt(dxPair2PV * dxPair2PV + dyPair2PV * dyPair2PV); + values[kVertexingLz] = std::sqrt(dzPair2PV * dzPair2PV); + values[kVertexingLxyz] = std::sqrt(dxPair2PV * dxPair2PV + dyPair2PV * dyPair2PV + dzPair2PV * dzPair2PV); + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoTwoProng.GetCovariance(0)) * dxPair2PV * dxPair2PV + (KFPV.GetCovariance(2) + KFGeoTwoProng.GetCovariance(2)) * dyPair2PV * dyPair2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoTwoProng.GetCovariance(1)) * dxPair2PV * dyPair2PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoTwoProng.GetCovariance(5)) * dzPair2PV * dzPair2PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoTwoProng.GetCovariance(0)) * dxPair2PV * dxPair2PV + (KFPV.GetCovariance(2) + KFGeoTwoProng.GetCovariance(2)) * dyPair2PV * dyPair2PV + (KFPV.GetCovariance(5) + KFGeoTwoProng.GetCovariance(5)) * dzPair2PV * dzPair2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoTwoProng.GetCovariance(1)) * dxPair2PV * dyPair2PV + (KFPV.GetCovariance(3) + KFGeoTwoProng.GetCovariance(3)) * dxPair2PV * dzPair2PV + (KFPV.GetCovariance(4) + KFGeoTwoProng.GetCovariance(4)) * dyPair2PV * dzPair2PV); + if (fabs(values[kVertexingLxy]) < 1.e-8f) + values[kVertexingLxy] = 1.e-8f; + values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; + if (fabs(values[kVertexingLz]) < 1.e-8f) + values[kVertexingLz] = 1.e-8f; + values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; + if (fabs(values[kVertexingLxyz]) < 1.e-8f) + values[kVertexingLxyz] = 1.e-8f; + values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; + values[kVertexingTauxy] = KFGeoTwoProng.GetPseudoProperDecayTime(KFPV, KFGeoTwoProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzPair2PV * KFGeoTwoProng.GetMass() / (TMath::Abs(KFGeoTwoProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(KFGeoTwoProng.GetPz()); + values[kVertexingSV] = KFGeoTwoProng.GetZ(); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoTwoProng.GetMass() / (TMath::Abs(KFGeoTwoProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kCosPointingAngle] = (std::sqrt(dxPair2PV * dxPair2PV) * v12.Px() + + std::sqrt(dyPair2PV * dyPair2PV) * v12.Py() + + std::sqrt(dzPair2PV * dzPair2PV) * v12.Pz()) / + (v12.P() * values[VarManager::kVertexingLxyz]); + } + // As defined in Run 2 (projected onto momentum) + if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || fgUsedVars[kVertexingLzProjected]) { + values[kVertexingLzProjected] = (dzPair2PV * KFGeoTwoProng.GetPz()) / TMath::Sqrt(KFGeoTwoProng.GetPz() * KFGeoTwoProng.GetPz()); + values[kVertexingLxyProjected] = (dxPair2PV * KFGeoTwoProng.GetPx()) + (dyPair2PV * KFGeoTwoProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy())); + values[kVertexingLxyzProjected] = (dxPair2PV * KFGeoTwoProng.GetPx()) + (dyPair2PV * KFGeoTwoProng.GetPy()) + (dzPair2PV * KFGeoTwoProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy()) + (KFGeoTwoProng.GetPz() * KFGeoTwoProng.GetPz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetPt()); + values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (KFGeoTwoProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoTwoProng.GetMass() / TMath::Abs(KFGeoTwoProng.GetPz()); + } + + if (fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr]) { + values[kVertexingLxyOverErr] = values[kVertexingLxy] / values[kVertexingLxyErr]; + values[kVertexingLzOverErr] = values[kVertexingLz] / values[kVertexingLzErr]; + values[kVertexingLxyzOverErr] = values[kVertexingLxyz] / values[kVertexingLxyzErr]; + } + + if (fgUsedVars[kKFChi2OverNDFGeo]) + values[kKFChi2OverNDFGeo] = KFGeoTwoProng.GetChi2() / KFGeoTwoProng.GetNDF(); + if (fgUsedVars[kKFCosPA]) + values[kKFCosPA] = calculateCosPA(KFGeoTwoProng, KFPV); + + // in principle, they should be in FillTrack + if (fgUsedVars[kKFTrack0DCAxyz] || fgUsedVars[kKFTrack1DCAxyz]) { + values[kKFTrack0DCAxyz] = trk0KF.GetDistanceFromVertex(KFPV); + values[kKFTrack1DCAxyz] = trk1KF.GetDistanceFromVertex(KFPV); + } + if (fgUsedVars[kKFTrack0DCAxy] || fgUsedVars[kKFTrack1DCAxy]) { + values[kKFTrack0DCAxy] = trk0KF.GetDistanceFromVertexXY(KFPV); + values[kKFTrack1DCAxy] = trk1KF.GetDistanceFromVertexXY(KFPV); + } + if (fgUsedVars[kKFDCAxyzBetweenProngs]) + values[kKFDCAxyzBetweenProngs] = trk0KF.GetDistanceFromParticle(trk1KF); + if (fgUsedVars[kKFDCAxyBetweenProngs]) + values[kKFDCAxyBetweenProngs] = trk0KF.GetDistanceFromParticleXY(trk1KF); + + if (fgUsedVars[kKFTracksDCAxyzMax]) { + values[kKFTracksDCAxyzMax] = values[kKFTrack0DCAxyz] > values[kKFTrack1DCAxyz] ? values[kKFTrack0DCAxyz] : values[kKFTrack1DCAxyz]; + } + if (fgUsedVars[kKFTracksDCAxyMax]) { + values[kKFTracksDCAxyMax] = TMath::Abs(values[kKFTrack0DCAxy]) > TMath::Abs(values[kKFTrack1DCAxy]) ? values[kKFTrack0DCAxy] : values[kKFTrack1DCAxy]; + } + if (fgUsedVars[kKFTrack0DeviationFromPV] || fgUsedVars[kKFTrack1DeviationFromPV]) { + values[kKFTrack0DeviationFromPV] = trk0KF.GetDeviationFromVertex(KFPV); + values[kKFTrack1DeviationFromPV] = trk1KF.GetDeviationFromVertex(KFPV); + } + if (fgUsedVars[kKFTrack0DeviationxyFromPV] || fgUsedVars[kKFTrack1DeviationxyFromPV]) { + values[kKFTrack0DeviationxyFromPV] = trk0KF.GetDeviationFromVertexXY(KFPV); + values[kKFTrack1DeviationxyFromPV] = trk1KF.GetDeviationFromVertexXY(KFPV); + } + if (fgUsedVars[kKFJpsiDCAxyz]) { + values[kKFJpsiDCAxyz] = KFGeoTwoProng.GetDistanceFromVertex(KFPV); + } + if (fgUsedVars[kKFJpsiDCAxy]) { + values[kKFJpsiDCAxy] = KFGeoTwoProng.GetDistanceFromVertexXY(KFPV); + } + if (fgUsedVars[kKFPairDeviationFromPV] || fgUsedVars[kKFPairDeviationxyFromPV]) { + values[kKFPairDeviationFromPV] = KFGeoTwoProng.GetDeviationFromVertex(KFPV); + values[kKFPairDeviationxyFromPV] = KFGeoTwoProng.GetDeviationFromVertexXY(KFPV); + } + if (fgUsedVars[kKFChi2OverNDFGeoTop] || fgUsedVars[kKFMassGeoTop]) { + KFParticle KFGeoTopTwoProngBarrel = KFGeoTwoProng; + KFGeoTopTwoProngBarrel.SetProductionVertex(KFPV); + values[kKFChi2OverNDFGeoTop] = KFGeoTopTwoProngBarrel.GetChi2() / KFGeoTopTwoProngBarrel.GetNDF(); + float mass = 0., massErr = 0.; + if (!KFGeoTopTwoProngBarrel.GetMass(mass, massErr)) + values[kKFMassGeoTop] = mass; + else + values[kKFMassGeoTop] = -999.; + } + if (propToSV) { + if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); + + auto geoMan1 = o2::base::GeometryManager::meanMaterialBudget(t1.x(), t1.y(), t1.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); + auto geoMan2 = o2::base::GeometryManager::meanMaterialBudget(t2.x(), t2.y(), t2.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); + auto x2x01 = static_cast(geoMan1.meanX2X0); + auto x2x02 = static_cast(geoMan2.meanX2X0); + float B[3]; + float xyz[3] = {0, 0, 0}; + KFGeoTwoProng.GetFieldValue(xyz, B); + // TODO: find better soluton to handle cases where KF outputs negative variances + /*float covXX = 0.1; + float covYY = 0.1; + if (KFGeoTwoProng.GetCovariance(0, 0) > 0) { + covXX = KFGeoTwoProng.GetCovariance(0, 0); + } + if (KFGeoTwoProng.GetCovariance(1, 1) > 0) { + covYY = KFGeoTwoProng.GetCovariance(0, 0); + }*/ + pars1.propagateToVtxhelixWithMCS(KFGeoTwoProng.GetZ(), {KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY()}, {KFGeoTwoProng.GetCovariance(0, 0), KFGeoTwoProng.GetCovariance(1, 1)}, B[2], x2x01); + pars2.propagateToVtxhelixWithMCS(KFGeoTwoProng.GetZ(), {KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY()}, {KFGeoTwoProng.GetCovariance(0, 0), KFGeoTwoProng.GetCovariance(1, 1)}, B[2], x2x02); + v1 = {pars1.getPt(), pars1.getEta(), pars1.getPhi(), m1}; + v2 = {pars2.getPt(), pars2.getEta(), pars2.getPhi(), m2}; + v12 = v1 + v2; + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + values[kPhi] = v12.Phi(); + values[kRap] = -v12.Rapidity(); + values[kVertexingTauxy] = KFGeoTwoProng.GetPseudoProperDecayTime(KFPV, v12.M()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzPair2PV * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(v12.Pz()); + values[kVertexingSV] = KFGeoTwoProng.GetZ(); + + values[kPt1] = pars1.getPt(); + values[kEta1] = pars1.getEta(); + values[kPhi1] = pars1.getPhi(); + + values[kPt2] = pars2.getPt(); + values[kEta2] = pars2.getEta(); + values[kPhi2] = pars2.getPhi(); + } + } + } + } + if (propToSV) { + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + // values[kPhi] = v12.Phi(); + values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; + } else { + values[kPt1] = t1.pt(); + values[kEta1] = t1.eta(); + values[kPhi1] = t1.phi(); + + values[kPt2] = t2.pt(); + values[kEta2] = t2.eta(); + values[kPhi2] = t2.phi(); + } +} + +template +void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, VarManager::PairCandidateType tripletType, float* values) +{ + // TODO: Vertexing error variables + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + bool trackHasCov = ((fillMap & ReducedTrackBarrelCov) > 0); + + if (!values) { + values = fgValues; + } + + float m1, m2, m3; + + if (tripletType == kTripleCandidateToKPiPi) { + m1 = o2::constants::physics::MassKaonCharged; + m2 = o2::constants::physics::MassPionCharged; + m3 = o2::constants::physics::MassPionCharged; + } + if (tripletType == kTripleCandidateToPKPi) { + m1 = o2::constants::physics::MassProton; + m2 = o2::constants::physics::MassKaonCharged; + m3 = o2::constants::physics::MassPionCharged; + } + 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 v3(t3.pt(), t3.eta(), t3.phi(), m3); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + int procCode = 0; + + if (trackHasCov) { + std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; + std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), + t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), + t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; + std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; + std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), + t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), + t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; + std::array t3pars = {t3.y(), t3.z(), t3.snp(), t3.tgl(), t3.signed1Pt()}; + std::array t3covs = {t3.cYY(), t3.cZY(), t3.cZZ(), t3.cSnpY(), t3.cSnpZ(), + t3.cSnpSnp(), t3.cTglY(), t3.cTglZ(), t3.cTglSnp(), t3.cTglTgl(), + t3.c1PtY(), t3.c1PtZ(), t3.c1PtSnp(), t3.c1PtTgl(), t3.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{t3.x(), t3.alpha(), t3pars, t3covs}; + procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); + } else { + return; + } + + values[VarManager::kVertexingProcCode] = procCode; + if (procCode == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingChi2PCA] = -999.; + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + + values[kVertexingTauxy] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauzErr] = -999.; + + values[kVertexingLzProjected] = -999.; + values[kVertexingLxyProjected] = -999.; + values[kVertexingLxyzProjected] = -999.; + values[kVertexingTauzProjected] = -999.; + values[kVertexingTauxyProjected] = -999.; + values[kVertexingTauxyzProjected] = -999.; + + return; + } + + Vec3D secondaryVertex; + + if constexpr (eventHasVtxCov) { + secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); + + std::array covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); + + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; + auto covMatrixPV = primaryVertex.getCov(); + + if (fgUsedVars[kVertexingChi2PCA]) { + auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); + values[VarManager::kVertexingChi2PCA] = chi2PCA; + } + + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + + (collision.posY() - secondaryVertex[1]) * v123.Py() + + (collision.posZ() - secondaryVertex[2]) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); + + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / (v123.Pt()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v123.M() / (v123.P()); + } + } else { + KFParticle trk0KF; + KFParticle trk1KF; + KFParticle trk2KF; + KFParticle KFGeoThreeProng; + if ((tripletType == kTripleCandidateToKPiPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); + trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); + + KFGeoThreeProng.SetConstructMethod(3); + KFGeoThreeProng.AddDaughter(trk0KF); + KFGeoThreeProng.AddDaughter(trk1KF); + KFGeoThreeProng.AddDaughter(trk2KF); + + } else if ((tripletType == kTripleCandidateToPKPi) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); + trk0KF = KFParticle(kfpTrack0, 2212 * t1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); + trk1KF = KFParticle(kfpTrack1, 321 * t2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); + trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); + + KFGeoThreeProng.SetConstructMethod(3); + KFGeoThreeProng.AddDaughter(trk0KF); + KFGeoThreeProng.AddDaughter(trk1KF); + KFGeoThreeProng.AddDaughter(trk2KF); + } + if (fgUsedVars[kKFMass]) { + float mass = 0., massErr = 0.; + if (!KFGeoThreeProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; + } + + if constexpr (eventHasVtxCov) { + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + values[kKFNContributorsPV] = kfpVertex.GetNContributors(); + KFParticle KFPV(kfpVertex); + double dxTriplet2PV = KFGeoThreeProng.GetX() - KFPV.GetX(); + double dyTriplet2PV = KFGeoThreeProng.GetY() - KFPV.GetY(); + double dzTriplet2PV = KFGeoThreeProng.GetZ() - KFPV.GetZ(); + + values[kVertexingLxy] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV); + values[kVertexingLz] = std::sqrt(dzTriplet2PV * dzTriplet2PV); + values[kVertexingLxyz] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV + dzTriplet2PV * dzTriplet2PV); + + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(3) + KFGeoThreeProng.GetCovariance(3)) * dxTriplet2PV * dzTriplet2PV + (KFPV.GetCovariance(4) + KFGeoThreeProng.GetCovariance(4)) * dyTriplet2PV * dzTriplet2PV); + if (fabs(values[kVertexingLxy]) < 1.e-8f) + values[kVertexingLxy] = 1.e-8f; + values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; + if (fabs(values[kVertexingLz]) < 1.e-8f) + values[kVertexingLz] = 1.e-8f; + values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; + if (fabs(values[kVertexingLxyz]) < 1.e-8f) + values[kVertexingLxyz] = 1.e-8f; + values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; + + values[kVertexingTauxy] = KFGeoThreeProng.GetPseudoProperDecayTime(KFPV, KFGeoThreeProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzTriplet2PV * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(KFGeoThreeProng.GetPz()); + values[kVertexingSV] = KFGeoThreeProng.GetZ(); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kCosPointingAngle] = (std::sqrt(dxTriplet2PV * dxTriplet2PV) * v123.Px() + + std::sqrt(dyTriplet2PV * dyTriplet2PV) * v123.Py() + + std::sqrt(dzTriplet2PV * dzTriplet2PV) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + + values[kVertexingLzProjected] = (dzTriplet2PV * KFGeoThreeProng.GetPz()) / TMath::Sqrt(KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz()); + values[kVertexingLxyProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); + values[kVertexingLxyzProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()) + (dzTriplet2PV * KFGeoThreeProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoThreeProng.GetMass() / TMath::Abs(KFGeoThreeProng.GetPz()); + } + } +} + +template +void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values) +{ + + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); + constexpr bool muonHasCov = ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0); + if (!values) { + values = fgValues; + } + + float mtrack; + float mlepton1, mlepton2; + + int procCode = 0; + int procCodeJpsi = 0; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + if constexpr ((candidateType == kBcToThreeMuons) && muonHasCov) { + mlepton1 = o2::constants::physics::MassMuon; + mlepton2 = o2::constants::physics::MassMuon; + mtrack = o2::constants::physics::MassMuon; + + o2::track::TrackParCovFwd pars1 = FwdToTrackPar(lepton1, lepton1); + o2::track::TrackParCovFwd pars2 = FwdToTrackPar(lepton2, lepton2); + o2::track::TrackParCovFwd pars3 = FwdToTrackPar(track, track); + + procCode = VarManager::fgFitterThreeProngFwd.process(pars1, pars2, pars3); + procCodeJpsi = VarManager::fgFitterTwoProngFwd.process(pars1, pars2); + } else if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { + if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { + mlepton1 = o2::constants::physics::MassElectron; + mlepton2 = o2::constants::physics::MassElectron; + mtrack = o2::constants::physics::MassKaonCharged; + } else if constexpr ((candidateType == kDstarToD0KPiPi) && trackHasCov) { + mlepton1 = o2::constants::physics::MassKaonCharged; + mlepton2 = o2::constants::physics::MassPionCharged; + mtrack = o2::constants::physics::MassPionCharged; + } + std::array lepton1pars = {lepton1.y(), lepton1.z(), lepton1.snp(), lepton1.tgl(), lepton1.signed1Pt()}; + std::array lepton1covs = {lepton1.cYY(), lepton1.cZY(), lepton1.cZZ(), lepton1.cSnpY(), lepton1.cSnpZ(), + lepton1.cSnpSnp(), lepton1.cTglY(), lepton1.cTglZ(), lepton1.cTglSnp(), lepton1.cTglTgl(), + lepton1.c1PtY(), lepton1.c1PtZ(), lepton1.c1PtSnp(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{lepton1.x(), lepton1.alpha(), lepton1pars, lepton1covs}; + std::array lepton2pars = {lepton2.y(), lepton2.z(), lepton2.snp(), lepton2.tgl(), lepton2.signed1Pt()}; + std::array lepton2covs = {lepton2.cYY(), lepton2.cZY(), lepton2.cZZ(), lepton2.cSnpY(), lepton2.cSnpZ(), + lepton2.cSnpSnp(), lepton2.cTglY(), lepton2.cTglZ(), lepton2.cTglSnp(), lepton2.cTglTgl(), + lepton2.c1PtY(), lepton2.c1PtZ(), lepton2.c1PtSnp(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{lepton2.x(), lepton2.alpha(), lepton2pars, lepton2covs}; + std::array lepton3pars = {track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt()}; + std::array lepton3covs = {track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), + track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), + track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{track.x(), track.alpha(), lepton3pars, lepton3covs}; + procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); + procCodeJpsi = VarManager::fgFitterTwoProngBarrel.process(pars1, pars2); + } else { + return; + } + + ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton1); + ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton2); + ROOT::Math::PtEtaPhiMVector v3(track.pt(), track.eta(), track.phi(), mtrack); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + ROOT::Math::PtEtaPhiMVector vdilepton(v12.pt(), v12.eta(), v12.phi(), v12.M()); + ROOT::Math::PtEtaPhiMVector v123 = vdilepton + v3; + values[VarManager::kPairMass] = v123.M(); + values[VarManager::kMassDau] = mtrack; + values[VarManager::kDeltaMass] = v123.M() - v12.M(); + values[VarManager::kPairPt] = v123.Pt(); + values[VarManager::kPairRap] = -v123.Rapidity(); + values[VarManager::kPairEta] = v123.Eta(); + if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { + values[VarManager::kPairMassDau] = v12.M(); + values[VarManager::kPairPtDau] = v12.Pt(); + } + values[VarManager::kPt] = track.pt(); + values[kS12] = (v1 + v2).M2(); + values[kS13] = (v1 + v3).M2(); + values[kS23] = (v2 + v3).M2(); + + values[VarManager::kVertexingProcCode] = procCode; + if (procCode == 0 || procCodeJpsi == 0) { + // TODO: set the other variables to appropriate values and return + values[VarManager::kVertexingChi2PCA] = -999.; + values[VarManager::kVertexingLxy] = -999.; + values[VarManager::kVertexingLxyz] = -999.; + values[VarManager::kVertexingLz] = -999.; + values[VarManager::kVertexingLxyErr] = -999.; + values[VarManager::kVertexingLxyzErr] = -999.; + values[VarManager::kVertexingLzErr] = -999.; + + values[VarManager::kVertexingTauxy] = -999.; + values[VarManager::kVertexingTauz] = -999.; + values[VarManager::kVertexingTauxyErr] = -999.; + values[VarManager::kVertexingTauzErr] = -999.; + values[VarManager::kVertexingPz] = -999.; + values[VarManager::kVertexingSV] = -999.; + return; + } + + Vec3D secondaryVertex; + + if constexpr (eventHasVtxCov) { + std::array covMatrixPCA; + o2::dataformats::DCA impactParameter0; + o2::dataformats::DCA impactParameter1; + + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; + auto covMatrixPV = primaryVertex.getCov(); + + if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { + secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); + covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); + } else if constexpr (candidateType == kBcToThreeMuons && muonHasCov) { + secondaryVertex = fgFitterThreeProngFwd.getPCACandidate(); + covMatrixPCA = fgFitterThreeProngFwd.calcPCACovMatrixFlat(); + } + + if (fgUsedVars[kVertexingChi2PCA]) { + auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); + values[VarManager::kVertexingChi2PCA] = chi2PCA; + } + + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz]) { + + values[VarManager::kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[VarManager::kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[VarManager::kVertexingLxyz] = values[VarManager::kVertexingLxy] + values[VarManager::kVertexingLz]; + values[VarManager::kVertexingLxy] = std::sqrt(values[VarManager::kVertexingLxy]); + values[VarManager::kVertexingLz] = std::sqrt(values[VarManager::kVertexingLz]); + values[VarManager::kVertexingLxyz] = std::sqrt(values[VarManager::kVertexingLxyz]); + } + + if (fgUsedVars[kVertexingLxyzErr] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr]) { + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + } + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingPz] = TMath::Abs(v123.Pz()); + values[kVertexingSV] = secondaryVertex[2]; + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); + + if (fgUsedVars[kCosPointingAngle] && fgUsedVars[kVertexingLxyz]) { + values[VarManager::kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + + (collision.posY() - secondaryVertex[1]) * v123.Py() + + (collision.posZ() - secondaryVertex[2]) * v123.Pz()) / + (v123.P() * values[VarManager::kVertexingLxyz]); + } + // run 2 definitions: Lxy projected onto the momentum vector of the candidate + if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || values[kVertexingTauxyProjected]) { + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / v123.Pt(); + } + } + } else { + KFParticle lepton1KF; + KFParticle lepton2KF; + KFParticle hadronKF; + KFParticle KFGeoTwoLeptons; + KFParticle KFGeoThreeProng; + + if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); + lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); + lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track); + hadronKF = KFParticle(kfpTrack2, 321 * track.sign()); // kaon mass + + KFGeoTwoLeptons.SetConstructMethod(2); + KFGeoTwoLeptons.AddDaughter(lepton1KF); + KFGeoTwoLeptons.AddDaughter(lepton2KF); + + if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { + values[VarManager::kPairMassDau] = KFGeoTwoLeptons.GetMass(); + values[VarManager::kPairPtDau] = KFGeoTwoLeptons.GetPt(); + } + + // Quantities between 3rd prong and candidate + if (fgUsedVars[kKFDCAxyzBetweenProngs]) + values[kKFDCAxyzBetweenProngs] = KFGeoTwoLeptons.GetDistanceFromParticle(hadronKF); + + KFGeoThreeProng.SetConstructMethod(2); + KFGeoThreeProng.AddDaughter(KFGeoTwoLeptons); + KFGeoThreeProng.AddDaughter(hadronKF); + + if (fgUsedVars[kKFMass]) + values[kKFMass] = KFGeoThreeProng.GetMass(); + + if constexpr (eventHasVtxCov) { + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle KFPV(kfpVertex); + double dxTriplet3PV = KFGeoThreeProng.GetX() - KFPV.GetX(); + double dyTriplet3PV = KFGeoThreeProng.GetY() - KFPV.GetY(); + double dzTriplet3PV = KFGeoThreeProng.GetZ() - KFPV.GetZ(); + + if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr] || fgUsedVars[kVertexingTauxy] || fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr] || fgUsedVars[kCosPointingAngle]) { + values[kVertexingLxy] = std::sqrt(dxTriplet3PV * dxTriplet3PV + dyTriplet3PV * dyTriplet3PV); + values[kVertexingLz] = std::sqrt(dzTriplet3PV * dzTriplet3PV); + values[kVertexingLxyz] = std::sqrt(dxTriplet3PV * dxTriplet3PV + dyTriplet3PV * dyTriplet3PV + dzTriplet3PV * dzTriplet3PV); + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet3PV * dxTriplet3PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet3PV * dyTriplet3PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet3PV * dyTriplet3PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet3PV * dzTriplet3PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet3PV * dxTriplet3PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet3PV * dyTriplet3PV + (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet3PV * dzTriplet3PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet3PV * dyTriplet3PV + (KFPV.GetCovariance(3) + KFGeoThreeProng.GetCovariance(3)) * dxTriplet3PV * dzTriplet3PV + (KFPV.GetCovariance(4) + KFGeoThreeProng.GetCovariance(4)) * dyTriplet3PV * dzTriplet3PV); + if (fabs(values[kVertexingLxy]) < 1.e-8f) + values[kVertexingLxy] = 1.e-8f; + values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; + if (fabs(values[kVertexingLz]) < 1.e-8f) + values[kVertexingLz] = 1.e-8f; + values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; + if (fabs(values[kVertexingLxyz]) < 1.e-8f) + values[kVertexingLxyz] = 1.e-8f; + values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; + + if (fgUsedVars[kVertexingTauxy]) + values[kVertexingTauxy] = KFGeoThreeProng.GetPseudoProperDecayTime(KFPV, KFGeoThreeProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + if (fgUsedVars[kVertexingTauxyErr]) + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + + if (fgUsedVars[kCosPointingAngle]) + values[VarManager::kCosPointingAngle] = (dxTriplet3PV * KFGeoThreeProng.GetPx() + + dyTriplet3PV * KFGeoThreeProng.GetPy() + + dzTriplet3PV * KFGeoThreeProng.GetPz()) / + (KFGeoThreeProng.GetP() * values[VarManager::kVertexingLxyz]); + } // end calculate vertex variables + + // As defined in Run 2 (projected onto momentum) + if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || fgUsedVars[kVertexingLzProjected]) { + values[kVertexingLzProjected] = (dzTriplet3PV * KFGeoThreeProng.GetPz()) / TMath::Sqrt(KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz()); + values[kVertexingLxyProjected] = (dxTriplet3PV * KFGeoThreeProng.GetPx()) + (dyTriplet3PV * KFGeoThreeProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); + values[kVertexingLxyzProjected] = (dxTriplet3PV * KFGeoThreeProng.GetPx()) + (dyTriplet3PV * KFGeoThreeProng.GetPy()) + (dzTriplet3PV * KFGeoThreeProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); + values[kVertexingTauxyProjected] = (values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass()) / (KFGeoThreeProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = (values[kVertexingLzProjected] * KFGeoThreeProng.GetMass()) / TMath::Abs(KFGeoThreeProng.GetPz()); + } // end Run 2 quantities + } // end eventHasVtxCov + } // end (candidateType == kBtoJpsiEEK) && trackHasCov + } // end KF +} + +template +void VarManager::FillQVectorFromGFW(C const& /*collision*/, A const& compA11, A const& compB11, A const& compC11, A const& compA21, A const& compB21, A const& compC21, A const& compA31, A const& compB31, A const& compC31, A const& compA41, A const& compB41, A const& compC41, A const& compA23, A const& compA42, float S10A, float S10B, float S10C, float S11A, float S11B, float S11C, float S12A, float S13A, float S14A, float S21A, float S22A, float S31A, float S41A, float* values) +{ + if (!values) { + values = fgValues; + } + + // Fill Qn vectors from generic flow framework for different eta gap A, B, C (n=1,2,3,4) with proper normalisation + // Use normalized Q-vectors for SP and EP + values[kQ1X0A] = compA11.real() / S11A; + values[kQ1Y0A] = compA11.imag() / S11A; + values[kQ1X0B] = compB11.real() / S11B; + values[kQ1Y0B] = compB11.imag() / S11B; + values[kQ1X0C] = compC11.real() / S11C; + values[kQ1Y0C] = compC11.imag() / S11C; + values[kQ2X0A] = compA21.real() / S11A; + values[kQ2Y0A] = compA21.imag() / S11A; + values[kQ2X0B] = compB21.real() / S11B; + values[kQ2Y0B] = compB21.imag() / S11B; + values[kQ2X0C] = compC21.real() / S11C; + values[kQ2Y0C] = compC21.imag() / S11C; + values[kQ3X0A] = compA31.real() / S11A; + values[kQ3Y0A] = compA31.imag() / S11A; + values[kQ3X0B] = compB31.real() / S11B; + values[kQ3Y0B] = compB31.imag() / S11B; + values[kQ3X0C] = compC31.real() / S11C; + values[kQ3Y0C] = compC31.imag() / S11C; + values[kQ4X0A] = compA41.real() / S11A; + values[kQ4Y0A] = compA41.imag() / S11A; + values[kQ4X0B] = compB41.real() / S11B; + values[kQ4Y0B] = compB41.imag() / S11B; + values[kQ4X0C] = compC41.real() / S11C; + values[kQ4Y0C] = compC41.imag() / S11C; + values[kQ42XA] = compA42.real(); // Only being used by cumulants, no need for normalization + values[kQ42YA] = compA42.imag(); // Only being used by cumulants, no need for normalization + values[kQ23XA] = compA23.real(); // Only being used by cumulants, no need for normalization + values[kQ23YA] = compA23.imag(); // Only being used by cumulants, no need for normalization + values[kS11A] = S11A; + values[kS12A] = S12A; + values[kS13A] = S13A; + values[kS31A] = S31A; + + // Q-vectors components correlation (A, B, C) + values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; + values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; + values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; + values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; + values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; + values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; + values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; + values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; + values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; + values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; + values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; + values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; + + // Fill event multiplicities + values[kMultA] = S10A; + values[kMultB] = S10B; + values[kMultC] = S10C; + + // Fill necessary quantities for cumulant calculations with weighted Q-vectors + values[kM11REF] = S21A - S12A; + values[kM1111REF] = S41A - 6. * S12A * S21A + 8. * S13A * S11A + 3. * S22A - 6. * S14A; + values[kCORR2REF] = (norm(compA21) - S12A) / values[kM11REF]; + values[kCORR4REF] = (pow(norm(compA21), 2) + norm(compA42) - 2. * (compA42 * conj(compA21) * conj(compA21)).real() + 8. * (compA23 * conj(compA21)).real() - 4. * S12A * norm(compA21) - 6. * S14A + 2. * S22A) / values[kM1111REF]; + values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR2REF]; + values[kM11REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kM11REF]; + values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR4REF]; + values[kM1111REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kM1111REF]; + values[kCORR2CORR4REF] = values[kCORR2REF] * values[kCORR4REF]; + values[kM11M1111REF] = values[kM11REF] * values[kM1111REF]; + + // For cumulants: A = Full TPC, B = Negative TPC, C = Positive TPC + complex QA(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex QB(values[kQ2X0B] * S11B, values[kQ2Y0B] * S11B); + complex QC(values[kQ2X0C] * S11C, values[kQ2Y0C] * S11C); + values[kM11REFetagap] = S11B * S11C; + values[kCORR2REFetagap] = ((QB * conj(QC)).real()) / values[kM11REFetagap]; + values[kCORR2REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kCORR2REFetagap]; + values[kM11REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kM11REFetagap]; + + // TODO: provide different computations for R + // Compute the R factor using the 2 sub-events technique for second and third harmonic + // Compute event planes + auto Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); + auto Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); + auto Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); + auto Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); + auto Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); + values[kPsi2A] = Psi2A; + values[kPsi2B] = Psi2B; + values[kPsi2C] = Psi2C; + + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); + + values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); + values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); + values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); + values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); +} + +template +void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) +{ + if (!values) { + values = fgValues; + } + + float xQVecFT0a = collision.qvecFT0ARe(); // already normalised + float yQVecFT0a = collision.qvecFT0AIm(); // already normalised + float xQVecFT0c = collision.qvecFT0CRe(); // already normalised + float yQVecFT0c = collision.qvecFT0CIm(); // already normalised + float xQVecFT0m = collision.qvecFT0MRe(); // already normalised + float yQVecFT0m = collision.qvecFT0MIm(); // already normalised + float xQVecFV0a = collision.qvecFV0ARe(); // already normalised + float yQVecFV0a = collision.qvecFV0AIm(); // already normalised + float xQVecBPos = collision.qvecTPCposRe(); // already normalised + float yQVecBPos = collision.qvecTPCposIm(); // already normalised + float xQVecBNeg = collision.qvecTPCnegRe(); // already normalised + float yQVecBNeg = collision.qvecTPCnegIm(); // already normalised + + values[kQ2X0A] = collision.qvecTPCallRe(); + values[kQ2Y0A] = collision.qvecTPCallIm(); + values[kQ2X0APOS] = xQVecBPos; + values[kQ2Y0APOS] = yQVecBPos; + values[kQ2X0ANEG] = xQVecBNeg; + values[kQ2Y0ANEG] = yQVecBNeg; + values[kQ2X0B] = xQVecFT0a; + values[kQ2Y0B] = yQVecFT0a; + values[kQ2X0C] = xQVecFT0c; + values[kQ2Y0C] = yQVecFT0c; + values[kMultA] = collision.nTrkTPCpos() + collision.nTrkTPCneg(); + values[kMultAPOS] = collision.nTrkTPCpos(); + values[kMultANEG] = collision.nTrkTPCneg(); + values[kMultB] = collision.sumAmplFT0A(); // Be careful, this is weighted sum of multiplicity + values[kMultC] = collision.sumAmplFT0C(); // Be careful, this is weighted sum of multiplicity + + // Q-vectors components correlation (A, B, C) + values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; + values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; + values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; + values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; + values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; + values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; + values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; + values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; + values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; + values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; + values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; + values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; + + EventPlaneHelper epHelper; + float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); + float Psi2ANEG = epHelper.GetEventPlane(values[kQ2X0ANEG], values[kQ2Y0ANEG], 2); + float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); + float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); + + values[kPsi2A] = Psi2A; + values[kPsi2APOS] = Psi2APOS; + values[kPsi2ANEG] = Psi2ANEG; + values[kPsi2B] = Psi2B; + values[kPsi2C] = Psi2C; + + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + values[kR2SP_FT0CTPCPOS] = (xQVecFT0c * xQVecBPos + yQVecFT0c * yQVecBPos); + values[kR2SP_FT0CTPCNEG] = (xQVecFT0c * xQVecBNeg + yQVecFT0c * yQVecBNeg); + values[kR2SP_FT0ATPCPOS] = (xQVecFT0a * xQVecBPos + yQVecFT0a * yQVecBPos); + values[kR2SP_FT0ATPCNEG] = (xQVecFT0a * xQVecBNeg + yQVecFT0a * yQVecBNeg); + values[kR2SP_FT0MTPCPOS] = (xQVecFT0m * xQVecBPos + yQVecFT0m * yQVecBPos); + values[kR2SP_FT0MTPCNEG] = (xQVecFT0m * xQVecBNeg + yQVecFT0m * yQVecBNeg); + values[kR2SP_FV0ATPCPOS] = (xQVecFV0a * xQVecBPos + yQVecFV0a * yQVecBPos); + values[kR2SP_FV0ATPCNEG] = (xQVecFV0a * xQVecBNeg + yQVecFV0a * yQVecBNeg); + + float epFT0a = epHelper.GetEventPlane(xQVecFT0a, yQVecFT0a, 2); + float epFT0c = epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, 2); + float epFT0m = epHelper.GetEventPlane(xQVecFT0m, yQVecFT0m, 2); + float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, 2); + float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, 2); + float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, 2); + float epTPCFull = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); + + values[kR2EP_AB] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0a, 2)); + values[kR2EP_AC] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0c, 2)); + values[kR2EP_BC] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epFT0c, 2)); + values[kR2EP_FT0CTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBPoss, 2)); + values[kR2EP_FT0CTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBNegs, 2)); + values[kR2EP_FT0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBPoss, 2)); + values[kR2EP_FT0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBNegs, 2)); + values[kR2EP_FT0MTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBPoss, 2)); + values[kR2EP_FT0MTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBNegs, 2)); + values[kR2EP_FV0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBPoss, 2)); + values[kR2EP_FV0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBNegs, 2)); +} + +template +void VarManager::FillSpectatorPlane(C const& collision, float* values) +{ + if (!values) { + values = fgValues; + } + + auto zncEnergy = collision.energySectorZNC(); + auto znaEnergy = collision.energySectorZNA(); + for (int i = 0; i < 4; i++) { // avoid std::numeric_limits::infinity() in the table + if (zncEnergy[i] < -1.e12) { + zncEnergy[i] = -1.f; + } + if (znaEnergy[i] < -1.e12) { + znaEnergy[i] = -1.f; + } + } + float znaCommon = collision.energyCommonZNA() < 0 ? -1.f : collision.energyCommonZNA(); + float zncCommon = collision.energyCommonZNC() < 0 ? -1.f : collision.energyCommonZNC(); + float zpaCommon = collision.energyCommonZPA() < 0 ? -1.f : collision.energyCommonZPA(); + float zpcCommon = collision.energyCommonZPC() < 0 ? -1.f : collision.energyCommonZPC(); + + // Store ZNA and ZNC energies for calibrations + values[kEnergyCommonZNA] = znaCommon; + values[kEnergyCommonZNC] = zncCommon; + values[kEnergyCommonZPA] = zpaCommon; + values[kEnergyCommonZPC] = zpcCommon; + values[kEnergyZNA1] = znaEnergy[0]; + values[kEnergyZNA2] = znaEnergy[1]; + values[kEnergyZNA3] = znaEnergy[2]; + values[kEnergyZNA4] = znaEnergy[3]; + values[kEnergyZNC1] = zncEnergy[0]; + values[kEnergyZNC2] = zncEnergy[1]; + values[kEnergyZNC3] = zncEnergy[2]; + values[kEnergyZNC4] = zncEnergy[3]; + values[kTimeZNA] = collision.timeZNA(); + values[kTimeZNC] = collision.timeZNC(); + values[kTimeZPA] = collision.timeZPA(); + values[kTimeZPC] = collision.timeZPC(); + + constexpr float beamEne = 5.36 * 0.5; + constexpr float x[4] = {-1.75, 1.75, -1.75, 1.75}; + constexpr float y[4] = {-1.75, -1.75, 1.75, 1.75}; + // constexpr float intcalibZNA[4] = {0.7997028, 0.8453715, 0.7879917, 0.7695486}; + // constexpr float intcalibZNC[4] = {0.7631577, 0.8408003, 0.7083920, 0.7731769}; + // constexpr float alpha = 0.395; // WARNING: Run 2 coorection, to be checked + constexpr float alpha = 1.; + float numXZNC = 0., numYZNC = 0., denZNC = 0.; + float numXZNA = 0., numYZNA = 0., denZNA = 0.; + + float sumZNA = 0; + float sumZNC = 0; + + for (int i = 0; i < 4; i++) { + if (zncEnergy[i] > 0.) { + float wZNC = std::pow(zncEnergy[i], alpha); + // sumZNC += intcalibZNC[i] * wZNC; + sumZNC += wZNC; + numXZNC -= x[i] * wZNC; + numYZNC += y[i] * wZNC; + denZNC += wZNC; + } + if (znaEnergy[i] > 0.) { + float wZNA = std::pow(znaEnergy[i], alpha); + // sumZNA += intcalibZNA[i] * wZNA; + sumZNA += wZNA; + numXZNA += x[i] * wZNA; + numYZNA += y[i] * wZNA; + denZNA += wZNA; + } + } + + if (denZNC != 0.) { + float nSpecnC = zncCommon / beamEne; // WARNING: Run 2 coorection, to be checked + float cZNC = 1.89358 - 0.71262 / (nSpecnC + 0.71789); // WARNING: Run 2 coorection, to be checked + cZNC = 1.; + values[kQ1ZNCX] = cZNC * numXZNC / denZNC; + values[kQ1ZNCY] = cZNC * numYZNC / denZNC; + } else { + values[kQ1ZNCX] = values[kQ1ZNCY] = 999.; + } + + if (denZNA != 0.) { + float nSpecnA = znaCommon / beamEne; // WARNING: Run 2 coorection, to be checked + float cZNA = 1.89358 - 0.71262 / (nSpecnA + 0.71789); // WARNING: Run 2 coorection, to be checked + cZNA = 1.; + values[kQ1ZNAX] = cZNA * numXZNA / denZNA; + values[kQ1ZNAY] = cZNA * numYZNA / denZNA; + } else { + values[kQ1ZNAX] = values[kQ1ZNAY] = 999.; + } + + if (denZNA != 0. && denZNC != 0.) { + values[kQ1ZNACXX] = values[kQ1ZNAX] * values[kQ1ZNCX]; + values[kQ1ZNACYY] = values[kQ1ZNAY] * values[kQ1ZNCY]; + values[kQ1ZNACYX] = values[kQ1ZNAY] * values[kQ1ZNCX]; + values[kQ1ZNACXY] = values[kQ1ZNAX] * values[kQ1ZNCY]; + } else { + values[kQ1ZNACXX] = values[kQ1ZNACYY] = values[kQ1ZNACYX] = values[kQ1ZNACXY] = 999.; + } + + if (znaCommon != 0 && sumZNA != 0 && zncCommon != 0 && sumZNC) { + values[KIntercalibZNA] = znaCommon - sumZNA; + values[KIntercalibZNC] = zncCommon - sumZNC; + } +} + +template +void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) +{ + + if (!values) { + values = fgValues; + } + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if constexpr (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if constexpr (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + // Fill dilepton information + 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; + values[kPt1] = t1.pt(); + values[kPt2] = t2.pt(); + + // TODO: provide different computations for vn + // Compute the scalar product UQ using Q-vector from A, for second and third harmonic + // Dilepton vn could be accessible after dividing this product with the R factor + values[kU2Q2] = values[kQ2X0A] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A] * TMath::Sin(2 * v12.Phi()); + values[kU3Q3] = values[kQ3X0A] * TMath::Cos(3 * v12.Phi()) + values[kQ3Y0A] * TMath::Sin(3 * v12.Phi()); + values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); + values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); + values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); + values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); + + float Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); + float Psi3A = getEventPlane(3, values[kQ3X0A], values[kQ3Y0A]); + float Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); + float Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); + float Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); + float Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); + values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A)); + values[kCos3DeltaPhi] = TMath::Cos(3 * (v12.Phi() - Psi3A)); + values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); + values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); + values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); + values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); + + float V2SP = values[kU2Q2] / values[kR2SP]; + float V2EP = values[kCos2DeltaPhi] / values[kR2EP]; + values[kV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : V2SP; + values[kWV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : 1.0; + values[kV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : V2EP; + values[kWV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : 1.0; + + if (std::isnan(VarManager::fgValues[VarManager::kU2Q2]) == true) { + values[kU2Q2] = -999.; + values[kR2SP_AB] = -999.; + values[kR2SP_AC] = -999.; + values[kR2SP_BC] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kU3Q3]) == true) { + values[kU3Q3] = -999.; + values[kR3SP] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kCos2DeltaPhi]) == true) { + values[kCos2DeltaPhi] = -999.; + values[kR2EP_AB] = -999.; + values[kR2EP_AC] = -999.; + values[kR2EP_BC] = -999.; + } + if (std::isnan(VarManager::fgValues[VarManager::kCos3DeltaPhi]) == true) { + values[kCos3DeltaPhi] = -999.; + values[kR3EP] = -999.; + } + + // global polarization parameters + bool useGlobalPolarizatiobSpinOne = fgUsedVars[kCosThetaStarTPC] || fgUsedVars[kCosThetaStarFT0A] || fgUsedVars[kCosThetaStarFT0C]; + if (useGlobalPolarizatiobSpinOne) { + ROOT::Math::Boost boostv12{v12.BoostToCM()}; + ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; + ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; + + // using positive sign convention for the first track + ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); + + ROOT::Math::XYZVector zaxisTPC = ROOT::Math::XYZVector(TMath::Cos(Psi2A), TMath::Sin(Psi2A), 0).Unit(); + values[kCosThetaStarTPC] = v_CM.Dot(zaxisTPC); + + ROOT::Math::XYZVector zaxisFT0A = ROOT::Math::XYZVector(TMath::Cos(Psi2B), TMath::Sin(Psi2B), 0).Unit(); + values[kCosThetaStarFT0A] = v_CM.Dot(zaxisFT0A); + + ROOT::Math::XYZVector zaxisFT0C = ROOT::Math::XYZVector(TMath::Cos(Psi2C), TMath::Sin(Psi2C), 0).Unit(); + values[kCosThetaStarFT0C] = v_CM.Dot(zaxisFT0C); + } + + // kV4, kC4POI, kC4REF etc. + if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { + complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); + complex Q42(values[kQ42XA], values[kQ42YA]); + complex Q23(values[kQ23XA], values[kQ23YA]); + complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); + values[kM01POI] = values[kMultDimuons] * values[kS11A]; + values[kM0111POI] = values[kMultDimuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POI] = (P2 * conj(Q21)).real() / values[kM01POI]; + values[kCORR4POI] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POI]; + values[kM01POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? values[kM01POI] / values[kMultDimuons] : 0; + values[kM0111POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? values[kM0111POI] / values[kMultDimuons] : 0; + values[kM11REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuons] : 0; + values[kM1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuons] : 0; + values[kCORR2REFbydimuons] = std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; + values[kCORR4REFbydimuons] = std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; + values[kCORR2POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI]; + values[kCORR4POI] = std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR4POI]; + values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REFoverMp]) || std::isinf(values[kM11M1111REFoverMp]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : values[kCORR2CORR4REF]; + values[kCORR2POICORR4POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI] * values[kCORR4POI]; + values[kCORR2REFCORR4POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2REF] * values[kCORR4POI]; + values[kCORR2REFCORR2POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR2REF] * values[kCORR2POI]; + values[kM11M1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? values[kM11M1111REF] / values[kMultDimuons] : 0; + values[kM01M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM01POI] * values[kM0111POI]) / values[kMultDimuons] : 0; + values[kM11M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM11REF] * values[kM0111POI]) / values[kMultDimuons] : 0; + values[kM11M01overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? (values[kM11REF] * values[kM01POI]) / values[kMultDimuons] : 0; + + complex P2plus(TMath::Cos(2 * v1.Phi()), TMath::Sin(2 * v1.Phi())); + complex P2minus(TMath::Cos(2 * v2.Phi()), TMath::Sin(2 * v2.Phi())); + values[kM11REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultAntiMuons] : 0; + values[kM1111REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultAntiMuons] : 0; + values[kM11REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultMuons] : 0; + values[kM1111REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultMuons] : 0; + values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POI]; + values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POI]; + values[kM01POIplus] = values[kMultAntiMuons] * values[kS11A]; + values[kM0111POIplus] = values[kMultAntiMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POIplus]; + values[kCORR4POIplus] = (P2plus * Q21 * conj(Q21) * conj(Q21) - P2plus * Q21 * conj(Q42) - 2. * values[kS12A] * P2plus * conj(Q21) + 2. * P2plus * conj(Q23)).real() / values[kM0111POIplus]; + values[kM01POIminus] = values[kMultMuons] * values[kS11A]; + values[kM0111POIminus] = values[kMultMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); + values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POIminus]; + values[kCORR4POIminus] = (P2minus * Q21 * conj(Q21) * conj(Q21) - P2minus * Q21 * conj(Q42) - 2. * values[kS12A] * P2minus * conj(Q21) + 2. * P2minus * conj(Q23)).real() / values[kM0111POIminus]; + values[kM01POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM01POIplus]; + values[kM0111POIplus] = std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM0111POIplus]; + values[kCORR2POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR2POIplus]; + values[kCORR4POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR4POIplus]; + values[kM01POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM01POIminus]; + values[kM0111POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM0111POIminus]; + values[kCORR2POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR2POIminus]; + values[kCORR4POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR4POIminus]; + values[kM01POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM01POIminus] / values[kMultMuons] : 0; + values[kM0111POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM0111POIminus] / values[kMultMuons] : 0; + values[kM01POIoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM01POIplus] / values[kMultAntiMuons] : 0; + values[kM0111POIoverMpplus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM0111POIplus] / values[kMultAntiMuons] : 0; + } + + ROOT::Math::PtEtaPhiMVector v1_vp(v1.Pt(), v1.Eta(), v1.Phi() - Psi2B, v1.M()); + ROOT::Math::PtEtaPhiMVector v2_vp(v2.Pt(), v2.Eta(), v2.Phi() - Psi2B, v2.M()); + ROOT::Math::PtEtaPhiMVector v12_vp = v1_vp + v2_vp; + auto p12_vp = ROOT::Math::XYZVectorF(v12_vp.Px(), v12_vp.Py(), v12_vp.Pz()); + auto p12_vp_projXZ = ROOT::Math::XYZVectorF(p12_vp.X(), 0, p12_vp.Z()); + auto vDimu = (t1.sign() > 0 ? ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz())) + : ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()))); + auto vRef = p12_vp.Cross(p12_vp_projXZ); + values[kCosPhiVP] = vDimu.Dot(vRef) / (vRef.R() * vDimu.R()); + values[kPhiVP] = std::acos(vDimu.Dot(vRef) / (vRef.R() * vDimu.R())); +} + +template +void VarManager::FillZDC(T const& zdc, float* values) +{ + if (!values) { + values = fgValues; + } + + values[kEnergyCommonZNA] = (zdc.energyCommonZNA() > 0) ? zdc.energyCommonZNA() : -1.; + values[kEnergyCommonZNC] = (zdc.energyCommonZNC() > 0) ? zdc.energyCommonZNC() : -1.; + values[kEnergyCommonZPA] = (zdc.energyCommonZPA() > 0) ? zdc.energyCommonZPA() : -1.; + values[kEnergyCommonZPC] = (zdc.energyCommonZPC() > 0) ? zdc.energyCommonZPC() : -1.; + values[kTimeZNA] = zdc.timeZNA(); + values[kTimeZNC] = zdc.timeZNC(); + values[kTimeZPA] = zdc.timeZPA(); + values[kTimeZPC] = zdc.timeZPC(); +} + +template +void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values, float hadronMass) +{ + if (!values) { + values = fgValues; + } + + 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; + values[kPairMass] = v12.M(); + values[kPairPt] = v12.Pt(); + values[kPairEta] = v12.Eta(); + values[kPairPhi] = v12.Phi(); + values[kPairMassDau] = dilepton.mass(); + values[kPairPtDau] = dilepton.pt(); + values[kMassDau] = hadronMass; + values[kDeltaMass] = v12.M() - dilepton.mass(); + // Calculate kstar of Dilepton and hadron pair + ROOT::Math::PtEtaPhiMVector v12_Qvect = v1 - v2; + 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] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + 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] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); + + float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); + values[kCosChi_randomPhi_trans] = -999.9f; + values[kCosChi_randomPhi_toward] = -999.9f; + values[kCosChi_randomPhi_away] = -999.9f; + + values[kdeltaphi_randomPhi_trans] = -999.9f; + values[kdeltaphi_randomPhi_toward] = -999.9f; + values[kdeltaphi_randomPhi_away] = -999.9f; + + float randomPhi_trans = -o2::constants::math::PIHalf; + float randomPhi_toward = -o2::constants::math::PIHalf; + float randomPhi_away = -o2::constants::math::PIHalf; + + if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { + randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); + values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); + values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); + + ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); + values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); + values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); + + values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); + values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); + } + } + + if (fgUsedVars[kDeltaPhi]) { + double delta = dilepton.phi() - hadron.phi(); + if (delta > 3.0 / 2.0 * M_PI) { + delta -= 2.0 * M_PI; + } + if (delta < -0.5 * M_PI) { + delta += 2.0 * M_PI; + } + values[kDeltaPhi] = delta; + } + if (fgUsedVars[kDeltaPhiSym]) { + double delta = std::abs(dilepton.phi() - hadron.phi()); + if (delta > M_PI) { + delta = 2 * M_PI - delta; + } + values[kDeltaPhiSym] = delta; + } + if (fgUsedVars[kDeltaEta]) { + values[kDeltaEta] = dilepton.eta() - hadron.eta(); + } +} + +template +void VarManager::FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values) +{ + if (!values) { + values = fgValues; + } + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi]) { + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); + ROOT::Math::PtEtaPhiMVector v2(photon.pt(), photon.eta(), photon.phi(), photon.mGamma()); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + values[kPairMass] = v12.M(); + values[kPairPt] = v12.Pt(); + values[kPairEta] = v12.Eta(); + values[kPairPhi] = v12.Phi(); + values[kPairMassDau] = dilepton.mass(); + values[kMassDau] = photon.mGamma(); + values[kPairPtDau] = dilepton.pt(); + values[kPt] = photon.pt(); + values[kDeltaEta] = dilepton.eta(); + values[kEta] = photon.eta(); + values[VarManager::kDeltaMass] = v12.M() - dilepton.mass(); + float m4 = o2::constants::physics::MassJPsi; + values[VarManager::kDeltaMass_jpsi] = v12.M() - dilepton.mass() + m4; + values[kRap] = v12.Rapidity(); + } +} + +template +void VarManager::FillHadron(T const& hadron, float* values, float hadronMass) +{ + if (!values) { + values = fgValues; + } + + ROOT::Math::PtEtaPhiMVector vhadron(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); + values[kMass] = hadronMass; + values[kPt] = hadron.pt(); + values[kEta] = hadron.eta(); + values[kPhi] = hadron.phi(); + values[kRap] = vhadron.Rapidity(); +} + +template +void VarManager::FillSingleDileptonCharmHadron(Cand const& candidate, H hfHelper, T& bdtScoreCharmHad, float* values) +{ + if (!values) { + values = fgValues; + } + + if constexpr (partType == kJPsi) { + values[kMass] = candidate.mass(); + values[kPt] = candidate.pt(); + values[kPhi] = candidate.phi(); + values[kRap] = candidate.rap(); + } + if constexpr (partType == kD0ToPiK) { + values[kMassCharmHadron] = hfHelper.invMassD0ToPiK(candidate); + values[kPtCharmHadron] = candidate.pt(); + values[kPhiCharmHadron] = candidate.phi(); + values[kRapCharmHadron] = hfHelper.yD0(candidate); + values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); + } + if constexpr (partType == kD0barToKPi) { + values[kMassCharmHadron] = hfHelper.invMassD0barToKPi(candidate); + values[kPtCharmHadron] = candidate.pt(); + values[kPhiCharmHadron] = candidate.phi(); + values[kRapCharmHadron] = hfHelper.yD0(candidate); + values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); + } +} + +template +void VarManager::FillDileptonCharmHadron(DQ const& dilepton, HF const& charmHadron, H hfHelper, T& bdtScoreCharmHad, float* values) +{ + FillSingleDileptonCharmHadron(dilepton, hfHelper, bdtScoreCharmHad, values); + FillSingleDileptonCharmHadron(charmHadron, hfHelper, bdtScoreCharmHad, values); +} + +template +void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T3 const& hadron2, float* values) +{ + if (!values) { + values = fgValues; + } + + double defaultDileptonMass = 3.096; + double hadronMass1 = o2::constants::physics::MassPionCharged; + double hadronMass2 = o2::constants::physics::MassPionCharged; + if (candidateType == kXtoJpsiPiPi) { + defaultDileptonMass = 3.096; + hadronMass1 = o2::constants::physics::MassPionCharged; + hadronMass2 = o2::constants::physics::MassPionCharged; + } + if (candidateType == kChictoJpsiEE) { + defaultDileptonMass = 3.096; + hadronMass1 = o2::constants::physics::MassElectron; + hadronMass2 = o2::constants::physics::MassElectron; + } + + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); + ROOT::Math::PtEtaPhiMVector v2(hadron1.pt(), hadron1.eta(), hadron1.phi(), hadronMass1); + ROOT::Math::PtEtaPhiMVector v3(hadron2.pt(), hadron2.eta(), hadron2.phi(), hadronMass2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + values[kQuadMass] = v123.M(); + values[kQuadDefaultDileptonMass] = v123.M() - v1.M() + defaultDileptonMass; + values[kQuadPt] = v123.Pt(); + values[kQuadEta] = v123.Eta(); + values[kQuadPhi] = v123.Phi(); + + values[kTrackDCAxyProng1] = hadron1.dcaXY(); + values[kTrackDCAzProng1] = hadron1.dcaZ(); + values[kPt1] = hadron1.pt(); + + values[kTrackDCAxyProng2] = hadron2.dcaXY(); + values[kTrackDCAzProng2] = hadron2.dcaZ(); + values[kPt2] = hadron2.pt(); + + if (fgUsedVars[kCosthetaDileptonDitrack] || fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kDitrackPt] || fgUsedVars[kDitrackMass] || fgUsedVars[kQ] || fgUsedVars[kDeltaR1] || fgUsedVars[kDeltaR2] || fgUsedVars[kRap]) { + ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; + values[kPairMass] = v1.M(); + values[kPairPt] = v1.Pt(); + values[kDitrackMass] = v23.M(); + values[kDitrackPt] = v23.Pt(); + values[kCosthetaDileptonDitrack] = (v1.Px() * v123.Px() + v1.Py() * v123.Py() + v1.Pz() * v123.Pz()) / (v1.P() * v123.P()); + values[kQ] = v123.M() - defaultDileptonMass - v23.M(); + values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); + values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); + values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); + values[kRap] = v123.Rapidity(); + } +} + +//__________________________________________________________________ +template +void VarManager::FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values) +{ + constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); + constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); + + if (!eventHasVtxCov || !trackHasCov) { + return; + } + + if (!values) { + values = fgValues; + } + + float mtrack1, mtrack2; + float mlepton1, mlepton2; + + if constexpr (candidateType == kXtoJpsiPiPi || candidateType == kPsi2StoJpsiPiPi) { + mlepton1 = o2::constants::physics::MassElectron; + mlepton2 = o2::constants::physics::MassElectron; + mtrack1 = o2::constants::physics::MassPionCharged; + mtrack2 = o2::constants::physics::MassPionCharged; + } + + ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton1); + ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton2); + ROOT::Math::PtEtaPhiMVector v3(track1.pt(), track1.eta(), track1.phi(), mtrack1); + ROOT::Math::PtEtaPhiMVector v4(track2.pt(), track2.eta(), track2.phi(), mtrack2); + ROOT::Math::PtEtaPhiMVector v1234 = v1 + v2 + v3 + v4; + + int procCodeDilepton = 0; + int procCodeDileptonTrackTrack = 0; + + values[kUsedKF] = fgUsedKF; + if (!fgUsedKF) { + // create covariance matrix + std::array lepton1pars = {lepton1.y(), lepton1.z(), lepton1.snp(), lepton1.tgl(), lepton1.signed1Pt()}; + std::array lepton1covs = {lepton1.cYY(), lepton1.cZY(), lepton1.cZZ(), lepton1.cSnpY(), lepton1.cSnpZ(), + lepton1.cSnpSnp(), lepton1.cTglY(), lepton1.cTglZ(), lepton1.cTglSnp(), lepton1.cTglTgl(), + lepton1.c1PtY(), lepton1.c1PtZ(), lepton1.c1PtSnp(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; + o2::track::TrackParCov pars1{lepton1.x(), lepton1.alpha(), lepton1pars, lepton1covs}; + std::array lepton2pars = {lepton2.y(), lepton2.z(), lepton2.snp(), lepton2.tgl(), lepton2.signed1Pt()}; + std::array lepton2covs = {lepton2.cYY(), lepton2.cZY(), lepton2.cZZ(), lepton2.cSnpY(), lepton2.cSnpZ(), + lepton2.cSnpSnp(), lepton2.cTglY(), lepton2.cTglZ(), lepton2.cTglSnp(), lepton2.cTglTgl(), + lepton2.c1PtY(), lepton2.c1PtZ(), lepton2.c1PtSnp(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; + o2::track::TrackParCov pars2{lepton2.x(), lepton2.alpha(), lepton2pars, lepton2covs}; + std::array track1pars = {track1.y(), track1.z(), track1.snp(), track1.tgl(), track1.signed1Pt()}; + std::array track1covs = {track1.cYY(), track1.cZY(), track1.cZZ(), track1.cSnpY(), track1.cSnpZ(), + track1.cSnpSnp(), track1.cTglY(), track1.cTglZ(), track1.cTglSnp(), track1.cTglTgl(), + track1.c1PtY(), track1.c1PtZ(), track1.c1PtSnp(), track1.c1PtTgl(), track1.c1Pt21Pt2()}; + o2::track::TrackParCov pars3{track1.x(), track1.alpha(), track1pars, track1covs}; + std::array track2pars = {track2.y(), track2.z(), track2.snp(), track2.tgl(), track2.signed1Pt()}; + std::array track2covs = {track2.cYY(), track2.cZY(), track2.cZZ(), track2.cSnpY(), track2.cSnpZ(), + track2.cSnpSnp(), track2.cTglY(), track2.cTglZ(), track2.cTglSnp(), track2.cTglTgl(), + track2.c1PtY(), track2.c1PtZ(), track2.c1PtSnp(), track2.c1PtTgl(), track2.c1Pt21Pt2()}; + o2::track::TrackParCov pars4{track2.x(), track2.alpha(), track2pars, track2covs}; + + procCodeDilepton = VarManager::fgFitterTwoProngBarrel.process(pars1, pars2); + // create dilepton track + // o2::track::TrackParCov parsDilepton = VarManager::fgFitterTwoProngBarrel.createParentTrackParCov(0); + // procCodeDileptonTrackTrack = VarManager::fgFitterThreeProngBarrel.process(parsDilepton, pars3, pars4); + procCodeDileptonTrackTrack = VarManager::fgFitterFourProngBarrel.process(pars1, pars2, pars3, pars4); + + // fill values + if (procCodeDilepton == 0 && procCodeDileptonTrackTrack == 0) { + // TODO: set the other variables to appropriate values and return + values[kVertexingLxy] = -999.; + values[kVertexingLxyz] = -999.; + values[kVertexingLz] = -999.; + values[kVertexingLxyErr] = -999.; + values[kVertexingLxyzErr] = -999.; + values[kVertexingLzErr] = -999.; + values[kVertexingTauxy] = -999.; + values[kVertexingTauxyErr] = -999.; + values[kVertexingTauz] = -999.; + values[kVertexingTauzErr] = -999.; + values[kVertexingLzProjected] = -999.; + values[kVertexingLxyProjected] = -999.; + values[kVertexingLxyzProjected] = -999.; + values[kVertexingTauzProjected] = -999.; + values[kVertexingTauxyProjected] = -999.; + values[kVertexingTauxyzProjected] = -999.; + return; + } else { + Vec3D secondaryVertex; + std::array covMatrixPCA; + secondaryVertex = fgFitterFourProngBarrel.getPCACandidate(); + covMatrixPCA = fgFitterFourProngBarrel.calcPCACovMatrixFlat(); + + o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); + std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; + o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; + auto covMatrixPV = primaryVertex.getCov(); + + double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); + double theta = std::atan2(secondaryVertex[2] - collision.posZ(), + std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + + (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); + + values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); + values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; + values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); + values[kVertexingLz] = std::sqrt(values[kVertexingLz]); + values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); + + values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); + values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); + values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); + + values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxy] = values[kVertexingLxy] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kVertexingTauzErr] = values[kVertexingLzErr] * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); + + values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v1234.Px() + + (collision.posY() - secondaryVertex[1]) * v1234.Py() + + (collision.posZ() - secondaryVertex[2]) * v1234.Pz()) / + (v1234.P() * values[VarManager::kVertexingLxyz]); + // // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v1234.Pz(); + values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v1234.Pz() * v1234.Pz()); + values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py())); + values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()) + ((secondaryVertex[2] - collision.posZ()) * v1234.Pz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py()) + (v1234.Pz() * v1234.Pz())); + + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v1234.M() / TMath::Abs(v1234.Pz()); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v1234.M() / (v1234.Pt()); + values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v1234.M() / (v1234.P()); + } + } else if (fgUsedKF) { + KFParticle lepton1KF; // lepton1 + KFParticle lepton2KF; // lepton2 + KFParticle KFGeoTwoLeptons; + KFParticle trk1KF; // track1 + KFParticle trk2KF; // track2 + KFParticle KFGeoTwoTracks; + KFParticle KFGeoFourProng; + if constexpr (candidateType == kXtoJpsiPiPi) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); + lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); + lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); + trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); + KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); + trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); + + KFGeoTwoLeptons.SetConstructMethod(2); + KFGeoTwoLeptons.AddDaughter(lepton1KF); + KFGeoTwoLeptons.AddDaughter(lepton2KF); + + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { + values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); + values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); + } + + KFGeoTwoTracks.SetConstructMethod(2); + KFGeoTwoTracks.AddDaughter(trk1KF); + KFGeoTwoTracks.AddDaughter(trk2KF); + + if (fgUsedVars[kDitrackMass] || fgUsedVars[kDitrackPt]) { + values[VarManager::kDitrackMass] = KFGeoTwoTracks.GetMass(); + values[VarManager::kDitrackPt] = KFGeoTwoTracks.GetPt(); + } + + KFGeoFourProng.SetConstructMethod(2); + KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); + KFGeoFourProng.AddDaughter(KFGeoTwoTracks); + } + + if constexpr (candidateType == kPsi2StoJpsiPiPi) { + KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); + lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); + KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); + lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); + KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); + trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); + KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); + trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); + + KFGeoTwoLeptons.SetConstructMethod(2); + KFGeoTwoLeptons.AddDaughter(lepton1KF); + KFGeoTwoLeptons.AddDaughter(lepton2KF); + + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { + values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); + values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); + } + + KFGeoFourProng.SetConstructMethod(2); + KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); + KFGeoFourProng.AddDaughter(trk1KF); + KFGeoFourProng.AddDaughter(trk2KF); + } + + if (fgUsedVars[kKFMass]) { + float mass = 0., massErr = 0.; + if (!KFGeoFourProng.GetMass(mass, massErr)) + values[kKFMass] = mass; + else + values[kKFMass] = -999.; + } + + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + values[kKFNContributorsPV] = kfpVertex.GetNContributors(); + KFParticle KFPV(kfpVertex); + double dxQuadlet2PV = KFGeoFourProng.GetX() - KFPV.GetX(); + double dyQuadlet2PV = KFGeoFourProng.GetY() - KFPV.GetY(); + double dzQuadlet2PV = KFGeoFourProng.GetZ() - KFPV.GetZ(); + + values[kVertexingLxy] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV); + values[kVertexingLz] = std::sqrt(dzQuadlet2PV * dzQuadlet2PV); + values[kVertexingLxyz] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV + dzQuadlet2PV * dzQuadlet2PV); + + values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV); + values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV; + values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(3) + KFGeoFourProng.GetCovariance(3)) * dxQuadlet2PV * dzQuadlet2PV + (KFPV.GetCovariance(4) + KFGeoFourProng.GetCovariance(4)) * dyQuadlet2PV * dzQuadlet2PV); + + if (fabs(values[kVertexingLxy]) < 1.e-8f) + values[kVertexingLxy] = 1.e-8f; + values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; + if (fabs(values[kVertexingLz]) < 1.e-8f) + values[kVertexingLz] = 1.e-8f; + values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; + if (fabs(values[kVertexingLxyz]) < 1.e-8f) + values[kVertexingLxyz] = 1.e-8f; + values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; + + values[kVertexingTauxy] = KFGeoFourProng.GetPseudoProperDecayTime(KFPV, KFGeoFourProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauz] = -1 * dzQuadlet2PV * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingPz] = TMath::Abs(KFGeoFourProng.GetPz()); + values[kVertexingSV] = KFGeoFourProng.GetZ(); + + values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); + values[kVertexingChi2PCA] = KFGeoFourProng.GetChi2(); + values[kCosPointingAngle] = (std::sqrt(dxQuadlet2PV * dxQuadlet2PV) * v1234.Px() + + std::sqrt(dyQuadlet2PV * dyQuadlet2PV) * v1234.Py() + + std::sqrt(dzQuadlet2PV * dzQuadlet2PV) * v1234.Pz()) / + (v1234.P() * values[VarManager::kVertexingLxyz]); + // // run 2 definitions: Decay length projected onto the momentum vector of the candidate + values[kVertexingLzProjected] = (dzQuadlet2PV * KFGeoFourProng.GetPz()) / TMath::Sqrt(KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz()); + values[kVertexingLxyProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()); + values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy())); + values[kVertexingLxyzProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()) + (dzQuadlet2PV * KFGeoFourProng.GetPz()); + values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy()) + (KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz())); + values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt()); + values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; + values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoFourProng.GetMass() / TMath::Abs(KFGeoFourProng.GetPz()); + values[kKFChi2OverNDFGeo] = KFGeoFourProng.GetChi2() / KFGeoFourProng.GetNDF(); + } else { + return; + } +} + +//__________________________________________________________________ +template +void VarManager::FillQuadMC(T1 const& dilepton, T2 const& track1, T2 const& track2, float* values) +{ + if (!values) { + values = fgValues; + } + + double defaultDileptonMass = 3.096; + double hadronMass1 = o2::constants::physics::MassPionCharged; + double hadronMass2 = o2::constants::physics::MassPionCharged; + if (candidateType == kXtoJpsiPiPi) { + defaultDileptonMass = 3.096; + hadronMass1 = o2::constants::physics::MassPionCharged; + hadronMass2 = o2::constants::physics::MassPionCharged; + } + + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), defaultDileptonMass); + ROOT::Math::PtEtaPhiMVector v2(track1.pt(), track1.eta(), track1.phi(), hadronMass1); + ROOT::Math::PtEtaPhiMVector v3(track2.pt(), track2.eta(), track2.phi(), hadronMass2); + ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; + ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; + values[kQuadMass] = v123.M(); + values[kQuadDefaultDileptonMass] = v123.M(); + values[kQuadPt] = v123.Pt(); + values[kQuadEta] = v123.Eta(); + values[kQuadPhi] = v123.Phi(); + values[kQ] = v123.M() - defaultDileptonMass - v23.M(); + values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); + values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); + values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); + values[kDitrackMass] = v23.M(); + values[kDitrackPt] = v23.Pt(); +} + +//__________________________________________________________________ +template +float VarManager::calculatePhiV(T1 const& t1, T2 const& t2) +{ + // cos(phiv) = w*a /|w||a| + // with w = u x v + // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) + // u = v12 / |v12| , the unit vector of v12 + // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 + + float m1 = o2::constants::physics::MassElectron; + float m2 = o2::constants::physics::MassElectron; + if constexpr (pairType == kDecayToMuMu) { + m1 = o2::constants::physics::MassMuon; + m2 = o2::constants::physics::MassMuon; + } + + if constexpr (pairType == kDecayToPiPi) { + m1 = o2::constants::physics::MassPionCharged; + m2 = o2::constants::physics::MassPionCharged; + } + + if constexpr (pairType == kElectronMuon) { + m2 = o2::constants::physics::MassMuon; + } + + 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; + + float pairPhiV = -999; + float bz = fgMagField; + + bool swapTracks = false; + if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 + ROOT::Math::PtEtaPhiMVector v3 = v1; + v1 = v2; + v2 = v3; + swapTracks = true; + } + + // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. + // vector product of pep X pem + float vpx = 0, vpy = 0, vpz = 0; + if (t1.sign() * t2.sign() > 0) { // Like Sign + if (!swapTracks) { + if (bz * t1.sign() < 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } else { // swaped tracks + if (bz * t2.sign() < 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } + } else { // Unlike Sign + if (!swapTracks) { + if (bz * t1.sign() > 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } else { // swaped tracks + if (bz * t2.sign() > 0) { + vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); + vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); + vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); + } else { + vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); + vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); + vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); + } + } + } + + // unit vector of pep X pem + float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); + + float px = v12.Px(); + float py = v12.Py(); + float pz = v12.Pz(); + + // unit vector of (pep+pem) + float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); + float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); + float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); + float ax = uy / TMath::Sqrt(ux * ux + uy * uy); + float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); + + // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) + float wx = uy * vz - uz * vy; + float wy = uz * vx - ux * vz; + // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). + // The angle between them should be small if the pair is conversion. This function then returns values close to pi! + pairPhiV = TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; + return pairPhiV; +} + +/// Fill BDT score values. +/// Supports binary (1 output) and multiclass (3 outputs) models. +template +void VarManager::FillBdtScore(T1 const& bdtScore, float* values) +{ + if (!values) { + values = fgValues; + } + + if (bdtScore.size() == 1) { + values[kBdtBackground] = bdtScore[0]; + } else if (bdtScore.size() == 3) { + values[kBdtBackground] = bdtScore[0]; + values[kBdtPrompt] = bdtScore[1]; + values[kBdtNonprompt] = bdtScore[2]; + } else { + LOG(warning) << "Unexpected number of BDT outputs: " << bdtScore.size(); + } +} +//__________________________________________________________________ +template +float VarManager::LorentzTransformJpsihadroncosChi(TString Option, T1 const& v1, T2 const& v2) +{ + 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") { + 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(); + } + return value; +} + +#endif // PWGDQ_CORE_VARMANAGER_H_ From 663c7ac15d351957d8c6e45510eca8c4384274b1 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 18:27:58 +0800 Subject: [PATCH 23/24] Delete PWGDQ/VarManager.h --- PWGDQ/VarManager.h | 5840 -------------------------------------------- 1 file changed, 5840 deletions(-) delete mode 100644 PWGDQ/VarManager.h diff --git a/PWGDQ/VarManager.h b/PWGDQ/VarManager.h deleted file mode 100644 index 2056a88416e..00000000000 --- a/PWGDQ/VarManager.h +++ /dev/null @@ -1,5840 +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 -// -// Class to handle analysis variables -// - -#ifndef PWGDQ_CORE_VARMANAGER_H_ -#define PWGDQ_CORE_VARMANAGER_H_ - -#ifndef HomogeneousField -#define HomogeneousField -#endif - -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/CCDB/TriggerAliases.h" -#include "Common/Core/CollisionTypeHelper.h" -#include "Common/Core/EventPlaneHelper.h" -#include "Common/Core/fwdtrackUtilities.h" -#include "Common/Core/trackUtilities.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using std::complex; -using std::cout; -using std::endl; - -using SMatrix55 = ROOT::Math::SMatrix>; -using SMatrix5 = ROOT::Math::SVector; -using Vec3D = ROOT::Math::SVector; - -//_________________________________________________________________________ -class VarManager : public TObject -{ - public: - // map the information contained in the objects passed to the Fill functions - enum ObjTypes { - // NOTE: Elements containing "Reduced" in their name refer strictly to skimmed data tables - // and the ones that don't refer to tables from the Framework data model or both models - BC = BIT(0), - Collision = BIT(1), - CollisionCentRun2 = BIT(2), - CollisionTimestamp = BIT(3), - ReducedEvent = BIT(4), - ReducedEventExtended = BIT(5), - ReducedEventVtxCov = BIT(6), - CollisionMC = BIT(7), - ReducedEventMC = BIT(8), - ReducedEventQvector = BIT(9), - CollisionCent = BIT(10), - CollisionMult = BIT(11), - EventFilter = BIT(12), - CollisionQvect = BIT(13), - ReducedEventQvectorExtra = BIT(14), - ReducedEventRefFlow = BIT(15), - Zdc = BIT(16), - ReducedZdc = BIT(17), - CollisionMultExtra = BIT(18), - ReducedEventMultExtra = BIT(19), - CollisionQvectCentr = BIT(20), - RapidityGapFilter = BIT(21), - Track = BIT(0), - TrackCov = BIT(1), - TrackExtra = BIT(2), - TrackPID = BIT(3), // used for basic PID properties (needed such that we can subscribe to a minimal set of PID tables): e,pi,K,p for TPC and TOF - TrackPIDExtra = BIT(4), // extra PID information - TrackDCA = BIT(5), - TrackSelection = BIT(6), - TrackV0Bits = BIT(7), - ReducedTrack = BIT(8), - ReducedTrackBarrel = BIT(9), - ReducedTrackBarrelCov = BIT(10), - ReducedTrackBarrelPID = BIT(11), - Muon = BIT(12), - MuonCov = BIT(13), - ReducedMuon = BIT(14), - ReducedMuonExtra = BIT(15), - ReducedMuonCov = BIT(16), - ParticleMC = BIT(17), - Pair = BIT(18), // TODO: check whether we really need the Pair member here - AmbiTrack = BIT(19), - AmbiMuon = BIT(20), - DalitzBits = BIT(21), - TrackTPCPID = BIT(22), - TrackMFT = BIT(23), - ReducedTrackCollInfo = BIT(24), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo - ReducedMuonCollInfo = BIT(25), // TODO: remove it once new reduced data tables are produced for dielectron with ReducedTracksBarrelInfo - MuonRealign = BIT(26), - MuonCovRealign = BIT(27), - MFTCov = BIT(28) - }; - - enum PairCandidateType { - // TODO: need to agree on a scheme to incorporate all various hypotheses (e.g. e - mu, jpsi - K+, Jpsi - pipi,...) - kDecayToEE = 0, // e.g. J/psi -> e+ e- - kDecayToMuMu, // e.g. J/psi -> mu+ mu- - kDecayToPiPi, - kElectronMuon, // e.g. Electron - muon correlations - kBcToThreeMuons, // e.g. Bc -> mu+ mu- mu+ - kBtoJpsiEEK, // e.g. B+ -> e+ e- K+ - kJpsiEEProton, // e.g. Jpsi-proton correlation, Jpsi to e+e- - kXtoJpsiPiPi, // e.g. X(3872) -> J/psi pi+ pi- - kPsi2StoJpsiPiPi, // e.g. Psi(2S) -> J/psi pi+ pi- - kChictoJpsiEE, // e.g. Chi_c1 -> J/psi e+ e- - kDstarToD0KPiPi, // e.g. D*+ -> D0 pi+ -> K- pi+ pi+ - kTripleCandidateToEEPhoton, // e.g. chi_c -> e+ e- photon or pi0 -> e+ e- photon - kDecayToKPi, // e.g. D0 -> K+ pi- or cc. - kTripleCandidateToKPiPi, // e.g. D+ -> K- pi+ pi+ - kTripleCandidateToPKPi, // e.g. Lambda_c -> p K- pi+ - kJpsiHadronMass, // using the real hadron mass - kJpsiPionMass, // treat the hadron as pion - kNMaxCandidateTypes - }; - - enum BarrelTrackFilteringBits { - kIsConversionLeg = 0, // electron from conversions - kIsK0sLeg, // pion from K0s - kIsLambdaLeg, // proton or pion from Lambda - kIsALambdaLeg, // proton or pion from anti-Lambda - kIsOmegaLeg, // kaon from Omega baryon decay - kDalitzBits = 5, // first bit for Dalitz tagged tracks - kBarrelUserCutsBits = 13, // first bit for user track cuts - kIsTPCPostcalibrated = 63 // tracks were postcalibrated for the TPC PID - }; - - enum MuonTrackFilteringBits { - kMuonUserCutsBits = 0, // first bit for user muon cuts - kMuonIsPropagated = 7 // whether the muon was propagated already - }; - - public: - enum Variables { - kNothing = -1, - // Run wise variables - kRunNo = 0, - kNRunWiseVariables, - - // Event wise variables - kTimestamp, - kTimeFromSOR, // Time since Start of Run (SOR) in minutes - kCollisionTime, - kCollisionTimeRes, - kBC, - kBCOrbit, - kIsPhysicsSelection, - kIsNoTFBorder, // No time frame border - kIsNoITSROFBorder, // No ITS read out frame border (from event selection) - kIsNoITSROFBorderRecomputed, // No ITS read out frame border, computed here - kIsNoSameBunch, // No collisions with same T0 BC - kIsGoodZvtxFT0vsPV, // No collisions w/ difference between z_ {PV, tracks} and z_{PV FT0A-C} - kIsVertexITSTPC, // At least one ITS-TPC track - kIsVertexTOFmatched, // At least one TOF-matched track - kIsSel8, // TVX in Run3 && No time frame border && No ITS read out frame border (from event selection) - kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value - kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values - kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values - kIsINT7, - kIsEMC7, - kIsINT7inMUON, - kIsMuonSingleLowPt7, - kIsMuonSingleHighPt7, - kIsMuonUnlikeLowPt7, - kIsMuonLikeLowPt7, - kIsCUP8, - kIsCUP9, - kIsMUP10, - kIsMUP11, - kVtxX, - kVtxY, - kVtxZ, - kVtxNcontrib, - kVtxNcontribReal, - kVtxCovXX, - kVtxCovXY, - kVtxCovXZ, - kVtxCovYY, - kVtxCovYZ, - kVtxCovZZ, - kVtxChi2, - kCentVZERO, - kCentFT0C, - kCentFT0A, - kCentFT0M, - kMultTPC, - kMultFV0A, - kMultFV0C, - kMultFT0A, - kMultFT0C, - kMultFDDA, - kMultFDDC, - kMultZNA, - kMultZNC, - kMultTracklets, - kMultDimuons, - kMultAntiMuons, - kMultMuons, - kMultSingleMuons, - kMultNTracksHasITS, - kMultNTracksHasTPC, - kMultNTracksHasTOF, - kMultNTracksHasTRD, - kMultNTracksITSOnly, - kMultNTracksTPCOnly, - kMultNTracksITSTPC, - kMultNTracksPVeta1, - kMultNTracksPVetaHalf, - kTrackOccupancyInTimeRange, - kFT0COccupancyInTimeRange, - kNoCollInTimeRangeStandard, - kMultAllTracksTPCOnly, - kMultAllTracksITSTPC, - kNTPCpileupContribA, - kNTPCpileupContribC, - kNTPCpileupZA, - kNTPCpileupZC, - kNTPCtracksInPast, - kNTPCtracksInFuture, - kNTPCcontribLongA, - kNTPCcontribLongC, - kNTPCmeanTimeLongA, - kNTPCmeanTimeLongC, - kNTPCmedianTimeLongA, - kNTPCmedianTimeLongC, - kNTPCcontribShortA, - kNTPCcontribShortC, - kNTPCmeanTimeShortA, - kNTPCmeanTimeShortC, - kNTPCmedianTimeShortA, - kNTPCmedianTimeShortC, - kMCEventGeneratorId, - kMCEventSubGeneratorId, - kMCVtxX, - kMCVtxY, - kMCVtxZ, - kMCEventTime, - kMCEventWeight, - kMCEventImpParam, - kMCEventCentrFT0C, - kMultMCNParticlesEta10, - kMultMCNParticlesEta08, - kMultMCNParticlesEta05, - kQ1ZNAX, - kQ1ZNAY, - kQ1ZNCX, - kQ1ZNCY, - KIntercalibZNA, - KIntercalibZNC, - kQ1ZNACXX, - kQ1ZNACYY, - kQ1ZNACYX, - kQ1ZNACXY, - kQ1X0A, // q-vector (e.g. from TPC) with x component (harmonic 1 and power 0), sub-event A - kQ1Y0A, // q-vector (e.g. from TPC) with y component (harmonic 1 and power 0), sub-event A - kQ1X0B, - kQ1Y0B, - kQ1X0C, - kQ1Y0C, - kQ2X0A, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 0), sub-event A - kQ2Y0A, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 0), sub-event A - kQ2X0APOS, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 1), Pos. TPC - kQ2Y0APOS, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 1), Pos. TPC - kQ2X0ANEG, // q-vector (e.g. from TPC) with x component (harmonic 2 and power 1), Neg. TPC - kQ2Y0ANEG, // q-vector (e.g. from TPC) with y component (harmonic 2 and power 1), Neg. TPC - kQ2X0B, - kQ2Y0B, - kQ2X0C, - kQ2Y0C, - kQ2YYAB, - kQ2XXAB, - kQ2XYAB, - kQ2YXAB, - kQ2YYAC, - kQ2XXAC, - kQ2XYAC, - kQ2YXAC, - kQ2YYBC, - kQ2XXBC, - kQ2XYBC, - kQ2YXBC, - kMultA, // Multiplicity of the sub-event A - kMultAPOS, // Multiplicity of the sub-event A - kMultANEG, // Multiplicity of the sub-event A - kMultB, - kMultC, - kQ3X0A, // q-vector (e.g. from TPC) with x component (harmonic 3 and power 0), sub-event A - kQ3Y0A, // q-vector (e.g. from TPC) with y component (harmonic 3 and power 0), sub-event A - kQ3X0B, - kQ3Y0B, - kQ3X0C, - kQ3Y0C, - kQ4X0A, // q-vector (e.g. from TPC) with x component (harmonic 4 and power 0), sub-event A - kQ4Y0A, // q-vector (e.g. from TPC) with y component (harmonic 4 and power 0), sub-event A - kQ4X0B, - kQ4Y0B, - kQ4X0C, - kQ4Y0C, - kR2SP_AB, - kR2SP_AC, - kR2SP_BC, - kWR2SP_AB, - kWR2SP_AC, - kWR2SP_BC, - kR2SP_AB_Im, - kR2SP_AC_Im, - kR2SP_BC_Im, - kWR2SP_AB_Im, - kWR2SP_AC_Im, - kWR2SP_BC_Im, - kR2SP_FT0CTPCPOS, - kR2SP_FT0CTPCNEG, - kR2SP_FT0ATPCPOS, - kR2SP_FT0ATPCNEG, - kR2SP_FT0MTPCPOS, - kR2SP_FT0MTPCNEG, - kR2SP_FV0ATPCPOS, - kR2SP_FV0ATPCNEG, - kR3SP, - kR2EP_AB, - kR2EP_AC, - kR2EP_BC, - kWR2EP_AB, - kWR2EP_AC, - kWR2EP_BC, - kR2EP_AB_Im, - kR2EP_AC_Im, - kR2EP_BC_Im, - kWR2EP_AB_Im, - kWR2EP_AC_Im, - kWR2EP_BC_Im, - kR2EP_FT0CTPCPOS, - kR2EP_FT0CTPCNEG, - kR2EP_FT0ATPCPOS, - kR2EP_FT0ATPCNEG, - kR2EP_FT0MTPCPOS, - kR2EP_FT0MTPCNEG, - kR2EP_FV0ATPCPOS, - kR2EP_FV0ATPCNEG, - kR3EP, - kIsDoubleGap, // Double rapidity gap - kIsSingleGapA, // Rapidity gap on side A - kIsSingleGapC, // Rapidity gap on side C - kIsSingleGap, // Rapidity gap on either side - kIsITSUPCMode, // UPC mode used for event - kTwoEvPosZ1, // vtx-z for collision 1 in two events correlations - kTwoEvPosZ2, // vtx-z for collision 2 in two events correlations - kTwoEvPosR1, // vtx-R for collision 1 in two events correlations - kTwoEvPosR2, - kTwoEvCentFT0C1, - kTwoEvCentFT0C2, - kTwoEvPVcontrib1, // n-contributors for collision 1 in two events correlations - kTwoEvPVcontrib2, - kTwoEvDeltaZ, // distance in z between collisions - kTwoEvDeltaX, // distance in x between collisions - kTwoEvDeltaY, // distance in y between collisions - kTwoEvDeltaR, // distance in (x,y) plane between collisions - kEnergyCommonZNA, - kEnergyCommonZNC, - kEnergyCommonZPA, - kEnergyCommonZPC, - kEnergyZNA1, - kEnergyZNA2, - kEnergyZNA3, - kEnergyZNA4, - kEnergyZNC1, - kEnergyZNC2, - kEnergyZNC3, - kEnergyZNC4, - kTimeZNA, - kTimeZNC, - kTimeZPA, - kTimeZPC, - kQ2X0A1, - kQ2X0A2, - kQ2Y0A1, - kQ2Y0A2, - kU2Q2Ev1, - kU2Q2Ev2, - kCos2DeltaPhiEv1, - kCos2DeltaPhiEv2, - kV2SP1, - kV2SP2, - kV2EP1, - kV2EP2, - kV2ME_SP, - kV2ME_EP, - kWV2ME_SP, - kWV2ME_EP, - kTwoR2SP1, // Scalar product resolution of event1 for ME technique - kTwoR2SP2, // Scalar product resolution of event2 for ME technique - kTwoR2EP1, // Event plane resolution of event2 for ME technique - kTwoR2EP2, // Event plane resolution of event2 for ME technique - kNEventWiseVariables, - - // Variables for event mixing with cumulant - kV22m, - kV24m, - kV22p, - kV24p, - kV22ME, - kV24ME, - kWV22ME, - kWV24ME, - - // Basic track/muon/pair wise variables - kX, - kY, - kZ, - kPt, - kSignedPt, - kInvPt, - kEta, - kTgl, - kPhi, - kP, - kPx, - kPy, - kPz, - kRap, - kMass, - kCharge, - kNBasicTrackVariables, - kUsedKF, - kKFMass, - kKFMassGeoTop, - - kPt1, - kEta1, - kPhi1, - kCharge1, - kPin_leg1, - kTPCnSigmaKa_leg1, - kPt2, - kEta2, - kPhi2, - kCharge2, - - // Barrel track variables - kPin, - kSignedPin, - kTOFExpMom, - kTrackTime, - kTrackTimeRes, - kTrackTimeResRelative, - kDetectorMap, - kHasITS, - kHasTRD, - kHasTOF, - kHasTPC, - kIsGlobalTrack, - kIsGlobalTrackSDD, - kIsITSrefit, - kIsSPDany, - kIsSPDfirst, - kIsSPDboth, - kIsITSibAny, - kIsITSibFirst, - kIsITSibAll, - kITSncls, - kITSchi2, - kITSlayerHit, - kITSmeanClsSize, - kIsTPCrefit, - kTPCncls, - kITSClusterMap, - kTPCnclsCR, - kTPCnCRoverFindCls, - kTPCchi2, - kTPCsignal, - kPhiTPCOuter, - kTrackIsInsideTPCModule, - kTRDsignal, - kTRDPattern, - kTOFbeta, - kTrackLength, - kTrackDCAxy, - kTrackDCAxyProng1, - kTrackDCAxyProng2, - kTrackDCAz, - kTrackDCAzProng1, - kTrackDCAzProng2, - kTrackDCAsigXY, - kTrackDCAsigZ, - kTrackDCAresXY, - kTrackDCAresZ, - kIsGoldenChi2, - kTrackCYY, - kTrackCZZ, - kTrackCSnpSnp, - kTrackCTglTgl, - kTrackC1Pt21Pt2, - kTPCnSigmaEl, - kTPCnSigmaMu, - kTPCnSigmaPi, - kTPCnSigmaKa, - kTPCnSigmaPr, - kTPCnSigmaEl_Corr, - kTPCnSigmaPi_Corr, - kTPCnSigmaKa_Corr, - kTPCnSigmaPr_Corr, - kTOFnSigmaEl, - kTOFnSigmaMu, - kTOFnSigmaPi, - kTOFnSigmaKa, - kTOFnSigmaPr, - kTrackTimeResIsRange, // Gaussian or range (see Framework/DataTypes) - kPVContributor, // This track has contributed to the collision vertex fit (see Framework/DataTypes) - kOrphanTrack, // Track has no association with any collision vertex (see Framework/DataTypes) - kIsAmbiguous, - kIsLegFromGamma, - kIsLegFromK0S, - kIsLegFromLambda, - kIsLegFromAntiLambda, - kIsLegFromOmega, - kIsProtonFromLambdaAndAntiLambda, - kIsDalitzLeg, // Up to 8 dalitz selections - kBarrelNAssocsInBunch = kIsDalitzLeg + 8, // number of in bunch collision associations - kBarrelNAssocsOutOfBunch, // number of out of bunch collision associations - kNBarrelTrackVariables, - - // Muon track variables - kMuonNClusters, - kMuonPDca, - kMuonRAtAbsorberEnd, - kMCHBitMap, - kMuonChi2, - kMuonChi2MatchMCHMID, - kMuonChi2MatchMCHMFT, - kMuonMatchScoreMCHMFT, - kMuonCXX, - kMuonCXY, - kMuonCYY, - kMuonCPhiX, - kMuonCPhiY, - kMuonCPhiPhi, - kMuonCTglX, - kMuonCTglY, - kMuonCTglPhi, - kMuonCTglTgl, - kMuonC1Pt2X, - kMuonC1Pt2Y, - kMuonC1Pt2Phi, - kMuonC1Pt2Tgl, - kMuonC1Pt21Pt2, - kMuonTrackType, - kMuonDCAx, - kMuonDCAy, - kMuonTime, - kMuonTimeRes, - kMftNClusters, - kMftClusterSize, - kMftMeanClusterSize, - kMuonNAssocsInBunch, - kMuonNAssocsOutOfBunch, - kNMuonTrackVariables, - - // MC particle variables - kMCPdgCode, - kMCParticleWeight, - kMCPx, - kMCPy, - kMCPz, - kMCMass, - kMCE, - kMCVx, - kMCVy, - kMCVz, - kMCPt, - kMCPhi, - kMCEta, - kMCY, - kMCParticleGeneratorId, - kNMCParticleVariables, - kMCHadronPdgCode, - kMCCosTheta, - kMCJpsiPt, - kMCCosChi, - kMCdeltaphi, - kMCdeltaeta, - kMCHadronPt, - kMCHadronEta, - kMCHadronPhi, - kMCWeight, - kMCCosChi_randomPhi_toward, - kMCWeight_randomPhi_toward, - kMCCosChi_randomPhi_away, - kMCWeight_randomPhi_away, - kMCCosChi_randomPhi_trans, - kMCWeight_randomPhi_trans, - kMCdeltaphi_randomPhi_toward, - kMCdeltaphi_randomPhi_away, - kMCdeltaphi_randomPhi_trans, - kMCWeight_before, - - // MC mother particle variables - kMCMotherPdgCode, - - // MC pair variables - kMCCosThetaHE, - kMCPhiHE, - kMCPhiTildeHE, - kMCCosThetaCS, - kMCPhiCS, - kMCPhiTildeCS, - kMCCosThetaPP, - kMCPhiPP, - kMCPhiTildePP, - kMCCosThetaRM, - - // Pair variables - kCandidateId, - kPairType, - kVertexingLxy, - kVertexingLxyErr, - kVertexingPseudoCTau, - kVertexingLxyz, - kVertexingLxyzErr, - kVertexingLz, - kVertexingLzErr, - kVertexingTauxy, - kVertexingTauxyErr, - kVertexingLzProjected, - kVertexingLxyProjected, - kVertexingLxyzProjected, - kVertexingTauzProjected, - kVertexingTauxyProjected, - kVertexingTauxyProjectedPoleJPsiMass, - kVertexingTauxyProjectedNs, - kVertexingTauxyzProjected, - kVertexingTauz, - kVertexingTauzErr, - kVertexingPz, - kVertexingSV, - kVertexingProcCode, - kVertexingChi2PCA, - kCosThetaHE, - kPhiHE, - kPhiTildeHE, - kCosThetaCS, - kPhiCS, - kPhiTildeCS, - kCosThetaPP, - kPhiPP, - kPhiTildePP, - kCosThetaRM, - kCosThetaStarTPC, - kCosThetaStarFT0A, - kCosThetaStarFT0C, - kCosPhiVP, - kPhiVP, - kDeltaPhiPair2, - kDeltaEtaPair2, - kPsiPair, - kDeltaPhiPair, - kOpeningAngle, - kQuadDCAabsXY, - kQuadDCAsigXY, - kQuadDCAabsZ, - kQuadDCAsigZ, - kQuadDCAsigXYZ, - kSignQuadDCAsigXY, - kCosPointingAngle, - kImpParXYJpsi, - kImpParXYK, - kDCATrackProd, - kDCATrackVtxProd, - kV2SP, - kV2EP, - kWV2SP, - kWV2EP, - kU2Q2, - kU3Q3, - kQ42XA, - kQ42YA, - kQ23XA, - kQ23YA, - kS11A, - kS12A, - kS13A, - kS31A, - kM11REF, - kM11REFetagap, - kM01POI, - kM1111REF, - kM11M1111REF, - kM11M1111REFoverMp, - kM01M0111POIoverMp, - kM0111POI, - kCORR2REF, - kCORR2REFbydimuons, - kCORR2REFbysinglemu, - kCORR2REFetagap, - kCORR2POI, - kCORR2POICORR4POI, - kCORR2REFCORR4POI, - kCORR2REFCORR2POI, - kM01M0111overMp, - kM11M0111overMp, - kM11M01overMp, - kCORR2CORR4REF, - kCORR4REF, - kCORR4REFbydimuons, - kCORR4REFbysinglemu, - kCORR4POI, - kM11REFoverMp, - kM01POIoverMp, - kM1111REFoverMp, - kM0111POIoverMp, - kCORR2POIMp, - kCORR4POIMp, - kM01POIplus, - kM0111POIplus, - kM01POIminus, - kM0111POIminus, - kM01POIsingle, - kM0111POIsingle, - kM01POIoverMpminus, - kM01POIoverMpplus, - kM01POIoverMpsingle, - kM01POIoverMpmoins, - kM0111POIoverMpminus, - kM0111POIoverMpplus, - kM0111POIoverMpsingle, - kCORR2POIplus, - kCORR2POIminus, - kCORR2POIsingle, - kCORR4POIplus, - kCORR4POIminus, - kCORR4POIsingle, - kM11REFoverMpplus, - kM1111REFoverMpplus, - kM11REFoverMpminus, - kM1111REFoverMpminus, - kM11REFoverMpsingle, - kM1111REFoverMpsingle, - kM01POIME, - kMultDimuonsME, - kM0111POIME, - kCORR2POIME, - kCORR4POIME, - kM01POIoverMpME, - kM0111POIoverMpME, - kM11REFoverMpME, - kM1111REFoverMpME, - kCORR2REFbydimuonsME, - kCORR4REFbydimuonsME, - kR2SP, - kR2EP, - kPsi2A, - kPsi2APOS, - kPsi2ANEG, - kPsi2B, - kPsi2C, - kCos2DeltaPhi, - kCos2DeltaPhiMu1, // cos(phi - phi1) for muon1 - kCos2DeltaPhiMu2, ////cos(phi - phi2) for muon2 - kCos3DeltaPhi, - kDeltaPtotTracks, - kVertexingLxyOverErr, - kVertexingLzOverErr, - kVertexingLxyzOverErr, - kKFTrack0DCAxyz, - kKFTrack1DCAxyz, - kKFTracksDCAxyzMax, - kKFDCAxyzBetweenProngs, - kKFTrack0DCAxy, - kKFTrack1DCAxy, - kKFTracksDCAxyMax, - kKFDCAxyBetweenProngs, - kKFTrack0DeviationFromPV, - kKFTrack1DeviationFromPV, - kKFTrack0DeviationxyFromPV, - kKFTrack1DeviationxyFromPV, - kKFChi2OverNDFGeo, - kKFNContributorsPV, - kKFCosPA, - kKFChi2OverNDFGeoTop, - kKFJpsiDCAxyz, - kKFJpsiDCAxy, - kKFPairDeviationFromPV, - kKFPairDeviationxyFromPV, - kS12, - kS13, - kS23, - kNPairVariables, - - // Candidate-track correlation variables - kPairMass, - kPairMassDau, - kMassDau, - kPairPt, - kPairPtDau, - kPairEta, - kPairRap, - kPairPhi, - kPairPhiv, - kDeltaEta, - kDeltaPhi, - kDeltaPhiSym, - kNCorrelationVariables, - kDileptonHadronKstar, - kCosChi, - kEtaDau, - kPhiDau, - kECWeight, - kPtDau, - kCosTheta, - kEWeight_before, - kCosChi_randomPhi_trans, - kCosChi_randomPhi_toward, - kCosChi_randomPhi_away, - kWeight_randomPhi_trans, - kWeight_randomPhi_toward, - kWeight_randomPhi_away, - kdeltaphi_randomPhi_trans, - kdeltaphi_randomPhi_toward, - kdeltaphi_randomPhi_away, - - // Dilepton-track-track variables - kQuadMass, - kQuadDefaultDileptonMass, - kQuadPt, - kQuadEta, - kQuadPhi, - kCosthetaDileptonDitrack, - kDitrackMass, - kDitrackPt, - kQ, - kDeltaR1, - kDeltaR2, - kDeltaR, - - // DQ-HF correlation variables - kMassCharmHadron, - kPtCharmHadron, - kRapCharmHadron, - kPhiCharmHadron, - kBdtCharmHadron, - - // Index used to scan bit maps - kBitMapIndex, - - // deltaMass = kPairMass - kPairMassDau - kDeltaMass, - // deltaMass_jpsi = kPairMass - kPairMassDau +3.096900 - kDeltaMass_jpsi, - - // BDT score - kBdtBackground, - kBdtPrompt, - kBdtNonprompt, - - kNVars - }; // end of Variables enumeration - - enum CalibObjects { - kTPCElectronMean = 0, - kTPCElectronSigma, - kTPCElectronStatus, - kTPCPionMean, - kTPCPionSigma, - kTPCPionStatus, - kTPCKaonMean, - kTPCKaonSigma, - kTPCKaonStatus, - kTPCProtonMean, - kTPCProtonSigma, - kTPCProtonStatus, - kNCalibObjects - }; - - enum DileptonCharmHadronTypes { - kJPsi = 0, - kD0ToPiK, - kD0barToKPi - }; - - enum EventFilters { - kDoubleGap = 0, - kSingleGapA, - kSingleGapC, - kITSUPCMode - }; - - enum MuonExtrapolation { - // Index used to set different options for Muon propagation - kToVertex = 0, // propagtion to vertex by default - kToDCA, - kToRabs, - kToMatching - }; - - static TString fgVariableNames[kNVars]; // variable names - static TString fgVariableUnits[kNVars]; // variable units - static std::map fgVarNamesMap; // key: variables short name, value: order in the Variables enum - static void SetDefaultVarNames(); - - static void SetUseVariable(int var) - { - if (var >= 0 && var < kNVars) { - fgUsedVars[var] = kTRUE; - } - SetVariableDependencies(); - } - static void SetUseVars(const bool* usedVars) - { - for (int i = 0; i < kNVars; ++i) { - if (usedVars[i]) { - fgUsedVars[i] = true; // overwrite only the variables that are being used since there are more channels to modify the used variables array, independently - } - } - SetVariableDependencies(); - } - static void SetUseVars(const std::vector usedVars) - { - for (auto& var : usedVars) { - fgUsedVars[var] = true; - } - } - static bool GetUsedVar(int var) - { - if (var >= 0 && var < kNVars) { - return fgUsedVars[var]; - } - return false; - } - - // Setup the collision system - static void SetCollisionSystem(TString system, float energy); - static void SetCollisionSystem(o2::parameters::GRPLHCIFData* grplhcif); - - static void SetMagneticField(float magField) - { - fgMagField = magField; - } - - // Setup plane position for MFT-MCH matching - static void SetMatchingPlane(float z) - { - fgzMatching = z; - } - - static float GetMatchingPlane() - { - return fgzMatching; - } - - // Setup the 2 prong KFParticle - static void SetupTwoProngKFParticle(float magField) - { - KFParticle::SetField(magField); - fgUsedKF = true; - } - // Setup magnetic field for muon propagation - static void SetupMuonMagField() - { - o2::mch::TrackExtrap::setField(); - } - - // Setup the 2 prong DCAFitterN - static void SetupTwoProngDCAFitter(float magField, bool propagateToPCA, float maxR, float maxDZIni, float minParamChange, float minRelChi2Change, bool useAbsDCA) - { - fgFitterTwoProngBarrel.setBz(magField); - fgFitterTwoProngBarrel.setPropagateToPCA(propagateToPCA); - fgFitterTwoProngBarrel.setMaxR(maxR); - fgFitterTwoProngBarrel.setMaxDZIni(maxDZIni); - fgFitterTwoProngBarrel.setMinParamChange(minParamChange); - fgFitterTwoProngBarrel.setMinRelChi2Change(minRelChi2Change); - fgFitterTwoProngBarrel.setUseAbsDCA(useAbsDCA); - fgUsedKF = false; - } - - // Setup the 2 prong FwdDCAFitterN - static void SetupTwoProngFwdDCAFitter(float magField, bool propagateToPCA, float maxR, float minParamChange, float minRelChi2Change, bool useAbsDCA) - { - fgFitterTwoProngFwd.setBz(magField); - fgFitterTwoProngFwd.setPropagateToPCA(propagateToPCA); - fgFitterTwoProngFwd.setMaxR(maxR); - fgFitterTwoProngFwd.setMinParamChange(minParamChange); - fgFitterTwoProngFwd.setMinRelChi2Change(minRelChi2Change); - fgFitterTwoProngFwd.setUseAbsDCA(useAbsDCA); - fgUsedKF = false; - } - // Use MatLayerCylSet to correct MCS in fwdtrack propagation - static void SetupMatLUTFwdDCAFitter(o2::base::MatLayerCylSet* m) - { - fgFitterTwoProngFwd.setTGeoMat(false); - fgFitterTwoProngFwd.setMatLUT(m); - } - // Use GeometryManager to correct MCS in fwdtrack propagation - static void SetupTGeoFwdDCAFitter() - { - fgFitterTwoProngFwd.setTGeoMat(true); - } - // No material budget in fwdtrack propagation - static void SetupFwdDCAFitterNoCorr() - { - fgFitterTwoProngFwd.setTGeoMat(false); - } - // Setup the 3 prong KFParticle - static void SetupThreeProngKFParticle(float magField) - { - KFParticle::SetField(magField); - fgUsedKF = true; - } - - // Setup the 3 prong DCAFitterN - static void SetupThreeProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) - { - fgFitterThreeProngBarrel.setBz(magField); - fgFitterThreeProngBarrel.setPropagateToPCA(propagateToPCA); - fgFitterThreeProngBarrel.setMaxR(maxR); - fgFitterThreeProngBarrel.setMinParamChange(minParamChange); - fgFitterThreeProngBarrel.setMinRelChi2Change(minRelChi2Change); - fgFitterThreeProngBarrel.setUseAbsDCA(useAbsDCA); - fgUsedKF = false; - } - - // Setup the 4 prong KFParticle - static void SetupFourProngKFParticle(float magField) - { - KFParticle::SetField(magField); - fgUsedKF = true; - } - - // Setup the 4 prong DCAFitterN - static void SetupFourProngDCAFitter(float magField, bool propagateToPCA, float maxR, float /*maxDZIni*/, float minParamChange, float minRelChi2Change, bool useAbsDCA) - { - fgFitterFourProngBarrel.setBz(magField); - fgFitterFourProngBarrel.setPropagateToPCA(propagateToPCA); - fgFitterFourProngBarrel.setMaxR(maxR); - fgFitterFourProngBarrel.setMinParamChange(minParamChange); - fgFitterFourProngBarrel.setMinRelChi2Change(minRelChi2Change); - fgFitterFourProngBarrel.setUseAbsDCA(useAbsDCA); - fgUsedKF = false; - } - - static auto getEventPlane(int harm, float qnxa, float qnya) - { - // Compute event plane angle from qn vector components for the sub-event A - return (1.0 / harm) * TMath::ATan2(qnya, qnxa); - }; - - static float getDeltaPsiInRange(float psi1, float psi2, float harmonic) - { - float deltaPsi = psi1 - psi2; - if (std::abs(deltaPsi) > o2::constants::math::PI / harmonic) { - if (deltaPsi > 0.) { - deltaPsi -= o2::constants::math::TwoPI / harmonic; - } else { - deltaPsi += o2::constants::math::TwoPI / harmonic; - } - } - return deltaPsi; - } - - template - static o2::track::TrackParCovFwd FwdToTrackPar(const T& track, const C& cov); - template - static o2::dataformats::GlobalFwdTrack PropagateMuon(const T& muon, const C& collision, int endPoint = kToVertex); - template - static o2::track::TrackParCovFwd PropagateFwd(const T& track, const C& cov, float z); - template - static void FillMuonPDca(const T& muon, const C& collision, float* values = nullptr); - template - static void FillPropagateMuon(const T& muon, const C& collision, float* values = nullptr); - template - static void FillBC(T const& bc, float* values = nullptr); - template - static void FillEvent(T const& event, float* values = nullptr); - template - static void FillEventTrackEstimators(TEvent const& collision, TAssoc const& groupedTrackIndices, TTracks const& tracks, float* values = nullptr); - template - static void FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); - template - static void FillTwoEvents(T const& event1, T const& event2, float* values = nullptr); - template - static void FillTwoMixEvents(T1 const& event1, T1 const& event2, T2 const& tracks1, T2 const& tracks2, float* values = nullptr); - template - static void FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values = nullptr); - template - static void FillTwoMixEventsCumulants(T const& h_v22m, T const& h_v24m, T const& h_v22p, T const& h_v24p, T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillTrack(T const& track, float* values = nullptr); - template - static void FillPhoton(T const& photon, float* values = nullptr); - template - static void FillTrackCollision(T const& track, C const& collision, float* values = nullptr); - template - 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 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 - static void FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values = nullptr); - template - static void FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, float* values = nullptr); - template - static void FillPair(T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillPairCollision(C const& collision, T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values = nullptr); - template - static void FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values = nullptr, PairCandidateType pairType = kTripleCandidateToEEPhoton); - template - 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 FillQuadMC(T1 const& t1, T2 const& t2, T2 const& t3, float* values = nullptr); - template - static void FillPairVertexing(C const& collision, T const& t1, T const& t2, bool propToSV = false, float* values = nullptr); - template - static void FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, PairCandidateType tripletType, float* values = nullptr); - template - static void FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values); - template - static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); - template - static void FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values = nullptr); - template - static void FillHadron(T const& hadron, float* values = nullptr, float hadronMass = 0.0f); - template - static void FillSingleDileptonCharmHadron(Cand const& candidate, H hfHelper, T& bdtScoreCharmHad, float* values = nullptr); - template - static void FillDileptonCharmHadron(DQ const& dilepton, HF const& charmHadron, H hfHelper, T& bdtScoreCharmHad, float* values = nullptr); - template - static void FillQVectorFromGFW(C const& collision, A const& compA11, A const& compB11, A const& compC11, A const& compA21, A const& compB21, A const& compC21, A const& compA31, A const& compB31, A const& compC31, A const& compA41, A const& compB41, A const& compC41, A const& compA23, A const& compA42, float S10A = 1.0, float S10B = 1.0, float S10C = 1.0, float S11A = 1.0, float S11B = 1.0, float S11C = 1.0, float S12A = 1.0, float S13A = 1.0, float S14A = 1.0, float S21A = 1.0, float S22A = 1.0, float S31A = 1.0, float S41A = 1.0, float* values = nullptr); - template - static void FillQVectorFromCentralFW(C const& collision, float* values = nullptr); - template - static void FillNewQVectorFromCentralFW(C const& collision, float* values = nullptr); - template - static void FillSpectatorPlane(C const& collision, float* values = nullptr); - template - static void FillPairVn(T1 const& t1, T2 const& t2, float* values = nullptr); - template - static void FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T3 const& hadron2, float* values = nullptr); - template - static void FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values); - template - static void FillZDC(const T& zdc, float* values = nullptr); - template - static void FillBdtScore(const T& bdtScore, float* values = nullptr); - - static void SetCalibrationObject(CalibObjects calib, TObject* obj) - { - fgCalibs[calib] = obj; - // Check whether all the needed objects for TPC postcalibration are available - if (fgCalibs.find(kTPCElectronMean) != fgCalibs.end() && fgCalibs.find(kTPCElectronSigma) != fgCalibs.end()) { - fgRunTPCPostCalibration[0] = true; - fgUsedVars[kTPCnSigmaEl_Corr] = true; - } - if (fgCalibs.find(kTPCPionMean) != fgCalibs.end() && fgCalibs.find(kTPCPionSigma) != fgCalibs.end()) { - fgRunTPCPostCalibration[1] = true; - fgUsedVars[kTPCnSigmaPi_Corr] = true; - } - if (fgCalibs.find(kTPCKaonMean) != fgCalibs.end() && fgCalibs.find(kTPCKaonSigma) != fgCalibs.end()) { - fgRunTPCPostCalibration[2] = true; - fgUsedVars[kTPCnSigmaKa_Corr] = true; - } - if (fgCalibs.find(kTPCProtonMean) != fgCalibs.end() && fgCalibs.find(kTPCProtonSigma) != fgCalibs.end()) { - fgRunTPCPostCalibration[3] = true; - fgUsedVars[kTPCnSigmaPr_Corr] = true; - } - } - - static void SetCalibrationType(int type, bool useInterpolation = true) - { - if (type < 0 || type > 2) { - LOG(fatal) << "Invalid calibration type. Must be 0, 1, or 2."; - } - fgCalibrationType = type; - fgUseInterpolatedCalibration = useInterpolation; - } - static double ComputePIDcalibration(int species, double nSigmaValue); - - static TObject* GetCalibrationObject(CalibObjects calib) - { - auto obj = fgCalibs.find(calib); - if (obj == fgCalibs.end()) { - return 0x0; - } else { - return obj->second; - } - } - static void SetTPCInterSectorBoundary(float boundarySize) - { - fgTPCInterSectorBoundary = boundarySize; - } - static void SetITSROFBorderselection(int bias, int length, int marginLow, int marginHigh) - { - fgITSROFbias = bias; - fgITSROFlength = length; - fgITSROFBorderMarginLow = marginLow; - fgITSROFBorderMarginHigh = marginHigh; - } - - static void SetSORandEOR(uint64_t sor, uint64_t eor) - { - fgSOR = sor; - fgEOR = eor; - } - - public: - VarManager(); - ~VarManager() override; - - static float fgValues[kNVars]; // array holding all variables computed during analysis - static void ResetValues(int startValue = 0, int endValue = kNVars, float* values = nullptr); - - private: - static bool fgUsedVars[kNVars]; // holds flags for when the corresponding variable is needed (e.g., in the histogram manager, in cuts, mixing handler, etc.) - static bool fgUsedKF; - static void SetVariableDependencies(); // toggle those variables on which other used variables might depend - - 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 ROOT::Math::PxPyPzEVector fgBeamA; // beam from A-side 4-momentum vector - static ROOT::Math::PxPyPzEVector fgBeamC; // beam from C-side 4-momentum vector - - // static void FillEventDerived(float* values = nullptr); - static void FillTrackDerived(float* values = nullptr); - template - static auto getRotatedCovMatrixXX(const T& matrix, U phi, V theta); - template - static KFPTrack createKFPTrackFromTrack(const T& track); - template - static KFPTrack createKFPFwdTrackFromFwdTrack(const T& muon); - template - static KFPVertex createKFPVertexFromCollision(const T& collision); - static float calculateCosPA(KFParticle kfp, KFParticle PV); - template - static float calculatePhiV(const T1& t1, const T2& t2); - template - static float LorentzTransformJpsihadroncosChi(TString Option, const T1& v1, const T2& v2); - - static o2::vertexing::DCAFitterN<2> fgFitterTwoProngBarrel; - static o2::vertexing::DCAFitterN<3> fgFitterThreeProngBarrel; - static o2::vertexing::DCAFitterN<4> fgFitterFourProngBarrel; - static o2::vertexing::FwdDCAFitterN<2> fgFitterTwoProngFwd; - static o2::vertexing::FwdDCAFitterN<3> fgFitterThreeProngFwd; - static o2::globaltracking::MatchGlobalFwd mMatching; - - static std::map fgCalibs; // map of calibration histograms - static bool fgRunTPCPostCalibration[4]; // 0-electron, 1-pion, 2-kaon, 3-proton - static int fgCalibrationType; // 0 - no calibration, 1 - calibration vs (TPCncls,pIN,eta) typically for pp, 2 - calibration vs (eta,nPV,nLong,tLong) typically for PbPb - static bool fgUseInterpolatedCalibration; // use interpolated calibration histograms (default: true) - - VarManager& operator=(const VarManager& c); - VarManager(const VarManager& c); - - ClassDef(VarManager, 4); -}; - -template -o2::track::TrackParCovFwd VarManager::FwdToTrackPar(const T& track, const C& cov) -{ - double chi2 = track.chi2(); - SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); - std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), - cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), - cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; - SMatrix55 tcovs(v1.begin(), v1.end()); - o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; - return trackparCov; -} - -template -auto VarManager::getRotatedCovMatrixXX(const T& matrix, U phi, V theta) -{ - // - auto cp = std::cos(phi); - auto sp = std::sin(phi); - auto ct = std::cos(theta); - auto st = std::sin(theta); - return matrix[0] * cp * cp * ct * ct // covXX - + matrix[1] * 2. * cp * sp * ct * ct // covXY - + matrix[2] * sp * sp * ct * ct // covYY - + matrix[3] * 2. * cp * ct * st // covXZ - + matrix[4] * 2. * sp * ct * st // covYZ - + matrix[5] * st * st; // covZZ -} - -template -KFPTrack VarManager::createKFPTrackFromTrack(const T& track) -{ - std::array trackpars = {track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt()}; - std::array trackcovs = {track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), - track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), - track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()}; - o2::track::TrackParametrizationWithError trackparCov{track.x(), track.alpha(), std::move(trackpars), std::move(trackcovs)}; - std::array trkpos_par; - std::array trkmom_par; - std::array trk_cov; - trackparCov.getXYZGlo(trkpos_par); - trackparCov.getPxPyPzGlo(trkmom_par); - trackparCov.getCovXYZPxPyPzGlo(trk_cov); - float trkpar_KF[6] = {trkpos_par[0], trkpos_par[1], trkpos_par[2], - trkmom_par[0], trkmom_par[1], trkmom_par[2]}; - float trkcov_KF[21]; - for (int i = 0; i < 21; i++) { - trkcov_KF[i] = trk_cov[i]; - } - KFPTrack kfpTrack; - kfpTrack.SetParameters(trkpar_KF); - kfpTrack.SetCovarianceMatrix(trkcov_KF); - kfpTrack.SetCharge(track.sign()); - kfpTrack.SetNDF(track.tpcNClsFound() - 5); - kfpTrack.SetChi2(track.tpcChi2NCl() * track.tpcNClsFound()); - return kfpTrack; -} - -template -KFPTrack VarManager::createKFPFwdTrackFromFwdTrack(const T& muon) -{ - o2::track::TrackParCovFwd trackparCov = FwdToTrackPar(muon, muon); - - std::array trk_cov; - trackparCov.getCovXYZPxPyPzGlo(trk_cov); - double trkpar_KF[6] = {trackparCov.getX(), trackparCov.getY(), trackparCov.getZ(), - trackparCov.getPx(), trackparCov.getPy(), trackparCov.getPz()}; - float trkcov_KF[21]; - for (int i = 0; i < 21; i++) { - trkcov_KF[i] = trk_cov[i]; - } - KFPTrack kfpTrack; - kfpTrack.SetParameters(trkpar_KF); - kfpTrack.SetCovarianceMatrix(trkcov_KF); - kfpTrack.SetCharge(muon.sign()); - kfpTrack.SetNDF(muon.nClusters() - 5); - kfpTrack.SetChi2(muon.chi2()); - return kfpTrack; -} - -template -KFPVertex VarManager::createKFPVertexFromCollision(const T& collision) -{ - KFPVertex kfpVertex; - kfpVertex.SetXYZ(collision.posX(), collision.posY(), collision.posZ()); - kfpVertex.SetCovarianceMatrix(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - kfpVertex.SetChi2(collision.chi2()); - kfpVertex.SetNDF(2 * collision.numContrib() - 3); - kfpVertex.SetNContributors(collision.numContrib()); - return kfpVertex; -} - -template -o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C& collision, const int endPoint) -{ - o2::track::TrackParCovFwd fwdtrack = FwdToTrackPar(muon, muon); - o2::dataformats::GlobalFwdTrack propmuon; - if (static_cast(muon.trackType()) > 2) { - o2::dataformats::GlobalFwdTrack track; - track.setParameters(fwdtrack.getParameters()); - track.setZ(fwdtrack.getZ()); - track.setCovariances(fwdtrack.getCovariances()); - auto mchTrack = mMatching.FwdtoMCH(track); - - if (endPoint == kToVertex) { - o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); - } - if (endPoint == kToDCA) { - o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, collision.posZ()); - } - if (endPoint == kToRabs) { - o2::mch::TrackExtrap::extrapToZ(mchTrack, -505.); - } - if (endPoint == kToMatching) { - o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, fgzMatching); - } - - auto proptrack = mMatching.MCHtoFwd(mchTrack); - propmuon.setParameters(proptrack.getParameters()); - propmuon.setZ(proptrack.getZ()); - propmuon.setCovariances(proptrack.getCovariances()); - - } else if (static_cast(muon.trackType()) < 2) { - double centerMFT[3] = {0, 0, -61.4}; - o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - auto Bz = field->getBz(centerMFT); // Get field at centre of MFT - auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.x(), muon.y(), muon.z(), collision.posX(), collision.posY(), collision.posZ()); - auto x2x0 = static_cast(geoMan.meanX2X0); - fwdtrack.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, Bz, x2x0); - propmuon.setParameters(fwdtrack.getParameters()); - propmuon.setZ(fwdtrack.getZ()); - propmuon.setCovariances(fwdtrack.getCovariances()); - } - return propmuon; -} - -template -o2::track::TrackParCovFwd VarManager::PropagateFwd(const T& track, const C& cov, float z) -{ - o2::track::TrackParCovFwd fwdtrack = FwdToTrackPar(track, cov); - fwdtrack.propagateToZhelix(z, fgMagField); - return fwdtrack; -} - -template -void VarManager::FillMuonPDca(const T& muon, const C& collision, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { - - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); - - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - values[kMuonPDca] = muon.p() * dcaXY; - } -} - -template -void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & ReducedMuonCov) > 0) { - if (muon.filteringFlags() & (uint8_t(1) << VarManager::kMuonIsPropagated)) { // the muon is already propagated, so nothing to do - return; - } - } - - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); - values[kPt] = propmuon.getPt(); - values[kX] = propmuon.getX(); - values[kY] = propmuon.getY(); - values[kZ] = propmuon.getZ(); - values[kEta] = propmuon.getEta(); - values[kTgl] = propmuon.getTgl(); - values[kPhi] = propmuon.getPhi(); - - // Redo propagation only for muon tracks - // propagation of MFT tracks alredy done in fwdtrack-extention task - if (static_cast(muon.trackType()) > 2) { - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, kToRabs); - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - values[kMuonDCAx] = dcaX; - values[kMuonDCAy] = dcaY; - double xAbs = propmuonAtRabs.getX(); - double yAbs = propmuonAtRabs.getY(); - values[kMuonRAtAbsorberEnd] = std::sqrt(xAbs * xAbs + yAbs * yAbs); - } - - SMatrix55 cov = propmuon.getCovariances(); - values[kMuonCXX] = cov(0, 0); - values[kMuonCXY] = cov(1, 0); - values[kMuonCYY] = cov(1, 1); - values[kMuonCPhiX] = cov(2, 0); - values[kMuonCPhiY] = cov(2, 1); - values[kMuonCPhiPhi] = cov(2, 2); - values[kMuonCTglX] = cov(3, 0); - values[kMuonCTglY] = cov(3, 1); - values[kMuonCTglPhi] = cov(3, 2); - values[kMuonCTglTgl] = cov(3, 3); - values[kMuonC1Pt2X] = cov(4, 0); - values[kMuonC1Pt2Y] = cov(4, 1); - values[kMuonC1Pt2Phi] = cov(4, 2); - values[kMuonC1Pt2Tgl] = cov(4, 3); - values[kMuonC1Pt21Pt2] = cov(4, 4); - } -} - -template -void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, const C& collision, float* values) -{ - if (!values) { - values = fgValues; - } - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); - double px = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * cos(mfttrack.phi()); - double py = propmuon.getP() * sin(M_PI / 2 - atan(mfttrack.tgl())) * sin(mfttrack.phi()); - double pz = propmuon.getP() * cos(M_PI / 2 - atan(mfttrack.tgl())); - double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); - values[kX] = mfttrack.x(); - values[kY] = mfttrack.y(); - values[kZ] = mfttrack.z(); - values[kTgl] = mfttrack.tgl(); - values[kPt] = pt; - values[kPz] = pz; - values[kEta] = mfttrack.eta(); - values[kPhi] = mfttrack.phi(); - } -} - -template -void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, const C& collision, C2 const& mftcov, float* values) -{ - if (!values) { - values = fgValues; - } - if constexpr ((MuonfillMap & MuonCov) > 0) { - if constexpr ((MFTfillMap & MFTCov) > 0) { - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); - o2::track::TrackParCovFwd mft = FwdToTrackPar(mfttrack, mftcov); - - o2::dataformats::GlobalFwdTrack globalRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); - values[kX] = globalRefit.getX(); - values[kY] = globalRefit.getY(); - values[kZ] = globalRefit.getZ(); - values[kTgl] = globalRefit.getTgl(); - values[kPt] = globalRefit.getPt(); - values[kPz] = globalRefit.getPz(); - values[kEta] = globalRefit.getEta(); - values[kPhi] = globalRefit.getPhi(); - } - } -} - -template -void VarManager::FillBC(T const& bc, float* values) -{ - if (!values) { - values = fgValues; - } - values[kRunNo] = bc.runNumber(); - values[kBC] = bc.globalBC(); - values[kBCOrbit] = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; - values[kTimestamp] = bc.timestamp(); - values[kTimeFromSOR] = (fgSOR > 0 ? (bc.timestamp() - fgSOR) / 60000. : -1.0); -} - -template -void VarManager::FillEvent(T const& event, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & CollisionTimestamp) > 0) { - values[kTimestamp] = event.timestamp(); - } - - if constexpr ((fillMap & Collision) > 0) { - // TODO: trigger info from the event selection requires a separate flag - // so that it can be switched off independently of the rest of Collision variables (e.g. if event selection is not available) - - if (fgUsedVars[kIsNoITSROFBorder]) { - values[kIsNoITSROFBorder] = event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); - } - if (fgUsedVars[kTrackOccupancyInTimeRange]) { - values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); - } - if (fgUsedVars[kFT0COccupancyInTimeRange]) { - values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); - } - if (fgUsedVars[kNoCollInTimeRangeStandard]) { - values[kNoCollInTimeRangeStandard] = event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard); - } - if (fgUsedVars[kIsNoTFBorder]) { - values[kIsNoTFBorder] = event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); - } - if (fgUsedVars[kIsNoSameBunch]) { - values[kIsNoSameBunch] = event.selection_bit(o2::aod::evsel::kNoSameBunchPileup); - } - if (fgUsedVars[kIsGoodZvtxFT0vsPV]) { - values[kIsGoodZvtxFT0vsPV] = event.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); - } - if (fgUsedVars[kIsVertexITSTPC]) { - values[kIsVertexITSTPC] = event.selection_bit(o2::aod::evsel::kIsVertexITSTPC); - } - if (fgUsedVars[kIsVertexTOFmatched]) { - values[kIsVertexTOFmatched] = event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched); - } - if (fgUsedVars[kIsSel8]) { - values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder); - } - if (fgUsedVars[kIsGoodITSLayer3]) { - values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); - } - if (fgUsedVars[kIsGoodITSLayer0123]) { - values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); - } - if (fgUsedVars[kIsGoodITSLayersAll]) { - values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); - } - if (fgUsedVars[kIsINT7]) { - values[kIsINT7] = (event.alias_bit(kINT7) > 0); - } - if (fgUsedVars[kIsEMC7]) { - values[kIsEMC7] = (event.alias_bit(kEMC7) > 0); - } - if (fgUsedVars[kIsINT7inMUON]) { - values[kIsINT7inMUON] = (event.alias_bit(kINT7inMUON) > 0); - } - if (fgUsedVars[kIsMuonSingleLowPt7]) { - values[kIsMuonSingleLowPt7] = (event.alias_bit(kMuonSingleLowPt7) > 0); - } - if (fgUsedVars[kIsMuonSingleHighPt7]) { - values[kIsMuonSingleHighPt7] = (event.alias_bit(kMuonSingleHighPt7) > 0); - } - if (fgUsedVars[kIsMuonUnlikeLowPt7]) { - values[kIsMuonUnlikeLowPt7] = (event.alias_bit(kMuonUnlikeLowPt7) > 0); - } - if (fgUsedVars[kIsMuonLikeLowPt7]) { - values[kIsMuonLikeLowPt7] = (event.alias_bit(kMuonLikeLowPt7) > 0); - } - if (fgUsedVars[kIsCUP8]) { - values[kIsCUP8] = (event.alias_bit(kCUP8) > 0); - } - if (fgUsedVars[kIsCUP9]) { - values[kIsCUP9] = (event.alias_bit(kCUP9) > 0); - } - if (fgUsedVars[kIsMUP10]) { - values[kIsMUP10] = (event.alias_bit(kMUP10) > 0); - } - if (fgUsedVars[kIsMUP11]) { - values[kIsMUP11] = (event.alias_bit(kMUP11) > 0); - } - values[kVtxX] = event.posX(); - values[kVtxY] = event.posY(); - values[kVtxZ] = event.posZ(); - values[kVtxNcontrib] = event.numContrib(); - values[kVtxCovXX] = event.covXX(); - values[kVtxCovXY] = event.covXY(); - values[kVtxCovXZ] = event.covXZ(); - values[kVtxCovYY] = event.covYY(); - values[kVtxCovYZ] = event.covYZ(); - values[kVtxCovZZ] = event.covZZ(); - values[kVtxChi2] = event.chi2(); - values[kCollisionTime] = event.collisionTime(); - values[kCollisionTimeRes] = event.collisionTimeRes(); - } - - if constexpr ((fillMap & CollisionCentRun2) > 0) { - values[kCentVZERO] = event.centRun2V0M(); - } - - if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { - if constexpr ((fillMap & CollisionMC) == 0) { - values[kCentFT0C] = event.centFT0C(); - values[kCentFT0A] = event.centFT0A(); - values[kCentFT0M] = event.centFT0M(); - } - } - - if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { - values[kMultFV0A] = event.multFV0A(); - values[kMultFT0A] = event.multFT0A(); - values[kMultFT0C] = event.multFT0C(); - values[kMultFDDA] = event.multFDDA(); - values[kMultFDDC] = event.multFDDC(); - values[kMultTPC] = event.multTPC(); - values[kMultFV0C] = event.multFV0C(); - values[kMultZNA] = event.multZNA(); - values[kMultZNC] = event.multZNC(); - values[kMultTracklets] = event.multTracklets(); - values[kVtxNcontribReal] = event.multNTracksPV(); - } - - if constexpr ((fillMap & CollisionMultExtra) > 0 || (fillMap & ReducedEventMultExtra) > 0) { - values[kMultNTracksHasITS] = event.multNTracksHasITS(); - values[kMultNTracksHasTPC] = event.multNTracksHasTPC(); - values[kMultNTracksHasTOF] = event.multNTracksHasTOF(); - values[kMultNTracksHasTRD] = event.multNTracksHasTRD(); - values[kMultNTracksITSOnly] = event.multNTracksITSOnly(); - values[kMultNTracksTPCOnly] = event.multNTracksTPCOnly(); - values[kMultNTracksITSTPC] = event.multNTracksITSTPC(); - values[kMultNTracksPVeta1] = event.multNTracksPVeta1(); - values[kMultNTracksPVetaHalf] = event.multNTracksPVetaHalf(); - values[kMultAllTracksTPCOnly] = event.multAllTracksTPCOnly(); - values[kMultAllTracksITSTPC] = event.multAllTracksITSTPC(); - values[kTrackOccupancyInTimeRange] = event.trackOccupancyInTimeRange(); - values[kFT0COccupancyInTimeRange] = event.ft0cOccupancyInTimeRange(); - if constexpr ((fillMap & ReducedEventMultExtra) > 0) { - values[kNTPCcontribLongA] = event.nTPCoccupContribLongA(); - values[kNTPCcontribLongC] = event.nTPCoccupContribLongC(); - values[kNTPCcontribShortA] = event.nTPCoccupContribShortA(); - values[kNTPCcontribShortC] = event.nTPCoccupContribShortC(); - values[kNTPCmeanTimeLongA] = event.nTPCoccupMeanTimeLongA(); - values[kNTPCmeanTimeLongC] = event.nTPCoccupMeanTimeLongC(); - values[kNTPCmeanTimeShortA] = event.nTPCoccupMeanTimeShortA(); - values[kNTPCmeanTimeShortC] = event.nTPCoccupMedianTimeShortC(); - values[kNTPCmedianTimeLongA] = event.nTPCoccupMedianTimeLongA(); - values[kNTPCmedianTimeLongC] = event.nTPCoccupMedianTimeLongC(); - values[kNTPCmedianTimeShortA] = event.nTPCoccupMedianTimeShortA(); - values[kNTPCmedianTimeShortC] = event.nTPCoccupMedianTimeShortC(); - } - } - // TODO: need to add EvSels and Cents tables, etc. in case of the central data model - - if constexpr ((fillMap & ReducedEvent) > 0) { - values[kRunNo] = event.runNumber(); - values[kVtxX] = event.posX(); - values[kVtxY] = event.posY(); - values[kVtxZ] = event.posZ(); - values[kVtxNcontrib] = event.numContrib(); - if (fgUsedVars[kIsDoubleGap]) { - values[kIsDoubleGap] = (event.tag_bit(56 + kDoubleGap) > 0); - } - if (fgUsedVars[kIsSingleGap] || fgUsedVars[kIsSingleGapA] || fgUsedVars[kIsSingleGapC]) { - values[kIsSingleGapA] = (event.tag_bit(56 + kSingleGapA) > 0); - values[kIsSingleGapC] = (event.tag_bit(56 + kSingleGapC) > 0); - values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; - } - if (fgUsedVars[kIsITSUPCMode]) { - values[kIsITSUPCMode] = (event.tag_bit(56 + kITSUPCMode) > 0); - } - values[kCollisionTime] = event.collisionTime(); - values[kCollisionTimeRes] = event.collisionTimeRes(); - } - - if constexpr ((fillMap & ReducedEventExtended) > 0) { - values[kBC] = event.globalBC(); - values[kBCOrbit] = event.globalBC() % o2::constants::lhc::LHCMaxBunches; - values[kTimestamp] = event.timestamp(); - values[kTimeFromSOR] = (fgSOR > 0 ? (event.timestamp() - fgSOR) / 60000. : -1.0); - values[kCentVZERO] = event.centRun2V0M(); - values[kCentFT0C] = event.centFT0C(); - if (fgUsedVars[kIsNoITSROFBorderRecomputed]) { - uint16_t bcInITSROF = (event.globalBC() + 3564 - fgITSROFbias) % fgITSROFlength; - values[kIsNoITSROFBorderRecomputed] = bcInITSROF > fgITSROFBorderMarginLow && bcInITSROF < fgITSROFlength - fgITSROFBorderMarginHigh ? 1.0 : 0.0; - } - if (fgUsedVars[kIsNoITSROFBorder]) { - values[kIsNoITSROFBorder] = (event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder) > 0); - } - if (fgUsedVars[kIsNoTFBorder]) { - values[kIsNoTFBorder] = (event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) > 0); - } - if (fgUsedVars[kNoCollInTimeRangeStandard]) { - values[kNoCollInTimeRangeStandard] = (event.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard) > 0); - } - if (fgUsedVars[kIsNoSameBunch]) { - values[kIsNoSameBunch] = (event.selection_bit(o2::aod::evsel::kNoSameBunchPileup) > 0); - } - if (fgUsedVars[kIsGoodZvtxFT0vsPV]) { - values[kIsGoodZvtxFT0vsPV] = (event.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) > 0); - } - if (fgUsedVars[kIsVertexITSTPC]) { - values[kIsVertexITSTPC] = (event.selection_bit(o2::aod::evsel::kIsVertexITSTPC) > 0); - } - if (fgUsedVars[kIsVertexTOFmatched]) { - values[kIsVertexTOFmatched] = (event.selection_bit(o2::aod::evsel::kIsVertexTOFmatched) > 0); - } - if (fgUsedVars[kIsSel8]) { - values[kIsSel8] = event.selection_bit(o2::aod::evsel::kIsTriggerTVX) && event.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) && event.selection_bit(o2::aod::evsel::kNoITSROFrameBorder); - } - if (fgUsedVars[kIsGoodITSLayer3]) { - values[kIsGoodITSLayer3] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer3); - } - if (fgUsedVars[kIsGoodITSLayer0123]) { - values[kIsGoodITSLayer0123] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123); - } - if (fgUsedVars[kIsGoodITSLayersAll]) { - values[kIsGoodITSLayersAll] = event.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll); - } - if (fgUsedVars[kIsINT7]) { - values[kIsINT7] = (event.alias_bit(kINT7) > 0); - } - if (fgUsedVars[kIsEMC7]) { - values[kIsEMC7] = (event.alias_bit(kEMC7) > 0); - } - if (fgUsedVars[kIsINT7inMUON]) { - values[kIsINT7inMUON] = (event.alias_bit(kINT7inMUON) > 0); - } - if (fgUsedVars[kIsMuonSingleLowPt7]) { - values[kIsMuonSingleLowPt7] = (event.alias_bit(kMuonSingleLowPt7) > 0); - } - if (fgUsedVars[kIsMuonSingleHighPt7]) { - values[kIsMuonSingleHighPt7] = (event.alias_bit(kMuonSingleHighPt7) > 0); - } - if (fgUsedVars[kIsMuonUnlikeLowPt7]) { - values[kIsMuonUnlikeLowPt7] = (event.alias_bit(kMuonUnlikeLowPt7) > 0); - } - if (fgUsedVars[kIsMuonLikeLowPt7]) { - values[kIsMuonLikeLowPt7] = (event.alias_bit(kMuonLikeLowPt7) > 0); - } - if (fgUsedVars[kIsCUP8]) { - values[kIsCUP8] = (event.alias_bit(kCUP8) > 0); - } - if (fgUsedVars[kIsCUP9]) { - values[kIsCUP9] = (event.alias_bit(kCUP9) > 0); - } - if (fgUsedVars[kIsMUP10]) { - values[kIsMUP10] = (event.alias_bit(kMUP10) > 0); - } - if (fgUsedVars[kIsMUP11]) { - values[kIsMUP11] = (event.alias_bit(kMUP11) > 0); - } - } - - if constexpr ((fillMap & ReducedEventVtxCov) > 0) { - values[kVtxCovXX] = event.covXX(); - values[kVtxCovXY] = event.covXY(); - values[kVtxCovXZ] = event.covXZ(); - values[kVtxCovYY] = event.covYY(); - values[kVtxCovYZ] = event.covYZ(); - values[kVtxCovZZ] = event.covZZ(); - values[kVtxChi2] = event.chi2(); - } - - if constexpr ((fillMap & ReducedEventQvector) > 0) { - values[kQ1X0A] = event.q1x0a(); - values[kQ1Y0A] = event.q1y0a(); - values[kQ1X0B] = event.q1x0b(); - values[kQ1Y0B] = event.q1y0b(); - values[kQ1X0C] = event.q1x0c(); - values[kQ1Y0C] = event.q1y0c(); - values[kQ2X0A] = event.q2x0a(); - values[kQ2Y0A] = event.q2y0a(); - values[kQ2X0B] = event.q2x0b(); - values[kQ2Y0B] = event.q2y0b(); - values[kQ2X0C] = event.q2x0c(); - values[kQ2Y0C] = event.q2y0c(); - values[kMultA] = event.multa(); - values[kMultB] = event.multb(); - values[kMultC] = event.multc(); - values[kQ3X0A] = event.q3x0a(); - values[kQ3Y0A] = event.q3y0a(); - values[kQ3X0B] = event.q3x0b(); - values[kQ3Y0B] = event.q3y0b(); - values[kQ3X0C] = event.q3x0c(); - values[kQ3Y0C] = event.q3y0c(); - values[kQ4X0A] = event.q4x0a(); - values[kQ4Y0A] = event.q4y0a(); - values[kQ4X0B] = event.q4x0b(); - values[kQ4Y0B] = event.q4y0b(); - values[kQ4X0C] = event.q4x0c(); - values[kQ4Y0C] = event.q4y0c(); - - EventPlaneHelper epHelper; - float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); - float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); - float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); - - values[VarManager::kPsi2A] = Psi2A; - values[VarManager::kPsi2B] = Psi2B; - values[VarManager::kPsi2C] = Psi2C; - - if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { - values[kQ42XA] = event.q42xa(); - values[kQ42YA] = event.q42ya(); - values[kQ23XA] = event.q23xa(); - values[kQ23YA] = event.q23ya(); - values[kS11A] = event.s11a(); - values[kS12A] = event.s12a(); - values[kS13A] = event.s13a(); - values[kS31A] = event.s31a(); - } - - if constexpr ((fillMap & ReducedEventRefFlow) > 0) { - values[kMultA] = event.multa(); - values[kCORR2REFetagap] = event.corr2refetagap(); - values[kM11REFetagap] = event.m11refetagap(); - values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : event.corr2ref(); - values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : event.corr4ref(); - values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : event.corr2ref() * event.corr4ref(); - values[kM11REF] = !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? event.m11ref() : 0; - values[kM1111REF] = !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? event.m1111ref() : 0; - values[kM11M1111REF] = !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? event.m11ref() * event.m1111ref() : 0; - } - } - - if constexpr ((fillMap & CollisionQvect) > 0) { - values[kQ1X0A] = -999; - values[kQ1Y0A] = -999; - values[kQ1X0B] = -999; - values[kQ1Y0B] = -999; - values[kQ1X0C] = -999; - values[kQ1Y0C] = -999; - values[kQ2X0A] = (event.qvecBPosRe() * event.nTrkBPos() + event.qvecBNegRe() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); - values[kQ2Y0A] = (event.qvecBPosIm() * event.nTrkBPos() + event.qvecBNegIm() * event.nTrkBNeg()) / (event.nTrkBPos() + event.nTrkBNeg()); - values[kQ2X0APOS] = event.qvecBPosRe(); - values[kQ2Y0APOS] = event.qvecBPosIm(); - values[kQ2X0ANEG] = event.qvecBNegRe(); - values[kQ2Y0ANEG] = event.qvecBNegIm(); - values[kQ2X0B] = event.qvecFT0ARe(); - values[kQ2Y0B] = event.qvecFT0AIm(); - values[kQ2X0C] = event.qvecFT0CRe(); - values[kQ2Y0C] = event.qvecFT0CIm(); - values[kMultA] = event.nTrkBPos() + event.nTrkBNeg(); - values[kMultAPOS] = event.nTrkBPos(); - values[kMultANEG] = event.nTrkBNeg(); - values[kMultB] = event.sumAmplFT0A(); - values[kMultC] = event.sumAmplFT0C(); - values[kQ3X0A] = -999; - values[kQ3Y0A] = -999; - values[kQ3X0B] = -999; - values[kQ3Y0B] = -999; - values[kQ3X0C] = -999; - values[kQ3Y0C] = -999; - values[kQ4X0A] = -999; - values[kQ4Y0A] = -999; - values[kQ4X0B] = -999; - values[kQ4Y0B] = -999; - values[kQ4X0C] = -999; - values[kQ4Y0C] = -999; - - EventPlaneHelper epHelper; - float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); - float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); - float Psi2ANEG = epHelper.GetEventPlane(values[kQ2X0ANEG], values[kQ2Y0ANEG], 2); - float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); - float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); - - values[kPsi2A] = Psi2A; - values[kPsi2APOS] = Psi2APOS; - values[kPsi2ANEG] = Psi2ANEG; - values[kPsi2B] = Psi2B; - values[kPsi2C] = Psi2C; - - float R2SP_AB = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); - float R2SP_AC = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); - float R2SP_BC = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); - float R2SP_AB_Im = (values[kQ2Y0A] * values[kQ2X0B] - values[kQ2X0A] * values[kQ2Y0B]); - float R2SP_AC_Im = (values[kQ2Y0A] * values[kQ2X0C] - values[kQ2X0A] * values[kQ2Y0C]); - float R2SP_BC_Im = (values[kQ2Y0B] * values[kQ2X0C] - values[kQ2X0B] * values[kQ2Y0C]); - values[kR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : R2SP_AB; - values[kWR2SP_AB] = std::isnan(R2SP_AB) || std::isinf(R2SP_AB) ? 0. : 1.0; - values[kR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : R2SP_AC; - values[kWR2SP_AC] = std::isnan(R2SP_AC) || std::isinf(R2SP_AC) ? 0. : 1.0; - values[kR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : R2SP_BC; - values[kWR2SP_BC] = std::isnan(R2SP_BC) || std::isinf(R2SP_BC) ? 0. : 1.0; - values[kR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : R2SP_AB_Im; - values[kWR2SP_AB_Im] = std::isnan(R2SP_AB_Im) || std::isinf(R2SP_AB_Im) ? 0. : 1.0; - values[kR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : R2SP_AC_Im; - values[kWR2SP_AC_Im] = std::isnan(R2SP_AC_Im) || std::isinf(R2SP_AC_Im) ? 0. : 1.0; - values[kR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : R2SP_BC_Im; - values[kWR2SP_BC_Im] = std::isnan(R2SP_BC_Im) || std::isinf(R2SP_BC_Im) ? 0. : 1.0; - - float R2EP_AB = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Cos(2 * (Psi2A - Psi2B)); - float R2EP_AC = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2A - Psi2C)); - float R2EP_BC = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Cos(2 * (Psi2B - Psi2C)); - float R2EP_AB_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2B) || std::isinf(Psi2B) ? 0. : TMath::Sin(2 * (Psi2A - Psi2B)); - float R2EP_AC_Im = std::isnan(Psi2A) || std::isinf(Psi2A) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2A - Psi2C)); - float R2EP_BC_Im = std::isnan(Psi2B) || std::isinf(Psi2B) || std::isnan(Psi2C) || std::isinf(Psi2C) ? 0. : TMath::Sin(2 * (Psi2B - Psi2C)); - values[kR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : R2EP_AB; - values[kWR2EP_AB] = std::isnan(R2EP_AB) || std::isinf(R2EP_AB) ? 0. : 1.0; - values[kR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : R2EP_AC; - values[kWR2EP_AC] = std::isnan(R2EP_AC) || std::isinf(R2EP_AC) ? 0. : 1.0; - values[kR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : R2EP_BC; - values[kWR2EP_BC] = std::isnan(R2EP_BC) || std::isinf(R2EP_BC) ? 0. : 1.0; - values[kR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : R2EP_AB_Im; - values[kWR2EP_AB_Im] = std::isnan(R2EP_AB_Im) || std::isinf(R2EP_AB_Im) ? 0. : 1.0; - values[kR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : R2EP_AC_Im; - values[kWR2EP_AC_Im] = std::isnan(R2EP_AC_Im) || std::isinf(R2EP_AC_Im) ? 0. : 1.0; - values[kR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : R2EP_BC_Im; - values[kWR2EP_BC_Im] = std::isnan(R2EP_BC_Im) || std::isinf(R2EP_BC_Im) ? 0. : 1.0; - } - - if constexpr ((fillMap & CollisionMC) > 0) { - values[kMCEventGeneratorId] = event.generatorsID(); - values[kMCEventSubGeneratorId] = event.getSubGeneratorId(); - values[kMCVtxX] = event.posX(); - values[kMCVtxY] = event.posY(); - values[kMCVtxZ] = event.posZ(); - values[kMCEventTime] = event.t(); - values[kMCEventWeight] = event.weight(); - values[kMCEventImpParam] = event.impactParameter(); - if constexpr ((fillMap & CollisionCent) > 0) { - // WARNING: temporary solution, ongoing work to provide proper MC gen. centrality - values[kMCEventCentrFT0C] = event.bestCollisionCentFT0C(); - values[kMultMCNParticlesEta05] = event.multMCNParticlesEta05(); - values[kMultMCNParticlesEta08] = event.multMCNParticlesEta08(); - values[kMultMCNParticlesEta10] = event.multMCNParticlesEta10(); - } - } - - if constexpr ((fillMap & ReducedEventMC) > 0) { - values[kMCEventGeneratorId] = event.generatorsID(); - values[kMCEventGeneratorId] = -999; // to be added in reduced events - values[kMCVtxX] = event.mcPosX(); - values[kMCVtxY] = event.mcPosY(); - values[kMCVtxZ] = event.mcPosZ(); - values[kMCEventTime] = event.t(); - values[kMCEventWeight] = event.weight(); - values[kMCEventImpParam] = event.impactParameter(); - values[kMCEventCentrFT0C] = event.centFT0C(); - } - - if constexpr ((fillMap & EventFilter) > 0 || (fillMap & RapidityGapFilter) > 0) { - values[kIsDoubleGap] = (event.eventFilter() & (static_cast(1) << kDoubleGap)) > 0; - values[kIsSingleGapA] = (event.eventFilter() & (static_cast(1) << kSingleGapA)) > 0; - values[kIsSingleGapC] = (event.eventFilter() & (static_cast(1) << kSingleGapC)) > 0; - values[kIsSingleGap] = values[kIsSingleGapA] || values[kIsSingleGapC]; - values[kIsITSUPCMode] = (event.eventFilter() & (static_cast(1) << kITSUPCMode)) > 0; - } - - if constexpr ((fillMap & ReducedZdc) > 0) { - FillZDC(event, values); - } - - // FillEventDerived(values); -} - -template -void VarManager::FillEventTrackEstimators(TEvent const& collision, TAssoc const& assocs, TTracks const& /*tracks*/, float* values) -{ - // Compute median Z for the large dcaZ tracks in the TPC - // This is for studies of the pileup impact on the TPC - - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & Track) > 0 && (fillMap & TrackDCA) > 0) { - - std::vector tracksP; - std::vector tracksM; - - for (const auto& assoc : assocs) { - auto track = assoc.template track_as(); - // compute the dca of this track wrt the collision - auto trackPar = getTrackPar(track); - std::array dca{1e10f, 1e10f}; - trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); - - // if it is a displaced track longitudinally, add it to the track vector - if (abs(dca[0]) < 3.0 && abs(dca[1]) > 4.0) { - if (track.tgl() > 0.1) { - tracksP.push_back(track.z()); - } - if (track.tgl() < -0.1) { - tracksM.push_back(track.z()); - } - } - } // end loop over associations - - // compute the number of pileup contributors and the median z for pileup - if (tracksP.size() > 0) { - std::sort(tracksP.begin(), tracksP.end()); - auto midP = tracksP.size() / 2; - values[kNTPCpileupContribA] = tracksP.size(); - values[kNTPCpileupZA] = (tracksP.size() % 2 ? (tracksP[midP] + tracksP[midP - 1]) / 2 : tracksP[midP]); - } - - if (tracksM.size() > 0) { - std::sort(tracksM.begin(), tracksM.end()); - values[kNTPCpileupContribC] = tracksM.size(); - auto midM = tracksM.size() / 2; - values[kNTPCpileupZC] = (tracksM.size() % 2 ? (tracksM[midM] + tracksM[midM - 1]) / 2 : tracksM[midM]); - } - } -} - -template -void VarManager::FillEventFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) -{ - if (!values) { - values = fgValues; - } - - if (values[kCentFT0C] >= 0.) { - int idx_sp = hs_sp->FindBin(values[kCentFT0C]); - int idx_ep = hs_ep->FindBin(values[kCentFT0C]); - - values[kR2SP] = hs_sp->GetBinContent(idx_sp); - values[kR2EP] = hs_ep->GetBinContent(idx_ep); - } -} - -template -void VarManager::FillTwoMixEventsFlowResoFactor(T const& hs_sp, T const& hs_ep, float* values) -{ - if (!values) { - values = fgValues; - } - - if (values[kTwoEvCentFT0C1] >= 0.) { - int idx_sp1 = hs_sp->FindBin(values[kTwoEvCentFT0C1]); - int idx_ep1 = hs_ep->FindBin(values[kTwoEvCentFT0C1]); - - values[kTwoR2SP1] = hs_sp->GetBinContent(idx_sp1); - values[kTwoR2EP1] = hs_ep->GetBinContent(idx_ep1); - } - - if (values[kTwoEvCentFT0C2] >= 0.) { - int idx_sp2 = hs_sp->FindBin(values[kTwoEvCentFT0C2]); - int idx_ep2 = hs_ep->FindBin(values[kTwoEvCentFT0C2]); - - values[kTwoR2SP2] = hs_sp->GetBinContent(idx_sp2); - values[kTwoR2EP2] = hs_ep->GetBinContent(idx_ep2); - } -} - -template -void VarManager::FillTwoMixEventsCumulants(T const& h_v22ev1, T const& h_v24ev1, T const& h_v22ev2, T const& h_v24ev2, T1 const& t1, T2 const& t2, float* values) -{ - if (!values) { - values = fgValues; - } - - int idx_v22ev1; - int idx_v24ev1; - int idx_v22ev2; - int idx_v24ev2; - - if (values[kTwoEvCentFT0C1] >= 0.) { - if (t1.sign() < 0) { - - idx_v22ev1 = h_v22ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); - idx_v24ev1 = h_v24ev1->FindBin(values[kTwoEvCentFT0C1], t1.pt()); - values[kV22m] = h_v22ev1->GetBinContent(idx_v22ev1); - values[kV24m] = h_v24ev1->GetBinContent(idx_v24ev1); - - } else { - - idx_v22ev1 = h_v22ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); - idx_v24ev1 = h_v24ev2->FindBin(values[kTwoEvCentFT0C1], t1.pt()); - values[kV22m] = h_v22ev2->GetBinContent(idx_v22ev1); - values[kV24m] = h_v24ev2->GetBinContent(idx_v24ev1); - } - } - if (values[kTwoEvCentFT0C2] >= 0.) { - if (t2.sign() < 0) { - - idx_v22ev2 = h_v22ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); - idx_v24ev2 = h_v24ev1->FindBin(values[kTwoEvCentFT0C2], t2.pt()); - values[kV22p] = h_v22ev1->GetBinContent(idx_v22ev2); - values[kV24p] = h_v24ev1->GetBinContent(idx_v24ev2); - - } else { - - idx_v22ev2 = h_v22ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); - idx_v24ev2 = h_v24ev2->FindBin(values[kTwoEvCentFT0C2], t2.pt()); - values[kV22p] = h_v22ev2->GetBinContent(idx_v22ev2); - values[kV24p] = h_v24ev2->GetBinContent(idx_v24ev2); - } - } -} - -template -void VarManager::FillTwoEvents(T const& ev1, T const& ev2, float* values) -{ - if (!values) { - values = fgValues; - } - - values[kTwoEvPosZ1] = ev1.posZ(); - values[kTwoEvPosZ2] = ev2.posZ(); - values[kTwoEvPosR1] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); - values[kTwoEvPosR2] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); - values[kTwoEvPVcontrib1] = ev1.numContrib(); - values[kTwoEvPVcontrib2] = ev2.numContrib(); - if (ev1.numContrib() < ev2.numContrib()) { - values[kTwoEvPosZ1] = ev2.posZ(); - values[kTwoEvPosZ2] = ev1.posZ(); - values[kTwoEvPVcontrib1] = ev2.numContrib(); - values[kTwoEvPVcontrib2] = ev1.numContrib(); - values[kTwoEvPosR1] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); - ; - values[kTwoEvPosR2] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); - } - values[kTwoEvDeltaZ] = ev1.posZ() - ev2.posZ(); - values[kTwoEvDeltaX] = ev1.posX() - ev2.posX(); - values[kTwoEvDeltaY] = ev1.posY() - ev2.posY(); - values[kTwoEvDeltaR] = std::sqrt(values[kTwoEvDeltaX] * values[kTwoEvDeltaX] + values[kTwoEvDeltaY] * values[kTwoEvDeltaY]); -} - -template -void VarManager::FillTwoMixEvents(T1 const& ev1, T1 const& ev2, T2 const& /*tracks1*/, T2 const& /*tracks2*/, float* values) -{ - if (!values) { - values = fgValues; - } - values[kTwoEvPosZ1] = ev1.posZ(); - values[kTwoEvPosZ2] = ev2.posZ(); - values[kTwoEvPosR1] = std::sqrt(ev1.posX() * ev1.posX() + ev1.posY() * ev1.posY()); - values[kTwoEvPosR2] = std::sqrt(ev2.posX() * ev2.posX() + ev2.posY() * ev2.posY()); - values[kTwoEvPVcontrib1] = ev1.numContrib(); - values[kTwoEvPVcontrib2] = ev2.numContrib(); - /* - uint32_t Track1Filter = 0; - uint32_t Track2Filter = 0; - for (auto& track1 : tracks1) { Track1Filter = uint32_t(track1.isMuonSelected());} - for (auto& track2 : tracks2) { Track2Filter = uint32_t(track2.isMuonSelected());} - */ - if constexpr ((fillMap & CollisionCent) > 0 || (fillMap & ReducedEventExtended) > 0) { - values[kTwoEvCentFT0C1] = ev1.centFT0C(); - values[kTwoEvCentFT0C2] = ev2.centFT0C(); - } - if constexpr ((fillMap & ReducedEventQvector) > 0) { - // Tobe used for the calculation of u1q1 and u2q2 - values[kQ2X0A1] = ev1.q2x0a(); - values[kQ2X0A2] = ev2.q2x0a(); - values[kQ2Y0A1] = ev1.q2y0a(); - values[kQ2Y0A2] = ev2.q2y0a(); - } - if constexpr ((fillMap & CollisionQvect) > 0) { - // Tobe used for the calculation of u1q1 and u2q2 - values[kQ2X0A1] = (ev1.qvecBPosRe() * ev1.nTrkBPos() + ev1.qvecBNegRe() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); - values[kQ2X0A2] = (ev2.qvecBPosRe() * ev2.nTrkBPos() + ev2.qvecBNegRe() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); - values[kQ2Y0A1] = (ev1.qvecBPosIm() * ev1.nTrkBPos() + ev1.qvecBNegIm() * ev1.nTrkBNeg()) / (ev1.nTrkBPos() + ev1.nTrkBNeg()); - values[kQ2Y0A2] = (ev2.qvecBPosIm() * ev2.nTrkBPos() + ev2.qvecBNegIm() * ev2.nTrkBNeg()) / (ev2.nTrkBPos() + ev2.nTrkBNeg()); - } -} - -template -void VarManager::FillTrack(T const& track, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & TrackMFT) > 0) { - values[kPt] = track.pt(); - values[kEta] = track.eta(); - values[kPhi] = track.phi(); - values[kMftNClusters] = track.nClusters(); - - uint64_t mftClsAndFlgs = track.mftClusterSizesAndTrackFlags(); - double meanClusterSize = 0; - for (int i = 0; i < 10; ++i) { - double size = (mftClsAndFlgs >> (i * 6)) & 0x3fULL; - values[kMftClusterSize + i] = (mftClsAndFlgs >> (i * 6)) & 0x3fULL; - if (size > 0) { - meanClusterSize += size; - } - } - meanClusterSize /= track.nClusters(); - values[kMftMeanClusterSize] = meanClusterSize; - } - - // Quantities based on the basic table (contains just kine information and filter bits) - if constexpr ((fillMap & Track) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0 || (fillMap & ReducedTrack) > 0 || (fillMap & ReducedMuon) > 0) { - values[kPt] = track.pt(); - values[kSignedPt] = track.pt() * track.sign(); - if (fgUsedVars[kP]) { - values[kP] = track.p(); - } - if (fgUsedVars[kPx]) { - values[kPx] = track.px(); - } - if (fgUsedVars[kPy]) { - values[kPy] = track.py(); - } - if (fgUsedVars[kPz]) { - values[kPz] = track.pz(); - } - if (fgUsedVars[kInvPt]) { - values[kInvPt] = 1. / track.pt(); - } - values[kEta] = track.eta(); - values[kPhi] = track.phi(); - values[kCharge] = track.sign(); - if (fgUsedVars[kPhiTPCOuter]) { - values[kPhiTPCOuter] = track.phi() - (track.sign() > 0 ? 1.0 : -1.0) * (TMath::PiOver2() - TMath::ACos(0.22 * fgMagField / track.pt())); - if (values[kPhiTPCOuter] > TMath::TwoPi()) { - values[kPhiTPCOuter] -= TMath::TwoPi(); - } - if (values[kPhiTPCOuter] < 0.0) { - values[kPhiTPCOuter] += TMath::TwoPi(); - } - } - if (fgUsedVars[kTrackIsInsideTPCModule]) { - float localSectorPhi = values[kPhiTPCOuter] - TMath::Floor(18.0 * values[kPhiTPCOuter] / TMath::TwoPi()) * (TMath::TwoPi() / 18.0); - float edge = fgTPCInterSectorBoundary / 2.0 / 246.6; // minimal inter-sector boundary as angle - float curvature = 3.0 * 3.33 * track.pt() / fgMagField * (1.0 - TMath::Sin(TMath::ACos(0.22 * fgMagField / track.pt()))); - if (curvature / 2.466 > edge) { - edge = curvature / 2.466; - } - double min = edge; - double max = TMath::TwoPi() / 18.0 - edge; - values[kTrackIsInsideTPCModule] = (localSectorPhi > min && localSectorPhi < max ? 1.0 : 0.0); - } - - if constexpr ((fillMap & ReducedTrack) > 0 && !((fillMap & Pair) > 0)) { - // values[kIsGlobalTrack] = track.filteringFlags_bit(0); - // values[kIsGlobalTrackSDD] = track.filteringFlags_bit(1); - values[kIsAmbiguous] = track.isAmbiguous(); - - values[kIsLegFromGamma] = track.filteringFlags_bit(VarManager::kIsConversionLeg); - values[kIsLegFromK0S] = track.filteringFlags_bit(VarManager::kIsK0sLeg); - values[kIsLegFromLambda] = track.filteringFlags_bit(VarManager::kIsLambdaLeg); - values[kIsLegFromAntiLambda] = track.filteringFlags_bit(VarManager::kIsALambdaLeg); - values[kIsLegFromOmega] = track.filteringFlags_bit(VarManager::kIsOmegaLeg); - - values[kIsProtonFromLambdaAndAntiLambda] = static_cast((values[kIsLegFromLambda] * track.sign() > 0) || (values[kIsLegFromAntiLambda] * (-track.sign()) > 0)); - - for (int i = 0; i < 8; i++) { - values[kIsDalitzLeg + i] = track.filteringFlags_bit(VarManager::kDalitzBits + i); - } - } - - if (fgUsedVars[kM11REFoverMpsingle]) { - float m = o2::constants::physics::MassMuon; - ROOT::Math::PtEtaPhiMVector v(track.pt(), track.eta(), track.phi(), m); - complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); - complex Q42(values[kQ42XA], values[kQ42YA]); - complex Q23(values[kQ23XA], values[kQ23YA]); - complex P2(TMath::Cos(2 * v.Phi()), TMath::Sin(2 * v.Phi())); - values[kM11REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultSingleMuons] : 0; - values[kM1111REFoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultSingleMuons] : 0; - values[kCORR2REFbysinglemu] = std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; - values[kCORR4REFbysinglemu] = std::isnan(values[kM1111REFoverMpsingle]) || std::isinf(values[kM1111REFoverMpsingle]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpsingle]) || std::isinf(values[kM11REFoverMpsingle]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; - values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POI]; - values[kM01POIsingle] = values[kMultSingleMuons] * values[kS11A]; - values[kM0111POIsingle] = values[kMultSingleMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); - values[kCORR2POIsingle] = (P2 * conj(Q21)).real() / values[kM01POIsingle]; - values[kCORR4POIsingle] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIsingle]; - values[kM01POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM01POIsingle]; - values[kM0111POIsingle] = std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kM0111POIsingle]; - values[kCORR2POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR2POIsingle]; - values[kCORR4POIsingle] = std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) ? 0 : values[kCORR4POIsingle]; - values[kM01POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM01POIsingle] / values[kMultSingleMuons] : 0; - values[kM0111POIoverMpsingle] = values[kMultSingleMuons] > 0 && !(std::isnan(values[kM0111POIsingle]) || std::isinf(values[kM0111POIsingle]) || std::isnan(values[kCORR4POIsingle]) || std::isinf(values[kCORR4POIsingle]) || std::isnan(values[kM01POIsingle]) || std::isinf(values[kM01POIsingle]) || std::isnan(values[kCORR2POIsingle]) || std::isinf(values[kCORR2POIsingle])) ? values[kM0111POIsingle] / values[kMultSingleMuons] : 0; - } - } - - // Quantities based on the barrel tables - if constexpr ((fillMap & TrackExtra) > 0 || (fillMap & ReducedTrackBarrel) > 0) { - values[kPin] = track.tpcInnerParam(); - values[kSignedPin] = track.tpcInnerParam() * track.sign(); - if (fgUsedVars[kIsITSrefit]) { - values[kIsITSrefit] = (track.flags() & o2::aod::track::ITSrefit) > 0; // NOTE: This is just for Run-2 - } - if (fgUsedVars[kTrackTimeResIsRange]) { - values[kTrackTimeResIsRange] = (track.flags() & o2::aod::track::TrackTimeResIsRange) > 0; // NOTE: This is NOT for Run-2 - } - if (fgUsedVars[kIsTPCrefit]) { - values[kIsTPCrefit] = (track.flags() & o2::aod::track::TPCrefit) > 0; // NOTE: This is just for Run-2 - } - if (fgUsedVars[kPVContributor]) { - values[kPVContributor] = (track.flags() & o2::aod::track::PVContributor) > 0; // NOTE: This is NOT for Run-2 - } - if (fgUsedVars[kIsGoldenChi2]) { - values[kIsGoldenChi2] = (track.flags() & o2::aod::track::GoldenChi2) > 0; // NOTE: This is just for Run-2 - } - if (fgUsedVars[kOrphanTrack]) { - values[kOrphanTrack] = (track.flags() & o2::aod::track::OrphanTrack) > 0; // NOTE: This is NOT for Run-2 - } - if (fgUsedVars[kIsSPDfirst]) { - values[kIsSPDfirst] = (track.itsClusterMap() & uint8_t(1)) > 0; - } - if (fgUsedVars[kIsSPDboth]) { - values[kIsSPDboth] = (track.itsClusterMap() & uint8_t(3)) > 0; - } - if (fgUsedVars[kIsSPDany]) { - values[kIsSPDany] = (track.itsClusterMap() & uint8_t(1)) || (track.itsClusterMap() & uint8_t(2)); - } - if (fgUsedVars[kITSClusterMap]) { - values[kITSClusterMap] = track.itsClusterMap(); - } - - if (fgUsedVars[kIsITSibFirst]) { - values[kIsITSibFirst] = (track.itsClusterMap() & uint8_t(1)) > 0; - } - if (fgUsedVars[kIsITSibAny]) { - values[kIsITSibAny] = (track.itsClusterMap() & (1 << uint8_t(0))) > 0 || (track.itsClusterMap() & (1 << uint8_t(1))) > 0 || (track.itsClusterMap() & (1 << uint8_t(2))) > 0; - } - if (fgUsedVars[kIsITSibAll]) { - values[kIsITSibAll] = (track.itsClusterMap() & (1 << uint8_t(0))) > 0 && (track.itsClusterMap() & (1 << uint8_t(1))) > 0 && (track.itsClusterMap() & (1 << uint8_t(2))) > 0; - } - - values[kTrackTime] = track.trackTime(); - values[kTrackTimeRes] = track.trackTimeRes(); - values[kTrackTimeResRelative] = track.trackTimeRes() / track.trackTime(); - values[kTOFExpMom] = track.tofExpMom(); - values[kITSchi2] = track.itsChi2NCl(); - values[kTPCncls] = track.tpcNClsFound(); - values[kTPCchi2] = track.tpcChi2NCl(); - values[kTrackLength] = track.length(); - values[kTPCnclsCR] = track.tpcNClsCrossedRows(); - values[kTRDPattern] = track.trdPattern(); - - values[kTPCsignal] = track.tpcSignal(); - values[kTRDsignal] = track.trdSignal(); - - values[kDetectorMap] = track.detectorMap(); - values[kHasITS] = track.hasITS(); - values[kHasTRD] = track.hasTRD(); - values[kHasTOF] = track.hasTOF(); - values[kHasTPC] = track.hasTPC(); - - if constexpr ((fillMap & TrackExtra) > 0) { - if (fgUsedVars[kTPCnCRoverFindCls]) { - values[kTPCnCRoverFindCls] = track.tpcCrossedRowsOverFindableCls(); - } - if (fgUsedVars[kITSncls]) { - values[kITSncls] = track.itsNCls(); // dynamic column - } - if (fgUsedVars[kITSmeanClsSize]) { - values[kITSmeanClsSize] = 0.0; - uint32_t clsizeflag = track.itsClusterSizes(); - float mcls = 0.; - for (unsigned int layer = 0; layer < 7; layer++) { - mcls += (clsizeflag >> (layer * 4)) & 0xF; - } - if (track.itsNCls() > 0) { - values[kITSmeanClsSize] = mcls / track.itsNCls(); - } - } - } - if constexpr ((fillMap & ReducedTrackBarrel) > 0) { - if (fgUsedVars[kITSncls]) { - values[kITSncls] = 0.0; - for (int i = 0; i < 7; ++i) { - values[kITSncls] += ((track.itsClusterMap() & (1 << i)) ? 1 : 0); - } - } - values[kTrackDCAxy] = track.dcaXY(); - values[kTrackDCAz] = track.dcaZ(); - if constexpr ((fillMap & ReducedTrackBarrelCov) > 0) { - if (fgUsedVars[kTrackDCAsigXY]) { - values[kTrackDCAsigXY] = track.dcaXY() / std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAsigZ]) { - values[kTrackDCAsigZ] = track.dcaZ() / std::sqrt(track.cZZ()); - } - if (fgUsedVars[kTrackDCAresXY]) { - values[kTrackDCAresXY] = std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAresZ]) { - values[kTrackDCAresZ] = std::sqrt(track.cZZ()); - } - } - } - } - - // Quantities based on the barrel track selection table - if constexpr ((fillMap & TrackDCA) > 0) { - values[kTrackDCAxy] = track.dcaXY(); - values[kTrackDCAz] = track.dcaZ(); - if constexpr ((fillMap & TrackCov) > 0) { - if (fgUsedVars[kTrackDCAsigXY]) { - values[kTrackDCAsigXY] = track.dcaXY() / std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAsigZ]) { - values[kTrackDCAsigZ] = track.dcaZ() / std::sqrt(track.cZZ()); - } - if (fgUsedVars[kTrackDCAresXY]) { - values[kTrackDCAresXY] = std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAresZ]) { - values[kTrackDCAresZ] = std::sqrt(track.cZZ()); - } - } - } - - // Quantities based on the barrel track selection table - if constexpr ((fillMap & TrackSelection) > 0) { - values[kIsGlobalTrack] = track.isGlobalTrack(); - values[kIsGlobalTrackSDD] = track.isGlobalTrackSDD(); - } - - // Quantities based on the barrel covariance tables - if constexpr ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0) { - values[kTrackCYY] = track.cYY(); - values[kTrackCZZ] = track.cZZ(); - values[kTrackCSnpSnp] = track.cSnpSnp(); - values[kTrackCTglTgl] = track.cTglTgl(); - values[kTrackC1Pt21Pt2] = track.c1Pt21Pt2(); - } - - // Quantities based on the dalitz selections - if constexpr ((fillMap & DalitzBits) > 0) { - for (int i = 0; i < 8; i++) { - values[kIsDalitzLeg + i] = static_cast(track.dalitzBits() & (uint8_t(1) << i)); - } - } - - // Quantities based on the V0 selections - if constexpr ((fillMap & TrackV0Bits) > 0) { - values[kIsLegFromGamma] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsConversionLeg)); - values[kIsLegFromK0S] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsK0sLeg)); - values[kIsLegFromLambda] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsLambdaLeg)); - values[kIsLegFromAntiLambda] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsALambdaLeg)); - values[kIsLegFromOmega] = static_cast(track.pidbit() & (uint8_t(1) << VarManager::kIsOmegaLeg)); - values[kIsProtonFromLambdaAndAntiLambda] = static_cast((values[kIsLegFromLambda] * track.sign() > 0) || (values[kIsLegFromAntiLambda] * (-track.sign()) > 0)); - } - - // Quantities based on the barrel PID tables - if constexpr ((fillMap & TrackPID) > 0 || (fillMap & TrackTPCPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { - values[kTPCnSigmaEl] = track.tpcNSigmaEl(); - values[kTPCnSigmaPi] = track.tpcNSigmaPi(); - values[kTPCnSigmaKa] = track.tpcNSigmaKa(); - values[kTPCnSigmaPr] = track.tpcNSigmaPr(); - - bool isTPCCalibrated = false; - if constexpr ((fillMap & ReducedTrackBarrelPID) > 0) { - if (track.filteringFlags_bit(kIsTPCPostcalibrated)) { - isTPCCalibrated = true; - } - } - // compute TPC postcalibrated electron nsigma based on calibration histograms from CCDB - if (fgUsedVars[kTPCnSigmaEl_Corr] && fgRunTPCPostCalibration[0]) { - if (!isTPCCalibrated) { - values[kTPCnSigmaEl_Corr] = ComputePIDcalibration(0, values[kTPCnSigmaEl]); - } else { - LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; - values[kTPCnSigmaEl_Corr] = track.tpcNSigmaEl(); - } - } - - // compute TPC postcalibrated pion nsigma if required - if (fgUsedVars[kTPCnSigmaPi_Corr] && fgRunTPCPostCalibration[1]) { - if (!isTPCCalibrated) { - values[kTPCnSigmaPi_Corr] = ComputePIDcalibration(1, values[kTPCnSigmaPi]); - } else { - LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; - values[kTPCnSigmaPi_Corr] = track.tpcNSigmaPi(); - } - } - if (fgUsedVars[kTPCnSigmaKa_Corr] && fgRunTPCPostCalibration[2]) { - // compute TPC postcalibrated kaon nsigma if required - if (!isTPCCalibrated) { - values[kTPCnSigmaKa_Corr] = ComputePIDcalibration(2, values[kTPCnSigmaKa]); - } else { - LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; - values[kTPCnSigmaKa_Corr] = track.tpcNSigmaKa(); - } - } - // compute TPC postcalibrated proton nsigma if required - if (fgUsedVars[kTPCnSigmaPr_Corr] && fgRunTPCPostCalibration[3]) { - if (!isTPCCalibrated) { - values[kTPCnSigmaPr_Corr] = ComputePIDcalibration(3, values[kTPCnSigmaPr]); - } else { - LOG(fatal) << "TPC PID postcalibration is configured but the tracks are already postcalibrated. This is not allowed. Please check your configuration."; - values[kTPCnSigmaPr_Corr] = track.tpcNSigmaPr(); - } - } - - if constexpr ((fillMap & TrackPID) > 0 || (fillMap & ReducedTrackBarrelPID) > 0) { - values[kTOFnSigmaEl] = track.tofNSigmaEl(); - values[kTOFnSigmaPi] = track.tofNSigmaPi(); - values[kTOFnSigmaKa] = track.tofNSigmaKa(); - values[kTOFnSigmaPr] = track.tofNSigmaPr(); - } - - if constexpr ((fillMap & ReducedTrackBarrelPID) > 0) { - values[kTPCnSigmaMu] = track.tpcNSigmaMu(); - values[kTOFnSigmaMu] = track.tofNSigmaMu(); - values[kTPCsignal] = track.tpcSignal(); - values[kTRDsignal] = track.trdSignal(); - values[kTOFbeta] = track.beta(); - } - } - if constexpr ((fillMap & TrackTPCPID) > 0) { - values[kTPCnSigmaEl] = track.tpcNSigmaEl(); - values[kTPCnSigmaPi] = track.tpcNSigmaPi(); - values[kTPCnSigmaKa] = track.tpcNSigmaKa(); - values[kTPCnSigmaPr] = track.tpcNSigmaPr(); - } - if constexpr ((fillMap & TrackPIDExtra) > 0) { - values[kTPCnSigmaMu] = track.tpcNSigmaMu(); - values[kTOFnSigmaMu] = track.tofNSigmaMu(); - values[kTOFbeta] = track.beta(); - } - - // Quantities based on the muon extra table - if constexpr ((fillMap & ReducedMuonExtra) > 0 || (fillMap & Muon) > 0 || (fillMap & MuonRealign) > 0) { - values[kMuonNClusters] = track.nClusters(); - values[kMuonPDca] = track.pDca(); - values[kMCHBitMap] = track.mchBitMap(); - values[kMuonRAtAbsorberEnd] = track.rAtAbsorberEnd(); - values[kMuonChi2] = track.chi2(); - values[kMuonChi2MatchMCHMID] = track.chi2MatchMCHMID(); - values[kMuonChi2MatchMCHMFT] = track.chi2MatchMCHMFT(); - values[kMuonMatchScoreMCHMFT] = track.matchScoreMCHMFT(); - values[kMuonTrackType] = track.trackType(); - values[kMuonDCAx] = track.fwdDcaX(); - values[kMuonDCAy] = track.fwdDcaY(); - values[kMuonTime] = track.trackTime(); - values[kMuonTimeRes] = track.trackTimeRes(); - } - // Quantities based on the muon covariance table - if constexpr ((fillMap & ReducedMuonCov) > 0 || (fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { - values[kX] = track.x(); - values[kY] = track.y(); - values[kZ] = track.z(); - values[kTgl] = track.tgl(); - values[kMuonCXX] = track.cXX(); - values[kMuonCXY] = track.cXY(); - values[kMuonCYY] = track.cYY(); - values[kMuonCPhiX] = track.cPhiX(); - values[kMuonCPhiY] = track.cPhiY(); - values[kMuonCPhiPhi] = track.cPhiPhi(); - values[kMuonCTglX] = track.cTglX(); - values[kMuonCTglY] = track.cTglY(); - values[kMuonCTglPhi] = track.cTglPhi(); - values[kMuonCTglTgl] = track.cTglTgl(); - values[kMuonC1Pt2X] = track.c1PtX(); - values[kMuonC1Pt2Y] = track.c1PtY(); - values[kMuonC1Pt2Phi] = track.c1PtPhi(); - values[kMuonC1Pt2Tgl] = track.c1PtTgl(); - values[kMuonC1Pt21Pt2] = track.c1Pt21Pt2(); - } - - // Quantities based on the pair table(s) - if constexpr ((fillMap & Pair) > 0) { - values[kMass] = track.mass(); - ROOT::Math::PtEtaPhiMVector vpair(track.pt(), track.eta(), track.phi(), track.mass()); - values[kRap] = vpair.Rapidity(); - } - - // Derived quantities which can be computed based on already filled variables - FillTrackDerived(values); -} - -template -void VarManager::FillTrackCollision(T const& track, C const& collision, float* values) -{ - - if (!values) { - values = fgValues; - } - if constexpr ((fillMap & ReducedTrackBarrel) > 0 || (fillMap & TrackDCA) > 0) { - auto trackPar = getTrackPar(track); - std::array dca{1e10f, 1e10f}; - trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); - - values[kTrackDCAxy] = dca[0]; - values[kTrackDCAz] = dca[1]; - - if constexpr ((fillMap & ReducedTrackBarrelCov) > 0 || (fillMap & TrackCov) > 0) { - if (fgUsedVars[kTrackDCAsigXY]) { - values[kTrackDCAsigXY] = dca[0] / std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAsigZ]) { - values[kTrackDCAsigZ] = dca[1] / std::sqrt(track.cZZ()); - } - } - } - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0 || (fillMap & ReducedMuonCov) > 0) { - - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); - - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - values[kMuonPDca] = track.p() * dcaXY; - } -} - -template -void VarManager::FillTrackCollisionMatCorr(T const& track, C const& collision, M const& materialCorr, P const& propagator, float* values) -{ - if (!values) { - values = fgValues; - } - if constexpr ((fillMap & ReducedTrackBarrel) > 0 || (fillMap & TrackDCA) > 0) { - auto trackPar = getTrackPar(track); - std::array dca{1e10f, 1e10f}; - std::array pVec = {track.px(), track.py(), track.pz()}; - // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); - propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, materialCorr, &dca); - getPxPyPz(trackPar, pVec); - - values[kTrackDCAxy] = dca[0]; - values[kTrackDCAz] = dca[1]; - - if constexpr ((fillMap & ReducedTrackBarrelCov) > 0 || (fillMap & TrackCov) > 0) { - if (fgUsedVars[kTrackDCAsigXY]) { - values[kTrackDCAsigXY] = dca[0] / std::sqrt(track.cYY()); - } - if (fgUsedVars[kTrackDCAsigZ]) { - values[kTrackDCAsigZ] = dca[1] / std::sqrt(track.cZZ()); - } - } - } -} - -template -void VarManager::FillPhoton(T const& track, float* values) -{ - if (!values) { - values = fgValues; - } - - // Quantities based on the basic table (contains just kine information and filter bits) - if constexpr ((fillMap & Track) > 0 || (fillMap & ReducedTrack) > 0) { - values[kPt] = track.pt(); - if (fgUsedVars[kP]) { - values[kP] = track.p(); - } - if (fgUsedVars[kPx]) { - values[kPx] = track.px(); - } - if (fgUsedVars[kPy]) { - values[kPy] = track.py(); - } - if (fgUsedVars[kPz]) { - values[kPz] = track.pz(); - } - if (fgUsedVars[kInvPt]) { - values[kInvPt] = 1. / track.pt(); - } - values[kEta] = track.eta(); - values[kPhi] = track.phi(); - values[kRap] = track.eta(); // photon does not know rapidity .y() - values[kMassDau] = track.mGamma(); - } -} - -template -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(); - values[kMCPx] = track.px(); - values[kMCPy] = track.py(); - values[kMCPz] = track.pz(); - values[kMCE] = track.e(); - values[kMCVx] = track.vx(); - values[kMCVy] = track.vy(); - values[kMCVz] = track.vz(); - values[kMCPt] = track.pt(); - values[kMCPhi] = track.phi(); - values[kMCEta] = track.eta(); - values[kMCY] = -track.y(); - values[kMCParticleGeneratorId] = track.producedByGenerator(); - if (fgUsedVars[kMCMotherPdgCode]) { - if (track.has_mothers()) { - auto motherId = track.mothersIds()[0]; - auto mother = mcStack.rawIteratorAt(motherId); - values[kMCMotherPdgCode] = mother.pdgCode(); - } - } - - FillTrackDerived(values); -} - -template -void VarManager::FillEnergyCorrelatorsMC(T const& track, T1 const& t1, float* values) -{ - // energy correlators - float MassHadron; - if constexpr (pairType == kJpsiHadronMass) { - MassHadron = TMath::Sqrt(t1.e() * t1.e() - t1.p() * t1.p()); - } - if constexpr (pairType == kJpsiPionMass) { - MassHadron = o2::constants::physics::MassPionCharged; - } - ROOT::Math::PtEtaPhiMVector v1(track.pt(), track.eta(), track.phi(), o2::constants::physics::MassJPsi); - 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); - 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; - values[kMCdeltaeta] = deltaeta; - values[kMCHadronPt] = t1.pt(); - values[kMCHadronEta] = t1.eta(); - values[kMCHadronPhi] = RecoDecay::constrainAngle(t1.phi(), -o2::constants::math::PIHalf); - values[kMCHadronPdgCode] = t1.pdgCode(); - values[kMCWeight] = E_boost / o2::constants::physics::MassJPsi; - - values[kMCCosChi_randomPhi_trans] = -999.9f; - values[kMCCosChi_randomPhi_toward] = -999.9f; - values[kMCCosChi_randomPhi_away] = -999.9f; - - values[kMCdeltaphi_randomPhi_trans] = -999.9f; - values[kMCdeltaphi_randomPhi_toward] = -999.9f; - values[kMCdeltaphi_randomPhi_away] = -999.9f; - - float randomPhi_trans = -o2::constants::math::PIHalf; - float randomPhi_toward = -o2::constants::math::PIHalf; - float randomPhi_away = -o2::constants::math::PIHalf; - - if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { - randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); - values[kMCWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); - values[kMCWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); - values[kMCCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); - values[kMCWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); - - values[kMCdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); - values[kMCdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); - values[kMCdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); - } -} - -template -void VarManager::FillPairPropagateMuon(T1 const& muon1, T2 const& muon2, const C& collision, float* values) -{ - if (!values) { - values = fgValues; - } - o2::dataformats::GlobalFwdTrack propmuon1 = PropagateMuon(muon1, collision); - o2::dataformats::GlobalFwdTrack propmuon2 = PropagateMuon(muon2, collision); - - float m = o2::constants::physics::MassMuon; - - ROOT::Math::PtEtaPhiMVector v1(propmuon1.getPt(), propmuon1.getEta(), propmuon1.getPhi(), m); - ROOT::Math::PtEtaPhiMVector v2(propmuon2.getPt(), propmuon2.getEta(), propmuon2.getPhi(), m); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); - values[kRap] = -v12.Rapidity(); - - double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); - double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); - values[kDeltaPtotTracks] = Ptot1 - Ptot2; -} - -template -void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) -{ - if (!values) { - values = fgValues; - } - - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if constexpr (pairType == kDecayToMuMu) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - - if constexpr (pairType == kDecayToPiPi) { - m1 = o2::constants::physics::MassPionCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if constexpr (pairType == kDecayToKPi) { - m1 = o2::constants::physics::MassKaonCharged; - m2 = o2::constants::physics::MassPionCharged; - // Make the TPC information of the kaon available for pair histograms - values[kPin_leg1] = t1.tpcInnerParam(); - values[kTPCnSigmaKa_leg1] = t1.tpcNSigmaKa(); - } - - if constexpr (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - - values[kCharge] = t1.sign() + t2.sign(); - values[kCharge1] = t1.sign(); - values[kCharge2] = t2.sign(); - 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; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - // values[kPhi] = v12.Phi(); - values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; - values[kRap] = -v12.Rapidity(); - double Ptot1 = TMath::Sqrt(v1.Px() * v1.Px() + v1.Py() * v1.Py() + v1.Pz() * v1.Pz()); - double Ptot2 = TMath::Sqrt(v2.Px() * v2.Px() + v2.Py() * v2.Py() + v2.Pz() * v2.Pz()); - values[kDeltaPtotTracks] = Ptot1 - Ptot2; - - values[kPt1] = t1.pt(); - values[kEta1] = t1.eta(); - values[kPhi1] = t1.phi(); - values[kPt2] = t2.pt(); - values[kEta2] = t2.eta(); - values[kPhi2] = t2.phi(); - - if (fgUsedVars[kDeltaPhiPair2]) { - double phipair2 = v1.Phi() - v2.Phi(); - if (phipair2 > 3 * TMath::Pi() / 2) { - values[kDeltaPhiPair2] = phipair2 - 2 * TMath::Pi(); - } else if (phipair2 < -TMath::Pi() / 2) { - values[kDeltaPhiPair2] = phipair2 + 2 * TMath::Pi(); - } else { - values[kDeltaPhiPair2] = phipair2; - } - } - - if (fgUsedVars[kDeltaEtaPair2]) { - values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); - } - - if (fgUsedVars[kPsiPair]) { - values[kDeltaPhiPair] = (t1.sign() * fgMagField > 0.) ? (v1.Phi() - v2.Phi()) : (v2.Phi() - v1.Phi()); - double xipair = TMath::ACos((v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz()) / v1.P() / v2.P()); - values[kPsiPair] = (t1.sign() * fgMagField > 0.) ? TMath::ASin((v1.Theta() - v2.Theta()) / xipair) : TMath::ASin((v2.Theta() - v1.Theta()) / xipair); - } - - if (fgUsedVars[kOpeningAngle]) { - double scalar = v1.Px() * v2.Px() + v1.Py() * v2.Py() + v1.Pz() * v2.Pz(); - double Ptot12 = Ptot1 * Ptot2; - if (Ptot12 <= 0) { - values[kOpeningAngle] = 0.; - } else { - double arg = scalar / Ptot12; - if (arg > 1.) - arg = 1.; - if (arg < -1) - arg = -1; - values[kOpeningAngle] = TMath::ACos(arg); - } - } - - // polarization parameters - bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame - bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame - bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame - bool useRM = fgUsedVars[kCosThetaRM]; // Random frame - - if (useHE || useCS || usePP || useRM) { - ROOT::Math::Boost boostv12{v12.BoostToCM()}; - ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; - ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; - - // using positive sign convention for the first track - ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); - - if (useHE) { - ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; - ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; - if (fgUsedVars[kCosThetaHE]) - values[kCosThetaHE] = zaxis_HE.Dot(v_CM); - if (fgUsedVars[kPhiHE]) { - values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); - if (values[kPhiHE] < 0) { - values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildeHE]) { - if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { - if (values[kCosThetaHE] > 0) { - values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildeHE] < 0) { - values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildeHE] < 0) { - values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildeHE] = -999; // not computable - } - } - } - - if (useCS) { - ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; - ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; - if (fgUsedVars[kCosThetaCS]) - values[kCosThetaCS] = zaxis_CS.Dot(v_CM); - if (fgUsedVars[kPhiCS]) { - values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); - if (values[kPhiCS] < 0) { - values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildeCS]) { - if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { - if (values[kCosThetaCS] > 0) { - values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildeCS] < 0) { - values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildeCS] < 0) { - values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildeCS] = -999; // not computable - } - } - } - - if (usePP) { - ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); - ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; - ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; - if (fgUsedVars[kCosThetaPP]) { - values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); - } - if (fgUsedVars[kPhiPP]) { - values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); - if (values[kPhiPP] < 0) { - values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildePP]) { - if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { - if (values[kCosThetaPP] > 0) { - values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildePP] < 0) { - values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildePP] < 0) { - values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildePP] = -999; // not computable - } - } - } - - if (useRM) { - double randomCostheta = gRandom->Uniform(-1., 1.); - double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); - ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); - if (fgUsedVars[kCosThetaRM]) - values[kCosThetaRM] = zaxis_RM.Dot(v_CM); - } - } - - if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { - - if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { - // Quantities based on the barrel tables - double dca1XY = t1.dcaXY(); - double dca2XY = t2.dcaXY(); - double dca1Z = t1.dcaZ(); - double dca2Z = t2.dcaZ(); - double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); - double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); - double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); - double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); - - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); - values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); - values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); - values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - - double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); - double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); - if ((det1 < 0) || (det2 < 0)) { - values[kQuadDCAsigXYZ] = -999; - } else { - double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; - double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; - - double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); - double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); - - values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); - } - } - } - if constexpr ((pairType == kDecayToMuMu) && ((fillMap & Muon) > 0 || (fillMap & ReducedMuon) > 0)) { - if (fgUsedVars[kQuadDCAabsXY]) { - double dca1X = t1.fwdDcaX(); - double dca1Y = t1.fwdDcaY(); - double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); - double dca2X = t2.fwdDcaX(); - double dca2Y = t2.fwdDcaY(); - double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); - } - } - if (fgUsedVars[kPairPhiv]) { - values[kPairPhiv] = calculatePhiV(t1, t2); - } -} - -template -void VarManager::FillPairCollision(const C& collision, T1 const& t1, T2 const& t2, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { - - if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { - - auto trackPart1 = getTrackPar(t1); - std::array dca1{1e10f, 1e10f}; - trackPart1.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca1); - - auto trackPart2 = getTrackPar(t2); - std::array dca2{1e10f, 1e10f}; - trackPart2.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca2); - - // Recalculated quantities - double dca1XY = dca1[0]; - double dca2XY = dca2[0]; - double dca1Z = dca1[1]; - double dca2Z = dca2[1]; - double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); - double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); - double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); - double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); - - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); - values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); - values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); - values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - - double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); - double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); - if ((det1 < 0) || (det2 < 0)) { - values[kQuadDCAsigXYZ] = -999; - } else { - double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; - double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; - - double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); - double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); - - values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); - } - } - } -} - -template -void VarManager::FillPairCollisionMatCorr(C const& collision, T1 const& t1, T2 const& t2, M const& materialCorr, P const& propagator, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((pairType == kDecayToEE) && ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0)) { - - if (fgUsedVars[kQuadDCAabsXY] || fgUsedVars[kQuadDCAsigXY] || fgUsedVars[kQuadDCAabsZ] || fgUsedVars[kQuadDCAsigZ] || fgUsedVars[kQuadDCAsigXYZ] || fgUsedVars[kSignQuadDCAsigXY]) { - - auto trackPart1 = getTrackPar(t1); - std::array dca1{1e10f, 1e10f}; - std::array pVect1 = {t1.px(), t1.py(), t1.pz()}; - // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); - propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart1, 2.f, materialCorr, &dca1); - getPxPyPz(trackPart1, pVect1); - - auto trackPart2 = getTrackPar(t2); - std::array dca2{1e10f, 1e10f}; - std::array pVect2 = {t2.px(), t2.py(), t2.pz()}; - // trackPar.propagateParamToDCA({collision.posX(), collision.posY(), collision.posZ()}, fgMagField, &dca); - propagator->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPart2, 2.f, materialCorr, &dca2); - getPxPyPz(trackPart2, pVect2); - - // Recalculated quantities - double dca1XY = dca1[0]; - double dca2XY = dca2[0]; - double dca1Z = dca1[1]; - double dca2Z = dca2[1]; - double dca1sigXY = dca1XY / std::sqrt(t1.cYY()); - double dca2sigXY = dca2XY / std::sqrt(t2.cYY()); - double dca1sigZ = dca1Z / std::sqrt(t1.cZZ()); - double dca2sigZ = dca2Z / std::sqrt(t2.cZZ()); - - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2); - values[kQuadDCAsigXY] = std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - values[kQuadDCAabsZ] = std::sqrt((dca1Z * dca1Z + dca2Z * dca2Z) / 2); - values[kQuadDCAsigZ] = std::sqrt((dca1sigZ * dca1sigZ + dca2sigZ * dca2sigZ) / 2); - values[kSignQuadDCAsigXY] = t1.sign() * t2.sign() * TMath::Sign(1., dca1sigXY) * TMath::Sign(1., dca2sigXY) * std::sqrt((dca1sigXY * dca1sigXY + dca2sigXY * dca2sigXY) / 2); - - double det1 = t1.cYY() * t1.cZZ() - t1.cZY() * t1.cZY(); - double det2 = t2.cYY() * t2.cZZ() - t2.cZY() * t2.cZY(); - if ((det1 < 0) || (det2 < 0)) { - values[kQuadDCAsigXYZ] = -999; - } else { - double chi2t1 = (dca1XY * dca1XY * t1.cZZ() + dca1Z * dca1Z * t1.cYY() - 2. * dca1XY * dca1Z * t1.cZY()) / det1; - double chi2t2 = (dca2XY * dca2XY * t2.cZZ() + dca2Z * dca2Z * t2.cYY() - 2. * dca2XY * dca2Z * t2.cZY()) / det2; - - double dca1sigXYZ = std::sqrt(std::abs(chi2t1) / 2.); - double dca2sigXYZ = std::sqrt(std::abs(chi2t2) / 2.); - - values[kQuadDCAsigXYZ] = std::sqrt((dca1sigXYZ * dca1sigXYZ + dca2sigXYZ * dca2sigXYZ) / 2); - } - } - } -} - -template -void VarManager::FillTriple(T1 const& t1, T2 const& t2, T3 const& t3, float* values, PairCandidateType pairType) -{ - - if (!values) { - values = fgValues; - } - if (pairType == kTripleCandidateToEEPhoton) { - float m1 = o2::constants::physics::MassElectron; - float m3 = o2::constants::physics::MassPhoton; - 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(), m1); - ROOT::Math::PtEtaPhiMVector v3(t3.pt(), t3.eta(), t3.phi(), m3); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - ROOT::Math::PtEtaPhiMVector v123 = v12 + v3; - values[kPairMass] = v123.M(); - values[kPairPt] = v123.Pt(); - values[kPairEta] = v123.Eta(); - values[kPairPhi] = v123.Phi(); - values[kPairMassDau] = v12.M(); - values[kMassDau] = m3; - values[kPairPtDau] = v12.Pt(); - values[kPt] = t3.pt(); - values[kEta] = t3.eta(); - values[kEta1] = t1.eta(); - values[kEta2] = t2.eta(); - values[kDeltaEta] = v12.Eta(); - values[VarManager::kDeltaMass] = v123.M() - v12.M(); - values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; - values[kRap] = v123.Rapidity(); - values[kPt1] = t1.pt(); - values[kPt2] = t2.pt(); - } - - if (pairType == kTripleCandidateToKPiPi) { - float m1 = o2::constants::physics::MassKaonCharged; - float m2 = o2::constants::physics::MassPionCharged; - - 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 v3(t3.pt(), t3.eta(), t3.phi(), m2); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - values[kMass] = v123.M(); - values[kPt] = v123.Pt(); - values[kEta] = v123.Eta(); - values[kPhi] = v123.Phi(); - values[kRap] = -v123.Rapidity(); - values[kCharge] = t1.sign() + t2.sign() + t3.sign(); - values[kS12] = (v1 + v2).M2(); - values[kS13] = (v1 + v3).M2(); - values[kS23] = (v2 + v3).M2(); - } - - if (pairType == kTripleCandidateToPKPi) { - float m1 = o2::constants::physics::MassProton; - float m2 = o2::constants::physics::MassKaonCharged; - float m3 = o2::constants::physics::MassPionCharged; - - 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 v3(t3.pt(), t3.eta(), t3.phi(), m3); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - values[kMass] = v123.M(); - values[kPt] = v123.Pt(); - values[kEta] = v123.Eta(); - values[kPhi] = v123.Phi(); - values[kRap] = -v123.Rapidity(); - } -} - -template -void VarManager::FillPairME(T1 const& t1, T2 const& t2, float* values) -{ - // - // Lightweight fill function called from the innermost event mixing loop - // - if (!values) { - values = fgValues; - } - - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if constexpr (pairType == kDecayToMuMu) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - - if constexpr (pairType == kDecayToPiPi) { - m1 = o2::constants::physics::MassPionCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if constexpr (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - - 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; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - // values[kPhi] = v12.Phi(); - values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; - values[kRap] = -v12.Rapidity(); - - if (fgUsedVars[kDeltaPhiPair2]) { - double phipair2ME = v1.Phi() - v2.Phi(); - if (phipair2ME > 3 * TMath::Pi() / 2) { - values[kDeltaPhiPair2] = phipair2ME - 2 * TMath::Pi(); - } else if (phipair2ME < -TMath::Pi() / 2) { - values[kDeltaPhiPair2] = phipair2ME + 2 * TMath::Pi(); - } else { - values[kDeltaPhiPair2] = phipair2ME; - } - } - - if (fgUsedVars[kDeltaEtaPair2]) { - values[kDeltaEtaPair2] = v1.Eta() - v2.Eta(); - } - - // polarization parameters - bool useHE = fgUsedVars[kCosThetaHE] || fgUsedVars[kPhiHE]; // helicity frame - bool useCS = fgUsedVars[kCosThetaCS] || fgUsedVars[kPhiCS]; // Collins-Soper frame - bool usePP = fgUsedVars[kCosThetaPP]; // production plane frame - bool useRM = fgUsedVars[kCosThetaRM]; // Random frame - - if (useHE || useCS || usePP || useRM) { - ROOT::Math::Boost boostv12{v12.BoostToCM()}; - ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; - ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; - - // using positive sign convention for the first track - ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); - - if (useHE) { - ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; - ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; - if (fgUsedVars[kCosThetaHE]) - values[kCosThetaHE] = zaxis_HE.Dot(v_CM); - if (fgUsedVars[kPhiHE]) { - values[kPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); - if (values[kPhiHE] < 0) { - values[kPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildeHE]) { - if (fgUsedVars[kCosThetaHE] && fgUsedVars[kPhiHE]) { - if (values[kCosThetaHE] > 0) { - values[kPhiTildeHE] = values[kPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildeHE] < 0) { - values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildeHE] = values[kPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildeHE] < 0) { - values[kPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildeHE] = -999; // not computable - } - } - } - - if (useCS) { - ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; - ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; - if (fgUsedVars[kCosThetaCS]) - values[kCosThetaCS] = zaxis_CS.Dot(v_CM); - if (fgUsedVars[kPhiCS]) { - values[kPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); - if (values[kPhiCS] < 0) { - values[kPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildeCS]) { - if (fgUsedVars[kCosThetaCS] && fgUsedVars[kPhiCS]) { - if (values[kCosThetaCS] > 0) { - values[kPhiTildeCS] = values[kPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildeCS] < 0) { - values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildeCS] = values[kPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildeCS] < 0) { - values[kPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildeCS] = -999; // not computable - } - } - } - - if (usePP) { - ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); - ROOT::Math::XYZVector yaxis_PP{(v12.Vect()).Unit()}; - ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; - if (fgUsedVars[kCosThetaPP]) { - values[kCosThetaPP] = zaxis_PP.Dot(v_CM) / std::sqrt(zaxis_PP.Mag2()); - } - if (fgUsedVars[kPhiPP]) { - values[kPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); - if (values[kPhiPP] < 0) { - values[kPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kPhiTildePP]) { - if (fgUsedVars[kCosThetaPP] && fgUsedVars[kPhiPP]) { - if (values[kCosThetaPP] > 0) { - values[kPhiTildePP] = values[kPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kPhiTildePP] < 0) { - values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kPhiTildePP] = values[kPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kPhiTildePP] < 0) { - values[kPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kPhiTildePP] = -999; // not computable - } - } - } - - if (useRM) { - double randomCostheta = gRandom->Uniform(-1., 1.); - double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); - ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); - if (fgUsedVars[kCosThetaRM]) - values[kCosThetaRM] = zaxis_RM.Dot(v_CM); - } - } - - if constexpr ((fillMap & ReducedEventQvector) > 0 || (fillMap & CollisionQvect) > 0) { - // TODO: provide different computations for vn - // Compute the scalar product UQ for two muon from different event using Q-vector from A, for second and third harmonic - float Psi2A1 = getEventPlane(2, values[kQ2X0A1], values[kQ2Y0A1]); - float Psi2A2 = getEventPlane(2, values[kQ2X0A2], values[kQ2Y0A2]); - values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A1)); // WARNING: using the first event EP - values[kCos2DeltaPhiEv1] = TMath::Cos(2 * (v1.Phi() - Psi2A1)); - values[kCos2DeltaPhiEv2] = TMath::Cos(2 * (v2.Phi() - Psi2A2)); - values[kU2Q2] = values[kQ2X0A1] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v12.Phi()); // WARNING: using the first event EP - values[kU2Q2Ev1] = values[kQ2X0A1] * TMath::Cos(2 * v1.Phi()) + values[kQ2Y0A1] * TMath::Sin(2 * v1.Phi()); - values[kU2Q2Ev2] = values[kQ2X0A2] * TMath::Cos(2 * v2.Phi()) + values[kQ2Y0A2] * TMath::Sin(2 * v2.Phi()); - - values[kCos2DeltaPhiMu1] = TMath::Cos(2 * (v1.Phi() - v12.Phi())); - values[kCos2DeltaPhiMu2] = TMath::Cos(2 * (v2.Phi() - v12.Phi())); - - values[kV2SP1] = values[kU2Q2Ev1] / values[kTwoR2SP1]; - values[kV2SP2] = values[kU2Q2Ev2] / values[kTwoR2SP2]; - values[kV2EP1] = values[kCos2DeltaPhiEv1] / values[kTwoR2EP1]; - values[kV2EP2] = values[kCos2DeltaPhiEv2] / values[kTwoR2EP2]; - - float V2ME_SP = values[kV2SP1] * values[kCos2DeltaPhiMu1] + values[kV2SP2] * values[kCos2DeltaPhiMu2]; - float V2ME_EP = values[kV2EP1] * values[kCos2DeltaPhiMu1] + values[kV2EP2] * values[kCos2DeltaPhiMu2]; - values[kV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : V2ME_SP; - values[kWV2ME_SP] = std::isnan(V2ME_SP) || std::isinf(V2ME_SP) ? 0. : 1.0; - values[kV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : V2ME_EP; - values[kWV2ME_EP] = std::isnan(V2ME_EP) || std::isinf(V2ME_EP) ? 0. : 1.0; - - // Cumulant part - float V22ME = values[kV22m] * values[kCos2DeltaPhiMu1] + values[kV22p] * values[kCos2DeltaPhiMu2]; - float V24ME = values[kV24m] * values[kCos2DeltaPhiMu1] + values[kV24p] * values[kCos2DeltaPhiMu2]; - values[kV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V22ME; - values[kWV22ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; - values[kV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : V24ME; - values[kWV24ME] = (std::isnan(V22ME) || std::isinf(V22ME) || std::isnan(V24ME) || std::isinf(V24ME)) ? 0. : 1.0; - - if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { - complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); - complex Q42(values[kQ42XA], values[kQ42YA]); - complex Q23(values[kQ23XA], values[kQ23YA]); - complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); - values[kM01POIME] = values[kMultDimuonsME] * values[kS11A]; - values[kM0111POIME] = values[kMultDimuonsME] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); - values[kCORR2POIME] = (P2 * conj(Q21)).real() / values[kM01POIME]; - values[kCORR4POIME] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POIME]; - values[kM01POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME])) ? values[kM01POIME] / values[kMultDimuonsME] : 0; - values[kM0111POIoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME])) ? values[kM0111POIME] / values[kMultDimuonsME] : 0; - values[kM11REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuonsME] : 0; - values[kM1111REFoverMpME] = values[kMultDimuonsME] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuonsME] : 0; - values[kCORR2REFbydimuonsME] = std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; - values[kCORR4REFbydimuonsME] = std::isnan(values[kM1111REFoverMpME]) || std::isinf(values[kM1111REFoverMpME]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMpME]) || std::isinf(values[kM11REFoverMpME]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; - values[kCORR2POIME] = std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) || std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) ? 0 : values[kCORR2POIME]; - values[kCORR4POIME] = std::isnan(values[kCORR4POIME]) || std::isinf(values[kCORR4POIME]) || std::isnan(values[kM0111POIME]) || std::isinf(values[kM0111POIME]) || std::isnan(values[kCORR2POIME]) || std::isinf(values[kCORR2POIME]) || std::isnan(values[kM01POIME]) || std::isinf(values[kM01POIME]) ? 0 : values[kCORR4POIME]; - } - } - if constexpr (pairType == kDecayToMuMu) { - if (fgUsedVars[kQuadDCAabsXY]) { - double dca1X = t1.fwdDcaX(); - double dca1Y = t1.fwdDcaY(); - double dca1XY = std::sqrt(dca1X * dca1X + dca1Y * dca1Y); - double dca2X = t2.fwdDcaX(); - double dca2Y = t2.fwdDcaY(); - double dca2XY = std::sqrt(dca2X * dca2X + dca2Y * dca2Y); - values[kQuadDCAabsXY] = std::sqrt((dca1XY * dca1XY + dca2XY * dca2XY) / 2.); - } - } - if (fgUsedVars[kPairPhiv]) { - values[kPairPhiv] = calculatePhiV(t1, t2); - } -} - -template -void VarManager::FillPairMC(T1 const& t1, T2 const& t2, float* values) -{ - if (!values) { - values = fgValues; - } - - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if (pairType == kDecayToMuMu) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - - if (pairType == kDecayToPiPi) { - m1 = o2::constants::physics::MassPionCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if (pairType == kDecayToKPi) { - m1 = o2::constants::physics::MassKaonCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - - // TODO : implement resolution smearing. - 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; - values[kMCMass] = v12.M(); - values[kMCPt] = v12.Pt(); - values[kMCEta] = v12.Eta(); - values[kMCPhi] = v12.Phi(); - values[kMCY] = -v12.Rapidity(); - - // polarization parameters - bool useHE = fgUsedVars[kMCCosThetaHE] || fgUsedVars[kMCPhiHE]; // helicity frame - bool useCS = fgUsedVars[kMCCosThetaCS] || fgUsedVars[kMCPhiCS]; // Collins-Soper frame - bool usePP = fgUsedVars[kMCCosThetaPP]; // production plane frame - bool useRM = fgUsedVars[kMCCosThetaRM]; // Random frame - - if (useHE || useCS || usePP || useRM) { - ROOT::Math::Boost boostv12{v12.BoostToCM()}; - ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; - ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam1_CM{(boostv12(fgBeamA).Vect()).Unit()}; - ROOT::Math::XYZVectorF Beam2_CM{(boostv12(fgBeamC).Vect()).Unit()}; - - // using positive sign convention for the first track - ROOT::Math::XYZVectorF v_CM = (t1.pdgCode() > 0 ? v1_CM : v2_CM); - - if (useHE) { - ROOT::Math::XYZVectorF zaxis_HE{(v12.Vect()).Unit()}; - ROOT::Math::XYZVectorF yaxis_HE{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_HE{(yaxis_HE.Cross(zaxis_HE)).Unit()}; - if (fgUsedVars[kMCCosThetaHE]) - values[kMCCosThetaHE] = zaxis_HE.Dot(v_CM); - if (fgUsedVars[kMCPhiHE]) { - values[kMCPhiHE] = TMath::ATan2(yaxis_HE.Dot(v_CM), xaxis_HE.Dot(v_CM)); - if (values[kMCPhiHE] < 0) { - values[kMCPhiHE] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kMCPhiTildeHE]) { - if (fgUsedVars[kMCCosThetaHE] && fgUsedVars[kMCPhiHE]) { - if (values[kMCCosThetaHE] > 0) { - values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kMCPhiTildeHE] < 0) { - values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kMCPhiTildeHE] = values[kMCPhiHE] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kMCPhiTildeHE] < 0) { - values[kMCPhiTildeHE] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kMCPhiTildeHE] = -999; // not computable - } - } - } - - if (useCS) { - ROOT::Math::XYZVectorF zaxis_CS{(Beam1_CM - Beam2_CM).Unit()}; - ROOT::Math::XYZVectorF yaxis_CS{(Beam1_CM.Cross(Beam2_CM)).Unit()}; - ROOT::Math::XYZVectorF xaxis_CS{(yaxis_CS.Cross(zaxis_CS)).Unit()}; - if (fgUsedVars[kMCCosThetaCS]) - values[kMCCosThetaCS] = zaxis_CS.Dot(v_CM); - if (fgUsedVars[kMCPhiCS]) { - values[kMCPhiCS] = TMath::ATan2(yaxis_CS.Dot(v_CM), xaxis_CS.Dot(v_CM)); - if (values[kMCPhiCS] < 0) { - values[kMCPhiCS] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kMCPhiTildeCS]) { - if (fgUsedVars[kMCCosThetaCS] && fgUsedVars[kMCPhiCS]) { - if (values[kMCCosThetaCS] > 0) { - values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kMCPhiTildeCS] < 0) { - values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kMCPhiTildeCS] = values[kMCPhiCS] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kMCPhiTildeCS] < 0) { - values[kMCPhiTildeCS] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kMCPhiTildeCS] = -999; // not computable - } - } - } - - if (usePP) { - ROOT::Math::XYZVector zaxis_PP = ROOT::Math::XYZVector(v12.Py(), -v12.Px(), 0.f); - ROOT::Math::XYZVector yaxis_PP{v12.Vect().Unit()}; - ROOT::Math::XYZVector xaxis_PP{(yaxis_PP.Cross(zaxis_PP)).Unit()}; - if (fgUsedVars[kMCCosThetaPP]) { - values[kMCCosThetaPP] = zaxis_PP.Dot(v_CM); - } - if (fgUsedVars[kMCPhiPP]) { - values[kMCPhiPP] = TMath::ATan2(yaxis_PP.Dot(v_CM), xaxis_PP.Dot(v_CM)); - if (values[kMCPhiPP] < 0) { - values[kMCPhiPP] += 2 * TMath::Pi(); // ensure phi is in [0, 2pi] - } - } - if (fgUsedVars[kMCPhiTildePP]) { - if (fgUsedVars[kMCCosThetaPP] && fgUsedVars[kMCPhiPP]) { - if (values[kMCCosThetaPP] > 0) { - values[kMCPhiTildePP] = values[kMCPhiPP] - 0.25 * TMath::Pi(); // phi_tilde = phi - pi/4 - if (values[kMCPhiTildePP] < 0) { - values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } else { - values[kMCPhiTildePP] = values[kMCPhiPP] - 0.75 * TMath::Pi(); // phi_tilde = phi - 3pi/4 - if (values[kMCPhiTildePP] < 0) { - values[kMCPhiTildePP] += 2 * TMath::Pi(); // ensure phi_tilde is in [0, 2pi] - } - } - } else { - values[kMCPhiTildePP] = -999; // not computable - } - } - } - - if (useRM) { - double randomCostheta = gRandom->Uniform(-1., 1.); - double randomPhi = gRandom->Uniform(0., 2. * TMath::Pi()); - ROOT::Math::XYZVectorF zaxis_RM(randomCostheta, std::sqrt(1 - randomCostheta * randomCostheta) * std::cos(randomPhi), std::sqrt(1 - randomCostheta * randomCostheta) * std::sin(randomPhi)); - if (fgUsedVars[kMCCosThetaRM]) - values[kMCCosThetaRM] = zaxis_RM.Dot(v_CM); - } - } -} - -template -void VarManager::FillTripleMC(T1 const& t1, T2 const& t2, T3 const& t3, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr (candidateType == kTripleCandidateToEEPhoton) { - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - float m3 = o2::constants::physics::MassPhoton; - 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[kPairMassDau] = v12.M(); - values[kMassDau] = m3; - values[kPairPtDau] = v12.Pt(); - values[kPt] = t3.pt(); - values[kEta] = t3.eta(); - values[kEta1] = t1.eta(); - values[kEta2] = t2.eta(); - values[kDeltaEta] = v12.Eta(); - values[VarManager::kDeltaMass] = v123.M() - v12.M(); - values[VarManager::kDeltaMass_jpsi] = v123.M() - v12.M() + m4; - values[kRap] = -v123.Rapidity(); - values[kPt1] = t1.pt(); - values[kPt2] = t2.pt(); - } - - if constexpr (candidateType == kTripleCandidateToKPiPi) { - float m1 = o2::constants::physics::MassKaonCharged; - float m2 = o2::constants::physics::MassPionCharged; - - 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 v3(t3.pt(), t3.eta(), t3.phi(), m2); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - values[kMass] = v123.M(); - values[kPt] = v123.Pt(); - values[kEta] = v123.Eta(); - values[kPhi] = v123.Phi(); - values[kRap] = -v123.Rapidity(); - values[kCharge] = t1.sign() + t2.sign() + t3.sign(); - values[kS12] = (v1 + v2).M2(); - 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 -void VarManager::FillPairVertexing(C const& collision, T const& t1, T const& t2, bool propToSV, float* values) -{ - // check at compile time that the event and cov matrix have the cov matrix - constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); - constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); - constexpr bool muonHasCov = ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0); - - if (!values) { - values = fgValues; - } - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if constexpr (pairType == kDecayToKPi) { - m1 = o2::constants::physics::MassKaonCharged; - m2 = o2::constants::physics::MassPionCharged; - } - if constexpr (pairType == kDecayToMuMu && muonHasCov) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - 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; - - values[kUsedKF] = fgUsedKF; - if (!fgUsedKF) { - int procCode = 0; - - // TODO: use trackUtilities functions to initialize the various matrices to avoid code duplication - // auto pars1 = getTrackParCov(t1); - // auto pars2 = getTrackParCov(t2); - // We need to hide the cov data members from the cases when no cov table is provided - if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { - std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; - std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), - t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), - t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; - o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; - std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; - std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), - t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), - t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; - o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; - procCode = fgFitterTwoProngBarrel.process(pars1, pars2); - } else if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { - // Initialize track parameters for forward - o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); - o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); - procCode = fgFitterTwoProngFwd.process(pars1, pars2); - } else { - return; - } - - values[kVertexingProcCode] = procCode; - if (procCode == 0) { - // TODO: set the other variables to appropriate values and return - values[kVertexingChi2PCA] = -999.; - values[kVertexingLxy] = -999.; - values[kVertexingLxyz] = -999.; - values[kVertexingLz] = -999.; - values[kVertexingLxyErr] = -999.; - values[kVertexingLxyzErr] = -999.; - values[kVertexingLzErr] = -999.; - - values[kVertexingTauxy] = -999.; - values[kVertexingTauz] = -999.; - values[kVertexingTauxyErr] = -999.; - values[kVertexingTauzErr] = -999.; - values[kVertexingPz] = -999.; - values[kVertexingSV] = -999.; - return; - } - - Vec3D secondaryVertex; - - if constexpr (eventHasVtxCov) { - - std::array covMatrixPCA{}; - // get track impact parameters - // This modifies track momenta! - o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; - o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; - // auto primaryVertex = getPrimaryVertex(collision); - auto covMatrixPV = primaryVertex.getCov(); - - if constexpr ((pairType == kDecayToEE || pairType == kDecayToKPi) && trackHasCov) { - secondaryVertex = fgFitterTwoProngBarrel.getPCACandidate(); - covMatrixPCA = fgFitterTwoProngBarrel.calcPCACovMatrixFlat(); - auto chi2PCA = fgFitterTwoProngBarrel.getChi2AtPCACandidate(); - auto trackParVar0 = fgFitterTwoProngBarrel.getTrack(0); - auto trackParVar1 = fgFitterTwoProngBarrel.getTrack(1); - values[kVertexingChi2PCA] = chi2PCA; - v1 = {trackParVar0.getPt(), trackParVar0.getEta(), trackParVar0.getPhi(), m1}; - v2 = {trackParVar1.getPt(), trackParVar1.getEta(), trackParVar1.getPhi(), m2}; - v12 = v1 + v2; - - } else if constexpr (pairType == kDecayToMuMu && muonHasCov) { - // Get pca candidate from forward DCA fitter - secondaryVertex = fgFitterTwoProngFwd.getPCACandidate(); - covMatrixPCA = fgFitterTwoProngFwd.calcPCACovMatrixFlat(); - auto chi2PCA = fgFitterTwoProngFwd.getChi2AtPCACandidate(); - auto trackParVar0 = fgFitterTwoProngFwd.getTrack(0); - auto trackParVar1 = fgFitterTwoProngFwd.getTrack(1); - values[kVertexingChi2PCA] = chi2PCA; - v1 = {trackParVar0.getPt(), trackParVar0.getEta(), trackParVar0.getPhi(), m1}; - v2 = {trackParVar1.getPt(), trackParVar1.getEta(), trackParVar1.getPhi(), m2}; - v12 = v1 + v2; - - values[kPt1] = trackParVar0.getPt(); - values[kEta1] = trackParVar0.getEta(); - values[kPhi1] = trackParVar0.getPhi(); - - values[kPt2] = trackParVar1.getPt(); - values[kEta2] = trackParVar1.getEta(); - values[kPhi2] = trackParVar1.getPhi(); - } - double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); - double theta = std::atan2(secondaryVertex[2] - collision.posZ(), - std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + - (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); - - values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); - - values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + - (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); - values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); - values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; - values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); - values[kVertexingLz] = std::sqrt(values[kVertexingLz]); - values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); - - values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kVertexingPz] = TMath::Abs(v12.Pz()); - values[kVertexingSV] = secondaryVertex[2]; - - values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v12.Px() + - (collision.posY() - secondaryVertex[1]) * v12.Py() + - (collision.posZ() - secondaryVertex[2]) * v12.Pz()) / - (v12.P() * values[VarManager::kVertexingLxyz]); - // Decay length defined as in Run 2 - values[kVertexingLzProjected] = ((secondaryVertex[2] - collision.posZ()) * v12.Pz()) / TMath::Sqrt(v12.Pz() * v12.Pz()); - values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py())); - values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v12.Px()) + ((secondaryVertex[1] - collision.posY()) * v12.Py()) + ((secondaryVertex[2] - collision.posZ()) * v12.Pz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v12.Px() * v12.Px()) + (v12.Py() * v12.Py()) + (v12.Pz() * v12.Pz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v12.M() / (v12.Pt()); - values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (v12.Pt()); - values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v12.M() / TMath::Abs(v12.Pz()); - values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v12.M() / (v12.P()); - } - } else { - KFParticle trk0KF; - KFParticle trk1KF; - KFParticle KFGeoTwoProng; - if constexpr ((pairType == kDecayToEE) && trackHasCov) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); - trk0KF = KFParticle(kfpTrack0, -11 * t1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); - trk1KF = KFParticle(kfpTrack1, -11 * t2.sign()); - - KFGeoTwoProng.SetConstructMethod(2); - KFGeoTwoProng.AddDaughter(trk0KF); - KFGeoTwoProng.AddDaughter(trk1KF); - - } else if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { - KFPTrack kfpTrack0 = createKFPFwdTrackFromFwdTrack(t1); - trk0KF = KFParticle(kfpTrack0, -13 * t1.sign()); - KFPTrack kfpTrack1 = createKFPFwdTrackFromFwdTrack(t2); - trk1KF = KFParticle(kfpTrack1, -13 * t2.sign()); - - KFGeoTwoProng.SetConstructMethod(2); - KFGeoTwoProng.AddDaughter(trk0KF); - KFGeoTwoProng.AddDaughter(trk1KF); - - } else if constexpr ((pairType == kDecayToKPi) && trackHasCov) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); - trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); - trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); - - KFGeoTwoProng.SetConstructMethod(2); - KFGeoTwoProng.AddDaughter(trk0KF); - KFGeoTwoProng.AddDaughter(trk1KF); - } - if (fgUsedVars[kKFMass]) { - float mass = 0., massErr = 0.; - if (!KFGeoTwoProng.GetMass(mass, massErr)) - values[kKFMass] = mass; - else - values[kKFMass] = -999.; - } - - if constexpr (eventHasVtxCov) { - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - values[kKFNContributorsPV] = kfpVertex.GetNContributors(); - KFParticle KFPV(kfpVertex); - double dxPair2PV = KFGeoTwoProng.GetX() - KFPV.GetX(); - double dyPair2PV = KFGeoTwoProng.GetY() - KFPV.GetY(); - double dzPair2PV = KFGeoTwoProng.GetZ() - KFPV.GetZ(); - if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr] || fgUsedVars[kVertexingTauxy] || fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr] || fgUsedVars[kCosPointingAngle]) { - values[kVertexingLxy] = std::sqrt(dxPair2PV * dxPair2PV + dyPair2PV * dyPair2PV); - values[kVertexingLz] = std::sqrt(dzPair2PV * dzPair2PV); - values[kVertexingLxyz] = std::sqrt(dxPair2PV * dxPair2PV + dyPair2PV * dyPair2PV + dzPair2PV * dzPair2PV); - values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoTwoProng.GetCovariance(0)) * dxPair2PV * dxPair2PV + (KFPV.GetCovariance(2) + KFGeoTwoProng.GetCovariance(2)) * dyPair2PV * dyPair2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoTwoProng.GetCovariance(1)) * dxPair2PV * dyPair2PV); - values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoTwoProng.GetCovariance(5)) * dzPair2PV * dzPair2PV; - values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoTwoProng.GetCovariance(0)) * dxPair2PV * dxPair2PV + (KFPV.GetCovariance(2) + KFGeoTwoProng.GetCovariance(2)) * dyPair2PV * dyPair2PV + (KFPV.GetCovariance(5) + KFGeoTwoProng.GetCovariance(5)) * dzPair2PV * dzPair2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoTwoProng.GetCovariance(1)) * dxPair2PV * dyPair2PV + (KFPV.GetCovariance(3) + KFGeoTwoProng.GetCovariance(3)) * dxPair2PV * dzPair2PV + (KFPV.GetCovariance(4) + KFGeoTwoProng.GetCovariance(4)) * dyPair2PV * dzPair2PV); - if (fabs(values[kVertexingLxy]) < 1.e-8f) - values[kVertexingLxy] = 1.e-8f; - values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; - if (fabs(values[kVertexingLz]) < 1.e-8f) - values[kVertexingLz] = 1.e-8f; - values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; - if (fabs(values[kVertexingLxyz]) < 1.e-8f) - values[kVertexingLxyz] = 1.e-8f; - values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; - values[kVertexingTauxy] = KFGeoTwoProng.GetPseudoProperDecayTime(KFPV, KFGeoTwoProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauz] = -1 * dzPair2PV * KFGeoTwoProng.GetMass() / (TMath::Abs(KFGeoTwoProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingPz] = TMath::Abs(KFGeoTwoProng.GetPz()); - values[kVertexingSV] = KFGeoTwoProng.GetZ(); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoTwoProng.GetMass() / (TMath::Abs(KFGeoTwoProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kCosPointingAngle] = (std::sqrt(dxPair2PV * dxPair2PV) * v12.Px() + - std::sqrt(dyPair2PV * dyPair2PV) * v12.Py() + - std::sqrt(dzPair2PV * dzPair2PV) * v12.Pz()) / - (v12.P() * values[VarManager::kVertexingLxyz]); - } - // As defined in Run 2 (projected onto momentum) - if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || fgUsedVars[kVertexingLzProjected]) { - values[kVertexingLzProjected] = (dzPair2PV * KFGeoTwoProng.GetPz()) / TMath::Sqrt(KFGeoTwoProng.GetPz() * KFGeoTwoProng.GetPz()); - values[kVertexingLxyProjected] = (dxPair2PV * KFGeoTwoProng.GetPx()) + (dyPair2PV * KFGeoTwoProng.GetPy()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy())); - values[kVertexingLxyzProjected] = (dxPair2PV * KFGeoTwoProng.GetPx()) + (dyPair2PV * KFGeoTwoProng.GetPy()) + (dzPair2PV * KFGeoTwoProng.GetPz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoTwoProng.GetPx() * KFGeoTwoProng.GetPx()) + (KFGeoTwoProng.GetPy() * KFGeoTwoProng.GetPy()) + (KFGeoTwoProng.GetPz() * KFGeoTwoProng.GetPz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoTwoProng.GetMass() / (KFGeoTwoProng.GetPt()); - values[kVertexingTauxyProjectedPoleJPsiMass] = values[kVertexingLxyProjected] * o2::constants::physics::MassJPsi / (KFGeoTwoProng.GetPt()); - values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoTwoProng.GetMass() / TMath::Abs(KFGeoTwoProng.GetPz()); - } - - if (fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr]) { - values[kVertexingLxyOverErr] = values[kVertexingLxy] / values[kVertexingLxyErr]; - values[kVertexingLzOverErr] = values[kVertexingLz] / values[kVertexingLzErr]; - values[kVertexingLxyzOverErr] = values[kVertexingLxyz] / values[kVertexingLxyzErr]; - } - - if (fgUsedVars[kKFChi2OverNDFGeo]) - values[kKFChi2OverNDFGeo] = KFGeoTwoProng.GetChi2() / KFGeoTwoProng.GetNDF(); - if (fgUsedVars[kKFCosPA]) - values[kKFCosPA] = calculateCosPA(KFGeoTwoProng, KFPV); - - // in principle, they should be in FillTrack - if (fgUsedVars[kKFTrack0DCAxyz] || fgUsedVars[kKFTrack1DCAxyz]) { - values[kKFTrack0DCAxyz] = trk0KF.GetDistanceFromVertex(KFPV); - values[kKFTrack1DCAxyz] = trk1KF.GetDistanceFromVertex(KFPV); - } - if (fgUsedVars[kKFTrack0DCAxy] || fgUsedVars[kKFTrack1DCAxy]) { - values[kKFTrack0DCAxy] = trk0KF.GetDistanceFromVertexXY(KFPV); - values[kKFTrack1DCAxy] = trk1KF.GetDistanceFromVertexXY(KFPV); - } - if (fgUsedVars[kKFDCAxyzBetweenProngs]) - values[kKFDCAxyzBetweenProngs] = trk0KF.GetDistanceFromParticle(trk1KF); - if (fgUsedVars[kKFDCAxyBetweenProngs]) - values[kKFDCAxyBetweenProngs] = trk0KF.GetDistanceFromParticleXY(trk1KF); - - if (fgUsedVars[kKFTracksDCAxyzMax]) { - values[kKFTracksDCAxyzMax] = values[kKFTrack0DCAxyz] > values[kKFTrack1DCAxyz] ? values[kKFTrack0DCAxyz] : values[kKFTrack1DCAxyz]; - } - if (fgUsedVars[kKFTracksDCAxyMax]) { - values[kKFTracksDCAxyMax] = TMath::Abs(values[kKFTrack0DCAxy]) > TMath::Abs(values[kKFTrack1DCAxy]) ? values[kKFTrack0DCAxy] : values[kKFTrack1DCAxy]; - } - if (fgUsedVars[kKFTrack0DeviationFromPV] || fgUsedVars[kKFTrack1DeviationFromPV]) { - values[kKFTrack0DeviationFromPV] = trk0KF.GetDeviationFromVertex(KFPV); - values[kKFTrack1DeviationFromPV] = trk1KF.GetDeviationFromVertex(KFPV); - } - if (fgUsedVars[kKFTrack0DeviationxyFromPV] || fgUsedVars[kKFTrack1DeviationxyFromPV]) { - values[kKFTrack0DeviationxyFromPV] = trk0KF.GetDeviationFromVertexXY(KFPV); - values[kKFTrack1DeviationxyFromPV] = trk1KF.GetDeviationFromVertexXY(KFPV); - } - if (fgUsedVars[kKFJpsiDCAxyz]) { - values[kKFJpsiDCAxyz] = KFGeoTwoProng.GetDistanceFromVertex(KFPV); - } - if (fgUsedVars[kKFJpsiDCAxy]) { - values[kKFJpsiDCAxy] = KFGeoTwoProng.GetDistanceFromVertexXY(KFPV); - } - if (fgUsedVars[kKFPairDeviationFromPV] || fgUsedVars[kKFPairDeviationxyFromPV]) { - values[kKFPairDeviationFromPV] = KFGeoTwoProng.GetDeviationFromVertex(KFPV); - values[kKFPairDeviationxyFromPV] = KFGeoTwoProng.GetDeviationFromVertexXY(KFPV); - } - if (fgUsedVars[kKFChi2OverNDFGeoTop] || fgUsedVars[kKFMassGeoTop]) { - KFParticle KFGeoTopTwoProngBarrel = KFGeoTwoProng; - KFGeoTopTwoProngBarrel.SetProductionVertex(KFPV); - values[kKFChi2OverNDFGeoTop] = KFGeoTopTwoProngBarrel.GetChi2() / KFGeoTopTwoProngBarrel.GetNDF(); - float mass = 0., massErr = 0.; - if (!KFGeoTopTwoProngBarrel.GetMass(mass, massErr)) - values[kKFMassGeoTop] = mass; - else - values[kKFMassGeoTop] = -999.; - } - if (propToSV) { - if constexpr ((pairType == kDecayToMuMu) && muonHasCov) { - o2::track::TrackParCovFwd pars1 = FwdToTrackPar(t1, t1); - o2::track::TrackParCovFwd pars2 = FwdToTrackPar(t2, t2); - - auto geoMan1 = o2::base::GeometryManager::meanMaterialBudget(t1.x(), t1.y(), t1.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); - auto geoMan2 = o2::base::GeometryManager::meanMaterialBudget(t2.x(), t2.y(), t2.z(), KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY(), KFGeoTwoProng.GetZ()); - auto x2x01 = static_cast(geoMan1.meanX2X0); - auto x2x02 = static_cast(geoMan2.meanX2X0); - float B[3]; - float xyz[3] = {0, 0, 0}; - KFGeoTwoProng.GetFieldValue(xyz, B); - // TODO: find better soluton to handle cases where KF outputs negative variances - /*float covXX = 0.1; - float covYY = 0.1; - if (KFGeoTwoProng.GetCovariance(0, 0) > 0) { - covXX = KFGeoTwoProng.GetCovariance(0, 0); - } - if (KFGeoTwoProng.GetCovariance(1, 1) > 0) { - covYY = KFGeoTwoProng.GetCovariance(0, 0); - }*/ - pars1.propagateToVtxhelixWithMCS(KFGeoTwoProng.GetZ(), {KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY()}, {KFGeoTwoProng.GetCovariance(0, 0), KFGeoTwoProng.GetCovariance(1, 1)}, B[2], x2x01); - pars2.propagateToVtxhelixWithMCS(KFGeoTwoProng.GetZ(), {KFGeoTwoProng.GetX(), KFGeoTwoProng.GetY()}, {KFGeoTwoProng.GetCovariance(0, 0), KFGeoTwoProng.GetCovariance(1, 1)}, B[2], x2x02); - v1 = {pars1.getPt(), pars1.getEta(), pars1.getPhi(), m1}; - v2 = {pars2.getPt(), pars2.getEta(), pars2.getPhi(), m2}; - v12 = v1 + v2; - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - values[kPhi] = v12.Phi(); - values[kRap] = -v12.Rapidity(); - values[kVertexingTauxy] = KFGeoTwoProng.GetPseudoProperDecayTime(KFPV, v12.M()) / (o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauz] = -1 * dzPair2PV * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauzErr] = values[kVertexingLzErr] * v12.M() / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingPz] = TMath::Abs(v12.Pz()); - values[kVertexingSV] = KFGeoTwoProng.GetZ(); - - values[kPt1] = pars1.getPt(); - values[kEta1] = pars1.getEta(); - values[kPhi1] = pars1.getPhi(); - - values[kPt2] = pars2.getPt(); - values[kEta2] = pars2.getEta(); - values[kPhi2] = pars2.getPhi(); - } - } - } - } - if (propToSV) { - values[kMass] = v12.M(); - values[kPt] = v12.Pt(); - values[kEta] = v12.Eta(); - // values[kPhi] = v12.Phi(); - values[kPhi] = v12.Phi() > 0 ? v12.Phi() : v12.Phi() + 2. * M_PI; - } else { - values[kPt1] = t1.pt(); - values[kEta1] = t1.eta(); - values[kPhi1] = t1.phi(); - - values[kPt2] = t2.pt(); - values[kEta2] = t2.eta(); - values[kPhi2] = t2.phi(); - } -} - -template -void VarManager::FillTripletVertexing(C const& collision, T const& t1, T const& t2, T const& t3, VarManager::PairCandidateType tripletType, float* values) -{ - // TODO: Vertexing error variables - constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); - bool trackHasCov = ((fillMap & ReducedTrackBarrelCov) > 0); - - if (!values) { - values = fgValues; - } - - float m1, m2, m3; - - if (tripletType == kTripleCandidateToKPiPi) { - m1 = o2::constants::physics::MassKaonCharged; - m2 = o2::constants::physics::MassPionCharged; - m3 = o2::constants::physics::MassPionCharged; - } - if (tripletType == kTripleCandidateToPKPi) { - m1 = o2::constants::physics::MassProton; - m2 = o2::constants::physics::MassKaonCharged; - m3 = o2::constants::physics::MassPionCharged; - } - 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 v3(t3.pt(), t3.eta(), t3.phi(), m3); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - - values[kUsedKF] = fgUsedKF; - if (!fgUsedKF) { - int procCode = 0; - - if (trackHasCov) { - std::array t1pars = {t1.y(), t1.z(), t1.snp(), t1.tgl(), t1.signed1Pt()}; - std::array t1covs = {t1.cYY(), t1.cZY(), t1.cZZ(), t1.cSnpY(), t1.cSnpZ(), - t1.cSnpSnp(), t1.cTglY(), t1.cTglZ(), t1.cTglSnp(), t1.cTglTgl(), - t1.c1PtY(), t1.c1PtZ(), t1.c1PtSnp(), t1.c1PtTgl(), t1.c1Pt21Pt2()}; - o2::track::TrackParCov pars1{t1.x(), t1.alpha(), t1pars, t1covs}; - std::array t2pars = {t2.y(), t2.z(), t2.snp(), t2.tgl(), t2.signed1Pt()}; - std::array t2covs = {t2.cYY(), t2.cZY(), t2.cZZ(), t2.cSnpY(), t2.cSnpZ(), - t2.cSnpSnp(), t2.cTglY(), t2.cTglZ(), t2.cTglSnp(), t2.cTglTgl(), - t2.c1PtY(), t2.c1PtZ(), t2.c1PtSnp(), t2.c1PtTgl(), t2.c1Pt21Pt2()}; - o2::track::TrackParCov pars2{t2.x(), t2.alpha(), t2pars, t2covs}; - std::array t3pars = {t3.y(), t3.z(), t3.snp(), t3.tgl(), t3.signed1Pt()}; - std::array t3covs = {t3.cYY(), t3.cZY(), t3.cZZ(), t3.cSnpY(), t3.cSnpZ(), - t3.cSnpSnp(), t3.cTglY(), t3.cTglZ(), t3.cTglSnp(), t3.cTglTgl(), - t3.c1PtY(), t3.c1PtZ(), t3.c1PtSnp(), t3.c1PtTgl(), t3.c1Pt21Pt2()}; - o2::track::TrackParCov pars3{t3.x(), t3.alpha(), t3pars, t3covs}; - procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); - } else { - return; - } - - values[VarManager::kVertexingProcCode] = procCode; - if (procCode == 0) { - // TODO: set the other variables to appropriate values and return - values[kVertexingChi2PCA] = -999.; - values[kVertexingLxy] = -999.; - values[kVertexingLxyz] = -999.; - values[kVertexingLz] = -999.; - values[kVertexingLxyErr] = -999.; - values[kVertexingLxyzErr] = -999.; - values[kVertexingLzErr] = -999.; - - values[kVertexingTauxy] = -999.; - values[kVertexingTauz] = -999.; - values[kVertexingTauxyErr] = -999.; - values[kVertexingTauzErr] = -999.; - - values[kVertexingLzProjected] = -999.; - values[kVertexingLxyProjected] = -999.; - values[kVertexingLxyzProjected] = -999.; - values[kVertexingTauzProjected] = -999.; - values[kVertexingTauxyProjected] = -999.; - values[kVertexingTauxyzProjected] = -999.; - - return; - } - - Vec3D secondaryVertex; - - if constexpr (eventHasVtxCov) { - secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); - - std::array covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); - - o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; - o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; - auto covMatrixPV = primaryVertex.getCov(); - - if (fgUsedVars[kVertexingChi2PCA]) { - auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); - values[VarManager::kVertexingChi2PCA] = chi2PCA; - } - - double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); - double theta = std::atan2(secondaryVertex[2] - collision.posZ(), - std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + - (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); - - values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + - (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); - values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); - values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; - values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); - values[kVertexingLz] = std::sqrt(values[kVertexingLz]); - values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); - - values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); - - values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + - (collision.posY() - secondaryVertex[1]) * v123.Py() + - (collision.posZ() - secondaryVertex[2]) * v123.Pz()) / - (v123.P() * values[VarManager::kVertexingLxyz]); - // run 2 definitions: Decay length projected onto the momentum vector of the candidate - values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); - values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); - values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); - values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); - - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / (v123.Pt()); - values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v123.M() / (v123.P()); - } - } else { - KFParticle trk0KF; - KFParticle trk1KF; - KFParticle trk2KF; - KFParticle KFGeoThreeProng; - if ((tripletType == kTripleCandidateToKPiPi) && trackHasCov) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); - trk0KF = KFParticle(kfpTrack0, 321 * t1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); - trk1KF = KFParticle(kfpTrack1, 211 * t2.sign()); - KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); - trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); - - KFGeoThreeProng.SetConstructMethod(3); - KFGeoThreeProng.AddDaughter(trk0KF); - KFGeoThreeProng.AddDaughter(trk1KF); - KFGeoThreeProng.AddDaughter(trk2KF); - - } else if ((tripletType == kTripleCandidateToPKPi) && trackHasCov) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(t1); - trk0KF = KFParticle(kfpTrack0, 2212 * t1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(t2); - trk1KF = KFParticle(kfpTrack1, 321 * t2.sign()); - KFPTrack kfpTrack2 = createKFPTrackFromTrack(t3); - trk2KF = KFParticle(kfpTrack2, 211 * t3.sign()); - - KFGeoThreeProng.SetConstructMethod(3); - KFGeoThreeProng.AddDaughter(trk0KF); - KFGeoThreeProng.AddDaughter(trk1KF); - KFGeoThreeProng.AddDaughter(trk2KF); - } - if (fgUsedVars[kKFMass]) { - float mass = 0., massErr = 0.; - if (!KFGeoThreeProng.GetMass(mass, massErr)) - values[kKFMass] = mass; - else - values[kKFMass] = -999.; - } - - if constexpr (eventHasVtxCov) { - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - values[kKFNContributorsPV] = kfpVertex.GetNContributors(); - KFParticle KFPV(kfpVertex); - double dxTriplet2PV = KFGeoThreeProng.GetX() - KFPV.GetX(); - double dyTriplet2PV = KFGeoThreeProng.GetY() - KFPV.GetY(); - double dzTriplet2PV = KFGeoThreeProng.GetZ() - KFPV.GetZ(); - - values[kVertexingLxy] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV); - values[kVertexingLz] = std::sqrt(dzTriplet2PV * dzTriplet2PV); - values[kVertexingLxyz] = std::sqrt(dxTriplet2PV * dxTriplet2PV + dyTriplet2PV * dyTriplet2PV + dzTriplet2PV * dzTriplet2PV); - - values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV); - values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV; - values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet2PV * dxTriplet2PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet2PV * dzTriplet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet2PV * dyTriplet2PV + (KFPV.GetCovariance(3) + KFGeoThreeProng.GetCovariance(3)) * dxTriplet2PV * dzTriplet2PV + (KFPV.GetCovariance(4) + KFGeoThreeProng.GetCovariance(4)) * dyTriplet2PV * dzTriplet2PV); - if (fabs(values[kVertexingLxy]) < 1.e-8f) - values[kVertexingLxy] = 1.e-8f; - values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; - if (fabs(values[kVertexingLz]) < 1.e-8f) - values[kVertexingLz] = 1.e-8f; - values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; - if (fabs(values[kVertexingLxyz]) < 1.e-8f) - values[kVertexingLxyz] = 1.e-8f; - values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; - - values[kVertexingTauxy] = KFGeoThreeProng.GetPseudoProperDecayTime(KFPV, KFGeoThreeProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauz] = -1 * dzTriplet2PV * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingPz] = TMath::Abs(KFGeoThreeProng.GetPz()); - values[kVertexingSV] = KFGeoThreeProng.GetZ(); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoThreeProng.GetMass() / (TMath::Abs(KFGeoThreeProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kCosPointingAngle] = (std::sqrt(dxTriplet2PV * dxTriplet2PV) * v123.Px() + - std::sqrt(dyTriplet2PV * dyTriplet2PV) * v123.Py() + - std::sqrt(dzTriplet2PV * dzTriplet2PV) * v123.Pz()) / - (v123.P() * values[VarManager::kVertexingLxyz]); - - values[kVertexingLzProjected] = (dzTriplet2PV * KFGeoThreeProng.GetPz()) / TMath::Sqrt(KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz()); - values[kVertexingLxyProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); - values[kVertexingLxyzProjected] = (dxTriplet2PV * KFGeoThreeProng.GetPx()) + (dyTriplet2PV * KFGeoThreeProng.GetPy()) + (dzTriplet2PV * KFGeoThreeProng.GetPz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt()); - values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoThreeProng.GetMass() / TMath::Abs(KFGeoThreeProng.GetPz()); - } - } -} - -template -void VarManager::FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values) -{ - - constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); - constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); - constexpr bool muonHasCov = ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0); - if (!values) { - values = fgValues; - } - - float mtrack; - float mlepton1, mlepton2; - - int procCode = 0; - int procCodeJpsi = 0; - - values[kUsedKF] = fgUsedKF; - if (!fgUsedKF) { - if constexpr ((candidateType == kBcToThreeMuons) && muonHasCov) { - mlepton1 = o2::constants::physics::MassMuon; - mlepton2 = o2::constants::physics::MassMuon; - mtrack = o2::constants::physics::MassMuon; - - o2::track::TrackParCovFwd pars1 = FwdToTrackPar(lepton1, lepton1); - o2::track::TrackParCovFwd pars2 = FwdToTrackPar(lepton2, lepton2); - o2::track::TrackParCovFwd pars3 = FwdToTrackPar(track, track); - - procCode = VarManager::fgFitterThreeProngFwd.process(pars1, pars2, pars3); - procCodeJpsi = VarManager::fgFitterTwoProngFwd.process(pars1, pars2); - } else if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { - if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { - mlepton1 = o2::constants::physics::MassElectron; - mlepton2 = o2::constants::physics::MassElectron; - mtrack = o2::constants::physics::MassKaonCharged; - } else if constexpr ((candidateType == kDstarToD0KPiPi) && trackHasCov) { - mlepton1 = o2::constants::physics::MassKaonCharged; - mlepton2 = o2::constants::physics::MassPionCharged; - mtrack = o2::constants::physics::MassPionCharged; - } - std::array lepton1pars = {lepton1.y(), lepton1.z(), lepton1.snp(), lepton1.tgl(), lepton1.signed1Pt()}; - std::array lepton1covs = {lepton1.cYY(), lepton1.cZY(), lepton1.cZZ(), lepton1.cSnpY(), lepton1.cSnpZ(), - lepton1.cSnpSnp(), lepton1.cTglY(), lepton1.cTglZ(), lepton1.cTglSnp(), lepton1.cTglTgl(), - lepton1.c1PtY(), lepton1.c1PtZ(), lepton1.c1PtSnp(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; - o2::track::TrackParCov pars1{lepton1.x(), lepton1.alpha(), lepton1pars, lepton1covs}; - std::array lepton2pars = {lepton2.y(), lepton2.z(), lepton2.snp(), lepton2.tgl(), lepton2.signed1Pt()}; - std::array lepton2covs = {lepton2.cYY(), lepton2.cZY(), lepton2.cZZ(), lepton2.cSnpY(), lepton2.cSnpZ(), - lepton2.cSnpSnp(), lepton2.cTglY(), lepton2.cTglZ(), lepton2.cTglSnp(), lepton2.cTglTgl(), - lepton2.c1PtY(), lepton2.c1PtZ(), lepton2.c1PtSnp(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; - o2::track::TrackParCov pars2{lepton2.x(), lepton2.alpha(), lepton2pars, lepton2covs}; - std::array lepton3pars = {track.y(), track.z(), track.snp(), track.tgl(), track.signed1Pt()}; - std::array lepton3covs = {track.cYY(), track.cZY(), track.cZZ(), track.cSnpY(), track.cSnpZ(), - track.cSnpSnp(), track.cTglY(), track.cTglZ(), track.cTglSnp(), track.cTglTgl(), - track.c1PtY(), track.c1PtZ(), track.c1PtSnp(), track.c1PtTgl(), track.c1Pt21Pt2()}; - o2::track::TrackParCov pars3{track.x(), track.alpha(), lepton3pars, lepton3covs}; - procCode = VarManager::fgFitterThreeProngBarrel.process(pars1, pars2, pars3); - procCodeJpsi = VarManager::fgFitterTwoProngBarrel.process(pars1, pars2); - } else { - return; - } - - ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton1); - ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton2); - ROOT::Math::PtEtaPhiMVector v3(track.pt(), track.eta(), track.phi(), mtrack); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - ROOT::Math::PtEtaPhiMVector vdilepton(v12.pt(), v12.eta(), v12.phi(), v12.M()); - ROOT::Math::PtEtaPhiMVector v123 = vdilepton + v3; - values[VarManager::kPairMass] = v123.M(); - values[VarManager::kMassDau] = mtrack; - values[VarManager::kDeltaMass] = v123.M() - v12.M(); - values[VarManager::kPairPt] = v123.Pt(); - values[VarManager::kPairRap] = -v123.Rapidity(); - values[VarManager::kPairEta] = v123.Eta(); - if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { - values[VarManager::kPairMassDau] = v12.M(); - values[VarManager::kPairPtDau] = v12.Pt(); - } - values[VarManager::kPt] = track.pt(); - values[kS12] = (v1 + v2).M2(); - values[kS13] = (v1 + v3).M2(); - values[kS23] = (v2 + v3).M2(); - - values[VarManager::kVertexingProcCode] = procCode; - if (procCode == 0 || procCodeJpsi == 0) { - // TODO: set the other variables to appropriate values and return - values[VarManager::kVertexingChi2PCA] = -999.; - values[VarManager::kVertexingLxy] = -999.; - values[VarManager::kVertexingLxyz] = -999.; - values[VarManager::kVertexingLz] = -999.; - values[VarManager::kVertexingLxyErr] = -999.; - values[VarManager::kVertexingLxyzErr] = -999.; - values[VarManager::kVertexingLzErr] = -999.; - - values[VarManager::kVertexingTauxy] = -999.; - values[VarManager::kVertexingTauz] = -999.; - values[VarManager::kVertexingTauxyErr] = -999.; - values[VarManager::kVertexingTauzErr] = -999.; - values[VarManager::kVertexingPz] = -999.; - values[VarManager::kVertexingSV] = -999.; - return; - } - - Vec3D secondaryVertex; - - if constexpr (eventHasVtxCov) { - std::array covMatrixPCA; - o2::dataformats::DCA impactParameter0; - o2::dataformats::DCA impactParameter1; - - o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; - o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; - auto covMatrixPV = primaryVertex.getCov(); - - if constexpr ((candidateType == kBtoJpsiEEK || candidateType == kDstarToD0KPiPi) && trackHasCov) { - secondaryVertex = fgFitterThreeProngBarrel.getPCACandidate(); - covMatrixPCA = fgFitterThreeProngBarrel.calcPCACovMatrixFlat(); - } else if constexpr (candidateType == kBcToThreeMuons && muonHasCov) { - secondaryVertex = fgFitterThreeProngFwd.getPCACandidate(); - covMatrixPCA = fgFitterThreeProngFwd.calcPCACovMatrixFlat(); - } - - if (fgUsedVars[kVertexingChi2PCA]) { - auto chi2PCA = fgFitterThreeProngBarrel.getChi2AtPCACandidate(); - values[VarManager::kVertexingChi2PCA] = chi2PCA; - } - - double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); - double theta = std::atan2(secondaryVertex[2] - collision.posZ(), - std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + - (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); - if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz]) { - - values[VarManager::kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + - (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); - values[VarManager::kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); - values[VarManager::kVertexingLxyz] = values[VarManager::kVertexingLxy] + values[VarManager::kVertexingLz]; - values[VarManager::kVertexingLxy] = std::sqrt(values[VarManager::kVertexingLxy]); - values[VarManager::kVertexingLz] = std::sqrt(values[VarManager::kVertexingLz]); - values[VarManager::kVertexingLxyz] = std::sqrt(values[VarManager::kVertexingLxyz]); - } - - if (fgUsedVars[kVertexingLxyzErr] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr]) { - values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); - } - - values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kVertexingPz] = TMath::Abs(v123.Pz()); - values[kVertexingSV] = secondaryVertex[2]; - - values[kVertexingTauzErr] = values[kVertexingLzErr] * v123.M() / (TMath::Abs(v123.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v123.M() / (v123.Pt() * o2::constants::physics::LightSpeedCm2NS); - - if (fgUsedVars[kCosPointingAngle] && fgUsedVars[kVertexingLxyz]) { - values[VarManager::kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v123.Px() + - (collision.posY() - secondaryVertex[1]) * v123.Py() + - (collision.posZ() - secondaryVertex[2]) * v123.Pz()) / - (v123.P() * values[VarManager::kVertexingLxyz]); - } - // run 2 definitions: Lxy projected onto the momentum vector of the candidate - if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || values[kVertexingTauxyProjected]) { - values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v123.Pz(); - values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v123.Pz() * v123.Pz()); - values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py())); - values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v123.Px()) + ((secondaryVertex[1] - collision.posY()) * v123.Py()) + ((secondaryVertex[2] - collision.posZ()) * v123.Pz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v123.Px() * v123.Px()) + (v123.Py() * v123.Py()) + (v123.Pz() * v123.Pz())); - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v123.M() / TMath::Abs(v123.Pz()); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v123.M() / v123.Pt(); - } - } - } else { - KFParticle lepton1KF; - KFParticle lepton2KF; - KFParticle hadronKF; - KFParticle KFGeoTwoLeptons; - KFParticle KFGeoThreeProng; - - if constexpr ((candidateType == kBtoJpsiEEK) && trackHasCov) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); - lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); - lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); - KFPTrack kfpTrack2 = createKFPTrackFromTrack(track); - hadronKF = KFParticle(kfpTrack2, 321 * track.sign()); // kaon mass - - KFGeoTwoLeptons.SetConstructMethod(2); - KFGeoTwoLeptons.AddDaughter(lepton1KF); - KFGeoTwoLeptons.AddDaughter(lepton2KF); - - if (fgUsedVars[kPairMassDau] || fgUsedVars[kPairPtDau]) { - values[VarManager::kPairMassDau] = KFGeoTwoLeptons.GetMass(); - values[VarManager::kPairPtDau] = KFGeoTwoLeptons.GetPt(); - } - - // Quantities between 3rd prong and candidate - if (fgUsedVars[kKFDCAxyzBetweenProngs]) - values[kKFDCAxyzBetweenProngs] = KFGeoTwoLeptons.GetDistanceFromParticle(hadronKF); - - KFGeoThreeProng.SetConstructMethod(2); - KFGeoThreeProng.AddDaughter(KFGeoTwoLeptons); - KFGeoThreeProng.AddDaughter(hadronKF); - - if (fgUsedVars[kKFMass]) - values[kKFMass] = KFGeoThreeProng.GetMass(); - - if constexpr (eventHasVtxCov) { - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle KFPV(kfpVertex); - double dxTriplet3PV = KFGeoThreeProng.GetX() - KFPV.GetX(); - double dyTriplet3PV = KFGeoThreeProng.GetY() - KFPV.GetY(); - double dzTriplet3PV = KFGeoThreeProng.GetZ() - KFPV.GetZ(); - - if (fgUsedVars[kVertexingLxy] || fgUsedVars[kVertexingLz] || fgUsedVars[kVertexingLxyz] || fgUsedVars[kVertexingLxyErr] || fgUsedVars[kVertexingLzErr] || fgUsedVars[kVertexingTauxy] || fgUsedVars[kVertexingLxyOverErr] || fgUsedVars[kVertexingLzOverErr] || fgUsedVars[kVertexingLxyzOverErr] || fgUsedVars[kCosPointingAngle]) { - values[kVertexingLxy] = std::sqrt(dxTriplet3PV * dxTriplet3PV + dyTriplet3PV * dyTriplet3PV); - values[kVertexingLz] = std::sqrt(dzTriplet3PV * dzTriplet3PV); - values[kVertexingLxyz] = std::sqrt(dxTriplet3PV * dxTriplet3PV + dyTriplet3PV * dyTriplet3PV + dzTriplet3PV * dzTriplet3PV); - values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet3PV * dxTriplet3PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet3PV * dyTriplet3PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet3PV * dyTriplet3PV); - values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet3PV * dzTriplet3PV; - values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoThreeProng.GetCovariance(0)) * dxTriplet3PV * dxTriplet3PV + (KFPV.GetCovariance(2) + KFGeoThreeProng.GetCovariance(2)) * dyTriplet3PV * dyTriplet3PV + (KFPV.GetCovariance(5) + KFGeoThreeProng.GetCovariance(5)) * dzTriplet3PV * dzTriplet3PV + 2 * ((KFPV.GetCovariance(1) + KFGeoThreeProng.GetCovariance(1)) * dxTriplet3PV * dyTriplet3PV + (KFPV.GetCovariance(3) + KFGeoThreeProng.GetCovariance(3)) * dxTriplet3PV * dzTriplet3PV + (KFPV.GetCovariance(4) + KFGeoThreeProng.GetCovariance(4)) * dyTriplet3PV * dzTriplet3PV); - if (fabs(values[kVertexingLxy]) < 1.e-8f) - values[kVertexingLxy] = 1.e-8f; - values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; - if (fabs(values[kVertexingLz]) < 1.e-8f) - values[kVertexingLz] = 1.e-8f; - values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; - if (fabs(values[kVertexingLxyz]) < 1.e-8f) - values[kVertexingLxyz] = 1.e-8f; - values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; - - if (fgUsedVars[kVertexingTauxy]) - values[kVertexingTauxy] = KFGeoThreeProng.GetPseudoProperDecayTime(KFPV, KFGeoThreeProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); - if (fgUsedVars[kVertexingTauxyErr]) - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoThreeProng.GetMass() / (KFGeoThreeProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); - - if (fgUsedVars[kCosPointingAngle]) - values[VarManager::kCosPointingAngle] = (dxTriplet3PV * KFGeoThreeProng.GetPx() + - dyTriplet3PV * KFGeoThreeProng.GetPy() + - dzTriplet3PV * KFGeoThreeProng.GetPz()) / - (KFGeoThreeProng.GetP() * values[VarManager::kVertexingLxyz]); - } // end calculate vertex variables - - // As defined in Run 2 (projected onto momentum) - if (fgUsedVars[kVertexingLxyProjected] || fgUsedVars[kVertexingLxyzProjected] || fgUsedVars[kVertexingLzProjected]) { - values[kVertexingLzProjected] = (dzTriplet3PV * KFGeoThreeProng.GetPz()) / TMath::Sqrt(KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz()); - values[kVertexingLxyProjected] = (dxTriplet3PV * KFGeoThreeProng.GetPx()) + (dyTriplet3PV * KFGeoThreeProng.GetPy()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy())); - values[kVertexingLxyzProjected] = (dxTriplet3PV * KFGeoThreeProng.GetPx()) + (dyTriplet3PV * KFGeoThreeProng.GetPy()) + (dzTriplet3PV * KFGeoThreeProng.GetPz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoThreeProng.GetPx() * KFGeoThreeProng.GetPx()) + (KFGeoThreeProng.GetPy() * KFGeoThreeProng.GetPy()) + (KFGeoThreeProng.GetPz() * KFGeoThreeProng.GetPz())); - values[kVertexingTauxyProjected] = (values[kVertexingLxyProjected] * KFGeoThreeProng.GetMass()) / (KFGeoThreeProng.GetPt()); - values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = (values[kVertexingLzProjected] * KFGeoThreeProng.GetMass()) / TMath::Abs(KFGeoThreeProng.GetPz()); - } // end Run 2 quantities - } // end eventHasVtxCov - } // end (candidateType == kBtoJpsiEEK) && trackHasCov - } // end KF -} - -template -void VarManager::FillQVectorFromGFW(C const& /*collision*/, A const& compA11, A const& compB11, A const& compC11, A const& compA21, A const& compB21, A const& compC21, A const& compA31, A const& compB31, A const& compC31, A const& compA41, A const& compB41, A const& compC41, A const& compA23, A const& compA42, float S10A, float S10B, float S10C, float S11A, float S11B, float S11C, float S12A, float S13A, float S14A, float S21A, float S22A, float S31A, float S41A, float* values) -{ - if (!values) { - values = fgValues; - } - - // Fill Qn vectors from generic flow framework for different eta gap A, B, C (n=1,2,3,4) with proper normalisation - // Use normalized Q-vectors for SP and EP - values[kQ1X0A] = compA11.real() / S11A; - values[kQ1Y0A] = compA11.imag() / S11A; - values[kQ1X0B] = compB11.real() / S11B; - values[kQ1Y0B] = compB11.imag() / S11B; - values[kQ1X0C] = compC11.real() / S11C; - values[kQ1Y0C] = compC11.imag() / S11C; - values[kQ2X0A] = compA21.real() / S11A; - values[kQ2Y0A] = compA21.imag() / S11A; - values[kQ2X0B] = compB21.real() / S11B; - values[kQ2Y0B] = compB21.imag() / S11B; - values[kQ2X0C] = compC21.real() / S11C; - values[kQ2Y0C] = compC21.imag() / S11C; - values[kQ3X0A] = compA31.real() / S11A; - values[kQ3Y0A] = compA31.imag() / S11A; - values[kQ3X0B] = compB31.real() / S11B; - values[kQ3Y0B] = compB31.imag() / S11B; - values[kQ3X0C] = compC31.real() / S11C; - values[kQ3Y0C] = compC31.imag() / S11C; - values[kQ4X0A] = compA41.real() / S11A; - values[kQ4Y0A] = compA41.imag() / S11A; - values[kQ4X0B] = compB41.real() / S11B; - values[kQ4Y0B] = compB41.imag() / S11B; - values[kQ4X0C] = compC41.real() / S11C; - values[kQ4Y0C] = compC41.imag() / S11C; - values[kQ42XA] = compA42.real(); // Only being used by cumulants, no need for normalization - values[kQ42YA] = compA42.imag(); // Only being used by cumulants, no need for normalization - values[kQ23XA] = compA23.real(); // Only being used by cumulants, no need for normalization - values[kQ23YA] = compA23.imag(); // Only being used by cumulants, no need for normalization - values[kS11A] = S11A; - values[kS12A] = S12A; - values[kS13A] = S13A; - values[kS31A] = S31A; - - // Q-vectors components correlation (A, B, C) - values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; - values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; - values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; - values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; - values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; - values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; - values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; - values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; - values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; - values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; - values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; - values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; - - // Fill event multiplicities - values[kMultA] = S10A; - values[kMultB] = S10B; - values[kMultC] = S10C; - - // Fill necessary quantities for cumulant calculations with weighted Q-vectors - values[kM11REF] = S21A - S12A; - values[kM1111REF] = S41A - 6. * S12A * S21A + 8. * S13A * S11A + 3. * S22A - 6. * S14A; - values[kCORR2REF] = (norm(compA21) - S12A) / values[kM11REF]; - values[kCORR4REF] = (pow(norm(compA21), 2) + norm(compA42) - 2. * (compA42 * conj(compA21) * conj(compA21)).real() + 8. * (compA23 * conj(compA21)).real() - 4. * S12A * norm(compA21) - 6. * S14A + 2. * S22A) / values[kM1111REF]; - values[kCORR2REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR2REF]; - values[kM11REF] = std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kM11REF]; - values[kCORR4REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR4REF]; - values[kM1111REF] = std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kM1111REF]; - values[kCORR2CORR4REF] = values[kCORR2REF] * values[kCORR4REF]; - values[kM11M1111REF] = values[kM11REF] * values[kM1111REF]; - - // For cumulants: A = Full TPC, B = Negative TPC, C = Positive TPC - complex QA(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); - complex QB(values[kQ2X0B] * S11B, values[kQ2Y0B] * S11B); - complex QC(values[kQ2X0C] * S11C, values[kQ2Y0C] * S11C); - values[kM11REFetagap] = S11B * S11C; - values[kCORR2REFetagap] = ((QB * conj(QC)).real()) / values[kM11REFetagap]; - values[kCORR2REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kCORR2REFetagap]; - values[kM11REFetagap] = std::isnan(values[kM11REFetagap]) || std::isinf(values[kM11REFetagap]) || std::isnan(values[kCORR2REFetagap]) || std::isinf(values[kCORR2REFetagap]) ? 0 : values[kM11REFetagap]; - - // TODO: provide different computations for R - // Compute the R factor using the 2 sub-events technique for second and third harmonic - // Compute event planes - auto Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); - auto Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); - auto Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); - auto Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); - auto Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); - values[kPsi2A] = Psi2A; - values[kPsi2B] = Psi2B; - values[kPsi2C] = Psi2C; - - values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); - values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); - values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); - values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); - - values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); - values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); - values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); - values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); -} - -template -void VarManager::FillQVectorFromCentralFW(C const& collision, float* values) -{ - if (!values) { - values = fgValues; - } - - float xQVecFT0a = collision.qvecFT0ARe(); // already normalised - float yQVecFT0a = collision.qvecFT0AIm(); // already normalised - float xQVecFT0c = collision.qvecFT0CRe(); // already normalised - float yQVecFT0c = collision.qvecFT0CIm(); // already normalised - float xQVecFT0m = collision.qvecFT0MRe(); // already normalised - float yQVecFT0m = collision.qvecFT0MIm(); // already normalised - float xQVecFV0a = collision.qvecFV0ARe(); // already normalised - float yQVecFV0a = collision.qvecFV0AIm(); // already normalised - float xQVecBPos = collision.qvecTPCposRe(); // already normalised - float yQVecBPos = collision.qvecTPCposIm(); // already normalised - float xQVecBNeg = collision.qvecTPCnegRe(); // already normalised - float yQVecBNeg = collision.qvecTPCnegIm(); // already normalised - - values[kQ2X0A] = collision.qvecTPCallRe(); - values[kQ2Y0A] = collision.qvecTPCallIm(); - values[kQ2X0APOS] = xQVecBPos; - values[kQ2Y0APOS] = yQVecBPos; - values[kQ2X0ANEG] = xQVecBNeg; - values[kQ2Y0ANEG] = yQVecBNeg; - values[kQ2X0B] = xQVecFT0a; - values[kQ2Y0B] = yQVecFT0a; - values[kQ2X0C] = xQVecFT0c; - values[kQ2Y0C] = yQVecFT0c; - values[kMultA] = collision.nTrkTPCpos() + collision.nTrkTPCneg(); - values[kMultAPOS] = collision.nTrkTPCpos(); - values[kMultANEG] = collision.nTrkTPCneg(); - values[kMultB] = collision.sumAmplFT0A(); // Be careful, this is weighted sum of multiplicity - values[kMultC] = collision.sumAmplFT0C(); // Be careful, this is weighted sum of multiplicity - - // Q-vectors components correlation (A, B, C) - values[kQ2YYAB] = values[kQ2Y0A] * values[kQ2Y0B]; - values[kQ2XXAB] = values[kQ2X0A] * values[kQ2X0B]; - values[kQ2XYAB] = values[kQ2X0A] * values[kQ2Y0B]; - values[kQ2YXAB] = values[kQ2Y0A] * values[kQ2X0B]; - values[kQ2YYAC] = values[kQ2Y0A] * values[kQ2Y0C]; - values[kQ2XXAC] = values[kQ2X0A] * values[kQ2X0C]; - values[kQ2XYAC] = values[kQ2X0A] * values[kQ2Y0C]; - values[kQ2YXAC] = values[kQ2Y0A] * values[kQ2X0C]; - values[kQ2YYBC] = values[kQ2Y0B] * values[kQ2Y0C]; - values[kQ2XXBC] = values[kQ2X0B] * values[kQ2X0C]; - values[kQ2XYBC] = values[kQ2X0B] * values[kQ2Y0C]; - values[kQ2YXBC] = values[kQ2Y0B] * values[kQ2X0C]; - - EventPlaneHelper epHelper; - float Psi2A = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); - float Psi2APOS = epHelper.GetEventPlane(values[kQ2X0APOS], values[kQ2Y0APOS], 2); - float Psi2ANEG = epHelper.GetEventPlane(values[kQ2X0ANEG], values[kQ2Y0ANEG], 2); - float Psi2B = epHelper.GetEventPlane(values[kQ2X0B], values[kQ2Y0B], 2); - float Psi2C = epHelper.GetEventPlane(values[kQ2X0C], values[kQ2Y0C], 2); - - values[kPsi2A] = Psi2A; - values[kPsi2APOS] = Psi2APOS; - values[kPsi2ANEG] = Psi2ANEG; - values[kPsi2B] = Psi2B; - values[kPsi2C] = Psi2C; - - values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); - values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); - values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); - values[kR2SP_FT0CTPCPOS] = (xQVecFT0c * xQVecBPos + yQVecFT0c * yQVecBPos); - values[kR2SP_FT0CTPCNEG] = (xQVecFT0c * xQVecBNeg + yQVecFT0c * yQVecBNeg); - values[kR2SP_FT0ATPCPOS] = (xQVecFT0a * xQVecBPos + yQVecFT0a * yQVecBPos); - values[kR2SP_FT0ATPCNEG] = (xQVecFT0a * xQVecBNeg + yQVecFT0a * yQVecBNeg); - values[kR2SP_FT0MTPCPOS] = (xQVecFT0m * xQVecBPos + yQVecFT0m * yQVecBPos); - values[kR2SP_FT0MTPCNEG] = (xQVecFT0m * xQVecBNeg + yQVecFT0m * yQVecBNeg); - values[kR2SP_FV0ATPCPOS] = (xQVecFV0a * xQVecBPos + yQVecFV0a * yQVecBPos); - values[kR2SP_FV0ATPCNEG] = (xQVecFV0a * xQVecBNeg + yQVecFV0a * yQVecBNeg); - - float epFT0a = epHelper.GetEventPlane(xQVecFT0a, yQVecFT0a, 2); - float epFT0c = epHelper.GetEventPlane(xQVecFT0c, yQVecFT0c, 2); - float epFT0m = epHelper.GetEventPlane(xQVecFT0m, yQVecFT0m, 2); - float epFV0a = epHelper.GetEventPlane(xQVecFV0a, yQVecFV0a, 2); - float epBPoss = epHelper.GetEventPlane(xQVecBPos, yQVecBPos, 2); - float epBNegs = epHelper.GetEventPlane(xQVecBNeg, yQVecBNeg, 2); - float epTPCFull = epHelper.GetEventPlane(values[kQ2X0A], values[kQ2Y0A], 2); - - values[kR2EP_AB] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0a, 2)); - values[kR2EP_AC] = TMath::Cos(2 * getDeltaPsiInRange(epTPCFull, epFT0c, 2)); - values[kR2EP_BC] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epFT0c, 2)); - values[kR2EP_FT0CTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBPoss, 2)); - values[kR2EP_FT0CTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0c, epBNegs, 2)); - values[kR2EP_FT0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBPoss, 2)); - values[kR2EP_FT0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0a, epBNegs, 2)); - values[kR2EP_FT0MTPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBPoss, 2)); - values[kR2EP_FT0MTPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFT0m, epBNegs, 2)); - values[kR2EP_FV0ATPCPOS] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBPoss, 2)); - values[kR2EP_FV0ATPCNEG] = TMath::Cos(2 * getDeltaPsiInRange(epFV0a, epBNegs, 2)); -} - -template -void VarManager::FillSpectatorPlane(C const& collision, float* values) -{ - if (!values) { - values = fgValues; - } - - auto zncEnergy = collision.energySectorZNC(); - auto znaEnergy = collision.energySectorZNA(); - for (int i = 0; i < 4; i++) { // avoid std::numeric_limits::infinity() in the table - if (zncEnergy[i] < -1.e12) { - zncEnergy[i] = -1.f; - } - if (znaEnergy[i] < -1.e12) { - znaEnergy[i] = -1.f; - } - } - float znaCommon = collision.energyCommonZNA() < 0 ? -1.f : collision.energyCommonZNA(); - float zncCommon = collision.energyCommonZNC() < 0 ? -1.f : collision.energyCommonZNC(); - float zpaCommon = collision.energyCommonZPA() < 0 ? -1.f : collision.energyCommonZPA(); - float zpcCommon = collision.energyCommonZPC() < 0 ? -1.f : collision.energyCommonZPC(); - - // Store ZNA and ZNC energies for calibrations - values[kEnergyCommonZNA] = znaCommon; - values[kEnergyCommonZNC] = zncCommon; - values[kEnergyCommonZPA] = zpaCommon; - values[kEnergyCommonZPC] = zpcCommon; - values[kEnergyZNA1] = znaEnergy[0]; - values[kEnergyZNA2] = znaEnergy[1]; - values[kEnergyZNA3] = znaEnergy[2]; - values[kEnergyZNA4] = znaEnergy[3]; - values[kEnergyZNC1] = zncEnergy[0]; - values[kEnergyZNC2] = zncEnergy[1]; - values[kEnergyZNC3] = zncEnergy[2]; - values[kEnergyZNC4] = zncEnergy[3]; - values[kTimeZNA] = collision.timeZNA(); - values[kTimeZNC] = collision.timeZNC(); - values[kTimeZPA] = collision.timeZPA(); - values[kTimeZPC] = collision.timeZPC(); - - constexpr float beamEne = 5.36 * 0.5; - constexpr float x[4] = {-1.75, 1.75, -1.75, 1.75}; - constexpr float y[4] = {-1.75, -1.75, 1.75, 1.75}; - // constexpr float intcalibZNA[4] = {0.7997028, 0.8453715, 0.7879917, 0.7695486}; - // constexpr float intcalibZNC[4] = {0.7631577, 0.8408003, 0.7083920, 0.7731769}; - // constexpr float alpha = 0.395; // WARNING: Run 2 coorection, to be checked - constexpr float alpha = 1.; - float numXZNC = 0., numYZNC = 0., denZNC = 0.; - float numXZNA = 0., numYZNA = 0., denZNA = 0.; - - float sumZNA = 0; - float sumZNC = 0; - - for (int i = 0; i < 4; i++) { - if (zncEnergy[i] > 0.) { - float wZNC = std::pow(zncEnergy[i], alpha); - // sumZNC += intcalibZNC[i] * wZNC; - sumZNC += wZNC; - numXZNC -= x[i] * wZNC; - numYZNC += y[i] * wZNC; - denZNC += wZNC; - } - if (znaEnergy[i] > 0.) { - float wZNA = std::pow(znaEnergy[i], alpha); - // sumZNA += intcalibZNA[i] * wZNA; - sumZNA += wZNA; - numXZNA += x[i] * wZNA; - numYZNA += y[i] * wZNA; - denZNA += wZNA; - } - } - - if (denZNC != 0.) { - float nSpecnC = zncCommon / beamEne; // WARNING: Run 2 coorection, to be checked - float cZNC = 1.89358 - 0.71262 / (nSpecnC + 0.71789); // WARNING: Run 2 coorection, to be checked - cZNC = 1.; - values[kQ1ZNCX] = cZNC * numXZNC / denZNC; - values[kQ1ZNCY] = cZNC * numYZNC / denZNC; - } else { - values[kQ1ZNCX] = values[kQ1ZNCY] = 999.; - } - - if (denZNA != 0.) { - float nSpecnA = znaCommon / beamEne; // WARNING: Run 2 coorection, to be checked - float cZNA = 1.89358 - 0.71262 / (nSpecnA + 0.71789); // WARNING: Run 2 coorection, to be checked - cZNA = 1.; - values[kQ1ZNAX] = cZNA * numXZNA / denZNA; - values[kQ1ZNAY] = cZNA * numYZNA / denZNA; - } else { - values[kQ1ZNAX] = values[kQ1ZNAY] = 999.; - } - - if (denZNA != 0. && denZNC != 0.) { - values[kQ1ZNACXX] = values[kQ1ZNAX] * values[kQ1ZNCX]; - values[kQ1ZNACYY] = values[kQ1ZNAY] * values[kQ1ZNCY]; - values[kQ1ZNACYX] = values[kQ1ZNAY] * values[kQ1ZNCX]; - values[kQ1ZNACXY] = values[kQ1ZNAX] * values[kQ1ZNCY]; - } else { - values[kQ1ZNACXX] = values[kQ1ZNACYY] = values[kQ1ZNACYX] = values[kQ1ZNACXY] = 999.; - } - - if (znaCommon != 0 && sumZNA != 0 && zncCommon != 0 && sumZNC) { - values[KIntercalibZNA] = znaCommon - sumZNA; - values[KIntercalibZNC] = zncCommon - sumZNC; - } -} - -template -void VarManager::FillPairVn(T1 const& t1, T2 const& t2, float* values) -{ - - if (!values) { - values = fgValues; - } - - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if constexpr (pairType == kDecayToMuMu) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - - if constexpr (pairType == kDecayToPiPi) { - m1 = o2::constants::physics::MassPionCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if constexpr (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - - // Fill dilepton information - 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; - values[kPt1] = t1.pt(); - values[kPt2] = t2.pt(); - - // TODO: provide different computations for vn - // Compute the scalar product UQ using Q-vector from A, for second and third harmonic - // Dilepton vn could be accessible after dividing this product with the R factor - values[kU2Q2] = values[kQ2X0A] * TMath::Cos(2 * v12.Phi()) + values[kQ2Y0A] * TMath::Sin(2 * v12.Phi()); - values[kU3Q3] = values[kQ3X0A] * TMath::Cos(3 * v12.Phi()) + values[kQ3Y0A] * TMath::Sin(3 * v12.Phi()); - values[kR2SP_AB] = (values[kQ2X0A] * values[kQ2X0B] + values[kQ2Y0A] * values[kQ2Y0B]); - values[kR2SP_AC] = (values[kQ2X0A] * values[kQ2X0C] + values[kQ2Y0A] * values[kQ2Y0C]); - values[kR2SP_BC] = (values[kQ2X0B] * values[kQ2X0C] + values[kQ2Y0B] * values[kQ2Y0C]); - values[kR3SP] = (values[kQ3X0B] * values[kQ3X0C] + values[kQ3Y0B] * values[kQ3Y0C]); - - float Psi2A = getEventPlane(2, values[kQ2X0A], values[kQ2Y0A]); - float Psi3A = getEventPlane(3, values[kQ3X0A], values[kQ3Y0A]); - float Psi2B = getEventPlane(2, values[kQ2X0B], values[kQ2Y0B]); - float Psi3B = getEventPlane(3, values[kQ3X0B], values[kQ3Y0B]); - float Psi2C = getEventPlane(2, values[kQ2X0C], values[kQ2Y0C]); - float Psi3C = getEventPlane(3, values[kQ3X0C], values[kQ3Y0C]); - values[kCos2DeltaPhi] = TMath::Cos(2 * (v12.Phi() - Psi2A)); - values[kCos3DeltaPhi] = TMath::Cos(3 * (v12.Phi() - Psi3A)); - values[kR2EP_AB] = TMath::Cos(2 * (Psi2A - Psi2B)); - values[kR2EP_AC] = TMath::Cos(2 * (Psi2A - Psi2C)); - values[kR2EP_BC] = TMath::Cos(2 * (Psi2B - Psi2C)); - values[kR3EP] = TMath::Cos(3 * (Psi3B - Psi3C)); - - float V2SP = values[kU2Q2] / values[kR2SP]; - float V2EP = values[kCos2DeltaPhi] / values[kR2EP]; - values[kV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : V2SP; - values[kWV2SP] = std::isnan(V2SP) || std::isinf(V2SP) ? 0. : 1.0; - values[kV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : V2EP; - values[kWV2EP] = std::isnan(V2EP) || std::isinf(V2EP) ? 0. : 1.0; - - if (std::isnan(VarManager::fgValues[VarManager::kU2Q2]) == true) { - values[kU2Q2] = -999.; - values[kR2SP_AB] = -999.; - values[kR2SP_AC] = -999.; - values[kR2SP_BC] = -999.; - } - if (std::isnan(VarManager::fgValues[VarManager::kU3Q3]) == true) { - values[kU3Q3] = -999.; - values[kR3SP] = -999.; - } - if (std::isnan(VarManager::fgValues[VarManager::kCos2DeltaPhi]) == true) { - values[kCos2DeltaPhi] = -999.; - values[kR2EP_AB] = -999.; - values[kR2EP_AC] = -999.; - values[kR2EP_BC] = -999.; - } - if (std::isnan(VarManager::fgValues[VarManager::kCos3DeltaPhi]) == true) { - values[kCos3DeltaPhi] = -999.; - values[kR3EP] = -999.; - } - - // global polarization parameters - bool useGlobalPolarizatiobSpinOne = fgUsedVars[kCosThetaStarTPC] || fgUsedVars[kCosThetaStarFT0A] || fgUsedVars[kCosThetaStarFT0C]; - if (useGlobalPolarizatiobSpinOne) { - ROOT::Math::Boost boostv12{v12.BoostToCM()}; - ROOT::Math::XYZVectorF v1_CM{(boostv12(v1).Vect()).Unit()}; - ROOT::Math::XYZVectorF v2_CM{(boostv12(v2).Vect()).Unit()}; - - // using positive sign convention for the first track - ROOT::Math::XYZVectorF v_CM = (t1.sign() > 0 ? v1_CM : v2_CM); - - ROOT::Math::XYZVector zaxisTPC = ROOT::Math::XYZVector(TMath::Cos(Psi2A), TMath::Sin(Psi2A), 0).Unit(); - values[kCosThetaStarTPC] = v_CM.Dot(zaxisTPC); - - ROOT::Math::XYZVector zaxisFT0A = ROOT::Math::XYZVector(TMath::Cos(Psi2B), TMath::Sin(Psi2B), 0).Unit(); - values[kCosThetaStarFT0A] = v_CM.Dot(zaxisFT0A); - - ROOT::Math::XYZVector zaxisFT0C = ROOT::Math::XYZVector(TMath::Cos(Psi2C), TMath::Sin(Psi2C), 0).Unit(); - values[kCosThetaStarFT0C] = v_CM.Dot(zaxisFT0C); - } - - // kV4, kC4POI, kC4REF etc. - if constexpr ((fillMap & ReducedEventQvectorExtra) > 0) { - complex Q21(values[kQ2X0A] * values[kS11A], values[kQ2Y0A] * values[kS11A]); - complex Q42(values[kQ42XA], values[kQ42YA]); - complex Q23(values[kQ23XA], values[kQ23YA]); - complex P2(TMath::Cos(2 * v12.Phi()), TMath::Sin(2 * v12.Phi())); - values[kM01POI] = values[kMultDimuons] * values[kS11A]; - values[kM0111POI] = values[kMultDimuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); - values[kCORR2POI] = (P2 * conj(Q21)).real() / values[kM01POI]; - values[kCORR4POI] = (P2 * Q21 * conj(Q21) * conj(Q21) - P2 * Q21 * conj(Q42) - 2. * values[kS12A] * P2 * conj(Q21) + 2. * P2 * conj(Q23)).real() / values[kM0111POI]; - values[kM01POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? values[kM01POI] / values[kMultDimuons] : 0; - values[kM0111POIoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? values[kM0111POI] / values[kMultDimuons] : 0; - values[kM11REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultDimuons] : 0; - values[kM1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF])) ? values[kM1111REF] / values[kMultDimuons] : 0; - values[kCORR2REFbydimuons] = std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) ? 0 : values[kCORR2REF]; - values[kCORR4REFbydimuons] = std::isnan(values[kM1111REFoverMp]) || std::isinf(values[kM1111REFoverMp]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF]) || std::isnan(values[kM11REFoverMp]) || std::isinf(values[kM11REFoverMp]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) ? 0 : values[kCORR4REF]; - values[kCORR2POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI]; - values[kCORR4POI] = std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR4POI]; - values[kCORR2CORR4REF] = std::isnan(values[kM11M1111REFoverMp]) || std::isinf(values[kM11M1111REFoverMp]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF]) ? 0 : values[kCORR2CORR4REF]; - values[kCORR2POICORR4POI] = std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2POI] * values[kCORR4POI]; - values[kCORR2REFCORR4POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) ? 0 : values[kCORR2REF] * values[kCORR4POI]; - values[kCORR2REFCORR2POI] = std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) ? 0 : values[kCORR2REF] * values[kCORR2POI]; - values[kM11M1111REFoverMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11M1111REF]) || std::isinf(values[kM11M1111REF]) || std::isnan(values[kCORR2CORR4REF]) || std::isinf(values[kCORR2CORR4REF])) ? values[kM11M1111REF] / values[kMultDimuons] : 0; - values[kM01M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM01POI] * values[kM0111POI]) / values[kMultDimuons] : 0; - values[kM11M0111overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM0111POI]) || std::isinf(values[kM0111POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR4POI]) || std::isinf(values[kCORR4POI])) ? (values[kM11REF] * values[kM0111POI]) / values[kMultDimuons] : 0; - values[kM11M01overMp] = values[kMultDimuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kM01POI]) || std::isinf(values[kM01POI]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kCORR2POI]) || std::isinf(values[kCORR2POI])) ? (values[kM11REF] * values[kM01POI]) / values[kMultDimuons] : 0; - - complex P2plus(TMath::Cos(2 * v1.Phi()), TMath::Sin(2 * v1.Phi())); - complex P2minus(TMath::Cos(2 * v2.Phi()), TMath::Sin(2 * v2.Phi())); - values[kM11REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultAntiMuons] : 0; - values[kM1111REFoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultAntiMuons] : 0; - values[kM11REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM11REF] / values[kMultMuons] : 0; - values[kM1111REFoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM11REF]) || std::isinf(values[kM11REF]) || std::isnan(values[kCORR2REF]) || std::isinf(values[kCORR2REF]) || std::isnan(values[kM1111REF]) || std::isinf(values[kM1111REF]) || std::isnan(values[kCORR4REF]) || std::isinf(values[kCORR4REF])) ? values[kM1111REF] / values[kMultMuons] : 0; - values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POI]; - values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POI]; - values[kM01POIplus] = values[kMultAntiMuons] * values[kS11A]; - values[kM0111POIplus] = values[kMultAntiMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); - values[kCORR2POIplus] = (P2plus * conj(Q21)).real() / values[kM01POIplus]; - values[kCORR4POIplus] = (P2plus * Q21 * conj(Q21) * conj(Q21) - P2plus * Q21 * conj(Q42) - 2. * values[kS12A] * P2plus * conj(Q21) + 2. * P2plus * conj(Q23)).real() / values[kM0111POIplus]; - values[kM01POIminus] = values[kMultMuons] * values[kS11A]; - values[kM0111POIminus] = values[kMultMuons] * (values[kS31A] - 3. * values[kS11A] * values[kS12A] + 2. * values[kS13A]); - values[kCORR2POIminus] = (P2minus * conj(Q21)).real() / values[kM01POIminus]; - values[kCORR4POIminus] = (P2minus * Q21 * conj(Q21) * conj(Q21) - P2minus * Q21 * conj(Q42) - 2. * values[kS12A] * P2minus * conj(Q21) + 2. * P2minus * conj(Q23)).real() / values[kM0111POIminus]; - values[kM01POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM01POIplus]; - values[kM0111POIplus] = std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kM0111POIplus]; - values[kCORR2POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR2POIplus]; - values[kCORR4POIplus] = std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) ? 0 : values[kCORR4POIplus]; - values[kM01POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM01POIminus]; - values[kM0111POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kM0111POIminus]; - values[kCORR2POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR2POIminus]; - values[kCORR4POIminus] = std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) ? 0 : values[kCORR4POIminus]; - values[kM01POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM01POIminus] / values[kMultMuons] : 0; - values[kM0111POIoverMpminus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIminus]) || std::isinf(values[kM0111POIminus]) || std::isnan(values[kCORR4POIminus]) || std::isinf(values[kCORR4POIminus]) || std::isnan(values[kM01POIminus]) || std::isinf(values[kM01POIminus]) || std::isnan(values[kCORR2POIminus]) || std::isinf(values[kCORR2POIminus])) ? values[kM0111POIminus] / values[kMultMuons] : 0; - values[kM01POIoverMpplus] = values[kMultAntiMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM01POIplus] / values[kMultAntiMuons] : 0; - values[kM0111POIoverMpplus] = values[kMultMuons] > 0 && !(std::isnan(values[kM0111POIplus]) || std::isinf(values[kM0111POIplus]) || std::isnan(values[kCORR4POIplus]) || std::isinf(values[kCORR4POIplus]) || std::isnan(values[kM01POIplus]) || std::isinf(values[kM01POIplus]) || std::isnan(values[kCORR2POIplus]) || std::isinf(values[kCORR2POIplus])) ? values[kM0111POIplus] / values[kMultAntiMuons] : 0; - } - - ROOT::Math::PtEtaPhiMVector v1_vp(v1.Pt(), v1.Eta(), v1.Phi() - Psi2B, v1.M()); - ROOT::Math::PtEtaPhiMVector v2_vp(v2.Pt(), v2.Eta(), v2.Phi() - Psi2B, v2.M()); - ROOT::Math::PtEtaPhiMVector v12_vp = v1_vp + v2_vp; - auto p12_vp = ROOT::Math::XYZVectorF(v12_vp.Px(), v12_vp.Py(), v12_vp.Pz()); - auto p12_vp_projXZ = ROOT::Math::XYZVectorF(p12_vp.X(), 0, p12_vp.Z()); - auto vDimu = (t1.sign() > 0 ? ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz())) - : ROOT::Math::XYZVectorF(v2_vp.Px(), v2_vp.Py(), v2_vp.Pz()).Cross(ROOT::Math::XYZVectorF(v1_vp.Px(), v1_vp.Py(), v1_vp.Pz()))); - auto vRef = p12_vp.Cross(p12_vp_projXZ); - values[kCosPhiVP] = vDimu.Dot(vRef) / (vRef.R() * vDimu.R()); - values[kPhiVP] = std::acos(vDimu.Dot(vRef) / (vRef.R() * vDimu.R())); -} - -template -void VarManager::FillZDC(T const& zdc, float* values) -{ - if (!values) { - values = fgValues; - } - - values[kEnergyCommonZNA] = (zdc.energyCommonZNA() > 0) ? zdc.energyCommonZNA() : -1.; - values[kEnergyCommonZNC] = (zdc.energyCommonZNC() > 0) ? zdc.energyCommonZNC() : -1.; - values[kEnergyCommonZPA] = (zdc.energyCommonZPA() > 0) ? zdc.energyCommonZPA() : -1.; - values[kEnergyCommonZPC] = (zdc.energyCommonZPC() > 0) ? zdc.energyCommonZPC() : -1.; - values[kTimeZNA] = zdc.timeZNA(); - values[kTimeZNC] = zdc.timeZNC(); - values[kTimeZPA] = zdc.timeZPA(); - values[kTimeZPC] = zdc.timeZPC(); -} - -template -void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values, float hadronMass) -{ - if (!values) { - values = fgValues; - } - - 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; - values[kPairMass] = v12.M(); - values[kPairPt] = v12.Pt(); - values[kPairEta] = v12.Eta(); - values[kPairPhi] = v12.Phi(); - values[kPairMassDau] = dilepton.mass(); - values[kPairPtDau] = dilepton.pt(); - values[kMassDau] = hadronMass; - values[kDeltaMass] = v12.M() - dilepton.mass(); - // Calculate kstar of Dilepton and hadron pair - ROOT::Math::PtEtaPhiMVector v12_Qvect = v1 - v2; - 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] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { - 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] = RecoDecay::constrainAngle(v2.phi(), -o2::constants::math::PIHalf); - - float deltaphi = RecoDecay::constrainAngle(v1.phi() - v2.phi(), -o2::constants::math::PIHalf); - values[kCosChi_randomPhi_trans] = -999.9f; - values[kCosChi_randomPhi_toward] = -999.9f; - values[kCosChi_randomPhi_away] = -999.9f; - - values[kdeltaphi_randomPhi_trans] = -999.9f; - values[kdeltaphi_randomPhi_toward] = -999.9f; - values[kdeltaphi_randomPhi_away] = -999.9f; - - float randomPhi_trans = -o2::constants::math::PIHalf; - float randomPhi_toward = -o2::constants::math::PIHalf; - float randomPhi_away = -o2::constants::math::PIHalf; - - if ((deltaphi > -0.5 * TMath::Pi() && deltaphi < -1. / 3 * TMath::Pi()) || (deltaphi > 4. / 3 * TMath::Pi() && deltaphi < 1.5 * TMath::Pi()) || (deltaphi > 1. / 3 * TMath::Pi() && deltaphi < 2. / 3 * TMath::Pi())) { - randomPhi_trans = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_toward = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - randomPhi_away = gRandom->Uniform(-o2::constants::math::PIHalf, 3. * o2::constants::math::PIHalf); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_trans(v2.pt(), v2.eta(), randomPhi_trans, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_trans] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_trans); - values[kWeight_randomPhi_trans] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_trans) / v1.M(); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_toward(v2.pt(), v2.eta(), randomPhi_toward, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_toward] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_toward); - values[kWeight_randomPhi_toward] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_toward) / v1.M(); - - ROOT::Math::PtEtaPhiMVector v2_randomPhi_away(v2.pt(), v2.eta(), randomPhi_away, o2::constants::physics::MassPionCharged); - values[kCosChi_randomPhi_away] = LorentzTransformJpsihadroncosChi("coschi", v1, v2_randomPhi_away); - values[kWeight_randomPhi_away] = LorentzTransformJpsihadroncosChi("weight_boost", v1, v2_randomPhi_away) / v1.M(); - - values[kdeltaphi_randomPhi_trans] = RecoDecay::constrainAngle(v1.phi() - randomPhi_trans, -o2::constants::math::PIHalf); - values[kdeltaphi_randomPhi_toward] = RecoDecay::constrainAngle(v1.phi() - randomPhi_toward, -o2::constants::math::PIHalf); - values[kdeltaphi_randomPhi_away] = RecoDecay::constrainAngle(v1.phi() - randomPhi_away, -o2::constants::math::PIHalf); - } - } - - if (fgUsedVars[kDeltaPhi]) { - double delta = dilepton.phi() - hadron.phi(); - if (delta > 3.0 / 2.0 * M_PI) { - delta -= 2.0 * M_PI; - } - if (delta < -0.5 * M_PI) { - delta += 2.0 * M_PI; - } - values[kDeltaPhi] = delta; - } - if (fgUsedVars[kDeltaPhiSym]) { - double delta = std::abs(dilepton.phi() - hadron.phi()); - if (delta > M_PI) { - delta = 2 * M_PI - delta; - } - values[kDeltaPhiSym] = delta; - } - if (fgUsedVars[kDeltaEta]) { - values[kDeltaEta] = dilepton.eta() - hadron.eta(); - } -} - -template -void VarManager::FillDileptonPhoton(T1 const& dilepton, T2 const& photon, float* values) -{ - if (!values) { - values = fgValues; - } - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi]) { - ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); - ROOT::Math::PtEtaPhiMVector v2(photon.pt(), photon.eta(), photon.phi(), photon.mGamma()); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - values[kPairMass] = v12.M(); - values[kPairPt] = v12.Pt(); - values[kPairEta] = v12.Eta(); - values[kPairPhi] = v12.Phi(); - values[kPairMassDau] = dilepton.mass(); - values[kMassDau] = photon.mGamma(); - values[kPairPtDau] = dilepton.pt(); - values[kPt] = photon.pt(); - values[kDeltaEta] = dilepton.eta(); - values[kEta] = photon.eta(); - values[VarManager::kDeltaMass] = v12.M() - dilepton.mass(); - float m4 = o2::constants::physics::MassJPsi; - values[VarManager::kDeltaMass_jpsi] = v12.M() - dilepton.mass() + m4; - values[kRap] = v12.Rapidity(); - } -} - -template -void VarManager::FillHadron(T const& hadron, float* values, float hadronMass) -{ - if (!values) { - values = fgValues; - } - - ROOT::Math::PtEtaPhiMVector vhadron(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); - values[kMass] = hadronMass; - values[kPt] = hadron.pt(); - values[kEta] = hadron.eta(); - values[kPhi] = hadron.phi(); - values[kRap] = vhadron.Rapidity(); -} - -template -void VarManager::FillSingleDileptonCharmHadron(Cand const& candidate, H hfHelper, T& bdtScoreCharmHad, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr (partType == kJPsi) { - values[kMass] = candidate.mass(); - values[kPt] = candidate.pt(); - values[kPhi] = candidate.phi(); - values[kRap] = candidate.rap(); - } - if constexpr (partType == kD0ToPiK) { - values[kMassCharmHadron] = hfHelper.invMassD0ToPiK(candidate); - values[kPtCharmHadron] = candidate.pt(); - values[kPhiCharmHadron] = candidate.phi(); - values[kRapCharmHadron] = hfHelper.yD0(candidate); - values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); - } - if constexpr (partType == kD0barToKPi) { - values[kMassCharmHadron] = hfHelper.invMassD0barToKPi(candidate); - values[kPtCharmHadron] = candidate.pt(); - values[kPhiCharmHadron] = candidate.phi(); - values[kRapCharmHadron] = hfHelper.yD0(candidate); - values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); - } -} - -template -void VarManager::FillDileptonCharmHadron(DQ const& dilepton, HF const& charmHadron, H hfHelper, T& bdtScoreCharmHad, float* values) -{ - FillSingleDileptonCharmHadron(dilepton, hfHelper, bdtScoreCharmHad, values); - FillSingleDileptonCharmHadron(charmHadron, hfHelper, bdtScoreCharmHad, values); -} - -template -void VarManager::FillDileptonTrackTrack(T1 const& dilepton, T2 const& hadron1, T3 const& hadron2, float* values) -{ - if (!values) { - values = fgValues; - } - - double defaultDileptonMass = 3.096; - double hadronMass1 = o2::constants::physics::MassPionCharged; - double hadronMass2 = o2::constants::physics::MassPionCharged; - if (candidateType == kXtoJpsiPiPi) { - defaultDileptonMass = 3.096; - hadronMass1 = o2::constants::physics::MassPionCharged; - hadronMass2 = o2::constants::physics::MassPionCharged; - } - if (candidateType == kChictoJpsiEE) { - defaultDileptonMass = 3.096; - hadronMass1 = o2::constants::physics::MassElectron; - hadronMass2 = o2::constants::physics::MassElectron; - } - - ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); - ROOT::Math::PtEtaPhiMVector v2(hadron1.pt(), hadron1.eta(), hadron1.phi(), hadronMass1); - ROOT::Math::PtEtaPhiMVector v3(hadron2.pt(), hadron2.eta(), hadron2.phi(), hadronMass2); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - values[kQuadMass] = v123.M(); - values[kQuadDefaultDileptonMass] = v123.M() - v1.M() + defaultDileptonMass; - values[kQuadPt] = v123.Pt(); - values[kQuadEta] = v123.Eta(); - values[kQuadPhi] = v123.Phi(); - - values[kTrackDCAxyProng1] = hadron1.dcaXY(); - values[kTrackDCAzProng1] = hadron1.dcaZ(); - values[kPt1] = hadron1.pt(); - - values[kTrackDCAxyProng2] = hadron2.dcaXY(); - values[kTrackDCAzProng2] = hadron2.dcaZ(); - values[kPt2] = hadron2.pt(); - - if (fgUsedVars[kCosthetaDileptonDitrack] || fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kDitrackPt] || fgUsedVars[kDitrackMass] || fgUsedVars[kQ] || fgUsedVars[kDeltaR1] || fgUsedVars[kDeltaR2] || fgUsedVars[kRap]) { - ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; - values[kPairMass] = v1.M(); - values[kPairPt] = v1.Pt(); - values[kDitrackMass] = v23.M(); - values[kDitrackPt] = v23.Pt(); - values[kCosthetaDileptonDitrack] = (v1.Px() * v123.Px() + v1.Py() * v123.Py() + v1.Pz() * v123.Pz()) / (v1.P() * v123.P()); - values[kQ] = v123.M() - defaultDileptonMass - v23.M(); - values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); - values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); - values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); - values[kRap] = v123.Rapidity(); - } -} - -//__________________________________________________________________ -template -void VarManager::FillDileptonTrackTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track1, T1 const& track2, float* values) -{ - constexpr bool eventHasVtxCov = ((collFillMap & Collision) > 0 || (collFillMap & ReducedEventVtxCov) > 0); - constexpr bool trackHasCov = ((fillMap & TrackCov) > 0 || (fillMap & ReducedTrackBarrelCov) > 0); - - if (!eventHasVtxCov || !trackHasCov) { - return; - } - - if (!values) { - values = fgValues; - } - - float mtrack1, mtrack2; - float mlepton1, mlepton2; - - if constexpr (candidateType == kXtoJpsiPiPi || candidateType == kPsi2StoJpsiPiPi) { - mlepton1 = o2::constants::physics::MassElectron; - mlepton2 = o2::constants::physics::MassElectron; - mtrack1 = o2::constants::physics::MassPionCharged; - mtrack2 = o2::constants::physics::MassPionCharged; - } - - ROOT::Math::PtEtaPhiMVector v1(lepton1.pt(), lepton1.eta(), lepton1.phi(), mlepton1); - ROOT::Math::PtEtaPhiMVector v2(lepton2.pt(), lepton2.eta(), lepton2.phi(), mlepton2); - ROOT::Math::PtEtaPhiMVector v3(track1.pt(), track1.eta(), track1.phi(), mtrack1); - ROOT::Math::PtEtaPhiMVector v4(track2.pt(), track2.eta(), track2.phi(), mtrack2); - ROOT::Math::PtEtaPhiMVector v1234 = v1 + v2 + v3 + v4; - - int procCodeDilepton = 0; - int procCodeDileptonTrackTrack = 0; - - values[kUsedKF] = fgUsedKF; - if (!fgUsedKF) { - // create covariance matrix - std::array lepton1pars = {lepton1.y(), lepton1.z(), lepton1.snp(), lepton1.tgl(), lepton1.signed1Pt()}; - std::array lepton1covs = {lepton1.cYY(), lepton1.cZY(), lepton1.cZZ(), lepton1.cSnpY(), lepton1.cSnpZ(), - lepton1.cSnpSnp(), lepton1.cTglY(), lepton1.cTglZ(), lepton1.cTglSnp(), lepton1.cTglTgl(), - lepton1.c1PtY(), lepton1.c1PtZ(), lepton1.c1PtSnp(), lepton1.c1PtTgl(), lepton1.c1Pt21Pt2()}; - o2::track::TrackParCov pars1{lepton1.x(), lepton1.alpha(), lepton1pars, lepton1covs}; - std::array lepton2pars = {lepton2.y(), lepton2.z(), lepton2.snp(), lepton2.tgl(), lepton2.signed1Pt()}; - std::array lepton2covs = {lepton2.cYY(), lepton2.cZY(), lepton2.cZZ(), lepton2.cSnpY(), lepton2.cSnpZ(), - lepton2.cSnpSnp(), lepton2.cTglY(), lepton2.cTglZ(), lepton2.cTglSnp(), lepton2.cTglTgl(), - lepton2.c1PtY(), lepton2.c1PtZ(), lepton2.c1PtSnp(), lepton2.c1PtTgl(), lepton2.c1Pt21Pt2()}; - o2::track::TrackParCov pars2{lepton2.x(), lepton2.alpha(), lepton2pars, lepton2covs}; - std::array track1pars = {track1.y(), track1.z(), track1.snp(), track1.tgl(), track1.signed1Pt()}; - std::array track1covs = {track1.cYY(), track1.cZY(), track1.cZZ(), track1.cSnpY(), track1.cSnpZ(), - track1.cSnpSnp(), track1.cTglY(), track1.cTglZ(), track1.cTglSnp(), track1.cTglTgl(), - track1.c1PtY(), track1.c1PtZ(), track1.c1PtSnp(), track1.c1PtTgl(), track1.c1Pt21Pt2()}; - o2::track::TrackParCov pars3{track1.x(), track1.alpha(), track1pars, track1covs}; - std::array track2pars = {track2.y(), track2.z(), track2.snp(), track2.tgl(), track2.signed1Pt()}; - std::array track2covs = {track2.cYY(), track2.cZY(), track2.cZZ(), track2.cSnpY(), track2.cSnpZ(), - track2.cSnpSnp(), track2.cTglY(), track2.cTglZ(), track2.cTglSnp(), track2.cTglTgl(), - track2.c1PtY(), track2.c1PtZ(), track2.c1PtSnp(), track2.c1PtTgl(), track2.c1Pt21Pt2()}; - o2::track::TrackParCov pars4{track2.x(), track2.alpha(), track2pars, track2covs}; - - procCodeDilepton = VarManager::fgFitterTwoProngBarrel.process(pars1, pars2); - // create dilepton track - // o2::track::TrackParCov parsDilepton = VarManager::fgFitterTwoProngBarrel.createParentTrackParCov(0); - // procCodeDileptonTrackTrack = VarManager::fgFitterThreeProngBarrel.process(parsDilepton, pars3, pars4); - procCodeDileptonTrackTrack = VarManager::fgFitterFourProngBarrel.process(pars1, pars2, pars3, pars4); - - // fill values - if (procCodeDilepton == 0 && procCodeDileptonTrackTrack == 0) { - // TODO: set the other variables to appropriate values and return - values[kVertexingLxy] = -999.; - values[kVertexingLxyz] = -999.; - values[kVertexingLz] = -999.; - values[kVertexingLxyErr] = -999.; - values[kVertexingLxyzErr] = -999.; - values[kVertexingLzErr] = -999.; - values[kVertexingTauxy] = -999.; - values[kVertexingTauxyErr] = -999.; - values[kVertexingTauz] = -999.; - values[kVertexingTauzErr] = -999.; - values[kVertexingLzProjected] = -999.; - values[kVertexingLxyProjected] = -999.; - values[kVertexingLxyzProjected] = -999.; - values[kVertexingTauzProjected] = -999.; - values[kVertexingTauxyProjected] = -999.; - values[kVertexingTauxyzProjected] = -999.; - return; - } else { - Vec3D secondaryVertex; - std::array covMatrixPCA; - secondaryVertex = fgFitterFourProngBarrel.getPCACandidate(); - covMatrixPCA = fgFitterFourProngBarrel.calcPCACovMatrixFlat(); - - o2::math_utils::Point3D vtxXYZ(collision.posX(), collision.posY(), collision.posZ()); - std::array vtxCov{collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()}; - o2::dataformats::VertexBase primaryVertex = {std::move(vtxXYZ), std::move(vtxCov)}; - auto covMatrixPV = primaryVertex.getCov(); - - double phi = std::atan2(secondaryVertex[1] - collision.posY(), secondaryVertex[0] - collision.posX()); - double theta = std::atan2(secondaryVertex[2] - collision.posZ(), - std::sqrt((secondaryVertex[0] - collision.posX()) * (secondaryVertex[0] - collision.posX()) + - (secondaryVertex[1] - collision.posY()) * (secondaryVertex[1] - collision.posY()))); - - values[kVertexingLxy] = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + - (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); - values[kVertexingLz] = (collision.posZ() - secondaryVertex[2]) * (collision.posZ() - secondaryVertex[2]); - values[kVertexingLxyz] = values[kVertexingLxy] + values[kVertexingLz]; - values[kVertexingLxy] = std::sqrt(values[kVertexingLxy]); - values[kVertexingLz] = std::sqrt(values[kVertexingLz]); - values[kVertexingLxyz] = std::sqrt(values[kVertexingLxyz]); - - values[kVertexingLxyzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta)); - values[kVertexingLxyErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.)); - values[kVertexingLzErr] = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, 0, theta) + getRotatedCovMatrixXX(covMatrixPCA, 0, theta)); - - values[kVertexingTauz] = (collision.posZ() - secondaryVertex[2]) * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxy] = values[kVertexingLxy] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kVertexingTauzErr] = values[kVertexingLzErr] * v1234.M() / (TMath::Abs(v1234.Pz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * v1234.M() / (v1234.Pt() * o2::constants::physics::LightSpeedCm2NS); - - values[kCosPointingAngle] = ((collision.posX() - secondaryVertex[0]) * v1234.Px() + - (collision.posY() - secondaryVertex[1]) * v1234.Py() + - (collision.posZ() - secondaryVertex[2]) * v1234.Pz()) / - (v1234.P() * values[VarManager::kVertexingLxyz]); - // // run 2 definitions: Decay length projected onto the momentum vector of the candidate - values[kVertexingLzProjected] = (secondaryVertex[2] - collision.posZ()) * v1234.Pz(); - values[kVertexingLzProjected] = values[kVertexingLzProjected] / TMath::Sqrt(v1234.Pz() * v1234.Pz()); - values[kVertexingLxyProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py())); - values[kVertexingLxyzProjected] = ((secondaryVertex[0] - collision.posX()) * v1234.Px()) + ((secondaryVertex[1] - collision.posY()) * v1234.Py()) + ((secondaryVertex[2] - collision.posZ()) * v1234.Pz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((v1234.Px() * v1234.Px()) + (v1234.Py() * v1234.Py()) + (v1234.Pz() * v1234.Pz())); - - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * v1234.M() / TMath::Abs(v1234.Pz()); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * v1234.M() / (v1234.Pt()); - values[kVertexingTauxyzProjected] = values[kVertexingLxyzProjected] * v1234.M() / (v1234.P()); - } - } else if (fgUsedKF) { - KFParticle lepton1KF; // lepton1 - KFParticle lepton2KF; // lepton2 - KFParticle KFGeoTwoLeptons; - KFParticle trk1KF; // track1 - KFParticle trk2KF; // track2 - KFParticle KFGeoTwoTracks; - KFParticle KFGeoFourProng; - if constexpr (candidateType == kXtoJpsiPiPi) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); - lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); - lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); - KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); - trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); - KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); - trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); - - KFGeoTwoLeptons.SetConstructMethod(2); - KFGeoTwoLeptons.AddDaughter(lepton1KF); - KFGeoTwoLeptons.AddDaughter(lepton2KF); - - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { - values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); - values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); - } - - KFGeoTwoTracks.SetConstructMethod(2); - KFGeoTwoTracks.AddDaughter(trk1KF); - KFGeoTwoTracks.AddDaughter(trk2KF); - - if (fgUsedVars[kDitrackMass] || fgUsedVars[kDitrackPt]) { - values[VarManager::kDitrackMass] = KFGeoTwoTracks.GetMass(); - values[VarManager::kDitrackPt] = KFGeoTwoTracks.GetPt(); - } - - KFGeoFourProng.SetConstructMethod(2); - KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); - KFGeoFourProng.AddDaughter(KFGeoTwoTracks); - } - - if constexpr (candidateType == kPsi2StoJpsiPiPi) { - KFPTrack kfpTrack0 = createKFPTrackFromTrack(lepton1); - lepton1KF = KFParticle(kfpTrack0, -11 * lepton1.sign()); - KFPTrack kfpTrack1 = createKFPTrackFromTrack(lepton2); - lepton2KF = KFParticle(kfpTrack1, -11 * lepton2.sign()); - KFPTrack kfpTrack2 = createKFPTrackFromTrack(track1); - trk1KF = KFParticle(kfpTrack2, 211 * track1.sign()); - KFPTrack kfpTrack3 = createKFPTrackFromTrack(track2); - trk2KF = KFParticle(kfpTrack3, 211 * track2.sign()); - - KFGeoTwoLeptons.SetConstructMethod(2); - KFGeoTwoLeptons.AddDaughter(lepton1KF); - KFGeoTwoLeptons.AddDaughter(lepton2KF); - - if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt]) { - values[VarManager::kPairMass] = KFGeoTwoLeptons.GetMass(); - values[VarManager::kPairPt] = KFGeoTwoLeptons.GetPt(); - } - - KFGeoFourProng.SetConstructMethod(2); - KFGeoFourProng.AddDaughter(KFGeoTwoLeptons); - KFGeoFourProng.AddDaughter(trk1KF); - KFGeoFourProng.AddDaughter(trk2KF); - } - - if (fgUsedVars[kKFMass]) { - float mass = 0., massErr = 0.; - if (!KFGeoFourProng.GetMass(mass, massErr)) - values[kKFMass] = mass; - else - values[kKFMass] = -999.; - } - - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - values[kKFNContributorsPV] = kfpVertex.GetNContributors(); - KFParticle KFPV(kfpVertex); - double dxQuadlet2PV = KFGeoFourProng.GetX() - KFPV.GetX(); - double dyQuadlet2PV = KFGeoFourProng.GetY() - KFPV.GetY(); - double dzQuadlet2PV = KFGeoFourProng.GetZ() - KFPV.GetZ(); - - values[kVertexingLxy] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV); - values[kVertexingLz] = std::sqrt(dzQuadlet2PV * dzQuadlet2PV); - values[kVertexingLxyz] = std::sqrt(dxQuadlet2PV * dxQuadlet2PV + dyQuadlet2PV * dyQuadlet2PV + dzQuadlet2PV * dzQuadlet2PV); - - values[kVertexingLxyErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV); - values[kVertexingLzErr] = (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV; - values[kVertexingLxyzErr] = (KFPV.GetCovariance(0) + KFGeoFourProng.GetCovariance(0)) * dxQuadlet2PV * dxQuadlet2PV + (KFPV.GetCovariance(2) + KFGeoFourProng.GetCovariance(2)) * dyQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(5) + KFGeoFourProng.GetCovariance(5)) * dzQuadlet2PV * dzQuadlet2PV + 2 * ((KFPV.GetCovariance(1) + KFGeoFourProng.GetCovariance(1)) * dxQuadlet2PV * dyQuadlet2PV + (KFPV.GetCovariance(3) + KFGeoFourProng.GetCovariance(3)) * dxQuadlet2PV * dzQuadlet2PV + (KFPV.GetCovariance(4) + KFGeoFourProng.GetCovariance(4)) * dyQuadlet2PV * dzQuadlet2PV); - - if (fabs(values[kVertexingLxy]) < 1.e-8f) - values[kVertexingLxy] = 1.e-8f; - values[kVertexingLxyErr] = values[kVertexingLxyErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyErr]) / values[kVertexingLxy]; - if (fabs(values[kVertexingLz]) < 1.e-8f) - values[kVertexingLz] = 1.e-8f; - values[kVertexingLzErr] = values[kVertexingLzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLzErr]) / values[kVertexingLz]; - if (fabs(values[kVertexingLxyz]) < 1.e-8f) - values[kVertexingLxyz] = 1.e-8f; - values[kVertexingLxyzErr] = values[kVertexingLxyzErr] < 0. ? 1.e8f : std::sqrt(values[kVertexingLxyzErr]) / values[kVertexingLxyz]; - - values[kVertexingTauxy] = KFGeoFourProng.GetPseudoProperDecayTime(KFPV, KFGeoFourProng.GetMass()) / (o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauz] = -1 * dzQuadlet2PV * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingPz] = TMath::Abs(KFGeoFourProng.GetPz()); - values[kVertexingSV] = KFGeoFourProng.GetZ(); - - values[kVertexingTauxyErr] = values[kVertexingLxyErr] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt() * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingTauzErr] = values[kVertexingLzErr] * KFGeoFourProng.GetMass() / (TMath::Abs(KFGeoFourProng.GetPz()) * o2::constants::physics::LightSpeedCm2NS); - values[kVertexingChi2PCA] = KFGeoFourProng.GetChi2(); - values[kCosPointingAngle] = (std::sqrt(dxQuadlet2PV * dxQuadlet2PV) * v1234.Px() + - std::sqrt(dyQuadlet2PV * dyQuadlet2PV) * v1234.Py() + - std::sqrt(dzQuadlet2PV * dzQuadlet2PV) * v1234.Pz()) / - (v1234.P() * values[VarManager::kVertexingLxyz]); - // // run 2 definitions: Decay length projected onto the momentum vector of the candidate - values[kVertexingLzProjected] = (dzQuadlet2PV * KFGeoFourProng.GetPz()) / TMath::Sqrt(KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz()); - values[kVertexingLxyProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()); - values[kVertexingLxyProjected] = values[kVertexingLxyProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy())); - values[kVertexingLxyzProjected] = (dxQuadlet2PV * KFGeoFourProng.GetPx()) + (dyQuadlet2PV * KFGeoFourProng.GetPy()) + (dzQuadlet2PV * KFGeoFourProng.GetPz()); - values[kVertexingLxyzProjected] = values[kVertexingLxyzProjected] / TMath::Sqrt((KFGeoFourProng.GetPx() * KFGeoFourProng.GetPx()) + (KFGeoFourProng.GetPy() * KFGeoFourProng.GetPy()) + (KFGeoFourProng.GetPz() * KFGeoFourProng.GetPz())); - values[kVertexingTauxyProjected] = values[kVertexingLxyProjected] * KFGeoFourProng.GetMass() / (KFGeoFourProng.GetPt()); - values[kVertexingTauxyProjectedNs] = values[kVertexingTauxyProjected] / o2::constants::physics::LightSpeedCm2NS; - values[kVertexingTauzProjected] = values[kVertexingLzProjected] * KFGeoFourProng.GetMass() / TMath::Abs(KFGeoFourProng.GetPz()); - values[kKFChi2OverNDFGeo] = KFGeoFourProng.GetChi2() / KFGeoFourProng.GetNDF(); - } else { - return; - } -} - -//__________________________________________________________________ -template -void VarManager::FillQuadMC(T1 const& dilepton, T2 const& track1, T2 const& track2, float* values) -{ - if (!values) { - values = fgValues; - } - - double defaultDileptonMass = 3.096; - double hadronMass1 = o2::constants::physics::MassPionCharged; - double hadronMass2 = o2::constants::physics::MassPionCharged; - if (candidateType == kXtoJpsiPiPi) { - defaultDileptonMass = 3.096; - hadronMass1 = o2::constants::physics::MassPionCharged; - hadronMass2 = o2::constants::physics::MassPionCharged; - } - - ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), defaultDileptonMass); - ROOT::Math::PtEtaPhiMVector v2(track1.pt(), track1.eta(), track1.phi(), hadronMass1); - ROOT::Math::PtEtaPhiMVector v3(track2.pt(), track2.eta(), track2.phi(), hadronMass2); - ROOT::Math::PtEtaPhiMVector v123 = v1 + v2 + v3; - ROOT::Math::PtEtaPhiMVector v23 = v2 + v3; - values[kQuadMass] = v123.M(); - values[kQuadDefaultDileptonMass] = v123.M(); - values[kQuadPt] = v123.Pt(); - values[kQuadEta] = v123.Eta(); - values[kQuadPhi] = v123.Phi(); - values[kQ] = v123.M() - defaultDileptonMass - v23.M(); - values[kDeltaR1] = ROOT::Math::VectorUtil::DeltaR(v1, v2); - values[kDeltaR2] = ROOT::Math::VectorUtil::DeltaR(v1, v3); - values[kDeltaR] = sqrt(pow(values[kDeltaR1], 2) + pow(values[kDeltaR2], 2)); - values[kDitrackMass] = v23.M(); - values[kDitrackPt] = v23.Pt(); -} - -//__________________________________________________________________ -template -float VarManager::calculatePhiV(T1 const& t1, T2 const& t2) -{ - // cos(phiv) = w*a /|w||a| - // with w = u x v - // and a = u x z / |u x z| , unit vector perpendicular to v12 and z-direction (magnetic field) - // u = v12 / |v12| , the unit vector of v12 - // v = v1 x v2 / |v1 x v2| , unit vector perpendicular to v1 and v2 - - float m1 = o2::constants::physics::MassElectron; - float m2 = o2::constants::physics::MassElectron; - if constexpr (pairType == kDecayToMuMu) { - m1 = o2::constants::physics::MassMuon; - m2 = o2::constants::physics::MassMuon; - } - - if constexpr (pairType == kDecayToPiPi) { - m1 = o2::constants::physics::MassPionCharged; - m2 = o2::constants::physics::MassPionCharged; - } - - if constexpr (pairType == kElectronMuon) { - m2 = o2::constants::physics::MassMuon; - } - - 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; - - float pairPhiV = -999; - float bz = fgMagField; - - bool swapTracks = false; - if (v1.Pt() < v2.Pt()) { // ordering of track, pt1 > pt2 - ROOT::Math::PtEtaPhiMVector v3 = v1; - v1 = v2; - v2 = v3; - swapTracks = true; - } - - // momentum of e+ and e- in (ax,ay,az) axis. Note that az=0 by definition. - // vector product of pep X pem - float vpx = 0, vpy = 0, vpz = 0; - if (t1.sign() * t2.sign() > 0) { // Like Sign - if (!swapTracks) { - if (bz * t1.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (bz * t2.sign() < 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } else { // Unlike Sign - if (!swapTracks) { - if (bz * t1.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } else { // swaped tracks - if (bz * t2.sign() > 0) { - vpx = v1.Py() * v2.Pz() - v1.Pz() * v2.Py(); - vpy = v1.Pz() * v2.Px() - v1.Px() * v2.Pz(); - vpz = v1.Px() * v2.Py() - v1.Py() * v2.Px(); - } else { - vpx = v2.Py() * v1.Pz() - v2.Pz() * v1.Py(); - vpy = v2.Pz() * v1.Px() - v2.Px() * v1.Pz(); - vpz = v2.Px() * v1.Py() - v2.Py() * v1.Px(); - } - } - } - - // unit vector of pep X pem - float vx = vpx / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vy = vpy / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - float vz = vpz / TMath::Sqrt(vpx * vpx + vpy * vpy + vpz * vpz); - - float px = v12.Px(); - float py = v12.Py(); - float pz = v12.Pz(); - - // unit vector of (pep+pem) - float ux = px / TMath::Sqrt(px * px + py * py + pz * pz); - float uy = py / TMath::Sqrt(px * px + py * py + pz * pz); - float uz = pz / TMath::Sqrt(px * px + py * py + pz * pz); - float ax = uy / TMath::Sqrt(ux * ux + uy * uy); - float ay = -ux / TMath::Sqrt(ux * ux + uy * uy); - - // The third axis defined by vector product (ux,uy,uz)X(vx,vy,vz) - float wx = uy * vz - uz * vy; - float wy = uz * vx - ux * vz; - // by construction, (wx,wy,wz) must be a unit vector. Measure angle between (wx,wy,wz) and (ax,ay,0). - // The angle between them should be small if the pair is conversion. This function then returns values close to pi! - pairPhiV = TMath::ACos(wx * ax + wy * ay); // phiv in [0,pi] //cosPhiV = wx * ax + wy * ay; - return pairPhiV; -} - -/// Fill BDT score values. -/// Supports binary (1 output) and multiclass (3 outputs) models. -template -void VarManager::FillBdtScore(T1 const& bdtScore, float* values) -{ - if (!values) { - values = fgValues; - } - - if (bdtScore.size() == 1) { - values[kBdtBackground] = bdtScore[0]; - } else if (bdtScore.size() == 3) { - values[kBdtBackground] = bdtScore[0]; - values[kBdtPrompt] = bdtScore[1]; - values[kBdtNonprompt] = bdtScore[2]; - } else { - LOG(warning) << "Unexpected number of BDT outputs: " << bdtScore.size(); - } -} -//__________________________________________________________________ -template -float VarManager::LorentzTransformJpsihadroncosChi(TString Option, T1 const& v1, T2 const& v2) -{ - 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") { - 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(); - } - return value; -} - -#endif // PWGDQ_CORE_VARMANAGER_H_ From 91cbb0324b39bb034b186a0ec068d2476243dd81 Mon Sep 17 00:00:00 2001 From: YazhenLin Date: Thu, 20 Nov 2025 18:28:17 +0800 Subject: [PATCH 24/24] Add files via upload --- PWGDQ/Core/VarManager.h | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index af9210cab56..2056a88416e 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -1710,20 +1710,11 @@ void VarManager::FillEvent(T const& event, float* values) } if constexpr ((fillMap & CollisionMult) > 0 || (fillMap & ReducedEventExtended) > 0) { - if constexpr ((fillMap & RapidityGapFilter) > 0) { - // UPC: Use the FIT signals from the nearest BC with FIT amplitude above threshold - values[kMultFV0A] = event.newBcMultFV0A(); - values[kMultFT0A] = event.newBcMultFT0A(); - values[kMultFT0C] = event.newBcMultFT0C(); - values[kMultFDDA] = event.newBcMultFDDA(); - values[kMultFDDC] = event.newBcMultFDDC(); - } else { - values[kMultFV0A] = event.multFV0A(); - values[kMultFT0A] = event.multFT0A(); - values[kMultFT0C] = event.multFT0C(); - values[kMultFDDA] = event.multFDDA(); - values[kMultFDDC] = event.multFDDC(); - } + values[kMultFV0A] = event.multFV0A(); + values[kMultFT0A] = event.multFT0A(); + values[kMultFT0C] = event.multFT0C(); + values[kMultFDDA] = event.multFDDA(); + values[kMultFDDC] = event.multFDDC(); values[kMultTPC] = event.multTPC(); values[kMultFV0C] = event.multFV0C(); values[kMultZNA] = event.multZNA();