ATLAS Offline Software
Trigger/TriggerCommon/TrigEDMConfig/python/Utils.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 from functools import lru_cache
4 from collections import defaultdict
5 import re
6 from GaudiKernel.DataHandle import DataHandle
7 from AthenaCommon.Logging import logging
8 log = logging.getLogger('TrigEDMConfig')
9 
10 @lru_cache(maxsize=None)
11 def getEDMVersionFromBS(filename):
12  """Determine Trigger EDM version based on the input ByteStream file.
13 
14  Run-3 EDM is indicated by HLT ROD version > 1.0. For Run 1 and 2 the
15  HLT ROD version was 0.0 and the run number is used to disambiguate between them.
16  """
17 
18  boundary_run12 = 230000
19  boundary_run23 = 368000
20 
21  import eformat
22  from libpyeformat_helper import SubDetector
23  bs = eformat.istream(filename)
24 
25  rodVersionM = None
26  rodVersionL = None
27  # Find the first HLT ROBFragment in the first event
28  for robf in bs[0]:
29  if robf.rob_source_id().subdetector_id()==SubDetector.TDAQ_HLT:
30  rodVersionM = robf.rod_minor_version() >> 8
31  rodVersionL = robf.rod_minor_version() & 0xFF
32  log.debug("HLT ROD minor version from input file is %d.%d", rodVersionM, rodVersionL)
33  break
34 
35  # Case 1: failed to read ROD version
36  if rodVersionM is None or rodVersionL is None:
37  log.warning("Cannot determine HLT ROD version from input file, falling back to run-number-based decision")
38  # Case 2: ROD version indicating Run 3
39  elif rodVersionM >= 1:
40  log.info("Determined EDMVersion to be 3, because running on BS file with HLT ROD version %d.%d",
41  rodVersionM, rodVersionL)
42  return 3
43 
44  # Case 3: ROD version indicating Run 1 or 2 - use run number to disambiguate
45  runNumber = bs[0].run_no()
46  log.debug("Read run number %s", runNumber)
47 
48  if not runNumber or runNumber <= 0:
49  log.warning("Cannot determine EDM version because run number %s is invalid. ", runNumber)
50  return None
51  elif runNumber < boundary_run12:
52  # Run-1 data
53  log.info("Determined EDMVersion to be 1 based on BS file run number (runNumber < %d)",
54  boundary_run12)
55  return 1
56  elif runNumber < boundary_run23:
57  # Run-2 data
58  log.info("Determined EDMVersion to be 2 based on BS file run number (%d < runNumber < %d)",
59  boundary_run12, boundary_run23)
60  return 2
61  else:
62  # Run-3 data
63  log.info("Determined EDMVersion to be 3 based on BS file run number (runNumber > %d)",
64  boundary_run23)
65  return 3
66 
67 
68 def edmDictToList(edmDict):
69  '''
70  Convert EDM dictionary in the format:
71  {'type1': ['key1','key2'], 'type2': ['key3']}
72  to a flat list in the format:
73  ['type1#key1', 'type1#key2', 'type2#key3']
74  '''
75  return [ f"{type}#{name}" for type, names in edmDict.items() for name in names ]
76 
77 
78 def edmListToDict(edmList):
79  '''
80  Convert EDM list in the format:
81  ['type1#key1', 'type1#key2', 'type2#key3']
82  to a dictionary in the format:
83  {'type1': ['key1','key2'], 'type2': ['key3']}
84  '''
85  edmDict = defaultdict(list)
86  for typeName in edmList:
87  edmType, edmKey = typeName.split('#')
88  edmDict[edmType].append(edmKey)
89  return edmDict
90 
91 
92 def getEDMListFromWriteHandles(configurables):
93  '''
94  Build OutputStream ItemList from all WriteHandles in a list of components (configurables),
95  for example a list of AlgTools. The output is in flat list format:
96  ['type1#key1', 'type1#key2', 'type2#key3']
97  '''
98 
99  def getWriteHandles(comp):
100  properties = [getattr(comp,propName) for propName in comp.getDefaultProperties().keys()]
101  return [prop for prop in properties if isinstance(prop,DataHandle) and prop.mode()=='W']
102 
103  def formatItem(containerType, containerKey):
104  auxType = containerType.replace('Container','AuxContainer')
105  return [f'{containerType}#{containerKey}',
106  f'{auxType}#{containerKey}Aux.-']
107 
108  def containerTypedef(containerType):
109  if containerType.startswith('xAOD::') and containerType.endswith('Container'):
110  # Already the right typedef
111  return containerType
112  m = re.match(r'DataVector<xAOD::(\w+)_v[0-9]+,', containerType)
113  if m and len(m.groups()) > 0:
114  return f'xAOD::{m.group(1)}Container'
115  raise RuntimeError(f'Failed to convert type {containerType} into a container typedef')
116 
117  def itemListFromConfigurable(comp):
118  items = []
119  for handle in getWriteHandles(comp):
120  sgKey = handle.Path.replace('StoreGateSvc+','')
121  if not sgKey:
122  continue
123  items += formatItem(containerTypedef(handle.Type), handle.Path)
124  return items
125 
126  itemList = []
127  for comp in configurables:
128  itemList += itemListFromConfigurable(comp)
129  return itemList
python.Utils.getEDMVersionFromBS
def getEDMVersionFromBS(filename)
Definition: Trigger/TriggerCommon/TrigEDMConfig/python/Utils.py:11
python.Utils.edmDictToList
def edmDictToList(edmDict)
Definition: Trigger/TriggerCommon/TrigEDMConfig/python/Utils.py:68
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.Utils.getEDMListFromWriteHandles
def getEDMListFromWriteHandles(configurables)
Definition: Trigger/TriggerCommon/TrigEDMConfig/python/Utils.py:92
python.Utils.edmListToDict
def edmListToDict(edmList)
Definition: Trigger/TriggerCommon/TrigEDMConfig/python/Utils.py:78
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:790