Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ada77b0
Create workflow for B+->JPsiK
fchinu May 21, 2025
e64c6f2
Add selections to B+ task
fchinu May 25, 2025
0a695d5
Add Bs workflow
fchinu May 26, 2025
7f1391a
Fix linter
fchinu May 26, 2025
2be4867
Fix headers, naming, and double initialisation
fchinu May 27, 2025
6efbcb8
Define pseudoproper decay length function in RecoDecay
fchinu May 30, 2025
7d3997d
Add pseudoproper decay length selection for J/Psi
fchinu May 30, 2025
e8326d8
Implement other Fabrizio's comments
fchinu May 30, 2025
f1abed5
Rename pseudoproprDL to ctXY
fchinu Jun 3, 2025
dd1a960
Add ctXY to tasks output
fchinu Jun 3, 2025
617fc93
Remove non included headers
fchinu Jun 4, 2025
1b75b7b
Use angled brackets
fchinu Jun 4, 2025
1e6d8fc
Refactor DCA selections
fchinu Jun 4, 2025
c7555ca
Implement remaining comments from Vit
fchinu Jun 4, 2025
da805a6
Fix format
fchinu Jun 4, 2025
d8a71ee
Replace o2::gpu::gpustd::array with std::array
fchinu Jun 4, 2025
e0749ac
Implement last comments from Vit
fchinu Jun 6, 2025
a65ce5e
Implement Vit's comments
fchinu Jun 10, 2025
99a6561
Rename files (JPsi -> Jpsi)
fchinu Jun 10, 2025
b60bdf5
Please consider the following formatting changes
alibuild Jun 10, 2025
fc0c514
Merge pull request #29 from alibuild/alibot-cleanup-11368
fchinu Jun 10, 2025
e4fedb5
pTBin -> binPt
fchinu Jun 10, 2025
90caf89
Move to central decay table
fchinu Jun 10, 2025
b6595a8
Refactor decay channels
fchinu Jun 11, 2025
ee3a0d6
Implement comments from Vit
fchinu Jun 12, 2025
a0641df
Fix compilation issue
fchinu Jun 12, 2025
9815412
Remove not needed templates
fchinu Jun 12, 2025
00d57e3
fix decay enum
fchinu Jun 12, 2025
fe187cf
Use latest clang-format
fchinu Jun 12, 2025
0a75b7d
IWYU
fchinu Jun 12, 2025
80e2aaa
Add Common/Core
fchinu Jun 12, 2025
6eac500
clang-format, reorganise headers
fchinu Jun 13, 2025
30eb660
Add documentation for isSelectedTrackDCA
fchinu Jun 13, 2025
6203202
More clang-format
fchinu Jun 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Common/Core/RecoDecay.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <array> // std::array
#include <cmath> // std::abs, std::sqrt
#include <cstdio>
#include <tuple> // std::apply
#include <utility> // std::move
#include <vector> // std::vector

Expand Down Expand Up @@ -285,6 +286,19 @@
return static_cast<double>(length) * static_cast<double>(mass) / p(mom);
}

/// Calculates proper lifetime times c (pseudoproper decay length) in XY from information on daughter tracks.
/// \param posPV {x, y, z} or {x, y} position of the primary vertex
/// \param posSV {x, y, z} or {x, y} position of the secondary vertex
/// \param mom array of {x, y, z} or {x, y} momentum arrays of the decay products
/// \param mass mass of the decay products
/// \return pseudoproper decay length
template <std::size_t N, std::size_t NM, typename T, typename U, typename V, typename M>
static double ctXY(const T& posPV, const U& posSV, const std::array<std::array<V, NM>, N>& mom, const std::array<M, N> mass)
{
// c t_xy = l_xy * m c^2 / (pT c)
return distanceXY(posPV, posSV) * m(mom, mass) / std::apply([](const auto&... args) { return pt(args...); }, mom);
}

