Skip to content

Commit 92f0a57

Browse files
authored
[PWGJE] Adding D0+JET correlation task (#14795)
1 parent b5a10f8 commit 92f0a57

File tree

2 files changed

+389
-0
lines changed

2 files changed

+389
-0
lines changed

PWGJE/Tasks/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,10 @@ if(FastJet_FOUND)
375375
SOURCES jetFormationTimeReclustering.cxx
376376
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore
377377
COMPONENT_NAME Analysis)
378+
o2physics_add_dpl_workflow(jet-correlation-d0
379+
SOURCES jetCorrelationD0.cxx
380+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore
381+
COMPONENT_NAME Analysis)
378382
o2physics_add_dpl_workflow(hf-debug
379383
SOURCES hfDebug.cxx
380384
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore

PWGJE/Tasks/jetCorrelationD0.cxx

Lines changed: 385 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
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 jetCorrelationD0.cxx
13+
/// \brief Task for analysing D0 triggered jet events.
14+
/// \author Matthew Ockleton matthew.ockleton@cern.ch, University of Liverpool
15+
16+
#include "PWGHF/Core/DecayChannels.h"
17+
#include "PWGHF/DataModel/AliasTables.h"
18+
#include "PWGJE/Core/JetDerivedDataUtilities.h"
19+
#include "PWGJE/Core/JetUtilities.h"
20+
#include "PWGJE/DataModel/Jet.h"
21+
#include "PWGJE/DataModel/JetReducedData.h"
22+
23+
#include "Common/Core/RecoDecay.h"
24+
25+
#include "Framework/AnalysisDataModel.h"
26+
#include "Framework/AnalysisTask.h"
27+
#include "Framework/HistogramRegistry.h"
28+
#include "Framework/Logger.h"
29+
#include "Framework/runDataProcessing.h"
30+
#include <Framework/ASoA.h>
31+
#include <Framework/HistogramSpec.h>
32+
33+
#include <fairlogger/Logger.h>
34+
35+
#include <string>
36+
#include <vector>
37+
38+
using namespace o2;
39+
using namespace o2::framework;
40+
using namespace o2::framework::expressions;
41+
42+
namespace o2::aod
43+
{
44+
45+
namespace d0collisionInfo
46+
{
47+
DECLARE_SOA_COLUMN(PosZ, posZ, float);
48+
} // namespace d0collisionInfo
49+
50+
DECLARE_SOA_TABLE(CollisionTables, "AOD", "COLLINFOTABLE",
51+
o2::soa::Index<>,
52+
d0collisionInfo::PosZ);
53+
54+
DECLARE_SOA_TABLE(McCollisionTables, "AOD", "MCCOLLINFOTABLE",
55+
o2::soa::Index<>,
56+
d0collisionInfo::PosZ);
57+
58+
namespace collisionInfo
59+
{
60+
DECLARE_SOA_INDEX_COLUMN(CollisionTable, collisionTable);
61+
DECLARE_SOA_INDEX_COLUMN(McCollisionTable, mcCollisionTable);
62+
} // namespace collisionInfo
63+
namespace d0Info
64+
{
65+
// D0
66+
DECLARE_SOA_COLUMN(D0PromptBDT, d0PromptBDT, float);
67+
DECLARE_SOA_COLUMN(D0NonPromptBDT, d0NonPromptBDT, float);
68+
DECLARE_SOA_COLUMN(D0BkgBDT, d0BkgBDT, float);
69+
DECLARE_SOA_COLUMN(D0M, d0M, float);
70+
DECLARE_SOA_COLUMN(D0Pt, d0Pt, float);
71+
DECLARE_SOA_COLUMN(D0Eta, d0Eta, float);
72+
DECLARE_SOA_COLUMN(D0Phi, d0Phi, float);
73+
DECLARE_SOA_COLUMN(D0Y, d0Y, float);
74+
DECLARE_SOA_COLUMN(D0McOrigin, d0McOrigin, float);
75+
DECLARE_SOA_COLUMN(D0MD, d0MD, float);
76+
DECLARE_SOA_COLUMN(D0PtD, d0PtD, float);
77+
DECLARE_SOA_COLUMN(D0EtaD, d0EtaD, float);
78+
DECLARE_SOA_COLUMN(D0PhiD, d0PhiD, float);
79+
DECLARE_SOA_COLUMN(D0Reflection, d0Reflection, int);
80+
} // namespace d0Info
81+
82+
DECLARE_SOA_TABLE(D0DataTables, "AOD", "D0DATATABLE",
83+
o2::soa::Index<>,
84+
collisionInfo::CollisionTableId,
85+
d0Info::D0PromptBDT,
86+
d0Info::D0NonPromptBDT,
87+
d0Info::D0BkgBDT,
88+
d0Info::D0M,
89+
d0Info::D0Pt,
90+
d0Info::D0Eta,
91+
d0Info::D0Phi,
92+
d0Info::D0Y);
93+
94+
DECLARE_SOA_TABLE(D0McPTables, "AOD", "D0MCPARTICLELEVELTABLE",
95+
o2::soa::Index<>,
96+
collisionInfo::McCollisionTableId,
97+
d0Info::D0McOrigin,
98+
d0Info::D0Pt,
99+
d0Info::D0Eta,
100+
d0Info::D0Phi,
101+
d0Info::D0Y);
102+
103+
namespace jetInfo
104+
{
105+
// D0 tables
106+
DECLARE_SOA_INDEX_COLUMN(D0DataTable, d0Data);
107+
DECLARE_SOA_INDEX_COLUMN(D0McPTable, d0MCP);
108+
// Jet
109+
DECLARE_SOA_COLUMN(JetPt, jetPt, float);
110+
DECLARE_SOA_COLUMN(JetEta, jetEta, float);
111+
DECLARE_SOA_COLUMN(JetPhi, jetPhi, float);
112+
// D0-jet
113+
DECLARE_SOA_COLUMN(D0JetDeltaPhi, d0JetDeltaPhi, float);
114+
} // namespace jetInfo
115+
116+
DECLARE_SOA_TABLE_STAGED(JetDataTables, "JETDATATABLE",
117+
o2::soa::Index<>,
118+
collisionInfo::CollisionTableId,
119+
jetInfo::D0DataTableId,
120+
jetInfo::JetPt,
121+
jetInfo::JetEta,
122+
jetInfo::JetPhi,
123+
jetInfo::D0JetDeltaPhi);
124+
125+
DECLARE_SOA_TABLE_STAGED(JetMCPTables, "JETMCPTABLE",
126+
o2::soa::Index<>,
127+
collisionInfo::McCollisionTableId,
128+
jetInfo::D0McPTableId,
129+
jetInfo::JetPt,
130+
jetInfo::JetEta,
131+
jetInfo::JetPhi,
132+
jetInfo::D0JetDeltaPhi);
133+
134+
} // namespace o2::aod
135+
136+
struct JetCorrelationD0 {
137+
// Define new table
138+
Produces<aod::CollisionTables> tableCollision;
139+
Produces<aod::McCollisionTables> tableMcCollision;
140+
Produces<aod::D0DataTables> tableD0;
141+
Produces<aod::D0McPTables> tableD0MCParticle;
142+
Produces<aod::JetDataTables> tableJet;
143+
Produces<aod::JetMCPTables> tableJetMCParticle;
144+
145+
// Configurables
146+
Configurable<std::string> eventSelections{"eventSelections", "sel8", "choose event selection"};
147+
Configurable<bool> skipMBGapEvents{"skipMBGapEvents", false, "decide to run over MB gap events or not"};
148+
Configurable<bool> applyRCTSelections{"applyRCTSelections", true, "decide to apply RCT selections"};
149+
// Configurable<std::string> triggerMasks{"triggerMasks", "", "possible JE Trigger masks: fJetChLowPt,fJetChHighPt,fTrackLowPt,fTrackHighPt,fJetD0ChLowPt,fJetD0ChHighPt,fJetLcChLowPt,fJetLcChHighPt,fEMCALReadout,fJetFullHighPt,fJetFullLowPt,fJetNeutralHighPt,fJetNeutralLowPt,fGammaVeryHighPtEMCAL,fGammaVeryHighPtDCAL,fGammaHighPtEMCAL,fGammaHighPtDCAL,fGammaLowPtEMCAL,fGammaLowPtDCAL,fGammaVeryLowPtEMCAL,fGammaVeryLowPtDCAL"};
150+
Configurable<float> jetPtCutMin{"jetPtCutMin", 5.0, "minimum value of jet pt"};
151+
Configurable<float> d0PtCutMin{"d0PtCutMin", 1.0, "minimum value of d0 pt"};
152+
Configurable<float> vertexZCut{"vertexZCut", 10.0, "Accepted z-vertex range"};
153+
Configurable<float> pTHatExponent{"pTHatExponent", 6.0, "exponent of the event weight for the calculation of pTHat"};
154+
Configurable<float> pTHatMaxMCD{"pTHatMaxMCD", 999.0, "maximum fraction of hard scattering for jet acceptance in detector MC"};
155+
Configurable<float> pTHatMaxMCP{"pTHatMaxMCP", 999.0, "maximum fraction of hard scattering for jet acceptance in particle MC"};
156+
Configurable<float> pTHatAbsoluteMin{"pTHatAbsoluteMin", -99.0, "minimum value of pTHat"};
157+
158+
// Filters
159+
Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut);
160+
std::vector<int> eventSelectionBits;
161+
162+
// Histograms
163+
HistogramRegistry registry{"histos", {}, OutputObjHandlingPolicy::AnalysisObject};
164+
template <typename T, typename U>
165+
void fillD0Histograms(T const& d0, U const& scores)
166+
{
167+
registry.fill(HIST("hD0MlBkg"), scores[0]);
168+
registry.fill(HIST("hD0MlNonPrompt"), scores[1]);
169+
registry.fill(HIST("hD0MlPrompt"), scores[2]);
170+
171+
registry.fill(HIST("hD0Pt"), d0.pt());
172+
registry.fill(HIST("hD0M"), d0.m());
173+
registry.fill(HIST("hD0Eta"), d0.eta());
174+
registry.fill(HIST("hD0Phi"), d0.phi());
175+
}
176+
template <typename T, typename U>
177+
void fillJetHistograms(T const& jet, U const& dphi)
178+
{
179+
registry.fill(HIST("hJetPt"), jet.pt());
180+
registry.fill(HIST("hJetEta"), jet.eta());
181+
registry.fill(HIST("hJetPhi"), jet.phi());
182+
registry.fill(HIST("hJet3D"), jet.pt(), jet.eta(), jet.phi());
183+
registry.fill(HIST("h_Jet_pT_D0_Jet_dPhi"), jet.pt(), dphi);
184+
}
185+
186+
template <typename T>
187+
bool applyCollisionSelections(T const& collision)
188+
{
189+
registry.fill(HIST("hCollisions"), 0.5); // All collisions
190+
if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) {
191+
return false;
192+
}
193+
registry.fill(HIST("hCollisions"), 1.5); // Selected collisions
194+
registry.fill(HIST("hZvtxSelected"), collision.posZ());
195+
return true;
196+
}
197+
198+
template <typename T, typename U>
199+
// Jetbase is an MCD jet. We then loop through jettagv(MCP jets) to test if they match
200+
// void fillMatchedHistograms(T const& jetBase, float weight = 1.0) // float leadingTrackPtBase,
201+
void fillMatchedHistograms(T const& jetsBase, U const&, float weight = 1.0, float rho = 0.0)
202+
{
203+
for (const auto& jetBase : jetsBase) {
204+
if (jetBase.has_matchedJetGeo()) { // geometric matching
205+
for (auto& jetTag : jetBase.template matchedJetGeo_as<std::decay_t<U>>()) {
206+
registry.fill(HIST("hPtMatched"), jetBase.pt() - (rho * jetBase.area()), jetTag.pt(), weight);
207+
registry.fill(HIST("hPtMatched1d"), jetTag.pt(), weight);
208+
registry.fill(HIST("hPhiMatched"), jetBase.phi(), jetTag.phi(), weight);
209+
registry.fill(HIST("hEtaMatched"), jetBase.eta(), jetTag.eta(), weight);
210+
registry.fill(HIST("hPtResolution"), jetTag.pt(), (jetTag.pt() - (jetBase.pt() - (rho * jetBase.area()))) / jetTag.pt(), weight);
211+
registry.fill(HIST("hPhiResolution"), jetTag.pt(), jetTag.phi() - jetBase.phi(), weight);
212+
registry.fill(HIST("hEtaResolution"), jetTag.pt(), jetTag.eta() - jetBase.eta(), weight);
213+
}
214+
}
215+
}
216+
}
217+
void init(InitContext const&)
218+
{
219+
eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(static_cast<std::string>(eventSelections));
220+
// General Axes
221+
AxisSpec axisEta = {100, -1.0, 1.0, "#eta"};
222+
AxisSpec axisPhi = {100, 0.0, o2::constants::math::TwoPI, "#phi"};
223+
AxisSpec axisInvMass = {500, 0, 10, "M (GeV/c)"};
224+
225+
// General Histograms
226+
registry.add("hCollisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}});
227+
registry.add("hZvtxSelected", "Z vertex position;Z_{vtx};entries", {HistType::kTH1F, {{80, -20, 20}}});
228+
229+
// D0 Histograms
230+
registry.add("hD0MlPrompt", "D0 ML Prompt Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}});
231+
registry.add("hD0MlNonPrompt", "D0 ML NonPrompt Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}});
232+
registry.add("hD0MlBkg", "D0 ML Background Scores", {HistType::kTH1F, {{100, -1.0, 2.0}}});
233+
234+
registry.add("hD0Pt", "D^{0} p_{T};p_{T}^{D^{0}} (GeV/c);entries", {HistType::kTH1F, {{500, -100, 400, "p_{T}^{D^{0}} (GeV/c)"}}});
235+
registry.add("hD0M", "D^{0} Mass;M_{#pi K} (GeV/c);entries", HistType::kTH1F, {axisInvMass});
236+
registry.add("hD0Eta", "D^{0} #eta ;#eta_{D^{0}};entries", HistType::kTH1F, {axisEta});
237+
registry.add("hD0Phi", "D^{0} #phi ;#phi_{D^{0}};entries", HistType::kTH1F, {axisPhi});
238+
239+
// Jet Histograms
240+
registry.add("hJetPt", "jet p_{T};p_{T,jet};entries", {HistType::kTH1F, {{500, -100, 400}}});
241+
registry.add("hJetEta", "jet #eta;#eta_{jet};entries", HistType::kTH1F, {axisEta});
242+
registry.add("hJetPhi", "jet #phi;#phi_{jet};entries", HistType::kTH1F, {axisPhi});
243+
registry.add("hJet3D", "3D jet distribution;p_{T};#eta;#phi", {HistType::kTH3F, {{500, -100, 400}, {100, -1.0, 1.0}, {100, 0.0, o2::constants::math::TwoPI}}});
244+
registry.add("h_Jet_pT_D0_Jet_dPhi", "p_{T, jet} vs #Delta #phi _{D^{0}, jet}", kTH2F, {{100, 0, 100}, {100, 0, o2::constants::math::TwoPI}});
245+
246+
// Matching histograms
247+
registry.add("hPtMatched", "p_{T} matching;p_{T,det};p_{T,part}", {HistType::kTH2F, {{500, -100, 400}, {400, 0, 400}}});
248+
registry.add("hPtMatched1d", "p_{T} matching 1d;p_{T,part}", {HistType::kTH1F, {{400, 0, 400}}});
249+
registry.add("hPhiMatched", "#phi matching;#phi_{det};#phi_{part}", {HistType::kTH2F, {{100, 0.0, o2::constants::math::TwoPI}, {100, 0.0, o2::constants::math::TwoPI}}});
250+
registry.add("hEtaMatched", "#eta matching;#eta_{det};#eta_{part}", {HistType::kTH2F, {{100, -1, 1}, {100, -1, 1}}});
251+
registry.add("hPtResolution", "p_{T} resolution;p_{T,part};Relative Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -5.0, 5.0}}});
252+
registry.add("hPhiResolution", "#phi resolution;#p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -7.0, 7.0}}});
253+
registry.add("hEtaResolution", "#eta resolution;#p_{T,part};Resolution", {HistType::kTH2F, {{400, 0, 400}, {1000, -1.0, 1.0}}});
254+
}
255+
void processData(soa::Filtered<aod::JetCollisions>::iterator const& collision,
256+
aod::CandidatesD0Data const& d0Candidates,
257+
soa::Join<aod::ChargedJets, aod::ChargedJetConstituents> const& jets)
258+
{
259+
if (!applyCollisionSelections(collision)) {
260+
return;
261+
}
262+
tableCollision(collision.posZ());
263+
for (const auto& d0Candidate : d0Candidates) {
264+
if (d0Candidate.pt() < d0PtCutMin) { // once settled on a mlcut, then add the lower bound of the systematics as a cut here
265+
continue;
266+
}
267+
const auto scores = d0Candidate.mlScores();
268+
fillD0Histograms(d0Candidate, scores);
269+
tableD0(tableCollision.lastIndex(),
270+
scores[2],
271+
scores[1],
272+
scores[0],
273+
d0Candidate.m(),
274+
d0Candidate.pt(),
275+
d0Candidate.eta(),
276+
d0Candidate.phi(),
277+
d0Candidate.y());
278+
for (const auto& jet : jets) {
279+
if (jet.pt() < jetPtCutMin) {
280+
continue;
281+
}
282+
float dphi = RecoDecay::constrainAngle(jet.phi() - d0Candidate.phi());
283+
if (abs(dphi - M_PI) > (M_PI / 2)) { // this is quite loose instead of pi/2 could do 0.6
284+
continue;
285+
}
286+
fillJetHistograms(jet, dphi);
287+
tableJet(tableCollision.lastIndex(),
288+
tableD0.lastIndex(),
289+
jet.pt(),
290+
jet.eta(),
291+
jet.phi(),
292+
dphi);
293+
}
294+
}
295+
}
296+
PROCESS_SWITCH(JetCorrelationD0, processData, "charged particle level jet analysis", true);
297+
298+
void processMCDetector(soa::Filtered<aod::JetCollisions>::iterator const& collision,
299+
aod::CandidatesD0MCD const& d0Candidates,
300+
soa::Join<aod::ChargedMCDetectorLevelJets, aod::ChargedMCDetectorLevelJetConstituents> const& jets)
301+
{
302+
if (!applyCollisionSelections(collision)) {
303+
return;
304+
}
305+
tableCollision(collision.posZ());
306+
for (const auto& d0Candidate : d0Candidates) {
307+
if (d0Candidate.pt() < d0PtCutMin) { // once settled on a mlcut, then add the lower biund of the systematics as a cut here
308+
continue;
309+
}
310+
const auto scores = d0Candidate.mlScores();
311+
fillD0Histograms(d0Candidate, scores);
312+
tableD0(tableCollision.lastIndex(), // might want to add some more detector level D0 quantities like prompt or non prompt info
313+
scores[2],
314+
scores[1],
315+
scores[0],
316+
d0Candidate.m(),
317+
d0Candidate.pt(),
318+
d0Candidate.eta(),
319+
d0Candidate.phi(),
320+
d0Candidate.y());
321+
for (const auto& jet : jets) {
322+
if (jet.pt() < jetPtCutMin) {
323+
continue;
324+
}
325+
float dphi = RecoDecay::constrainAngle(jet.phi() - d0Candidate.phi());
326+
if (abs(dphi - M_PI) > (M_PI / 2)) { // this is quite loose instead of pi/2 could do 0.6
327+
continue;
328+
}
329+
fillJetHistograms(jet, dphi);
330+
tableJet(tableCollision.lastIndex(),
331+
tableD0.lastIndex(),
332+
jet.pt(),
333+
jet.eta(),
334+
jet.phi(),
335+
dphi);
336+
}
337+
}
338+
}
339+
PROCESS_SWITCH(JetCorrelationD0, processMCDetector, "charged particle level jet analysis", false);
340+
341+
void processMCParticle(aod::JetMcCollision const& collision,
342+
aod::CandidatesD0MCP const& d0MCPCandidates,
343+
soa::Filtered<soa::Join<aod::ChargedMCParticleLevelJets, aod::ChargedMCParticleLevelJetConstituents>> const& jets)
344+
{
345+
if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // build without this
346+
return;
347+
}
348+
tableMcCollision(collision.posZ());
349+
for (const auto& d0MCPCandidate : d0MCPCandidates) {
350+
if (d0MCPCandidate.pt() < d0PtCutMin) {
351+
continue;
352+
}
353+
tableD0MCParticle(tableCollision.lastIndex(),
354+
d0MCPCandidate.originMcGen(),
355+
d0MCPCandidate.pt(),
356+
d0MCPCandidate.eta(),
357+
d0MCPCandidate.phi(),
358+
d0MCPCandidate.y());
359+
360+
for (const auto& jet : jets) {
361+
if (jet.pt() < jetPtCutMin) {
362+
continue;
363+
}
364+
float dphi = RecoDecay::constrainAngle(jet.phi() - d0MCPCandidate.phi());
365+
if (abs(dphi - M_PI) > (M_PI / 2)) {
366+
continue;
367+
}
368+
fillJetHistograms(jet, dphi);
369+
tableJetMCParticle(tableCollision.lastIndex(),
370+
tableD0MCParticle.lastIndex(),
371+
jet.pt(),
372+
jet.eta(),
373+
jet.phi(),
374+
dphi);
375+
}
376+
}
377+
}
378+
PROCESS_SWITCH(JetCorrelationD0, processMCParticle, "process MC Particle jets", false);
379+
};
380+
381+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
382+
{
383+
return WorkflowSpec{
384+
adaptAnalysisTask<JetCorrelationD0>(cfgc)};
385+
}

0 commit comments

Comments
 (0)