Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PWGHF,PWGJE] Update B+ selector task to be similar to B+ reduced selector task and use machine learning #8858

Merged
merged 5 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 32 additions & 7 deletions PWGHF/Core/HfHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -947,34 +947,59 @@ class HfHelper
}

/// Apply selection on ML scores for charm-hadron daughter in b-hadron decays (common for all the beauty channels)
/// \param candB b-hadron candidates
/// \param cuts ML score selection per bin of charm-hadron pT
/// \param binsPtC pT bin limits of charm hadron
/// \param mlScores vector with ml scores of charm hadron (position 0:bkg 1:prompt 2:nonprompt)
/// \return true if b-hadron candidate passes all selections
template <typename T1, typename T2, typename T3>
bool selectionDmesMlScoresForB(const T1& candB, const T2& cuts, const T3& binsPtC)
template <typename T1, typename T2>
bool applySelectionDmesMlScoresForB(const T1& cuts, const T2& binsPtC, float ptC, std::vector<float> mlScores)
{
auto ptC = RecoDecay::pt(candB.pxProng0(), candB.pyProng0()); // the first daughter is the charm hadron
int pTBin = o2::analysis::findBin(binsPtC, ptC);
if (pTBin == -1) {
return false;
}

if (candB.prong0MlScoreBkg() > cuts->get(pTBin, "ML score charm bkg")) {
if (mlScores[0] > cuts->get(pTBin, "ML score charm bkg")) {
return false;
}

if (candB.prong0MlScorePrompt() > cuts->get(pTBin, "ML score charm prompt")) { // we want non-prompt for beauty
if (mlScores[1] > cuts->get(pTBin, "ML score charm prompt")) { // we want non-prompt for beauty
return false;
}

if (candB.prong0MlScoreNonprompt() < cuts->get(pTBin, "ML score charm nonprompt")) { // we want non-prompt for beauty
if (mlScores[2] < cuts->get(pTBin, "ML score charm nonprompt")) { // we want non-prompt for beauty
return false;
}

return true;
}

/// Apply selection on ML scores for charm-hadron daughter in b-hadron decays (could be common for all the beauty channels)
/// \param candB b-hadron candidates
/// \param cuts ML score selection per bin of charm-hadron pT
/// \param binsPtC pT bin limits of charm hadron
/// \return true if b-hadron candidate passes all selections
template <typename T1, typename T2, typename T3>
bool selectionDmesMlScoresForB(const T1& candD, const T2& cuts, const T3& binsPtC, const std::vector<float>& mlScores)
{
return applySelectionDmesMlScoresForB(cuts, binsPtC, candD.pt(), mlScores);
}

/// Apply selection on ML scores for charm-hadron daughter in b-hadron decays in reduced format (common for all the beauty channels)
/// \param candB b-hadron candidates
/// \param cuts ML score selection per bin of charm-hadron pT
/// \param binsPtC pT bin limits of charm hadron
/// \return true if b-hadron candidate passes all selections
template <typename T1, typename T2, typename T3>
bool selectionDmesMlScoresForBReduced(const T1& candB, const T2& cuts, const T3& binsPtC)
{
std::vector<float> mlScores;
mlScores.push_back(candB.prong0MlScoreBkg());
mlScores.push_back(candB.prong0MlScorePrompt());
mlScores.push_back(candB.prong0MlScoreNonprompt()); // we want non-prompt for beauty
return applySelectionDmesMlScoresForB(cuts, binsPtC, RecoDecay::pt(candB.pxProng0(), candB.pyProng0()), mlScores);
}

private:
};

Expand Down
41 changes: 27 additions & 14 deletions PWGHF/Core/HfMlResponseBplusToD0Pi.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
// Fill the map of available input features
// the key is the feature's name (std::string)
// the value is the corresponding value in EnumInputFeatures
#define FILL_MAP_BPLUS(FEATURE) \
{ \
#FEATURE, static_cast < uint8_t>(InputFeaturesBplusToD0Pi::FEATURE) \
#define FILL_MAP_BPLUS(FEATURE) \
{ \
#FEATURE, static_cast<uint8_t>(InputFeaturesBplusToD0Pi::FEATURE) \
}

// Check if the index of mCachedIndices (index associated to a FEATURE)
Expand Down Expand Up @@ -59,6 +59,17 @@
break; \
}

// where OBJECT is named candidateD , FEATURE = GETTER and INDEX is the index of the vector
#define CHECK_AND_FILL_VEC_D0_INDEX(FEATURE, GETTER1, GETTER2, INDEX) \
case static_cast<uint8_t>(InputFeaturesBplusToD0Pi::FEATURE): { \
if (pdgCode == o2::constants::physics::kD0) { \
inputFeatures.emplace_back((candidateD0.GETTER1())[INDEX]); \
} else { \
inputFeatures.emplace_back((candidateD0.GETTER2())[INDEX]); \
} \
break; \
}

namespace o2::analysis
{

Expand All @@ -76,9 +87,9 @@ enum class InputFeaturesBplusToD0Pi : uint8_t {
cpa,
cpaXY,
maxNormalisedDeltaIP,
prong0MlScoreBkg,
prong0MlScorePrompt,
prong0MlScoreNonprompt,
prong0MlProbBkg,
prong0MlProbPrompt,
prong0MlProbNonPrompt,
tpcNSigmaPi1,
tofNSigmaPi1,
tpcTofNSigmaPi1
Expand All @@ -97,9 +108,11 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse<TypeOutputScore>
/// \param candidate is the B+ candidate
/// \param prong1 is the candidate's prong1
/// \return inputFeatures vector
template <bool withDmesMl, typename T1, typename T2>
template <bool withDmesMl, typename T1, typename T2, typename T3>
std::vector<float> getInputFeatures(T1 const& candidate,
T2 const& prong1)
T2 const& candidateD0,
int const& pdgCode,
T3 const& prong1)
{
std::vector<float> inputFeatures;

Expand All @@ -119,9 +132,9 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse<TypeOutputScore>
CHECK_AND_FILL_VEC_BPLUS(cpa);
CHECK_AND_FILL_VEC_BPLUS(cpaXY);
CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreBkg);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScorePrompt);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreNonprompt);
CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbBkg, mlProbD0, mlProbD0bar, 0);
CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbPrompt, mlProbD0, mlProbD0bar, 1);
CHECK_AND_FILL_VEC_D0_INDEX(prong0MlProbNonPrompt, mlProbD0, mlProbD0bar, 2);
// TPC PID variable
CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi);
// TOF PID variable
Expand Down Expand Up @@ -175,9 +188,9 @@ class HfMlResponseBplusToD0Pi : public HfMlResponse<TypeOutputScore>
FILL_MAP_BPLUS(cpa),
FILL_MAP_BPLUS(cpaXY),
FILL_MAP_BPLUS(maxNormalisedDeltaIP),
FILL_MAP_BPLUS(prong0MlScoreBkg),
FILL_MAP_BPLUS(prong0MlScorePrompt),
FILL_MAP_BPLUS(prong0MlScoreNonprompt),
FILL_MAP_BPLUS(prong0MlProbBkg),
FILL_MAP_BPLUS(prong0MlProbPrompt),
FILL_MAP_BPLUS(prong0MlProbNonPrompt),
// TPC PID variable
FILL_MAP_BPLUS(tpcNSigmaPi1),
// TOF PID variable
Expand Down
197 changes: 197 additions & 0 deletions PWGHF/Core/HfMlResponseBplusToD0PiReduced.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// \file HfMlResponseBplusToD0PiReduced.h
/// \brief Class to compute the ML response for B± → D0(bar) π± analysis selections in the reduced format
/// \author Antonio Palasciano <[email protected]>, INFN Bari

