ATLAS Offline Software
Loading...
Searching...
No Matches
TrigTauHypoTool.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3from typing import Any
4
5from AthenaCommon.SystemOfUnits import GeV
6from AthenaConfiguration.AthConfigFlags import AthConfigFlags
7
8from TriggerMenuMT.HLT.Tau.TauConfigurationTools import getChainIDConfigName
9from .TrigTauHypoMonitoring import (
10 getTrigTauPrecisionIDHypoToolMonitoring, getTrigTauPrecisionDiKaonHypoToolMonitoring,
11 getTrigTauCaloHitsIDHypoToolMonitoring
12)
13
14from AthenaCommon.Logging import logging
15log = logging.getLogger('TrigHLTTauHypoTool')
16
17
18#============================================================================================
19# Precision step hypothesis tool
20#============================================================================================
21def TrigTauPrecisionHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
22 chainPart = chainDict['chainParts'][0]
23
24 identification = getChainIDConfigName(flags, chainPart)
25
26 if identification == 'MesonCuts':
27 # Meson cut-based triggers (ATR-22644)
28 return TrigTauPrecisionDiKaonHypoToolFromDict(flags, chainDict)
29 else:
30 # Everything else
31 return TrigTauPrecisionIDHypoToolFromDict(flags, chainDict)
32
33
34#-----------------------------------------------------------------
35# Standard tau triggers configuration
36#-----------------------------------------------------------------
37class TauCuts:
38 def __init__(self, flags, chain_part: dict[str, Any]):
39 self._id = getChainIDConfigName(flags, chain_part)
40 self._chain_part = chain_part
41
42 self._id_wp = ''
43 self._highpt_id_wp = ''
44 self._do_perfcore = True
45 self._do_perfiso = True
46
47 self._use_rnn_selection = False
48
49 if self._id in ['idperf', 'noperf', 'perfcore', 'perfiso', 'perf']:
50 self._do_perfcore = self._id in ['perfcore', 'perf']
51 self._do_perfiso = self._id in ['perfiso', 'perf']
52
53 else:
54 if self._id in ['DeepSet', 'RNNLLP'] and self._chain_part['selection'].endswith('RNN'):
55 # Support for the legacy triggers
56 self._use_rnn_selection = True
57 self._id_wp = self._chain_part['selection'][:-3] # Remove the "RNN" suffix
58 if self._id_wp in ['medium', 'tight']: self._highpt_id_wp = 'loose'
59
60 else:
61 id_wp = self._chain_part['selection'].removesuffix(self._id).lower()
62
63 # Check for a perf selection specifier
64 if id_wp.endswith('noperf'):
65 id_wp = id_wp.removesuffix('noperf')
66 self._do_perfcore = self._do_perfiso = False
67 elif id_wp.endswith('perfcore'):
68 id_wp = id_wp.removesuffix('perfcore')
69 self._do_perfiso = False
70 elif id_wp.endswith('perfiso'):
71 id_wp = id_wp.removesuffix('perfiso')
72 self._do_perfcore = False
73
74 # Find the matching WP with the correct casing
75 def find_wp(wp: str, fail: bool = True) -> str:
76 for twp in getattr(flags.Trigger.Offline.Tau, self._id).TargetWPs.keys():
77 if twp.lower() == wp: return twp
78 else:
79 if fail: ValueError(f'Cannot find the "{self._id}" WP "{wp}"')
80 else: return ''
81
82 # Standard ID WP
83 self._id_wp = find_wp(id_wp)
84
85 # High-pT ID WP
86 if id_wp.startswith('medium'): self._highpt_id_wp = find_wp(f'loose{id_wp[6:]}', True)
87 elif id_wp.startswith('tight'): self._highpt_id_wp = find_wp(f'loose{id_wp[5:]}', True)
88
89 @property
90 def n_track_max(self) -> int:
91 return 3 if self._do_perfcore else 999
92
93 @property
94 def n_iso_track_max(self) -> int:
95 return 1 if self._do_perfiso else 999
96
97 @property
98 def pt_min(self) -> float: return float(self._chain_part['threshold']) * GeV
99
100 @property
101 def id_wp_decor(self) -> str:
102 if not self._id_wp: return ''
103 if self._use_rnn_selection: return self._id_wp
104 return f'{self._id}_{self._id_wp}'
105
106 @property
107 def highpt_id_wp_decor(self) -> int:
108 if not self._highpt_id_wp: return ''
109 if self._use_rnn_selection: return self._highpt_id_wp
110 return f'{self._id}_{self._highpt_id_wp}'
111
112
113def TrigTauPrecisionIDHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
114 '''TrigTauPrecisionIDHypoTool configuration for the standard Tau triggers'''
115 name = chainDict['chainName']
116 chainPart = chainDict['chainParts'][0]
117 cuts = TauCuts(flags, chainPart)
118
119 # Setup the Hypothesis tool
120 from AthenaConfiguration.ComponentFactory import CompFactory
121 currentHypo = CompFactory.TrigTauPrecisionIDHypoTool(
122 name,
123 PtMin=cuts.pt_min,
124 NTracksMax=cuts.n_track_max,
125 NIsoTracksMax=cuts.n_iso_track_max,
126 IDWP=cuts.id_wp_decor,
127 HighPtIDWP=cuts.highpt_id_wp_decor,
128 )
129
130 from TriggerMenuMT.HLT.Tau.TauConfigurationTools import getChainPrecisionSeqName, useBuiltInTauJetRNNScore, getPrecisionSequenceTauIDs, getTauIDScoreVariables
131
132 id_score_monitoring = {}
133
134 precision_seq_name = getChainPrecisionSeqName(chainPart)
135 identification = getChainIDConfigName(flags, chainPart)
136 if identification in ['idperf', 'noperf', 'perf', 'perfcore', 'perfiso']:
137 if identification == 'idperf':
138 # Disable everything, even the pT cut
139 currentHypo.AcceptAll = True
140
141 # Monitor all the included algorithms
142 used_builtin_rnnscore = False
143 for tau_id in getPrecisionSequenceTauIDs(flags, precision_seq_name):
144 # Skip algs without inference scores
145 if tau_id in ['MesonCuts']: continue
146
147 # We can only have at most one alg. using the built-in TauJet RNN score variables
148 if useBuiltInTauJetRNNScore(tau_id):
149 if used_builtin_rnnscore:
150 raise ValueError('Cannot have two TauID algorithms with scores stored in the built-in TauJet RNN score variables')
151 used_builtin_rnnscore = True
152
153 id_score_monitoring[tau_id] = getTauIDScoreVariables(tau_id)
154
155 else:
156 if useBuiltInTauJetRNNScore(identification):
157 # To support the legacy tracktwoMVA/LLP/LRT chains, only in those cases we store the
158 # ID score and passed WPs in the native TauJet variables
159 currentHypo.IDMethod = 1 # TauJet built-in RNN score
160 else:
161 # Decorator-based triggers
162 currentHypo.IDMethod = 2 # Use decorators
163
164 # Monitor this algorithm only
165 id_score_monitoring[identification] = getTauIDScoreVariables(identification)
166
167 # For any triggers following the tracktwoMVA reconstruction (2023+ DeepSet and GNTau)
168 if chainPart['reconstruction'] == 'tracktwoMVA':
169 currentHypo.TrackPtCut = 1.5*GeV
170 currentHypo.HighPtSelectionIDThr = 200*GeV
171 currentHypo.HighPtSelectionJetThr = 430*GeV
172
173 # Only monitor chains with the 'tauMon:online' groups
174 if 'tauMon:online' in chainDict['monGroups']:
175 currentHypo.MonTool = getTrigTauPrecisionIDHypoToolMonitoring(flags, name, id_score_monitoring.keys())
176
177 # TauID Score monitoring
178 currentHypo.MonitoredIDScores = id_score_monitoring
179
180 return currentHypo
181
182
183#-----------------------------------------------------------------
184# Meson cut-based triggers configuration (ATR-22644 + ATR-23239)
185#-----------------------------------------------------------------
186from collections import namedtuple
187
188DiKaonCuts = namedtuple('DiKaonCuts', 'massTrkSysMin massTrkSysMax massTrkSysKaonMin massTrkSysKaonMax massTrkSysKaonPiMin massTrkSysKaonPiMax targetMassTrkSysKaonPi leadTrkPtMin PtMin EMPOverTrkSysPMax')
189thresholds_dikaon = {
190 ('dikaonmass', 25): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.987*GeV, 1.060*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 15.0*GeV, 25.0*GeV, 1.5),
191 ('dikaonmass', 35): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.987*GeV, 1.060*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 25.0*GeV, 35.0*GeV, 1.5),
192
193 ('kaonpi1', 25): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.79*GeV, 0.99*GeV, 0.89*GeV, 15.0*GeV, 25.0*GeV, 1.0),
194 ('kaonpi1', 35): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.79*GeV, 0.99*GeV, 0.89*GeV, 25.0*GeV, 35.0*GeV, 1.0),
195
196 ('kaonpi2', 25): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 1.8*GeV, 1.93*GeV, 1.865*GeV, 15.0*GeV, 25.0*GeV, 1.0),
197 ('kaonpi2', 35): DiKaonCuts(0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 1.8*GeV, 1.93*GeV, 1.865*GeV, 25.0*GeV, 35.0*GeV, 1.0),
198
199 ('dipion1', 25): DiKaonCuts(0.475*GeV, 1.075*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 15.0*GeV, 25.0*GeV, 1.0),
200 ('dipion2', 25): DiKaonCuts(0.460*GeV, 0.538*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 15.0*GeV, 25.0*GeV, 1.0),
201 ('dipion3', 25): DiKaonCuts(0.279*GeV, 0.648*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 25.0*GeV, 25.0*GeV, 2.2),
202 ('dipion4', 25): DiKaonCuts(0.460*GeV, 1.075*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 1000.0*GeV, 0.0*GeV, 15.0*GeV, 25.0*GeV, 1.0),
203}
204
205SinglePionCuts = namedtuple('SinglePionCuts', 'leadTrkPtMin PtMin NTracksMax NIsoTracksMax dRmaxMax etOverPtLeadTrkMin etOverPtLeadTrkMax')
206thresholds_singlepion = {
207 ('singlepion', 25): SinglePionCuts(30.0*GeV, 25.0*GeV, 1, 0, 0.06, 0.4, 0.85),
208}
209
210def TrigTauPrecisionDiKaonHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
211 '''TrigTauPrecisionDiKaonHypoTool configuration for the meson cut-based Tau triggers (ATR-22644)'''
212 name = chainDict['chainName']
213 chainPart = chainDict['chainParts'][0]
214
215 # Setup the Hypothesis tool
216 from AthenaConfiguration.ComponentFactory import CompFactory
217 currentHypo = CompFactory.TrigTauPrecisionDiKaonHypoTool(name)
218
219 key = (chainPart['selection'], int(chainPart['threshold']))
220 if key in thresholds_dikaon:
221 thr = thresholds_dikaon[key]
222 currentHypo.PtMin = thr.PtMin
223 currentHypo.leadTrkPtMin = thr.leadTrkPtMin
224 currentHypo.massTrkSysMin = thr.massTrkSysMin
225 currentHypo.massTrkSysMax = thr.massTrkSysMax
226 currentHypo.massTrkSysKaonMin = thr.massTrkSysKaonMin
227 currentHypo.massTrkSysKaonMax = thr.massTrkSysKaonMax
228 currentHypo.massTrkSysKaonPiMin = thr.massTrkSysKaonPiMin
229 currentHypo.massTrkSysKaonPiMax = thr.massTrkSysKaonPiMax
230 currentHypo.targetMassTrkSysKaonPi = thr.targetMassTrkSysKaonPi
231 currentHypo.EMPOverTrkSysPMax = thr.EMPOverTrkSysPMax
232
233 elif key in thresholds_singlepion:
234 thr = thresholds_singlepion[key]
235 currentHypo.PtMin = thr.PtMin
236 currentHypo.NTracksMax = thr.NTracksMax
237 currentHypo.NIsoTracksMax = thr.NIsoTracksMax
238 currentHypo.leadTrkPtMin = thr.leadTrkPtMin
239 currentHypo.dRmaxMax = thr.dRmaxMax
240 currentHypo.etOverPtLeadTrkMin = thr.etOverPtLeadTrkMin
241 currentHypo.etOverPtLeadTrkMax = thr.etOverPtLeadTrkMax
242
243 currentHypo.MonTool = getTrigTauPrecisionDiKaonHypoToolMonitoring(flags, name)
244
245 return currentHypo
246
247
248
249#============================================================================================
250# Tracking step hypothesis tool (without selection)
251#============================================================================================
252def TrigTauTrackingHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
253 name = chainDict['chainName']
254
255 from AthenaConfiguration.ComponentFactory import CompFactory
256 currentHypo = CompFactory.TrigTauTrackingHypoTool(name)
257
258 return currentHypo
259
260
261
262#============================================================================================
263# CaloHits step hypothesis tool
264#============================================================================================
265def TrigTauCaloHitsHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
266 name = chainDict['chainName']
267 chain_part = chainDict['chainParts'][0]
268
269 # Setup the Hypothesis tool
270 from AthenaConfiguration.ComponentFactory import CompFactory
271 currentHypo = CompFactory.TrigTauPrecisionIDHypoTool(
272 name,
273 HighPtSelectionIDThr=200*GeV,
274 HighPtSelectionJetThr=430*GeV,
275 )
276
277 id_score_monitoring = {}
278
279 from TriggerMenuMT.HLT.Tau.TauConfigurationTools import getChainCaloHitsPreselConfigName, getTauIDScoreVariables
280 id = getChainCaloHitsPreselConfigName(flags, chain_part)
281 if id == 'idperf':
282 currentHypo.AcceptAll = True
283
284 # Monitor all the included algorithms
285 from TriggerMenuMT.HLT.Tau.TauConfigurationTools import getChainPrecisionSeqName, getCaloHitsPreselAlgs
286 algs = getCaloHitsPreselAlgs(flags, getChainPrecisionSeqName(chain_part, True), getChainPrecisionSeqName(chain_part))
287 if algs:
288 for tau_id in algs:
289 id_score_monitoring[tau_id] = getTauIDScoreVariables(tau_id)
290
291 else:
292 currentHypo.IDMethod = 2 # Use decorators
293
294 id_wp = chain_part['calohitsPresel'].removesuffix(id).lower()
295
296 # Find the matching WP with the correct casing
297 def find_wp(wp: str, fail: bool = True) -> str:
298 for twp in getattr(flags.Trigger.Offline.Tau, id).TargetWPs.keys():
299 if twp.lower() == wp: return twp
300 else:
301 if fail: ValueError(f'Cannot find the "{id}" WP "{wp}"')
302 else: return ''
303
304 # Standard preselection WP
305 currentHypo.IDWP = find_wp(id_wp)
306
307 # High-pT ID WP
308 if id_wp.startswith('medium'): currentHypo.HighPtIDWP = find_wp(f'loose{id_wp[6:]}', True)
309 elif id_wp.startswith('tight'): currentHypo.HighPtIDWP = find_wp(f'loose{id_wp[5:]}', True)
310
311 # Monitor this algorithm only
312 id_score_monitoring[id] = getTauIDScoreVariables(id)
313
314 # Only monitor chains with the 'tauMon:online' groups
315 if 'tauMon:online' in chainDict['monGroups']:
316 currentHypo.MonTool = getTrigTauCaloHitsIDHypoToolMonitoring(flags, name, id_score_monitoring.keys())
317
318 # TauID Score monitoring
319 currentHypo.MonitoredIDScores = id_score_monitoring
320
321 return currentHypo
322
323
324
325#============================================================================================
326# CaloMVA step hypothesis tool
327#============================================================================================
328def TrigTauCaloMVAHypoToolFromDict(flags: AthConfigFlags, chainDict: dict[str, Any]):
329 name = chainDict['chainName']
330 threshold = float(chainDict['chainParts'][0]['threshold'])
331
332 from AthenaConfiguration.ComponentFactory import CompFactory
333 currentHypo = CompFactory.TrigTauCaloHypoTool(name)
334 currentHypo.PtMin = threshold * GeV
335
336 return currentHypo
337
__init__(self, flags, dict[str, Any] chain_part)
TrigTauTrackingHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)
TrigTauPrecisionIDHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)
TrigTauCaloMVAHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)
TrigTauCaloHitsHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)
TrigTauPrecisionDiKaonHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)
TrigTauPrecisionHypoToolFromDict(AthConfigFlags flags, dict[str, Any] chainDict)