Skip to content

Commit 152abf8

Browse files
committed
Add ML inference and BDT scores in output table
1 parent 0c9de0b commit 152abf8

File tree

3 files changed

+149
-26
lines changed

3 files changed

+149
-26
lines changed

DPG/Tasks/AOTTrack/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,6 @@ o2physics_add_dpl_workflow(tag-and-probe-dmesons
8787

8888
o2physics_add_dpl_workflow(derived-data-creator-d0-calibration
8989
SOURCES derivedDataCreatorD0Calibration.cxx
90-
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCore O2::DCAFitter
90+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCore O2::DCAFitter O2Physics::MLCore
9191
COMPONENT_NAME Analysis)
9292

DPG/Tasks/AOTTrack/D0CalibTables.h

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ namespace o2
6161
return static_cast<uint8_t>(std::clamp(roundValue, 0, 255));
6262
}
6363

64+
/// It compresses a value to a uint16_t with a given precision
65+
///\param origValue is the original values
66+
///\param precision is the desired precision
67+
///\return The value compressed to a uint16_t
68+
template<typename T>
69+
uint16_t getCompressedUint16(T origValue, double precision)
70+
{
71+
int roundValue = static_cast<int>(std::round(origValue / precision));
72+
return static_cast<uint16_t>(std::clamp(roundValue, 0, 65535));
73+
}
74+
6475
/// It uses a sinh-based scaling function, which provides a compromise between fixed-step and relative quantization.
6576
// This approach reflects typical resolution formulas and is well-suited for detector calibration data.
6677
///\param origValue is the original value
@@ -108,7 +119,7 @@ namespace o2
108119
template<typename T>
109120
int8_t getCompressedCosPa(T cosPa)
110121
{
111-
return getCompressedUint8(cosPa - 0.25, 0.001); // in the range from 0.75 to 1
122+
return getCompressedUint8(cosPa - 0.75, 0.001); // in the range from 0.75 to 1
112123
}
113124

114125
/// It compresses the chi2
@@ -131,6 +142,24 @@ namespace o2
131142
return compressedNumSigma;
132143
}
133144

145+
/// It compresses the bdt score (1./65535 precision)
146+
///\param bdtScore is the bdt score
147+
///\return The bdt score compressed to a uint16_t with 1./65535 precision
148+
template<typename T>
149+
uint16_t getCompressedBdtScoreBkg(T bdtScore)
150+
{
151+
return getCompressedUint16(bdtScore, 1./65535);
152+
}
153+
154+
/// It compresses the bdt score (1./255 precision)
155+
///\param bdtScore is the bdt score
156+
///\return The bdt score compressed to a uint8_t with 1./255 precision
157+
template<typename T>
158+
uint8_t getCompressedBdtScoreSgn(T bdtScore)
159+
{
160+
return getCompressedUint8(bdtScore, 1./255);
161+
}
162+
134163
/// It compresses the number of sigma (0.1 sigma precision)
135164
///\param occupancy is the occupancy value
136165
///\return The number of sigma compressed to a int8_t with 0.1 precision
@@ -174,11 +203,11 @@ namespace o2
174203
0,
175204
1.0,
176205
2.0,
206+
3.0,
177207
4.0,
178208
6.0,
179209
8.0,
180210
12.0,
181-
16.0,
182211
24.0,
183212
50.0,
184213
1000.0};
@@ -187,12 +216,12 @@ namespace o2
187216
// default values for the cuts
188217
constexpr float CutsCand[NBinsPtCand][NCutVarsCand] = {{0.400, 0., 10., 10., 0.97, 0.97, 0, 2, 0.01, 0.01}, /* 0 < pT < 1 */
189218
{0.400, 0., 10., 10., 0.97, 0.97, 0, 2, 0.01, 0.01}, /* 1 < pT < 2 */
190-
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 2 < pT < 4 */
219+
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 2 < pT < 3 */
220+
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 3 < pT < 4 */
191221
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 4 < pT < 6 */
192222
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 6 < pT < 8 */
193223
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 8 < pT < 12 */
194-
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 12 < pT < 16 */
195-
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 16 < pT < 24 */
224+
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 12 < pT < 24 */
196225
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}, /* 24 < pT < 50 */
197226
{0.400, 0., 10., 10., 0.95, 0.95, 0, 2, 0.01, 0.01}}; /* 50 < pT < 1000 */
198227

