ATLAS Offline Software
Loading...
Searching...
No Matches
NewLikelihoodTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8
9#include <cmath>
10#include <string>
11#include <utility>
12#include <vector>
13
14#include "TH1.h"
15#include "TH2.h"
16#include "TH3.h"
17
18namespace Analysis {
19
20 NewLikelihoodTool::NewLikelihoodTool(const std::string& t, const std::string& n, const IInterface* p) :
21 AthAlgTool(t,n,p),
22 m_taggerName("undefined"),
24 m_normalizedProb(true),
25 m_interpolate(false),
29
30 declareInterface<NewLikelihoodTool>(this);
31 declareProperty("taggerName", m_taggerName);
32 declareProperty("hypotheses", m_hypotheses);
33 declareProperty("normalizedProb", m_normalizedProb);
34 declareProperty("interpolate",m_interpolate);
35 declareProperty("smoothNTimes",m_smoothNTimes);
36 declareProperty("vetoSmoothingOf", m_vetoSmoothingOf);
37 m_hypotheses.push_back("B");
38 m_hypotheses.push_back("U");
39 m_hypotheses.push_back("C");
40 m_vetoSmoothingOf.push_back("/N2T");
41 m_vetoSmoothingOf.push_back("/N2TEffSV2");
42 m_vetoSmoothingOf.push_back("/Sip3D");
43 }
44
46 ATH_CHECK(m_readKey.initialize());
47 return StatusCode::SUCCESS;
48 }
49
50 void NewLikelihoodTool::defineHypotheses(const std::vector<std::string>& hyp) {
51 m_hypotheses = hyp;
52 }
53
55 msg(MSG::INFO) << "#BTAG# - hypotheses : ";
56 for(const auto& hypo : m_hypotheses) msg(MSG::INFO) << hypo << ", ";
57 msg(MSG::INFO) << endmsg;
58 msg(MSG::INFO) << "#BTAG# - histograms : " << endmsg;
59 for(const auto& histo : m_histograms) msg(MSG::INFO) << histo << endmsg;
60 }
61
62 std::vector<std::string> NewLikelihoodTool::gradeList(const std::string& histoName) const {
63 ATH_MSG_VERBOSE("#BTAG# gradeList() called for " << histoName);
64 const std::string delimSlash("/");
65 // first count slashes:
66 unsigned int nSlash = 0;
67 std::string::size_type slashPos;
68 for( unsigned int i = 0;
69 (slashPos = histoName.find(delimSlash, i)) != std::string::npos;
70 i = slashPos + 1) nSlash++;
71 // extract string before the 2nd / sign: this is for the grades, the rest is the histogram name
72 slashPos = histoName.find_first_of(delimSlash);
73 std::string newName = histoName.substr(slashPos+1);
74 slashPos = newName.find_first_of(delimSlash);
75 std::string grades = newName.substr(0,slashPos);
76 std::string hhname = newName.substr(slashPos+1);
77 if(nSlash<2) grades = "";
78 ATH_MSG_VERBOSE("#BTAG# -> grades: " << grades);
79 ATH_MSG_VERBOSE("#BTAG# -> hhname: " << hhname);
80 // now decode the grades:
81 std::vector<std::string> gradeList;
82 if(grades!="") {
83 const std::string delimUds("_");
84 std::string::size_type sPos, sEnd, sLen;
85 sPos = grades.find_first_not_of(delimUds);
86 while ( sPos != std::string::npos ) {
87 sEnd = grades.find_first_of(delimUds, sPos);
88 if(sEnd==std::string::npos) sEnd = grades.length();
89 sLen = sEnd - sPos;
90 std::string word = grades.substr(sPos,sLen);
91 ATH_MSG_DEBUG("#BTAG# --> grade = " << word);
92 gradeList.push_back(std::move(word));
93 sPos = grades.find_first_not_of(delimUds, sEnd);
94 }
95 }
96 // add the histogram name at the end of the list:
97 gradeList.push_back(std::move(hhname));
98 return gradeList;
99 }
100
101 TH1* NewLikelihoodTool::prepareHistogram(const std::string& hypo, const std::string& hname) const {
102 TH1* histoSum = nullptr;
103
105 std::string channelName = readCdo->channelName(hname);
106 std::string histoName = readCdo->histoName(hname);
107 std::string actualName = hypo + "/" + histoName;
108 std::string longName = channelName + "#" + actualName;
109 ATH_MSG_VERBOSE("#BTAG# preparing histogram " << longName);
110 ATH_MSG_VERBOSE("#BTAG# -> channel is " << channelName);
111 ATH_MSG_VERBOSE("#BTAG# -> histo is " << histoName);
112 // now decode the grades:
113 std::vector<std::string> gradeList = this->gradeList(histoName);
114 // - case with no grade:
115 if(1==gradeList.size()) {
116 ATH_MSG_DEBUG("#BTAG# Histo "<<actualName<<" has no grade: direct retrieval");
117 histoSum = readCdo->retrieveHistogram(m_taggerName,
118 channelName,
119 actualName);
120 }
121 // - case with 1 grade:
122 if(2==gradeList.size()) {
123 ATH_MSG_DEBUG("#BTAG# Histo "<<actualName<<" has only one grade: direct retrieval");
124 histoSum = readCdo->retrieveHistogram(m_taggerName,
125 channelName,
126 actualName);
127 //Part not fully migrated
128 //smoothAndNormalizeHistogram should not be called here but in condition algorithm
129 ATH_MSG_VERBOSE("#BTAG# Smoothing histogram " << longName << " ...");
130 this->smoothAndNormalizeHistogram(histoSum, longName);
131 }
132 // - for many grades, get individual histos and sum them up:
133 if(gradeList.size()>2) {
134 TH1* histo = nullptr;
135 ATH_MSG_DEBUG("Histo " << actualName << " has " << (gradeList.size()-1) << " grades:");
136 for(unsigned int i=0;i<(gradeList.size()-1);i++) {
137 actualName = hypo+"/"+gradeList[i]+gradeList[gradeList.size()-1];
138 ATH_MSG_VERBOSE("#BTAG# -> retrieving histo for grade " << i << " " << gradeList[i] << ": ");
139 histo = readCdo->retrieveHistogram(m_taggerName,
140 channelName,
141 actualName);
142 if(histo) ATH_MSG_VERBOSE("#BTAG# histo " << actualName
143 << " has " << histo->GetEntries() << " entries.");
144 if(0==i) {
145 histoSum = histo;
146 } else {
147 if(histo&&histoSum) histoSum->Add(histo,1.);
148 }
149 }
150 //Part not fully migrated
151 //smoothAndNormalizeHistogram should not be called here but in condition algorithm
152 ATH_MSG_VERBOSE("#BTAG# Smoothing histogram " << longName << " ...");
153 this->smoothAndNormalizeHistogram(histoSum, longName);
154 }
155 return histoSum;
156 }
157
158 void NewLikelihoodTool::smoothAndNormalizeHistogram(TH1* h, const std::string& hname = "") const {
159 if(h) {
160 double norm = h->Integral();
161 if(norm) {
162 // check if smoothing of histogram is not vetoed:
163 bool veto = false;
164 for(const auto& v : m_vetoSmoothingOf) {
165 if(hname.find(v)!=std::string::npos) {
166 veto = true;
167 ATH_MSG_VERBOSE("#BTAG# Smoothing of " << hname << " is vetoed !");
168 break;
169 }
170 }
171 if(1==h->GetDimension() && m_smoothNTimes) {
172 if(!veto) {
173 if(norm>10000)h->Smooth(m_smoothNTimes);
174 else h->Smooth((int)(m_smoothNTimes*100./sqrt(norm)));
175 }
176 }
177 if(2==h->GetDimension()) {
178 int m2d=3;
179 //if(hname.find("#B/")==std::string::npos) m2d=5; //VK oversmoothing!!!
180 if(!veto) {
181 TH2 * dc_tmp = dynamic_cast<TH2*>(h);
182 if (dc_tmp) {
183 HistoHelperRoot::smoothASH2D(dc_tmp, m2d, m2d, msgLvl(MSG::DEBUG));
184 }
185 }
186 }
187 if(3==h->GetDimension()) {
188 int m3d1=3;
189 int m3d3=2;
190 if(!veto) {
191 TH3 * dc_tmp = dynamic_cast<TH3*>(h);
192 if (dc_tmp) {
193 int Nx=dc_tmp->GetNbinsX();
194 int Ny=dc_tmp->GetNbinsY();
195 int Nz=dc_tmp->GetNbinsZ();
196 if(Nz == 7) //==========Old SV2
197 HistoHelperRoot::smoothASH3D(dc_tmp, m3d1, m3d1, m3d3, msgLvl(MSG::DEBUG));
198 else if(Nz == 6){ //==========New SV2Pt
199 double total=dc_tmp->Integral(1,Nx,1,Ny,1,Nz,"");
200 for(int iz=1; iz<=Nz; iz++){
201 double content=dc_tmp->Integral(1,Nx,1,Ny,iz,iz,""); if(content==0.)content=Nz;
202 double dnorm=total/content/Nz;
203 for(int ix=1; ix<=Nx; ix++){
204 for(int iy=1; iy<=Ny; iy++){
205 double cbin=dc_tmp->GetBinContent(ix,iy,iz)*dnorm; cbin= cbin>0. ? cbin : 0.1; //Protection against empty bins
206 dc_tmp->SetBinContent(ix,iy,iz, cbin);
207 }
208 }
209 }
210 HistoHelperRoot::smoothASH3D(dc_tmp, m3d1, m3d1, m3d3, msgLvl(MSG::DEBUG));
211 }
212 }
213 }
214 }
215 // normalize:
216 norm = h->Integral();
217 h->Scale(1./norm);
218 } else {
219 ATH_MSG_DEBUG("#BTAG# Histo "<<h<<" is empty!");
220 }
221 }
222 }
223
224 std::vector<double> NewLikelihoodTool::calculateLikelihood(const std::vector<Slice>& lhVariableValues) const
225 {
226 ATH_MSG_VERBOSE("#BTAG# calculate called for " << m_hypotheses.size() << " hypotheses.");
227 std::vector<double> probDensityPerEventClassAllVariables;
228 probDensityPerEventClassAllVariables.resize(m_hypotheses.size());
229 for (unsigned int i = 0 ; i < m_hypotheses.size(); ++i) {
230 probDensityPerEventClassAllVariables[i]=1.;
231 }
232 ATH_MSG_VERBOSE("#BTAG# -- lhVarVal size= " << lhVariableValues.size());
233 // loop on Tracks in the Jet (IP) / Vertices in the Jet (SV)
234 for (const auto& value : lhVariableValues) {
235 ATH_MSG_VERBOSE( "#BTAG# -- element " << value.name );
236 int ncompo = value.composites.size();
237 ATH_MSG_VERBOSE( "#BTAG# -- element " << value.name
238 << " has " << ncompo << " composites." );
239 // loop on variables that make up the Tag, e.g.
240 // one 1D for IP2D, one 2D for IP3D, one 1D and one 2D for SV1, one 3D for SV2
241 for (const auto& compo : value.composites) {
242 double sum(0.);
243 std::vector<double> tmpVector;
244 std::string histName = compo.name;
245 int idim = compo.atoms.size();
246 ATH_MSG_VERBOSE( "#BTAG# -- composite histo= "
247 << histName << " dim= " << idim );
248 for (const auto& hypo : m_hypotheses) {
249 TH1* tmpHisto = this->prepareHistogram(hypo,histName);
250 if(tmpHisto) {
251 if(1==idim) {
252 double valuex = compo.atoms[0].value;
253 int binx = (tmpHisto->GetXaxis())->FindBin(valuex);
254 if(valuex >= tmpHisto->GetXaxis()->GetXmax()) binx = tmpHisto->GetXaxis()->GetNbins();
255 if(valuex <= tmpHisto->GetXaxis()->GetXmin()) binx = 1;
256 double tmp = tmpHisto->GetBinContent(binx);
257 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << "#BTAG# For hypothesis= " << hypo
258 << " (1D) actual value= " << valuex
259 << " --> bin= " << binx << " f = " << tmp;
260 if(m_interpolate) {
261 TH1* dc_tmp = dynamic_cast<TH1*>(tmpHisto);
262 if (dc_tmp) {
263 tmp = HistoHelperRoot::Interpol1d(valuex, dc_tmp);
264 if( msgLvl(MSG::VERBOSE) )msg(MSG::VERBOSE) << " interpolated f = " << tmp;
265 }
266 }
267 if(m_normalizedProb) { // pdf are already normalized
268 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " (normalized)" << endmsg;
269 } else {
270 double binw = tmpHisto->GetBinWidth(binx);
271 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " binw= " << binw;
272 if(0==binw) {
273 msg(MSG::ERROR) << "bin width is 0" << endmsg;
274 } else {
275 tmp /= binw;
276 }
277 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " normalized f = " << tmp << endmsg;
278 }
279 tmpVector.push_back(tmp);
280 sum += tmp;
281 }
282 if(2==idim) {
283 double valuex = compo.atoms[0].value;
284 double valuey = compo.atoms[1].value;
285 int binx = (tmpHisto->GetXaxis())->FindBin(valuex);
286 int biny = (tmpHisto->GetYaxis())->FindBin(valuey);
287 if(valuex >= tmpHisto->GetXaxis()->GetXmax()) binx = tmpHisto->GetXaxis()->GetNbins();
288 if(valuex <= tmpHisto->GetXaxis()->GetXmin()) binx = 1;
289 if(valuey >= tmpHisto->GetYaxis()->GetXmax()) biny = tmpHisto->GetYaxis()->GetNbins();
290 if(valuey <= tmpHisto->GetYaxis()->GetXmin()) biny = 1;
291 double tmp = tmpHisto->GetBinContent(binx, biny);
292 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << "#BTAG# For hypothesis= " << hypo
293 << " (2D) actual value= " << valuex << " " << valuey
294 << " --> bin= " << binx << " " << biny << " f = " << tmp;
295 if(m_interpolate) {
296 TH2* dc_tmp = dynamic_cast<TH2*>(tmpHisto);
297 if (dc_tmp) {
298 tmp = HistoHelperRoot::Interpol2d(valuex, valuey, dc_tmp);
299 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " interpolated f = " << tmp;
300 }
301 }
302 if(m_normalizedProb) { // pdf are already normalized
303 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " (normalized)" << endmsg;
304 } else {
305 double binw = tmpHisto->GetXaxis()->GetBinWidth(binx)
306 * tmpHisto->GetYaxis()->GetBinWidth(biny);
307 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " binw= " << binw;
308 if(0==binw) {
309 msg(MSG::ERROR) << "bin width is 0" << endmsg;
310 } else {
311 tmp /= binw;
312 }
313 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " normalized f = " << tmp << endmsg;
314 }
315 tmpVector.push_back(tmp);
316 sum += tmp;
317 }
318 if(3==idim) {
319 double valuex = compo.atoms[0].value;
320 double valuey = compo.atoms[1].value;
321 double valuez = compo.atoms[2].value;
322 int binx = (tmpHisto->GetXaxis())->FindBin(valuex);
323 int biny = (tmpHisto->GetYaxis())->FindBin(valuey);
324 int binz = (tmpHisto->GetZaxis())->FindBin(valuez);
325 if(valuex >= tmpHisto->GetXaxis()->GetXmax()) binx = tmpHisto->GetXaxis()->GetNbins();
326 if(valuex <= tmpHisto->GetXaxis()->GetXmin()) binx = 1;
327 if(valuey >= tmpHisto->GetYaxis()->GetXmax()) biny = tmpHisto->GetYaxis()->GetNbins();
328 if(valuey <= tmpHisto->GetYaxis()->GetXmin()) biny = 1;
329 if(valuez >= tmpHisto->GetZaxis()->GetXmax()) binz = tmpHisto->GetZaxis()->GetNbins();
330 if(valuez <= tmpHisto->GetZaxis()->GetXmin()) binz = 1;
331 double tmp = tmpHisto->GetBinContent(binx, biny, binz);
332 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << "#BTAG# For hypothesis= " << hypo
333 << " (3D) actual value= " << valuex
334 << " " << valuey << " " << valuez
335 << " --> bin= " << binx << " " << biny
336 << " " << binz << " f = " << tmp;
337 if(m_interpolate) {
338 TH3* dc_tmp = dynamic_cast<TH3*>(tmpHisto);
339 if (dc_tmp) {
340 tmp = HistoHelperRoot::Interpol3d(valuex, valuey, valuez, dc_tmp);
341 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " interpolated f = " << tmp;
342 }
343 }
344 if(m_normalizedProb) { // pdf are already normalized
345 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " (normalized)" << endmsg;
346 } else {
347 double binw = tmpHisto->GetXaxis()->GetBinWidth(binx)
348 * tmpHisto->GetYaxis()->GetBinWidth(biny)
349 * tmpHisto->GetZaxis()->GetBinWidth(binz);
350 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " binw= " << binw;
351 if(0==binw) {
352 msg(MSG::ERROR) << "bin width is 0" << endmsg;
353 } else {
354 tmp /= binw;
355 }
356 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << " normalized f = " << tmp << endmsg;
357 }
358 tmpVector.push_back(tmp);
359 sum += tmp;
360 }
361 if(idim>3 || idim<1 ) msg(MSG::DEBUG) << "#BTAG# " << idim
362 << " is not a correct dimensionality for pdfs !"
363 << endmsg;
364 }
365 } // endloop on hypotheses (B,U,C..)
366 unsigned int classCount(0);
367 for (const auto& f : tmpVector) {
368 if(sum != 0.) {
369 if( msgLvl(MSG::DEBUG) ) msg(MSG::DEBUG) << "#BTAG# sum of pX = " << sum << endmsg;
370 double p = f;
371 if(m_normalizedProb) p /= sum;
372 probDensityPerEventClassAllVariables[classCount] *= p;
373 } else {
374 msg(MSG::DEBUG) << "#BTAG# Empty bins for all hypothesis... "
375 << "The discriminating variables are not taken into "
376 << "account in this jet." << endmsg;
377 msg(MSG::DEBUG) << "#BTAG# Please check your inputs" << endmsg;
378 }
379 if( msgLvl(MSG::DEBUG) ) msg(MSG::DEBUG) << "#BTAG# probDensity= "
380 << probDensityPerEventClassAllVariables[classCount]
381 << " ic= " << classCount << endmsg;
382 classCount++;
383 }
384 if( msgLvl(MSG::DEBUG) ) msg(MSG::DEBUG) << "#BTAG# Final probDensity= "
385 << probDensityPerEventClassAllVariables
386 << endmsg;
387 }
388 }
389 if( msgLvl(MSG::DEBUG) ) msg(MSG::DEBUG) << "#BTAG# Ending ..." << endmsg;
390 return probDensityPerEventClassAllVariables;
391 }
392
393 double NewLikelihoodTool::getEff(const std::string& hypo, const std::string& hname, const std::string& suffix) const {
394 double eff(0.);
395 TH1* numH = this->prepareHistogram(hypo, hname+"Eff"+suffix);
396 TH1* denH = this->prepareHistogram(hypo, hname+"Norm"+suffix);
397 if(numH && denH) {
398 double nnum = numH->GetEntries();
399 double nden = denH->GetEntries();
400 if(nden!=0) {
401 eff = nnum / nden;
402 if( msgLvl(MSG::VERBOSE) ) msg(MSG::VERBOSE) << "#BTAG# Efficiency for " << hypo << "#" << hname << " "
403 << suffix << ": " << nnum << "/" << nden << "= " << eff << endmsg;
404 } else {
405 msg(MSG::DEBUG) << "#BTAG# Problem with Efficiency for " << hypo << "#" << hname << " "
406 << suffix << ": " << nnum << "/" << nden << "= " << eff << endmsg;
407 }
408 } else {
409 msg(MSG::DEBUG) << "#BTAG# Unknown histogram for Efficiency for " << hypo
410 << "#" << hname << " " << suffix << endmsg;
411 }
412 return eff;
413 }
414
415
416}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
static double Interpol3d(double, double, double, TH3 *)
static double Interpol1d(double, TH1 *)
static double Interpol2d(double, double, TH2 *)
static void smoothASH2D(TH2 *, int m1=3, int m2=3, bool debug=false)
static void smoothASH3D(TH3 *, int m1=3, int m2=3, int m3=2, bool debug=false)
std::vector< std::string > m_histograms
std::vector< std::string > gradeList(const std::string &hname) const
TH1 * prepareHistogram(const std::string &hypo, const std::string &hname) const
double getEff(const std::string &hypo, const std::string &histo, const std::string &suffix) const
std::vector< std::string > m_hypotheses
bool m_normalizedProb
Treatment of histograms:
std::vector< double > calculateLikelihood(const std::vector< Slice > &lhVariableValues) const
SG::ReadCondHandleKey< JetTagCalibCondData > m_readKey
Key of calibration data:
std::vector< std::string > m_vetoSmoothingOf
NewLikelihoodTool(const std::string &, const std::string &, const IInterface *)
virtual StatusCode initialize() override
void smoothAndNormalizeHistogram(TH1 *histo, const std::string &hname) const
void defineHypotheses(const std::vector< std::string > &)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
Header file for AthHistogramAlgorithm.
STL class.
std::vector< std::string > veto
these patterns are anded
Definition listroot.cxx:191
The namespace of all packages in PhysicsAnalysis/JetTagging.
STL namespace.