Skip to content
Open
28 changes: 23 additions & 5 deletions PWGCF/Femto/Core/cascadeBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <array>
#include <cmath>
#include <cstdint>
#include <limits>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This include is no longer needed. Same in V0Builder

#include <string>
#include <unordered_map>
#include <vector>
Expand Down Expand Up @@ -78,7 +79,9 @@ struct ConfCascadeFilters : o2::framework::ConfigurableGroup {
o2::framework::Configurable<std::vector<float>> posDauTpc{"posDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for positive daughter tracks"}; \
o2::framework::Configurable<std::vector<float>> negDauTpc{"negDauTpc", {5.f}, "Maximum |nsimga_Pion/Proton| TPC for negative daughter tracks"}; \
o2::framework::Configurable<std::vector<float>> posDauTof{"posDauTof", {}, "Maximum |nsimga_Pion/Proton| TOF for positive daughter tracks"}; \
o2::framework::Configurable<std::vector<float>> negDauTof{"negDauTof", {}, "Maximum |nsigma_Pion/Proton| TOF for negative daughter tracks"};
o2::framework::Configurable<std::vector<float>> negDauTof{"negDauTof", {}, "Maximum |nsigma_Pion/Proton| TOF for negative daughter tracks"}; \
o2::framework::Configurable<bool> requireTof{"requireTof", false, "If true, TOF PID is a mandatory selection"}; \
o2::framework::Configurable<bool> keepTracksWithoutTof{"keepTracksWithoutTof", true, "If true, candidates whose daughters have no TOF signal are kept"};

struct ConfXiBits : o2::framework::ConfigurableGroup {
std::string prefix = std::string("XiBits");
Expand Down Expand Up @@ -242,7 +245,7 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
mOmegaMassLowerLimit = filter.rejectMassOmegaMin.value;
mOmegaMassUpperLimit = filter.rejectMassOmegaMax.value;
this->addSelection(kBachelorTpcPion, cascadeSelectionNames.at(kBachelorTpcPion), config.bachelorTpcPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kBachelorTofPion, cascadeSelectionNames.at(kBachelorTofPion), config.bachelorTofPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kBachelorTofPion, cascadeSelectionNames.at(kBachelorTofPion), config.bachelorTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false);
}
if constexpr (modes::isEqual(cascadeType, modes::Cascade::kOmega)) {
mOmegaMassLowerLimit = filter.massOmegaMin.value;
Expand All @@ -251,7 +254,7 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
mXiMassLowerLimit = filter.rejectMassXiMin.value;
mXiMassUpperLimit = filter.rejectMassXiMax.value;
this->addSelection(kBachelorTpcKaon, cascadeSelectionNames.at(kBachelorTpcKaon), config.bachelorTpcKaon.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kBachelorTofKaon, cascadeSelectionNames.at(kBachelorTofKaon), config.bachelorTofKaon.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kBachelorTofKaon, cascadeSelectionNames.at(kBachelorTofKaon), config.bachelorTofKaon.value, limits::kAbsUpperLimit, true, mRequireTof, false);
}

mPtMin = filter.ptMin.value;
Expand All @@ -262,11 +265,13 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
mPhiMax = filter.phiMax.value;
mLambdaMassMin = filter.massLambdaMin.value;
mLambdaMassMax = filter.massLambdaMax.value;
mRequireTof = config.requireTof.value;
mKeepTracksWithoutTof = config.keepTracksWithoutTof.value;

this->addSelection(kPosDauTpc, cascadeSelectionNames.at(kPosDauTpc), config.posDauTpc.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDauTpc, cascadeSelectionNames.at(kNegDauTpc), config.negDauTpc.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDauTof, cascadeSelectionNames.at(kPosDauTof), config.posDauTof.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDauTof, cascadeSelectionNames.at(kNegDauTof), config.negDauTof.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDauTof, cascadeSelectionNames.at(kPosDauTof), config.posDauTof.value, limits::kAbsUpperLimit, true, mRequireTof, false);
this->addSelection(kNegDauTof, cascadeSelectionNames.at(kNegDauTof), config.negDauTof.value, limits::kAbsUpperLimit, true, mRequireTof, false);

this->addSelection(kCascadeCpaMin, cascadeSelectionNames.at(kCascadeCpaMin), config.cascadeCpaMin.value, limits::kLowerLimit, true, true, false);
this->addSelection(kCascadeTransRadMin, cascadeSelectionNames.at(kCascadeTransRadMin), config.cascadeTransRadMin.value, limits::kLowerLimit, true, true, false);
Expand Down Expand Up @@ -336,6 +341,9 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
if (bachelor.hasTOF()) {
this->evaluateObservable(kBachelorTofPion, bachelor.tofNSigmaPi());
this->evaluateObservable(kBachelorTofKaon, bachelor.tofNSigmaKa());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kBachelorTofPion, 0);

@ariedel-cern ariedel-cern Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call would set the bitmask itself to 0, i.e. the selection would not be passed, which is what we want to avoid in this branch if the track has no TOF.
You have to call here

this->evaluateObservable(kBachelorTofPion, 0);

Like this we compare 0 against all the limits (which are positive definite), so all bits in the bitmask will be set to 1.
This applies to all other calls below (and in the V0Builder).

this->setBitmask(kBachelorTofKaon, 0);
}