@@ -211,6 +240,51 @@ namespace o2
211240

212241
// column labels
213242
static const std::vector<std::string> labelsCutVarCand = {"delta inv. mass", "max d0d0", "max pointing angle", "max pointing angle XY", "min cos pointing angle", "min cos pointing angle xy", "min norm decay length", "min norm decay length XY", "min decay length", "min decay length XY"};
243+
244+
static constexpr int NBinsPtMl = 10;
245+
// default values for the pT bin edges (can be used to configure histogram axis)
246+
// offset by 1 from the bin numbers in cuts array
247+
constexpr double BinsPtMl[NBinsPtMl + 1] = {
248+
0,
249+
1.0,
250+
2.0,
251+
3.0,
252+
4.0,
253+
6.0,
254+
8.0,
255+
12.0,
256+
24.0,
257+
50.0,
258+
1000.0};
259+
auto vecBinsPtMl = std::vector<double>{BinsPtMl, BinsPtMl + NBinsPtMl + 1};
260+
261+
// default values for the cuts
262+
constexpr double CutsMl[NBinsPtMl][3] = {{1., 0., 0.}, /* 0 < pT < 1 */
263+
{1., 0., 0.}, /* 1 < pT < 2 */
264+
{1., 0., 0.}, /* 2 < pT < 3 */
265+
{1., 0., 0.}, /* 3 < pT < 4 */
266+
{1., 0., 0.}, /* 4 < pT < 6 */
267+
{1., 0., 0.}, /* 6 < pT < 8 */
268+
{1., 0., 0.}, /* 8 < pT < 12 */
269+
{1., 0., 0.}, /* 12 < pT < 24 */
270+
{1., 0., 0.}, /* 24 < pT < 50 */
271+
{1., 0., 0.}}; /* 50 < pT < 1000 */
272+
273+
// row labels
274+
static const std::vector<std::string> labelsPtMl = {
275+
"pT bin 0",
276+
"pT bin 1",
277+
"pT bin 2",
278+
"pT bin 3",
279+
"pT bin 4",
280+
"pT bin 5",
281+
"pT bin 6",
282+
"pT bin 7",
283+
"pT bin 8",
284+
"pT bin 9"};
285+
286+
// column labels
287+
static const std::vector<std::string> labelsCutMl = {"max BDT score bkg", "min BDT score prompt", "min BDT score nonprompt"};
214288
} // namespace hf_calib
215289

216290
namespace aod
@@ -330,6 +404,12 @@ namespace o2
330404
DECLARE_SOA_COLUMN(PointingAngle, pointingAngle, uint8_t); //! compressed pointing angle
331405
DECLARE_SOA_COLUMN(PointingAngleXY, pointingAngleXY, uint8_t); //! compressed pointing angle XY
332406
DECLARE_SOA_COLUMN(DecVtxChi2, decVtxChi2, uint8_t); //! compressed decay vertex chi2
407+
DECLARE_SOA_COLUMN(BdtScoreBkgD0, bdtScoreBkgD0, uint16_t); //! compressed BDT score (bkg, D0 mass hypo)
408+
DECLARE_SOA_COLUMN(BdtScorePromptD0, bdtScorePromptD0, uint8_t); //! compressed BDT score (prompt, D0 mass hypo)
409+
DECLARE_SOA_COLUMN(BdtScoreNonpromptD0, bdtScoreNonpromptD0, uint8_t); //! compressed BDT score (non-prompt, D0 mass hypo)
410+
DECLARE_SOA_COLUMN(BdtScoreBkgD0bar, bdtScoreBkgD0bar, uint16_t); //! compressed BDT score (bkg, D0bar mass hypo)
411+
DECLARE_SOA_COLUMN(BdtScorePromptD0bar, bdtScorePromptD0bar, uint8_t); //! compressed BDT score (prompt, D0bar mass hypo)
412+
DECLARE_SOA_COLUMN(BdtScoreNonpromptD0bar, bdtScoreNonpromptD0bar, uint8_t); //! compressed BDT score (non-prompt, D0bar mass hypo)
333413
} // namespace hf_calib
334414