#ifndef PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_
#define PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_

#include <map>
#include <string>
#include <vector>

#include "PWGHF/Core/HfMlResponse.h"
#include "PWGHF/D2H/Utils/utilsRedDataFormat.h"

// Fill the map of available input features
// the key is the feature's name (std::string)
// the value is the corresponding value in EnumInputFeatures
#define FILL_MAP_BPLUS(FEATURE) \
{ \
#FEATURE, static_cast<uint8_t>(InputFeaturesBplusToD0PiReduced::FEATURE) \
}

// Check if the index of mCachedIndices (index associated to a FEATURE)
// matches the entry in EnumInputFeatures associated to this FEATURE
// if so, the inputFeatures vector is filled with the FEATURE's value
// by calling the corresponding GETTER from OBJECT
#define CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER) \
case static_cast<uint8_t>(InputFeaturesBplusToD0PiReduced::FEATURE): { \
inputFeatures.emplace_back(OBJECT.GETTER()); \
break; \
}

// Check if the index of mCachedIndices (index associated to a FEATURE)
// matches the entry in EnumInputFeatures associated to this FEATURE
// if so, the inputFeatures vector is filled with the FEATURE's value
// by calling the GETTER function taking OBJECT in argument
#define CHECK_AND_FILL_VEC_BPLUS_FUNC(OBJECT, FEATURE, GETTER) \
case static_cast<uint8_t>(InputFeaturesBplusToD0PiReduced::FEATURE): { \
inputFeatures.emplace_back(GETTER(OBJECT)); \
break; \
}

