ATLAS Offline Software
ComboHypoHandling.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
2 
3 
6 
7 from AthenaCommon.Logging import logging
8 log = logging.getLogger(__name__)
9 logging.getLogger().info("Importing %s",__name__)
10 import math
11 import re
12 from TrigConfHLTUtils.HLTUtils import string2hash
13 from AthenaConfiguration.ComponentFactory import CompFactory
14 
15 topoLegIndices = "ABCDEF"
16 
17 #the list of the variables reported below must match the one specified
18 # here: Trigger/TrigHypothesis/TrigHypoCommonTools/src/TrigComboHypoTool.cxx::fillVarMap()
19 # (and accordingly the list of the enums comboHypoVars in the header file)
20 allowed_obs = {
21  'dR' : {
22  'n_MET_legs' : [0],
23  'hist_nbins' : 50,
24  'hist_min' : 0.,
25  'hist_max' : 5.
26  },
27  'invm' : {
28  'n_MET_legs' : [0],
29  'hist_nbins' : 100,
30  'hist_min' : 0.,
31  'hist_max' : 1000.
32  },
33  'dphi' : {
34  'n_MET_legs' : [0,1,2],
35  'hist_nbins' : 40,
36  'hist_min' : 0.,
37  'hist_max' : math.pi
38  },
39  'deta' : {
40  'n_MET_legs' : [0,1,2],
41  'hist_nbins' : 50,
42  'hist_min' : 0.,
43  'hist_max' : 10.
44  },
45  'mT' : {
46  'n_MET_legs' : [1],
47  'hist_nbins' : 100,
48  'hist_min' : 0.,
49  'hist_max' : 1000.
50  }
51 }
52 
53 from TriggerMenuMT.HLT.MinBias.AFPMenuSequence import TrigAFPDijetComboHypoToolCfg
54 from TriggerMenuMT.HLT.Muon.MuonChainConfiguration import TrigMuonEFIdtpInvMassHypoToolCfg
55 
56 def TrigComboHypoToolFromDict(flags, chainDict):
57  from AthenaMonitoringKernel.GenericMonitoringTool import GenericMonitoringTool
58 
59  chainName = chainDict['chainName']
60  log.debug("[TrigComboHypoToolFromDict] chain %s, combo hypos to be processed: %s, t", chainName, chainDict['extraComboHypos'])
61  #define the list for housing all the info needed to initialize the TrigComboHypoTool module in the form of a dict
62  topoDefs = []
63 
64  # Define regex for parsing the topoInfo
65  # Pattern is: min cut, var, legA, legB, max cut
66  # Min and max are both optional, check afterwards that at least one is filled
67  # Only the allowed vars and legs will be recognised, anything else fails to match
68  theregex = fr"(\d*)({'|'.join(allowed_obs.keys())})([{topoLegIndices}])([{topoLegIndices}])(\d*)"
69  matcher = re.compile(theregex)
70 
71  for iTopo, topoInfo in enumerate(chainDict['extraComboHypos']):
72  log.debug("[TrigComboHypoToolFromDict] new combo hypo for chain: %s, topoInfo = %s", chainName, topoInfo)
73  # Attempt to regex-match the topo specification
74  result = matcher.match(topoInfo)
75  if not result:
76  log.error("[TrigComboHypoToolFromDict] Topo expression %s does not conform to format (min?)(var)(legA)(legB)(max?).",topoInfo)
77  log.error("[TrigComboHypoToolFromDict] Must use leg IDs in %s, vars in {allowed_obs.keys()}",topoLegIndices)
78  raise ValueError(f"[TrigComboHypoToolFromDict] Invalid topo expression {topoInfo} received in 'extraComboHypos'!")
79 
80  # Extract the matched info and validate
81  str_min, var, char_legA, char_legB, str_max = result.groups()
82  # Manipulation of the cuts
83  # At least one must be filled
84  use_min = bool(str_min)
85  use_max = bool(str_max)
86  if not (use_min or use_max):
87  log.error("[TrigComboHypoToolFromDict] Topo expression %s does not specify a min or max cut value.",topoInfo)
88  raise ValueError(f"[TrigComboHypoToolFromDict] Invalid topo expression {topoInfo} received in 'extraComboHypos'!")
89  # Convert into float values, dividing for 0.1 precision as needed
90  if var in ['dR','dphi','deta']:
91  cut_min = float(str_min)/10. if use_min else float('nan')
92  cut_max = float(str_max)/10. if use_max else float('nan')
93  else:
94  cut_min = float(str_min) if use_min else float('nan')
95  cut_max = float(str_max) if use_max else float('nan')
96 
97  # Convert char leg representation to int
98  i_legA = topoLegIndices.find(char_legA)
99  i_legB = topoLegIndices.find(char_legB)
100 
101  # Fill info for each leg, looking up in chainParts
102  # Convert leg name into HLT identifier for matching in the tool
103  legInfo = []
104  for ileg in [i_legA,i_legB]:
105  cpart = chainDict['chainParts'][ileg]
106  legname = f"leg{ileg:03d}_{chainName}"
107  legInfo.append({
108  'index' : ileg,
109  'legname' : legname,
110  'HLTId' : string2hash(legname),
111  'isMET' : cpart['signature']=='MET',
112  'multiplicity': int(cpart['multiplicity'])
113  })
114 
115  # Count how many input legs are MET, for consistency checks
116  n_MET_legs = legInfo[0]['isMET'] + legInfo[1]['isMET']
117 
118  # Check multiplicity of the configured legs
119  # For chains like "HLT_2muX_10invm70AA", no leg ID will be attached
120  # in which case set a flag to use all objects in the combination list
121  skipLegCheck = False
122  if i_legA==i_legB:
123  if legInfo[0]['multiplicity'] != 2:
124  log.error("[TrigComboHypoToolFromDict] Error configuring topo for chain %s!",chainName)
125  log.error("[TrigComboHypoToolFromDict] Topo selection %s requires multiplicity 2 on leg %d, found %d!",topoInfo,i_legA,legInfo[0]['multiplicity'])
126  raise Exception("[TrigComboHypoToolFromDict] Invalid multiplicity")
127  if n_MET_legs==2:
128  log.error("[TrigComboHypoToolFromDict] Configured with the same MET leg on both sides -- impossible to satisfy!")
129  raise Exception("[TrigComboHypoToolFromDict] Identical MET legs for topo selection")
130  if len(chainDict['chainParts'])==1:
131  skipLegCheck=True
132  else:
133  for li in legInfo:
134  if li['multiplicity'] != 1:
135  log.error("[TrigComboHypoToolFromDict] Error configuring topo for chain %s!",chainName)
136  log.error("[TrigComboHypoToolFromDict] Topo selection %s requires multiplicity 1 on leg %d, found %d!",topoInfo,li['index'],li['multiplicity'])
137  raise Exception("[TrigComboHypoToolFromDict] Invalid multiplicity")
138 
139  #now check that the variable we plan to use allows the use of the MET
140  if n_MET_legs not in allowed_obs[var]['n_MET_legs']:
141  log.error("[TrigComboHypoToolFromDict] Attempting var %s with %d MET legs, %s allowed", var, n_MET_legs, allowed_obs[var]['n_MET_legs'])
142  raise Exception("[TrigComboHypoToolFromDict] Attempting to use the MET leg in var")
143 
144  if len(chainDict['extraComboHypos'])==1:#to avoid breaking changes in the ref files
145  monToolName = "MonTool_"+chainName
146  else:
147  monToolName = f"MonTool_{chainName}_{chainDict['extraComboHypos'][iTopo]}"
148  histNameTag = var
149  monTool = GenericMonitoringTool(flags, monToolName)
150  monTool.defineHistogram(histNameTag+'OfAccepted', type='TH1F', path='EXPERT',
151  title=var+" in accepted combinations; {}".format(var),
152  xbins=allowed_obs[var]['hist_nbins'],
153  xmin=allowed_obs[var]['hist_min'],
154  xmax=allowed_obs[var]['hist_max'])
155  monTool.defineHistogram(histNameTag+'OfProcessed', type='TH1F', path='EXPERT',
156  title=var+" in processed combinations; {}".format(var),
157  xbins=allowed_obs[var]['hist_nbins'],
158  xmin=allowed_obs[var]['hist_min'],
159  xmax=allowed_obs[var]['hist_max'])
160  log.debug("[TrigComboHypoToolFromDict] tool configured for hypo name: %s, topoInfo = %s", chainName, topoInfo)
161  log.debug("[TrigComboHypoToolFromDict] histName = %s", histNameTag)
162 
163  if len(chainDict['extraComboHypos'])==1:#to avoid breaking changes in the ref files
164  monTool.HistPath = f'ComboHypo/{chainName}'
165  else:
166  subDirNameTag = f"{var}leg{i_legA:03d}leg{i_legB:03d}"
167  monTool.HistPath = f'ComboHypo/{chainName}/detail_{subDirNameTag}'
168 
169  # Set keys of dict to match tool config properties
170  singleTopoDef = {
171  "Variables" : var,
172  "UseMinVec" : use_min,
173  "UseMaxVec" : use_max,
174  "LowerCutVec" : cut_min,
175  "UpperCutVec" : cut_max,
176  "LegAVec" : legInfo[0]["HLTId"],
177  "LegBVec" : legInfo[1]["HLTId"],
178  "IsLegA_METVec": legInfo[0]["isMET"],
179  "IsLegB_METVec": legInfo[1]["isMET"],
180  "MonTools" : monTool,
181  }
182  topoDefs.append(singleTopoDef)
183 
184  #some debug info
185  log.debug("[TrigComboHypoToolFromDict] tool configured for hypo name: %s, topoInfo = %s", chainName, topoInfo)
186  log.debug("[TrigComboHypoToolFromDict] var = %s", singleTopoDef['Variables'])
187  log.debug("[TrigComboHypoToolFromDict] legA = %s", singleTopoDef['LegAVec'])
188  log.debug("[TrigComboHypoToolFromDict] legB = %s", singleTopoDef['LegBVec'])
189  if use_min:
190  log.debug("[TrigComboHypoToolFromDict] min = %10.3f", singleTopoDef['LowerCutVec'])
191  if use_max:
192  log.debug("[TrigComboHypoToolFromDict] max = %10.3f", singleTopoDef['UpperCutVec'])
193 
194  #end of the loop over the hypos
195 
196  # convert list of dicts into dict of lists
197  toolProps = {k:[thedef[k] for thedef in topoDefs] for k in topoDefs[0]}
198  tool = CompFactory.TrigComboHypoTool(chainName, SkipLegCheck=skipLegCheck, **toolProps)
199 
200  return tool
201 
202 comboConfigurator = {
203  'dR':TrigComboHypoToolFromDict,
204  'dphi':TrigComboHypoToolFromDict,
205  'deta':TrigComboHypoToolFromDict,
206  'invm':TrigComboHypoToolFromDict,
207  'mT':TrigComboHypoToolFromDict,
208  'afpdijet':TrigAFPDijetComboHypoToolCfg,
209  'idZmumu':TrigMuonEFIdtpInvMassHypoToolCfg,
210  'idJpsimumu':TrigMuonEFIdtpInvMassHypoToolCfg,
211 }
212 
213 def addTopoInfo(theChainConfig, mainChainDict, listOfChainDefs, lengthOfChainConfigs):
214  log.debug("[addTopoInfo] Adding topo info to chain %s", theChainConfig)
215 
216  def findStepIndexInChain(chain, step):
217  for istep,chainstep in enumerate(chain.steps):
218  if chainstep.name==step:
219  return istep
220  return None
221 
222  for step,(topoCfg,topoExpr) in theChainConfig.topoMap.items():
223  thestep = theChainConfig.steps[-1] if step=="last" else theChainConfig.steps[findStepIndexInChain(theChainConfig,step)]
224  log.debug("[addTopoInfo] Adding %s to step %s",topoExpr,thestep)
225 
226  if thestep is None:
227  log.error("Failed to find step %s in Chain! ChainDict follows:", step)
228  log.error(mainChainDict)
229  raise RuntimeError("Step not found when adding topo to chain")
230 
231  bonus_debug = False
232 
233  if bonus_debug:
234  log.debug("[addTopoInfo] theChainConfig %s", theChainConfig)
235  log.debug("[addTopoInfo] listOfChainDefs %s", listOfChainDefs)
236  log.debug("[addTopoInfo] theTopoInfo being added is %s",topoExpr)
237 
238  # No need to add if it has been added previously
239  # Handle better and avoid doing this repeatedly on the same steps?
240  if topoCfg not in thestep.comboToolConfs:
241  if len(thestep.comboToolConfs) > 0:
242  log.warning("[addTopoInfo] step %s already has ComboHypo tools %s",thestep,thestep.comboToolConfs)
243  log.warning("[addTopoInfo] these will be added to, make sure this is the behaviour you want.")
244 
245  thestep.name = thestep.name+'_combo_'+topoExpr
246  thestep.addComboHypoTools(topoCfg)
247 
248  thestep.makeCombo()
249  log.debug("[addTopoInfo] new combo hypo name: %s",thestep.combo.name)
250 
251  if bonus_debug:
252  log.debug("[addTopoInfo] new theChainConfig %s", theChainConfig)
grepfile.info
info
Definition: grepfile.py:38
vtune_athena.format
format
Definition: vtune_athena.py:14
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
ComboHypoHandling.TrigComboHypoToolFromDict
def TrigComboHypoToolFromDict(flags, chainDict)
Definition: ComboHypoHandling.py:56
GenericMonitoringTool
Definition: GenericMonitoringTool.h:53
ComboHypoHandling.addTopoInfo
def addTopoInfo(theChainConfig, mainChainDict, listOfChainDefs, lengthOfChainConfigs)
Definition: ComboHypoHandling.py:213
HLTUtils.string2hash
def string2hash(string)
Definition: HLTUtils.py:5
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
readCCLHist.float
float
Definition: readCCLHist.py:83