335415
DECLARE_SOA_TABLE(D0CalibCand, "AOD", "D0CALIBCANDS",
@@ -351,7 +431,13 @@ namespace o2
351431
hf_calib::CosPaXY,
352432
hf_calib::PointingAngle,
353433
hf_calib::PointingAngleXY,
354-
hf_calib::DecVtxChi2);
434+
hf_calib::DecVtxChi2,
435+
hf_calib::BdtScoreBkgD0,
436+
hf_calib::BdtScorePromptD0,
437+
hf_calib::BdtScoreNonpromptD0,
438+
hf_calib::BdtScoreBkgD0bar,
439+
hf_calib::BdtScorePromptD0bar,
440+
hf_calib::BdtScoreNonpromptD0bar);
355441
} // namespace aod
356442
} // namespace o2
357443
#endif // D0CALIBTABLES_H_

DPG/Tasks/AOTTrack/derivedDataCreatorD0Calibration.cxx

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,12 @@
1414
///
1515
/// \author Fabrizio Grosa <fabrizio.grosa@cern.ch>, CERN
1616

17-
#include <algorithm>
18-
#include <array>
19-
#include <cmath>
20-
#include <map>
21-
#include <string>
22-
23-
#include <TH1D.h>
24-
#include <TRandom3.h>
25-
26-
#include "CommonConstants/PhysicsConstants.h"
27-
#include "DCAFitter/DCAFitterN.h"
28-
#include "Framework/AnalysisTask.h"
29-
#include "Framework/runDataProcessing.h"
30-
#include "Framework/RunningWorkflowInfo.h"
31-
#include "ReconstructionDataFormats/DCA.h"
32-
3317
#include "D0CalibTables.h"
3418

19+
#include "PWGHF/Utils/utilsAnalysis.h"
20+
#include "PWGHF/Utils/utilsBfieldCCDB.h"
21+
#include "PWGHF/Utils/utilsPid.h"
22+
3523
#include "Common/Core/RecoDecay.h"
3624
#include "Common/Core/TrackSelectorPID.h"
3725
#include "Common/Core/trackUtilities.h"
@@ -42,9 +30,23 @@
4230
#include "Common/DataModel/PIDResponseTPC.h"
4331
#include "Common/DataModel/TrackSelectionTables.h"
4432
#include "CommonDataFormat/InteractionRecord.h"
33+
#include "Tools/ML/MlResponse.h"
4534

46-
#include "PWGHF/Utils/utilsAnalysis.h"
47-
#include "PWGHF/Utils/utilsBfieldCCDB.h"
35+
#include <CommonConstants/PhysicsConstants.h>
36+
#include <DCAFitter/DCAFitterN.h>
37+
#include <Framework/AnalysisTask.h>
38+
#include <Framework/runDataProcessing.h>
39+
#include <Framework/RunningWorkflowInfo.h>
40+
#include <ReconstructionDataFormats/DCA.h>
41+
42+
#include <TH1D.h>
43+
#include <TRandom3.h>
44+
45+
#include <algorithm>
46+
#include <array>
47+
#include <cmath>
48+
#include <map>
49+
#include <string>
4850

