ATLAS Offline Software
Loading...
Searching...
No Matches
TrigEgammaPrecisionElectronHypoTool.py
Go to the documentation of this file.
2# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3#
4from AthenaCommon.SystemOfUnits import GeV
5from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
6from AthenaConfiguration.ComponentFactory import CompFactory
7from AthenaMonitoringKernel.GenericMonitoringTool import GenericMonitoringTool
8
9
10def same( val , tool):
11 return [val]*( len( tool.EtaBins ) - 1 )
12
13#
14# Create the hypo alg with all selectors
15#
16def createTrigEgammaPrecisionElectronHypoAlg(flags, name, sequenceOut):
17 acc = ComponentAccumulator()
18 monTool = GenericMonitoringTool(flags, "MonTool_"+name,
19 HistPath = 'PrecisionElectronHypo/'+name)
20
21 acc_ElectronCBSelectorTools = TrigEgammaPrecisionElectronCBSelectorCfg(flags)
22 acc_ElectronLHSelectorTools = TrigEgammaPrecisionElectronLHSelectorCfg(flags)
23 acc_ElectronDNNSelectorTools = TrigEgammaPrecisionElectronDNNSelectorCfg(flags)
24
25 acc.merge(acc_ElectronCBSelectorTools)
26 acc.merge(acc_ElectronLHSelectorTools)
27 acc.merge(acc_ElectronDNNSelectorTools)
28
29 thePrecisionElectronHypo = CompFactory.TrigEgammaPrecisionElectronHypoAlg(name)
30 thePrecisionElectronHypo.Electrons = str(sequenceOut)
31 thePrecisionElectronHypo.RunInView = True
32 thePrecisionElectronHypo.ElectronCBSelectorTools = acc_ElectronCBSelectorTools.getPublicTools()
33 thePrecisionElectronHypo.ElectronLHSelectorTools = acc_ElectronLHSelectorTools.getPublicTools()
34 thePrecisionElectronHypo.ElectronDNNSelectorTools = acc_ElectronDNNSelectorTools.getPublicTools()
35 thePrecisionElectronHypo.CBNames = ["medium", "loose", "mergedtight"] # just like the pidnames
36 thePrecisionElectronHypo.LHNames = ["lhtight", "lhmedium", "lhloose", "lhvloose",
37 "lhtight_nopix", "lhmedium_nopix","lhloose_nopix","lhvloose_nopix",
38 "lhtight_nogsf", "lhmedium_nogsf","lhloose_nogsf","lhvloose_nogsf",
39 "lhtight_nogsf_nopix", "lhmedium_nogsf_nopix","lhloose_nogsf_nopix","lhvloose_nogsf_nopix"] # just like the pidnames
40 thePrecisionElectronHypo.DNNNames = ["dnntight", "dnnmedium", "dnnloose"] # just like the pidnames
41 monTool.defineHistogram('TIME_exec', type='TH1F', path='EXPERT', title="Precision Electron Hypo Algtime; time [ us ] ; Nruns", xbins=80, xmin=0.0, xmax=8000.0)
42 monTool.defineHistogram('TIME_LH_exec', type='TH1F', path='EXPERT', title="Precision Electron Hypo LH Algtime; time [ us ] ; Nruns", xbins=20, xmin=0.0, xmax=2000)
43 monTool.defineHistogram('TIME_DNN_exec', type='TH1F', path='EXPERT', title="Precision Electron Hypo DNN Algtime; time [ us ] ; Nruns", xbins=20, xmin=0.0, xmax=2000)
44
45 thePrecisionElectronHypo.MonTool=monTool
46
47 return thePrecisionElectronHypo, acc
48
49def TrigEgammaPrecisionElectronHypoAlgCfg(flags, name, inputElectronCollection ):
50 acc = ComponentAccumulator()
51 hypo_tuple = createTrigEgammaPrecisionElectronHypoAlg( flags, name, inputElectronCollection )
52 hypo_alg = hypo_tuple[0]
53 hypo_acc = hypo_tuple[1]
54 acc.addEventAlgo( hypo_alg )
55 acc.merge(hypo_acc)
56 return acc
57
59
60
61 __operation_points = [ 'tight' ,
62 'medium' ,
63 'loose' ,
64 'vloose' ,
65 'lhtight' ,
66 'lhmedium' ,
67 'lhloose' ,
68 'lhvloose' ,
69 'lhtight_nopix' ,
70 'lhmedium_nopix' ,
71 'lhloose_nopix' ,
72 'lhvloose_nopix' ,
73 'lhtight_nogsf' ,
74 'lhmedium_nogsf' ,
75 'lhloose_nogsf' ,
76 'lhvloose_nogsf' ,
77 'lhtight_nogsf_nopix' ,
78 'lhmedium_nogsf_nopix' ,
79 'lhloose_nogsf_nopix' ,
80 'lhvloose_nogsf_nopix' ,
81 'dnntight' ,
82 'dnnmedium',
83 'dnnloose' ,
84 'mergedtight',
85 'nopid',
86 ]
87
88 __operation_points_lhInfo = [
89 'nopix'
90 ]
91
92 __operation_points_gsfInfo = [
93 'nogsf'
94 ]
95
96 # isolation cuts:w
97 __isolationCut = {
98 None: None,
99 'ivarloose': 0.15,
100 'ivarmedium': 0.065,
101 'ivartight': 0.06
102 }
103
104 # LRT d0 cuts
105 __lrtD0Cut = {
106 '': -1.,
107 None: None,
108 'lrtloose':2.0,
109 'lrtmedium':3.0,
110 'lrttight':5.,
111 'lrtxtight':10.0,
112 'lrtvxtight':20.0
113 }
114
115
116 def __init__(self, name, monGroups, cpart, tool=None):
117
118 from AthenaCommon.Logging import logging
119 self.__log = logging.getLogger('TrigEgammaPrecisionElectronHypoTool')
120 self.__name = name
121 self.__threshold = float(cpart['threshold'])
122 self.__sel = cpart['addInfo'][0] if cpart['addInfo'] else cpart['IDinfo']
123 self.__iso = cpart['isoInfo']
124 self.__d0 = cpart['lrtInfo']
125 self.__gsfInfo = cpart['gsfInfo']
126 self.__lhInfo = cpart['lhInfo']
127 self.__monGroups = monGroups
128
129 if not tool:
130 from AthenaConfiguration.ComponentFactory import CompFactory
131 tool = CompFactory.TrigEgammaPrecisionElectronHypoTool( name )
132
133 tool.EtaBins = [0.0, 0.6, 0.8, 1.15, 1.37, 1.52, 1.81, 2.01, 2.37, 2.47]
134 tool.ETthr = same( self.__threshold*GeV, tool )
135 tool.dETACLUSTERthr = 0.1
136 tool.dPHICLUSTERthr = 0.1
137 tool.RelPtConeCut = -999
138 tool.PidName = ""
139 tool.d0Cut = -1
140 tool.AcceptAll = False
141 tool.DoNoPid = False
142 tool.UseRelptvarcone30 = False
143 tool.UseTopoetcone20 = False
144 self.__tool = tool
145
146 self.__log.debug( 'Electron_Chain :%s', self.__name )
147 self.__log.debug( 'Electron_Threshold :%s', self.__threshold )
148 self.__log.debug( 'Electron_Pidname :%s', self.pidname() )
149 self.__log.debug( 'Electron_iso :%s', self.__iso )
150 self.__log.debug( 'Electron_d0 :%s', self.__d0 )
151
152 def chain(self):
153 return self.__name
154
155 #
156 # Get the pidname
157 #
158 def pidname( self ):
159 # if LLH, we should append the LH extra information if exist
160 pidname = self.__sel
161
162 extra = ""
163 if 'lh' in self.__sel and self.__gsfInfo and self.__gsfInfo in self.__operation_points_gsfInfo:
164 extra += '_' + self.__gsfInfo
165 if 'lh' in self.__sel and self.__lhInfo and self.__lhInfo in self.__operation_points_lhInfo:
166 extra += '_' + self.__lhInfo
167
168 return pidname+extra
169
170 def etthr(self):
171 return self.__threshold
172
173 def isoInfo(self):
174 return self.__iso
175
176 def d0Info(self):
177 return self.__d0
178
179 def gsfInfo(self):
180 return self.__gsfInfo
181
182 def tool(self):
183 return self.__tool
184
185 def nocut(self):
186
187 self.__log.debug( 'Configure nocut' )
188 self.tool().ETthr = same( self.etthr()*GeV, self.tool())
189 self.tool().dETACLUSTERthr = 9999.
190 self.tool().dPHICLUSTERthr = 9999.
191
192 def noPid(self):
193
194 self.tool().DoNoPid = True
195 self.__log.debug( 'Configure noPid' )
196 self.tool().ETthr = same( self.etthr()*GeV, self.tool())
197 # No other cuts applied
198 self.tool().dETACLUSTERthr = 9999.
199 self.tool().dPHICLUSTERthr = 9999.
200
201 #
202 # LRT extra cut
203 #
204 def addLRTCut(self):
205 if not self.d0Info() in self.__lrtD0Cut:
206 self.__log.fatal(f"Bad LRT selection name: {self.d0Info()}")
207 self.__tool.d0Cut = self.__lrtD0Cut[self.d0Info()]
208
209 def acceptAll(self):
210 self.tool().AcceptAll = True
211 #
212 # Isolation extra cut
213 #
214 def addIsoCut(self,flags):
215 # rely on flag rather than self.__isolationCut
216 valIsoCut = {None:None, 'ivarloose':flags.Trigger.egamma.isoWPs[0], 'ivarmedium':flags.Trigger.egamma.isoWPs[1], 'ivartight':flags.Trigger.egamma.isoWPs[2]}
217 topoIsoCut = {None:None, 'ivarloose':flags.Trigger.egamma.topoIsoWPs[0], 'ivarmedium':flags.Trigger.egamma.topoIsoWPs[1], 'ivartight':flags.Trigger.egamma.topoIsoWPs[2]}
218 if not self.isoInfo() in valIsoCut:
219 self.__log.fatal(f"Bad Iso selection name: {self.isoInfo()}")
220 self.tool().UseRelptvarcone30 = flags.Trigger.egamma.useRelptvarcone30
221 self.tool().RelPtConeCut = valIsoCut[self.isoInfo()]
222 self.tool().UseTopoetcone20 = flags.Trigger.egamma.useTopoetcone20
223 self.tool().TopoEtConeCut = topoIsoCut[self.isoInfo()]
224
225
226
227
228 def nominal(self):
229 if not self.pidname() in self.__operation_points:
230 self.__log.fatal("Bad selection name: %s" % self.pidname())
231 self.tool().PidName = self.pidname()
232
233
234 #
235 # Compile the chain
236 #
237 def compile(self, flags):
238
239 if 'nocut' == self.pidname():
240 self.nocut()
241 elif 'nopid' == self.pidname():
242 self.noPid()
243 else: # nominal chain using pid selection
244 self.nominal()
245
246
247 # secundary cut configurations
248 if self.isoInfo() and self.isoInfo()!="":
249 self.addIsoCut(flags)
250 if self.d0Info() and self.d0Info()!="":
251 self.addLRTCut()
252
253
254 if hasattr(self.tool(), "MonTool"):
255
256 doValidationMonitoring = flags.Trigger.doValidationMonitoring # True to monitor all chains for validation purposes
257 monGroups = self.__monGroups
258
259 if (any('egammaMon:online' in group for group in monGroups) or doValidationMonitoring):
260 self.addMonitoring(flags)
261
262
263 #
264 # Create the monitoring code
265 #
266 def addMonitoring(self, flags):
267
268 monTool = GenericMonitoringTool(flags, "MonTool_"+self.chain(),HistPath = 'PrecisionElectronHypo/'+self.chain())
269 monTool.defineHistogram('dEta', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo #Delta#eta_{EF L1}; #Delta#eta_{EF L1}", xbins=80, xmin=-0.01, xmax=0.01)
270 monTool.defineHistogram('dPhi', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo #Delta#phi_{EF L1}; #Delta#phi_{EF L1}", xbins=80, xmin=-0.01, xmax=0.01)
271 monTool.defineHistogram('Et_em', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo cluster E_{T}^{EM};E_{T}^{EM} [MeV]", xbins=50, xmin=-2000, xmax=100000)
272 monTool.defineHistogram('Eta', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo entries per Eta;Eta", xbins=100, xmin=-2.5, xmax=2.5)
273 monTool.defineHistogram('Phi', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo entries per Phi;Phi", xbins=128, xmin=-3.2, xmax=3.2)
274 monTool.defineHistogram('EtaBin', type='TH1I', path='EXPERT', title="PrecisionElectron Hypo entries per Eta bin;Eta bin no.", xbins=11, xmin=-0.5, xmax=10.5)
275 monTool.defineHistogram('LikelihoodRatio', type='TH1F', path='EXPERT', title="PrecisionElectron Hypo LH", xbins=100, xmin=-5, xmax=5)
276 monTool.defineHistogram('mu', type='TH1F', path='EXPERT', title="Average interaction per crossing", xbins=100, xmin=0, xmax=100)
277 monTool.defineHistogram('relptvarcone20',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo; ptvarcone20/pt;", xbins=50, xmin=0, xmax=2)
278 monTool.defineHistogram('relptvarcone30',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo; ptvarcone30/pt;", xbins=50, xmin=0, xmax=2)
279 monTool.defineHistogram('ptvarcone20',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo ptvarcone20; ptvarcone20;", xbins=50, xmin=0, xmax=5.0)
280 monTool.defineHistogram('ptvarcone30',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo ptvarcone30; ptvarcone30;", xbins=50, xmin=0, xmax=5.0)
281
282
283 cuts=['Input','#Delta #eta EF-L1', '#Delta #phi EF-L1','eta','E_{T}^{EM}','LH','Isolation']
284 monTool.defineHistogram('CutCounter', type='TH1I', path='EXPERT', title="PrecisionElectron Hypo Cut Counter;Cut Counter", xbins=7, xmin=0, xmax=7, opt="kCumulative",xlabels=cuts)
285
286
287
288 if flags.Trigger.doValidationMonitoring:
289 monTool.defineHistogram('relptcone20',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo; ptcone20/pt;", xbins=50, xmin=0, xmax=2)
290 monTool.defineHistogram('relptcone30',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo; ptcone30/pt;", xbins=50, xmin=0, xmax=2)
291 monTool.defineHistogram('ptcone20',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo ptcone20; ptcone20;", xbins=50, xmin=0, xmax=5.0)
292 monTool.defineHistogram('ptcone30',type='TH1F',path='EXPERT',title= "PrecisionElectron Hypo ptcone30; ptcone30;", xbins=50, xmin=0, xmax=5.0)
293 monTool.defineHistogram('trk_d0', type="TH1F", path='EXPERT', title="PrecisionElectron Hypo Track d0; d0 [mm]", xbins=100, xmin=-1, xmax=1)
294
295 self.tool().MonTool = monTool
296
297
298def _IncTool(flags, name, monGroups, cpart, tool=None):
299 config = TrigEgammaPrecisionElectronHypoToolConfig(name, monGroups, cpart, tool=tool)
300 config.compile(flags)
301 return config.tool()
302
303
304
306 """ Use menu decoded chain dictionary to configure the tool """
307 cparts = [i for i in d['chainParts'] if ((i['signature']=='Electron') or (i['signature']=='Electron'))]
308 return _IncTool( flags, d['chainName'], d['monGroups'], cparts[0] , tool=tool )
309
310
311
312
313#
314# Electron DNN Selectors
315#
316def TrigEgammaPrecisionElectronDNNSelectorCfg(flags, name='TrigEgammaPrecisionElectronDNNSelector', ConfigFilePath=None):
317 acc = ComponentAccumulator()
318 # We should include the DNN here
319 if not ConfigFilePath:
320 ConfigFilePath = flags.Trigger.egamma.dnnVersion
321
322 SelectorNames = {
323 'dnntight' :'AsgElectronDNNTightSelector',
324 'dnnmedium' :'AsgElectronDNNMediumSelector',
325 'dnnloose' :'AsgElectronDNNLooseSelector',
326 }
327
328 ElectronToolConfigFile = {
329 'dnntight' :'ElectronDNNMulticlassTight.conf',
330 'dnnmedium' :'ElectronDNNMulticlassMedium.conf',
331 'dnnloose' :'ElectronDNNMulticlassLoose.conf',
332 }
333
334 for dnnname, name in SelectorNames.items():
335 SelectorTool = CompFactory.AsgElectronSelectorTool(name)
336 SelectorTool.ConfigFile = ConfigFilePath + '/' + ElectronToolConfigFile[dnnname]
337 SelectorTool.skipDeltaPoverP = True
338 acc.addPublicTool(SelectorTool)
339
340 return acc
341
342#
343# Electron LH Selectors
344#
345def TrigEgammaPrecisionElectronLHSelectorCfg(flags, name='TrigEgammaPrecisionElectronLHSelector', ConfigFilePath=None, ConfigFileNoPixPath=None, ConfigFileNoGSFPath=None, ConfigFileNoGSFNoPixPath=None):
346
347 # Configure the LH selectors
348 acc = ComponentAccumulator()
349
350 # Must be careful that order matches LHNames at the start of the file!
351 SelectorConfigFiles = {
352 'lhtight' : 'ElectronLikelihoodTightTriggerConfig',
353 'lhmedium' : 'ElectronLikelihoodMediumTriggerConfig',
354 'lhloose' : 'ElectronLikelihoodLooseTriggerConfig',
355 'lhvloose' : 'ElectronLikelihoodVeryLooseTriggerConfig'
356 }
357
358 VariationConfigInfos = {
359 '_default' : {},
360 '_nopix' : {},
361 '_nogsf' : {},
362 '_nogsf_nopix' : {}
363 }
364
365 VariationConfigInfos['_default']['postfix'] = ''
366 VariationConfigInfos['_nopix']['postfix'] = '_NoPix'
367 VariationConfigInfos['_nogsf']['postfix'] = ''
368 VariationConfigInfos['_nogsf_nopix']['postfix'] = '_NoPix'
369
370 VariationConfigInfos['_default']['path'] = ConfigFilePath if ConfigFilePath else flags.Trigger.egamma.electronPidVersion
371 VariationConfigInfos['_nopix']['path'] = ConfigFileNoPixPath if ConfigFileNoPixPath else flags.Trigger.egamma.electronNoPixPidVersion
372 VariationConfigInfos['_nogsf']['path'] = ConfigFileNoGSFPath if ConfigFileNoGSFPath else flags.Trigger.egamma.electronNoGSFPidVersion
373 VariationConfigInfos['_nogsf_nopix']['path'] = ConfigFileNoGSFNoPixPath if ConfigFileNoGSFNoPixPath else flags.Trigger.egamma.electronNoGSFNoPixPidVersion
374
375 from AthenaCommon.Logging import logging
376 log = logging.getLogger('TrigEgammaPrecisionElectronHypoTool')
377 log.debug( 'TrigEgammaPrecisionElectronLHSelectorCfg, order of LH tools:' )
378
379 for pidvar, config in VariationConfigInfos.items():
380 for pidname, configfilebase in SelectorConfigFiles.items():
381 fullpidname = pidname if pidvar == '_default' else pidname + pidvar
382 toolname = 'AsgElectronSelector_' + fullpidname
383 configfile = config['path'] + '/' + configfilebase + config['postfix'] + '.conf'
384 skipdeltapcheck = True if 'nogsf' in pidvar else False
385
386 log.debug( ' --> %s, config file: %s', fullpidname, configfile )
387
388 SelectorTool = CompFactory.AsgElectronLikelihoodTool(toolname)
389 SelectorTool.ConfigFile = configfile
390 SelectorTool.usePVContainer = False
391 SelectorTool.skipDeltaPoverP = skipdeltapcheck
392 acc.addPublicTool(SelectorTool)
393
394 return acc
395
396
397#
398# Electron CB Selectors
399#
400
401def TrigEgammaPrecisionElectronCBSelectorCfg(flags, name='TrigEgammaPrecisionElectronCBSelector', ConfigFilePath=None):
402 acc = ComponentAccumulator()
403 from ElectronPhotonSelectorTools.TrigEGammaPIDdefs import BitDefElectron
404 from ROOT import egammaPID
405
406 ElectronLooseHI = (0
407 | 1 << BitDefElectron.ClusterEtaRange_Electron
408 | 1 << BitDefElectron.ClusterHadronicLeakage_Electron
409 | 1 << BitDefElectron.ClusterMiddleEnergy_Electron
410 | 1 << BitDefElectron.ClusterMiddleEratio37_Electron
411 | 1 << BitDefElectron.ClusterMiddleWidth_Electron
412 | 1 << BitDefElectron.ClusterStripsWtot_Electron
413 )
414
415 ElectronMediumHI = (ElectronLooseHI
416 | 1 << BitDefElectron.ClusterMiddleEratio33_Electron
417 | 1 << BitDefElectron.ClusterBackEnergyFraction_Electron
418 | 1 << BitDefElectron.ClusterStripsEratio_Electron
419 | 1 << BitDefElectron.ClusterStripsDeltaEmax2_Electron
420 | 1 << BitDefElectron.ClusterStripsDeltaE_Electron
421 | 1 << BitDefElectron.ClusterStripsFracm_Electron
422 | 1 << BitDefElectron.ClusterStripsWeta1c_Electron
423 )
424
425 if not ConfigFilePath:
426 ConfigFilePath = flags.Trigger.egamma.electronHIPidVersion
427
428 SelectorNames = {
429 'medium': 'AsgElectronIsEMSelectorHIMedium',
430 'loose': 'AsgElectronIsEMSelectorHILoose',
431 'mergedtight' : 'AsgElectronIsEMSelectorMergedTight',
432 }
433
434 ElectronToolConfigFile = {
435 'medium': 'ElectronIsEMMediumSelectorCutDefs.conf',
436 'loose': 'ElectronIsEMLooseSelectorCutDefs.conf',
437 'mergedtight' : 'ElectronIsEMMergedTightSelectorCutDefs.conf',
438 }
439
440 ElectronMaskBits = {
441 'medium': ElectronMediumHI,
442 'loose': ElectronLooseHI,
443 'mergedtight' : egammaPID.ElectronTightHLT,
444 }
445
446 for sel, name in SelectorNames.items():
447 SelectorTool = CompFactory.AsgElectronIsEMSelector(name)
448 SelectorTool.ConfigFile = ConfigFilePath + '/' + ElectronToolConfigFile[sel]
449 SelectorTool.isEMMask = ElectronMaskBits[sel]
450 acc.addPublicTool(SelectorTool)
451
452 return acc
const bool debug
TrigEgammaPrecisionElectronCBSelectorCfg(flags, name='TrigEgammaPrecisionElectronCBSelector', ConfigFilePath=None)
TrigEgammaPrecisionElectronHypoAlgCfg(flags, name, inputElectronCollection)
TrigEgammaPrecisionElectronLHSelectorCfg(flags, name='TrigEgammaPrecisionElectronLHSelector', ConfigFilePath=None, ConfigFileNoPixPath=None, ConfigFileNoGSFPath=None, ConfigFileNoGSFNoPixPath=None)
TrigEgammaPrecisionElectronDNNSelectorCfg(flags, name='TrigEgammaPrecisionElectronDNNSelector', ConfigFilePath=None)