ATLAS Offline Software
TriggerConfigAccess.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 from typing import Any, Optional
4 from AthenaConfiguration.AccumulatorCache import AccumulatorCache
5 from AthenaCommon.Logging import logging
6 log = logging.getLogger( "TriggerConfigAccess.py" )
7 
8 from .TrigConfigSvcCfg import getTrigConfigFromFlag, getL1MenuFileName, getHLTMenuFileName, getL1PrescalesSetFileName, getHLTPrescalesSetFileName, getBunchGroupSetFileName, getHLTJobOptionsFileName, getHLTMonitoringFileName
9 
10 from TrigConfIO.L1TriggerConfigAccess import L1MenuAccess, L1PrescalesSetAccess, BunchGroupSetAccess
11 from TrigConfIO.HLTTriggerConfigAccess import HLTMenuAccess, HLTPrescalesSetAccess, HLTJobOptionsAccess, HLTMonitoringAccess
12 
13 from AthenaConfiguration.AutoConfigFlags import GetFileMD
14 from AthenaConfiguration.Enums import Format
15 
16 from functools import lru_cache
17 
18 """
19 Access to the trigger configuration in python is provided depending on
20 the trigger configuration source
21 
22 The tc source is taken from the TriggerFlag triggerConfig
23 
24 1) tc source is set to INFILE
25 
26 This is usually the case when running on ESD, AOD, and dAOD files and
27 only in this case. An exception is RDO with trigger information in
28 MC. The menu and prescales are taken from the pool file, from the
29 in-file metadata.
30 
31 
32 2) tc source is set to FILE
33 
34 This is the case when executing the trigger with the configuration
35 taken from file. The filename is provided by the function
36 @getL1MenuFileName
37 
38 3) tc source is set to DB
39 
40 This is the case when executing the trigger from the DB. The DB
41 connection and keys are provided by the triggerConfig flag
42 
43 4) tc source is COOL
44 
45 This is the case when reconstructing the data. From COOL the
46 configuration keys and db alias are taken, the configurations
47 are then loaded from the DB.
48 
49 """
50 
51 @lru_cache(maxsize=None)
52 def getKeysFromCool(runNr: int, lbNr: int = 0) -> dict[str,int]:
53  """Return dictionary of trigger keys for given run and lumiblock number
54  """
55  from TrigConfStorage.TriggerCoolUtil import TriggerCoolUtil
56  condb = "CONDBR2" if runNr > 236108 else "COMP200"
57  db = TriggerCoolUtil.GetConnection(condb)
58  run_range = [[runNr,runNr]]
59  d = { k: TriggerCoolUtil.getHLTConfigKeys(db, run_range)[runNr][k] for k in ['SMK', 'DB'] }
60  for ( key, lbfirst, lblast) in TriggerCoolUtil.getBunchGroupKey(db, run_range)[runNr]['BGKey']:
61  if lbNr>=lbfirst and (lbNr<=lblast or lblast==-1):
62  d['BGSK'] = key
63  break
64  for ( key, lbfirst, lblast) in TriggerCoolUtil.getL1ConfigKeys(db, run_range)[runNr]['LVL1PSK']:
65  if lbNr>=lbfirst and (lbNr<=lblast or lblast==-1):
66  d['L1PSK'] = key
67  break
68  for ( key, lbfirst, lblast) in TriggerCoolUtil.getHLTPrescaleKeys(db, run_range)[runNr]['HLTPSK2']:
69  if lbNr>=lbfirst and (lbNr<=lblast or lblast==-1):
70  d['HLTPSK'] = key
71  break
72 
73  # dbalias mapping
74  dbaliasMapping = { "TRIGGERDBR2R" : "TRIGGERDB",
75  "TRIGGERDBV2" : "TRIGGERDB_RUN1" }
76  if d["DB"] in dbaliasMapping:
77  d["DB"] = dbaliasMapping[ d["DB"] ]
78 
79  return d
80 
81 def getDBKeysFromMetadata(flags) -> Optional[dict[str, Any]]:
82  """Provides access to the database keys from the in-file metadata
83 
84  Gets the database keys from the in-file metadata which are stored together with the json representation
85  If the keys are in the file, then usually SMK, L1PSK and HLTPSK are present.
86  The bunchgroupset is not stored in the metadata, so 0 is returned for the BGS key for completeness.
87 
88  @returns: dictionary with the DB keys. Returns 'None' if information is not present.
89  """
90  metadata = GetFileMD(flags.Input.Files)
91  keys = metadata.get("TriggerConfigInfo", None)
92  if keys is None:
93  return None
94  return {
95  'SMK': keys['HLT']['key'] if 'HLT' in keys else 0,
96  'L1PSK': keys['L1PS']['key'] if 'L1PS' in keys else 0,
97  'HLTPSK': keys['HLTPS']['key'] if 'HLTPSK' in keys else 0,
98  'BGSK': 0
99  }
100 
101 """
102 Returns a string-serialised JSON object from the metadata store.
103 Checks AOD syntax first, then fully-qualified ESD syntax
104 """
105 def _getJSONFromMetadata(flags, key) -> Optional[dict[str,Any]]:
106  if flags.Input.Format != Format.POOL:
107  raise RuntimeError("Cannot read trigger configuration (%s) from input type %s", key, flags.Input.Format)
108  from AthenaConfiguration.AutoConfigFlags import GetFileMD
109  metadata = GetFileMD(flags.Input.Files)
110  menu_json = metadata.get(key, None)
111  if menu_json is None:
112  menu_json = metadata.get('DataVector<xAOD::TriggerMenuJson_v1>_%s' % key, None)
113  if menu_json is None:
114  if key == 'TriggerMenuJson_HLTMonitoring':
115  # currently the HLT Monitoring information is missing from many pool files' metadata
116  log.info("Trigger metadata with key 'TriggerMenuJson_HLTMonitoring' is not available in this file. This feature is currently being introduced.")
117  return None
118  else:
119  raise RuntimeError("Cannot read trigger configuration (%s) from input file metadata" % key)
120  return menu_json
121 
122 
123 """
124 
125 L1 information
126 
127 """
128 @AccumulatorCache
129 def getL1MenuAccess( flags = None ) -> L1MenuAccess:
130  tc = getTrigConfigFromFlag( flags )
131  if tc["SOURCE"] == "FILE":
132  cfg = L1MenuAccess( filename = getL1MenuFileName( flags ) )
133  elif tc["SOURCE"] == "COOL":
134  """This is the case when reconstructing the data."""
135  if len(flags.Input.RunNumbers) == 0:
136  raise RuntimeError("No run number available in input metadata")
137  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
138  cfg = L1MenuAccess( dbalias = keysFromCool["DB"], smkey = keysFromCool['SMK'] )
139  elif tc["SOURCE"] == "DB":
140  cfg = L1MenuAccess( dbalias = tc["DBCONN"], smkey = tc["SMK"] )
141  elif tc["SOURCE"] == "INFILE":
142  cfg = L1MenuAccess(jsonString=_getJSONFromMetadata(flags, key='TriggerMenuJson_L1'))
143  else:
144  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
145  return cfg
146 
147 
148 @AccumulatorCache
149 def getL1PrescalesSetAccess( flags = None ) -> L1PrescalesSetAccess:
150  tc = getTrigConfigFromFlag( flags )
151  if tc["SOURCE"] == "FILE":
152  cfg = L1PrescalesSetAccess( filename = getL1PrescalesSetFileName( flags ) )
153  elif tc["SOURCE"] == "COOL":
154  """This is the case when reconstructing the data."""
155  if len(flags.Input.RunNumbers) == 0:
156  raise RuntimeError("No run number available in input metadata")
157  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
158  cfg = L1PrescalesSetAccess( dbalias = keysFromCool["DB"], l1pskey = keysFromCool['L1PSK'] )
159  elif tc["SOURCE"] == "DB":
160  cfg = L1PrescalesSetAccess( dbalias = tc["DBCONN"], l1pskey = tc["L1PSK"] )
161  elif tc["SOURCE"] == "INFILE":
162  cfg = L1PrescalesSetAccess(jsonString=_getJSONFromMetadata(flags, key='TriggerMenuJson_L1PS'))
163  else:
164  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
165  return cfg
166 
167 
168 @AccumulatorCache
169 def getBunchGroupSetAccess( flags = None ) -> BunchGroupSetAccess:
170  tc = getTrigConfigFromFlag( flags )
171  if tc["SOURCE"] == "FILE":
172  cfg = BunchGroupSetAccess( filename = getBunchGroupSetFileName( flags ) )
173  elif tc["SOURCE"] == "COOL":
174  """This is the case when reconstructing the data."""
175  if len(flags.Input.RunNumbers) == 0:
176  raise RuntimeError("No run number available in input metadata")
177  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
178  cfg = BunchGroupSetAccess( dbalias = keysFromCool["DB"], bgskey = keysFromCool['BGSK'] )
179  elif tc["SOURCE"] == "DB":
180  cfg = BunchGroupSetAccess( dbalias = tc["DBCONN"], bgskey = tc["BGSK"] )
181  elif tc["SOURCE"] == "INFILE":
182  if flags.Input.Format != Format.POOL:
183  raise RuntimeError(f"Cannot read trigger configuration (Bunchgroup Set) from input type {flags.Input.Format}")
184  raise NotImplementedError("Python access to the trigger configuration (Bunchgroup Set) from in-file metadata not yet implemented")
185  else:
186  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
187  return cfg
188 
189 
190 """
191 
192 HLT information
193 
194 """
195 @AccumulatorCache
196 def getHLTMenuAccess( flags = None ) -> HLTMenuAccess:
197  tc = getTrigConfigFromFlag( flags )
198  if tc["SOURCE"] == "FILE":
199  cfg = HLTMenuAccess( filename = getHLTMenuFileName( flags ) )
200  elif tc["SOURCE"] == "COOL":
201  """This is the case when reconstructing the data."""
202  if len(flags.Input.RunNumbers) == 0:
203  raise RuntimeError("No run number available in input metadata")
204  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
205  cfg = HLTMenuAccess( dbalias = keysFromCool["DB"], smkey = keysFromCool['SMK'] )
206  elif tc["SOURCE"] == "DB":
207  cfg = HLTMenuAccess( dbalias = tc["DBCONN"], smkey = tc["SMK"] )
208  elif tc["SOURCE"] == "INFILE":
209  cfg = HLTMenuAccess(jsonString=_getJSONFromMetadata(flags, key='TriggerMenuJson_HLT'))
210  else:
211  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
212  return cfg
213 
214 
215 @AccumulatorCache
216 def getHLTPrescalesSetAccess( flags = None ) -> HLTPrescalesSetAccess:
217  tc = getTrigConfigFromFlag( flags )
218  if tc["SOURCE"] == "FILE":
219  cfg = HLTPrescalesSetAccess( filename = getHLTPrescalesSetFileName( flags ) )
220  elif tc["SOURCE"] == "COOL":
221  """This is the case when reconstructing the data."""
222  if len(flags.Input.RunNumbers) == 0:
223  raise RuntimeError("No run number available in input metadata")
224  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
225  cfg = HLTPrescalesSetAccess( dbalias = keysFromCool["DB"], hltpskey = keysFromCool['HLTPSK'] )
226  elif tc["SOURCE"] == "DB":
227  cfg = HLTPrescalesSetAccess( dbalias = tc["DBCONN"], hltpskey = tc["HLTPSK"] )
228  elif tc["SOURCE"] == "INFILE":
229  cfg = HLTPrescalesSetAccess(jsonString=_getJSONFromMetadata(flags, key='TriggerMenuJson_HLTPS'))
230  else:
231  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
232  return cfg
233 
234 
235 @AccumulatorCache
236 def getHLTJobOptionsAccess( flags = None ) -> HLTJobOptionsAccess:
237  tc = getTrigConfigFromFlag( flags )
238  if tc["SOURCE"] == "FILE":
239  cfg = HLTJobOptionsAccess( filename = getHLTJobOptionsFileName() )
240  elif tc["SOURCE"] == "COOL":
241  """This is the case when reconstructing the data."""
242  if len(flags.Input.RunNumbers) == 0:
243  raise RuntimeError("No run number available in input metadata")
244  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
245  cfg = HLTJobOptionsAccess( dbalias = keysFromCool["DB"], smkey = keysFromCool['SMK'] )
246  elif tc["SOURCE"] == "DB":
247  cfg = HLTJobOptionsAccess( dbalias = tc["DBCONN"], smkey = tc["SMK"] )
248  elif tc["SOURCE"] == "INFILE":
249  raise NotImplementedError("Python access to the HLT Job Options configuration from in-file metadata is NOT SUPPORTED (this file is huge!)")
250  else:
251  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
252  return cfg
253 
254 
255 @AccumulatorCache
256 def getHLTMonitoringAccess( flags = None ) -> HLTMonitoringAccess:
257  tc = getTrigConfigFromFlag( flags )
258  if tc["SOURCE"] == "FILE":
259  cfg = HLTMonitoringAccess( filename = getHLTMonitoringFileName( flags ) )
260  elif tc["SOURCE"] == "COOL":
261  """This is the case when reconstructing the data."""
262  if len(flags.Input.RunNumbers) == 0:
263  raise RuntimeError("No run number available in input metadata")
264  keysFromCool = getKeysFromCool( flags.Input.RunNumbers[0] )
265  cfg = HLTMonitoringAccess( dbalias = keysFromCool["DB"], smkey = keysFromCool['SMK'] )
266  elif tc["SOURCE"] == "DB":
267  cfg = HLTMonitoringAccess( dbalias = tc["DBCONN"], smkey = tc["SMK"] )
268  elif tc["SOURCE"] == "INFILE":
269  jsonHLTMon = _getJSONFromMetadata(flags, key='TriggerMenuJson_HLTMonitoring')
270  if jsonHLTMon is not None:
271  cfg = HLTMonitoringAccess(jsonString=jsonHLTMon)
272  else:
273  keysFromInfileMD = getDBKeysFromMetadata(flags)
274  smkey = keysFromInfileMD['SMK'] if keysFromInfileMD is not None else 0
275  if smkey < 3000 and not flags.Input.isMC:
276  # Run 1/2 data or keys missing in metadata
277  log.info("Trigger metadata with key 'TriggerMenuJson_HLTMonitoring' is not available for Run 2 data. Returning empty dummy.")
278  jsonHLTMon = '{"filetype": "hltmonitoringsummary","name": "EmptyDefault", "signatures": {}}'
279  cfg = HLTMonitoringAccess(jsonString=jsonHLTMon)
280  else:
281  # Run 3 data or MC
282  try:
283  log.info("Falling back on reading the HLTMonitoring from the TRIGGERDB_RUN3 for SMK %i.", smkey)
284  cfg = HLTMonitoringAccess( dbalias = "TRIGGERDB_RUN3", smkey = smkey )
285  except KeyError:
286  # SMK for this run has no HLT monitoring (earlier 2022 data) => providing dummy configuration
287  log.info("Trigger HLTMonitoring is not available for SMK %i. Returning empty dummy.", smkey)
288  jsonHLTMon = '{"filetype": "hltmonitoringsummary","name": "EmptyDefault", "signatures": {}}'
289  cfg = HLTMonitoringAccess(jsonString=jsonHLTMon)
290 
291  else:
292  raise RuntimeError("Unknown source of trigger configuration: %s" % tc["SOURCE"])
293  return cfg
python.AutoConfigFlags.GetFileMD
def GetFileMD(filenames, allowEmpty=True, maxLevel='peeker')
Definition: AutoConfigFlags.py:65
python.TrigConfigSvcCfg.getHLTMenuFileName
def getHLTMenuFileName(flags)
Definition: TrigConfigSvcCfg.py:140
python.TriggerConfigAccess.getHLTMonitoringAccess
HLTMonitoringAccess getHLTMonitoringAccess(flags=None)
Definition: TriggerConfigAccess.py:256
python.TrigConfigSvcCfg.getTrigConfigFromFlag
def getTrigConfigFromFlag(flags)
Definition: TrigConfigSvcCfg.py:80
python.TrigConfigSvcCfg.getL1MenuFileName
def getL1MenuFileName(flags)
Definition: TrigConfigSvcCfg.py:136
python.TrigConfigSvcCfg.getHLTJobOptionsFileName
def getHLTJobOptionsFileName()
Definition: TrigConfigSvcCfg.py:160
python.TrigConfigSvcCfg.getBunchGroupSetFileName
def getBunchGroupSetFileName(flags)
Definition: TrigConfigSvcCfg.py:156
python.TrigConfigSvcCfg.getL1PrescalesSetFileName
def getL1PrescalesSetFileName(flags)
Definition: TrigConfigSvcCfg.py:148
python.TriggerConfigAccess.getL1MenuAccess
L1MenuAccess getL1MenuAccess(flags=None)
Definition: TriggerConfigAccess.py:129
python.TriggerConfigAccess.getHLTPrescalesSetAccess
HLTPrescalesSetAccess getHLTPrescalesSetAccess(flags=None)
Definition: TriggerConfigAccess.py:216
python.TriggerConfigAccess.getDBKeysFromMetadata
Optional[dict[str, Any]] getDBKeysFromMetadata(flags)
Definition: TriggerConfigAccess.py:81
python.TriggerConfigAccess.getL1PrescalesSetAccess
L1PrescalesSetAccess getL1PrescalesSetAccess(flags=None)
Definition: TriggerConfigAccess.py:149
python.TrigConfigSvcCfg.getHLTMonitoringFileName
def getHLTMonitoringFileName(flags)
Definition: TrigConfigSvcCfg.py:144
python.TriggerConfigAccess.getHLTJobOptionsAccess
HLTJobOptionsAccess getHLTJobOptionsAccess(flags=None)
Definition: TriggerConfigAccess.py:236
python.TriggerConfigAccess.getHLTMenuAccess
HLTMenuAccess getHLTMenuAccess(flags=None)
Definition: TriggerConfigAccess.py:196
python.TriggerConfigAccess._getJSONFromMetadata
Optional[dict[str, Any]] _getJSONFromMetadata(flags, key)
Definition: TriggerConfigAccess.py:105
python.TriggerConfigAccess.getBunchGroupSetAccess
BunchGroupSetAccess getBunchGroupSetAccess(flags=None)
Definition: TriggerConfigAccess.py:169
python.TriggerConfigAccess.getKeysFromCool
dict[str, int] getKeysFromCool(int runNr, int lbNr=0)
Definition: TriggerConfigAccess.py:52
python.TrigConfigSvcCfg.getHLTPrescalesSetFileName
def getHLTPrescalesSetFileName(flags)
Definition: TrigConfigSvcCfg.py:152