4951
using namespace o2;
5052
using namespace o2::analysis;
@@ -86,15 +88,28 @@ struct DerivedDataCreatorD0Calibration {
8688
struct : ConfigurableGroup {
8789
Configurable<bool> apply{"apply", false, "flag to apply downsampling"};
8890
Configurable<std::string> pathCcdbWeights{"pathCcdbWeights", "", "CCDB path containing pT-differential weights"};
91+
std::string prefix = "downsampling";
8992
} cfgDownsampling;
9093

94+
struct : ConfigurableGroup {
95+
Configurable<bool> apply{"apply", false, "flag to apply downsampling"};
96+
Configurable<std::vector<double>> binsPt{"binsPt", std::vector<double>{hf_calib::vecBinsPtMl}, "pT bin limits for ML models inference"};
97+
Configurable<LabeledArray<double>> thresholdMlScores{"thresholdMlScores", {hf_calib::CutsMl[0], hf_calib::NBinsPtMl, 3, hf_calib::labelsPtMl, hf_calib::labelsCutMl}, "Threshold values for Ml output scores of D0 candidates"};
98+
Configurable<bool> loadMlModelsFromCCDB{"loadMlModelsFromCCDB", true, "Flag to enable or disable the loading of ML models from CCDB"};
99+
Configurable<std::vector<std::string>> modelPathsCCDB{"modelPathsCCDB", std::vector<std::string>{"Users/f/fgrosa/D0Calib/BDT/Pt0_1"}, "Paths of models on CCDB"};
100+
Configurable<std::vector<std::string>> onnxFileNames{"onnxFileNames", std::vector<std::string>{"ModelHandler_pT_0_1.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"};
101+
std::string prefix = "ml";
102+
} cfgMl;
103+
91104
using TracksWCovExtraPid = soa::Join<aod::Tracks, aod::TracksCov, aod::TracksExtra, aod::TrackSelection, aod::pidTPCFullPi, aod::pidTOFFullPi, aod::pidTPCFullKa, aod::pidTOFFullKa>;
92105
using CollisionsWEvSel = soa::Join<aod::Collisions, aod::CentFT0Cs, aod::EvSels>;
93106

94107
Preslice<aod::TrackAssoc> trackIndicesPerCollision = aod::track_association::collisionId;
95108

96109
o2::vertexing::DCAFitterN<2> df; // 2-prong vertex fitter
97110
Service<o2::ccdb::BasicCCDBManager> ccdb;
111+
o2::ccdb::CcdbApi ccdbApi;
112+
o2::analysis::MlResponse<float> mlResponse;
98113

99114
TrackSelectorPi selectorPion;
100115
TrackSelectorKa selectorKaon;
@@ -119,6 +134,18 @@ struct DerivedDataCreatorD0Calibration {
119134
histDownSampl.setObject(reinterpret_cast<TH1D*>(ccdb->getSpecific<TH1D>(cfgDownsampling.pathCcdbWeights)));
120135
}
121136

137+
if (cfgMl.apply) {
138+
std::vector<int> cutDir = {o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller};
139+
mlResponse.configure(cfgMl.binsPt, cfgMl.thresholdMlScores, cutDir, 3);
140+
if (cfgMl.loadMlModelsFromCCDB) {
141+
ccdbApi.init("http://alice-ccdb.cern.ch");
142+
mlResponse.setModelPathsCCDB(cfgMl.onnxFileNames, ccdbApi, cfgMl.modelPathsCCDB, -1);
143+
} else {
144+
mlResponse.setModelPathsLocal(cfgMl.onnxFileNames);
145+
}
146+
mlResponse.init();
147+
}
148+
122149
df.setPropagateToPCA(true);
123150
df.setMaxR(200.f);
124151
df.setMaxDZIni(4.f);
@@ -374,16 +401,26 @@ struct DerivedDataCreatorD0Calibration {
374401
}
375402

376403
float invMassD0{0.f}, invMassD0bar{0.f};
404+
std::vector<float> bdtScoresD0{0.f, 1.f, 1.f}, bdtScoresD0bar{0.f, 1.f, 1.f}; // always selected a priori
377405
if (massHypo == D0MassHypo::D0 || massHypo == D0MassHypo::D0AndD0Bar) {
378406
invMassD0 = RecoDecay::m(std::array{pVecPos, pVecNeg}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus});
379407
if (std::abs(invMassD0 - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinD0, "delta inv. mass")) {
380408
massHypo -= D0MassHypo::D0;
409+
bdtScoresD0 = std::vector<float>{1.f, 0.f, 0.f};
410+
} else {
411+
// apply BDT models
412+
std::vector<float> featuresCandD0 = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma<false>(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi())};
413+
mlResponse.isSelectedMl(featuresCandD0, ptD0, bdtScoresD0);
381414
}
382415
}
383416
if (massHypo >= D0MassHypo::D0Bar) {
384417
invMassD0bar = RecoDecay::m(std::array{pVecNeg, pVecPos}, std::array{o2::constants::physics::MassPiPlus, o2::constants::physics::MassKPlus});
385418
if (std::abs(invMassD0bar - o2::constants::physics::MassD0) > cfgCandCuts.topologicalCuts->get(ptBinD0, "delta inv. mass")) {
386419
massHypo -= D0MassHypo::D0Bar;
420+
bdtScoresD0bar = std::vector<float>{1.f, 0.f, 0.f};
421+
} else {
422+
std::vector<float> featuresCandD0bar = {dcaPos.getY(), dcaNeg.getY(), chi2PCA, cosPaD0, cosPaXYD0, decLenXYD0, decLenD0, dcaPos.getY() * dcaNeg.getY(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackNeg.tpcNSigmaPi(), trackNeg.tofNSigmaPi()), aod::pid_tpc_tof_utils::combineNSigma<false>(trackPos.tpcNSigmaKa(), trackPos.tofNSigmaKa()), trackNeg.tpcNSigmaPi(), trackNeg.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackNeg.tpcNSigmaKa(), trackNeg.tofNSigmaKa()), trackPos.tpcNSigmaPi(), trackPos.tpcNSigmaKa(), aod::pid_tpc_tof_utils::combineNSigma<false>(trackPos.tpcNSigmaPi(), trackPos.tofNSigmaPi())};
423+
mlResponse.isSelectedMl(featuresCandD0bar, ptD0, bdtScoresD0bar);
387424
}
388425
}
389426
if (massHypo == 0) {
@@ -426,7 +463,7 @@ struct DerivedDataCreatorD0Calibration {
426463
// candidate
427464
candTable(selectedCollisions[collision.globalIndex()], selectedTracks[trackPos.globalIndex()], selectedTracks[trackNeg.globalIndex()], massHypo, ptD0, etaD0, phiD0, invMassD0, invMassD0bar,
428465
getCompressedDecayLength(decLenD0), getCompressedDecayLength(decLenXYD0), getCompressedNormDecayLength(decLenD0/errorDecayLengthD0), getCompressedNormDecayLength(decLenXYD0/errorDecayLengthXYD0),
429-
getCompressedCosPa(cosPaD0), getCompressedCosPa(cosPaXYD0), getCompressedPointingAngle(paD0), getCompressedPointingAngle(paXYD0), getCompressedChi2(chi2PCA));
466+
getCompressedCosPa(cosPaD0), getCompressedCosPa(cosPaXYD0), getCompressedPointingAngle(paD0), getCompressedPointingAngle(paXYD0), getCompressedChi2(chi2PCA), getCompressedBdtScoreBkg(bdtScoresD0[0]), getCompressedBdtScoreSgn(bdtScoresD0[1]), getCompressedBdtScoreSgn(bdtScoresD0[2]), getCompressedBdtScoreBkg(bdtScoresD0bar[0]), getCompressedBdtScoreSgn(bdtScoresD0bar[1]), getCompressedBdtScoreSgn(bdtScoresD0bar[2]));
430467
} // end loop over negative tracks
431468
} // end loop over positive tracks
432469
} // end loop over collisions tracks

0 commit comments

Comments
 (0)