Skip to content

Commit 764ee1b

Browse files
MRazza879Marta Razza
andauthored
[PWGHF] Add task h2fromlb (#16372)
Co-authored-by: Marta Razza <marta.razza@cern.ch>
1 parent 196d274 commit 764ee1b

2 files changed

Lines changed: 331 additions & 0 deletions

File tree

PWGHF/D2H/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,8 @@ o2physics_add_dpl_workflow(task-hidden-charm
168168
SOURCES taskHiddenCharm.cxx
169169
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
170170
COMPONENT_NAME Analysis)
171+
172+
o2physics_add_dpl_workflow(task-deuteron-from-lb
173+
SOURCES taskDeuteronFromLb.cxx
174+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils
175+
COMPONENT_NAME Analysis)
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
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+
/// \brief A filter task for non prompt deuterons from beauty-hadron decays
13+
/// \author Marta Razza marta.razza@cern.ch
14+
/// \author Francesca Ercolessi francesca.ercolessi@cern.ch
15+
/// \since May 25, 2026
16+
17+
#include "Common/Core/Zorro.h"
18+
#include "Common/Core/ZorroSummary.h"
19+
#include "Common/Core/trackUtilities.h"
20+
#include "Common/DataModel/CollisionAssociationTables.h"
21+
#include "Common/DataModel/EventSelection.h"
22+
#include "Common/DataModel/PIDResponseTOF.h"
23+
#include "Common/DataModel/PIDResponseTPC.h"
24+
#include "Common/DataModel/TrackSelectionTables.h"
25+
26+
#include <CCDB/BasicCCDBManager.h>
27+
#include <DataFormatsParameters/GRPMagField.h>
28+
#include <DetectorsBase/Propagator.h>
29+
#include <Framework/AnalysisDataModel.h>
30+
#include <Framework/AnalysisHelpers.h>
31+
#include <Framework/AnalysisTask.h>
32+
#include <Framework/Configurable.h>
33+
#include <Framework/HistogramRegistry.h>
34+
#include <Framework/HistogramSpec.h>
35+
#include <Framework/InitContext.h>
36+
#include <Framework/OutputObjHeader.h>
37+
#include <Framework/runDataProcessing.h>
38+
#include <ReconstructionDataFormats/Track.h>
39+
#include <ReconstructionDataFormats/TrackParametrization.h>
40+
41+
#include <TH1.h>
42+
43+
#include <array>
44+
#include <chrono>
45+
#include <cmath>
46+
#include <string>
47+
48+
using namespace o2;
49+
using namespace o2::framework;
50+
using namespace o2::framework::expressions;
51+
52+
struct HfTaskDeuteronFromLb {
53+
54+
Zorro zorro;
55+
o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE;
56+
57+
Configurable<float> cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"};
58+
Configurable<bool> applySkimming{"applySkimming", false, "Skimmed dataset processing"};
59+
Configurable<std::string> cfgSkimming{"cfgSkimming", "fH2fromLb", "Configurable for skimming"};
60+
Configurable<bool> sel8{"sel8", true, "sel8 event selection"};
61+
Configurable<bool> separateAntideuterons{"separateAntideuterons", true, "Fill FromLb histos for primary deuterons whose mother is Lb, Primary histos for all others"};
62+
Configurable<float> cfgEta{"cfgEta", 0.8f, "Track eta selection"};
63+
Configurable<float> cfgTPCNclsFound{"cfgTPCNclsFound", 100, "Minimum TPC clusters found"};
64+
Configurable<float> cfgTPCChi2Ncl{"cfgTPCChi2Ncl", 4.0f, "Maximum TPC chi2 per N clusters"};
65+
Configurable<float> cfgITSChi2Ncl{"cfgITSChi2Ncl", 36.0f, "Maximum ITS chi2 per N clusters"};
66+
Configurable<float> cfgITScls{"cfgITScls", 2, "Minimum ITS clusters"};
67+
Configurable<float> cfgMaxPt{"cfgMaxPt", 5.0f, "Maximum pT cut"};
68+
Configurable<float> cfgMinPt{"cfgMinPt", 0.5f, "Minimum pT cut"};
69+
Configurable<float> cfgTPCNsigma{"cfgTPCNsigma", 4.0f, "TPC n sigma for deuteron PID"};
70+
Configurable<float> cfgTofNsigmaMin{"cfgTofNsigmaMin", 3.0f, "TOF n sigma min for deuteron PID"};
71+
Configurable<float> cfgTofNsigmaMax{"cfgTofNsigmaMax", 4.0f, "TOF n sigma max for deuteron PID"};
72+
Configurable<float> ptThresholdPid{"ptThresholdPid", 1.0f, "pT threshold to switch between 4 and 3 sigmas for TOF PID"};
73+
Configurable<float> rapidityCut{"rapidityCut", 0.5f, "Rapidity cut"};
74+
// PDG codes
75+
Configurable<int> pdgCodeMother{"pdgCodeMother", -5122, "PDG code of the mother particle (default: anti-Lambda_b)"};
76+
Configurable<int> pdgCodeDaughter{"pdgCodeDaughter", -1000010020, "PDG code of the daughter particle (default: anti-deuteron)"};
77+
78+
int mRunNumber = 0;
79+
float d_bz = 0.f;
80+
int mCurrentRun = -1;
81+
82+
framework::Service<ccdb::BasicCCDBManager> ccdb;
83+
84+
using CollisionCandidates = o2::soa::Join<o2::aod::Collisions, o2::aod::EvSels>;
85+
using MCTrackCandidates = o2::soa::Join<o2::aod::TracksIU, o2::aod::TracksExtra, o2::aod::TracksDCA, o2::aod::McTrackLabels>;
86+
using MCCollisionCandidates = o2::soa::Join<o2::aod::Collisions, o2::aod::EvSels, o2::aod::McCollisionLabels>;
87+
using TrackCandidates = o2::soa::Join<o2::aod::Tracks, o2::aod::TracksCov, o2::aod::TracksExtra, o2::aod::TracksDCA, o2::aod::TrackSelection, o2::aod::pidTPCFullDe, o2::aod::pidTOFFullDe>;
88+
89+
Preslice<o2::aod::TrackAssoc> trackIndicesPerCollision = o2::aod::track_association::collisionId;
90+
91+
HistogramRegistry QAHistos{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true};
92+
HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject};
93+
94+
OutputObj<ZorroSummary> zorroSummary{"zorroSummary"};
95+
OutputObj<TH1D> hProcessedEvents{TH1D("hProcessedEvents", "Event filtered;; Number of events", 4, 0., 4.)};
96+
97+
void init(framework::InitContext&)
98+
{
99+
ccdb->setURL("http://alice-ccdb.cern.ch");
100+
ccdb->setCaching(true);
101+
ccdb->setLocalObjectValidityChecking();
102+
ccdb->setCreatedNotAfter(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
103+
104+
if (applySkimming) {
105+
zorroSummary.setObject(zorro.getZorroSummary());
106+
}
107+
108+
ConfigurableAxis ptAxis{"ptAxis", {100, 0., 10.f}, "p_{T} GeV/c"};
109+
ConfigurableAxis nSigmaAxis{"nSigmaAxis", {200, -10.f, 10.f}, "nSigma"};
110+
ConfigurableAxis dcaXyAxis{"dcaXyAxis", {1000, -0.2f, 0.2f}, "DCA xy (cm)"};
111+
ConfigurableAxis dcaZAxis{"dcaZAxis", {1000, -0.2f, 0.2f}, "DCA z (cm)"};
112+
113+
QAHistos.add("hVtxZ", "Z-Vertex distribution after selection;Z (cm)", HistType::kTH1F, {{100, -50, 50}});
114+
QAHistos.add("ptGeneratedLb", "ptGeneratedLb", HistType::kTH1F, {ptAxis});
115+
QAHistos.add("ptAntiDeuteronPrimary", "ptAntiDeuteronPrimaryReco", HistType::kTH1F, {ptAxis});
116+
QAHistos.add("ptAntiDeuteronFromLb", "ptAntiDeuteronFromLbReco", HistType::kTH1F, {ptAxis});
117+
QAHistos.add("hDCAxy-Primary", "DCAxy-Primary", {HistType::kTH1D, {{400, -0.2f, 0.2f, "DCA xy (cm)"}}});
118+
QAHistos.add("hDCAxy-FromLb", "DCAxy-FromLb", {HistType::kTH1D, {{400, -0.2f, 0.2f, "DCA xy (cm)"}}});
119+
QAHistos.add("hDCAxyVsPt", "DCAxy #bar{d} vs p_{T}", {HistType::kTH2D, {ptAxis, dcaXyAxis}});
120+
QAHistos.add("hDCAzVsPt", "DCAz #bar{d} vs p_{T}", {HistType::kTH2D, {ptAxis, dcaZAxis}});
121+
QAHistos.add("hnSigmaTPCVsPt", "n#sigma TPC vs p_{T} for #bar{d} hypothesis; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}});
122+
QAHistos.add("hnSigmaTOFVsPt", "n#sigma TOF vs p_{T} for #bar{d} hypothesis; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}});
123+
QAHistos.add("ptAntiDeuteron", "ptAntiDeuteron", {HistType::kTH1F, {ptAxis}});
124+
QAHistos.add("etaAntideuteron", "etaAntideuteron", {HistType::kTH1F, {{100, -1.0f, 1.0f, "eta #bar{d}"}}});
125+
126+
hProcessedEvents->GetXaxis()->SetBinLabel(1, "Events processed");
127+
hProcessedEvents->GetXaxis()->SetBinLabel(2, "ZORRO");
128+
hProcessedEvents->GetXaxis()->SetBinLabel(3, "sel8");
129+
hProcessedEvents->GetXaxis()->SetBinLabel(4, "z-vertex");
130+
}
131+
132+
void initCCDB(o2::aod::BCsWithTimestamps::iterator const& bc)
133+
{
134+
if (mRunNumber == bc.runNumber()) {
135+
return;
136+
}
137+
d_bz = 0.f;
138+
139+
if (applySkimming) {
140+
zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), cfgSkimming.value);
141+
zorro.populateHistRegistry(registry, bc.runNumber());
142+
}
143+
}
144+
145+
template <typename T1>
146+
bool passedSingleTrackSelection(const T1& track)
147+
{
148+
if (std::abs(track.eta()) > cfgEta)
149+
return false;
150+
if (!track.hasITS())
151+
return false;
152+
if (!track.hasTPC())
153+
return false;
154+
if (!track.hasTOF())
155+
return false;
156+
if (track.tpcNClsFound() < cfgTPCNclsFound)
157+
return false;
158+
if (track.tpcChi2NCl() > cfgTPCChi2Ncl)
159+
return false;
160+
if (track.itsChi2NCl() > cfgITSChi2Ncl)
161+
return false;
162+
if (track.itsNCls() < cfgITScls)
163+
return false;
164+
if (track.pt() > cfgMaxPt)
165+
return false;
166+
if (track.pt() < cfgMinPt)
167+
return false;
168+
if (track.sign() > 0)
169+
return false;
170+
171+
return true;
172+
}
173+
174+
void processData(CollisionCandidates const& collisions,
175+
o2::aod::TrackAssoc const& trackIndices,
176+
TrackCandidates const& tracks,
177+
o2::aod::BCsWithTimestamps const&)
178+
{
179+
for (const auto& collision : collisions) {
180+
if (mCurrentRun != collision.bc_as<o2::aod::BCsWithTimestamps>().runNumber()) {
181+
o2::parameters::GRPMagField* grpo = ccdb->getForTimeStamp<o2::parameters::GRPMagField>("GLO/Config/GRPMagField", collision.bc_as<o2::aod::BCsWithTimestamps>().timestamp());
182+
o2::base::Propagator::initFieldFromGRP(grpo);
183+
mCurrentRun = collision.bc_as<o2::aod::BCsWithTimestamps>().runNumber();
184+
}
185+
186+
const auto& bc = collision.bc_as<o2::aod::BCsWithTimestamps>();
187+
initCCDB(bc);
188+
hProcessedEvents->Fill(0.5);
189+
if (applySkimming) {
190+
if (!zorro.isSelected(bc.globalBC())) {
191+
continue;
192+
}
193+
}
194+
hProcessedEvents->Fill(1.5);
195+
if (sel8 && !collision.sel8()) {
196+
continue;
197+
}
198+
hProcessedEvents->Fill(2.5);
199+
if (std::abs(collision.posZ()) > cutzvertex) {
200+
continue;
201+
}
202+
hProcessedEvents->Fill(3.5);
203+
QAHistos.fill(HIST("hVtxZ"), collision.posZ());
204+
205+
const auto& trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex());
206+
207+
for (const auto& trackId : trackIdsThisCollision) {
208+
const auto& track = tracks.rawIteratorAt(trackId.trackId());
209+
std::array<float, 2> dca{track.dcaXY(), track.dcaZ()};
210+
211+
if (track.collisionId() != collision.globalIndex()) {
212+
auto trackPar = getTrackParCov(track);
213+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackPar, 2.f, noMatCorr, &dca);
214+
}
215+
216+
if (!passedSingleTrackSelection(track)) {
217+
continue;
218+
}
219+
220+
const bool isTPCDe = std::abs(track.tpcNSigmaDe()) < cfgTPCNsigma;
221+
const bool isTOFDe_min = std::abs(track.tofNSigmaDe()) > cfgTofNsigmaMin;
222+
const bool isTOFDe_max = std::abs(track.tofNSigmaDe()) < cfgTofNsigmaMax;
223+
224+
if (track.pt() < ptThresholdPid) {
225+
if (isTPCDe && isTOFDe_max) {
226+
QAHistos.fill(HIST("ptAntiDeuteron"), track.pt());
227+
QAHistos.fill(HIST("etaAntideuteron"), track.eta());
228+
QAHistos.fill(HIST("hDCAxyVsPt"), track.pt(), dca[0]);
229+
QAHistos.fill(HIST("hDCAzVsPt"), track.pt(), dca[1]);
230+
QAHistos.fill(HIST("hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe());
231+
QAHistos.fill(HIST("hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe());
232+
}
233+
} else {
234+
if (isTPCDe && isTOFDe_min && isTOFDe_max) {
235+
QAHistos.fill(HIST("ptAntiDeuteron"), track.pt());
236+
QAHistos.fill(HIST("etaAntideuteron"), track.eta());
237+
QAHistos.fill(HIST("hDCAxyVsPt"), track.pt(), dca[0]);
238+
QAHistos.fill(HIST("hDCAzVsPt"), track.pt(), dca[1]);
239+
QAHistos.fill(HIST("hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe());
240+
QAHistos.fill(HIST("hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe());
241+
}
242+
}
243+
}
244+
}
245+
}
246+
PROCESS_SWITCH(HfTaskDeuteronFromLb, processData, "processData", false);
247+
248+
void processMC(MCCollisionCandidates::iterator const&, MCTrackCandidates const& tracks, o2::aod::McParticles const&)
249+
{
250+
for (const auto& track : tracks) {
251+
if (!passedSingleTrackSelection(track)) {
252+
continue;
253+
}
254+
255+
if (!track.has_mcParticle()) {
256+
continue;
257+
}
258+
259+
auto mcParticle = track.mcParticle();
260+
if (mcParticle.pdgCode() == pdgCodeDaughter) {
261+
if (std::abs(mcParticle.y()) > rapidityCut) {
262+
continue;
263+
}
264+
if (mcParticle.isPhysicalPrimary()) {
265+
bool isFromLb = false;
266+
if (separateAntideuterons) {
267+
for (const auto& mom : mcParticle.mothers_as<o2::aod::McParticles>()) {
268+
if (mom.pdgCode() == pdgCodeMother) {
269+
isFromLb = true;
270+
break;
271+
}
272+
}
273+
}
274+
if (isFromLb) {
275+
QAHistos.fill(HIST("hDCAxy-FromLb"), track.dcaXY());
276+
QAHistos.fill(HIST("ptAntiDeuteronFromLb"), track.pt());
277+
} else {
278+
QAHistos.fill(HIST("hDCAxy-Primary"), track.dcaXY());
279+
QAHistos.fill(HIST("ptAntiDeuteronPrimary"), track.pt());
280+
}
281+
}
282+
}
283+
}
284+
}
285+
PROCESS_SWITCH(HfTaskDeuteronFromLb, processMC, "processMC", true);
286+
287+
void processGen(o2::aod::McCollision const&, o2::aod::McParticles const& mcParticles)
288+
{
289+
hProcessedEvents->Fill(0.5);
290+
for (const auto& mcParticle : mcParticles) {
291+
if (mcParticle.pdgCode() == pdgCodeMother) {
292+
if (std::abs(mcParticle.y()) <= rapidityCut) {
293+
QAHistos.fill(HIST("ptGeneratedLb"), mcParticle.pt());
294+
}
295+
}
296+
297+
if (mcParticle.pdgCode() == pdgCodeDaughter) {
298+
if (std::abs(mcParticle.y()) > rapidityCut)
299+
continue;
300+
301+
bool isFromLb = false;
302+
if (mcParticle.has_mothers()) {
303+
for (const auto& mom : mcParticle.mothers_as<o2::aod::McParticles>()) {
304+
if (mom.pdgCode() == pdgCodeMother) {
305+
isFromLb = true;
306+
break;
307+
}
308+
}
309+
}
310+
311+
if (isFromLb) {
312+
QAHistos.fill(HIST("ptAntiDeuteronFromLb"), mcParticle.pt());
313+
} else if (mcParticle.isPhysicalPrimary()) {
314+
QAHistos.fill(HIST("ptAntiDeuteronPrimary"), mcParticle.pt());
315+
}
316+
}
317+
}
318+
}
319+
PROCESS_SWITCH(HfTaskDeuteronFromLb, processGen, "processGen", false);
320+
};
321+
322+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
323+
{
324+
return WorkflowSpec{
325+
adaptAnalysisTask<HfTaskDeuteronFromLb>(cfgc)};
326+
}

0 commit comments

Comments
 (0)