/// Calculates cosine of θ* (theta star).
/// \note Implemented for 2 prongs only.
/// \param arrMom array of two 3-momentum arrays
Expand Down Expand Up @@ -431,7 +445,7 @@
std::array<double, 3> momTotal{0., 0., 0.}; // candidate momentum vector
double energyTot{0.}; // candidate energy
for (std::size_t iProng = 0; iProng < N; ++iProng) {
for (std::size_t iMom = 0; iMom < 3; ++iMom) {

Check failure on line 448 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
momTotal[iMom] += arrMom[iProng][iMom];
} // loop over momentum components
energyTot += e(arrMom[iProng], arrMass[iProng]);
Expand Down Expand Up @@ -1000,7 +1014,7 @@
arrayIds.push_back(initVec); // the first vector contains the index of the original particle
auto pdgParticle = std::abs(particle.pdgCode());
bool couldBePrompt = false;
if (pdgParticle / 100 == kCharm || pdgParticle / 1000 == kCharm) {

Check failure on line 1017 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
couldBePrompt = true;
}
while (arrayIds[-stage].size() > 0) {
Expand All @@ -1014,7 +1028,7 @@
if (!searchUpToQuark) {
auto mother = particlesMC.rawIteratorAt(particleMother.mothersIds().front() - particlesMC.offset());
auto pdgParticleIMother = std::abs(mother.pdgCode()); // PDG code of the mother
if (pdgParticleIMother < 9 || (pdgParticleIMother > 20 && pdgParticleIMother < 38)) {

Check failure on line 1031 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
return OriginType::Prompt;
}
}
Expand All @@ -1033,8 +1047,8 @@

if (searchUpToQuark) {
if (idxBhadMothers) {
if (pdgParticleIMother / 100 == kBottom || // b mesons

Check failure on line 1050 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
pdgParticleIMother / 1000 == kBottom) // b baryons

Check failure on line 1051 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
{
idxBhadMothers->push_back(iMother);
}
Expand All @@ -1047,8 +1061,8 @@
}
} else {
if (
(pdgParticleIMother / 100 == kBottom || // b mesons

Check failure on line 1064 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
pdgParticleIMother / 1000 == kBottom) // b baryons

Check failure on line 1065 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
) {
if (idxBhadMothers) {
idxBhadMothers->push_back(iMother);
Expand All @@ -1056,8 +1070,8 @@
return OriginType::NonPrompt;
}
if (
(pdgParticleIMother / 100 == kCharm || // c mesons

Check failure on line 1073 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
pdgParticleIMother / 1000 == kCharm) // c baryons

Check failure on line 1074 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
) {
couldBePrompt = true;
}
Expand Down Expand Up @@ -1098,7 +1112,7 @@
arrayIds.push_back(initVec); // the first vector contains the index of the original particle
auto pdgParticle = std::abs(particle.pdgCode());
bool couldBeCharm = false;
if (pdgParticle / 100 == kCharm || pdgParticle / 1000 == kCharm) {

Check failure on line 1115 in Common/Core/RecoDecay.h

View workflow job for this annotation

GitHub Actions / O2 linter

[magic-number]

Avoid magic numbers in expressions. Assign the value to a clearly named variable or constant.
couldBeCharm = true;
}
while (arrayIds[-stage].size() > 0) {
Expand Down
24 changes: 24 additions & 0 deletions PWGHF/Core/DecayChannels.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,30 @@ enum DecayChannelResonant : int8_t {
//
LastChannelResonant
};
/// @brief beauty candidates: beauty to J/ψ decay channels
enum DecayChannelToJpsiMain : int8_t {
// B0
B0ToJpsiPiK = 1, // J/ψ π- K+
// Bs0
BsToJpsiKK, // J/ψ K+ K-
// Λb0
LbToJpsiPK, // J/ψ p K-
// B+
BplusToJpsiK, // J/ψ K+
// Bc+
BcToJpsiPi, // J/ψ π+
//
LastChannelToJpsiMain
};
/// @brief beauty candidates: beauty to J/ψ resonant decay channels
enum DecayChannelToJpsiResonant : int8_t {
// B0
B0ToJpsiKstar0 = 1, // J/ψ K*0(892)
// Bs0
BsToJpsiPhi, // J/ψ φ
//
LastChannelToJpsiResonant
};
} // namespace hf_cand_beauty
} // namespace o2::hf_decay

Expand Down
250 changes: 233 additions & 17 deletions PWGHF/Core/HfHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@
#ifndef PWGHF_CORE_HFHELPER_H_
#define PWGHF_CORE_HFHELPER_H_

#include <Math/GenVector/Boost.h>
#include <Math/Vector4D.h> // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h)
#include "PWGHF/Utils/utilsAnalysis.h"

#include "Common/Core/RecoDecay.h"
#include "Common/Core/TrackSelectorPID.h"

#include <CommonConstants/MathConstants.h>
#include <CommonConstants/PhysicsConstants.h>

#include <Math/GenVector/Boost.h>
#include <Math/Vector4D.h> // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h)

#include <array>
#include <cmath>
#include <vector>

#include "Common/Core/RecoDecay.h"
#include "Common/Core/TrackSelectorPID.h"

#include "PWGHF/Utils/utilsAnalysis.h"

class HfHelper
{
public:
Expand Down Expand Up @@ -173,6 +173,12 @@ class HfHelper
return candidate.m(std::array{o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus});
}

template <typename T>
auto invMassBplusToJpsiK(const T& candidate)
{
return candidate.m(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus});
}

template <typename T>
auto cosThetaStarBplus(const T& candidate)
{
Expand Down Expand Up @@ -659,6 +665,12 @@ class HfHelper
return candidate.m(std::array{o2::constants::physics::MassDSBar, o2::constants::physics::MassPiPlus});
}

template <typename T>
auto invMassBsToJpsiPhi(const T& candidate)
{
return candidate.m(std::array{o2::constants::physics::MassMuon, o2::constants::physics::MassMuon, o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus});
}

template <typename T>
auto cosThetaStarBs(const T& candidate)
{
Expand Down Expand Up @@ -784,8 +796,7 @@ class HfHelper
/// \param pidTrackPi PID status of trackPi (prong1 of B0 candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of B0 candidate passes all selections
template <typename T1 = int, typename T2 = bool>
bool selectionB0ToDPiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable)
bool selectionB0ToDPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) {
return false;
Expand All @@ -805,10 +816,10 @@ class HfHelper
template <typename T1, typename T2, typename T3>
bool selectionBplusToD0PiTopol(const T1& candBp, const T2& cuts, const T3& binsPt)
{
auto ptcandBp = candBp.pt();
auto ptCandBp = candBp.pt();
auto ptPi = RecoDecay::pt(candBp.pxProng1(), candBp.pyProng1());

int pTBin = o2::analysis::findBin(binsPt, ptcandBp);
int pTBin = o2::analysis::findBin(binsPt, ptCandBp);
if (pTBin == -1) {
return false;
}
Expand Down Expand Up @@ -860,8 +871,7 @@ class HfHelper
/// \param pidTrackPi PID status of trackPi (prong1 of B+ candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of B+ candidate passes all selections
template <typename T1 = int, typename T2 = bool>
bool selectionBplusToD0PiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable)
bool selectionBplusToD0PiPid(const int pidTrackPi, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) {
return false;
Expand All @@ -873,6 +883,105 @@ class HfHelper
return true;
}

// Apply topological cuts as defined in SelectorCuts.h
/// \param candBp B+ candidate
/// \param cuts B+ candidate selection per pT bin
/// \param binsPt pT bin limits
/// \return true if candidate passes all selections
template <typename T1, typename T2, typename T3>
bool selectionBplusToJpsiKTopol(const T1& candBp, const T2& cuts, const T3& binsPt)
{
auto ptCandBp = candBp.pt();
auto mCandBp = invMassBplusToJpsiK(candBp);
auto ptJpsi = RecoDecay::pt(candBp.pxProng0(), candBp.pyProng0());
auto ptKa = RecoDecay::pt(candBp.pxProng1(), candBp.pyProng1());
auto candJpsi = candBp.jpsi();
float pseudoPropDecLen = candBp.decayLengthXY() * mCandBp / ptCandBp;

int binPt = o2::analysis::findBin(binsPt, ptCandBp);
if (binPt == -1) {
return false;
}

// B+ mass cut
if (std::abs(mCandBp - o2::constants::physics::MassBPlus) > cuts->get(binPt, "m")) {
return false;
}

// kaon pt
if (ptKa < cuts->get(binPt, "pT K")) {
return false;
}

// J/Psi pt
if (ptJpsi < cuts->get(binPt, "pT J/Psi")) {
return false;
}

// J/Psi mass
if (std::abs(candJpsi.m() - o2::constants::physics::MassJPsi) < cuts->get(binPt, "DeltaM J/Psi")) {
return false;
}

// d0(J/Psi)xd0(K)
if (candBp.impactParameterProduct() > cuts->get(binPt, "B Imp. Par. Product")) {
return false;
}

// B+ Decay length
if (candBp.decayLength() < cuts->get(binPt, "B decLen")) {
return false;
}

// B+ Decay length XY
if (candBp.decayLengthXY() < cuts->get(binPt, "B decLenXY")) {
return false;
}

// B+ CPA cut
if (candBp.cpa() < cuts->get(binPt, "CPA")) {
return false;
}

// B+ CPAXY cut
if (candBp.cpaXY() < cuts->get(binPt, "CPAXY")) {
return false;
}

// d0 of K
if (std::abs(candBp.impactParameter1()) < cuts->get(binPt, "d0 K")) {
return false;
}

// d0 of J/Psi
if (std::abs(candBp.impactParameter0()) < cuts->get(binPt, "d0 J/Psi")) {
return false;
}

// B pseudoproper decay length
if (pseudoPropDecLen < cuts->get(binPt, "B pseudoprop. decLen")) {
return false;
}

return true;
}

/// Apply PID selection
/// \param pidTrackKa PID status of trackKa (prong1 of B+ candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of B+ candidate passes all selections
bool selectionBplusToJpsiKPid(const int pidTrackKa, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackKa != TrackSelectorPID::Accepted) {
return false;
}
if (acceptPIDNotApplicable && pidTrackKa == TrackSelectorPID::Rejected) {
return false;
}

return true;
}

/// Apply topological cuts as defined in SelectorCuts.h
/// \param candBs Bs candidate
/// \param cuts Bs candidate selections
Expand Down Expand Up @@ -947,8 +1056,7 @@ class HfHelper
/// \param pidTrackPi PID status of trackPi (prong1 of Bs candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of Bs candidate passes all selections
template <typename T1 = int, typename T2 = bool>
bool selectionBsToDsPiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable)
bool selectionBsToDsPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) {
return false;
Expand All @@ -960,6 +1068,115 @@ class HfHelper
return true;
}

