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;
20using namespace ADD_CMODE(TauAnalysisTools);
21
22//=================================PUBLIC-PART==================================
23//______________________________________________________________________________
24DiTauSelectionTool::DiTauSelectionTool( const std::string& name )
25 : asg::AsgMetadataTool( name )
26 , m_sOmniIDWP("OMNIIDNONE")
27 , m_fOutFile(nullptr)
28 , m_aAccept( "DiTauSelection" )
29{}
30
31//______________________________________________________________________________
32DiTauSelectionTool::~DiTauSelectionTool()
33{
34 m_cMap.clear();
35}
36
37//______________________________________________________________________________
38StatusCode DiTauSelectionTool::initialize()
39{
40
41 m_vAbsEtaRegion = m_vecAbsEtaRegion.value();
42 m_vAbsCharges = m_vecAbsCharges.value();
43
44 bool bConfigViaConfigFile = !m_sConfigPath.empty();
45 bool bConfigViaProperties = false;
46 if (!bConfigViaProperties and !std::isnan(m_dPtMin.value())) bConfigViaProperties = true;
47 if (!bConfigViaProperties and !m_vAbsEtaRegion.empty()) bConfigViaProperties = true;
48 if (!bConfigViaProperties and !std::isnan(m_dAbsEtaMin.value())) bConfigViaProperties = true;
49 if (!bConfigViaProperties and !std::isnan(m_dAbsEtaMax.value())) bConfigViaProperties = true;
50 if (!bConfigViaProperties and !std::isnan(m_dNSubjetsMin.value())) bConfigViaProperties = true;
51 if (!bConfigViaProperties and !m_vAbsCharges.empty()) bConfigViaProperties = true;
52 if (!bConfigViaProperties and !std::isnan(m_iAbsCharge.value())) bConfigViaProperties = true;
53 if (!bConfigViaProperties and !std::isnan(m_dOmniScoreMin.value())) bConfigViaProperties = true;
54 if (!bConfigViaProperties and m_iOmniIDWP != 0) bConfigViaProperties = true;
55
56 if (bConfigViaConfigFile and bConfigViaProperties)
57 {
58 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.");
59 return StatusCode::FAILURE;
60
61 }
62 if (!bConfigViaConfigFile and !bConfigViaProperties)
63 {
64 ATH_MSG_WARNING("No cut configuration provided, the tool will not do anything. For further details please refer to the documentation:");
65 ATH_MSG_WARNING("https://gitlab.cern.ch/atlas/athena/blob/main/PhysicsAnalysis/TauID/TauAnalysisTools/doc/README-DiTauSelectionTool.rst");
66 }
67
68 if (bConfigViaConfigFile)
69 {
70 TEnv rEnv;
71 std::string sInputFilePath = PathResolverFindCalibFile(m_sConfigPath);
72
73 if (!testFileForEOFContainsCharacters(sInputFilePath))
74 ATH_MSG_WARNING("Config file for DiTauSelectionTool with path "<<sInputFilePath<<" does not contain an empty last line. The tool might not be properly configured!");
75
76 rEnv.ReadFile(sInputFilePath.c_str(),
77 kEnvAll);
78
79 std::vector<std::string> vCuts;
80 // if Cuts are specified in the config file take these ones, if not take all
81 // specified in the config
82 if (rEnv.Defined("SelectionCuts"))
83 ADD_CMODE(TauAnalysisTools)::split(rEnv, "SelectionCuts", ' ', vCuts);
84 else
85 {
86 auto lList = rEnv.GetTable();
87 for( Int_t i = 0; i < lList->GetEntries(); ++i )
88 {
89 vCuts.push_back( lList->At( i )->GetName() );
90 }
91 }
92
93 int iSelectionCuts = 0;
94
95 for (const std::string& sCut : vCuts)
96 {
97 if (sCut == "PtMin")
98 {
99 iSelectionCuts = iSelectionCuts | DiTauCutPt;
100 if (std::isnan(m_dPtMin.value()))
101 m_dPtMin = rEnv.GetValue("PtMin",NAN);
102 }
103 else if (sCut == "AbsEtaRegion")
104 {
105 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
106 if (m_vAbsEtaRegion.empty())
107 ADD_CMODE(TauAnalysisTools)::split(rEnv,"AbsEtaRegion", ';', m_vAbsEtaRegion);
108 }
109 else if (sCut == "AbsEtaMin")
110 {
111 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
112 if (std::isnan(m_dAbsEtaMin.value()))
113 m_dAbsEtaMin = rEnv.GetValue("AbsEtaMin",NAN);
114 }
115 else if (sCut == "AbsEtaMax")
116 {
117 iSelectionCuts = iSelectionCuts | DiTauCutAbsEta;
118 if (std::isnan(m_dAbsEtaMax.value()))
119 m_dAbsEtaMax = rEnv.GetValue("AbsEtaMax",NAN);
120 }
121 else if (sCut == "NSubjetsMin")
122 {
123 iSelectionCuts = iSelectionCuts | DiTauCutNSubjets;
124 if (std::isnan(m_dNSubjetsMin.value()))
125 m_dNSubjetsMin = rEnv.GetValue("NSubjetsMin",NAN);
126 }
127 else if (sCut == "AbsCharges")
128 {
129 iSelectionCuts = iSelectionCuts | DiTauCutAbsCharge;
130 if (m_vAbsCharges.empty())
131 ADD_CMODE(TauAnalysisTools)::split(rEnv,"AbsCharges", ';', m_vAbsCharges);
132 }
133 else if (sCut == "AbsCharge")
134 {
135 iSelectionCuts = iSelectionCuts | DiTauCutAbsCharge;
136 if (std::isnan(m_iAbsCharge.value()))
137 m_iAbsCharge = rEnv.GetValue("AbsCharge",NAN);
138 }
139 else if (sCut == "OmniScoreMin")
140 {
141 iSelectionCuts = iSelectionCuts | DiTauCutOmniScore;
142 if (std::isnan(m_dOmniScoreMin.value()))
143 m_dOmniScoreMin = rEnv.GetValue("OmniScoreMin",NAN);
144
145 // check for possible mis-config in DiTau selection
146 for (const std::string& checkCut : vCuts){
147 if (checkCut.find("OmniScoreRegion") != std::string::npos) {
148 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");
149 return StatusCode::FAILURE;
150 }
151 }
152
153 // check if using OmniScore
154 m_useOmniScore = true;
155 }
156 else if (sCut == "OmniIDWP")
157 {
158 iSelectionCuts = iSelectionCuts | DiTauCutOmniIDWP;
159 if (m_iOmniIDWP == OMNIIDNONE){
160 m_sOmniIDWP = rEnv.GetValue("OmniIDWP","OMNIIDNONE");
161 m_iOmniIDWP = convertStrToOmniIDWP(m_sOmniIDWP);
162 }
163 // check for possible mis-config in Tau selection
164 for (const std::string& checkCut : vCuts){
165 if (checkCut.find("OmniScore") != std::string::npos) {
166 ATH_MSG_ERROR("Misconfig due to OmniIDWP and OmniScore cuts both present in the config file. Please CHECK carefully config file again");
167 return StatusCode::FAILURE;
168 }
169 }
170 }
171 else ATH_MSG_WARNING("Cut " << sCut << " is not available");
172 }
173
174 if (m_iSelectionCuts == NoDiTauCut)
175 m_iSelectionCuts = iSelectionCuts;
176 }
177
178 // initialise the ReadDecorHandleKey if OmniScore is applied
179 if (m_useOmniScore) {
180 if(m_OmniScoreDecorKey.empty()) {
181 ATH_CHECK( m_OmniScoreDecorKey.assign("DiTauJets.omni_score"));
182 }
183 }
184 ATH_CHECK( m_OmniScoreDecorKey.initialize( m_useOmniScore ) );
185
186 // specify all available cut descriptions
187 using map_type = std::map<DiTauSelectionCuts, std::unique_ptr<DiTauSelectionCut>>;
188 using pair_type = map_type::value_type;
189
190 pair_type elements[] =
191 {
192 {DiTauCutPt, std::make_unique<DiTauSelectionCutPt>(this)},
193 {DiTauCutAbsEta, std::make_unique<DiTauSelectionCutAbsEta>(this)},
194 {DiTauCutNSubjets, std::make_unique<DiTauSelectionCutNSubjets>(this)},
195 {DiTauCutAbsCharge, std::make_unique<DiTauSelectionCutAbsCharge>(this)},
196 {DiTauCutOmniScore, std::make_unique<DiTauSelectionCutOmniScore>(this)},
197 {DiTauCutOmniIDWP, std::make_unique<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" );
203 FillRegionVector(m_vPtRegion, m_dPtMin.value(), NAN);
204 FillRegionVector(m_vAbsEtaRegion, m_dAbsEtaMin.value(), m_dAbsEtaMax.value());
205 FillRegionVector(m_vNSubjetsRegion, m_dNSubjetsMin.value(), NAN);
206 FillValueVector(m_vAbsCharges, m_iAbsCharge.value());
207 FillRegionVector(m_vOmniScoreRegion, m_dOmniScoreMin.value(), NAN );
208
209 PrintConfigRegion ("Pt", m_vPtRegion);
210 PrintConfigRegion ("AbsEta", m_vAbsEtaRegion);
211 PrintConfigRegion ("NSubjets", m_vNSubjetsRegion);
212 PrintConfigValue ("AbsCharge", m_vAbsCharges);
213 PrintConfigRegion ("OmniScore", m_vOmniScoreRegion);
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
226 if (m_bCreateControlPlots)
227 setupCutFlowHistogram();
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//______________________________________________________________________________
240StatusCode DiTauSelectionTool::beginEvent()
241{
242 return StatusCode::SUCCESS;
243}
244
245//______________________________________________________________________________
246const asg::AcceptInfo& DiTauSelectionTool::getAcceptInfo() const
247{
248 return m_aAccept;
249}
250
251//______________________________________________________________________________
252asg::AcceptData DiTauSelectionTool::accept( const xAOD::IParticle* xP ) const
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//______________________________________________________________________________
274asg::AcceptData DiTauSelectionTool::accept( const xAOD::DiTauJet& xDiTau ) const
275{
276 asg::AcceptData acceptData (&m_aAccept);
277
278 int iNBin = 0;
279
280 if (m_bCreateControlPlots)
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 {
298 if (m_bCreateControlPlots)
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
326 if (m_bCreateControlPlots)
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//______________________________________________________________________________
343void DiTauSelectionTool::writeControlHistograms()
344{
345 if (m_bCreateControlPlots and !m_fOutFile)
346 ATH_MSG_WARNING("CreateControlPlots was set to true, but no valid file pointer was provided");
347 if (m_bCreateControlPlots and m_fOutFile)
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=================================
362void DiTauSelectionTool::setupCutFlowHistogram()
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
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
#define ADD_CMODE(name)
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Class providing the definition of the 4-vector interface.
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
StatusCode accept(const xAOD::Muon *mu)
@ Jet
The object is a jet.
Definition ObjectType.h:40
DiTauJet_v1 DiTauJet
Definition of the current version.
Definition DiTauJet.h:17