// Specific case of CHECK_AND_FILL_VEC_BPLUS_FULL(OBJECT, FEATURE, GETTER)
// where OBJECT is named candidate and FEATURE = GETTER
#define CHECK_AND_FILL_VEC_BPLUS(GETTER) \
case static_cast<uint8_t>(InputFeaturesBplusToD0PiReduced::GETTER): { \
inputFeatures.emplace_back(candidate.GETTER()); \
break; \
}

namespace o2::analysis
{

enum class InputFeaturesBplusToD0PiReduced : uint8_t {
ptProng0 = 0,
ptProng1,
impactParameter0,
impactParameter1,
impactParameterProduct,
chi2PCA,
decayLength,
decayLengthXY,
decayLengthNormalised,
decayLengthXYNormalised,
cpa,
cpaXY,
maxNormalisedDeltaIP,
prong0MlScoreBkg,
prong0MlScorePrompt,
prong0MlScoreNonprompt,
tpcNSigmaPi1,
tofNSigmaPi1,
tpcTofNSigmaPi1
};

template <typename TypeOutputScore = float>
class HfMlResponseBplusToD0PiReduced : public HfMlResponse<TypeOutputScore>
{
public:
/// Default constructor
HfMlResponseBplusToD0PiReduced() = default;
/// Default destructor
virtual ~HfMlResponseBplusToD0PiReduced() = default;

/// Method to get the input features vector needed for ML inference
/// \param candidate is the B+ candidate
/// \param prong1 is the candidate's prong1
/// \return inputFeatures vector
template <bool withDmesMl, typename T1, typename T2>
std::vector<float> getInputFeatures(T1 const& candidate,
T2 const& prong1)
{
std::vector<float> inputFeatures;

for (const auto& idx : MlResponse<TypeOutputScore>::mCachedIndices) {
if constexpr (withDmesMl) {
switch (idx) {
CHECK_AND_FILL_VEC_BPLUS(ptProng0);
CHECK_AND_FILL_VEC_BPLUS(ptProng1);
CHECK_AND_FILL_VEC_BPLUS(impactParameter0);
CHECK_AND_FILL_VEC_BPLUS(impactParameter1);
CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct);
CHECK_AND_FILL_VEC_BPLUS(chi2PCA);
CHECK_AND_FILL_VEC_BPLUS(decayLength);
CHECK_AND_FILL_VEC_BPLUS(decayLengthXY);
CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised);
CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised);
CHECK_AND_FILL_VEC_BPLUS(cpa);
CHECK_AND_FILL_VEC_BPLUS(cpaXY);
CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreBkg);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScorePrompt);
CHECK_AND_FILL_VEC_BPLUS(prong0MlScoreNonprompt);
// TPC PID variable
CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi);
// TOF PID variable
CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi);
// Combined PID variables
CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1);
}
} else {
switch (idx) {
CHECK_AND_FILL_VEC_BPLUS(ptProng0);
CHECK_AND_FILL_VEC_BPLUS(ptProng1);
CHECK_AND_FILL_VEC_BPLUS(impactParameter0);
CHECK_AND_FILL_VEC_BPLUS(impactParameter1);
CHECK_AND_FILL_VEC_BPLUS(impactParameterProduct);
CHECK_AND_FILL_VEC_BPLUS(chi2PCA);
CHECK_AND_FILL_VEC_BPLUS(decayLength);
CHECK_AND_FILL_VEC_BPLUS(decayLengthXY);
CHECK_AND_FILL_VEC_BPLUS(decayLengthNormalised);
CHECK_AND_FILL_VEC_BPLUS(decayLengthXYNormalised);
CHECK_AND_FILL_VEC_BPLUS(cpa);
CHECK_AND_FILL_VEC_BPLUS(cpaXY);
CHECK_AND_FILL_VEC_BPLUS(maxNormalisedDeltaIP);
// TPC PID variable
CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tpcNSigmaPi1, tpcNSigmaPi);
// TOF PID variable
CHECK_AND_FILL_VEC_BPLUS_FULL(prong1, tofNSigmaPi1, tofNSigmaPi);
// Combined PID variables
CHECK_AND_FILL_VEC_BPLUS_FUNC(prong1, tpcTofNSigmaPi1, o2::pid_tpc_tof_utils::getTpcTofNSigmaPi1);
}
}
}

return inputFeatures;
}