// Apply topological cuts as defined in SelectorCuts.h
/// \param candBs Bs candidate
/// \param candKa0 kaon candidate 0 (phi daughter)
/// \param candKa1 kaon candidate 1 (phi daughter)
/// \param cuts Bs candidate selection per pT bin
/// \param binsPt pT bin limits
/// \return true if candidate passes all selections
template <typename T1, typename T2, typename T3, typename T4, typename T5>
bool selectionBsToJpsiPhiTopol(const T1& candBs, const T2& candKa0, const T3& candKa1, const T4& cuts, const T5& binsPt)
{
auto ptCandBs = candBs.pt();
auto mCandBs = invMassBsToJpsiPhi(candBs);
std::array<float, 3> pVecKa0 = candKa0.pVector();
std::array<float, 3> pVecKa1 = candKa1.pVector();
auto mCandPhi = RecoDecay::m(std::array{pVecKa0, pVecKa1}, std::array{o2::constants::physics::MassKPlus, o2::constants::physics::MassKPlus});
auto ptJpsi = RecoDecay::pt(candBs.pxProng0(), candBs.pyProng0());
auto candJpsi = candBs.jpsi();
float pseudoPropDecLen = candBs.decayLengthXY() * mCandBs / ptCandBs;

int binPt = o2::analysis::findBin(binsPt, ptCandBs);
if (binPt == -1) {
return false;
}

// Bs mass cut
if (std::abs(mCandBs - o2::constants::physics::MassBPlus) > cuts->get(binPt, "m")) {
return false;
}

// kaon pt
if (candKa0.pt() < cuts->get(binPt, "pT K") &&
candKa1.pt() < cuts->get(binPt, "pT K")) {
return false;
}

// J/Psi pt
if (ptJpsi < cuts->get(binPt, "pT J/Psi")) {
return false;
}

// phi mass
if (std::abs(mCandPhi - o2::constants::physics::MassPhi) < cuts->get(binPt, "DeltaM phi")) {
return false;
}

// J/Psi mass
if (std::abs(candJpsi.m() - o2::constants::physics::MassJPsi) < cuts->get(binPt, "DeltaM J/Psi")) {
return false;
}

// d0(J/Psi)xd0(phi)
if (candBs.impactParameterProduct() > cuts->get(binPt, "B Imp. Par. Product")) {
return false;
}

// Bs Decay length
if (candBs.decayLength() < cuts->get(binPt, "B decLen")) {
return false;
}

// Bs Decay length XY
if (candBs.decayLengthXY() < cuts->get(binPt, "B decLenXY")) {
return false;
}

// Bs CPA cut
if (candBs.cpa() < cuts->get(binPt, "CPA")) {
return false;
}

// Bs CPAXY cut
if (candBs.cpaXY() < cuts->get(binPt, "CPAXY")) {
return false;
}

// d0 of phi
if (std::abs(candBs.impactParameter1()) < cuts->get(binPt, "d0 phi")) {
return false;
}

// d0 of J/Psi
if (std::abs(candBs.impactParameter0()) < cuts->get(binPt, "d0 J/Psi")) {
return false;
}

// B pseudoproper decay length
if (pseudoPropDecLen < cuts->get(binPt, "B pseudoprop. decLen")) {
return false;
}

return true;
}