// depending on the charge, we check lambda or antilambda hypothesis
Expand All @@ -344,18 +352,26 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPi());
if (posDaughter.hasTOF()) {
this->evaluateObservable(kPosDauTof, posDaughter.tofNSigmaPr());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kPosDauTof, 0);
}
if (negDaughter.hasTOF()) {
this->evaluateObservable(kNegDauTof, negDaughter.tofNSigmaPi());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kNegDauTof, 0);
}
} else if (cascade.sign() > 0) {
this->evaluateObservable(kPosDauTpc, posDaughter.tpcNSigmaPi());
this->evaluateObservable(kNegDauTpc, negDaughter.tpcNSigmaPr());
if (posDaughter.hasTOF()) {
this->evaluateObservable(kPosDauTof, posDaughter.tofNSigmaPi());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kPosDauTof, 0);
}
if (negDaughter.hasTOF()) {
this->evaluateObservable(kNegDauTof, negDaughter.tofNSigmaPr());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kNegDauTof, 0);
}
} else {
LOG(warn) << "Encountered Cascade candidate with 0 charge";
Expand Down Expand Up @@ -468,6 +484,8 @@ class CascadeSelection : public baseselection::BaseSelection<float, o2::analysis
float mPhiMax = o2::constants::math::TwoPI;
float mLambdaMassMin = 1.f;
float mLambdaMassMax = 1.2f;
bool mRequireTof = false;
bool mKeepTracksWithoutTof = false;
};

