ATLAS Offline Software
Loading...
Searching...
No Matches
DiTauSelectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Local include(s):
8
9// Framework include(s):
11
12// ROOT include(s)
13#include "TEnv.h"
14#include "THashList.h"
15
16// System include(s)
17#include <cmath> // for std::isnan
18
19using namespace TauAnalysisTools;
20
21//=================================PUBLIC-PART==================================
22//______________________________________________________________________________
23DiTauSelectionTool::DiTauSelectionTool( const std::string& name )
24 : asg::AsgMetadataTool( name )
25 , m_sOmniIDWP("OMNIIDNONE")
26 , m_fOutFile(nullptr)
27 , m_aAccept( "DiTauSelection" )
28{}
29
30//______________________________________________________________________________
35
36//______________________________________________________________________________
38{
39
42
43 bool bConfigViaConfigFile = !m_sConfigPath.empty();
44 bool bConfigViaProperties = false;
45 if (!bConfigViaProperties and !std::isnan(m_dPtMin.value())) bConfigViaProperties = true;
46 if (!bConfigViaProperties and !m_vAbsEtaRegion.empty()) bConfigViaProperties = true;
47 if (!bConfigViaProperties and !std::isnan(m_dAbsEtaMin.value())) bConfigViaProperties = true;
48 if (!bConfigViaProperties and !std::isnan(m_dAbsEtaMax.value())) bConfigViaProperties = true;
49 if (!bConfigViaProperties and !std::isnan(m_dNSubjetsMin.value())) bConfigViaProperties = true;
50 if (!bConfigViaProperties and !m_vAbsCharges.empty()) bConfigViaProperties = true;
51 if (!bConfigViaProperties and !std::isnan(m_iAbsCharge.value())) bConfigViaProperties = true;
52 if (!bConfigViaProperties and !std::isnan(m_dOmniScoreMin.value())) bConfigViaProperties = true;
53 if (!bConfigViaProperties and m_iOmniIDWP != 0) bConfigViaProperties = true;
54
55 if (bConfigViaConfigFile and bConfigViaProperties)
56 {
57 ATH_MSG_ERROR("Configured tool via setProperty and configuration file, which may lead to unexpected configuration. Please setup the DiTauSelectionTool using only one of the two methods. For further details please refer to the documentation https://gitlab.cern.ch/atlas/athena/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/doc/README-DiTauSelectionTool.rst or contact the TauCP group.");
58 return StatusCode::FAILURE;
59
60 }
61 if (!bConfigViaConfigFile and !bConfigViaProperties)
62 {
63 ATH_MSG_WARNING("No cut configuration provided, the tool will not do anything. For further details please refer to the documentation:");
64 ATH_MSG_WARNING("https://gitlab.cern.ch/atlas/athena/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/doc/README-DiTauSelectionTool.rst");
65 }
66
67 if (bConfigViaConfigFile)
68 {
69 TEnv rEnv;
70 std::string sInputFilePath = PathResolverFindCalibFile(m_sConfigPath);
71
72 if (!testFileForEOFContainsCharacters(sInputFilePath))
73 ATH_MSG_WARNING("Config file for DiTauSelectionTool with path "<<sInputFilePath<<" does not contain an empty last line. The tool might not be properly configured!");
74
75 rEnv.ReadFile(sInputFilePath.c_str(),
76 kEnvAll);
77
78 std::vector<std::string> vCuts;
79 // if Cuts are specified in the config file take these ones, if not take all
80 // specified in the config
81 if (rEnv.Defined("SelectionCuts"))
82 TauAnalysisTools::split(rEnv, "SelectionCuts", ' ', vCuts);
83 else
84 {
85 auto lList = rEnv.GetTable();
86 for( Int_t i = 0; i < lList->GetEntries(); ++i )
87 {
88 vCuts.push_back( lList->At( i )->GetName() );
89 }
90 }
91
92 int iSelectionCuts = 0;
93
94 for (const std::string& sCut : vCuts)
95 {
96 if (sCut == "PtMin")
97 {
98 iSelectionCuts = iSelectionCuts | DiTauCutPt;
99 if (std::isnan(m_dPtMin.value()))
100 m_dPtMin = rEnv.GetValue("PtMin",NAN);
101 }
102 else if (sCut == "AbsEtaRegion")
103 {
104 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
105 if (m_vAbsEtaRegion.empty())
106 TauAnalysisTools::split(rEnv,"AbsEtaRegion", ';', m_vAbsEtaRegion);
107 }
108 else if (sCut == "AbsEtaMin")
109 {
110 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
111 if (std::isnan(m_dAbsEtaMin.value()))
112 m_dAbsEtaMin = rEnv.GetValue("AbsEtaMin",NAN);
113 }
114 else if (sCut == "AbsEtaMax")
115 {
116 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
117 if (std::isnan(m_dAbsEtaMax.value()))
118 m_dAbsEtaMax = rEnv.GetValue("AbsEtaMax",NAN);
119 }
120 else if (sCut == "NSubjetsMin")
121 {
122 iSelectionCuts = iSelectionCuts | DiTauCutNSubjets;
123 if (std::isnan(m_dNSubjetsMin.value()))
124 m_dNSubjetsMin = rEnv.GetValue("NSubjetsMin",NAN);
125 }
126 else if (sCut == "AbsCharges")
127 {
128 iSelectionCuts = iSelectionCuts | DiTauCutAbsCharge;
129 if (m_vAbsCharges.empty())
130 TauAnalysisTools::split(rEnv,"AbsCharges", ';', m_vAbsCharges);
131 }
132 else if (sCut == "AbsCharge")
133 {
134 iSelectionCuts = iSelectionCuts | DiTauCutAbsCharge;
135 if (std::isnan(m_iAbsCharge.value()))
136 m_iAbsCharge = rEnv.GetValue("AbsCharge",NAN);
137 }
138 else if (sCut == "OmniScoreMin")
139 {
140 iSelectionCuts = iSelectionCuts | DiTauCutOmniScore;
141 if (std::isnan(m_dOmniScoreMin.value()))
142 m_dOmniScoreMin = rEnv.GetValue("OmniScoreMin",NAN);
143
144 // check for possible mis-config in DiTau selection
145 for (const std::string& checkCut : vCuts){
146 if (checkCut.find("OmniScoreRegion") != std::string::npos) {
147 ATH_MSG_ERROR("Misconfig due to OmniScoreRegion and OmniScoreMin cuts both present in the config file. Please CHECK carefully config file again and choose of the two");
148 return StatusCode::FAILURE;
149 }
150 }
151
152 // check if using OmniScore
153 m_useOmniScore = true;
154 }
155 else if (sCut == "OmniIDWP")
156 {
157 iSelectionCuts = iSelectionCuts | DiTauCutOmniIDWP;
158 if (m_iOmniIDWP == OMNIIDNONE){
159 m_iOmniIDWP = convertStrToOmniIDWP(rEnv.GetValue("OmniIDWP","OMNIIDNONE"));
160 }
161 // check for possible mis-config in Tau selection
162 for (const std::string& checkCut : vCuts){
163 if (checkCut.find("OmniScore") != std::string::npos) {
164 ATH_MSG_ERROR("Misconfig due to OmniIDWP and OmniScore cuts both present in the config file. Please CHECK carefully config file again");
165 return StatusCode::FAILURE;
166 }
167 }
168 }
169 else ATH_MSG_WARNING("Cut " << sCut << " is not available");
170 }
171
173 m_iSelectionCuts = iSelectionCuts;
174 }
175
176 // initialise the ReadDecorHandleKey if OmniScore is applied
177 if (m_useOmniScore) {
178 if(m_OmniScoreDecorKey.empty()) {
179 ATH_CHECK( m_OmniScoreDecorKey.assign("DiTauJets.omni_score"));
180 }
181 }
183
185
186 // specify all available cut descriptions
187 using map_type = std::map<DiTauSelectionCuts, std::unique_ptr<TauAnalysisTools::DiTauSelectionCut>>;
188 using pair_type = map_type::value_type;
189
190 pair_type elements[] =
191 {
192 {DiTauCutPt, std::make_unique<TauAnalysisTools::DiTauSelectionCutPt>(this)},
193 {DiTauCutAbsEta, std::make_unique<TauAnalysisTools::DiTauSelectionCutAbsEta>(this)},
194 {DiTauCutNSubjets, std::make_unique<TauAnalysisTools::DiTauSelectionCutNSubjets>(this)},
195 {DiTauCutAbsCharge, std::make_unique<TauAnalysisTools::DiTauSelectionCutAbsCharge>(this)},
196 {DiTauCutOmniScore, std::make_unique<TauAnalysisTools::DiTauSelectionCutOmniScore>(this)},
197 {DiTauCutOmniIDWP, std::make_unique<TauAnalysisTools::DiTauSelectionCutOmniIDWP>(this)},
198 };
199
200 m_cMap = { std::make_move_iterator( begin(elements) ), std::make_move_iterator( end(elements) ) };
201
202 ATH_MSG_INFO( "Initializing DiTauSelectionTool" );
208
212 PrintConfigValue ("AbsCharge", m_vAbsCharges);
214 PrintConfigValue ("OmniIDWP", m_sOmniIDWP);
215
216 std::string sCuts = "";
217 if (m_iSelectionCuts & DiTauCutPt) sCuts += "Pt ";
218 if (m_iSelectionCuts & DiTauCutAbsEta) sCuts += "AbsEta ";
219 if (m_iSelectionCuts & DiTauCutNSubjets) sCuts += "NSubjets ";
220 if (m_iSelectionCuts & DiTauCutAbsCharge) sCuts += "AbsCharge ";
221 if (m_iSelectionCuts & DiTauCutOmniScore) sCuts += "OmniScore ";
222 if (m_iSelectionCuts & DiTauCutOmniIDWP) sCuts += "OmniIDWP ";
223
224 ATH_MSG_DEBUG( "cuts: " << sCuts);
225
228
229 for ( const auto& entry : m_cMap ) {
230 if ( m_iSelectionCuts &entry.first ) {
231 entry.second->setAcceptInfo(m_aAccept);
232 }
233 }
234
235 return StatusCode::SUCCESS;
236}
237
238
239//______________________________________________________________________________
241{
242 return StatusCode::SUCCESS;
243}
244
245//______________________________________________________________________________
250
251//______________________________________________________________________________
253{
254 // Check if this is a jet:
255 if( xP->type() != xAOD::Type::Jet )
256 {
257 ATH_MSG_ERROR( "accept(...) Function received a non-jet" );
258 return asg::AcceptData (&m_aAccept);
259 }
260
261 // Cast it to a ditau:
262 const xAOD::DiTauJet* xDiTau = dynamic_cast< const xAOD::DiTauJet* >( xP );
263 if( ! xDiTau )
264 {
265 ATH_MSG_FATAL( "accept(...) Failed to cast particle to tau" );
266 return asg::AcceptData (&m_aAccept);
267 }
268
269 // Let the specific function do the work:
270 return accept( *xDiTau );
271}
272
273//______________________________________________________________________________
275{
276 asg::AcceptData acceptData (&m_aAccept);
277
278 int iNBin = 0;
279
281 {
282 // fill cutflow 'All' bin
283 m_hCutFlow->Fill(iNBin);
284 // fill main distributions before all cuts
285 for (const auto& entry : m_cMap)
286 entry.second->fillHistogramCutPre(xDiTau);
287 }
288 try
289 {
290 for (const auto& entry : m_cMap)
291 {
292 if (m_iSelectionCuts & entry.first)
293 {
294 if (!entry.second->accept(xDiTau, acceptData))
295 return acceptData;
296 else
297 {
299 {
300 // fill cutflow after each passed cut
301 iNBin++;
302 m_hCutFlow->Fill(iNBin);
303 }
304 }
305 }
306 }
307 }
308 catch (const std::runtime_error& error)
309 {
310 // LEGACY: In practical terms this should probably just throw, not
311 // print a warning/error and then continue on. However, I leave
312 // that to the experts who probably had a reason not to let the
313 // exception escape. For now I just downgraded it from error to
314 // warning and limited the number of warnings (04 Jan 22).
315 static std::atomic<uint64_t> warning_count (0u);
316 auto mycount = ++ warning_count;
317 if (mycount < 10u)
318 {
319 ATH_MSG_WARNING(error.what());
320 if (mycount == 9u)
321 ATH_MSG_WARNING ("this is your last warning");
322 }
323 }
324
325 // fill main distributions after all cuts
327 {
328 for (const auto& entry : m_cMap)
329 entry.second->fillHistogramCut(xDiTau);
330 }
331
332 // // Return the result:
333 return acceptData;
334}
335
336//______________________________________________________________________________
337void DiTauSelectionTool::setOutFile( TFile* fOutFile )
338{
339 m_fOutFile = fOutFile;
340}
341
342//______________________________________________________________________________
344{
346 ATH_MSG_WARNING("CreateControlPlots was set to true, but no valid file pointer was provided");
348 {
350 m_fOutFile->mkdir((this->name()+"_control").c_str());
351 m_fOutFile->cd((this->name()+"_control").c_str());
353 m_hCutFlow->Write();
354
355 for (const auto& entry : m_cMap)
356 entry.second->writeControlHistograms();
357 }
358}
359
360
361//=================================PRIVATE-PART=================================
363{
364 // count number of cuts
365 int iNBins = 0;
366 for (const auto& entry : m_cMap)
367 if (m_iSelectionCuts & entry.first)
368 iNBins++;
369 // create cutflow histogram with iNBins+1 bins, where first bin is 'All' bin
370 m_hCutFlow = std::make_shared<TH1F>("hCutFlow","CutFlow;; events",iNBins+1,0,iNBins+1);
371 m_hCutFlow->GetXaxis()->SetBinLabel(1,"All");
372
373 // reusing this variable to reduce overhead
374 iNBins = 2;
375 // set bin labels
376 for (const auto& entry : m_cMap)
377 if (m_iSelectionCuts & entry.first)
378 {
379 m_hCutFlow->GetXaxis()->SetBinLabel(iNBins, entry.second->getName().c_str());
380 iNBins++;
381 }
382}
383
384//______________________________________________________________________________
385template<typename T, typename U>
386void DiTauSelectionTool::FillRegionVector(std::vector<T>& vRegion, U tMin, U tMax) const
387{
388 if (!vRegion.empty())
389 return;
390 if (!std::isnan(tMin)) // if tMin is NAN, then this assumption fails and -inf is added to the vector
391 vRegion.push_back(tMin);
392 else
393 vRegion.push_back(-std::numeric_limits<T>::infinity());
394
395 if (!std::isnan(tMax)) // if tMax is NAN, then this assumption fails and inf is added to the vector
396 vRegion.push_back(tMax);
397 else
398 vRegion.push_back(std::numeric_limits<T>::infinity());
399}
400
401//______________________________________________________________________________
402template<typename T, typename U>
403void DiTauSelectionTool::FillValueVector(std::vector<T>& vRegion, U tVal) const
404{
405 if (!vRegion.empty())
406 return;
407 if (tVal == tVal) // if tMax is NAN, then this assumption fails and nothing is added to the vector
408 vRegion.push_back(tVal);
409}
410
411//______________________________________________________________________________
412template<typename T>
413void DiTauSelectionTool::PrintConfigRegion(const std::string& sCutName, std::vector<T>& vRegion) const
414{
415 unsigned int iNumRegion = vRegion.size()/2;
416 for( unsigned int iRegion = 0; iRegion < iNumRegion; iRegion++ )
417 {
418 ATH_MSG_DEBUG( sCutName<<": " << vRegion.at(iRegion*2) << " to " << vRegion.at(iRegion*2+1) );
419 }
420}
421
422//______________________________________________________________________________
423template<typename T>
424void DiTauSelectionTool::PrintConfigValue(const std::string& sCutName, std::vector<T>& vRegion) const
425{
426 for (auto tVal : vRegion)
427 ATH_MSG_DEBUG( sCutName<<": " << tVal );
428}
429
430//______________________________________________________________________________
431template<typename T>
432void DiTauSelectionTool::PrintConfigValue(const std::string& sCutName, T& tVal) const
433{
434 ATH_MSG_DEBUG( sCutName<<": " << tVal );
435}
436
437//______________________________________________________________________________
438int DiTauSelectionTool::convertStrToOmniIDWP(const std::string& sOmniIDWP) const
439{
440 if (sOmniIDWP == "OMNIIDNONE") return int(OMNIIDNONE);
441 else if (sOmniIDWP == "OMNIIDVERYLOOSE") return int(OMNIIDVERYLOOSE);
442 else if (sOmniIDWP == "OMNIIDLOOSE") return int(OMNIIDLOOSE);
443 else if (sOmniIDWP == "OMNIIDMEDIUM") return int(OMNIIDMEDIUM);
444 else if (sOmniIDWP == "OMNIIDTIGHT") return int(OMNIIDTIGHT);
445
446 ATH_MSG_ERROR( "omni ID working point "<<sOmniIDWP<<" is unknown, the OmniIDWP cut will not accept any ditau!" );
447 return -1;
448}
449
450//______________________________________________________________________________
451std::string DiTauSelectionTool::convertOmniIDWPToStr(int iOmniIDWP) const
452{
453 switch (iOmniIDWP)
454 {
455 case OMNIIDNONE:
456 return "OMNIIDNONE";
457 case OMNIIDVERYLOOSE:
458 return "OMNIIDVERYLOOSE";
459 case OMNIIDLOOSE:
460 return "OMNIIDLOOSE";
461 case OMNIIDMEDIUM:
462 return "OMNIIDMEDIUM";
463 case OMNIIDTIGHT:
464 return "OMNIIDTIGHT";
465
466 default:
467 ATH_MSG_WARNING( "OmniID working point with enum " << iOmniIDWP << " is unknown, the OmniIDWP cut will not accept any ditau!" );
468 return "";
469 }
470}
471
472
473
474
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
std::map< DiTauSelectionCuts, std::unique_ptr< TauAnalysisTools::DiTauSelectionCut > > m_cMap
Gaudi::Property< std::vector< float > > m_vecAbsEtaRegion
Gaudi::Property< bool > m_bCreateControlPlots
virtual asg::AcceptData accept(const xAOD::IParticle *p) const override
Get the decision using a generic IParticle pointer.
Gaudi::Property< std::string > m_sConfigPath
SG::ReadDecorHandleKey< xAOD::DiTauJetContainer > m_OmniScoreDecorKey
virtual StatusCode beginEvent() override
Function called when a new events is loaded.
int convertStrToOmniIDWP(const std::string &sOmniIDWP) const
Gaudi::Property< std::vector< int > > m_vecAbsCharges
void FillValueVector(std::vector< T > &vRegion, U tVal) const
void FillRegionVector(std::vector< T > &vRegion, U tMin, U tMax) const
void PrintConfigRegion(const std::string &sCutName, std::vector< T > &vRegion) const
virtual ASG_TOOL_CLASS2(DiTauSelectionTool, IAsgSelectionTool, TauAnalysisTools::IDiTauSelectionTool) public ~DiTauSelectionTool()
Create a proper constructor for Athena.
virtual const asg::AcceptInfo & getAcceptInfo() const override
Get an object describing the "selection steps" of the tool.
std::string convertOmniIDWPToStr(int iOmniIDWP) const
void PrintConfigValue(const std::string &sCutName, std::vector< T > &vRegion) const
virtual void writeControlHistograms() override
Write control histograms to output file.
asg::AcceptInfo m_aAccept
Object used to store selection information.
virtual void setOutFile(TFile *fOutFile) override
Set output file for control histograms.
virtual StatusCode initialize() override
Function initialising the tool.
Class providing the definition of the 4-vector interface.
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
void split(const std::string &sInput, const char cDelim, std::vector< std::string > &vOut)
bool testFileForEOFContainsCharacters(const std::string &sFileName)
returns true if last line in file is empty or the line starts with the number sign
@ Jet
The object is a jet.
Definition ObjectType.h:40
DiTauJet_v1 DiTauJet
Definition of the current version.
Definition DiTauJet.h:17