Skip to content

Commit 983f119

Browse files
lucamicheletti93Luca Michelettivkucera
authored
PWGHF: Add dimuon channel to X task (#78)
* Adding muon channel to X * Running dielectron and dimuon channels separately * Implementing comments * Small fix * Small Fix * Implementing comments * Fixing the issue with the X pdg code * Fixing the issue with the X pdg code * Modification to select candidates in both the channels * Checking the Jpsi is in the decay chain * Checking the Jpsi is in the decay chain * Small fix * Moving X functions from hf_cand_prong3 to hf_cand_x * Small fix * Fix selector Co-authored-by: Luca Micheletti <lmichele@alicecerno2.cern.ch> Co-authored-by: Vít Kučera <vit.kucera@cern.ch>
1 parent c7deb27 commit 983f119

File tree

6 files changed

+128
-61
lines changed

6 files changed

+128
-61
lines changed

PWGHF/DataModel/HFCandidateSelectionTables.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@ DECLARE_SOA_TABLE(HFSelBPlusToD0PiCandidate, "AOD", "HFSELBPLUSCAND", //!
8585

8686
namespace hf_selcandidate_x
8787
{
88-
DECLARE_SOA_COLUMN(IsSelXToJpsiPiPi, isSelXToJpsiPiPi, int); //!
88+
DECLARE_SOA_COLUMN(IsSelXToJpsiToEEPiPi, isSelXToJpsiToEEPiPi, int); //!
89+
DECLARE_SOA_COLUMN(IsSelXToJpsiToMuMuPiPi, isSelXToJpsiToMuMuPiPi, int); //!
8990
} // namespace hf_selcandidate_x
9091
DECLARE_SOA_TABLE(HFSelXToJpsiPiPiCandidate, "AOD", "HFSELXCAND", //!
91-
hf_selcandidate_x::IsSelXToJpsiPiPi);
92+
hf_selcandidate_x::IsSelXToJpsiToEEPiPi, hf_selcandidate_x::IsSelXToJpsiToMuMuPiPi);
9293
} // namespace o2::aod
9394

9495
namespace o2::aod

PWGHF/DataModel/HFSecondaryVertex.h

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -702,32 +702,6 @@ auto InvMassXicToPiKP(const T& candidate)
702702
return InvMassLcpiKp(candidate);
703703
}
704704

705-
// X → Jpsi π+ π-
706-
// TODO: add pdg code for X (9920443), temporarily hardcode mass here:
707-
float massX = 3.872; // replace this with: "RecoDecay::getMassPDG(9920443)" when pdg is added
708-
template <typename T>
709-
auto CtX(const T& candidate)
710-
{
711-
return candidate.ct(massX);
712-
}
713-
714-
template <typename T>
715-
auto YX(const T& candidate)
716-
{
717-
return candidate.y(massX);
718-
}
719-
720-
template <typename T>
721-
auto EX(const T& candidate)
722-
{
723-
return candidate.e(massX);
724-
}
725-
template <typename T>
726-
auto InvMassXToJpsiPiPi(const T& candidate)
727-
{
728-
return candidate.m(array{RecoDecay::getMassPDG(443), RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kPiPlus)});
729-
}
730-
731705
} // namespace hf_cand_prong3
732706

733707
// 3-prong decay candidate table
@@ -800,9 +774,36 @@ DECLARE_SOA_COLUMN(OriginMCGen, originMCGen, int8_t); // particle
800774
DECLARE_SOA_COLUMN(FlagMCDecayChanRec, flagMCDecayChanRec, int8_t); // resonant decay channel flag, reconstruction level
801775
DECLARE_SOA_COLUMN(FlagMCDecayChanGen, flagMCDecayChanGen, int8_t); // resonant decay channel flag, generator level
802776
// mapping of decay types
803-
enum DecayType { XToJpsiPiPi = 0 }; // move this to a dedicated cascade namespace in the future?
777+
enum DecayType { XToJpsiToEEPiPi = 0,
778+
XToJpsiToMuMuPiPi }; // move this to a dedicated cascade namespace in the future?
804779
} // namespace hf_cand_x
805780