protected:
/// Method to fill the map of available input features
void setAvailableInputFeatures()
{
MlResponse<TypeOutputScore>::mAvailableInputFeatures = {
FILL_MAP_BPLUS(ptProng0),
FILL_MAP_BPLUS(ptProng1),
FILL_MAP_BPLUS(impactParameter0),
FILL_MAP_BPLUS(impactParameter1),
FILL_MAP_BPLUS(impactParameterProduct),
FILL_MAP_BPLUS(chi2PCA),
FILL_MAP_BPLUS(decayLength),
FILL_MAP_BPLUS(decayLengthXY),
FILL_MAP_BPLUS(decayLengthNormalised),
FILL_MAP_BPLUS(decayLengthXYNormalised),
FILL_MAP_BPLUS(cpa),
FILL_MAP_BPLUS(cpaXY),
FILL_MAP_BPLUS(maxNormalisedDeltaIP),
FILL_MAP_BPLUS(prong0MlScoreBkg),
FILL_MAP_BPLUS(prong0MlScorePrompt),
FILL_MAP_BPLUS(prong0MlScoreNonprompt),
// TPC PID variable
FILL_MAP_BPLUS(tpcNSigmaPi1),
// TOF PID variable
FILL_MAP_BPLUS(tofNSigmaPi1),
// Combined PID variable
FILL_MAP_BPLUS(tpcTofNSigmaPi1)};
}
};

} // namespace o2::analysis

#undef FILL_MAP_BPLUS
#undef CHECK_AND_FILL_VEC_BPLUS_FULL
#undef CHECK_AND_FILL_VEC_BPLUS_FUNC
#undef CHECK_AND_FILL_VEC_BPLUS

#endif // PWGHF_CORE_HFMLRESPONSEBPLUSTOD0PIREDUCED_H_
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ struct HfCandidateSelectorB0ToDPiReduced {
}

if constexpr (withDmesMl) { // we include it in the topological selections
if (!hfHelper.selectionDmesMlScoresForB(hfCandB0, cutsDmesMl, binsPtDmesMl)) {
if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandB0, cutsDmesMl, binsPtDmesMl)) {
hfSelB0ToDPiCandidate(statusB0ToDPi);
if (applyB0Ml) {
hfMlB0ToDPiCandidate(outputMlNotPreselected);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.

Check warning on line 1 in PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx

View workflow job for this annotation

GitHub Actions / O2 linter

[pwghf/struct-member-order]

Declare struct members in the conventional order. See the PWGHF coding guidelines.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
Expand All @@ -23,7 +23,7 @@
#include "Common/Core/TrackSelectorPID.h"

#include "PWGHF/Core/HfHelper.h"
#include "PWGHF/Core/HfMlResponseBplusToD0Pi.h"
#include "PWGHF/Core/HfMlResponseBplusToD0PiReduced.h"
#include "PWGHF/Core/SelectorCuts.h"
#include "PWGHF/DataModel/CandidateReconstructionTables.h"
#include "PWGHF/DataModel/CandidateSelectionTables.h"
Expand Down Expand Up @@ -78,7 +78,7 @@
int mySelectionFlagD0 = -1;
int mySelectionFlagD0bar = -1;

o2::analysis::HfMlResponseBplusToD0Pi<float> hfMlResponse;
o2::analysis::HfMlResponseBplusToD0PiReduced<float> hfMlResponse;
float outputMlNotPreselected = -1.;
std::vector<float> outputMl = {};
o2::ccdb::CcdbApi ccdbApi;
Expand All @@ -86,7 +86,7 @@
HfHelper hfHelper;
TrackSelectorPi selectorPion;

HistogramRegistry registry{"registry"};

Check warning on line 89 in PWGHF/D2H/TableProducer/candidateSelectorBplusToD0PiReduced.cxx

View workflow job for this annotation

GitHub Actions / O2 linter

[pwghf/struct-member-order]

HfCandidateSelectorBplusToD0PiReduced: HistogramRegistry appears too early (before end of using).

using TracksPion = soa::Join<HfRedTracks, HfRedTracksPid>;

Expand Down Expand Up @@ -174,7 +174,7 @@
}

if constexpr (withDmesMl) { // we include it in the topological selections
if (!hfHelper.selectionDmesMlScoresForB(hfCandBp, cutsDmesMl, binsPtDmesMl)) {
if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandBp, cutsDmesMl, binsPtDmesMl)) {
hfSelBplusToD0PiCandidate(statusBplus);
if (applyBplusMl) {
hfMlBplusToD0PiCandidate(outputMlNotPreselected);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ struct HfCandidateSelectorBsToDsPiReduced {
}

if constexpr (withDmesMl) { // we include it in the topological selections
if (!hfHelper.selectionDmesMlScoresForB(hfCandBs, cutsDmesMl, binsPtDmesMl)) {
if (!hfHelper.selectionDmesMlScoresForBReduced(hfCandBs, cutsDmesMl, binsPtDmesMl)) {
hfSelBsToDsPiCandidate(statusBsToDsPi);
if (applyBsMl) {
hfMlBsToDsPiCandidate(outputMl);
Expand Down
Loading
Loading