Skip to content

Commit 221bba9

Browse files
[PWGDQ] Add J/psi-muon correlations task (#17059)
Co-authored-by: ALICE Action Bot <alibuild@cern.ch>
1 parent 5e4aa34 commit 221bba9

2 files changed

Lines changed: 275 additions & 0 deletions

File tree

PWGDQ/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ o2physics_add_dpl_workflow(muon-global-alignment
194194
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2::MCHGeometryTransformer
195195
COMPONENT_NAME Analysis)
196196

197+
o2physics_add_dpl_workflow(j-psi-muon-correlations
198+
SOURCES jPsiMuonCorrelations.cxx
199+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2::MCHGeometryTransformer
200+
COMPONENT_NAME Analysis)
201+
197202
o2physics_add_dpl_workflow(global-muon-matcher
198203
SOURCES global-muon-matcher.cxx
199204
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGDQCore O2::MCHGeometryTransformer
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
//
12+
/// \file jPsiMuonCorrelations.cxx
13+
/// \brief Task to perform correlations between J/Psi candidates and single muon tracks
14+
/// \author Kaare Endrup Iversen <kaare.endrup.iversen@cern.ch> Lund University
15+
//
16+
#include "PWGDQ/Core/VarManager.h"
17+
#include "PWGDQ/DataModel/ReducedInfoTables.h"
18+
19+
#include "Common/Core/RecoDecay.h"
20+
21+
#include <CCDB/BasicCCDBManager.h>
22+
#include <CommonConstants/MathConstants.h>
23+
#include <CommonConstants/PhysicsConstants.h>
24+
#include <Framework/AnalysisDataModel.h>
25+
#include <Framework/AnalysisHelpers.h>
26+
#include <Framework/AnalysisTask.h>
27+
#include <Framework/Configurable.h>
28+
#include <Framework/HistogramRegistry.h>
29+
#include <Framework/HistogramSpec.h>
30+
#include <Framework/InitContext.h>
31+
#include <Framework/runDataProcessing.h>
32+
33+
#include <chrono>
34+
#include <cmath>
35+
#include <cstddef>
36+
#include <cstdint>
37+
#include <string>
38+
#include <vector>
39+
40+
using std::string;
41+
42+
using namespace o2;
43+
using namespace o2::framework;
44+
using namespace o2::framework::expressions;
45+
using namespace o2::aod;
46+
47+
// Some definitions
48+
namespace o2::aod
49+
{
50+
51+
namespace dqanalysisflags
52+
{
53+
DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 8); //! Event decision
54+
DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc)
55+
} // namespace dqanalysisflags
56+
57+
DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTSA", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents
58+
DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTSA", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc
59+
} // namespace o2::aod
60+
61+
// Declarations of various short names
62+
using MyEvents = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended>;
63+
using MyEventsSelected = soa::Join<aod::ReducedEvents, aod::ReducedEventsExtended, aod::EventCuts>;
64+
65+
// using MyPairCandidatesSelected = soa::Join<aod::Dimuons, aod::DimuonsExtra>;
66+
using MyPairCandidatesSelected = soa::Join<aod::Dimuons, aod::DimuonsExtra, aod::DimuonsAll>;
67+
using MyMuonTracks = soa::Join<aod::ReducedMuons, aod::ReducedMuonsExtra>;
68+
using MyMuonAssocsSelected = soa::Join<aod::ReducedMuonsAssoc, aod::MuonTrackCuts>;
69+
70+
// bit maps used for the Fill functions of the VarManager
71+
constexpr static uint32_t GkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended;
72+
constexpr static uint32_t GkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra;
73+
74+
// Declare helper function
75+
double getRapidity(const double pT, const double eta);
76+
double getWeight(const double pT, const std::vector<double>& binsPT, const std::vector<double>& efficiency, const double etaMin, const double etaMax);
77+
78+
struct DqJPsiMuonCorrelations {
79+
80+
// Configurables for the dilepton signal region
81+
Configurable<float> fConfigDileptonLowMass{"fConfigDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"};
82+
Configurable<float> fConfigDileptonHighMass{"fConfigDileptonHighMass", 3.4, "High mass cut for the dileptons used in analysis"};
83+
Configurable<float> fConfigBackgroundLowMass{"fConfigBackgroundLowMass", 2.5, "Low mass cut for the background used in analysis"};
84+
Configurable<float> fConfigBackgroundHighMass{"fConfigBackgroundHighMass", 3.7, "High mass cut for the background used in analysis"};
85+
86+
// Configurables for the dilepton and associated muon cuts
87+
Configurable<float> fConfigDileptonPtMin{"fConfigDileptonPtMin", 1.0, "Minimum pT cut for the dilepton"};
88+
Configurable<float> fConfigDileptonPtMax{"fConfigDileptonPtMax", 20.0, "Maximum pT cut for the dilepton"};
89+
Configurable<float> fConfigDileptonEtaMin{"fConfigDileptonEtaMin", -4.0, "Minimum eta cut for the dileptons"};
90+
Configurable<float> fConfigDileptonEtaMax{"fConfigDileptonEtaMax", -2.5, "Maximum eta cut for the dileptons"};
91+
Configurable<float> fConfigMuonEtaMin{"fConfigMuonEtaMin", -4.0, "Minimum eta cut for the associated muons"};
92+
Configurable<float> fConfigMuonEtaMax{"fConfigMuonEtaMax", -2.5, "Maximum eta cut for the associated muons"};
93+
94+
// Configurables for histograms
95+
ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 10.0f, 12.0f, 14.0f, 16.0f, 18.0f, 20.0f}, "p_{T} (GeV/c)"};
96+
ConfigurableAxis axisInvMass{"axisInvMass", {80, 1.0f, 5.0f}, "Invariant Mass (GeV/c^{2})"};
97+
ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {10, -constants::math::PIHalf, 3.0f * constants::math::PIHalf}, "#Delta#phi (rad)"};
98+
ConfigurableAxis axisDeltaEta{"axisDeltaEta", {10, -2.0f, 2.0f}, "#Delta#eta"};
99+
100+
// Configurable for acceptance efficiency correction
101+
Configurable<std::vector<double>> fConfigBinEffJPsi{"fConfigBinEffJPsi", std::vector<double>{1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, "acceptance efficiency correction factors for each pT bin"};
102+
Configurable<std::vector<double>> fConfigBinEffMuon{"fConfigBinEffMuon", std::vector<double>{1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, "acceptance efficiency correction factors for each pT bin"};
103+
104+
// Connect to ccdb
105+
Service<ccdb::BasicCCDBManager> ccdb{};
106+
Configurable<int64_t> ccdbNoLaterThan{"ccdbNoLaterThan", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"};
107+
Configurable<std::string> ccdbUrl{"ccdbUrl", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"};
108+
109+
// Define the filter for events
110+
Filter eventFilter = aod::dqanalysisflags::isEventSelected == 1;
111+
112+
// Define the filter for the dileptons
113+
Filter dileptonFilter = aod::reducedpair::sign == 0;
114+
115+
constexpr static uint32_t FgDimuonsFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::Pair; // fill map
116+
117+
// use two values array to avoid mixing up the quantities
118+
std::vector<float> fValuesDilepton;
119+
std::vector<float> fValuesMuon;
120+
121+
HistogramRegistry registry{"registry"};
122+
123+
void init(o2::framework::InitContext&)
124+
{
125+
ccdb->setURL(ccdbUrl.value);
126+
ccdb->setCaching(true);
127+
ccdb->setCreatedNotAfter(ccdbNoLaterThan.value);
128+
129+
// Assert correct size of the efficiency correction vector
130+
uint8_t nAxisPtBins = axisPt.value.size() - 2;
131+
if (nAxisPtBins != fConfigBinEffJPsi.value.size() || nAxisPtBins != fConfigBinEffMuon.value.size()) {
132+
LOGF(fatal, "Configurables axisPt: %zu must have one more value than fConfigBinEffJPsi: %zu and fConfigBinEffMuon: %zu (excluding 'VARIABLE_WIDTH' entry)",
133+
axisPt.value.size() - 1, fConfigBinEffJPsi.value.size(), fConfigBinEffMuon.value.size());
134+
}
135+
136+
fValuesDilepton.resize(VarManager::kNVars, 0.0f);
137+
fValuesMuon.resize(VarManager::kNVars, 0.0f);
138+
VarManager::SetDefaultVarNames();
139+
140+
// Define trigger histograms
141+
ConfigurableAxis axisTriggerMass{"axisTriggerMass", {VARIABLE_WIDTH, fConfigBackgroundLowMass, fConfigDileptonLowMass, fConfigDileptonHighMass, fConfigBackgroundHighMass}, "Invariant Mass (GeV/c^{2}) for trigger counting"};
142+
registry.add("h2dDimuonPtInvVsInvMass", "h2dDimuonPtInvVsInvMass", kTH2D, {axisInvMass, axisPt});
143+
registry.add("h2dTriggersPtInvVsInvMassRegion", "h2dTriggersPtInvVsInvMassRegion", kTH2D, {axisTriggerMass, axisPt});
144+
145+
// Define histograms for the dilepton-muon correlations
146+
registry.add("h2dDimuonMuonDeltaEtaVsMuonPtSignal", "h2dDimuonMuonDeltaEtaVsMuonPtSignal", kTH2D, {axisDeltaEta, axisPt});
147+
registry.add("h2dDimuonMuonDeltaPhiVsMuonPtSignal", "h2dDimuonMuonDeltaPhiVsMuonPtSignal", kTH2D, {axisDeltaPhi, axisPt});
148+
registry.add("h2dDimuonMuonDeltaEtaVsMuonPtBackground", "h2dDimuonMuonDeltaEtaVsMuonPtBackground", kTH2D, {axisDeltaEta, axisPt});
149+
registry.add("h2dDimuonMuonDeltaPhiVsMuonPtBackground", "h2dDimuonMuonDeltaPhiVsMuonPtBackground", kTH2D, {axisDeltaPhi, axisPt});
150+
151+
// QA histograms
152+
registry.add("hEventPosZMuon", "hEventPosZMuon", kTH1D, {{50, -25, 25}});
153+
}
154+
155+
// Template function to run pair - muon combinations
156+
template <int TCandidateType, uint32_t TEventFillMap, uint32_t TMuonFillMap, typename TEvent, typename TMuonAssocs, typename TMuonTracks, typename TDileptons>
157+
void runDileptonMuon(TEvent const& event, TMuonAssocs const& assocs, TMuonTracks const& /*tracks*/, TDileptons const& dileptons)
158+
{
159+
VarManager::ResetValues(0, VarManager::kNVars, fValuesMuon.data());
160+
VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton.data());
161+
VarManager::FillEvent<TEventFillMap>(event, fValuesMuon.data());
162+
VarManager::FillEvent<TEventFillMap>(event, fValuesDilepton.data());
163+
164+
if (!event.isEventSelected_bit(0)) {
165+
return;
166+
}
167+
168+
if (assocs.size() > 0) {
169+
registry.fill(HIST("hEventPosZMuon"), event.posZ());
170+
}
171+
172+
if (dileptons.size() > 0) {
173+
174+
for (const auto& dilepton : dileptons) {
175+
VarManager::FillTrack<FgDimuonsFillMap>(dilepton, fValuesDilepton.data());
176+
177+
// Dilepton kinematic cuts
178+
if ((dilepton.eta() < fConfigDileptonEtaMin || dilepton.eta() > fConfigDileptonEtaMax) ||
179+
(dilepton.pt() < fConfigDileptonPtMin || dilepton.pt() > fConfigDileptonPtMax)) {
180+
continue;
181+
}
182+
// Dilepton leg kinematic cuts
183+
if ((dilepton.eta1() < fConfigMuonEtaMin || dilepton.eta1() > fConfigMuonEtaMax) ||
184+
(dilepton.pt1() < axisPt.value[1] || dilepton.pt1() > axisPt.value.back()) ||
185+
(dilepton.eta2() < fConfigMuonEtaMin || dilepton.eta2() > fConfigMuonEtaMax) ||
186+
(dilepton.pt2() < axisPt.value[1] || dilepton.pt2() > axisPt.value.back())) {
187+
continue;
188+
}
189+
190+
// Fill invariant mass vs pT histogram for the dileptons and for trigger counting
191+
double weightDilepton = getWeight(dilepton.pt(), axisPt.value, fConfigBinEffJPsi.value, fConfigDileptonEtaMin, fConfigDileptonEtaMax);
192+
193+
registry.fill(HIST("h2dDimuonPtInvVsInvMass"), dilepton.mass(), dilepton.pt(), weightDilepton);
194+
registry.fill(HIST("h2dTriggersPtInvVsInvMassRegion"), dilepton.mass(), dilepton.pt(), weightDilepton);
195+
196+
for (const auto& assoc : assocs) {
197+
// Check selection bit
198+
if (!assoc.isMuonSelected_bit(0)) {
199+
continue;
200+
}
201+
202+
// Skip associated muons that are part of the dilepton candidate
203+
if (dilepton.index0Id() == assoc.reducedmuonId() || dilepton.index1Id() == assoc.reducedmuonId()) {
204+
continue;
205+
}
206+
207+
// Get muon track information
208+
auto track = assoc.template reducedmuon_as<TMuonTracks>();
209+
210+
// Muon kinematic cuts
211+
if ((track.eta() < fConfigMuonEtaMin || track.eta() > fConfigMuonEtaMax) ||
212+
(track.pt() < axisPt.value[1] || track.pt() > axisPt.value.back())) {
213+
continue;
214+
}
215+
216+
// Compute deltaEta and deltaPhi between the dilepton and the associated muon
217+
float deltaEta = dilepton.eta() - track.eta();
218+
float deltaPhi = RecoDecay::constrainAngle(dilepton.phi() - track.phi(), -constants::math::PIHalf);
219+
220+
// Fill signal and background histograms based on the dilepton mass
221+
double weightMuon = getWeight(track.pt(), axisPt.value, fConfigBinEffMuon.value, fConfigMuonEtaMin, fConfigMuonEtaMax);
222+
223+
if (dilepton.mass() > fConfigDileptonLowMass && dilepton.mass() < fConfigDileptonHighMass) {
224+
registry.fill(HIST("h2dDimuonMuonDeltaEtaVsMuonPtSignal"), deltaEta, track.pt(), weightDilepton * weightMuon);
225+
registry.fill(HIST("h2dDimuonMuonDeltaPhiVsMuonPtSignal"), deltaPhi, track.pt(), weightDilepton * weightMuon);
226+
} else if (dilepton.mass() > fConfigBackgroundLowMass && dilepton.mass() < fConfigBackgroundHighMass) {
227+
registry.fill(HIST("h2dDimuonMuonDeltaEtaVsMuonPtBackground"), deltaEta, track.pt(), weightDilepton * weightMuon);
228+
registry.fill(HIST("h2dDimuonMuonDeltaPhiVsMuonPtBackground"), deltaPhi, track.pt(), weightDilepton * weightMuon);
229+
}
230+
}
231+
}
232+
}
233+
}
234+
235+
void processSkimmedDimuon(MyEventsSelected::iterator const& event, MyMuonAssocsSelected const& muonassocs, MyMuonTracks const& muontracks, soa::Filtered<MyPairCandidatesSelected> const& dileptons)
236+
{
237+
runDileptonMuon<VarManager::kDecayToMuMu, GkEventFillMap, GkMuonFillMap>(event, muonassocs, muontracks, dileptons);
238+
}
239+
void processDummy(MyEvents const&)
240+
{
241+
}
242+
243+
PROCESS_SWITCH(DqJPsiMuonCorrelations, processSkimmedDimuon, "Run dilepton-muon pairing, using skimmed data", false);
244+
PROCESS_SWITCH(DqJPsiMuonCorrelations, processDummy, "Dummy function", false);
245+
};
246+
247+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
248+
{
249+
return WorkflowSpec{
250+
adaptAnalysisTask<DqJPsiMuonCorrelations>(cfgc)};
251+
}
252+
253+
double getWeight(const double pT, const std::vector<double>& binsPT, const std::vector<double>& efficiency, const double etaMin, const double etaMax)
254+
{
255+
256+
int binEff = -1;
257+
for (size_t b = 0; b < binsPT.size() - 1; ++b) {
258+
// Shift pT index by one to account for the VARIABLE_WIDTH entry in the axis configuration
259+
if (pT >= binsPT[b + 1] && pT < binsPT[b + 2]) {
260+
binEff = b;
261+
break;
262+
}
263+
}
264+
265+
if (binEff == -1) {
266+
LOGF(warn, "pT value %f is outside the defined pT bins", pT);
267+
return 0.0;
268+
}
269+
return 1.0 / (efficiency[binEff] * (RecoDecayPtEtaPhi::y(pT, etaMax, o2::constants::physics::MassJPsi) - RecoDecayPtEtaPhi::y(pT, etaMin, o2::constants::physics::MassJPsi)));
270+
}

0 commit comments

Comments
 (0)