struct CascadeBuilderProducts : o2::framework::ProducesGroup {
Expand Down
28 changes: 22 additions & 6 deletions PWGCF/Femto/Core/v0Builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <array>
#include <cmath>
#include <cstdint>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
Expand Down Expand Up @@ -85,6 +86,8 @@ struct ConfLambdaBits : o2::framework::ConfigurableGroup {
o2::framework::Configurable<std::vector<float>> posDauTofProton{"posDauTofProton", {}, "Maximum |nsigma_Proton| TOF for positive daughter tracks"};
o2::framework::Configurable<std::vector<float>> negDauTofPion{"negDauTofPion", {}, "Maximum |nsigma_Pion| TOF for negative daughter tracks"};
o2::framework::Configurable<std::vector<float>> negDauTofProton{"negDauTofProton", {}, "Maximum |nsigma_Proton| TOF for negative daughter tracks"};
o2::framework::Configurable<bool> requireTof{"requireTof", false, "If true, TOF PID is a mandatory selection"};
o2::framework::Configurable<bool> keepTracksWithoutTof{"keepTracksWithoutTof", true, "If true, candidates whose daughters have no TOF signal are kept"};
};

// derived selection bits for K0Short
Expand All @@ -95,6 +98,8 @@ struct ConfK0shortBits : o2::framework::ConfigurableGroup {
o2::framework::Configurable<std::vector<float>> negDauTpcPion{"negDauTpcPion", {5.f}, "Maximum |nsimga_Pion| TPC for negative daughter tracks"};
o2::framework::Configurable<std::vector<float>> posDauTofPion{"posDauTofPion", {}, "Maximum |nsigma_Pion| TOF for positive daughter tracks"};
o2::framework::Configurable<std::vector<float>> negDauTofPion{"negDauTofPion", {}, "Maximum |nsigma_Pion| TOF for negative daughter tracks"};
o2::framework::Configurable<bool> requireTof{"requireTof", false, "If true, TOF PID is a mandatory selection"};
o2::framework::Configurable<bool> keepTracksWithoutTof{"keepTracksWithoutTof", true, "If true, candidates whose daughters have no TOF signal are kept"};
};

#undef V0_DEFAULT_BITS
Expand Down Expand Up @@ -246,6 +251,8 @@ class V0Selection : public baseselection::BaseSelection<float, datatypes::V0Mask
mEtaMax = filter.etaMax.value;
mPhiMin = filter.phiMin.value;
mPhiMax = filter.phiMax.value;
mRequireTof = config.requireTof.value;
mKeepTracksWithoutTof = config.keepTracksWithoutTof.value;

if constexpr (modes::isEqual(v0Type, modes::V0::kLambda) || modes::isEqual(v0Type, modes::V0::kAntiLambda)) {
mMassLambdaLowerLimit = filter.massMinLambda.value;
Expand All @@ -257,15 +264,15 @@ class V0Selection : public baseselection::BaseSelection<float, datatypes::V0Mask
if constexpr (modes::isEqual(v0Type, modes::V0::kLambda)) {
this->addSelection(kPosDaughTpcProton, v0SelectionNames.at(kPosDaughTpcProton), config.posDauTpcProton.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofProton, v0SelectionNames.at(kPosDaughTofProton), config.posDauTofProton.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofProton, v0SelectionNames.at(kPosDaughTofProton), config.posDauTofProton.value, limits::kAbsUpperLimit, true, mRequireTof, false);
this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false);
}

if constexpr (modes::isEqual(v0Type, modes::V0::kAntiLambda)) {
this->addSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTpcProton, v0SelectionNames.at(kNegDaughTpcProton), config.negDauTpcProton.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTofProton, v0SelectionNames.at(kNegDaughTofProton), config.negDauTofProton.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false);
this->addSelection(kNegDaughTofProton, v0SelectionNames.at(kNegDaughTofProton), config.negDauTofProton.value, limits::kAbsUpperLimit, true, mRequireTof, false);
}
}
if constexpr (modes::isEqual(v0Type, modes::V0::kK0short)) {
Expand All @@ -277,8 +284,8 @@ class V0Selection : public baseselection::BaseSelection<float, datatypes::V0Mask

this->addSelection(kPosDaughTpcPion, v0SelectionNames.at(kPosDaughTpcPion), config.posDauTpcPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTpcPion, v0SelectionNames.at(kNegDaughTpcPion), config.negDauTpcPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, true, false);
this->addSelection(kPosDaughTofPion, v0SelectionNames.at(kPosDaughTofPion), config.posDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false);
this->addSelection(kNegDaughTofPion, v0SelectionNames.at(kNegDaughTofPion), config.negDauTofPion.value, limits::kAbsUpperLimit, true, mRequireTof, false);
}

this->addSelection(kDcaDaughMax, v0SelectionNames.at(kDcaDaughMax), config.dcaDauMax.value, limits::kAbsUpperLimit, true, true, false);
Expand Down Expand Up @@ -345,10 +352,16 @@ class V0Selection : public baseselection::BaseSelection<float, datatypes::V0Mask
if (posDaughter.hasTOF()) {
this->evaluateObservable(kPosDaughTofPion, posDaughter.tofNSigmaPi());
this->evaluateObservable(kPosDaughTofProton, posDaughter.tofNSigmaPr());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kPosDaughTofPion, 0);
this->setBitmask(kPosDaughTofProton, 0);
}
if (negDaughter.hasTOF()) {
this->evaluateObservable(kNegDaughTofPion, negDaughter.tofNSigmaPi());
this->evaluateObservable(kNegDaughTofProton, negDaughter.tofNSigmaPr());
} else if (mKeepTracksWithoutTof) {
this->setBitmask(kNegDaughTofPion, 0);
this->setBitmask(kNegDaughTofProton, 0);
}

this->assembleBitmask<SelectionHistName>();
Expand Down Expand Up @@ -452,6 +465,9 @@ class V0Selection : public baseselection::BaseSelection<float, datatypes::V0Mask
float mEtaMax = 1.f;
float mPhiMin = 0.f;
float mPhiMax = o2::constants::math::TwoPI;

bool mRequireTof = false;
bool mKeepTracksWithoutTof = false;
};

struct V0BuilderProducts : o2::framework::ProducesGroup {
Expand Down
Loading