/// Apply PID selection
/// \param pidTrackKa PID status of trackKa (prong1 of B+ candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of B+ candidate passes all selections
bool selectionBsToJpsiPhiPid(const int pidTrackKa, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackKa != TrackSelectorPID::Accepted) {
return false;
}
if (acceptPIDNotApplicable && pidTrackKa == TrackSelectorPID::Rejected) {
return false;
}

return true;
}

/// Apply topological cuts as defined in SelectorCuts.h
/// \param candLb Lb candidate
/// \param cuts Lb candidate selection per pT bin"
Expand Down Expand Up @@ -1028,8 +1245,7 @@ class HfHelper
/// \param pidTrackPi PID status of trackPi (prong1 of Lb candidate)
/// \param acceptPIDNotApplicable switch to accept Status::NotApplicable
/// \return true if prong1 of Lb candidate passes all selections
template <typename T1 = int, typename T2 = bool>
bool selectionLbToLcPiPid(const T1& pidTrackPi, const T2& acceptPIDNotApplicable)
bool selectionLbToLcPiPid(const int pidTrackPi, const bool acceptPIDNotApplicable)
{
if (!acceptPIDNotApplicable && pidTrackPi != TrackSelectorPID::Accepted) {
return false;
Expand Down
Loading
Loading