781+
// X → Jpsi π+ π-
782+
// TODO: add pdg code for X (9920443), temporarily hardcode mass here:
783+
float massX = 3.872; // replace this with: "RecoDecay::getMassPDG(9920443)" when pdg is added
784+
template <typename T>
785+
auto CtX(const T& candidate)
786+
{
787+
return candidate.ct(massX);
788+
}
789+
790+
template <typename T>
791+
auto YX(const T& candidate)
792+
{
793+
return candidate.y(massX);
794+
}
795+
796+
template <typename T>
797+
auto EX(const T& candidate)
798+
{
799+
return candidate.e(massX);
800+
}
801+
template <typename T>
802+
auto InvMassXToJpsiPiPi(const T& candidate)
803+
{
804+
return candidate.m(array{RecoDecay::getMassPDG(443), RecoDecay::getMassPDG(kPiPlus), RecoDecay::getMassPDG(kPiPlus)});
805+
}
806+
806807
// declare dedicated X candidate table
807808
DECLARE_SOA_TABLE(HfCandXBase, "AOD", "HFCANDXBASE",
808809
// general columns

PWGHF/TableProducer/HFCandidateCreatorX.cxx

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
/// \note Adapted from HFCandidateCreator3Prong
1515
///
1616
/// \author Rik Spijkers <r.spijkers@students.uu.nl>, Utrecht University
17+
/// \author Luca Micheletti <luca.micheletti@to.infn.it>, INFN
1718

1819
#include "Framework/AnalysisTask.h"
1920
#include "DetectorsVertexing/DCAFitterN.h"
@@ -24,10 +25,10 @@
2425
#include "PWGHF/DataModel/HFCandidateSelectionTables.h"
2526

2627
using namespace o2;
28+
using namespace o2::aod;
2729
using namespace o2::framework;
2830
using namespace o2::aod::hf_cand;
2931
using namespace o2::aod::hf_cand_prong2;
30-
using namespace o2::aod::hf_cand_prong3;
3132
using namespace o2::aod::hf_cand_x;
3233
using namespace o2::framework::expressions;
3334

@@ -52,10 +53,13 @@ struct HFCandidateCreatorX {
5253
Configurable<double> ptPionMin{"ptPionMin", 0.15, "minimum pion pT threshold (GeV/c)"};
5354
Configurable<bool> b_dovalplots{"b_dovalplots", true, "do validation plots"};
5455

55-
OutputObj<TH1F> hMassJpsi{TH1F("hMassJpsi", "J/#psi candidates;inv. mass (#e+ e-) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
56+
OutputObj<TH1F> hMassJpsiToEE{TH1F("hMassJpsiToEE", "J/#psi candidates;inv. mass (e^{#plus} e^{#minus}) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
57+
OutputObj<TH1F> hMassJpsiToMuMu{TH1F("hMassJpsiToMuMu", "J/#psi candidates;inv. mass (#mu^{#plus} #mu^{#minus}) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
5658
OutputObj<TH1F> hPtJpsi{TH1F("hPtJpsi", "J/#psi candidates;candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)};
59+
OutputObj<TH1F> hPtPion{TH1F("hPtPion", "#pi candidates;candidate #it{p}_{T} (GeV/#it{c});entries", 100, 0., 10.)};
5760
OutputObj<TH1F> hCPAJpsi{TH1F("hCPAJpsi", "J/#psi candidates;cosine of pointing angle;entries", 110, -1.1, 1.1)};
58-
OutputObj<TH1F> hMassX{TH1F("hMassX", "3-prong candidates;inv. mass (J/#psi #pi+ #pi-) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
61+
OutputObj<TH1F> hMassXToJpsiToEEPiPi{TH1F("hMassXToJpsiToEEPiPi", "3-prong candidates;inv. mass (J/#psi (#rightarrow e+ e-) #pi+ #pi-) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
62+
OutputObj<TH1F> hMassXToJpsiToMuMuPiPi{TH1F("hMassXToJpsiToMuMuPiPi", "3-prong candidates;inv. mass (J/#psi (#rightarrow #mu+ #mu-) #pi+ #pi-) (GeV/#it{c}^{2});entries", 500, 0., 5.)};
5963
OutputObj<TH1F> hCovPVXX{TH1F("hCovPVXX", "3-prong candidates;XX element of cov. matrix of prim. vtx position (cm^{2});entries", 100, 0., 1.e-4)};
6064
OutputObj<TH1F> hCovSVXX{TH1F("hCovSVXX", "3-prong candidates;XX element of cov. matrix of sec. vtx position (cm^{2});entries", 100, 0., 0.2)};
6165

@@ -65,7 +69,7 @@ struct HFCandidateCreatorX {
6569

6670
Configurable<int> d_selectionFlagJpsi{"d_selectionFlagJpsi", 1, "Selection Flag for Jpsi"};
6771
Configurable<double> cutYCandMax{"cutYCandMax", -1., "max. cand. rapidity"};
68-
Filter filterSelectCandidates = (aod::hf_selcandidate_jpsi::isSelJpsiToEE >= d_selectionFlagJpsi);
72+
Filter filterSelectCandidates = (aod::hf_selcandidate_jpsi::isSelJpsiToEE >= d_selectionFlagJpsi || aod::hf_selcandidate_jpsi::isSelJpsiToMuMu >= d_selectionFlagJpsi);
6973

7074
void process(aod::Collision const& collision,
7175
soa::Filtered<soa::Join<
@@ -95,13 +99,18 @@ struct HFCandidateCreatorX {
9599

96100
// loop over Jpsi candidates
97101
for (auto& jpsiCand : jpsiCands) {
98-
if (!(jpsiCand.hfflag() & 1 << JpsiToEE)) {
102+
if (!(jpsiCand.hfflag() & 1 << hf_cand_prong2::DecayType::JpsiToEE) && !(jpsiCand.hfflag() & 1 << hf_cand_prong2::DecayType::JpsiToMuMu)) {
99103
continue;
100104
}
101105
if (cutYCandMax >= 0. && std::abs(YJpsi(jpsiCand)) > cutYCandMax) {
102106
continue;
103107
}
104-
hMassJpsi->Fill(InvMassJpsiToEE(jpsiCand));
108+
if (jpsiCand.isSelJpsiToEE() > 0) {
109+
hMassJpsiToEE->Fill(InvMassJpsiToEE(jpsiCand));
110+
}
111+
if (jpsiCand.isSelJpsiToMuMu() > 0) {
112+
hMassJpsiToMuMu->Fill(InvMassJpsiToMuMu(jpsiCand));
113+
}
105114
hPtJpsi->Fill(jpsiCand.pt());
106115
hCPAJpsi->Fill(jpsiCand.cpa());
107116
// create Jpsi track to pass to DCA fitter; use cand table + rebuild vertex
@@ -138,6 +147,7 @@ struct HFCandidateCreatorX {
138147
if (trackPos.pt() < ptPionMin) {
139148
continue;
140149
}
150+
hPtPion->Fill(trackPos.pt());
141151

142152
// loop over pi- candidates
143153
for (auto& trackNeg : tracks) {
@@ -150,6 +160,7 @@ struct HFCandidateCreatorX {
150160
if (trackNeg.pt() < ptPionMin) {
151161
continue;
152162
}
163+
hPtPion->Fill(trackNeg.pt());
153164

154165
auto trackParVarPos = getTrackParCov(trackPos);
155166
auto trackParVarNeg = getTrackParCov(trackNeg);
@@ -190,7 +201,13 @@ struct HFCandidateCreatorX {
190201
auto errorDecayLength = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, theta) + getRotatedCovMatrixXX(covMatrixPCA, phi, theta));
191202
auto errorDecayLengthXY = std::sqrt(getRotatedCovMatrixXX(covMatrixPV, phi, 0.) + getRotatedCovMatrixXX(covMatrixPCA, phi, 0.));
192203

193-
int hfFlag = 1 << XToJpsiPiPi;
204+
int hfFlag = 0;
205+
if (TESTBIT(jpsiCand.hfflag(), hf_cand_prong2::DecayType::JpsiToMuMu)) {
206+
SETBIT(hfFlag, hf_cand_x::DecayType::XToJpsiToMuMuPiPi); // dimuon channel
207+
}
208+
if (TESTBIT(jpsiCand.hfflag(), hf_cand_prong2::DecayType::JpsiToEE)) {
209+
SETBIT(hfFlag, hf_cand_x::DecayType::XToJpsiToEEPiPi); // dielectron channel
210+
}
194211

195212
// fill the candidate table for the X here:
196213
rowCandidateBase(collision.globalIndex(),
@@ -209,7 +226,12 @@ struct HFCandidateCreatorX {
209226
// calculate invariant mass
210227
auto arrayMomenta = array{pvecJpsi, pvecPos, pvecNeg};
211228
massJpsiPiPi = RecoDecay::M(std::move(arrayMomenta), array{massJpsi, massPi, massPi});
212-
hMassX->Fill(massJpsiPiPi);
229+
if (jpsiCand.isSelJpsiToEE() > 0) {
230+
hMassXToJpsiToEEPiPi->Fill(massJpsiPiPi);
231+
}
232+
if (jpsiCand.isSelJpsiToMuMu() > 0) {
233+
hMassXToJpsiToMuMuPiPi->Fill(massJpsiPiPi);
234+
}
213235
} // pi- loop
214236
} // pi+ loop
215237
} // Jpsi loop
@@ -233,6 +255,8 @@ struct HFCandidateCreatorXMC {
233255
aod::McParticles const& particlesMC)
234256
{
235257
int indexRec = -1;
258+
int pdgCodeX = pdg::Code::kX3872;
259+
int pdgCodeJpsi = pdg::Code::kJpsi;
236260
int8_t sign = 0;
237261
int8_t flag = 0;
238262
int8_t origin = 0;
@@ -245,16 +269,32 @@ struct HFCandidateCreatorXMC {
245269
origin = 0;
246270
channel = 0;
247271
auto jpsiTrack = candidate.index0();
272+
auto daughterPosJpsi = jpsiTrack.index0_as<aod::BigTracksMC>();
273+
auto daughterNegJpsi = jpsiTrack.index1_as<aod::BigTracksMC>();
274+
auto arrayJpsiDaughters = array{daughterPosJpsi, daughterNegJpsi};
248275
auto arrayDaughters = array{candidate.index1_as<aod::BigTracksMC>(),
249276
candidate.index2_as<aod::BigTracksMC>(),
250-
jpsiTrack.index0_as<aod::BigTracksMC>(),
251-
jpsiTrack.index1_as<aod::BigTracksMC>()};
277+
daughterPosJpsi,
278+
daughterNegJpsi};
252279

253280
// X → J/ψ π+ π-
254281
//Printf("Checking X → J/ψ π+ π-");
255-
indexRec = RecoDecay::getMatchedMCRec(particlesMC, arrayDaughters, 9920443, array{+kPiPlus, -kPiPlus, +kElectron, -kElectron}, true, &sign, 2);
282+
indexRec = RecoDecay::getMatchedMCRec(particlesMC, arrayJpsiDaughters, pdg::Code::kJpsi, array{+kElectron, -kElectron}, true);
256283
if (indexRec > -1) {
257-
flag = 1 << XToJpsiPiPi;
284+
indexRec = RecoDecay::getMatchedMCRec(particlesMC, arrayDaughters, pdgCodeX, array{+kPiPlus, -kPiPlus, +kElectron, -kElectron}, true, &sign, 2);
285+
if (indexRec > -1) {
286+
flag = 1 << hf_cand_x::DecayType::XToJpsiToEEPiPi;
287+
}
288+
}
289+
290+
if (flag == 0) {
291+
indexRec = RecoDecay::getMatchedMCRec(particlesMC, arrayJpsiDaughters, pdg::Code::kJpsi, array{+kMuonPlus, -kMuonPlus}, true);
292+
if (indexRec > -1) {
293+
indexRec = RecoDecay::getMatchedMCRec(particlesMC, arrayDaughters, pdgCodeX, array{+kPiPlus, -kPiPlus, +kMuonPlus, -kMuonPlus}, true, &sign, 2);
294+
if (indexRec > -1) {
295+
flag = 1 << hf_cand_x::DecayType::XToJpsiToMuMuPiPi;
296+
}
297+
}
258298
}
259299

260300
// Check whether the particle is non-prompt (from a b quark).
@@ -275,13 +315,19 @@ struct HFCandidateCreatorXMC {
275315

276316
// X → J/ψ π+ π-
277317
//Printf("Checking X → J/ψ π+ π-");
278-
if (RecoDecay::isMatchedMCGen(particlesMC, particle, 9920443, array{443, +kPiPlus, -kPiPlus}, true)) {
318+
if (RecoDecay::isMatchedMCGen(particlesMC, particle, pdgCodeX, array{pdgCodeJpsi, +kPiPlus, -kPiPlus}, true)) {
279319
// Match J/psi --> e+e-
280320
std::vector<int> arrDaughter;
281-
RecoDecay::getDaughters(particlesMC, particle, &arrDaughter, array{443}, 1);
321+
RecoDecay::getDaughters(particlesMC, particle, &arrDaughter, array{pdgCodeJpsi}, 1);
282322
auto jpsiCandMC = particlesMC.iteratorAt(arrDaughter[0]);
283-
if (RecoDecay::isMatchedMCGen(particlesMC, jpsiCandMC, 443, array{+kElectron, -kElectron}, true)) {
284-
flag = 1 << XToJpsiPiPi;
323+
if (RecoDecay::isMatchedMCGen(particlesMC, jpsiCandMC, pdgCodeJpsi, array{+kElectron, -kElectron}, true)) {
324+
flag = 1 << hf_cand_x::DecayType::XToJpsiToEEPiPi;
325+
}
326+
327+
if (flag == 0) {
328+
if (RecoDecay::isMatchedMCGen(particlesMC, jpsiCandMC, pdgCodeJpsi, array{+kMuonPlus, -kMuonPlus}, true)) {
329+
flag = 1 << hf_cand_x::DecayType::XToJpsiToMuMuPiPi;
330+
}
285331
}
286332
}
287333

PWGHF/TableProducer/HFTreeCreatorXToJpsiPiPi.cxx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "ReconstructionDataFormats/DCA.h"
2727

2828
using namespace o2;
29+
using namespace o2::aod;
2930
using namespace o2::framework;
3031
using namespace o2::aod::hf_cand_x;
3132

@@ -173,14 +174,15 @@ struct HfTreeCreatorXTojpsipipi {
173174
}
174175
};
175176

176-
fillTable(0, candidate.isSelXToJpsiPiPi(), InvMassXToJpsiPiPi(candidate), CtX(candidate), YX(candidate));
177+
fillTable(0, candidate.isSelXToJpsiToEEPiPi(), InvMassXToJpsiPiPi(candidate), CtX(candidate), YX(candidate));
178+
fillTable(1, candidate.isSelXToJpsiToMuMuPiPi(), InvMassXToJpsiPiPi(candidate), CtX(candidate), YX(candidate));
177179
}
178180

179181
// Filling particle properties
180182
float massX = 3.872;
181183
rowCandidateFullParticles.reserve(particles.size());
182184
for (auto& particle : particles) {
183-
if (std::abs(particle.flagMCMatchGen()) == 1 << DecayType::XToJpsiPiPi) {
185+
if (std::abs(particle.flagMCMatchGen()) == 1 << DecayType::XToJpsiToEEPiPi || std::abs(particle.flagMCMatchGen()) == 1 << DecayType::XToJpsiToMuMuPiPi) {
184186
rowCandidateFullParticles(
185187
particle.mcCollision().bcId(),
186188
particle.pt(),

PWGHF/TableProducer/HFXToJpsiPiPiCandidateSelector.cxx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
/// \brief X(3872) selection task.
1414
/// \note Adapted from HFJpsiCandidateSelector.cxx
1515
/// \author Rik Spijkers <r.spijkers@students.uu.nl>, Utrecht University
16+
/// \author Luca Micheletti <luca.micheletti@to.infn.it>, INFN
1617

1718
#include "Framework/runDataProcessing.h"
1819
#include "Framework/AnalysisTask.h"
1920
#include "PWGHF/Core/HFSelectorCuts.h"
2021
#include "PWGHF/DataModel/HFSecondaryVertex.h"
2122
#include "PWGHF/DataModel/HFCandidateSelectionTables.h"
2223
using namespace o2;
24+
using namespace o2::aod;
2325
using namespace o2::framework;
2426
using namespace o2::aod::hf_cand_x;
2527
using namespace o2::analysis;
@@ -191,16 +193,26 @@ struct HFXToJpsiPiPiCandidateSelector {
191193
auto trackPos = hfCandX.index1_as<aod::BigTracksPID>(); //positive daughter
192194
auto trackNeg = hfCandX.index2_as<aod::BigTracksPID>(); //negative daughter
193195

196+
int selJpsiToEE = 1;
197+
int selJpsiToMuMu = 1;
198+
194199
// check if flagged as X --> Jpsi Pi Pi
195-
if (!(hfCandX.hfflag() & 1 << XToJpsiPiPi)) {
196-
hfSelXToJpsiPiPiCandidate(0);
197-
// Printf("X candidate selection failed at hfflag check");
200+
if (!(hfCandX.hfflag() & 1 << hf_cand_x::DecayType::XToJpsiToEEPiPi)) {
201+
selJpsiToEE = 0;
202+
}
203+
204+
if (!(hfCandX.hfflag() & 1 << hf_cand_x::DecayType::XToJpsiToMuMuPiPi)) {
205+
selJpsiToMuMu = 0;
206+
}
207+
208+
if (selJpsiToEE == 0 && selJpsiToMuMu == 0) {
209+
hfSelXToJpsiPiPiCandidate(0, 0);
198210
continue;
199211
}
200212

201213
// daughter track validity selection
202214
if (!daughterSelection(trackPos) || !daughterSelection(trackNeg)) {
203-
hfSelXToJpsiPiPiCandidate(0);
215+
hfSelXToJpsiPiPiCandidate(0, 0);
204216
// Printf("X candidate selection failed at daughter selection");
205217
continue;
206218
}
@@ -209,18 +221,18 @@ struct HFXToJpsiPiPiCandidateSelector {
209221
//need to add special cuts (additional cuts on decay length and d0 norm)
210222

211223
if (!selectionTopol(hfCandX, candJpsi, trackPos, trackNeg)) {
212-
hfSelXToJpsiPiPiCandidate(0);
224+
hfSelXToJpsiPiPiCandidate(0, 0);
213225
// Printf("X candidate selection failed at selection topology");
214226
continue;
215227
}
216228

217229
if (selectionPID(trackPos) == 0 || selectionPID(trackNeg) == 0) {
218-
hfSelXToJpsiPiPiCandidate(0);
230+
hfSelXToJpsiPiPiCandidate(0, 0);
219231
// Printf("X candidate selection failed at selection PID");
220232
continue;
221233
}
222234

223-
hfSelXToJpsiPiPiCandidate(1);
235+
hfSelXToJpsiPiPiCandidate(selJpsiToEE, selJpsiToMuMu);
224236
// Printf("X candidate selection successful, candidate should be selected");
225237
}
226238
}

0 commit comments

Comments
 (0)